{-# OPTIONS --safe #-}
open import Level hiding (suc)
import Level as L
open import Data.Empty
open import Data.Nat as ℕ hiding (_⊔_)
open import Data.Nat.Properties as ℕ
open import Data.Nat
open import Data.Nat.Logarithm
open import Data.Maybe using (Maybe; just; nothing; map)
import Data.Maybe as Maybe
open import Data.Product as Σ
open import Data.Sum as ⊎
open import Data.Unit
open import Function.Base
open import Relation.Binary.PropositionalEquality
open import Relation.Binary.Definitions
open import Relation.Unary
open import Relation.Nullary
open import Utils
module NatExamples.GuessingLearner {ℓr : Level} (R : Set ℓr) (ret : ℕ → R) where
open import NatLearning
learnerδ : Learnerδ R (Lift ℓr ℕ)
learnerδ (lift n) = guess n (ret n) λ
{ too-high → lift (pred n)
; too-low → lift (suc n)
}
lucky-first-guess : ℕ → Learner ℓr
lucky-first-guess init = record
{ C = Lift ℓr ℕ
; R = R
; q₀ = lift init
; learner-on = record
{ δ = learnerδ
}
}
IsSingleton : ∀ {ℓ} (X : Set ℓ) → Set ℓ
IsSingleton X = ∀ (x x' : X) → x ≡ x'
module StatelessTeacher {ℓt} (teacher : NatTeacher ℓt) (singleton : IsSingleton (NatTeacher.T teacher)) where
module teacher = NatTeacher teacher
open Game NatLearning-Semantics (mkTeacherδ teacher.δ) learnerδ
case-nothing : (n : ℕ) (st : teacher.T) → teacher.δ st n ≡ nothing
→ (∀ sec → learner (st , lift n) finds sec within 2 rounds)
case-nothing n st eq sec rewrite eq = tt
case-zero-too-high : (st : teacher.T)
→ ∃[ st' ] teacher.δ st 0 ≡ just (too-high , st')
→ ∀ sec → learner (st , lift 0) finds sec within 2 rounds
case-zero-too-high st (st' , eq) sec rewrite eq =
λ 1≤0 → case 1≤0 of λ ()
case-<> : (n : ℕ) (st : teacher.T)
→ ∃[ st' ] ∃[ st'' ] teacher.δ st (suc n) ≡ just (too-high , st')
× teacher.δ st' n ≡ just (too-low , st'')
→ ∀ sec → learner (st , lift (suc n)) finds sec within 2 rounds
case-<> n st (st' , st'' , eq1 , eq2) rewrite eq1 rewrite eq2 = λ
{ ℕ.zero 1≤suc[n] suc[n]≤0 → case suc[n]≤0 of λ ()
; (suc sec) (s≤s 1+sec≤n) (s≤s n≤sec) → <-irrefl refl (≤-trans 1+sec≤n n≤sec)
}
case-too-high : (n : ℕ) (st : teacher.T) → (∃[ st' ] teacher.δ st n ≡ just (too-high , st'))
→ ∃[ q₀ ] ∀ sec → (learner (st , lift q₀) finds sec within 2 rounds)
case-too-high ℕ.zero st (st' , eq) = 0 , case-zero-too-high st (st' , eq)
case-too-high (suc n) st (st' , eq) with (teacher.δ st' n) in eq'
... | nothing rewrite (singleton st st') = n , (case-nothing n st' eq')
... | just (too-high , st'') rewrite (singleton st st') = case-too-high n st' (st'' , eq')
... | just (too-low , st'') = suc n , case-<> n st (st' , st'' , eq , eq')
thm-in-module : ∃[ query ] Maybe.map proj₁ (teacher.δ teacher.st₀ query) ≢ just too-low
→ ∃[ learner ] (∀ secret → learner learns secret from teacher within 2 rounds)
thm-in-module (n , δ[n]≢too-low) with (teacher.δ teacher.st₀ n) in eq
... | just (too-low , _) = ⊥-elim (δ[n]≢too-low refl)
... | nothing = lucky-first-guess n , case-nothing n teacher.st₀ eq
... | just (too-high , st') =
let
m , learner-guesses-m = case-too-high n teacher.st₀ (st' , eq)
in
lucky-first-guess m , learner-guesses-m
module theorems {ℓt} (teacher : NatTeacher ℓt) where
module teacher = NatTeacher teacher
teacher-defeated-within-2-rounds :
IsSingleton (NatTeacher.T teacher)
→ ∃[ query ] Maybe.map proj₁ (teacher.δ teacher.st₀ query) ≢ just too-low
→ ∃[ learner ] learner defeats teacher with-bound (λ secret → 2)
teacher-defeated-within-2-rounds singl query = StatelessTeacher.thm-in-module teacher singl query
learner-finds-every-secret :
IsSingleton (NatTeacher.T teacher)
→ ∃[ query ] Maybe.map proj₁ (teacher.δ teacher.st₀ query) ≢ just too-low
→ ∃[ learner ] ∀ secret → learner learns secret from teacher within 2 rounds
learner-finds-every-secret singl query = StatelessTeacher.thm-in-module teacher singl query