Zulip Chat Archive

Stream: mathlib4

Topic: Help with complitacted induction proof


Thomas Vigouroux (Dec 03 2023 at 09:45):

Hey there ! Lately I have been asking a lot of questions related to some proofs I have been attempting to formalize in Lean4 about G4ip (a contraction-free sequent calculus for intuitionistic propositional logic).

Currently I am stuck because of a dependent elimination error, I am am somewhat puzzled by the problem.

Here is the code:

import Mathlib.Tactic
import Mathlib.Data.Finset.Basic

abbrev Variable := 

inductive Formula
| bot
| var : Variable  Formula
| and : Formula  Formula  Formula
| or : Formula  Formula  Formula
| imp : Formula  Formula  Formula
deriving DecidableEq

instance : HAnd Formula Formula Formula where
  hAnd := Formula.and

instance : HOr Formula Formula Formula where
  hOr := Formula.or

abbrev Formula.not (G: Formula) := Formula.imp G .bot
abbrev Formula.top := not bot
abbrev Formula.equiv (A B: Formula) := (imp A B) &&& (imp B A)

notation:max (priority := high) "#" v:max => Formula.var v
infixr:27 (priority := high) " ⟹ " => Formula.imp

instance: Neg Formula where
  neg := Formula.not

instance: Bot Formula where
  bot := Formula.bot

instance: Top Formula where
  top := Formula.top

-- Model theory

variable {H : Type _} [HeytingAlgebra H]
@[simp]
def eval (v : Variable  H) : Formula  H
  | .bot    => 
  | # P    => v P
  | A ||| B => eval v A  eval v B
  | A &&& B => eval v A  eval v B
  | A  B => eval v A  eval v B


/- We say that `A` is a consequence of `Γ` if for all valuations in any Heyting algebra, if
  `eval v B` is above a certain element for all `B ∈ Γ` then `eval v A` is above this element.
  Note that for finite sets `Γ` this corresponds exactly to
  `Infimum { eval v B | B ∈ Γ } ≤ eval v A`.
  This "yoneda'd" version of the definition of validity is very convenient to work with. -/
def Models (Γ : Finset Formula) (A : Formula) : Prop :=
   {H : Type} [HeytingAlgebra H] {v : Variable  H} {c}, ( B  Γ, c  eval v B)  c  eval v A

local infix:27 (priority := high) " ⊨ " => Models
def Valid (A : Formula) : Prop :=   A

set_option hygiene false
infix:27 (priority:=high) " ⊢ " => Sequent

inductive Sequent : Finset Formula  Formula  Prop
| Ax : A  Γ   Γ  A
| ExFalso :   Γ  Γ  G
| AndI : Γ  A  Γ  B  Γ  A &&& B
| AndE : insert A (insert B Γ)  C  insert (A &&& B) Γ  C
| OrI1 : Γ  A  Γ  (A ||| B)
| OrI2 : Γ  B  Γ  (A ||| B)
| OrE : insert A Γ  C  insert B Γ  C  insert (A ||| B) Γ  C
| ImpI : insert A Γ  B  Γ  (A  B)
-- Now the ImpE rules, that are exploded by cases
-- Γ, a, B ⊢ C → Γ, a, a ⇒ B ⊢ C
| ImpEAtom : insert A (insert B Γ)  C  insert A (insert (A  B) Γ)  C
| ImpEBot : Γ  C  insert (  B) Γ  C
| ImpEAnd : insert (A₁  A₂  B) Γ  C  insert ((A₁ &&& A₂)  B) Γ  C
| ImpEOr : insert (A₁  B) (insert (A₂  B) Γ)  C  insert ((A₁ ||| A₂)  B) Γ  C
| ImpEImp : insert A₁ (insert (A₂  B) Γ)  A₂  insert B Γ  C  insert ((A₁  A₂)  B) Γ  C
-- ImpETop is not necessary see the lemma later

