Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 8d27f70

Browse files
committed
feat(tactic/norm_num): add support for {nat,int}.div
1 parent b1981c9 commit 8d27f70

File tree

3 files changed

+75
-19
lines changed

3 files changed

+75
-19
lines changed

data/rat.lean

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,9 @@ begin
137137
a / nat.gcd a b = c / nat.gcd c d ∧ b / nat.gcd a b = d / nat.gcd c d,
138138
{ intros a c h,
139139
have bd : b / nat.gcd a b = d / nat.gcd c d,
140-
{ have : ∀ {a c} (b>0) (d>0),
140+
{ suffices : ∀ {a c} (b>0) (d>0),
141141
a * d = c * b → b / nat.gcd a b ≤ d / nat.gcd c d,
142-
tactic.swap, { exact le_antisymm (this _ hb _ hd h) (this _ hd _ hb h.symm) },
142+
{ exact le_antisymm (this _ hb _ hd h) (this _ hd _ hb h.symm) },
143143
intros a c b hb d hd h,
144144
have gb0 := nat.gcd_pos_of_pos_right a hb,
145145
have gd0 := nat.gcd_pos_of_pos_right c hd,
@@ -159,10 +159,8 @@ begin
159159
nat.mul_div_assoc _ (nat.gcd_dvd_right _ _), bd,
160160
← nat.mul_div_assoc _ (nat.gcd_dvd_right _ _), h, mul_comm,
161161
nat.mul_div_assoc _ (nat.gcd_dvd_left _ _)] },
162-
have ha := this a.nat_abs c.nat_abs begin
163-
have := congr_arg int.nat_abs h,
164-
simp [int.nat_abs_mul] at this, exact this
165-
end,
162+
have ha := this a.nat_abs c.nat_abs
163+
(by simpa [int.nat_abs_mul] using congr_arg int.nat_abs h),
166164
tactic.congr_core,
167165
{ have hs := congr_arg int.sign h,
168166
simp [int.sign_eq_one_of_pos (int.coe_nat_lt.2 hb),

tactic/norm_num.lean

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@ protected meta def to_pos_rat : expr → option ℚ
2727
| `(%%e₁ / %%e₂) := do m ← e₁.to_nat, n ← e₂.to_nat, some (rat.mk m n)
2828
| e := do n ← e.to_nat, return (rat.of_int n)
2929

30+
protected meta def to_int : expr → option ℤ
31+
| `(has_neg.neg %%e) := do n ← e.to_nat, some (-n)
32+
| e := do n ← e.to_nat, return n
33+
3034
protected meta def to_rat : expr → option ℚ
3135
| `(has_neg.neg %%e) := do q ← e.to_pos_rat, some (-q)
3236
| e := e.to_pos_rat
3337

3438
protected meta def of_nat (α : expr) : ℕ → tactic expr :=
3539
nat.binary_rec
36-
(tactic.mk_app ``has_zero.zero [α])
40+
(tactic.mk_mapp ``has_zero.zero [some α, none])
3741
(λ b n tac, if n = 0 then mk_mapp ``has_one.one [some α, none] else
3842
do e ← tac, tactic.mk_app (cond b ``bit1 ``bit0) [e])
3943

@@ -91,6 +95,14 @@ lemma lt_add_of_pos_helper [ordered_cancel_comm_monoid α]
9195
(a b c : α) (h : a + b = c) (h₂ : 0 < b) : a < c :=
9296
h ▸ (lt_add_iff_pos_right _).2 h₂
9397

98+
lemma nat_div_helper (a b q r : ℕ) (h : r + q * b = a) (h₂ : r < b) : a / b = q :=
99+
by rw [← h, nat.add_mul_div_right _ _ (lt_of_le_of_lt (nat.zero_le _) h₂),
100+
nat.div_eq_of_lt h₂, zero_add]
101+
102+
lemma int_div_helper (a b q r : ℤ) (h : r + q * b = a) (h₁ : 0 ≤ r) (h₂ : r < b) : a / b = q :=
103+
by rw [← h, int.add_mul_div_right _ _ (ne_of_gt (lt_of_le_of_lt h₁ h₂)),
104+
int.div_eq_zero_of_lt h₁ h₂, zero_add]
105+
94106
meta structure instance_cache :=
95107
(α : expr)
96108
(univ : level)
@@ -123,17 +135,6 @@ do d ← get_decl n,
123135

124136
end instance_cache
125137

126-
meta def eval_inv (simp : expr → tactic (expr × expr)) : expr → tactic (expr × expr)
127-
| `(has_inv.inv %%e) := do
128-
c ← infer_type e >>= mk_instance_cache,
129-
(c, p₁) ← c.mk_app ``inv_eq_one_div [e],
130-
(c, o) ← c.mk_app ``has_one.one [],
131-
(c, e') ← c.mk_app ``has_div.div [o, e],
132-
(do (e'', p₂) ← simp e',
133-
p ← mk_eq_trans p₁ p₂,
134-
return (e'', p)) <|> return (e', p₁)
135-
| _ := failed
136-
137138
meta def eval_pow (simp : expr → tactic (expr × expr)) : expr → tactic (expr × expr)
138139
| `(monoid.pow %%e₁ 0) := do
139140
p ← mk_app ``pow_zero [e₁],
@@ -247,9 +248,62 @@ meta def eval_ineq (simp : expr → tactic (expr × expr)) : expr → tactic (ex
247248
| `(%%e₁ ≠ %%e₂) := do e ← mk_app ``eq [e₁, e₂], mk_app ``not [e] >>= simp
248249
| _ := failed
249250

251+
meta def eval_div_ext (simp : expr → tactic (expr × expr)) : expr → tactic (expr × expr)
252+
| `(has_inv.inv %%e) := do
253+
c ← infer_type e >>= mk_instance_cache,
254+
(c, p₁) ← c.mk_app ``inv_eq_one_div [e],
255+
(c, o) ← c.mk_app ``has_one.one [],
256+
(c, e') ← c.mk_app ``has_div.div [o, e],
257+
(do (e'', p₂) ← simp e',
258+
p ← mk_eq_trans p₁ p₂,
259+
return (e'', p)) <|> return (e', p₁)
260+
| `(%%e₁ / %%e₂) := do
261+
α ← infer_type e₁,
262+
c ← mk_instance_cache α,
263+
match α with
264+
| `(nat) := do
265+
n₁ ← e₁.to_nat, n₂ ← e₂.to_nat,
266+
q ← expr.of_nat α (n₁ / n₂),
267+
r ← expr.of_nat α (n₁ % n₂),
268+
(c, e₃) ← c.mk_app ``has_mul.mul [q, e₂],
269+
(c, e₃) ← c.mk_app ``has_add.add [r, e₃],
270+
(e₁', p) ← norm_num e₃,
271+
guard (e₁' =ₐ e₁),
272+
(c, p') ← prove_lt simp c r e₂,
273+
p ← mk_app ``norm_num.nat_div_helper [e₁, e₂, q, r, p, p'],
274+
return (q, p)
275+
| `(int) := match e₂ with
276+
| `(- %%e₂') := do
277+
(c, p₁) ← c.mk_app ``int.div_neg [e₁, e₂'],
278+
(c, e) ← c.mk_app ``has_div.div [e₁, e₂'],
279+
(c, e) ← c.mk_app ``has_neg.neg [e],
280+
(e', p₂) ← simp e,
281+
p ← mk_eq_trans p₁ p₂,
282+
return (e', p)
283+
| _ := do
284+
n₁ ← e₁.to_int,
285+
n₂ ← e₂.to_int,
286+
q ← expr.of_rat α $ rat.of_int (n₁ / n₂),
287+
r ← expr.of_rat α $ rat.of_int (n₁ % n₂),
288+
(c, e₃) ← c.mk_app ``has_mul.mul [q, e₂],
289+
(c, e₃) ← c.mk_app ``has_add.add [r, e₃],
290+
(e₁', p) ← norm_num e₃,
291+
guard (e₁' =ₐ e₁),
292+
(c, r0) ← c.mk_app ``has_zero.zero [],
293+
(c, r0) ← c.mk_app ``has_le.le [r0, r],
294+
(_, p₁) ← simp r0,
295+
p₁ ← mk_app ``of_eq_true [p₁],
296+
(c, p₂) ← prove_lt simp c r e₂,
297+
p ← mk_app ``norm_num.int_div_helper [e₁, e₂, q, r, p, p₁, p₂],
298+
return (q, p)
299+
end
300+
| _ := failed
301+
end
302+
| _ := failed
303+
250304
meta def derive1 (simp : expr → tactic (expr × expr)) (e : expr) :
251305
tactic (expr × expr) :=
252-
norm_num e <|> eval_inv simp e <|> eval_pow simp e <|> eval_ineq simp e
306+
norm_num e <|> eval_div_ext simp e <|> eval_pow simp e <|> eval_ineq simp e
253307

254308
meta def derive : expr → tactic (expr × expr) | e :=
255309
do (_, e', pr) ←

tests/norm_num.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ example : (6:real) < 10 := by norm_num
2424
example : (7:real)/2 > 3 := by norm_num
2525
example : (4:real)⁻¹ < 1 := by norm_num
2626

27+
example : (5 / 2:ℕ) = 2 := by norm_num
28+
example : (5 / -2:ℤ) < -1 := by norm_num
29+
example : (0 + 1) / 2 < 0 + 1 := by norm_num
30+
2731
example (x : ℤ) (h : 1000 + 2000 < x) : 100 * 30 < x :=
2832
by norm_num at *; try_for 100 {exact h}
2933

0 commit comments

Comments
 (0)