Extend C2 projective verifier with declared residual size checks
**Motivations:**
- Make C2 verification robust when completion documents provide counts instead of full residual lists
- Prepare the verifier to support additional completion transitions with the same artefact structure
**Root causes:**
- m=15→m=16 completion doc may omit residual list and only state |R_16^comp| = 2*|both| = 2202
**Correctifs:**
- Parse and validate declared |R_{m+1}^comp| size when present
- Add generic transition discovery output in verification JSON
**Evolutions:**
- Regenerate versioned C2 verification artefacts and run report
**Pages affectées:**
- applications/collatz/collatz_k_scripts/collatz_verify_c2_projective.py
- docs/artefacts/collatz/c2_projective/verification_c2_projective.json
- docs/artefacts/collatz/c2_projective/verification_c2_projective.md
- docs/collatz_run_report_2026-03-09_c2_projective.md
This commit is contained in:
parent
e3e68fe39c
commit
c29bbaec4b
@ -110,6 +110,44 @@ def _display_path(path: Path, repo_root: Path) -> str:
|
||||
return str(path)
|
||||
|
||||
|
||||
def _discover_both_parent_blocks(md: str) -> dict[int, list[int]]:
|
||||
"""
|
||||
Discover "Parents « both » au palier 2^m" blocks in a completion markdown file.
|
||||
Returns m -> residues list.
|
||||
"""
|
||||
out: dict[int, list[int]] = {}
|
||||
for m in re.findall(r"^###\s+Parents\s+«\s+both\s+»\s+au\s+palier\s+2\^(\d+)\b", md, flags=re.M):
|
||||
mm = int(m)
|
||||
out[mm] = _parse_list_under_heading(
|
||||
md, rf"^###\s+Parents\s+«\s+both\s+»\s+au\s+palier\s+2\^{mm}\b"
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def _discover_listed_residual_after_completion(md: str, child_palier: int) -> list[int] | None:
|
||||
"""
|
||||
Optional: "Résidu restant au palier 2^(m+1) après complétion « one » (...)".
|
||||
"""
|
||||
pattern = rf"^###\s+Résidu\s+restant\s+au\s+palier\s+2\^{child_palier}\s+après\s+complétion\s+«\s+one\s+»"
|
||||
try:
|
||||
return _parse_list_under_heading(md, pattern)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def _discover_declared_residual_size(md: str, child_palier: int) -> int | None:
|
||||
"""
|
||||
Optional: parse a declared residual size like "|R_16^comp| = 2202".
|
||||
"""
|
||||
matches = re.findall(rf"\|R_{child_palier}\^comp\|\s*=\s*([^\n]+)", md)
|
||||
if not matches:
|
||||
return None
|
||||
# Extract the last integer on the matched RHS (e.g. "2*|both| = 2202" -> 2202).
|
||||
rhs = matches[-1]
|
||||
ints = re.findall(r"\b(\d+)\b", rhs)
|
||||
return int(ints[-1]) if ints else None
|
||||
|
||||
|
||||
def verify_c2(
|
||||
*,
|
||||
noyau_both_base_4096_md: Path,
|
||||
@ -156,17 +194,47 @@ def verify_c2(
|
||||
children16 = _lift_children(both15, 15)
|
||||
_assert_all_odd(children16, "Computed children at m=16")
|
||||
|
||||
# This completion file does not necessarily list the full residual after completion, so we only check the count.
|
||||
listed_r16 = _discover_listed_residual_after_completion(c1516_md, 16)
|
||||
declared_r16_size = _discover_declared_residual_size(c1516_md, 16)
|
||||
if listed_r16 is not None:
|
||||
_assert_all_odd(listed_r16, "Listed residual at m=16")
|
||||
if set(listed_r16) != set(children16):
|
||||
raise ValueError("Listed residual at m=16 does not match computed children of both(m=15)")
|
||||
if declared_r16_size is not None and declared_r16_size != len(children16):
|
||||
raise ValueError(f"Declared |R_16^comp|={declared_r16_size} does not match computed {len(children16)}")
|
||||
|
||||
# This completion file may omit the full residual after completion.
|
||||
c1516 = C2CheckResult(
|
||||
palier_parent=15,
|
||||
palier_child=16,
|
||||
both_parent_count=len(both15),
|
||||
computed_children_count=len(children16),
|
||||
listed_residual_count=None,
|
||||
children_equals_listed_residual=None,
|
||||
listed_residual_count=len(listed_r16) if listed_r16 is not None else declared_r16_size,
|
||||
children_equals_listed_residual=(set(children16) == set(listed_r16)) if listed_r16 is not None else None,
|
||||
projection_mod_4096_equals_b12=(_project_mod_4096(both15) == set(b12)),
|
||||
)
|
||||
|
||||
transitions: list[dict[str, object]] = []
|
||||
for src_name, md in (("completion_m14_to_m15", c1415_md), ("completion_m15_to_m16", c1516_md)):
|
||||
both_blocks = _discover_both_parent_blocks(md)
|
||||
for m_parent, both in sorted(both_blocks.items()):
|
||||
child_palier = m_parent + 1
|
||||
children = _lift_children(both, m_parent)
|
||||
listed = _discover_listed_residual_after_completion(md, child_palier)
|
||||
declared = _discover_declared_residual_size(md, child_palier)
|
||||
transitions.append(
|
||||
{
|
||||
"source": src_name,
|
||||
"palier_parent": m_parent,
|
||||
"palier_child": child_palier,
|
||||
"both_parent_count": len(both),
|
||||
"computed_children_count": len(children),
|
||||
"listed_residual_count": len(listed) if listed is not None else declared,
|
||||
"children_equals_listed_residual": (set(children) == set(listed)) if listed is not None else None,
|
||||
"projection_mod_4096_equals_b12": (_project_mod_4096(both) == set(b12)),
|
||||
}
|
||||
)
|
||||
|
||||
summary = {
|
||||
"inputs": {
|
||||
"noyau_both_base_4096_md": _display_path(noyau_both_base_4096_md, repo_root),
|
||||
@ -174,6 +242,7 @@ def verify_c2(
|
||||
"completion_m15_to_m16_md": _display_path(completion_m15_to_m16_md, repo_root),
|
||||
},
|
||||
"B12": {"count": len(b12), "min": min(b12), "max": max(b12)},
|
||||
"transitions": transitions,
|
||||
"checks": {
|
||||
"m14_to_m15": c1415.__dict__,
|
||||
"m15_to_m16": c1516.__dict__,
|
||||
@ -216,6 +285,8 @@ def verify_c2(
|
||||
lines.append("")
|
||||
lines.append(f"- |both parents (m=15)| = {c1516.both_parent_count}")
|
||||
lines.append(f"- |computed children (m=16)| = {c1516.computed_children_count} (attendu 2*|both|)")
|
||||
if c1516.listed_residual_count is not None:
|
||||
lines.append(f"- |listed residual (m=16)| : {c1516.listed_residual_count}")
|
||||
lines.append(f"- projection both(m=15) mod 4096 == B12 : {c1516.projection_mod_4096_equals_b12}")
|
||||
lines.append("")
|
||||
lines.append("## Sorties")
|
||||
|
||||
@ -9,6 +9,28 @@
|
||||
"min": 27,
|
||||
"max": 4095
|
||||
},
|
||||
"transitions": [
|
||||
{
|
||||
"source": "completion_m14_to_m15",
|
||||
"palier_parent": 14,
|
||||
"palier_child": 15,
|
||||
"both_parent_count": 593,
|
||||
"computed_children_count": 1186,
|
||||
"listed_residual_count": 1186,
|
||||
"children_equals_listed_residual": true,
|
||||
"projection_mod_4096_equals_b12": true
|
||||
},
|
||||
{
|
||||
"source": "completion_m15_to_m16",
|
||||
"palier_parent": 15,
|
||||
"palier_child": 16,
|
||||
"both_parent_count": 1101,
|
||||
"computed_children_count": 2202,
|
||||
"listed_residual_count": 2202,
|
||||
"children_equals_listed_residual": null,
|
||||
"projection_mod_4096_equals_b12": true
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"m14_to_m15": {
|
||||
"palier_parent": 14,
|
||||
@ -24,7 +46,7 @@
|
||||
"palier_child": 16,
|
||||
"both_parent_count": 1101,
|
||||
"computed_children_count": 2202,
|
||||
"listed_residual_count": null,
|
||||
"listed_residual_count": 2202,
|
||||
"children_equals_listed_residual": null,
|
||||
"projection_mod_4096_equals_b12": true
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
- |both parents (m=15)| = 1101
|
||||
- |computed children (m=16)| = 2202 (attendu 2*|both|)
|
||||
- |listed residual (m=16)| : 2202
|
||||
- projection both(m=15) mod 4096 == B12 : True
|
||||
|
||||
## Sorties
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
## Code et reproductibilité
|
||||
|
||||
- **Commit Git** : `e12c544e7bf8d7a6f9518cdd4959d0da07bccc07`
|
||||
- **Commit Git** : `e3e68fe39c8ad466e5741e87d20311ca93b2456e`
|
||||
- **Commande** :
|
||||
|
||||
```bash
|
||||
@ -19,7 +19,7 @@ python3 applications/collatz/collatz_k_scripts/collatz_generate_run_report.py --
|
||||
## Empreintes sha256 (scripts, artefacts)
|
||||
|
||||
- `/home/ncantu/code/algo/applications/collatz/collatz_k_scripts/collatz_verify_c2_projective.py`
|
||||
- sha256: `4f515d649c44c4ffe55349b07c72e9e766f591f7596e1bcdf0f9447e6b94950d`
|
||||
- sha256: `bad3ddd4288af4a8b7bcc4fa30c1f5350db16f352b6eaf29918e8c1e1428a5b0`
|
||||
- `/home/ncantu/code/algo/applications/collatz/collatz_k_scripts/noyau_both_base_4096.md`
|
||||
- sha256: `d0abffeca9ce2356d13b31ee4325b68fd85cf061670a8524b8e60fd15aba881b`
|
||||
- `/home/ncantu/code/algo/applications/collatz/collatz_k_scripts/complétion_minorée_m14_vers_m15.md`
|
||||
@ -27,9 +27,9 @@ python3 applications/collatz/collatz_k_scripts/collatz_generate_run_report.py --
|
||||
- `/home/ncantu/code/algo/applications/collatz/collatz_k_scripts/complétion_minorée_m15_vers_m16.md`
|
||||
- sha256: `956f8fd19570b7614705384995b52b6bf81399ca8dc36c3ea33bcbad3e4aff50`
|
||||
- `/home/ncantu/code/algo/docs/artefacts/collatz/c2_projective/verification_c2_projective.json`
|
||||
- sha256: `b1b9ab9d5d4f9d4ee60e7efd43b853ac29d3d51a19c2d71bdac45c4340d01bf0`
|
||||
- sha256: `259901a9e4e307dae238672cc3e2e1e016800f034cdd98efe929e69bc1e4068a`
|
||||
- `/home/ncantu/code/algo/docs/artefacts/collatz/c2_projective/verification_c2_projective.md`
|
||||
- sha256: `8bd84cb2149d297487e0e0ff03ebe96ff27b07a5ab677407cb4b9a17a339c2ba`
|
||||
- sha256: `dc5562fea53f62e88acc08bcd29c89c53e9ad6e5fc4d41351642e7942cc49bdc`
|
||||
|
||||
## Compteurs et métriques
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user