Research-Stack/0-Core-Formalism/lean/Semantics/BindServer.lean

401 lines
14 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.

import Semantics.Bind
import Semantics.FixedPoint
import Semantics.Physics.Boundary
import Semantics.Physics.Conservation
import Semantics.Physics.BindPhysics
import Lean.Data.Json
namespace BindServer
open Lean Semantics Semantics.Physics
-- ============================================================================
-- JSON helpers
-- ============================================================================
def jsonObj (fields : List (String × Json)) : Json :=
Json.mkObj fields
@[inline]
def q16_16_of_float (f : Float) : UInt32 :=
if f.isNaN || f ≥ 32768.0 then 0xFFFFFFFF
else if f ≤ -32768.0 then 0x80000000
else (f * 65536.0).floor.toUInt32
@[inline]
def q16_16_to_float (u : UInt32) : Float :=
let signed : Int := if u ≥ 0x80000000 then (Int.ofNat (u.toUInt64.toNat) - 0x100000000) else Int.ofNat (u.toUInt64.toNat)
Float.ofInt signed / 65536.0
@[inline]
def jsonToQ16_16 (j : Json) : Except String Q16_16 :=
match j.getNum? with
| .ok n => .ok (Q16_16.ofFloat n.toFloat)
| .error _ => match j.getInt? with
| .ok n => .ok (Q16_16.ofInt n)
| .error e => .error e
def parseQ16_16Dict (j : Json) : Except String (List (String × Q16_16)) := do
let obj ← j.getObj?
obj.toList.mapM (fun (k, v) => do let q ← jsonToQ16_16 v; return (k, q))
def parseQ16_16List (j : Json) : Except String (List Q16_16) := do
let arr ← match j.getArr? with
| .ok a => .ok a
| .error _ => do
let obj ← j.getObjVal? "state_vector"
obj.getArr?
arr.toList.mapM jsonToQ16_16
@[inline]
def parseString (j : Json) : Except String String :=
j.getStr?
-- Quantity kind parsing
@[inline]
def parseQuantityKind (s : String) : QuantityKind :=
match s with
| "charge" => .charge
| "mass" => .mass
| "spin" => .spin
| "energy" => .energy
| "momentum" => .momentum
| "baryonNumber" => .baryonNumber
| "leptonNumber" => .leptonNumber
| _ => .charge
-- Simplified particle kind aliases for the bridge API
@[inline]
def parseParticleKind (s : String) : Except String ParticleKind :=
match s with
| "electron" => .ok (.lepton .electron false)
| "positron" => .ok (.lepton .electron true)
| "photon" => .ok (.gauge .photon)
| "proton" => .ok (.hadron .proton)
| "neutron" => .ok (.hadron .neutron)
| "neutrino" => .ok (.lepton .eNeutrino false)
| "up_quark" => .ok (.quark .up .red false)
| "down_quark" => .ok (.quark .down .blue false)
| _ => .error s!"Unknown particle kind: {s}"
def parseQuantity (k : String) (v : Json) : Except String Quantity := do
let n ← v.getInt?
return { kind := parseQuantityKind k, value := n }
def parseQuantities (j : Json) : Except String (List Quantity) := do
let obj ← j.getObj?
obj.toList.mapM (fun (k, v) => parseQuantity k v)
def parseParticle (j : Json) : Except String Particle := do
let kindJson ← j.getObjVal? "kind"
let kindStr ← parseString kindJson
let kind ← parseParticleKind kindStr
let quantities ← match j.getObjVal? "quantities" with
| .ok q => parseQuantities q
| .error _ => .ok []
return { kind := kind, quantities := quantities }
def parseParticles (j : Json) : Except String (List Particle) := do
-- Allow either a direct array or {"particles": [...]}
let arr ← match j.getArr? with
| .ok a => .ok a
| .error _ => do
let obj ← j.getObjVal? "particles"
obj.getArr?
arr.toList.mapM parseParticle
-- Float fallback: try JsonNumber first, then Int
@[inline]
def jsonToFloat (j : Json) : Except String Float :=
match j.getNum? with
| .ok n => .ok n.toFloat
| .error _ => match j.getInt? with
| .ok n => .ok (Float.ofInt n)
| .error e => .error e
def parseFloatDict (j : Json) : Except String (List (String × Float)) := do
let obj ← j.getObj?
obj.toList.mapM (fun (k, v) => do let f ← jsonToFloat v; return (k, f))
def parseFloatList (j : Json) : Except String (List Float) := do
-- Allow either a direct array or {"state_vector": [...]}
let arr ← match j.getArr? with
| .ok a => .ok a
| .error _ => do
let obj ← j.getObjVal? "state_vector"
obj.getArr?
arr.toList.mapM jsonToFloat
-- ============================================================================
-- Cost functions implemented in Lean (Q16.16 fixed-point)
-- ============================================================================
@[inline]
def euclideanCost (left right : List Q16_16) : UInt32 :=
let n := max left.length right.length
let a := left ++ List.replicate (n - left.length) Q16_16.zero
let b := right ++ List.replicate (n - right.length) Q16_16.zero
let sumSq := (List.zip a b).foldl (fun acc (x, y) => Q16_16.add acc (Q16_16.mul (Q16_16.sub x y) (Q16_16.sub x y))) Q16_16.zero
(Q16_16.sqrt sumSq).val
@[inline]
def klCost (left right : List (String × Float)) : UInt32 :=
-- log requires fixed-point lookup table or series expansion.
-- Keeping Float computation until Q16.16 log is implemented.
let total := left.foldl (fun acc (k, p) =>
let q := match right.lookup k with | some v => v | none => 1e-12
if p > 0.0 then acc + p * (Float.log (p / max q 1e-12)) else acc
) 0.0
q16_16_of_float total
@[inline]
def thermodynamicCost (left right :List (String × Q16_16)) : UInt32 :=
let entropyL := match left.lookup "entropy" with | some v => v | none => Q16_16.zero
let entropyR := match right.lookup "entropy" with | some v => v | none => Q16_16.zero
let temp := match left.lookup "temperature" with | some v => v | none => Q16_16.ofNat 300
let deltaS := Q16_16.sub entropyL entropyR
let kB := Q16_16.ofFloat 8.617e-5 -- Boltzmann constant in Q16.16
(Q16_16.abs (Q16_16.mul (Q16_16.mul deltaS temp) kB)).val
@[inline]
def controlCost (left right : List (String × Q16_16)) : UInt32 :=
let obs := match left.lookup "observation" with | some v => v | none => Q16_16.zero
let target := match right.lookup "setpoint" with | some v => v | none => Q16_16.zero
(Q16_16.abs (Q16_16.sub obs target)).val
@[inline]
def geodesicCost (left right : List Q16_16) (metric : Metric) : UInt32 :=
if metric.tensor == "identity" then
euclideanCost left right
else
let n := max left.length right.length
let a := left ++ List.replicate (n - left.length) Q16_16.zero
let b := right ++ List.replicate (n - right.length) Q16_16.zero
let scale := Q16_16.add Q16_16.one ⟨metric.cost⟩
let torsionPenalty := Q16_16.mul ⟨metric.torsion⟩ (Q16_16.ofFloat (3.1415926535 / 8.0))
let indices := List.range a.length
let dist := (List.zip a indices).foldl (fun acc (x, i) =>
let y := b.getD i Q16_16.zero
let delta := Q16_16.mul (Q16_16.sub x y) scale
let torsion := Q16_16.mul torsionPenalty (Q16_16.sin (Q16_16.ofInt i))
Q16_16.add acc (Q16_16.add (Q16_16.mul delta delta) (Q16_16.mul torsion torsion))
) Q16_16.zero
(Q16_16.sqrt dist).val
-- ============================================================================
-- Request / Response
-- ============================================================================
instance : Lean.FromJson UInt32 where
fromJson? j := match j.getNat? with | .ok n => .ok n.toUInt32 | .error e => .error e
instance : Lean.ToJson UInt32 where
toJson u := Json.num (Lean.JsonNumber.fromNat u.toNat)
structure BindRequest where
metricKind : String
left : Json
right : Json
useHistory : Bool := false
historyLen : Nat := 0
historyCost : UInt32 := 0x00000000
historyTorsion : UInt32 := 0x00000000
deriving FromJson, ToJson
structure BindResponse where
cost : UInt32
lawful : Bool
leftInvariant : String
rightInvariant : String
traceHash : String
metricTensor : String
metricTorsion : UInt32
metricHistoryLen : Nat
deriving ToJson
@[inline]
def buildMetric (req : BindRequest) : Metric :=
if req.useHistory && req.historyLen >= 2 then
{ cost := req.historyCost, tensor := req.metricKind, torsion := req.historyTorsion, reference := s!"nlocal_from_{req.historyLen}_binds", history_len := req.historyLen }
else
{ cost := 0x00000000, tensor := req.metricKind, torsion := 0x00000000, reference := "euclidean_baseline", history_len := req.historyLen }
@[inline]
def genericInvariant (j : Json) : String :=
j.compress
-- ============================================================================
-- Handlers
-- ============================================================================
def handlePhysical (req : BindRequest) : Except String BindResponse := do
let leftParticles ← parseParticles req.left
let rightParticles ← parseParticles req.right
let metric := buildMetric req
let invL := particleInvariant leftParticles
let invR := particleInvariant rightParticles
let b := physicalBindEval leftParticles rightParticles metric
return {
cost := b.cost,
lawful := b.lawful,
leftInvariant := invL,
rightInvariant := invR,
traceHash := b.witness.trace_hash,
metricTensor := metric.tensor,
metricTorsion := metric.torsion,
metricHistoryLen := metric.history_len
}
def handleInformational (req : BindRequest) : Except String BindResponse := do
let leftDict ← parseFloatDict req.left
let rightDict ← parseFloatDict req.right
let metric := buildMetric req
let cost := klCost leftDict rightDict
let invL := genericInvariant req.left
let invR := genericInvariant req.right
let lawful := invL == invR
return {
cost := cost,
lawful := lawful,
leftInvariant := invL,
rightInvariant := invR,
traceHash := if lawful then s!"lawful:{invL}={invR}" else "unlawful",
metricTensor := metric.tensor,
metricTorsion := metric.torsion,
metricHistoryLen := metric.history_len
}
def handleGeometric (req : BindRequest) : Except String BindResponse := do
let leftVec ← parseQ16_16List req.left
let rightVec ← parseQ16_16List req.right
let metric := buildMetric req
let cost := geodesicCost leftVec rightVec metric
let invL := genericInvariant req.left
let invR := genericInvariant req.right
let lawful := invL == invR
return {
cost := cost,
lawful := lawful,
leftInvariant := invL,
rightInvariant := invR,
traceHash := if lawful then s!"lawful:{invL}={invR}" else "unlawful",
metricTensor := metric.tensor,
metricTorsion := metric.torsion,
metricHistoryLen := metric.history_len
}
def handleThermodynamic (req : BindRequest) : Except String BindResponse := do
let leftDict ← parseQ16_16Dict req.left
let rightDict ← parseQ16_16Dict req.right
let metric := buildMetric req
let cost := thermodynamicCost leftDict rightDict
let invL := genericInvariant req.left
let invR := genericInvariant req.right
let lawful := invL == invR
return {
cost := cost,
lawful := lawful,
leftInvariant := invL,
rightInvariant := invR,
traceHash := if lawful then s!"lawful:{invL}={invR}" else "unlawful",
metricTensor := metric.tensor,
metricTorsion := metric.torsion,
metricHistoryLen := metric.history_len
}
def handleControl (req : BindRequest) : Except String BindResponse := do
let leftDict ← parseQ16_16Dict req.left
let rightDict ← parseQ16_16Dict req.right
let metric := buildMetric req
let cost := controlCost leftDict rightDict
let invL := genericInvariant req.left
let invR := genericInvariant req.right
let lawful := invL == invR
return {
cost := cost,
lawful := lawful,
leftInvariant := invL,
rightInvariant := invR,
traceHash := if lawful then s!"lawful:{invL}={invR}" else "unlawful",
metricTensor := metric.tensor,
metricTorsion := metric.torsion,
metricHistoryLen := metric.history_len
}
def handleRequest (req : BindRequest) : Except String BindResponse :=
match req.metricKind with
| "physical" => handlePhysical req
| "informational" => handleInformational req
| "geometric" | "riemannian" => handleGeometric req
| "thermodynamic" => handleThermodynamic req
| "control" => handleControl req
| _ => .error s!"Unknown metric kind: {req.metricKind}"
-- ============================================================================
-- Batch handlers
-- ============================================================================
structure BindBatchRequest where
requests : List BindRequest
deriving FromJson
structure BindBatchResponse where
results : List BindResponse
deriving ToJson
def handleBatchRequest (req : BindBatchRequest) : BindBatchResponse :=
{ results := req.requests.map (fun r => match handleRequest r with | .ok resp => resp | .error e => {
cost := 0xFFFFFFFF,
lawful := false,
leftInvariant := "",
rightInvariant := "",
traceHash := s!"error:{e}",
metricTensor := "",
metricTorsion := 0x00000000,
metricHistoryLen := 0
}) }
-- ============================================================================
-- I/O Loop
-- ============================================================================
partial def serve : IO Unit := do
let stdin ← IO.getStdin
let stdout ← IO.getStdout
let line ← stdin.getLine
if line.isEmpty || line == "\n" then
return ()
match Json.parse line with
| .error e =>
stdout.putStrLn (Json.compress (jsonObj [("error", Json.str e)]))
stdout.flush
| .ok j =>
-- Dispatch: if "requests" field exists, treat as batch; else single
let isBatch := match j.getObjVal? "requests" with | .ok _ => true | .error _ => false
if isBatch then
match fromJson? j with
| .error e =>
stdout.putStrLn (Json.compress (jsonObj [("error", Json.str e)]))
stdout.flush
| .ok batchReq =>
let batchResp := handleBatchRequest batchReq
stdout.putStrLn (Json.compress (toJson batchResp))
stdout.flush
else
match fromJson? j with
| .error e =>
stdout.putStrLn (Json.compress (jsonObj [("error", Json.str e)]))
stdout.flush
| .ok req =>
match handleRequest req with
| .error e =>
stdout.putStrLn (Json.compress (jsonObj [("error", Json.str e)]))
stdout.flush
| .ok resp =>
stdout.putStrLn (Json.compress (toJson resp))
stdout.flush
serve
end BindServer
def main : IO Unit := BindServer.serve