------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties related to Any
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

open import Relation.Binary.Bundles using (StrictTotalOrder)

module Data.Tree.AVL.Indexed.Relation.Unary.Any.Properties
  {a ℓ₁ ℓ₂} (sto : StrictTotalOrder a ℓ₁ ℓ₂)
  where

open import Data.Maybe.Base as Maybe using (Maybe; nothing; just; maybe′)
open import Data.Maybe.Properties using (just-injective)
open import Data.Maybe.Relation.Unary.All as Maybe using (nothing; just)
open import Data.Nat.Base using ()
open import Data.Product.Base as Prod using (; ∃-syntax; _×_; _,_; proj₁; proj₂)
open import Data.Sum.Base as Sum using (_⊎_; inj₁; inj₂)
open import Function.Base as F
open import Level using (Level)

open import Relation.Binary.Definitions using (_Respects_; tri<; tri≈; tri>)
open import Relation.Binary.PropositionalEquality.Core using (_≡_) renaming (refl to ≡-refl)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (contradiction)
open import Relation.Unary using (Pred; _∩_)

open import Data.Tree.AVL.Indexed sto as AVL
open import Data.Tree.AVL.Indexed.Relation.Unary.Any sto as Any
open StrictTotalOrder sto renaming (Carrier to Key; trans to <-trans); open Eq using (sym; trans)

open import Relation.Binary.Construct.Add.Extrema.Strict _<_ using ([<]-injective)

import Relation.Binary.Reasoning.StrictPartialOrder as <-Reasoning

private
  variable
    v p q : Level
    k : Key
    V : Value v
    l u : Key⁺
    n : 
    P Q : Pred (K& V) p

------------------------------------------------------------------------
-- Any.lookup

lookup-result : {t : Tree V l u n} (p : Any P t)  P (Any.lookup p)
lookup-result (here p)  = p
lookup-result (left p)  = lookup-result p
lookup-result (right p) = lookup-result p

lookup-bounded : {t : Tree V l u n} (p : Any P t)  l < Any.lookup p .key < u
lookup-bounded {t = node kv lk ku bal} (here p)  = ordered lk , ordered ku
lookup-bounded {t = node kv lk ku bal} (left p)  =
  Prod.map₂ (flip (trans⁺ _) (ordered ku)) (lookup-bounded p)
lookup-bounded {t = node kv lk ku bal} (right p) =
  Prod.map₁ (trans⁺ _ (ordered lk)) (lookup-bounded p)

lookup-rebuild : {t : Tree V l u n} (p : Any P t)  Q (Any.lookup p)  Any Q t
lookup-rebuild (here _)  q = here q
lookup-rebuild (left p)  q = left (lookup-rebuild p q)
lookup-rebuild (right p) q = right (lookup-rebuild p q)

lookup-rebuild-accum : {t : Tree V l u n} (p : Any P t)  Q (Any.lookup p)  Any (Q  P) t
lookup-rebuild-accum p q = lookup-rebuild p (q , lookup-result p)

joinˡ⁺-here⁺ :  {l u   h} 
             (kv : K& V) 
             (l :  λ i  Tree V l [ kv .key ] (i  )) 
             (r : Tree V [ kv .key ] u ) 
             (bal :     h) 
             P kv  Any P (proj₂ (joinˡ⁺ kv l r bal))
joinˡ⁺-here⁺ k₂ (0# , t₁)                       t₃ bal p = here p
joinˡ⁺-here⁺ k₂ (1# , t₁)                       t₃ ∼0  p = here p
joinˡ⁺-here⁺ k₂ (1# , t₁)                       t₃ ∼+  p = here p
joinˡ⁺-here⁺ k₄ (1# , node k₂ t₁ t₃ ∼-)         t₅ ∼-  p = right (here p)
joinˡ⁺-here⁺ k₄ (1# , node k₂ t₁ t₃ ∼0)         t₅ ∼-  p = right (here p)
joinˡ⁺-here⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  p = right (here p)

joinˡ⁺-left⁺ :  {l u   h} 
             (k : K& V) 
             (l :  λ i  Tree V l [ k .key ] (i  )) 
             (r : Tree V [ k .key ] u ) 
             (bal :     h) 
             Any P (proj₂ l)  Any P (proj₂ (joinˡ⁺ k l r bal))
joinˡ⁺-left⁺ k₂ (0# , t₁)                       t₃ bal p                 = left p
joinˡ⁺-left⁺ k₂ (1# , t₁)                       t₃ ∼0  p                 = left p
joinˡ⁺-left⁺ k₂ (1# , t₁)                       t₃ ∼+  p                 = left p
joinˡ⁺-left⁺ k₄ (1# , node k₂ t₁ t₃ ∼-)         t₅ ∼-  (here p)          = here p
joinˡ⁺-left⁺ k₄ (1# , node k₂ t₁ t₃ ∼-)         t₅ ∼-  (left p)          = left p
joinˡ⁺-left⁺ k₄ (1# , node k₂ t₁ t₃ ∼-)         t₅ ∼-  (right p)         = right (left p)
joinˡ⁺-left⁺ k₄ (1# , node k₂ t₁ t₃ ∼0)         t₅ ∼-  (here p)          = here p
joinˡ⁺-left⁺ k₄ (1# , node k₂ t₁ t₃ ∼0)         t₅ ∼-  (left p)          = left p
joinˡ⁺-left⁺ k₄ (1# , node k₂ t₁ t₃ ∼0)         t₅ ∼-  (right p)         = right (left p)
joinˡ⁺-left⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  (here p)          = left (here p)
joinˡ⁺-left⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  (left p)          = left (left p)
joinˡ⁺-left⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  (right (here p))  = here p
joinˡ⁺-left⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  (right (left p))  = left (right p)
joinˡ⁺-left⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  (right (right p)) = right (left p)

joinˡ⁺-right⁺ :  {l u   h} 
                (kv@(k , v) : K& V) 
                (l :  λ i  Tree V l [ k ] (i  )) 
                (r : Tree V [ k ] u ) 
                (bal :     h) 
                Any P r  Any P (proj₂ (joinˡ⁺ kv l r bal))
joinˡ⁺-right⁺ k₂ (0# , t₁)                       t₃ bal p = right p
joinˡ⁺-right⁺ k₂ (1# , t₁)                       t₃ ∼0  p = right p
joinˡ⁺-right⁺ k₂ (1# , t₁)                       t₃ ∼+  p = right p
joinˡ⁺-right⁺ k₄ (1# , node k₂ t₁ t₃ ∼-)         t₅ ∼-  p = right (right p)
joinˡ⁺-right⁺ k₄ (1# , node k₂ t₁ t₃ ∼0)         t₅ ∼-  p = right (right p)
joinˡ⁺-right⁺ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼-  p = right (right p)

joinʳ⁺-here⁺ :  {l u   h} 
               (kv : K& V) 
               (l : Tree V l [ kv .key ] ) 
               (r :  λ i  Tree V [ kv .key ] u (i  )) 
               (bal :     h) 
               P kv  Any P (proj₂ (joinʳ⁺ kv l r bal))
joinʳ⁺-here⁺ k₂ t₁ (0# , t₃)                       bal p = here p
joinʳ⁺-here⁺ k₂ t₁ (1# , t₃)                       ∼0  p = here p
joinʳ⁺-here⁺ k₂ t₁ (1# , t₃)                       ∼-  p = here p
joinʳ⁺-here⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼+)         ∼+  p = left (here p)
joinʳ⁺-here⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼0)         ∼+  p = left (here p)
joinʳ⁺-here⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  p = left (here p)

joinʳ⁺-left⁺ :  {l u   h} 
              (kv : K& V) 
              (l : Tree V l [ kv .key ] ) 
              (r :  λ i  Tree V [ kv .key ] u (i  )) 
              (bal :     h) 
              Any P l  Any P (proj₂ (joinʳ⁺ kv l r bal))
joinʳ⁺-left⁺ k₂ t₁ (0# , t₃)                       bal p = left p
joinʳ⁺-left⁺ k₂ t₁ (1# , t₃)                       ∼0  p = left p
joinʳ⁺-left⁺ k₂ t₁ (1# , t₃)                       ∼-  p = left p
joinʳ⁺-left⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼+)         ∼+  p = left (left p)
joinʳ⁺-left⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼0)         ∼+  p = left (left p)
joinʳ⁺-left⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  p = left (left p)

joinʳ⁺-right⁺ :  {l u   h} 
                (kv : K& V) 
                (l : Tree V l [ kv .key ] ) 
                (r :  λ i  Tree V [ kv .key ] u (i  )) 
                (bal :     h) 
                Any P (proj₂ r)  Any P (proj₂ (joinʳ⁺ kv l r bal))
joinʳ⁺-right⁺ k₂ t₁ (0# , t₃)                       bal p                = right p
joinʳ⁺-right⁺ k₂ t₁ (1# , t₃)                       ∼0  p                = right p
joinʳ⁺-right⁺ k₂ t₁ (1# , t₃)                       ∼-  p                = right p
joinʳ⁺-right⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼+)         ∼+  (here p)         = here p
joinʳ⁺-right⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼+)         ∼+  (left p)         = left (right p)
joinʳ⁺-right⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼+)         ∼+  (right p)        = right p
joinʳ⁺-right⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼0)         ∼+  (here p)         = here p
joinʳ⁺-right⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼0)         ∼+  (left p)         = left (right p)
joinʳ⁺-right⁺ k₂ t₁ (1# , node k₄ t₃ t₅ ∼0)         ∼+  (right p)        = right p
joinʳ⁺-right⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  (here p)         = right (here p)
joinʳ⁺-right⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  (left (here p))  = here p
joinʳ⁺-right⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  (left (left p))  = left (right p)
joinʳ⁺-right⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  (left (right p)) = right (left p)
joinʳ⁺-right⁺ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  (right p)        = right (right p)

joinˡ⁺⁻ :  {l u   h} 
            (kv@(k , v) : K& V) 
            (l :  λ i  Tree V l [ k ] (i  )) 
            (r : Tree V [ k ] u ) 
            (bal :     h) 
            Any P (proj₂ (joinˡ⁺ kv l r bal)) 
            P kv  Any P (proj₂ l)  Any P r
joinˡ⁺⁻ k₂ (0# , t₁)                       t₃ ba = Any.toSum
joinˡ⁺⁻ k₂ (1# , t₁)                       t₃ ∼0 = Any.toSum
joinˡ⁺⁻ k₂ (1# , t₁)                       t₃ ∼+ = Any.toSum
joinˡ⁺⁻ k₄ (1# , node k₂ t₁ t₃ ∼-)         t₅ ∼- = λ where
  (left p)           inj₂ (inj₁ (left p))
  (here p)           inj₂ (inj₁ (here p))
  (right (left p))   inj₂ (inj₁ (right p))
  (right (here p))   inj₁ p
  (right (right p))  inj₂ (inj₂ p)
joinˡ⁺⁻ k₄ (1# , node k₂ t₁ t₃ ∼0)         t₅ ∼- = λ where
  (left p)           inj₂ (inj₁ (left p))
  (here p)           inj₂ (inj₁ (here p))
  (right (left p))   inj₂ (inj₁ (right p))
  (right (here p))   inj₁ p
  (right (right p))  inj₂ (inj₂ p)
joinˡ⁺⁻ k₆ (1# , node⁺ k₂ t₁ k₄ t₃ t₅ bal) t₇ ∼- = λ where
  (left (left p))    inj₂ (inj₁ (left p))
  (left (here p))    inj₂ (inj₁ (here p))
  (left (right p))   inj₂ (inj₁ (right (left p)))
  (here p)           inj₂ (inj₁ (right (here p)))
  (right (left p))   inj₂ (inj₁ (right (right p)))
  (right (here p))   inj₁ p
  (right (right p))  inj₂ (inj₂ p)

joinʳ⁺⁻ :  {l u   h} 
            (kv : K& V) 
            (l : Tree V l [ kv .key ] ) 
            (r :  λ i  Tree V [ kv .key ] u (i  )) 
            (bal :     h) 
            Any P (proj₂ (joinʳ⁺ kv l r bal)) 
            P kv  Any P l  Any P (proj₂ r)
joinʳ⁺⁻ k₂ t₁ (0# , t₃)                       bal = Any.toSum
joinʳ⁺⁻ k₂ t₁ (1# , t₃)                       ∼0  = Any.toSum
joinʳ⁺⁻ k₂ t₁ (1# , t₃)                       ∼-  = Any.toSum
joinʳ⁺⁻ k₂ t₁ (1# , node k₄ t₃ t₅ ∼+)         ∼+  = λ where
  (left (left p))   inj₂ (inj₁ p)
  (left (here p))   inj₁ p
  (left (right p))  inj₂ (inj₂ (left p))
  (here p)          inj₂ (inj₂ (here p))
  (right p)         inj₂ (inj₂ (right p))
joinʳ⁺⁻ k₂ t₁ (1# , node k₄ t₃ t₅ ∼0)         ∼+  = λ where
  (left (left p))   inj₂ (inj₁ p)
  (left (here p))   inj₁ p
  (left (right p))  inj₂ (inj₂ (left p))
  (here p)          inj₂ (inj₂ (here p))
  (right p)         inj₂ (inj₂ (right p))
joinʳ⁺⁻ k₂ t₁ (1# , node⁻ k₆ k₄ t₃ t₅ bal t₇) ∼+  = λ where
  (left (left p))    inj₂ (inj₁ p)
  (left (here p))    inj₁ p
  (left (right p))   inj₂ (inj₂ (left (left p)))
  (here p)           inj₂ (inj₂ (left (here p)))
  (right (left p))   inj₂ (inj₂ (left (right p)))
  (right (here p))   inj₂ (inj₂ (here p))
  (right (right p))  inj₂ (inj₂ (right p))

module _ {V : Value v} where

  private
    Val  = Value.family V
    Val≈ = Value.respects V

  singleton⁺ : {P : Pred (K& V) p} 
               (k : Key) 
               (v : Val k) 
               (l<k<u : l < k < u) 
               P (k , v)  Any P (singleton k v l<k<u)
  singleton⁺ k v l<k<u Pkv = here Pkv

  singleton⁻ : {P : Pred (K& V) p} 
               (k : Key) 
               (v : Val k) 
               (l<k<u : l < k < u) 
               Any P (singleton k v l<k<u)  P (k , v)
  singleton⁻ k v l<k<u (here Pkv) = Pkv

  ----------------------------------------------------------------------
  -- insert

  module _ (k : Key) (f : Maybe (Val k)  Val k) where

    open <-Reasoning AVL.strictPartialOrder

    Any-insertWith-nothing : (t : Tree V l u n) (seg : l < k < u) 
                             P (k , f nothing) 
                             ¬ (Any ((k ≈_) ∘′ key) t)  Any P (proj₂ (insertWith k f t seg))
    Any-insertWith-nothing (leaf l<u)                   seg         pr ¬p = here pr
    Any-insertWith-nothing (node kv@(k′ , v) lk ku bal) (l<k , k<u) pr ¬p
      with compare k k′
    ... | tri≈ _ k≈k′ _ = contradiction (here k≈k′) ¬p
    ... | tri< k<k′ _ _ = let seg′ = l<k , [ k<k′ ]ᴿ; lk′ = insertWith k f lk seg′
                              ih = Any-insertWith-nothing lk seg′ pr  p  ¬p (left p))
                          in joinˡ⁺-left⁺ kv lk′ ku bal ih
    ... | tri> _ _ k>k′ = let seg′ = [ k>k′ ]ᴿ , k<u; ku′ = insertWith k f ku seg′
                              ih = Any-insertWith-nothing ku seg′ pr  p  ¬p (right p))
                          in joinʳ⁺-right⁺ kv lk ku′ bal ih

    Any-insertWith-just : (t : Tree V l u n) (seg : l < k < u) 
                          (pr :  k′ v  (eq : k  k′)  P (k′ , Val≈ eq (f (just (Val≈ (sym eq) v))))) 
                          Any ((k ≈_) ∘′ key) t  Any P (proj₂ (insertWith k f t seg))
    Any-insertWith-just (node kv@(k′ , v) lk ku bal) (l<k , k<u) pr p
      with p | compare k k′
    -- happy paths
    ... | here _   | tri≈ _ k≈k′ _ = here (pr k′ v k≈k′)
    ... | left lp  | tri< k<k′ _ _ = let seg′ = l<k , [ k<k′ ]ᴿ; lk′ = insertWith k f lk seg′ in
                                     joinˡ⁺-left⁺ kv lk′ ku bal (Any-insertWith-just lk seg′ pr lp)
    ... | right rp | tri> _ _ k>k′ = let seg′ = [ k>k′ ]ᴿ , k<u; ku′ = insertWith k f ku seg′ in
                                     joinʳ⁺-right⁺ kv lk ku′ bal (Any-insertWith-just ku seg′ pr rp)

    -- impossible cases
    ... | here eq  | tri< k<k′ _ _ = begin-contradiction
      [ k  ] <⟨ [ k<k′ ]ᴿ 
      [ k′ ] ≈⟨ [ sym eq ]ᴱ 
      [ k  ] 
    ... | here eq  | tri> _ _ k>k′ = begin-contradiction
      [ k  ] ≈⟨ [ eq ]ᴱ 
      [ k′ ] <⟨ [ k>k′ ]ᴿ 
      [ k  ] 
    ... | left lp  | tri≈ _ k≈k′ _ = begin-contradiction
      let k″ = Any.lookup lp .key; k≈k″ = lookup-result lp; (_ , k″<k′) = lookup-bounded lp in
      [ k  ] ≈⟨ [ k≈k″ ]ᴱ 
      [ k″ ] <⟨ k″<k′ 
      [ k′ ] ≈⟨ [ sym k≈k′ ]ᴱ 
      [ k  ] 
    ... | left lp  | tri> _ _ k>k′ = begin-contradiction
      let k″ = Any.lookup lp .key; k≈k″ = lookup-result lp; (_ , k″<k′) = lookup-bounded lp in
      [ k  ] ≈⟨ [ k≈k″ ]ᴱ 
      [ k″ ] <⟨ k″<k′ 
      [ k′ ] <⟨ [ k>k′ ]ᴿ 
      [ k  ] 
    ... | right rp | tri< k<k′ _ _ = begin-contradiction
      let k″ = Any.lookup rp .key; k≈k″ = lookup-result rp; (k′<k″ , _) = lookup-bounded rp in
      [ k  ] <⟨ [ k<k′ ]ᴿ 
      [ k′ ] <⟨ k′<k″ 
      [ k″ ] ≈⟨ [ sym k≈k″ ]ᴱ 
      [ k  ] 
    ... | right rp | tri≈ _ k≈k′ _ = begin-contradiction
      let k″ = Any.lookup rp .key; k≈k″ = lookup-result rp; (k′<k″ , _) = lookup-bounded rp in
      [ k  ] ≈⟨ [ k≈k′ ]ᴱ 
      [ k′ ] <⟨ k′<k″ 
      [ k″ ] ≈⟨ [ sym k≈k″ ]ᴱ 
      [ k  ] 

  module _ (k : Key) (v : Val k) (t : Tree V l u n) (seg : l < k < u) where

    Any-insert-nothing : P (k , v)  ¬ (Any ((k ≈_) ∘′ key) t)  Any P (proj₂ (insert k v t seg))
    Any-insert-nothing = Any-insertWith-nothing k (F.const v) t seg

    Any-insert-just : (pr :  k′  (eq : k  k′)  P (k′ , Val≈ eq v)) 
                      Any ((k ≈_) ∘′ key) t  Any P (proj₂ (insert k v t seg))
    Any-insert-just pr = Any-insertWith-just k (F.const v) t seg  k′ _ eq  pr k′ eq)

  module _ (k : Key) (f : Maybe (Val k)  Val k) where

    insertWith⁺ : (t : Tree V l u n) (seg : l < k < u) 
                  (p : Any P t)  k  Any.lookupKey p 
                  Any P (proj₂ (insertWith k f t seg))
    insertWith⁺ (node kv@(k′ , v′) l r bal) (l<k , k<u) (here p) k≉
      with compare k k′
    ... | tri< k<k′ _ _ = let l′ = insertWith k f l (l<k , [ k<k′ ]ᴿ)
                          in joinˡ⁺-here⁺ kv l′ r bal p
    ... | tri≈ _ k≈k′ _ = contradiction k≈k′ k≉
    ... | tri> _ _ k′<k = let r′ = insertWith k f r ([ k′<k ]ᴿ , k<u)
                          in joinʳ⁺-here⁺ kv l r′ bal p
    insertWith⁺ (node kv@(k′ , v′) l r bal) (l<k , k<u) (left p) k≉
      with compare k k′
    ... | tri< k<k′ _ _ = let l′ = insertWith k f l (l<k , [ k<k′ ]ᴿ)
                              ih = insertWith⁺ l (l<k , [ k<k′ ]ᴿ) p k≉
                          in joinˡ⁺-left⁺ kv l′ r bal ih
    ... | tri≈ _ k≈k′ _ = left p
    ... | tri> _ _ k′<k = let r′ = insertWith k f r ([ k′<k ]ᴿ , k<u)
                          in joinʳ⁺-left⁺ kv l r′ bal p
    insertWith⁺ (node kv@(k′ , v′) l r bal) (l<k , k<u) (right p) k≉
      with compare k k′
    ... | tri< k<k′ _ _ = let l′ = insertWith k f l (l<k , [ k<k′ ]ᴿ)
                          in joinˡ⁺-right⁺ kv l′ r bal p
    ... | tri≈ _ k≈k′ _ = right p
    ... | tri> _ _ k′<k = let r′ = insertWith k f r ([ k′<k ]ᴿ , k<u)
                              ih = insertWith⁺ r ([ k′<k ]ᴿ , k<u) p k≉
                          in joinʳ⁺-right⁺ kv l r′ bal ih

  insert⁺ : (k : Key) (v : Val k) (t : Tree V l u n) (seg : l < k < u) 
            (p : Any P t)  k  Any.lookupKey p 
            Any P (proj₂ (insert k v t seg))
  insert⁺ k v = insertWith⁺ k (F.const v)

  module _
    {P : Pred (K& V) p}
    (P-Resp :  {k k′ v}  (k≈k′ : k  k′)  P (k′ , Val≈ k≈k′ v)  P (k , v))
    (k : Key) (v : Val k)
    where

    insert⁻ : (t : Tree V l u n) (seg : l < k < u) 
              Any P (proj₂ (insert k v t seg)) 
              P (k , v)  Any (λ{ (k′ , v′)  k  k′ × P (k′ , v′)}) t
    insert⁻ (leaf l<u) seg (here p) = inj₁ p
    insert⁻ (node kv′@(k′ , v′) l r bal) (l<k , k<u) p with compare k k′
    insert⁻ (node kv′@(k′ , v′) l r bal) (l<k , k<u) p | tri< k<k′ k≉k′ _
        with joinˡ⁺⁻ kv′ (insert k v l (l<k , [ k<k′ ]ᴿ)) r bal p
    ... | inj₁ p        = inj₂ (here (k≉k′ , p))
    ... | inj₂ (inj₂ p) = inj₂ (right (lookup-rebuild-accum p k≉p))
      where
      k′<p = [<]-injective (proj₁ (lookup-bounded p))
      k≉p = λ k≈p  irrefl k≈p (<-trans k<k′ k′<p)
    ... | inj₂ (inj₁ p) = Sum.map₂  q  left q) (insert⁻ l (l<k , [ k<k′ ]ᴿ) p)
    insert⁻ (node kv′@(k′ , v′) l r bal) (l<k , k<u) p | tri> _ k≉k′ k′<k
        with joinʳ⁺⁻ kv′ l (insert k v r ([ k′<k ]ᴿ , k<u)) bal p
    ... | inj₁ p        = inj₂ (here (k≉k′ , p))
    ... | inj₂ (inj₁ p) = inj₂ (left (lookup-rebuild-accum p k≉p))
      where
      p<k′ = [<]-injective (proj₂ (lookup-bounded p))
      k≉p = λ k≈p  irrefl (sym k≈p) (<-trans p<k′ k′<k)
    ... | inj₂ (inj₂ p) = Sum.map₂  q  right q) (insert⁻ r ([ k′<k ]ᴿ , k<u) p)
    insert⁻ (node kv′@(k′ , v′) l r bal) (l<k , k<u) p | tri≈ _ k≈k′ _
        with p
    ... | left p  = inj₂ (left (lookup-rebuild-accum p k≉p))
      where
      p<k′ = [<]-injective (proj₂ (lookup-bounded p))
      k≉p = λ k≈p  irrefl (trans (sym k≈p) k≈k′) p<k′
    ... | here p  = inj₁ (P-Resp k≈k′ p)
    ... | right p = inj₂ (right (lookup-rebuild-accum p k≉p))
      where
      k′<p = [<]-injective (proj₁ (lookup-bounded p))
      k≉p = λ k≈p  irrefl (trans (sym k≈k′) k≈p) k′<p

  lookup⁺ : (t : Tree V l u n) (k : Key) (seg : l < k < u) 
            (p : Any P t) 
            key (Any.lookup p)  k  ∃[ p≈k ] AVL.lookup t k seg  just (Val≈ p≈k (value (Any.lookup p)))
  lookup⁺ (node (k′ , v′) l r bal) k (l<k , k<u) p
      with compare k′ k | p
  ... | tri< k′<k _ _ | right p = lookup⁺ r k ([ k′<k ]ᴿ , k<u) p
  ... | tri≈ _ k′≈k _ | here p = inj₂ (k′≈k , ≡-refl)
  ... | tri> _ _ k<k′ | left p = lookup⁺ l k (l<k , [ k<k′ ]ᴿ) p
  ... | tri< k′<k _ _ | left p = inj₁  p≈k  irrefl p≈k (<-trans p<k′ k′<k))
    where p<k′ = [<]-injective (proj₂ (lookup-bounded p))
  ... | tri< k′<k _ _ | here p = inj₁  p≈k  irrefl p≈k k′<k)
  ... | tri≈ _ k′≈k _ | left p = inj₁  p≈k  irrefl (trans p≈k (sym k′≈k)) p<k′)
    where p<k′ = [<]-injective (proj₂ (lookup-bounded p))
  ... | tri≈ _ k′≈k _ | right p = inj₁  p≈k  irrefl (trans k′≈k (sym p≈k)) k′<p)
    where k′<p = [<]-injective (proj₁ (lookup-bounded p))
  ... | tri> _ _ k<k′ | here p = inj₁  p≈k  irrefl (sym p≈k) k<k′)
  ... | tri> _ _ k<k′ | right p = inj₁  p≈k  irrefl (sym p≈k) (<-trans k<k′ k′<p))
    where k′<p = [<]-injective (proj₁ (lookup-bounded p))

  lookup⁻ : (t : Tree V l u n) (k : Key) (v : Val k) (seg : l < k < u) 
            AVL.lookup t k seg  just v 
            Any (λ{ (k′ , v′)   λ k′≈k  Val≈ k′≈k v′  v}) t
  lookup⁻ (node (k′ , v′) l r bal) k v (l<k , k<u) eq with compare k′ k
  ... | tri< k′<k _ _ = right (lookup⁻ r k v ([ k′<k ]ᴿ , k<u) eq)
  ... | tri≈ _ k′≈k _ = here (k′≈k , just-injective eq)
  ... | tri> _ _ k<k′ = left (lookup⁻ l k v (l<k , [ k<k′ ]ᴿ) eq)