{-# OPTIONS --without-K --rewriting --overlapping-instances #-} open import lib.Basics open import lib.types.Coproduct open import lib.types.Fin open import lib.types.Pi open import lib.types.Truncation module lib.types.Choice where unchoose : ∀ {i j} {n : ℕ₋₂} {A : Type i} {B : A → Type j} → Trunc n (Π A B) → Π A (Trunc n ∘ B) unchoose = Trunc-rec (λ f → [_] ∘ f) has-choice : ∀ {i} (n : ℕ₋₂) (A : Type i) j → Type (lmax i (lsucc j)) has-choice {i} n A j = (B : A → Type j) → is-equiv (unchoose {n = n} {A} {B}) Empty-has-choice : ∀ {n} {j} → has-choice n Empty j Empty-has-choice {n} B = is-eq to from to-from from-to where to = unchoose {n = n} {Empty} {B} from : Π Empty (Trunc n ∘ B) → Trunc n (Π Empty B) from _ = [ (λ{()}) ] abstract to-from : ∀ f → to (from f) == f to-from _ = λ= λ{()} from-to : ∀ f → from (to f) == f from-to = Trunc-elim (λ _ → ap [_] (λ= λ{()})) Unit-has-choice : ∀ {n} {j} → has-choice n Unit j Unit-has-choice {n} B = is-eq to from to-from from-to where to = unchoose {n = n} {Unit} {B} Unit-elim' : B unit → Π Unit B Unit-elim' u unit = u from : Π Unit (Trunc n ∘ B) → Trunc n (Π Unit B) from f = Trunc-fmap Unit-elim' (f unit) abstract to-from : ∀ f → to (from f) == f to-from f = λ= λ{unit → Trunc-elim {P = λ f-unit → to (Trunc-fmap Unit-elim' f-unit) unit == f-unit} (λ _ → idp) (f unit)} from-to : ∀ f → from (to f) == f from-to = Trunc-elim (λ f → ap [_] (λ= λ{unit → idp})) Coprod-has-choice : ∀ {i j} {n} {A : Type i} {B : Type j} {k} → has-choice n A k → has-choice n B k → has-choice n (A ⊔ B) k Coprod-has-choice {n = n} {A} {B} A-hc B-hc C = is-eq to from to-from from-to where A-unchoose = unchoose {n = n} {A} {C ∘ inl} B-unchoose = unchoose {n = n} {B} {C ∘ inr} module A-unchoose = is-equiv (A-hc (C ∘ inl)) module B-unchoose = is-equiv (B-hc (C ∘ inr)) to = unchoose {n = n} {A ⊔ B} {C} from : Π (A ⊔ B) (Trunc n ∘ C) → Trunc n (Π (A ⊔ B) C) from f = Trunc-fmap2 Coprod-elim (A-unchoose.g (f ∘ inl)) (B-unchoose.g (f ∘ inr)) abstract to-from-inl' : ∀ f a → to (from f) (inl a) == A-unchoose (A-unchoose.g (f ∘ inl)) a to-from-inl' f a = Trunc-elim {P = λ f-inl → to (Trunc-fmap2 Coprod-elim f-inl (B-unchoose.g (f ∘ inr))) (inl a) == A-unchoose f-inl a} (λ f-inl → Trunc-elim {P = λ f-inr → to (Trunc-fmap2 Coprod-elim [ f-inl ] f-inr) (inl a) == [ f-inl a ]} (λ f-inr → idp) (B-unchoose.g (f ∘ inr))) (A-unchoose.g (f ∘ inl)) to-from-inl : ∀ f a → to (from f) (inl a) == f (inl a) to-from-inl f a = to-from-inl' f a ∙ app= (A-unchoose.f-g (f ∘ inl)) a to-from-inr' : ∀ f b → to (from f) (inr b) == B-unchoose (B-unchoose.g (f ∘ inr)) b to-from-inr' f b = Trunc-elim {P = λ f-inr → to (Trunc-fmap2 Coprod-elim (A-unchoose.g (f ∘ inl)) f-inr) (inr b) == B-unchoose f-inr b} (λ f-inr → Trunc-elim {P = λ f-inl → to (Trunc-fmap2 Coprod-elim f-inl [ f-inr ]) (inr b) == [ f-inr b ]} (λ f-inl → idp) (A-unchoose.g (f ∘ inl))) (B-unchoose.g (f ∘ inr)) to-from-inr : ∀ f b → to (from f) (inr b) == f (inr b) to-from-inr f b = to-from-inr' f b ∙ app= (B-unchoose.f-g (f ∘ inr)) b to-from : ∀ f → to (from f) == f to-from f = λ= λ{(inl a) → to-from-inl f a; (inr b) → to-from-inr f b} from-to : ∀ f → from (to f) == f from-to = Trunc-elim (λ f → Trunc-fmap2 Coprod-elim (A-unchoose.g (λ a → [ f (inl a)])) (B-unchoose.g (λ b → [ f (inr b)])) =⟨ ap2 (Trunc-fmap2 Coprod-elim) (A-unchoose.g-f [ f ∘ inl ]) (B-unchoose.g-f [ f ∘ inr ]) ⟩ [ Coprod-elim (f ∘ inl) (f ∘ inr) ] =⟨ ap [_] $ λ= (λ{(inl _) → idp; (inr _) → idp}) ⟩ [ f ] =∎) equiv-preserves-choice : ∀ {i j} {n} {A : Type i} {B : Type j} (e : A ≃ B) {k} → has-choice n A k → has-choice n B k equiv-preserves-choice {n = n} {A} {B} (f , f-ise) A-hc C = is-eq to from to-from from-to where module f = is-equiv f-ise A-unchoose = unchoose {n = n} {A} {C ∘ f} module A-unchoose = is-equiv (A-hc (C ∘ f)) to = unchoose {n = n} {B} {C} from' : Trunc n (Π A (C ∘ f)) → Trunc n (Π B C) from' = Trunc-fmap (λ g' b → transport C (f.f-g b) (g' (f.g b))) from : Π B (Trunc n ∘ C) → Trunc n (Π B C) from g = from' (A-unchoose.g (g ∘ f)) abstract to-from''' : ∀ (g-f' : Π A (C ∘ f)) {a a'} (path : f.g (f a) == a') → transport C (ap f path) (g-f' (f.g (f a))) == g-f' a' to-from''' g-f' idp = idp to-from'' : ∀ (g-f' : Π A (C ∘ f)) a → transport C (f.f-g (f a)) (g-f' (f.g (f a))) == g-f' a to-from'' g-f' a = transport C (f.f-g (f a)) (g-f' (f.g (f a))) =⟨ ! $ ap (λ p → transport C p (g-f' (f.g (f a)))) (f.adj a) ⟩ transport C (ap f (f.g-f a)) (g-f' (f.g (f a))) =⟨ to-from''' g-f' (f.g-f a) ⟩ g-f' a =∎ to-from' : ∀ g a → to (from g) (f a) == A-unchoose (A-unchoose.g (g ∘ f)) a to-from' g a = Trunc-elim {P = λ g-f → to (from' g-f) (f a) == A-unchoose g-f a} (λ g-f' → ap [_] $ to-from'' g-f' a) (A-unchoose.g (g ∘ f)) to-from : ∀ g → to (from g) == g to-from g = λ= λ b → transport (λ b → to (from g) b == g b) (f.f-g b) ( to (from g) (f (f.g b)) =⟨ to-from' g (f.g b) ⟩ A-unchoose (A-unchoose.g (g ∘ f)) (f.g b) =⟨ app= (A-unchoose.f-g (g ∘ f)) (f.g b) ⟩ g (f (f.g b)) =∎) from-to' : ∀ g {b b'} (path : f (f.g b) == b') → transport C path (g (f (f.g b))) == g b' from-to' g idp = idp from-to : ∀ g → from (to g) == g from-to = Trunc-elim {P = λ g → from (to g) == g} (λ g → from' (A-unchoose.g (λ a → [ g (f a) ])) =⟨ ap from' (A-unchoose.g-f [ (g ∘ f) ]) ⟩ from' [ (g ∘ f) ] =⟨ ap [_] $ λ= (λ b → from-to' g (f.f-g b)) ⟩ [ g ] =∎) Fin-has-choice : ∀ (n : ℕ₋₂) {m} l → has-choice n (Fin m) l Fin-has-choice _ {O} _ = equiv-preserves-choice (Fin-equiv-Empty ⁻¹) Empty-has-choice Fin-has-choice n {S m} l = equiv-preserves-choice (Fin-equiv-Coprod ⁻¹) (Coprod-has-choice (Fin-has-choice n l) Unit-has-choice)