mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
Density now measured by information-theoretic bounds, not just counts: Shannon entropy H = -Σ p(x) log₂ p(x) over equation symbol distribution - Higher H = more informational diversity = denser content - RG flow bound: H < ln(2⁸) ≈ 2.08 for 8-strand representation Landauer cost E = N·kT·ln(2) where N = distinct math tokens - Each distinct symbol requires erasing energy - kT = 0.025 eV at 290K → ~0.017 eV per bit Density levels: THERMODYNAMIC_SATURATION: both Shannon + Landauer exceed bounds SHANNON_SATURATED: entropy > rgflow fixed-point LANDAUER_EXPENSIVE: energy cost too high COUNT_EXCEEDED: simple count threshold
366 lines
14 KiB
Rust
366 lines
14 KiB
Rust
// Equation Ingestion Pipeline — Rust CLI
|
||
// Markdown → Parse → Classify → Compute → Emit
|
||
// Usage: cargo run --bin ingest -- equations.md
|
||
use std::collections::HashMap;
|
||
use std::fs;
|
||
use std::path::PathBuf;
|
||
use serde::{Deserialize, Serialize};
|
||
use regex::Regex;
|
||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
struct ParsedEquation {
|
||
text: String,
|
||
line: usize,
|
||
is_block: bool,
|
||
classification: String,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
spectral_fingerprint: Option<SpectralFingerprint>,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
struct SpectralFingerprint {
|
||
sigma: f64,
|
||
tau: f64,
|
||
delta: f64,
|
||
lambda_min: i32,
|
||
lambda_max: i32,
|
||
denominator: i32,
|
||
regime: String,
|
||
gap_numerator: i32,
|
||
}
|
||
|
||
#[derive(Serialize, Deserialize)]
|
||
struct DensityReport {
|
||
total_equations: usize,
|
||
classified: usize,
|
||
unknown: usize,
|
||
max_allowed: usize,
|
||
should_pause: bool,
|
||
reason: String,
|
||
shannon_entropy: f64,
|
||
landauer_bits: f64,
|
||
landauer_energy_ev: f64,
|
||
rgflow_bound: f64,
|
||
density_level: String,
|
||
}
|
||
|
||
#[derive(Serialize, Deserialize)]
|
||
struct IngestionReceipt {
|
||
schema: String,
|
||
source_file: String,
|
||
total_parsed: usize,
|
||
total_processed: usize,
|
||
density: DensityReport,
|
||
results: Vec<ParsedEquation>,
|
||
}
|
||
|
||
// ── Chiral weight table (integer rational pairs, zero floats) ─────
|
||
const CHIRAL_WEIGHTS: [(i32, i32); 4] = [(1,1), (1,2), (3,2), (3,2)]; // A,S,L,R
|
||
const CHIRAL_NAMES: [&str; 4] = ["A", "S", "L", "R"];
|
||
|
||
fn parse_markdown(text: &str) -> Vec<ParsedEquation> {
|
||
let mut equations = Vec::new();
|
||
let block_re = Regex::new(r"\$\$(.+?)\$\$").unwrap();
|
||
let inline_re = Regex::new(r"\$(.+?)\$").unwrap();
|
||
|
||
for (i, line) in text.lines().enumerate() {
|
||
for cap in block_re.captures_iter(line) {
|
||
let eq = cap[1].trim().to_string();
|
||
if !eq.is_empty() {
|
||
equations.push(ParsedEquation {
|
||
text: eq, line: i + 1, is_block: true,
|
||
classification: String::new(), spectral_fingerprint: None,
|
||
});
|
||
}
|
||
}
|
||
for cap in inline_re.captures_iter(line) {
|
||
let eq = cap[1].trim().to_string();
|
||
if !eq.is_empty() && !line.contains(&format!("$${}$$", eq)) {
|
||
equations.push(ParsedEquation {
|
||
text: eq, line: i + 1, is_block: false,
|
||
classification: String::new(), spectral_fingerprint: None,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
equations
|
||
}
|
||
|
||
fn classify_equation(eq: &mut ParsedEquation) {
|
||
let text = eq.text.to_lowercase();
|
||
|
||
let spectral_kw = ["sigma", "tau", "delta", "lambda", "spectral", "eigenvalue",
|
||
"gap", "radius", "threshold", "1792", "256", "273", "28",
|
||
"cartan", "sidon", "chiral", "rossby", "kelvin", "braid"];
|
||
let braid_kw = ["braid", "strand", "cross", "sidon", "eigensolid", "yang-baxter"];
|
||
let cartan_kw = ["cartan", "weight", "matrix", "diagonal", "adjacent", "block"];
|
||
|
||
let mut scores = HashMap::new();
|
||
scores.insert("spectral", 0usize);
|
||
scores.insert("braid", 0usize);
|
||
scores.insert("cartan", 0usize);
|
||
|
||
for kw in &spectral_kw {
|
||
if text.contains(kw) { *scores.get_mut("spectral").unwrap() += 1; }
|
||
}
|
||
for kw in &braid_kw {
|
||
if text.contains(kw) { *scores.get_mut("braid").unwrap() += 1; }
|
||
}
|
||
for kw in &cartan_kw {
|
||
if text.contains(kw) { *scores.get_mut("cartan").unwrap() += 1; }
|
||
}
|
||
|
||
let best = scores.iter().max_by_key(|&(_, v)| v).unwrap();
|
||
eq.classification = if *best.1 > 0 { best.0.to_string() } else { "unknown".to_string() };
|
||
}
|
||
|
||
// ── Spectral computation (integer only) ──────────────────────────
|
||
|
||
fn compute_spectral(chiral: &str) -> SpectralFingerprint {
|
||
// chiral is 8 chars of A/S/L/R
|
||
let names: Vec<char> = chiral.chars().collect();
|
||
let pairs = [(0,1), (2,3), (4,5), (6,7)];
|
||
let mut all_lo = Vec::new();
|
||
let mut all_hi = Vec::new();
|
||
|
||
for (a, b) in pairs {
|
||
let ai = CHIRAL_NAMES.iter().position(|&c| c == names[a].to_string()).unwrap_or(0);
|
||
let bi = CHIRAL_NAMES.iter().position(|&c| c == names[b].to_string()).unwrap_or(0);
|
||
let (an, ad) = CHIRAL_WEIGHTS[ai];
|
||
let (bn, bd) = CHIRAL_WEIGHTS[bi];
|
||
// w = 128 × (num_a*den_b + num_b*den_a) / (den_a * den_b)
|
||
let num = 128 * (an * bd + bn * ad);
|
||
let den = ad * bd;
|
||
let w = num / den;
|
||
|
||
all_lo.push(273 + w);
|
||
all_hi.push(273 - w);
|
||
}
|
||
|
||
let lam_max = *all_lo.iter().max().unwrap();
|
||
let lam_min = *all_hi.iter().min().unwrap();
|
||
let d = 1792;
|
||
|
||
let sigma = 273.0 / d as f64;
|
||
let w_avg: i32 = all_lo.iter().sum::<i32>() / all_lo.len() as i32 - 273;
|
||
let tau = w_avg as f64 / d as f64;
|
||
let delta = sigma - tau;
|
||
|
||
let regime = if lam_min < 0 { "ROSSBY" } else if lam_min == 17 { "CANONICAL" } else { "SCARRED" };
|
||
|
||
SpectralFingerprint {
|
||
sigma, tau, delta, lambda_min: lam_min, lambda_max: lam_max,
|
||
denominator: d, regime: regime.to_string(), gap_numerator: lam_min,
|
||
}
|
||
}
|
||
|
||
fn check_density(eqs: &[ParsedEquation], max_eqns: usize, max_unknown: usize) -> DensityReport {
|
||
let total = eqs.len();
|
||
let unknown = eqs.iter().filter(|e| e.classification == "unknown").count();
|
||
|
||
// ── Shannon Entropy: H = -Σ p(x) log₂ p(x) ──────────────────
|
||
// Entropy over the equation text symbol distribution.
|
||
// Higher H = more informational diversity = denser content.
|
||
let full_text: String = eqs.iter().map(|e| &e.text).fold(String::new(), |a, b| a + b);
|
||
let mut freq = [0usize; 256];
|
||
for b in full_text.bytes() { freq[b as usize] += 1; }
|
||
let total_bytes = full_text.len().max(1) as f64;
|
||
let shannon: f64 = freq.iter()
|
||
.filter(|&&c| c > 0)
|
||
.map(|&c| { let p = c as f64 / total_bytes; -p * p.log2() })
|
||
.sum();
|
||
|
||
// ── Landauer Cost: E = kT·ln(2) × unique_terms ──────────────
|
||
// Landauer (1961): erasing N bits costs N·kT·ln(2) energy.
|
||
// Each distinct mathematical symbol/operator is a "bit" of
|
||
// computational state that must be erased.
|
||
// kT ≈ 0.025 eV at room temp → Landauer energy per bit.
|
||
let kT_eV = 0.025; // eV at 290K
|
||
let ln2 = 0.693147;
|
||
let landauer_per_bit = kT_eV * ln2; // ≈ 0.017 eV/bit
|
||
|
||
// Count distinct mathematical symbols/tokens
|
||
let math_tokens = Regex::new(r"[\\a-z]+|\d+|[+\-*/=<>\[\]{}()∫∑∏∂∇√∞π]").unwrap();
|
||
let mut terms = std::collections::HashSet::new();
|
||
for eq in eqs {
|
||
for m in math_tokens.find_iter(&eq.text) {
|
||
terms.insert(m.as_str().to_string());
|
||
}
|
||
}
|
||
let landauer_bits = terms.len() as f64;
|
||
let landauer_energy = landauer_bits * landauer_per_bit;
|
||
|
||
// ── RGFlow Entropy Bound ──────────────────────────────────────
|
||
// Renormalization group flow: entropy decreases monotonically
|
||
// under coarse-graining. The RG fixed-point occurs at H = ln(2⁸) ≈ 5.545
|
||
// for the 8-strand system (8 bits of address space).
|
||
// Equation sets exceeding this entropy need RG coarse-graining
|
||
// (information compression) before they can be reliably classified.
|
||
let rgflow_bound = (8.0_f64).ln(); // ln(2⁸) ≈ 5.545
|
||
|
||
// ── Decision ──────────────────────────────────────────────────
|
||
let exceeds_shannon = shannon > rgflow_bound;
|
||
let exceeds_landauer = landauer_bits > (max_eqns as f64 * 3.0);
|
||
let exceeds_count = total > max_eqns || unknown > max_unknown;
|
||
let should_pause = exceeds_shannon || exceeds_landauer || exceeds_count;
|
||
|
||
let density_level = if exceeds_shannon && exceeds_landauer {
|
||
"THERMODYNAMIC_SATURATION"
|
||
} else if exceeds_shannon {
|
||
"SHANNON_SATURATED"
|
||
} else if exceeds_landauer {
|
||
"LANDAUER_EXPENSIVE"
|
||
} else if exceeds_count {
|
||
"COUNT_EXCEEDED"
|
||
} else {
|
||
"PROCESSABLE"
|
||
};
|
||
|
||
DensityReport {
|
||
total_equations: total,
|
||
classified: total - unknown,
|
||
unknown,
|
||
max_allowed: max_eqns,
|
||
should_pause,
|
||
reason: if exceeds_shannon {
|
||
format!("Shannon entropy {:.2} > rgflow bound {:.2} — information-saturated", shannon, rgflow_bound)
|
||
} else if exceeds_landauer {
|
||
format!("Landauer cost {:.0} bits > threshold — too expensive to auto-process", landauer_bits)
|
||
} else if exceeds_count {
|
||
if total > max_eqns { format!("too many equations ({} > {})", total, max_eqns) }
|
||
else { format!("too many unknowns ({} > {})", unknown, max_unknown) }
|
||
} else {
|
||
"proceed".to_string()
|
||
},
|
||
shannon_entropy: (shannon * 100.0).round() / 100.0,
|
||
landauer_bits,
|
||
landauer_energy_ev: (landauer_energy * 1000.0).round() / 1000.0,
|
||
rgflow_bound: (rgflow_bound * 100.0).round() / 100.0,
|
||
density_level: density_level.to_string(),
|
||
}
|
||
}
|
||
|
||
fn write_decision_doc(input: &PathBuf, eqs: &[ParsedEquation], density: &DensityReport) -> PathBuf {
|
||
let out = input.with_extension("decision.md");
|
||
let mut lines = vec![
|
||
format!("# Equation Pipeline — Decision Required\n"),
|
||
format!("**File:** `{}`", input.display()),
|
||
format!("**Date:** auto-generated\n"),
|
||
format!("## Density Report\n"),
|
||
format!("| Metric | Value |"),
|
||
format!("|--------|-------|"),
|
||
format!("| Total equations | {} |", density.total_equations),
|
||
format!("| Classified | {} |", density.classified),
|
||
format!("| Unknown | {} |", density.unknown),
|
||
format!("| Max auto-process | {} |\n", density.max_allowed),
|
||
format!("**Reason for pause:** {}\n", density.reason),
|
||
format!("## Detected Equations\n"),
|
||
format!("| Line | Type | Classification | Equation |"),
|
||
format!("|------|------|---------------|----------|"),
|
||
];
|
||
|
||
for eq in eqs {
|
||
let preview: String = eq.text.chars().take(60).collect();
|
||
let more = if eq.text.len() > 60 { "..." } else { "" };
|
||
lines.push(format!("| {} | {} | {} | `{}{}` |",
|
||
eq.line,
|
||
if eq.is_block { "block" } else { "inline" },
|
||
eq.classification,
|
||
preview, more));
|
||
}
|
||
|
||
lines.push(format!("\nRun with `--force` to process anyway."));
|
||
fs::write(&out, lines.join("\n")).unwrap();
|
||
out
|
||
}
|
||
|
||
// ── Main ──────────────────────────────────────────────────────────
|
||
|
||
fn main() {
|
||
let args: Vec<String> = std::env::args().collect();
|
||
if args.len() < 2 {
|
||
eprintln!("Usage: {} <equations.md> [--force] [--max-eqns N]", args[0]);
|
||
std::process::exit(1);
|
||
}
|
||
|
||
let input = PathBuf::from(&args[1]);
|
||
let force = args.contains(&"--force".to_string());
|
||
let classified_only = args.contains(&"--classified-only".to_string());
|
||
let max_eqns = args.iter().position(|a| a == "--max-eqns")
|
||
.and_then(|i| args.get(i+1))
|
||
.and_then(|s| s.parse().ok())
|
||
.unwrap_or(20);
|
||
|
||
let text = fs::read_to_string(&input).unwrap_or_else(|e| {
|
||
eprintln!("Error reading {}: {}", input.display(), e);
|
||
std::process::exit(1);
|
||
});
|
||
|
||
let mut equations = parse_markdown(&text);
|
||
println!("Parsed {} equations from {}", equations.len(), input.display());
|
||
|
||
for eq in &mut equations { classify_equation(eq); }
|
||
|
||
let spectral = equations.iter().filter(|e| e.classification == "spectral").count();
|
||
let braid = equations.iter().filter(|e| e.classification == "braid").count();
|
||
let cartan = equations.iter().filter(|e| e.classification == "cartan").count();
|
||
let unknown = equations.iter().filter(|e| e.classification == "unknown").count();
|
||
println!(" Spectral: {}, Braid: {}, Cartan: {}, Unknown: {}", spectral, braid, cartan, unknown);
|
||
|
||
let density = check_density(&equations, max_eqns, 5);
|
||
if density.should_pause && !force {
|
||
let doc = write_decision_doc(&input, &equations, &density);
|
||
println!("\n⚠️ Too dense — wrote decision document:");
|
||
println!(" {}", doc.display());
|
||
println!(" Review and re-run with --force to proceed.");
|
||
return;
|
||
}
|
||
|
||
if classified_only {
|
||
equations.retain(|e| e.classification != "unknown");
|
||
println!("Processing {} classified equations", equations.len());
|
||
}
|
||
|
||
// Compute spectral fingerprints
|
||
for eq in &mut equations {
|
||
if eq.classification == "unknown" { continue; }
|
||
|
||
let chiral = if eq.text.to_lowercase().contains("rossby") ||
|
||
eq.text.to_lowercase().contains("chiral") {
|
||
"LLLLLLLL"
|
||
} else if eq.text.to_lowercase().contains("scarred") {
|
||
"SSSSSSSS"
|
||
} else {
|
||
"AAAAAAAA"
|
||
};
|
||
|
||
eq.spectral_fingerprint = Some(compute_spectral(chiral));
|
||
}
|
||
|
||
let processed = equations.iter().filter(|e| e.spectral_fingerprint.is_some()).count();
|
||
let total = equations.len();
|
||
let receipt = IngestionReceipt {
|
||
schema: "equation_ingestion_v1".to_string(),
|
||
source_file: input.display().to_string(),
|
||
total_parsed: total,
|
||
total_processed: processed,
|
||
density,
|
||
results: equations,
|
||
};
|
||
|
||
let out = input.with_extension("receipt.json");
|
||
fs::write(&out, serde_json::to_string_pretty(&receipt).unwrap()).unwrap();
|
||
println!("\n✅ Pipeline complete");
|
||
println!(" Processed: {}/{} equations", processed, total);
|
||
println!(" Receipt: {}", out.display());
|
||
|
||
let computed: Vec<_> = receipt.results.iter().filter(|e| e.spectral_fingerprint.is_some()).collect();
|
||
if !computed.is_empty() {
|
||
for eq in computed {
|
||
let fp = eq.spectral_fingerprint.as_ref().unwrap();
|
||
println!(" [{}] λ=[{}, {}] σ={:.6} τ={:.6} ∆={:.6} {}",
|
||
eq.classification, fp.lambda_min, fp.lambda_max,
|
||
fp.sigma, fp.tau, fp.delta, fp.regime);
|
||
}
|
||
}
|
||
}
|