11module
22
3- def iscube : Unit :=
4- ()
3+ public section
4+
5+ open Std
6+
7+ /-! ## Implementation -/
8+
9+ def isCubeOfRange (x : Int) (lower : Int) (upper : Int) : Bool :=
10+ if upper ≤ lower + 1 then
11+ lower ^ 3 = x
12+ else
13+ let mid := (lower + upper) / 2
14+ isCubeOfRange x lower mid || isCubeOfRange x mid upper
15+ termination_by (upper - lower).toNat
16+
17+ def isCube (x : Int) : Bool :=
18+ isCubeOfRange x (- Int.natAbs x) (Int.natAbs x + 1 )
19+
20+ /-! ## Tests -/
21+
22+ example : isCube 1 = true := by native_decide
23+ example : isCube 2 = false := by native_decide
24+ example : isCube (-1 ) = true := by native_decide
25+ example : isCube 64 = true := by native_decide
26+ example : isCube 180 = false := by native_decide
27+ example : isCube 1000 = true := by native_decide
28+ example : isCube 0 = true := by native_decide
29+ example : isCube 1729 = false := by native_decide
30+
31+ /-! ## Missing API -/
32+
33+ theorem Int.natAbs_le_iff {x y : Int} :
34+ x.natAbs ≤ y ↔ x ≤ y ∧ -x ≤ y := by
35+ grind
36+
37+ theorem Int.le_pow {x : Int} (h : 0 ≤ x) (hn : 0 < n) :
38+ x ≤ x ^ n := by
39+ have : x.toNat ≤ x.toNat ^ n := Nat.le_pow (by grind)
40+ grind
41+
42+ protected theorem Int.mul_le_mul_iff_of_pos_left {a b c : Int} (ha : 0 < a) : a * b ≤ a * c ↔ b ≤ c :=
43+ ⟨(le_of_mul_le_mul_left · ha), (Int.mul_le_mul_of_nonneg_left · (Int.le_of_lt ha))⟩
44+
45+ protected theorem Int.mul_nonneg_iff_of_pos_left {a b : Int} (ha : 0 < a) : 0 ≤ a * b ↔ 0 ≤ b := by
46+ simpa using (Int.mul_le_mul_iff_of_pos_left ha : a * 0 ≤ a * b ↔ 0 ≤ b)
47+
48+ protected theorem Int.mul_nonneg_iff {a b : Int} :
49+ 0 ≤ a * b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := by
50+ constructor
51+ · intro h
52+ cases hcmp : compare 0 a
53+ · rw [Int.mul_nonneg_iff_of_pos_left (by grind)] at h
54+ grind
55+ · grind
56+ · let a' := -a
57+ let b' := -b
58+ replace h : 0 ≤ a' * b' := by grind
59+ have : 0 < a' := by grind
60+ rw [Int.mul_nonneg_iff_of_pos_left (by grind)] at h
61+ grind
62+ · rintro (h | h)
63+ · exact Int.mul_nonneg (by grind) (by grind)
64+ · exact Int.mul_nonneg_of_nonpos_of_nonpos (by grind) (by grind)
65+
66+ protected theorem Int.mul_pos_iff {a b : Int} :
67+ 0 < a * b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := by
68+ let a' := -a
69+ suffices ¬ 0 ≤ a' * b ↔ a' < 0 ∧ 0 < b ∨ 0 < a' ∧ b < 0 by grind
70+ rw [Int.mul_nonneg_iff]
71+ grind
72+
73+ protected theorem Int.mul_neg_iff_of_neg_right {a b : Int} (hb : b < 0 ) : a * b < 0 ↔ 0 < a := by
74+ suffices ¬ 0 ≤ a * b ↔ 0 < a by grind
75+ rw [Int.mul_nonneg_iff]
76+ grind
77+
78+ protected theorem Int.mul_self_nonneg {a : Int} :
79+ 0 ≤ a * a := by
80+ rw [Int.mul_nonneg_iff]
81+ grind
82+
83+ protected theorem Int.mul_self_pos {a : Int} (h : a ≠ 0 ) :
84+ 0 < a * a := by
85+ rw [Int.mul_pos_iff]
86+ grind
87+
88+ /-! ## Verification -/
89+
90+ private theorem isCubeOfRange_iff (h : lower < upper) :
91+ isCubeOfRange x lower upper ↔ ∃ y ∈ lower...upper, y ^ 3 = x := by
92+ fun_induction isCubeOfRange x lower upper <;> grind [Rco.mem_iff]
93+
94+ private theorem Int.pow_three_lt_pow_three {x y : Int} (h : x < y) :
95+ x ^ 3 < y ^ 3 := by
96+ simp only [show ∀ x : Int, x ^ 3 = x * x * x by grind]
97+ by_cases 0 ≤ x
98+ · apply Int.mul_lt_mul'
99+ · apply Int.mul_self_le_mul_self (by grind) (by grind)
100+ · grind
101+ · grind
102+ · have : 0 < y := by grind
103+ apply Int.mul_pos (by grind) (by grind)
104+ · by_cases 0 ≤ y
105+ · have : x * x * x < 0 := by
106+ rw [Int.mul_neg_iff_of_neg_right]
107+ · apply Int.mul_self_pos (by grind)
108+ · grind
109+ have : 0 ≤ y * y * y := by
110+ apply Int.mul_nonneg
111+ · apply Int.mul_self_nonneg
112+ · assumption
113+ grind
114+ · let x' := -x
115+ let y' := -y
116+ suffices y' * y' * y' < x' * x' * x' by grind
117+ apply Int.mul_lt_mul'
118+ · apply Int.mul_self_le_mul_self (by grind) (by grind)
119+ · grind
120+ · grind
121+ · have : 0 < x' := by grind
122+ apply Int.mul_pos (by grind) (by grind)
123+
124+ private theorem Int.pow_three_le_pow_three_iff {x y : Int} :
125+ x ^ 3 ≤ y ^ 3 ↔ x ≤ y := by
126+ have := Int.pow_three_lt_pow_three (x := x) (y := y)
127+ have := Int.pow_three_lt_pow_three (x := y) (y := x)
128+ cases hcmp : compare x y <;> grind
129+
130+ theorem isCube_iff :
131+ isCube x ↔ ∃ y, y ^ 3 = x := by
132+ rw [isCube, isCubeOfRange_iff]
133+ · constructor
134+ · grind
135+ · rintro ⟨y, hy⟩
136+ refine ⟨y, ?_, hy⟩
137+ simp only [Rco.mem_iff, ← hy, Int.natAbs_pow, Int.natCast_pow, Int.lt_add_one_iff,
138+ Int.neg_le_iff, and_comm, ← Int.natAbs_le_iff]
139+ exact Int.le_pow (by grind) (by grind)
140+ · grind
5141
6142/-!
7143## Prompt
@@ -10,7 +146,7 @@ def iscube : Unit :=
10146
11147def iscube(a):
12148 '''
13- Write a function that takes an integer a and returns True
149+ Write a function that takes an integer a and returns True
14150 if this ingeger is a cube of some integer number.
15151 Note: you may assume the input is always valid.
16152 Examples:
@@ -49,4 +185,4 @@ def check(candidate):
49185 assert candidate(1729) == False, "2nd edge test error: " + str(candidate(1728))
50186
51187```
52- -/
188+ -/
0 commit comments