mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
337 lines
12 KiB
Python
337 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
"""ln(2) ladder-chart invariant probe.
|
|
|
|
This fixture records a small, exact example of the ladder model: one invariant
|
|
object, ln(2), observed through several lawful charts. It also records the
|
|
projection guardrails: infinite sum/integral exchange and endpoint convergence
|
|
must be justified, and symbolic/rhythmic shadows are not proof by themselves.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
import math
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
REPO = Path(__file__).resolve().parents[2]
|
|
OUT_DIR = REPO / "shared-data" / "data" / "ln2_ladder_chart_invariant"
|
|
REGISTRY = OUT_DIR / "ln2_ladder_chart_invariant_registry.json"
|
|
RECEIPT = OUT_DIR / "ln2_ladder_chart_invariant_receipt.json"
|
|
SUMMARY = OUT_DIR / "ln2_ladder_chart_invariant.md"
|
|
TIDDLER = REPO / "6-Documentation" / "tiddlywiki-local" / "wiki" / "tiddlers" / "ln2 Ladder Chart Invariant.tid"
|
|
|
|
SOURCE_REFS = [
|
|
REPO / "shared-data" / "data" / "observer_chart_projection_guardrail" / "observer_chart_projection_guardrail_receipt.json",
|
|
REPO / "shared-data" / "data" / "collatz_ladder_shadow_filter" / "collatz_ladder_shadow_filter_receipt.json",
|
|
REPO / "shared-data" / "data" / "underverse_variant_accounting" / "underverse_variant_accounting_receipt.json",
|
|
REPO / "6-Documentation" / "docs" / "specs" / "FORWARD_FOUNDATION_EQUATION_COMPILER.md",
|
|
]
|
|
|
|
LN2 = math.log(2.0)
|
|
TOL = 1.0e-12
|
|
|
|
|
|
def stable_json(obj: Any) -> str:
|
|
return json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
|
|
|
|
|
|
def sha256_bytes(data: bytes) -> str:
|
|
return hashlib.sha256(data).hexdigest()
|
|
|
|
|
|
def hash_obj(obj: Any) -> str:
|
|
return sha256_bytes(stable_json(obj).encode("utf-8"))
|
|
|
|
|
|
def rel(path: Path) -> str:
|
|
try:
|
|
return str(path.relative_to(REPO))
|
|
except ValueError:
|
|
return str(path)
|
|
|
|
|
|
def file_hash(path: Path) -> str | None:
|
|
return sha256_bytes(path.read_bytes()) if path.exists() else None
|
|
|
|
|
|
def source_ref(path: Path) -> dict[str, Any]:
|
|
return {"path": rel(path), "exists": path.exists(), "sha256": file_hash(path)}
|
|
|
|
|
|
def alternating_harmonic(partials: int) -> float:
|
|
return sum(((-1.0) ** n) / (n + 1) for n in range(partials))
|
|
|
|
|
|
def unit_interval_midpoint(samples: int) -> float:
|
|
step = 1.0 / samples
|
|
return sum(step / (1.0 + (i + 0.5) * step) for i in range(samples))
|
|
|
|
|
|
def chart_entry(
|
|
chart_id: str,
|
|
projection: str,
|
|
evaluation: str,
|
|
value: float | None,
|
|
decision: str,
|
|
guardrail: str,
|
|
role: str = "lawful_chart",
|
|
) -> dict[str, Any]:
|
|
error = None if value is None else abs(value - LN2)
|
|
entry = {
|
|
"chart_id": chart_id,
|
|
"projection": projection,
|
|
"evaluation": evaluation,
|
|
"value": value,
|
|
"target_ln2": LN2,
|
|
"abs_error": error,
|
|
"decision": decision,
|
|
"guardrail": guardrail,
|
|
"role": role,
|
|
}
|
|
entry["chart_hash"] = hash_obj({k: v for k, v in entry.items() if k != "chart_hash"})
|
|
return entry
|
|
|
|
|
|
def build_registry() -> dict[str, Any]:
|
|
charts = [
|
|
chart_entry(
|
|
"direct_antiderivative",
|
|
"I=int_0^infty 1/(1+e^x) dx",
|
|
"[-log(1+e^-x)]_0^infty = log(2)",
|
|
LN2,
|
|
"ADMIT_EXACT_CHART",
|
|
"improper endpoint limit must be declared",
|
|
),
|
|
chart_entry(
|
|
"exponential_substitution",
|
|
"u=e^-x maps x in [0,infty) to u in [1,0]",
|
|
"I=int_0^1 1/(1+u) du = log(2)",
|
|
LN2,
|
|
"ADMIT_EXACT_CHART",
|
|
"orientation reversal and dx=-du/u must be paid",
|
|
),
|
|
chart_entry(
|
|
"geometric_expansion",
|
|
"1/(1+e^x)=e^-x/(1+e^-x)=sum_n (-1)^n e^{-(n+1)x}",
|
|
"termwise integral gives alternating harmonic series",
|
|
alternating_harmonic(100000),
|
|
"ADMIT_LIMIT_CHART_WITH_JUSTIFICATION",
|
|
"exchange of infinite sum and improper integral requires convergence justification",
|
|
),
|
|
chart_entry(
|
|
"alternating_harmonic_series",
|
|
"sum_{n=0}^infty (-1)^n/(n+1)",
|
|
"Taylor log(1+z) at z=1 gives log(2)",
|
|
alternating_harmonic(100000),
|
|
"ADMIT_LIMIT_CHART_WITH_ENDPOINT_GUARD",
|
|
"endpoint z=1 needs Abel/alternating convergence justification",
|
|
),
|
|
chart_entry(
|
|
"unit_interval_integral",
|
|
"int_0^1 du/(1+u)",
|
|
"midpoint numerical replay over unit chart",
|
|
unit_interval_midpoint(1_000_000),
|
|
"ADMIT_NUMERIC_REPLAY_CHART",
|
|
"numeric replay is evidence only; exact chart is antiderivative",
|
|
),
|
|
chart_entry(
|
|
"parametric_derivative_trick",
|
|
"d/da log(1+a) at a=1 or eta/xi-style derivative route",
|
|
"derivative/integral parameter chart returns log(2) when domain is declared",
|
|
LN2,
|
|
"ADMIT_SYMBOLIC_CHART",
|
|
"parameter domain and derivative-exchange law must be declared",
|
|
),
|
|
chart_entry(
|
|
"music_sheet_shadow",
|
|
"rhythmic or symbolic shadow of the transform ladder",
|
|
"no numeric proof; chart is mnemonic/projection only",
|
|
None,
|
|
"HOLD_SHADOW_ONLY",
|
|
"rhythm-shadow cannot certify the invariant without a lawful adapter",
|
|
role="observer_shadow",
|
|
),
|
|
]
|
|
return {
|
|
"schema": "ln2_ladder_chart_invariant_registry_v1",
|
|
"source_refs": [source_ref(path) for path in SOURCE_REFS],
|
|
"invariant": {
|
|
"id": "ln2",
|
|
"canonical_object": "I=int_0^infty 1/(1+e^x) dx = ln(2)",
|
|
"numeric_value": LN2,
|
|
"short_form": "ln 2 is the invariant; the integral, series, substitution, and rhythm are charts.",
|
|
},
|
|
"claim_boundary": (
|
|
"Toy ladder-chart invariant fixture only. The admitted charts show "
|
|
"that one object can survive lawful projection changes. The fixture "
|
|
"does not admit arbitrary symbolic shadows, unjustified exchange of "
|
|
"limits, or rhythm/music notation as proof."
|
|
),
|
|
"canonical_statement": (
|
|
"A lawful object survives chart changes. A bad derivation loses the "
|
|
"invariant during projection. A good proof states the adapter, pays "
|
|
"the endpoint and limit-exchange costs, and shows every shadow belongs "
|
|
"to the same object."
|
|
),
|
|
"ladder_mapping": {
|
|
"continuous_field_chart": "improper integral",
|
|
"substitution_chart": "unit interval projection",
|
|
"packetized_recursive_chart": "geometric expansion",
|
|
"parity_torsion_chart": "alternating harmonic signs",
|
|
"invariant_attractor": "ln(2)",
|
|
"observer_shadow": "music/rhythm notation, held until adapter exists",
|
|
},
|
|
"charts": charts,
|
|
"chart_root": hash_obj([chart["chart_hash"] for chart in charts]),
|
|
"aggregates": {
|
|
"chart_count": len(charts),
|
|
"admit_count": sum(1 for chart in charts if chart["decision"].startswith("ADMIT")),
|
|
"hold_count": sum(1 for chart in charts if chart["decision"].startswith("HOLD")),
|
|
"max_numeric_error": max(chart["abs_error"] or 0.0 for chart in charts),
|
|
"missing_source_count": sum(1 for path in SOURCE_REFS if not path.exists()),
|
|
},
|
|
"decision": "ADMIT_LN2_LADDER_CHART_FIXTURE_WITH_SHADOW_HOLD",
|
|
}
|
|
|
|
|
|
def build_receipt(registry: dict[str, Any]) -> dict[str, Any]:
|
|
receipt = {
|
|
"schema": "ln2_ladder_chart_invariant_receipt_v1",
|
|
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
|
|
"timestamp_role": "metadata_only",
|
|
"generated_at_utc_included_in_receipt_hash": False,
|
|
"registry": rel(REGISTRY),
|
|
"registry_hash": hash_obj(registry),
|
|
"chart_root": registry["chart_root"],
|
|
"aggregates": registry["aggregates"],
|
|
"decision": registry["decision"],
|
|
"claim_boundary": registry["claim_boundary"],
|
|
}
|
|
receipt["receipt_hash"] = sha256_bytes(
|
|
stable_json({k: v for k, v in receipt.items() if k not in {"receipt_hash", "generated_at_utc"}}).encode("utf-8")
|
|
)
|
|
return receipt
|
|
|
|
|
|
def write_summary(registry: dict[str, Any], receipt: dict[str, Any]) -> None:
|
|
lines = [
|
|
"# ln2 Ladder Chart Invariant",
|
|
"",
|
|
f"Decision: `{receipt['decision']}` ",
|
|
f"Receipt hash: `{receipt['receipt_hash']}`",
|
|
f"Chart root: `{registry['chart_root']}`",
|
|
"",
|
|
registry["claim_boundary"],
|
|
"",
|
|
"## Invariant",
|
|
"",
|
|
registry["invariant"]["short_form"],
|
|
"",
|
|
"## Canonical Statement",
|
|
"",
|
|
registry["canonical_statement"],
|
|
"",
|
|
"## Charts",
|
|
"",
|
|
"| Chart | Projection | Decision | Guardrail |",
|
|
"|---|---|---|---|",
|
|
]
|
|
for chart in registry["charts"]:
|
|
lines.append(
|
|
f"| {chart['chart_id']} | {chart['projection']} | "
|
|
f"{chart['decision']} | {chart['guardrail']} |"
|
|
)
|
|
lines.extend(
|
|
[
|
|
"",
|
|
"## Aggregates",
|
|
"",
|
|
f"- Charts: `{registry['aggregates']['chart_count']}`",
|
|
f"- Admitted charts: `{registry['aggregates']['admit_count']}`",
|
|
f"- Held shadows: `{registry['aggregates']['hold_count']}`",
|
|
f"- Max numeric error: `{registry['aggregates']['max_numeric_error']}`",
|
|
f"- Missing sources: `{registry['aggregates']['missing_source_count']}`",
|
|
]
|
|
)
|
|
SUMMARY.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
|
|
|
|
def write_tiddler(registry: dict[str, Any], receipt: dict[str, Any]) -> None:
|
|
lines = [
|
|
"created: 20260509000000000",
|
|
"modified: 20260509000000000",
|
|
"tags: ResearchStack Ladder Invariant Chart Guardrail",
|
|
"title: ln2 Ladder Chart Invariant",
|
|
"type: text/vnd.tiddlywiki",
|
|
"",
|
|
"! ln2 Ladder Chart Invariant",
|
|
"",
|
|
registry["invariant"]["short_form"],
|
|
"",
|
|
f"* Decision: `{receipt['decision']}`",
|
|
f"* Receipt hash: `{receipt['receipt_hash']}`",
|
|
f"* Chart root: `{registry['chart_root']}`",
|
|
f"* Registry: `{rel(REGISTRY)}`",
|
|
f"* Receipt: `{rel(RECEIPT)}`",
|
|
"",
|
|
"!! Rule",
|
|
"",
|
|
"A lawful object survives chart changes; an observer shadow stays HOLD until its adapter and proof obligations are declared.",
|
|
"",
|
|
"```",
|
|
registry["invariant"]["canonical_object"],
|
|
"```",
|
|
"",
|
|
"!! Charts",
|
|
"",
|
|
"| Chart | Decision | Guardrail |",
|
|
"|---|---|---|",
|
|
]
|
|
for chart in registry["charts"]:
|
|
lines.append(f"| {chart['chart_id']} | {chart['decision']} | {chart['guardrail']} |")
|
|
lines.extend(
|
|
[
|
|
"",
|
|
"!! Links",
|
|
"",
|
|
"* [[Observer Chart Projection Guardrail]]",
|
|
"* [[Collatz Ladder Shadow Filter]]",
|
|
"* [[Underverse Variant Accounting]]",
|
|
]
|
|
)
|
|
TIDDLER.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
|
|
|
|
def main() -> int:
|
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
TIDDLER.parent.mkdir(parents=True, exist_ok=True)
|
|
registry = build_registry()
|
|
receipt = build_receipt(registry)
|
|
REGISTRY.write_text(json.dumps(registry, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
RECEIPT.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
write_summary(registry, receipt)
|
|
write_tiddler(registry, receipt)
|
|
print(
|
|
json.dumps(
|
|
{
|
|
"registry": rel(REGISTRY),
|
|
"receipt": rel(RECEIPT),
|
|
"summary": rel(SUMMARY),
|
|
"tiddler": rel(TIDDLER),
|
|
"receipt_hash": receipt["receipt_hash"],
|
|
"chart_root": registry["chart_root"],
|
|
"aggregates": registry["aggregates"],
|
|
},
|
|
indent=2,
|
|
sort_keys=True,
|
|
)
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|