\begin{code}
module Parallel where

open import Level
open import Function
open import Atom
open import Alpha
open import ListProperties
open import Term hiding (fv)
open import TermRecursion
open import TermInduction
open import TermAcc
open import NaturalProperties
open import Equivariant
open import Permutation
open import Substitution
open import FreeVariables
open import Chi
open import Relation Λ hiding (_++_;trans)
open import Beta

open import Data.Bool hiding (_∨_)
open import Data.Nat hiding (_*_)
open import Data.Nat.Properties
open import Data.Empty
open import Data.Sum -- renaming (_⊎_ to _∨_)
open import Data.List
open import Data.List.Any as Any hiding (map)
open import Data.List.Any.Membership
open Any.Membership-≡ hiding (_⊆_)
open import Data.Product
open import Relation.Binary.PropositionalEquality as PropEq renaming ([_] to [_]ᵢ)
open import Relation.Nullary
open import Relation.Nullary.Decidable
\end{code}

\begin{code}
infixl 3 _⇉_
\end{code}

Parallel reduction.

%<*parallel>
\begin{code}
data _⇉_ : Rel where
  ⇉v :  (x : Atom)
         v x  v x
  ⇉ƛ :  {M M' : Λ}{x y : Atom}(xs : List Atom)
         ((z : Atom)  z  xs   x  z  M   y  z  M')
         ƛ x M  ƛ y M'
  ⇉· :  {M M' N N' : Λ}
         M  M'  N  N'
         M · N  M' · N'
  ⇉β :  {M M' N N' P : Λ}(x y : Atom)
         ƛ x M  ƛ y M' 
         N  N'
         M' [ y  N' ] ∼α P
         ƛ x M · N  P
\end{code}
%</parallel>

\begin{code}
lemma⇉ƛ : {x : Atom}{M N : Λ}  ƛ x M  N
              y    P    ys  N  ƛ y P × ((z : Atom)  z  ys   x  z  M   y  z  P))))
lemma⇉ƛ {x} {M} {ƛ y P} (⇉ƛ ys fys) = y , P , ys , refl , fys 
\end{code}


Parallel diamond property.

\begin{code}
open PropEq.≡-Reasoning renaming (begin_ to begin≡_;_∎ to _□)

lemma⇉Equiv : EquivariantRel (_⇉_)
lemma⇉Equiv π (⇉v x) 
  = subst  H  H  H) (sym (lemmaπv {x} {π})) (⇉v (π ∙ₐ x))
lemma⇉Equiv π (⇉ƛ {M} {M'} {x} {y} xs fxs) 
  = subst₂   H I  H  I) (sym (lemmaπƛ {x} {M} {π})) (sym (lemmaπƛ {y} {M'} {π})) 
            (⇉ƛ (xs ++ atoms π) 
                 z z∉xs++π   subst₂   H I  H  I) 
                                        (  begin≡
                                             π   x  z  M
                                           ≡⟨ lemmaπ∙distributive {x} {z} {M} {π} 
                                              π ∙ₐ x  π ∙ₐ z  (π  M)
                                           ≡⟨ cong  H   π ∙ₐ x  H  (π  M)) (lemmaπ∙ₐ≡ {z} {π} (c∉xs++ys→c∉ys {xs = xs} z∉xs++π)) 
                                              π ∙ₐ x  z  (π  M)
                                            ) 
                                        (  begin≡
                                             π   y  z  M'
                                           ≡⟨ lemmaπ∙distributive {y} {z} {M'} {π} 
                                              π ∙ₐ y  π ∙ₐ z  (π  M')
                                           ≡⟨ cong  H   π ∙ₐ y  H  (π  M')) (lemmaπ∙ₐ≡ {z} {π} (c∉xs++ys→c∉ys {xs = xs} z∉xs++π)) 
                                              π ∙ₐ y  z  (π  M')
                                            ) 
                                        (lemma⇉Equiv π (fxs z (c∉xs++ys→c∉xs z∉xs++π)))))
lemma⇉Equiv π (⇉· {M} {M'} {N} {N'} M⇉M' N⇉N') 
  = subst₂   H I  H  I) (sym (lemmaπ· {M} {N} {π})) (sym (lemmaπ· {M'} {N'} {π})) 
            (⇉· (lemma⇉Equiv π M⇉M') (lemma⇉Equiv π N⇉N'))
lemma⇉Equiv π (⇉β {M} {M'} {N} {N'} {P} x y ƛxM⇉ƛyM' N⇉N' M'[y≔N']∼P) 
  = subst   H  H  π  P) 
           (sym (trans (lemmaπ· {ƛ x M} {N} {π}) (cong  H  H · (π  N)) (lemmaπƛ {x} {M} {π})))) 
           (⇉β  {π  M} {π  M'} {π  N} {π  N'} {π  P} (π ∙ₐ x) (π ∙ₐ y) 
                (subst₂  H I  H  I) (lemmaπƛ {x} {M} {π}) (lemmaπƛ {y} {M'} {π}) (lemma⇉Equiv π ƛxM⇉ƛyM')) 
                (lemma⇉Equiv π N⇉N') 
                (begin 
                   (π  M') [ π ∙ₐ y  π  N' ] 
                 ∼⟨  σ (lemmaπ[] {M'} {N'} {y} {π})  
                   π  (M' [ y  N' ]) 
                 ∼⟨ lemma∼αEquiv π M'[y≔N']∼P 
                   π  P
                 ))

lemma⇉ƛpres : {x : Atom}{M N : Λ}  M  N  ƛ x M  ƛ x N
lemma⇉ƛpres {x} M⇉N =  ⇉ƛ [] ( λ y _  lemma⇉Equiv [ (x , y) ] M⇉N)

lemma⇉αright : {M N P : Λ}  M  N  N ∼α P  M  P
lemma⇉αright (⇉v a)          ∼αv
  = ⇉v a
lemma⇉αright (⇉· M⇉M' N⇉N')  (∼α· M'∼P N'∼P') 
  = ⇉· (lemma⇉αright M⇉M' M'∼P) (lemma⇉αright N⇉N' N'∼P')
lemma⇉αright (⇉ƛ xs fxs)     (∼αƛ ys fys) 
  = ⇉ƛ  (xs ++ ys) 
         z z∉xs++ys  lemma⇉αright (fxs z (c∉xs++ys→c∉xs z∉xs++ys)) (fys z (c∉xs++ys→c∉ys {xs = xs} z∉xs++ys)))
lemma⇉αright (⇉β x y ƛxM⇉ƛyM' N⇉N' M'[y≔N']∼N) N∼P 
  = ⇉β x y ƛxM⇉ƛyM' N⇉N' (τ M'[y≔N']∼N N∼P)

lemma⇉αleft : {M N P : Λ}  M ∼α N  N  P  M  P
lemma⇉αleft ∼αv          (⇉v a)
  = ⇉v a
lemma⇉αleft (∼αƛ xs fxs) (⇉ƛ ys fys) 
  = ⇉ƛ (xs ++ ys)  z z∉xs++ys  lemma⇉αleft (fxs z (c∉xs++ys→c∉xs z∉xs++ys)) (fys z (c∉xs++ys→c∉ys {xs = xs} z∉xs++ys)))
