\import Algebra.Monoid
\import Algebra.Semiring
\import Category.Limit
\import Data.Array
\import Equiv
\import Function.Meta
\import HLevel
\import Logic
\import Paths
\import Order.PartialOrder
\import Paths.Meta
\import Set.Fin
\class MeetSemilattice \extends Poset {
| meet \alias \infixl 7 ∧ : E -> E -> E
| meet-left {x y : E} : x ∧ y <= x
| meet-right {x y : E} : x ∧ y <= y
| meet-univ {x y z : E} : z <= x -> z <= y -> z <= x ∧ y
\lemma meet-idemp {x : E} : x ∧ x = x =>
<=-antisymmetric meet-left (meet-univ <=-refl <=-refl)
\lemma meet-comm {x y : E} : x ∧ y = y ∧ x =>
<=-antisymmetric (meet-univ meet-right meet-left)
(meet-univ meet-right meet-left)
\lemma meet-monotone {x y x' y' : E} (p : x <= x') (q : y <= y') : x ∧ y <= x' ∧ y'
=> meet-univ (meet-left <=∘ p) (meet-right <=∘ q)
\lemma meet-assoc {x y z : E} : (x ∧ y) ∧ z = x ∧ (y ∧ z) =>
<=-antisymmetric (meet-univ (meet-left <=∘ meet-left) (meet-monotone meet-right <=-refl))
(meet-univ (meet-monotone <=-refl meet-left) (meet-right <=∘ meet-right))
\lemma meet_<= {x y : E} (x<=y : x <= y) : x ∧ y = x
=> <=-antisymmetric meet-left (meet-univ <=-refl x<=y)
\lemma meet_<=' {x y : E} (p : x ∧ y = x) : x <= y
=> transport (`<= y) p meet-right
\lemma Big_<=_meet0 {l : Array E} {x : E} : Big (∧) x l <= x \elim l
| nil => <=-refl
| :: a l => meet-right <=∘ Big_<=_meet0
\lemma Big_<=_meet1 {l : Array E} {x : E} (i : Fin l.len) : Big (∧) x l <= l i \elim l, i
| :: a l, 0 => meet-left
| :: a l, suc i => meet-right <=∘ Big_<=_meet1 i
\lemma Big_meet-univ {l : Array E} {x y : E} (p : y <= x) (f : \Pi (i : Fin l.len) -> y <= l i) : y <= Big (∧) x l \elim l
| nil => p
| :: a l => meet-univ (f 0) (Big_meet-univ p (\lam i => f (suc i)))
} \where {
-- | ``Meet x y`` is the type of elements which are meets of {x} and {y}.
\func Meet {E : Poset} (x y : E) =>
\Sigma (j : E) (j <= x) (j <= y) (\Pi (z : E) -> z <= x -> z <= y -> z <= j)
\lemma Meet-isProp {E : Poset} {x y : E} : isProp (Meet x y) => \lam p1 p2 =>
ext (<=-antisymmetric (p2.4 p1.1 p1.2 p1.3) (p1.4 p2.1 p2.2 p2.3))
}
\class JoinSemilattice \extends Poset {
| join \alias \infixl 6 ∨ : E -> E -> E
| join-left {x y : E} : x <= x ∨ y
| join-right {x y : E} : y <= x ∨ y
| join-univ {x y z : E} : x <= z -> y <= z -> x ∨ y <= z
\lemma join-monotone {x y x' y' : E} (p : x <= x') (q : y <= y') : x ∨ y <= x' ∨ y'
=> join-univ (p <=∘ join-left) (q <=∘ join-right)
\lemma join-idemp {x : E} : x ∨ x = x =>
<=-antisymmetric (join-univ <=-refl <=-refl) join-left
\lemma join-comm {x y : E} : x ∨ y = y ∨ x =>
<=-antisymmetric (join-univ join-right join-left)
(join-univ join-right join-left)
\lemma join-assoc {x y z : E} : (x ∨ y) ∨ z = x ∨ (y ∨ z) =>
<=-antisymmetric (join-univ (join-univ join-left (join-left >> join-right))
(join-right >> join-right))
(join-univ (join-left >> join-left)
(join-univ (join-right >> join-left) join-right))
\lemma join_<= {x y : E} (x<=y : x <= y) : x ∨ y = y
=> <=-antisymmetric (join-univ x<=y <=-refl) join-right
\lemma join_<=' {x y : E} (p : x ∨ y = y) : x <= y
=> transport (x <=) p join-left
\lemma Big0_<=_fold {l : Array E} {x : E} : x <= Big (∨) x l \elim l
| nil => <=-refl
| :: a l => Big0_<=_fold <=∘ join-right
\lemma Big1_<=_fold {l : Array E} {x : E} (i : Fin l.len) : l i <= Big (∨) x l \elim l, i
| :: a l, 0 => join-left
| :: a l, suc i => Big1_<=_fold i <=∘ join-right
\lemma Big_join-univ {l : Array E} {x y : E} (p : x <= y) (f : \Pi (i : Fin l.len) -> l i <= y) : Big (∨) x l <= y \elim l
| nil => p
| :: a l => join-univ (f 0) (Big_join-univ p (\lam i => f (suc i)))
} \where {
-- | ``Join x y`` is the type of elements which are joins of {x} and {y}.
\func Join {E : Poset} (x y : E) =>
\Sigma (m : E) (x <= m) (y <= m) (\Pi (z : E) -> x <= z -> y <= z -> m <= z)
\lemma Join-isProp {E : Poset} {x y : E} : isProp (Join x y) => \lam p1 p2 =>
ext (<=-antisymmetric (p1.4 p2.1 p2.2 p2.3) (p2.4 p1.1 p1.2 p1.3))
}
\class Lattice \extends MeetSemilattice, JoinSemilattice {
\lemma ldistr<= {x y z : E} : (x ∧ y) ∨ (x ∧ z) <= x ∧ (y ∨ z)
=> join-univ (meet-monotone <=-refl join-left) (meet-monotone <=-refl join-right)
}
\class DistributiveLattice \extends Lattice {
| ldistr>= {x y z : E} : x ∧ (y ∨ z) <= (x ∧ y) ∨ (x ∧ z)
\lemma ldistr {x y z : E} : x ∧ (y ∨ z) = (x ∧ y) ∨ (x ∧ z)
=> <=-antisymmetric ldistr>= ldistr<=
\lemma rdistr {x y z : E} : (y ∨ z) ∧ x = (y ∧ x) ∨ (z ∧ x)
=> meet-comm *> ldistr *> pmap2 (∨) meet-comm meet-comm
\lemma rdistr>= {x y z : E} : (y ∨ z) ∧ x <= (y ∧ x) ∨ (z ∧ x)
=> =_<= rdistr
\lemma lcodistr {x y z : E} : x ∨ (y ∧ z) = (x ∨ y) ∧ (x ∨ z) => inv $
ldistr *>
pmap2 (∨) (meet-comm *> meet_<= join-left) (meet-comm *> ldistr) *>
inv join-assoc *> pmap2 (∨) (join-comm *> join_<= meet-right) meet-comm
}
\module Bounded \where {
\class MeetSemilattice \extends Order.Lattice.MeetSemilattice, CartesianPrecat (\lp,\lp) {
| top : E
| top-univ {x : E} : x <= top
| terminal => \new Product {
| apex => top
| proj => \case __
| tupleMap _ => top-univ
| tupleBeta {_} {_} {j} => \case j
| tupleEq _ => propPath
}
| Bprod x y => \new Product {
| apex => x ∧ y
| proj => \case \elim __ \with {
| 0 => meet-left
| 1 => meet-right
}
| tupleMap f => meet-univ (f 0) (f 1)
| tupleBeta => propPath
| tupleEq _ => propPath
}
\lemma top-left {x : E} : top ∧ x = x
=> <=-antisymmetric meet-right (meet-univ top-univ <=-refl)
\lemma top-right {x : E} : x ∧ top = x
=> <=-antisymmetric meet-left (meet-univ <=-refl top-univ)
} \where {
\use \coerce toMonoid (L : MeetSemilattice) : CMonoid L \cowith
| ide => top
| * => meet
| ide-left => top-left
| *-assoc => meet-assoc
| *-comm => meet-comm
}
\class JoinSemilattice \extends Order.Lattice.JoinSemilattice {
| bottom : E
| bottom-univ {x : E} : bottom <= x
\func BigJoin (l : Array E) : E
=> Big (∨) bottom l
\lemma BigJoin-cond {l : Array E} (j : Fin l.len) : l j <= BigJoin l \elim l, j
| a :: l, 0 => join-left
| a :: l, suc j => BigJoin-cond j <=∘ join-right
\lemma BigJoin-univ {l : Array E} {x : E} (p : \Pi (j : Fin l.len) -> l j <= x) : BigJoin l <= x \elim l
| nil => bottom-univ
| a :: l => join-univ (p 0) $ BigJoin-univ $ \lam j => p (suc j)
\sfunc FinJoin {J : FinSet} (a : J -> E) : E
=> AbMonoid.FinSum {\this} a
\lemma FinJoin-cond {J : FinSet} (j : J) {a : J -> E} : a j <= FinJoin a
=> \case (AbMonoid.FinSum.aux a).2 \with {
| inP (e : Equiv, q) => \have t => (\peval FinJoin a) *> (\peval AbMonoid.FinSum a) *> inv q
\in transport2 (<=) (pmap a (e.f_ret j)) (inv t) (BigJoin-cond (e.ret j))
}
\lemma FinJoin-univ {J : FinSet} {a : J -> E} {x : E} (p : \Pi (j : J) -> a j <= x) : FinJoin a <= x
=> \case (AbMonoid.FinSum.aux a).2 \with {
| inP (e,q) => \have t => (\peval FinJoin a) *> (\peval AbMonoid.FinSum a) *> inv q
\in transportInv (`<= x) t $ BigJoin-univ $ \lam j => p (e j)
}
} \where {
\use \coerce toMonoid (L : JoinSemilattice) : AbMonoid L \cowith
| zro => bottom
| + => join
| zro-left {x} => <=-antisymmetric (join-univ bottom-univ <=-refl) join-right
| +-assoc => join-assoc
| +-comm => join-comm
}
\class Lattice \extends Order.Lattice.Lattice, MeetSemilattice, JoinSemilattice
\class DistributiveLattice \extends Lattice, Order.Lattice.DistributiveLattice
\where {
\use \coerce toSemiring (L : DistributiveLattice) : CSemiring L \cowith
| zro => bottom
| + => join
| zro-left {x} => <=-antisymmetric (join-univ bottom-univ <=-refl) join-right
| +-assoc => join-assoc
| +-comm => join-comm
| ide => top
| * => meet
| ide-left {x} => <=-antisymmetric meet-right (meet-univ top-univ <=-refl)
| *-assoc => meet-assoc
| ldistr => Order.Lattice.DistributiveLattice.ldistr
| zro_*-left {x} => <=-antisymmetric meet-left bottom-univ
| *-comm => meet-comm
}
}