Skip to content

New Module Index

This page preserves the historical March 2026 module notes and now routes the newer v0.10 public surfaces to their maintained guides. Use the guide pages below for current examples, evidence boundaries, and API contracts before reading the older module-by-module notes.

v0.10 public surfaces

Surface Primary module or command Current guide Evidence boundary
QRNG streaming and health reports scpn_quantum_control.entropy.QRNGStream Quantum Random-Number Generation Aer simulator entropy with FIPS/NIST health checks, not hardware RNG promotion.
ML-DSA-65 trigger authorisation scpn_quantum_control.crypto.ml_dsa, PqcTriggerSigner Post-Quantum Trigger Signer FIPS 204 vector-conformant, not FIPS-140 validated.
UltraScale+ HLS pulse artifact emission scpn_quantum_control.codegen.ultrascale_hls and scripts/export_ultrascale_hls_artifact.py Pulse -> UltraScale+ HLS Codegen Emits manifest-bound source artifacts for SC-NEUROCORE ingest; synthesis, timing closure, pinout, and hardware execution are outside this claim.
NV-centre ODMR magnetometry scpn_quantum_control.sensing.nv_magnetometry_20T NV-Centre 20 T Magnetometry Simulation and calibration contract; hardware calibration needs evidence.
FRC pulsed-shot scheduling scpn_quantum_control.phase.frc_pulsed_qaoa FRC Pulsed-Shot QAOA Control-grade surrogate unless physics-derived provenance is attached.
Realtime loop telemetry scpn_quantum_control.realtime Realtime Runtime Software-loop timing, not intra-shot QPU latency.
Kuramoto variants and acceleration scpn_quantum_control.variants, scpn_quantum_control.accel Kuramoto Variants Benchmark wording follows the local/isolated evidence classifier.
Studio federation scpn-emit-studio-manifest, scpn_quantum_control.studio.evidence_bundle Studio Federation Schema-A manifest plus schema-B bundles for existing ledgers and result packs; no new evidence promotion.

Historical March 2026 module batch

11 modules added in the 2026-03-30 session, closing gaps identified by competitive analysis against QuSpin, quimb, Mitiq, MISTIQS, Tequila, and NetKet. 78 tests, all passing, zero skips.


Open-System Dynamics

phase/lindblad.py — Lindblad Master Equation Solver

Solves \(d\rho/dt = -i[H, \rho] + \sum_k (L_k \rho L_k^\dagger - \frac{1}{2}\{L_k^\dagger L_k, \rho\})\) for the Kuramoto-XY Hamiltonian with configurable amplitude damping (\(\gamma_\text{amp}\)) and dephasing (\(\gamma_\text{deph}\)) channels.

Why it matters: The quantum synchronisation community (Ameri et al. PRA 2015, Giorgi et al. PRA 2012) primarily uses QuTiP Lindblad dynamics. Without this module, our package was limited to unitary (closed-system) evolution.

from scpn_quantum_control.phase.lindblad import LindbladKuramotoSolver
import numpy as np

n = 4
K = 0.45 * np.exp(-0.3 * np.abs(np.subtract.outer(range(n), range(n))))
omega = np.linspace(0.8, 1.2, n)

solver = LindbladKuramotoSolver(n, K, omega, gamma_amp=0.05, gamma_deph=0.02)
result = solver.run(t_max=2.0, dt=0.05)

print(f"R: {result['R'][0]:.3f}{result['R'][-1]:.3f}")
print(f"Purity: {result['purity'][0]:.3f}{result['purity'][-1]:.3f}")

API:

Function Returns
LindbladKuramotoSolver(n, K, omega, gamma_amp, gamma_deph) Solver instance
.run(t_max, dt) {times, R, purity, rho_final}
.order_parameter(rho) Kuramoto R from density matrix
.purity(rho) \(\text{Tr}(\rho^2)\)

Tests: 13 (purity preservation under unitary, purity decay under damping, R bounded, strong damping kills sync, density matrix positivity, matches unitary solver at zero dissipation)


phase/tensor_jump.py — Monte Carlo Wave Function Method

Stochastic simulation of open Kuramoto-XY using quantum jumps. Each trajectory evolves a pure state under the effective non-Hermitian Hamiltonian \(H_\text{eff} = H - \frac{i}{2}\sum_k L_k^\dagger L_k\), with random quantum jumps at rate \(dp = 1 - \langle\psi|\psi\rangle\).

