------------------------------------------------------------------------
-- The Agda standard library
--
-- Many properties which hold for _∼_ also hold for _∼_ on f
------------------------------------------------------------------------

open import Relation.Binary

module Relation.Binary.On where

open import Function
open import Data.Product

module _ {a b} {A : Set a} {B : Set b} (f : B  A) where

  implies :  {ℓ₁ ℓ₂} ( : Rel A ℓ₁) ( : Rel A ℓ₂) 
                ( on f)  ( on f)
  implies _ _ impl = impl

  reflexive :  {} ( : Rel A )  Reflexive   Reflexive ( on f)
  reflexive _ refl = refl

  irreflexive :  {ℓ₁ ℓ₂} ( : Rel A ℓ₁) ( : Rel A ℓ₂) 
                Irreflexive    Irreflexive ( on f) ( on f)
  irreflexive _ _ irrefl = irrefl

  symmetric :  {} ( : Rel A )  Symmetric   Symmetric ( on f)
  symmetric _ sym = sym

  transitive :  {} ( : Rel A )  Transitive   Transitive ( on f)
  transitive _ trans = trans

  antisymmetric :  {ℓ₁ ℓ₂} ( : Rel A ℓ₁) ( : Rel A ℓ₂) 
                  Antisymmetric    Antisymmetric ( on f) ( on f)
  antisymmetric _ _ antisym = antisym

  asymmetric :  {} (< : Rel A )  Asymmetric <  Asymmetric (< on f)
  asymmetric _ asym = asym

  respects :  { p} ( : Rel A ) (P : A  Set p) 
             P Respects   (P  f) Respects ( on f)
  respects _ _ resp = resp

  respects₂ :  {ℓ₁ ℓ₂} (∼₁ : Rel A ℓ₁) (∼₂ : Rel A ℓ₂) 
              ∼₁ Respects₂ ∼₂  (∼₁ on f) Respects₂ (∼₂ on f)
  respects₂ _ _ (resp₁ , resp₂) =
    ((λ {_} {_} {_}  resp₁) , λ {_} {_} {_}  resp₂)

  decidable :  {} ( : Rel A )  Decidable   Decidable ( on f)
  decidable _ dec = λ x y  dec (f x) (f y)

  total :  {} ( : Rel A )  Total   Total ( on f)
  total _ tot = λ x y  tot (f x) (f y)

  trichotomous :  {ℓ₁ ℓ₂} ( : Rel A ℓ₁) (< : Rel A ℓ₂) 
                 Trichotomous  <  Trichotomous ( on f) (< on f)
  trichotomous _ _ compare = λ x y  compare (f x) (f y)

  isEquivalence :  {} { : Rel A } 
                  IsEquivalence   IsEquivalence ( on f)
  isEquivalence { = } eq = record
    { refl  = reflexive   Eq.refl
    ; sym   = symmetric   Eq.sym
    ; trans = transitive  Eq.trans
    }
    where module Eq = IsEquivalence eq

  isPreorder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} { : Rel A ℓ₂} 
               IsPreorder    IsPreorder ( on f) ( on f)
  isPreorder { = } {} pre = record
    { isEquivalence = isEquivalence Pre.isEquivalence
    ; reflexive     = implies   Pre.reflexive
    ; trans         = transitive  Pre.trans
    }
    where module Pre = IsPreorder pre

  isDecEquivalence :  {} { : Rel A } 
                     IsDecEquivalence   IsDecEquivalence ( on f)
  isDecEquivalence { = } dec = record
    { isEquivalence = isEquivalence Dec.isEquivalence
    ; _≟_           = decidable  Dec._≟_
    }
    where module Dec = IsDecEquivalence dec

  isPartialOrder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} { : Rel A ℓ₂} 
                   IsPartialOrder   
                   IsPartialOrder ( on f) ( on f)
  isPartialOrder { = } {} po = record
    { isPreorder = isPreorder Po.isPreorder
    ; antisym    = antisymmetric   Po.antisym
    }
    where module Po = IsPartialOrder po

  isDecPartialOrder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} { : Rel A ℓ₂} 
                      IsDecPartialOrder   
                      IsDecPartialOrder ( on f) ( on f)
  isDecPartialOrder dpo = record
    { isPartialOrder = isPartialOrder DPO.isPartialOrder
    ; _≟_            = decidable _ DPO._≟_
    ; _≤?_           = decidable _ DPO._≤?_
    }
    where module DPO = IsDecPartialOrder dpo

  isStrictPartialOrder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} {< : Rel A ℓ₂} 
                         IsStrictPartialOrder  < 
                         IsStrictPartialOrder ( on f) (< on f)
  isStrictPartialOrder { = } {<} spo = record
    { isEquivalence = isEquivalence Spo.isEquivalence
    ; irrefl        = irreflexive  < Spo.irrefl
    ; trans         = transitive < Spo.trans
    ; <-resp-≈      = respects₂ <  Spo.<-resp-≈
    }
    where module Spo = IsStrictPartialOrder spo

  isTotalOrder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} { : Rel A ℓ₂} 
                 IsTotalOrder   
                 IsTotalOrder ( on f) ( on f)
  isTotalOrder { = } {} to = record
    { isPartialOrder = isPartialOrder To.isPartialOrder
    ; total          = total  To.total
    }
    where module To = IsTotalOrder to

  isDecTotalOrder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} { : Rel A ℓ₂} 
                    IsDecTotalOrder   
                    IsDecTotalOrder ( on f) ( on f)
  isDecTotalOrder { = } {} dec = record
    { isTotalOrder = isTotalOrder Dec.isTotalOrder
    ; _≟_          = decidable  Dec._≟_
    ; _≤?_         = decidable  Dec._≤?_
    }
    where module Dec = IsDecTotalOrder dec

  isStrictTotalOrder :  {ℓ₁ ℓ₂} { : Rel A ℓ₁} {< : Rel A ℓ₂} 
                       IsStrictTotalOrder  < 
                       IsStrictTotalOrder ( on f) (< on f)
  isStrictTotalOrder { = } {<} sto = record
    { isEquivalence = isEquivalence Sto.isEquivalence
    ; trans         = transitive < Sto.trans
    ; compare       = trichotomous  < Sto.compare
    ; <-resp-≈      = respects₂ <  Sto.<-resp-≈
    }
    where module Sto = IsStrictTotalOrder sto

