\begin{code}
module Alpha where

open import Atom
open import Term
open import Equivariant
open import Permutation
open import ListProperties
open import Chi
open import TermAcc

open import Level
open import Relation.Nullary
open import Relation.Binary
open import Data.Empty
open import Data.Product renaming (_×_ to _∧_)
open import Data.Sum
open import Data.List
open import Data.List.Any as Any hiding (map)
open import Data.List.Any.Properties
open import Data.List.Any.Membership
open Any.Membership-≡ 
open import Relation.Binary.PropositionalEquality as PropEq hiding ([_])

infix 3 _∼α_ _≈α_

\end{code}

%<*alpha>
\begin{code}
data _∼α_ : Λ  Λ  Set where
  ∼αv  : {a : Atom}  v a ∼α v a
  ∼α·  : {M M' N N' : Λ}  M ∼α M'  N ∼α N'  
        M · N ∼α M' · N'
  ∼αƛ  : {M N : Λ}{a b : Atom}(xs : List Atom) 
        ((c : Atom)  c  xs   a  c  M ∼α  b  c  N)
        ƛ a M ∼α ƛ b N
\end{code}
%</alpha>

\begin{code}
lemma∼αEquiv : EquivariantRel _∼α_
lemma∼αEquiv .{v a}    .{v a}      π (∼αv {a}) 
  rewrite lemmaπv {a} {π} = ∼αv
lemma∼αEquiv .{M · N}  .{M' · N'}  π (∼α· {M} {M'} {N} {N'} M∼αM' N∼αN') 
  rewrite lemmaπ· {M} {N} {π} | lemmaπ· {M'} {N'} {π} 
  = ∼α· (lemma∼αEquiv π M∼αM') (lemma∼αEquiv π N∼αN')
lemma∼αEquiv .{ƛ a M}  .{ƛ b N}    π (∼αƛ {M} {N} {a} {b} xs p) 
  rewrite lemmaπƛ {a} {M} {π} | lemmaπƛ {b} {N} {π}
  = ∼αƛ  {π  M} {π  N} {π ∙ₐ a} {π ∙ₐ b} (xs ++ atoms π)
         c c∉xs++π  lemma-aux c π c∉xs++π) 
  where 
  lemma-aux :  (c : Atom)(π : Π)  c  xs ++ atoms π  
                π ∙ₐ a  c  (π  M) ∼α  π ∙ₐ b  c  (π  N)
  lemma-aux c π c∉xs++π 
    rewrite 
      cong   w   π ∙ₐ a  w  (π  M)) 
            (sym (lemmaπ∙ₐ≡ {c} {π} (c∉xs++ys→c∉ys {c} {xs} c∉xs++π))) 
    | cong   w   π ∙ₐ b  w  (π  N)) 
            (sym (lemmaπ∙ₐ≡ {c} {π} (c∉xs++ys→c∉ys {c} {xs} c∉xs++π))) 
    | sym (lemmaπ∙distributive {a} {c} {M} {π})
    | sym (lemmaπ∙distributive {b} {c} {N} {π})
    = lemma∼αEquiv π (p c (c∉xs++ys→c∉xs c∉xs++π))      
--
lemma∼αƛ : {a : Atom}{M N : Λ}  M ∼α N  ƛ a M ∼α ƛ a N
lemma∼αƛ {a} {M} {N} M∼αN = ∼αƛ []  c c∉[]  lemma∼αEquiv [(a , c)] M∼αN)
--
ρ : Reflexive _∼α_
ρ {v a}    = ∼αv
ρ {M · N}  = ∼α· ρ ρ
ρ {ƛ a M}  = ∼αƛ []  c c∉[]  lemma∼αEquiv {M} {M} [ (a , c) ] ρ) 
--
σ : Symmetric _∼α_
σ ∼αv                = ∼αv
σ (∼α· M∼αM' N∼αN')   = ∼α· (σ M∼αM') (σ N∼αN') 
σ (∼αƛ xs p)         = ∼αƛ xs  c c∉xs  σ (p c c∉xs)) 
--
τ : Transitive _∼α_
τ ∼αv ∼αv                            = ∼αv
τ (∼α· M∼αM′ N∼αN′) (∼α· M′∼αM″ N′∼αN″)  = ∼α· (τ M∼αM′ M′∼αM″) (τ N∼αN′ N′∼αN″)
τ (∼αƛ xs p) (∼αƛ xs′ p′)  
  = ∼αƛ  (xs ++ xs′)
         c c∉xs++xs′  
                         τ  (p   c (c∉xs++ys→c∉xs c∉xs++xs′))
                            (p′  c (c∉xs++ys→c∉ys {c} {xs} c∉xs++xs′))) 
