import Lean open Lean Meta Elab Tactic elab "sym_simp" "[" declNames:ident,* "]" : tactic => do let rewrite ← Sym.mkSimprocFor (← declNames.getElems.mapM fun s => realizeGlobalConstNoOverload s.raw) Sym.Simp.dischargeSimpSelf let methods : Sym.Simp.Methods := { pre := Sym.Simp.simpControl post := Sym.Simp.evalGround.andThen rewrite } liftMetaTactic1 fun mvarId => Sym.SymM.run do let mvarId ← Sym.preprocessMVar mvarId (← Sym.simpGoal mvarId methods).toOption example : (1-1) + x*1 + (2-1)*0 = x := by sym_simp [Nat.add_zero, Nat.zero_add, Nat.mul_one] opaque f : Nat → Nat axiom fax : x > 10 → f x = 0 example : f 12 = 0 := by sym_simp [fax] example : (if true then a else b) = a := by sym_simp [] example : (if True then a else b) = a := by sym_simp [] example : (if False then a else b) = b := by sym_simp [] example (f g : Nat → Nat) : (if a + 0 = a then f else g) a = f a := by sym_simp [Nat.add_zero] example (f g : Nat → Nat → Nat) : (if a + 0 ≠ a then f else g) a (b + 0) = g a b := by sym_simp [Nat.add_zero] /-- trace: a b : Nat f g : Nat → Nat → Nat h : a = b ⊢ (if ¬a = b then id f else id (id g)) a (b + 0) = g a b -/ #guard_msgs in example (f g : Nat → Nat → Nat) (h : a = b) : (if a + 0 ≠ b then id f else id (id g)) a (b + 0) = g a b := by sym_simp [Nat.add_zero, id_eq] trace_state -- `if-then-else` branches should not have been simplified subst h sym_simp [Nat.add_zero, id_eq] def isNil (xs : List α) : Bool := match xs with | [] => true | _::_ => false example : isNil ([] : List Nat) = true := by sym_simp [isNil.eq_def] inductive Kind where | a | b | c def pick : Kind → Nat → Nat | .a => Nat.succ | .b => (2 * ·) | .c => id example : pick .a 2 = 3 := by sym_simp [pick.eq_def] example : pick .b 2 = 4 := by sym_simp [pick.eq_def] example : pick .c 2 = 2 := by sym_simp [pick.eq_def, id_eq] example : (match 1 - 1 with | 0 => 1 | _ => 2) = 1 := by sym_simp [] /-- trace: c : Bool h : c = false ⊢ (match 0, c with | 0, true => 1 + 0 | 0, false => 2 + 1 | x, x_1 => 3 + 1) = 3 -/ #guard_msgs in example (h : c = false) : (match 1 - 1, c with | 0, true => 1+0 | 0, false => 2+1 | _, _ => 3+1) = 3 := by sym_simp [] -- Only discriminant should have been simplified, simplifier must not visit branches trace_state subst c sym_simp [] /-- trace: a : Nat h : a = 0 ⊢ (match a, false with | 0, true => 1 + 0 | 0, false => 2 + 1 | x, x_1 => 3 + 1) = 3 -/ #guard_msgs in example (h : a = 0) : (match a, !true with | 0, true => 1+0 | 0, false => 2+1 | _, _ => 3+1) = 3 := by sym_simp [Bool.not_true] -- Only discriminant should have been simplified, simplifier must not visit branches trace_state subst a sym_simp [] inductive Foo where | mk1 (a : Nat) | mk2 (b : Bool) | mk3 (c : Int) example : (match Foo.mk3 c, Foo.mk2 b with | .mk1 _, _ => 1+0 | _, .mk2 _ => 2+1 | _, _ => id 4) = 3 := by sym_simp [id_eq] example : (match (true, false, true) with | (false, _, _) => 1 | (_, false, _) => 2 | _ => 3) = 2 := by sym_simp [] example : (if _ : true then a else b) = a := by sym_simp [] example : (if _ : True then a else b) = a := by sym_simp [] example : (if _ : False then a else b) = b := by sym_simp [] example (f g : Nat → Nat) : (if _ : a + 0 = a then f else g) a = f a := by sym_simp [Nat.add_zero] example (f g : Nat → Nat → Nat) : (if _ : a + 0 ≠ a then f else g) a (b + 0) = g a b := by sym_simp [Nat.add_zero] /-- trace: a b : Nat f g : Nat → Nat → Nat h : a = b ⊢ (if h : ¬a = b then id f else id (id g)) a (b + 0) = g a b -/ #guard_msgs in example (f g : Nat → Nat → Nat) (h : a = b) : (if _ : a + 0 ≠ b then id f else id (id g)) a (b + 0) = g a b := by sym_simp [Nat.add_zero, id_eq] trace_state -- `if-then-else` branches should not have been simplified subst h sym_simp [Nat.add_zero, id_eq] example : (bif true then a else b) = a := by sym_simp [] example : (bif false then a else b) = b := by sym_simp [] example (f g : Nat → Nat) : (bif a + 0 == a then f else g) a = f a := by sym_simp [Nat.add_zero, beq_self_eq_true] example (f g : Nat → Nat → Nat) : (bif a + 0 != a then f else g) a (b + 0) = g a b := by sym_simp [Nat.add_zero, bne_self_eq_false] /-- trace: a b : Nat f g : Nat → Nat → Nat h : a = b ⊢ (bif a != b then id f else id (id g)) a (b + 0) = g a b -/ #guard_msgs in example (f g : Nat → Nat → Nat) (h : a = b) : (bif a + 0 != b then id f else id (id g)) a (b + 0) = g a b := by sym_simp [Nat.add_zero, id_eq] trace_state -- `cond` branches should not have been simplified subst h sym_simp [Nat.add_zero, bne_self_eq_false, id_eq] def pw (n : Nat) : Nat := match n with | 0 => 1 | n+1 => 2 * pw n example : pw 0 = 1 := by sym_simp [pw.eq_1] example : pw 2 = 4 := by sym_simp [pw.eq_1, pw.eq_2] example : pw 4 = 16 := by sym_simp [pw.eq_1, pw.eq_2] example : pw (a + 2) = 2 * (2 * pw a) := by sym_simp [pw.eq_2] example : pw (Nat.succ a) = 2 * pw a := by sym_simp [pw.eq_2] example : pw (a + 3) = 2 * (2 * (2 * pw a)) := by sym_simp [pw.eq_2] example : pw (Nat.succ (Nat.succ a)) = 2 * (2 * pw a) := by sym_simp [pw.eq_2]