{-# OPTIONS --safe #-} module Finite where open import Prelude open import Function.Properties open import Data.List.Membership ℰ : Type a → Type a ℰ A = ∃ n × ∥ Fin n ≃ A ∥ open import Data.Nat.Properties using (isSetNat) open import Data.Fin.Injective open import Isomorphism.Properties isPropℰ : isProp (ℰ A) isPropℰ (n , xe) (m , ye) = Σ≡Prop (λ _ → squash) (∥rec2∥ (isSetNat _ _) (λ lhs rhs → Fin-inj (ua (lhs ⟨ ≃-trans ⟩ ≃-sym rhs))) xe ye) trav : ∀ {n} {P : Lift {ℓ₂ = b} (Fin n) → Type p} → (∀ x → ∥ P x ∥) → ∥ (∀ x → P x) ∥ trav {n = zero } f = ∣ (λ ()) ∣ trav {b = b} {n = suc n} f = let h = f (lift zero) in ∥liftA2∥ (λ { x xs (lift zero) → x ; x xs (lift (suc i)) → xs (lift i) }) h (trav {b = b} (f ∘′ lift ∘′ suc ∘′ lower)) travℰ : ℰ A → ((x : A) → ∥ P x ∥) → ∥ ((x : A) → P x) ∥ travℰ (n , p) k = ∥rec∥ squash (λ e → let h = ua (≃-trans (isoToEquiv ⇔-lift) e) in subst (λ t → ∀ {P : t → Type _} → ((x : t) → ∥ P x ∥) → ∥ (∀ x → P x) ∥ ) h trav k) p module _ where open import Finite.OnLists ≃⇒ℰ! : ∃ n × (Fin n ≃ A) → ℰ! A ≃⇒ℰ! (n , p) .fst = tabulate (p .fst) ≃⇒ℰ! (n , p) .snd x = let e = p .snd .equiv-proof x h = tabulate-∈ (p .fst) (e .fst .fst) in subst (_∈ tabulate (p .fst)) (e .fst .snd) h module _ {A : Type a} where ℰΣ : ℰ A → ((x : A) → ℰ (P x)) → ℰ (Σ A P) ℰΣ (n , xs) k = ∥rec2∥ isPropℰ conv xs (travℰ (n , xs) (snd ∘′ k)) where conv : Fin n ≃ A → ((x : A) → Fin (k x .fst) ≃ P x) → ℰ (Σ A P) conv e k′ = let h = ≃⇒ℰ! (_ , e) |Σ| λ x → ≃⇒ℰ! (_ , k′ x) in map₂ ∣_∣ (ℬ→ℱ (ℰ!⇒ℬ h)) open import Data.Nat.Order ⇔→ℰ : A ⇔ B → ℰ A → ℰ B ⇔→ℰ i = map₂ (∥map∥ (flip ≃-trans (isoToEquiv i))) Equiv⇒SplitSurj : (f : A → B) → isEquiv f → SplitSurjective f Equiv⇒SplitSurj f x y = x .equiv-proof y .fst ≃⇒↠! : A ≃ B → A ↠! B ≃⇒↠! = map₂ (Equiv⇒SplitSurj _) ℰ⇒Discrete : ℰ A → Discrete A ℰ⇒Discrete = ∥rec∥ isPropDiscrete (flip Discrete-↠! discreteFin ∘ ≃⇒↠!) ∘′ snd open import Data.Fin.Properties using (isPropFin1; Fin⊥) ℰ⇒Dec : ℰ A → Dec ∥ A ∥ ℰ⇒Dec (zero , xs) = no (∥rec2∥ (λ ()) (λ e x → Fin⊥ .fun (e .snd .equiv-proof x .fst .fst)) xs) ℰ⇒Dec (suc n , xs) = yes (∥map∥ ((_$ zero) ∘ fst) xs) open import Cubical.Foundations.Prelude using (isContr→isProp) isContr⇒ℰ : isContr A → ℰ A isContr⇒ℰ (x , p) .fst = 1 isContr⇒ℰ (x , p) .snd = ∣ (λ where .fst _ → x .snd .equiv-proof y .fst .fst → 0 .snd .equiv-proof y .fst .snd → p y .snd .equiv-proof y .snd (zero , q) i → zero , isProp→isSet (isContr→isProp (x , p)) x y (p y) q i) ∣ ¬⇒ℰ : ¬ A → ℰ A ¬⇒ℰ ¬A .fst = 0 ¬⇒ℰ ¬A .snd = ∣ (λ where .fst () .snd .equiv-proof y → absurd (¬A y) ) ∣ ℰ× : ℰ A → ℰ B → ℰ (A × B) ℰ× x y = ℰΣ x (const y) ℰ⟨⊤⟩ : ℰ ⊤ ℰ⟨⊤⟩ = isContr⇒ℰ (tt , λ _ → refl) open import Data.Nat.Properties private variable n m : ℕ ℰ⟨Fin⟩ : ℰ (Fin n) ℰ⟨Fin⟩ {n = n} = n , ∣ isoToEquiv id-⇔ ∣ ℰ⟨ℕ≤⟩ : ℰ (∃ m × m ≤ n) ℰ⟨ℕ≤⟩ = suc _ , ∣ isoToEquiv lemma ∣ where fin→≤ : Fin (suc n) → ∃ m × m ≤ n fin→≤ zero = zero , tt fin→≤ {n = suc n} (suc f) = let g , p = fin→≤ {n = n} f in suc g , p ≤→fin : ∃ m × m ≤ n → Fin (suc n) ≤→fin (zero , p) = zero ≤→fin {n = suc n} (suc m , p) = suc (≤→fin {n} (m , p)) linv : (x : Fin (suc n)) → ≤→fin (fin→≤ x) ≡ x linv zero = refl linv {n = suc n} (suc x) = cong suc (linv {n} x) rinv : (x : ∃ m × m ≤ n) → fin→≤ (≤→fin x) ≡ x rinv {n} (zero , p) = refl rinv {suc n} (suc m , p) = cong (map-Σ suc id) (rinv {n} (m , p)) lemma : Fin (suc n) ⇔ (∃ m × m ≤ n) lemma .fun = fin→≤ lemma .inv = ≤→fin lemma .rightInv = rinv lemma .leftInv = linv DecProp⇒ℰ : isProp A → Dec A → ℰ A DecProp⇒ℰ isPropA (yes p) = isContr⇒ℰ (p , isPropA p) DecProp⇒ℰ isPropA (no ¬p) = ¬⇒ℰ ¬p Discrete⇒ℰ : Discrete A → {x y : A} → ℰ (x ≡ y) Discrete⇒ℰ d = DecProp⇒ℰ (Discrete→isSet d _ _) (d _ _) ℰ? : (∀ x → isProp (P x)) → ℰ A → ((x : A) → Dec (P x)) → ℰ (Σ A P) ℰ? pIsProp ℰA ℰP? = ℰΣ ℰA λ x → DecProp⇒ℰ (pIsProp x) (ℰP? x) module _ (ℰ⟨A⟩ : ℰ A) where ℰ⟨List·length⟩ : ∀ n → ℰ (Σ[ xs ⦂ List A ] × length xs ≡ n) ℰ⟨List·length⟩ zero = ⇔→ℰ lemma ℰ⟨⊤⟩ where lemma : ⊤ ⇔ (Σ[ xs ⦂ List A ] × length xs ≡ 0) lemma .fun _ = [] , refl lemma .inv _ = tt lemma .rightInv ([] , p) = Σ≡Prop (λ _ → isSetNat _ _) refl lemma .rightInv (x ∷ xs , p) = absurd (suc≢zero p) lemma .leftInv _ = refl ℰ⟨List·length⟩ (suc n) = ⇔→ℰ lemma (ℰ× ℰ⟨A⟩ (ℰ⟨List·length⟩ n)) where lemma : (A × Σ[ xs ⦂ List A ] × length xs ≡ n) ⇔ (Σ[ xs ⦂ List A ] × length xs ≡ suc n) lemma .fun (x , xs , p) = x ∷ xs , cong suc p lemma .inv ([] , p) = absurd (zero≢suc p) lemma .inv (x ∷ xs , p) = x , xs , suc-inj p lemma .rightInv ([] , p) = absurd (zero≢suc p) lemma .rightInv (x ∷ xs , p) = Σ≡Prop (λ _ → isSetNat _ _) refl lemma .leftInv (x , xs , p) = refl open import Isomorphism.Properties ℰ⟨List≤length⟩ : ∀ n → ℰ (Σ[ xs ⦂ List A ] × length xs ≤ n) ℰ⟨List≤length⟩ n = ⇔→ℰ lemma (ℰΣ (ℰ⟨ℕ≤⟩ {n}) (ℰ⟨List·length⟩ ∘′ fst)) where lemma : (Σ[ p ⦂ (∃ m × m ≤ n) ] × Σ[ xs ⦂ List A ] × length xs ≡ fst p) ⇔ (Σ[ xs ⦂ List A ] × length xs ≤ n) lemma .fun ((m , p) , xs , q) = xs , subst (_≤ _) (sym q) p lemma .inv (xs , q) = (length xs , q) , xs , refl lemma .rightInv (xs , q) = Σ≡Prop (λ x → isProp≤ {length x} ) refl lemma .leftInv ((m , p) , xs , q) = ΣPathP (Σ≡Prop (λ x → isProp≤ {x}) q , toPathP (Σ≡Prop (λ x → isSetNat _ _) (transportRefl xs))) ℰ×NoDup⇒List≤ : (xs : List A) → NoDup xs → length xs ≤ ℰ⟨A⟩ .fst ℰ×NoDup⇒List≤ xs nd = let h = ((xs !!_) , NoDup⇒Inj xs nd) ⦂ (Fin (length xs) ↣ A) in ∥rec∥ (isProp≤ {length xs}) (λ p → ↣⇒≤ (↣-trans h (_ , ⇔-fun-inj (sym-⇔ (equivToIso p)) _ _))) (ℰ⟨A⟩ .snd) ℰ⟨List⟩ : ℰ (Σ[ xs ⦂ List A ] × NoDup xs) ℰ⟨List⟩ = ⇔→ℰ (Σ-assoc ⟨ trans-⇔ ⟩ cong-Σ lemma) (ℰ? (λ _ → isPropNoDup _) (ℰ⟨List≤length⟩ (ℰ⟨A⟩ .fst)) (NoDups? (ℰ⇒Discrete ℰ⟨A⟩) ∘′ fst)) where lemma : (xs : List A) → ((length xs ≤ ℰ⟨A⟩ .fst) × NoDup xs) ⇔ NoDup xs lemma xs .fun = snd lemma xs .inv nd = ℰ×NoDup⇒List≤ xs nd , nd lemma xs .rightInv _ = refl lemma xs .leftInv x = ΣPathP (isProp≤ {length xs} _ _ , refl) module _ {P : A → Type p} where ℰ⇒search : ℰ A → (P? : ∀ (x : A) → Dec (P x)) → Dec ∥ ∃ x × P x ∥ ℰ⇒search ℰA P? = ∥rec∥ (isPropDec squash) (dec-trunc ∘ search) (ℰA .snd) where search′ : (f : Fin n → A) → Dec (∃ i × P (f i)) search′ {n = zero} f = no λ () search′ {n = suc n} f with P? (f 0) | search′ (f ∘ suc) ... | yes p | _ = yes (0 , p) ... | no ¬p | yes (i , p) = yes (suc i , p) ... | no ¬p | no ¬ps = no λ { (zero , p) → ¬p p ; (suc i , p) → ¬ps (i , p) } open import Cubical.Foundations.Everything using (equivToIso) search : (Fin n ≃ A) → Dec (∃ x × P x) search f≃A = let f⇔A = equivToIso f≃A in iff-dec (map-Σ (f⇔A .fun) id , map-Σ (f⇔A .inv) (subst P (sym (f⇔A .rightInv _)))) (search′ (f⇔A .fun))