--
≈-preorder : Preorder _ _ _
≈-preorder =  
    record { 
      Carrier = Λ;
      _≈_ = _≡_;
      _∼_ = _∼α_;
      isPreorder =  record {
        isEquivalence = Relation.Binary.Setoid.isEquivalence (setoid Λ) ;
        reflexive = λ { {M} {.M} refl  ρ};
        trans = τ } }

import Relation.Binary.PreorderReasoning as PreR
open PreR ≈-preorder
--
lemma∙cancel∼α :  {a b c : Atom}{M : Λ}  b # M  c # M  
                 c  b   a  c  M ∼α  a  b  M  
lemma∙cancel∼α {a} {b}   {c} {M} b#M c#M with a ≟ₐ b
lemma∙cancel∼α {a} {.a}  {c} {M} a#M c#M 
  | yes refl =  begin
                   c  a   a  c  M
                ≈⟨ lemma∙comm  
                   a  c   a  c  M
                ≈⟨ lemma(ab)(ab)M≡M 
                  M
                ≈⟨ sym lemma(aa)M≡M 
                   a  a  M
                
lemma∙cancel∼α {a} {b}   {c} {M} b#M c#M 
  | no a≢b with a ≟ₐ c
lemma∙cancel∼α {a} {b}   {.a} {M} b#M a#M 
  | no a≢b | yes refl =   begin
                             a  b   a  a  M
                          ≈⟨ cong  x   a  b  x) lemma(aa)M≡M  
                             a  b  M
                          
lemma∙cancel∼α {a} {b}   {c} {M} b#M c#M 
  | no a≢b | no a≢c with b ≟ₐ c
lemma∙cancel∼α {a} {b}   {.b} {M} b#M c#M 
  | no a≢b | no a≢c | yes refl =  begin
                                     b  b   a  b  M
                                  ≈⟨ lemma(aa)M≡M 
                                     a  b  M
                                  
lemma∙cancel∼α {a} {b} {c} {v d} (#v d≢b) (#v d≢c) | no a≢b | no a≢c | no b≢c 
  =  begin
        c  b   a  c  (v d)
     ≈⟨ refl 
        v ( c  b )ₐ  a  c )ₐ d)
     ≈⟨ cong v (lemma∙ₐcancel {a} {b} {c} {d} d≢b d≢c) 
        v ( a  b )ₐ d)
     ≈⟨ refl 
        a  b  (v d)
     