syntax "solve_mem": tactic
syntax "apply_ax": tactic
macro_rules
| `(tactic | solve_mem) => `(tactic |
  first
  | exact Finset.mem_singleton.mpr rfl
  | apply Finset.mem_insert_self
  | apply Finset.mem_insert_of_mem; solve_mem)
| `(tactic | apply_ax) => `(tactic | {apply Sequent.Ax; solve_mem})

lemma Sequent.ImpETop (h: insert B Γ  C) : insert (  B) Γ  C := by {
  apply Sequent.ImpEImp
  · apply_ax
  · exact h
}

lemma Sequent.AndE.invertible {Γ: Finset Formula} {A B C: Formula} (h: insert (A &&& B) Γ  C): insert A (insert B Γ)  C := by {
  cases h with
  | Ax h => {
    simp at h
    cases h with
    | inl h => {
      rw [h]
      apply AndI <;> apply_ax
    }
    | inr h => {
      apply Ax
      simp
      right
      right
      exact h
    }
  }
  | ExFalso h => {
    simp at h
    apply ExFalso
    simp
    right
    right
    exact h
  }
  | @AndI Γ A' B' hA hB => {
    apply AndI
    · exact Sequent.AndE.invertible hA
    · exact Sequent.AndE.invertible hB
  }
  | @OrI1 Γ A' B' hA => {
    apply OrI1
    exact Sequent.AndE.invertible hA
  }
  | @OrI2 Γ A' B' hB => {
    apply OrI2
    exact Sequent.AndE.invertible hB
  }
  -- dependent elimination failed
  | @AndE A' B' Γ' C hAB => sorry
  -- | AndE _ => sorry
  -- | OrE _ _ => sorry
  -- | ImpI _ => sorry
  -- | ImpEAtom _ => sorry
  -- | ImpEBot _ => sorry
  -- | ImpEAnd _ => sorry
  -- | ImpEOr _ => sorry
  -- | ImpEImp _ _ => sorry
}

Thomas Vigouroux (Dec 03 2023 at 09:46):

I realize that the example is a bit big, but it is mostly a modified version of GlimpseOfLean applied to the sequent calculus mentionned

Thomas Vigouroux (Dec 03 2023 at 09:49):

Another thing that surprised me is that changing the cases to a induction in the very last theorem causes an error stating the following:

index in target's type is not a variable (consider using the `cases` tactic instead)
  insert (A &&& B) Γ

Mario Carneiro (Dec 03 2023 at 09:55):

use generalize e : A &&& B = AB at h before induction

Thomas Vigouroux (Dec 03 2023 at 09:58):

Oh, I did not know about that generalize tactic, that's good for future use
Though doing that does not seem to fix the problem on my end

Thomas Vigouroux (Dec 03 2023 at 09:58):

Maybe I need to generalize e : insert (A &&& B) \Gamma = \Gamma' at h rather ?

Mario Carneiro (Dec 03 2023 at 10:03):

oh, yes you should

Thomas Vigouroux (Dec 03 2023 at 10:05):

So that seemed to fix the issue then, may I ask why it happened ?

Mario Carneiro (Dec 03 2023 at 10:19):

induction would otherwise lose information about the index at which you are applying the inductive type, you would be left with subgoals like Γ' ⊢ C -> insert A (insert B Γ) ⊢ C which are obviously not provable

Mario Carneiro (Dec 03 2023 at 10:21):

Proofs like this usually have to be careful / explicit about exactly how the index is generalized, because doing it wrong results in the wrong inductive hypothesis. The one I just showed means that you can only recurse on cases which don't change the context, meaning that OrI1 is okay but you may have difficulty with ImpEOr

Mario Carneiro (Dec 03 2023 at 10:22):

You may need to think a bit more carefully about what the induction hypothesis is here

Thomas Vigouroux (Dec 03 2023 at 10:24):

Hmm okay, I'll look into that carefully then

