mindquantum.device.QPU

View Source On AtomGit
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 implement sampling(); the base class provides default shot-based implementations for expectation values and gradients.

Parameters
  • n_qubits (int) – Number of qubits available on this QPU.

  • default_shots (int) – Default number of measurement shots used when shots is not explicitly provided. Default: 1000.

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 Hamiltonian constructed from QubitOperator is supported in the default expectation / gradient implementation (hardware-measurable Pauli sums).

  • Non-Hermitian expectation values and the circ_left / simulator_left overlap form are not supported.

  • Circuits passed to get_expectation() or get_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_right and \(|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, uses default_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 Simulator API.

Raises
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, uses default_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 from QubitOperator.

  • 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.