Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
fbbfe2a
feat : initial algorithm foundation for linUCB
FawadHa1der May 29, 2026
cce2458
feat : initial algorithm foundation for linUCB
FawadHa1der May 29, 2026
86f4300
Merge branch 'main' into issue-112
FawadHa1der May 29, 2026
7b654c3
feat(linUCB): proving generic one-step bound
FawadHa1der Jun 3, 2026
394750e
feat(linUCB): almost-sure instantaneous regret/gap bound
FawadHa1der Jun 4, 2026
c27ce9b
feat(linUCB): all-positive-times instantaneous gap bound
FawadHa1der Jun 5, 2026
9cde158
feat(linUCB): cumulative regret bridge
FawadHa1der Jun 8, 2026
af7a718
sum of widths inequality using Cauchy-Schwarz from mathlib
FawadHa1der Jun 9, 2026
93b64a8
feat(linUCB): simplify the Cauchy beta factor
FawadHa1der Jun 9, 2026
2db39aa
squared LinUCB width sum is bounded by W, then the regret bound can u…
FawadHa1der Jun 10, 2026
f813c85
feat(linUCB): moving closer to text book version regret ≤ initial gap…
FawadHa1der Jun 10, 2026
bf90410
feat(linUCB): moving closer to text book version regret ≤ initial gap…
FawadHa1der Jun 10, 2026
d8bcffb
feat(linUCB): remaining initial gap sum + cleanup
FawadHa1der Jun 10, 2026
2eaf435
feat(linUCB): widthSqSum as quadtratic with proof
FawadHa1der Jun 11, 2026
32d15ef
feat(linUCB): widthSqSum as quadtratic with proof
FawadHa1der Jun 11, 2026
7bfa214
feat(linUCB): bridge from a quadratic-form sum bound to a widthSqSum …
FawadHa1der Jun 11, 2026
ae83109
feat(linUCB): clean up repeated term with quadraticWidthSum
FawadHa1der Jun 11, 2026
5c922c7
feat(linUCB): lint clean up
FawadHa1der Jun 11, 2026
d2bc9e2
feat(linUCB): design matrix is just the regularization matrix
FawadHa1der Jun 11, 2026
0b0a904
feat(linUCB): proof for initial response vector
FawadHa1der Jun 11, 2026
f1da71a
feat(linUCB): responseVector is the LinUCB reward-feature accumulator
FawadHa1der Jun 11, 2026
a96beab
feat(linUCB): estimated reward for any arm is zero
FawadHa1der Jun 12, 2026
5c633f2
feat(linUCB): at time 0, LinUCB’s optimistic index for an arm is just…
FawadHa1der Jun 12, 2026
523728e
feat(linUCB): at 0 time, the LinUCB width is computed using only the …
FawadHa1der Jun 12, 2026
c47c7e1
feat(linUCB): combining index_zero, width_zero
FawadHa1der Jun 12, 2026
84fd6fd
feat(linUCB): the accumulated squared-width term is zero at horizon 0
FawadHa1der Jun 12, 2026
33ee65a
feat(linUCB): proof for quadraticWidthSum
FawadHa1der Jun 12, 2026
fe9b9f1
feat(linUCB): when the horizon advances from n to n + 1, the accumula…
FawadHa1der Jun 12, 2026
1d1725e
feat(linUCB): when the horizon advances from n to n + 1, the accumula…
FawadHa1der Jun 12, 2026
c86ad3e
feat(linUCB): proof for widthSqSum_succ when n not equal to 0
FawadHa1der Jun 12, 2026
3f94ae7
feat(linUCB): proof for quadraticWidth_succ when n not equal to 0
FawadHa1der Jun 12, 2026
94c32a3
feat(linUCB): if the two accumulators agree at time n, then they als…
FawadHa1der Jun 12, 2026
ee5c82b
feat(linUCB): refactor
FawadHa1der Jun 12, 2026
e75d4ca
feat(linUCB): history-level companion to widthQuadraticForm
FawadHa1der Jun 15, 2026
9c2a1cc
feat(linUCB): history-level analogue of the existing process-level sq…
FawadHa1der Jun 15, 2026
9aea432
feat(linUCB): transports the nonnegativity condition across the proce…
FawadHa1der Jun 15, 2026
a943c01
feat(linUCB): for positive process time n, the process-level squared …
FawadHa1der Jun 15, 2026
49ad7c9
feat(linUCB): widthSqSum(n + 1)=widthSqSum(n)+history-level quadratic…
FawadHa1der Jun 15, 2026
54db96b
feat(linUCB): sums the history-level quadratic forms
FawadHa1der Jun 15, 2026
2a6a0cd
feat(linUCB): history-level quadratic-width related lemmas
FawadHa1der Jun 15, 2026
38e20e1
feat(linUCB): capped version of the quadratic-width accumulator:
FawadHa1der Jun 15, 2026
1bb706d
feat(linUCB): bridge from the capped elliptical-potential-style quant…
FawadHa1der Jun 15, 2026
24b5503
feat(linUCB): process-level capped accumulator
FawadHa1der Jun 15, 2026
c511de3
feat(linUCB): process/history transport lemmas
FawadHa1der Jun 16, 2026
85c4425
feat(linUCB): compact regret theorem
FawadHa1der Jun 16, 2026
2a7e5b1
feat(linUCB): direct regret theorem
FawadHa1der Jun 16, 2026
d568d50
feat(linUCB): base case for the log-determinant elliptical-potential …
FawadHa1der Jun 16, 2026
9766e16
feat(linUCB): per-step potential-increment shell
FawadHa1der Jun 16, 2026
9d11254
feat(linUCB): one-step determinant ratio related lemmas
FawadHa1der Jun 16, 2026
70916c4
feat(linUCB): elliptical-potential chain related changes
FawadHa1der Jun 16, 2026
88d52b6
feat : initial algorithm foundation for linUCB
FawadHa1der May 29, 2026
56cf08f
feat(linUCB):D = 2 ^ n intermediate bound
FawadHa1der Jun 17, 2026
feff54d
feat(linUCB):trace/determinant-budget layer
FawadHa1der Jun 17, 2026
5472ce8
feat(linUCB):trace/determinant-budget layer
FawadHa1der Jun 17, 2026
0a81fe7
feat(linUCB):trace/determinant-budget layer
FawadHa1der Jun 17, 2026
51d73c5
feat(linUCB):packaging step which allows formal slot where the hard m…
FawadHa1der Jun 17, 2026
13b222e
feat(linUCB): formal bound shaped like the standard elliptical-potent…
FawadHa1der Jun 17, 2026
c01cb04
feat(linUCB): end-to-end regret-facing step
FawadHa1der Jun 17, 2026
c6e6606
feat(linUCB): proof chain no longer needs the future matrix theorem
FawadHa1der Jun 17, 2026
5c3eb5c
feat(linUCB): small clean up
FawadHa1der Jun 17, 2026
c45b446
feat(linUCB): positive regularization now proves the design matrix is…
FawadHa1der Jun 17, 2026
c79afb0
feat(linUCB): linear-algebra bridge for the elliptical-potential regr…
FawadHa1der Jun 17, 2026
0fb3ae1
feat(linUCB): convert matrix inequalities into scalar quadratic-form …
FawadHa1der Jun 17, 2026
e4ac770
feat(linUCB): width comparison needed by the regret theorem path
FawadHa1der Jun 17, 2026
6c16639
feat(linUCB): regret theorem now using updated matrix theorem
FawadHa1der Jun 17, 2026
92c3df1
feat(linUCB): regret theorem dependent on reusable linear-algebra the…
FawadHa1der Jun 17, 2026
5fb147e
feat(linUCB): remaining deterministic/regret-shell steps
FawadHa1der Jun 18, 2026
2057e73
feat(linUCB): the matrix determinant/trace assumption
FawadHa1der Jun 18, 2026
fdf56f9
feat(linUCB): regret theorem no longer requires the assumption hd : d…
FawadHa1der Jun 18, 2026
2ca2a1b
feat(linUCB): final theorem no longer exposes the raw GapBound ν 2 as…
FawadHa1der Jun 18, 2026
36fa51a
feat(linUCB): remove hβ_nonneg assumption
FawadHa1der Jun 18, 2026
3ad7f30
feat(linUCB): theorem statement closer to textbook
FawadHa1der Jun 18, 2026
be7acde
feat(linUCB): theorem statement closer to textbook
FawadHa1der Jun 18, 2026
23fa3c7
feat(linUCB): new lemmas that lift sample-path implication into proba…
FawadHa1der Jun 18, 2026
3460962
feat(linUCB): remaining deterministic/probability plumbing
FawadHa1der Jun 18, 2026
f63a9cf
feat(LinUCB Algorithm And Process API): formalize the actual finite-a…
FawadHa1der Jun 25, 2026
c62f829
feat(112): reorg the linUCB into modular files
FawadHa1der Jun 26, 2026
9257d57
feat(112): remove the regret file reference
FawadHa1der Jun 26, 2026
60874d4
Merge branch 'main' into issue-112
FawadHa1der Jun 26, 2026
60c75ad
linUCB(issue-112): update the LML main import file
FawadHa1der Jun 26, 2026
2009014
linUCB(issue-112): fix author comment
FawadHa1der Jun 26, 2026
ac1a4ec
libUCB(issue-112): feedback changes to use mathlibs euclideans space
FawadHa1der Jul 1, 2026
032c01a
resolve merge conflict
FawadHa1der Jun 26, 2026
c1c6ec6
pulling/merging changes from main
FawadHa1der Jul 1, 2026
32a03c2
linUCB(issue-112): refactor related to removal of measurableArgmax
FawadHa1der Jul 1, 2026
9d69692
linUCB(issue-112):barrel file update
FawadHa1der Jul 2, 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
2 changes: 2 additions & 0 deletions LeanMachineLearning.lean
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public import LeanMachineLearning.ForMathlib.Probability.Kernel.KernelSub
public import LeanMachineLearning.ForMathlib.Probability.Moments.SubGaussian
public import LeanMachineLearning.ForMathlib.Probability.WithDensity
public import LeanMachineLearning.Online.Bandit.Algorithms.ETC
public import LeanMachineLearning.Online.Bandit.Algorithms.LinUCB
public import LeanMachineLearning.Online.Bandit.Algorithms.LinUCB.Basic
public import LeanMachineLearning.Online.Bandit.Algorithms.Regret.BayesRegretTS
public import LeanMachineLearning.Online.Bandit.Algorithms.TS
public import LeanMachineLearning.Online.Bandit.Algorithms.UCB
Expand Down
19 changes: 19 additions & 0 deletions LeanMachineLearning/Online/Bandit/Algorithms/LinUCB.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/-
Copyright (c) 2026. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: OpenAI, Fawad Haider
Comment thread
RemyDegenne marked this conversation as resolved.
-/
module



/-!
# LinUCB for finite-action linear bandits

This module is the public entry point for the finite-action LinUCB development.

The implementation is split across submodules under
`LeanMachineLearning.Online.Bandit.Algorithms.LinUCB.*`; importing this file re-exports the full
LinUCB API, including the algorithm definition, confidence events, concentration interfaces,
deterministic regret decomposition, elliptical-potential/log-det bounds, and final regret theorems.
-/
276 changes: 276 additions & 0 deletions LeanMachineLearning/Online/Bandit/Algorithms/LinUCB/Basic.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
/-
Copyright (c) 2026 Fawad Haider. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: OpenAI, Fawad Haider
-/
module

public import LeanMachineLearning.Online.Bandit.SumRewards
public import LeanMachineLearning.SequentialLearning.Deterministic
public import Mathlib.Analysis.MeanInequalities
public import Mathlib.Analysis.InnerProductSpace.PiL2
public import Mathlib.Analysis.SpecialFunctions.Log.Deriv
public import Mathlib.Analysis.Matrix.Order
public import LeanMachineLearning.ForMathlib.MeasureTheory.Order.MeasurableArg
public import Mathlib.Algebra.Order.Star.Real
public import Mathlib.LinearAlgebra.Matrix.PosDef
public import Mathlib.LinearAlgebra.Matrix.SchurComplement
public import Mathlib.LinearAlgebra.Matrix.NonsingularInverse
public import Mathlib.Probability.Martingale.OptionalStopping

