open import Algebra
module Algebra.Properties.Lattice {l₁ l₂} (L : Lattice l₁ l₂) where
open Lattice L
open import Algebra.Structures
import Algebra.FunctionProperties as P; open P _≈_
open import Relation.Binary
import Relation.Binary.Lattice as R
import Relation.Binary.EqReasoning as EqR; open EqR setoid
open import Function
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence using (_⇔_; module Equivalence)
open import Data.Product
∧-idempotent : Idempotent _∧_
∧-idempotent x = begin
  x ∧ x            ≈⟨ refl ⟨ ∧-cong ⟩ sym (proj₁ absorptive _ _) ⟩
  x ∧ (x ∨ x ∧ x)  ≈⟨ proj₂ absorptive _ _ ⟩
  x                ∎
∨-idempotent : Idempotent _∨_
∨-idempotent x = begin
  x ∨ x      ≈⟨ refl ⟨ ∨-cong ⟩ sym (∧-idempotent _) ⟩
  x ∨ x ∧ x  ≈⟨ proj₁ absorptive _ _ ⟩
  x          ∎
∧-∨-isLattice : IsLattice _≈_ _∧_ _∨_
∧-∨-isLattice = record
  { isEquivalence = isEquivalence
  ; ∨-comm        = ∧-comm
  ; ∨-assoc       = ∧-assoc
  ; ∨-cong        = ∧-cong
  ; ∧-comm        = ∨-comm
  ; ∧-assoc       = ∨-assoc
  ; ∧-cong        = ∨-cong
  ; absorptive    = swap absorptive
  }
∧-∨-lattice : Lattice _ _
∧-∨-lattice = record
  { _∧_       = _∨_
  ; _∨_       = _∧_
  ; isLattice = ∧-∨-isLattice
  }
poset : Poset _ _ _
poset = record
  { Carrier        = Carrier
  ; _≈_            = _≈_
  ; _≤_            = λ x y → x ≈ x ∧ y
  ; isPartialOrder = record
    { isPreorder = record
      { isEquivalence = isEquivalence
      ; reflexive     = λ {i} {j} i≈j → begin
                          i      ≈⟨ sym $ ∧-idempotent _ ⟩
                          i ∧ i  ≈⟨ ∧-cong refl i≈j ⟩
                          i ∧ j  ∎
      ; trans         = λ {i} {j} {k} i≈i∧j j≈j∧k → begin
                          i            ≈⟨ i≈i∧j ⟩
                          i ∧ j        ≈⟨ ∧-cong refl j≈j∧k ⟩
                          i ∧ (j ∧ k)  ≈⟨ sym (∧-assoc _ _ _) ⟩
                          (i ∧ j) ∧ k  ≈⟨ ∧-cong (sym i≈i∧j) refl ⟩
                          i ∧ k        ∎
      }
    ; antisym = λ {x} {y} x≈x∧y y≈y∧x → begin
                  x      ≈⟨ x≈x∧y ⟩
                  x ∧ y  ≈⟨ ∧-comm _ _ ⟩
                  y ∧ x  ≈⟨ sym y≈y∧x ⟩
                  y      ∎
    }
  }
