quchip.backend.qutip¶
QuTiP backend implementation of the quchip.backend.protocol contract.
QuTiP stores operators as qutip.Qobj (sparse CSR by default, dense on
request). This backend lowers engine IR into Qobj / QobjEvo form and
dispatches the sesolve/mesolve drivers directly.
Batched sweeps and heterogeneous problem lists are parallelized via the
loky reusable process pool. QuTiP solvers release the GIL only partially,
so processes beat threads. Final QobjEvo assembly happens inside the
workers so the main process never pays for it.
References
Johansson, Nation, Nori — QuTiP 2, Comput. Phys. Commun. 183, 1760 (2012)
Breuer & Petruccione — The Theory of Open Quantum Systems (OUP, 2002)
Classes
Concrete backend backed by QuTiP. |
- class quchip.backend.qutip.QuTiPBackend[source]¶
Bases:
BackendConcrete backend backed by QuTiP.
Operator=State=qutip.Qobj.Example
>>> from quchip.backend.qutip import QuTiPBackend >>> backend = QuTiPBackend() >>> a = backend.destroy(3) >>> float((a.dag() * a).diag()[2].real) 2.0
- destroy(n)[source]¶
Return the annihilation operator for an n-level Fock space (
qutip.destroy, memoized).
- from_array(data, dims=None)[source]¶
Construct a
Qobjfrom a dense matrix with optional row/col dims.
- to_canonical_operator(op)[source]¶
Serialize a
Qobjinto the backend-agnostic canonical IR (CSR or dense).
- eigenenergies(op)[source]¶
Return the ascending eigenvalues of a Hermitian operator (
Qobj.eigenenergies).
- eigensystem_data(op)[source]¶
Return ascending eigenvalues, eigenvector matrix, and primed eigenstate kets.
A
QobjusesQobj.eigenstatesverbatim to preserve the exact degenerate-subspace basis; dense inputs fall through to the protocol default.- Parameters:
op (Any)
- Return type:
- expect(op, state)[source]¶
Return the expectation value ⟨op⟩ for a ket or density matrix via
qutip.expect.
- ptrace(state, keep, dims)[source]¶
Reduce onto subsystem(s) keep via
Qobj.ptrace(partial trace).Rebuilds the composite dims when the incoming state carries flat dims.
- permute_state(state, dims, order)[source]¶
Reorder a
Qobj’s subsystems viaQobj.permute(sparse-friendly, keeps dims).Rebuilds composite
dimsfirst when the incoming state carries flat dims, mirroringptrace(). Non-Qobjinputs fall through to the protocol default.
- tensor(*operators)[source]¶
Return the tensor product of operators via
qutip.tensor(array-likes coerced first).
- embed_two_body(op_ab, index_a, index_b, dims)[source]¶
Embed a two-body operator on devices index_a ⊗ index_b into the full space.
Reorders subsystems (via sparse SWAP when
index_a > index_b) and identity-pads spectators without densifying the full matrix.
- coherent(n, alpha)[source]¶
Return the coherent state |α⟩ truncated to n Fock levels (
qutip.coherent).
- resolve_solver_options(options, *, metadata, tlist)[source]¶
Fill in
nstepsandmax_stepfrom Hamiltonian-metadata heuristics when unset.nstepsis an abort ceiling on the integrator’s total internal step count, not a step-size bound — seedefault_solver_steps()for the heuristic that derives it from the Hamiltonian’s fastest frequency scale.max_stepbounds the size of an individual adaptive step. Without it, QuTiP’s adaptive integrator can step clean over a finite-support pulse that sits inside a long idle span, sampling it only at points where its envelope happens to be near zero. When the user has not setmax_stepandmetadata["max_step_ns"]carries a concrete, positive, finite value — half the narrowest window across the Hamiltonian’s dynamic terms, computed by_solver_hint_metadata()— it is used as the ceiling. An explicit usermax_stepis always authoritative, including QuTiP’s ownmax_step=0(unbounded): the key’s presence inoptionsdecides, not its truthiness.This is QuTiP’s single option-merge boundary (shared by the single and batched solve paths), so the dynamiqs-only
gradientknob — which QuTiP’sSolverOptionsrejects — is stripped here exactly once for portability; downstream runners trust the merged dict.
- coerce_state(state, dims=None)[source]¶
Wrap a foreign-native array state (ket or density matrix) into a
Qobj.Used when a per-call
backend="qutip"override consumes states built under the dynamiqs backend.dimsrestores the tensor structure QuTiP’s solvers require to match the Hamiltonian’s dims.
- sesolve(H, psi0, tlist, e_ops=None, options=None)[source]¶
Solve the Schrödinger equation — wraps
qutip.solver.sesolve.SESolver.
- mesolve(H, rho0, tlist, c_ops=None, e_ops=None, options=None)[source]¶
Solve the Lindblad master equation — wraps
qutip.solver.mesolve.MESolver.
- steadystate(problem)[source]¶
Solve a static Lindblad generator with
qutip.steadystate().- Parameters:
problem (Any)
- Return type:
- parallel_solve_problems(problems, *, progress=True)[source]¶
Solve large structurally heterogeneous problem lists through loky workers.
- Parameters:
- Return type:
list[SolverResult] | None
- batched_sesolve(problems, *, n_jobs=-1, progress=True)[source]¶
Run sesolve in parallel via loky workers; fall back to sequential on failure.
- batched_mesolve(problems, *, n_jobs=-1, progress=True)[source]¶
Run mesolve in parallel via loky workers; fall back to sequential on failure.
- prepare_hamiltonian(description, tlist=None)[source]¶
Convert a
EngineResultinto aQobjorQobjEvo.Each dynamic coefficient is band-normalized: every carrier stays analytic while only its slow, carrier-free envelope is sampled (on tlist, locally densified around any window edge — see
_band_coefficient()/_augmented_sample_grid()). This avoids cubic-spline error from pre-sampling the fullenvelope·carrierproduct, including for resonant carriers in the lab frame.- Parameters:
- Return type:
- prepare_batch(batch)[source]¶
Build a deferred-construction batch; per-element
QobjEvois built in workers.Each unique
CanonicalOperatoris converted exactly once (shared across elements) and only the slow, carrier-free envelope is sampled on the user grid, locally densified around any window edge (carriers stay analytic — see_band_coefficient()). FinalQobjEvoassembly lives insolve_batch()so larger concrete sweeps can build and solve each point inside loky workers.- Parameters:
batch (Any)
- Return type:
- solve_batch(batch, *, progress=True)[source]¶
Solve a
SolveBatchwith per-elementQobjEvobuilt in loky workers.- Parameters:
- Return type:
- warmup(n_jobs=-1)[source]¶
Pre-spawn the reusable loky worker pool out of any timed region.
Entirely optional:
solve_batchspins the pool up on demand, so the only reason to call this is to move that one-time spin-up cost out of a region you are timing (benchmarks). Ordinary scripts and notebooks never need it.Forks the workers and pays the per-worker import cost up front by mapping a no-op over the worker count. A subsequent sweep then reuses the live pool instead of paying cold spin-up inside the timed solve. No-op (with a warning) when loky is unavailable.
- Parameters:
n_jobs (int)
- Return type:
None