Mario Carneiro (Dec 03 2023 at 10:32):

Thinking about it some more, I think the theorem is provable with the generalize as I suggested, but you also need to use induction h generalizing Γ

Thomas Vigouroux (Dec 03 2023 at 10:33):

Hmm, probably, I'll try that then (I can't rn)

Thomas Vigouroux (Dec 04 2023 at 06:57):

So using the generalize as you suggested does not fix the problem about the index in the induction, which seems weird to me.

I am trying right now to do it using generalize e : insert (A &&& B) \Gamma = \Gamma' at h but while it helped in the beginning, it does not help much anymore

Thomas Vigouroux (Dec 04 2023 at 06:58):

Here is the (partial) proof at the moment (note that the case ImpI is done now):

lemma Sequent.AndE.invertible {Γ: Finset Formula} {A B C: Formula} (h: insert (A &&& B) Γ  C): insert A (insert B Γ)  C := by {
  generalize e : insert (A &&& B) Γ = Γ₀ at h
  induction h generalizing Γ with
  | @Ax A' Γ' h => {
    rw [ e] at h
    simp at h
    cases h with
    | inl h => {
      rw [h]
      apply AndI <;> apply_ax
    }
    | inr h => {
      apply Ax
      solve_mem
    }
  }
  | ExFalso h => {
    rw [ e] at h
    simp at h
    apply ExFalso
    solve_mem
  }
  | @AndI Γ A' B' hA hB IHA IHB => {
    apply AndI
    · exact IHA e
    · exact IHB e
  }
  | @ImpI A' Γ' B' hA IHA => {
    apply ImpI
    repeat rw [Finset.Insert.comm A']
    rw [ e] at hA
    rw [Finset.Insert.comm] at hA
    apply IHA
    rw [Finset.Insert.comm]
    congr
  }
  | OrI1 hA IHA => {
    apply OrI1
    exact IHA e
  }
  | OrI2 hB IHB => {
    apply OrI2
    exact IHB e
  }
  | @AndE A' B' Γ' C' hC' IHC' => {
    /-
    case AndE
    H : Type ?u.59957
    inst✝ : HeytingAlgebra H
    A B C : Formula
    Γ₀ : Finset Formula
    A' B' : Formula
    Γ' : Finset Formula
    C' : Formula
    hC' : Sequent (insert A' (insert B' Γ')) C'
    IHC' : ∀ {Γ : Finset Formula}, insert (A &&& B) Γ = insert A' (insert B' Γ') → Sequent (insert A (insert B Γ)) C'
    Γ : Finset Formula
    e : insert (A &&& B) Γ = insert (A' &&& B') Γ'
    ⊢ Sequent (insert A (insert B Γ)) C'
    -/
  }
  | @OrE A' Γ' C' B' hA' hB' IHA' IHB' => {
    sorry
  }
  | @ImpEAtom A' B' Γ' C hC IHC => sorry
  | ImpEBot _ => sorry
  | ImpEAnd _ => sorry
  | ImpEOr _ => sorry
  | ImpEImp _ _ => sorry
}

Thomas Vigouroux (Dec 04 2023 at 07:07):

I can't really find a way to use the insert (A &&& B) \Gamma = insert (A' &&& B') \Gamma' to my advantage though, and that seems to be the main culprit

Thomas Vigouroux (Dec 04 2023 at 14:40):

It seems that my induction principle is a little off, but I quite can't come up with another one.

My intuition would be to make it simpler by inducting on the "height" of a derivaion, but I can't come up with a good way of defining the height for some reason

Thomas Vigouroux (Dec 04 2023 at 14:41):

This gives me an error:

def Sequent.height: Γ  C  
/-
tactic 'cases' failed, nested error:
tactic 'induction' failed, recursor 'Sequent.casesOn' can only eliminate into Prop

