import Mathlib /-! # Random sampling for an element We implement sampling to find an element with a given property, for instance being prime or being coprime to a given number. For this we need a hypothesis that such an element exists. We use the `IO` monad to generate random numbers. This is because a random number is not a function, in the sense of having value determined by arguments. -/ /-! The basic way we sample is to choose an element at random from the list, and then check if it satisfies the property. If it does, we return it. If not, we remove it from the list and try again. To show termination we see (following a lab) that the length of the list decreases by at least one each time. -/ universe u /-- Removing an element from a list does not increase length -/ theoremremove_length_le {remove_length_le: ∀ {α : Type u} [inst : DecidableEq α] (a : α) (l : List α), List.length (List.remove a l) ≤ List.length lα :α: Type uType u} [DecidableEqType u: Type (u+1)α](α: Type ua :a: αα) (α: Type ul : Listl: List αα) : (α: Type uList.removeList.remove: {α : Type ?u.19} → [inst : DecidableEq α] → α → List α → List αaa: αl).length ≤l: List αl.length :=l: List αGoals accomplished! 🐙List.length (List.remove a l) ≤ List.length lList.length (List.remove a l) ≤ List.length l
nilList.length (List.remove a []) ≤ List.length []Goals accomplished! 🐙List.length (List.remove a l) ≤ List.length l
consList.length (List.remove a (h' :: t)) ≤ List.length (h' :: t)
consList.length (if a = h' then List.remove a t else h' :: List.remove a t) ≤ Nat.succ (List.length t)
consList.length (List.remove a (h' :: t)) ≤ List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: a = h'
cons.inlList.length (List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)
consList.length (List.remove a (h' :: t)) ≤ List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: a = h'
cons.inlList.length (List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: a = h'
cons.inl.hList.length (List.remove a t) ≤ List.length tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: a = h'
cons.inlList.length (List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)Goals accomplished! 🐙
consList.length (List.remove a (h' :: t)) ≤ List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrNat.succ (List.length (List.remove a t)) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrNat.succ (List.length (List.remove a t)) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inr.aList.length (List.remove a t) ≤ List.length tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: List.length (List.remove a t) ≤ List.length t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) ≤ Nat.succ (List.length t)/-- Removing a member from a list shortens the list -/ theoremGoals accomplished! 🐙remove_mem_length {remove_mem_length: ∀ {α : Type u} [inst : DecidableEq α] {a : α} {l : List α}, a ∈ l → List.length (List.remove a l) < List.length lα :α: Type uType u} [DecidableEqType u: Type (u+1)α]{α: Type ua :a: αα } {α: Type ul : Listl: List αα} (α: Type uhyp :hyp: a ∈ la ∈a: αl) : (l: List αList.removeList.remove: {α : Type ?u.2403} → [inst : DecidableEq α] → α → List α → List αaa: αl).length <l: List αl.length :=l: List αGoals accomplished! 🐙List.length (List.remove a l) < List.length lList.length (List.remove a l) < List.length l
nilList.length (List.remove a []) < List.length []Goals accomplished! 🐙List.length (List.remove a l) < List.length lα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
consList.length (List.remove a (h' :: t)) < List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
consList.length (if a = h' then List.remove a t else h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
consList.length (List.remove a (h' :: t)) < List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: a = h'
cons.inlList.length (List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
consList.length (List.remove a (h' :: t)) < List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: a = h'
cons.inlList.length (List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: a = h'
cons.inl.aList.length (List.remove a t) ≤ List.length tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: a = h'
cons.inlList.length (List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)Goals accomplished! 🐙α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
consList.length (List.remove a (h' :: t)) < List.length (h' :: t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrNat.succ (List.length (List.remove a t)) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrNat.succ (List.length (List.remove a t)) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inr.aList.length (List.remove a t) < List.length tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inr.aList.length (List.remove a t) < List.length tGoals accomplished! 🐙α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'a ∈ tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'a ∈ tGoals accomplished! 🐙α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'Goals accomplished! 🐙α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'a ∈ tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
h✝, this: ¬a = h'
hyp: a ∈ ta ∈ tα: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'a ∈ tGoals accomplished! 🐙α: Type u
inst✝: DecidableEq α
a, h': α
t: List α
ih: a ∈ t → List.length (List.remove a t) < List.length t
hyp: a ∈ h' :: t
h✝: ¬a = h'
cons.inrList.length (h' :: List.remove a t) < Nat.succ (List.length t)/-! We pick an index of the list `l`, which is of type `Fin l.length`. Rather than proving that the random number generator has this property we pass `mod n`. -/ /-- A random number in `Fin n` -/ def IO.randFin (Goals accomplished! 🐙n :n: ℕℕ)(ℕ: Typeh :h: 0 < n0 <0: ?m.6449n ) : IO <| Finn: ℕn := do letn: ℕr ← IO.randr: ?m.65920 (0: ?m.6530n -n: ℕ1) pure ⟨1: ?m.6536r %r: ?m.6592n, Nat.mod_ltn: ℕrr: ?m.6592h⟩h: 0 < nList.mem_remove_iff -- ∀ {α : Type u_1} [inst : DecidableEq α] {a b : α} {as : List α}, b ∈ List.remove a as ↔ b ∈ as ∧ b ≠ aList.mem_remove_iff: ∀ {α : Type u_1} [inst : DecidableEq α] {a b : α} {as : List α}, b ∈ List.remove a as ↔ b ∈ as ∧ b ≠ aList.length_pos_of_mem -- ∀ {α : Type u_1} {a : α} {l : List α}, a ∈ l → 0 < List.length l List.get_mem -- ∀ {α : Type u_1} (l : List α) (n : ℕ) (h : n < List.length l), List.get l { val := n, isLt := h } ∈ l /-- A random element with a given property from a list, within `IO` -/ defList.length_pos_of_mem: ∀ {α : Type u_1} {a : α} {l : List α}, a ∈ l → 0 < List.length lpickElemIO [DecidableEqα](α: ?m.6946l: Listl: List αα)(α: ?m.6946p:p: α → Boolα →α: ?m.6946Bool)(h : ∃Bool: Typet :t: αα,α: ?m.6946t ∈t: αl ∧l: List αpp: α → Boolt =t: αtrue) : IO {true: Boolt :t: αα //α: ?m.6946t ∈t: αl ∧l: List αpp: α → Boolt =t: αtrue} := do havetrue: Boolh' :h': 0 < List.length l0 <0: ?m.7049l.length :=l: List αGoals accomplished! 🐙0 < List.length l0 < List.length lletGoals accomplished! 🐙index ← IO.randFinindex: ?m.7114l.lengthl: List αh' leth': 0 < List.length la :=a: ?m.7117l.l: List αgetget: {α : Type ?u.7118} → (as : List α) → Fin (List.length as) → αindex ifindex: ?m.7114c:c: ?m.7208pp: α → Boola =a: ?m.7117true then return ⟨true: Boola,a: ?m.7117Goals accomplished! 🐙⟩ else letGoals accomplished! 🐙l' :=l': ?m.7211l.l: List αremoveremove: {α : Type ?u.7212} → [inst : DecidableEq α] → α → List α → List αa have h' : ∃a: ?m.7117t :t: αα,α: Typet ∈t: αl' ∧l': ?m.7211pp: α → Boolt =t: αtrue :=true: BoolGoals accomplished! 🐙have :Goals accomplished! 🐙l'.length <l': ?m.7211l.length :=l: List αGoals accomplished! 🐙α: Type
inst✝: DecidableEq α
l: List α
p: α → Bool
h: ∃ t, t ∈ l ∧ p t = true
h'✝: 0 < List.length l
index: Fin (List.length l)
a:= List.get l index: α
c: ¬p a = true
l':= List.remove a l: List α
h': ∃ t, t ∈ l' ∧ p t = trueList.length l' < List.length lα: Type
inst✝: DecidableEq α
l: List α
p: α → Bool
h: ∃ t, t ∈ l ∧ p t = true
h'✝: 0 < List.length l
index: Fin (List.length l)
a:= List.get l index: α
c: ¬p a = true
l':= List.remove a l: List α
h': ∃ t, t ∈ l' ∧ p t = trueList.length l' < List.length llet ⟨Goals accomplished! 🐙t,t: αh₁, h₂⟩ ←h₁: t ∈ l'pickElemIOl'l': ?m.7211p h' havep: α → Boolm :m: t ∈ lt ∈t: αl :=l: List αList.mem_of_mem_removeList.mem_of_mem_remove: ∀ {α : Type ?u.7518} [inst : DecidableEq α] {a b : α} {as : List α}, b ∈ List.remove a as → b ∈ ash₁ return ⟨h₁: t ∈ l't,t: αm, h₂⟩ termination_by _ _ _ l _ _ =>m: t ∈ ll.length /-- A random element with a given property from a list. As IO may in principle give an error, we specify a default to fallback and the conditions that this is in the list and has the property `p` -/ defl: List αpickElemD [DecidableEqα](α: ?m.34031l: Listl: List αα)(α: ?m.34031p:p: α → Boolα →α: ?m.34031Bool)(Bool: Typedefault :default: αα)(α: ?m.34031h₁ :h₁: default ∈ ldefault ∈default: αl)(h₂ :l: List αpp: α → Booldefault =default: αtrue) : {true: Boolt :t: αα //α: ?m.34031t ∈t: αl ∧l: List αpp: α → Boolt =t: αtrue} := (pickElemIOtrue: Boolll: List αp ⟨p: α → Booldefault,default: αh₁, h₂⟩).run'h₁: default ∈ l() |>.getD ⟨(): Unitdefault,default: αh₁, h₂⟩ /-! ## Random Monad We used the IO Monad which has a lot of stuff besides randomness. We will now demistify this by constructing a Monad for randomness only. -/h₁: default ∈ lStdGen mkStdGen -- mkStdGen (s : ℕ := 0) : StdGen randNat -- randNat.{u} {gen : Type u} [inst✝ : RandomGen gen] (g : gen) (lo hi : ℕ) : ℕ × gen defStdGen: TypeRandomMRandomM: (α : ?m.34437) → ?m.34441 αα :=α: ?m.34437StdGen →StdGen: Typeα ×α: ?m.34437StdGen IO.rand -- IO.rand (lo hi : ℕ) : IO ℕ namespace RandomM def rand (StdGen: Typelolo: ℕhi :hi: ℕℕ): RandomMℕ: Typeℕ := funℕ: Typegen ↦ randNatgen: ?m.34467gengen: ?m.34467lolo: ℕhi def run (hi: ℕx : RandomMx: RandomM αα) :α: ?m.34527StdGen →StdGen: Typeα ×α: ?m.34527StdGen :=StdGen: Typex def run' (x: RandomM αx : RandomMx: RandomM αα)(gen :α: ?m.34610StdGen := default) :StdGen: Typeα := (α: ?m.34610x gen).1 randx: RandomM α00: ?m.3521310 |>.run' instance : Monad RandomM where pure := fun10: ?m.35224x ↦ funx: ?m.35852gen ↦ (gen: ?m.35855x,x: ?m.35852gen) map := fungen: ?m.35855ff: ?m.35725x ↦ funx: ?m.35729gen ↦ let (gen: ?m.35732a ,a: α✝gen') :=gen': StdGenxx: ?m.35729gen (gen: ?m.35732ff: ?m.35725a,a: α✝gen') bind := fungen': StdGenxx: ?m.35960b ↦ funb: ?m.35963gen ↦ let (gen: ?m.35968a ,a: α✝gen') :=gen': StdGenxx: ?m.35960gengen: ?m.35968bb: ?m.35963aa: α✝gen' def randBool : RandomMgen': StdGenBool := do letBool: Typen ← randn: ?m.3806700: ?m.380481 pure (1: ?m.38059n ==n: ?m.380670) randBool |>.run' (mkStdGen0: ?m.3808884938743) def randList (84938743: ?m.38309lolo: ℕhihi: ℕn :n: ℕℕ) : RandomM <| Listℕ: Typeℕ := do matchℕ: Typen with |n: ℕ0 => pure0: ℕ[] |[]: List ?m.38808k + 1 => do letk: ℕx ← randx: ?m.38935lolo: ℕhi lethi: ℕxs ← randListxs: ?m.38957lolo: ℕhihi: ℕk pure <|k: ℕx ::x: ?m.38935xs randListxs: ?m.3895711: ?m.395621010: ?m.395737 |>.run' (mkStdGen7: ?m.3957984938743) def setSeed (84938743: ?m.39592n :n: ℕℕ) : RandomMℕ: TypeUnit := funUnit: Type_ ↦ (_: ?m.40056(), mkStdGen(): Unitn) def withSeed (n: ℕn:n: ℕℕ) (ℕ: Typec : RandomMc: RandomM αα) : RandomMα: ?m.40118α := do setSeedα: ?m.40118nn: ℕc (withSeedc: RandomM α376872 <| randList376872: ?m.4034011: ?m.403521010: ?m.4035912) |>.run' end RandomM def StateM'12: ?m.40365σσ: ?m.40850α :=α: ?m.40857 σσ →σ: ?m.40850α ×α: ?m.40857 σσ instance : Monad <| StateM'σ: ?m.40850σ where pure := funσ: ?m.40887x ↦ funx: ?m.41052gen ↦ (gen: ?m.41055x,x: ?m.41052gen) map := fungen: ?m.41055ff: ?m.40922x ↦ funx: ?m.40926gen ↦ let (gen: ?m.40929a ,a: α✝gen') :=gen': σxx: ?m.40926gen (gen: ?m.40929ff: ?m.40922a,a: α✝gen') bind := fungen': σxx: ?m.41160b ↦ funb: ?m.41163gen ↦ let (gen: ?m.41168a ,a: α✝gen') :=gen': σxx: ?m.41160gengen: ?m.41168bb: ?m.41163aa: α✝gen' namespace StateM' def run (gen': σx : StateM'x: StateM' σ ασσ: ?m.42796α) :α: ?m.42802σ →σ: ?m.42796α ×α: ?m.42802σ :=σ: ?m.42796x defx: StateM' σ αrun' [Inhabitedσ](σ: ?m.42881x : StateM'x: StateM' σ ασσ: ?m.42881α)(α: ?m.42890s :s: optParam σ defaultσ := default) :σ: ?m.42881α := (α: ?m.42890xx: StateM' σ αs).1 def setState (s: optParam σ defaults :s: σσ) : StateM'σ: ?m.43488σσ: ?m.43488Unit := funUnit: Type_ ↦ (_: ?m.43501(),(): Units) def getState : StateM's: σσσ: ?m.43558σ := funσ: ?m.43558s ↦ (s: ?m.43567s,s: ?m.43567s) def withState (s: ?m.43567s:s: σσ) (σ: ?m.43612c : StateM'c: StateM' σ ασσ: ?m.43612α) : StateM'α: ?m.43620σσ: ?m.43612α := do setStateα: ?m.43620ss: σc end StateM' def RandomM' := StateM'c: StateM' σ αStdGen namespace RandomM' end RandomM'StdGen: Type