FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat(tactic/interactive): add apply_rules tactic (#190) · SzJS/mathlib@4c6d7e2 · GitHub

Repository navigation

Commit 4c6d7e2

Browse files
authored andcommitted
feat(tactic/interactive): add apply_rules tactic (leanprover-community#190)
1 parent 6495c20 commit 4c6d7e2

4 files changed

Lines changed: 134 additions & 16 deletions

File tree

‎docs/tactics.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,30 @@ refine_struct ({ .. } : semigroup α),
192192
{ have field := @semigroup.mul, ... },
193193
{ have field := @semigroup.mul_assoc, ... },
194194
```
195+
196+
### apply_rules
197+
198+
`apply_rules hs n` applies the list of lemmas `hs` and `assumption` on the
199+
first goal and the resulting subgoals, iteratively, at most `n` times.
200+
`n` is optional, equal to 50 by default.
201+
`hs` can contain user attributes: in this case all theorems with this
202+
attribute are added to the list of rules.
203+
204+
For instance:
205+
206+
```
207+
@[user_attribute]
208+
meta def mono_rules : user_attribute :=
209+
{ name := `mono_rules,
210+
descr := "lemmas usable to prove monotonicity" }
211+
212+
attribute [mono_rules] add_le_add mul_le_mul_of_nonneg_right
213+
214+
lemma my_test {a b c d e : real} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
215+
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
216+
-- any of the following lines solve the goal:
217+
add_le_add (add_le_add (add_le_add (add_le_add h1 (mul_le_mul_of_nonneg_right h2 h3)) h1 ) h2) h3
218+
by apply_rules [add_le_add, mul_le_mul_of_nonneg_right]
219+
by apply_rules [mono_rules]
220+
by apply_rules mono_rules
221+
```

‎tactic/basic.lean‎

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ meta def subst_locals (s : list (expr × expr)) (e : expr) : expr :=
116116
(e.abstract_locals (s.map (expr.local_uniq_name ∘ prod.fst)).reverse).instantiate_vars (s.map prod.snd)
117117

118118
meta def set_binder : expr → list binder_info → expr
119-
| e [] := e
120-
| (expr.pi v _ d b) (bi :: bs) := expr.pi v bi d (set_binder b bs)
121-
| e _ := e
119+
| e [] := e
120+
| (expr.pi v _ d b) (bi :: bs) := expr.pi v bi d (set_binder b bs)
121+
| e _ := e
122122

123123
/-- variation on `assert` where a (possibly incomplete)
124124
proof of the assertion is provided as a parameter.
@@ -147,28 +147,28 @@ do h' ← assert h p,
147147
return (h' , gs)
148148

149149
meta def try_intros : list name → tactic (list name)
150-
| [] := do
151-
tgt ← target >>= instantiate_mvars,
152-
if tgt.is_pi then failed
153-
else return []
154-
| (x::xs) := (intro x >> try_intros xs) <|> pure (x :: xs)
150+
| [] := do
151+
tgt ← target >>= instantiate_mvars,
152+
if tgt.is_pi then failed
153+
else return []
154+
| (x::xs) := (intro x >> try_intros xs) <|> pure (x :: xs)
155155

156156
meta def ext1 (xs : list name) : tactic (list name) :=
157157
do ls ← attribute.get_instances `extensionality,
158158
ls.any_of (λ l, applyc l),
159159
try_intros xs
160160

161161
meta def ext : list name → option ℕ → tactic unit
162-
| _ (some 0) := return ()
163-
| xs n := focus1 (do ys ← ext1 xs, ext ys (nat.pred <$> n) <|> return ())
162+
| _ (some 0) := return ()
163+
| xs n := focus1 (do ys ← ext1 xs, ext ys (nat.pred <$> n) <|> return ())
164164

165165
meta def var_names : expr → list name
166-
| (expr.pi n _ _ b) := n :: var_names b
167-
| _ := []
166+
| (expr.pi n _ _ b) := n :: var_names b
167+
| _ := []
168168

169169
meta def drop_binders : expr → tactic expr
170-
| (expr.pi n bi t b) := b.instantiate_var <$> mk_local' n bi t >>= drop_binders
171-
| e := pure e
170+
| (expr.pi n bi t b) := b.instantiate_var <$> mk_local' n bi t >>= drop_binders
171+
| e := pure e
172172

173173
meta def subobject_names (struct_n : name) : tactic (list name × list name) :=
174174
do env ← get_env,
@@ -191,8 +191,47 @@ dlist.to_list <$> expanded_field_list' struct_n
191191
open nat
192192

193193
meta def mk_mvar_list : ℕ → tactic (list expr)
194-
| 0 := pure []
195-
| (succ n) := (::) <$> mk_mvar <*> mk_mvar_list n
194+
| 0 := pure []
195+
| (succ n) := (::) <$> mk_mvar <*> mk_mvar_list n
196+
197+
/--`iterate_at_most_on_all_goals n t`: repeat the given tactic at most `n` times on all goals,
198+
or until it fails. Always succeeds. -/
199+
meta def iterate_at_most_on_all_goals : nat → tactic unit → tactic unit
200+
| 0 tac := trace "maximal iterations reached"
201+
| (succ n) tac := tactic.all_goals $ (do tac, iterate_at_most_on_all_goals n tac) <|> skip
202+
203+
/--`iterate_at_most_on_subgoals n t`: repeat the tactic `t` at most `n` times on the first
204+
goal and on all subgoals thus produced, or until it fails. Fails iff `t` fails on
205+
current goal. -/
206+
meta def iterate_at_most_on_subgoals : nat → tactic unit → tactic unit
207+
| 0 tac := trace "maximal iterations reached"
208+
| (succ n) tac := focus1 (do tac, iterate_at_most_on_all_goals n tac)
209+
210+
/--`apply_list l`: try to apply the tactics in the list `l` on the first goal, and
211+
fail if none succeeds -/
212+
meta def apply_list_expr : list expr → tactic unit
213+
| [] := fail "no matching rule"
214+
| (h::t) := do interactive.concat_tags (apply h) <|> apply_list_expr t
215+
216+
/-- constructs a list of expressions given a list of p-expressions, as follows:
217+
- if the p-expression is the name of a theorem, use `i_to_expr_for_apply` on it
218+
- if the p-expression is a user attribute, add all the theorems with this attribute
219+
to the list.-/
220+
meta def build_list_expr_for_apply : list pexpr → tactic (list expr)
221+
| [] := return []
222+
| (h::t) := do
223+
tail ← build_list_expr_for_apply t,
224+
a ← i_to_expr_for_apply h,
225+
(do l ← attribute.get_instances (expr.const_name a),
226+
m ← list.mmap mk_const l,
227+
return (m.append tail))
228+
<|> return (a::tail)
229+
230+
/--`apply_rules hs n`: apply the list of rules `hs` (given as pexpr) and `assumption` on the
231+
first goal and the resulting subgoals, iteratively, at most `n` times -/
232+
meta def apply_rules (hs : list pexpr) (n : nat) : tactic unit :=
233+
do l ← build_list_expr_for_apply hs,
234+
iterate_at_most_on_subgoals n (assumption <|> apply_list_expr l)
196235

197236
meta def replace (h : name) (p : pexpr) : tactic unit :=
198237
do h' ← get_local h,

‎tactic/interactive.lean‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,5 +431,31 @@ meta def apply_field : tactic unit :=
431431
propagate_tags $
432432
get_current_field >>= applyc
433433

434+
/--`apply_rules hs n`: apply the list of rules `hs` (given as pexpr) and `assumption` on the
435+
first goal and the resulting subgoals, iteratively, at most `n` times.
436+
`n` is 50 by default. `hs` can contain user attributes: in this case all theorems with this
437+
attribute are added to the list of rules.
438+
439+
example, with or without user attribute:
440+
```
441+
@[user_attribute]
442+
meta def mono_rules : user_attribute :=
443+
{ name := `mono_rules,
444+
descr := "lemmas usable to prove monotonicity" }
445+
446+
attribute [mono_rules] add_le_add mul_le_mul_of_nonneg_right
447+
448+
lemma my_test {a b c d e : real} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
449+
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
450+
by apply_rules mono_rules
451+
-- any of the following lines would also work:
452+
-- add_le_add (add_le_add (add_le_add (add_le_add h1 (mul_le_mul_of_nonneg_right h2 h3)) h1 ) h2) h3
453+
-- by apply_rules [add_le_add, mul_le_mul_of_nonneg_right]
454+
-- by apply_rules [mono_rules]
455+
```
456+
-/
457+
meta def apply_rules (hs : parse pexpr_list_or_texpr) (n : nat := 50) : tactic unit :=
458+
tactic.apply_rules hs n
459+
434460
end interactive
435461
end tactic

‎tests/tactics.lean‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,3 +454,29 @@ begin
454454
end
455455

456456
end ext
457+
458+
section apply_rules
459+
460+
example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
461+
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
462+
add_le_add (add_le_add (add_le_add (add_le_add h1 (mul_le_mul_of_nonneg_right h2 h3)) h1 ) h2) h3
463+
464+
example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
465+
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
466+
by apply_rules [add_le_add, mul_le_mul_of_nonneg_right]
467+
468+
@[user_attribute]
469+
meta def mono_rules : user_attribute :=
470+
{ name := `mono_rules,
471+
descr := "lemmas usable to prove monotonicity" }
472+
attribute [mono_rules] add_le_add mul_le_mul_of_nonneg_right
473+
474+
example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
475+
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
476+
by apply_rules [mono_rules]
477+
478+
example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
479+
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
480+
by apply_rules mono_rules
481+
482+
end apply_rules

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL