@@ -2,29 +2,29 @@ module Lattice.Builder where
open import Lattice
open import Equivalence
open import Utils using ( Unique; push; empty; Unique-append; Unique-++⁻ˡ; Unique-++⁻ʳ; Unique-narrow; All¬-¬Any; ¬Any-map; fins; fins-complete; findUniversal; Decidable-¬)
open import Utils using ( Unique; push; empty; Unique-append; Unique-++⁻ˡ; Unique-++⁻ʳ; Unique-narrow; All¬-¬Any; ¬Any-map; fins; fins-complete; findUniversal; Decidable-¬; ∈-cartesianProduct; foldr₁; x∷xs≢[] )
open import Data.Nat as Nat using ( ℕ )
open import Data.Fin as Fin using ( Fin; suc; zero; _≟_)
open import Data.Maybe as Maybe using ( Maybe; just; nothing; _>>=_; maybe)
open import Data.Maybe.Properties using ( just-injective)
open import Data.Unit using ( ⊤ ; tt)
open import Data.List.NonEmpty using ( List⁺; tail; toList) renaming ( _∷_ to _∷⁺_)
open import Data.List.Membership.Propositional as MemProp using ( lose) renaming ( _∈_ to _∈ˡ_; mapWith∈ to mapWith∈ˡ)
open import Data.List.Membership.Propositional.Properties using ( ) renaming ( ∈-++⁺ʳ to ∈ˡ-++⁺ʳ; ∈-++⁺ˡ to ∈ˡ-++⁺ˡ; ∈-cartesianProductWith⁺ to ∈ˡ-cartesianProductWith⁺)
open import Data.List.Relation.Unary.Any using ( Any; here; there; any?; satisfied)
open import Data.List.Relation.Unary.Any.Properties using ( ¬Any[])
open import Data.List.Relation.Unary.All using ( All; []; _∷_; map; lookup; zipWith; tabulate; all?)
open import Data.List.Membership.Propositional.Properties using ( ) renaming ( ∈-++⁺ʳ to ∈ˡ-++⁺ʳ; ∈-++⁺ˡ to ∈ˡ-++⁺ˡ; ∈-cartesianProductWith⁺ to ∈ˡ-cartesianProductWith⁺; ∈-filter⁻ to ∈ˡ-filter⁻; ∈-filter⁺ to ∈ˡ-filter⁺; ∈-lookup to ∈ˡ-lookup )
open import Data.List.Relation.Unary.Any as Any using ( Any; here; there; any?; satisfied; index )
open import Data.List.Relation.Unary.Any.Properties using ( ¬Any[]; lookup-result )
open import Data.List.Relation.Unary.All using ( All; []; _∷_; map; lookup; zipWith; tabulate; universal; all?)
open import Data.List.Relation.Unary.All.Properties using ( ) renaming ( ++⁺ to ++ˡ⁺; ++⁻ʳ to ++ˡ⁻ʳ)
open import Data.List using ( List; _∷_; []; cartesianProduct; cartesianProductWith; foldr) renaming ( _++_ to _++ˡ_)
open import Data.List using ( List; _∷_; []; cartesianProduct; cartesianProductWith; foldr; filter ) renaming ( _++_ to _++ˡ_)
open import Data.List.Properties using ( ) renaming ( ++-conicalʳ to ++ˡ-conicalʳ; ++-identityʳ to ++ˡ-identityʳ; ++-assoc to ++ˡ-assoc)
open import Data.Sum using ( _⊎_; inj₁; inj₂)
open import Data.Product using ( Σ; _,_; _× _; proj₁; proj₂; uncurry)
open import Data.Empty using ( ⊥; ⊥ -elim)
open import Relation.Nullary using ( ¬_; Dec; yes; no; ¬?)
open import Data.Empty using ( ⊥-elim)
open import Relation.Nullary using ( ¬_; Dec; yes; no; ¬?; _× -dec_ )
open import Relation.Binary.PropositionalEquality as Eq using ( _≡_; refl; sym; trans; cong; subst)
open import Relation.Binary.PropositionalEquality.Properties using ( decSetoid)
open import Relation.Binary using ( ) renaming ( Decidable to Decidable²)
open import Relation.Unary using ( Decidable)
open import Relation.Unary.Properties using ( _∩?_)
open import Agda.Primitive using ( lsuc; Level) renaming ( _⊔_ to _⊔ℓ _)
record Graph : Set where
@@ -33,11 +33,11 @@ record Graph : Set where
size : ℕ
Node : Set
Node = Fin size
Node = Fin ( Nat.suc size)
nodes = fins size
nodes = fins ( Nat.suc size)
nodes-complete = fins-complete size
nodes-complete = fins-complete ( Nat.suc size)
Edge : Set
Edge = Node × Node
@@ -45,6 +45,9 @@ record Graph : Set where
field
edges : List Edge
nodes-nonempty : ¬ ( proj₁ nodes ≡ [])
nodes-nonempty ( )
data Path : Node → Node → Set where
done : ∀ { n : Node} → Path n n
step : ∀ { n₁ n₂ n₃ : Node} → ( n₁ , n₂) ∈ˡ edges → Path n₂ n₃ → Path n₁ n₃
@@ -252,10 +255,10 @@ record Graph : Set where
... | yes refl | yes refl = f ( adj n₁ n₂)
... | _ | _ = adj n₁' n₂'
Adje cency-append : ∀ { n₁ n₂ : Node} → List ( Path n₁ n₂) → Adjacency → Adjacency
Adje cency-append { n₁} { n₂} ps = Adjacency-update n₁ n₂ ( ps ++ˡ_)
Adja cency-append : ∀ { n₁ n₂ : Node} → List ( Path n₁ n₂) → Adjacency → Adjacency
Adja cency-append { n₁} { n₂} ps = Adjacency-update n₁ n₂ ( ps ++ˡ_)
Adjacency-append-monotonic : ∀ { adj n₁ n₂ n₁' n₂'} { ps : List ( Path n₁ n₂) } { p : Path n₁' n₂'} → p ∈ˡ adj n₁' n₂' → p ∈ˡ Adje cency-append ps adj n₁' n₂'
Adjacency-append-monotonic : ∀ { adj n₁ n₂ n₁' n₂'} { ps : List ( Path n₁ n₂) } { p : Path n₁' n₂'} → p ∈ˡ adj n₁' n₂' → p ∈ˡ Adja cency-append ps adj n₁' n₂'
Adjacency-append-monotonic { adj} { n₁} { n₂} { n₁'} { n₂'} { ps} p∈adj
with n₁ ≟ n₁' | n₂ ≟ n₂'
... | yes refl | yes refl = ∈ˡ-++⁺ʳ ps p∈adj
@@ -371,11 +374,512 @@ record Graph : Set where
Has-⊤ : Set
Has-⊤ = Any Is-⊤ ( proj₁ nodes)
Has-T ? : Dec Has-⊤
Has-T ? = findUniversal ( proj₁ nodes) PathExists?
Has-⊤ ? : Dec Has-⊤
Has-⊤ ? = findUniversal ( proj₁ nodes) PathExists?
Has-⊥ : Set
Has-⊥ = Any Is-⊥ ( proj₁ nodes)
Has-⊥? : Dec Has-⊥
Has-⊥? = findUniversal ( proj₁ nodes) ( λ n₁ n₂ → PathExists? n₂ n₁)
Pred : Node → Node → Node → Set
Pred n₁ n₂ n = PathExists n n₁ × PathExists n n₂
Succ : Node → Node → Node → Set
Succ n₁ n₂ n = PathExists n₁ n × PathExists n₂ n
Pred? : ∀ ( n₁ n₂ : Node) → Decidable ( Pred n₁ n₂)
Pred? n₁ n₂ n = PathExists? n n₁ × -dec PathExists? n n₂
Suc? : ∀ ( n₁ n₂ : Node) → Decidable ( Succ n₁ n₂)
Suc? n₁ n₂ n = PathExists? n₁ n × -dec PathExists? n₂ n
preds : Node → Node → List Node
preds n₁ n₂ = filter ( Pred? n₁ n₂) ( proj₁ nodes)
sucs : Node → Node → List Node
sucs n₁ n₂ = filter ( Suc? n₁ n₂) ( proj₁ nodes)
Have-⊔ : Node → Node → Set
Have-⊔ n₁ n₂ = Σ Node ( λ n → Pred n₁ n₂ n × ( ∀ n' → Pred n₁ n₂ n' → PathExists n' n) )
Have-⊓ : Node → Node → Set
Have-⊓ n₁ n₂ = Σ Node ( λ n → Succ n₁ n₂ n × ( ∀ n' → Succ n₁ n₂ n' → PathExists n n') )
-- when filtering nodes by a predicate P, then trying to find a universal
-- element according to another predicate Q, the universality can be
-- extended from "element of the filtered list for to which all other elements relate" to
-- "node satisfying P to which all other nodes satisfying P relate".
filter-nodes-universal : ∀ { P : Node → Set } ( P? : Decidable P) -- e.g. Pred n₁ n₂
{ Q : Node → Node → Set } ( Q? : Decidable² Q) -- e.g. PathExists? n' n
→ Dec ( Σ Node λ n → P n × ( ∀ n' → P n' → Q n n') )
filter-nodes-universal { P = P} P? { Q = Q} Q?
with findUniversal ( filter P? ( proj₁ nodes) ) Q?
... | yes founduni =
let idx = index founduni
n = Any.lookup founduni
n∈filter = ∈ˡ-lookup idx
( _ , Pn) = ∈ˡ-filter⁻ P? { xs = proj₁ nodes} n∈filter
nuni = lookup-result founduni
in yes ( n , ( Pn , λ n' Pn' →
let n'∈filter = ∈ˡ-filter⁺ P? ( nodes-complete n') Pn'
in lookup nuni n'∈filter) )
... | no nouni = no λ ( n , ( Pn , nuni') ) →
let n∈filter = ∈ˡ-filter⁺ P? ( nodes-complete n) Pn
nuni = tabulate { xs = filter P? ( proj₁ nodes) } ( λ { n'} n'∈filter → nuni' n' ( proj₂ ( ∈ˡ-filter⁻ P? { xs = proj₁ nodes} n'∈filter) ) )
in nouni ( lose n∈filter nuni)
Have-⊔? : Decidable² Have-⊔
Have-⊔? n₁ n₂ = filter-nodes-universal ( Pred? n₁ n₂) ( λ n₁ n₂ → PathExists? n₂ n₁)
Have-⊓? : Decidable² Have-⊓
Have-⊓? n₁ n₂ = filter-nodes-universal ( Suc? n₁ n₂) PathExists?
Total-⊔ : Set
Total-⊔ = ∀ n₁ n₂ → Have-⊔ n₁ n₂
Total-⊓ : Set
Total-⊓ = ∀ n₁ n₂ → Have-⊓ n₁ n₂
P-Total? : ∀ { P : Node → Node → Set } ( P? : Decidable² P) → Dec ( ∀ n₁ n₂ → P n₁ n₂)
P-Total? { P} P?
with all? ( λ ( n₁ , n₂) → P? n₁ n₂) ( cartesianProduct ( proj₁ nodes) ( proj₁ nodes) )
... | yes allP = yes λ n₁ n₂ →
let n₁n₂∈prod = ∈-cartesianProduct ( nodes-complete n₁) ( nodes-complete n₂)
in lookup allP n₁n₂∈prod
... | no ¬allP = no λ allP → ¬allP ( universal ( λ ( n₁ , n₂) → allP n₁ n₂) _)
Total-⊔? : Dec Total-⊔
Total-⊔? = P-Total? Have-⊔?
Total-⊓? : Dec Total-⊓
Total-⊓? = P-Total? Have-⊓?
module Basic ( noCycles : NoCycles) ( total-⊔ : Total-⊔) ( total-⊓ : Total-⊓) where
n₁→n₂× n₂→n₁⇒n₁≡n₂ : ∀ { n₁ n₂} → PathExists n₁ n₂ → PathExists n₂ n₁ → n₁ ≡ n₂
n₁→n₂× n₂→n₁⇒n₁≡n₂ n₁→n₂ n₂→n₁
with n₁→n₂ | n₂→n₁ | noCycles ( n₁→n₂ ++ n₂→n₁)
... | done | done | _ = refl
... | step _ _ | done | _ = refl
... | done | step _ _ | _ = refl
... | step _ _ | step _ _ | ( )
_⊔_ : Node → Node → Node
_⊔_ n₁ n₂ = proj₁ ( total-⊔ n₁ n₂)
_⊓_ : Node → Node → Node
_⊓_ n₁ n₂ = proj₁ ( total-⊓ n₁ n₂)
⊤ : Node
⊤ = foldr₁ nodes-nonempty _⊔_
⊥ : Node
⊥ = foldr₁ nodes-nonempty _⊓_
_≼_ : Node → Node → Set
_≼_ n₁ n₂ = n₁ ⊔ n₂ ≡ n₂
n₁≼n₂→PathExistsn₂n₁ : ∀ n₁ n₂ → ( n₁ ≼ n₂) → PathExists n₂ n₁
n₁≼n₂→PathExistsn₂n₁ n₁ n₂ n₁⊔n₂≡n₂
with total-⊔ n₁ n₂ | n₁⊔n₂≡n₂
... | ( _ , ( ( n₂→n₁ , _) , _) ) | refl = n₂→n₁
PathExistsn₂n₁→n₁≼n₂ : ∀ n₁ n₂ → PathExists n₂ n₁ → ( n₁ ≼ n₂)
PathExistsn₂n₁→n₁≼n₂ n₁ n₂ n₂→n₁
with total-⊔ n₁ n₂
... | ( n , ( ( n→n₁ , n→n₂) , n'→n₁× n'→n₂⇒n'→n) )
rewrite n₁→n₂× n₂→n₁⇒n₁≡n₂ n→n₂ ( n'→n₁× n'→n₂⇒n'→n n₂ ( n₂→n₁ , done) ) = refl
foldr₁⊔-Pred : ∀ { ns : List Node} ( ns≢[] : ¬ ( ns ≡ []) ) → let n = foldr₁ ns≢[] _⊔_ in All ( PathExists n) ns
foldr₁⊔-Pred { ns = []} []≢[] = ⊥-elim ( []≢[] refl)
foldr₁⊔-Pred { ns = n₁ ∷ []} _ = done ∷ []
foldr₁⊔-Pred { ns = n₁ ∷ ns'@( n₂ ∷ ns'') } ns≢[] =
let
ns'≢[] = x∷xs≢[] n₂ ns''
n' = foldr₁ ns'≢[] _⊔_
( n , ( ( n→n₁ , n→n') , r) ) = total-⊔ n₁ n'
in
n→n₁ ∷ map ( n→n' ++_) ( foldr₁⊔-Pred ns'≢[])
-- TODO: this is very similar structurally to foldr₁⊔-Pred
foldr₁⊓-Suc : ∀ { ns : List Node} ( ns≢[] : ¬ ( ns ≡ []) ) → let n = foldr₁ ns≢[] _⊓_ in All ( λ n' → PathExists n' n) ns
foldr₁⊓-Suc { ns = []} []≢[] = ⊥-elim ( []≢[] refl)
foldr₁⊓-Suc { ns = n₁ ∷ []} _ = done ∷ []
foldr₁⊓-Suc { ns = n₁ ∷ ns'@( n₂ ∷ ns'') } ns≢[] =
let
ns'≢[] = x∷xs≢[] n₂ ns''
n' = foldr₁ ns'≢[] _⊓_
( n , ( ( n₁→n , n'→n) , r) ) = total-⊓ n₁ n'
in
n₁→n ∷ map ( _++ n'→n) ( foldr₁⊓-Suc ns'≢[])
⊤ -is-⊤ : Is-⊤ ⊤
⊤ -is-⊤ = foldr₁⊔-Pred nodes-nonempty
⊥-is-⊥ : Is-⊥ ⊥
⊥-is-⊥ = foldr₁⊓-Suc nodes-nonempty
⊔-idemp : ∀ n → n ⊔ n ≡ n
⊔-idemp n
with ( n' , ( ( n'→n , _) , n''→n× n''→n⇒n''→n') ) ← total-⊔ n n
= n₁→n₂× n₂→n₁⇒n₁≡n₂ n'→n ( n''→n× n''→n⇒n''→n' n ( done , done) )
⊓-idemp : ∀ n → n ⊓ n ≡ n
⊓-idemp n
with ( n' , ( ( n→n' , _) , n→n''× n→n''⇒n'→n'') ) ← total-⊓ n n
= n₁→n₂× n₂→n₁⇒n₁≡n₂ ( n→n''× n→n''⇒n'→n'' n ( done , done) ) n→n'
⊔-comm : ∀ n₁ n₂ → n₁ ⊔ n₂ ≡ n₂ ⊔ n₁
⊔-comm n₁ n₂
with ( n₁₂ , ( ( n₁n₂→n₁ , n₁n₂→n₂) , n'→n₁× n'→n₂⇒n'→n₁₂) ) ← total-⊔ n₁ n₂
with ( n₂₁ , ( ( n₂n₁→n₂ , n₂n₁→n₁) , n'→n₂× n'→n₁⇒n'→n₂₁) ) ← total-⊔ n₂ n₁
= n₁→n₂× n₂→n₁⇒n₁≡n₂ ( n'→n₂× n'→n₁⇒n'→n₂₁ n₁₂ ( n₁n₂→n₂ , n₁n₂→n₁) )
( n'→n₁× n'→n₂⇒n'→n₁₂ n₂₁ ( n₂n₁→n₁ , n₂n₁→n₂) )
⊓-comm : ∀ n₁ n₂ → n₁ ⊓ n₂ ≡ n₂ ⊓ n₁
⊓-comm n₁ n₂
with ( n₁₂ , ( ( n₁→n₁n₂ , n₂→n₁n₂) , n₁→n'× n₂→n'⇒n₁₂→n') ) ← total-⊓ n₁ n₂
with ( n₂₁ , ( ( n₂→n₂n₁ , n₁→n₂n₁) , n₂→n'× n₁→n'⇒n₂₁→n') ) ← total-⊓ n₂ n₁
= n₁→n₂× n₂→n₁⇒n₁≡n₂ ( n₁→n'× n₂→n'⇒n₁₂→n' n₂₁ ( n₁→n₂n₁ , n₂→n₂n₁) )
( n₂→n'× n₁→n'⇒n₂₁→n' n₁₂ ( n₂→n₁n₂ , n₁→n₁n₂) )
⊔-assoc : ∀ n₁ n₂ n₃ → ( n₁ ⊔ n₂) ⊔ n₃ ≡ n₁ ⊔ ( n₂ ⊔ n₃)
⊔-assoc n₁ n₂ n₃
with ( n₁₂ , ( ( n₁₂→n₁ , n₁₂→n₂) , n'→n₁× n'→n₂⇒n'→n₁₂) ) ← total-⊔ n₁ n₂
with ( n₁₂,₃ , ( ( n₁₂,₃→n₁₂ , n₁₂,₃→n₃) , n'→n₁₂× n'→n₃⇒n'→n₁₂,₃) ) ← total-⊔ n₁₂ n₃
with ( n₂₃ , ( ( n₂₃→n₂ , n₂₃→n₃) , n'→n₂× n'→n₃⇒n'→n₂₃) ) ← total-⊔ n₂ n₃
with ( n₁,₂₃ , ( ( n₁,₂₃→n₁ , n₁,₂₃→n₂₃) , n'→n₁× n'→n₂₃⇒n'→n₁,₂₃) ) ← total-⊔ n₁ n₂₃
=
let n₁₂,₃→n₂₃ = n'→n₂× n'→n₃⇒n'→n₂₃ n₁₂,₃ ( n₁₂,₃→n₁₂ ++ n₁₂→n₂ , n₁₂,₃→n₃)
n₁₂,₃→n₁,₂₃ = n'→n₁× n'→n₂₃⇒n'→n₁,₂₃ n₁₂,₃ ( n₁₂,₃→n₁₂ ++ n₁₂→n₁ , n₁₂,₃→n₂₃)
n₁,₂₃→n₁₂ = n'→n₁× n'→n₂⇒n'→n₁₂ n₁,₂₃ ( n₁,₂₃→n₁ , n₁,₂₃→n₂₃ ++ n₂₃→n₂)
n₁,₂₃→n₁₂,₃ = n'→n₁₂× n'→n₃⇒n'→n₁₂,₃ n₁,₂₃ ( n₁,₂₃→n₁₂ , n₁,₂₃→n₂₃ ++ n₂₃→n₃)
in n₁→n₂× n₂→n₁⇒n₁≡n₂ n₁₂,₃→n₁,₂₃ n₁,₂₃→n₁₂,₃
⊓-assoc : ∀ n₁ n₂ n₃ → ( n₁ ⊓ n₂) ⊓ n₃ ≡ n₁ ⊓ ( n₂ ⊓ n₃)
⊓-assoc n₁ n₂ n₃
with ( n₁₂ , ( ( n₁→n₁₂ , n₂→n₁₂) , n₁→n'× n₂→n'⇒n₁₂→n') ) ← total-⊓ n₁ n₂
with ( n₁₂,₃ , ( ( n₁₂→n₁₂,₃ , n₃→n₁₂,₃) , n₁₂→n'× n₃→n'⇒n₁₂,₃→n') ) ← total-⊓ n₁₂ n₃
with ( n₂₃ , ( ( n₂→n₂₃ , n₃→n₂₃) , n₂→n'× n₃→n'⇒n₂₃→n') ) ← total-⊓ n₂ n₃
with ( n₁,₂₃ , ( ( n₁→n₁,₂₃ , n₂₃→n₁,₂₃) , n₁→n'× n₂₃→n'⇒n₁,₂₃→n') ) ← total-⊓ n₁ n₂₃
=
let n₁₂→n₁,₂₃ = n₁→n'× n₂→n'⇒n₁₂→n' n₁,₂₃ ( n₁→n₁,₂₃ , n₂→n₂₃ ++ n₂₃→n₁,₂₃)
n₁₂,₃→n₁,₂₃ = n₁₂→n'× n₃→n'⇒n₁₂,₃→n' n₁,₂₃ ( n₁₂→n₁,₂₃ , n₃→n₂₃ ++ n₂₃→n₁,₂₃)
n₂₃→n₁₂,₃ = n₂→n'× n₃→n'⇒n₂₃→n' n₁₂,₃ ( n₂→n₁₂ ++ n₁₂→n₁₂,₃ , n₃→n₁₂,₃)
n₁,₂₃→n₁₂,₃ = n₁→n'× n₂₃→n'⇒n₁,₂₃→n' n₁₂,₃ ( n₁→n₁₂ ++ n₁₂→n₁₂,₃ , n₂₃→n₁₂,₃)
in n₁→n₂× n₂→n₁⇒n₁≡n₂ n₁₂,₃→n₁,₂₃ n₁,₂₃→n₁₂,₃
absorb-⊔-⊓ : ∀ n₁ n₂ → n₁ ⊔ ( n₁ ⊓ n₂) ≡ n₁
absorb-⊔-⊓ n₁ n₂
with ( n₁₂ , ( ( n₁→n₁₂ , n₂→n₁₂) , n₁→n'× n₂→n'⇒n₁₂→n') ) ← total-⊓ n₁ n₂
with ( n₁,₁₂ , ( ( n₁,₁₂→n₁ , n₁,₁₂→n₁₂) , n'→n₁× n'→n₁₂⇒n'→n₁,₁₂) ) ← total-⊔ n₁ n₁₂
= n₁→n₂× n₂→n₁⇒n₁≡n₂ n₁,₁₂→n₁ ( n'→n₁× n'→n₁₂⇒n'→n₁,₁₂ n₁ ( done , n₁→n₁₂) )
absorb-⊓-⊔ : ∀ n₁ n₂ → n₁ ⊓ ( n₁ ⊔ n₂) ≡ n₁
absorb-⊓-⊔ n₁ n₂
with ( n₁₂ , ( ( n₁₂→n₁ , n₁₂→n₂) , n'→n₁× n'→n₂⇒n'→n₁₂) ) ← total-⊔ n₁ n₂
with ( n₁,₁₂ , ( ( n₁→n₁,₁₂ , n₁₂→n₁,₁₂) , n₁→n'× n₁₂→n'⇒n₁,₁₂→n') ) ← total-⊓ n₁ n₁₂
= n₁→n₂× n₂→n₁⇒n₁≡n₂ ( n₁→n'× n₁₂→n'⇒n₁,₁₂→n' n₁ ( done , n₁₂→n₁) ) n₁→n₁,₁₂
instance
isJoinSemilattice : IsSemilattice Node _≡_ _⊔_
isJoinSemilattice = record
{ ≈-equiv = isEquivalence-≡
; ≈-⊔-cong = ( λ { refl refl → refl } )
; ⊔-idemp = ⊔-idemp
; ⊔-comm = ⊔-comm
; ⊔-assoc = ⊔-assoc
}
isMeetSemilattice : IsSemilattice Node _≡_ _⊓_
isMeetSemilattice = record
{ ≈-equiv = isEquivalence-≡
; ≈-⊔-cong = ( λ { refl refl → refl } )
; ⊔-idemp = ⊓-idemp
; ⊔-comm = ⊓-comm
; ⊔-assoc = ⊓-assoc
}
isLattice : IsLattice Node _≡_ _⊔_ _⊓_
isLattice = record
{ absorb-⊔-⊓ = absorb-⊔-⊓
; absorb-⊓-⊔ = absorb-⊓-⊔
}
module Tagged ( noCycles : NoCycles) ( total-⊔ : Total-⊔) ( total-⊓ : Total-⊓) ( 𝓛 : Node → Σ Set λ L → Σ ( FiniteHeightLattice L) λ fhl → FiniteHeightLattice.Known-⊥ fhl × FiniteHeightLattice.Known-⊤ fhl) where
open Basic noCycles total-⊔ total-⊓ using ( ) renaming ( _⊔_ to _⊔ᵇ_; _⊓_ to _⊓ᵇ_; ⊔-idemp to ⊔ᵇ-idemp; ⊔-comm to ⊔ᵇ-comm; ⊔-assoc to ⊔ᵇ-assoc; _≼_ to _≼ᵇ_; isJoinSemilattice to isJoinSemilatticeᵇ; isMeetSemilattice to isMeetSemilatticeᵇ; isLattice to isLatticeᵇ)
open IsLattice isLatticeᵇ using ( ) renaming ( ≈-⊔-cong to ≡-⊔ᵇ-cong; x≼x⊔y to x≼ᵇx⊔ᵇy; ≼-antisym to ≼ᵇ-antisym; ⊔-Monotonicʳ to ⊔ᵇ-Monotonicʳ)
Elem : Set
Elem = Σ Node λ n → ( proj₁ ( 𝓛 n) )
LatticeT : Node → Set
LatticeT n = proj₁ ( 𝓛 n)
FHL : ( n : Node) → FiniteHeightLattice ( LatticeT n)
FHL n = proj₁ ( proj₂ ( 𝓛 n) )
⊥≼x : ∀ { n : Node} ( l : LatticeT n) → FiniteHeightLattice._≼_ ( FHL n) ( FiniteHeightLattice.⊥ ( FHL n) ) l
⊥≼x { n} = proj₁ ( proj₂ ( proj₂ ( 𝓛 n) ) )
data _≈_ : Elem → Elem → Set where
≈-lift : ∀ { n : Node} { l₁ l₂ : LatticeT n} →
FiniteHeightLattice._≈_ ( FHL n) l₁ l₂ →
( n , l₁) ≈ ( n , l₂)
≈-refl : ∀ { e : Elem} → e ≈ e
≈-refl { n , l} = ≈-lift ( FiniteHeightLattice.≈-refl ( FHL n) )
≈-sym : ∀ { e₁ e₂ : Elem} → e₁ ≈ e₂ → e₂ ≈ e₁
≈-sym { n₁ , l₁} ( ≈-lift l₁≈l₂) = ≈-lift ( FiniteHeightLattice.≈-sym ( FHL n₁) l₁≈l₂)
≈-trans : ∀ { e₁ e₂ e₃ : Elem} → e₁ ≈ e₂ → e₂ ≈ e₃ → e₁ ≈ e₃
≈-trans { n₁ , l₁} ( ≈-lift l₁≈l₂) ( ≈-lift l₂≈l₃) = ≈-lift ( FiniteHeightLattice.≈-trans ( FHL n₁) l₁≈l₂ l₂≈l₃)
_⊔_ : Elem → Elem → Elem
_⊔_ e₁ e₂
using n₁ ← proj₁ e₁ using n₂ ← proj₁ e₂
using n' ← n₁ ⊔ᵇ n₂ = ( n' , select n' e₁ e₂)
where
select : ∀ n' e₁ e₂ → LatticeT n'
select n' ( n₁ , l₁) ( n₂ , l₂)
with n' ≟ n₁ | n' ≟ n₂
... | yes refl | yes refl = FiniteHeightLattice._⊔_ ( FHL n') l₁ l₂
... | yes refl | _ = l₁
... | _ | yes refl = l₂
... | no _ | no _ = FiniteHeightLattice.⊥ ( FHL n')
⊔-idemp : ∀ e → ( e ⊔ e) ≈ e
⊔-idemp ( n , l) rewrite ⊔ᵇ-idemp n
with n ≟ n
... | yes refl = ≈-lift ( FiniteHeightLattice.⊔-idemp ( FHL n) l)
... | no n≢n = ⊥-elim ( n≢n refl)
⊔-comm : ∀ ( e₁ e₂ : Elem) → ( e₁ ⊔ e₂) ≈ ( e₂ ⊔ e₁)
⊔-comm ( n₁ , l₁) ( n₂ , l₂)
rewrite ⊔ᵇ-comm n₁ n₂
with n ← n₂ ⊔ᵇ n₁
with n ≟ n₁ | n ≟ n₂
... | yes refl | yes refl = ≈-lift ( FiniteHeightLattice.⊔-comm ( FHL n) l₁ l₂)
... | no _ | yes refl = ≈-lift ( FiniteHeightLattice.≈-refl ( FHL n) )
... | yes refl | no _ = ≈-lift ( FiniteHeightLattice.≈-refl ( FHL n) )
... | no _ | no _ = ≈-lift ( FiniteHeightLattice.≈-refl ( FHL n) )
private
scary : ∀ ( n₁ n₂ : Node) → ( p : n₁ ≡ n₂) → ( n₁ ≟ n₂) ≡ subst ( λ n → Dec ( n₁ ≡ n) ) p ( yes refl)
scary n₁ n₂ refl with n₁ ≟ n₂
... | yes refl = refl
... | no n₁≢n₂ = ⊥-elim ( n₁≢n₂ refl)
payloadˡ : ∀ e₁ e₂ e₃ → let n = proj₁ ( ( e₁ ⊔ e₂) ⊔ e₃)
in LatticeT n
payloadˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
with n ← ( n₁ ⊔ᵇ n₂) ⊔ᵇ n₃
using _⊔ⁿ_ ← FiniteHeightLattice._⊔_ ( FHL n)
with n ≟ n₁ | n ≟ n₂ | n ≟ n₃
... | yes refl | yes refl | yes refl = ( l₁ ⊔ⁿ l₂) ⊔ⁿ l₃
... | yes refl | yes refl | no _ = l₁ ⊔ⁿ l₂
... | yes refl | no _ | yes refl = l₁ ⊔ⁿ l₃
... | yes refl | no _ | no _ = l₁
... | no _ | yes refl | yes refl = l₂ ⊔ⁿ l₃
... | no _ | yes refl | no _ = l₂
... | no _ | no _ | yes refl = l₃
... | no _ | no _ | no _ = FiniteHeightLattice.⊥ ( FHL n)
payloadʳ : ∀ e₁ e₂ e₃ → let n = proj₁ ( e₁ ⊔ ( e₂ ⊔ e₃) )
in LatticeT n
payloadʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
with n ← n₁ ⊔ᵇ ( n₂ ⊔ᵇ n₃)
using _⊔ⁿ_ ← FiniteHeightLattice._⊔_ ( FHL n)
with n ≟ n₁ | n ≟ n₂ | n ≟ n₃
... | yes refl | yes refl | yes refl = l₁ ⊔ⁿ ( l₂ ⊔ⁿ l₃)
... | yes refl | yes refl | no _ = l₁ ⊔ⁿ l₂
... | yes refl | no _ | yes refl = l₁ ⊔ⁿ l₃
... | yes refl | no _ | no _ = l₁
... | no _ | yes refl | yes refl = l₂ ⊔ⁿ l₃
... | no _ | yes refl | no _ = l₂
... | no _ | no _ | yes refl = l₃
... | no _ | no _ | no _ = FiniteHeightLattice.⊥ ( FHL n)
⊔ᵇ-prop : ∀ n₁ n₂ n₃ → ( n₁ ⊔ᵇ n₂) ⊔ᵇ n₃ ≡ n₁ →
( n₁ ⊔ᵇ n₂ ≡ n₁) × ( n₁ ⊔ᵇ n₃ ≡ n₁)
⊔ᵇ-prop n₁ n₂ n₃ pⁿ =
let n₁≼n₁⊔n₂ = x≼ᵇx⊔ᵇy n₁ n₂
n₁⊔n₂≼n₁₂⊔n₃ = x≼ᵇx⊔ᵇy ( n₁ ⊔ᵇ n₂) n₃
n₁⊔n₂≼n₁ = trans ( trans ( ≡-⊔ᵇ-cong refl ( sym pⁿ) ) ( n₁⊔n₂≼n₁₂⊔n₃) ) pⁿ
n₁⊔n₂≡n₁ = ≼ᵇ-antisym n₁⊔n₂≼n₁ n₁≼n₁⊔n₂
n₁≼n₁⊔n₃ = x≼ᵇx⊔ᵇy n₁ n₃
n₁⊔n₃≼n₁₂⊔n₃ = ⊔ᵇ-Monotonicʳ n₃ n₁≼n₁⊔n₂
n₁⊔n₃≼n₁ = trans ( trans ( ≡-⊔ᵇ-cong refl ( sym pⁿ) ) ( n₁⊔n₃≼n₁₂⊔n₃) ) pⁿ
n₁⊔n₃≡n₁ = ≼ᵇ-antisym n₁⊔n₃≼n₁ n₁≼n₁⊔n₃
in ( n₁⊔n₂≡n₁ , n₁⊔n₃≡n₁)
Reassocˡ : ∀ e₁ e₂ e₃ →
( ( e₁ ⊔ e₂) ⊔ e₃) ≈ ( proj₁ ( ( e₁ ⊔ e₂) ⊔ e₃) , payloadˡ e₁ e₂ e₃)
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
with n ← ( n₁ ⊔ᵇ n₂) ⊔ᵇ n₃ in pⁿ
with n ≟ n₁ in d₁ | n ≟ n₂ in d₂ | n ≟ n₃ in d₃
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes refl | yes refl | yes refl
with ( n₁ ⊔ᵇ n₁) ≟ n₁
... | no n₁≢n₁ = ⊥-elim ( n₁≢n₁ ( ⊔ᵇ-idemp n₁) )
... | yes p rewrite p
with n₁ ≟ n₁
... | no n₁≢n₁ = ⊥-elim ( n₁≢n₁ refl)
... | yes refl = ≈-refl
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes refl | yes refl | no _
with ( n₁ ⊔ᵇ n₁) ≟ n₁
... | no n₁≢n₁ = ⊥-elim ( n₁≢n₁ ( ⊔ᵇ-idemp n₁) )
... | yes p rewrite p
with n₁ ≟ n₁
... | no n₁≢n₁ = ⊥-elim ( n₁≢n₁ refl)
... | yes refl = ≈-refl
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes p₁@refl | no n₁≢n₂ | yes p₃@refl
using n₁⊔n₂≡n₁ ← trans ( trans ( trans ( ≡-⊔ᵇ-cong ( sym ( ⊔ᵇ-idemp n₁) ) ( refl { x = n₂} ) ) ( ⊔ᵇ-assoc n₁ n₁ n₂) ) ( ⊔ᵇ-comm n₁ ( n₁ ⊔ᵇ n₂) ) ) pⁿ
with ( n₁ ⊔ᵇ n₂) ≟ n₁
... | no n₁⊔n₂≢n₁ = ⊥-elim ( n₁⊔n₂≢n₁ n₁⊔n₂≡n₁)
... | yes p rewrite p
with n₁ ≟ n₁ | n₁ ≟ n₂
... | no n₁≢n₁ | _ = ⊥-elim ( n₁≢n₁ refl)
... | _ | yes n₁≡n₂ = ⊥-elim ( n₁≢n₂ n₁≡n₂)
... | yes refl | no _ = ≈-refl
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes p₁@refl | no n₁≢n₂ | no n₁≢n₃
using ( n₁⊔n₂≡n₁ , n₁⊔n₃≡n₁) ← ⊔ᵇ-prop n₁ n₂ n₃ pⁿ
with n₁ ⊔ᵇ n₂ ≟ n₁
... | no n₁⊔n₂≢n₁ = ⊥-elim ( n₁⊔n₂≢n₁ n₁⊔n₂≡n₁)
... | yes p rewrite p
with n₁ ≟ n₁ | n₁ ≟ n₂
... | no n₁≢n₁ | _ = ⊥-elim ( n₁≢n₁ refl)
... | _ | yes n₁≡n₂ = ⊥-elim ( n₁≢n₂ n₁≡n₂)
... | yes refl | no _ = ≈-refl
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n₂≢n₁ | yes p₂@refl | yes p₃@refl
using n₁⊔n₂≡n₂ ← trans ( trans ( ≡-⊔ᵇ-cong ( refl { x = n₁} ) ( sym ( ⊔ᵇ-idemp n₂) ) ) ( sym ( ⊔ᵇ-assoc n₁ n₂ n₂) ) ) pⁿ
with ( n₁ ⊔ᵇ n₂) ≟ n₂
... | no n₁⊔n₂≢n₂ = ⊥-elim ( n₁⊔n₂≢n₂ n₁⊔n₂≡n₂)
... | yes p rewrite p
with n₂ ≟ n₁ | n₂ ≟ n₂
... | yes n₂≡n₁ | _ = ⊥-elim ( n₂≢n₁ n₂≡n₁)
... | _ | no n₂≢n₂ = ⊥-elim ( n₂≢n₂ refl)
... | no _ | yes refl = ≈-refl
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n₂≢n₁ | yes p₂@refl | no n₂≢n₃
using ( n₂⊔n₁≡n₂ , n₂⊔n₃≡n₂) ← ⊔ᵇ-prop n₂ n₁ n₃ ( trans ( ≡-⊔ᵇ-cong ( ⊔ᵇ-comm n₂ n₁) ( refl { x = n₃} ) ) pⁿ)
with ( n₁ ⊔ᵇ n₂) ≟ n₁ | ( n₁ ⊔ᵇ n₂) ≟ n₂
... | yes n₁⊔n₂≡n₁ | _ = ⊥-elim ( n₂≢n₁ ( trans ( sym n₂⊔n₁≡n₂) ( trans ( ⊔ᵇ-comm n₂ n₁) ( n₁⊔n₂≡n₁) ) ) )
... | _ | no n₁⊔n₂≢n₂ = ⊥-elim ( n₁⊔n₂≢n₂ ( trans ( ⊔ᵇ-comm n₁ n₂) n₂⊔n₁≡n₂) )
... | no n₁⊔n₂≢n₁ | yes p rewrite p
with n₂ ≟ n₂
... | no n₂≢n₂ = ⊥-elim ( n₂≢n₂ refl)
... | yes refl = ≈-refl
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n₃≢n₁ | no n₃≢n₂ | yes p₃@refl
with n₁₂ ← n₁ ⊔ᵇ n₂
with n₃ ≟ n₁₂
... | no n₃≢n₁₂ = ≈-refl
... | yes refl rewrite d₁ rewrite d₂ = ≈-lift ( ⊥≼x l₃) -- TODO: need ⊥ ⊔ n₃ ≡ n₃
Reassocˡ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n≢n₁ | no n≢n₂ | no n≢n₃
with n₁₂ ← n₁ ⊔ᵇ n₂
with n₁₂ ≟ n₁ | n₁₂ ≟ n₂ | n ≟ n₃ | n ≟ n₁₂
... | _ | _ | yes n≡n₃ | _ = ⊥-elim ( n≢n₃ n≡n₃)
... | _ | _ | no _ | no n≢n₁₂ = ≈-refl
... | yes refl | yes refl | no _ | yes refl = ⊥-elim ( n≢n₁ refl)
... | yes refl | no n₁₂≢n₂ | no _ | yes refl = ⊥-elim ( n≢n₁ refl)
... | no n₁₂≢n₁ | yes refl | no _ | yes refl = ⊥-elim ( n≢n₂ refl)
... | no _ | no _ | no _ | yes refl = ≈-refl
Reassocʳ : ∀ e₁ e₂ e₃ →
( e₁ ⊔ ( e₂ ⊔ e₃) ) ≈ ( proj₁ ( e₁ ⊔ ( e₂ ⊔ e₃) ) , payloadʳ e₁ e₂ e₃)
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
with n ← n₁ ⊔ᵇ ( n₂ ⊔ᵇ n₃) in pⁿ
with n ≟ n₁ in d₁ | n ≟ n₂ in d₂ | n ≟ n₃ in d₃
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes refl | yes refl | yes refl
with ( n₁ ⊔ᵇ n₁) ≟ n₁
... | no n₁≢n₁ = ⊥-elim ( n₁≢n₁ ( ⊔ᵇ-idemp n₁) )
... | yes p rewrite p
with n₁ ≟ n₁
... | no n₁≢n₁ = ⊥-elim ( n₁≢n₁ refl)
... | yes refl = ≈-refl
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes refl | yes refl | no n₁≢n₃
using n₁⊔n₃≡n₁ ← trans ( ≡-⊔ᵇ-cong ( sym ( ⊔ᵇ-idemp n₁) ) ( refl { x = n₃} ) ) ( trans ( ⊔ᵇ-assoc n₁ n₁ n₃) pⁿ)
rewrite n₁⊔n₃≡n₁
with n₁ ≟ n₁ | n₁ ≟ n₃
... | no n₁≢n₁ | _ = ⊥-elim ( n₁≢n₁ refl)
... | _ | yes n₁≡n₃ = ⊥-elim ( n₁≢n₃ n₁≡n₃)
... | yes refl | no _ = ≈-refl
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes refl | no n₁≢n₂ | yes refl
using n₂⊔n₁≡n₁ ← trans ( trans ( trans ( ≡-⊔ᵇ-cong ( refl { x = n₂} ) ( sym ( ⊔ᵇ-idemp n₁) ) ) ( sym ( ⊔ᵇ-assoc n₂ n₁ n₁) ) ) ( ⊔ᵇ-comm _ _) ) pⁿ
rewrite n₂⊔n₁≡n₁
with n₁ ≟ n₁ | n₁ ≟ n₂
... | no n₁≢n₁ | _ = ⊥-elim ( n₁≢n₁ refl)
... | _ | yes n₁≡n₂ = ⊥-elim ( n₁≢n₂ n₁≡n₂)
... | yes refl | no _ = ≈-refl
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| yes refl | no n₁≢n₂ | no n₁≢n₃
with n₂₃ ← n₂ ⊔ᵇ n₃
with n₁ ≟ n₂₃
... | no n₁≢n₂₃ = ≈-refl
... | yes refl rewrite d₂ rewrite d₃ = ≈-lift ( FiniteHeightLattice.≈-trans ( FHL n₁) ( FiniteHeightLattice.⊔-comm ( FHL n₁) _ _) ( ⊥≼x l₁) )
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n₂≢n₁ | yes refl | yes refl
rewrite ⊔ᵇ-idemp n₂
with n₂ ≟ n₂
... | no n₂≢n₂ = ⊥-elim ( n₂≢n₂ refl)
... | yes refl = ≈-refl
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n₂≢n₁ | yes refl | no n₂≢n₃
using ( n₂⊔n₃=n₂ , n₂⊔n₁=n₂) ← ⊔ᵇ-prop n₂ n₃ n₁ ( trans ( ⊔ᵇ-comm _ _) pⁿ)
rewrite n₂⊔n₃=n₂
with n₂ ≟ n₂ | n₂ ≟ n₃
... | no n₂≢n₂ | _ = ⊥-elim ( n₂≢n₂ refl)
... | _ | yes n₂≡n₃ = ⊥-elim ( n₂≢n₃ n₂≡n₃)
... | yes refl | no _ = ≈-refl
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n₃≢n₁ | no n₃≢n₂ | yes refl
using ( n₃⊔n₂≡n₃ , n₃⊔n₁≡n₃) ← ⊔ᵇ-prop n₃ n₂ n₁ ( trans ( ⊔ᵇ-comm _ _) ( trans ( ≡-⊔ᵇ-cong ( refl { x = n₁} ) ( ⊔ᵇ-comm n₃ n₂) ) pⁿ) )
rewrite trans ( ⊔ᵇ-comm _ _) n₃⊔n₂≡n₃
with n₃ ≟ n₃ | n₃ ≟ n₂
... | no n₃≢n₃ | _ = ⊥-elim ( n₃≢n₃ refl)
... | _ | yes n₃≡n₂ = ⊥-elim ( n₃≢n₂ n₃≡n₂)
... | yes refl | no _ = ≈-refl
Reassocʳ ( n₁ , l₁) ( n₂ , l₂) ( n₃ , l₃)
| no n≢n₁ | no n≢n₂ | no n≢n₃
with n₂₃ ← n₂ ⊔ᵇ n₃
with n₂₃ ≟ n₂ | n₂₃ ≟ n₃ | n ≟ n₁ | n ≟ n₂₃
... | _ | _ | yes n≡n₁ | _ = ⊥-elim ( n≢n₁ n≡n₁)
... | _ | _ | no _ | no _ = ≈-refl
... | yes refl | yes refl | no _ | yes refl = ⊥-elim ( n≢n₂ refl)
... | yes refl | no n₁₂≢n₂ | no _ | yes refl = ⊥-elim ( n≢n₂ refl)
... | no n₁₂≢n₁ | yes refl | no _ | yes refl = ⊥-elim ( n≢n₃ refl)
... | no n₁₂≢n₁ | no n₁₂≢n₂ | no _ | yes refl = ≈-refl
⊔-assoc : ∀ ( e₁ e₂ e₃ : Elem) → ( ( e₁ ⊔ e₂) ⊔ e₃) ≈ ( e₁ ⊔ ( e₂ ⊔ e₃) )
⊔-assoc e₁@( n₁ , l₁) e₂@( n₂ , l₂) e₃@( n₃ , l₃)
with nˡ ← proj₁ ( ( e₁ ⊔ e₂) ⊔ e₃) in pˡ
with nʳ ← proj₁ ( e₁ ⊔ ( e₂ ⊔ e₃) ) in pʳ
with final₁ ← Reassocˡ e₁ e₂ e₃
with final₂ ← Reassocʳ e₁ e₂ e₃
rewrite pˡ rewrite pʳ
rewrite ⊔ᵇ-assoc n₁ n₂ n₃
rewrite trans ( sym pˡ ) pʳ
with nʳ ≟ n₁ | nʳ ≟ n₂ | nʳ ≟ n₃
... | yes refl | yes refl | yes refl =
let l-assoc = FiniteHeightLattice.⊔-assoc ( FHL n₁) l₁ l₂ l₃
in ≈-trans final₁ ( ≈-trans ( ≈-lift l-assoc) ( ≈-sym final₂) )
... | yes refl | yes refl | no _ = ≈-trans final₁ ( ≈-sym final₂)
... | yes refl | no _ | yes refl = ≈-trans final₁ ( ≈-sym final₂)
... | yes refl | no _ | no _ = ≈-trans final₁ ( ≈-sym final₂)
... | no _ | yes refl | yes refl = ≈-trans final₁ ( ≈-sym final₂)
... | no _ | yes refl | no _ = ≈-trans final₁ ( ≈-sym final₂)
... | no _ | no _ | yes refl = ≈-trans final₁ ( ≈-sym final₂)
... | no _ | no _ | no _ = ≈-trans final₁ ( ≈-sym final₂)