**Motivations:** - Implémenter le workflow complet de démonstration Collatz (commandes.md) - Permettre la reprise après interruption au palier D20 **Evolutions:** - Scripts 01-12 et run-full-workflow alignés sur commandes.md sections 1-10 - collatz_recover_noyau.py : recréation de noyau_post_D20 à partir du CSV candidats - Option --resume-from D20 dans collatz_k_pipeline pour reprendre sans recalculer D18-D19-F15 - Détection automatique : si candidats_D20 existe sans noyau_post_D20, récupération puis poursuite - Filtres --cible=critique et --modulo dans collatz_fusion_pipeline - ROOT par défaut = collatz_k_scripts (plus data/source vide) **Pages affectées:** - .gitignore (__pycache__, out/) - applications/collatz/collatz_k_scripts/*.py - applications/collatz/scripts/*.sh - applications/collatz/scripts/README.md
102 lines
3.4 KiB
Python
102 lines
3.4 KiB
Python
# -*- 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()
|