/-!
# LinUCB for finite-action linear bandits
Chapter 19 of *Bandit Algorithms*:
-/

@[expose] public section

open MeasureTheory ProbabilityTheory Filter Real Finset Learning

open scoped ENNReal NNReal Matrix MatrixOrder

namespace Bandits

variable {K d : ℕ}

section Algorithm

namespace LinUCB

/-- Feature vectors for finite-dimensional linear bandits.

We use mathlib's Euclidean space model so that LinUCB's feature vectors carry the standard
inner-product and norm structure of `ℝ^d`. Coordinate formulas remain available through the
coercion `Feature d → (Fin d → ℝ)`, which is useful for the matrix identities below. -/
abbrev Feature (d : ℕ) := EuclideanSpace ℝ (Fin d)

/-- View a coordinate matrix-vector product as a Euclidean feature vector. -/
noncomputable def matrixMulFeature (M : Matrix (Fin d) (Fin d) ℝ) (v : Feature d) :
Feature d :=
WithLp.toLp 2 (Matrix.mulVec M v)

lemma mulVec_matrixMulFeature (M N : Matrix (Fin d) (Fin d) ℝ) (v : Feature d) :
Matrix.mulVec M (matrixMulFeature N v) = Matrix.mulVec (M * N) v := by
ext i
simp [matrixMulFeature, Matrix.mulVec_mulVec]

