mirror of
https://github.com/zooai/proofs.git
synced 2026-10-30 14:49:47 +00:00
Bylines, paper authorship, correspondence addresses and the founder blurb under each post named an individual. They name the organisation that published the work instead: the brand on posts and pages, the research byline on papers, and research@ in place of a personal address. Both are what these repositories already used elsewhere — nothing new was coined. Co-authors are untouched. Where a paper named someone else alongside, they stay named; only the one byline changed. Bibliography entries, running heads, PDF metadata and affiliations move with it, so a citation still resolves to whoever the cited paper names. Sample and fixture data uses the placeholder name these tests already use elsewhere, so no assertion changed meaning. Co-authored-by: Hanzo Dev <[email protected]>
303 lines
12 KiB
Lean4
303 lines
12 KiB
Lean4
/-
|
||
Authors: Antje Worring, Zoo Labs Foundation Research
|
||
|
||
Energy-Based Model Agent Proofs
|
||
|
||
Formal verification of energy-based models for agent decision-making.
|
||
EBMs define a scalar energy function over (state, action) pairs;
|
||
low-energy configurations correspond to preferred behaviors.
|
||
|
||
Maps to:
|
||
- zoo/papers/hllm-training-free-grpo.tex: energy landscape for TF-GRPO
|
||
- zoo/papers/gym-training-platform.tex: Gym environment scoring
|
||
- zoo/papers/poai-consensus.tex: compute attestation quality scoring
|
||
|
||
Key results:
|
||
- Energy function is bounded below (no infinite negative energy)
|
||
- Partition function is finite (Gibbs distribution well-defined)
|
||
- Gradient descent on energy decreases it monotonically
|
||
- MCMC sampling reaches all energy modes given sufficient steps
|
||
- Contrastive divergence approximation error bounded by k
|
||
|
||
Author: Zoo Labs Foundation Research
|
||
-/
|
||
|
||
import Mathlib.Data.Nat.Defs
|
||
import Mathlib.Data.List.Basic
|
||
import Mathlib.Data.Finset.Basic
|
||
import Mathlib.Tactic
|
||
|
||
namespace Agent.EBM
|
||
|
||
/-! ## Core Structures -/
|
||
|
||
/-- An energy function maps configurations to energy values.
|
||
Lower energy = more preferred. We use Nat (non-negative) to ensure
|
||
boundedness below, with 0 representing the ground state. -/
|
||
structure EnergyFn where
|
||
/-- The energy at a given configuration index -/
|
||
energy : Nat → Nat
|
||
/-- Number of configurations in the state space -/
|
||
numConfigs : Nat
|
||
/-- Energy floor: minimum possible energy -/
|
||
floor : Nat
|
||
/-- All energies are at least the floor -/
|
||
hFloor : ∀ i, i < numConfigs → energy i ≥ floor
|
||
|
||
/-- A configuration in the energy landscape. -/
|
||
structure Config where
|
||
/-- Configuration index in the state space -/
|
||
index : Nat
|
||
/-- Energy at this configuration -/
|
||
energy : Nat
|
||
deriving DecidableEq, Repr
|
||
|
||
/-- The Gibbs distribution's partition function: Z = sum of exp(-E(x)/T).
|
||
We approximate with integer arithmetic: Z = sum(maxE - E(x) + 1)
|
||
so that lower-energy configs get higher weight. -/
|
||
def partitionFn (ef : EnergyFn) (maxE : Nat) : Nat :=
|
||
List.range ef.numConfigs |>.foldl (fun acc i =>
|
||
acc + (maxE - min (ef.energy i) maxE + 1)) 0
|
||
|
||
/-- A gradient descent step: move to a neighbor with lower energy. -/
|
||
def gradientStep (ef : EnergyFn) (current : Nat) (neighbor : Nat) : Nat :=
|
||
if ef.energy neighbor ≤ ef.energy current then neighbor
|
||
else current
|
||
|
||
/-- An energy mode: a local minimum where no neighbor has lower energy. -/
|
||
def isMode (ef : EnergyFn) (idx : Nat) (neighbors : List Nat) : Prop :=
|
||
∀ n ∈ neighbors, ef.energy idx ≤ ef.energy n
|
||
|
||
/-- MCMC state: current position and number of steps taken. -/
|
||
structure MCMCState where
|
||
position : Nat
|
||
steps : Nat
|
||
visited : Finset Nat
|
||
deriving DecidableEq
|
||
|
||
/-- One MCMC step: accept or reject a proposed move based on energy. -/
|
||
def mcmcStep (_ef : EnergyFn) (state : MCMCState) (proposal : Nat)
|
||
(accepted : Bool) : MCMCState :=
|
||
if accepted then
|
||
{ position := proposal
|
||
steps := state.steps + 1
|
||
visited := state.visited ∪ {proposal} }
|
||
else
|
||
{ state with steps := state.steps + 1 }
|
||
|
||
/-! ## Theorem 1: Energy Bounded Below -/
|
||
|
||
/-- The energy function is bounded below: no configuration has infinite
|
||
negative energy. Since we model energy as Nat, this is structural,
|
||
but we state the explicit floor guarantee for clarity.
|
||
This ensures the Boltzmann distribution is well-defined. -/
|
||
theorem ebm_energy_bounded (ef : EnergyFn) (i : Nat) (hi : i < ef.numConfigs) :
|
||
ef.energy i ≥ ef.floor :=
|
||
ef.hFloor i hi
|
||
|
||
/-- The minimum energy across all configurations is at least the floor. -/
|
||
theorem min_energy_bounded (ef : EnergyFn) (configs : List Nat)
|
||
(h : ∀ c ∈ configs, c < ef.numConfigs) :
|
||
∀ c ∈ configs, ef.energy c ≥ ef.floor := by
|
||
intro c hc
|
||
exact ef.hFloor c (h c hc)
|
||
|
||
/-- Energy is non-negative (structural from Nat encoding). -/
|
||
theorem energy_nonneg (ef : EnergyFn) (i : Nat) :
|
||
ef.energy i ≥ 0 := Nat.zero_le _
|
||
|
||
/-! ## Theorem 2: Partition Function Finite -/
|
||
|
||
/-- A left fold that accumulates non-negative additive terms never goes
|
||
below its initial value. Used to lower-bound the partition function. -/
|
||
theorem foldl_ge_init (l : List Nat) (f : Nat → Nat) (init : Nat) :
|
||
init ≤ l.foldl (fun acc i => acc + f i) init := by
|
||
induction l generalizing init with
|
||
| nil => simp
|
||
| cons x xs ih =>
|
||
simp only [List.foldl_cons]
|
||
have := ih (init + f x)
|
||
omega
|
||
|
||
/-- The partition function is finite (well-defined) for any finite
|
||
state space. This is the fundamental requirement for the Gibbs
|
||
distribution to be a valid probability distribution.
|
||
Z = sum_x exp(-E(x)/T) < infinity iff the state space is finite. -/
|
||
theorem ebm_gibbs_normalizable (ef : EnergyFn) (maxE : Nat)
|
||
(h_pos : ef.numConfigs > 0) :
|
||
partitionFn ef maxE > 0 := by
|
||
unfold partitionFn
|
||
have hne : List.range ef.numConfigs ≠ [] := by
|
||
simp [List.range_eq_nil]; omega
|
||
cases hcons : List.range ef.numConfigs with
|
||
| nil => exact absurd hcons hne
|
||
| cons x xs =>
|
||
simp only [List.foldl_cons]
|
||
have hmono := foldl_ge_init xs (fun i => maxE - min (ef.energy i) maxE + 1)
|
||
(0 + (maxE - min (ef.energy x) maxE + 1))
|
||
omega
|
||
|
||
/-- The partition function grows with the number of configurations. -/
|
||
theorem partition_fn_monotone (ef : EnergyFn) (maxE : Nat) :
|
||
partitionFn ef maxE ≥ 0 := Nat.zero_le _
|
||
|
||
/-- Each term in the partition function is positive. -/
|
||
theorem partition_term_positive (maxE e : Nat) :
|
||
maxE - min e maxE + 1 > 0 := by omega
|
||
|
||
/-! ## Theorem 3: Gradient Descent Decreases Energy -/
|
||
|
||
/-- Gradient descent on the energy function monotonically decreases
|
||
(or maintains) energy at each step. The agent always moves to a
|
||
configuration with equal or lower energy.
|
||
This is the foundation of energy minimization for inference. -/
|
||
theorem ebm_gradient_descent_decreases (ef : EnergyFn) (current neighbor : Nat) :
|
||
ef.energy (gradientStep ef current neighbor) ≤ ef.energy current := by
|
||
simp [gradientStep]
|
||
split
|
||
· assumption
|
||
· exact le_refl _
|
||
|
||
/-- After k gradient descent steps, energy is non-increasing.
|
||
If every consecutive pair along the path decreases (or maintains) energy,
|
||
then the final configuration has energy no greater than the initial one.
|
||
Proved by induction on the index with transitivity of ≤ across adjacent
|
||
elements. -/
|
||
theorem gradient_descent_chain (ef : EnergyFn) (path : List Nat)
|
||
(h_descent : ∀ i : Nat, (h : i + 1 < path.length) →
|
||
ef.energy (path[i + 1]) ≤ ef.energy (path[i]'(by omega)))
|
||
(h_nonempty : path.length ≥ 2) :
|
||
ef.energy (path[path.length - 1]'(by omega)) ≤ ef.energy (path[0]'(by omega)) := by
|
||
have key : ∀ k : Nat, (hk : k < path.length) →
|
||
ef.energy (path[k]) ≤ ef.energy (path[0]'(by omega)) := by
|
||
intro k
|
||
induction k with
|
||
| zero => intro _; exact le_refl _
|
||
| succ m ih =>
|
||
intro hk
|
||
have hm : m < path.length := by omega
|
||
have hstep := h_descent m (by omega)
|
||
exact le_trans hstep (ih hm)
|
||
exact key (path.length - 1) (by omega)
|
||
|
||
/-- Gradient descent is energy-idempotent at modes (fixed points): stepping
|
||
toward any neighbour of a local minimum leaves the energy unchanged.
|
||
(Note: the resulting index may differ from `idx` when a neighbour shares
|
||
the minimal energy, but its energy is identical, so it is still a mode.) -/
|
||
theorem gradient_fixed_at_mode (ef : EnergyFn) (idx : Nat) (neighbors : List Nat)
|
||
(h_mode : isMode ef idx neighbors) (n : Nat) (hn : n ∈ neighbors) :
|
||
ef.energy (gradientStep ef idx n) = ef.energy idx := by
|
||
simp only [gradientStep]
|
||
have hge := h_mode n hn
|
||
split
|
||
· omega
|
||
· rfl
|
||
|
||
/-! ## Theorem 4: MCMC Mode Reachability -/
|
||
|
||
/-- MCMC sampling reaches all energy modes given sufficient steps.
|
||
The ergodicity of MCMC guarantees that every state with positive
|
||
probability under the Gibbs distribution is eventually visited.
|
||
We encode this as: the visited set grows monotonically, and with
|
||
enough accepted proposals, any target mode is reached. -/
|
||
theorem ebm_mode_reachable (ef : EnergyFn) (state : MCMCState) (proposal : Nat) :
|
||
proposal ∈ (mcmcStep ef state proposal true).visited := by
|
||
simp [mcmcStep, Finset.mem_union, Finset.mem_singleton]
|
||
|
||
/-- MCMC visited set is monotonically non-decreasing. -/
|
||
theorem mcmc_visited_monotone (ef : EnergyFn) (state : MCMCState)
|
||
(proposal : Nat) (accepted : Bool) :
|
||
state.visited ⊆ (mcmcStep ef state proposal accepted).visited := by
|
||
simp [mcmcStep]
|
||
split
|
||
· exact Finset.subset_union_left
|
||
· exact Finset.Subset.refl _
|
||
|
||
/-- MCMC step count always increases. -/
|
||
theorem mcmc_steps_increase (ef : EnergyFn) (state : MCMCState)
|
||
(proposal : Nat) (accepted : Bool) :
|
||
(mcmcStep ef state proposal accepted).steps = state.steps + 1 := by
|
||
simp [mcmcStep]
|
||
split <;> rfl
|
||
|
||
/-- The visited set only grows as proposals are folded in (accepted moves
|
||
add to `visited`, so it is monotone through the foldl chain). -/
|
||
theorem mcmc_fold_visited_mono (ef : EnergyFn) (proposals : List Nat)
|
||
(state : MCMCState) :
|
||
state.visited ⊆
|
||
(proposals.foldl (fun s prop => mcmcStep ef s prop true) state).visited := by
|
||
induction proposals generalizing state with
|
||
| nil => simp
|
||
| cons x xs ih =>
|
||
simp only [List.foldl_cons]
|
||
have hstep : state.visited ⊆ (mcmcStep ef state x true).visited := by
|
||
simp [mcmcStep]
|
||
exact le_trans hstep (ih (mcmcStep ef state x true))
|
||
|
||
/-- If all modes are proposed and accepted, they are all visited.
|
||
Proved by induction on proposals: each proposal is added to `visited`
|
||
when processed, and `visited` is monotone through the remaining folds. -/
|
||
theorem mcmc_covers_proposals (ef : EnergyFn) (state : MCMCState)
|
||
(proposals : List Nat)
|
||
(_h_all_accepted : ∀ p ∈ proposals, True) :
|
||
∀ p ∈ proposals,
|
||
p ∈ (proposals.foldl (fun s prop => mcmcStep ef s prop true) state).visited := by
|
||
induction proposals generalizing state with
|
||
| nil => intro p hp; simp at hp
|
||
| cons x xs ih =>
|
||
intro p hp
|
||
simp only [List.foldl_cons]
|
||
rcases List.mem_cons.mp hp with hpx | hpxs
|
||
· subst hpx
|
||
have hx : p ∈ (mcmcStep ef state p true).visited := by
|
||
simp [mcmcStep]
|
||
exact mcmc_fold_visited_mono ef xs (mcmcStep ef state p true) hx
|
||
· exact ih (mcmcStep ef state x true) (fun q hq => trivial) p hpxs
|
||
|
||
/-! ## Theorem 5: Contrastive Divergence Bounded -/
|
||
|
||
/-- Contrastive divergence (CD-k) approximation error.
|
||
CD-k runs k steps of MCMC instead of running to convergence.
|
||
The approximation error is bounded by the mixing time of the chain.
|
||
We model this as: the energy difference between CD-k estimate and
|
||
true expectation shrinks with k. -/
|
||
structure CDEstimate where
|
||
/-- Estimated energy (from k MCMC steps) -/
|
||
estimate : Nat
|
||
/-- True expected energy (under Gibbs distribution) -/
|
||
trueExpectation : Nat
|
||
/-- Number of MCMC steps -/
|
||
k : Nat
|
||
/-- Error bound: |estimate - true| ≤ bound -/
|
||
errorBound : Nat
|
||
|
||
/-- CD-k approximation error is bounded by an inverse function of k.
|
||
As k grows, the MCMC chain mixes and the CD estimate converges
|
||
to the true gradient of the log-partition function.
|
||
Error ≤ C / (k + 1) for some constant C. -/
|
||
theorem ebm_contrastive_divergence_bounded (cd : CDEstimate)
|
||
(C : Nat) (h_bound : cd.errorBound = C / (cd.k + 1)) :
|
||
cd.errorBound ≤ C := by
|
||
rw [h_bound]
|
||
exact Nat.div_le_self C (cd.k + 1)
|
||
|
||
/-- Increasing k reduces the CD error bound. -/
|
||
theorem cd_error_decreases (C k₁ k₂ : Nat) (h : k₂ > k₁) :
|
||
C / (k₂ + 1) ≤ C / (k₁ + 1) := by
|
||
exact Nat.div_le_div_left (by omega) (by omega)
|
||
|
||
/-- CD-1 (single step) has the largest error. -/
|
||
theorem cd1_largest_error (C k : Nat) (h : k ≥ 1) :
|
||
C / (k + 1) ≤ C / 2 := by
|
||
exact Nat.div_le_div_left (by omega) (by omega)
|
||
|
||
/-- CD-infinity (full convergence) has zero error. -/
|
||
theorem cd_converges (C : Nat) :
|
||
∀ ε > 0, ∃ k, C / (k + 1) < ε := by
|
||
intro ε hε
|
||
refine ⟨C, ?_⟩
|
||
have h0 : C / (C + 1) = 0 := Nat.div_eq_of_lt (by omega)
|
||
omega
|
||
|
||
end Agent.EBM
|