lemma∙cancel∼α {a} {b} {c} {M · N} ( b#M b#N) ( c#M c#N) | no a≢b | no a≢c | no b≢c 
  =  ∼α· (lemma∙cancel∼α b#M c#M) (lemma∙cancel∼α b#N c#N)
lemma∙cancel∼α {a} {b} {c} {ƛ d M} b#λdM c#λdM | no a≢b | no a≢c | no b≢c 
  with b ≟ₐ d
lemma∙cancel∼α {a} {b} {.b} {ƛ .b M} b#λdM  #ƛ≡       | no a≢b | no _   | no b≢b 
  | yes refl = ⊥-elim (b≢b refl)
lemma∙cancel∼α {a} {b} {c} {ƛ .b M} b#λdM   ( c#M)  | no a≢b | no a≢c | no b≢c 
  | yes refl 
  rewrite lemma∙ₐ(ab)b≡a {a} {b} | lemma∙ₐc≢a∧c≢b (sym≢ a≢b) b≢c | lemma∙ₐ(ab)b≡a {c} {b}
  = ∼αƛ (a  b  c  ocurr M)   e e∉abc∷ocurrM  lemma(ce)(cb)(ac)M∼α(ae)(ab)M e e∉abc∷ocurrM)
  where 
  lemma(ce)(cb)(ac)M∼α(ae)(ab)M : (e : Atom)  e  a  b  c  ocurr M   c  e   c  b   a  c  M ∼α  a  e   a  b  M
  lemma(ce)(cb)(ac)M∼α(ae)(ab)M  e e∉abc∷ocurrM
    = begin
          c  e   c  b   a  c  M
       ≈⟨ lemma∙distributive {c} {e} {c} {b} { a  c  M} 
           c  e )ₐ c   c  e )ₐ b   c  e   a  c  M
       ≈⟨ cong  x   x   c  e )ₐ b   c  e   a  c  M) (lemma∙ₐ(ab)a≡b {c} {e}) 
          e   c  e )ₐ b   c  e   a  c  M
       ≈⟨ cong  x   e  x   c  e   a  c  M) (lemma∙ₐc≢a∧c≢b b≢c (sym≢ (d∉abc∷xs→d≢b e∉abc∷ocurrM))) 
          e  b   c  e   a  c  M
       ∼⟨ lemma∼αEquiv [( e , b)] (lemma∙cancel∼α {a} {e} {c} (lemma∉→# {e} {M} (lemmaocurr (d∉abc∷xs→d∉xs e∉abc∷ocurrM))) c#M) 
          e  b   a  e   M
       ≈⟨ sym (cong  x   e  x   a  e  M) (lemma∙ₐc≢a∧c≢b (sym≢ a≢b) (sym≢ (d∉abc∷xs→d≢b e∉abc∷ocurrM)))) 
          e   a  e )ₐ b   a  e   M
       ≈⟨ sym (cong  x   x   a  e )ₐ b   a  e   M) (lemma∙ₐ(ab)a≡b {a} {e})) 
           a  e )ₐ a   a  e )ₐ b   a  e   M
       ≈⟨ sym (lemma∙distributive {a} {e} {a} {b} {M}) 
          a  e   a  b  M
       
lemma∙cancel∼α {a} {b} {c} {ƛ d M} b#λdM c#λdM | no a≢b | no a≢c | no b≢c 
  | no b≢d with c ≟ₐ d 
lemma∙cancel∼α {a} {b} {.b} {ƛ .b M} #ƛ≡ c#λcM      | no a≢b | no a≢d | no _ | no b≢b 
  | yes refl = ⊥-elim (b≢b refl)