lemma⇉αleft (∼α· M∼M' N∼N') (⇉· M'⇉P N'⇉P') 
  = ⇉· (lemma⇉αleft M∼M' M'⇉P) (lemma⇉αleft N∼N' N'⇉P')
lemma⇉αleft (∼α· {ƛ z M} {ƛ .x N} {M'} {N'} ƛzM∼ƛxN M'∼N') (⇉β x y ƛxN⇉ƛyP' N'⇉P'' P'[x≔P'']∼P) 
  = ⇉β z y (lemma⇉αleft ƛzM∼ƛxN ƛxN⇉ƛyP') (lemma⇉αleft M'∼N' N'⇉P'') P'[x≔P'']∼P
lemma⇉αleft (∼α· {v _}   {ƛ .x N} {M'} {N'} () M'∼N') (⇉β x y ƛxN⇉ƛyP' N'⇉P'' P'[x≔P'']∼P) 
lemma⇉αleft (∼α· {_ · _} {ƛ .x N} {M'} {N'} () M'∼N') (⇉β x y ƛxN⇉ƛyP' N'⇉P'' P'[x≔P'']∼P) 

P⇉# : Atom  Λ  Set
P⇉# x M = {N : Λ}  x # M  M  N  x # N

αCompP⇉# : (x : Atom)  αCompatiblePred (P⇉# x)
αCompP⇉# x {M} {P} M~P PM x#P P⇉N = PM (lemma∼α# (σ M~P) x#P) (lemma⇉αleft M~P P⇉N)

lemma⇉# : {M : Λ}{x : Atom}  P⇉# x M
lemma⇉# {M} {x} = TermαIndPerm
                      (P⇉# x)
                      (αCompP⇉# x)
                      lemmav
                      lemma·
                      ([ x ] , lemmaƛ)
                      M
   where
   lemmav : (a : )  P⇉# x (v a)
   lemmav a x#a (⇉v .a) 
     = x#a
   lemma· : (M P : Λ)  P⇉# x M  P⇉# x P  P⇉# x (M · P)
   lemma· M P PM PP ( x#M x#P) (⇉· M⇉N' P⇉N'') 
     =  (PM x#M M⇉N') (PP x#P P⇉N'')
   lemma· (ƛ .y M) P PƛyM PP ( x#ƛyM x#P) (⇉β y z ƛyM⇉ƛzN' P⇉N'' N'[z:=N'']∼N)
     = lemma∼α# N'[z:=N'']∼N (lemma#Subst (PƛyM x#ƛyM ƛyM⇉ƛzN') (PP x#P P⇉N''))
   lemmaƛ : (M : Λ) (b : )  b  [ x ]  (∀ π  P⇉# x (π  M))  P⇉# x (ƛ b M)
   lemmaƛ M .x  x∉[x] PπM {ƛ y N} #ƛ≡       (⇉ƛ xs fxs) 
     = ⊥-elim (x∉[x] (here refl))
   lemmaƛ M b   b∉[x] PπM {ƛ y N} ( x#M)  (⇉ƛ xs fxs) 
     = corollarylemma*swap→ x≢z (PπM [ ( b , z ) ] x#(bz)M (fxs z z∉xs))
     where 
     z = χ' (x  fv N ++ xs)
     z∉x∷fvM++xs = lemmaχ∉ (x  fv N ++ xs)
     z∉xs : z  xs
     z∉xs = c∉xs++ys→c∉ys  {xs = fv N} (b∉a∷xs→b∉xs z∉x∷fvM++xs)
     x≢z : x  z
     x≢z = sym≢ (b∉a∷xs→b≢a z∉x∷fvM++xs)
     x≢b : x  b
     x≢b x≡b = ⊥-elim (b∉[x] (here (sym x≡b)))
     x#(bz)M : x #  b  z  M
     x#(bz)M = lemma#swap≢ x≢b x≢z x#M

-- lemma⇉#         u#x   (⇉v x)  
--   = u#x
-- lemma⇉# {x = u} u#ƛyM (⇉ƛ {M} {N} {x} {y} xs fxs) 
--   = corollarylemma*swap→ u≢z u#(yz)M
--   where
--   z = χ' (u ∷ (fv M ++ xs))
--   z∉u∷fvM++xs = χ'∉ (u ∷ (fv M ++ xs))
--   z∉xs : z ∉ xs
--   z∉xs = c∉xs++ys→c∉ys  {xs = fv M} (b∉a∷xs→b∉xs z∉u∷fvM++xs)
--   u≢z : u ≢ z
--   u≢z = sym≢ (b∉a∷xs→b≢a z∉u∷fvM++xs)
--   z#M : z # M
--   z#M =  lemma∉fv→# (c∉xs++ys→c∉xs (b∉a∷xs→b∉xs z∉u∷fvM++xs)) 
--   u#(xz)M : u # ( x ∙ z ) M
--   u#(xz)M = lemma#swapƛ z#M u≢z u#ƛyM
--   u#(yz)M : u # ( y ∙ z ) N
--   u#(yz)M = lemma⇉# u#(xz)M (fxs z z∉xs)
-- lemma⇉# (#· x#M x#M') (⇉· M⇉N M'⇉N') 
--   = #· (lemma⇉# x#M M⇉N) (lemma⇉# x#M' M'⇉N')
-- lemma⇉# (#· x#ƛyM x#M') (⇉β y z ƛyM⇉ƛzN M'⇉N' N[z≔N']∼P) 
--   = lemma∼α# N[z≔N']∼P (lemma#Subst (lemma⇉# x#ƛyM ƛyM⇉ƛzN) (lemma⇉# x#M' M'⇉N'))

lemma⇉ƛrule : {M M' : Λ}{x : Atom}
         ƛ x M  M'
         Σ Λ  M″  M  M″ × ƛ x M  ƛ x M″ × M' ∼α ƛ x M″) 
lemma⇉ƛrule {M} {ƛ y M'} {x} (⇉ƛ xs fxs) 
  =   y  x  M'                            , 
     M⇉(yx)M'                                , 
     lemma⇉αright (⇉ƛ xs fxs) ƛyM'∼ƛx(yx)M'  , 
     ƛyM'∼ƛx(yx)M'
  where
  x#ƛyM' : x # ƛ y M'
  x#ƛyM' = lemma⇉# #ƛ≡ (⇉ƛ xs fxs)
  ƛyM'∼ƛx(yx)M' : ƛ y M' ∼α ƛ x ( y  x  M')
  ƛyM'∼ƛx(yx)M' = lemma∼αλ' x#ƛyM'
  z : Atom
  z = χ' (xs ++ fv (ƛ y M'))
  z∉xs : z  xs
  z∉xs = c∉xs++ys→c∉xs (lemmaχ∉ (xs ++ fv (ƛ y M')))
  z#ƛyM' : z # ƛ y M'
  z#ƛyM' = lemma∉fv→# (c∉xs++ys→c∉ys {xs = xs} (lemmaχ∉ (xs ++ fv (ƛ y M')))) 
  M⇉(yx)M' : M   y  x  M'
  M⇉(yx)M' = lemma⇉αright 
                 (subst  H  H   x  z   y  z  M') lemma(ab)(ab)M≡M (lemma⇉Equiv [ (x , z) ] (fxs z z∉xs))) 
                 (  begin
                       x  z   y  z  M'
                    ≈⟨ lemma∙comm 
                       z  x   y  z  M'
                    ∼⟨ lemma∙cancel∼α'' x#ƛyM' z#ƛyM' 
                       y  x  M'
                        )

lemma⇉βrule : {M M' N N' P : Λ}(x y : Atom)
         ƛ x M  ƛ y M' 
         N  N'
         M' [ y  N' ] ∼α P
         Σ Λ  M″  ƛ x M  ƛ x M″ × M″ [ x  N' ] ∼α P) 
lemma⇉βrule {M} {M'} {N} {N'} {P} x y ƛxM⇉ƛyM' N⇉N' M'[y≔N']∼P 
  =   y  x  M'                              ,
     lemma⇉αright  ƛxM⇉ƛyM' (lemma∼αλ' x#ƛyM')  , 
     (  begin
          ( y  x  M') [ x  N' ]
        ≈⟨  cong  H  H [ x  N' ]) (lemma∙comm {y} {x} {M'})  
          ( x  y  M') [ x  N' ]
        ∼⟨ lemmaSwapSubstVar' x y N' M' x#ƛyM'  
          M' [ y  N' ]
        ∼⟨ M'[y≔N']∼P   
          P
            ) 
  where
  x#ƛyM' : x # ƛ y M'
  x#ƛyM' = lemma⇉# #ƛ≡ ƛxM⇉ƛyM'
\end{code}

\begin{code}
P⇉[] : {N N' : Λ}(x : Atom)  Λ  Set
P⇉[] {N} {N'} x M = {M' : Λ}  M  M'  N  N'  M [ x  N ]  M' [ x  N' ]

αCompP⇉[] : {N N' : Λ}(x : Atom)  αCompatiblePred (P⇉[] {N} {N'} x)
αCompP⇉[] {N} {N'} x {M} {P} M∼P P⇉[]M {M'} P⇉M' N⇉N' 
  = subst  H  H  (M' [ x  N' ])) (lemmaSubst1 N x M∼P) (P⇉[]M (lemma⇉αleft M∼P P⇉M') N⇉N')

lemma⇉Subst : {N N' : Λ}(x : Atom)(M : Λ)  P⇉[] {N} {N'} x M
lemma⇉Subst {N} {N'} x M 
  = TermαPrimInd2  (P⇉[] {N} {N'} x) 
                   (x  fv N ++ fv N')
                   (αCompP⇉[] {N} {N'} x) 
                   lemmav 
                   lemma· 
                   lemmaƛ 
                   M
  where
  lemmav : (a : )  P⇉[] {N} {N'} x (v a)
  lemmav a (⇉v .a) N⇉N' with x ≟ₐ a
  ... | yes  _ = N⇉N'
  ... | no   _ = ⇉v a
  lemma· : (P Q : Λ) 
     P⇉[] {N} {N'} x P 
     P⇉[] {N} {N'} x Q 
     ((c : )  c  x  fv N ++ fv N'  c ∉b P · Q) 
     P⇉[] {N} {N'} x (P · Q)
  lemma· P Q hiP hiQ f∉ .{P' · Q'} 
         (⇉· .{P} {P'} .{Q} {Q'} P⇉P' Q⇉Q') 
         N⇉N' 
    = ⇉· (hiP P⇉P' N⇉N') (hiQ Q⇉Q' N⇉N')
  lemma· (ƛ .y P) Q hiƛyP hiQ f∉ {M'} 
         (⇉β .{P} {P'} .{Q} {Q'} .{M'} y z (⇉ƛ xs ∀w∉xs(yw)P⇉(zw)P') Q⇉Q' P'[z≔Q']∼M') 
         N⇉N' 
    with lemma⇉βrule y z (⇉ƛ xs ∀w∉xs(yw)P⇉(zw)P') Q⇉Q' P'[z≔Q']∼M'
  ... | P″ , ƛyP⇉ƛyP″ , P″[y≔N']∼M'
    = lemma⇉αleft
            (  begin
                 ((ƛ y P) · Q) [ x  N ]
               ≈⟨ refl 
                 (ƛ y P) [ x  N ] · Q [ x  N ] 
               ∼⟨ ∼α· (lemmaƛ∼[] P y∉x∷fvN) ρ 
                 (ƛ y (P [ x  N ])) · Q [ x  N ]
                  )        
            (⇉β  {P [ x  N ]} {P″ [ x  N' ]} 
                 {Q [ x  N ]} {Q' [ x  N' ]} 
                 {M' [ x  N' ]} y y 
                 (lemma⇉αleft  (  begin
                                    ƛ y (P [ x  N ])
                                  ∼⟨ σ (lemmaƛ∼[] P y∉x∷fvN) 
                                    (ƛ y P) [ x  N ]
                                                      ) 
                               (lemma⇉αright  (hiƛyP ƛyP⇉ƛyP″ N⇉N') 
                                              (  begin
                                                   (ƛ y P″) [ x  N' ]
                                                 ∼⟨ lemmaƛ∼[] P″ y∉x∷fvN' 
                                                   ƛ y (P″ [ x  N' ])
                                                                       ))) 
                 (hiQ Q⇉Q' N⇉N') 
                 (  begin
                      (P″ [ x  N' ]) [ y  Q' [ x  N' ] ]
                    ∼⟨ σ (lemmaSubstComposition Q' P″ y∉x∷fvN') 
                      (P″ [ y  Q' ]) [ x  N' ] 
                    ≈⟨ lemmaSubst1 N' x P″[y≔N']∼M' 
                      M' [ x  N' ]
                                                             )            ) 
    where
    y∉x∷fvN++fvN' : y  x  (fv N ++ fv N')
    y∉x∷fvN++fvN' y∈x∷fvN++fvN' with f∉ y y∈x∷fvN++fvN'
    ... | ∉b· (∉bƛ y≢y _) _ = ⊥-elim (y≢y refl)
    y∉x∷fvN : y  x  fv N 
    y∉x∷fvN = c∉x∷xs++ys→c∉x∷xs y∉x∷fvN++fvN'
    y∉x∷fvN' : y  x  fv N'
    y∉x∷fvN' = c∉x∷xs++ys→c∉x∷ys {xs = fv N} y∉x∷fvN++fvN'
  lemmaƛ : (P : Λ) (b : ) 
     P⇉[] {N} {N'} x P 
     ((c : )  c  x  fv N ++ fv N'  c ∉b ƛ b P) 
     P⇉[] {N} {N'} x (ƛ b P)
  lemmaƛ P b hiP f∉ {Q} ⇉ƛbP⇉Q N⇉N'
    with lemma⇉ƛrule ⇉ƛbP⇉Q
  ... | P″ , P⇉P″ ,  ƛbP⇉ƛbP″ , Q∼ƛbP″
    = lemma⇉αright  (lemma⇉αleft (lemmaƛ∼[] P b∉x∷fvN) (lemma⇉ƛpres {b} (hiP P⇉P″ N⇉N'))) 
                    (  begin
                         ƛ b (P″ [ x  N' ]) 
                       ∼⟨ σ (lemmaƛ∼[] P″ b∉x∷fvN')    
                         (ƛ b P″)  [ x  N' ]
                       ≈⟨ lemmaSubst1 N' x (σ Q∼ƛbP″)  
                         Q         [ x  N' ]
                         )
    where
    b∉x∷fvN++fvN' : b  x  (fv N ++ fv N')
    b∉x∷fvN++fvN' b∈x∷fvN++fvN' with f∉ b b∈x∷fvN++fvN'
    ... | ∉bƛ b≢b _ = ⊥-elim (b≢b refl)
    b∉x∷fvN : b  x  fv N 
    b∉x∷fvN = c∉x∷xs++ys→c∉x∷xs b∉x∷fvN++fvN'
    b∉x∷fvN' : b  x  fv N'
    b∉x∷fvN' = c∉x∷xs++ys→c∉x∷ys {xs = fv N} b∉x∷fvN++fvN'
\end{code}
    
-- lemma⇉Subst : {N N' : Λ}(x : Atom)(M : Λ){M' : Λ} → M ⇉ M' → N ⇉ N' → M [ x ≔ N ] ⇉ M' [ x ≔ N' ]
-- lemma⇉Subst {N} {N'} x (v y)         (⇉v .y)                         N⇉N'      
--   with x ≟ₐ y
-- ... | yes  _ = N⇉N'
-- ... | no   _ = ⇉v y
-- lemma⇉Subst x (M · P)       (⇉· M⇉M' P⇉P') N⇉N'
--   = ⇉· (lemma⇉Subst x M M⇉M' N⇉N') (lemma⇉Subst x P P⇉P' N⇉N')
-- lemma⇉Subst {N} {N'} x (ƛ y M)       (⇉ƛ .{M} {M'} .{y} {z} xs fxs)  N⇉N'      
--   = proof
--   where 
--   ws = ((x ∷ fv N) ++ (x ∷ fv N') ++ xs ++ ocurr M ++ ocurr M')
--   w = χ' ws
--   w∉ws : w ∉ ws
--   w∉ws = χ'∉ ws
--   w#M : w # M
--   w#M = lemma∉→# (lemmaocurr (c∉xs++ys→c∉xs (c∉xs++ys→c∉ys {xs = xs} (c∉xs++ys→c∉ys {xs = x ∷ fv N'} (c∉xs++ys→c∉ys {xs = x ∷ fv N} w∉ws)))))
--   w#M' : w # M'
--   w#M' = lemma∉→# (lemmaocurr (c∉xs++ys→c∉ys {xs = ocurr M} (c∉xs++ys→c∉ys {xs = xs} (c∉xs++ys→c∉ys {xs = x ∷ fv N'} (c∉xs++ys→c∉ys {xs = x ∷ fv N} w∉ws)))))
--   w∉xs : w ∉ xs
--   w∉xs = c∉xs++ys→c∉xs (c∉xs++ys→c∉ys {xs = x ∷ fv N'} (c∉xs++ys→c∉ys {xs = x ∷ fv N} w∉ws))
--   w∉x∷fvN : w ∉ x ∷ fv N
--   w∉x∷fvN = c∉xs++ys→c∉xs w∉ws
--   w∉x∷fvN' : w ∉ x ∷ fv N'
--   w∉x∷fvN' = c∉xs++ys→c∉xs (c∉xs++ys→c∉ys {xs = x ∷ fv N} w∉ws)
--   ƛyM∼ƛw(yw)M : ƛ y M ∼α ƛ w (( y ∙ w ) M)
--   ƛyM∼ƛw(yw)M = lemma∼αλ w#M
--   ƛzM'∼ƛw(zw)M' : ƛ z M' ∼α ƛ w (( z ∙ w ) M')
--   ƛzM'∼ƛw(zw)M' = lemma∼αλ w#M'
--   ƛyM[x≔N]≡ƛw(yw)M[x≔N] :  (ƛ y M) [ x ≔ N ] ≡ (ƛ w (( y ∙ w ) M)) [ x ≔ N ]
--   ƛyM[x≔N]≡ƛw(yw)M[x≔N] = lemmaSubst1 N x ƛyM∼ƛw(yw)M
--   ƛzM'[x≔N]≡ƛw(zw)M'[x≔N] :  (ƛ z M') [ x ≔ N' ] ≡ (ƛ w (( z ∙ w ) M')) [ x ≔ N' ]
--   ƛzM'[x≔N]≡ƛw(zw)M'[x≔N] = lemmaSubst1 N' x ƛzM'∼ƛw(zw)M'
--   ƛw(yw)M[x≔N]∼ƛw((yw)M[x≔N]) : (ƛ w (( y ∙ w ) M)) [ x ≔ N ] ∼α ƛ w (((( y ∙ w ) M)) [ x ≔ N ])
--   ƛw(yw)M[x≔N]∼ƛw((yw)M[x≔N]) = lemmaƛ∼[] (( y ∙ w ) M) w∉x∷fvN
--   ƛw(zw)M'[x≔N]∼ƛw((zw)M'[x≔N]) : (ƛ w (( z ∙ w ) M')) [ x ≔ N' ] ∼α ƛ w (((( z ∙ w ) M')) [ x ≔ N' ])
--   ƛw(zw)M'[x≔N]∼ƛw((zw)M'[x≔N]) = lemmaƛ∼[] (( z ∙ w ) M') w∉x∷fvN'
--   proof' : (ƛ w (( y ∙ w ) M)) [ x ≔ N ] ⇉ (ƛ w (( z ∙ w ) M')) [ x ≔ N' ]
--   proof' = lemma⇉αleft ƛw(yw)M[x≔N]∼ƛw((yw)M[x≔N]) (lemma⇉αright (⇉ƛ ws (λ u u∉ws →  lemma⇉Equiv [ ( w , u ) ] (lemma⇉Subst x (( y ∙ w ) M) (fxs w w∉xs) N⇉N'))) (σ ƛw(zw)M'[x≔N]∼ƛw((zw)M'[x≔N])))
--   proof : ƛ y M [ x ≔ N ] ⇉ ƛ z M' [ x ≔ N' ]
--   proof = subst₂ (λ T U → T ⇉ U) (sym ƛyM[x≔N]≡ƛw(yw)M[x≔N]) (sym ƛzM'[x≔N]≡ƛw(zw)M'[x≔N]) proof'
-- lemma⇉Subst {N} {N'} x (ƛ .y P · Q)  (⇉β .{P} {P'} .{Q} {Q'} {M} y z ƛyP⇉ƛzP' Q⇉Q' P'[z≔Q']∼M) N⇉N' 
--   = proof
--   where
--   us = (x ∷ fv N) ++ ocurr P
--   u = χ' us
--   u∉us = χ'∉ us
--   u∉x∷fvN : u ∉ x ∷ fv N
--   u∉x∷fvN = c∉xs++ys→c∉xs u∉us
--   ws = (x ∷ fv N') ++ ocurr P'
--   w = χ' ws
--   w∉ws = χ'∉ ws
--   u#P : u # P
--   u#P = lemma∉→# (lemmaocurr  (c∉xs++ys→c∉ys {xs = x ∷ fv N} u∉us))
--   w#P' : w # P'
--   w#P' = lemma∉→# (lemmaocurr  (c∉xs++ys→c∉ys {xs = x ∷ fv N'} w∉ws))
--   w∉x∷fvN' : w ∉ x ∷ fv N'
--   w∉x∷fvN' = c∉xs++ys→c∉xs w∉ws
--   ƛyP∼ƛu(yu)P' : ƛ y P ∼α ƛ u (( y ∙ u ) P)
--   ƛyP∼ƛu(yu)P' = lemma∼αλ u#P
--   ƛyP[x≔N]∼ƛu((yu)P[x≔N]) : ƛ y P [ x ≔ N ] ∼α ƛ u ((( y ∙ u ) P) [ x ≔ N ])
--   ƛyP[x≔N]∼ƛu((yu)P[x≔N]) =  begin
--                                  ƛ y P [ x ≔ N ]
--                                ≈⟨ lemmaSubst1 N x ƛyP∼ƛu(yu)P'  ⟩
--                                  (ƛ u (( y ∙ u ) P)) [ x ≔ N ]
--                                ∼⟨ lemmaƛ∼[] (( y ∙ u ) P) u∉x∷fvN ⟩
--                                  ƛ u ((( y ∙ u ) P) [ x ≔ N ])
--                                ∎
--   ƛzP'∼ƛw(zw)P' : ƛ z P' ∼α ƛ w (( z ∙ w ) P')
--   ƛzP'∼ƛw(zw)P' = lemma∼αλ w#P'
--   ƛzP'[x≔N']∼ƛw((zw)P'[x≔N]) : ƛ z P' [ x ≔ N' ] ∼α ƛ w ((( z ∙ w ) P') [ x ≔ N' ])
--   ƛzP'[x≔N']∼ƛw((zw)P'[x≔N]) =  begin
--                                     ƛ z P' [ x ≔ N' ]
--                                   ≈⟨ lemmaSubst1 N' x ƛzP'∼ƛw(zw)P'  ⟩
--                                    (ƛ w (( z ∙ w ) P')) [ x ≔ N' ]
--                                   ∼⟨ lemmaƛ∼[] (( z ∙ w ) P') w∉x∷fvN' ⟩                                   
--                                     ƛ w ((( z ∙ w ) P') [ x ≔ N' ])
--                                   ∎
--   hiƛyP : ƛ y P [ x ≔ N ] ⇉ ƛ z P' [ x ≔ N' ]
--   hiƛyP = lemma⇉Subst x (ƛ y P) ƛyP⇉ƛzP' N⇉N'
--   ƛu((yu)P[x≔N])⇉ƛw((zw)P'[x≔N']) : ƛ u ((( y ∙ u ) P) [ x ≔ N ]) ⇉ ƛ w ((( z ∙ w ) P') [ x ≔ N' ])
--   ƛu((yu)P[x≔N])⇉ƛw((zw)P'[x≔N']) = lemma⇉αleft (σ ƛyP[x≔N]∼ƛu((yu)P[x≔N])) (lemma⇉αright hiƛyP ƛzP'[x≔N']∼ƛw((zw)P'[x≔N]))
--   hiQ : Q [ x ≔ N ] ⇉ Q' [ x ≔ N' ]
--   hiQ = lemma⇉Subst x Q Q⇉Q' N⇉N'
--   proof' : ƛ u ((( y ∙ u ) P) [ x ≔ N ]) · Q [ x ≔ N ] ⇉ (( z ∙ w ) P') [ x ≔ N' ] [ w ≔ Q' [ x ≔ N' ] ]
--   proof' = ⇉β u w ƛu((yu)P[x≔N])⇉ƛw((zw)P'[x≔N']) hiQ ρ
--   M[x≔N']∼α((zw)P')[x≔N'][w≔Q'[x≔N']] : M [ x ≔ N' ] ∼α (( z ∙ w ) P') [ x ≔ N' ] [ w ≔ Q' [ x ≔ N' ] ]
--   M[x≔N']∼α((zw)P')[x≔N'][w≔Q'[x≔N']]
--     = begin
--       M [ x ≔ N' ]
--     ≈⟨ lemmaSubst1 N' x (σ P'[z≔Q']∼M) ⟩
--       P' [ z ≔ Q' ] [ x ≔ N' ]
--     ≈⟨ lemmaSubst1 N' x (σ (lemmaSwapSubstVar w z Q' P' w#P')) ⟩
--       (( w ∙ z ) P') [ w ≔ Q' ] [ x ≔ N' ]
--     ≈⟨ cong (λ H → H [ w ≔ Q' ] [ x ≔ N' ]) (lemma∙comm {w} {z} {P'}) ⟩
--       (( z ∙ w ) P') [ w ≔ Q' ] [ x ≔ N' ]
--     ∼⟨ lemmaSubstComposition {w} {x} {N'} Q' (( z ∙ w ) P') w∉x∷fvN' ⟩
--       (( z ∙ w ) P') [ x ≔ N' ] [ w ≔ Q' [ x ≔ N' ] ]
--     ∎
--   proof : (ƛ y P · Q) [ x ≔ N ] ⇉ M [ x ≔ N' ]
--   proof = lemma⇉αleft (∼α· ƛyP[x≔N]∼ƛu((yu)P[x≔N]) ρ) (lemma⇉αright proof' (σ M[x≔N']∼α((zw)P')[x≔N'][w≔Q'[x≔N']]))

-- corollary⇉Equiv : (M N : Λ)(x y z : Atom) → y ∉ₜ M → z ∉ₜ M  → ( x ∙ y ) M ⇉ N → ( x ∙ z ) M ⇉ ( y ∙ z ) N
-- corollary⇉Equiv _ N _ y z y∉S z∉S (xy)M⇉N 
--   = subst  (λ T → T ⇉ ( y ∙ z ) N) 
--            (lemma∙cancel z∉S y∉S) 
--            (lemma⇉Equiv [ ( y , z ) ] (xy)M⇉N)

-- diam⇉ :  {M N P : Λ} → M ⇉ N → M ⇉ P
--          → ∃ (λ Q → N ⇉ Q × P ⇉ Q)
-- diam⇉  (⇉v x) (⇉v .x)
--   = v x , ⇉v x , ⇉v x 
-- diam⇉  {ƛ x M} {ƛ y N} {ƛ z P} 
--        (⇉ƛ xs fxs) (⇉ƛ ys fys)
--   =  ƛ u R                                                                                    , 
--      ⇉ƛ zs (λ w w∉zs → corollary⇉Equiv N R y u w (∀w∉zs→w∉N u∉zs) (∀w∉zs→w∉N w∉zs) (yu)N⇉R)  ,
--      ⇉ƛ zs (λ w w∉zs → corollary⇉Equiv P R z u w (∀w∉zs→w∉P u∉zs) (∀w∉zs→w∉P w∉zs) (zu)P⇉R) 
--   where
--   zs = (xs ++ ys) ++ (ocurr N ++ ocurr P)
--   u : Atom
--   u = χ' zs
--   u∉zs : u ∉ zs
--   u∉zs = χ'∉ zs
--   u∉xs++ys : u ∉ xs ++ ys
--   u∉xs++ys = c∉xs++ys→c∉xs {u} {xs ++ ys} u∉zs
--   ∀w∉zs→w∉N : {w : Atom} → w ∉ zs → w ∉ₜ N
--   ∀w∉zs→w∉N {w} w∉zs = lemmaocurr (c∉xs++ys→c∉xs {w} {ocurr N} (c∉xs++ys→c∉ys {w} {xs ++ ys} w∉zs))
--   ∀w∉zs→w∉P : {w : Atom} → w ∉ zs → w ∉ₜ P
--   ∀w∉zs→w∉P {w} w∉zs = lemmaocurr (c∉xs++ys→c∉ys {w} {ocurr N} (c∉xs++ys→c∉ys {w} {xs ++ ys} w∉zs))
--   hi : (w : Atom) → (w ∉ xs ++ ys) → ∃ (λ R → ( y ∙ w ) N ⇉ R × ( z ∙ w ) P ⇉ R)
--   hi w w∉xs++ys = diam⇉ (fxs w (c∉xs++ys→c∉xs w∉xs++ys)) (fys w (c∉xs++ys→c∉ys {w} {xs} w∉xs++ys)) -- induccion en la relación !
--   R : Λ 
--   R = proj₁ (hi u u∉xs++ys)
--   (yu)N⇉R : ( y ∙ u ) N ⇉ R
--   (yu)N⇉R = proj₁ (proj₂ (hi u u∉xs++ys))
--   (zu)P⇉R : ( z ∙ u ) P ⇉ R
--   (zu)P⇉R = proj₂ (proj₂ (hi u u∉xs++ys))
-- diam⇉  {ƛ x M · N} {P} {Q} 
--        (⇉β .{M} {P'} .{N} {P''} .x y (⇉ƛ xs fxs) N⇉P'' P'[y≔P'']∼P) 
--        (⇉β .{M} {Q'} .{N} {Q''} .x z (⇉ƛ ys fys) N⇉Q'' Q'[z≔Q'']∼Q)
--   =  R' [ u ≔ R'' ]                                                                 ,
--      lemma⇉αleft (σ P'[y≔P'']∼P)
--                  (lemma⇉αright  P'[y≔P'']⇉(yu)R'[y≔R''] (yu)R'[y≔R'']∼R'[u≔R''])  ,
--      lemma⇉αleft (σ Q'[z≔Q'']∼Q)
--                  (lemma⇉αright  Q'[z≔Q'']⇉(zu)R'[z≔R''] (zu)R'[z≔R'']∼R'[u≔R''])
--   where
--   zs = (y ∷ z ∷ ocurr P' ++ ocurr Q') ++ (xs ++ ys)
--   u : Atom
--   u = χ' zs
--   u∉zs : u ∉ zs
--   u∉zs = χ'∉ zs
--   u∉xs++ys : u ∉ xs ++ ys
--   u∉xs++ys = c∉xs++ys→c∉ys {xs = y ∷ z ∷ ocurr P' ++ ocurr Q'} u∉zs
--   hiu : ∃ (λ R → ( y ∙ u ) P' ⇉ R × ( z ∙ u ) Q' ⇉ R)
--   hiu = diam⇉ (fxs u (c∉xs++ys→c∉xs u∉xs++ys)) (fys u (c∉xs++ys→c∉ys {u} {xs} u∉xs++ys))
--   R' : Λ
--   R' = proj₁ hiu
--   (yu)P'⇉R' : ( y ∙ u ) P' ⇉  R'
--   (yu)P'⇉R' = (proj₁ (proj₂ hiu))
--   (zu)Q'⇉R' : ( z ∙ u ) Q' ⇉  R'
--   (zu)Q'⇉R' = (proj₂ (proj₂ hiu))
--   u≢y : u ≢ y
--   u≢y u≡y = ⊥-elim (u∉zs (here u≡y))
--   u#P' : u # P'
--   u#P' = lemma∉→# (lemmaocurr (c∉xs++ys→c∉xs (d∉ab∷xs→d∉xs (c∉xs++ys→c∉xs u∉zs)))) 
--   u#Q' : u # Q'
--   u#Q' = lemma∉→# (lemmaocurr (c∉xs++ys→c∉ys {xs = ocurr P'} (d∉ab∷xs→d∉xs (c∉xs++ys→c∉xs u∉zs)))) 
--   y#(yu)P' : y # ( y ∙ u ) P'
--   y#(yu)P' = lemma#swap u#P'
--   z#(zu)Q' : z # ( z ∙ u ) Q'
--   z#(zu)Q' = lemma#swap u#Q'
--   P'⇉(yu)R' : P' ⇉ ( y ∙ u ) R'
--   P'⇉(yu)R' = subst (λ S → S ⇉ ( y ∙ u ) R') lemma(ab)(ab)M≡M (lemma⇉Equiv [ ( y , u ) ] (yu)P'⇉R')
--   Q'⇉(zu)R' : Q' ⇉ ( z ∙ u ) R'
--   Q'⇉(zu)R' = subst (λ S → S ⇉ ( z ∙ u ) R') lemma(ab)(ab)M≡M (lemma⇉Equiv [ ( z , u ) ] (zu)Q'⇉R')
--   hi : ∃ (λ R → P'' ⇉ R × Q'' ⇉ R)
--   hi  = diam⇉ N⇉P'' N⇉Q''
--   R'' : Λ
--   R'' = proj₁ hi
--   P''⇉R'' : P'' ⇉ R''
--   P''⇉R'' = proj₁ (proj₂ hi)
--   Q''⇉R'' : Q'' ⇉ R''
--   Q''⇉R'' = proj₂ (proj₂ hi)
--   P'[y≔P'']⇉(yu)R'[y≔R''] : P' [ y ≔ P'' ] ⇉ (( y ∙ u ) R') [ y ≔ R'' ]
--   P'[y≔P'']⇉(yu)R'[y≔R''] = lemma⇉Subst y P'  P'⇉(yu)R' P''⇉R''
--   Q'[z≔Q'']⇉(zu)R'[z≔R''] : Q' [ z ≔ Q'' ] ⇉ (( z ∙ u ) R') [ z ≔ R'' ]
--   Q'[z≔Q'']⇉(zu)R'[z≔R''] = lemma⇉Subst z Q'  Q'⇉(zu)R' Q''⇉R''
--   (yu)R'[y≔R'']∼R'[u≔R''] : (( y ∙ u ) R') [ y ≔ R'' ] ∼α R' [ u ≔ R'' ]
--   (yu)R'[y≔R'']∼R'[u≔R''] = lemmaSwapSubstVar y u  R'' R' (lemma⇉# y#(yu)P' (yu)P'⇉R')
--   (zu)R'[z≔R'']∼R'[u≔R''] : (( z ∙ u ) R') [ z ≔ R'' ] ∼α R' [ u ≔ R'' ]
--   (zu)R'[z≔R'']∼R'[u≔R''] = lemmaSwapSubstVar z u  R'' R' (lemma⇉# z#(zu)Q' (zu)Q'⇉R')
-- diam⇉  {M · M'} {N · N'} {P · P'} (⇉· M⇉N M'⇉N') (⇉· M⇉P M'⇉P')
--   = Q · R , ⇉· N⇉Q  N'⇉R , ⇉· P⇉Q P'⇉R 
--   where
--   hi1 : ∃ (λ Q → N ⇉ Q × P ⇉ Q)
--   hi1 = diam⇉ M⇉N M⇉P
--   Q : Λ
--   Q = proj₁ hi1
--   N⇉Q : N ⇉ Q
--   N⇉Q = proj₁ (proj₂ hi1)
--   P⇉Q : P ⇉ Q
--   P⇉Q = proj₂ (proj₂ hi1)
--   hi2 : ∃ (λ R → N' ⇉ R × P' ⇉ R)
--   hi2 = diam⇉ M'⇉N' M'⇉P'
--   R : Λ
--   R = proj₁ hi2
--   N'⇉R : N' ⇉ R
--   N'⇉R = proj₁ (proj₂ hi2)
--   P'⇉R : P' ⇉ R
--   P'⇉R = proj₂ (proj₂ hi2)
-- diam⇉  {ƛ x M · N} {P} {ƛ z Q' · Q''} 
--        (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
--        (⇉· ƛxM⇉λzQ' N⇉Q'') 
--   =  R' [ u ≔ R'' ]               ,
--      P⇉R'[u≔R'']                  ,
--      ⇉β z u ƛzQ'⇉ƛuR' Q''⇉R'' ρ
--   where
--   hi : ∃ (λ R → P'' ⇉ R × Q'' ⇉ R)
--   hi  = diam⇉ N⇉P'' N⇉Q''
--   R'' : Λ
--   R'' = proj₁ hi
--   P''⇉R'' : P'' ⇉ R''
--   P''⇉R'' = proj₁ (proj₂ hi)
--   Q''⇉R'' : Q'' ⇉ R''
--   Q''⇉R'' = proj₂ (proj₂ hi)
--   hi2 : ∃ (λ R → ƛ y P' ⇉ R × ƛ z Q' ⇉ R)
--   hi2 = diam⇉ ƛxM⇉λyP' ƛxM⇉λzQ'
--   R : Λ
--   R = proj₁ hi2
--   u : Atom
--   u = proj₁ (lemma⇉ƛ (proj₁ (proj₂ hi2)))
--   R' : Λ
--   R' = proj₁ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2))))
--   us : List Atom
--   us = proj₁ (proj₂ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2)))))
--   R≡ƛuR' : R ≡ ƛ u R'
--   R≡ƛuR' = proj₁ (proj₂ (proj₂ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2))))))
--   ∀w∉us→(yw)P'⇉(uw)R' : (w : Atom) → w ∉ us → ( y ∙ w ) P' ⇉ ( u ∙ w ) R'
--   ∀w∉us→(yw)P'⇉(uw)R' = proj₂ (proj₂ (proj₂ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2))))))
--   w = χ' (us ++ fv R')
--   w∉ = χ'∉ (us ++ fv R')
--   w∉us : w ∉ us
--   w∉us = c∉xs++ys→c∉xs w∉
--   w#R' : w # R'
--   w#R' = lemma∉fv→# (c∉xs++ys→c∉ys {xs = us} w∉)
--   ƛyP'⇉ƛuR' : ƛ y P' ⇉ ƛ u R'
--   ƛyP'⇉ƛuR' = subst (λ H → ƛ y P' ⇉ H) R≡ƛuR' (proj₁ (proj₂ hi2))
--   y#ƛuR' : y # ƛ u R'
--   y#ƛuR' = lemma⇉# #ƛ≡ ƛyP'⇉ƛuR'
--   (yw)(uw)R'∼(uy)R' : ( y ∙ w ) (( u ∙ w ) R') ∼α ( u ∙ y ) R'
--   (yw)(uw)R'∼(uy)R'
--     =  begin
--          ( y ∙ w ) ( u ∙ w ) R'
--        ≈⟨ lemma∙comm ⟩
--          ( w ∙ y ) ( u ∙ w ) R'
--        ∼⟨ lemma∙cancel∼α' y#ƛuR' w#R' ⟩
--          ( u ∙ y ) R'
--        ∎        
--   P'⇉(uy)R' : P' ⇉ ( u ∙ y ) R'
--   P'⇉(uy)R' = lemma⇉αright (subst (λ H → H ⇉ ( y ∙ w ) ( u ∙ w ) R') (lemma(ab)(ab)M≡M {y} {w} {P'}) (lemma⇉Equiv [ (y , w) ] (∀w∉us→(yw)P'⇉(uw)R' w w∉us))) (yw)(uw)R'∼(uy)R'
--   ƛzQ'⇉ƛuR' : ƛ z Q' ⇉ ƛ u R'
--   ƛzQ'⇉ƛuR' = subst (λ H → ƛ z Q' ⇉ H) R≡ƛuR' (proj₂ (proj₂ hi2))
--   P'[y≔P'']⇉(uy)R'[y≔R''] : P' [ y ≔ P'' ] ⇉ (( y ∙ u ) R' ) [ y ≔ R'' ]
--   P'[y≔P'']⇉(uy)R'[y≔R''] = subst (λ H → P' [ y ≔ P'' ] ⇉ H [ y ≔ R'' ]) (lemma∙comm {u} {y} {R'}) (lemma⇉Subst y P' P'⇉(uy)R' P''⇉R'')
--   P⇉R'[u≔R''] : P ⇉ R' [ u ≔ R'' ]
--   P⇉R'[u≔R''] = lemma⇉αright (lemma⇉αleft (σ P'[y≔P'']∼P) P'[y≔P'']⇉(uy)R'[y≔R'']) (lemmaSwapSubstVar' y u R'' R' y#ƛuR')
-- diam⇉  {ƛ x M · N} {ƛ z Q' · Q''} {P}
--        (⇉· ƛxM⇉λzQ' N⇉Q'') 
--        (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
--   =  R' [ u ≔ R'' ]               ,
--      ⇉β z u ƛzQ'⇉ƛuR' Q''⇉R'' ρ   ,
--      P⇉R'[u≔R'']
--   where
--   hi : ∃ (λ R → P'' ⇉ R × Q'' ⇉ R)
--   hi  = diam⇉ N⇉P'' N⇉Q''
--   R'' : Λ
--   R'' = proj₁ hi
--   P''⇉R'' : P'' ⇉ R''
--   P''⇉R'' = proj₁ (proj₂ hi)
--   Q''⇉R'' : Q'' ⇉ R''
--   Q''⇉R'' = proj₂ (proj₂ hi)
--   hi2 : ∃ (λ R → ƛ y P' ⇉ R × ƛ z Q' ⇉ R)
--   hi2 = diam⇉ ƛxM⇉λyP' ƛxM⇉λzQ'
--   R : Λ
--   R = proj₁ hi2
--   u : Atom
--   u = proj₁ (lemma⇉ƛ (proj₁ (proj₂ hi2)))
--   R' : Λ
--   R' = proj₁ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2))))
--   us : List Atom
--   us = proj₁ (proj₂ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2)))))
--   R≡ƛuR' : R ≡ ƛ u R'
--   R≡ƛuR' = proj₁ (proj₂ (proj₂ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2))))))
--   ∀w∉us→(yw)P'⇉(uw)R' : (w : Atom) → w ∉ us → ( y ∙ w ) P' ⇉ ( u ∙ w ) R'
--   ∀w∉us→(yw)P'⇉(uw)R' = proj₂ (proj₂ (proj₂ (proj₂ (lemma⇉ƛ (proj₁ (proj₂ hi2))))))
--   w = χ' (us ++ fv R')
--   w∉ = χ'∉ (us ++ fv R')
--   w∉us : w ∉ us
--   w∉us = c∉xs++ys→c∉xs w∉
--   w#R' : w # R'
--   w#R' = lemma∉fv→# (c∉xs++ys→c∉ys {xs = us} w∉)
--   ƛyP'⇉ƛuR' : ƛ y P' ⇉ ƛ u R'
--   ƛyP'⇉ƛuR' = subst (λ H → ƛ y P' ⇉ H) R≡ƛuR' (proj₁ (proj₂ hi2))
--   y#ƛuR' : y # ƛ u R'
--   y#ƛuR' = lemma⇉# #ƛ≡ ƛyP'⇉ƛuR'
--   (yw)(uw)R'∼(uy)R' : ( y ∙ w ) (( u ∙ w ) R') ∼α ( u ∙ y ) R'
--   (yw)(uw)R'∼(uy)R'
--     =  begin
--          ( y ∙ w ) ( u ∙ w ) R'
--        ≈⟨ lemma∙comm ⟩
--          ( w ∙ y ) ( u ∙ w ) R'
--        ∼⟨ lemma∙cancel∼α' y#ƛuR' w#R' ⟩
--          ( u ∙ y ) R'
--        ∎        
--   P'⇉(uy)R' : P' ⇉ ( u ∙ y ) R'
--   P'⇉(uy)R' = lemma⇉αright (subst (λ H → H ⇉ ( y ∙ w ) ( u ∙ w ) R') (lemma(ab)(ab)M≡M {y} {w} {P'}) (lemma⇉Equiv [ (y , w) ] (∀w∉us→(yw)P'⇉(uw)R' w w∉us))) (yw)(uw)R'∼(uy)R'
--   ƛzQ'⇉ƛuR' : ƛ z Q' ⇉ ƛ u R'
--   ƛzQ'⇉ƛuR' = subst (λ H → ƛ z Q' ⇉ H) R≡ƛuR' (proj₂ (proj₂ hi2))
--   P'[y≔P'']⇉(uy)R'[y≔R''] : P' [ y ≔ P'' ] ⇉ (( y ∙ u ) R' ) [ y ≔ R'' ]
--   P'[y≔P'']⇉(uy)R'[y≔R''] = subst (λ H → P' [ y ≔ P'' ] ⇉ H [ y ≔ R'' ]) (lemma∙comm {u} {y} {R'}) (lemma⇉Subst y P' P'⇉(uy)R' P''⇉R'')
--   P⇉R'[u≔R''] : P ⇉ R' [ u ≔ R'' ]
--   P⇉R'[u≔R''] = lemma⇉αright (lemma⇉αleft (σ P'[y≔P'']∼P) P'[y≔P'']⇉(uy)R'[y≔R'']) (lemmaSwapSubstVar' y u R'' R' y#ƛuR')
-- diam⇉  {ƛ x M · N} {P} {v _ · Q''} 
--        (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
--        (⇉· () N⇉Q'') 
-- diam⇉  {ƛ x M · N} {P} {(_ · _) · Q''} 
--        (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
--        (⇉· () N⇉Q'') 
-- diam⇉  {ƛ x M · N} {v _ · Q''} {P}
--        (⇉· () N⇉Q'') 
--        (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
-- diam⇉  {ƛ x M · N} {(_ · _) · Q''} {P}
--        (⇉· () N⇉Q'') 
--        (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
\end{code}

\begin{code}
diam⇉ :  {M N P : Λ}  M  N  M  P
            Q  N  Q × P  Q)
diam⇉  (⇉v x) (⇉v .x)
  = v x , ⇉v x , ⇉v x
diam⇉  {M · M'} {N · N'} {P · P'} 
       (⇉· M⇉N M'⇉N') (⇉· M⇉P M'⇉P')
  = Q · R , ⇉· N⇉Q  N'⇉R , ⇉· P⇉Q P'⇉R
    where
  hi1 :   Q  N  Q × P  Q)
  hi1 = diam⇉ M⇉N M⇉P
  Q : Λ
  Q = proj₁ hi1
  N⇉Q : N  Q
  N⇉Q = proj₁ (proj₂ hi1)
  P⇉Q : P  Q
  P⇉Q = proj₂ (proj₂ hi1)
  hi2 :   R  N'  R × P'  R)
  hi2 = diam⇉ M'⇉N' M'⇉P'
  R : Λ
  R = proj₁ hi2
  N'⇉R : N'  R
  N'⇉R = proj₁ (proj₂ hi2)
  P'⇉R : P'  R
  P'⇉R = proj₂ (proj₂ hi2)
diam⇉  {ƛ x M} {ƛ y N} {ƛ z P} 
       (⇉ƛ xs fxs) (⇉ƛ ys fys)
  with  lemma⇉ƛrule (⇉ƛ xs fxs) 
     |  lemma⇉ƛrule (⇉ƛ ys fys)
...  |  N' , M⇉N' , _ , ƛyN~ƛxN' 
     |  P' , M⇉P' , _ , ƛzP~ƛxP'
  with  diam⇉ M⇉N' M⇉P'
...  |  Q , N'⇉Q , P'⇉Q
  = ƛ x Q , lemma⇉αleft ƛyN~ƛxN' (lemma⇉ƛpres N'⇉Q) , lemma⇉αleft ƛzP~ƛxP' (lemma⇉ƛpres P'⇉Q)
diam⇉  {ƛ x M · N} {P} {Q} 
       (⇉β .{M} {P'} .{N} {P''} .x y (⇉ƛ xs fxs) N⇉P'' P'[y≔P'']∼P) 
       (⇉β .{M} {Q'} .{N} {Q''} .x z (⇉ƛ ys fys) N⇉Q'' Q'[z≔Q'']∼Q)
  with  lemma⇉βrule x y (⇉ƛ xs fxs) N⇉P'' P'[y≔P'']∼P
     |  lemma⇉βrule x z (⇉ƛ ys fys) N⇉Q'' Q'[z≔Q'']∼Q  
...  |  P‴ , ƛxM⇉ƛxP‴ , M‴[x≔P'']~P
     |  Q‴ , ƛxM⇉ƛxQ‴ , Q‴[x≔P'']~Q
  with  diam⇉ ƛxM⇉ƛxP‴ ƛxM⇉ƛxQ‴
     |  diam⇉  N⇉P'' N⇉Q''
...  |  R , ƛxP‴⇉R , ƛxQ‴⇉R
     |  S , P''⇉S  , Q''⇉S
  with  lemma⇉ƛrule ƛxP‴⇉R
     |  lemma⇉ƛrule ƛxQ‴⇉R
...  |  R' , P‴⇉R' , ƛxP‴⇉ƛxR' , R~ƛxR'
     |  R″ , Q‴⇉R″ , ƛxQ‴⇉ƛxR″ , R~ƛxR″ 
  with  lemma∼αƛ← (τ (σ R~ƛxR') R~ƛxR″)
...  |  R'∼R″ 
  =  R' [ x  S ]                                                 , 
     lemma⇉αleft (σ M‴[x≔P'']~P) (lemma⇉Subst x P‴ P‴⇉R' P''⇉S )  , 
     lemma⇉αleft (σ Q‴[x≔P'']~Q) (lemma⇉Subst x Q‴ (lemma⇉αright Q‴⇉R″ (σ R'∼R″)) Q''⇉S ) 
diam⇉  {ƛ x M · N} {P} {ƛ z Q' · Q''} 
       (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
       (⇉· ƛxM⇉λzQ' N⇉Q'') 
  with  lemma⇉βrule x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P
     |  lemma⇉ƛrule ƛxM⇉λzQ'
...  |  P‴ , ƛxM⇉ƛxP‴ , P‴[x≔P'']~P
     |  Q‴ , M⇉Q‴ , ƛxM⇉ƛxQ‴ , ƛzQ'~ƛxQ‴
  with  diam⇉ ƛxM⇉ƛxP‴ ƛxM⇉ƛxQ‴
     |  diam⇉ N⇉P'' N⇉Q''
...  |  Q , ƛxP‴⇉Q , ƛxQ‴⇉Q
     |  R , P''⇉R  , Q''⇉R
  with  lemma⇉ƛrule ƛxP‴⇉Q
     |  lemma⇉ƛrule ƛxQ‴⇉Q
...  |  S' , P‴⇉S' , ƛxP‴⇉ƛxS' , Q~ƛxS'
     |  S″ , Q‴⇉S″ , ƛxQ‴⇉ƛxS″ , Q~ƛxS″ 
  with  lemma∼αƛ← (τ (σ Q~ƛxS') Q~ƛxS″)
...  |  S'∼S″ 
  =  S' [ x  R ]                                                  ,
     lemma⇉αleft  (σ P‴[x≔P'']~P) (lemma⇉Subst x P‴ P‴⇉S' P''⇉R)   ,
     lemma⇉αleft  (∼α· ƛzQ'~ƛxQ‴ ρ) 
                  (⇉β x x (lemma⇉αright ƛxQ‴⇉ƛxS″ (lemma∼αƛ (σ S'∼S″))) Q''⇉R ρ) 
diam⇉  {ƛ x M · N} {ƛ z Q' · Q''} {P}
       (⇉· ƛxM⇉λzQ' N⇉Q'') 
       (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
  with  lemma⇉βrule x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P
     |  lemma⇉ƛrule ƛxM⇉λzQ'
...  |  P‴ , ƛxM⇉ƛxP‴ , P‴[x≔P'']~P
     |  Q‴ , M⇉Q‴ , ƛxM⇉ƛxQ‴ , ƛzQ'~ƛxQ‴
  with  diam⇉ ƛxM⇉ƛxP‴ ƛxM⇉ƛxQ‴
     |  diam⇉ N⇉P'' N⇉Q''
...  |  Q , ƛxP‴⇉Q , ƛxQ‴⇉Q
     |  R , P''⇉R  , Q''⇉R
  with  lemma⇉ƛrule ƛxP‴⇉Q
     |  lemma⇉ƛrule ƛxQ‴⇉Q
...  |  S' , P‴⇉S' , ƛxP‴⇉ƛxS' , Q~ƛxS'
     |  S″ , Q‴⇉S″ , ƛxQ‴⇉ƛxS″ , Q~ƛxS″ 
  with  lemma∼αƛ← (τ (σ Q~ƛxS') Q~ƛxS″)
...  |  S'∼S″ 
  =  S' [ x  R ]                                                                 ,
     lemma⇉αleft  (∼α· ƛzQ'~ƛxQ‴ ρ) 
                  (⇉β x x (lemma⇉αright ƛxQ‴⇉ƛxS″ (lemma∼αƛ (σ S'∼S″))) Q''⇉R ρ)  ,
     lemma⇉αleft  (σ P‴[x≔P'']~P) (lemma⇉Subst x P‴ P‴⇉S' P''⇉R)   
diam⇉  {ƛ x M · N} {P} {v _ · Q''} 
       (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
       (⇉· () N⇉Q'') 
diam⇉  {ƛ x M · N} {P} {(_ · _) · Q''} 
       (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
       (⇉· () N⇉Q'') 
diam⇉  {ƛ x M · N} {v _ · Q''} {P}
       (⇉· () N⇉Q'') 
       (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P) 
diam⇉  {ƛ x M · N} {(_ · _) · Q''} {P}
       (⇉· () N⇉Q'') 
       (⇉β .{M} {P'} .{N} {P''} .{P} .x y ƛxM⇉λyP' N⇉P'' P'[y≔P'']∼P)
\end{code}