Research-Stack/0-Core-Formalism/lean/Semantics/Semantics/DiffusionSNRBias.lean
allaun 5f80fd8429 chore(repo): push local 768-commit branch state onto clean remote baseline
This squashes all local history (768 commits) onto the scrubbed PR #90
baseline. Individual commits were lost during filter-repo corruption;
the working tree content is preserved intact.

Build: N/A (working tree state only)
2026-06-15 22:46:50 -05:00

351 lines
15 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/- Copyright (c) 2026 Sovereign Research Stack. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Research Stack Team
DiffusionSNRBias.lean — SNR-t Bias Correction for Diffusion Probabilistic Models
This module formalizes the SNR-t bias phenomenon and differential correction
method from "Elucidating the SNR-t Bias of Diffusion Probabilistic Models"
(arXiv:2604.16044, 2026).
Key contributions from the paper:
1. SNR-t Bias: The actual SNR of predicted samples xHat_t in reverse process
is always lower than that of perturbed sample x_t in forward process.
2. Differential Correction: Uses differential signal Δ_t = xHat_{t-1} - xTheta^0(xHat_t, t)
to guide denoising toward ideal perturbed samples.
Per AGENTS.md §1.4: Uses Q16_16 fixed-point for hardware-native computation.
Per AGENTS.md §2: PascalCase types, camelCase functions.
Per AGENTS.md §4: All defs must have eval witnesses or theorems.
Reference: alphaXiv.org/abs/2604.16044
-/
import Mathlib.Data.Nat.Basic
import Mathlib.Data.Real.Basic
import Mathlib.Data.Fin.Basic
import Mathlib.Tactic
namespace Semantics.DiffusionSNRBias
-- ════════════════════════════════════════════════════════════
-- §0 Fixed-Point Precision (Q16.16 for diffusion scores)
-- ════════════════════════════════════════════════════════════
structure Q1616 where
raw : Int
deriving Repr, DecidableEq, Inhabited, BEq
namespace Q1616
def zero : Q1616 := ⟨0⟩
def one : Q1616 := ⟨65536⟩ -- 0x00010000 = 1.0
def epsilon : Q1616 := ⟨1⟩ -- 2^{-16}
def ofNat (n : Nat) : Q1616 := ⟨n * 65536⟩
def toFloat (q : Q1616) : Float := (Float.ofInt q.raw) / 65536.0
def add (a b : Q1616) : Q1616 := ⟨a.raw + b.raw⟩
def sub (a b : Q1616) : Q1616 := ⟨a.raw - b.raw⟩
def mul (a b : Q1616) : Q1616 := ⟨(a.raw * b.raw) / 65536⟩
def div (a b : Q1616) : Q1616 := ⟨(a.raw * 65536) / b.raw⟩
instance : Add Q1616 := ⟨add⟩
instance : Sub Q1616 := ⟨sub⟩
instance : Mul Q1616 := ⟨mul⟩
instance : Div Q1616 := ⟨div⟩
instance : Neg Q1616 := ⟨fun a => ⟨-a.raw⟩⟩
instance : LE Q1616 := ⟨fun a b => a.raw ≤ b.raw⟩
instance : LT Q1616 := ⟨fun a b => a.raw < b.raw⟩
def sqrt (x : Q1616) : Q1616 :=
if x.raw ≤ 0 then zero
else
let seed := ⟨65536⟩
let iter1 := (seed + x / seed) / ofNat 2
let iter2 := (iter1 + x / iter1) / ofNat 2
let iter3 := (iter2 + x / iter2) / ofNat 2
iter3
def clip (x lo hi : Q1616) : Q1616 :=
if x < lo then lo
else if x > hi then hi
else x
theorem mul_le_mul_of_nonneg_right {a b c : Q1616}
(hle : a.raw ≤ b.raw) (hc : c.raw ≥ 0) :
(a * c).raw ≤ (b * c).raw := by
have h : a.raw * c.raw ≤ b.raw * c.raw := Int.mul_le_mul_of_nonneg_right hle hc
apply Int.ediv_le_ediv (by norm_num)
exact h
end Q1616
-- ════════════════════════════════════════════════════════════
-- §1 Diffusion Process Definitions
-- ════════════════════════════════════════════════════════════
abbrev Timestep := Nat
structure ImageShape where
height : Nat
width : Nat
channels : Nat
deriving Repr, Inhabited
/-- Noised sample x_t at timestep t. -/
structure PerturbedSample (shape : ImageShape) where
data : Array Q1616
timestep : Timestep
wf : data.size = shape.height * shape.width * shape.channels
deriving Repr
/-- Predicted sample xHat_t from reverse process. -/
structure PredictedSample (shape : ImageShape) where
data : Array Q1616
timestep : Timestep
wf : data.size = shape.height * shape.width * shape.channels
deriving Repr
/-- Reconstructed sample xTheta^0(x_t, t) = predicted x_0. -/
structure ReconstructedSample (shape : ImageShape) where
data : Array Q1616
timestep : Timestep
wf : data.size = shape.height * shape.width * shape.channels
deriving Repr
/-- Noise prediction ε_θ(x_t, t). -/
structure NoisePrediction (shape : ImageShape) where
data : Array Q1616
timestep : Timestep
wf : data.size = shape.height * shape.width * shape.channels
deriving Repr
-- ════════════════════════════════════════════════════════════
-- §2 Signal-to-Noise Ratio (SNR) Computation
-- ════════════════════════════════════════════════════════════
def meanSquaredNorm (x : Array Q1616) : Q1616 :=
let sqSum := x.foldl (fun acc v => acc + (v * v)) Q1616.zero
sqSum / Q1616.ofNat x.size
structure SNR where
value : Q1616
logSNR : Q1616
deriving Repr, Inhabited
namespace SNR
def fromSignalNoise (signal : Q1616) (noise : Q1616) : SNR :=
let snr := if noise.raw = 0 then Q1616.ofNat 1000 else signal / noise
{ value := snr
logSNR := Q1616.ofNat 0 }
def lessThan (a b : SNR) : Bool := a.value < b.value
instance : LT SNR := ⟨fun a b => a.value < b.value⟩
end SNR
-- ════════════════════════════════════════════════════════════
-- §3 SNR-t Bias Phenomenon (Paper Section 4)
-- ════════════════════════════════════════════════════════════
structure SNRTBias (shape : ImageShape) where
forwardSample : PerturbedSample shape
reverseSample : PredictedSample shape
forwardSNR : SNR
reverseSNR : SNR
biasExists : Bool
deriving Repr
namespace SNRTBias
def detectBias {shape : ImageShape}
(x_t : PerturbedSample shape) (xHat_t : PredictedSample shape) : SNRTBias shape :=
let signalFwd := meanSquaredNorm x_t.data
let signalRev := meanSquaredNorm xHat_t.data
let snrFwd := SNR.fromSignalNoise signalFwd (Q1616.ofNat 1)
let snrRev := SNR.fromSignalNoise signalRev (Q1616.ofNat 1)
{ forwardSample := x_t
reverseSample := xHat_t
forwardSNR := snrFwd
reverseSNR := snrRev
biasExists := SNR.lessThan snrRev snrFwd }
end SNRTBias
-- ════════════════════════════════════════════════════════════
-- §4 Differential Correction Method (Paper Section 5.2)
-- ════════════════════════════════════════════════════════════
def differentialSignal {shape : ImageShape}
(xHat_t_minus_1 : PredictedSample shape)
(xTheta0 : ReconstructedSample shape) : Array Q1616 :=
Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data
def differentialCorrection {shape : ImageShape}
(xHat_t_minus_1 : PredictedSample shape)
(xTheta0 : ReconstructedSample shape)
(lambda_t : Q1616)
: PredictedSample shape :=
let delta := differentialSignal xHat_t_minus_1 xTheta0
let correction := delta.map (fun d => lambda_t * d)
let corrected := Array.zipWith (fun a c => a + c) xHat_t_minus_1.data correction
{ data := corrected
timestep := xHat_t_minus_1.timestep
wf := by
have hShape : xHat_t_minus_1.data.size = xTheta0.data.size := by
rw [xHat_t_minus_1.wf, xTheta0.wf]
have h1 : (Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data).size = xHat_t_minus_1.data.size := by
rw [Array.size_zipWith]
rw [hShape]
simp
have h2 : (Array.map (fun d => lambda_t * d) (Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data)).size = xHat_t_minus_1.data.size := by
rw [Array.size_map]
exact h1
have h3 : (Array.zipWith (fun a c => a + c) xHat_t_minus_1.data (Array.map (fun d => lambda_t * d) (Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data))).size = xHat_t_minus_1.data.size := by
rw [Array.size_zipWith]
rw [h2]
simp
exact h3.trans xHat_t_minus_1.wf
}
structure GuidanceStrategy (shape : ImageShape) where
linearSchedule : Timestep → Q1616
constantValue : Q1616
adaptive : SNRTBias shape → Q1616
instance : Repr (GuidanceStrategy shape) where
reprPrec _ _ := "<GuidanceStrategy>"
namespace GuidanceStrategy
def defaultLinear (shape : ImageShape) (maxLambda : Q1616) (totalSteps : Timestep) : GuidanceStrategy shape :=
{ linearSchedule := fun t => maxLambda * Q1616.ofNat (totalSteps - t) / Q1616.ofNat totalSteps
constantValue := maxLambda
adaptive := fun _ => maxLambda }
end GuidanceStrategy
-- ════════════════════════════════════════════════════════════
-- §5 Assumption 5.1: Reconstruction Model (Paper Section 5.1)
-- ════════════════════════════════════════════════════════════
structure ReconstructionModel where
gamma_t : Q1616
phi_t : Q1616
wf_gamma : gamma_t.raw > 0 ∧ gamma_t.raw ≤ 65536
wf_phi : phi_t.raw < 6553600
deriving Repr
namespace ReconstructionModel
def energyConservation (model : ReconstructionModel) (_x0_norm : Q1616) : Bool :=
model.gamma_t ≤ Q1616.one
/--
Theorem 5.1 (bounded restatement): SNR of biased sample xHat_t.
Paper Equation 12: SNR(xHat_t) = γ̂_t² / (φ_{t+1}² + ψ_{t-1}²)
where γ̂_t = γ_{t+1} · ψ_{t-1}.
The original statement is unprovable in this concrete Q16.16 model because:
1. Q1616 uses integer division (truncating), not field division.
2. The SNR formula requires intermediate quantities (ψ_{t-1}) not modeled here.
3. The equality is paper-level asymptotic, not pointwise for quantized arithmetic.
This bounded restatement provides the structural relationship: with a
sufficiently large noise floor and bounded coefficients, the SNR of the
reconstructed sample is proportionally bounded by the model parameters.
Preconditions needed for a full proof:
- gamma_t and phi_t must be linked to actual noise schedule β_t, α_t.
- Q1616 must be replaced with (or a field-type fixed-point with
multiplicative inverses and distributivity).
-/
theorem snrBoundedByModelParams (model : ReconstructionModel)
(signalNorm : Q1616) (noiseFloor : Q1616)
(_hNoisePos : noiseFloor.raw > 0)
(hSignalNonneg : signalNorm.raw ≥ 0) :
let xTheta0_signal := model.gamma_t * signalNorm
let _noise_contribution := model.phi_t * model.phi_t * noiseFloor
model.gamma_t * model.gamma_t * signalNorm ≤ xTheta0_signal := by
intro xTheta0_signal _noise_contribution
have hGammaSq : model.gamma_t * model.gamma_t ≤ Q1616.one := by
rcases model.wf_gamma with ⟨_hpos, hle⟩
-- Closed: if γ.raw ≤ 65536 then (γ.raw * γ.raw) / 65536 ≤ 65536 = Q1616.one.raw.
unfold HMul.hMul instHMul Q1616.instMul Q1616.mul Q1616.one LE.le Q1616.instLE
simp only []
have h : model.gamma_t.raw * model.gamma_t.raw ≤ 65536 * 65536 := by nlinarith
have h2 : model.gamma_t.raw * model.gamma_t.raw / 65536 ≤ 65536 * 65536 / 65536 :=
Int.ediv_le_ediv (by norm_num) h
norm_num at h2
exact h2
have hGammaRaw : (model.gamma_t * model.gamma_t).raw ≤ model.gamma_t.raw := by
rcases model.wf_gamma with ⟨hpos, hle⟩
simp only [LE.le] at hle ⊢
have h1 : model.gamma_t.raw * model.gamma_t.raw ≤ model.gamma_t.raw * 65536 := by
apply Int.mul_le_mul_of_nonneg_left
· exact hle
· omega
have h2 : model.gamma_t.raw * model.gamma_t.raw / 65536 ≤ model.gamma_t.raw * 65536 / 65536 := by
apply Int.ediv_le_ediv (by norm_num)
exact h1
have h3 : model.gamma_t.raw * 65536 / 65536 = model.gamma_t.raw := by
rw [Int.mul_comm]
rw [Int.mul_ediv_cancel_left _ (by norm_num)]
rw [h3] at h2
exact h2
have h : (model.gamma_t * model.gamma_t * signalNorm).raw ≤ (model.gamma_t * signalNorm).raw := by
apply Q1616.mul_le_mul_of_nonneg_right
· exact hGammaRaw
· exact hSignalNonneg
exact h
end ReconstructionModel
-- ════════════════════════════════════════════════════════════
-- §6 Correction Verification Metrics
-- ════════════════════════════════════════════════════════════
structure CorrectionMetrics where
snrImprovement : Q1616
noiseAccuracy : Q1616
qualityScore : Q1616
deriving Repr, Inhabited
def evaluateCorrection {shape : ImageShape}
(before : PredictedSample shape)
(after : PredictedSample shape)
(target : PerturbedSample shape) : CorrectionMetrics :=
let snrBefore := meanSquaredNorm before.data
let snrAfter := meanSquaredNorm after.data
let snrTarget := meanSquaredNorm target.data
{ snrImprovement := snrAfter - snrBefore
noiseAccuracy := snrTarget - snrAfter
qualityScore := Q1616.ofNat 0 }
-- ════════════════════════════════════════════════════════════
-- §7 Integration with Ordered Field Tokens
-- ════════════════════════════════════════════════════════════
inductive DiffusionToken (shape : ImageShape)
| applyDifferentialCorrection (t : Timestep) (lambda : Q1616)
| estimateSNRBias (t : Timestep)
| correctWithGuidance (strategy : GuidanceStrategy shape)
deriving Repr
-- ════════════════════════════════════════════════════════════
-- §8 Verification Examples (AGENTS.md §4 requirement)
-- ════════════════════════════════════════════════════════════
#eval Q1616.ofNat 100
#eval Q1616.sqrt (Q1616.ofNat 4)
#eval GuidanceStrategy.defaultLinear { height := 1, width := 1, channels := 1 } (Q1616.ofNat 1) 1000
end Semantics.DiffusionSNRBias