API stability¶
Research code outlives the version it was written against. A script from last year that no longer runs is not a small inconvenience — it is a result nobody can reproduce, and it is the most common complaint about every library in this field.
So this page is a promise, not a description.
What is promised¶
Everything exported from the top-level qmlkit namespace — qk.expectation,
qk.grad, qk.VQC, qk.QuantumKernel, the registries, and everything else in
qmlkit.__all__ — is public API. Within a major version:
- A public name will not be removed without a deprecation period.
- A public function will not change what it returns, or the meaning of an argument it already accepts.
- A default will not change silently. If a default changes, the old behaviour
stays reachable by passing the old value explicitly, and the change is in the
changelog under
Changed. - Numerical conventions are frozen: qubit 0 stays the most significant bit,
angles stay in radians, divergences stay in nats,
shots=Nonestays exact.
Names beginning with an underscore, and anything under qmlkit.core.* not
re-exported at the top level, are internal. They may change at any time.
The deprecation period¶
A public name that is going away:
- keeps working, and emits a
DeprecationWarningnaming its replacement; - stays that way for two minor releases;
- is removed only in the release after that, and only with a changelog entry.
A DeprecationWarning from qmlkit always names what to use instead. If one does
not, that is a bug worth reporting.
What is explicitly not promised¶
Being honest about the edges is what makes the rest of the promise worth having.
The 0.x line |
Semantic versioning allows breaking changes in 0.x, and this project uses that latitude — with the deprecation period above applied anyway wherever it is practical. The guarantees tighten at 1.0. |
| Exact floating-point output | Results are exact to the tolerances the test suite asserts, not bit-for-bit across versions, platforms, or NumPy releases. An optimisation that changes the last two digits is not a breaking change. |
| Performance | Speed may change in either direction. Where a change makes something slower for a plausible workload, it is in the changelog. |
| Simulator-only scope | The whole 0.x line is simulator-only. That is a scope decision, stated in the README, not something to be inferred from what happens to work. |
| Third-party conventions | If Qiskit, Cirq, PennyLane or SpinQit change a convention qmlkit maps onto, the mapping follows theirs. tests/test_cross_backend.py and tests/test_pennylane_parity.py exist to catch that when it happens. |
How you can check¶
The promise is only as good as the evidence for it, so:
- Executable documentation. Every Python block on this site runs in CI
(
tests/test_docs.py). An API change that breaks a documented example breaks the build before it reaches you. - Cross-library parity. 301 cases against PennyLane and every metric against scikit-learn, so a convention cannot drift unnoticed.
qk.fingerprint()records the versions that produced a number, so a result that stops reproducing can be traced to the layer that moved.
If you find something that broke without a deprecation, that is a bug — please open an issue.