**Motivations:** - Publish new Collatz palier runs and associated artefacts (C3 local descent, universal clauses, iteration protocol). - Extend the scripts toolbox to generate/verify clauses and build refinement certificates over S_m. **Root causes:** - Universal clause witnesses were lifted to 2^(A+1) even when the witness is already fixed modulo the domain palier, leading to unstable or unnecessarily weak/ambiguous modulus choices. - CSV palier inference in scission could mis-detect short column names (e.g. "m") by substring matching. **Correctifs:** - Lift D_exact/F witnesses to m_stable := max(m, A+1) in universal clause extraction and run reports. - Make scission palier/m column detection exact-match to avoid false positives. - Update C3 local descent verification/reporting to use strict fusion witness selection prioritizing lower modular stability and refreshed D/F metrics. - Add a dedicated run report profile for per-palier universal clauses. **Evolutions:** - Add scripts for terminal clauses and minorated descent clauses over S_m, their deterministic verification, and multi-level refinement certificate building. - Add modular tooling for register_K and incremental comparison of D_minor families. - Add/update feature documentation for the new pipelines and generated reports. **Pages affectées:** - applications/collatz/collatz_k_scripts/README.md - applications/collatz/collatz_k_scripts/collatz_extract_universal_clauses.py - applications/collatz/collatz_k_scripts/collatz_generate_run_report.py - applications/collatz/collatz_k_scripts/collatz_iterate_palier_protocol.py - applications/collatz/collatz_k_scripts/collatz_scission.py - applications/collatz/collatz_k_scripts/collatz_verify_c3_local_descent.py - applications/collatz/collatz_k_scripts/collatz_verify_universal_clauses.py - applications/collatz/collatz_k_scripts/*refinement*over_Sm*.py - applications/collatz/collatz_k_scripts/collatz_generate_*clauses_over_Sm.py - applications/collatz/collatz_k_scripts/collatz_verify_minorated_descent_clauses_over_Sm.py - applications/collatz/collatz_k_scripts/collatz_build_register_K_modular.py - applications/collatz/collatz_k_scripts/collatz_compare_dminor_families_incremental.py - applications/collatz/*.md - docs/features/*.md - docs/artefacts/collatz/** - docs/collatz_run_report_2026-03-09_*.md
242 lines
9.9 KiB
Python
242 lines
9.9 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
collatz_iterate_palier_protocol.py
|
||
|
||
Deterministic "next palier" protocol generator for the hybrid chain C1→C2→C3.
|
||
|
||
It does NOT run expensive computations. It inspects existing versioned artefacts
|
||
and writes a checklist (JSON + MD) describing:
|
||
- current certified palier for C3 (from verification JSON)
|
||
- current max C2 completion transition (from verification JSON)
|
||
- availability of local H6 directories at a chosen target palier
|
||
- commands to generate / verify / report the next iteration (2^m → 2^(m+1))
|
||
|
||
Outputs are intended to be versioned under `docs/artefacts/`.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import json
|
||
from dataclasses import dataclass
|
||
from pathlib import Path
|
||
|
||
|
||
def _read_json(path: Path) -> object:
|
||
return json.loads(path.read_text(encoding="utf-8", errors="strict"))
|
||
|
||
|
||
def _req_int(d: dict[str, object], key: str) -> int:
|
||
v = d.get(key)
|
||
if not isinstance(v, int):
|
||
raise ValueError(f"Expected int for {key}")
|
||
return v
|
||
|
||
|
||
def _write_json(path: Path, obj: object) -> None:
|
||
path.parent.mkdir(parents=True, exist_ok=True)
|
||
path.write_text(json.dumps(obj, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||
|
||
|
||
def _write_md(path: Path, lines: list[str]) -> None:
|
||
path.parent.mkdir(parents=True, exist_ok=True)
|
||
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||
|
||
|
||
def _discover_local_h6_state_dirs(root: Path, palier: int) -> list[Path]:
|
||
return sorted([p for p in root.glob(f"local_E*_palier2p{palier}") if p.is_dir()])
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class ProtocolState:
|
||
c3_palier: int
|
||
c2_max_child_palier: int
|
||
target_palier: int
|
||
local_h6_states_found: int
|
||
local_h6_missing_state_ids: list[int]
|
||
|
||
|
||
def _load_c3_palier(c3_verification_json: Path) -> int:
|
||
obj = _read_json(c3_verification_json)
|
||
if not isinstance(obj, dict):
|
||
raise ValueError("Invalid C3 verification JSON: expected object")
|
||
domain = obj.get("domain")
|
||
if not isinstance(domain, dict):
|
||
raise ValueError("Invalid C3 verification JSON: missing domain")
|
||
return _req_int(domain, "palier")
|
||
|
||
|
||
def _load_c2_max_child_palier(c2_verification_json: Path) -> int:
|
||
obj = _read_json(c2_verification_json)
|
||
if not isinstance(obj, dict):
|
||
raise ValueError("Invalid C2 verification JSON: expected object")
|
||
transitions = obj.get("transitions")
|
||
if not isinstance(transitions, list) or not all(isinstance(x, dict) for x in transitions):
|
||
raise ValueError("Invalid C2 verification JSON: missing transitions")
|
||
child_paliers = [_req_int(t, "palier_child") for t in transitions]
|
||
if not child_paliers:
|
||
raise ValueError("Invalid C2 verification JSON: empty transitions")
|
||
return max(child_paliers)
|
||
|
||
|
||
def _infer_state_id_from_dirname(dirname: str) -> int:
|
||
# expected: local_E{sid}_palier2p{m}
|
||
parts = dirname.split("_")
|
||
for p in parts:
|
||
if p.startswith("E") and p[1:].isdigit():
|
||
return int(p[1:])
|
||
raise ValueError(f"Cannot infer state id from {dirname}")
|
||
|
||
|
||
def run(
|
||
*,
|
||
local_h6_root: Path,
|
||
c2_verification_json: Path,
|
||
c3_verification_json: Path,
|
||
output_dir: Path,
|
||
target_palier: int | None,
|
||
) -> None:
|
||
c3_palier = _load_c3_palier(c3_verification_json)
|
||
c2_max_child = _load_c2_max_child_palier(c2_verification_json)
|
||
tgt = (c3_palier + 1) if target_palier is None else int(target_palier)
|
||
if tgt < 13:
|
||
raise ValueError("target_palier must be >= 13")
|
||
|
||
found_dirs = _discover_local_h6_state_dirs(local_h6_root, tgt)
|
||
found_ids = sorted({_infer_state_id_from_dirname(p.name) for p in found_dirs})
|
||
missing_ids = [sid for sid in range(1, 61) if sid not in found_ids]
|
||
|
||
state = ProtocolState(
|
||
c3_palier=c3_palier,
|
||
c2_max_child_palier=c2_max_child,
|
||
target_palier=tgt,
|
||
local_h6_states_found=len(found_ids),
|
||
local_h6_missing_state_ids=missing_ids,
|
||
)
|
||
|
||
commands = {
|
||
"C1_local_H6_generate": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_generate_local_h6_artefacts.py "
|
||
f"--docs-dir docs --output-root docs/artefacts/collatz --state-ids all "
|
||
f"--palier-start {tgt} --palier-max {tgt} "
|
||
"--t-min 9 --t-max 120 --write-index --index-path docs/artefacts/collatz/local_H6_index.md"
|
||
),
|
||
"C1_local_H6_run_reports": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_generate_local_h6_run_reports.py "
|
||
"--out-dir applications/collatz/out --docs-dir docs --local-h6-root docs/artefacts/collatz "
|
||
f"--palier {tgt} --index-path docs/artefacts/collatz/local_H6_index.md"
|
||
),
|
||
"C3_verify_local_descent": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_verify_c3_local_descent.py "
|
||
"--local-h6-root docs/artefacts/collatz "
|
||
"--output-dir docs/artefacts/collatz/c3_local_descent "
|
||
f"--palier {tgt}"
|
||
),
|
||
"C3_run_report_palier": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_generate_run_report.py "
|
||
"--profile c3_local_descent_palier "
|
||
"--c3-artefacts-dir docs/artefacts/collatz/c3_local_descent "
|
||
f"--c3-palier {tgt} "
|
||
"--out-dir applications/collatz/out --docs-dir docs"
|
||
),
|
||
"Universal_clauses_extract": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_extract_universal_clauses.py "
|
||
f"--verification-json docs/artefacts/collatz/c3_local_descent/verification_c3_local_descent_palier2p{tgt}.json "
|
||
f"--output-dir docs/artefacts/collatz/universal_clauses/palier2p{tgt}"
|
||
),
|
||
"Universal_clauses_verify": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_verify_universal_clauses.py "
|
||
f"--verification-json docs/artefacts/collatz/c3_local_descent/verification_c3_local_descent_palier2p{tgt}.json "
|
||
f"--clauses-json docs/artefacts/collatz/universal_clauses/palier2p{tgt}/clauses_universelles.json "
|
||
f"--output-dir docs/artefacts/collatz/universal_clauses/palier2p{tgt}"
|
||
),
|
||
"Universal_clauses_run_report_palier": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_generate_run_report.py "
|
||
"--profile universal_clauses_palier "
|
||
f"--universal-clauses-artefacts-dir docs/artefacts/collatz/universal_clauses/palier2p{tgt} "
|
||
"--out-dir applications/collatz/out --docs-dir docs"
|
||
),
|
||
"C2_verify_projective": (
|
||
"python3 applications/collatz/collatz_k_scripts/collatz_verify_c2_projective.py "
|
||
"--repo-root /home/ncantu/code/algo --output-dir docs/artefacts/collatz/c2_projective"
|
||
),
|
||
}
|
||
|
||
out_obj = {
|
||
"inputs": {
|
||
"local_h6_root": str(local_h6_root),
|
||
"c2_verification_json": str(c2_verification_json),
|
||
"c3_verification_json": str(c3_verification_json),
|
||
},
|
||
"state": {
|
||
"c3_palier": state.c3_palier,
|
||
"c2_max_child_palier": state.c2_max_child_palier,
|
||
"target_palier": state.target_palier,
|
||
"local_h6_states_found": state.local_h6_states_found,
|
||
"local_h6_missing_state_ids": state.local_h6_missing_state_ids,
|
||
},
|
||
"commands": commands,
|
||
}
|
||
|
||
output_dir.mkdir(parents=True, exist_ok=True)
|
||
out_json = output_dir / "iteration_protocol.json"
|
||
out_md = output_dir / "iteration_protocol.md"
|
||
_write_json(out_json, out_obj)
|
||
|
||
md: list[str] = []
|
||
md.append("**Auteur** : Équipe 4NK")
|
||
md.append("")
|
||
md.append("# Protocole déterministe — itération de palier (C1→C2→C3)")
|
||
md.append("")
|
||
md.append("## État courant (artefacts)")
|
||
md.append("")
|
||
md.append(f"- C3 palier certifié : 2^{state.c3_palier} (d’après `{c3_verification_json}`)")
|
||
md.append(f"- C2 transition max auditée : palier enfant 2^{state.c2_max_child_palier} (d’après `{c2_verification_json}`)")
|
||
md.append("")
|
||
md.append("## Palier cible")
|
||
md.append("")
|
||
md.append(f"- palier cible : 2^{state.target_palier}")
|
||
md.append(f"- H6 locale présente (états) : {state.local_h6_states_found}/60")
|
||
if state.local_h6_missing_state_ids:
|
||
md.append(f"- états manquants : {state.local_h6_missing_state_ids}")
|
||
md.append("")
|
||
md.append("## Étapes (commandes reproductibles)")
|
||
md.append("")
|
||
for k, cmd in commands.items():
|
||
md.append(f"- **{k}** :")
|
||
md.append("")
|
||
md.append("```bash")
|
||
md.append(cmd)
|
||
md.append("```")
|
||
md.append("")
|
||
md.append("## Notes")
|
||
md.append("")
|
||
md.append("- Pour `C3_verify_local_descent` : si `palier != 13`, les sorties attendues sont suffixées `..._palier2p<m>.{json,md}`.")
|
||
md.append("- Les rapports C3 par palier sont générés via le profil `c3_local_descent_palier` (nom de fichier déterministe).")
|
||
_write_md(out_md, md)
|
||
|
||
|
||
def main() -> None:
|
||
ap = argparse.ArgumentParser(description="Generate a deterministic next-palier protocol for C1→C2→C3")
|
||
ap.add_argument("--local-h6-root", default="docs/artefacts/collatz", help="Root containing local_E*_palier2p<m>/ dirs")
|
||
ap.add_argument("--c2-verification-json", default="docs/artefacts/collatz/c2_projective/verification_c2_projective.json")
|
||
ap.add_argument("--c3-verification-json", default="docs/artefacts/collatz/c3_local_descent/verification_c3_local_descent.json")
|
||
ap.add_argument("--output-dir", default="docs/artefacts/collatz/iteration_protocol")
|
||
ap.add_argument("--target-palier", default="", help="Override target palier m (defaults to c3_palier+1)")
|
||
args = ap.parse_args()
|
||
|
||
tgt = int(args.target_palier) if args.target_palier.strip() else None
|
||
run(
|
||
local_h6_root=Path(args.local_h6_root).resolve(),
|
||
c2_verification_json=Path(args.c2_verification_json).resolve(),
|
||
c3_verification_json=Path(args.c3_verification_json).resolve(),
|
||
output_dir=Path(args.output_dir).resolve(),
|
||
target_palier=tgt,
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|