/-- The coordinate dot product of a feature vector with itself is its squared Euclidean norm. -/
lemma dotProduct_self_eq_norm_sq (u : Feature d) :
dotProduct u u = ‖u‖ ^ 2 := by
rw [← real_inner_self_eq_norm_sq]
simp [dotProduct, inner]

/-- The squared Euclidean norm of an arbitrary feature vector is nonnegative. -/
lemma dotProduct_self_nonneg (u : Feature d) :
0 ≤ dotProduct u u := by
rw [dotProduct]
exact sum_nonneg fun i _ ↦ mul_self_nonneg (u i)

/-- Euclidean Cauchy-Schwarz for the finite-dimensional `Feature d` dot product. -/
lemma abs_dotProduct_le_sqrt_mul_sqrt (u v : Feature d) :
|dotProduct u v| ≤ √(dotProduct u u) * √(dotProduct v v) := by
have hpos :
dotProduct u v ≤ √(dotProduct u u) * √(dotProduct v v) := by
simpa [dotProduct, pow_two] using
(Real.sum_mul_le_sqrt_mul_sqrt (Finset.univ : Finset (Fin d)) u v)
have hneg :
-dotProduct u v ≤ √(dotProduct u u) * √(dotProduct v v) := by
have h := Real.sum_mul_le_sqrt_mul_sqrt (Finset.univ : Finset (Fin d))
(fun i : Fin d ↦ -u i) v
simpa [dotProduct, pow_two, Finset.sum_neg_distrib] using h
exact abs_le.mpr ⟨by linarith, hpos⟩

/-- Cauchy-Schwarz with external squared-norm bounds. -/
lemma abs_dotProduct_le_sqrt_mul_sqrt_of_sq_norm_le
(u v : Feature d) {U V : ℝ}
(hu : dotProduct u u ≤ U) (hv : dotProduct v v ≤ V) :
|dotProduct u v| ≤ √U * √V := by
refine (abs_dotProduct_le_sqrt_mul_sqrt u v).trans ?_
exact mul_le_mul (Real.sqrt_le_sqrt hu) (Real.sqrt_le_sqrt hv)
(Real.sqrt_nonneg _) (Real.sqrt_nonneg _)

/-- Uniform squared feature-norm bound for finite-action LinUCB.

This is the finite-action version of the textbook assumption `‖x‖₂ ≤ L`, written here in squared
form as `‖x_a‖₂² ≤ L2` for every action. -/
def FeatureSqNormBound (x : Fin K → Feature d) (L2 : ℝ) : Prop :=
∀ a, ‖x a‖ ^ 2 ≤ L2

/-- A uniform squared feature-norm bound is nonnegative whenever the finite action set is
nonempty. -/
lemma FeatureSqNormBound.nonneg [Nonempty (Fin K)]
{x : Fin K → Feature d} {L2 : ℝ} (hL2 : FeatureSqNormBound x L2) :
0 ≤ L2 := by
classical
exact (sq_nonneg ‖x (Classical.arbitrary (Fin K))‖).trans
(hL2 (Classical.arbitrary (Fin K)))