Ensemble averaging over many trajectories recovers the density matrix. Scales better than full Lindblad for larger systems (state vector vs density matrix).

Based on Dalibard et al., PRL 68, 580 (1992) and the Tensor Jump Method (Causer et al., Nature Comms 2025).

from scpn_quantum_control.phase.tensor_jump import mcwf_ensemble

result = mcwf_ensemble(K, omega, gamma_amp=0.1, t_max=1.0, dt=0.05,
                       n_trajectories=50, seed=42)
print(f"R_mean(T) = {result['R_mean'][-1]:.3f} ± {result['R_std'][-1]:.3f}")
print(f"Total jumps: {result['total_jumps']}")

API:

Function Returns
mcwf_trajectory(K, omega, gamma_amp, ...) {times, R, psi_final, n_jumps}
mcwf_ensemble(K, omega, ..., n_trajectories) {times, R_mean, R_std, R_trajectories, total_jumps}

Tests: 5 (single trajectory, R bounded, ensemble shape, no-damping norm, output keys)


phase/ancilla_lindblad.py — Single-Ancilla Open-System Circuit

Hardware-executable circuit for open-system dynamics using 1 ancilla qubit with repeated reset. Each dissipation step:

  1. Coherent Trotter evolution on system qubits
  2. Controlled-Ry from each system qubit to ancilla (\(\theta \propto \sqrt{\gamma \cdot dt}\))
  3. Reset ancilla

This implements amplitude damping without density matrix representation. Runs on IBM hardware with mid-circuit measurement and reset.

Based on Cattaneo et al., PRR 6, 043321 (2024).

from scpn_quantum_control.phase.ancilla_lindblad import (
    AncillaCircuitStats, build_ancilla_lindblad_circuit, ancilla_circuit_stats
)

qc = build_ancilla_lindblad_circuit(K, omega, t=0.5, gamma=0.05,
                                     n_dissipation_steps=5)
print(f"Qubits: {qc.num_qubits} ({qc.num_qubits-1} system + 1 ancilla)")

stats = ancilla_circuit_stats(K, omega)
print(f"CX gates: {stats['n_cx_gates']}, Resets: {stats['n_resets']}")

ancilla_circuit_stats(...) returns the typed AncillaCircuitStats envelope: qubit counts, CX/reset counts, total gate estimate, dissipation-step count, and the validated damping rate. The circuit and stats APIs use explicit float64 array contracts for K and omega.

Tests: module and contract suites cover circuit shape, reset scaling, finite-time damping angles, validation, stats consistency, and QASM-export workflow integration.


Exact Diagonalisation

analysis/magnetisation_sectors.py — U(1) Magnetisation Sectors

The XY interaction \(X_iX_j + Y_iY_j = 2(\sigma^+_i\sigma^-_j + \sigma^-_i\sigma^+_j)\) is a flip-flop: it swaps excitations but never creates or destroys them. Therefore the total magnetisation \(M = \sum_i Z_i\) is conserved. This decomposes the \(2^N\) Hilbert space into \(N+1\) sectors labelled by \(M\).

The largest sector (\(M=0\)) has dimension \(\binom{N}{N/2}\):

N Full dim Z₂ sector U(1) largest Reduction
12 4,096 2,048 924 4.4×
16 65,536 32,768 12,870 5.1×
18 262,144 131,072 48,620 5.4×
20 1,048,576 524,288 184,756 5.7×

For N=16: full ED needs 32 GB, U(1) sector needs 2.5 GB. 13× memory reduction.

from scpn_quantum_control.analysis.magnetisation_sectors import (
    eigh_by_magnetisation, level_spacing_by_magnetisation, memory_estimate
)

# All sectors — exact spectrum
result = eigh_by_magnetisation(K, omega)
print(f"Ground: E={result['ground_energy']:.4f}, M={result['ground_sector']}")

# Level spacing within M=0 sector (avoids inter-sector artefact)
ls = level_spacing_by_magnetisation(K, omega, M=0)
print(f"r̄(M=0) = {ls['r_bar']:.3f} (Poisson=0.386, GOE=0.530)")

