Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
dc318ac
partial independence proof
RemyDegenne Jan 2, 2026
6613ce8
Merge remote-tracking branch 'origin/main' into work
RemyDegenne Jan 2, 2026
be27b56
define new filtration
RemyDegenne Jan 3, 2026
a00150d
lots of stuff
RemyDegenne Jan 5, 2026
ace4f95
update to IsAlgEnvSeq
RemyDegenne Jan 6, 2026
9ab6f44
more
RemyDegenne Jan 6, 2026
812c0d1
work on sumRewards
RemyDegenne Jan 6, 2026
1b146e7
update
RemyDegenne Jan 7, 2026
de5d855
prove uniqueness of trajMeasure
RemyDegenne Jan 8, 2026
a7dd567
finish uniqueness proof
RemyDegenne Jan 8, 2026
aed6492
condDistrib progess
RemyDegenne Jan 8, 2026
5cade77
progress
RemyDegenne Jan 8, 2026
d84d16e
delete unused lemmas
RemyDegenne Jan 8, 2026
39ad41c
progress
RemyDegenne Jan 13, 2026
a548ef2
getting close
RemyDegenne Jan 13, 2026
830bad0
only two indepedence sorry left
RemyDegenne Jan 14, 2026
adfc693
lint
RemyDegenne Jan 14, 2026
e41825d
lake exe mk_all
RemyDegenne Jan 14, 2026
a6af988
temporary blueprint fix
RemyDegenne Jan 14, 2026
6647491
min_imports
RemyDegenne Jan 14, 2026
a565bed
mk_all
RemyDegenne Jan 14, 2026
f9591ce
add Claude proof
RemyDegenne Jan 14, 2026
63f5e42
add indepedence proof from Claude
RemyDegenne Jan 14, 2026
b8bca06
reorder Bandit file
RemyDegenne Jan 14, 2026
89ed9a4
comment out sorrys in RewardByCountMeasure
RemyDegenne Jan 14, 2026
1a991b7
minor cleanup
RemyDegenne Jan 14, 2026
634743a
sorry-free
RemyDegenne Jan 14, 2026
15f361d
fix blueprint refs
RemyDegenne Jan 15, 2026
75a3b70
add and adapt Paulo's regret lemmas
RemyDegenne Jan 15, 2026
7f31078
partial blueprint update
RemyDegenne Jan 15, 2026
a260892
fix
RemyDegenne Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion LeanBandits.lean
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import LeanBandits.Bandit.Bandit
import LeanBandits.Bandit.Regret
import LeanBandits.Bandit.RewardByCountMeasure
import LeanBandits.Bandit.SumRewards
import LeanBandits.BanditAlgorithms.AuxSums
import LeanBandits.BanditAlgorithms.ETC
import LeanBandits.BanditAlgorithms.UCB
import LeanBandits.ForMathlib.CondDistrib
import LeanBandits.ForMathlib.CondIndepFun
import LeanBandits.ForMathlib.HasCondDistrib
import LeanBandits.ForMathlib.IndepFun
import LeanBandits.ForMathlib.IndepInfinitePi
import LeanBandits.ForMathlib.KernelRepresentation
import LeanBandits.ForMathlib.KernelSub
import LeanBandits.ForMathlib.Measurable
import LeanBandits.ForMathlib.MeasurableArgMax
import LeanBandits.ForMathlib.StandardBorel
import LeanBandits.ForMathlib.SubGaussian
import LeanBandits.ForMathlib.Traj
import LeanBandits.RewardByCountMeasure
import LeanBandits.SequentialLearning.Algorithm
import LeanBandits.SequentialLearning.Deterministic
import LeanBandits.SequentialLearning.FiniteActions
import LeanBandits.SequentialLearning.IonescuTulceaSpace
import LeanBandits.SequentialLearning.StationaryEnv
1,164 changes: 1,079 additions & 85 deletions LeanBandits/Bandit/Bandit.lean

Large diffs are not rendered by default.

96 changes: 69 additions & 27 deletions LeanBandits/Bandit/Regret.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ Copyright (c) 2025 Rémy Degenne. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Rémy Degenne, Paulo Rauber
-/
import LeanBandits.Bandit.Bandit
import LeanBandits.SequentialLearning.FiniteActions

/-!
# Regret
# Regret, gap, best arm

-/

Expand All @@ -17,17 +16,12 @@ open scoped ENNReal NNReal

namespace Bandits

variable {α : Type*} [DecidableEq α] {mα : MeasurableSpace α} {ν : Kernel α ℝ}
{h : ℕ → α × ℝ} {m n t : ℕ} {a : α}
variable {α Ω : Type*} [DecidableEq α] {mα : MeasurableSpace α} {mΩ : MeasurableSpace Ω}
{ν : Kernel α ℝ}
{A : ℕ → Ω → α} {R : ℕ → Ω → ℝ}
{ω : Ω} {m n t : ℕ} {a : α}

/-! ### Definitions of regret, gaps, pull counts -/

/-- Regret of a sequence of pulls `k : ℕ → α` at time `t` for the reward kernel `ν ; Kernel α ℝ`. -/
noncomputable
def regret (ν : Kernel α ℝ) (t : ℕ) (h : ℕ → α × ℝ) : ℝ :=
t * (⨆ a, (ν a)[id]) - ∑ s ∈ range t, (ν (arm s h))[id]

/-- Gap of an arm `a`: difference between the highest mean of the arms and the mean of `a`. -/
/-- Gap of an action `a`: difference between the highest mean of the actions and the mean of `a`. -/
noncomputable
def gap (ν : Kernel α ℝ) (a : α) : ℝ := (⨆ i, (ν i)[id]) - (ν a)[id]