preorder :  {p₁ p₂ p₃ b} {B : Set b} (P : Preorder p₁ p₂ p₃) 
           (B  Preorder.Carrier P)  Preorder _ _ _
preorder P f = record
  { isPreorder = isPreorder f (Preorder.isPreorder P)
  }

setoid :  {s₁ s₂ b} {B : Set b} (S : Setoid s₁ s₂) 
         (B  Setoid.Carrier S)  Setoid _ _
setoid S f = record
  { isEquivalence = isEquivalence f (Setoid.isEquivalence S)
  }

decSetoid :  {d₁ d₂ b} {B : Set b} (D : DecSetoid d₁ d₂) 
            (B  DecSetoid.Carrier D)  DecSetoid _ _
decSetoid D f = record
  { isDecEquivalence = isDecEquivalence f (DecSetoid.isDecEquivalence D)
  }

poset :  {p₁ p₂ p₃ b} {B : Set b} (P : Poset p₁ p₂ p₃) 
        (B  Poset.Carrier P)  Poset _ _ _
poset P f = record
  { isPartialOrder = isPartialOrder f (Poset.isPartialOrder P)
  }

decPoset :  {d₁ d₂ d₃ b} {B : Set b} (D : DecPoset d₁ d₂ d₃) 
           (B  DecPoset.Carrier D)  DecPoset _ _ _
decPoset D f = record
  { isDecPartialOrder =
      isDecPartialOrder f (DecPoset.isDecPartialOrder D)
  }

strictPartialOrder :
   {s₁ s₂ s₃ b} {B : Set b} (S : StrictPartialOrder s₁ s₂ s₃) 
  (B  StrictPartialOrder.Carrier S)  StrictPartialOrder _ _ _
strictPartialOrder S f = record
  { isStrictPartialOrder =
      isStrictPartialOrder f (StrictPartialOrder.isStrictPartialOrder S)
  }

totalOrder :  {t₁ t₂ t₃ b} {B : Set b} (T : TotalOrder t₁ t₂ t₃) 
             (B  TotalOrder.Carrier T)  TotalOrder _ _ _
totalOrder T f = record
  { isTotalOrder = isTotalOrder f (TotalOrder.isTotalOrder T)
  }

decTotalOrder :
   {d₁ d₂ d₃ b} {B : Set b} (D : DecTotalOrder d₁ d₂ d₃) 
  (B  DecTotalOrder.Carrier D)  DecTotalOrder _ _ _
decTotalOrder D f = record
  { isDecTotalOrder = isDecTotalOrder f (DecTotalOrder.isDecTotalOrder D)
  }

strictTotalOrder :
   {s₁ s₂ s₃ b} {B : Set b} (S : StrictTotalOrder s₁ s₂ s₃) 
  (B  StrictTotalOrder.Carrier S)  StrictTotalOrder _ _ _
strictTotalOrder S f = record
  { isStrictTotalOrder =
      isStrictTotalOrder f (StrictTotalOrder.isStrictTotalOrder S)
  }