------------------------------------------------------------------------
-- The Agda standard library
--
-- Pointwise lifting of relations to lists
------------------------------------------------------------------------

module Relation.Binary.List.Pointwise where

open import Function
open import Function.Inverse using (Inverse)
open import Data.Product hiding (map)
open import Data.List.Base hiding (map)
open import Level
open import Relation.Nullary
import Relation.Nullary.Decidable as Dec using (map′)
open import Relation.Binary renaming (Rel to Rel₂)
open import Relation.Binary.PropositionalEquality as P using (_≡_)

infixr 5 _∷_

data Rel {a b } {A : Set a} {B : Set b}
         (_∼_ : REL A B ) : List A  List B  Set (a  b  ) where
  []  : Rel _∼_ [] []
  _∷_ :  {x xs y ys} (x∼y : x  y) (xs∼ys : Rel _∼_ xs ys) 
        Rel _∼_ (x  xs) (y  ys)

head :  {a b } {A : Set a} {B : Set b} {_∼_ : REL A B } {x y xs ys} 
       Rel _∼_ (x  xs) (y  ys)  x  y
head (x∼y  xs∼ys) = x∼y

tail :  {a b } {A : Set a} {B : Set b} {_∼_ : REL A B } {x y xs ys} 
       Rel _∼_ (x  xs) (y  ys)  Rel _∼_ xs ys
tail (x∼y  xs∼ys) = xs∼ys

rec :  {a b c } {A : Set a} {B : Set b} {_∼_ : REL A B }
      (P :  {xs ys}  Rel _∼_ xs ys  Set c) 
      (∀ {x y xs ys} {xs∼ys : Rel _∼_ xs ys} 
         (x∼y : x  y)  P xs∼ys  P (x∼y  xs∼ys)) 
      P [] 
       {xs ys} (xs∼ys : Rel _∼_ xs ys)  P xs∼ys
rec P c n []            = n
rec P c n (x∼y  xs∼ys) = c x∼y (rec P c n xs∼ys)

map :  {a b ℓ₁ ℓ₂} {A : Set a} {B : Set b}
        {_≈_ : REL A B ℓ₁} {_∼_ : REL A B ℓ₂} 
      _≈_  _∼_  Rel _≈_  Rel _∼_
map ≈⇒∼ []            = []
map ≈⇒∼ (x≈y  xs≈ys) = ≈⇒∼ x≈y  map ≈⇒∼ xs≈ys

reflexive :  {a b ℓ₁ ℓ₂} {A : Set a} {B : Set b}
              {_≈_ : REL A B ℓ₁} {_∼_ : REL A B ℓ₂} 
            _≈_  _∼_  Rel _≈_  Rel _∼_
reflexive ≈⇒∼ []            = []
reflexive ≈⇒∼ (x≈y  xs≈ys) = ≈⇒∼ x≈y  reflexive ≈⇒∼ xs≈ys

refl :  {a } {A : Set a} {_∼_ : Rel₂ A } 
       Reflexive _∼_  Reflexive (Rel _∼_)
refl rfl {[]}     = []
refl rfl {x  xs} = rfl  refl rfl

symmetric :  {a b ℓ₁ ℓ₂} {A : Set a} {B : Set b}
              {_≈_ : REL A B ℓ₁} {_∼_ : REL B A ℓ₂} 
            Sym _≈_ _∼_  Sym (Rel _≈_) (Rel _∼_)
symmetric sym []            = []
symmetric sym (x∼y  xs∼ys) = sym x∼y  symmetric sym xs∼ys

transitive :
   {a b c ℓ₁ ℓ₂ ℓ₃} {A : Set a} {B : Set b} {C : Set c}
    {_≋_ : REL A B ℓ₁} {_≈_ : REL B C ℓ₂} {_∼_ : REL A C ℓ₃} 
  Trans _≋_ _≈_ _∼_  Trans (Rel _≋_) (Rel _≈_) (Rel _∼_)
transitive trans []            []            = []
transitive trans (x∼y  xs∼ys) (y∼z  ys∼zs) =
  trans x∼y y∼z  transitive trans xs∼ys ys∼zs

antisymmetric :  {a ℓ₁ ℓ₂} {A : Set a}
                  {_≈_ : Rel₂ A ℓ₁} {_≤_ : Rel₂ A ℓ₂} 
                Antisymmetric _≈_ _≤_ 
                Antisymmetric (Rel _≈_) (Rel _≤_)
antisymmetric antisym []            []            = []
antisymmetric antisym (x∼y  xs∼ys) (y∼x  ys∼xs) =
  antisym x∼y y∼x  antisymmetric antisym xs∼ys ys∼xs

respects₂ :  {a ℓ₁ ℓ₂} {A : Set a}
              {_≈_ : Rel₂ A ℓ₁} {_∼_ : Rel₂ A ℓ₂} 
            _∼_ Respects₂ _≈_  (Rel _∼_) Respects₂ (Rel _≈_)
