algo/applications/collatz/collatz_k_scripts/collatz_iterate_palier_protocol.py
ncantu 67eb6a5e68 collatz: parameterize C3 palier and add iteration protocol tooling
**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
2026-03-09 04:56:44 +01:00

224 lines
8.9 KiB
Python
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.

#!/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} (daprès `{c3_verification_json}`)")
md.append(f"- C2 transition max auditée : palier enfant 2^{state.c2_max_child_palier} (daprè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 lextension 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()