open import Nat
open import Prelude
open import List

open import contexts
open import core

open import lemmas-general
open import preservation

module eval-checks where
  eval-unicity : ∀{⛽ Δ Σ' Γ E e τ r r' K K'} →
                   Δ , Σ' , Γ ⊢ E →
                   Δ , Σ' , Γ ⊢ e :: τ →
                   E ⊢ e ⌊ ⛽ ⌋⇒ r ⊣ K →
                   E ⊢ e ⌊ ⛽ ⌋⇒ r' ⊣ K' →
                   r == r' ∧ K == K'

  xc-unicity : ∀{Δ Σ' r1 r2 τ K K'} →
                 Δ , Σ' ⊢ r1 ·: τ →
                 Δ , Σ' ⊢ r2 ·: τ →
                 Constraints⦃ r1 , r2 ⦄:= K →
                 Constraints⦃ r1 , r2 ⦄:= K' →
                 K == K'

  eval-unicity Γ⊢E (TAFix _) EFix EFix = refl , refl
  eval-unicity Γ⊢E (TAVar _) (EVar h) (EVar h') = ctxunicity h h' , refl
  eval-unicity Γ⊢E (TAApp _ ta-f ta-arg) (EAppFix f1 form eval-f eval-arg eval) (EAppFix f2 form' eval-f' eval-arg' eval')
    rewrite form | form'
    with eval-unicity Γ⊢E ta-f eval-f eval-f' | eval-unicity Γ⊢E ta-arg eval-arg eval-arg'
  ... | refl , refl | refl , refl
    with preservation Γ⊢E ta-f eval-f
  ... | TAFix Γ'⊢Ef (TAFix ta-ef)
    rewrite Fuel-depletion-unicity f1 f2
    with eval-unicity (EnvInd (EnvInd Γ'⊢Ef (preservation Γ⊢E ta-f eval-f)) (preservation Γ⊢E ta-arg eval-arg)) ta-ef eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E TAUnit EUnit EUnit = refl , refl
  eval-unicity Γ⊢E (TAApp x ta-e ta-e₁) (EAppFix x₁ form eval eval₁ eval₂) (EAppUnfinished eval' nf eval'')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl
    rewrite form
      = abort (nf refl)
  eval-unicity Γ⊢E (TAApp x ta-e ta-e₁) (EAppUnfinished eval nf eval₁) (EAppFix x₂ form eval' eval'' eval''')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl
    rewrite form
      = abort (nf refl)
  eval-unicity Γ⊢E (TAApp x ta-f ta-arg) (EAppUnfinished eval-f x₁ eval-arg) (EAppUnfinished eval-f' x₂ eval-arg')
    with eval-unicity Γ⊢E ta-f eval-f eval-f' | eval-unicity Γ⊢E ta-arg eval-arg eval-arg'
  ... | refl , refl | refl , refl = refl , refl
  eval-unicity Γ⊢E (TAPair x ta-e1 ta-e2) (EPair eval1 eval2) (EPair eval1' eval2')
    with eval-unicity Γ⊢E ta-e1 eval1 eval1' | eval-unicity Γ⊢E ta-e2 eval2 eval2'
  ... | refl , refl | refl , refl = refl , refl
  eval-unicity Γ⊢E (TAFst ta-e) (EFst eval) (EFst eval')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TAFst ta-e) (EFst eval) (EFstUnfinished eval' np)
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = abort (np refl)
  eval-unicity Γ⊢E (TAFst ta-e) (EFstUnfinished eval np) (EFst eval')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = abort (np refl)
  eval-unicity Γ⊢E (TAFst ta-e) (EFstUnfinished eval x) (EFstUnfinished eval' x₁)
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TASnd ta-e) (ESnd eval) (ESnd eval')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TASnd ta-e) (ESnd eval) (ESndUnfinished eval' np)
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = abort (np refl)
  eval-unicity Γ⊢E (TASnd ta-e) (ESndUnfinished eval np) (ESnd eval')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = abort (np refl)
  eval-unicity Γ⊢E (TASnd ta-e) (ESndUnfinished eval x) (ESndUnfinished eval' x₁)
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TACtor x x₁ ta-e) (ECtor eval) (ECtor eval')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TACase d∈σ' ta-e x₁ ta-rules) (EMatch f1 form eval-e eval-ec) (EMatch f2 form' eval'-e eval'-ec)
    with eval-unicity Γ⊢E ta-e eval-e eval'-e
  ... | refl , refl
    with ctxunicity form form'
  ... | refl
    with ta-rules form
  ... | _ , _ , _ , c∈cctx , ta-ec
    with preservation Γ⊢E ta-e eval-e
  ... | TACtor d∈'σ' c∈'cctx ta-r'
    rewrite ctxunicity d∈σ' d∈'σ' | ctxunicity c∈cctx c∈'cctx | Fuel-depletion-unicity f1 f2
    with eval-unicity (EnvInd Γ⊢E ta-r') ta-ec eval-ec eval'-ec
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TACase x ta-e x₁ x₂) (EMatch x₃ x₄ eval eval₁) (EMatchUnfinished eval' nc)
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = abort (nc refl)
  eval-unicity Γ⊢E (TACase x ta-e x₁ x₂) (EMatchUnfinished eval nc) (EMatch x₄ x₅ eval' eval'')
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = abort (nc refl)
  eval-unicity Γ⊢E (TACase x ta-e x₁ x₂) (EMatchUnfinished eval x₃) (EMatchUnfinished eval' x₄)
    with eval-unicity Γ⊢E ta-e eval eval'
  ... | refl , refl = refl , refl
  eval-unicity Γ⊢E (TAHole x) EHole EHole = refl , refl
  eval-unicity Γ⊢E (TAAsrt x ta-e1 ta-e2) (EAsrt eval1 eval2 xc) (EAsrt eval1' eval2' xc')
    with eval-unicity Γ⊢E ta-e1 eval1 eval1' | eval-unicity Γ⊢E ta-e2 eval2 eval2'
  ... | refl , refl | refl , refl
    rewrite xc-unicity (preservation Γ⊢E ta-e1 eval1) (preservation Γ⊢E ta-e2 eval2) xc xc'
      = refl , refl

  xc-unicity ta1 ta2 RCRefl RCRefl = refl
  xc-unicity ta1 ta2 RCRefl (RCPair x rc2 rc3) = abort (x refl)
  xc-unicity ta1 ta2 RCRefl (RCCtor x rc2) = abort (x refl)
  xc-unicity ta1 ta2 RCRefl (RCVal1 x x₁ x₂ x₃) = abort (x refl)
  xc-unicity ta1 ta2 RCRefl (RCVal2 x x₁ x₂ x₃) = abort (x refl)
  xc-unicity ta1 ta2 (RCPair x rc1 rc2) RCRefl = abort (x refl)
  xc-unicity (TAPair ta1 ta2) (TAPair ta3 ta4) (RCPair x rc1 rc2) (RCPair x₁ rc3 rc4)
    rewrite xc-unicity ta1 ta3 rc1 rc3 | xc-unicity ta2 ta4 rc2 rc4
      = refl
  xc-unicity ta1 ta2 (RCPair x rc1 rc2) (RCVal1 x₁ (Inl x₂) x₃ x₄) = abort (x₂ refl)
  xc-unicity ta1 ta2 (RCPair x rc1 rc2) (RCVal1 x₁ (Inr x₂) x₃ x₄) = abort (x₂ refl)
  xc-unicity ta1 ta2 (RCPair x rc1 rc2) (RCVal2 x₁ (Inl x₂) x₃ x₄) = abort (x₂ refl)
  xc-unicity ta1 ta2 (RCPair x rc1 rc2) (RCVal2 x₁ (Inr x₂) x₃ x₄) = abort (x₂ refl)
  xc-unicity ta1 ta2 (RCCtor x rc1) RCRefl = abort (x refl)
  xc-unicity (TACtor d∈σ' c∈cctx ta1) (TACtor d∈'σ' c∈'cctx ta2) (RCCtor x rc1) (RCCtor x₁ rc2)
    rewrite ctxunicity d∈σ' d∈'σ' | ctxunicity c∈cctx c∈'cctx
      = xc-unicity ta1 ta2 rc1 rc2
  xc-unicity ta1 ta2 (RCCtor x rc1) (RCVal1 x₁ x₂ (Inl x₃) x₄) = abort (x₃ refl)
  xc-unicity ta1 ta2 (RCCtor x rc1) (RCVal1 x₁ x₂ (Inr x₃) x₄) = abort (x₃ refl)
  xc-unicity ta1 ta2 (RCCtor x rc1) (RCVal2 x₁ x₂ (Inl x₃) x₄) = abort (x₃ refl)
  xc-unicity ta1 ta2 (RCCtor x rc1) (RCVal2 x₁ x₂ (Inr x₃) x₄) = abort (x₃ refl)
  xc-unicity ta1 ta2 (RCVal1 x x₁ x₂ x₃) RCRefl = abort (x refl)
  xc-unicity ta1 ta2 (RCVal1 x (Inl x₁) x₂ x₃) (RCPair x₄ rc2 rc3) = abort (x₁ refl)
  xc-unicity ta1 ta2 (RCVal1 x (Inr x₁) x₂ x₃) (RCPair x₄ rc2 rc3) = abort (x₁ refl)
  xc-unicity ta1 ta2 (RCVal1 x _ (Inl x₁) x₃) (RCCtor x₄ rc2) = abort (x₁ refl)
  xc-unicity ta1 ta2 (RCVal1 x _ (Inr x₁) x₃) (RCCtor x₄ rc2) = abort (x₁ refl)
  xc-unicity ta1 ta2 (RCVal1 x x₁ x₂ x₃) (RCVal1 x₄ x₅ x₆ x₇)
    rewrite Coerce-unicity x₃ x₇
      = refl
  xc-unicity TAUnit TAUnit (RCVal1 x x₁ x₂ x₃) (RCVal2 x₄ x₅ x₆ x₇) = abort (x₄ refl)
  xc-unicity (TAPair ta1 ta2) (TAPair ta3 ta4) (RCVal1 x (Inl x₂) _ x₃) (RCVal2 x₄ x₅ x₆ x₇) = abort (x₂ refl)
  xc-unicity (TAPair ta1 ta2) (TAPair ta3 ta4) (RCVal1 x (Inr x₂) _ x₃) (RCVal2 x₄ x₅ x₆ x₇) = abort (x₂ refl)
  xc-unicity (TACtor x₈ x₉ ta1) (TACtor x₁₀ x₁₁ ta2) (RCVal1 x x₁ (Inl h) x₃) (RCVal2 x₄ x₅ x₆ x₇) = abort (h refl)
  xc-unicity (TACtor x₈ x₉ ta1) (TACtor x₁₀ x₁₁ ta2) (RCVal1 x x₁ (Inr h) x₃) (RCVal2 x₄ x₅ x₆ x₇) = abort (h refl)
  xc-unicity ta1 ta2 (RCVal2 x x₁ x₂ x₃) RCRefl = abort (x refl)
  xc-unicity ta1 ta2 (RCVal2 x (Inl x₁) x₂ x₃) (RCPair x₄ rc2 rc3) = abort (x₁ refl)
  xc-unicity ta1 ta2 (RCVal2 x (Inr x₁) x₂ x₃) (RCPair x₄ rc2 rc3) = abort (x₁ refl)
  xc-unicity ta1 ta2 (RCVal2 x x₁ (Inl x₂) x₃) (RCCtor x₄ rc2) = abort (x₂ refl)
  xc-unicity ta1 ta2 (RCVal2 x x₁ (Inr x₂) x₃) (RCCtor x₄ rc2) = abort (x₂ refl)
  xc-unicity TAUnit TAUnit (RCVal2 x x₁ x₂ x₃) (RCVal1 x₄ x₅ x₆ x₇) = abort (x refl)
  xc-unicity (TAPair ta1 ta2) (TAPair ta3 ta4) (RCVal2 x (Inl h) x₂ x₃) (RCVal1 x₄ x₅ x₆ x₇) = abort (h refl)
  xc-unicity (TAPair ta1 ta2) (TAPair ta3 ta4) (RCVal2 x (Inr h) x₂ x₃) (RCVal1 x₄ x₅ x₆ x₇) = abort (h refl)
  xc-unicity (TACtor x₈ x₉ ta1) (TACtor x₁₀ x₁₁ ta2) (RCVal2 x x₁ (Inl h) x₃) (RCVal1 x₄ x₅ x₆ x₇) = abort (h refl)
  xc-unicity (TACtor x₈ x₉ ta1) (TACtor x₁₀ x₁₁ ta2) (RCVal2 x x₁ (Inr h) x₃) (RCVal1 x₄ x₅ x₆ x₇) = abort (h refl)
  xc-unicity ta1 ta2 (RCVal2 x x₁ x₂ x₃) (RCVal2 x₄ x₅ x₆ x₇)
    rewrite Coerce-unicity x₃ x₇
      = refl

  -- useful in practice, since threading type-checks around everywhere can be a pain
  -- note that this does not prove unicity of constraints, which isn't true for poorly-typed terms
  untyped-eval-unicity : ∀{⛽ E e r r' K K'} →
                           E ⊢ e ⌊ ⛽ ⌋⇒ r ⊣ K →
                           E ⊢ e ⌊ ⛽ ⌋⇒ r' ⊣ K' →
                           r == r'
  untyped-eval-unicity EFix EFix = refl
  untyped-eval-unicity (EVar h) (EVar h') = ctxunicity h h'
  untyped-eval-unicity (EAppFix f1 form eval-f eval-arg eval) (EAppFix f2 form' eval-f' eval-arg' eval')
    rewrite form | form'
    with untyped-eval-unicity eval-f eval-f' | untyped-eval-unicity eval-arg eval-arg'
  ... | refl | refl
    rewrite Fuel-depletion-unicity f1 f2 | untyped-eval-unicity eval eval'
      = refl
  untyped-eval-unicity EUnit EUnit = refl
  untyped-eval-unicity (EAppFix x₁ form eval eval₁ eval₂) (EAppUnfinished eval' nf eval'')
    rewrite untyped-eval-unicity eval eval' | form
      = abort (nf refl)
  untyped-eval-unicity (EAppUnfinished eval nf eval₁) (EAppFix x₂ form eval' eval'' eval''')
    rewrite untyped-eval-unicity eval eval' | form
      = abort (nf refl)
  untyped-eval-unicity (EAppUnfinished eval-f x₁ eval-arg) (EAppUnfinished eval-f' x₂ eval-arg')
    rewrite untyped-eval-unicity eval-f eval-f' | untyped-eval-unicity eval-arg eval-arg'
      = refl
  untyped-eval-unicity (EPair eval1 eval2) (EPair eval1' eval2')
    rewrite untyped-eval-unicity eval1 eval1' | untyped-eval-unicity eval2 eval2'
      = refl
  untyped-eval-unicity (EFst eval) (EFst eval')
    with untyped-eval-unicity eval eval'
  ... | refl = refl
  untyped-eval-unicity (EFst eval) (EFstUnfinished eval' np)
    with untyped-eval-unicity eval eval'
  ... | refl = abort (np refl)
  untyped-eval-unicity (EFstUnfinished eval np) (EFst eval')
    with untyped-eval-unicity eval eval'
  ... | refl = abort (np refl)
  untyped-eval-unicity (EFstUnfinished eval x) (EFstUnfinished eval' x₁)
    with untyped-eval-unicity eval eval'
  ... | refl = refl
  untyped-eval-unicity (ESnd eval) (ESnd eval')
    with untyped-eval-unicity eval eval'
  ... | refl = refl
  untyped-eval-unicity (ESnd eval) (ESndUnfinished eval' np)
    with untyped-eval-unicity eval eval'
  ... | refl = abort (np refl)
  untyped-eval-unicity (ESndUnfinished eval np) (ESnd eval')
    with untyped-eval-unicity eval eval'
  ... | refl = abort (np refl)
  untyped-eval-unicity (ESndUnfinished eval x) (ESndUnfinished eval' x₁)
    with untyped-eval-unicity eval eval'
  ... | refl = refl
  untyped-eval-unicity (ECtor eval) (ECtor eval')
    with untyped-eval-unicity eval eval'
  ... | refl = refl
  untyped-eval-unicity (EMatch f1 form eval-e eval-ec) (EMatch f2 form' eval'-e eval'-ec)
    with untyped-eval-unicity eval-e eval'-e
  ... | refl
    with ctxunicity form form'
  ... | refl
    rewrite Fuel-depletion-unicity f1 f2
    with untyped-eval-unicity eval-ec eval'-ec
  ... | refl = refl
  untyped-eval-unicity (EMatch x₃ x₄ eval eval₁) (EMatchUnfinished eval' nc)
    with untyped-eval-unicity eval eval'
  ... | refl = abort (nc refl)
  untyped-eval-unicity (EMatchUnfinished eval nc) (EMatch x₄ x₅ eval' eval'')
    with untyped-eval-unicity eval eval'
  ... | refl = abort (nc refl)
  untyped-eval-unicity (EMatchUnfinished eval x₃) (EMatchUnfinished eval' x₄)
    with untyped-eval-unicity eval eval'
  ... | refl = refl
  untyped-eval-unicity EHole EHole = refl
  untyped-eval-unicity (EAsrt eval1 eval2 xc) (EAsrt eval1' eval2' xc')
    with untyped-eval-unicity eval1 eval1' | untyped-eval-unicity eval2 eval2'
  ... | refl | refl = refl


{-# OPTIONS --rewriting --without-K #-}

open import Agda.Primitive
open import Prelude
import GSeTT.Syntax
import GSeTT.Rules
open import GSeTT.Typed-Syntax
import Globular-TT.Syntax

module Globular-TT.Rules {l} (index : Set l) (rule : index → GSeTT.Typed-Syntax.Ctx × (Globular-TT.Syntax.Pre-Ty index)) where
  open import Globular-TT.Syntax index

  {- Notational shortcuts : the context corresponding to an index -}
  Ci : index → Pre-Ctx
  Ci i = GPre-Ctx (fst (fst (rule i)))

  Ti : index → Pre-Ty
  Ti i = snd (rule i)

  data _⊢C : Pre-Ctx → Set (lsuc l)
  data _⊢T_ : Pre-Ctx → Pre-Ty → Set (lsuc l)
  data _⊢t_#_ : Pre-Ctx → Pre-Tm → Pre-Ty → Set (lsuc l)
  data _⊢S_>_ : Pre-Ctx → Pre-Sub → Pre-Ctx → Set (lsuc l)

  data _⊢C where
    ec : ⊘ ⊢C
    cc : ∀ {Γ A x} → Γ ⊢C → Γ ⊢T A → x == C-length Γ → (Γ ∙ x # A) ⊢C

  data _⊢T_ where
    ob : ∀ {Γ} → Γ ⊢C → Γ ⊢T ∗
    ar : ∀ {Γ A t u} → Γ ⊢T A → Γ ⊢t t # A → Γ ⊢t u # A → Γ ⊢T ⇒ A t u

  data _⊢t_#_ where
    var : ∀ {Γ x A} → Γ ⊢C → x # A ∈ Γ → Γ ⊢t (Var x) # A
    tm : ∀ {Δ γ A i} → Ci i ⊢T Ti i → Δ ⊢S γ > Ci i → (A == (Ti i [ γ ]Pre-Ty)) → Δ ⊢t Tm-constructor i γ # A

  data _⊢S_>_ where
    es : ∀ {Δ} → Δ ⊢C → Δ ⊢S <> > ⊘
    sc : ∀ {Δ Γ γ x y A t} → Δ ⊢S γ > Γ → (Γ ∙ x # A) ⊢C → (Δ ⊢t t # (A [ γ ]Pre-Ty)) → x == y → Δ ⊢S < γ , y ↦ t > > (Γ ∙ x # A)

  {- Derivability is preserved by the translation from GSeTT to our TT -}
  x∈GCtx : ∀ {x A Γ} → x GSeTT.Syntax.# A ∈ Γ → x # GPre-Ty A ∈ GPre-Ctx Γ
  x∈GCtx {Γ = Γ :: a} (inl x∈Γ) = inl (x∈GCtx x∈Γ)
  x∈GCtx {Γ = Γ :: (x,A)} (inr (idp , idp)) = inr (idp , idp)

  G-length : ∀ Γ → length Γ == C-length (GPre-Ctx Γ)
  G-length nil = idp
  G-length (Γ :: _) = S= (G-length Γ)

  GCtx : ∀ (Γ : GSeTT.Syntax.Pre-Ctx) → Γ GSeTT.Rules.⊢C → (GPre-Ctx Γ) ⊢C
  GTy : ∀ (Γ : GSeTT.Syntax.Pre-Ctx) (A : GSeTT.Syntax.Pre-Ty) → Γ GSeTT.Rules.⊢T A → (GPre-Ctx Γ) ⊢T (GPre-Ty A)
  GTm : ∀ (Γ : GSeTT.Syntax.Pre-Ctx) (A : GSeTT.Syntax.Pre-Ty) (t : GSeTT.Syntax.Pre-Tm) → Γ GSeTT.Rules.⊢t t # A  → (GPre-Ctx Γ) ⊢t (GPre-Tm t) # (GPre-Ty A)

  GCtx .nil GSeTT.Rules.ec = ec
  GCtx (Γ :: (.(length Γ) , A)) (GSeTT.Rules.cc Γ⊢ Γ⊢A idp) = coe (ap (λ n → (GPre-Ctx (Γ :: (n , A)) ⊢C)) (G-length Γ) ^) (cc (GCtx Γ Γ⊢) (GTy Γ A Γ⊢A) idp)
  GTy Γ .GSeTT.Syntax.∗ (GSeTT.Rules.ob Γ⊢) = ob (GCtx Γ Γ⊢)
  GTy Γ (GSeTT.Syntax.⇒ A t u) (GSeTT.Rules.ar Γ⊢t:A Γ⊢u:A) = ar (GTy Γ A (GSeTT.Rules.Γ⊢t:A→Γ⊢A Γ⊢t:A)) (GTm Γ A t Γ⊢t:A) (GTm Γ A u Γ⊢u:A)
  GTm Γ A (GSeTT.Syntax.Var x) (GSeTT.Rules.var Γ⊢ x∈Γ) = var (GCtx Γ Γ⊢) (x∈GCtx x∈Γ)

  {- Properties of the type theory -}
  {- weakening admissibility -}
  wkT : ∀ {Γ A y B} → Γ ⊢T A → (Γ ∙ y # B) ⊢C → (Γ ∙ y # B) ⊢T A
  wkt : ∀ {Γ A t y B} → Γ ⊢t t # A → (Γ ∙ y # B) ⊢C → (Γ ∙ y # B) ⊢t t # A
  wkS : ∀ {Δ Γ γ y B} → Δ ⊢S γ > Γ → (Δ ∙ y # B) ⊢C → (Δ ∙ y # B) ⊢S γ > Γ

  wkT (ob _) Γ,y:B⊢ = ob Γ,y:B⊢
  wkT (ar Γ⊢A Γ⊢t:A Γ⊢u:A) Γ,y:B⊢ = ar (wkT Γ⊢A Γ,y:B⊢) (wkt Γ⊢t:A Γ,y:B⊢) (wkt Γ⊢u:A Γ,y:B⊢)
  wkt (var Γ⊢C x∈Γ) Γ,y:B⊢ = var Γ,y:B⊢ (inl x∈Γ)
  wkt (tm Ci⊢Ti Γ⊢γ:Δ idp) Γ,y:B⊢ = tm Ci⊢Ti (wkS Γ⊢γ:Δ Γ,y:B⊢) idp
  wkS (es _) Δ,y:B⊢ = es Δ,y:B⊢
  wkS (sc Δ⊢γ:Γ Γ,x:A⊢ Δ⊢t:A[γ] idp) Δ,y:B⊢ = sc (wkS Δ⊢γ:Γ Δ,y:B⊢) Γ,x:A⊢ (wkt Δ⊢t:A[γ] Δ,y:B⊢) idp

  {- Consistency : all objects appearing in derivable judgments are derivable -}
  Γ⊢A→Γ⊢ : ∀ {Γ A} → Γ ⊢T A → Γ ⊢C
  Γ⊢t:A→Γ⊢ : ∀ {Γ A t} → Γ ⊢t t # A → Γ ⊢C
  Δ⊢γ:Γ→Δ⊢ : ∀ {Δ Γ γ} → Δ ⊢S γ > Γ → Δ ⊢C

  Γ⊢A→Γ⊢ (ob Γ⊢) = Γ⊢
  Γ⊢A→Γ⊢ (ar Γ⊢A Γ⊢t:A Γ⊢u:A) = Γ⊢t:A→Γ⊢ Γ⊢t:A
  Γ⊢t:A→Γ⊢ (var Γ⊢ _) = Γ⊢
  Γ⊢t:A→Γ⊢ (tm _ Γ⊢γ:Δ idp) = Δ⊢γ:Γ→Δ⊢ Γ⊢γ:Δ
  Δ⊢γ:Γ→Δ⊢ (es Δ⊢) = Δ⊢
  Δ⊢γ:Γ→Δ⊢ (sc Δ⊢γ:Γ Γ,x:A⊢ Δ⊢t:A[γ] idp) = Δ⊢γ:Γ→Δ⊢ Δ⊢γ:Γ

  Δ⊢γ:Γ→Γ⊢ : ∀ {Δ Γ γ} → Δ ⊢S γ > Γ → Γ ⊢C
  Δ⊢γ:Γ→Γ⊢ (es Δ⊢) = ec
  Δ⊢γ:Γ→Γ⊢ (sc Δ⊢γ:Γ Γ,x:A⊢ Δ⊢t:A[γ] idp) = Γ,x:A⊢

  Γ,x:A⊢→Γ,x:A⊢A : ∀ {Γ x A} → (Γ ∙ x # A) ⊢C → (Γ ∙ x # A) ⊢T A
  Γ,x:A⊢→Γ,x:A⊢A Γ,x:A⊢@(cc Γ⊢ Γ⊢A idp) = wkT Γ⊢A Γ,x:A⊢

  Γ,x:A⊢→Γ,x:A⊢x:A : ∀ {Γ x A} → (Γ ∙ x # A) ⊢C → (Γ ∙ x # A) ⊢t (Var x) # A
  Γ,x:A⊢→Γ,x:A⊢x:A Γ,x:A⊢ = var Γ,x:A⊢ (inr (idp , idp))

  Γ⊢src : ∀ {Γ A t u} → Γ ⊢T ⇒ A t u → Γ ⊢t t # A
  Γ⊢src (ar Γ⊢ Γ⊢t Γ⊢u) = Γ⊢t

  Γ⊢tgt : ∀ {Γ A t u} → Γ ⊢T ⇒ A t u → Γ ⊢t u # A
  Γ⊢tgt (ar Γ⊢ Γ⊢t Γ⊢u) = Γ⊢u

  -- The proposition Γ⊢t:A→Γ⊢A is slightly harder and is moved in CwF-Struture since it depends on lemmas there

  -- Type epressing that the rules are well-founded (useful to show that judgments are decidable)
  well-founded : Set (lsuc l)
  well-founded = ∀ (i : index) → Ci i ⊢T Ti i → dimC (Ci i) ≤ dim (Ti i)

  -- Derivation of a term constructed by a term constructor
  Γ⊢tm→Ci⊢Ti : ∀ {i Γ γ A} → Γ ⊢t (Tm-constructor i γ) # A → Ci i ⊢T Ti i
  Γ⊢tm→Ci⊢Ti (tm Ci⊢Ti _ idp) = Ci⊢Ti

  Γ⊢tm→Γ⊢γ : ∀ {i Γ γ A} → Γ ⊢t (Tm-constructor i γ) # A → Γ ⊢S γ > Ci i
  Γ⊢tm→Γ⊢γ (tm _ Γ⊢γ idp) = Γ⊢γ


------------------------------------------------------------------------
-- Inversion of (sub)typing in Fω with interval kinds
------------------------------------------------------------------------

{-# OPTIONS --safe --without-K #-}

module FOmegaInt.Typing.Inversion where

open import Data.Product using (_,_; proj₁; proj₂; _×_; map)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Relation.Nullary using (¬_)

open import FOmegaInt.Syntax
open import FOmegaInt.Typing
open import FOmegaInt.Typing.Validity
open import FOmegaInt.Kinding.Declarative.Normalization
open import FOmegaInt.Kinding.Canonical.Equivalence
  using (sound-<:; sound-<∷; complete-<∷; complete-<:-⋯)
import FOmegaInt.Kinding.Canonical.Inversion as CanInv

open Syntax
open TermCtx hiding (map)
open Typing
open Substitution using (_[_]; weaken)
open WfCtxOps using (lookup-tp)
open TypedSubstitution
open TypedNarrowing

------------------------------------------------------------------------
-- Generation/inversion of typing.

infix 4 _⊢Tm-gen_∈_

-- The possible types of a term (i.e. the possible results of
-- generating/inverting _⊢Tp_∈_).
data _⊢Tm-gen_∈_ {n} (Γ : Ctx n) : Term n → Term n → Set where
  ∈-var : ∀ {a b} x → Γ ctx → lookup Γ x ≡ tp a → Γ ⊢ a <: b ∈ * →
          Γ ⊢Tm-gen var x ∈ b
  ∈-∀-i : ∀ {k a b c} → Γ ⊢ k kd → kd k ∷ Γ ⊢Tm a ∈ b → Γ ⊢ Π k b <: c ∈ * →
          Γ ⊢Tm-gen Λ k a ∈ c
  ∈-→-i : ∀ {a b c d} → Γ ⊢Tp a ∈ * → tp a ∷ Γ ⊢Tm b ∈ weaken c →
          Γ ⊢ a ⇒ c <: d ∈ * → Γ ⊢Tm-gen ƛ a b ∈ d
  ∈-∀-e : ∀ {a b k c d} → Γ ⊢Tm a ∈ Π k c → Γ ⊢Tp b ∈ k → Γ ⊢ c [ b ] <: d ∈ * →
          Γ ⊢Tm-gen a ⊡ b ∈ d
  ∈-→-e : ∀ {a b c d e} → Γ ⊢Tm a ∈ c ⇒ d → Γ ⊢Tm b ∈ c → Γ ⊢ d <: e ∈ * →
          Γ ⊢Tm-gen a · b ∈ e

-- Generation/inversion of typing.
Tm∈-gen : ∀ {n} {Γ : Ctx n} {a b} → Γ ⊢Tm a ∈ b → Γ ⊢Tm-gen a ∈ b
Tm∈-gen (∈-var x Γ-ctx Γ[x]≡kd-a) =
  ∈-var x Γ-ctx Γ[x]≡kd-a (<:-refl (Tm∈-valid (∈-var x Γ-ctx Γ[x]≡kd-a)))
Tm∈-gen (∈-∀-i k-kd a∈b) =
  ∈-∀-i k-kd a∈b (<:-refl (Tm∈-valid (∈-∀-i k-kd a∈b)))
Tm∈-gen (∈-→-i a∈* b∈c c∈*) =
  ∈-→-i a∈* b∈c (<:-refl (Tm∈-valid (∈-→-i a∈* b∈c c∈*)))
Tm∈-gen (∈-∀-e a∈∀kc b∈k) =
  ∈-∀-e a∈∀kc b∈k (<:-refl (Tm∈-valid (∈-∀-e a∈∀kc b∈k)))
Tm∈-gen (∈-→-e a∈c⇒d b∈c) =
  ∈-→-e a∈c⇒d b∈c (<:-refl (Tm∈-valid (∈-→-e a∈c⇒d b∈c)))
Tm∈-gen (∈-⇑ a∈b   b<:c) with Tm∈-gen a∈b
Tm∈-gen (∈-⇑ x∈b   c<:d) | ∈-var x Γ-ctx Γ[x]≡kd-a a<:b =
  ∈-var x Γ-ctx Γ[x]≡kd-a (<:-trans a<:b c<:d)
Tm∈-gen (∈-⇑ Λka∈b b<:c) | ∈-∀-i k-kd a∈d ∀kd<:b   =
  ∈-∀-i k-kd a∈d (<:-trans ∀kd<:b b<:c)
Tm∈-gen (∈-⇑ ƛab∈c c<:d) | ∈-→-i a∈* b∈c a⇒c<:d    =
  ∈-→-i a∈* b∈c (<:-trans a⇒c<:d c<:d)
Tm∈-gen (∈-⇑ a·b∈e e<:f) | ∈-∀-e a∈Πcd b∈c d[b]<:e =
  ∈-∀-e a∈Πcd b∈c (<:-trans d[b]<:e e<:f)
Tm∈-gen (∈-⇑ a·b∈e e<:f) | ∈-→-e a∈c⇒d b∈c d<:e    =
  ∈-→-e a∈c⇒d b∈c (<:-trans d<:e e<:f)

------------------------------------------------------------------------
-- Inversion of subtyping (in the empty context).

-- NOTE.  The following two lemmas only hold in the empty context
-- because we can not invert instances of the interval projection
-- rules (<:-⟨| and (<:-|⟩) in arbitrary contexts.  This is because
-- instances of these rules can reflect arbitrary subtyping
-- assumptions into the subtyping relation.  Consider, e.g.
--
--     Γ, X :: ⊤..⊥ ctx    Γ(X) = ⊥..⊤
--     ------------------------------- (∈-var)
--     Γ, X :: ⊤..⊥ ⊢ X :: ⊤..⊥
--     -------------------------- (<:-⟨|, <:-|⟩)
--     Γ, X :: ⊤..⊥ ⊢ ⊤ <: X <: ⊥
--
-- Which allows us to prove that ⊤ <: ⊥ using (<:-trans) under the
-- assumption (X : ⊤..⊥).  On the other hand, it is impossible to give
-- a transitivity-free proof of ⊤ <: ⊥.  In general, it is therefore
-- impossible to invert subtyping statements in non-empty contexts,
-- i.e. one cannot prove lemmas like (<:-→-inv) or (<:-∀-inv) below
-- for arbitrary contexts.

<:-∀-inv : ∀ {k₁ k₂ : Kind Term 0} {a₁ a₂} → [] ⊢ Π k₁ a₁ <: Π k₂ a₂ ∈ * →
           [] ⊢ k₂ <∷ k₁ × kd k₂ ∷ [] ⊢ a₁ <: a₂ ∈ *
<:-∀-inv ∀k₁a₁<:∀k₂a₂∈* =
  let nf-∀k₁a₁<:nf-∀k₂a₂          = complete-<:-⋯ ∀k₁a₁<:∀k₂a₂∈*
      nf-k₂<∷nf-k₁ , nf-a₁<:nf-a₂ = CanInv.<:-∀-inv nf-∀k₁a₁<:nf-∀k₂a₂
      ∀k₁a₁∈* , ∀k₂a₂∈*           = <:-valid ∀k₁a₁<:∀k₂a₂∈*
      k₁≅nf-k₁∈* , a₁≃nf-a₁∈*     = Tp∈-∀-≃-⌞⌟-nf ∀k₁a₁∈*
      k₂≅nf-k₂∈* , a₂≃nf-a₂∈*     = Tp∈-∀-≃-⌞⌟-nf ∀k₂a₂∈*
      k₂<∷nf-k₂∈*                 = ≅⇒<∷ k₂≅nf-k₂∈*
      k₂<∷k₁ = <∷-trans (<∷-trans k₂<∷nf-k₂∈* (sound-<∷ nf-k₂<∷nf-k₁))
                        (≅⇒<∷ (≅-sym k₁≅nf-k₁∈*))
  in k₂<∷k₁ ,
     <:-trans (<:-trans (⇓-<: k₂<∷k₁ (≃⇒<: a₁≃nf-a₁∈*))
                        (⇓-<: k₂<∷nf-k₂∈* (sound-<: nf-a₁<:nf-a₂)))
              (≃⇒<: (≃-sym a₂≃nf-a₂∈*))

<:-→-inv : ∀ {a₁ a₂ b₁ b₂ : Term 0} → [] ⊢ a₁ ⇒ b₁ <: a₂ ⇒ b₂ ∈ * →
           [] ⊢ a₂ <: a₁ ∈ * × [] ⊢ b₁ <: b₂ ∈ *
<:-→-inv a₁⇒b₁<:a₂⇒b₂∈* =
  let nf-a₁⇒b₁<:nf-a₂⇒b₂          = complete-<:-⋯ a₁⇒b₁<:a₂⇒b₂∈*
      nf-a₂<:nf-a₁ , nf-b₁<:nf-b₂ = CanInv.<:-→-inv nf-a₁⇒b₁<:nf-a₂⇒b₂
      a₁⇒b₁∈* , a₂⇒b₂∈*           = <:-valid a₁⇒b₁<:a₂⇒b₂∈*
      a₁≃nf-a₁∈* , b₁≃nf-b₁∈*     = Tp∈-→-≃-⌞⌟-nf a₁⇒b₁∈*
      a₂≃nf-a₂∈* , b₂≃nf-b₂∈*     = Tp∈-→-≃-⌞⌟-nf a₂⇒b₂∈*
  in <:-trans (<:-trans (≃⇒<: a₂≃nf-a₂∈*) (sound-<: nf-a₂<:nf-a₁))
              (≃⇒<: (≃-sym a₁≃nf-a₁∈*)) ,
     <:-trans (<:-trans (≃⇒<: b₁≃nf-b₁∈*) (sound-<: nf-b₁<:nf-b₂))
              (≃⇒<: (≃-sym b₂≃nf-b₂∈*))

-- ⊤ is not a subtype of ⊥.

⊤-≮:-⊥ : ∀ {a : Term 0} → ¬ [] ⊢ ⊤ <: ⊥ ∈ *
⊤-≮:-⊥ ⊤<:⊥ with CanInv.⊤-<:-max (complete-<:-⋯ ⊤<:⊥)
⊤-≮:-⊥ ⊤<:⊥ | ()

-- Arrows are not canonical subtypes of universals and vice-versa.

⇒-≮:-Π : ∀ {a₁ b₁ : Term 0} {k₂ a₂} → ¬ [] ⊢ a₁ ⇒ b₁ <: Π k₂ a₂ ∈ *
⇒-≮:-Π a₁⇒b₁<:∀k₂a₂∈* = CanInv.⇒-≮:-Π (complete-<:-⋯ a₁⇒b₁<:∀k₂a₂∈*)

Π-≮:-⇒ : ∀ {k₁ a₁} {a₂ b₂ : Term 0} → ¬ [] ⊢ Π k₁ a₁ <: a₂ ⇒ b₂ ∈ *
Π-≮:-⇒ ∀k₁a₁<:a₂⇒b₂∈* = CanInv.Π-≮:-⇒ (complete-<:-⋯ ∀k₁a₁<:a₂⇒b₂∈*)


record R (A : Set) : Set where field giveA : A
open R ⦃ … ⦄

record WrapR (A : Set) : Set where field instance ⦃ wrappedR ⦄ : R A
open WrapR ⦃ … ⦄

postulate
  instance R-instance : ∀ {X} → WrapR X

data D : Set where

works : D
works = giveA ⦃ WrapR.wrappedR (R-instance {D}) ⦄

fails : D
fails = giveA ⦃ {!!} ⦄
-- No instance of type R D was found in scope.

-- open import Agda.Primitive

-- {-
-- record IsBottom₀ (⊥ : Set) : Set (lsuc lzero) where
--   field
--     ⊥₀-elim : ⊥ → {A : Set lzero} → A

-- open IsBottom₀ ⦃ … ⦄ public

-- record Bottom₀ : Set (lsuc lzero) where
--   field
--     ⊥₀ : Set
--     ⦃ isBottom ⦄ : IsBottom₀ ⊥₀

-- open Bottom₀ ⦃ … ⦄ public

-- test : ⦃ bottom : ∀ {l : Set} → Bottom₀ ⦄ {fake : ⊥₀ ⦃ bottom {Level} ⦄} {real : Set} → real
-- test ⦃ bottom ⦄ {fake} {real} = ⊥₀-elim {⊥₀ ⦃ bottom ⦄} ⦃ Bottom₀.isBottom (bottom {Level}) ⦄ fake
-- -}

-- record IsBottom₀ (⊥ : Set) a : Set (lsuc a) where
--   field
--     ⊥₀-elim : ⊥ → {A : Set a} → A

-- open IsBottom₀ ⦃ … ⦄ public

-- record Bottom₀ a : Set (lsuc a) where
--   field
--     ⊥₀ : Set
--     ⦃ isBottom ⦄ : IsBottom₀ ⊥₀ a

-- open Bottom₀ ⦃ … ⦄ public

-- postulate
--   instance Bi : ∀ {a} → Bottom₀ a

-- --test : ⦃ bottom : ∀ {a} → Bottom₀ a ⦄ {fake : ⊥₀ {lzero}} {real : Set} → real
-- --test ⦃ bottom ⦄ {fake} {real} = let instance b = Bottom₀.isBottom (bottom {lzero}) in ⊥₀-elim {⊥₀ {lzero} ⦃ bottom ⦄} {lzero} ⦃ {!Bottom₀.isBottom bottom!} ⦄ fake

-- test : {fake : ⊥₀ {lzero}} {real : Set} → real
-- test {fake} {real} = ⊥₀-elim {⊥₀ {lzero} ⦃ Bi ⦄} {lzero} ⦃ Bottom₀.isBottom Bi ⦄ fake

-- -- record Bottom₀ a : Set (lsuc a) where
-- --   field
-- --     ⊥₀ : Set
-- --     ⊥₀-elim : ⊥₀ → {A : Set a} → A

-- -- open Bottom₀ ⦃ … ⦄ public

-- -- test : ⦃ bottom : ∀ {a} → Bottom₀ a ⦄ {fake : ⊥₀ {lzero}} {real : Set} → real
-- -- test ⦃ bottom ⦄ {fake} {real} = ⊥₀-elim fake -- ⊥₀-elim {⊥₀ {lzero} ⦃ bottom ⦄} {lzero} ⦃ bottom ⦄ fake

-- -- postulate
-- --   B : Set

-- -- record IsB (r : Set) a : Set (lsuc a) where
-- --   field
-- --     gotB : B
-- --     xx : r

-- -- open IsB ⦃ … ⦄ public

-- -- record RB a : Set (lsuc a) where
-- --   field
-- --     r : Set
-- --     ⦃ isB ⦄ : IsB r a

-- -- open RB ⦃ … ⦄ public

-- -- testB : ⦃ bottom : ∀ {a} → RB a ⦄ → B
-- -- testB ⦃ bottom ⦄ = gotB ⦃ {!isB bottom {lzero}!} ⦄


module test where

open import cry.gfp
open import cry.ec

{-
-- open import IO.Primitive
-- open import Foreign.Haskell

open import Agda.Builtin.List using (List; []; _∷_)
open import Agda.Builtin.Char using (Char) renaming (primCharToNat to toNat)
open import Agda.Builtin.String using (String) renaming (primStringAppend to _++_; primStringToList to toList)
open import Agda.Builtin.Unit using (⊤)
-}

open import Data.Char using (Char; toNat)
open import Data.Nat as N using (ℕ; zero)
open import Data.Nat.Show using (show)
open import Data.List using (List; []; _∷_)
-- open import Data.Product using (_×_; _,_; proj₁)
open import Data.String using (String; _++_; toList)
open import Relation.Nullary using (yes; no)
open import IO using (IO; run; putStrLn)
open import Coinduction using (♯_)
open import Function using (_∘_; _$_)

-- open import Agda.Builtin.IO public using (IO)

_>>=_ : ∀ {a} {A B : Set a} → IO A → (A → IO B) → IO B
m >>= f = ♯ m IO.>>= λ a → ♯ f a

_>>_ : ∀ {a} {A B : Set a} → IO A → IO B → IO B
m >> n = ♯ m IO.>> ♯ n

open cry.ec using (module test-ec)
open test-ec

showElem : 𝔽 → String
showElem n = show n

read₁₀ : ℕ → List Char → ℕ × List Char
read₁₀ n [] = n , []
read₁₀ n (c ∷ cs) with toNat '0' N.≤? toNat c
... | no _ = n , cs
... | yes _ with toNat c N.≤? toNat '9'
... | no _ = n , cs
... | yes _ = read₁₀ (10 N.* n N.+ (toNat c N.∸ toNat '0')) cs

readsElem : List Char → 𝔽 × List Char
readsElem cs with read₁₀ 0 cs
... | n , cs′ = n , cs′ where

readElem : String → 𝔽
readElem = proj₁ ∘ readsElem ∘ toList

showPoint : Point → String
showPoint (x ∶ y ∶ z) = showElem x ++ ":" ++ showElem y ++ ":" ++ showElem z

readsPoint : List Char → Point × List Char
readsPoint s with readsElem s
... | x , s′ with readsElem s′
... | y , s″ with readsElem s″
... | z , s‴ = (x ∶ y ∶ z) , s‴ where

readPoint : String → Point
readPoint = proj₁ ∘ readsPoint ∘ toList

showPoint′ : Point → String
showPoint′ p = showPoint p ++ " = " ++ showPoint (aff p)

main′ : IO _
main′ = do
  let
    p = readPoint "4:2:1"
    2p = dbl p
    3p = add 2p p
    3p′ = add p 2p
    4p = dbl 2p
    4p′ = add p 3p
    4p″ = add p 3p′
    5p = add 4p p
    5p′ = add 2p 3p
    5p+0 = add 5p 𝕆
    6p = dbl 3p
    6p′ = add 5p p
    6p″ = add p 5p
  putStrLn ("p = " ++ showPoint′ p)
  putStrLn ("2p = " ++ showPoint′ 2p)
  putStrLn ("3p = " ++ showPoint′ 3p)
  putStrLn ("3p′ = " ++ showPoint′ 3p′)
  putStrLn ("4p = " ++ showPoint′ 4p)
  putStrLn ("4p′ = " ++ showPoint′ 4p′)
  putStrLn ("4p″ = " ++ showPoint′ 4p″)
  putStrLn ("5p = " ++ showPoint′ 5p)
  putStrLn ("5p′ = " ++ showPoint′ 5p′)
  putStrLn ("5p+0 = " ++ showPoint′ 5p+0)
  putStrLn ("6p = " ++ showPoint′ 6p)
  putStrLn ("6p′ = " ++ showPoint′ 6p′)
  putStrLn ("6p″ = " ++ showPoint′ 6p″)

main = run main′


open import Relation.Binary.Core

module PLRTree.Push.Complete {A : Set}
                     (_≤_ : A → A → Set)
                     (tot≤ : Total _≤_)  where

open import Data.Sum
open import Induction.WellFounded
open import PLRTree {A}
open import PLRTree.Drop _≤_ tot≤
open import PLRTree.Complete {A}
open import PLRTree.Equality {A}
open import PLRTree.Equality.Properties {A}
open import PLRTree.Order {A}
open import PLRTree.Order.Properties {A}

mutual
  lemma-≃-push : {t t' : PLRTree} → t ≃ t' → (acc : Acc _≺_ t) → t ≃ push t acc
  lemma-≃-push ≃lf _ = ≃lf
  lemma-≃-push (≃nd x x' ≃lf ≃lf ≃lf) _ = ≃nd x x ≃lf ≃lf ≃lf
  lemma-≃-push (≃nd x x' (≃nd {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'≃r' (≃nd .x₁ x'₁ _ l'₁≃r'₁ l₁≃l'₁)) (acc rs)
      with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
  ... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ =
             let l₁≃l₁ = lemma-≃-≃ l₁≃r₁
             in ≃nd x x (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) (≃nd x₁ x₁ l₁≃r₁ l₁≃r₁ l₁≃l₁)
  ... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁≃x₂l₂r₂ = lemma-≃-push  (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂ ;
                  x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) push-xl₁r₁≃x₂l₂r₂ ;
                  x₁l₁r₁≃x₁l₁r₁ = lemma-≃-≃ (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂)
             in ≃nd x x₂ (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) x₁l₁r₁≃push-xl₂r₂ x₁l₁r₁≃x₁l₁r₁
  ... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) ;
                  l₁≃l₁ = lemma-≃-≃ l₁≃r₁ ;
                  x₁l₁r₁≃xl₁r₁ = ≃nd x₁ x l₁≃r₁ l₁≃r₁ l₁≃l₁ ;
                  xl₁r₁≃push-xl₁r₁ = lemma-≃-push (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁ ;
                  x₁l₁r₁≃push-xl₁r₁ = trans≃ x₁l₁r₁≃xl₁r₁ xl₁r₁≃push-xl₁r₁
             in ≃nd x x₁ (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) push-xl₁r₁≃x₂l₂r₂ x₁l₁r₁≃push-xl₁r₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) ;
                  l₁≃l₁ = lemma-≃-≃ l₁≃r₁ ;
                  x₁l₁r₁≃xl₁r₁ = ≃nd x₁ x l₁≃r₁ l₁≃r₁ l₁≃l₁ ;
                  xl₁r₁≃push-xl₁r₁ = lemma-≃-push (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁ ;
                  x₁l₁r₁≃push-xl₁r₁ = trans≃ x₁l₁r₁≃xl₁r₁ xl₁r₁≃push-xl₁r₁
             in ≃nd x x₁ (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) push-xl₁r₁≃x₂l₂r₂ x₁l₁r₁≃push-xl₁r₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁≃x₂l₂r₂ = lemma-≃-push  (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂ ;
                  x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) push-xl₁r₁≃x₂l₂r₂ ;
                  x₁l₁r₁≃x₁l₁r₁ = lemma-≃-≃ (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂)
             in ≃nd x x₂ (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) x₁l₁r₁≃push-xl₂r₂ x₁l₁r₁≃x₁l₁r₁

  lemma-push-≃ : {t t' : PLRTree} → t ≃ t' → (acc : Acc _≺_ t) → push t acc ≃ t
  lemma-push-≃ t≃t' at = sym≃ (lemma-≃-push t≃t' at)

lemma-push-⋗ : {t t' : PLRTree} → t ⋗ t' → (acc : Acc _≺_ t) → push t acc ⋗ t'
lemma-push-⋗ (⋗lf x) _ = ⋗lf x
lemma-push-⋗ (⋗nd _ _ ≃lf _ ()) _
lemma-push-⋗ (⋗nd x x' (≃nd x₁ x₂ ≃lf ≃lf ≃lf) ≃lf (⋗lf .x₁)) (acc rs)
    with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = ⋗nd x x' (≃nd x₁ x₂ ≃lf ≃lf ≃lf) ≃lf (⋗lf x₁)
... | inj₁ x≤x₁ | inj₂ x₂≤x | _ = ⋗nd x₂ x' (≃nd x₁ x ≃lf ≃lf ≃lf) ≃lf (⋗lf x₁)
... | inj₂ x₁≤x | inj₁ x≤x₂ | _ = ⋗nd x₁ x' (≃nd x x₂ ≃lf ≃lf ≃lf) ≃lf (⋗lf x)
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ = ⋗nd x₁ x' (≃nd x x₂ ≃lf ≃lf ≃lf) ≃lf (⋗lf x)
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ = ⋗nd x₂ x' (≃nd x₁ x ≃lf ≃lf ≃lf) ≃lf (⋗lf x₁)
lemma-push-⋗ (⋗nd _ _ (≃nd x₁ _ ≃lf (≃nd _ _ _ _ _) ()) ≃lf (⋗lf .x₁)) _
lemma-push-⋗ (⋗nd x x' (≃nd {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'≃r' (⋗nd .x₁ x'₁ _ l'₁≃r'₁ l₁⋗l'₁)) (acc rs)
    with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = ⋗nd x x' (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
           let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = lemma-≃-push  (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂ ;
                x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) push-xl₁r₁≃x₂l₂r₂
           in ⋗nd x₂ x' x₁l₁r₁≃push-xl₂r₂ l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
           let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) ;
                push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
           in ⋗nd x₁ x' push-xl₁r₁≃x₂l₂r₂ l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
           let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) ;
                push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
           in ⋗nd x₁ x' push-xl₁r₁≃x₂l₂r₂ l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
           let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = lemma-≃-push  (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂ ;
                x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) push-xl₁r₁≃x₂l₂r₂
           in ⋗nd x₂ x' x₁l₁r₁≃push-xl₂r₂ l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)

lemma-⋗-push : {t t' : PLRTree} → t ⋗ t' → (acc : Acc _≺_ t') → t ⋗ push t' acc
lemma-⋗-push (⋗lf x) _ = ⋗lf x
lemma-⋗-push (⋗nd x x' l≃r ≃lf l⋗l') _ = ⋗nd x x' l≃r ≃lf l⋗l'
lemma-⋗-push (⋗nd x x' l≃r (≃nd {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂  l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (⋗nd x₁ .x'₁ l₁≃r₁ _ l₁⋗l'₁)) (acc rs)
    with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = ⋗nd x x' l≃r (≃nd x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
           let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                x'₁l'₁r'₁≃push-x'l'₂r'₂ = trans≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (lemma-≃-push (sym≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)) acc-x'l'₂r'₂)
           in ⋗nd x x'₂ l≃r x'₁l'₁r'₁≃push-x'l'₂r'₂ (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
           let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                push-x'l'₁r'₁≃x'₂l'₂r'₂ = trans≃ (lemma-push-≃ (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁) (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) ;
                x₁l₁r₁⋗push-x'l'₁r'₁ = lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-x'l'₁r'₁
           in ⋗nd x x'₁ l≃r push-x'l'₁r'₁≃x'₂l'₂r'₂ x₁l₁r₁⋗push-x'l'₁r'₁
... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
           let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                push-x'l'₁r'₁≃x'₂l'₂r'₂ = trans≃ (lemma-push-≃ (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁) (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) ;
                x₁l₁r₁⋗push-x'l'₁r'₁ = lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-x'l'₁r'₁
           in ⋗nd x x'₁ l≃r push-x'l'₁r'₁≃x'₂l'₂r'₂ x₁l₁r₁⋗push-x'l'₁r'₁
... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
           let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                x'₁l'₁r'₁≃push-x'l'₂r'₂ = trans≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (lemma-≃-push (sym≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)) acc-x'l'₂r'₂)
           in ⋗nd x x'₂ l≃r x'₁l'₁r'₁≃push-x'l'₂r'₂ (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)

lemma-⋘-push : {t t' : PLRTree} → t ⋘ t' → (acc : Acc _≺_ t') → t ⋘ push t' acc
lemma-⋘-push (x⋘ x y z) _ = x⋘ x y z
lemma-⋘-push (l⋘ _ _ () ≃lf ≃lf) _
lemma-⋘-push (l⋘ x x' l⋘r (≃nd {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (≃nd x₂ .x'₁ l₂≃r₂ _ l₂≃l'₁)) (acc rs)
    with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = l⋘ x x' l⋘r (≃nd x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ l₂≃l'₁)
... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
           let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                x'₁l'₁r'₁≃push-x'l'₂r'₂ = trans≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (lemma-≃-push (sym≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)) acc-x'l'₂r'₂)
           in l⋘ x x'₂ l⋘r x'₁l'₁r'₁≃push-x'l'₂r'₂ (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ l₂≃l'₁)
... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
           let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                push-x'l'₁r'₁≃x'₂l'₂r'₂ = trans≃ (lemma-push-≃ (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁) (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) ;
                x₂l₂r₂≃push-x'l'₁r'₁ = trans≃ (≃nd x₂ x' l₂≃r₂ l'₁≃r'₁ l₂≃l'₁) (lemma-≃-push (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁)
           in l⋘ x x'₁ l⋘r push-x'l'₁r'₁≃x'₂l'₂r'₂ x₂l₂r₂≃push-x'l'₁r'₁
... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
           let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                push-x'l'₁r'₁≃x'₂l'₂r'₂ = trans≃ (lemma-push-≃ (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁) (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) ;
                x₂l₂r₂≃push-x'l'₁r'₁ = trans≃ (≃nd x₂ x' l₂≃r₂ l'₁≃r'₁ l₂≃l'₁) (lemma-≃-push (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁)
           in l⋘ x x'₁ l⋘r push-x'l'₁r'₁≃x'₂l'₂r'₂ x₂l₂r₂≃push-x'l'₁r'₁
... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
           let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                x'₁l'₁r'₁≃push-x'l'₂r'₂ = trans≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (lemma-≃-push (sym≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)) acc-x'l'₂r'₂)
           in l⋘ x x'₂ l⋘r x'₁l'₁r'₁≃push-x'l'₂r'₂ (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ l₂≃l'₁)
lemma-⋘-push (r⋘ x x' l⋙r ≃lf (⋗lf x₁)) _ = r⋘ x x' l⋙r ≃lf (⋗lf x₁)
lemma-⋘-push (r⋘ x x' l⋙r (≃nd {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (⋗nd x₁ .x'₁ l₁≃r₁ _ l₁⋗l'₁)) (acc rs)
    with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = r⋘ x x' l⋙r (≃nd x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
           let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                x'₁l'₁r'₁≃push-x'l'₂r'₂ = trans≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (lemma-≃-push (sym≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)) acc-x'l'₂r'₂)
           in r⋘ x x'₂ l⋙r  x'₁l'₁r'₁≃push-x'l'₂r'₂ (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
           let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                push-x'l'₁r'₁≃x'₂l'₂r'₂ = trans≃ (lemma-push-≃ (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) acc-x'l'₁r'₁) (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)
           in r⋘ x x'₁ l⋙r push-x'l'₁r'₁≃x'₂l'₂r'₂ (lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-x'l'₁r'₁)
... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
           let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                push-x'l'₁r'₁≃x'₂l'₂r'₂ = trans≃ (lemma-push-≃ (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)  acc-x'l'₁r'₁) (≃nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)
           in r⋘ x x'₁ l⋙r push-x'l'₁r'₁≃x'₂l'₂r'₂ (lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-x'l'₁r'₁)
... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
           let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right perfect x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                x'₁l'₁r'₁≃push-x'l'₂r'₂ = trans≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂) (lemma-≃-push (sym≃ (≃nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁≃l'₂)) acc-x'l'₂r'₂)
           in r⋘ x x'₂ l⋙r  x'₁l'₁r'₁≃push-x'l'₂r'₂ (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)

lemma-push-⋙ : {t t' : PLRTree} → t ⋙ t' → (acc : Acc _≺_ t) → push t acc ⋙ t'
lemma-push-⋙ (⋙p l⋗r) (acc rs) = ⋙p (lemma-push-⋗ l⋗r (acc rs))
lemma-push-⋙ (⋙l _ _ ≃lf _ ()) _
lemma-push-⋙ (⋙l _ _ (≃nd x₁ _ ≃lf _ _) () (⋗lf .x₁)) _
lemma-push-⋙ (⋙l x x' (≃nd {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'⋘r' (⋗nd .x₁ x₄ _ l₄≃r₄ l₁⋗r₄)) (acc rs)
    with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = ⋙l x x' (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'⋘r' (⋗nd x₁ x₄ l₁≃r₁ l₄≃r₄ l₁⋗r₄)
... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
           let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) (lemma-≃-push  (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂)
           in ⋙l x₂ x' x₁l₁r₁≃push-xl₂r₂ l'⋘r' (⋗nd x₁ x₄ l₁≃r₁ l₄≃r₄ l₁⋗r₄)
... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
           let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂)
           in ⋙l x₁ x' push-xl₁r₁≃x₂l₂r₂ l'⋘r' (lemma-push-⋗ (⋗nd x x₄ l₁≃r₁ l₄≃r₄ l₁⋗r₄) acc-xl₁r₁)
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
           let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂)
           in ⋙l x₁ x' push-xl₁r₁≃x₂l₂r₂ l'⋘r' (lemma-push-⋗ (⋗nd x x₄ l₁≃r₁ l₄≃r₄ l₁⋗r₄) acc-xl₁r₁)
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
           let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                x₁l₁r₁≃push-xl₂r₂ =  trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) (lemma-≃-push  (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂)
           in ⋙l x₂ x' x₁l₁r₁≃push-xl₂r₂ l'⋘r' (⋗nd x₁ x₄ l₁≃r₁ l₄≃r₄ l₁⋗r₄)
lemma-push-⋙ (⋙r _ _ ≃lf (⋙p ()) ≃lf) _
lemma-push-⋙ (⋙r x x' (≃nd {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'⋙r' (≃nd .x₁ x₃ _ l₃≃r₃ l₁≃l₃)) (acc rs)
    with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = ⋙r x x' (≃nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) l'⋙r' (≃nd x₁ x₃ l₁≃r₁ l₃≃r₃ l₁≃l₃)
... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
           let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) (lemma-≃-push (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂)
           in ⋙r x₂ x' x₁l₁r₁≃push-xl₂r₂ l'⋙r' (≃nd x₁ x₃ l₁≃r₁ l₃≃r₃ l₁≃l₃)
... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
           let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) ;
                push-xl₁r₁≃x₃l₃r₃ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₃ l₁≃r₁ l₃≃r₃ l₁≃l₃)
           in ⋙r x₁ x' push-xl₁r₁≃x₂l₂r₂ l'⋙r' push-xl₁r₁≃x₃l₃r₃
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
           let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                push-xl₁r₁≃x₂l₂r₂ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) ;
                push-xl₁r₁≃x₃l₃r₃ = trans≃ (lemma-push-≃ (≃nd x x₂ l₁≃r₁ l₂≃r₂ l₁≃l₂) acc-xl₁r₁) (≃nd x x₃ l₁≃r₁ l₃≃r₃ l₁≃l₃)
           in ⋙r x₁ x' push-xl₁r₁≃x₂l₂r₂ l'⋙r' push-xl₁r₁≃x₃l₃r₃
... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
           let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                x₁l₁r₁≃push-xl₂r₂ = trans≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂) (lemma-≃-push (sym≃ (≃nd x₁ x l₁≃r₁ l₂≃r₂ l₁≃l₂)) acc-xl₂r₂)
           in ⋙r x₂ x' x₁l₁r₁≃push-xl₂r₂ l'⋙r' (≃nd x₁ x₃ l₁≃r₁ l₃≃r₃ l₁≃l₃)

mutual
  lemma-⋙r-push : {l r l' r' : PLRTree}(x x' : A) → l ≃ r → l' ⋙ r' → l ≃ l' → (acc : Acc _≺_ (node right x' l' r')) → (node perfect x l r) ⋙ push (node right x' l' r') acc
  lemma-⋙r-push x x' l≃r (⋙p (⋗lf x'₁)) (≃nd x₁ .x'₁ ≃lf ≃lf ≃lf) (acc rs)
      with tot≤ x' x'₁
  ... | inj₁ x'≤x'₁ = ⋙r x x' l≃r (⋙p (⋗lf x'₁)) (≃nd x₁ x'₁ ≃lf ≃lf ≃lf)
  ... | inj₂ x'₁≤x' = ⋙r x x'₁ l≃r (⋙p (⋗lf x')) (≃nd x₁ x' ≃lf ≃lf ≃lf)
  lemma-⋙r-push x x' l≃r (⋙p (⋗nd {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁⋗l'₂)) (≃nd x₁ .x'₁ l₁≃r₁ _ l₁≃l'₁) (acc rs)
        with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
  ... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = ⋙r x x' l≃r (⋙p (⋗nd x'₁ x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁⋗l'₂)) (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  ... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂  =
             let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right right x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋗push-x'l'₂r'₂ = lemma-⋗-push (⋗nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁⋗l'₂) acc-x'l'₂r'₂
             in ⋙r x x'₂ l≃r (⋙p x'₁l'₁r'₁⋗push-x'l'₂r'₂) (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  ... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left right x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋗x'₂l'₂r'₂ = lemma-push-⋗ (⋗nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁⋗l'₂) acc-x'l'₁r'₁ ;
                  x₁l₁r₁≃push-x'l'₁r'₁ = trans≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁) (lemma-≃-push (sym≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)) acc-x'l'₁r'₁)
             in ⋙r x x'₁ l≃r (⋙p push-x'l'₁r'₁⋗x'₂l'₂r'₂) x₁l₁r₁≃push-x'l'₁r'₁
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left right x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋗x'₂l'₂r'₂ = lemma-push-⋗ (⋗nd x' x'₂ l'₁≃r'₁ l'₂≃r'₂ l'₁⋗l'₂) acc-x'l'₁r'₁ ;
                  x₁l₁r₁≃push-x'l'₁r'₁ = trans≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁) (lemma-≃-push (sym≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)) acc-x'l'₁r'₁)
             in ⋙r x x'₁ l≃r (⋙p push-x'l'₁r'₁⋗x'₂l'₂r'₂) x₁l₁r₁≃push-x'l'₁r'₁
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
             let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right right x' (node perfect x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋗push-x'l'₂r'₂ = lemma-⋗-push (⋗nd x'₁ x' l'₁≃r'₁ l'₂≃r'₂ l'₁⋗l'₂) acc-x'l'₂r'₂
             in ⋙r x x'₂ l≃r (⋙p x'₁l'₁r'₁⋗push-x'l'₂r'₂) (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  lemma-⋙r-push x x' l≃r (⋙l {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁≃r'₁ l'₂⋘r'₂ l'₁⋗r'₂) (≃nd x₁ .x'₁ l₁≃r₁ _ l₁≃l'₁) (acc rs)
        with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
  ... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = ⋙r x x' l≃r (⋙l x'₁ x'₂ l'₁≃r'₁ l'₂⋘r'₂ l'₁⋗r'₂) (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  ... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height left x' x'₂ l'₂ r'₂  =
             let acc-x'l'₂r'₂ = rs (node left x' l'₂ r'₂) (lemma-≺-right right x' (node perfect x'₁ l'₁ r'₁) (node left x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋙push-x'l'₂r'₂ = lemma-⋙l-push x'₁ x' l'₁≃r'₁ l'₂⋘r'₂ l'₁⋗r'₂ acc-x'l'₂r'₂
             in ⋙r x x'₂ l≃r  x'₁l'₁r'₁⋙push-x'l'₂r'₂ (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  ... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left right x' (node perfect x'₁ l'₁ r'₁) (node left x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋙x'₂l'₂r'₂ = lemma-push-⋙ (⋙l x' x'₂ l'₁≃r'₁ l'₂⋘r'₂ l'₁⋗r'₂) acc-x'l'₁r'₁ ;
                  x₁l₁r₁≃push-x'l'₁r'₁ = trans≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁) (lemma-≃-push (sym≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)) acc-x'l'₁r'₁)
             in ⋙r x x'₁ l≃r push-x'l'₁r'₁⋙x'₂l'₂r'₂ x₁l₁r₁≃push-x'l'₁r'₁
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left right x' (node perfect x'₁ l'₁ r'₁) (node left x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋙x'₂l'₂r'₂ = lemma-push-⋙ (⋙l x' x'₂ l'₁≃r'₁ l'₂⋘r'₂ l'₁⋗r'₂) acc-x'l'₁r'₁ ;
                  x₁l₁r₁≃push-x'l'₁r'₁ = trans≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁) (lemma-≃-push (sym≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)) acc-x'l'₁r'₁)
             in ⋙r x x'₁ l≃r push-x'l'₁r'₁⋙x'₂l'₂r'₂ x₁l₁r₁≃push-x'l'₁r'₁
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height left x' x'₂ l'₂ r'₂ =
             let acc-x'l'₂r'₂ = rs (node left x' l'₂ r'₂) (lemma-≺-right right x' (node perfect x'₁ l'₁ r'₁) (node left x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋙push-x'l'₂r'₂ = lemma-⋙l-push x'₁ x' l'₁≃r'₁ l'₂⋘r'₂ l'₁⋗r'₂ acc-x'l'₂r'₂
             in ⋙r x x'₂ l≃r  x'₁l'₁r'₁⋙push-x'l'₂r'₂ (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)

  lemma-⋙r-push x x' l≃r (⋙r {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁≃r'₁ l'₂⋙r'₂ l'₁≃l'₂) (≃nd x₁ .x'₁ l₁≃r₁ _ l₁≃l'₁) (acc rs)
        with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
  ... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = ⋙r x x' l≃r (⋙r x'₁ x'₂ l'₁≃r'₁ l'₂⋙r'₂ l'₁≃l'₂) (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  ... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height right x' x'₂ l'₂ r'₂  =
             let acc-x'l'₂r'₂ = rs (node right x' l'₂ r'₂) (lemma-≺-right right x' (node perfect x'₁ l'₁ r'₁) (node right x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋙push-x'l'₂r'₂ = lemma-⋙r-push x'₁ x' l'₁≃r'₁ l'₂⋙r'₂ l'₁≃l'₂ acc-x'l'₂r'₂
             in ⋙r x x'₂ l≃r x'₁l'₁r'₁⋙push-x'l'₂r'₂ (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)
  ... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left right x' (node perfect x'₁ l'₁ r'₁) (node right x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋙x'₂l'₂r'₂ = lemma-push-⋙ (⋙r x' x'₂ l'₁≃r'₁ l'₂⋙r'₂ l'₁≃l'₂) acc-x'l'₁r'₁ ;
                  x₁l₁r₁≃push-x'l'₁r'₁ = trans≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁) (lemma-≃-push (sym≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)) acc-x'l'₁r'₁)
             in ⋙r x x'₁ l≃r push-x'l'₁r'₁⋙x'₂l'₂r'₂ x₁l₁r₁≃push-x'l'₁r'₁
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height perfect x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node perfect x' l'₁ r'₁) (lemma-≺-left right x' (node perfect x'₁ l'₁ r'₁) (node right x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋙x'₂l'₂r'₂ = lemma-push-⋙ (⋙r x' x'₂ l'₁≃r'₁ l'₂⋙r'₂ l'₁≃l'₂) acc-x'l'₁r'₁ ;
                  x₁l₁r₁≃push-x'l'₁r'₁ = trans≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁) (lemma-≃-push (sym≃ (≃nd x₁ x' l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)) acc-x'l'₁r'₁)
             in ⋙r x x'₁ l≃r push-x'l'₁r'₁⋙x'₂l'₂r'₂ x₁l₁r₁≃push-x'l'₁r'₁
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height right x' x'₂ l'₂ r'₂ =
             let acc-x'l'₂r'₂ = rs (node right x' l'₂ r'₂) (lemma-≺-right right x' (node perfect x'₁ l'₁ r'₁) (node right x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋙push-x'l'₂r'₂ = lemma-⋙r-push x'₁ x' l'₁≃r'₁ l'₂⋙r'₂ l'₁≃l'₂ acc-x'l'₂r'₂
             in ⋙r x x'₂ l≃r x'₁l'₁r'₁⋙push-x'l'₂r'₂ (≃nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁≃l'₁)

  lemma-push-l⋘ : {l r l' r' : PLRTree}(x x' : A) → l ⋘ r → l' ≃ r' → r ≃ l' → (acc : Acc _≺_ (node left x l r)) → push (node left x l r) acc ⋘ node perfect x' l' r'
  lemma-push-l⋘ x x' (x⋘ x₁ x₂ x₃) l'≃r' (≃nd .x₃ x'₁ ≃lf ≃lf ≃lf) (acc rs)
      with tot≤ x x₁ | tot≤ x x₃ | tot≤ x₁ x₃
  ... | inj₁ x≤x₁ | inj₁ x≤x₃ | _ = l⋘ x x' (x⋘ x₁ x₂ x₃) l'≃r' (≃nd x₃ x'₁ ≃lf ≃lf ≃lf)
  ... | inj₁ x≤x₁ | inj₂ x₃≤x | _ = l⋘ x₃ x' (x⋘ x₁ x₂ x) l'≃r' (≃nd x x'₁ ≃lf ≃lf ≃lf)
  ... | inj₂ x₁≤x | inj₁ x≤x₃ | _
      with tot≤ x x₂
  ... | inj₁ x≤x₂ = l⋘ x₁ x' (x⋘ x x₂ x₃) l'≃r' (≃nd x₃ x'₁ ≃lf ≃lf ≃lf)
  ... | inj₂ x₂≤x = l⋘ x₁ x' (x⋘ x₂ x x₃) l'≃r' (≃nd x₃ x'₁ ≃lf ≃lf ≃lf)
  lemma-push-l⋘ x x' (x⋘ x₁ x₂ x₃) l'≃r' (≃nd .x₃ x'₁ ≃lf ≃lf ≃lf) (acc rs) | inj₂ x₁≤x | inj₂ x₃≤x | inj₁ x₁≤x₃
      with tot≤ x x₂
  ... | inj₁ x≤x₂ = l⋘ x₁ x' (x⋘ x x₂ x₃) l'≃r' (≃nd x₃ x'₁ ≃lf ≃lf ≃lf)
  ... | inj₂ x₂≤x = l⋘ x₁ x' (x⋘ x₂ x x₃) l'≃r' (≃nd x₃ x'₁ ≃lf ≃lf ≃lf)
  lemma-push-l⋘ x x' (x⋘ x₁ x₂ x₃) l'≃r' (≃nd .x₃ x'₁ ≃lf ≃lf ≃lf) (acc rs) | inj₂ x₁≤x | inj₂ x₃≤x | inj₂ x₃≤x₁ = l⋘ x₃ x' (x⋘ x₁ x₂ x) l'≃r' (≃nd x x'₁ ≃lf ≃lf ≃lf)
  lemma-push-l⋘ x x' (l⋘ {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁⋘r₁ l₂≃r₂ r₁≃l₂) l'≃r' (≃nd .x₂ x'₁ _ l'₁≃r'₁ r₂≃l'₁) (acc rs)
      with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
  ... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = l⋘ x x' (l⋘ x₁ x₂ l₁⋘r₁ l₂≃r₂ r₁≃l₂) l'≃r' (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
  ... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right left x (node left x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  x₁l₁r₁⋘push-xl₂r₂ = lemma-⋘-push (l⋘ x₁ x l₁⋘r₁ l₂≃r₂ r₁≃l₂) acc-xl₂r₂ ;
                  push-xl₂r₂≃x'₁l'₁r'₁ = trans≃ (lemma-push-≃ (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁) acc-xl₂r₂) (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
             in l⋘ x₂ x' x₁l₁r₁⋘push-xl₂r₂ l'≃r' push-xl₂r₂≃x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height left x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node left x l₁ r₁) (lemma-≺-left left x (node left x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁⋘x₂l₂r₂ = lemma-push-l⋘ x x₂ l₁⋘r₁ l₂≃r₂ r₁≃l₂ acc-xl₁r₁
             in l⋘ x₁ x' push-xl₁r₁⋘x₂l₂r₂ l'≃r' (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height left x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node left x l₁ r₁) (lemma-≺-left left x (node left x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁⋘x₂l₂r₂ = lemma-push-l⋘ x x₂ l₁⋘r₁ l₂≃r₂ r₁≃l₂ acc-xl₁r₁
             in l⋘ x₁ x' push-xl₁r₁⋘x₂l₂r₂ l'≃r' (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right left x (node left x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  x₁l₁r₁⋘push-xl₂r₂ = lemma-⋘-push (l⋘ x₁ x l₁⋘r₁ l₂≃r₂ r₁≃l₂) acc-xl₂r₂ ;
                  push-xl₂r₂≃x'₁l'₁r'₁ = trans≃ (lemma-push-≃ (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁) acc-xl₂r₂) (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
             in l⋘ x₂ x' x₁l₁r₁⋘push-xl₂r₂ l'≃r' push-xl₂r₂≃x'₁l'₁r'₁
  lemma-push-l⋘ x x' (r⋘ {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁⋙r₁ l₂≃r₂ l₁⋗l₂) l'≃r' (≃nd .x₂ x'₁ _ l'₁≃r'₁ r₂≃l'₁) (acc rs)
    with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
  ... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = l⋘ x x' (r⋘ x₁ x₂ l₁⋙r₁ l₂≃r₂ l₁⋗l₂) l'≃r' (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
  ... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right left x (node right x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  x₁l₁r₁⋘push-xl₂r₂ = lemma-⋘-push (r⋘ x₁ x l₁⋙r₁ l₂≃r₂ l₁⋗l₂) acc-xl₂r₂ ;
                  push-xl₂r₂≃x'₁l'₁r'₁ = trans≃ (lemma-push-≃ (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁) acc-xl₂r₂) (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
             in l⋘ x₂ x' x₁l₁r₁⋘push-xl₂r₂ l'≃r' push-xl₂r₂≃x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height right x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node right x l₁ r₁) (lemma-≺-left left x (node right x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁⋘x₂l₂r₂ = lemma-push-r⋘ x x₂ l₁⋙r₁ l₂≃r₂ l₁⋗l₂ acc-xl₁r₁
             in l⋘ x₁ x' push-xl₁r₁⋘x₂l₂r₂ l'≃r' (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height right x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node right x l₁ r₁) (lemma-≺-left left x (node right x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁⋘x₂l₂r₂ = lemma-push-r⋘ x x₂ l₁⋙r₁ l₂≃r₂ l₁⋗l₂ acc-xl₁r₁
             in l⋘ x₁ x' push-xl₁r₁⋘x₂l₂r₂ l'≃r' (≃nd x₂ x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right left x (node right x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  x₁l₁r₁⋘push-xl₂r₂ = lemma-⋘-push (r⋘ x₁ x l₁⋙r₁ l₂≃r₂ l₁⋗l₂) acc-xl₂r₂ ;
                  push-xl₂r₂≃x'₁l'₁r'₁ = trans≃ (lemma-push-≃ (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁) acc-xl₂r₂) (≃nd x x'₁ l₂≃r₂ l'₁≃r'₁ r₂≃l'₁)
             in l⋘ x₂ x' x₁l₁r₁⋘push-xl₂r₂ l'≃r' push-xl₂r₂≃x'₁l'₁r'₁

  lemma-push-r⋘ : {l r l' r' : PLRTree}(x x' : A) → l ⋙ r → l' ≃ r' → l ⋗ l' → (acc : Acc _≺_ (node right x l r)) → push (node right x l r) acc ⋘ node perfect x' l' r'
  lemma-push-r⋘ x x' (⋙p (⋗lf x₁)) ≃lf (⋗lf .x₁) (acc rs)
      with tot≤ x x₁
  ... | inj₁ x≤x₁ = x⋘ x x₁ x'
  ... | inj₂ x₁≤x = x⋘ x₁ x x'
  lemma-push-r⋘  _ _ (⋙p (⋗lf x₁)) _ (⋗nd .x₁ _ _ _ ()) _
  lemma-push-r⋘ _ _ (⋙p (⋗nd x₁ _ _ _ ())) ≃lf (⋗lf .x₁) _
  lemma-push-r⋘ x x' (⋙p (⋗nd {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂≃r₂ l₁⋗l₂)) l'≃r' (⋗nd .x₁ x'₁ _ l'₁≃r'₁ l₁⋗l'₁) (acc rs)
      with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
  ... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = r⋘ x x' (⋙p (⋗nd x₁ x₂ l₁≃r₁ l₂≃r₂ l₁⋗l₂)) l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  ... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  x₁l₁r₁⋗push-xl₂r₂ = lemma-⋗-push (⋗nd x₁ x l₁≃r₁ l₂≃r₂ l₁⋗l₂) acc-xl₂r₂
             in r⋘ x₂ x' (⋙p x₁l₁r₁⋗push-xl₂r₂) l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  ... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁⋗x₂l₂r₂ = lemma-push-⋗ (⋗nd x x₂ l₁≃r₁ l₂≃r₂ l₁⋗l₂) acc-xl₁r₁ ;
                  push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
             in r⋘ x₁ x' (⋙p push-xl₁r₁⋗x₂l₂r₂) l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  push-xl₁r₁⋗x₂l₂r₂ = lemma-push-⋗ (⋗nd x x₂ l₁≃r₁ l₂≃r₂ l₁⋗l₂) acc-xl₁r₁ ;
                  push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
             in r⋘ x₁ x' (⋙p push-xl₁r₁⋗x₂l₂r₂) l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height perfect x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node perfect x l₂ r₂) (lemma-≺-right perfect x (node perfect x₁ l₁ r₁) (node perfect x₂ l₂ r₂)) ;
                  x₁l₁r₁⋗push-xl₂r₂ = lemma-⋗-push (⋗nd x₁ x l₁≃r₁ l₂≃r₂ l₁⋗l₂) acc-xl₂r₂
             in r⋘ x₂ x' (⋙p x₁l₁r₁⋗push-xl₂r₂) l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  lemma-push-r⋘  _ _ (⋙l x₁ _ _ _ ()) _ (⋗lf .x₁) _
  lemma-push-r⋘ x x' (⋙l {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂⋘r₂ l₁⋗r₂) l'≃r' (⋗nd .x₁ x'₁ _ l'₁≃r'₁ l₁⋗l'₁) (acc rs)
      with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
  ... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = r⋘ x x' (⋙l x₁ x₂ l₁≃r₁ l₂⋘r₂ l₁⋗r₂) l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  ... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height left x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node left x l₂ r₂) (lemma-≺-right right x (node perfect x₁ l₁ r₁) (node left x₂ l₂ r₂)) ;
                  x₁l₁r₁⋙push-xl₂r₂ = lemma-⋙l-push x₁ x l₁≃r₁ l₂⋘r₂ l₁⋗r₂ acc-xl₂r₂
             in r⋘ x₂ x' x₁l₁r₁⋙push-xl₂r₂ l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  ... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left right x (node perfect x₁ l₁ r₁) (node left x₂ l₂ r₂)) ;
                  push-xl₁r₁⋙x₂l₂r₂ = lemma-push-⋙ (⋙l x x₂ l₁≃r₁ l₂⋘r₂ l₁⋗r₂) acc-xl₁r₁ ;
                  push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
             in r⋘ x₁ x' push-xl₁r₁⋙x₂l₂r₂ l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left right x (node perfect x₁ l₁ r₁) (node left x₂ l₂ r₂)) ;
                  push-xl₁r₁⋙x₂l₂r₂ = lemma-push-⋙ (⋙l x x₂ l₁≃r₁ l₂⋘r₂ l₁⋗r₂) acc-xl₁r₁ ;
                  push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
             in r⋘ x₁ x' push-xl₁r₁⋙x₂l₂r₂ l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height left x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node left x l₂ r₂) (lemma-≺-right right x (node perfect x₁ l₁ r₁) (node left x₂ l₂ r₂)) ;
                  x₁l₁r₁⋙push-xl₂r₂ = lemma-⋙l-push x₁ x l₁≃r₁ l₂⋘r₂ l₁⋗r₂ acc-xl₂r₂
             in r⋘ x₂ x' x₁l₁r₁⋙push-xl₂r₂ l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  lemma-push-r⋘ _ _ (⋙r x₁ _ ≃lf (⋙p ()) ≃lf) ≃lf (⋗lf .x₁) _
  lemma-push-r⋘ _ _ (⋙r x₁ x₂ ≃lf (⋙l _ _ _ _ _) ()) ≃lf (⋗lf .x₁) _
  lemma-push-r⋘ _ _ (⋙r x₁ x₂ ≃lf (⋙r _ _ _ _ _) ()) ≃lf (⋗lf .x₁) _
  lemma-push-r⋘ x x' (⋙r {l₁} {r₁} {l₂} {r₂} x₁ x₂ l₁≃r₁ l₂⋙r₂ l₁≃l₂) l'≃r' (⋗nd .x₁ x'₁ _ l'₁≃r'₁ l₁⋗l'₁) (acc rs)
      with tot≤ x x₁ | tot≤ x x₂ | tot≤ x₁ x₂
  ... | inj₁ x≤x₁ | inj₁ x≤x₂ | _ = r⋘ x x' (⋙r x₁ x₂ l₁≃r₁ l₂⋙r₂ l₁≃l₂) l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  ... | inj₁ x≤x₁ | inj₂ x₂≤x | _ rewrite lemma-≡-height right x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node right x l₂ r₂) (lemma-≺-right right x (node perfect x₁ l₁ r₁) (node right x₂ l₂ r₂)) ;
                  x₁l₁r₁⋙push-xl₂r₂ = lemma-⋙r-push x₁ x l₁≃r₁ l₂⋙r₂ l₁≃l₂ acc-xl₂r₂
             in r⋘ x₂ x' x₁l₁r₁⋙push-xl₂r₂ l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)
  ... | inj₂ x₁≤x | inj₁ x≤x₂ | _ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left right x (node perfect x₁ l₁ r₁) (node right x₂ l₂ r₂)) ;
                  push-xl₁r₁⋙x₂l₂r₂ = lemma-push-⋙ (⋙r x x₂ l₁≃r₁ l₂⋙r₂ l₁≃l₂) acc-xl₁r₁ ;
                  push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
             in r⋘ x₁ x' push-xl₁r₁⋙x₂l₂r₂ l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₁ x₁≤x₂ rewrite lemma-≡-height perfect x x₁ l₁ r₁ =
             let acc-xl₁r₁ = rs (node perfect x l₁ r₁) (lemma-≺-left right x (node perfect x₁ l₁ r₁) (node right x₂ l₂ r₂)) ;
                  push-xl₁r₁⋙x₂l₂r₂ = lemma-push-⋙ (⋙r x x₂ l₁≃r₁ l₂⋙r₂ l₁≃l₂) acc-xl₁r₁ ;
                  push-xl₁r₁⋗x'₁l'₁r'₁ = lemma-push-⋗ (⋗nd x x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁) acc-xl₁r₁
             in r⋘ x₁ x' push-xl₁r₁⋙x₂l₂r₂ l'≃r' push-xl₁r₁⋗x'₁l'₁r'₁
  ... | inj₂ x₁≤x | inj₂ x₂≤x | inj₂ x₂≤x₁ rewrite lemma-≡-height right x x₂ l₂ r₂ =
             let acc-xl₂r₂ = rs (node right x l₂ r₂) (lemma-≺-right right x (node perfect x₁ l₁ r₁) (node right x₂ l₂ r₂)) ;
                  x₁l₁r₁⋙push-xl₂r₂ = lemma-⋙r-push x₁ x l₁≃r₁ l₂⋙r₂ l₁≃l₂ acc-xl₂r₂
             in r⋘ x₂ x' x₁l₁r₁⋙push-xl₂r₂ l'≃r' (⋗nd x₁ x'₁ l₁≃r₁ l'₁≃r'₁ l₁⋗l'₁)

  lemma-⋙l-push : {l r l' r' : PLRTree}(x x' : A) → l ≃ r → l' ⋘ r' → l ⋗ r' → (acc : Acc _≺_ (node left x' l' r')) → node perfect x l r ⋙ push (node left x' l' r') acc
  lemma-⋙l-push x x' l≃r (x⋘ x'₁ x'₂ x'₃) (⋗nd x₁ .x'₃ x₂≃x₃ ≃lf (⋗lf x₂)) (acc rs)
      with tot≤ x' x'₁ | tot≤ x' x'₃ | tot≤ x'₁ x'₃
  ... | inj₁ x'≤x'₁ | inj₁ x'≤x'₃ | _ = ⋙l x x' l≃r (x⋘ x'₁ x'₂ x'₃) (⋗nd x₁ x'₃ x₂≃x₃ ≃lf (⋗lf x₂))
  ... | inj₁ x'≤x'₁ | inj₂ x'₃≤x' | _ = ⋙l x x'₃ l≃r (x⋘ x'₁ x'₂ x') (⋗nd x₁ x' x₂≃x₃ ≃lf (⋗lf x₂))
  ... | inj₂ x'₁≤x' | inj₁ x'≤x'₃ | _
      with tot≤ x' x'₂
  ... | inj₁ x'≤x'₂ = ⋙l x x'₁ l≃r (x⋘ x' x'₂ x'₃) (⋗nd x₁ x'₃ x₂≃x₃ ≃lf (⋗lf x₂))
  ... | inj₂ x'₂≤x' = ⋙l x x'₁ l≃r (x⋘ x'₂ x' x'₃) (⋗nd x₁ x'₃ x₂≃x₃ ≃lf (⋗lf x₂))
  lemma-⋙l-push x x' l≃r (x⋘ x'₁ x'₂ x'₃) (⋗nd x₁ .x'₃ x₂≃x₃ ≃lf (⋗lf x₂)) (acc rs) | inj₂ x'₁≤x' | inj₂ x'₃≤x' | inj₁ x'₁≤x'₃
      with tot≤ x' x'₂
  ... | inj₁ x'≤x'₂ = ⋙l x x'₁ l≃r (x⋘ x' x'₂ x'₃) (⋗nd x₁ x'₃ x₂≃x₃ ≃lf (⋗lf x₂))
  ... | inj₂ x'₂≤x' = ⋙l x x'₁ l≃r (x⋘ x'₂ x' x'₃) (⋗nd x₁ x'₃ x₂≃x₃ ≃lf (⋗lf x₂))
  lemma-⋙l-push x x' l≃r (x⋘ x'₁ x'₂ x'₃) (⋗nd x₁ .x'₃ x₂≃x₃ ≃lf (⋗lf x₂)) (acc rs) | inj₂ x'₁≤x' | inj₂ x'₃≤x' | inj₂ x'₃≤x'₁ =  ⋙l x x'₃ l≃r (x⋘ x'₁ x'₂ x') (⋗nd x₁ x' x₂≃x₃ ≃lf (⋗lf x₂))
  lemma-⋙l-push x x' l≃r (l⋘ {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁⋘r'₁ l'₂≃r'₂ r'₁≃l'₂) (⋗nd x₁ .x'₂ l₁≃r₁ _ l₁⋗l'₂) (acc rs)
      with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
  ... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = ⋙l x x' l≃r (l⋘ x'₁ x'₂ l'₁⋘r'₁ l'₂≃r'₂ r'₁≃l'₂) (⋗nd x₁ x'₂ l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂)
  ... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂  =
             let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right left x' (node left x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋘push-x'l'₂r'₂ = lemma-⋘-push (l⋘ x'₁ x' l'₁⋘r'₁ l'₂≃r'₂ r'₁≃l'₂) acc-x'l'₂r'₂ ;
                  x₁l₁r₁⋗push-x'l'₂r'₂ = lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂) acc-x'l'₂r'₂
             in ⋙l x x'₂ l≃r x'₁l'₁r'₁⋘push-x'l'₂r'₂ x₁l₁r₁⋗push-x'l'₂r'₂
  ... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height left x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node left x' l'₁ r'₁) (lemma-≺-left left x' (node left x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋘x'₂l'₂r'₂ = lemma-push-l⋘ x' x'₂ l'₁⋘r'₁ l'₂≃r'₂ r'₁≃l'₂ acc-x'l'₁r'₁
             in ⋙l x x'₁ l≃r push-x'l'₁r'₁⋘x'₂l'₂r'₂ (⋗nd x₁ x'₂ l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂)
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height left x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node left x' l'₁ r'₁) (lemma-≺-left left x' (node left x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋘x'₂l'₂r'₂ = lemma-push-l⋘ x' x'₂ l'₁⋘r'₁ l'₂≃r'₂ r'₁≃l'₂ acc-x'l'₁r'₁
             in ⋙l x x'₁ l≃r push-x'l'₁r'₁⋘x'₂l'₂r'₂ (⋗nd x₁ x'₂ l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂)
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
             let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right left x' (node left x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋘push-x'l'₂r'₂ = lemma-⋘-push (l⋘ x'₁ x' l'₁⋘r'₁ l'₂≃r'₂ r'₁≃l'₂) acc-x'l'₂r'₂ ;
                  x₁l₁r₁⋗push-x'l'₂r'₂ = lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂) acc-x'l'₂r'₂
             in ⋙l x x'₂ l≃r x'₁l'₁r'₁⋘push-x'l'₂r'₂ x₁l₁r₁⋗push-x'l'₂r'₂
  lemma-⋙l-push x x' l≃r (r⋘ {l'₁} {r'₁} {l'₂} {r'₂} x'₁ x'₂ l'₁⋙r'₁ l'₂≃r'₂ l'₁⋗l'₂) (⋗nd x₁ .x'₂ l₁≃r₁ _ l₁⋗l'₂) (acc rs)
      with tot≤ x' x'₁ | tot≤ x' x'₂ | tot≤ x'₁ x'₂
  ... | inj₁ x'≤x'₁ | inj₁ x'≤x'₂ | _ = ⋙l x x' l≃r (r⋘ x'₁ x'₂ l'₁⋙r'₁ l'₂≃r'₂ l'₁⋗l'₂) (⋗nd x₁ x'₂ l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂)
  ... | inj₁ x'≤x'₁ | inj₂ x'₂≤x' | _ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂  =
             let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right left x' (node right x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋘push-x'l'₂r'₂ = lemma-⋘-push (r⋘ x'₁ x' l'₁⋙r'₁ l'₂≃r'₂ l'₁⋗l'₂) acc-x'l'₂r'₂ ;
                  x₁l₁r₁⋗push-x'l'₂r'₂ = lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂) acc-x'l'₂r'₂
             in ⋙l x x'₂ l≃r x'₁l'₁r'₁⋘push-x'l'₂r'₂ x₁l₁r₁⋗push-x'l'₂r'₂
  ... | inj₂ x'₁≤x' | inj₁ x'≤x'₂ | _ rewrite lemma-≡-height right x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node right x' l'₁ r'₁) (lemma-≺-left left x' (node right x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋘x'₂l'₂r'₂ = lemma-push-r⋘ x' x'₂ l'₁⋙r'₁ l'₂≃r'₂ l'₁⋗l'₂ acc-x'l'₁r'₁
             in ⋙l x x'₁ l≃r push-x'l'₁r'₁⋘x'₂l'₂r'₂ (⋗nd x₁ x'₂ l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂)
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₁ x'₁≤x'₂ rewrite lemma-≡-height right x' x'₁ l'₁ r'₁ =
             let acc-x'l'₁r'₁ = rs (node right x' l'₁ r'₁) (lemma-≺-left left x' (node right x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  push-x'l'₁r'₁⋘x'₂l'₂r'₂ = lemma-push-r⋘ x' x'₂ l'₁⋙r'₁ l'₂≃r'₂ l'₁⋗l'₂ acc-x'l'₁r'₁
             in ⋙l x x'₁ l≃r push-x'l'₁r'₁⋘x'₂l'₂r'₂ (⋗nd x₁ x'₂ l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂)
  ... | inj₂ x'₁≤x' | inj₂ x'₂≤x' | inj₂ x'₂≤x'₁ rewrite lemma-≡-height perfect x' x'₂ l'₂ r'₂ =
             let acc-x'l'₂r'₂ = rs (node perfect x' l'₂ r'₂) (lemma-≺-right left x' (node right x'₁ l'₁ r'₁) (node perfect x'₂ l'₂ r'₂)) ;
                  x'₁l'₁r'₁⋘push-x'l'₂r'₂ = lemma-⋘-push (r⋘ x'₁ x' l'₁⋙r'₁ l'₂≃r'₂ l'₁⋗l'₂) acc-x'l'₂r'₂ ;
                  x₁l₁r₁⋗push-x'l'₂r'₂ = lemma-⋗-push (⋗nd x₁ x' l₁≃r₁ l'₂≃r'₂ l₁⋗l'₂) acc-x'l'₂r'₂
             in ⋙l x x'₂ l≃r x'₁l'₁r'₁⋘push-x'l'₂r'₂ x₁l₁r₁⋗push-x'l'₂r'₂

lemma-⋙-push : {t t' : PLRTree} → t ⋙ t' → (acc : Acc _≺_ t') → t ⋙ push t' acc
lemma-⋙-push (⋙p l⋗r) (acc rs) = ⋙p (lemma-⋗-push l⋗r (acc rs))
lemma-⋙-push (⋙l x x' l≃r l'⋘r' l⋗r') (acc rs) = lemma-⋙l-push x x' l≃r l'⋘r' l⋗r' (acc rs)
lemma-⋙-push (⋙r x x' l≃r l'⋙r' l≃l') (acc rs) = lemma-⋙r-push x x' l≃r l'⋙r' l≃l' (acc rs)

lemma-push-⋘ : {t t' : PLRTree} → t ⋘ t' → (acc : Acc _≺_ t) → push t acc ⋘ t'
lemma-push-⋘ (x⋘ x y z) _
    with tot≤ x y
... | inj₁ x≤y = x⋘ x y z
... | inj₂ y≤x = x⋘ y x z
lemma-push-⋘ (l⋘ x x' l⋘r l'≃r' r≃l') (acc rs) = lemma-push-l⋘ x x' l⋘r l'≃r' r≃l' (acc rs)
lemma-push-⋘ (r⋘ x x' l⋙r l'≃r' l⋗l') (acc rs) = lemma-push-r⋘ x x' l⋙r l'≃r' l⋗l' (acc rs)

lemma-push-complete-≃ : {l r : PLRTree}(x : A) → Complete l → Complete r → l ≃ r → (acc : Acc _≺_ (node perfect x l r)) → Complete (push (node perfect x l r) acc)
lemma-push-complete-≃ {l} {r} x cl cr l≃r (acc rs)
    with l | r | l≃r | cl | cr
... | leaf | leaf | ≃lf | _ | _ = perfect x leaf leaf ≃lf
... | node perfect x' l' r' | node perfect x'' l'' r'' | ≃nd .x' .x'' l'≃r' l''≃r'' l'≃l'' | perfect .x' cl' cr' _ | perfect .x'' cl'' cr'' _
    with tot≤ x x' | tot≤ x x'' | tot≤ x' x''
... | inj₁ x≤x' | inj₁ x≤x'' | _ = perfect x (perfect x' cl' cr' l'≃r') (perfect x'' cl'' cr'' l''≃r'') (≃nd x' x'' l'≃r' l''≃r'' l'≃l'')
... | inj₁ x≤x' | inj₂ x''≤x | _ rewrite lemma-≡-height perfect x x'' l'' r'' =
           let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right perfect x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                xl''r''≃push-xl''r'' = lemma-≃-push (sym≃ (≃nd x x l'≃r' l''≃r'' l'≃l'')) acc-xl''r'' ;
                x'l'r'≃push-xl''r'' = trans≃ (≃nd x' x l'≃r' l''≃r'' l'≃l'') xl''r''≃push-xl''r''
           in perfect x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') x'l'r'≃push-xl''r''
... | inj₂ x'≤x | inj₁ x≤x'' | _ rewrite lemma-≡-height perfect x x' l' r' =
           let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left perfect x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                push-xl'r'≃xl'r' = lemma-push-≃ (≃nd x x l'≃r' l''≃r'' l'≃l'') acc-xl'r' ;
                push-xl'r'≃x''l''r'' = trans≃ push-xl'r'≃xl'r' (≃nd x x'' l'≃r' l''≃r'' l'≃l'')
           in perfect x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') push-xl'r'≃x''l''r''
... | inj₂ x'≤x | inj₂ x''≤x | inj₁ x'≤x'' rewrite lemma-≡-height perfect x x' l' r' =
           let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left perfect x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                push-xl'r'≃xl'r' = lemma-push-≃ (≃nd x x l'≃r' l''≃r'' l'≃l'') acc-xl'r' ;
                push-xl'r'≃x''l''r'' = trans≃ push-xl'r'≃xl'r' (≃nd x x'' l'≃r' l''≃r'' l'≃l'')
           in perfect x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') push-xl'r'≃x''l''r''
... | inj₂ x'≤x | inj₂ x''≤x | inj₂ x''≤x' rewrite lemma-≡-height perfect x x'' l'' r'' =
           let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right perfect x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                xl''r''≃push-xl''r'' = lemma-≃-push (sym≃ (≃nd x x l'≃r' l''≃r'' l'≃l'')) acc-xl''r'' ;
                x'l'r'≃push-xl''r'' = trans≃ (≃nd x' x l'≃r' l''≃r'' l'≃l'') xl''r''≃push-xl''r''
           in perfect x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') x'l'r'≃push-xl''r''

lemma-push-complete-⋗ : {l r : PLRTree}(x : A) → Complete l → Complete r → l ⋗ r → (acc : Acc _≺_ (node right x l r)) → Complete (push (node right x l r) acc)
lemma-push-complete-⋗ {l} {r} x cl cr l⋗r (acc rs)
    with l | r | l⋗r | cl | cr
... | leaf | _ | () | _ | _
... | node perfect x' leaf leaf | leaf | ⋗lf .x' | perfect .x' leaf leaf ≃lf | leaf
    with tot≤ x x'
... | inj₁ x≤x' = right x (perfect x' leaf leaf ≃lf) leaf (⋙p (⋗lf x'))
... | inj₂ x'≤x = right x' (perfect x leaf leaf ≃lf) leaf (⋙p (⋗lf x))
lemma-push-complete-⋗ x cl cr l⋗r (acc rs) | node perfect x' l' r' | node perfect x'' l'' r'' | ⋗nd .x' .x'' l'≃r' l''≃r'' l'⋗l'' | perfect .x' cl' cr' _ | perfect .x'' cl'' cr'' _
    with tot≤ x x' | tot≤ x x'' | tot≤ x' x''
... | inj₁ x≤x' | inj₁ x≤x'' | _ = right x (perfect x' cl' cr' l'≃r') (perfect x'' cl'' cr'' l''≃r'') (⋙p (⋗nd x' x'' l'≃r' l''≃r'' l'⋗l''))
... | inj₁ x≤x' | inj₂ x''≤x | _ rewrite lemma-≡-height perfect x x'' l'' r'' =
           let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right right x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                x'l'r'⋗push-xl''r'' = lemma-⋗-push (⋗nd x' x l'≃r' l''≃r'' l'⋗l'') acc-xl''r''
           in right x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') (⋙p x'l'r'⋗push-xl''r'')
... | inj₂ x'≤x | inj₁ x≤x'' | _ rewrite lemma-≡-height perfect x x' l' r' =
           let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left right x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                push-xl'r'⋗x''l''r'' = lemma-push-⋗ (⋗nd x x'' l'≃r' l''≃r'' l'⋗l'') acc-xl'r'
           in right x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') (⋙p push-xl'r'⋗x''l''r'')
... | inj₂ x'≤x | inj₂ x''≤x | inj₁ x'≤x'' rewrite lemma-≡-height perfect x x' l' r' =
           let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left right x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                push-xl'r'⋗x''l''r'' = lemma-push-⋗ (⋗nd x x'' l'≃r' l''≃r'' l'⋗l'') acc-xl'r'
           in right x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') (⋙p push-xl'r'⋗x''l''r'')
... | inj₂ x'≤x | inj₂ x''≤x | inj₂ x''≤x' rewrite lemma-≡-height perfect x x'' l'' r'' =
           let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right right x (node perfect x' l' r') (node perfect x'' l'' r'')) ;
                x'l'r'⋗push-xl''r'' = lemma-⋗-push (⋗nd x' x l'≃r' l''≃r'' l'⋗l'') acc-xl''r''
           in right x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') (⋙p x'l'r'⋗push-xl''r'')

mutual
  lemma-push-complete-⋙ : {l r : PLRTree}(x : A) → Complete l → Complete r → l ⋙ r → (acc : Acc _≺_ (node right x l r)) → Complete (push (node right x l r) acc)
  lemma-push-complete-⋙ {l} {r} x cl cr l⋙r (acc rs)
      with l | r | l⋙r | cl | cr
  ... | leaf | _ | ⋙p () | _ | _
  ... | node perfect x' leaf leaf | leaf | ⋙p (⋗lf .x') | perfect .x' leaf leaf ≃lf | leaf =
             lemma-push-complete-⋗ x (perfect x' leaf leaf ≃lf) leaf (⋗lf x') (acc rs)
  ... | node perfect x' l' r' | node perfect x'' l'' r'' | ⋙p (⋗nd .x' .x'' l'≃r' l''≃r'' l'⋗l'') | perfect .x' cl' cr' _ | perfect .x'' cl'' cr'' _ =
             lemma-push-complete-⋗ x (perfect x' cl' cr' l'≃r') (perfect x'' cl'' cr'' l''≃r'') (⋗nd x' x'' l'≃r' l''≃r'' l'⋗l'') (acc rs)
  ... | node perfect x' leaf leaf | node left _ _ _ | ⋙p () | _ | _
  ... | node perfect x' leaf leaf | node right _ _ _ | ⋙p () | _ | _
  ... | node perfect x' l' r' | node left x'' l'' r'' | ⋙l .x' .x'' l'≃r' l''⋘r'' l'⋗r'' | perfect .x' cl' cr' _ | left .x'' cl'' cr'' _
      with tot≤ x x' | tot≤ x x'' | tot≤ x' x''
  ... | inj₁ x≤x' | inj₁ x≤x'' | _ = right x (perfect x' cl' cr' l'≃r') (left x'' cl'' cr'' l''⋘r'') (⋙l x' x'' l'≃r' l''⋘r'' l'⋗r'')
  ... | inj₁ x≤x' | inj₂ x''≤x | _ rewrite lemma-≡-height left x x'' l'' r'' =
             let acc-xl''r'' = rs (node left x l'' r'') (lemma-≺-right right x (node perfect x' l' r') (node left x'' l'' r'')) ;
                  x'l'r'⋙push-xl''r'' = lemma-⋙-push (⋙l x' x l'≃r' l''⋘r'' l'⋗r'') acc-xl''r''
             in right x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-⋘ x cl'' cr'' l''⋘r'' acc-xl''r'') x'l'r'⋙push-xl''r''
  ... | inj₂ x'≤x | inj₁ x≤x'' | _ rewrite lemma-≡-height perfect x x' l' r' =
             let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left right x (node perfect x' l' r') (node left x'' l'' r'')) ;
                  push-xl'r'⋙x''l''r'' = lemma-push-⋙ (⋙l x x'' l'≃r' l''⋘r'' l'⋗r'') acc-xl'r'
             in right x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (left x'' cl'' cr'' l''⋘r'') push-xl'r'⋙x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₁ x'≤x'' rewrite lemma-≡-height perfect x x' l' r' =
             let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left right x (node perfect x' l' r') (node left x'' l'' r'')) ;
                  push-xl'r'⋙x''l''r'' = lemma-push-⋙ (⋙l x x'' l'≃r' l''⋘r'' l'⋗r'') acc-xl'r'
             in right x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (left x'' cl'' cr'' l''⋘r'') push-xl'r'⋙x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₂ x''≤x' rewrite lemma-≡-height left x x'' l'' r'' =
             let acc-xl''r'' = rs (node left x l'' r'') (lemma-≺-right right x (node perfect x' l' r') (node left x'' l'' r'')) ;
                  x'l'r'⋙push-xl''r'' = lemma-⋙-push (⋙l x' x l'≃r' l''⋘r'' l'⋗r'') acc-xl''r''
             in right x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-⋘ x cl'' cr'' l''⋘r'' acc-xl''r'') x'l'r'⋙push-xl''r''
  lemma-push-complete-⋙ x cl cr l⋙r (acc rs)| node perfect x' l' r' | node right x'' l'' r'' | ⋙r .x' .x'' l'≃r' l''⋙r'' l'≃l'' | perfect .x' cl' cr' _ | right .x'' cl'' cr'' _
      with tot≤ x x' | tot≤ x x'' | tot≤ x' x''
  ... | inj₁ x≤x' | inj₁ x≤x'' | _ = right x (perfect x' cl' cr' l'≃r') (right x'' cl'' cr'' l''⋙r'') (⋙r x' x'' l'≃r' l''⋙r'' l'≃l'')
  ... | inj₁ x≤x' | inj₂ x''≤x | _ rewrite lemma-≡-height right x x'' l'' r'' =
             let acc-xl''r'' = rs (node right x l'' r'') (lemma-≺-right right x (node perfect x' l' r') (node right x'' l'' r'')) ;
                  x'l'r'⋙push-xl''r'' = lemma-⋙-push (⋙r x' x l'≃r' l''⋙r'' l'≃l'') acc-xl''r''
             in right x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-⋙ x cl'' cr'' l''⋙r'' acc-xl''r'') x'l'r'⋙push-xl''r''
  ... | inj₂ x'≤x | inj₁ x≤x'' | _ rewrite lemma-≡-height perfect x x' l' r' =
             let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left right x (node perfect x' l' r') (node right x'' l'' r'')) ;
                  push-xl'r'⋙x''l''r'' = lemma-push-⋙ (⋙r x x'' l'≃r' l''⋙r'' l'≃l'') acc-xl'r'
             in right x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (right x'' cl'' cr'' l''⋙r'') push-xl'r'⋙x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₁ x'≤x'' rewrite lemma-≡-height perfect x x' l' r' =
             let acc-xl'r' = rs (node perfect x l' r') (lemma-≺-left right x (node perfect x' l' r') (node right x'' l'' r'')) ;
                  push-xl'r'⋙x''l''r'' = lemma-push-⋙ (⋙r x x'' l'≃r' l''⋙r'' l'≃l'') acc-xl'r'
             in right x' (lemma-push-complete-≃ x cl' cr' l'≃r' acc-xl'r') (right x'' cl'' cr'' l''⋙r'') push-xl'r'⋙x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₂ x''≤x' rewrite lemma-≡-height right x x'' l'' r'' =
             let acc-xl''r'' = rs (node right x l'' r'') (lemma-≺-right right x (node perfect x' l' r') (node right x'' l'' r'')) ;
                  x'l'r'⋙push-xl''r'' = lemma-⋙-push (⋙r x' x l'≃r' l''⋙r'' l'≃l'') acc-xl''r''
             in right x'' (perfect x' cl' cr' l'≃r') (lemma-push-complete-⋙ x cl'' cr'' l''⋙r'' acc-xl''r'') x'l'r'⋙push-xl''r''
  lemma-push-complete-⋙ x cl cr l⋙r (acc rs) | node left _ _ _ | _ | ⋙p () | _ | _
  lemma-push-complete-⋙ x cl cr l⋙r (acc rs) | node right _ _ _ | _ | ⋙p () | _ | _

  lemma-push-complete-⋘ : {l r : PLRTree}(x : A) → Complete l → Complete r → l ⋘ r → (acc : Acc _≺_ (node left x l r)) → Complete (push (node left x l r) acc)
  lemma-push-complete-⋘ {l} {r} x cl cr l⋘r (acc rs)
      with l | r | l⋘r | cl | cr
  ... | node left x' l' r' | node perfect x'' l'' r'' | l⋘ .x' .x'' l'⋘r' l''≃r'' r'≃l'' | left .x' cl' cr' _ | perfect .x'' cl'' cr'' _
      with tot≤ x x' | tot≤ x x'' | tot≤ x' x''
  ... | inj₁ x≤x' | inj₁ x≤x'' | _ = left x (left x' cl' cr' l'⋘r') (perfect x'' cl'' cr'' l''≃r'') (l⋘ x' x'' l'⋘r' l''≃r'' r'≃l'')
  ... | inj₁ x≤x' | inj₂ x''≤x | _ rewrite lemma-≡-height perfect x x'' l'' r'' =
             let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right left x (node left x' l' r') (node perfect x'' l'' r'')) ;
                  xl''r''≃push-xl''r'' = lemma-≃-push  (≃nd x x l''≃r'' l''≃r'' (lemma-≃-≃ l''≃r'')) acc-xl''r'' ;
                  x''l''r''≃push-xl''r'' = trans≃ (≃nd x'' x l''≃r'' l''≃r'' (lemma-≃-≃ l''≃r'')) xl''r''≃push-xl''r'' ;
                  x'l'r'⋘push-xl''r'' = lemma-⋘-push (l⋘ x' x l'⋘r' l''≃r'' r'≃l'') acc-xl''r''
             in left x'' (left x' cl' cr' l'⋘r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') x'l'r'⋘push-xl''r''
  ... | inj₂ x'≤x | inj₁ x≤x'' | _ rewrite lemma-≡-height left x x' l' r' =
             let acc-xl'r' = rs (node left x l' r') (lemma-≺-left left x (node left x' l' r') (node perfect x'' l'' r'')) ;
                  push-xl'r'⋘x''l''r'' = lemma-push-⋘ (l⋘ x x'' l'⋘r' l''≃r'' r'≃l'') acc-xl'r'
             in left x' (lemma-push-complete-⋘ x cl' cr' l'⋘r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') push-xl'r'⋘x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₁ x'≤x'' rewrite lemma-≡-height left x x' l' r' =
             let acc-xl'r' = rs (node left x l' r') (lemma-≺-left left x (node left x' l' r') (node perfect x'' l'' r'')) ;
                  push-xl'r'⋘x''l''r'' = lemma-push-⋘ (l⋘ x x'' l'⋘r' l''≃r'' r'≃l'') acc-xl'r'
             in left x' (lemma-push-complete-⋘ x cl' cr' l'⋘r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') push-xl'r'⋘x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₂ x''≤x' rewrite lemma-≡-height perfect x x'' l'' r'' =
             let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right left x (node left x' l' r') (node perfect x'' l'' r'')) ;
                  xl''r''≃push-xl''r'' = lemma-≃-push  (≃nd x x l''≃r'' l''≃r'' (lemma-≃-≃ l''≃r'')) acc-xl''r'' ;
                  x''l''r''≃push-xl''r'' = trans≃ (≃nd x'' x l''≃r'' l''≃r'' (lemma-≃-≃ l''≃r'')) xl''r''≃push-xl''r'' ;
                  x'l'r'⋘push-xl''r'' = lemma-⋘-push (l⋘ x' x l'⋘r' l''≃r'' r'≃l'') acc-xl''r''
             in left x'' (left x' cl' cr' l'⋘r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') x'l'r'⋘push-xl''r''
  lemma-push-complete-⋘ x cl cr l⋘r (acc rs) | node right x' (node perfect x'' leaf leaf) leaf | node perfect x''' leaf leaf | x⋘ .x' .x'' .x''' | right .x' (perfect .x'' leaf leaf ≃lf) leaf (⋙p (⋗lf .x'')) | perfect .x''' leaf leaf ≃lf
      with tot≤ x x' | tot≤ x x''' | tot≤ x' x'''
  ... | inj₁ x≤x' | inj₁ x≤x''' | _ = left x (right x' (perfect x'' leaf leaf ≃lf) leaf (⋙p (⋗lf x''))) (perfect x''' leaf leaf ≃lf) (x⋘ x' x'' x''')
  ... | inj₁ x≤x' | inj₂ x'''≤x | _ = left x''' (right x' (perfect x'' leaf leaf ≃lf) leaf (⋙p (⋗lf x''))) (perfect x leaf leaf ≃lf) (x⋘ x' x'' x)
  ... | inj₂ x'≤x | inj₁ x≤x''' | _ =
             let acc-xx'' = rs (node right x (node perfect x'' leaf leaf) leaf) (lemma-≺-left left x (node right x' (node perfect x'' leaf leaf) leaf) (node perfect x''' leaf leaf)) ;
                  cdl = lemma-push-complete-⋙ x (perfect x'' leaf leaf ≃lf) leaf (⋙p (⋗lf x'')) acc-xx''
             in left x' cdl (perfect x''' leaf leaf ≃lf) (lemma-push-⋘ (x⋘ x x'' x''') acc-xx'')
  ... | inj₂ x'≤x | inj₂ x'''≤x | inj₁ x'≤x''' =
             let acc-xx'' = rs (node right x (node perfect x'' leaf leaf) leaf) (lemma-≺-left left x (node right x' (node perfect x'' leaf leaf) leaf) (node perfect x''' leaf leaf)) ;
                  cdl = lemma-push-complete-⋙ x (perfect x'' leaf leaf ≃lf) leaf (⋙p (⋗lf x'')) acc-xx''
             in left x' cdl (perfect x''' leaf leaf ≃lf) (lemma-push-⋘ (x⋘ x x'' x''') acc-xx'')
  ... | inj₂ x'≤x | inj₂ x'''≤x | inj₂ x'''≤x' = left x''' (right x' (perfect x'' leaf leaf ≃lf) leaf (⋙p (⋗lf x''))) (perfect x leaf leaf ≃lf) (x⋘ x' x'' x)
  lemma-push-complete-⋘ x cl cr l⋘r (acc rs) | node right x' l' r' | node perfect x'' l'' r'' | r⋘ .x' .x'' l'⋙r' l''≃r'' l'⋗l'' | right .x' cl' cr' _ | perfect .x'' cl'' cr'' _
      with tot≤ x x' | tot≤ x x'' | tot≤ x' x''
  ... | inj₁ x≤x' | inj₁ x≤x'' | _ = left x (right x' cl' cr' l'⋙r') (perfect x'' cl'' cr'' l''≃r'') (r⋘ x' x'' l'⋙r' l''≃r'' l'⋗l'')
  ... | inj₁ x≤x' | inj₂ x''≤x | _ rewrite lemma-≡-height perfect x x'' l'' r'' =
             let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right left x (node right x' l' r') (node perfect x'' l'' r'')) ;
                  x'lr'⋘push-xl''r'' = lemma-⋘-push (r⋘ x' x l'⋙r' l''≃r'' l'⋗l'') acc-xl''r''
             in left x'' (right x' cl' cr' l'⋙r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') x'lr'⋘push-xl''r''
  ... | inj₂ x'≤x | inj₁ x≤x'' | _ rewrite lemma-≡-height right x x' l' r' =
             let acc-xl'r' = rs (node right x l' r') (lemma-≺-left left x (node right x' l' r') (node perfect x'' l'' r'')) ;
                  push-xl'r'⋘x''l''r'' = lemma-push-⋘ (r⋘ x x'' l'⋙r' l''≃r'' l'⋗l'') acc-xl'r'
             in left x' (lemma-push-complete-⋙ x cl' cr' l'⋙r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') push-xl'r'⋘x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₁ x'≤x'' rewrite lemma-≡-height right x x' l' r' =
             let acc-xl'r' = rs (node right x l' r') (lemma-≺-left left x (node right x' l' r') (node perfect x'' l'' r'')) ;
                  push-xl'r'⋘x''l''r'' = lemma-push-⋘ (r⋘ x x'' l'⋙r' l''≃r'' l'⋗l'') acc-xl'r'
             in left x' (lemma-push-complete-⋙ x cl' cr' l'⋙r' acc-xl'r') (perfect x'' cl'' cr'' l''≃r'') push-xl'r'⋘x''l''r''
  ... | inj₂ x'≤x | inj₂ x''≤x | inj₂ x''≤x' rewrite lemma-≡-height perfect x x'' l'' r'' =
             let acc-xl''r'' = rs (node perfect x l'' r'') (lemma-≺-right left x (node right x' l' r') (node perfect x'' l'' r'')) ;
                   x'lr'⋘push-xl''r'' = lemma-⋘-push (r⋘ x' x l'⋙r' l''≃r'' l'⋗l'') acc-xl''r''
             in left x'' (right x' cl' cr' l'⋙r') (lemma-push-complete-≃ x cl'' cr'' l''≃r'' acc-xl''r'') x'lr'⋘push-xl''r''

lemma-push-complete : {t : PLRTree} → Complete t → (acc : Acc _≺_ t) → Complete (push t acc)
lemma-push-complete leaf _ = leaf
lemma-push-complete (perfect {l} {r}x cl cr l≃r) (acc rs) = lemma-push-complete-≃ x cl cr l≃r (acc rs)
lemma-push-complete (left {l} {r}x cl cr l⋘r) (acc rs) = lemma-push-complete-⋘ x cl cr l⋘r (acc rs)
lemma-push-complete (right {l} {r}x cl cr l⋙r) (acc rs) = lemma-push-complete-⋙ x cl cr l⋙r (acc rs)


module LiftGet where

open import Data.Unit using (⊤ ; tt)
open import Data.Nat using (ℕ ; suc)
open import Data.Vec using (Vec ; toList ; fromList) renaming ([] to []V ; _∷_ to _∷V_ ; map to mapV)
open import Data.List using (List ; [] ; _∷_ ; length ; replicate ; map)
open import Data.List.Properties using (length-map)
open import Data.Product using (∃ ; _,_ ; proj₁ ; proj₂)
open import Function using (_∘_ ; flip ; const)
open import Relation.Binary.Core using (_≡_)
open import Relation.Binary.PropositionalEquality using (_≗_ ; sym ; cong ; refl ; subst ; trans ; proof-irrelevance ; module ≡-Reasoning)
open import Relation.Binary.HeterogeneousEquality as H using (module ≅-Reasoning ; _≅_ ; ≅-to-≡ ; ≡-to-≅ ; ≡-subst-removable) renaming (refl to het-refl ; sym to het-sym ; cong to het-cong ; reflexive to het-reflexive)

import FreeTheorems
open import Generic using (length-replicate ; toList-fromList ; toList-subst)
open FreeTheorems.ListList using (get-type) renaming (free-theorem to free-theoremL ; Get to GetL ; module Get to GetL)
open FreeTheorems.VecVec using () renaming (get-type to getV-type ; Get to GetV ; module Get to GetV)

getVec-to-getList : {getlen : ℕ → ℕ} → (getV-type getlen) → get-type
getVec-to-getList get = toList ∘ get ∘ fromList

fromList∘map : {α β : Set} → (f : α → β) → (l : List α) → fromList (map f l) ≅ mapV f (fromList l)
fromList∘map f []       = het-refl
fromList∘map f (x ∷ xs) = H.cong₂ (λ n → _∷V_ {n = n} (f x)) (H.reflexive (length-map f xs)) (fromList∘map f xs)

toList∘map : {α β : Set} {n : ℕ} → (f : α → β) → (v : Vec α n) → toList (mapV f v) ≡ map f (toList v)
toList∘map f []V       = refl
toList∘map f (x ∷V xs) = cong (_∷_ (f x)) (toList∘map f xs)

GetV-to-GetL : GetV → GetL
GetV-to-GetL getrecord = record { get = toList ∘ get ∘ fromList; free-theorem = ft }
  where open GetV getrecord
        open ≡-Reasoning
        ft : {α β : Set} → (f : α → β) → (xs : List α) → toList (get (fromList (map f xs))) ≡ map f (toList (get (fromList xs)))
        ft f xs = begin
          toList (get (fromList (map f xs)))
            ≅⟨ H.cong₂ {B = Vec _} (λ n → toList ∘ get) (het-reflexive (length-map f xs)) (fromList∘map f xs) ⟩
          toList (get (mapV f (fromList xs)))
            ≡⟨ cong toList (free-theorem f (fromList xs)) ⟩
          toList (mapV f (get (fromList xs)))
            ≡⟨ toList∘map f (get (fromList xs)) ⟩
          map f (toList (get (fromList xs))) ∎

getList-to-getlen : get-type → ℕ → ℕ
getList-to-getlen get = length ∘ get ∘ flip replicate tt

replicate-length : {A : Set} → (l : List A) → map (const tt) l ≡ replicate (length l) tt
replicate-length [] = refl
replicate-length (_ ∷ l) = cong (_∷_ tt) (replicate-length l)

getList-length : (get : get-type) → {B : Set} → (l : List B) → length (get l) ≡ getList-to-getlen get (length l)
getList-length get l = begin
  length (get l)
    ≡⟨ sym (length-map (const tt) (get l)) ⟩
  length (map (const tt) (get l))
    ≡⟨ cong length (sym (free-theoremL get (const tt) l)) ⟩
  length (get (map (const tt) l))
    ≡⟨ cong (length ∘ get) (replicate-length l) ⟩
  length (get (replicate (length l) tt)) ∎
  where open ≡-Reasoning

length-toList : {A : Set} {n : ℕ} → (v : Vec A n) → length (toList v) ≡ n
length-toList []V = refl
length-toList (x ∷V xs) = cong suc (length-toList xs)

getList-to-getVec-length-property : (get : get-type) → {C : Set} → {m : ℕ} → (v : Vec C m) → length (get (toList v)) ≡ length (get (replicate m tt))
getList-to-getVec-length-property get {_} {m} v = begin
    length (get (toList v))
      ≡⟨ getList-length get (toList v) ⟩
    length (get (replicate (length (toList v)) tt))
      ≡⟨ cong (length ∘ get ∘ flip replicate tt) (length-toList v) ⟩
    length (get (replicate m tt)) ∎
    where open ≡-Reasoning

getList-to-getVec : get-type → ∃ λ (getlen : ℕ → ℕ) → (getV-type getlen)
getList-to-getVec get = getlen , get'
  where getlen : ℕ → ℕ
        getlen = getList-to-getlen get
        get' : {C : Set} {m : ℕ} → Vec C m → Vec C (getlen m)
        get' {C} v = subst (Vec C) (getList-to-getVec-length-property get v) (fromList (get (toList v)))

private
  module GetV-Implementation (getrecord : GetL) where

    open GetL getrecord

    getlen = length ∘ get ∘ flip replicate tt

    length-property : {C : Set} {m : ℕ} → (s : Vec C m) → length (get (toList s)) ≡ getlen m
    length-property = getList-to-getVec-length-property get

    getV : {C : Set} {m : ℕ} → Vec C m → Vec C (getlen m)
    getV s = subst (Vec _) (length-property s) (fromList (get (toList s)))

    ft : {α β : Set} (f : α → β) {n : ℕ} (v : Vec α n) → getV (mapV f v) ≡ mapV f (getV v)
    ft f v = ≅-to-≡ (begin
      subst (Vec _) (length-property (mapV f v)) (fromList (get (toList (mapV f v))))
        ≅⟨ ≡-subst-removable (Vec _) (length-property (mapV f v)) (fromList (get (toList (mapV f v)))) ⟩
      fromList (get (toList (mapV f v)))
        ≅⟨ het-cong (fromList ∘ get) (het-reflexive (toList∘map f v)) ⟩
      fromList (get (map f (toList v)))
        ≅⟨ het-cong fromList (het-reflexive (free-theorem f (toList v))) ⟩
      fromList (map f (get (toList v)))
        ≅⟨ fromList∘map f (get (toList v)) ⟩
      mapV f (fromList (get (toList v)))
        ≅⟨ H.cong₂ (λ n → mapV {n = n} f) (H.reflexive (length-property v)) (H.sym (≡-subst-removable (Vec _) (length-property v) (fromList (get (toList v))))) ⟩
      mapV f (subst (Vec _) (length-property v) (fromList (get (toList v)))) ∎)
      where open ≅-Reasoning

GetL-to-GetV : GetL → GetV
GetL-to-GetV getrecord = record { getlen = getlen; get = getV; free-theorem = ft }
  where open GetV-Implementation getrecord

get-commut-1-≅ : (get : get-type) {A : Set} → (l : List A) → fromList (get l) ≅ proj₂ (getList-to-getVec get) (fromList l)
get-commut-1-≅ get l = begin
  fromList (get l)
    ≅⟨ het-cong (fromList ∘ get) (≡-to-≅ (sym (toList-fromList l))) ⟩
  fromList (get (toList (fromList l)))
    ≅⟨ het-sym (≡-subst-removable (Vec _) (getList-to-getVec-length-property get (fromList l)) (fromList (get (toList (fromList l))))) ⟩
  subst (Vec _) (getList-to-getVec-length-property get (fromList l)) (fromList (get (toList (fromList l)))) ∎
  where open ≅-Reasoning

get-commut-1 : (get : get-type) {A : Set} → (l : List A) → fromList (get l) ≡ subst (Vec A) (sym (getList-length get l)) (proj₂ (getList-to-getVec get) (fromList l))
get-commut-1 get {A} l = ≅-to-≡ (begin
  fromList (get l)
    ≅⟨ get-commut-1-≅ get l ⟩
  proj₂ (getList-to-getVec get) (fromList l)
    ≅⟨ het-sym (≡-subst-removable (Vec _) (sym (getList-length get l)) (proj₂ (getList-to-getVec get) (fromList l))) ⟩
  subst (Vec _) (sym (getList-length get l)) (proj₂ (getList-to-getVec get) (fromList l)) ∎)
  where open ≅-Reasoning

get-trafo-1 : (get : get-type) → {B : Set} → getVec-to-getList (proj₂ (getList-to-getVec get)) {B} ≗ get {B}
get-trafo-1 get {B} l = begin
  getVec-to-getList (proj₂ (getList-to-getVec get)) l
    ≡⟨ refl ⟩
  toList (proj₂ (getList-to-getVec get) (fromList l))
    ≡⟨ refl ⟩
  toList (subst (Vec B) (getList-to-getVec-length-property get (fromList l)) (fromList (get (toList (fromList l)))))
    ≡⟨ toList-subst (fromList (get (toList (fromList l)))) (getList-to-getVec-length-property get (fromList l)) ⟩
  toList (fromList (get (toList (fromList l))))
    ≡⟨ toList-fromList (get (toList (fromList l))) ⟩
  get (toList (fromList l))
    ≡⟨ cong get (toList-fromList l) ⟩
  get l ∎
  where open ≡-Reasoning

GetLVL-identity : (G : GetL) → {A : Set} → GetL.get (GetV-to-GetL (GetL-to-GetV G)) ≗ GetL.get G {A}
GetLVL-identity G = get-trafo-1 (GetL.get G)

vec-len : {A : Set} {n : ℕ} → Vec A n → ℕ
vec-len {_} {n} _ = n

fromList-toList : {A : Set} {n : ℕ} → (v : Vec A n) → fromList (toList v) ≅ v
fromList-toList []V       = het-refl
fromList-toList (x ∷V xs) = H.cong₂ (λ n → _∷V_ {n = n} x) (het-reflexive (length-toList xs)) (fromList-toList xs)

get-commut-2 : {getlen : ℕ → ℕ} → (get : getV-type getlen) → {B : Set} {n : ℕ} → (toList ∘ get {B} {n}) ≗ (getVec-to-getList get) ∘ toList
get-commut-2 get {B} v = sym (≅-to-≡ (H.cong₂ (λ n → toList ∘ get {n = n}) (H.reflexive (length-toList v)) (fromList-toList v)))

get-trafo-2-getlen : {getlen : ℕ → ℕ} → (get : getV-type getlen) → proj₁ (getList-to-getVec (getVec-to-getList get)) ≗ getlen
get-trafo-2-getlen {getlen} get n = begin
  proj₁ (getList-to-getVec (getVec-to-getList get)) n
    ≡⟨ refl ⟩
  length (toList (get (fromList (replicate n tt))))
    ≡⟨ length-toList (get (fromList (replicate n tt))) ⟩
  vec-len (get (fromList (replicate n tt)))
    ≡⟨ cong getlen (length-replicate n) ⟩
  getlen n ∎
  where open ≡-Reasoning

get-trafo-2-get-≅ : {getlen : ℕ → ℕ} → (get : getV-type getlen) → {B : Set} {n : ℕ} → (v : Vec B n) → proj₂ (getList-to-getVec (getVec-to-getList get)) v ≅ get v
get-trafo-2-get-≅ {getlen} get v = begin
  subst (Vec _) (getList-to-getVec-length-property (getVec-to-getList get) v) (fromList (toList (get (fromList (toList v)))))
    ≅⟨ ≡-subst-removable (Vec _) (getList-to-getVec-length-property (getVec-to-getList get) v) (fromList (toList (get (fromList (toList v))))) ⟩
  fromList (toList (get (fromList (toList v))))
    ≅⟨ fromList-toList (get (fromList (toList v))) ⟩
  get (fromList (toList v))
    ≅⟨ H.cong₂ (λ n → get {n = n}) (H.reflexive (length-toList v)) (fromList-toList v) ⟩
  get v ∎
  where open ≅-Reasoning

get-trafo-2-get : {getlen : ℕ → ℕ} → (get : getV-type getlen) → {B : Set} {n : ℕ} → proj₂ (getList-to-getVec (getVec-to-getList get)) ≗ subst (Vec B) (sym (get-trafo-2-getlen get n)) ∘ get
get-trafo-2-get get v = ≅-to-≡ (begin
  proj₂ (getList-to-getVec (getVec-to-getList get)) v
    ≅⟨ get-trafo-2-get-≅ get v ⟩
  get v
    ≅⟨ het-sym (≡-subst-removable (Vec _) (sym (get-trafo-2-getlen get (vec-len v))) (get v)) ⟩
  subst (Vec _) (sym (get-trafo-2-getlen get (vec-len v))) (get v) ∎)
  where open ≅-Reasoning