Research-Stack/0-Core-Formalism/lean/Semantics/Semantics/TopologicalPersistence.lean
2026-05-05 21:09:48 -05:00

139 lines
5.7 KiB
Text

import Semantics.Bind
import Semantics.FixedPoint
namespace Semantics.TopologicalPersistence
open Semantics.Q16_16
open Semantics.Q16_16
-- =========================================================================
-- 1. Persistence Interval
-- =========================================================================
/-- A persistence interval (birth, death) in Q0_16 normalized units.
birth < death for valid intervals.
In neural compression: birth = threshold when feature appears,
death = threshold when feature disappears. -/
structure PersistentInterval where
birth : Q0_16
death : Q0_16
deriving Repr, BEq, Inhabited
/-- Persistence = death - birth. Longer = more robust feature. -/
def persistence (interval : PersistentInterval) : Q0_16 :=
Q0_16.sub interval.death interval.birth
/-- A barcode is a list of persistence intervals.
Represents the topological signature of a dataset. -/
def Barcode := List PersistentInterval
deriving Repr, BEq, Inhabited
-- =========================================================================
-- 2. Barcode Metrics
-- =========================================================================
/-- Total persistence: sum of all interval lengths, promoted to Q16_16.
Uses raw-value promotion (not semantic conversion) because this is
an accumulator that may exceed Q0_16 range [-1, 1]. -/
def totalPersistence (barcode : Barcode) : Q16_16 :=
barcode.foldl (λ acc interval =>
let p := persistence interval
Q16_16.add acc (Q16_16.ofNat p.val.toNat)
) (Q16_16.ofNat 0)
/-- Count features with persistence above threshold. -/
def significantFeatures (barcode : Barcode) (threshold : Q0_16) : Nat :=
barcode.foldl (λ count interval =>
let p := persistence interval
if p.val ≥ threshold.val then count + 1 else count
) 0
/-- Bottleneck distance: max difference between matched interval persistences.
For #eval demo: pairs by position, computes max |p1 - p2|.
Full TDA would use optimal matching (Hungarian); this is an upper bound. -/
def bottleneckDistance (b1 b2 : Barcode) : Q16_16 :=
let pairs := b1.zip b2
pairs.foldl (λ maxDiff pair =>
let (i1, i2) := pair
let p1 := (persistence i1).val.toNat
let p2 := (persistence i2).val.toNat
let diff := if p1 ≥ p2 then p1 - p2 else p2 - p1
let diffQ := Q16_16.ofNat diff
if diffQ.val > maxDiff.val then diffQ else maxDiff
) (Q16_16.ofNat 0)
-- =========================================================================
-- 3. Topological Invariant Extractor (for bind)
-- =========================================================================
/-- Canonical string invariant for geometricBind.
Format: count=<n>;total=<raw> -/
def barcodeInvariant (b : Barcode) : String :=
let count := b.length
let total := totalPersistence b
s!"count={count};total={total.val}"
-- =========================================================================
-- 4. Cost Function
-- =========================================================================
/-- Cost = bottleneck distance between original and compressed barcodes.
Lower cost = more topologically similar. -/
def barcodeCost (original compressed : Barcode) (_metric : Metric) : Q16_16 :=
bottleneckDistance original compressed
-- =========================================================================
-- 5. geometricBind Instance
-- =========================================================================
/-- Bind two barcodes geometrically.
Lawful iff their canonical invariants match exactly.
Cost = bottleneck distance. -/
def topologicalBind (original compressed : Barcode) (metric : Metric) : Bind Barcode Barcode :=
geometricBind original compressed metric barcodeCost barcodeInvariant barcodeInvariant
-- =========================================================================
-- 6. Verification Theorems
-- =========================================================================
/-- Theorem: A barcode bound to itself is lawful.
Identity bind preserves exact invariants. -/
theorem topologicalBind_selfLawful (b : Barcode) (metric : Metric) :
(topologicalBind b b metric).lawful = true := by
simp [topologicalBind, geometricBind, bind, barcodeInvariant]
/-- Theorem: A barcode bound to itself produces zero bottleneck cost.
Proven by native_decide on a concrete barcode witness. -/
theorem barcodeDistance_selfZero (b : Barcode)
(h : b = [
{ birth := ⟨0x1000⟩, death := ⟨0x7000⟩ },
{ birth := ⟨0x2000⟩, death := ⟨0x6000⟩ }
]) :
bottleneckDistance b b = Q16_16.ofNat 0 := by
rw [h]
native_decide
-- =========================================================================
-- 7. Witness Examples
-- =========================================================================
/-- Sample barcode: 3 features with varying persistence. -/
def sampleBarcode1 : Barcode := [
{ birth := ⟨0x1000⟩, death := ⟨0x7000⟩ }, -- persistence ≈ 0.75 (raw 0x6000)
{ birth := ⟨0x2000⟩, death := ⟨0x6000⟩ }, -- persistence ≈ 0.50 (raw 0x4000)
{ birth := ⟨0x3000⟩, death := ⟨0x5000⟩ } -- persistence ≈ 0.25 (raw 0x2000)
]
/-- Sample barcode 2: same first feature, second feature merged (persistence reduced). -/
def sampleBarcode2 : Barcode := [
{ birth := ⟨0x1000⟩, death := ⟨0x7000⟩ }, -- unchanged
{ birth := ⟨0x2500⟩, death := ⟨0x5500⟩ } -- persistence ≈ 0.19 (raw 0x3000)
]
#eval totalPersistence sampleBarcode1
#eval significantFeatures sampleBarcode1 ⟨0x1000⟩
#eval bottleneckDistance sampleBarcode1 sampleBarcode2
#eval (topologicalBind sampleBarcode1 sampleBarcode2 Metric.euclidean).cost
#eval (topologicalBind sampleBarcode1 sampleBarcode2 Metric.euclidean).lawful
end Semantics.TopologicalPersistence