qslib documentation
qslib is a quantum simulation library for finite lattice models. The project defines physical conventions first, then exposes the same checked objects through Rust, the command line, and Python.
Start here
- Scientific conventions - canonical site order, bits, physical axes, bases, couplings, boundaries, and normalization.
- CLI guide - run the four-site exact and tiny SSE examples.
- Installation - install the command, Rust library, and optional Python wheel.
- API stability review - understand the candidate 1.0 public surface and compatibility rules.
- Python guide - use the
qslib_quantumNumPy binding. - Geometry and interactions - pair-dependent and disordered couplings.
- Operators and models - Hamiltonian signs and model construction.
- Exact methods - basis enumeration, spectra, evolution, and residual diagnostics.
- Observables and statistics - totals, densities, axes, correlations, and uncertainty.
- TDVP - real- and imaginary-time statistics and solves.
- SSE - sign-safe finite-temperature sampling.
- IO - versioned configurations, checkpoints, and trajectories.
- Symmetry - site permutations, characters, and projections.
- Reproducibility - provenance, seeds, checksums, and uncertainty.
- Limitations - finite-system scope and numerical caveats.
- Migration from ncli
- Migration from standalone SSE
API reference
Build the Rust API reference locally with:
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --all-features
The generated entry point is target/doc/qslib/index.html. The combined
published site also provides the Rust API reference.
The API reference is generated output and is intentionally not committed to
the source tree.
Architecture and governance
All worked examples in the CLI guide are executed by integration tests. The Python wheel and its contract tests are built separately because Python is an optional foreign-function boundary rather than a dependency of the Rust core.
Installation
qslib is currently distributed as source, a Rust workspace, and an optional
Python wheel. The release bundle contains the qslib command, API docs, and
wheel artifacts when those platform builds are available. Registry publication
is still owner-gated, so the commands below distinguish the prepared future
install path from the currently available local path.
Third-party installation channels
After an authorized versioned release, the supported package-manager commands will be:
cargo add qslib-quantum --version 1.0.0 --features exact
python -m pip install qslib-quantum==1.0.0
The Rust distribution is named qslib-quantum but its library target remains
qslib, so Rust code writes use qslib::.... The Python distribution is also
named qslib-quantum, while its collision-safe import is qslib_quantum.
The command-line binary is named qslib and is distributed in platform
archives attached to the GitHub release. Pin a release version in automated
workflows and verify the accompanying SHA256SUMS file before installation.
Before registry publication, a versioned Git dependency is the reproducible Rust fallback:
[dependencies]
qslib-quantum = { git = "https://github.com/lere01/qslib", tag = "v0.1.0", features = ["exact"] }
Use the source-checkout and local-wheel instructions below when the referenced tag or release asset is not yet available.
Run the command locally
From a source checkout with Rust 1.85 or newer:
cargo run --locked -p qslib-quantum-cli -- inspect conventions
For a local optimized binary:
cargo build --locked --release -p qslib-quantum-cli
target/release/qslib inspect environment
Rust library
Add the facade to a Rust application using a local checkout while the v1 crate remains unpublished:
[dependencies]
qslib-quantum = { path = "../qslib" }
Enable only the capabilities needed by the application, such as exact,
variational, sse, or io. The public Rust API is linked from the combined
Rust API reference.
Python binding
Install a platform wheel from a release bundle with:
python -m pip install qslib_quantum-*.whl
The import name is qslib_quantum; the Python package exposes NumPy-backed
exact, observable, and TDVP contracts documented in Python bindings.
Verify an installation
Every release bundle includes SHA256SUMS. Verify the files before use, then
run:
qslib inspect conventions --json
qslib conformance self-test --json
The self-test is a one-fixture smoke test. Scientific production runs must also execute the full conformance and model-specific validation suites.
API stability review
This is the pre-1.0 public API freeze record for qslib. It complements the Rust documentation: rustdoc explains what an item calculates, while this page records whether a physicist or downstream integrator may rely on that item in the 1.0 contract.
Stability dispositions
| Surface | Disposition | Compatibility rule |
|---|---|---|
qslib facade and qslib::core | Candidate 1.0 stable | The default facade is core-only. Re-exports preserve canonical basis, geometry, interaction, model, operator, randomness, scalar, and symmetry meanings. |
qslib::exact | Candidate 1.0 stable behind exact | Exact matrices, spectra, residuals, observables, thermodynamics, and evolution retain their documented conventions and quantity-specific errors. |
qslib::variational | Candidate 1.0 stable behind variational | TDVP statistics, regularization, solver provenance, and transactional evolution retain their documented signs and metadata. |
qslib::sse | Candidate 1.0 stable behind sse | SSE update semantics, chain seeds, measurements, and confidence metadata retain the canonical qslib conventions. |
qslib::io | Candidate 1.0 stable behind io | Versioned schemas are separate compatibility contracts. Unknown fields and unsupported schema versions remain errors. |
qslib-quantum-cli | Candidate 1.0 user interface | Commands, physically labelled JSON fields, schema identifiers, and error categories are tested semantic interfaces. Human-readable prose may improve without changing machine fields. |
qslib-quantum-python | Candidate 1.0 Python interface | The ABI3 module owns returned arrays and exposes only documented coarse-grained kernels. NumPy shape, dtype, order, and exception contracts are tested. |
qslib-sse::legacy | Stable migration adapter, not a new model API | Legacy spin labels and seed reproduction are explicit compatibility tools. They do not redefine canonical qslib behavior. |
qslib-test-support | Internal test-support surface | Fixtures and oracle helpers are for conformance tests and are not part of the published scientific API. |
Enum and extension policy
The binary-state, site-order, basis-axis, boundary, lattice, interaction, Pauli, and model-family enums describe the currently supported scientific contract. They are intentionally documented as closed for qslib 1.0: adding a new physical meaning requires a convention review, independent reference fixtures, and a compatibility decision.
Error enums and numerical-control enums are also candidate-stable, but their
variants are not a license for callers to infer undocumented implementation
details. A new error or backend algorithm requires an API review, a rustdoc
entry, conformance tests, and an explicit semver decision before it is added.
No experimental algorithm is re-exported from a stable module, and the
repository currently has no experimental module or feature.
Freeze evidence
- Every production crate denies missing public documentation.
- The facade has an empty default feature set and additive capability features; feature-boundary tests verify the dependency policy.
- The current facade was compared with baseline commit
2584261bycargo-semver-checks 0.42.0as an assumed patch release: 165 checks passed and 12 were skipped. - The SSE sampler no longer suppresses deprecated RNG traits; it uses the
current
rand_core::Rngcontract explicitly. - Public JSON and serialized artifacts carry independent version identifiers; Rust storage layout is not treated as a schema guarantee.
Before a 1.0 tag, a maintainer must rerun the semver check against the selected release baseline, review any newly exported item, and update this page if an API moves from candidate-stable to an explicitly experimental or migration status. This review does not authorize publication, tagging, or remote changes.
qslib scientific conventions
Specification identifier: qslib-conventions-v1
Status: normative draft for the first qslib implementation
1. Purpose and authority
This document defines the scientific and data conventions shared by qslib components. It is the authority for geometry, basis states, Hamiltonians, symmetries, observables, exact calculations, stochastic estimators, TDVP, SSE, serialization, and interoperability.
An implementation is conforming only when it follows these conventions or requires the caller to select a separately named compatibility convention. Legacy behavior must never be selected silently.
The words must, must not, should, should not, and may are normative. A public API may use different Rust type names, but it must preserve the meanings defined here.
2. General principles
- Physical definitions are independent of simulation algorithms.
- A basis representation is not itself a physical spin or occupation value.
- Site ordering, bit ordering, boundary behavior, and normalization are part of the scientific input and reproducibility record.
- Total quantities and densities must have distinct names.
- Algorithmic shifts, regularizers, truncations, and gauges must not silently alter the physical Hamiltonian.
- Invalid dimensions, indices, coefficients, or states must produce errors. They must not be repaired by wrapping, clipping, or dropping data unless the requested operation explicitly defines that behavior.
3. Units and scalar conventions
3.1 Natural units
qslib uses
[ \hbar = 1, \qquad k_B = 1. ]
Hamiltonian coefficients have units of energy. Time has units of inverse energy, inverse temperature is
[ \beta = \frac{1}{T}, ]
and frequencies specified as Hamiltonian coefficients are angular frequencies. An API accepting dimensional input must require one internally consistent unit system. qslib does not infer unit conversions from numerical magnitudes.
3.2 Real and complex values
Built-in TFIM, J1-J2, and Rydberg Hamiltonian coefficients are real. General Hamiltonian terms may be complex only when Hermiticity requirements are explicitly satisfied or the operator is explicitly declared non-Hermitian.
Reference calculations should use f64 and Complex<f64>. Lower precision may
be used for accelerated execution, but the dtype must be recorded and
accumulations that affect scientific results should use at least f64 when the
backend supports it.
NaN and infinity are invalid configuration values. Runtime non-finite values must be reported as numerical failures with context.
3.3 Angles and phases
Angles are measured in radians. Phases are equivalent modulo (2\pi), but stored log-wavefunction phases are not required to be reduced to a principal interval.
4. Identifiers and collection sizes
Sites are numbered by a zero-based SiteId. The first valid site is 0, and a
system with (N) sites contains exactly
[ 0, 1, \ldots, N-1. ]
The intended Rust representation is a checked newtype over u32. Collection
lengths and memory indices use usize. Conversion from usize to SiteId
must be checked.
Bond and term identifiers are also zero-based. An identifier is stable only within the owning validated object unless a serialized schema explicitly guarantees broader stability.
Simulation geometries must contain at least one site. Arithmetic used to derive site counts, Hilbert-space dimensions, or allocation sizes must be checked for overflow.
5. Lattice geometry and site order
5.1 Coordinate axes
Two-dimensional coordinates are written (x, y). x increases horizontally
and y increases vertically in mathematical descriptions. Display software
may invert the visual y direction, but that must not change site identifiers or
physical coordinates.
5.2 Canonical rectangular indexing
Rectangular lattices use row-major indexing:
[ i(x,y) = x + L_x y, ]
with
[ 0 \le x < L_x, \qquad 0 \le y < L_y. ]
The inverse mapping is
[ x = i \bmod L_x, \qquad y = \left\lfloor\frac{i}{L_x}\right\rfloor. ]
Thus a dense array with logical shape [Ly, Lx] has site i at [y, x] and
its C-order flattening is the canonical site vector.
The expression x * Ly + y is called legacy x-major indexing. It is not a
qslib site order and must be handled through an explicit permutation adapter.
5.3 Chains
A chain of length (L) is embedded along the positive x axis:
[ \mathbf r_i = (i,0). ]
It uses site order 0, 1, ..., L-1.
5.4 Square and rectangular embeddings
The default rectangular embedding has unit lattice vectors
[ \mathbf a_1=(1,0), \qquad \mathbf a_2=(0,1), ]
and
[ \mathbf r(x,y)=x\mathbf a_1+y\mathbf a_2. ]
Non-unit spacing must be explicit in the geometry.
5.5 Triangular embedding
The canonical triangular embedding uses integer cell coordinates with
[ \mathbf a_1=(1,0), \qquad \mathbf a_2=\left(\frac12,\frac{\sqrt3}{2}\right). ]
Site indexing remains x + Lx*y. Geometry and site order are separate from the
real-space embedding.
5.6 Custom geometry
A custom geometry is an ordered collection of finite Cartesian coordinates.
Coordinate entry i belongs to SiteId(i). Duplicate coordinates are invalid
for models containing singular distance-dependent interactions, but may be
accepted by purely graph-defined models when explicitly allowed.
5.7 Physical order versus scan order
Autoregressive scan order, patch order, memory tiling, and distributed
partitioning do not change physical site identifiers. Any non-canonical scan
order must be represented by an explicit bijection between sequence positions
and canonical SiteId values.
6. Boundaries, displacement, and distance
6.1 Boundary names
Canonical boundary values are open and periodic. Abbreviations such as
obc and pbc are accepted only by named compatibility parsers.
Each independent lattice direction may have its own boundary condition.
6.2 Open boundaries
Open boundaries do not wrap coordinates. A neighbour step leaving the finite domain produces no bond.
6.3 Periodic boundaries
Periodic boundaries identify coordinates separated by integer simulation-cell translations. Wrapping an integer coordinate uses Euclidean modulo and always returns a coordinate in the half-open interval beginning at zero.
6.4 Minimum-image displacement
The displacement from site i to site j is
[ \Delta\mathbf r_{ij}=\mathbf r_j-\mathbf r_i ]
reduced to a minimum-length periodic image when periodic directions exist.
For an orthogonal direction of length (L), the canonical scalar reduction is
[ d’ = d - L\left\lfloor\frac{d+L/2}{L}\right\rfloor, ]
which lies in ([-L/2,L/2)).
For a skew periodic cell, the selected image must minimize Euclidean length over valid cell translations. If multiple images have exactly equal length, the integer cell-translation vector is chosen in lexicographic order. This tie rule makes oriented displacements deterministic.
Distance is the Euclidean norm of the canonical displacement. Squared distance should be used when a square root is unnecessary.
6.5 Long-range periodic interactions
The default periodic long-range interaction uses one minimum-image separation for each unordered site pair. It is not an Ewald sum and does not include multiple periodic images. Ewald, cutoff, image-sum, or experimentally supplied interaction matrices must be separate named policies.
7. Bonds, pair sets, and interaction graphs
An undirected bond has two distinct endpoints and is canonically represented as
[ (\min(i,j),\max(i,j)). ]
A bond defines topology. A weighted interaction additionally associates a coefficient and operator channel with that bond. Couplings belong to weighted interactions, not to the bond set as a whole. The canonical resolved form is
[ (i,j,\kappa_{ij},\text{channel}), ]
where i < j, kappa_ij is finite, and channel identifies the operator
acted on by the coefficient. For example, an isotropic Heisenberg interaction
has channel heisenberg_exchange and coefficient (J_{ij}).
Distinct channels may act on the same unordered pair. Multiple contributions to the same pair and channel are also allowed when they represent distinct periodic images or named physical terms. A canonicalization operation may sum algebraically identical contributions, but it must preserve enough provenance to reconstruct how the resolved coefficient was obtained.
An interaction identity consists of its canonical endpoints, operator channel, and, when relevant, periodic-image or named-term identity. Shell membership is metadata rather than identity unless two shell contributions to the same pair are intended to remain distinct. Pair-dependent data must be keyed by this identity, never by incidental insertion or hash-map iteration order.
A canonical simple bond set:
- rejects self-bonds;
- contains each unordered pair at most once;
- is sorted lexicographically when serialized or returned as canonical output.
Tiny periodic lattices may connect the same pair through more than one lattice direction. qslib distinguishes:
simplemultiplicity, which stores the unordered pair once;periodic_imagesmultiplicity, which stores each physically distinct image or directed step with explicit multiplicity.
Built-in model constructors use simple multiplicity unless their API or
serialized specification says otherwise. Multiplicity is part of the physical
model and must be included in fingerprints.
A uniform coupling, a coupling per geometric shell, and a coupling per pair are three input forms for the same resolved weighted-interaction collection. Uniform and shell-based inputs are convenience constructors. They must be expanded and validated before Hamiltonian evaluation. No evaluator may assume that all entries in an interaction collection share one coefficient.
Pair-dependent couplings may be positive, negative, or zero. Canonical output should omit exactly zero weighted terms from numerical evaluation, while provenance may retain them when their presence is scientifically meaningful. Signed zero is not scientifically distinct.
A sparse pair table and a dense coupling matrix are equivalent input forms. A
dense matrix for an undirected scalar channel must have shape [N,N], be
symmetric within a declared validation tolerance, and have a zero diagonal
unless onsite terms are part of that channel. It is resolved from entries with
i < j, so symmetric entries are never counted twice. A sparse table must
reject duplicate interaction identities unless its schema explicitly declares
that duplicates are additive.
For quenched disorder, the durable run description must store the realized coefficient associated with every interaction identity. A distribution name and random seed are useful provenance but are not substitutes for the realized coupling table. Generation order must be defined from canonical interaction order rather than map iteration or worker scheduling.
Distance shells are selected by a target squared distance and a non-negative tolerance. A shell selector must state whether tolerance is absolute or relative. The default is absolute tolerance.
8. Binary basis states
8.1 Canonical bit meaning
Each two-level site is stored as a bit (b_i\in{0,1}). In a simulation basis associated with Pauli axis (a),
[ \sigma_i^a |b_i\rangle = (1-2b_i)|b_i\rangle. ]
Therefore:
| Bit | Axis eigenvalue | Canonical label |
|---|---|---|
0 | +1 | Plus |
1 | -1 | Minus |
APIs should prefer Plus and Minus over Up and Down, because the latter
are used inconsistently across physics communities.
The Pauli eigenvalue conversion is
[ z(b)=1-2b=(-1)^b. ]
8.2 Rydberg occupation
The canonical Rydberg occupation is
[ n_i=b_i=\frac{1-\sigma_i^z}{2}. ]
Thus bit 0 is the unoccupied ground state and bit 1 is the occupied Rydberg
state. This convention is intentionally separate from the names Plus and
Minus.
An alternate convention (n=(1+Z)/2) must be represented by an explicit basis or compatibility transform. It must not reuse the same serialized state label.
8.3 Dense state layout
A batch of basis states has logical shape [batch, site]. The site dimension is
in canonical site order. Accepted scalar storage types may include booleans and
unsigned integers, but every value must be exactly zero or one.
8.4 Bit-packed state and endianness
Bit-packed states are little-endian by site identifier:
[ m(b)=\sum_{i=0}^{N-1} b_i 2^i. ]
Site 0 is the least significant bit. Full computational-basis state vectors
use mask m as the vector index. The basis order is therefore
[ |00\ldots0\rangle, |10\ldots0\rangle, |01\ldots0\rangle, \ldots ]
when site 0 is written first inside the ket.
For more sites than fit in one machine word, words are ordered from least to most significant and each word is itself little-endian by site identifier. Serialized packed states must record the word width.
8.5 Fixed-occupation sectors
The Hamming weight is
[ K(b)=\sum_i b_i. ]
A fixed sector contains states with one declared value of K. Sector basis
states are ordered by increasing packed integer value unless another order is
explicitly named. A Hamiltonian may use this sector only if it conserves
Hamming weight in the selected simulation basis.
9. Physical axes and simulation bases
Physical operators are expressed in a fixed physical frame with axes x, y,
and z. A simulation basis states which physical Pauli operator is diagonal in
the stored bits.
In simulation basis z, bit values encode physical (Z) eigenstates. In
simulation basis x, they encode physical (X) eigenstates. A basis change
does not relabel the physical Hamiltonian or observables.
The Hadamard rotation satisfies
[ H Z H = X, \qquad H X H = Z. ]
Consequently, the physical TFIM
[ H_{\mathrm{TFIM}}=-J\sum_{\langle i,j\rangle}Z_iZ_j-h\sum_iX_i ]
is represented in simulation basis x as
[ H_{\mathrm{TFIM},x}=-J\sum_{\langle i,j\rangle}X_iX_j-h\sum_iZ_i. ]
Initial-state specifications must distinguish physical polarization from the
simulation basis. For example, physical PlusZ is the all-zero bitstring only
in simulation basis z; in simulation basis x it is a superposition.
10. Wavefunctions and state vectors
A wavefunction assigns a complex amplitude (\psi(b)) to each basis state. Unless explicitly normalized,
[ Z_\psi=\sum_b |\psi(b)|^2 ]
need not equal one. Sampling probability is
[ p(b)=\frac{|\psi(b)|^2}{Z_\psi}. ]
The canonical complex log wavefunction is
[ \log\psi(b)=\log|\psi(b)|+i\arg\psi(b). ]
Its imaginary part may be unwrapped. Ratios are evaluated as
[ \frac{\psi(b’)}{\psi(b)}= \exp\left(\log\psi(b’)-\log\psi(b)\right). ]
A zero amplitude has real log amplitude -infinity. Algorithms must handle
such states deliberately and must not create NaN through an unguarded
-infinity - -infinity operation.
Global complex phase does not affect physical observables. State-vector comparisons that are intended to be phase insensitive must align or eliminate global phase explicitly.
11. Pauli and spin operators
The Pauli matrices are
[ X=\begin{pmatrix}0&1\1&0\end{pmatrix},\quad Y=\begin{pmatrix}0&-i\i&0\end{pmatrix},\quad Z=\begin{pmatrix}1&0\0&-1\end{pmatrix}. ]
Spin-half operators use
[ S^a=\frac12\sigma^a. ]
In simulation basis z, X_i flips bit i, while Z_i multiplies a state by
1 - 2*b_i. A product of X operators flips every listed site exactly once.
Repeated Pauli factors on the same site must be algebraically reduced rather
than represented as duplicate flips.
Operator support is an ordered or canonical set of distinct SiteId values as
required by the operator. Support arity is validated.
12. Hamiltonian conventions
12.1 General term representation
A physical Hamiltonian is
[ H=cI+\sum_a c_a O_a. ]
The scalar constant c is part of the physical energy. Algorithmic shifts used
for sampling or solving are stored separately.
Term order has no physical meaning. Duplicate algebraically identical terms may be combined, but the combination procedure must be deterministic.
Every resolved term carries its own coefficient (c_a). Writing one coupling outside a sum is only shorthand for assigning that value to every term in the sum. Public model representations and Hamiltonian evaluators must support term-dependent coefficients. A representation may factor a common numerical scale for storage or performance, but its resolved physical coefficient is the product of that scale and the term weight and must be used in serialization, fingerprinting, validation, and cross-backend comparisons.
12.2 Transverse-field Ising model
The general pair-dependent TFIM is
[ H=-\sum_{(i,j)\in E}J_{ij}Z_iZ_j-\sum_i h_iX_i. ]
The homogeneous notation (-J\sum Z_iZ_j-h\sum X_i) is a constructor shorthand
for J_ij=J and h_i=h. Each weighted bond contributes once, including any
explicit multiplicity. Positive J_ij is ferromagnetic in this convention.
qslib model construction permits any finite real J_ij and h_i; a particular
algorithm may impose additional sign restrictions.
In simulation basis z:
- diagonal contribution from pair
(i,j): (-J_{ij} z_i z_j); - connected state for each field term: flip site
iwith matrix element (-h_i).
In simulation basis x:
- diagonal contribution: (-h_i z_i), where
z_i=1-2*b_inow labels the physical X eigenvalue; - connected state for each bond: flip sites
iandjwith matrix element (-J_{ij}).
12.3 Heisenberg exchange and the J1-J2 model
The general isotropic pair-dependent Heisenberg exchange model is
[ H=\sum_{(i,j)\in E}J_{ij},\mathbf S_i\cdot\mathbf S_j. ]
Positive J_ij is antiferromagnetic and negative J_ij is ferromagnetic.
With (\hbar=1) and simulation basis z, one bond has
[ \langle b|H_{ij}|b\rangle=\frac{J_{ij}}{4}z_i z_j. ]
If the two bits are different, the pair-flipped state has matrix element
[ \langle b^{ij}|H_{ij}|b\rangle=\frac{J_{ij}}{2}. ]
Parallel bits have no off-diagonal connection from that bond. This Hamiltonian
conserves Hamming weight in simulation basis z.
The homogeneous J1-J2 model is the specialization
[ H=J_1\sum_{(i,j)\in E_1}\mathbf S_i\cdot\mathbf S_j +J_2\sum_{(i,j)\in E_2}\mathbf S_i\cdot\mathbf S_j, ]
expanded to J_ij=J1 on E1 and J_ij=J2 on E2. The sets E1 and E2
must state their geometric meaning. For the unit square lattice, E1 is the
axial nearest-neighbour shell and E2 is the diagonal next-nearest-neighbour
shell.
A disordered J1-J2 model may instead assign a distinct realized coupling to
each member of either shell, for example (J_{ij}^{(1)}) on E1 and
(J_{ij}^{(2)}) on E2. This remains an isotropic Heisenberg exchange model
with J1-J2 geometry, but it is not the homogeneous two-parameter J1-J2 model.
Its input must say whether values are supplied directly, drawn independently,
or generated with spatial correlations.
Pair-dependent values constitute bond disorder. They produce frustration only
when the preferred local bond constraints cannot all be satisfied, as can
happen through mixed signs, competing interaction shells, or lattice geometry.
Documentation and result metadata should not use disordered and frustrated
as synonyms.
If the same pair occurs in more than one shell or periodic image, the physical contributions are additive unless the model explicitly treats the images as separate channels. The resolved representation must make this choice visible.
12.4 Rydberg model
The canonical driven Rydberg Hamiltonian is
[ H=-\frac{\Omega}{2}\sum_i X_i -\Delta\sum_i n_i +\sum_{i<j}V_{ij}n_i n_j, \qquad n_i=b_i=\frac{1-Z_i}{2}. ]
For van der Waals interactions,
[ V_{ij}=\frac{C_6}{r_{ij}^6}. ]
An interaction matrix must be symmetric, finite, and have a zero diagonal unless a separately defined onsite term is intended. When the complete matrix is used, the diagonal energy is evaluated either as
[ \sum_{i<j}V_{ij}n_i n_j ]
or equivalently
[ \frac12\sum_{i,j}V_{ij}n_i n_j. ]
Each site flip has matrix element (-\Omega/2). Omega, Delta, and C6 are
finite real values. Algorithms may restrict their signs, but the physical
model does not silently take absolute values.
12.5 Basis-aware construction
A model specification describes a physical Hamiltonian. Conversion to a simulation basis produces an equivalent operator representation. The original physical specification and selected simulation basis must both remain available for provenance and observable evaluation.
13. Hamiltonian action and local energy
For a basis state b, a Hamiltonian action consists of:
- its diagonal matrix element (H_{bb});
- connected states (b’\ne b) with nonzero matrix elements (H_{bb’}).
Connected states must be unique after applying all flips. Contributions from different terms leading to the same state may be returned separately or combined, but the selected behavior must be explicit.
The variational local energy is
[ E_{\mathrm{loc}}(b)= \frac{\langle b|H|\psi\rangle}{\langle b|\psi\rangle} =H_{bb}+\sum_{b’\ne b}H_{bb’}\frac{\psi(b’)}{\psi(b)}. ]
The variational energy is
[ E=\mathbb E_{p(b)}[E_{\mathrm{loc}}(b)]. ]
For a Hermitian Hamiltonian the exact expectation is real. A measured imaginary component must be retained as a diagnostic rather than silently discarded.
Energy variance is
[ \operatorname{Var}(H)= \mathbb E_p\left[|E_{\mathrm{loc}}-E|^2\right]. ]
energy_variance_density means Var(H)/N. A quantity divided by N^2 must use
a different explicit name.
14. Symmetry conventions
14.1 Site permutations
A site permutation stores source_for_destination:
[ (g\cdot b)j=b{p_g(j)}. ]
This definition matches gather-style array indexing. APIs must not describe the
same array ambiguously as both old_to_new and new_to_old. Conversion to a
destination-for-source representation requires an explicit inverse.
A permutation must be a bijection over 0..N. Composition and inversion must
be tested against the action above.
14.2 Lattice transformations
A translation by (dx, dy) maps physical coordinates to
[ (x,y)\mapsto(x+dx,y+dy) ]
with periodic wrapping where defined. Point-group operations act on physical coordinates and are then converted to canonical site permutations.
14.3 Group projection
For a finite group G and one-dimensional unitary character chi, the
projected wavefunction convention is
[ (P_\chi\psi)(b)=\frac{1}{|G|} \sum_{g\in G}\chi(g)^*\psi(g^{-1}\cdot b). ]
The trivial representation has chi(g)=1. Any implementation using an
equivalent change of summation variable must demonstrate parity with this
definition.
14.4 Spin inversion
Global spin inversion maps every bit as
[ b_i\mapsto1-b_i. ]
It is a symmetry only when it commutes with the physical Hamiltonian in the selected parameters and basis.
14.5 Diagonal sign and phase gauges
A diagonal gauge acts as
[ \psi’(b)=e^{i\phi(b)}\psi(b). ]
The standard linear gauge form is
[ \phi(b)=\pi\sum_i a_i b_i. ]
Integer a_i values produce signs. Non-integer values produce general phases
and must not be described as a sign-only Marshall transformation. A gauge
changes the representation of amplitudes and operator matrix elements but not
physical predictions when applied consistently.
15. Observable normalization
15.1 Energy
energy is total energy (\langle H\rangle). energy_density and
energy_per_site both mean
[ e=\frac{\langle H\rangle}{N}. ]
Public schemas should choose one canonical field name and treat the other as a documented alias only at compatibility boundaries.
15.2 Magnetization
Total and per-site magnetization are
[ M_a=\sum_i\sigma_i^a, \qquad m_a=\frac{M_a}{N}. ]
A field named sigma_a in aggregate output means (m_a), not (M_a).
15.3 Correlations
The two-site Pauli correlation is
[ C_{aa}(i,j)=\langle\sigma_i^a\sigma_j^a\rangle. ]
The connected correlation is
[ C^{\mathrm c}{aa}(i,j)=C{aa}(i,j) -\langle\sigma_i^a\rangle\langle\sigma_j^a\rangle. ]
A shell or distance average is the arithmetic mean over the explicitly selected pair set. Ordered and unordered pair averages must not share a field name unless their normalization makes them identical.
15.4 Structure factor
The raw static structure factor is
[ S_{aa}(\mathbf q)=\frac1N\sum_{i,j} e^{i\mathbf q\cdot(\mathbf r_i-\mathbf r_j)} \langle\sigma_i^a\sigma_j^a\rangle. ]
The connected structure factor replaces the correlation with its connected
form and must be named accordingly. Wavevectors are Cartesian and satisfy that
q dot r is dimensionless.
15.5 Sublattice order
For real weights w_i,
[ m_w=\frac1N\sum_i w_i\sigma_i^z. ]
Outputs must distinguish (\langle m_w\rangle), (\langle|m_w|\rangle), and (\langle m_w^2\rangle). They are not interchangeable order parameters.
15.6 Quantum Fisher information
For the pure-state generator
[ G=\frac12\sum_i w_i\sigma_i^z, ]
qslib defines
[ F_Q=4\operatorname{Var}(G) =\operatorname{Var}\left(\sum_i w_i\sigma_i^z\right), \qquad f_Q=\frac{F_Q}{N}. ]
The factor of four is therefore already absorbed by using Pauli values in the last expression. APIs using a different generator must report it explicitly.
15.7 Thermal observables
With kB=1, heat capacity is
[ C=\beta^2\left(\langle H^2\rangle-\langle H\rangle^2\right), \qquad c=C/N. ]
16. Exact bases and exact solvers
A full two-level Hilbert space has dimension (2^N). A fixed-Hamming-weight sector has dimension
[ \binom NK. ]
Exact basis enumeration follows increasing little-endian packed-state value. Sparse matrices use basis indices, not raw packed masks, when a restricted sector is active.
Eigenvalues are returned in ascending algebraic order unless the request names another ordering. Eigenvectors are columns and correspond one-to-one with the returned eigenvalues.
Degenerate eigenspaces do not have unique eigenvectors. Tests must compare the invariant subspace or projector rather than individual vector phases and bases.
Real-time exact evolution uses
[ |\psi(t)\rangle=e^{-iHt}|\psi(0)\rangle. ]
Imaginary-time evolution uses (e^{-\tau H}) followed by explicit normalization when a normalized state is required.
17. Stochastic samples and statistics
A sample batch has shape [sample, site]. Sample count refers to the leading
dimension after all distributed partitions are combined.
Means use normalized sample weights. Unweighted samples have equal weight. Exact enumeration weights must sum to one after normalization.
An IID standard error for real values is
[ \mathrm{SE}=\frac{s}{\sqrt B}, ]
where s is the sample standard deviation with denominator B-1. This formula
must not be reported for correlated Markov-chain samples without an effective
sample-size correction.
Complex estimators retain real and imaginary sample statistics. A real-only summary may be produced only when the discarded imaginary component remains available as a diagnostic.
Independent-chain aggregation must distinguish within-chain Monte Carlo error from between-chain variation. R-hat, effective sample size, and integrated autocorrelation time must name the algorithm used because multiple estimators exist.
For quenched disorder, expectation at fixed realization and the disorder
ensemble average are distinct operations. Using r for a realization,
[ \overline{\langle A\rangle} =\sum_r w_r\langle A\rangle_r, \qquad \sum_r w_r=1. ]
Outputs must retain the realization identifier and fixed-realization estimate before ensemble reduction. Uncertainty from stochastic sampling within each realization and uncertainty from the finite realization ensemble must be reported separately. A run with one realization has no empirical estimate of disorder-ensemble uncertainty.
18. Variational geometry and TDVP
For real parameters (\theta_k), define complex log derivatives
[ O_k(b)=\frac{\partial\log\psi(b)}{\partial\theta_k}, \qquad \Delta O_k=O_k-\langle O_k\rangle. ]
The real-parameter quantum geometric tensor is
[ S_{kl}=\operatorname{Re}\left\langle \Delta O_k^*\Delta O_l \right\rangle. ]
Define the complex energy covariance
[ F_k=\left\langle\Delta O_k^* \left(E_{\mathrm{loc}}-\langle E_{\mathrm{loc}}\rangle\right) \right\rangle. ]
The canonical equations are
[ S\dot\theta=\operatorname{Im}F \quad\text{for real time}, ]
and
[ S\dot\theta=-\operatorname{Re}F \quad\text{for imaginary time}. ]
Empirical covariances use denominator B, matching expectation-value
estimators. Statistical uncertainty estimates may use B-1 where appropriate.
Regularization is part of the numerical solve, not the physical QGT. A result must record the requested and effective backend, regularization method, regularization magnitude, spectral cutoff, convergence tolerance, iteration count, and residual.
For a solved direction v and mode-specific right-hand side f, the projected
residual diagnostic is
[ r^2=\operatorname{Var}(H)+v^T S v-2v^T f. ]
The normalized residual is r2 / Var(H) when variance is nonzero. Numerical
flooring used at zero variance must be recorded.
Parameter flattening order must be deterministic and fingerprinted. Restoring a checkpoint with a different parameter-layout fingerprint is an error.
19. Time integration
An integrator state records at least physical time, parameters, proposed next step, accepted-step count, and rejected-step count.
Adaptive attempts are transactional. A rejected attempt must not change physical time, accepted parameters, accepted trajectory, or the random streams assigned to accepted time nodes.
Step-error norms must state their metric and normalization. A QGT norm uses
[ |\delta|_S=\sqrt{\delta^T S\delta}. ]
If this value is divided by parameter count or another scale, the output and tolerance specification must say so explicitly.
Trajectory observations are associated with accepted states. Attempt logs may include rejected states but must not present them as physical trajectory points.
20. SSE decomposition conventions
An SSE decomposition may write the physical Hamiltonian as
[ H=E_{\mathrm{shift}}-\sum_a B_a, ]
where sampled matrix elements of B_a are non-negative. E_shift is an
algorithmic decomposition value derived from the physical Hamiltonian. It does
not modify that Hamiltonian.
For expansion order n, inverse temperature beta, and this sign convention,
[ E=E_{\mathrm{shift}}-\frac{\langle n\rangle}{\beta}, ]
and
[ C=\langle n^2\rangle-\langle n\rangle^2-\langle n\rangle. ]
Reported physical results must restore the shift. SSE-specific operator kinds, padding identities, and update vertices must not be exposed as physical Hamiltonian operators.
21. Determinism and numerical validation
Canonical collections such as bond sets, site permutations, sectors, and connected-state lists must have deterministic ordering.
A seed alone is not a complete reproducibility contract. Reproducible output must identify the random-number algorithm, qslib version, convention version, threading or distributed policy where it affects reduction order, and relevant floating-point dtype.
Parallel scheduling must not change per-chain random streams. Chain or job seeds should be derived from a master seed and stable logical index rather than worker identity.
Floating-point equality tolerances belong to the tested quantity. qslib must not define one global epsilon for geometry, Hermiticity, solver convergence, and physical parity tests.
Reference parity tests should use f64, deterministic inputs, and small systems
whose full matrices or state spaces can be independently enumerated.
22. Serialization and schema evolution
Every durable scientific document must include a schema version. Documents governed by this specification include
convention_schema: qslib-conventions-v1
Canonical serialized enum values use lowercase snake case. Examples include
open, periodic, row_major, z, real_time, and imaginary_time.
Versioned input schemas should reject unknown fields by default. Compatibility loaders may accept legacy fields, but they must resolve them into a canonical document before simulation.
Serialized multidimensional arrays must record shape, dtype, and flattening order. Native Rust, NumPy, Torch, or BLAS memory layout must not be inferred from an unlabelled byte sequence.
Serialized complex JSON scalars use an object with named real and imaginary parts:
{"re": 1.0, "im": -0.25}
Binary formats may use interleaved or split complex storage only when the format metadata identifies it.
Scientific fingerprints must include all convention-sensitive fields, including site order, bit convention, simulation basis, boundary policy, bond multiplicity, every resolved Hamiltonian coefficient, and convention schema. For disordered models they must also include the canonical interaction identities and realized coupling table. Distribution parameters, correlation rules, and random-generator details must be stored as provenance when qslib generated that table.
A breaking change to any normative mapping or normalization requires a new convention schema identifier.
23. Interoperability with existing projects
23.1 ncli dynamics and modern row-major paths
The modern ncli dynamics path uses site = x + Lx*y, little-endian exact basis
masks, bit 0 -> +1, bit 1 -> -1, and Rydberg occupation = bit. These map
directly to qslib after validation of Hamiltonian signs and boundary policy.
23.2 ncli legacy x-major paths
Legacy J1-J2 and symmetry paths may use
[ i_{\mathrm{legacy}}=xL_y+y. ]
They require an explicit permutation to qslib row-major order. Stripe labels and directional observables must be transformed with the state. Merely reinterpreting the same flat array is invalid.
23.3 Existing Rust SSE states
The existing SSE crate uses row-major geometry, but its Spin type combines
two conventions:
- TFIM interprets
Upas Pauli-Z+1; - Rydberg interprets
Upas occupied.
Under qslib, occupied Rydberg state has Pauli-Z value -1. Therefore there is
no universal raw enum conversion from legacy SSE Spin to qslib bits.
Adapters must be model aware:
| Meaning | qslib bit | legacy SSE state |
|---|---|---|
Pauli-Z +1 | 0 | Up |
Pauli-Z -1 | 1 | Down |
| Rydberg unoccupied | 0 | Down |
| Rydberg occupied | 1 | Up |
New shared code must use qslib basis and occupation types rather than extending the ambiguous legacy enum.
24. Required conformance vectors
Implementations must include equivalent automated tests for the following vectors.
24.1 Rectangular indexing
For Lx=3, Ly=2:
(x,y) | Site |
|---|---|
(0,0) | 0 |
(1,0) | 1 |
(2,0) | 2 |
(0,1) | 3 |
(1,1) | 4 |
(2,1) | 5 |
The open square-lattice nearest-neighbour simple bond set is
(0,1), (0,3), (1,2), (1,4), (2,5), (3,4), (4,5)
The periodic simple bond set is
(0,1), (0,2), (0,3), (1,2), (1,4),
(2,5), (3,4), (3,5), (4,5)
24.2 Bit packing and local values
For site-ordered bits [1, 0, 1, 1]:
packed mask = 13
Pauli-Z values = [-1, +1, -1, -1]
Rydberg occupancy = [1, 0, 1, 1]
Hamming weight = 3
24.3 Two-site TFIM
For one bond (0,1) in simulation basis z:
- state
00has diagonal energy-J; - state
01has diagonal energy+J; - every state connects to its site-0 flip with matrix element
-h; - every state connects to its site-1 flip with matrix element
-h.
24.4 One Heisenberg bond
For one bond of strength J:
00and11have diagonal energy+J/4and no pair-flip connection;01and10have diagonal energy-J/4;01connects to10, and10connects to01, with matrix elementJ/2.
24.5 Pair-dependent Heisenberg couplings
For three sites with weighted bonds J_01=2 and J_12=-3, state 010 has
Pauli values [+1, -1, +1]. Its diagonal exchange energy is
[ \frac{2}{4}(+1)(-1)+\frac{-3}{4}(-1)(+1)=\frac14. ]
It connects to 100 by flipping pair (0,1) with matrix element +1, and it
connects to 001 by flipping pair (1,2) with matrix element -3/2. A
backend that factors out one global exchange coupling cannot pass this vector.
24.6 Two-site Rydberg model
For interaction V:
| State | Diagonal energy |
|---|---|
00 | 0 |
01 | -Delta |
10 | -Delta |
11 | -2*Delta + V |
Every single-site flip has matrix element -Omega/2.
24.7 Observable normalization
For the all-zero product state in simulation basis z:
sigma_z per site = +1
raw zz correlation = +1 for every pair
connected zz correlation = 0
uniform Pauli-generator Fisher density = 0
24.8 Basis rotation parity
For every small TFIM system used as a reference, the spectra of the canonical
z-basis and Hadamard-rotated x-basis matrices must agree within the declared
f64 eigensolver tolerance.
25. Open decisions for later specifications
The following are deliberately not fixed by this first convention document:
- the public crate and module hierarchy inside the qslib workspace;
- the sparse matrix storage format;
- the default dense and sparse eigensolver implementations;
- a particular random-number generator;
- binary artifact and checkpoint container formats;
- GPU tensor interoperability;
- model-specific Ewald or cutoff conventions;
- the public stability level of experimental algorithms.
Each may be specified separately without changing this document, provided it does not alter the scientific meanings defined above.
Geometry and weighted interactions
This guide describes the physical objects represented by qslib’s foundational API. It is written for users specifying a lattice model; the Rust type names are included only after the scientific convention is clear.
Sites and coordinates
Rectangular systems use canonical row-major site order
[ i(x,y)=x+L_x y. ]
The first coordinate is horizontal and the second vertical. Boundary::Open
does not wrap a neighbour, while Boundary::Periodic identifies opposite
faces independently in each direction. LatticeKind::Triangular uses the
embedding (r(x,y)=x(1,0)+y(1/2,\sqrt{3}/2)); this changes distances, not site
order.
#![allow(unused)]
fn main() {
use qslib_core::{Boundary, RectangularGeometry, SiteId};
let geometry = RectangularGeometry::new(3, 2, Boundary::Open, Boundary::Periodic)?;
assert_eq!(geometry.site_id(2, 1)?, SiteId::new(5));
assert_eq!(geometry.coordinate(SiteId::new(4))?.as_tuple(), (1.0, 1.0));
Ok::<(), Box<dyn std::error::Error>>(())
}
Periodic minimum-image distances are explicit. A shell selector receives a
squared target and either ShellTolerance::Absolute(epsilon) or
ShellTolerance::Relative(epsilon). The relative policy is
(|d^2-d_0^2|\leq\epsilon |d_0^2|). Invalid targets and tolerances return a
structured error.
BondMultiplicity::Simple returns one endpoint-only bond for each unordered
pair. BondMultiplicity::PeriodicImages retains the source site, lattice step,
and cell translation, so two physically distinct images never collapse into an
ambiguous duplicate. Extent-one periodic directions simply produce no self-bond.
Couplings belong to terms
For a pair interaction, qslib resolves the physical coefficient per term:
[ (i,j,\kappa_{ij},\mathrm{channel},\mathrm{name}). ]
The coefficient may be positive, negative, or exactly zero. Zero terms remain
in the declared table for provenance but are excluded by
InteractionTable::active_interactions() during numerical evaluation. Dense
coupling matrices are row-major, finite, symmetric within an explicitly chosen
tolerance, and have a zero diagonal. Sparse pairs are canonicalized and reject
self-pairs and duplicate identities.
This makes a frustrated or disordered J1-J2 model representable without a
hidden global J: each realized (J_{ij}) is stored beside its shell or named
term. InteractionIdentity::named keeps overlapping physical contributions
distinct when they should not be algebraically merged.
Disorder provenance
InteractionTable::realize_uniform_disorder samples replacement coefficients
from the requested finite interval. The durable result includes the complete
realized interaction table, site count, master seed, distribution bounds,
coefficient semantics, the chacha20 algorithm, and the keyed qslib-seed-v1
child-seed scheme in the disorder domain. Derivation is keyed by canonical
interaction identity and logical realization index, so worker scheduling and
insertion order cannot change a realization.
Legacy order
Legacy x-major arrays (x * Ly + y) are not silently reinterpreted. Use
XMajorAdapter to convert both state vectors and interaction endpoints before
comparing them with canonical qslib data.
Operators and model Hamiltonians
qslib represents a physical Hamiltonian as
[ H=cI+\sum_a c_a O_a, ]
where c is a physical energy constant and every Pauli-string term has its
own resolved coefficient. Algorithmic shifts are not folded into c.
Basis action
Bits use the simulation axis as their diagonal Pauli operator. In a z basis,
Z multiplies a state by (1-2b_i), while X flips site i and Y flips it
with phase i on bit zero and -i on bit one. PauliString::new accepts
canonical distinct support. PauliString::product is the explicit
ordered-product API and reduces repeated factors, including XY=iZ and
YX=-iZ.
TFIM
The physical convention is (H=-\sum_{ij}J_{ij}Z_iZ_j-\sum_i h_iX_i).
tfim requires InteractionChannel::IsingZZ. In simulation basis z it emits
ZZ bond terms and X field terms. In basis x it emits XX bond terms and
diagonal Z field terms. Positive J_ij is ferromagnetic under this sign
convention; signed heterogeneous values remain resolved term by term. The y
basis is rejected explicitly because this first conversion surface does not
yet provide its complex phase convention.
Each builder returns a ResolvedModel. It dereferences to the operator
Hamiltonian for matrix and connected-state APIs, and also exposes family,
basis, the complete weighted interaction identities (including names and
zero coefficients), and a typed ModelSpecification containing named site
fields or shell vectors. This prevents a numerical operator from losing the
physical inputs that produced it.
Heisenberg and J1-J2
The isotropic exchange is
(H=\sum_{ij}J_{ij}(X_iX_j+Y_iY_j+Z_iZ_j)/4). The builder requires
HeisenbergExchange and supports x, y, and z simulation bases because the
isotropic sum is invariant under a common axis rotation. Positive J_ij is
antiferromagnetic and negative values are allowed. The j1j2 convenience
constructor selects axial nearest-neighbour and diagonal next-nearest-neighbour
shells, names them j1 and j2, and delegates to the same resolved term path.
j1j2_disordered accepts one signed or zero coefficient per resolved bond in
each shell, validates both lengths, and retains the shell names even when
periodic geometry makes two physical contributions share an endpoint pair.
Rydberg
The z-basis builder uses
(H=-\sum_i\Omega_iX_i/2-\sum_i\Delta_i n_i+\sum_{i<j}V_{ij}n_in_j),
with n_i=b_i. It requires RydbergDensityDensity, validates per-site drive
and detuning, and accepts a symmetric finite zero-diagonal coupling matrix.
Its density expansion retains the physical constant and Z terms. Other bases
return an explicit unsupported-basis error rather than silently changing the
occupation convention.
Application and local energy
Hamiltonian::apply returns unique connected states with algebraically combined
coefficients in canonical packed-mask order. Hamiltonian::local_energy
computes (\sum_b H_{ab}\psi_b/\psi_a) from an explicit amplitude table. Since
apply is column-oriented and returns (H_{ba}), local energy conjugates the
Pauli matrix element when evaluating the row element while preserving the
physical complex coefficient. It combines and prunes exactly cancelling row
transitions before requesting connected amplitudes, then rejects a missing
uncancelled amplitude or zero reference amplitude. Physical terms and constants
remain separate from future solver shifts.
Exact calculations
qslib-quantum-exact is the reference small-system backend. It consumes the
canonical BasisState, Hamiltonian, site order, and bit convention from
qslib-core; it does not introduce a second basis encoding.
Basis and matrix contracts
ExactBasis::full enumerates packed little-endian states in increasing integer
order. ExactBasis::fixed_weight uses the same order while retaining exactly
the requested Hamming weight. DenseMatrix::from_hamiltonian stores rows and
columns in that basis order and uses the conventional action
y[row] = sum_column H[row,column] x[column]. CsrMatrix is a deterministic
compressed representation of the same matrix and is checked against dense
matrix-vector action in the test suite. CSR assembly resolves Hamiltonian
actions directly into row storage and rejects a non-conserving Hamiltonian when
the supplied basis is a fixed sector.
The builder preserves physical constants and all pair-dependent coefficients. It reports missing connected states, dimension mismatches, non-Hermitian input, and non-convergent numerical work as typed errors.
Spectra, thermal sums, and evolution
diagonalize_hermitian is a deterministic reference Hermitian eigensolver. It
returns ascending eigenvalues, normalized complex eigenvectors, and the norm of
H|v>-lambda|v> for every pair. GroundState selects the lowest eigenvalue;
degenerate vectors must be compared through their invariant subspace rather
than by vector identity. ground_state_sparse uses deterministic full
reorthogonalization with basis-vector restarts and the same residual contract
for CSR matrices. Eigensystem::projector compares degenerate invariant
subspaces without comparing arbitrary eigenvector representatives.
ThermalSummary evaluates Z, stable log Z, the canonical mean energy, and
beta^2 Var(H) from the exact spectrum using an energy-shifted log-sum-exp
calculation. evolve uses the same spectral data
for unitary exp(-i H t) evolution and normalized imaginary-time
exp(-H tau) evolution. Imaginary time and inverse temperature are
non-negative; real time may be signed. All parameters are finite and use the
natural units defined by the project conventions.
If Z exceeds the finite f64 range, partition_function_overflowed is true
and log_partition_function remains the authoritative finite-scale result.
The backend is intended for validation and small systems. It is not a claim of production-scale exact diagonalization; later milestones may add a maintained sparse solver or a qslib-owned Lanczos implementation behind a separate, diagnosable API.
The exact observable surface also includes normalized Pauli-matrix expectation and variance, Shannon entropy, pure-state bipartite entropy, axis-labelled magnetization, raw and connected correlations, position- and momentum-bound structure factors, weighted sublattice moments, QFI normalization, and thermal heat-capacity density. These APIs bind site count, physical axis, normalization, and connected-correlation choice explicitly rather than accepting pre-aggregated scalars without provenance.
Observables and statistics
Exact expectation and variance functions normalize by the supplied state norm, so callers may provide an unnormalized exact vector. Zero-norm and non-finite states are errors. Matrix rows and columns retain the canonical exact-basis order, and Hermitian variance is evaluated from the centered vector norm rather than from a subtraction of two potentially ill-conditioned moments.
WeightedMoments uses normalized non-negative weights and a parallel-moments
merge formula. This makes independently accumulated batches equivalent to one
serial accumulator without discarding weight information. Complex estimators
retain independent real and imaginary moments through
ComplexWeightedMoments.
autocorrelation uses Geyer’s initial-positive-sequence estimator with a
common 1/N autocovariance normalization, summing adjacent pairs until the
first non-positive pair, and reports
both integrated autocorrelation time and effective sample size. The reported
time is clamped to at least one, so alternating or very short chains never
produce a negative effective sample size. r_hat is the
classic equal-length, unsplit Gelman-Rubin diagnostic and returns its within-
chain W, between-chain B, value, and algorithm identity. The algorithm is
part of the result contract and should be recorded with reports.
disorder_average keeps each realization identifier and computes the weighted
fixed-realization mean separately from between-realization variance. One
realization reports ensemble variance as unavailable, rather than zero. This
prevents sampling uncertainty within one realization from being silently
combined with finite-disorder ensemble uncertainty. When per-realization
sampling variances are supplied, the summary reports the uncertainty of the
weighted ensemble mean, sum_r w_r^2 Var_r / (sum_r w_r)^2, considering only
positive-weight records.
The exact backend also provides direct Pauli-string expectations, two-site
correlations, axis-labelled Pauli magnetization, spin magnetization using
S^a = sigma^a/2, and the exact <S_tot^2> observable from an explicit basis
and state.
Structure-factor
results retain their physical axis and raw versus connected convention. A
weighted sublattice helper returns per-configuration signed, absolute, and
squared values; callers average those components over configurations.
Variational and TDVP kernels
qslib-quantum-variational accepts the numerical products of a wavefunction
frontend without depending on an autodiff framework. A caller supplies one
complex local energy and one complex log derivative per sample and parameter,
in row-major sample order. Non-negative normalized or unnormalized sample
weights are accepted; the estimator normalizes them internally.
For real parameters, the estimator forms
S_kl = Re E[conj(delta O_k) delta O_l]
F_k = E[conj(delta O_k) delta E_loc]
and uses Im(F) for real time or -Re(F) for imaginary time. Energy mean and
variance are retained alongside the dense real QGT. DenseQgt::matvec and
solve_cg cover dense and caller-supplied matrix-free solves.
qgt_vector_product_stream consumes derivative chunks directly, so a frontend
can stream rows without constructing a sample-space identity.
Regularization::FixedTikhonov adds a documented diagonal shift,
Regularization::Gcv selects a positive shift from a supplied grid, and
Regularization::SpectralCutoff removes modes below a relative eigenvalue
threshold. Solve results report clipping, QGT metric norm, projected residual,
and normalized residual. ParameterLayout records deterministic names,
shapes, offsets, and a stable fingerprint for checkpoint compatibility.
The Rust layer does not compute neural-network derivatives. Python and other frontends may adapt their own derivative engines to these checked arrays at a coarse boundary.
For local energy, local_energy_from_ratios expects row-oriented matrix
elements (H_{b b'}, psi(b')/psi(b)), including the diagonal separately. A
Hamiltonian::apply is column-oriented and returns c * P_ba; do not
conjugate that whole coefficient for complex c. Prefer a row/local-energy
API, or conjugate only the Pauli matrix element when constructing the pair.
Transactional variational evolution
qslib-quantum-variational provides model-independent Euler and Heun
integration over a checked flat parameter vector. The integrator does not own a
neural-network or model object. A caller supplies the current flat state and a
velocity callback, then applies the accepted state to its model after each
accepted boundary.
State and callbacks
FlatState contains finite parameter values and a deterministic layout
fingerprint. EvolutionMetadata records the schema version, physical time,
proposed next step, accepted and rejected counts, seed, method, metric, and
layout fingerprint. Metadata is JSON round-trippable and cannot be restored
against a different layout fingerprint.
The callback receives (parameters, time, stage_seed) and returns a
Velocity. A velocity contains a real parameter direction and may include a
validated positive-semidefinite dense QGT. Stage seeds are derived from the
master seed, accepted step, and stage index. Retry attempts expose their
attempt count for diagnostics, but the derived accepted-node seed is invariant
under rejection, so a resumed accepted-boundary trajectory reproduces the same
callback stream.
Euler, Heun, and adaptive acceptance
Euler uses one velocity evaluation. Heun evaluates a predictor and then a corrector. When adaptive mode is enabled, the predictor-corrector difference is measured in either the Euclidean norm or the QGT norm
[ |\delta|_S = \sqrt{\delta^T S\delta}. ]
An accepted step commits parameters, advances physical time, increments the accepted count, and records a bounded controller-proposed next step. The controller applies the safety factor to both rejection shrinkage and accepted step growth; an exact zero error permits growth up to the configured maximum. Adaptive Euler is rejected because it has no error estimator. A rejected attempt changes none of those accepted quantities. Only the rejected count and proposed step are updated before the retry. Observation callbacks run only after acceptance, so rejected trial states cannot appear in physical trajectories.
The integrator owns no sampling or automatic differentiation. Python or other frontends can compute local energies, QGT directions, and observables and pass them through the callback without per-sample foreign-function calls.
Canonical SSE interface
qslib-quantum-sse is the sign-safe finite-temperature stochastic-series
expansion backend. It uses qslib’s canonical BasisBit directly. Bit zero has
Pauli-Z eigenvalue +1; bit one has eigenvalue -1 and is the Rydberg
occupation. No model-independent Spin alias is introduced.
The decomposition contract is
[ H = E_{\rm shift} - \sum_a B_a, ]
where each sampled matrix element of B_a is non-negative. LocalSseModel
provides explicit TFIM and Rydberg constructors. TFIM accepts explicit bonds
and non-negative J and h. Rydberg accepts per-site detunings and explicit
pair interactions, preserving pair-dependent coefficients and applying the
canonical occupation convention.
BasisSseState stores a padded operator string and validates propagation and
trace closure. The sampler performs three explicit Metropolis update families:
diagonal insertion/removal, paired off-diagonal vertices, and boundary basis
state flips. The latter is required for ergodic trace sampling and is model
agnostic because it operates on canonical BasisBit values. Two cluster
updates complement them. tfim_cluster_sweep is the deterministic
transverse-field Ising linked-cluster update: world-line legs are joined
through bond vertices and around the imaginary-time boundary, each connected
component flips with probability one half, and flipping toggles the
weight-neutral SiteConstant/SpinFlip partner vertices, which decorrelates
low-temperature and near-critical TFIM chains far faster than local moves.
Models must advertise supports_tfim_cluster_update; occupation-dependent
Rydberg decompositions are rejected. rydberg_global_cluster_sweep reuses the
same breakup as a global proposal with a Metropolis correction on the full
path weight. It is retained as a correctness reference for validating local
Rydberg updates; its acceptance may be poor for large or strongly interacting
systems. Operator strings
grow geometrically when their identity headroom is low, preserving all existing
vertices. Thermodynamic estimators use expansion-order moments.
The result also reports a naive independent-sample energy standard error;
correlated chains must be combined through independent logical chains for a
confidence interval.
Cutoff growth is permitted during thermalization only. If identity headroom is insufficient after thermalization, the run fails explicitly instead of mixing finite-cutoff ensembles in one estimate.
qslib_sse::legacy contains opt-in adapters for old Up/Down labels. The
adapter requires a model family because TFIM and Rydberg occupation semantics
differ. derive_chain_seed and logical_chain_seeds provide deterministic
logical chain seeds suitable for sequential, threaded, or process-level
execution without coupling results to a particular thread count.
Versioned scientific IO
qslib-quantum-io stores scientific meaning alongside numerical payloads. A
configuration records the convention schema, site and byte order, simulation
basis, resolved coefficients, scalar dtype, backend, tolerances, and the
versioned RNG scheme. JSON and YAML are strict: unknown fields and unsupported
schema versions are rejected.
Artifact manifests bind every immutable file to a BLAKE3 checksum and byte
length and record the convention schema. Checkpoints bind an accepted step,
configuration checksum, parameter-layout fingerprint, RNG algorithm and state
schema, complete evolution controls, accepted-state schema, and checksums for
the typed payload and every named little-endian C-order f64 NPY array.
ChaCha20 positions are recorded in complete 64-byte blocks and expose their
equivalent 16-word stream position. atomic_write completes a sibling
temporary file before replacing the target, so an interrupted write cannot
masquerade as a complete artifact.
Accepted trajectory rows are represented as equal-length typed columns and can
be written as immutable Apache Parquet parts, matching ADR-0004. The dataset
manifest is bound to the resolved configuration and is the transaction boundary
for a set of parts. Completion is published only after every part is readable,
the complete manifest is atomically written, and the exact COMPLETE marker is
written last. Readers must validate checksums before interpreting arrays. A
seed is provenance, not a substitute for storing realized disorder or resolved
coefficients.
ParquetDatasetManifest::load may explicitly recover a durable complete
manifest whose marker publication was interrupted. Read-only audit tools use
ParquetDatasetManifest::inspect, which validates the exact marker and parts
without rewriting user data.
The independent standard-library verifier in
tools/verify_io_artifacts.py checks
checkpoint JSON/NPY structure and completed Parquet framing without importing
qslib. Install pyarrow separately when full Parquet column decoding is
desired.
To produce a fixture for that check locally:
cargo run -p qslib-quantum-io --example io_artifacts -- /tmp/qslib-io-fixture
python tools/verify_io_artifacts.py \
--checkpoint /tmp/qslib-io-fixture/checkpoint \
--dataset /tmp/qslib-io-fixture/dataset
Python bindings
qslib-quantum-python builds the qslib_quantum import package with Maturin
and the PyO3 abi3-py312 interface. The binding accepts NumPy arrays only for
the duration of one call and returns newly allocated C-contiguous arrays; it
does not retain Python buffers or expose mutable Rust handles.
The initial stable kernel surface is intentionally coarse grained:
row_major_site_ids(lx, ly)returns canonicaluint32site identifiers in(Ly, Lx)row-major order.resolve_ising_interactions(couplings)validates a symmetric dense matrix and returns integer endpoint pairs plus their resolvedfloat64coefficients.basis_states(site_count, weight=None)returns the canonical exact basis.tfim_matrixandtfim_ground_stateexpose exact TFIM matrices and residual- checked ground states.heisenberg_matrixandrydberg_matrixexpose the corresponding canonical exact matrices for pair-dependent couplings.tfim_observablesreports energy, energy density, energy variance, and an axis-labelled magnetization total and density, with an optional two-site correlation. Energy is a total and all densities divide by the number of physical sites.tdvp_estimateandtdvp_solveexpose owned sufficient statistics and a checked dense QGT solve with explicit regularization shift and diagnostics.
Inputs are validated for shape, finite values, symmetry, site order, and model
basis. C-order, Fortran-order, sliced, and read-only NumPy views are copied or
indexed safely. Wrong dtypes and malformed ranks are rejected by the Python
boundary. Errors are exposed as InputError or NumericalError, both derived
from QslibError.
The 1.0 binding keeps the Python GIL while exact dense kernels run. This is a deliberate small-system policy: calls copy their inputs before entering Rust, retain no Python-owned buffers, and return promptly bounded results. A future release may detach the GIL for larger kernels after adding an explicit threading contract and benchmark evidence.
Build and test a local wheel without publishing it:
maturin build --manifest-path crates/qslib-python/Cargo.toml --out dist
python -m venv /tmp/qslib-venv
/tmp/qslib-venv/bin/pip install dist/qslib_quantum-*.whl pytest
/tmp/qslib-venv/bin/pytest crates/qslib-python/tests/python_contract.py
For an authorized PyPI release, install the same binding with:
python -m pip install qslib-quantum==1.0.0
The package name and import name are intentionally different: distribution
qslib-quantum installs the qslib_quantum module. Pin the version for
reproducible research and use the release checksum manifest when installing
from a downloaded wheel instead of PyPI.
The wheel is ABI-compatible with Python 3.12 and later on the platform where it is built. Publishing, signing, and registry uploads remain owner-gated.
This is the qslib-local backend surface. ncli backend selection and parity adapters are intentionally deferred until the separately owned parent project grants coordinated migration authority.
qslib command line
The qslib command is a thin interface over the validated Rust kernels. It
lets a physicist inspect conventions, validate a Hamiltonian, calculate a tiny
exact ground state or evolution, run a small TFIM SSE demonstration, and
inspect an artifact directory without writing Rust.
Build it locally from the repository root:
cargo build --release -p qslib-quantum-cli
target/release/qslib inspect conventions
Use --json for scripts and notebooks. Without it, the command prints one
labelled field per line. Errors are written to stderr and return exit status 2.
They identify the physical field or convention that failed validation.
Configuration conventions
Configuration files are YAML or JSON. Dense coupling matrices are square,
symmetric, zero-diagonal arrays in canonical row-major site order. Each upper
triangle entry is one resolved pair coefficient, including zero coefficients.
basis names the simulation basis (z, x, or y where the model supports
it), while physical observable axes remain separate concepts.
Every configuration must declare the versioned scientific contract. The CLI rejects unknown fields and rejects convention metadata that does not match the selected model basis:
schema_version: qslib-model-input-v1
conventions:
schema: qslib-conventions-v1
site_order: row_major
byte_order: little_endian
basis: z
JSON results include a provenance object with this schema, the resolved
model family, basis, interaction count, and operator-term count. This makes a
result inspectable without guessing which convention was used.
For TFIM,
[ H=-\sum_{i<j}J_{ij}\sigma_i^z\sigma_j^z-\sum_i h_i\sigma_i^x ]
when basis: z. fields therefore contains one transverse field per site.
Heisenberg configurations use the same pair matrix and represent
J_ij S_i . S_j with S = sigma/2. Rydberg configurations use omega and
detuning arrays in addition to the pair matrix. J1-J2 configurations use
lx, ly, j1, and j2, with optional open or periodic boundaries.
Commands
qslib inspect conventions [--json]
qslib inspect environment [--json]
qslib model validate CONFIG [--json]
qslib exact ground-state CONFIG [--json]
qslib exact evolve CONFIG --t-max TIME [--imaginary] [--json]
qslib sse run CONFIG [--json]
qslib artifacts inspect PATH [--json]
qslib conformance self-test [--json]
exact ground-state reports the total energy, exact-basis dimension, and the
residual norm (|H|\psi\rangle-E|\psi\rangle|). Degenerate ground spaces
should be interpreted through the energy and residual, not a phase-sensitive
individual eigenvector. exact evolve starts from canonical basis state zero;
real time uses (e^{-iHt}), and imaginary time uses the normalized
(e^{-H\tau}) convention.
The SSE command is a small-system TFIM demonstration. It reports the mean energy per site across independent logical chains. It does not claim an autocorrelation-corrected confidence interval; production studies must choose thermalization, sweep, chain, and uncertainty controls for the physical question.
artifacts inspect PATH accepts a qslib Parquet dataset directory. It validates
the versioned manifest, exact completion marker, immutable part checksums, and
returns the configuration checksum and convention schema. A directory that
only happens to contain a file named COMPLETE is rejected.
conformance self-test reports smoke_pass for one independent one-site TFIM
matrix fixture. It is an installation smoke test, not a replacement for the
full conformance suite run by CI.
Worked examples
cargo run -p qslib-quantum-cli -- model validate examples/heisenberg_disordered_4.yaml
cargo run -p qslib-quantum-cli -- exact ground-state examples/tfim_4.yaml
cargo run -p qslib-quantum-cli -- exact evolve examples/tfim_4.yaml --t-max 0.1
cargo run -p qslib-quantum-cli -- sse run examples/tfim_thermal_4.yaml
The examples are executed by the CLI integration tests. The Python equivalent
uses the qslib_quantum import documented in python.md.
Symmetry actions and sectors
qslib stores a site permutation as source_for_destination. Its action is
[ (g\cdot b)j=b{p_g(j)}, ]
so it has the same gather direction as a row-major array read. Permutation
validates bijectivity, composes and inverts actions, and can act on dense
binary states or map Pauli supports. A separately named adapter is required
when converting to a destination-for-source convention.
translation and translation_group derive coordinate actions from the
declared geometry and boundaries. Rectangle and square point-group builders
return validated finite groups. Open-boundary translations that leave the
finite domain are rejected; periodic translations wrap explicitly.
SpinInversion applies (b_i\mapsto1-b_i). It is an available action, not an
automatic claim that a particular Hamiltonian is invariant. Use
is_interaction_symmetry to verify that every resolved weighted interaction,
including its channel, name, bond, and coefficient, is preserved.
validate_model_symmetry checks the complete resolved Pauli Hamiltonian,
including onsite fields, and reports the first missing mapped term;
validate_spin_inversion performs the corresponding commutator check.
DiagonalGauge implements (\phi(b)=\pi\sum_i a_i b_i) and applies the
resulting complex phase to amplitudes. Integer coefficients are classified as
sign-only. sublattice_gauge supplies the checkerboard gauge for square
geometries and rejects unsupported triangular embeddings.
For a finite group and a one-dimensional character, FiniteGroup::project_amplitudes
implements
[ (P_\chi\psi)(b)=|G|^{-1}\sum_g\chi(g)^*\psi(g^{-1}\cdot b). ]
Orbit methods return deterministic packed-state representatives. Projection and orbit utilities operate on explicit dense amplitudes and are intended as small-system reference primitives before sector-specific exact solvers.
Reproducibility
qslib treats reproducibility as a scientific result, not as a promise that a seed alone recreates every run. A durable record should retain:
- the resolved model family, every pair coefficient and onsite parameter;
- canonical row-major site order, boundaries, physical axes, and simulation basis;
- algorithm, integrator, regularizer, cutoff, tolerance, and accepted-step controls;
- random algorithm, seed derivation version, logical chain identifiers, and checkpoint RNG position;
- software revision, schema version, dtype, parameter-layout fingerprint, and checksums for arrays and columnar parts.
For disordered models, persist the realized interaction table. Regenerating it from a seed can hide changes in ordering, periodic image multiplicity, or a future random-stream implementation. For stochastic SSE estimates, separate finite-sample uncertainty, autocorrelation, and finite-disorder ensemble error.
The IO layer provides strict JSON/YAML configuration, typed checkpoints, named
NPY arrays, and append-only Parquet trajectories. The independent verifier in
tools/verify_io_artifacts.py is useful in a clean Python environment. The
CLI and Python examples in this repository are small deterministic contract
fixtures; they are not substitutes for production thermalization or error
analysis.
Kernel benchmarks
The benchmark target is a small regression smoke suite, not a portable performance claim. Run it with the pinned minimum toolchain and retain the machine, compiler, feature set, and workload alongside any comparison:
cargo +1.85.0 bench --locked --all-features --bench kernels
The baseline below was recorded on the local development host after the M15 kernel expansion. Times are total wall-clock times for the stated number of short repetitions and are intended only for same-host comparisons.
periodic geometry and bonds (128 runs): 131.375us
interaction resolution (128 runs): 21.083us
dense matrix construction (32 runs): 632.375us
matrix-vector action (16 runs): 4.583us
dense diagonalization (2 runs): 652.541us
exact expectation (32 runs): 7.125us
TDVP statistics (128 runs): 264.75us
TDVP solve (32 runs): 46.166us
SSE sweeps (4 short runs): 454.083us
The target covers geometry and interaction resolution, dense matrix construction and action, exact diagonalization and expectation, TDVP statistics and solve, and a short SSE sweep. A future performance gate should compare like-for-like workloads and report compiler, CPU, feature, and thread settings rather than treating these values as universal thresholds.
Limitations and numerical scope
qslib 1.0 is deliberately a validated finite-system foundation. The exact backend enumerates full or fixed-weight bases and therefore scales exponentially with site count. Its dense reference eigensolver is intended for small matrices and reports residuals so callers can reject an under-resolved result.
The variational layer supplies statistics, dense QGT solves, regularization, and transactional integration. It does not compute neural-network derivatives or prescribe an optimizer. The Python binding exposes coarse kernels and copies foreign arrays for each call. It retains the GIL during the bounded small-system kernels in the 1.0 contract.
The SSE backend supports the sign-safe TFIM and Rydberg decompositions that are covered by conformance tests. Statistical estimates require user-selected thermalization, chain count, autocorrelation analysis, and confidence criteria. The CLI’s tiny SSE example is a smoke test, not a production error bar.
The ncli backend-selection adapter remains outside this repository’s ownership boundary. qslib preserves explicit adapters and does not silently reinterpret legacy site order, spin labels, coupling signs, or basis conventions.
Local release-candidate evidence
This document describes the local evidence bundle for the current 0.1.0
implementation snapshot. It is not a publication or a release authorization.
Test matrix
- Rust 1.85.0: locked workspace tests, formatting, and feature checks.
- Current stable Rust: workspace tests, Clippy with warnings denied, rustdoc with warnings denied, and feature-boundary checks.
- Python: ABI3 wheel contract tests on the locally available interpreter, plus the exact four-site example.
- Documentation: mdBook, Rust API docs, doctests, Markdown links, and combined site API-copy validation.
- Policy: cargo-deny advisories, licenses, and sources.
- Hardening: bounded structured CLI parser/resolution fuzz smoke and expanded kernel benchmark target.
- Generated invariants: bounded packed-state byte/word round trips and permutation inverse/compose properties pass on Rust 1.85 and under Miri.
- Fuzzing: the isolated
fuzz/state_conversionlibFuzzer target passescargo fuzz run state_conversion --sanitizer none -- -runs=1000with no crash; CI has the same bounded invocation. - Safety: nightly Rust 1.99.0 Miri passes every qslib-core target, including the generated conversion tests.
- Dependency audit:
cargo auditexits zero with one allowed unmaintainedpaste 1.0.15warning in the Parquet dependency tree; cargo-deny reports the same documented exception. - Coverage: nightly
cargo llvm-cov --locked --workspace --all-features --branch --summary-onlypassed with 77.99% line coverage, 77.66% region coverage, and 57.76% branch coverage. The file-level report was reviewed; the CLI binary entry point and Python FFI remain unexercised by Rust tests, while core scientific branches have direct conformance or invalid-input coverage. - API stability:
cargo semver-checks check-release -p qslib-quantum --baseline-rev 2584261 --release-type patch --only-explicit-features(cargo-semver-checks 0.42.0) compared the current facade with baseline commit2584261and passed 165 checks with 12 skips; the broader disposition is recorded indocs/api-stability.md. - Packaging: the ABI3 wheel and Maturin source distribution both install in a
temporary environment; each runs the ten Python contract tests and the exact
four-site example. The current bundle is
/private/tmp/qslib-release-final-20260720-124823, built from the final local distribution-preparation revision. The guarded release workflow is the reproducible path for rebuilding a bundle from the current revision. - Distribution preparation (2026-07-20): Python packaging metadata now carries the physicist-facing description, Apache-2.0 license, repository and documentation URLs, classifiers, and a crate-local README/license boundary that works in both wheels and source distributions. The release workflow has a guarded PyPI trusted-publishing job and builds Linux, macOS, and Windows CLI archives with the same archive contract tests.
- Final local rehearsal (2026-07-20): the current wheel and source distribution
each installed into a fresh Python 3.14 environment, passed all ten Python
contract tests and the exact ground-state example, and the packaged CLI
passed
qslib --help. The candidate checksum manifest verified in place. - Revalidation (2026-07-20 09:58Z): the full Rust 1.85 workspace test matrix, stable Clippy and rustdoc with warnings denied, formatting, all facade feature boundaries, conformance/workspace harnesses, Markdown links, and CI YAML parsing passed on the clean source revision used for the current bundle.
- Hosted CI (2026-07-20): GitHub Actions run
29752717024for commite63466fcompleted successfully. All 17 jobs passed, including the Linux/macOS/Windows Rust stable and MSRV matrix, Python 3.12/3.13 wheels on all three operating systems, Miri, branch coverage, bounded fuzzing, facade feature checks, formatting, documentation, and dependency policy. - Hosted revalidation (2026-07-20): GitHub Actions run
29755394438for commit61c5138completed successfully with the same 17-job matrix. This run includes the corrected guarded release workflow in the pushed source. - ncli parity (2026-07-20 10:20Z): the separately owned parent repository has
an explicit optional qslib backend with TFIM, signed J1-J2, Rydberg, and exact
spectrum parity tests. Its native backend remains the default. The adapter
preflights a 256 MiB dense budget, rejects nonzero Rydberg diagonals and
non-Hermitian outputs, and the parent workflow installs qslib at pinned
revision
e63466fand marks the parity tests required on all three hosted operating systems. Local execution against the current ABI3 wheel passed all 11 parity tests withNCLI_REQUIRE_QSLIB_PARITY=1. - Publication preparation (2026-07-20 10:20Z):
.github/workflows/release.ymldefines a guarded artifact build and a manual, tag-checked GitHub release job. The build clean-installs and exercises wheel/sdist artifacts, smoke-tests the CLI, and verifies the generated checksum manifest before upload. - Release rehearsal (2026-07-20): the local workflow-equivalent build exposed
and corrected an invalid
--lockedflag onmaturin sdist. Wheel and sdist installs, ten Python contract tests, the exact ground-state example, CLI help, mdBook, the combined Rust API site, and relocated checksum verification all passed for commit61c5138. - Checksums:
SHA256SUMSis generated from inside the bundle with./...relative paths and verifies both in place and after relocation.
Known external gates
The hosted qslib Linux/macOS/Windows matrix is green for commit e63466f as
recorded above. Its Rust jobs explicitly exclude the Python cdylib, which is
built and tested through Maturin jobs on all three platforms. The local semver
comparison above does not replace a Linux registry or release-baseline check.
The ncli adapter remains a separate ownership unit and must be validated in
its own repository’s CI.
The Python cdylib is packaged through Maturin; a workspace-wide Cargo release
link is not a supported way to build that extension on macOS.
Migration status
qslib uses canonical row-major site order, little-endian site-zero bit packing, explicit simulation bases, and resolved pair coefficients. Legacy ncli and standalone-SSE inputs require the named adapters documented in the migration chapters. No destructive migration is performed by the release bundle.
Migration from ncli
qslib is the canonical scientific layer for future ncli integration. The migration boundary is intentionally explicit because ncli and qslib may have different site ordering, basis labels, array ownership, and optimizer state.
The qslib side is ready with:
- canonical row-major geometry and little-endian packed states;
- typed weighted interactions that preserve pair identity and realized disorder;
- exact, TDVP, SSE, and versioned artifact kernels;
- an ABI3
qslib_quantumPython surface for coarse matrices, observables, ground states, and TDVP statistics.
The parent ncli repository must add and test the backend protocol before a consumer migration is complete. That protocol should select Rust or Python explicitly, preserve the existing ncli path until parity is proven, and record the adapter’s site-order, basis, dtype, and normalization conversions. qslib does not modify the separately owned ncli tree or claim parity that has not run.
Migration from standalone SSE
The standalone SSE implementation is represented by the qslib-sse crate and
the qslib facade’s sse feature. Canonical BasisBit, weighted interactions,
logical chain seeds, operator-string trace closure, and thermodynamic moments
are owned by qslib types.
Migration should proceed in this order:
- Resolve the model using qslib’s canonical row-major sites and explicit per-pair coefficients.
- Select the sign-safe
LocalSseModeldecomposition and verify the supported interaction channels. - Preserve logical chain identifiers and the versioned seed derivation when changing worker counts.
- Compare tiny thermal energies against exact enumeration before scaling the system or changing sweep controls.
- Store resolved inputs, controls, checksums, and uncertainty metadata in the versioned IO artifacts.
Legacy spin labels and x-major site order require named adapters. They must not be inferred from an array shape or silently accepted as canonical qslib input.
qslib architecture
This directory describes qslib’s current architecture. Scientific meanings are
defined by ../conventions.md, while consequential design
choices and their rationale are recorded in ../decisions/.
Architectural direction
qslib should develop as a layered workspace whose dependency direction follows physical foundations toward algorithms and applications:
foundations
geometry, basis, scalar policy, identifiers
|
operators and interactions
|
physical models and observables
|
state representations and numerical kernels
|
exact, variational, TDVP, thermal, and SSE algorithms
|
adapters, command-line programs, and external interfaces
The dependency direction will be implemented in Milestone 1 through the workspace topology approved in ADR-0001:
qslib-core
^ ^ ^
| | |
exact variational sse
^ ^ ^
+-------+-------+------+
|
facade
qslib-io converts public domain and result values to versioned DTOs.
qslib-cli and qslib-python consume coarse public APIs.
qslib-test-support is never a production dependency.
Arrows point from a consumer toward its foundational dependency. Algorithm crates do not depend on IO, CLI, Python, or test support. The facade owns no second implementation. ADR-0001, ADR-0008, and ADR-0009 approve this topology, the dedicated repository boundary, and package names. No competing production structure may be introduced without a superseding decision record.
Cargo uses collision-safe distribution names while Rust code retains concise imports:
| Responsibility | Cargo package | Rust target |
|---|---|---|
| Facade | qslib-quantum | qslib |
| Foundations | qslib-quantum-core | qslib_core |
| Exact methods | qslib-quantum-exact | qslib_exact |
| Variational methods | qslib-quantum-variational | qslib_variational |
| Thermal SSE | qslib-quantum-sse | qslib_sse |
| Scientific IO | qslib-quantum-io | qslib_io |
| Python boundary | qslib-quantum-python | qslib_quantum |
| Command line | qslib-quantum-cli | qslib binary |
| Test support | qslib-test-support | qslib_test_support |
The facade has no default optional features. Core is always present. The
additive exact, variational, sse, and io features expose capability
crates, and full enables those four Rust capabilities. CLI and Python remain
separate packages.
Stable boundaries
- Geometry defines sites, coordinates, boundaries, bonds, and distances. It does not know about Hamiltonians or solvers.
- Basis types define state meaning and layout. They do not attach model-specific meanings such as Rydberg occupation to a generic spin label.
- Operators and weighted interactions define mathematical action with resolved per-term coefficients.
- Models assemble physical operators without depending on how a state is sampled, optimized, diagonalized, or thermally expanded.
- Observables state normalization and physical axes independently of the estimator used to evaluate them.
- Algorithms consume validated abstractions and expose their approximations and numerical diagnostics.
- Adapters own every conversion to legacy ncli, legacy SSE, Python arrays, serialized formats, and future accelerator backends.
- qslib-owned core scientific crates forbid unsafe code. Reviewed dependency internals and the isolated Python FFI boundary follow their own audited policies.
Milestone 3 now supplies the foundational geometry and interaction boundary in
qslib-core: checked row-major rectangular and triangular coordinates, mixed
open/periodic directions, minimum-image shells, explicit periodic-image bond
identity, custom coordinate order, canonical x-major conversion, dense or
sparse pair couplings, named weighted terms, and deterministic disorder
provenance. The user-facing physical explanation is in
../geometry-interactions.md. Model assembly,
Hamiltonian action, and interoperability adapters remain downstream layers.
Milestone 4 adds the operator and model boundary in qslib-core: Pauli action,
Hermitian Hamiltonian term resolution, basis-aware TFIM, isotropic Heisenberg,
J1-J2 shell shorthand, Rydberg density expansion, and local-energy evaluation
remain independent of exact, variational, thermal, or sampling algorithms. See
the ../operators-models.md guide for physical sign
and basis conventions.
Milestone 5 adds explicit gather-direction permutations, generated lattice
groups, spin inversion, orbit representatives, character projection, and
resolved-interaction symmetry validation. These actions remain independent of
exact-sector storage and solver algorithms; see the ../symmetry.md
guide.
Milestone 6 adds canonical full and fixed-weight exact bases, dense and CSR
Hamiltonian matrices, residual-reporting Hermitian diagonalization, exact
thermal sums, and spectral real- or imaginary-time evolution. See the
../exact.md contract and its independent small-system tests.
Milestone 7 adds normalized exact pure-state expectation and variance,
weighted online real and complex moments, autocorrelation and effective sample
size diagnostics, classic R-hat, and disorder-realization aggregation. See
the ../observables-statistics.md contract.
Milestone 8 adds caller-supplied weighted TDVP statistics, deterministic
parameter-layout fingerprints, dense QGT matrix-vector products, conjugate
gradient solves, fixed Tikhonov, GCV, spectral cutoffs, clipping, and residual
diagnostics. Neural-network derivative evaluation remains outside the Rust
kernel boundary. See the ../tdvp.md contract.
Milestone 9 adds transactional Euler and Heun evolution over checked flat
parameter state. Adaptive attempts use explicit Euclidean or QGT error metrics,
commit only accepted states, derive deterministic stage seeds, expose
accepted-only observation boundaries, and serialize checkpoint-compatible
evolution metadata. See the ../evolution.md contract.
Milestone 10 migrated the standalone SSE backend onto canonical qslib
bits, explicit weighted local terms, trace-checked operator strings, and
sign-safe thermodynamic estimators. SSE chains use the shared ADR-0003
versioned BLAKE3/ChaCha20 seed derivation and expose worker-count-invariant
logical chain results. Legacy model adapters remain model-aware; the
ambiguous standalone Spin meaning is not part of qslib. See the
../sse.md contract.
Milestone 11 completes the durable IO boundary in qslib-io: strict versioned
JSON/YAML configuration, BLAKE3-bound manifests and checkpoints, atomic writes,
validated columnar trajectory tables, and Apache Parquet part output. Scientific
conventions, resolved coefficients, tolerances, dtype, backend, and RNG
provenance remain explicit serialized fields. Checkpoint envelopes carry typed
accepted evolution controls, exact named NPY arrays, and recoverable completion
metadata; an independent Python verifier exercises NPY, Parquet, and checksum
readers in CI.
The qslib-local portion of Milestone 12 establishes the Python boundary in
qslib-python. PyO3 and NumPy are
isolated in the binding crate, which builds an abi3-py312 Maturin wheel and
returns owned arrays from validated coarse-grained geometry, coupling,
exact-basis, TFIM, Heisenberg, and Rydberg kernels. Core and solver crates do
not depend on Python, and Python buffers are never retained after a call.
The qslib-local CLI boundary is implemented in qslib-quantum-cli. It parses
only public, versioned scientific inputs, delegates model construction and
solvers to the facade, and keeps presentation concerns in the CLI crate.
Machine-readable JSON and physicist-labelled text are both supported; the CLI
does not introduce alternate Hamiltonian or site-order semantics.
Development architecture
qslib uses specification-driven test-first development for supported behavior:
scientific convention or accepted decision
|
independent oracle and failing acceptance test
|
production implementation
|
refactoring under a green suite
The test oracle must be independent of the production path being tested. An oracle may be an analytic result, explicit small matrix, exact enumeration, unitary equivalence, manufactured numerical problem, or separately implemented reference backend. Tests must demonstrate the initial failure for the intended reason before implementation proceeds.
The test architecture has complementary layers:
- conformance tests encode normative conventions and required reference vectors;
- model tests verify matrix elements, Hermiticity, conserved quantities, heterogeneous interactions, and analytic limits;
- property tests verify general invariants across generated valid inputs;
- backend tests compare equivalent representations after explicit conversion;
- numerical tests verify residuals, convergence, and precision-specific error;
- stochastic tests use reproducible streams and robust statistical criteria;
- serialization tests preserve physical meaning and provenance through a round trip;
- doctests keep public physicist-first examples executable.
Production code must not depend on test fixtures or a test-only oracle. Shared reference functionality that is scientifically useful outside testing belongs in an explicit reference or exact backend with its own public contract. Regression fixes begin with a failing reproduction. Tests should bind to public behavior and scientific invariants, leaving private implementation structure free to evolve.
Neutral conformance data lives under fixtures/conformance/v1/. Every fixture
states one physical or representational claim, its resolved conventions, an
independent derivation, authorship and review provenance, and a
quantity-specific comparison policy. Matrices record basis masks, complex
f64 entries, shape, row-major layout, and the matrix-element definition. A
sorted manifest binds all eight required fixture kinds to their BLAKE3 digests.
The test-support harness validates this evidence without depending on a
production qslib crate.
Validation architecture
Every optimized path should have a small-system reference route that is simple enough to inspect independently. Exact enumeration and explicit matrices are scientific oracles at small sizes, not production scalability strategies. Cross-backend comparisons must resolve both sides to the same convention, basis, site order, coefficients, and observable normalization before numerical comparison.
Evolution
Update this document when layer responsibilities change. Create an architectural decision record when a decision is difficult to reverse, affects multiple layers, or constrains future projects.
Architectural decision records
This directory records consequential qslib design decisions and their rationale. Use an ADR when a choice is difficult to reverse, changes public semantics, introduces a major dependency, establishes a cross-cutting abstraction, or affects interoperability with another project.
Copy 0000-template.md and assign the next four-digit
number. Keep one decision per file. Use one of these statuses:
proposedacceptedsuperseded by ADR-NNNNrejected
An ADR does not override docs/conventions.md silently. A decision that changes
a scientific convention must update the convention schema and the normative
document explicitly.
Decision index
- ADR-0001: layered Cargo workspace boundaries
- accepted
- ADR-0002: linear algebra and sparse storage - accepted
- ADR-0003: deterministic randomness and seed derivation - accepted
- ADR-0004: versioned serialization and columnar artifacts - accepted
- ADR-0005: Python FFI and array ownership - accepted
- ADR-0006: public stability and feature policy - accepted
- ADR-0007: additive standalone SSE migration - accepted
- ADR-0008: dedicated repository ownership boundary - accepted
- ADR-0009: registry package identifiers - accepted
Rust toolchain and MSRV policy
qslib uses Rust edition 2024. The minimum supported Rust version for qslib 1.0
is Rust 1.85.0, the first stable release supporting edition 2024. Every stable
workspace package declares rust-version = "1.85" through workspace metadata.
The checked-in rust-toolchain.toml selects exactly Rust 1.85.0 and includes
rustfmt and Clippy, so ordinary local commands continuously exercise the MSRV.
CI must test both this pinned MSRV and current stable. A dependency that cannot
compile on the MSRV is not accepted merely because it works on the development
compiler.
Raising the MSRV requires an accepted ADR that records the dependency or language requirement, user impact, and migration date. Within the 1.x series, the project should provide at least one minor-release notice before an MSRV increase unless a security fix makes that impractical.
The lockfile is committed for reproducible workspace, CLI, Python, and release candidate validation. Library dependency requirements remain semver ranges, but CI validates the locked graph and a fresh dependency resolution separately.
The standard checks are listed in the repository workflow and the contribution policy. Nightly Rust may be used by optional analysis tools such as fuzzers, but supported library code and release artifacts must not require nightly features.