1- def x_or_y : Unit :=
2- ()
1+ import Std.Data.Iterators
2+ import Init.Notation
3+ import Std.Tactic.Do
4+
5+ open Std.Iterators
6+
7+ /-!
8+ ## Implementation
9+ -/
10+
11+ def isPrime (n : Nat) : Bool :=
12+ let divisors := (2 ...<n).iter.takeWhile (fun i => i * i ≤ n) |>.filter (· ∣ n)
13+ 2 ≤ n ∧ divisors.fold (init := 0 ) (fun count _ => count + 1 ) = 0
14+
15+ def x_or_y (n : Int) (x y : α) : α := Id.run do
16+ let some n := n.toNat? | return y
17+ if isPrime n then
18+ return x
19+ else
20+ return y
21+
22+ /-- info: [2, 3, 5, 7, 11, 13, 17, 19] -/
23+ #guard_msgs in
24+ #eval (1 ...20 ).iter.filter isPrime |>.toList
25+
26+ /-!
27+ ## Tests
28+ -/
29+
30+ example : x_or_y 15 8 5 = 5 := by native_decide
31+ example : x_or_y 3 33 5212 = 33 := by native_decide
32+ example : x_or_y 1259 3 52 = 3 := by native_decide
33+ example : x_or_y 7919 (-1 ) 12 = -1 := by native_decide
34+ example : x_or_y 3609 1245 583 = 583 := by native_decide
35+ example : x_or_y 91 56 129 = 129 := by native_decide
36+ example : x_or_y 6 34 1234 = 1234 := by native_decide
37+ example : x_or_y 1 2 0 = 0 := by native_decide
38+ example : x_or_y 2 2 0 = 2 := by native_decide
39+
40+ /-!
41+ ## Verification
42+ -/
43+
44+ def IsPrime (n : Nat) : Prop :=
45+ 2 ≤ n ∧ ∀ d : Nat, d ∣ n → d = 1 ∨ d = n
46+
47+ theorem isPrime_eq_true_iff {n : Nat} :
48+ isPrime n = true ↔ 2 ≤ n ∧
49+ (List.filter (· ∣ n) (List.takeWhile (fun i => i * i ≤ n) (2 ...n).toList)).length = 0 := by
50+ simp [isPrime, ← Iter.foldl_toList]
51+
52+ theorem isPrime_iff_mul_self {n : Nat} :
53+ IsPrime n ↔ (2 ≤ n ∧ ∀ (a : Nat), 2 ≤ a ∧ a < n → a ∣ n → n < a * a) := by
54+ rw [IsPrime]
55+ by_cases hn : 2 ≤ n; rotate_left; grind
56+ apply Iff.intro
57+ · grind
58+ · rintro ⟨hn, h⟩
59+ refine ⟨hn, fun d hd => ?_⟩
60+ · have : 0 < d := Nat.pos_of_dvd_of_pos hd (by grind)
61+ have : d ≤ n := Nat.le_of_dvd (by grind) hd
62+ false_or_by_contra
63+ by_cases hsq : d * d ≤ n
64+ · specialize h d
65+ grind
66+ · replace h := h (n / d) ?_ ?_; rotate_left
67+ · have : d ≥ 2 := by grind
68+ refine ⟨?_, Nat.div_lt_self (n := n) (k := d) (by grind) (by grind)⟩
69+ false_or_by_contra; rename_i hc
70+ have : n / d * d ≤ 1 * d := Nat.mul_le_mul_right d (Nat.le_of_lt_succ (Nat.lt_of_not_ge hc))
71+ grind [Nat.dvd_iff_div_mul_eq]
72+ · exact Nat.div_dvd_of_dvd hd
73+ simp only [Nat.not_le] at hsq
74+ have := Nat.mul_lt_mul_of_lt_of_lt h hsq
75+ replace : n * n < ((n / d) * d) * ((n / d) * d) := by grind
76+ rw [Nat.dvd_iff_div_mul_eq] at hd
77+ grind
78+
79+ theorem ClosedOpen.toList_eq_nil_of_le {m n : Nat} (h : n ≤ m) :
80+ (m...n).toList = [] := by
81+ simp [Std.PRange.toList_eq_nil_iff, Std.PRange.BoundedUpwardEnumerable.init?,
82+ Std.PRange.SupportsUpperBound.IsSatisfied, show n ≤ m by grind]
83+
84+ theorem List.takeWhile_eq_filter {P : α → Bool} {xs : List α}
85+ (h : xs.Pairwise (fun x y => P y → P x)) :
86+ xs.takeWhile P = xs.filter P := by
87+ induction xs with
88+ | nil => simp
89+ | cons x xs ih =>
90+ simp only [takeWhile_cons, filter_cons]
91+ simp only [pairwise_cons] at h
92+ split
93+ · simp [*]
94+ · simpa [*] using h
95+
96+ theorem isPrime_eq_true_iff_isPrime {n : Nat} :
97+ isPrime n ↔ IsPrime n := by
98+ simp only [isPrime_eq_true_iff]
99+ by_cases hn : 2 ≤ n; rotate_left
100+ · rw [ClosedOpen.toList_eq_nil_of_le (by grind)]
101+ grind [IsPrime]
102+ rw [List.takeWhile_eq_filter]; rotate_left
103+ · apply Std.PRange.pairwise_toList_le.imp
104+ intro a b hab hb
105+ have := Nat.mul_self_le_mul_self hab
106+ grind
107+ simp [Std.PRange.mem_toList_iff_mem, Std.PRange.mem_iff_isSatisfied,
108+ Std.PRange.SupportsLowerBound.IsSatisfied, Std.PRange.SupportsUpperBound.IsSatisfied,
109+ isPrime_iff_mul_self]
110+
111+ open Classical in
112+ theorem x_or_y_of_isPrime {n : Int} {x y : α} :
113+ x_or_y n x y = if n ≥ 0 ∧ IsPrime n.toNat then x else y := by
114+ generalize hwp : x_or_y n x y = w
115+ apply Std.Do.Id.of_wp_run_eq hwp
116+ mvcgen
117+ · grind [isPrime_eq_true_iff_isPrime, Int.mem_toNat?]
118+ · grind [isPrime_eq_true_iff_isPrime, Int.mem_toNat?]
119+ · suffices n < 0 by grind
120+ rename_i _ h₁ h₂
121+ specialize h₁ n.toNat
122+ cases h₂
123+ grind [Int.mem_toNat?]
3124
4125/-!
5126## Prompt
6127
7128```python3
8129
9130def x_or_y(n, x, y):
10- """A simple program which should return the value of x if n is
131+ """A simple program which should return the value of x if n is
11132 a prime number and should return the value of y otherwise.
12133
13134 Examples:
14135 for x_or_y(7, 34, 12) == 34
15136 for x_or_y(15, 8, 5) == 5
16-
137+
17138 """
18139```
19140
@@ -44,11 +165,11 @@ def check(candidate):
44165 assert candidate(3609, 1245, 583) == 583
45166 assert candidate(91, 56, 129) == 129
46167 assert candidate(6, 34, 1234) == 1234
47-
168+
48169
49170 # Check some edge cases that are easy to work out by hand.
50171 assert candidate(1, 2, 0) == 0
51172 assert candidate(2, 2, 0) == 2
52173
53174```
54- -/
175+ -/
0 commit comments