Zulip Chat Archive

Stream: new members

Topic: Reasoning with inductive relations


Thorsten Altenkirch (Nov 13 2020 at 12:44):

I am trying to translate an agda proof (about permutations) to Lean but I find this rather difficult even though I know how to do it in principle. Hence I wonder wether there is any tactic support I miss or any general advice?

Here is my agda code:

open import Data.List
open import Data.Product

variable A : Set
variable a b : A
variable as bs cs : List A

data Add : A  List A  List A  Set where
  zero : Add a as (a  as)
  suc : Add a as bs  Add a (b  as) (b  bs)

addLem : Add a as bs  Add b bs cs
        Σ (List A) (λ ds  Add b as ds × Add a ds cs)
addLem zero zero = _ , zero , suc zero
addLem zero (suc q) = _ , q , zero
addLem (suc p) zero = _ , zero , suc (suc p)
addLem (suc p) (suc q) with addLem p q
...                      |  bs' , p' , q' = _ , suc p' , suc q'

and here are the corresponding Lean definitions:

variable {A : Type}

open list

inductive Add : A  list A  list A  Prop
| add_zero :  a:A,  as : list A,Add a as (a :: as)
| add_succ :  a b:A,  as as': list A, Add a as as'  Add a (b :: as) (b :: as')

open Add

variables as bs cs as' cs' : list A
variables a b : A

lemma add_lem : Add a as bs  Add b bs cs   ds : list A, Add b as ds  Add a ds cs :=
begin
  sorry
end

So I try to translate the proof using pattern matching and structural recursion into just using the induction tactic. This is a bit a dejavue from my PhD ... I remember this was one of the reasons I never seriously used Coq, but Lean doesn't seem any better if not worse because in coq there is Matthieu Sozeau's equations package which I think would enable me to do the agda proof in coq (haven't tried it).

Anne Baanen (Nov 13 2020 at 13:10):

The induction tactic has some limitations, most notably that it tends to forget what you applied it to. @Jannis Limperg, am I right that your improved induction' will work here?

Jannis Limperg (Nov 13 2020 at 13:32):

Yes. induction' is partly a reimplementation of Conor's Depelim, which helps a lot with indexed families. It's very similar to Coq's dependent induction and the Equations package is built on the same tech afaik. Let me try what induction' says in this example...

Jannis Limperg (Nov 13 2020 at 15:14):

Slightly embarrassingly, I'm failing to do the induction' proof right now. The problem is with the double induction, which induction tactics don't do well. I'll try again later. For the moment, here's the Agda-style proof transcribed to Lean, using the equation compiler:

variable {A : Type}

open list

inductive Add : A  list A  list A  Prop
| add_zero :  a:A,  as : list A, Add a as (a :: as)
| add_succ :  a b:A,  as as': list A, Add a as as'  Add a (b :: as) (b :: as')

open Add

lemma add_lem₁ :  {a b as bs cs},
  Add a as bs  Add b bs cs   ds : list A, Add b as ds  Add a ds cs
| _ _ _ _ _ (add_zero a as) (add_zero b bs) :=
  b :: as, add_zero _ _, add_succ _ _ _ _ (add_zero _ _)⟩
| _ _ _ _ _ (add_zero a as) (add_succ a' b as' as'' p) :=
  as'', p, add_zero _ _
| _ _ _ _ _ (add_succ a b as as' p) (add_zero b' bs) :=
  b' :: b :: as, add_zero _ _, add_succ _ _ _ _ (add_succ _ _ _ _ p)⟩
| _ _ _ _ _ (add_succ a b as as' p) (add_succ a₀ b₀ as₀ as'₀ q) :=
  let ds', p', q' := add_lem₁ p q in
  b₀ :: ds', add_succ _ _ _ _ p', add_succ _ _ _ _ q'

Mario Carneiro (Nov 13 2020 at 15:27):

Here's a version using the induction tactic:

import tactic

variable {A : Type}

open list

inductive Add : A  list A  list A  Prop
| zero {a:A} {as : list A} : Add a as (a :: as)
| succ {a b:A} {as as': list A} : Add a as as'  Add a (b :: as) (b :: as')

variables as bs cs as' cs' : list A
variables a b : A

lemma add_lem : Add a as bs  Add b bs cs   ds : list A, Add b as ds  Add a ds cs :=
begin
  intros h1 h2,
  generalize_hyp e : bs = bs' at h2,
  induction h1 with _ _ _ _ _ _ p generalizing cs bs';
    induction h2 with _ _ _ _ _ _ q; cases e,
  { exact _, Add.zero, Add.zero.succ },
  { exact _, q, Add.zero },
  { exact _, Add.zero, p.succ.succ },
  { obtain bs', p', q' := h1_ih _ _ rfl q,
    exact _, p'.succ, q'.succ },
end

Thorsten Altenkirch (Nov 14 2020 at 20:38):

Thanks for the helpful comments. Yes, I was wondering wether the easiest way would be to just use the equations compiler. However, I avoided talking about proof terms in my undergraduate course (maybe this is a mistake), hence a tactic based proof like the one by @Mario Carneiro fits the bill perfectly. I need to study it in more detail and hopefully I will be able to translate the rest of my proof.

Thorsten Altenkirch (Sep 22 2022 at 15:36):

Jannis Limperg said:

Slightly embarrassingly, I'm failing to do the induction' proof right now. The problem is with the double induction, which induction tactics don't do well. I'll try again later. For the moment, here's the Agda-style proof transcribed to Lean, using the equation compiler:

variable {A : Type}

open list

inductive Add : A  list A  list A  Prop
| add_zero :  a:A,  as : list A, Add a as (a :: as)
| add_succ :  a b:A,  as as': list A, Add a as as'  Add a (b :: as) (b :: as')

open Add

lemma add_lem₁ :  {a b as bs cs},
  Add a as bs  Add b bs cs   ds : list A, Add b as ds  Add a ds cs
| _ _ _ _ _ (add_zero a as) (add_zero b bs) :=
  b :: as, add_zero _ _, add_succ _ _ _ _ (add_zero _ _)⟩
| _ _ _ _ _ (add_zero a as) (add_succ a' b as' as'' p) :=
  as'', p, add_zero _ _
| _ _ _ _ _ (add_succ a b as as' p) (add_zero b' bs) :=
  b' :: b :: as, add_zero _ _, add_succ _ _ _ _ (add_succ _ _ _ _ p)⟩
| _ _ _ _ _ (add_succ a b as as' p) (add_succ a₀ b₀ as₀ as'₀ q) :=
  let ds', p', q' := add_lem₁ p q in
  b₀ :: ds', add_succ _ _ _ _ p', add_succ _ _ _ _ q'

Hi Jannis,

I am having problems loading this proof into lean. It says that the equation compiler failed. Is this a version issue or is there something wrong with my lean installation?

Cheers,
Thorsten

Kevin Buzzard (Sep 23 2022 at 11:58):

That file compiles fine for me with Lean (version 3.48.0, commit 283f6ed8083a, Release)


Last updated: Dec 20 2023 at 11:08 UTC