# Memory comparison
est = memory_estimate(16)
print(f"Full: {est['full_ed_mb']:.0f} MB, U(1): {est['u1_largest_mb']:.0f} MB")

API:

Function Returns
basis_by_magnetisation(n) dict[M] → array of basis indices
sector_dimensions(n) dict[M] → dimension
eigh_by_magnetisation(K, omega, sectors) Full spectrum decomposed by M
level_spacing_by_magnetisation(K, omega, M) r̄ within single sector
memory_estimate(n) Comparison: full vs Z₂ vs U(1)

Tests: 21 (partition, binomial match, eigenvalue exact match at n=4,6,8, level spacing, memory estimates, N=16/20 dimensions)


analysis/symmetry_sectors.py — Z₂ Parity Sector Decomposition

Exploits the Z₂ parity symmetry \(P = Z_1 \otimes \cdots \otimes Z_N\) to halve the Hilbert space for exact diagonalisation. At n=16, full ED needs 32 GB; with sectors, each sector needs 8 GB.

Inspired by QuSpin's symmetry handling (Weinberg & Bukov, SciPost 2017).

from scpn_quantum_control.analysis.symmetry_sectors import (
    eigh_by_sector, level_spacing_by_sector, memory_estimate_mb
)

result = eigh_by_sector(K, omega)
print(f"Ground energy: {result['ground_energy']:.4f}")
print(f"Ground parity: {'even' if result['ground_parity'] == 0 else 'odd'}")
print(f"Memory (full): {memory_estimate_mb(16, False):.0f} MB")
print(f"Memory (sector): {memory_estimate_mb(16, True):.0f} MB")

# Sector-aware level spacing (avoids artefact of overlaying two spectra)
ls = level_spacing_by_sector(K, omega)
print(f"r̄ (even): {ls['r_bar_even']:.3f}, r̄ (odd): {ls['r_bar_odd']:.3f}")

Tests: 13 (partition correctness, sector dimensions, Hermiticity, eigenvalue match with full ED, level spacing bounded, memory estimates)


Tensor Network

phase/mps_evolution.py — MPS/DMRG via quimb

Matrix Product State backend for systems beyond ED limits (n=32-64). DMRG for ground state, TEBD for time evolution.

Currently nearest-neighbour couplings only (quimb SpinHam1D / LocalHam1D limitation). Full-K inputs with non-adjacent couplings are rejected by default; callers must pass allow_long_range_truncation=True for the explicitly labelled nearest-neighbour diagnostic path.

Requires pip install quimb.

from scpn_quantum_control.phase.mps_evolution import dmrg_ground_state, tebd_evolution

# Ground state
gs = dmrg_ground_state(K, omega, bond_dim=64, max_sweeps=20)
print(f"DMRG energy: {gs['energy']:.4f}, converged: {gs['converged']}")

# Time evolution
dyn = tebd_evolution(K, omega, t_max=1.0, dt=0.05, bond_dim=64)
print(f"R(0) = {dyn['R'][0]:.3f}, R(T) = {dyn['R'][-1]:.3f}")

Tests: 10 (DMRG energy, bond dims, TEBD R bounded, output keys)


Error Mitigation

mitigation/mitiq_integration.py — Mitiq ZNE + DDD

Production-quality error mitigation via Mitiq (LaRose et al., Quantum 6, 774, 2022). Wraps Mitiq's ZNE (Richardson extrapolation) and DDD (digital dynamical decoupling) around our circuits.

Requires pip install mitiq.

from scpn_quantum_control.mitigation.mitiq_integration import zne_mitigated_expectation
from qiskit import QuantumCircuit

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

mitigated = zne_mitigated_expectation(qc, scale_factors=[1.0, 3.0, 5.0])
print(f"ZNE-mitigated ⟨Z⟩ = {mitigated:.4f}")

Tests: 5 (availability, returns float, bounded, identity circuit, custom executor)

Note: Mitiq 1.0 has a bug where from __future__ import annotations breaks executor introspection. This module avoids the __future__ import as a workaround.


Variational Methods

phase/param_shift.py — Parameter-Shift Gradient Rule

Analytic gradient computation: \(\partial\langle H\rangle/\partial\theta_k = \frac{1}{2}[\langle H\rangle(\theta_k + \pi/2) - \langle H\rangle(\theta_k - \pi/2)]\).

