# -*- coding: utf-8 -*- """ collatz_verify_both_extinction.py Vérifie la taille du noyau « both » |B_m| au palier 2^m. Produit un rapport Markdown avec taille, coefficient de contraction κ, et comparaison avec le noyau précédent si fourni. CLI: --palier N --input-noyau PATH --output MD_PATH [--previous PATH] """ from __future__ import annotations from pathlib import Path import argparse import json from collatz_k_utils import write_text def load_noyau(path: str) -> list[int]: """Load noyau from JSON: list of residues or dict with R*_after / noyau / residues.""" data = json.loads(Path(path).read_text(encoding="utf-8")) if isinstance(data, list): return [int(x) for x in data] if isinstance(data, dict): for key in ("R25_after", "R24_after", "noyau", "residues", "uncovered"): if key in data and isinstance(data[key], list): return [int(x) for x in data[key]] raise ValueError(f"Noyau JSON: no known key in {list(data.keys())}") raise ValueError("Noyau JSON must be a list or dict with residue list") def run_verify( palier: int, input_noyau: str, output_md: str, previous_noyau: str | None = None, ) -> None: noyau = load_noyau(input_noyau) B_m = len(noyau) R_m = 1 << (palier - 1) # odd residues at level 2^m lines: list[str] = [] lines.append("# Vérification extinction noyau « both »") lines.append("") lines.append("## Paramètres") lines.append("") lines.append(f"- Palier : 2^{palier}") lines.append(f"- |R_m| (impairs mod 2^{palier}) : {R_m}") lines.append(f"- |B_m| (noyau both) : {B_m}") lines.append("") # Contraction coefficient κ = |B_m| / |R_m| kappa = B_m / R_m if R_m else 0.0 lines.append("## Coefficient de contraction κ") lines.append("") lines.append(f"- κ = |B_m| / |R_m| = {B_m} / {R_m} = {kappa}") lines.append("") if previous_noyau: prev = load_noyau(previous_noyau) B_prev = len(prev) lines.append("## Comparaison avec noyau précédent") lines.append("") lines.append(f"- |B_m| précédent : {B_prev}") lines.append(f"- |B_m| actuel : {B_m}") if B_m < B_prev: lines.append(f"- **Contraction** : |B_m| diminue de {B_prev - B_m} (✓)") elif B_m == B_prev: lines.append("- **Stable** : |B_m| inchangé") else: lines.append(f"- **Augmentation** : |B_m| augmente de {B_m - B_prev}") lines.append("") else: lines.append("## Comparaison") lines.append("") lines.append("(Aucun noyau précédent fourni pour comparaison)") lines.append("") write_text(output_md, "\n".join(lines) + "\n") print(f"Wrote: {output_md}") def main() -> None: ap = argparse.ArgumentParser(description="Verify both-extinction: |B_m| size and contraction") ap.add_argument("--palier", type=int, required=True, help="Modulus power (e.g. 25 for 2^25)") ap.add_argument("--input-noyau", required=True, help="Path to noyau JSON") ap.add_argument("--output", required=True, help="Path to output Markdown report") ap.add_argument("--previous", default=None, help="Path to previous noyau JSON for comparison") args = ap.parse_args() run_verify( palier=args.palier, input_noyau=args.input_noyau, output_md=args.output, previous_noyau=args.previous, ) if __name__ == "__main__": main()