respects₂ {_≈_ = _≈_} {_∼_} resp =
   {xs} {ys} {zs}  resp¹ {xs} {ys} {zs}) ,
   {xs} {ys} {zs}  resp² {xs} {ys} {zs})
  where
  resp¹ :  {xs}  (Rel _∼_ xs) Respects (Rel _≈_)
  resp¹ []            []            = []
  resp¹ (x≈y  xs≈ys) (z∼x  zs∼xs) =
    proj₁ resp x≈y z∼x  resp¹ xs≈ys zs∼xs

  resp² :  {ys}  (flip (Rel _∼_) ys) Respects (Rel _≈_)
  resp² []            []            = []
  resp² (x≈y  xs≈ys) (x∼z  xs∼zs) =
    proj₂ resp x≈y x∼z  resp² xs≈ys xs∼zs

decidable :  {a b } {A : Set a} {B : Set b} {_∼_ : REL A B } 
            Decidable _∼_  Decidable (Rel _∼_)
decidable dec []       []       = yes []
decidable dec []       (y  ys) = no  ())
decidable dec (x  xs) []       = no  ())
decidable dec (x  xs) (y  ys) with dec x y
... | no ¬x∼y = no (¬x∼y  head)
... | yes x∼y with decidable dec xs ys
...           | no ¬xs∼ys = no (¬xs∼ys  tail)
...           | yes xs∼ys = yes (x∼y  xs∼ys)

isEquivalence :  {a } {A : Set a} {_≈_ : Rel₂ A } 
                IsEquivalence _≈_  IsEquivalence (Rel _≈_)
isEquivalence eq = record
  { refl  = refl       Eq.refl
  ; sym   = symmetric  Eq.sym
  ; trans = transitive Eq.trans
  } where module Eq = IsEquivalence eq

isPreorder :  {a ℓ₁ ℓ₂} {A : Set a}
               {_≈_ : Rel₂ A ℓ₁} {_∼_ : Rel₂ A ℓ₂} 
             IsPreorder _≈_ _∼_  IsPreorder (Rel _≈_) (Rel _∼_)
isPreorder pre = record
  { isEquivalence = isEquivalence Pre.isEquivalence
  ; reflexive     = reflexive     Pre.reflexive
  ; trans         = transitive    Pre.trans
  } where module Pre = IsPreorder pre

isDecEquivalence :  {a } {A : Set a}
                     {_≈_ : Rel₂ A }  IsDecEquivalence _≈_ 
                   IsDecEquivalence (Rel _≈_)
isDecEquivalence eq = record
  { isEquivalence = isEquivalence DE.isEquivalence
  ; _≟_           = decidable     DE._≟_
  } where module DE = IsDecEquivalence eq

isPartialOrder :  {a ℓ₁ ℓ₂} {A : Set a}
                   {_≈_ : Rel₂ A ℓ₁} {_≤_ : Rel₂ A ℓ₂} 
                 IsPartialOrder _≈_ _≤_ 
                 IsPartialOrder (Rel _≈_) (Rel _≤_)
isPartialOrder po = record
  { isPreorder = isPreorder    PO.isPreorder
  ; antisym    = antisymmetric PO.antisym
  } where module PO = IsPartialOrder po

preorder :  {p₁ p₂ p₃}  Preorder p₁ p₂ p₃  Preorder _ _ _
preorder p = record
  { isPreorder = isPreorder (Preorder.isPreorder p)
  }

setoid :  {c }  Setoid c   Setoid _ _
setoid s = record
  { isEquivalence = isEquivalence (Setoid.isEquivalence s)
  }

decSetoid :  {c }  DecSetoid c   DecSetoid _ _
decSetoid d = record
  { isDecEquivalence = isDecEquivalence (DecSetoid.isDecEquivalence d)
  }

poset :  {c ℓ₁ ℓ₂}  Poset c ℓ₁ ℓ₂  Poset _ _ _
poset p = record
  { isPartialOrder = isPartialOrder (Poset.isPartialOrder p)
  }

-- Rel _≡_ coincides with _≡_.

Rel≡⇒≡ :  {a} {A : Set a}  Rel {A = A} _≡_  _≡_
Rel≡⇒≡ []               = P.refl
Rel≡⇒≡ (P.refl  xs∼ys) with Rel≡⇒≡ xs∼ys
Rel≡⇒≡ (P.refl  xs∼ys) | P.refl = P.refl

≡⇒Rel≡ :  {a} {A : Set a}  _≡_  Rel {A = A} _≡_
≡⇒Rel≡ P.refl = refl P.refl

Rel↔≡ :  {a} {A : Set a} 
        Inverse (setoid (P.setoid A)) (P.setoid (List A))
Rel↔≡ = record
  { to         = record { _⟨$⟩_ = id; cong = Rel≡⇒≡ }
  ; from       = record { _⟨$⟩_ = id; cong = ≡⇒Rel≡ }
  ; inverse-of = record
    { left-inverse-of  = λ _  refl P.refl
    ; right-inverse-of = λ _  P.refl
    }
  }

decidable-≡ :  {a} {A : Set a} 
              Decidable {A = A} _≡_  Decidable {A = List A} _≡_
decidable-≡ dec xs ys = Dec.map′ Rel≡⇒≡ ≡⇒Rel≡ (xs  ys)
  where
  open DecSetoid (decSetoid (P.decSetoid dec))