Expand All @@ -36,28 +30,35 @@ lemma gap_nonneg [Fintype α] : 0 ≤ gap ν a := by
rw [gap, sub_nonneg]
exact le_ciSup (f := fun i ↦ (ν i)[id]) (by simp) a

lemma arm_stepsUntil (hm : m ≠ 0) (h_exists : ∃ s, pullCount a (s + 1) h = m) :
arm (stepsUntil a m h).toNat h = a := by
exact action_stepsUntil hm h_exists
/-- Regret of a sequence of pulls `k : ℕ → α` at time `t` for the reward kernel `ν ; Kernel α ℝ`. -/
noncomputable
def regret (ν : Kernel α ℝ) (A : ℕ → Ω → α) (t : ℕ) (ω : Ω) : ℝ :=
t * (⨆ a, (ν a)[id]) - ∑ s ∈ range t, (ν (A s ω))[id]

omit [DecidableEq α] in
lemma regret_eq_sum_gap : regret ν A t ω = ∑ s ∈ range t, gap ν (A s ω) := by
simp [regret, gap]

lemma arm_eq_of_stepsUntil_eq_coe {ω : ℕ → α × ℝ} (hm : m ≠ 0)
(h : stepsUntil a m ω = n) :
arm n ω = a := by
exact action_eq_of_stepsUntil_eq_coe hm h
omit [DecidableEq α] in
lemma regret_nonneg [Fintype α] : 0 ≤ regret ν A t ω := by
rw [regret_eq_sum_gap]
exact sum_nonneg (fun _ _ ↦ gap_nonneg)

section RewardByCount
omit [DecidableEq α] in
lemma gap_eq_zero_of_regret_eq_zero [Fintype α] (hr : regret ν A t ω = 0) {s : ℕ} (hs : s < t) :
gap ν (A s ω) = 0 := by
rw [regret_eq_sum_gap] at hr
exact (sum_eq_zero_iff_of_nonneg fun _ _ ↦ gap_nonneg).1 hr s (mem_range.2 hs)

lemma regret_eq_sum_pullCount_mul_gap [Fintype α] :
regret ν t h = ∑ a, pullCount a t h * gap ν a := by
simp [sum_pullCount_mul, regret, gap, sum_sub_distrib, arm, action]
regret ν A t ω = ∑ a, pullCount A a t ω * gap ν a := by
simp_rw [regret_eq_sum_gap, sum_pullCount_mul]

end RewardByCount

section BestArm
section bestArm

variable [Fintype α] [Nonempty α]

/-- Arm with the highest mean. -/
/-- action with the highest mean. -/
noncomputable def bestArm (ν : Kernel α ℝ) : α :=
(exists_max_image univ (fun a ↦ (ν a)[id]) (univ_nonempty_iff.mpr inferInstance)).choose

Expand All @@ -78,6 +79,47 @@ omit [DecidableEq α] in
lemma gap_bestArm : gap ν (bestArm ν) = 0 := by
rw [gap_eq_bestArm_sub, sub_self]

end BestArm
omit [DecidableEq α] in
lemma integral_eq_of_gap_eq_zero (hg : gap ν a = 0) : (ν (bestArm ν))[id] = (ν a)[id] := by
rwa [← sub_eq_zero, ← gap_eq_bestArm_sub]

end bestArm

section Asymptotics

omit [DecidableEq α] in
/-- If the regret is sublinear, the average mean reward tends to the highest mean of the arms. -/
lemma avg_mean_reward_tendsto_of_sublinear_regret
(hr : (regret ν A · ω) =o[atTop] fun t ↦ (t : ℝ)) :
Tendsto (fun t ↦ (∑ s ∈ range t, (ν (A s ω))[id]) / (t : ℝ))
atTop (nhds (⨆ a, (ν a)[id])) := by
have ht : Tendsto (fun t ↦ (⨆ a, (ν a)[id]) - regret ν A t ω / t)
atTop (nhds (⨆ a, (ν a)[id])) := by
simpa using tendsto_const_nhds.sub hr.tendsto_div_nhds_zero
apply ht.congr'
filter_upwards [eventually_ne_atTop 0] with t ht
rw [regret]
field_simp
ring

/-- If the regret is sublinear, the rate of suboptimal arm pulls tends to zero. -/
lemma pullCount_rate_tendsto_of_sublinear_regret [Fintype α]
(hr : (regret ν A · ω) =o[atTop] fun t ↦ (t : ℝ)) (hg : 0 < gap ν a) :
Tendsto (fun t ↦ (pullCount A a t ω : ℝ) / t) atTop (nhds 0) := by
have hb (t : ℕ) : (pullCount A a t ω : ℝ) * gap ν a ≤ regret ν A t ω := by
rw [regret_eq_sum_pullCount_mul_gap]
exact single_le_sum (f := fun a ↦ pullCount A a t ω * gap ν a)
(fun _ _ ↦ mul_nonneg (Nat.cast_nonneg _) gap_nonneg) (mem_univ a)
have hb' (t : ℕ) : (pullCount A a t ω : ℝ) / t ≤ regret ν A t ω / t / gap ν a := by
obtain ht | ht := eq_or_ne t 0
· simp [ht]
· calc (pullCount A a t ω : ℝ) / t
= pullCount A a t ω * gap ν a / gap ν a / t := by field_simp
_ ≤ regret ν A t ω / gap ν a / t := by gcongr; exact hb t
_ = regret ν A t ω / t / gap ν a := by ring
apply squeeze_zero' (Eventually.of_forall fun _ ↦ by positivity) (Eventually.of_forall hb')
simpa using hr.tendsto_div_nhds_zero.div_const (gap ν a)

end Asymptotics

end Bandits
Loading
Loading