No finite-difference error. Works on real hardware (only needs 2 circuit evaluations per parameter). Replaces the finite-difference gradients in nqs_ansatz.py.

Based on Mitarai et al., PRA 98, 032309 (2018).

from scpn_quantum_control.phase.param_shift import vqe_with_param_shift

result = vqe_with_param_shift(cost_fn, n_params=10, learning_rate=0.1,
                               n_iterations=100, seed=42)
print(f"Energy: {result['energy']:.4f}")

Tests: 4 (quadratic gradient, VQE convergence, output keys, zero at minimum)


phase/nqs_ansatz.py — Neural Quantum State (RBM)

Restricted Boltzmann Machine wavefunction for variational ground state search. \(\log\psi(\sigma) = \sum_i a_i \sigma_i + \sum_j \log\cosh(\sum_i W_{ji}\sigma_i + b_j)\).

Pure numpy, no JAX/torch. Exact mode for n ≤ 12 (all \(2^n\) configurations). This path uses central finite-difference gradients and rejects n_samples instead of silently ignoring requested sampling budgets. Returned metadata records sampling_mode, n_samples_used, and gradient_method. For production at larger scales or sampled VMC, use NetKet.

Based on Carleo & Troyer, Science 355, 602 (2017).

from scpn_quantum_control.phase.nqs_ansatz import vmc_ground_state

result = vmc_ground_state(K, omega, n_iterations=200, seed=42)
print(f"VMC energy: {result['energy']:.4f}, params: {result['n_params']}")

Tests: RBM amplitude invariants, normalisation, parameter counting, reproducibility, variational energy checks, output metadata, explicit n_samples rejection, and large-n rejection.


Circuit Compilation

phase/xy_compiler.py — XY-Optimised Gate Decomposition

Domain-specific compiler for the XX+YY interaction. Each coupling term \(e^{-iK_{ij}t(X_iX_j + Y_iY_j)}\) decomposes into 2 CNOT + 1 Rx, which is more efficient than generic PauliEvolutionGate Trotter decomposition.

Inspired by MISTIQS domain-specific TFIM compiler.

from scpn_quantum_control.phase.xy_compiler import compile_xy_trotter, depth_comparison

qc = compile_xy_trotter(K, omega, t=0.1, reps=5, order=2)
print(f"Depth: {qc.depth()}, gates: {qc.size()}")

cmp = depth_comparison(K, omega, t=0.1, reps=5)
print(f"Generic: {cmp['generic_depth']}, Optimised: {cmp['optimised_depth']}")
print(f"Reduction: {cmp['reduction_pct']}%")

Tests: 4 (circuit creation, order 2 ≥ order 1, depth comparison, unitarity)


hardware/circuit_export.py — Multi-Platform Export

Export Kuramoto-XY circuits to OpenQASM, Quil (Rigetti), and Cirq formats.

from scpn_quantum_control.hardware.circuit_export import export_all

result = export_all(K, omega, t=0.1, reps=5)
print(f"QASM length: {len(result['qasm3'])} chars")
print(f"Quil length: {len(result['quil'])} chars")
print(f"Depth: {result['depth']}, gates: {result['gate_count']}")

# Save for Rigetti
with open("kuramoto.quil", "w") as f:
    f.write(result["quil"])

Tests: 4 (QASM string, Quil string, export_all keys, measurements present)


Infrastructure

phase/backend_selector.py — Automatic Backend Selection

Auto-selects the best simulation backend based on system size, available RAM, installed packages, and whether open-system dynamics are needed.

Inspired by Maestro (Qoro, arXiv:2512.04216).

from scpn_quantum_control.phase.backend_selector import recommend_backend, auto_solve

# Recommendation only
rec = recommend_backend(n=16, ram_gb=32.0)
print(f"Backend: {rec['backend']}, Memory: {rec['memory_mb']:.0f} MB")

# Auto-solve (selects backend and runs)
result = auto_solve(K, omega)
print(f"Used: {result['backend_used']}, E₀ = {result['result']['ground_energy']:.4f}")
System size Backend selected
n ≤ 14 exact_diag (numpy eigh)
n = 15-16 sector_ed (Z₂ parity)
n = 17-64 mps_dmrg (quimb, if installed)
n > 64 hardware (IBM)
Open system, n ≤ 12 lindblad_scipy

