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

96 lines
3.6 KiB
Text

/- 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
SpectralField.lean — Local Field Accumulation and Interaction Metrics
Per AGENTS.md §2: PascalCase for types, camelCase for functions.
Lean 4 is the source of truth.
-/
import Semantics.FixedPoint
import Semantics.GeneticCode
import Semantics.ShellModel
import Semantics.Spectrum
namespace Semantics
open Semantics.GeneticCode
open Semantics.ShellModel
open Semantics.Spectrum
/-- Local field aggregates mass, polarity, and spectral contributions from a neighborhood. -/
structure LocalField where
massField : Q16_16
polarityField : Q16_16
spectrum : SpectralSignature
deriving Repr, DecidableEq
/-- Zero field (neutral element for accumulation). -/
def zeroField : LocalField :=
{ massField := Q16_16.zero
, polarityField := Q16_16.zero
, spectrum := SpectralSignature.empty }
/-- Add two fields (piecewise summation). -/
def addField (x y : LocalField) : LocalField :=
{ massField := Q16_16.add x.massField y.massField
, polarityField := Q16_16.add x.polarityField y.polarityField
, spectrum := x.spectrum.piecewiseMerge y.spectrum }
/-- Compute contribution of an event at distance d to a local field. -/
def fieldContribution (w : Q16_16) (tip : TipCoord) (col : SpectralSignature) : LocalField :=
{ massField := Q16_16.mul w (Q16_16.ofInt tip.mass)
, polarityField := Q16_16.mul w (Q16_16.ofInt tip.polarity)
, spectrum := { bins := col.bins.map (λ b => Q16_16.mul w b) } }
/-- Build local field at position n by looking up to maxN. -/
partial def buildFieldAtLoop (n maxN : Nat) (m : Nat) (acc : LocalField) : LocalField :=
if m > maxN then
acc
else
let acc' :=
if m > n then
let d := m - n
let w := tailWeight d
match eventAt m with
| some (_, _, tip, col) =>
if w.val.toNat = 0 then acc else addField acc (fieldContribution w tip col)
| none => acc
else acc
buildFieldAtLoop n maxN (m+1) acc'
def buildFieldAt (n maxN : Nat) : LocalField :=
buildFieldAtLoop n maxN (n+1) zeroField
/-- Compute interaction score between a tip and a local field. -/
def interactionScore (tip : TipCoord) (field : LocalField) (col : SpectralSignature) : Q16_16 :=
let massTerm := Q16_16.mul (Q16_16.ofInt tip.mass) field.massField
let polTerm := Q16_16.mul (Q16_16.ofInt tip.polarity) field.polarityField
let specTerm := SpectralSignature.spectralOverlap col field.spectrum
Q16_16.add (Q16_16.add massTerm polTerm) specTerm
/-- Interaction score with only spectral component. -/
def spectralInteractionOnly (sig1 sig2 : SpectralSignature) : Q16_16 :=
SpectralSignature.spectralOverlap sig1 sig2
/-- Compute field magnitude (L2 norm approximation). -/
def fieldMagnitude (field : LocalField) : Q16_16 :=
let m2 := Q16_16.mul field.massField field.massField
let p2 := Q16_16.mul field.polarityField field.polarityField
let sum := Q16_16.add m2 p2
if field.massField.val.toNat > field.polarityField.val.toNat then
Q16_16.div sum (Q16_16.add field.massField (Q16_16.ofInt 1))
else
Q16_16.div sum (Q16_16.add field.polarityField (Q16_16.ofInt 1))
/-- Check if field is non-trivial. -/
def fieldIsActive (field : LocalField) : Bool :=
field.massField.val.toNat ≠ 0 || field.polarityField.val.toNat ≠ 0 ||
field.spectrum.bins.any (λ b => b.val.toNat ≠ 0)
-- Verification
#eval buildFieldAt 1 10
#eval spectralInteractionOnly (SpectralSignature.eventSpectrum EventType.a) (SpectralSignature.eventSpectrum EventType.a)
end Semantics