lemma exists_abs_dotProduct_feature_bound (x : Fin K → Feature d) (v : Feature d) :
∃ Q : ℝ, 0 ≤ Q ∧ ∀ a, |dotProduct v (x a)| ≤ Q := by
refine ⟨∑ a, |dotProduct v (x a)|, ?_, ?_⟩
· exact sum_nonneg fun a _ha ↦ abs_nonneg _
· intro a
exact Finset.single_le_sum
(fun b _hb ↦ abs_nonneg (dotProduct v (x b))) (Finset.mem_univ a)

/-- History-level regularized design matrix for LinUCB. -/
noncomputable def designMatrix' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) : Matrix (Fin d) (Fin d) ℝ :=
reg • 1 + ∑ s : Iic n, Matrix.vecMulVec (x (h s).1) (x (h s).1)

/-- History-level response vector for LinUCB. -/
noncomputable def responseVector' (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) : Feature d :=
∑ s : Iic n, (h s).2 • x (h s).1

/-- History-level regularized least-squares estimate. -/
noncomputable def thetaHat' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) : Feature d :=
matrixMulFeature (designMatrix' reg x n h)⁻¹ (responseVector' x n h)

/-- History-level estimated reward of an arm. -/
noncomputable def estimatedReward' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) (a : Fin K) : ℝ :=
dotProduct (thetaHat' reg x n h) (x a)

/-- History-level quadratic form underlying the LinUCB confidence width. -/
noncomputable def widthQuadraticForm' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) (a : Fin K) : ℝ :=
dotProduct (x a) (Matrix.mulVec (designMatrix' reg x n h)⁻¹ (x a))

/-- History-level elliptical confidence width of an arm. -/
noncomputable def width' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) (a : Fin K) : ℝ :=
√(widthQuadraticForm' reg x n h a)

/-- History-level LinUCB optimistic index for a candidate arm. -/
noncomputable def index' (reg : ℝ) (β : ℕ → ℝ) (x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) (a : Fin K) : ℝ :=
estimatedReward' reg x n h a + √(β (n + 2)) * width' reg x n h a

lemma measurable_designMatrix'_apply (reg : ℝ) (x : Fin K → Feature d) (n : ℕ)
(i j : Fin d) :
Measurable (fun h ↦ designMatrix' reg x n h i j) := by
unfold designMatrix'
change Measurable fun h : Iic n → Fin K × ℝ ↦
(reg • (1 : Matrix (Fin d) (Fin d) ℝ)) i j +
(∑ s : Iic n, Matrix.vecMulVec (x (h s).1) (x (h s).1)) i j
refine Measurable.const_add ?_ _
rw [show (fun h : Iic n → Fin K × ℝ ↦
(∑ s : Iic n, Matrix.vecMulVec (x (h s).1) (x (h s).1)) i j) =
fun h ↦ ∑ s : Iic n, x (h s).1 i * x (h s).1 j by
funext h
simp [Matrix.sum_apply, Matrix.vecMulVec]]
fun_prop

@[fun_prop]
lemma measurable_responseVector'_apply (x : Fin K → Feature d) (n : ℕ) (i : Fin d) :
Measurable (fun h ↦ responseVector' x n h i) := by
unfold responseVector'
fun_prop

lemma measurable_matrix_det_apply {α : Type*} {mα : MeasurableSpace α}
(M : α → Matrix (Fin d) (Fin d) ℝ)
(hM : ∀ i j, Measurable fun a ↦ M a i j) :
Measurable fun a ↦ (M a).det := by
simp_rw [Matrix.det_apply']
fun_prop

lemma measurable_matrix_adjugate_apply {α : Type*} {mα : MeasurableSpace α}
(M : α → Matrix (Fin d) (Fin d) ℝ)
(hM : ∀ i j, Measurable fun a ↦ M a i j) (i j : Fin d) :
Measurable fun a ↦ (M a).adjugate i j := by
simp_rw [Matrix.adjugate_apply]
refine measurable_matrix_det_apply (fun a ↦ (M a).updateRow j (Pi.single i 1)) ?_
intro k l
by_cases hkj : k = j
· subst k
simp [Matrix.updateRow_self]
· simpa [Matrix.updateRow_ne hkj] using hM k l

lemma measurable_matrix_inv_apply {α : Type*} {mα : MeasurableSpace α}
(M : α → Matrix (Fin d) (Fin d) ℝ)
(hM : ∀ i j, Measurable fun a ↦ M a i j) (i j : Fin d) :
Measurable fun a ↦ (M a)⁻¹ i j := by
simp_rw [Matrix.inv_def]
have hdet : Measurable fun a ↦ ((M a).det)⁻¹ :=
(measurable_matrix_det_apply M hM).inv
have hadj : Measurable fun a ↦ (M a).adjugate i j :=
measurable_matrix_adjugate_apply M hM i j
convert hdet.mul hadj using 1
ext a
simp [Ring.inverse_eq_inv, Matrix.smul_apply]

@[fun_prop]
lemma measurable_thetaHat'_apply (reg : ℝ) (x : Fin K → Feature d) (n : ℕ) (i : Fin d) :
Measurable (fun h ↦ thetaHat' reg x n h i) := by
unfold thetaHat'
change Measurable fun h ↦
∑ j, (designMatrix' reg x n h)⁻¹ i j * responseVector' x n h j
refine Finset.measurable_sum _ fun j _ ↦ ?_
exact (measurable_matrix_inv_apply (fun h ↦ designMatrix' reg x n h)
(measurable_designMatrix'_apply reg x n) i j).mul
(measurable_responseVector'_apply x n j)

@[fun_prop]
lemma measurable_estimatedReward' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (a : Fin K) :
Measurable (fun h ↦ estimatedReward' reg x n h a) := by
unfold estimatedReward'
change Measurable fun h ↦ ∑ i, thetaHat' reg x n h i * x a i
fun_prop

@[fun_prop]
lemma measurable_widthQuadraticForm' (reg : ℝ) (x : Fin K → Feature d)
(n : ℕ) (a : Fin K) :
Measurable (fun h ↦ widthQuadraticForm' reg x n h a) := by
unfold widthQuadraticForm'
change Measurable fun h ↦
∑ i, x a i * (∑ j, (designMatrix' reg x n h)⁻¹ i j * x a j)
refine Finset.measurable_sum _ fun i _ ↦ ?_
refine Measurable.const_mul ?_ _
refine Finset.measurable_sum _ fun j _ ↦ ?_
exact (measurable_matrix_inv_apply (fun h ↦ designMatrix' reg x n h)
(measurable_designMatrix'_apply reg x n) i j).mul measurable_const

@[fun_prop]
lemma measurable_width' (reg : ℝ) (x : Fin K → Feature d) (n : ℕ) (a : Fin K) :
Measurable (fun h ↦ width' reg x n h a) := by
unfold width'
fun_prop

@[fun_prop]
lemma measurable_index' (reg : ℝ) (β : ℕ → ℝ) (x : Fin K → Feature d)
(n : ℕ) (a : Fin K) :
Measurable (fun h ↦ index' reg β x n h a) := by
unfold index'
fun_prop

open Classical in
/-- Arm pulled by finite-action LinUCB at time `n + 1`. -/
noncomputable def nextArm (hK : 0 < K) (reg : ℝ) (β : ℕ → ℝ)
(x : Fin K → Feature d)
(n : ℕ) (h : Iic n → Fin K × ℝ) : Fin K :=
have : Nonempty (Fin K) := Fin.pos_iff_nonempty.mp hK
argmax (fun a ↦ index' reg β x n h a)

@[fun_prop]
lemma measurable_nextArm (hK : 0 < K) (reg : ℝ) (β : ℕ → ℝ)
(x : Fin K → Feature d)
(n : ℕ) :
Measurable (nextArm hK reg β x n) := by
have : Nonempty (Fin K) := Fin.pos_iff_nonempty.mp hK
unfold nextArm
fun_prop

end LinUCB

/-- The finite-action LinUCB algorithm. -/
noncomputable def linUCBAlgorithm (hK : 0 < K) (reg : ℝ) (β : ℕ → ℝ)
(x : Fin K → LinUCB.Feature d) :
Algorithm (Fin K) ℝ :=
detAlgorithm (LinUCB.nextArm hK reg β x) (by fun_prop) ⟨0, hK⟩

end Algorithm

end Bandits