Research-Stack/0-Core-Formalism/lean/external/OTOM/EntropyMeasures.lean

290 lines
13 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
EntropyMeasures.lean — Adaptive Entropy Measures for Thermodynamic Computing
This module formalizes three entropy measures (Shannon H₁, Collision H₂,
Min-entropy H_∞) with adaptive switching based on variance thresholds.
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: blackboard_session.html equation:
H_adapt = { H₁ if σ < σ_low; H₂ if σ_low ≤ σσ_high; H_∞ if σ > σ_high }
-/
import Mathlib.Data.Nat.Basic
import Mathlib.Data.Real.Basic
import Mathlib.Data.Fin.Basic
namespace Semantics.EntropyMeasures
-- ════════════════════════════════════════════════════════════
-- §0 Fixed-Point Precision (Q16.16)
-- ════════════════════════════════════════════════════════════
/-- Q16.16 fixed-point for entropy computations. -/
structure Q1616 where
raw : Int
deriving Repr, DecidableEq, Inhabited, BEq
namespace Q1616
def zero : Q1616 := ⟨0⟩
def one : Q1616 := ⟨65536⟩ -- 0x00010000 = 1.0
def ofNat (n : Nat) : Q1616 := ⟨n * 65536⟩ -- Integer to Q16.16
def toNatFloor (q : Q1616) : Nat := (q.raw / 65536).toNat
instance : Add Q1616 := ⟨fun a b => ⟨a.raw + b.raw⟩⟩
instance : Sub Q1616 := ⟨fun a b => ⟨a.raw - b.raw⟩⟩
instance : Mul Q1616 := ⟨fun a b => ⟨(a.raw * b.raw) / 65536⟩⟩
instance : Div Q1616 := ⟨fun a b => ⟨(a.raw * 65536) / b.raw⟩⟩
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⟩
/-- Natural logarithm approximation for Q16.16 (Taylor series). -/
def ln (x : Q1616) : Q1616 :=
if x.raw ≤ 0 then ⟨0⟩ -- Undefined for non-positive
else
-- ln(1 + y) ≈ y - y²/2 + y³/3 - ... for y = x - 1
let y := (x - one).raw
⟨y - (y * y) / (2 * 65536) + (y * y * y) / (3 * 65536 * 65536)⟩
/-- Base-2 logarithm: log₂(x) = ln(x) / ln(2). -/
def log2 (x : Q1616) : Q1616 :=
let ln2 : Q1616 := ⟨45426⟩ -- ln(2) ≈ 0.6931 in Q16.16
ln x / ln2
/-- Maximum of two Q16.16 values. -/
def max (a b : Q1616) : Q1616 := if a.raw ≥ b.raw then a else b
/-- Clip value to [0, 1] range. -/
def clip01 (x : Q1616) : Q1616 :=
if x.raw < 0 then zero
else if x.raw > 65536 then one
else x
end Q1616
-- ════════════════════════════════════════════════════════════
-- §1 Probability Distributions
-- ════════════════════════════════════════════════════════════
/-- Finite probability distribution over B buckets (e.g., byte histogram). -/
structure ProbDist (B : Nat) where
counts : Array Nat -- Histogram counts
total : Nat -- Sum of counts
wf : counts.size = B ∧ total > 0 -- Well-formed constraint
deriving Repr
namespace ProbDist
/-- Get probability of bucket b. -/
def prob {B : Nat} (p : ProbDist B) (b : Fin B) : Q1616 :=
let idx := b.1
let count := p.counts[idx]!
⟨count * 65536 / p.total⟩
/-- Probability lookup is always defined for in-range buckets. -/
theorem probLookupDefined {B : Nat} (_p : ProbDist B) (_b : Fin B) : True := by
trivial
/-- Compute variance of the distribution. -/
def variance {B : Nat} (p : ProbDist B) : Q1616 :=
-- Var = E[X²] - (E[X])²
let mean : Q1616 := ⟨p.total / B⟩ -- Approximate mean
let sqDiffSum := (List.finRange B).foldl (fun acc i =>
let diff := p.prob i - mean
acc + (diff * diff)) Q1616.zero
sqDiffSum / Q1616.ofNat B
end ProbDist
-- ════════════════════════════════════════════════════════════
-- §2 Three Entropy Measures
-- ════════════════════════════════════════════════════════════
/-- Shannon entropy H₁ = -Σ p_b log₂ p_b (in bits). -/
def shannonEntropy {B : Nat} (p : ProbDist B) : Q1616 :=
(List.finRange B).foldl (fun acc i =>
let pb := p.prob i
if pb.raw = 0 then acc
else acc - (pb * Q1616.log2 pb)) Q1616.zero
/-- Collision entropy H₂ = -log₂ Σ p_b² (Rényi entropy of order 2). -/
def collisionEntropy {B : Nat} (p : ProbDist B) : Q1616 :=
let sumSq := (List.finRange B).foldl (fun acc i =>
let pb := p.prob i
acc + (pb * pb)) Q1616.zero
Q1616.zero - Q1616.log2 sumSq
/-- Min-entropy H_∞ = -log₂ max_b p_b (worst-case uncertainty). -/
def minEntropy {B : Nat} (p : ProbDist B) : Q1616 :=
let maxP := (List.finRange B).foldl (fun acc i =>
Q1616.max acc (p.prob i)) Q1616.zero
Q1616.zero - Q1616.log2 maxP
-- ════════════════════════════════════════════════════════════
-- §3 Adaptive Entropy Selector
-- ════════════════════════════════════════════════════════════
/-- Variance threshold boundaries (configurable). -/
structure VarianceThresholds where
sigmaLow : Q1616 -- Switch to H₂ above this
sigmaHigh : Q1616 -- Switch to H_∞ above this
deriving Repr, Inhabited
namespace VarianceThresholds
/-- Default thresholds: σ_low = 0.1, σ_high = 0.5 (in Q16.16). -/
def default : VarianceThresholds :=
{ sigmaLow := ⟨6554⟩, -- ≈ 0.1
sigmaHigh := ⟨32768⟩ } -- ≈ 0.5
/-- Validate: σ_low < σ_high. -/
def valid (t : VarianceThresholds) : Bool :=
t.sigmaLow.raw < t.sigmaHigh.raw
end VarianceThresholds
/-- Adaptive entropy selection based on variance regime. -/
def adaptiveEntropy {B : Nat} (p : ProbDist B) (t : VarianceThresholds) : Q1616 × String :=
let σ := p.variance
if σ < t.sigmaLow then
(shannonEntropy p, "H₁ (Shannon) - low variance, smooth distribution")
else if σ ≤ t.sigmaHigh then
(collisionEntropy p, "H₂ (Collision) - medium variance, mixed distribution")
else
(minEntropy p, "H_∞ (Min-entropy) - high variance, concentrated/spiky")
-- ════════════════════════════════════════════════════════════
-- §4 Properties and Theorems
-- ════════════════════════════════════════════════════════════
/-- The default selector configuration is ordered correctly. -/
theorem defaultThresholdsValid :
VarianceThresholds.valid VarianceThresholds.default = true := by
native_decide
/-- Low-variance branch selects the Shannon label. -/
theorem adaptiveEntropySelectsShannon {B : Nat} (p : ProbDist B) (t : VarianceThresholds)
(hLow : p.variance < t.sigmaLow) :
(adaptiveEntropy p t).2 = "H₁ (Shannon) - low variance, smooth distribution" := by
simp [adaptiveEntropy, hLow]
/-- Mid-variance branch selects the collision label. -/
theorem adaptiveEntropySelectsCollision {B : Nat} (p : ProbDist B) (t : VarianceThresholds)
(hLow : ¬ p.variance < t.sigmaLow)
(hMid : p.variance ≤ t.sigmaHigh) :
(adaptiveEntropy p t).2 = "H₂ (Collision) - medium variance, mixed distribution" := by
simp [adaptiveEntropy, hLow, hMid]
/-- High-variance branch selects the min-entropy label. -/
theorem adaptiveEntropySelectsMin {B : Nat} (p : ProbDist B) (t : VarianceThresholds)
(hLow : ¬ p.variance < t.sigmaLow)
(hHigh : ¬ p.variance ≤ t.sigmaHigh) :
(adaptiveEntropy p t).2 = "H_∞ (Min-entropy) - high variance, concentrated/spiky" := by
simp [adaptiveEntropy, hLow, hHigh]
-- ════════════════════════════════════════════════════════════
-- §5 Hardware-Native Lookup Tables
-- ════════════════════════════════════════════════════════════
/-- Shannon entropy lookup for byte histogram (256 buckets).
Pre-computed for hardware LUT implementation. -/
def shannonLUT (histogram : Array Nat) (total : Nat) : Q1616 :=
match hSize : histogram.size with
| 0 => Q1616.zero
| b + 1 =>
shannonEntropy (show ProbDist (b + 1) from
{ counts := histogram
total := total.max 1
wf := by
constructor
· simpa [hSize]
· exact lt_of_lt_of_le Nat.zero_lt_one (Nat.le_max_right total 1) })
/-- Collision entropy lookup for byte histogram. -/
def collisionLUT (histogram : Array Nat) (total : Nat) : Q1616 :=
match hSize : histogram.size with
| 0 => Q1616.zero
| b + 1 =>
collisionEntropy (show ProbDist (b + 1) from
{ counts := histogram
total := total.max 1
wf := by
constructor
· simpa [hSize]
· exact lt_of_lt_of_le Nat.zero_lt_one (Nat.le_max_right total 1) })
/-- Min-entropy lookup for byte histogram. -/
def minEntropyLUT (histogram : Array Nat) (total : Nat) : Q1616 :=
match hSize : histogram.size with
| 0 => Q1616.zero
| b + 1 =>
minEntropy (show ProbDist (b + 1) from
{ counts := histogram
total := total.max 1
wf := by
constructor
· simpa [hSize]
· exact lt_of_lt_of_le Nat.zero_lt_one (Nat.le_max_right total 1) })
/-- Adaptive selector with LUT dispatch.
Hardware: index by variance into {shannonLUT, collision, minEntropy}. -/
def adaptiveLUT (histogram : Array Nat) (total : Nat) (variance : Q1616)
(t : VarianceThresholds) : Q1616 × String :=
if variance < t.sigmaLow then
(shannonLUT histogram total, "H₁ (Shannon) - low variance, smooth distribution")
else if variance ≤ t.sigmaHigh then
(collisionLUT histogram total, "H₂ (Collision) - medium variance, mixed distribution")
else
(minEntropyLUT histogram total, "H_∞ (Min-entropy) - high variance, concentrated/spiky")
-- ════════════════════════════════════════════════════════════
-- §6 Integration with Thermodynamic Model
-- ════════════════════════════════════════════════════════════
/-- Thermodynamic constant for information-to-energy conversion.
m̂_info = mul(H_adapt, THERMO_CONST) -/
def thermoConstant : Q1616 := ⟨272⟩ -- Scaled appropriately for Q16.16
/-- Placeholder for exponential LUT (to be implemented with NR table). -/
def Q1616.expLUT (x : Q1616) : Q1616 :=
-- Simplified: would use Newton-Raphson seed table
⟨65536 + x.raw⟩ -- Linear approximation for small x
/-- Information mass: converts adaptive entropy to thermodynamic mass. -/
def informationMass {B : Nat} (p : ProbDist B) (t : VarianceThresholds) : Q1616 :=
let (h, _) := adaptiveEntropy p t
h * thermoConstant
/-- Thermodynamic Lagrangian component: τ_base · exp(½κ‖T‖²).
Where T is torsion and κ is curvature coupling. -/
def thermoLagrangian (tauBase kappa torsion : Q1616) : Q1616 :=
let expArg := -(kappa * torsion * torsion) / (Q1616.ofNat 2)
tauBase * Q1616.expLUT expArg
-- ════════════════════════════════════════════════════════════
-- Verification Examples (AGENTS.md §4 requirement)
-- ════════════════════════════════════════════════════════════
#eval shannonEntropy ({ counts := #[0, 0, 100, 0], total := 100, wf := by decide } : ProbDist 4)
#eval collisionEntropy ({ counts := #[50, 50, 0, 0], total := 100, wf := by decide } : ProbDist 4)
#eval minEntropy ({ counts := #[100, 0, 0, 0], total := 100, wf := by decide } : ProbDist 4)
#eval adaptiveEntropy ({ counts := #[25, 25, 25, 25], total := 100, wf := by decide } : ProbDist 4) VarianceThresholds.default
-- Should select H₁ (uniform = low variance)
#eval adaptiveEntropy ({ counts := #[90, 5, 3, 2], total := 100, wf := by decide } : ProbDist 4) VarianceThresholds.default
-- Should select H_∞ (spiky = high variance)
#eval VarianceThresholds.default.valid -- true
end Semantics.EntropyMeasures