mindquantum.device.QPU
- class mindquantum.device.QPU(n_qubits, default_shots=1000)[source]
Base class for QPU execution.
Users should instantiate a concrete QPU subclass provided by a hardware vendor (e.g.
MyVendorQPU(n_qubits, ...)). Subclasses only need to implementsampling(); the base class provides default shot-based implementations for expectation values and gradients.- Parameters
- Raises
TypeError – If n_qubits or default_shots is not an integer.
ValueError – If n_qubits or default_shots is less than 1.
Note
Only
Hamiltonianconstructed fromQubitOperatoris supported in the default expectation / gradient implementation (hardware-measurable Pauli sums).Non-Hermitian expectation values and the
circ_left/simulator_leftoverlap form are not supported.Circuits passed to
get_expectation()orget_expectation_with_grad()must not contain measurement gates; measurement bases are generated internally.Hardware constraints (topology, native gates, calibration-aware compilation) are intentionally left to concrete subclasses.
Providers can override
_sampling_batch()to submit batched circuit jobs to hardware.
Examples
>>> import numpy as np >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.gates import Measure >>> from mindquantum.core.operators import QubitOperator, Hamiltonian >>> from mindquantum.device import QPU >>> class DummyQPU(QPU): ... def sampling(self, circuit, pr=None, shots=1, seed=None): ... # Concrete subclass implements real hardware sampling here. ... from mindquantum.simulator import Simulator ... sim = Simulator('mqvector', self.n_qubits) ... return sim.sampling(circuit, pr=pr, shots=shots, seed=seed) >>> qpu = DummyQPU(n_qubits=2, default_shots=1000) >>> qpu DummyQPU(n_qubits=2, default_shots=1000) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> circ = Circuit().ry(1.2, 0) >>> isinstance(qpu.get_expectation(ham, circ), complex) True
- get_expectation(hamiltonian, circ_right=None, circ_left=None, simulator_left=None, pr=None, *, shots=None, seed=None)[source]
Estimate the expectation value of a Hamiltonian by sampling.
This method mirrors the user API of
mindquantum.simulator.Simulator.get_expectation(), but the value is estimated from measurement shots rather than computed exactly.Only the Hermitian Pauli-sum case is supported:
\[E = \langle 0 | U^\dagger H U | 0 \rangle\]where \(U\) is
circ_rightand \(|0\rangle\) denotes the implicit all-zero initial state \(|0\cdots0\rangle\).- Parameters
hamiltonian (Hamiltonian) – The Hamiltonian to evaluate. Must be constructed from
QubitOperator.circ_right (Circuit) – State-preparation circuit \(U\). Default:
None(empty circuit).circ_left – Not supported. Must be
None.simulator_left – Not supported. Must be
None.pr (Union[Dict[str, numbers.Number], ParameterResolver, numpy.ndarray, list, numbers.Number]) – Parameter values for
circ_right. Default:None.shots (int) – Shots per Pauli-term measurement circuit. If
None, usesdefault_shots. Default:None.seed (int) – Optional seed forwarded to
sampling(). Default:None.
- Returns
numbers.Number, the estimated expectation value. A complex number with zero imaginary part is returned to match the
SimulatorAPI.- Raises
TypeError – If hamiltonian is not a
Hamiltonian.NotImplementedError – If circ_left or simulator_left is not
None, or if the Hamiltonian is not constructed fromQubitOperator.ValueError – If circ_right contains measurement gates, or if the circuit requires more qubits than the QPU provides.
- get_expectation_with_grad(hams, circ_right, circ_left=None, simulator_left=None, parallel_worker=None, pr_shift=False, *, shots=None, seed=None, fd_gap=0.001)[source]
Get a function that returns expectation values and gradients w.r.t. circuit parameters.
The returned object is a
GradOpsWrapper, preserving compatibility with MindQuantum's VQA / MindSpore integration.For real hardware, gradients are estimated by repeatedly executing circuits:
When
pr_shift=True, a parameter-shift rule is used for parameters that appear in exactly one grad-enabled intrinsic parameter occurrence and whose gate matches the shift-rule table (RX, RY, RZ, Rxx, Ryy, Rzz, Rxy, Rxz, Ryz, RPS, GP, PS, U3, and SWAPalpha with its special shift constant). Controlled gates and unsupported gates (e.g. Givens, FSim, custom) fall back to finite differences.When
pr_shift=False(default), all gradients use central finite differences.
- Parameters
hams (Union[
Hamiltonian, List[Hamiltonian]]) – A Hamiltonian or a list of Hamiltonians whose expectations are evaluated.circ_right (Circuit) – The variational circuit \(U\).
circ_left – Not supported. Must be
None.simulator_left – Not supported. Must be
None.parallel_worker (int) – Accepted for signature compatibility but not used. Default:
None.pr_shift (bool) – Whether to prefer the parameter-shift rule when applicable. Default:
False.shots (int) – Shots per circuit execution. If
None, usesdefault_shots. Default:None.seed (int) – Optional base seed for reproducible gradient estimation. Default:
None.fd_gap (float) – Step size for central finite-difference gradients. Default:
0.001.
- Returns
GradOpsWrapper, a callable whose signature is
grad_ops(*inputs) -> (f, g_enc[, g_ans])where f has shape(batch, n_hams)and each gradient array has shape(batch, n_hams, n_params).- Raises
TypeError – If hams is not a Hamiltonian or list of Hamiltonians, or if circ_right is not a Circuit.
NotImplementedError – If circ_left or simulator_left is not
None, or if any Hamiltonian is not constructed fromQubitOperator.ValueError – If circ_right contains measurement gates, if the circuit exceeds the QPU qubit count, if fd_gap is not positive, or if encoder and ansatz parameter sets overlap.
Examples
>>> import numpy as np >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import QubitOperator, Hamiltonian >>> from mindquantum.device import QPU >>> class DummyQPU(QPU): ... def sampling(self, circuit, pr=None, shots=1, seed=None): ... from mindquantum.simulator import Simulator ... sim = Simulator('mqvector', self.n_qubits) ... return sim.sampling(circuit, pr=pr, shots=shots, seed=seed) >>> qpu = DummyQPU(n_qubits=1, default_shots=10000) >>> circ = Circuit().ry('a', 0) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> grad_ops = qpu.get_expectation_with_grad(ham, circ, shots=10000, seed=42) >>> f, g = grad_ops(np.array([1.0])) >>> f.shape, g.shape ((1, 1), (1, 1, 1))
- property n_qubits: int
Get the number of qubits available on this QPU.
- Returns
int, the qubit count.
- abstract sampling(circuit, pr=None, shots=1, seed=None)[source]
Execute circuit on this QPU and return sampling results.
This is the only method a hardware backend must implement. All other public methods (expectation, gradients) are built on top of this primitive.
- Parameters
circuit (Circuit) – Circuit containing at least one measurement gate.
pr (Union[dict, ParameterResolver]) – Parameter values for a parameterized circuit. Default:
None.shots (int) – Number of measurement shots. Default:
1.seed (int) – Optional seed for reproducibility (may be ignored by real hardware). Default:
None.
- Returns
MeasureResult, the sampling results.