Tests: 6 (small/medium/large/open/huge system selection, auto_solve runs)


Batch 3 — Scalability & Ecosystem Integration (March 2026)

8 modules closing capability gaps identified by analysis of 20+ competing projects (QuSpin, quimb, Stim, NetKet, TensorCircuit, OpenFermion, TorchQuantum, Maestro, cotengra). 53 tests, all passing.


Sparse Hamiltonian

bridge/sparse_hamiltonian.py — CSC Sparse XY Hamiltonian

The XY Hamiltonian has \(O(n^2 \cdot 2^n)\) non-zero elements in a \(2^N \times 2^N\) matrix — less than 1% fill for \(n \geq 10\). Sparse storage (scipy CSC) + ARPACK eigensolver (eigsh) enables exact diagonalisation at scales impossible with dense matrices.

n Dense (MB) Sparse (MB) Reduction
12 134 12 11×
14 2,147 50 43×
16 32,768 200 164×
18 524,288 800 655×

Combined with U(1) sectors: sparse eigsh on \(C(20,10) = 184{,}756\) with \(\sim 10^6\) non-zeros → feasible on a 32 GB workstation.

Inspired by QuSpin's sparse Hamiltonian construction.

from scpn_quantum_control.bridge.sparse_hamiltonian import (
    build_sparse_hamiltonian, sparse_eigsh, sparsity_stats
)

# Full sparse Hamiltonian
H = build_sparse_hamiltonian(K, omega)
print(f"Shape: {H.shape}, NNZ: {H.nnz}, Fill: {H.nnz/H.shape[0]**2:.4%}")

# Sparse eigenvalues (ARPACK — k smallest)
result = sparse_eigsh(K, omega, k=10)
print(f"Ground energy: {result['eigvals'][0]:.6f}")

# Within U(1) sector
result_m0 = sparse_eigsh(K, omega, k=10, M=0)
print(f"M=0 ground: {result_m0['eigvals'][0]:.6f}")

# Memory estimate
stats = sparsity_stats(16, K)
print(f"Sparse: {stats['memory_sparse_mb']:.0f} MB vs Dense: {stats['memory_dense_mb']:.0f} MB")

API:

Function Returns
build_sparse_hamiltonian(K, omega) scipy.sparse.csc_matrix
build_sparse_sector_hamiltonian(K, omega, M) (csc_matrix, indices) within U(1) sector
sparse_eigsh(K, omega, k, which, M) {eigvals, eigvecs, nnz, dim, method}
sparsity_stats(n, K) {dim, nnz_estimate, fill_pct, memory_sparse_mb, memory_dense_mb}

Tests: 14 (shape, Hermiticity, matches dense at n=4/6, nnz bounds, sector match, ground energy match, ARPACK feasible at n=8, dense fallback, sparsity stats)


JAX Acceleration

phase/jax_nqs.py — JAX-Accelerated RBM Wavefunction

Replaces the numpy finite-difference gradients in nqs_ansatz.py with JAX jit + grad for automatic differentiation. This exact-enumeration research path has no committed isolated speed benchmark and no NumPy fallback.

Inspired by NetKet (Vicentini et al., SoftwareX 2022).

Requires: pip install jax jaxlib

from scpn_quantum_control.phase.jax_nqs import jax_vmc_ground_state

result = jax_vmc_ground_state(K, omega, n_iterations=200, learning_rate=0.01, seed=42)
print(f"JAX VMC energy: {result['energy']:.4f}")
print(f"Parameters: {result['n_params']}")

API:

Function Returns
is_jax_available() bool
jax_rbm_energy(params, H, n) JAX scalar (differentiable)
jax_vmc_ground_state(K, omega, ...) {energy, energy_history, params, n_params}

Tests: Requires JAX installation — included in batch 3 test file as conditional.

For validated 2 <= N <= 6 exact-reference evidence, environment provenance, and the no-advantage boundary, use jax_nqs_baseline_product.


Multi-Backend Dispatch

backend_dispatch.py — Runtime Backend Selection

Switch between numpy, JAX, and PyTorch for array operations at runtime. Inspired by TensorCircuit's tc.set_backend().

