**Motivations:** - Enable deterministic iteration beyond palier 2^13 (C1→C2→C3). **Root causes:** - The C3 verifier and reporting were hard-coded to palier 13, blocking palier-by-palier iteration. **Correctifs:** - Parameterize `collatz_verify_c3_local_descent.py` with `--palier` and suffix outputs for m!=13. - Add deterministic iteration protocol generator and versioned protocol artefacts. - Extend run report generator `c3_local_descent` profile with `--c3-palier`. **Evolutions:** - Reference the protocol in proof documents. **Pages affectées:** - applications/collatz/collatz_k_scripts/collatz_verify_c3_local_descent.py - applications/collatz/collatz_k_scripts/collatz_iterate_palier_protocol.py - docs/artefacts/collatz/iteration_protocol/* - applications/collatz/collatz_k_scripts/collatz_generate_run_report.py - docs/collatz_run_report_format.md - applications/collatz/démonstration collatz.md
224 lines
8.9 KiB
Python
224 lines
8.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"
|
||
),
|
||
"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}"
|
||
),
|
||
"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 "
|
||
"--output-dir docs/artefacts/collatz/universal_clauses"
|
||
),
|
||
"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 "
|
||
"--clauses-json docs/artefacts/collatz/universal_clauses/clauses_universelles.json "
|
||
"--output-dir docs/artefacts/collatz/universal_clauses"
|
||
),
|
||
"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("- La génération de run reports (sha256 + compteurs) pour des paliers `m != 13` peut nécessiter l’extension du profil `c3_local_descent` du générateur de rapports.")
|
||
_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()
|
||
|