module Order where

open import Equality
open import EquationalReasoning
open import Function
open import Level
open import Proposition
open import Sum
open import UIP

----------------------------------------------------------------------
-- Partial orders
----------------------------------------------------------------------
record Poset {ℓ : Level}(A : Set ℓ) : Set (lsuc ℓ) where
  infix 4 _≤_
  field
    _≤_ : A → A → Set ℓ
    instance {{≤isProp}} : {x y : A} → isProp (x ≤ y)
    ≤refl  : (x : A) → x ≤ x
    ≤trans : {x y z : A} → x ≤ y → y ≤ z → x ≤ z
    ≤antisymm : {x y : A} → x ≤ y → y ≤ x → x ≡ y
    
open Poset{{...}} public

{-# DISPLAY Poset._≤_ _ x y = x ≤ y #-}

----------------------------------------------------------------------
-- Total orders
----------------------------------------------------------------------
record Order {ℓ : Level}(A : Set ℓ) : Set (lsuc ℓ) where
  field
    instance {{po}} : Poset A
    ≤tot            : (x y : A) → x ≤ y or y ≤ x

open Order{{...}} public

-- Case analysis on ≤
≤ind :
  {ℓ ℓ' : Level}
  {A : Set ℓ}
  {{_ : Order A}}
  (B : A → Set ℓ')
  (_ : (x : A) → isProp (B x))
  (x : A)
  (_ : {y : A} → y ≤ x → B y)
  (_ : {y : A} → x ≤ y → B y)
  → ----------------------------
  (y : A) → B y
≤ind {{α}} B β x f g y =
  orrec
    f
    g
    (λ _ _ → cong f (≤isProp {{po {{α}}}}))
    (λ _ _ → cong g (≤isProp {{po {{α}}}}) )
    (λ _ _ → β y)
    (≤tot y x)

-- Branch on ≤
infix 8 if≤then_else_by_
if≤then_else_by_ :
   {ℓ ℓ' : Level}
   {A : Set ℓ}
   {{_ : Order A}}
   {B : Set ℓ'}
   (f g : A → A → B)
   (e : (x : A) → f x x ≡ g x x)
   → --------------------------
   A → A → B
(if≤then f else g by e) x y =
  orrec
    (λ _ → f x y)
    (λ _ → g x y)
    (λ _ _ → refl)
    (λ _ _ → refl)
    (λ u v → subst (λ z → f x z ≡ g x z) (≤antisymm u v) (e x))
    (≤tot x y)

if≤then-l :
   {ℓ ℓ' : Level}
   {A : Set ℓ}
   {{_ : Order A}}
   {B : Set ℓ'}
   (f g : A → A → B)
   (e : (x : A) → f x x ≡ g x x)
   {x y : A}
   → -----------------------------------------
   x ≤ y → (if≤then f else g by e) x y ≡ f x y
if≤then-l f g e {x} {y} u =
  let h = orrec
        (λ _ → f x y)
        (λ _ → g x y)
        (λ _ _ → refl)
        (λ _ _ → refl)
        (λ u v → subst (λ z → f x z ≡ g x z) (≤antisymm u v) (e x))
  in
  proof:
    h (≤tot x y)
  ≡[ cong h (∥∥isProp) ]
    h (inl u mod∇)
  ≡[ orcompl (λ _ → f x y) (λ _ → g x y) (λ _ _ → refl) (λ _ _ → refl)
     (λ u v → subst (λ z → f x z ≡ g x z) (≤antisymm u v) (e x)) u ]
    f x y
  qed

if≤then-r :
   {ℓ ℓ' : Level}
   {A : Set ℓ}
   {{_ : Order A}}
   {B : Set ℓ'}
   (f g : A → A → B)
   (e : (x : A) → f x x ≡ g x x)
   {x y : A}
   → -----------------------------------------
   y ≤ x → (if≤then f else g by e) x y ≡ g x y
if≤then-r f g e {x} {y} u =
  let h = orrec
        (λ _ → f x y)
        (λ _ → g x y)
        (λ _ _ → refl)
        (λ _ _ → refl)
        (λ u v → subst (λ z → f x z ≡ g x z) (≤antisymm u v) (e x))
  in
  proof:
    h (≤tot x y)
  ≡[ cong h (∥∥isProp) ]
    h (inr u mod∇)
  ≡[ orcompr (λ _ → f x y) (λ _ → g x y) (λ _ _ → refl) (λ _ _ → refl)
     (λ u v → subst (λ z → f x z ≡ g x z) (≤antisymm u v) (e x)) u ]
    g x y
  qed

∘if≤then :
   {ℓ ℓ' ℓ'' : Level}
   {A : Set ℓ}
   {{_ : Order A}}
   {B : Set ℓ'}
   {C : Set ℓ''}
   (f g : A → A → B)
   (e : (x : A) → f x x ≡ g x x)
   (h : B → C)
   (x y : A)
   → -----------------------------------------------------
   h ((if≤then f else g by e) x y) ≡
   (if≤then h ∘₂ f else h ∘₂ g by λ x → cong h (e x)) x y
∘if≤then {ℓ'' = ℓ''} {A} f g e h x = ≤ind E (λ _ → uip) x f' g'
  where
  E : A → Set ℓ''
  E y =
    h ((if≤then f else g by e) x y) ≡
    (if≤then h ∘₂ f else h ∘₂ g by λ x → cong h (e x)) x y
    
  f' : {y : A} → y ≤ x → E y
  f' {y} u =
    proof:
      h ((if≤then f else g by e) x y)
    ≡[ cong h (if≤then-r f g e u) ]
      h (g x y)
    ≡[ symm (if≤then-r (h ∘₂ f ) (h ∘₂ g) (λ x → cong h (e x)) u ) ]
      (if≤then h ∘₂ f else h ∘₂ g by λ x → cong h (e x)) x y
    qed

  g' : {y : A} → x ≤ y → E y
  g' {y} v =
    proof:
      h ((if≤then f else g by e) x y)
    ≡[ cong h (if≤then-l f g e v) ]
      h (f x y)
    ≡[ symm (if≤then-l (h ∘₂ f ) (h ∘₂ g) (λ x → cong h (e x)) v ) ]
      (if≤then h ∘₂ f else h ∘₂ g by λ x → cong h (e x)) x y
    qed