from scpn_quantum_control.backend_dispatch import set_backend, get_backend, available_backends

print(available_backends())  # ['numpy', 'jax', 'torch']
set_backend("jax")           # all array ops now use JAX
set_backend("numpy")         # back to numpy

API:

Function Returns
set_backend(name) Sets global backend ("numpy", "jax", "torch")
get_backend() Current backend name
get_array_module() The active array module (np, jnp, or torch)
to_numpy(arr) Convert any backend array to numpy
from_numpy(arr) Convert numpy to current backend
available_backends() List installed backends

Tests: 6 (default numpy, set/get, available list, to/from numpy, array module)


Plugin Architecture

hardware/plugin_registry.py — Extensible Backend Registry

Register and discover hardware backends at runtime. Supports lazy loading of built-in backends (Qiskit, PennyLane, Cirq) and registration of custom backends.

Inspired by OpenFermion's plugin architecture.

from scpn_quantum_control.hardware.plugin_registry import registry

# List and use built-in backends
print(registry.available_backends())  # ['qiskit', 'pennylane', 'cirq']
runner = registry.get_runner("pennylane", K, omega, device="default.qubit")
result = runner.run_trotter(t=0.5, reps=3)

# Register a custom backend
@registry.register("my_simulator")
class MyRunner:
    def __init__(self, K, omega, **kwargs): ...
    def run_trotter(self, t, reps): ...

API:

Method Description
registry.list_backends() All registered + lazy-loadable names
registry.available_backends() Only actually importable backends
registry.is_available(name) Check single backend
registry.get_runner(name, K, omega, **kw) Get instantiated runner
@registry.register(name) Decorator for custom backends

Tests: 6 (list, availability, get runner, custom registration, error on unknown, subset check)


GPU Batch Evaluation

phase/gpu_batch_vqe.py — Parallel VQE Parameter Scan

Evaluate multiple VQE parameter sets in batch. CPU baseline with NumPy; use_gpu=True requests a PyTorch/CUDA execution path and raises if CUDA is not available rather than silently falling back.

Inspired by TorchQuantum (MIT HAN Lab).

from scpn_quantum_control.phase.gpu_batch_vqe import batch_vqe_scan

result = batch_vqe_scan(K, omega, n_samples=100, seed=42)
print(f"Best energy: {result['best_energy']:.4f}")
print(f"Scanned {result['n_samples']} parameter sets")

API:

Function Returns
batch_energy_numpy(H, param_sets, ansatz_fn) energies array
batch_energy_torch(H, param_sets, ansatz_fn, device) energies array (GPU)
batch_vqe_scan(K, omega, n_samples, seed, use_gpu) {energies, params, best_energy, best_params, n_samples, backend, ansatz_family, optimizer, hardware_claim}

The built-in scan is a product-Ry random-parameter statevector expectation diagnostic, not a gradient-optimised or hardware-executed VQE.

Tests: batch energy, VQE scan, output keys, backend contract, input validation.


Translation Symmetry

analysis/translation_symmetry.py — Cyclic Translation for Periodic Chains

When frequencies are homogeneous (\(\omega_i = \omega\)) AND the coupling matrix is circulant (\(K_{ij} = K(|i-j| \bmod N)\)), the cyclic shift operator \(T\) commutes with \(H\). Eigenstates then carry definite crystal momentum \(k = 2\pi m/N\).

Combined with U(1), this gives \(N \times (N+1)\) sectors. For \(n=16\): full 65,536 → \(k=0\) sector of \(M=0\): ~805 states → 80× reduction.

Only applicable to homogeneous systems. For heterogeneous \(\omega\) (the SCPN case), translation is broken — use U(1) sectors instead.

Inspired by QuSpin's full symmetry chain.

from scpn_quantum_control.analysis.translation_symmetry import (
    is_translation_invariant, eigh_with_translation
)

# Check if system is translation-invariant
K_ring = ...  # circulant coupling
omega_uniform = np.ones(n) * 1.0
print(is_translation_invariant(K_ring, omega_uniform))  # True

# Diagonalise in k=0 sector
result = eigh_with_translation(K_ring, omega_uniform, momentum=0)
print(f"k=0 sector: {result['dim']} states, ground={result['eigvals'][0]:.4f}")

