{-# OPTIONS --cubical --safe #-}
module Data.List.Relation.Unary where
open import Prelude
open import Data.List.Base
open import Data.Fin
open import Relation.Nullary
open import Data.Sum
private
variable p : Level
module Inductive◇ where
data ◇ {A : Type a} (P : A → Type p) : List A → Type (a ℓ⊔ p) where
here : ∀ {x xs} → P x → ◇ P (x ∷ xs)
there : ∀ {x xs} → ◇ P xs → ◇ P (x ∷ xs)
◇ : (P : A → Type p) → List A → Type _
◇ P xs = ∃[ i ] P (xs ! i)
◇! : (P : A → Type p) → List A → Type _
◇! P xs = isContr (◇ P xs)
module Exists {a} {A : Type a} {p} (P : A → Type p) where
push : ∀ {x xs} → ◇ P xs → ◇ P (x ∷ xs)
push (n , p) = fs n , p
pull : ∀ {x xs} → ¬ P x → ◇ P (x ∷ xs) → ◇ P xs
pull ¬Px (f0 , p) = ⊥-elim (¬Px p)
pull ¬Px (fs n , p) = n , p
uncons : ∀ {x xs} → ◇ P (x ∷ xs) → P x ⊎ ◇ P xs
uncons (f0 , p) = inl p
uncons (fs x , p) = inr (x , p)
infixr 5 _++◇_ _◇++_
_++◇_ : ∀ {xs} ys → ◇ P xs → ◇ P (ys ++ xs)
[] ++◇ ys = ys
(x ∷ xs) ++◇ ys = push (xs ++◇ ys)
_◇++_ : ∀ xs → ◇ P xs → ∀ {ys} → ◇ P (xs ++ ys)
_◇++_ (x ∷ xs) (f0 , ∃Pxs) = f0 , ∃Pxs
_◇++_ (x ∷ xs) (fs n , ∃Pxs) = push (xs ◇++ (n , ∃Pxs))
push! : ∀ {x xs} → ¬ P x → ◇! P xs → ◇! P (x ∷ xs)
push! ¬Px x∈!xs .fst = push (x∈!xs .fst)
push! ¬Px x∈!xs .snd (f0 , px) = ⊥-elim (¬Px px)
push! ¬Px x∈!xs .snd (fs n , y∈xs) i = push (x∈!xs .snd (n , y∈xs) i)
pull! : ∀ {x xs} → ¬ P x → ◇! P (x ∷ xs) → ◇! P xs
pull! ¬Px ((f0 , px ) , uniq) = ⊥-elim (¬Px px)
pull! ¬Px ((fs n , x∈xs ) , uniq) .fst = (n , x∈xs)
pull! ¬Px ((fs n , x∈xs ) , uniq) .snd (m , x∈xs′) i =
pull ¬Px (uniq (fs m , x∈xs′ ) i)
here! : ∀ {x xs} → isContr (P x) → ¬ ◇ P xs → ◇! P (x ∷ xs)
here! Px p∉xs .fst = f0 , Px .fst
here! Px p∉xs .snd (f0 , p∈xs) i .fst = f0
here! Px p∉xs .snd (f0 , p∈xs) i .snd = Px .snd p∈xs i
here! Px p∉xs .snd (fs n , p∈xs) = ⊥-elim (p∉xs (n , p∈xs))
module _ (P? : ∀ x → Dec (P x)) where
open import Relation.Nullary.Decidable.Logic
◇? : ∀ xs → Dec (◇ P xs)
◇? [] = no λ ()
◇? (x ∷ xs) = ⟦yes ⟦l f0 ,_ ,r push ⟧ ,no uncons ⟧ (P? x || ◇? xs)
◻ : (P : A → Type p) → List A → Type _
◻ P xs = ∀ i → P (xs ! i)
module Forall {a} {A : Type a} {p} (P : A → Type p) where
push : ∀ {x xs} → P x → ◻ P xs → ◻ P (x ∷ xs)
push Px Pxs f0 = Px
push Px Pxs (fs n) = Pxs n
uncons : ∀ {x xs} → ◻ P (x ∷ xs) → P x × ◻ P xs
uncons Pxs = Pxs f0 , Pxs ∘ fs
pull : ∀ {x xs} → ◻ P (x ∷ xs) → ◻ P xs
pull = snd ∘ uncons
_++◇_ : ∀ xs {ys} → ◻ P (xs ++ ys) → ◻ P ys
[] ++◇ xs⊆P = xs⊆P
(x ∷ xs) ++◇ xs⊆P = xs ++◇ (xs⊆P ∘ fs)
_◇++_ : ∀ xs {ys} → ◻ P (xs ++ ys) → ◻ P xs
([] ◇++ xs⊆P) ()
((x ∷ xs) ◇++ xs⊆P) f0 = xs⊆P f0
((x ∷ xs) ◇++ xs⊆P) (fs n) = (xs ◇++ pull xs⊆P) n
both : ∀ xs {ys} → ◻ P xs → ◻ P ys → ◻ P (xs ++ ys)
both [] xs⊆P ys⊆P = ys⊆P
both (x ∷ xs) xs⊆P ys⊆P f0 = xs⊆P f0
both (x ∷ xs) xs⊆P ys⊆P (fs i) = both xs (pull xs⊆P) ys⊆P i
empty : ◻ P []
empty ()
module _ where
open import Relation.Nullary.Decidable.Logic
◻? : (∀ x → Dec (P x)) → ∀ xs → Dec (◻ P xs)
◻? P? [] = yes λ ()
◻? P? (x ∷ xs) = ⟦yes uncurry push
,no uncons
⟧ (P? x && ◻? P? xs)
module Forall-NotExists {a} {A : Type a} {p} (P : A → Type p) where
open import Relation.Nullary.Stable
open import Data.Empty.Properties
open Forall P
¬P = ¬_ ∘ P
module ∃¬ = Exists ¬P
∀⇒¬∃¬ : ∀ xs → ◻ P xs → ¬ (◇ ¬P xs)
∀⇒¬∃¬ (x ∷ xs) xs⊆P (f0 , ∃¬P∈xs) = ∃¬P∈xs(xs⊆P f0)
∀⇒¬∃¬ (x ∷ xs) xs⊆P (fs n , ∃¬P∈xs) = ∀⇒¬∃¬ xs (xs⊆P ∘ fs) (n , ∃¬P∈xs)
module _ (stable : ∀ {x} → Stable (P x)) where
¬∃¬⇒∀ : ∀ xs → ¬ (◇ ¬P xs) → ◻ P xs
¬∃¬⇒∀ (x ∷ xs) ¬∃¬P∈xs f0 = stable (¬∃¬P∈xs ∘ (f0 ,_))
¬∃¬⇒∀ (x ∷ xs) ¬∃¬P∈xs (fs n) = ¬∃¬⇒∀ xs (¬∃¬P∈xs ∘ ∃¬.push) n
leftInv′ : ∀ (prop : ∀ {x} → isProp (P x)) xs → (x : ◻ P xs) → ¬∃¬⇒∀ xs (∀⇒¬∃¬ xs x) ≡ x
leftInv′ prop [] x i ()
leftInv′ prop (x ∷ xs) xs⊆P i f0 = prop (stable λ ¬p → ¬p (xs⊆P f0)) (xs⊆P f0) i
leftInv′ prop (x ∷ xs) xs⊆P i (fs n) = leftInv′ prop xs (pull xs⊆P) i n
∀⇔¬∃¬ : ∀ (prop : ∀ {x} → isProp (P x)) xs → ◻ P xs ⇔ (¬ ◇ ¬P xs)
∀⇔¬∃¬ _ xs .fun = ∀⇒¬∃¬ xs
∀⇔¬∃¬ _ xs .inv = ¬∃¬⇒∀ xs
∀⇔¬∃¬ p xs .leftInv = leftInv′ p xs
∀⇔¬∃¬ _ xs .rightInv x = isProp¬ _ _ x
module Exists-NotForall {a} {A : Type a} {p} (P : A → Type p) where
open Exists P
¬P = ¬_ ∘ P
module ∀¬ = Forall ¬P
∃⇒¬∀¬ : ∀ xs → ◇ P xs → ¬ ◻ ¬P xs
∃⇒¬∀¬ (x ∷ xs) (f0 , P∈xs) xs⊆P = xs⊆P f0 P∈xs
∃⇒¬∀¬ (x ∷ xs) (fs n , P∈xs) xs⊆P = ∃⇒¬∀¬ xs (n , P∈xs) (xs⊆P ∘ fs)
module _ (P? : ∀ x → Dec (P x)) where
¬∀¬⇒∃ : ∀ xs → ¬ ◻ ¬P xs → ◇ P xs
¬∀¬⇒∃ [] ¬xs⊆¬P = ⊥-elim (¬xs⊆¬P λ ())
¬∀¬⇒∃ (x ∷ xs) ¬xs⊆¬P with P? x
¬∀¬⇒∃ (x ∷ xs) ¬xs⊆¬P | yes p = f0 , p
¬∀¬⇒∃ (x ∷ xs) ¬xs⊆¬P | no ¬p = push (¬∀¬⇒∃ xs (¬xs⊆¬P ∘ ∀¬.push ¬p))
module Congruence {p q} (P : A → Type p) (Q : B → Type q)
{f : A → B} (f↑ : ∀ {x} → P x → Q (f x)) where
cong-◇ : ∀ xs → ◇ P xs → ◇ Q (map f xs)
cong-◇ (x ∷ xs) (f0 , P∈xs) = f0 , f↑ P∈xs
cong-◇ (x ∷ xs) (fs n , P∈xs) = Exists.push Q (cong-◇ xs (n , P∈xs))
◇-concat : ∀ (P : A → Type p) xs → ◇ (◇ P) xs → ◇ P (concat xs)
◇-concat P (x ∷ xs) (f0 , ps) = Exists._◇++_ P x ps
◇-concat P (x ∷ xs) (fs n , ps) = Exists._++◇_ P x (◇-concat P xs (n , ps))
◻-concat : ∀ (P : A → Type p) xs → ◻ (◻ P) xs → ◻ P (concat xs)
◻-concat P [] xs⊆P ()
◻-concat P (x ∷ xs) xs⊆P = Forall.both P x (xs⊆P f0) (◻-concat P xs (xs⊆P ∘ fs))
module Search {A : Type a} where
data Result {p} (P : A → Type p) (xs : List A) : Bool → Type (a ℓ⊔ p) where
all′ : ◻ P xs → Result P xs true
except′ : ◇ (¬_ ∘ P) xs → Result P xs false
record Found {p} (P : A → Type p) (xs : List A) : Type (a ℓ⊔ p) where
field
found? : Bool
result : Result P xs found?
open Found public
pattern all ps = record { found? = true ; result = all′ ps }
pattern except ¬p = record { found? = false ; result = except′ ¬p }
module _ {p} {P : A → Type p} (P? : ∀ x → Dec (P x)) where
search : ∀ xs → Found P xs
search [] = all λ ()
search (x ∷ xs) = search′ x xs (P? x) (search xs)
where
search′ : ∀ x xs → Dec (P x) → Found P xs → Found P (x ∷ xs)
search′ x xs Px Pxs .found? = Px .does and Pxs .found?
search′ x xs (no ¬p) Pxs .result = except′ (f0 , ¬p)
search′ x xs (yes p) (except ¬p) .result = except′ (Exists.push (¬_ ∘ P) ¬p)
search′ x xs (yes p) (all ps) .result = all′ (Forall.push P p ps)