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

Commit 059f937

Browse files
robertylewisjohoelzl
authored andcommitted
feat(tactic): add linear arithmetic tactic (#301)
* feat(data/list, tactic): small helper functions * feat(meta/rb_map): extra operations on native rb_maps * feat(tactic/linarith): add tactic for solving linear arithmetic goals * doc(tactic/linarith): add documentation and tests * chore(tactic/linarith): add copyright * feat(tactic/linarith): allow products of coefficients * feat(tactic/linarith): cut off search early if contradiction is found * feat(tests/linarith_tests): add test * doc(doc/tactics): update doc * feat(tactic/linarith): add config options * feat(tactic/linarith): support equality goals * chore(tactic/linarith): move non-tactic code out of tactic monad * feat(tactic/linarith): support rational coefficients * doc(tactic/linarith): update doc * feat(tactic/linarith): fix obvious inefficiency in canceling denoms * feat(tactic/linarith): efficiency improvements * fix(tactic/linarith): remove unnecessary import and dead code * fix(data/list/basic, meta/rb_map): shorter proofs
1 parent 8c19da7 commit 059f937

File tree

6 files changed

+787
-3
lines changed

6 files changed

+787
-3
lines changed

data/list/basic.lean

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,8 @@ index_of_cons_eq _ rfl
686686
@[simp] theorem index_of_cons_ne {a b : α} (l : list α) : a ≠ b → index_of a (b::l) = succ (index_of a l) :=
687687
assume n, if_neg n
688688

689-
theorem index_of_eq_length {a : α} {l : list α} : index_of a l = length l ↔ a ∉ l :=
689+
theorem index_of_eq_length {a : α} {l : list α} : index_of a l = length l ↔ a ∉ l
690+
:=
690691
begin
691692
induction l with b l ih; simp [-add_comm],
692693
by_cases h : a = b; simp [h, -add_comm],
@@ -3831,6 +3832,9 @@ theorem reverse_range' : ∀ s n : ℕ,
38313832
map prod.fst (enum l) = range l.length :=
38323833
by simp [enum, range_eq_range']
38333834

3835+
def reduce_option {α} : list (option α) → list α :=
3836+
list.filter_map id
3837+
38343838
def map_head {α} (f : α → α) : list α → list α
38353839
| [] := []
38363840
| (x :: xs) := f x :: xs

docs/tactics.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,4 +312,29 @@ end
312312
The default list of tactics can be found by looking up the definition of
313313
[`default_tidy_tactics`](https://github.com/leanprover/mathlib/blob/master/tactic/tidy.lean).
314314

315-
This list can be overriden using `tidy { tactics := ... }`. (The list must be a list of `tactic string`.)
315+
This list can be overriden using `tidy { tactics := ... }`. (The list must be a list of `tactic string`.)
316+
317+
## linarith
318+
319+
`linarith` attempts to find a contradiction between hypotheses that are linear (in)equalities.
320+
Equivalently, it can prove a linear inequality by assuming its negation and proving `false`.
321+
This tactic is currently work in progress, and has various limitations. In particular,
322+
it will not work on `nat`. The tactic can be made much more efficient.
323+
324+
An example:
325+
```
326+
example (x y z : ℚ) (h1 : 2*x < 3*y) (h2 : -4*x + 2*z < 0)
327+
(h3 : 12*y - 4* z < 0) : false :=
328+
by linarith
329+
```
330+
331+
`linarith` will use all appropriate hypotheses and the negation of the goal, if applicable.
332+
`linarith h1 h2 h3` will ohly use the local hypotheses `h1`, `h2`, `h3`.
333+
`linarith using [t1, t2, t3] will add `t1`, `t2`, `t3` to the local context and then run
334+
`linarith`.
335+
`linarith {discharger := tac, restrict_type := tp}` takes a config object with two optional
336+
arguments. `discharger` specifies a tactic to be used for reducing an algebraic equation in the
337+
proof stage. The default is `ring`. Other options currently include `ring SOP` or `simp` for basic
338+
problems. `restrict_type` will only use hypotheses that are inequalities over `tp`. This is useful
339+
if you have e.g. both integer and rational valued inequalities in the local context, which can
340+
sometimes confuse the tactic.

meta/rb_map.lean

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/-
2+
Copyright (c) 2018 Robert Y. Lewis. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Robert Y. Lewis
5+
6+
Additional operations on native rb_maps and rb_sets.
7+
-/
8+
import data.option
9+
10+
namespace native
11+
namespace rb_set
12+
13+
meta def filter {key} (s : rb_set key) (P : key → bool) : rb_set key :=
14+
s.fold s (λ a m, if P a then m else m.erase a)
15+
16+
meta def union {key} (s t : rb_set key) : rb_set key :=
17+
s.fold t (λ a t, t.insert a)
18+
19+
end rb_set
20+
21+
namespace rb_map
22+
23+
meta def ifind {α β} [inhabited β] (m : rb_map α β) (a : α) : β :=
24+
(m.find a).iget
25+
26+
meta def zfind {α β} [has_zero β] (m : rb_map α β) (a : α) : β :=
27+
(m.find a).get_or_else 0
28+
29+
meta def add {α β} [has_add β] [has_zero β] [decidable_eq β] (m1 m2 : rb_map α β) : rb_map α β :=
30+
m1.fold m2
31+
(λ n v m,
32+
let nv := v + m2.zfind n in
33+
if nv = 0 then m.erase n else m.insert n nv)
34+
35+
meta def scale {α β} [has_lt α] [decidable_rel ((<) : α → α → Prop)] [has_mul β] (b : β) (m : rb_map α β) : rb_map α β :=
36+
m.map ((*) b)
37+
38+
end rb_map
39+
end native

tactic/basic.lean

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,12 @@ do l ← local_context,
509509

510510
run_cmd add_interactive [`injections_and_clear]
511511

512+
meta def note_anon (e : expr) : tactic unit :=
513+
do n ← get_unused_name "lh",
514+
note n none e, skip
515+
512516
meta def find_local (t : pexpr) : tactic expr :=
513517
do t' ← to_expr t,
514518
prod.snd <$> solve_aux t' assumption
515-
end tactic
519+
520+
end tactic

0 commit comments

Comments
 (0)