Γ: Finset Formula
C: Formula
x✝¹: Sequent Γ C
motive: Sequent Γ C → Sort ?u.60142
h_1: (a : C ∈ Γ) → motive _
a✝¹: Finset Formula
a✝: Formula
x✝: Sequent a✝¹ a✝
⊢ Γ = a✝¹ → C = a✝ → HEq x✝¹ x✝ → motive x✝¹
 after processing
  _
the dependent pattern matcher can solve the following kinds of equations
- <var> = <term> and <term> = <var>
- <term> = <term> where the terms are definitionally equal
- <constructor> = <constructor>, examples: List.cons x xs = List.cons y ys, and List.cons x xs = List.nil
-/
| Ax _ => 0

Thomas Vigouroux (Dec 04 2023 at 18:05):

I think I will give up on trying to prove this, I really simply can't come up with a correct way to formulate my induction hypothesis to make it work

Thomas Vigouroux (Dec 04 2023 at 20:21):

So, reworking the definition of my inductive type, I now include the height of the derivation _in_ the inductive type, such that Sequent G A n represents derivations From G to A with size n

Mario Carneiro (Dec 04 2023 at 20:53):

@Thomas Vigouroux your last proof doesn't work for me, solve_mem fails in two cases

Thomas Vigouroux (Dec 04 2023 at 21:17):

Oh I think I changed the definition of the macro to include assumption as a first clause in the first block

Mario Carneiro (Dec 04 2023 at 21:42):

I've also exceeded my budget to think about this, but my recommendation would be to try to prove

lemma Sequent.mono {Γ Γ': Finset Formula} (h1 : Γ  Γ') (h: Γ  C) : Γ'  C := sorry

lemma Sequent.AndE.invertible {Γ: Finset Formula} {A B C: Formula}
    (h: Γ  C) : insert A (insert B (Γ \ {A &&& B}))  C := sorry

and do cases on whether A &&& B is equal to A' &&& B' in the AndE case

Thomas Vigouroux (Dec 05 2023 at 09:01):

Okay so here is the new proof I am attempting (complete file for completeness):

import Mathlib.Tactic
import Mathlib.Data.Finset.Basic

abbrev Variable := 

inductive Formula
| bot
| var : Variable  Formula
| and : Formula  Formula  Formula
| or : Formula  Formula  Formula
| imp : Formula  Formula  Formula
deriving DecidableEq

instance : HAnd Formula Formula Formula where
  hAnd := Formula.and

instance : HOr Formula Formula Formula where
  hOr := Formula.or

abbrev Formula.not (G: Formula) := Formula.imp G .bot
abbrev Formula.top := not bot
abbrev Formula.equiv (A B: Formula) := (imp A B) &&& (imp B A)

notation:max (priority := high) "#" v:max => Formula.var v
infixr:27 (priority := high) " ⟹ " => Formula.imp

instance: Neg Formula where
  neg := Formula.not

instance: Bot Formula where
  bot := Formula.bot

instance: Top Formula where
  top := Formula.top

-- Model theory

variable {H : Type _} [HeytingAlgebra H]
@[simp]
def eval (v : Variable  H) : Formula  H
  | .bot    => 
  | # P    => v P
  | A ||| B => eval v A  eval v B
  | A &&& B => eval v A  eval v B
  | A  B => eval v A  eval v B


/- We say that `A` is a consequence of `Γ` if for all valuations in any Heyting algebra, if
  `eval v B` is above a certain element for all `B ∈ Γ` then `eval v A` is above this element.
  Note that for finite sets `Γ` this corresponds exactly to
  `Infimum { eval v B | B ∈ Γ } ≤ eval v A`.
  This "yoneda'd" version of the definition of validity is very convenient to work with. -/
def Models (Γ : Finset Formula) (A : Formula) : Prop :=
   {H : Type} [HeytingAlgebra H] {v : Variable  H} {c}, ( B  Γ, c  eval v B)  c  eval v A

local infix:27 (priority := high) " ⊨ " => Models
def Valid (A : Formula) : Prop :=   A