lemma∙cancel∼α {a} {b} {c} {ƛ .c M} ( b#M) c#λcM  | no a≢b | no a≢c | no _ | no b≢c 
  | yes refl rewrite lemma∙ₐ(ab)b≡a {a} {c} | lemma∙ₐc≢a∧c≢b a≢c a≢b | lemma∙ₐc≢a∧c≢b (sym≢ a≢c) (sym≢ b≢c)
  = ∼αƛ (a  b  c  ocurr M)  e e∉abc∷ocurrM  lemma(ae)(cb)(ac)M∼α(ce)(ab)M e e∉abc∷ocurrM)
  where 
  lemma(ae)(cb)(ac)M∼α(ce)(ab)M : (e : Atom)  e  a  b  c  ocurr M   a  e   c  b   a  c  M ∼α  c  e   a  b  M
  lemma(ae)(cb)(ac)M∼α(ce)(ab)M e e∉abc∷ocurrM
    =  begin
          a  e   c  b   a  c  M 
       ≈⟨ cong  x   a  e  x) (lemma∙distributive {c} {b} {a} {c} {M}) 
          a  e    c  b )ₐ a   c  b )ₐ c   c  b   M 
       ≈⟨ cong  x   a  e   x   c  b )ₐ c   c  b   M) (lemma∙ₐc≢a∧c≢b a≢c a≢b)  
          a  e   a   c  b )ₐ c   c  b   M 
       ≈⟨ cong  x   a  e   a  x   c  b   M) (lemma∙ₐ(ab)a≡b {c} {b}) 
          a  e   a  b   c  b   M 
       ≈⟨ lemma∙distributive {a} {e} {a} {b} { c  b   M}  
           a  e )ₐ a   a  e )ₐ b   a  e   c  b   M 
       ≈⟨ cong  x   x   a  e )ₐ b   a  e   c  b   M) (lemma∙ₐ(ab)a≡b {a} {e})      
          e   a  e )ₐ b   a  e   c  b   M 
       ≈⟨ cong  x   e  x   a  e   c  b   M) (lemma∙ₐc≢a∧c≢b (sym≢ a≢b) (sym≢ (d∉abc∷xs→d≢b e∉abc∷ocurrM)))  
          e  b   a  e   c  b   M 
       ≈⟨ lemma∙distributive {e} {b} {a} {e} { c  b   M}  
           e  b )ₐ a   e  b )ₐ e   e  b    c  b   M 
       ≈⟨ cong  x   x   e  b )ₐ e   e  b    c  b   M) (lemma∙ₐc≢a∧c≢b (sym≢ (d∉abc∷xs→d≢a e∉abc∷ocurrM)) a≢b)   
          a   e  b )ₐ e   e  b    c  b   M 
       ≈⟨ cong  x   a  x   e  b    c  b   M) (lemma∙ₐ(ab)a≡b {e} {b})  
          a  b   e  b    c  b   M 
       ≈⟨ cong  x   a  b  x) (lemma∙comm {e} {b} { c  b   M })  
          a  b   b  e    c  b   M 
       ∼⟨ lemma∼αEquiv [(a , b)] (lemma∙cancel∼α {c} {e} {b} {M} (lemma∉→# {e} {M} (lemmaocurr (d∉abc∷xs→d∉xs e∉abc∷ocurrM))) b#M) 
          a  b   c  e   M
       ≈⟨ sym (cong  x   a  x   c  e   M) (lemma∙ₐc≢a∧c≢b b≢c (sym≢ (d∉abc∷xs→d≢b e∉abc∷ocurrM)))) 
          a   c  e )ₐ b   c  e   M
       ≈⟨ sym (cong  x   x   c  e )ₐ b   c  e   M) (lemma∙ₐc≢a∧c≢b a≢c (sym≢ (d∉abc∷xs→d≢a e∉abc∷ocurrM)))) 
           c  e )ₐ a   c  e )ₐ b   c  e   M
       ≈⟨ sym (lemma∙distributive {c} {e} {a} {b} {M}) 
          c  e   a  b  M
       
lemma∙cancel∼α {a} {b} {c} {ƛ .b M}  #ƛ≡       c#λdM     | no a≢b | no a≢c | no b≢c | no b≢b
  | no c≢b = ⊥-elim (b≢b refl)
