diff --git a/applications/collatz/collatz_k_scripts/collatz_generate_run_report.py b/applications/collatz/collatz_k_scripts/collatz_generate_run_report.py index 3a88032..1b5a749 100644 --- a/applications/collatz/collatz_k_scripts/collatz_generate_run_report.py +++ b/applications/collatz/collatz_k_scripts/collatz_generate_run_report.py @@ -119,6 +119,17 @@ class LocalH6Metrics: certificate_paliers: list[tuple[str, int]] +@dataclass(frozen=True) +class C2TransitionMetric: + palier_parent: int + palier_child: int + both_parent_count: int + computed_children_count: int + listed_residual_count: int | None + children_equals_listed_residual: bool | None + projection_mod_4096_equals_b12: bool + + @dataclass(frozen=True) class C2ProjectiveMetrics: b12_size: int @@ -130,6 +141,7 @@ class C2ProjectiveMetrics: both15_size: int children16_size: int proj_both15_equals_b12: bool + transitions: list[C2TransitionMetric] @dataclass(frozen=True) @@ -151,8 +163,11 @@ def parse_c2_projective_metrics(verification_json: str) -> C2ProjectiveMetrics: b12 = obj.get("B12") checks = obj.get("checks") + transitions = obj.get("transitions") if not isinstance(b12, dict) or not isinstance(checks, dict): raise ValueError("Invalid C2 verification JSON: missing 'B12' or 'checks'") + if not isinstance(transitions, list) or not all(isinstance(x, dict) for x in transitions): + raise ValueError("Invalid C2 verification JSON: missing 'transitions' list") c1415 = checks.get("m14_to_m15") c1516 = checks.get("m15_to_m16") @@ -171,6 +186,37 @@ def parse_c2_projective_metrics(verification_json: str) -> C2ProjectiveMetrics: raise ValueError(f"Invalid C2 verification JSON: {k} must be bool") return v + def opt_int(d: dict, k: str) -> int | None: + v = d.get(k) + if v is None: + return None + if not isinstance(v, int): + raise ValueError(f"Invalid C2 verification JSON: {k} must be int or null") + return v + + def opt_bool(d: dict, k: str) -> bool | None: + v = d.get(k) + if v is None: + return None + if not isinstance(v, bool): + raise ValueError(f"Invalid C2 verification JSON: {k} must be bool or null") + return v + + parsed_transitions: list[C2TransitionMetric] = [] + for t in transitions: + parsed_transitions.append( + C2TransitionMetric( + palier_parent=req_int(t, "palier_parent"), + palier_child=req_int(t, "palier_child"), + both_parent_count=req_int(t, "both_parent_count"), + computed_children_count=req_int(t, "computed_children_count"), + listed_residual_count=opt_int(t, "listed_residual_count"), + children_equals_listed_residual=opt_bool(t, "children_equals_listed_residual"), + projection_mod_4096_equals_b12=req_bool(t, "projection_mod_4096_equals_b12"), + ) + ) + parsed_transitions = sorted(parsed_transitions, key=lambda x: (x.palier_parent, x.palier_child)) + return C2ProjectiveMetrics( b12_size=req_int(b12, "count"), both14_size=req_int(c1415, "both_parent_count"), @@ -181,6 +227,7 @@ def parse_c2_projective_metrics(verification_json: str) -> C2ProjectiveMetrics: both15_size=req_int(c1516, "both_parent_count"), children16_size=req_int(c1516, "computed_children_count"), proj_both15_equals_b12=req_bool(c1516, "projection_mod_4096_equals_b12"), + transitions=parsed_transitions, ) @@ -264,11 +311,22 @@ def write_c2_projective_run_report( lines.append("## Compteurs et métriques") lines.append("") lines.append(f"- |B12| = {metrics.b12_size}") - lines.append(f"- m=14: |both|={metrics.both14_size}, |children(m=15)|={metrics.children15_size}, |listed residual(m=15)|={metrics.residual15_size}") - lines.append(f"- m=14: children(m=15) == residual(m=15) : {metrics.children15_equals_residual15}") - lines.append(f"- m=14: both mod 4096 == B12 : {metrics.proj_both14_equals_b12}") - lines.append(f"- m=15: |both|={metrics.both15_size}, |children(m=16)|={metrics.children16_size}") - lines.append(f"- m=15: both mod 4096 == B12 : {metrics.proj_both15_equals_b12}") + for t in metrics.transitions: + if t.listed_residual_count is None: + lines.append( + f"- m={t.palier_parent}: |both|={t.both_parent_count}, |children(m={t.palier_child})|={t.computed_children_count}" + ) + else: + lines.append( + f"- m={t.palier_parent}: |both|={t.both_parent_count}, " + f"|children(m={t.palier_child})|={t.computed_children_count}, " + f"|listed residual(m={t.palier_child})|={t.listed_residual_count}" + ) + if t.children_equals_listed_residual is not None: + lines.append( + f"- m={t.palier_parent}: children(m={t.palier_child}) == residual(m={t.palier_child}) : {t.children_equals_listed_residual}" + ) + lines.append(f"- m={t.palier_parent}: both mod 4096 == B12 : {t.projection_mod_4096_equals_b12}") lines.append("") lines.append("## Chemins d’artefacts (versionnés)") lines.append("") diff --git a/applications/collatz/collatz_k_scripts/plan_lemmes_manquants_et_programme_de_preuve.md b/applications/collatz/collatz_k_scripts/plan_lemmes_manquants_et_programme_de_preuve.md index 962a77a..b0a38ba 100644 --- a/applications/collatz/collatz_k_scripts/plan_lemmes_manquants_et_programme_de_preuve.md +++ b/applications/collatz/collatz_k_scripts/plan_lemmes_manquants_et_programme_de_preuve.md @@ -296,6 +296,55 @@ Passer de l’instance locale au cas général exige de relier les témoins obse - D exact : contrôler l’extension “pour tout \(n\) dans une classe modulo \(2^m\), pour tout \(n\ge N_0\)” via les formules affines (seuil \(N_0\)) ; - fusion : contrôler l’extension “pour tout \(n\) dans une classe modulo \(2^m\), pour tout \(n\ge N_F\)” et la propriété de réduction \(m0\), on définit le seuil +\[ +N_0=\left\lfloor\frac{C_k}{\Delta_D}\right\rfloor+1, +\] +et l’énoncé universel attendu est : +\[ +\forall n\equiv r\!\!\!\pmod{2^m},\quad n\ge N_0 \Longrightarrow U^{(k)}(n)0\), le seuil +\[ +N_F = \mathrm{Nf\_F}(C_t,A_t,t,a), +\] +tel que l’énoncé universel attendu soit : +\[ +\forall n\equiv r\!\!\!\pmod{2^m},\quad n\ge N_F \Longrightarrow \bigl(U(m(n))=y(n)\ \wedge\ m(n)