instance hABool: HeytingAlgebra Bool where
  bot_le := by {
    intro a
    cases a <;> simp
  }
  himp_bot := by {
    intro a
    cases a <;> simp [himp]
  }

-- Provability

set_option hygiene false
infix:27 (priority:=high) " ⊢ " => Sequent

inductive Sequent : Finset Formula  Formula  Prop
| Ax : A  Γ  Γ  A
| ExFalso :   Γ  Γ  G
| AndI : Γ  A  Γ  B  Γ  A &&& B
| AndE : insert A (insert B Γ)  C  insert (A &&& B) Γ  C
| OrI1 : Γ  A  Γ  (A ||| B)
| OrI2 : Γ  B  Γ  (A ||| B)
| OrE : insert A Γ  C  insert B Γ  C  insert (A ||| B) Γ  C
| ImpI : insert A Γ  B  Γ  (A  B)
-- Now the ImpE rules, that are exploded by cases
-- Γ, a, B ⊢ C → Γ, a, a ⇒ B ⊢ C
| ImpEAtom : insert A (insert B Γ)  C  insert A (insert (A  B) Γ)  C
| ImpEBot : Γ  C  insert (  B) Γ  C
| ImpEAnd : insert (A₁  A₂  B) Γ  C  insert ((A₁ &&& A₂)  B) Γ  C
| ImpEOr : insert (A₁  B) (insert (A₂  B) Γ)  C  insert ((A₁ ||| A₂)  B) Γ  C
| ImpEImp : insert A₁ (insert (A₂  B) Γ)  A₂  insert B Γ  C  insert ((A₁  A₂)  B) Γ  C
-- ImpETop is not necessary see the lemma later

-- Because this is a recursive macro, this has to be done in two parts
lemma finset_extract [DecidableEq α] {A: α} {S: Finset α} (h: A  S): S', (insert A S' = S)  A  S' := by {
  exists S.erase A
  constructor
  · exact Finset.insert_erase h
  · exact Finset.not_mem_erase A S
}

syntax "solve_mem": tactic
macro_rules
| `(tactic | solve_mem) => `(tactic |
  first
  | trivial
  | exact Finset.mem_singleton.mpr rfl
  | apply Finset.mem_insert_self
  | apply Finset.mem_insert_of_mem; solve_mem)
