Contributing¶
Clifft is developed at unitaryfoundation/clifft on GitHub.
Reporting Issues¶
- Bugs: Use the bug report template with a minimal reproducer.
- Feature requests: Use the feature request template.
Development Workflow¶
- Fork the repository and create a feature branch
- Make your changes with atomic, conventional commits (
feat:,fix:,test:,docs:) - Run pre-commit checks before committing
- Open a pull request against
main
Contributor Agreement¶
By submitting a pull request, you confirm that:
- The contribution is your original work (or you have the right to submit it).
- You license it under this project's Apache-2.0 license.
The PR template includes a checkbox for this — please check it when opening your PR.
AI-Assisted Contributions¶
We welcome AI-assisted contributions. If you use AI tools (Claude, Copilot, ChatGPT, etc.) to help write code:
- Review all generated code before submitting. You are responsible for the correctness, security, and quality of the contribution.
-
Include an
Assisted-by:git trailer in your commit message identifying the tool and model used: -
The human author remains the commit author. The AI tool is credited via the trailer, not
Co-authored-by.
Users that do not follow these steps, and in particular fail to do a human pre-review of any AI generated content including issues and pull requests, may be subject to a ban from the repo.
Code Quality¶
We use pre-commit hooks to enforce formatting and linting:
# Install pre-commit hooks (runs automatically on git commit)
uv run pre-commit install
# Run all checks manually
uv run --frozen --only-group dev pre-commit run --all-files --show-diff-on-failure
C++¶
- Formatter: clang-format
- Standard: C++20
- Namespace: All code in
namespace clifft { ... } - Comments: Explain why, not what. Omit if the code is self-explanatory.
Python¶
- Linter/Formatter: Ruff
- Type checker: mypy (strict mode)
- Python version: 3.12+
Writing Tests¶
Choose tests that validate the behavior affected by your change. Reuse existing shared tests where applicable. Use sampling_mode for ordinary/survivor sampling, importance_sampling_mode for forced-fault sampling, or noncomp_sampling_api for leakage/loss trajectories. These fixtures test features across supported modes and let new modes inherit applicable tests.
Check that each test exercises the behavior it claims to cover. Configuration alone may not establish this: optimization can remove relevant work, and execution policies can select a different path. When adding an HIR optimization pass to kRegisteredPasses (including optional passes with default_enabled = false), register it in tests/test_pass_equivalence.cc with a planted scaffold where its rewrite metric fires, a paired positive/negative hazard-barrier case (EXP_VAL, Pauli and readout noise, resets, and feedback), and an exact distribution check against the dense reference oracle.
When testing parallel execution, provide enough work for multiple workers to contribute without asserting a particular scheduling outcome. Keep resource use bounded.
Mark measured high-cost sampling or fixture cases with Catch2 [expensive] or @pytest.mark.expensive so CI runs their full workload in optimized builds; retain small representative checks in Debug.
Exact comparisons and rare events¶
The C++ exact-distribution helpers compare each outcome's probability using a relative tolerance, including postselection's discarded mass. Conditional expectations have a separate absolute tolerance and are checked even on tiny positive branches. Aggregation retains every positive representable joint weight; an underflowed probability product fails instead of silently losing support. Invalid probabilities, nonfinite probes, and inconsistent normalization also fail.
For a rare-event fixture, pass an ExactComparisonBudget with max_omitted_probability smaller than the smallest probability being tested times its relative tolerance. The comparator rejects an excessive combined omission bound as inconclusive. Otherwise that bound is added to each probability comparison's error allowance. It bounds deliberate truncation, not floating-point roundoff: use an independent analytic or higher-precision calculation to justify the fixture's arithmetic accuracy. A total-mass check near one cannot establish accuracy on rare branches.
The dense circuit oracle's configurable cutoff applies to the conditional Born probability after normalization. Its default is 1e-18. Omitted mass is accumulated using the incoming joint history weight and is reported separately from postselection. Pauli noise and readout branches have no positive-probability cutoff. The Python noncomputational enumerator instead prunes joint weights, defaults to 1e-12, and reports dropped_mass. Rare fixtures can set prune_probability=0 and must call require_precision with their smallest signal and relative tolerance before using the reference.
The compact [rare_probability] C++ corpus uses stable closed-form Born probabilities and specified classical noise probabilities on at most two qubits. Its smallest two-measurement joint probability is about 6e-32; each conditional probability is above the FP64 production dust threshold. Arithmetic tolerances are 1e-9 relative, with omission budgets at least ten times smaller. These fixtures use direct enumeration or replay rather than waiting for rare samples. test_noncomp_enumerator_precision.py similarly calibrates initial populations, loss, and source-conditioned transitions against analytic weights. Both belong in regular CI.
Zero, numerical dust, and supported probabilities are separate cases. The reference-cutoff calibration covers FP64 and FP32 policies (1e-18 and 3.6e-12 respectively); it does not claim to execute a GPU backend. Production FP32 and FP64 policies remain distinct, and joint probabilities may be much smaller than a conditional dust cutoff. Do not loosen tolerances to accommodate an inconclusive reference; improve the reference or narrow the claim.
Running Tests¶
GPU behavioral tests¶
The sampling_mode fixture includes HIP and CUDA in FP64 and FP32 with automatic tier selection. Selected active-state tests also request explicit cooperative tiers. Each compiled program retains its own sampler, with a 65-shot batch limit to exercise batching and partial batches with bounded workspace. CPU and GPU modes share the behavioral assertions; identical random rows across backends are not required. Forced-fault sampling, noncomputational trajectories, and the CPU compiler-profile matrix keep their own fixtures.
GPU cases skip when their backend or device is unavailable.
Code Coverage¶
HTML reports are generated at coverage/python/index.html and coverage/cpp/index.html.