diff --git a/docs/CLAIM_SUPPORT.md b/docs/CLAIM_SUPPORT.md index c199b55..e83137e 100644 --- a/docs/CLAIM_SUPPORT.md +++ b/docs/CLAIM_SUPPORT.md @@ -42,7 +42,7 @@ analytic deductions. | The direct complex phase circuit decodes all leaf-phase derivatives | Paper-level exact signed one-hot check | `circuits.py`, `decoders.py`, `reference.py` | `test_complex_phase.py` | Expectation objectives are invariant under a uniform leaf-phase shift. | | A checkpoint circuit returns every derivative at a selected depth | Paper-level exact depth-block check | `circuits.py`, `decoders.py`, `reference.py` | `test_checkpoints.py` | Each selected depth uses its own circuit stream. | | Integrated complex checkpoint substitution is valid on the active interface | Paper-level projected-matrix and decoded-mean checks | `reference.py`, `circuits.py`, `conventions.py` | `test_operator_contracts.py`, `test_four_qubit_example.py` | It need not preserve the full unitary or complete distribution. | -| Singular magnitude and zero-amplitude phase coordinates are handled without division | Paper-level exact singular checks | `reference.py`, `circuits.py`, `decoders.py` | `test_singular_cases.py`, `test_complex_phase.py` | The derivative and ordinary record vanish when the differential vanishes. | +| Singular magnitude and zero-amplitude phase coordinates are handled without division | Paper-level exact singular checks | `reference.py`, `circuits.py`, `decoders.py` | `test_singular_cases.py`, `test_complex_phase.py` | Zero-weight magnitude records vanish. Zero-amplitude phase derivatives vanish, but individual phase records need not. | | Every single-depth global, checkpoint, and direct-phase record has norm `2` | Paper-level algebraic record checks | `decoders.py`, `reference.py` | `test_decoders.py`, `test_checkpoints.py`, `test_complex_phase.py` | Finite premise of the concentration argument. | | Global coordinatewise execution scaling is `O((1 + log(n/delta))/epsilon^2)` | Paper-level analytic deduction | Record definitions and norm tests | Norm and decoder tests above | Absolute raw-coordinate error. | | The concatenated magnitude record has norm `2*sqrt(n)` and fixed `l_2` accuracy costs `O(n/epsilon_2^2)` up to confidence | Appendix-B analytic result with executable support | `supporting_analysis.py`, `STATISTICAL_ACCURACY.md` | `test_supporting_analysis.py` | Raw magnitude vector; the complex phase stream is separate. | @@ -53,27 +53,7 @@ analytic deductions. | The direct-angle assigned CNOT ledger matches the manuscript's compiler model | **Paper-level resource claim** | `conventions.py`, `native_schedule.py`, `qbp_resource_ledger.py` | `test_resource_ledger.py` | Finite assigned counts, not global optimality or routing. | | One exact multiplexed realization preserves the estimator and the `O(N)` matched forward/frame scaling | **Appendix-B exact compiler result with detailed executable support** | `optimized_compiler.py`, `qbp_optimized_resource_ledger.py` | `test_optimized_compiler.py` | One reusable clean flag; elementary angles generally recombine Hopf coordinates. | | A reflection sum admits unbiased coefficient-one-norm term sampling with a `Lambda**2` sufficient-shot factor | Main-text extension with executable support | `supporting_analysis.py`, `OBSERVABLES_AND_READOUT.md` | `test_supporting_analysis.py` | Portable upper bound, not an optimal Hamiltonian strategy. | -| Independent symmetric readout errors transform records by attenuation and bin mixing | Supporting analytic readout model | `supporting_analysis.py` | `test_supporting_analysis.py` | Readout-only; no coherent gate-noise or mitigation claim. | - -## Scope relative to the first paper - -The first Hopf paper supplie²È="27hase. | -| The global complex magnitude circuit decodes all magnitude derivatives | Paper-level exact complete-distribution check | `circuits.py`, `decoders.py`, `reference.py` | `test_complex_magnitude.py` | General implementation uses separated phase/frame blocks. | -| The direct complex phase circuit decodes all leaf-phase derivatives | Paper-level exact signed one-hot check | `circuits.py`, `decoders.py`, `reference.py` | `test_complex_phase.py` | Expectation objectives are invariant under a uniform leaf-phase shift. | -| A checkpoint circuit returns every derivative at a selected depth | Paper-level exact depth-block check | `circuits.py`, `decoders.py`, `reference.py` | `test_checkpoints.py` | Each selected depth uses its own circuit stream. | -| Integrated complex checkpoint substitution is valid on the active interface | Paper-level projected-matrix and decoded-mean checks | reference.py`, `circuits.py`, `conventions.py` | `test_operator_contracts.py`, `test_four_qubit_example.py` | It need not preserve the full unitary or complete distribution. | -| Singular magnitude and zero-amplitude phase coordinates are handled without division | Paper-level exact singular checks | reference.py`, `circuits.py`, `decoders.py` | `test_singular_cases.py`, `test_complex_phase.py` | The derivative and ordinary record vanish when the differential vanishes. | -| Every single-depth global, checkpoint, and direct-phase record has norm 2 | Paper-level algebraic record checks | `decoders.py`, `reference.py` | `test_decoders.py`, `test_checkpoints.py`, `test_complex_phase.py` | Finite premise of the concentration argument. | -| Global coordinatewise execution scaling is O((1 + log(n/delta))/epsilon^2) | Paper-level analytic deduction | Record definitions and norm tests | Norm and decoder tests above | Absolute raw-coordinate error. | -| The concatenated magnitude record has norm 2*sqrt(n) and fixed l_2 accuracy costs O(n/epsilon_2^2) up to confidence | Appendix-B analytic result with executable support | `supporting_analysis.py`, `SHATISTICAL_ACCURACY.md` | `test_supporting_analysis.py` | Raw magnitude vector; the complex phase stream is separate. | -| Relative/directional control and magnitude-block natural-gradient conditioning follow from the l_2 bound and metric factors | Appendix-B conditional result | `supporting_analysis.py`, `STATISTICAL_ACCURACY.md` | `test_supporting_analysis.py` | Requires a nonzero-gradient margin; damping is an optimizer choice. | -| Raw-coordinate accuracy does not imply normalized-frame accuracy without metric conditioning | Main-text interpretation with Appendix-B proof and exact executable support | `swap_reflection`, `STATISTICAL_ACCURACY.md` | `test_coordinate_frame_separation_with_hopf_split` | Real-chart existence result; no efficient compiler for the witness reflection is claimed. | -| The ambient-sphere phase metric is the adopted convention; the projective block is an unused comparison | Main-text convention with Appendix-B derivation and executable support | `ambient_phase_metric`, `projective_phase_metric` | `test_phase_metric_conventions_and_support_rank` | The projective quotient remains low-profile and is not used by the theorem. | -| The magnitude output objects obey the stated sufficient norm hierarchy | Supporting analytic result | norm-bound helpers, `STATISTICAL_ACCURACY.md` | `test_magnitude_norm_hierarchy` | Upper bounds for the displayed rescaling decoder, not converses. | -| The direct-angle assigned CNOT ledger matches the manuscript's compiler model | Paper-level resource claim | `conventions.py`, `native_schedule.py`, `qbp_resource_ledger.py` | `test_resource_ledger.py` | Finite assigned counts, not global optimality or routing. | -| One exact multiplexed realization preserves the estimator and the O(N) matched forward/frame scaling | Appendix-B exact compiler result with detailed executable support | `optimized_compiler.py`, `qbp_optimized_resource_ledger.py` | `test_optimized_compiler.py` | One reusable clean flag; elementary angles generally recombine Hopf coordinates. | -| A reflection sum admits unbiased coefficient-one-norm term sampling with a Lambda**2 sufficient-shot factor | Main-text extension with executable support | `supporting_analysis.py`, `OBSERVABLES_AND_READOUT.md` | `test_supporting_analysis.py` | Portable upper bound, not an optimal Hamiltonian strategy. | -| Independent symmetric readout errors transform records by attenuation and bin mixing | Supporting analytic readout model | `supporting_analysis.py` | `test_supporting_analysis.py` | Readout-only; no coherent gate-noise or mitigation claim. | +| Independent symmetric readout errors transform records by attenuation and bin mixing | Supporting analytic readout model | `supporting_analysis.py`, `OBSERVABLES_AND_READOUT.md` | `test_supporting_analysis.py` | Readout-only; no coherent gate-noise or mitigation claim. | ## Scope relative to the first paper @@ -322,6 +302,7 @@ mechanism, and error/resource statement; it does not claim universal dominance. | `test_resource_ledger.py` | Direct-angle assigned charges. | | `test_optimized_compiler.py` | Clean-flag factorization and multiplexor ledger. | | `test_supporting_analysis.py` | `l_2`, direction, separation, phase metrics, norm hierarchy, reflection sums, and readout. | +| `test_documentation.py` | UTF-8 integrity, control characters, local link targets, fence balance, and claim-map structure. | ## Deliberate nonclaims diff --git a/qbp_validation/tests/test_documentation.py b/qbp_validation/tests/test_documentation.py new file mode 100644 index 0000000..7710a25 --- /dev/null +++ b/qbp_validation/tests/test_documentation.py @@ -0,0 +1,133 @@ +"""Offline documentation integrity checks; no quantum backend is required.""" +from __future__ import annotations + +import re +import tempfile +import unittest +from pathlib import Path +from urllib.parse import unquote, urlsplit + +ROOT = Path(__file__).resolve().parents[2] +FENCE = re.compile(r"^\s{0,3}(`{3,}|~{3,})(.*)$") +INLINE_LINK = re.compile(r"!?\[[^\]\n]*\]\(\s*(<[^>\n]*>|[^\s)]+)(?:\s+[^)\n]*)?\)") +REFERENCE_LINK = re.compile(r"^\s{0,3}\[[^\]\n]+\]:\s*(<[^>\n]*>|\S+)", re.MULTILINE) + + +def markdown_errors(root: Path) -> list[str]: + """Check UTF-8, controls, fences, and local *file* link targets. + + This deliberately does not fetch external links or validate heading fragments. + Link-shaped examples in fenced blocks and inline code are ignored. + """ + root = root.resolve() + errors: list[str] = [] + paths = sorted(root.rglob("*.md")) + for path in paths: + rel = path.relative_to(root) + if any(part.startswith(".") or part == "__pycache__" for part in rel.parts): + continue + try: + text = path.read_text(encoding="utf-8") + except (UnicodeError, OSError) as exc: + errors.append(f"{rel}: unreadable UTF-8: {exc}") + continue + for number, line in enumerate(text.split("\n"), 1): + bad = sorted({ord(c) for c in line if + (ord(c) < 32 and c not in "\t\r") or + 127 <= ord(c) < 160 or c == "\ufffd"}) + if bad: + errors.append(f"{rel}:{number}: invalid characters {bad}") + visible: list[str] = [] + opened: tuple[str, int] | None = None + for line in text.splitlines(): + match = FENCE.match(line) + if match: + marker, tail = match.groups() + if opened is None: + opened = (marker[0], len(marker)) + elif marker[0] == opened[0] and len(marker) >= opened[1] and not tail.strip(): + opened = None + visible.append("") + else: + visible.append(line if opened is None else "") + if opened is not None: + errors.append(f"{rel}: unclosed fenced block") + prose = "\n".join(visible) + prose = re.sub(r"(`+)[^`\n]*\1", "", prose) + targets = [m.group(1) for m in INLINE_LINK.finditer(prose)] + targets += [m.group(1) for m in REFERENCE_LINK.finditer(prose)] + for target in targets: + parsed = urlsplit(target.strip("<>")) + if parsed.scheme or parsed.netloc or not parsed.path: + continue + name = unquote(parsed.path) + candidate = ((root / name.lstrip("/")) if name.startswith("/") + else (path.parent / name)).resolve() + if not candidate.is_relative_to(root): + errors.append(f"{rel}: local link escapes repository: {target}") + elif not candidate.exists(): + errors.append(f"{rel}: missing local link target: {target}") + return errors + + +class DocumentationTests(unittest.TestCase): + def test_repository_markdown(self) -> None: + self.assertTrue((ROOT / "README.md").is_file()) + errors = markdown_errors(ROOT) + self.assertEqual(errors, [], "\n".join(errors)) + + def test_claim_map_has_one_scope_and_unique_audit_rows(self) -> None: + text = (ROOT / "docs" / "CLAIM_SUPPORT.md").read_text(encoding="utf-8") + self.assertEqual(text.count("## Scope relative to the first paper"), 1) + self.assertNotIn("SHATISTICAL_ACCURACY.md", text) + summary = text.split("## Audit summary\n", 1)[1].split("\n## ", 1)[0] + rows = [line for line in summary.splitlines() if line.startswith("| ")][1:] + names = [line.split("|", 2)[1].strip() for line in rows] + self.assertTrue(names) + self.assertEqual(len(names), len(set(names))) + + def test_valid_local_links_and_code_examples(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "docs").mkdir() + (root / "figure.png").write_bytes(b"fixture") + (root / "README.md").write_text("# Root\n", encoding="utf-8") + (root / "docs" / "guide.md").write_text( + "# Guide\n[parent](../README.md#root)\n![image](/figure.png)\n" + "[external](https://example.invalid/not-fetched)\n[local](#guide)\n" + "[ref]: ../README.md\n`[code](missing.md)`\n" + "```text\n[example](missing.md)\n```\n", encoding="utf-8") + self.assertEqual(markdown_errors(root), []) + + def test_rejects_controls_and_replacement_characters(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + for bad in ("\x01", "\x10", "\x7f", "\x85", "\ufffd"): + with self.subTest(character=repr(bad)): + (root / "README.md").write_text("broken" + bad, encoding="utf-8") + self.assertTrue(any("invalid characters" in e for e in markdown_errors(root))) + + def test_rejects_invalid_utf8(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "README.md").write_bytes(b"bad\xff") + self.assertTrue(any("unreadable UTF-8" in e for e in markdown_errors(root))) + + def test_rejects_missing_inline_and_reference_targets(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "README.md").write_text( + "[inline](missing.md)\n[ref]: absent.md\n", encoding="utf-8") + self.assertEqual(sum("missing local link" in e for e in markdown_errors(root)), 2) + + def test_rejects_unclosed_fences_and_escaping_links(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "README.md").write_text("[bad](../../elsewhere)\n```\n", encoding="utf-8") + errors = markdown_errors(root) + self.assertTrue(any("unclosed" in e for e in errors)) + self.assertTrue(any("escapes" in e for e in errors)) + + +if __name__ == "__main__": + unittest.main() diff --git a/validate_qbp.py b/validate_qbp.py index 17642b2..23a31c9 100644 --- a/validate_qbp.py +++ b/validate_qbp.py @@ -19,6 +19,7 @@ "qbp_validation.tests.test_resource_ledger", "qbp_validation.tests.test_optimized_compiler", "qbp_validation.tests.test_supporting_analysis", + "qbp_validation.tests.test_documentation", ) SMOKE_TESTS = ( @@ -43,7 +44,7 @@ def parse_args() -> argparse.Namespace: action="store_true", help=( "Run Qibo-free convention, decoder, schedule, resource, optimized-" - "compiler, and supporting-analysis checks." + "compiler, supporting-analysis, and documentation checks." ), ) mode.add_argument(