macro "apply_ax": tactic => `(tactic | {apply Sequent.Ax; solve_mem})

lemma Sequent.ImpETop (h: insert B Γ  C) : insert (  B) Γ  C := by {
  apply Sequent.ImpEImp
  · apply_ax
  · exact h
}

lemma Sequent.mono (h: Γ  Δ) (hΓ: Γ  A): Δ  A := by {
  induction hΓ generalizing Δ with
  | Ax h' => exact Sequent.Ax (h h')
  | ExFalso h' => exact Sequent.ExFalso (h h')
  | AndI hA hB IHA IHB => {
    apply AndI
    · exact IHA h
    · exact IHB h
  }
  | ImpI h' IH => {
    apply ImpI
    apply IH
    exact Finset.insert_subset_insert _ h
  }
  | OrI1 h' IH => {
    apply OrI1
    exact IH h
  }
  | OrI2 h' IH => {
    apply OrI2
    exact IH h
  }
  | @AndE A B Γ C h' IH => {
    if hAB: A &&& B  Γ then {
      obtain Γ', hΓ', hΓ'nm⟩⟩ := finset_extract hAB
      have hΓ : insert (A &&& B) Γ = Γ
      · exact Finset.insert_eq_self.mpr hAB
      rw [hΓ] at h
      rw [ hΓ'] at h

      obtain Δ', hΔ', hΔ'nm⟩⟩ := finset_extract (S:=Δ) (A:=A &&& B) (by {
        apply h
        simp
      })
      rw [ hΔ']
      apply AndE
    } else {
      obtain Δ', hΔ', hΔ'nm⟩⟩ := finset_extract (S:=Δ) (A:=A &&& B) (by {
        apply h
        simp
      })
      rw [ hΔ']
      apply AndE
      apply IH
      apply Finset.insert_subset_insert
      apply Finset.insert_subset_insert
      apply (Finset.insert_subset_insert_iff hAB).mp
      rw [ hΔ'] at h
      exact h
    }
  }
  | OrE _ _ _ _ => sorry
  | ImpEAtom _ _ => sorry
  | ImpEBot _ _ => sorry
  | ImpEAnd _ _ => sorry
  | ImpEOr _ _ => sorry
  | ImpEImp _ _ _ _ => sorry
}

Thomas Vigouroux (Dec 05 2023 at 09:02):

I am already stuck at the AndE case, when A &&& B \in \Gamma, in this case, my intuition is that I can just reduce to a case with a \Gamma' sucha that A &&& B \notin \Gamma', but the induction hypothesis is wrong in this case.

Mario Carneiro (Dec 05 2023 at 09:23):

I don't think you need to do cases on A &&& B \in Gamma to prove monotonicity

Thomas Vigouroux (Dec 05 2023 at 09:32):

I thought too, but I can't find the theorem I'd need to avoid the cases on that

Thomas Vigouroux (Dec 05 2023 at 15:24):

Okay so I think I found the correct way to state the theorem for the proof to work, the thing I am now proving is:

lemma Sequent.mono (hΓ: Γ  A): Γ  Δ  A

Which is much esaier to prove because of the union

Thomas Vigouroux (Dec 05 2023 at 15:33):

Here's the complete proof:

lemma Sequent.weakening (hΓ: Γ  A): Γ  Δ  A := by {
  induction hΓ with
  | Ax h' => {
    apply Ax
    exact Finset.mem_union_left Δ h'
  }
  | ExFalso h' => {
    apply ExFalso
    exact Finset.mem_union_left Δ h'
  }
  | AndI _ _ IHA IHB => {
    apply AndI
    · exact IHA
    · exact IHB
  }
  | ImpI _ IH => {
    apply ImpI
    rw [ Finset.insert_union]
    exact IH
  }
  | OrI1 _ IH => {
    apply OrI1
    exact IH
  }
  | OrI2 _ IH => {
    apply OrI2
    exact IH
  }
  | AndE _ IH => {
    rw [Finset.insert_union]
    apply AndE
    repeat rw [ Finset.insert_union]
    exact IH
  }
  | ImpEAtom _  IH => {
    repeat rw [Finset.insert_union]
    apply ImpEAtom
    repeat rw [ Finset.insert_union]
    exact IH
  }
  | OrE _ _ IHA IHB => {
    rw [Finset.insert_union]
    apply OrE <;> rw [ Finset.insert_union]
    · exact IHA
    · exact IHB
  }
  | ImpEBot _ IH => {
    rw [Finset.insert_union]
    apply ImpEBot
    exact IH
  }
  | ImpEAnd _ IH => {
    rw [Finset.insert_union]
    apply ImpEAnd
    rw [ Finset.insert_union]
    exact IH
  }
  | ImpEOr _ IH => {
    rw [Finset.insert_union]
    apply ImpEOr
    repeat rw [ Finset.insert_union]
    exact IH
  }
  | ImpEImp _ _ IHA IHC => {
    rw [Finset.insert_union]
    apply ImpEImp <;> repeat rw [ Finset.insert_union]
    · exact IHA
    · exact IHC
  }
}

theorem Sequent.mono (h: Γ  Δ) (hΓ: Γ  C): Δ  C := by {
  generalize hΔ': Δ \ Γ = Δ'
  have hΔ : Δ = Γ  Δ'
  · rw [ hΔ']
    simp
    exact h
  rw [hΔ]
  exact weakening hΓ
}

Last updated: Dec 20 2023 at 11:08 UTC