Tests: 6 (TI detection, non-TI detection, sector dimensions, k=0 eigenvalues, heterogeneous raises, ground energy within full spectrum)


Contraction Optimisation

phase/contraction_optimiser.py — Tensor Contraction Path Finder

Optimal einsum contraction paths using cotengra (if available), with numpy fallback. Drop-in replacement for np.einsum.

Inspired by quimb's cotengra integration.

from scpn_quantum_control.phase.contraction_optimiser import contract, benchmark_contraction

# Drop-in replacement for np.einsum
C = contract("ij,jk->ik", A, B)

# Benchmark
result = benchmark_contraction("ij,jk,kl->il", A, B, C, n_repeats=10)
print(f"Naive: {result['naive_ms']:.1f} ms, Optimised: {result['optimised_ms']:.1f} ms")
print(f"Speedup: {result['speedup']}×")

API:

Function Returns
is_cotengra_available() bool
optimal_contraction_path(subscripts, *operands) (path, info)
contract(subscripts, *operands) Result array (optimised)
benchmark_contraction(subscripts, *operands, n_repeats) {naive_ms, optimised_ms, speedup}

Tests: 4 (matches einsum, path info, benchmark, availability check)


Rust Engine Expansion

3 new PyO3 functions added to scpn_quantum_engine, bringing the total to 18. All wired into Python modules as automatic fast paths with Python fallback.

build_sparse_xy_hamiltonian — 80× faster sparse construction

Returns COO triplets (rows, cols, vals) for scipy.sparse.csc_matrix. Same bitwise flip-flop as build_xy_hamiltonian_dense but outputs sparse format instead of dense matrix. Eliminates the Python for k in range(2^n) bottleneck.

import scpn_quantum_engine as eng
rows, cols, vals = eng.build_sparse_xy_hamiltonian(K.ravel(), omega, n)
# Then: scipy.sparse.csc_matrix((vals, (rows, cols)), shape=(2**n, 2**n))

Wired into: bridge/sparse_hamiltonian.py — called automatically, Python fallback if engine not installed.

Measured: 0.024 ms (Rust) vs 1.9 ms (Python) at n=8 → 80× speedup

Tests: 6 (triplets returned, matches dense Rust, matches Python dense, Hermitian, NNZ bounds, eigenvalue match)


magnetisation_labels — 97× faster popcount

Returns array of magnetisation M for all 2^N basis states using hardware count_ones() instruction. M = N − 2×popcount(k).

labels = eng.magnetisation_labels(n)
# labels[k] = total magnetisation of basis state |k⟩

Wired into: analysis/magnetisation_sectors.py::basis_by_magnetisation() — called automatically.

Measured: 0.001 ms (Rust) vs 0.11 ms (Python) at n=8 → 97× speedup

Tests: 6 (n=2 explicit, n=4 range, all-up/all-down, matches Python, sum=0, popcount consistency)


order_param_from_statevector — 851× faster order parameter

Computes Kuramoto order parameter R from complex state vector via bitwise Pauli expectations. Critical inner loop in MCWF trajectories.

R = eng.order_param_from_statevector(psi.real, psi.imag, n)

Wired into: phase/tensor_jump.py::_order_param_vec() — called automatically.

Measured: 0.008 ms (Rust) vs 6.47 ms (Python) at n=8 → 851× speedup

Tests: 5 (all-up state, bounded, matches Python exactly, n=8 performance <1ms, deterministic)


Complete Rust Engine

Function Category Speedup
build_xy_hamiltonian_dense Hamiltonian ~111× (L=4) → parity (L=12)
build_sparse_xy_hamiltonian Hamiltonian 80×
order_param_from_statevector Order param 851×
otoc_from_eigendecomp OTOC 264×
lanczos_b_coefficients Krylov 27×
magnetisation_labels Symmetry 97×
all_xy_expectations Pauli 6.2×
state_order_param_sparse Order param
expectation_pauli_fast Pauli
pec_sample_parallel PEC (rayon)
brute_mpc MPC (rayon)
dla_dimension DLA (rayon)
mc_xy_simulate Monte Carlo
kuramoto_trajectory Kuramoto ODE
kuramoto_euler Kuramoto ODE
order_parameter Classical R
build_knm K matrix
pec_coefficients PEC