Zulip Chat Archive

Stream: general

Topic: Unification of equations by simp


Jannis Limperg (Dec 13 2020 at 17:12):

One of the reviews of the induction' paper pointed out that simp apparently does some first-order unification when simplifying equations, even without any simp lemmas:

example (P : Prop) (n m) (h : nat.succ n = nat.succ m  P) : n = m  P :=
begin
  simp only [] at h,
  guard_hyp h : n = m  P,
  exact h
end

Does anyone know what exactly is going on here? Does simp just use Lean's unification procedure whenever it encounters an equation?

Reid Barton (Dec 13 2020 at 17:13):

I don't know how it works, but simp does seem to have some built-in knowledge of disjointness and injectivity of constructors

Rob Lewis (Dec 13 2020 at 17:22):

A little experimenting shows it's the constructor_eq option to simp that allows this.

Jannis Limperg (Dec 13 2020 at 19:14):

Thanks! That led me to the right place in the C++: library/tactic/simplify.cpp, simplify_core_fn::simplify_constructor_eq_constructor.

With constructor_eq, the simplifier indeed uses a partial implementation of the usual unification algorithm. (This is the third such implementation in Core that I'm aware of. :P) It recognises equations whose LHS and RHS are constructor applications and uses injectivity or no-confusion as appropriate. However, it doesn't do any normalisation, doesn't use the cycle rule (cases also doesn't) and doesn't work with tuples for some reason.

universes u v

structure myprod (α : Type u) (β : Type v) : Type (max u v) :=
(a : α) (y : β)

-- Nested constructor applications work.
example (n n' m m' k k' : )
  (h : myprod.mk (myprod.mk n m) k = myprod.mk (myprod.mk n' m') k') :
  (n = n'  m = m')  k = k' :=
begin
  simp only [] at h,
  exact h
end

-- Also with different data types.
example (n : ) (h : myprod.mk nat.zero nat.zero = myprod.mk (nat.succ 1) (nat.succ 1)) : false :=
begin
  simp only [] at h,
  guard_hyp h : false  false,
  exact and.elim_left h
end

-- Tuples (`prod`) doesn't work for some reason.
example (n n' m m' : ) (h : (n, m) = (n', m')) : n = n'  m = m' :=
begin
  success_if_fail { simp only [] at h },
  sorry
end

-- Constructors are matched syntactically; no normalisation is performed.
example (n : ) (h : 0 = n + 1) : false :=
begin
  success_if_fail { simp only [] at h },
  sorry
end

-- The cycle rule is not implemented.
example (n : ) (h : n = nat.succ n) : false :=
begin
  success_if_fail { simp only [] at h {} },
  sorry
end

Last updated: Dec 20 2023 at 11:08 UTC