Skip to content

v0.14.0

Latest

Choose a tag to compare

@Shiro-Raven Shiro-Raven released this 02 Sep 07:39

0.14.0 (2026-09-02)

v0.14 adds LASSQD, a localised active-space sample-based quantum diagonalisation workflow for larger chemistry problems, together with the LUCJ ansatz that prepares its fragments. ProgramEnsemble.run() becomes an adaptive multi-round workflow that blocks until convergence, and ensembles now checkpoint at every round boundary, so an interrupted run picks up where it stopped. Circuit submission is unified behind a new CircuitPayload, and the core install shrinks by over 500 MB as PennyLane, qiskit-aer and dwave-hybrid move behind optional extras. This release also fixes a silently-wrong parameter-shift gradient for UCCSD and Hartree-Fock ansatze and five checkpointing defects.

⚠️ Breaking Changes

If you are upgrading from v0.13.x, review the following before merging:

What changed Migration
PennyLane no longer installs by default Install qoro-divi[pennylane] if your code passes PennyLane circuits/operators as inputs. The all extra still includes it.
QiskitSimulator and partitioned QUBO solving no longer install by default Install qoro-divi[aer] for QiskitSimulator, qoro-divi[qubo-decompose] for partitioned QUBO solving. Both raise an error naming the install command if used without it. Unpartitioned QUBO/HUBO (dimod) is unaffected.
ai dropped from the all extra Install qoro-divi[ai] explicitly if you need divi.ai.
A parameter-shift gradient on QAOA now raises NotImplementedError instead of returning a near-zero value QAOA's layer angles have no parameter-shift frequency family, so the two-term rule was silently wrong. Use a gradient-free optimizer (e.g. COBYLA) or a stochastic one (e.g. SPSA) with QAOA instead.
Backend authoring: SupportsCircuitTemplates is gone; QoroService has one submit_circuits instead of two submit methods A custom backend sets resolves_parameters = True instead of implementing SupportsCircuitTemplates. Callers of QoroService's old dual submit methods move to the single submit_circuits.

✨ Added

  • qprog: LASSQD — localised active-space sample-based quantum diagonalisation lands as a ProgramEnsemble where one round is one macro-cycle: build effective fragment integrals from the current orbitals, prepare and sample one circuit per fragment, recover the subspace with SQD, rebuild the fragment density matrices, and optimise the molecular orbitals until the energy converges. Ships active-space selection with independently localised occupied and virtual blocks, coupling-graph fragmentation, spin-polarised fragments, carryover SQD (arXiv:2512.14936), an analytic generalised-Fock orbital gradient, and a LASSQDRoundReport per round covering energy, per-fragment subspace sizes, orbital diagnostics and stage timings. Fragments are prepared classically by default — fragment ROHF and CCSD seed a one-repetition LUCJ operator that ffsim optimises on the exact statevector, so a round samples one circuit per fragment; preparation_mode="vqe" runs a full VQE loop per fragment instead. Requires the chem extra. Note the energy functional zeroes cross-fragment 2-RDM blocks, so it is not variational for more than one fragment (881e72c, 254604b, bbd05b7, b35ed3d, 9ec8a51, 3ba0cb7, 7ce78b0, 22b1309, f7c52ac, 58b0907, 698cc77)
  • qprog: LUCJ ansatz — a local unitary cluster Jastrow whose hopping terms stay inside one spin sector, with a full Clements brick-wall orbital rotation reaching U(n), an optional trailing rotation closing each layer, configurable rotation_depth, explicit Jastrow pair lists and shared_spin_params. Reachable through the new VQE(ansatz_kwargs=...), which forwards to both n_params_per_layer and build so the parameter count and the circuit cannot disagree (eb8f972, 09cfd5f, 8cc97d1)
  • qprog: ProgramEnsemble.run() is an adaptive multi-round workflow — it drives rounds (materialise programs, dispatch, reduce results into a workflow state, check convergence), blocks until done and returns self, and Ctrl-C cancels the workflow. The previous one-shot dispatch stays available as run_one_round(blocking=...), create_programs() now receives the current state, and ReportingLevel, WorkflowStatus and RoundRecord/round_history cover progress verbosity and per-round accounting (ca0450d)
  • qprog: ensembles checkpoint at every round boundary and restore onto an equivalently constructed instance, so an interrupted run picks up where it stopped. Within an interrupted round only work that no valid child artefact represents is rerun; partition children become reusable because every built-in decomposition is reproducible, and non-reproducible binary decomposers are rejected before dispatch (379b3a1)
  • qprog: sampling_backend runs a program's or ensemble's final measurement on a different backend than training, for anything exposing sample_solution (4789123)
  • qprog: MoleculeTransformer accepts PySCF molecules and mean fields — geometry reads and rebuilds dispatch on the molecule type, so a sweep emits the same type it was given (c7cf7ab)
  • circuits: CircuitPayload carries one circuit plus its labelled parameter sets, with a bound circuit as the degenerate case, and the pipeline compiles to payloads end to end. submit_circuits widens to accept payloads, {label: circuit} mappings, Qiskit circuits and bare sequences via normalise_circuit_batch, held across all four runners by shared contracts (a9ca3d9, faed8a0, b807301)
  • backends: typed Qoro job status errors, with backend status normalisation consolidated in JobStatus.coerce() so job failures stay tied to canonical statuses (7107838)
  • backends: reach maestro's pp_* knobs and match its config surface — the options are assigned after construction (maestro binds them as properties only, so any config carrying one previously raised TypeError before submitting), the precision and path_integral_threshold knobs from 0.2.19 are exposed, cadences are validated (zero aborts maestro with SIGFPE), and thresholds that silently do nothing without a cadence now warn (2e313b2)
  • qasm: validate_qasm and is_valid_qasm take an optional parameters collection naming identifiers allowed as bare gate arguments, so a parametric template can be validated before substitution. Undeclared identifiers are still rejected, and a placeholder no longer raises "Unknown symbol" first and masks a real syntax error behind it (d3edce3)