open Poset poset using (_≤_; isPartialOrder)
isOrderTheoreticLattice : R.IsLattice _≈_ _≤_ _∨_ _∧_
isOrderTheoreticLattice = record
  { isPartialOrder = isPartialOrder
  ; supremum       = λ x y →
                       sym (∧-absorbs-∨ x y) ,
                       (begin
                         y            ≈⟨ sym (∧-absorbs-∨ y x) ⟩
                         y ∧ (y ∨ x)  ≈⟨ ∧-cong refl (∨-comm y x) ⟩
                         y ∧ (x ∨ y)  ∎) ,
                       (λ z x≤z y≤z → sound (begin
                         (x ∨ y) ∨ z  ≈⟨ ∨-assoc x y z ⟩
                         x ∨ (y ∨ z)  ≈⟨ ∨-cong refl (complete y≤z) ⟩
                         x ∨ z        ≈⟨ complete x≤z  ⟩
                         z            ∎))
  ; infimum        = λ x y →
                       (begin
                         x ∧ y        ≈⟨ ∧-cong (sym (∧-idempotent x)) refl ⟩
                         (x ∧ x) ∧ y  ≈⟨ ∧-assoc x x y  ⟩
                         x ∧ (x ∧ y)  ≈⟨ ∧-comm x (x ∧ y) ⟩
                         (x ∧ y) ∧ x  ∎) ,
                       (begin
                         x ∧ y        ≈⟨ ∧-cong refl (sym (∧-idempotent y)) ⟩
                         x ∧ (y ∧ y)  ≈⟨ sym (∧-assoc x y y) ⟩
                         (x ∧ y) ∧ y  ∎) ,
                       (λ z z≈z∧x z≈z∧y → begin
                         z            ≈⟨ z≈z∧y ⟩
                         z ∧ y        ≈⟨ ∧-cong z≈z∧x refl ⟩
                         (z ∧ x) ∧ y  ≈⟨ ∧-assoc z x y ⟩
                         z ∧ (x ∧ y)  ∎)
  }
  where
    ∧-absorbs-∨ = proj₂ absorptive
    
    complete : ∀ {x y} → x ≤ y → x ∨ y ≈ y
    complete {x} {y} x≈x∧y = begin
      x ∨ y        ≈⟨ ∨-cong x≈x∧y refl ⟩
      (x ∧ y) ∨ y  ≈⟨ ∨-cong (∧-comm x y) refl ⟩
      (y ∧ x) ∨ y  ≈⟨ ∨-comm (y ∧ x) y ⟩
      y ∨ (y ∧ x)  ≈⟨ proj₁ absorptive y x ⟩
      y            ∎
    sound : ∀ {x y} → x ∨ y ≈ y → x ≤ y
    sound {x} {y} x∨y≈y = begin
      x            ≈⟨ sym (∧-absorbs-∨ x y) ⟩
      x ∧ (x ∨ y)  ≈⟨ ∧-cong refl x∨y≈y ⟩
      x ∧ y        ∎
orderTheoreticLattice : R.Lattice _ _ _
orderTheoreticLattice = record { isLattice = isOrderTheoreticLattice }
replace-equality : {_≈′_ : Rel Carrier l₂} →
                   (∀ {x y} → x ≈ y ⇔ (x ≈′ y)) → Lattice _ _
replace-equality {_≈′_} ≈⇔≈′ = record
  { _≈_       = _≈′_
  ; _∧_       = _∧_
  ; _∨_       = _∨_
  ; isLattice = record
    { isEquivalence = record
      { refl  = to ⟨$⟩ refl
      ; sym   = λ x≈y → to ⟨$⟩ sym (from ⟨$⟩ x≈y)
      ; trans = λ x≈y y≈z → to ⟨$⟩ trans (from ⟨$⟩ x≈y) (from ⟨$⟩ y≈z)
      }
    ; ∨-comm     = λ x y → to ⟨$⟩ ∨-comm x y
    ; ∨-assoc    = λ x y z → to ⟨$⟩ ∨-assoc x y z
    ; ∨-cong     = λ x≈y u≈v → to ⟨$⟩ ∨-cong (from ⟨$⟩ x≈y) (from ⟨$⟩ u≈v)
    ; ∧-comm     = λ x y → to ⟨$⟩ ∧-comm x y
    ; ∧-assoc    = λ x y z → to ⟨$⟩ ∧-assoc x y z
    ; ∧-cong     = λ x≈y u≈v → to ⟨$⟩ ∧-cong (from ⟨$⟩ x≈y) (from ⟨$⟩ u≈v)
    ; absorptive = (λ x y → to ⟨$⟩ proj₁ absorptive x y)
                 , (λ x y → to ⟨$⟩ proj₂ absorptive x y)
    }
  } where open module E {x y} = Equivalence (≈⇔≈′ {x} {y})