open import 1Lab.Path.Reasoning
open import 1Lab.Prelude
open import Algebra.Monoid.Category
open import Algebra.Group
open import Data.List hiding (lookup)
open import Data.Fin
open import Data.Fin.Closure
open is-iso
module Hats where
module _ (n-1 : Nat) where
private
n = suc n-1
Person = Fin n
Hat = Fin n
Hats = Person → Hat
record Strategy : Type where
field
guess : Person → (Fin n-1 → Hat) → Hat
_✓_ : Hats → Person → Type
hats ✓ i = guess i (delete hats i) ≡ hats i
field
one-right : ∀ hats → Σ Person λ i → hats ✓ i
exactly-one-right : ∀ hats → is-contr (Σ Person λ i → hats ✓ i)
exactly-one-right hats = Equiv→is-hlevel 0 (Fibre-equiv _ hats e⁻¹) (p-is-equiv .is-eqv hats)
where
probability : ∀ i → Iso (Σ Hats (_✓ i)) (Fin n-1 → Hat)
probability i .fst (hats , _) = delete hats i
probability i .snd .inv other .fst = other [ i ≔ guess i other ]
probability i .snd .inv other .snd =
guess i ⌜ delete (other [ i ≔ guess i other ]) i ⌝ ≡⟨ ap! (funext (delete-insert _ i _)) ⟩
guess i other ≡˘⟨ insert-lookup _ i _ ⟩
(other [ i ≔ guess i other ]) i ∎
probability i .snd .rinv _ = funext (delete-insert _ i _)
probability i .snd .linv (hats , r) = Σ-prop-path! (funext (insert-delete _ i _ (sym r)))
only-one : Σ Hats (λ hats → Σ Person (hats ✓_)) ≃ Hats
only-one =
Σ _ (λ hats → Σ _ λ i → hats ✓ i) ≃⟨ Σ-swap₂ ⟩
Σ _ (λ i → Σ _ λ hats → hats ✓ i) ≃⟨ Σ-ap-snd (Iso→Equiv ∘ probability) ⟩
Fin n × (Fin n-1 → Fin n) ≃˘⟨ Fin-suc-Π ⟩
(Fin n → Fin n) ≃∎
p : Σ Hats (λ hats → Σ Person (hats ✓_)) → Hats
p = fst
p-is-equiv : is-equiv p
p-is-equiv = Finite-surjection→equiv (inc only-one) p
λ other → inc ((other , one-right other) , refl)
open Strategy public
Hypercube : Nat → Type
Hypercube m = (Fin n → Fin m) → Fin m
is-latin : ∀ {m} → Hypercube m → Type
is-latin {m} h = ∀ (i : Fin n) (xs : Fin n-1 → Fin m) → is-equiv λ x → h (xs [ i ≔ x ])
Latin-hypercube : Nat → Type
Latin-hypercube m = Σ (Hypercube m) is-latin
latin→strategy : Latin-hypercube n → Strategy
latin→strategy (h , lat) .guess i other = equiv→inverse (lat i other) i
latin→strategy (h , lat) .one-right hats =
h hats , Equiv.from (eqv (h hats)) refl
where
module L i = Equiv (_ , lat i (delete hats i))
eqv : ∀ (i : Fin n) → (L.from i i ≡ hats i) ≃ (h hats ≡ i)
eqv i =
L.from i i ≡ hats i ≃⟨ Equiv.adjunct (L.inverse i) ⟩
i ≡ L.to i (hats i) ≃⟨ sym-equiv ⟩
L.to i (hats i) ≡ i ≃⟨ ∙-pre-equiv (sym (ap h (funext (insert-delete hats i _ refl)))) ⟩
h hats ≡ i ≃∎
group→latin : Group-on (Fin n) → Latin-hypercube n
group→latin G = mul , mul-equiv
where
open Group-on G hiding (magma-hlevel)
mul : ∀ {m} → (Fin m → Fin n) → Fin n
mul xs = fold underlying-monoid (tabulate xs)
mul-equiv : ∀ {m} (i : Fin (suc m)) (xs : Fin m → Fin n)
→ is-equiv (λ x → mul (xs [ i ≔ x ]))
mul-equiv fzero xs = ⋆-equivr _
mul-equiv {suc m} (fsuc i) xs = ∙-is-equiv (mul-equiv i (xs ∘ fsuc)) (⋆-equivl _)
group→strategy : Group-on (Fin n) → Strategy
group→strategy = latin→strategy ∘ group→latin