🐛 Fixed

  • qprog: each ansatz declares its own parameter-shift rule via Ansatz.parameter_frequencies — the two-term ±π/2 rule is exact only when a parameter drives one gate whose generator has two distinct eigenvalues, so UCCSD's gradient was numerically zero and Hartree-Fock's off by up to 0.22, both silently. QAOA, whose layer angles have no such frequency family, now refuses a gradient instead of returning a near-zero one (2e03d6d)
  • qprog: repair five checkpointing defects — load dispatch covers every checkpoint-capable optimizer, so GridSearchOptimizer checkpoints are loadable rather than writable-only; IterativeQAOA writes each depth to its own subdirectory and resumes the depth schedule instead of overwriting depths and restarting at 1; runs always checkpoint their final iteration, including on early stop and cancellation, with stop_reason surviving a reload; and latest-checkpoint resolution skips directories left incomplete by an interrupted write (e630358)
  • qprog: allow beam width to exceed the number of partition candidates (ea22b8f)
  • backends: flatten ham_ops groups and stop stripping measurements — maestro splits observables on ; only, so an unflattened XX|YY became one pseudo-term worth 0.0 (f4df502)
  • backends: hand on_complete the decoded status payload — it received the raw requests.Response while both consumers isinstance-check a dict or list, so the callback silently did nothing and total_run_time stayed at zero (d415667)
  • pipeline: show the param-set axis for deferred-binding traces, which backends that resolve parameters themselves leave on the MetaCircuit, so the tree no longer under-reports the expansion (3ddde8c)
  • scope the AI index and record SPSA's final exact loss — _should_skip received absolute paths, so a checkout directory named divi satisfied the allowlist for every file and .claude/ and exprmnts/ were indexed; SPSA and QN-SPSA best-tracked the iterate the final step reached only under blocking, unlike QUIVER (231eeb6)

🔄 Changed

  • deps: PennyLane, qiskit-aer and dwave-hybrid move behind optional extras — breaking: PennyLane now installs via qoro-divi[pennylane] and is imported lazily by the code that converts PennyLane inputs, QiskitSimulator needs the aer extra, and partitioned QUBO solving needs qubo-decompose; each raises an error naming the install command. Together this trims over 500 MB from the core install. dimod stays in core, so unpartitioned QUBO and HUBO are unaffected, and ai is dropped from the all extra so --all-extras --no-extra ai works again. HartreeFockAnsatz is rebuilt on Qiskit primitives, reproducing the previous circuits gate for gate at identical depth and CNOT count (171f0e6, 06eaffe, e064fc0)
  • reporting: event-driven progress sessions replace the reporter hierarchy — immutable progress events, a pure state reducer, and separate Rich and logging views, with ProgressSession owning the progress lifecycle including queued ensemble reporting, teardown, drain handling and non-interactive fallback. Compact, off and forced-logging behaviour is preserved (6d2fc67)
  • backends: consolidate the base contracts and group the runners — _circuit_runner, _async_job_backend and _execution_result merge into one _base module, the concrete runners move into a runners subpackage, and maestro's protocol facts (QASM dialect, MPS sizing, result bit order) move to _maestro_protocol (4b7012f)
  • collapse duplicated pipeline, backend and ansatz plumbing — eleven near-identical blocks now have one implementation each, and two hot loops are replaced: the QWC label match becomes a dict of index queues (1.8–3.1× on that phase) and the 2-RDM spin trace four array slices (14–20×) (4ba20f1)
  • vectorise bitstring processing across the expectation, parity and SQD occupation paths, and harden QH1/QH2 decoding and wide histogram rendering (3b963e5)
  • self-returning methods across programs, ensembles, optimizers and config objects return Self instead of a stringified concrete class, which under-reported the type for every subclass; the three optimizer copy() overrides also build via type(self), so a subclass copy keeps its type (01c8680)

🔧 Internal

  • backends: parity tests guard MaestroConfig against maestro.SimulatorConfig drift, so a renamed or newly added simulator option fails at CI instead of at execution time (6008430)
  • cover the gaps the review pass found — six behaviours had no test that could fail, including every optimizer's descent from its initial cost, a second Ctrl-C during round cleanup, and the session-level HTTP retry policy (e130afb)
  • pin BLAS threads to one per process — each xdist worker otherwise spawned one thread per core, making the parallel suite slower than serial (40 s pinned against 214 s unpinned) (07aaa77)
  • ci: install the chem extra for the docs and test jobs, and repair the LASSQD docs and optional tests (6570fd4, 8dc9f19)

📝 Documentation

  • reorganise and streamline the guides — the monolithic User Guide is replaced by Algorithms and Execution & Workflows sections, pipeline authoring is separated from pipeline usage, and partitioning and MaestroSimulator are featured in the README (aadf9dd)
  • qprog: document the LASSQD workflow — a user-guide page on explicit and automatic fragment specification, the macro-cycle round model and how to read the workflow state, plus a linear-H4 tutorial (7d953cb)
  • convert prose to British English across docstrings, RST, comments and user-facing message strings, and set spelling_ignore_pypi_package_names to False, since PyPI names a package for nearly every English word and the check was silently accepting "parameterized", "minimize" and "color" (4980c43)
  • mark dashboard example code blocks with .. dashboard-example: comments and notify qoro-dash on push to main (7378b7f)