lemma∙cancel∼α {a} {b} {c} {ƛ .c M}  ( b#M)  #ƛ≡       | no a≢b | no a≢c | no b≢c | no _
  | no c≢c = ⊥-elim (c≢c refl)
lemma∙cancel∼α {a} {b} {c} {ƛ d M}   ( b#M)  ( c#M)  | no a≢b | no a≢c | no b≢c | no b≢d
  | no c≢d with a ≟ₐ d
lemma∙cancel∼α {a} {b} {c} {ƛ .a M}   ( b#M)  ( c#M)  | no a≢b | no a≢c | no b≢c | no b≢a
  | no c≢a | yes refl rewrite lemma∙ₐ(ab)a≡b {a} {c} | lemma∙ₐ(ab)a≡b {c} {b} | lemma∙ₐ(ab)a≡b {a} {b}
  = lemma∼αƛ (lemma∙cancel∼α b#M c#M)
lemma∙cancel∼α {a} {b} {c} {ƛ d M}   ( b#M)  ( c#M)  | no a≢b | no a≢c | no b≢c | no b≢d
  | no c≢d | no a≢d rewrite lemma∙ₐc≢a∧c≢b (sym≢ a≢d) (sym≢ c≢d) | lemma∙ₐc≢a∧c≢b (sym≢ c≢d) (sym≢ b≢d) | lemma∙ₐc≢a∧c≢b (sym≢ a≢d) (sym≢ b≢d) 
  = lemma∼αƛ (lemma∙cancel∼α b#M c#M)
--
lemma∙cancel∼α' : {a b c : Atom}{M : Λ}  b # ƛ a M  c # M   c  b   a  c  M ∼α  a  b  M  
lemma∙cancel∼α' {a} {.a} {c} {M}       #ƛ≡     c#M           
  = begin
       c  a   a  c  M 
    ≈⟨ lemma∙comm {c} {a} { a  c  M} 
       a  c   a  c  M  
    ≈⟨ lemma(ab)(ab)M≡M {a} {c} {M} 
       M  
    ≈⟨ sym (lemma(aa)M≡M {a} {M}) 
       a  a  M  
    
lemma∙cancel∼α' {a} {b} {c} {M}       ( b#M)     c#M           
  = lemma∙cancel∼α {a} {b} {c} {M} b#M  c#M
--
lemma∙cancel∼α'' : {a b c : Atom}{M : Λ}  b # ƛ a M  c # ƛ a M   c  b   a  c  M ∼α  a  b  M  
lemma∙cancel∼α'' {a} {b} {.a} {M} b#ƛaM #ƛ≡ rewrite lemma(aa)M≡M {a} {M} = ρ
lemma∙cancel∼α'' b#ƛaM ( c#M) = lemma∙cancel∼α' b#ƛaM c#M
--
lemma∙cancel∼α‴ : {a b c : Atom}{M : Λ}  b # M  c # ƛ a M   c  b   a  c  M ∼α  a  b  M  
lemma∙cancel∼α‴ {a} {b} {.a}  {M} b#M #ƛ≡ rewrite lemma(aa)M≡M {a} {M} = ρ
lemma∙cancel∼α‴ {a} {b} {c}   {M}  b#M ( c#N)  = lemma∙cancel∼α b#M c#N
--
lemma∙ : {a b c : Atom}{M : Λ}  b # ƛ a M  c ∉ₜ M   c  b   a  c  M ∼α  a  b  M  
lemma∙ {a} {b} {c} {M}       b#ƛaM     c∉M           
  = lemma∙cancel∼α' {a} {b} {c} {M} b#ƛaM (lemma∉→# c∉M)           
--
lemma∼α* : {a : Atom}{M N : Λ}  M ∼α N  a * M  a * N
lemma∼α* {a}                  ∼αv               a*M           = a*M
lemma∼α* {a}                  (∼α· M∼αM' N∼αN')   (*·l a*M)     = *·l (lemma∼α* M∼αM' a*M)
lemma∼α* {a}                  (∼α· M∼αM' N∼αN')   (*·r a*N)     = *·r (lemma∼α* N∼αN' a*N)
lemma∼α* {a} {ƛ b M} {ƛ c N}  (∼αƛ xs f)        ( a*M b≢a) 
  with 
  χ' (a  b  c  [] ++ xs ++ ocurr N) |
  c∉xs++ys→c∉xs {χ' (a  b  c  [] ++ xs ++ ocurr N)}  {xs} {ocurr N} (c∉xs++ys→c∉ys {χ' (a  b  c  [] ++ xs ++ ocurr N)} {a  b  c  []} {xs ++ ocurr N} (χ'∉ (a  b  c  [] ++ xs ++ ocurr N))) |
  (χ'∉ (a  b  c  [] ++ xs ++ ocurr N))
... | d | d∉xs | d∉abcxsN
  with lemma*swap← (lemma∼α* (f d d∉xs) (lemma*swap→ a≢d (sym≢ b≢a) a*M)) 
  where 
  a≢d : a  d
  a≢d a≡d = d∉abcxsN (here (sym a≡d))
lemma∼α* {a} {ƛ b M} {ƛ c N} (∼αƛ xs f) ( a*M b≢a) 
  | d | d∉xs | d∉abcxsN | inj₁ (a≢c , _ , a*N)     =  a*N (sym≢ a≢c)
lemma∼α* {a} {ƛ b M} {ƛ c N} (∼αƛ xs f) ( a*M b≢a) 
  | d | d∉xs | d∉abcxsN | inj₂ (inj₁ (a≡c , d*N))  = ⊥-elim ((¬d*N) d*N)
  where
  d∉N : d ∉ₜ N
  d∉N = lemmaocurr (c∉xs++ys→c∉ys {d} {xs} {ocurr N} (c∉xs++ys→c∉ys {d} {a  b  c  []} {xs ++ ocurr N}  d∉abcxsN))
  ¬d*N : ¬ (d * N)
  ¬d*N d*N = (lemma∉→¬∈ d∉N) (lemma-free→∈ d*N)
lemma∼α* {a} {ƛ b M} {ƛ c N} (∼αƛ xs f) ( a*M b≢a) 
  | d | d∉xs | d∉abcxsN | inj₂ (inj₂ (a≡d , c*N))  = ⊥-elim (a≢d a≡d)
  where
  a≢d : a  d
  a≢d a≡d = d∉abcxsN (here (sym a≡d))
--
lemma∼α# : {a : Atom}{M N : Λ}  M ∼α N  a # M  a # N
lemma∼α# {a} {M} {N} M∼N a#M with a #? N
... | yes a#N = a#N
... | no ¬a#N = ⊥-elim (lemma-free→¬# (lemma∼α* (σ M∼N) (lemma¬#→free ¬a#N)) a#M)
-- Chi Alpha Lemma
χ∼α : (M N : Λ)(xs : List Atom)  M ∼α N  χ xs M  χ xs N
χ∼α M N xs M∼αN = lemmaχaux⊆ (xs ++ fv M) (xs ++ fv N) lemma⊆ lemma⊇
  where
  lemma⊆ : (xs ++ fv M)  (xs ++ fv N)
  lemma⊆ {a} a∈xs++fvM with c∈xs++ys→c∈xs∨c∈ys {a} {xs} {fv M} a∈xs++fvM
  ... | inj₁ a∈xs   = c∈xs∨c∈ys→c∈xs++ys {a} {xs} {fv N} (inj₁ a∈xs)
  ... | inj₂ a∈fvM  =  c∈xs∨c∈ys→c∈xs++ys {a} {xs} {fv N} (inj₂ (lemmafvfree← a N (lemma∼α* M∼αN (lemmafvfree→ a M (a∈fvM)))))
  lemma⊇ : (xs ++ fv N)  (xs ++ fv M)
  lemma⊇ {a} a∈xs++fvN with c∈xs++ys→c∈xs∨c∈ys {a} {xs} {fv N} a∈xs++fvN
  ... | inj₁ a∈xs   = c∈xs∨c∈ys→c∈xs++ys {a} {xs} {fv M} (inj₁ a∈xs)
  ... | inj₂ a∈fvN  =  c∈xs∨c∈ys→c∈xs++ys {a} {xs} {fv M} (inj₂ (lemmafvfree← a M (lemma∼α* (σ M∼αN) (lemmafvfree→ a N (a∈fvN)))))
-- A more classical alpha definition
data _≈α_ : Λ  Λ  Set where
  ≈αv  : {a : Atom}
        v a ≈α v a
  ≈α·  : {M M' N N' : Λ}  M ≈α M'  N ≈α N' 
        M · N ≈α M' · N'
  ≈αƛ  : {M N : Λ}{a b c : Atom} 
        c # ƛ a M  c # ƛ b N 
         a  c  M ≈α  b  c  N
        ƛ a M ≈α ƛ b N
--
lemma∼α∃#→∀ : {a b c : Atom}{M N : Λ}  
         c # ƛ a M  c # ƛ b N   a  c  M ∼α   b  c  N  
           xs  ((d : Atom)   d  xs   a  d  M ∼α   b  d  N))
lemma∼α∃#→∀ {a} {b} {c} {M} {N} c#ƛaM c#ƛbN (ac)M∼α(bc)N 
  = ocurr M ++ ocurr N ,
      d d∉ocurrM++ocurrN  
        (lemmaEqRel _∼α_ lemma∼αEquiv) [(d , c)]
                                         (  begin
                                               d  c   a  d  M 
                                            ∼⟨ lemma∙ c#ƛaM (lemmaocurr (c∉xs++ys→c∉xs {d} {ocurr M} {ocurr N} d∉ocurrM++ocurrN)) 
                                               a  c  M 
                                            ∼⟨ (ac)M∼α(bc)N 
                                               b  c  N
                                            ∼⟨ σ (lemma∙ c#ƛbN (lemmaocurr ((c∉xs++ys→c∉ys {d} {ocurr M} {ocurr N} d∉ocurrM++ocurrN)) )) 
                                               d  c   b  d  N
                                             ))
--
lemma∼α∀→∃# : {a b : Atom}{M N : Λ}{xs : List Atom}  
         ((c : Atom)   c  xs   a  c  M ∼α   b  c  N) 
           c  c # ƛ a M  c # ƛ b N   a  c  M ∼α  b  c  N)
lemma∼α∀→∃# {a} {b} {M} {N} {xs} f 
  with χ' (xs ++ ocurr (ƛ a M) ++ ocurr (ƛ b N))  | χ'∉ (xs ++ ocurr (ƛ a M) ++ ocurr (ƛ b N))
... | c | c∉xs++ocurrƛaM++ocurrƛbN
  =  c , 
     (lemma∉→# 
       (lemmaocurr 
          (c∉xs++ys→c∉xs  {c} {ocurr (ƛ a M)} {ocurr (ƛ b N)} 
                          (c∉xs++ys→c∉ys {c} {xs} {ocurr (ƛ a M) ++ ocurr (ƛ b N)} c∉xs++ocurrƛaM++ocurrƛbN)))) ,
     (lemma∉→# 
       (lemmaocurr 
         (c∉xs++ys→c∉ys  {c} {ocurr (ƛ a M)} {ocurr (ƛ b N)}
                         (c∉xs++ys→c∉ys {c} {xs} {ocurr (ƛ a M) ++ ocurr (ƛ b N)} c∉xs++ocurrƛaM++ocurrƛbN)))) , 
     (f c (c∉xs++ys→c∉xs {c} {xs} {ocurr (ƛ a M) ++ ocurr (ƛ b N)} c∉xs++ocurrƛaM++ocurrƛbN)) 

-- Alpha definitions equivalence; Study if this proof can be done with an induction principle without Accesible predicate !
lemma∼α→≈αAcc : {M N : Λ}  ΛAcc M  M ∼α N  M ≈α N
lemma∼α→≈αAcc _                 ∼αv                = ≈αv
lemma∼α→≈αAcc (acc· accM accN)  (∼α· M∼αM' N∼αN')  = ≈α· (lemma∼α→≈αAcc accM M∼αM') (lemma∼α→≈αAcc accN N∼αN')
lemma∼α→≈αAcc (accƛ facc)       (∼αƛ _ f) with lemma∼α∀→∃# f
... | c , c#λaM , c#λbN , (ac)M∼α(bc)N = ≈αƛ {c = c} c#λaM c#λbN (lemma∼α→≈αAcc (facc c) (ac)M∼α(bc)N)

lemma∼α→≈α : {M N : Λ}  M ∼α N  M ≈α N
lemma∼α→≈α {M} M∼N = lemma∼α→≈αAcc {M} (accesibleTerms M) M∼N
--
lemma≈α→∼α : {M N : Λ}  M ≈α N  M ∼α N
lemma≈α→∼α ≈αv              = ∼αv
lemma≈α→∼α (≈α· M≈αM' N≈αN')  = ∼α· (lemma≈α→∼α M≈αM') (lemma≈α→∼α N≈αN')
lemma≈α→∼α (≈αƛ c#ƛaM c#ƛbN (ac)M∼α(bc)N) 
  with lemma∼α∃#→∀ c#ƛaM c#ƛbN (lemma≈α→∼α (ac)M∼α(bc)N)
... | xs , prf = ∼αƛ xs prf
--
lemma∼αλ : {a b : Atom}{M : Λ}  b # M  ƛ a M ∼α ƛ b ( a  b  M)  
lemma∼αλ {a} {b} {M} b#M 
  = ∼αƛ (ocurr M)  c c∉ocurrM  σ (lemma∙cancel∼α (lemma∉→# (lemmaocurr c∉ocurrM)) b#M))
--
lemma∼αλ' : {a b : Atom}{M : Λ}  b # ƛ a M  ƛ a M ∼α ƛ b ( a  b  M)  
lemma∼αλ' {a} {.a} {M} #ƛ≡ rewrite lemma(aa)M≡M {a} {M} = ρ
lemma∼αλ' ( b#M) = lemma∼αλ b#M
--
lemma#∼α : {a b : Atom}{M : Λ}  a # M  b # M  M ∼α  a  b  M
lemma#∼α {a} {b} {v d}     (#v d≢a)      (#v d≢b) 
  rewrite lemma∙ₐc≢a∧c≢b d≢a d≢b     = ρ
lemma#∼α {a} {b} {M · N}   ( a#M a#N)  ( b#M b#N) 
  = ∼α· (lemma#∼α a#M b#M) (lemma#∼α a#N b#N)
lemma#∼α {a} {b} {ƛ c M}   a#ƛcM         b#ƛcM 
  with a ≟ₐ c
lemma#∼α {a} {.a} {ƛ .a M} a#ƛaM         #ƛ≡ 
  | yes refl 
  rewrite lemma(aa)M≡M {a} {ƛ a M}  = ρ
lemma#∼α {a} {b} {ƛ .a M}  a#ƛaM         ( b#M) 
  | yes refl 
  rewrite lemma∙ₐ(ab)a≡b {a} {b}    = lemma∼αλ b#M
lemma#∼α {a} {b} {ƛ c M}   a#ƛcM  b#ƛcM 
  | no  a≢c with b ≟ₐ c
lemma#∼α {.b} {b} {ƛ .b M} #ƛ≡ #ƛ≡ 
  | no b≢b | yes refl = ⊥-elim (b≢b refl)
lemma#∼α {a} {b} {ƛ .b M} ( a#M) #ƛ≡ 
  | no a≢b | yes refl 
  rewrite lemma∙ₐ(ab)b≡a {a} {b}
  |       lemma∙comm {a} {b} {M}     = lemma∼αλ a#M
lemma#∼α {.b} {b} {ƛ .b M} #ƛ≡ ( b#M) 
  | no b≢b | yes refl = ⊥-elim (b≢b refl)
lemma#∼α {a} {b} {ƛ .b M} ( a#M) ( b#M) 
  | no a≢b | yes refl 
  rewrite lemma∙ₐ(ab)b≡a {a} {b}
  |       lemma∙comm {a} {b} {M}     = lemma∼αλ a#M
lemma#∼α {a} {b} {ƛ c M}   a#ƛcM  b#ƛcM 
  | no  a≢c | no b≢c 
  rewrite lemma∙ₐc≢a∧c≢b (sym≢ a≢c) (sym≢ b≢c) 
  = lemma∼αƛ (lemma#∼α (lemma#λ a≢c a#ƛcM) (lemma#λ b≢c b#ƛcM))
\end{code}

Alpha Compatibility

%<*alphaCompatible>
\begin{code}
αCompatiblePred : {l : Level}  (Λ  Set l)  Set l
αCompatiblePred P = {M N : Λ}  M ∼α N  P M  P N
\end{code}
%</alphaCompatible>

Strong Compatibility

%<*strongAlphaCompatible>
\begin{code}
strong∼αCompatible : {l : Level}{A : Set l}  (Λ  A)  Λ  Set l
strong∼αCompatible f M =  N  M ∼α N  f M  f N
\end{code}
%</strongAlphaCompatible>