# -*- coding: utf-8 -*- """ collatz_compute_survival_rate.py Compute survival rate (coefficient of contraction) for a noyau. Outputs |B_m| and q = |B_m| / (2 * |R_{m-1}|) when previous noyau is available. Usage: python collatz_compute_survival_rate.py --noyau PATH [--previous PATH] """ from __future__ import annotations import argparse import json from pathlib import Path def load_noyau(path: str) -> tuple[list[int], int]: """Load noyau from JSON, return (residues, palier).""" data = json.loads(Path(path).read_text(encoding="utf-8")) if isinstance(data, list): residues = [int(x) for x in data] palier = max(n.bit_length() for n in residues) if residues else 0 return residues, palier if isinstance(data, dict): for key in ("noyau", "residues", "uncovered"): if key in data and isinstance(data[key], list): residues = [int(x) for x in data[key]] palier = data.get("palier", max(n.bit_length() for n in residues) if residues else 0) return residues, palier raise ValueError(f"Cannot load noyau from {path}") def main() -> None: ap = argparse.ArgumentParser(description="Compute survival rate of noyau") ap.add_argument("--noyau", required=True, help="Path to noyau JSON") ap.add_argument("--previous", help="Path to previous noyau (for q = |B_m| / 2|R_{m-1}|)") args = ap.parse_args() residues, palier = load_noyau(args.noyau) size = len(residues) lines = [ f"# Survival rate: {Path(args.noyau).name}", "", f"- |B_{{m}}| = {size}", f"- palier m ≈ {palier}", "", ] if args.previous and Path(args.previous).exists(): prev_residues, prev_palier = load_noyau(args.previous) prev_size = len(prev_residues) denom = 2 * prev_size q = size / denom if denom else 0 lines.extend([ f"- |R_{{m-1}}| = {prev_size}", f"- q = |B_m| / (2|R_{{m-1}}|) = {q:.6f}", "", ]) print("\n".join(lines)) if __name__ == "__main__": main()