Skip to content

Instantly share code, notes, and snippets.

@bobatkey
Created November 8, 2024 10:38
Show Gist options
  • Save bobatkey/b9ba09a9934bed48ae3551493173f952 to your computer and use it in GitHub Desktop.
Save bobatkey/b9ba09a9934bed48ae3551493173f952 to your computer and use it in GitHub Desktop.
"How to Make Good Choices" notes for a talk
{-# OPTIONS --postfix-projections #-}
module Choices where
open import Level using (0ℓ) renaming (suc to lsuc)
open import Data.Product using (_,_; _×_; Σ-syntax; proj₁; proj₂)
open import Data.Bool using (true; false; if_then_else_; _∧_; not)
renaming (Bool to 𝔹)
open import Data.Nat using (ℕ; zero; suc; _≤ᵇ_)
open import Data.Unit using (⊤; tt)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
------------------------------------------------------------------------------
--
-- HOW TO MAKE GOOD CHOICES
--
-- Robert Atkey, MSP 101, 8th November 2024
--
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Part I : Choice Monads
------------------------------------------------------------------------------
record ChoiceMonad : Set (lsuc 0ℓ) where
field
Mon : Set → Set
unit : ∀ {A} → A → Mon A
bind : ∀ {A B} → Mon A → (A → Mon B) → Mon B
choose : Mon 𝔹
open ChoiceMonad
-- Choice trees:
data Choices (A : Set) : Set where
success : A → Choices A
branch : Choices A → Choices A → Choices A
Choices-unit : ∀ {A} → A → Choices A
Choices-unit a = success a
Choices-bind : ∀ {A B} → Choices A → (A → Choices B) → Choices B
Choices-bind (success a) k = k a
Choices-bind (branch c₁ c₂) k = branch (Choices-bind c₁ k) (Choices-bind c₂ k)
Choices-choose : Choices 𝔹
Choices-choose = branch (success true) (success false)
ChoicesChoiceMonad : ChoiceMonad
ChoicesChoiceMonad .Mon = Choices
ChoicesChoiceMonad .unit = success
ChoicesChoiceMonad .bind = Choices-bind
ChoicesChoiceMonad .choose = Choices-choose
argmin : ∀ {A} → (A → ℕ) → Choices A → A
argmin cost (success a) = a
argmin cost (branch c₁ c₂) =
let a₁ = argmin cost c₁
a₂ = argmin cost c₂
in if cost a₁ ≤ᵇ cost a₂ then a₁ else a₂
-- Selectors:
Selection : Set → Set → Set
Selection R A = (A → R) → A
Selection-unit : ∀ {R A} → A → Selection R A
Selection-unit a _cost = a
Selection-bind : ∀ {A B R} → Selection R A → (A → Selection R B) → Selection R B
Selection-bind c k = λ cost →
let b = c (λ a → cost (k a cost)) in k b cost
Selection-choose : Selection ℕ 𝔹
Selection-choose cost =
if cost true ≤ᵇ cost false then true else false
SelectionChoiceMonad : ChoiceMonad
SelectionChoiceMonad .Mon = Selection ℕ
SelectionChoiceMonad .unit = λ a _ → a
SelectionChoiceMonad .bind = Selection-bind
SelectionChoiceMonad .choose = Selection-choose
-- Claim:
--
-- The Choices monad and the Selection monad are the same, *if* we
-- only use the `choose` operation, and we only care about the
-- `argmin` result.
------------------------------------------------------------------------------
-- Part II: A Language of choices
------------------------------------------------------------------------------
module Language where
data Type : Set where
`nat `bool : Type
_`×_ _`⇒_ : Type → Type → Type
`choices : Type → Type
data Ctx : Set where
ε : Ctx
_,-_ : Ctx → Type → Ctx
variable
S T U V : Type
Γ Δ : Ctx
data Var : Ctx → Type → Set where
zero : Var (Γ ,- T) T
suc : Var Γ T → Var (Γ ,- S) T
data Term : Ctx → Type → Set where
`var : Var Γ T → Term Γ T
`lam : Term (Γ ,- S) T
→ Term Γ (S `⇒ T)
`app : Term Γ (S `⇒ T)
→ Term Γ S
→ Term Γ T
`pair : Term Γ S
→ Term Γ T
→ Term Γ (S `× T)
`fst : Term Γ (S `× T)
→ Term Γ S
`snd : Term Γ (S `× T)
→ Term Γ T
`true `false : Term Γ `bool
`ifte : Term Γ `bool
→ Term Γ T
→ Term Γ T
→ Term Γ T
`const : ℕ → Term Γ `nat
`pure : Term Γ T
→ Term Γ (`choices T)
`let : Term Γ (`choices S)
→ Term (Γ ,- S) (`choices T)
→ Term Γ (`choices T)
`choose : Term Γ (`choices `bool)
------------------------------------------------------------------------------
-- Part III: Interpretation
------------------------------------------------------------------------------
module Interpretation (CM : ChoiceMonad) where
open Language
⟦_⟧ty : Type → Set
⟦ `nat ⟧ty = ℕ
⟦ `bool ⟧ty = 𝔹
⟦ S `× T ⟧ty = ⟦ S ⟧ty × ⟦ T ⟧ty
⟦ S `⇒ T ⟧ty = ⟦ S ⟧ty → ⟦ T ⟧ty
⟦ `choices T ⟧ty = CM .Mon ⟦ T ⟧ty
⟦_⟧ctx : Ctx → Set
⟦ ε ⟧ctx = ⊤
⟦ Γ ,- T ⟧ctx = ⟦ Γ ⟧ctx × ⟦ T ⟧ty
⟦_⟧var : Var Γ T → ⟦ Γ ⟧ctx → ⟦ T ⟧ty
⟦ zero ⟧var (_ , t) = t
⟦ suc x ⟧var (γ , _) = ⟦ x ⟧var γ
⟦_⟧tm : Term Γ T → ⟦ Γ ⟧ctx → ⟦ T ⟧ty
⟦ `var x ⟧tm γ = ⟦ x ⟧var γ
⟦ `lam M ⟧tm γ = λ s → ⟦ M ⟧tm (γ , s)
⟦ `app M N ⟧tm γ = ⟦ M ⟧tm γ (⟦ N ⟧tm γ)
⟦ `pair M N ⟧tm γ = ⟦ M ⟧tm γ , ⟦ N ⟧tm γ
⟦ `fst M ⟧tm γ = ⟦ M ⟧tm γ .proj₁
⟦ `snd M ⟧tm γ = ⟦ M ⟧tm γ .proj₂
⟦ `true ⟧tm γ = true
⟦ `false ⟧tm γ = false
⟦ `ifte L M N ⟧tm γ = if ⟦ L ⟧tm γ then ⟦ M ⟧tm γ else ⟦ N ⟧tm γ
⟦ `const n ⟧tm γ = n
⟦ `pure M ⟧tm γ = CM .unit (⟦ M ⟧tm γ)
⟦ `let M N ⟧tm γ = CM .bind (⟦ M ⟧tm γ) (λ s → ⟦ N ⟧tm (γ , s))
⟦ `choose ⟧tm γ = CM .choose
-- Interpretation using the choice trees:
module ChoiceInterp = Interpretation ChoicesChoiceMonad
-- Interpretation using the selection functions:
module SelectionInterp = Interpretation SelectionChoiceMonad
-- These two interpretations are not equal!
--
-- It is not true that
-- ∀ T → ChoiceInterp.⟦ T ⟧ty ≡ SelectionInterp.⟦ T ⟧ty
-- and we can't even state
-- ∀ M → ChoiceInterp.⟦ M ⟧tm ≡ SelectionInterp.⟦ M ⟧tm
------------------------------------------------------------------------------
-- Part IV: Relating two Interpretations
------------------------------------------------------------------------------
record ChoiceMonadR (CM1 CM2 : ChoiceMonad) : Set (lsuc 0ℓ) where
field
RMon : ∀ {A₁ A₂} → (A₁ → A₂ → Set) → (CM1 .Mon A₁ → CM2 .Mon A₂ → Set)
Runit : ∀ {A₁ A₂} {R : A₁ → A₂ → Set} →
∀ {a₁ a₂} → R a₁ a₂ → RMon R (CM1 .unit a₁) (CM2 .unit a₂)
Rbind : ∀ {A₁ A₂ B₁ B₂} {R : A₁ → A₂ → Set} {S : B₁ → B₂ → Set} →
∀ {c₁ c₂ k₁ k₂} →
RMon R c₁ c₂ →
(∀ {a₁ a₂} → R a₁ a₂ → RMon S (k₁ a₁) (k₂ a₂)) →
RMon S (CM1 .bind c₁ k₁) (CM2 .bind c₂ k₂)
Rchoose : RMon _≡_ (CM1 .choose) (CM2 .choose)
open ChoiceMonadR
module R {CM1 CM2 : ChoiceMonad} (RCM : ChoiceMonadR CM1 CM2) where
open Language
module I1 = Interpretation CM1
module I2 = Interpretation CM2
⟦_⟧ty : (T : Type) → I1.⟦ T ⟧ty → I2.⟦ T ⟧ty → Set
⟦ `nat ⟧ty n₁ n₂ = n₁ ≡ n₂
⟦ `bool ⟧ty b₁ b₂ = b₁ ≡ b₂
⟦ S `× T ⟧ty (s₁ , t₁) (s₂ , t₂) = ⟦ S ⟧ty s₁ s₂ × ⟦ T ⟧ty t₁ t₂
⟦ S `⇒ T ⟧ty f₁ f₂ = ∀ {s₁ s₂} → ⟦ S ⟧ty s₁ s₂ → ⟦ T ⟧ty (f₁ s₁) (f₂ s₂)
⟦ `choices T ⟧ty c₁ c₂ = RCM .RMon ⟦ T ⟧ty c₁ c₂
⟦_⟧ctx : (Γ : Ctx) → I1.⟦ Γ ⟧ctx → I2.⟦ Γ ⟧ctx → Set
⟦ ε ⟧ctx tt tt = ⊤
⟦ Γ ,- T ⟧ctx (γ₁ , t₁) (γ₂ , t₂) = (⟦ Γ ⟧ctx γ₁ γ₂) × (⟦ T ⟧ty t₁ t₂)
⟦_⟧var : (x : Var Γ T) → ∀ {γ₁ γ₂} → ⟦ Γ ⟧ctx γ₁ γ₂ → ⟦ T ⟧ty (I1.⟦ x ⟧var γ₁) (I2.⟦ x ⟧var γ₂)
⟦ zero ⟧var (_ , r) = r
⟦ suc x ⟧var (ρ , _) = ⟦ x ⟧var ρ
⟦_⟧tm : (M : Term Γ T) → ∀ {γ₁ γ₂} → ⟦ Γ ⟧ctx γ₁ γ₂ → ⟦ T ⟧ty (I1.⟦ M ⟧tm γ₁) (I2.⟦ M ⟧tm γ₂)
⟦ `var x ⟧tm ρ = ⟦ x ⟧var ρ
⟦ `lam M ⟧tm ρ = λ r → ⟦ M ⟧tm (ρ , r)
⟦ `app M N ⟧tm ρ = ⟦ M ⟧tm ρ (⟦ N ⟧tm ρ)
⟦ `pair M N ⟧tm ρ = (⟦ M ⟧tm ρ) , (⟦ N ⟧tm ρ)
⟦ `fst M ⟧tm ρ = ⟦ M ⟧tm ρ .proj₁
⟦ `snd M ⟧tm ρ = ⟦ M ⟧tm ρ .proj₂
⟦ `true ⟧tm ρ = refl
⟦ `false ⟧tm ρ = refl
⟦ `ifte L M N ⟧tm {γ₂ = γ₂} ρ rewrite ⟦ L ⟧tm ρ with I2.⟦ L ⟧tm γ₂
... | false = ⟦ N ⟧tm ρ
... | true = ⟦ M ⟧tm ρ
⟦ `const x ⟧tm ρ = refl
⟦ `pure M ⟧tm ρ = RCM .Runit (⟦ M ⟧tm ρ)
⟦ `let M N ⟧tm ρ = RCM .Rbind (⟦ M ⟧tm ρ) (λ s → ⟦ N ⟧tm (ρ , s))
⟦ `choose ⟧tm ρ = RCM .Rchoose
------------------------------------------------------------------------------
-- Part V: Relating Choices and Selection
------------------------------------------------------------------------------
module ChoicesAndSelections where
CS-R : ∀ {A₁ A₂} → (A₁ → A₂ → Set) → (Choices A₁ → Selection ℕ A₂ → Set)
CS-R {A₁} {A₂} R c s =
∀ {cost₁ : A₁ → ℕ} {cost₂ : A₂ → ℕ} →
(∀ {a₁ a₂} → R a₁ a₂ → cost₁ a₁ ≡ cost₂ a₂) →
R (argmin cost₁ c) (s cost₂)
CS-unit : ∀ {A₁ A₂} {R : A₁ → A₂ → Set} →
∀ {a₁ a₂} → R a₁ a₂ → CS-R R (success a₁) (λ _ → a₂)
CS-unit r _ = r
lemma0 : ∀ {A B : Set}{x y : A}(f : A → B) (b : 𝔹) →
(if b then f x else f y) ≡ f (if b then x else y)
lemma0 f false = refl
lemma0 f true = refl
lemma : ∀ {A B} (cost : B → ℕ) (c : Choices A) (k : A → Choices B) →
argmin cost (Choices-bind c k)
≡ argmin cost (k (argmin (λ x → cost (argmin cost (k x))) c))
lemma cost (success a) k = refl
lemma cost (branch c₁ c₂) k
rewrite lemma cost c₁ k
rewrite lemma cost c₂ k =
lemma0 (λ x → argmin cost (k x)) _
CS-bind : ∀ {A₁ A₂ B₁ B₂} {R : A₁ → A₂ → Set} {S : B₁ → B₂ → Set} →
∀ {c₁ c₂ k₁ k₂} →
CS-R R c₁ c₂ →
(∀ {a₁ a₂} → R a₁ a₂ → CS-R S (k₁ a₁) (k₂ a₂)) →
CS-R S (Choices-bind c₁ k₁) (Selection-bind c₂ k₂)
CS-bind {c₁ = c₁} {k₁ = k₁} c k {cost₁ = cost₁} cost rewrite lemma cost₁ c₁ k₁
= k (c (λ a → cost (k a cost))) cost
CS-choose : CS-R _≡_ (branch (success true) (success false)) Selection-choose
CS-choose cost rewrite cost {true} refl rewrite cost {false} refl = refl
RMonads : ChoiceMonadR ChoicesChoiceMonad SelectionChoiceMonad
RMonads .RMon = CS-R
RMonads .Runit = CS-unit
RMonads .Rbind {c₁ = c₁} {k₁ = k₁} c k = CS-bind {c₁ = c₁} {k₁ = k₁} c k
RMonads .Rchoose = CS-choose
module ChoicesAndSelections = R RMonads
open Language
result : (M : Term ε (`choices `nat)) →
argmin (λ x → x) (ChoiceInterp.⟦ M ⟧tm tt) ≡ SelectionInterp.⟦ M ⟧tm tt (λ x → x)
result M = ChoicesAndSelections.⟦ M ⟧tm tt (λ eq → eq)
------------------------------------------------------------------------------
-- Part IV: Changing the Objective
------------------------------------------------------------------------------
choose-f : ∀ {R} → (R → ℕ) → Selection R 𝔹
choose-f u cost =
if u (cost true) ≤ᵇ u (cost false) then true else false
{-
prisoner's-dilemma : Term ε (`choices (`nat `× `nat))
prisoner's-dilemma =
do m₁ ← choose fst
m₂ ← choose snd
return (if m₁ then (if m₂ then (2, 2)
else (10, 0))
else (if m₂ then (0, 10)
else (5, 5)))
-}
data Choices2 (R : Set) (A : Set) : Set where
success : A → Choices2 R A
branch : (R → ℕ) → Choices2 R A → Choices2 R A → Choices2 R A
argmin2 : ∀ {R A} → (A → R) → Choices2 R A → A
argmin2 cost (success x) = x
argmin2 cost (branch u c₁ c₂) =
let a₁ = argmin2 cost c₁
a₂ = argmin2 cost c₂
in if u (cost a₁) ≤ᵇ u (cost a₂) then a₁ else a₂
Choices-choose-f : ∀ {R} → (R → ℕ) → Choices2 R 𝔹
Choices-choose-f u = branch u (success true) (success false)
-- Claims:
--
-- 1. The language can be extended with these relativised choice
-- operators
--
-- 2. The logical relation can be adapted to relate these two
-- interpretations in a similar way.
--
-- 3. Every strategic game in normal form can be represented as above,
-- and the selected outcome is a Nash Equilibrium in pure
-- strategies.
--
-- 4. With a bit more work, we can argmin over mixed strategies, and
-- take expected payoffs, to get _a_ Nash Equilibrium in mixed
-- strategies.
------------------------------------------------------------------------------
-- Part V: Nominated Choices
------------------------------------------------------------------------------
data Choices3 (R : Set) (A : Set) : Set where
success : A → Choices3 R A
branch : (R → ℕ) → 𝔹 → (𝔹 → Choices3 R A) → Choices3 R A
selectC : ∀ {R} → (R → ℕ) → 𝔹 → Choices3 R 𝔹
selectC u b = branch u b success
outcome : ∀ {R A} → Choices3 R A → A
outcome (success a) = a
outcome (branch u b k) = outcome (k b)
abam : ∀ {R} → Choices3 R R → 𝔹
abam (success _) = true
abam (branch u b k) =
(u (outcome (k b)) ≤ᵇ u (outcome (k (not b)))) ∧ abam (k b)
Select3 : Set → Set → Set
Select3 R A = A × ((A → R) → 𝔹)
Select3-unit : ∀ {R A} → A → Select3 R A
Select3-unit a .proj₁ = a
Select3-unit a .proj₂ cost = true
Select3-bind : ∀ {R A B} → Select3 R A → (A → Select3 R B) → Select3 R B
Select3-bind (a , ϕ) k .proj₁ = k a .proj₁
Select3-bind (a , ϕ) k .proj₂ cost =
ϕ (λ a → cost (k a .proj₁)) ∧ k a .proj₂ cost
selectS : ∀ {R} → (R → ℕ) → 𝔹 → Select3 R 𝔹
selectS u b .proj₁ = b
selectS u b .proj₂ cost = u (cost b) ≤ᵇ u (cost (not b))
{-
prisoner's-dilemma : Term (ε ,- `bool ,- `bool) (`choices (`nat `× `nat))
prisoner's-dilemma σ₁ σ₂ =
do m₁ ← choose fst σ₁
m₂ ← choose snd σ₂
return (if m₁ then (if m₂ then (2, 2)
else (10, 0))
else (if m₂ then (0, 10)
else (5, 5)))
-}
-- Claims:
--
-- 1. The language can be extended with these nominated and
-- relativised choice operators.
--
-- 2. The logical relation can be adapted to relate these two
-- interpretations in a similar way.
--
-- 3. Every strategic game in normal form can be represented as above,
-- and the 'abam' predicate identifies exactly the Nash equilibria.
--
-- 4. With a bit more work, we can argmin over mixed strategies, and
-- take expected payoffs, to get all Nash Equilibria in mixed
-- strategies.
------------------------------------------------------------------------------
-- Part VI: Feedback
------------------------------------------------------------------------------
-- The “category writer monad”
Lens : Set → Set → Set → Set
Lens R S A = A × (S → R)
Lens-unit : ∀ {R A} → A → Lens R R A
Lens-unit a = a , (λ r → r)
Lens-bind : ∀ {R S T A B} → Lens R S A → (A → Lens S T B) → Lens R T B
Lens-bind (a , f) k = let (b , g) = k a in b , λ t → f (g t)
-- Nomination + Selection + Feedback
SelectF : Set → Set → Set → Set
SelectF R S A = A × ((A → S) → 𝔹) × (S → R)
-- Claims:
--
-- Functions A → SelectF R S B are Open Games (A, R) → (B, S)
--
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment