Precision & Capabilities -- precision selection, simulator registry, SIMD diagnostics
Every CPU-family simulator in pyqpanda3.core accepts an arithmetic precision at construction ("float32" or "float64"), reports its supported precisions, and — where meaningful — hands back state in the native dtype. Two new query surfaces complement the dials: simulator_capabilities(), a registry that answers "what can run here" without constructing anything, and the pyqpanda3.core.simd submodule, which exposes the runtime SIMD dispatch decision. All interfaces on this page are new in pyqpanda3 0.5.0.
Imports
from pyqpanda3.core import (
CPUQVM,
DensityMatrixSimulator,
InvalidPrecisionError,
MPSQVM,
PrecisionConversionError,
UnsupportedPrecisionError,
simulator_capabilities,
)
from pyqpanda3.core import simdPrecision selection
Constructor keyword
precision is a constructor keyword on CPUQVM, DensityMatrixSimulator, MPSQVM, PartialAmplitudeQVM, SingleAmplitudeQVM, SparseHeisenbergSimulator, and GPUQVM. It is immutable per instance and defaults to "float64" everywhere.
import numpy as np
from pyqpanda3.core import CPUQVM
seed = np.array([0.5, 0.5, 0.5, 0.5], dtype=np.complex64)
qvm32 = CPUQVM(precision="float32")
qvm32.init_state(seed)
print(qvm32.current_state().dtype, qvm32.current_state().shape, qvm32.precision,
tuple(qvm32.supported_precisions))
qvm64 = CPUQVM()
qvm64.init_state(seed)
print(qvm64.current_state().dtype, qvm64.current_state().shape, qvm64.precision)Output:
complex64 (4,) float32 ('float32', 'float64')
complex128 (4,) float64| Property | Type | Description |
|---|---|---|
precision | str | The arithmetic precision this instance was constructed with. Read-only. |
supported_precisions | tuple[str, ...] | Precisions this simulator class supports. Read-only. |
Stabilizer reports precision == "exact" with supported_precisions == ("exact",); it rejects arithmetic precisions with UnsupportedPrecisionError.
CPUQVM.current_state / MPSQVM.current_state
CPUQVM.current_state() -> numpy.ndarray
MPSQVM.current_state() -> numpy.ndarrayReturns simulator state as a NumPy array in the simulator's native precision (complex64 for "float32", complex128 for "float64"). Unlike result().get_state_vector(), no dtype conversion takes place.
The two classes differ in which state they report, and the difference is load-bearing:
| Simulator | What current_state() returns |
|---|---|
CPUQVM | The state most recently installed by init_state(...). A run() does not populate it — before any init_state(...) call it is an empty array of the correct dtype. To read the state a run() produced, use result().get_state_vector(). |
MPSQVM | The live state produced by the most recent run(). |
import numpy as np
from pyqpanda3.core import CPUQVM, MPSQVM, CNOT, H, QProg, measure
# CPUQVM: current_state() mirrors init_state(); run() leaves it alone.
cpu = CPUQVM(precision="float32")
cpu.run(QProg() << H(0) << CNOT(0, 1) << measure([0, 1], [0, 1]), 100)
print("before init_state:", len(cpu.current_state()))
cpu.init_state(np.array([0.5, 0.5, 0.5, 0.5], dtype=np.complex64))
print("after init_state:", cpu.current_state().dtype, cpu.current_state().shape)
print("after run (result path):", len(cpu.result().get_state_vector()))
# MPSQVM: current_state() is the post-run state.
mps = MPSQVM(precision="float32")
mps.run(QProg() << H(0) << CNOT(0, 1), 2)
print("mps:", mps.current_state().dtype, mps.current_state().shape)Output:
before init_state: 0
after init_state: complex64 (4,)
after run (result path): 4
mps: complex64 (4,)DensityMatrixSimulator.density_matrix_native
DensityMatrixSimulator.density_matrix_native() -> numpy.ndarrayReturns the density matrix as a NumPy array in the simulator's native dtype. Use density_matrix() for the always-complex128 view and this method when the native dtype should flow through downstream computation.
MPS truncation options and run statistics
MPSQVM(precision: str = "float64", truncation_atol: float | None = None, max_bond_dimension: int | None = None)| Parameter | Type | Description |
|---|---|---|
| precision | str | "float32" or "float64". Default "float64". |
| truncation_atol | float or None | Singular values below this weight are discarded after each SVD. Defaults are precision-dependent: 1e-6 for float32, 1e-12 for float64. |
| max_bond_dimension | int or None | Hard cap on the bond dimension kept after truncation. None means truncation is tolerance-driven only. |
MPSQVM.stats() -> MPSRunStatsMPSRunStats is a read-only record with discarded_weight (total probability weight dropped by truncation so far) and max_bond_dimension_seen (largest bond dimension materialized so far).
import numpy as np
from pyqpanda3.core import MPSQVM, QProg, RY, CZ
rng = np.random.default_rng(7)
prog = QProg()
for q in range(6):
prog << RY(q, rng.uniform(0, np.pi))
for layer in range(4):
pairs = [(0, 1), (2, 3), (4, 5)] if layer % 2 == 0 else [(1, 2), (3, 4)]
for a, b in pairs:
prog << CZ(a, b) << RY(a, rng.uniform(0, np.pi)) << RY(b, rng.uniform(0, np.pi))
capped = MPSQVM(precision="float64", max_bond_dimension=2)
capped.run(prog, 1)
print(capped.stats().discarded_weight, capped.stats().max_bond_dimension_seen)
exact = MPSQVM()
exact.run(prog, 1)
print(exact.stats().discarded_weight, exact.stats().max_bond_dimension_seen)Output:
0.024353811677256556 2
1.8613363972962274e-34 4SingleAmplitudeQVM.stats
SingleAmplitudeQVM.stats() -> SingleAmplitudeStatsSingleAmplitudeStats is a read-only record with cache_hit_count, cache_miss_count, and peak_workspace_bytes, describing the amplitude-evaluation workspace behavior of the most recent run.
Precision exceptions
Invalid precision requests raise early with dedicated exception types, all subclasses of ValueError:
| Exception | Raised when |
|---|---|
InvalidPrecisionError | The precision string is not a recognized precision name (for any backend). |
UnsupportedPrecisionError | The precision name is valid but the backend does not support it. |
PrecisionConversionError | A precision conversion requested by the user cannot be performed. |
from pyqpanda3.core import CPUQVM, Stabilizer
try:
CPUQVM(precision="float16")
except ValueError as e:
print(type(e).__name__, "-", e)
try:
Stabilizer(precision="float32")
except ValueError as e:
print(type(e).__name__, "-", e)Output:
InvalidPrecisionError - unknown precision 'float16'
UnsupportedPrecisionError - backend 'Stabilizer' does not support precision 'float32'; supported precisions are: exactBackendUnavailableError (a RuntimeError subclass) is raised when constructing an unregistered or unavailable simulator backend. Note that on a build without CUDA, GPUQVM is not registered at all: pyqpanda3.core.GPUQVM is None (an ImportWarning is emitted at import time) and cannot be constructed; the capability registry (below) reports the same condition as available=False. Use simulator_capabilities("GPUQVM").available to check.
Simulator capability registry
simulator_capabilities(name: str | None = None) -> SimulatorCapabilities | list[SimulatorCapabilities]| Parameter | Type | Description |
|---|---|---|
| name | str or None | Simulator class name (for example "MPSQVM"). When omitted, records for every registered simulator are returned. |
SimulatorCapabilities is a read-only record:
| Field | Type | Description |
|---|---|---|
name | str | Simulator class name. |
supported_precisions | tuple[str, ...] | Precisions the class supports. |
default_precision | str | Precision used when precision is not specified. |
available | bool | Whether the simulator can be constructed on this host (build present, hardware present). |
simd_domain | str | Compute domain the simulator occupies: StateVector, Density, Tensor, Amplitude, Sparse, or NotApplicable. |
from pyqpanda3.core import simulator_capabilities
for cap in simulator_capabilities():
print(f"{cap.name:26s} {','.join(cap.supported_precisions):16s}"
f" default={cap.default_precision:8s} available={str(cap.available):5s}"
f" domain={cap.simd_domain}")Output:
CPUQVM float32,float64 default=float64 available=True domain=StateVector
DensityMatrixSimulator float32,float64 default=float64 available=True domain=Density
GPUQVM float64 default=float64 available=False domain=NotApplicable
MPSQVM float32,float64 default=float64 available=True domain=Tensor
PartialAmplitudeQVM float32,float64 default=float64 available=True domain=Amplitude
SingleAmplitudeQVM float32,float64 default=float64 available=True domain=Amplitude
SparseHeisenbergSimulator float32,float64 default=float64 available=True domain=Sparse
Stabilizer exact default=exact available=True domain=NotApplicableSIMD diagnostics and preference
The pyqpanda3.core.simd submodule reports the runtime SIMD dispatch and lets you override it.
simd.capabilities
simd.capabilities() -> SIMDCapabilitiesSIMDCapabilities is an immutable snapshot with:
| Field | Type | Description |
|---|---|---|
architecture | str | Host architecture, for example x86_64. |
compiled_backends | list[str] | Backends compiled into this build: x86_64 — scalar, sse2, avx2, avx512; ARM64 — scalar, neon, sve, sve2. |
available_backends | list[str] | Compiled backends the host CPU can actually execute. |
default_backend | str | The backend the detector selected automatically. |
active_backend | str | The backend currently in effect (default or user preference). |
fallback_reason | str | Why a requested backend was not honored; empty when none. |
simd.active_backend
simd.active_backend() -> strReturns the backend currently in effect.
simd.set_preference
simd.set_preference(backend: str, strict: bool = False) -> None| Parameter | Type | Description |
|---|---|---|
| backend | str | One of "auto", "scalar", "sse2", "avx2", "avx512", "neon", "sve", "sve2" (as compiled/available). |
| strict | bool | When True, raise UnsupportedSIMDBackendError (a RuntimeError subclass) for unavailable backends instead of recording a fallback. Default False. |
from pyqpanda3.core import simd
cap = simd.capabilities()
print(cap.architecture, list(cap.available_backends), cap.active_backend)
simd.set_preference("scalar")
print(simd.active_backend())
simd.set_preference("auto")
print(simd.active_backend())Output (on an AVX2-capable x86_64 host):
x86_64 ['scalar', 'sse2', 'avx2', 'avx512'] avx2
scalar
avx2The preference applies to simulators constructed after the call. The automatic promotion policy is deliberately conservative: a backend becomes the automatic choice only when its correctness rows pass and its measured runtimes beat the next safe backend on the release benchmark suite (median AVX2 speedup over scalar is 2.13x there).
See Also
- Simulator -- per-simulator references
- Gates -- the gate zoo
- Noise --
NoiseModeland error channels - v0.5.0 release notes -- the release that introduced these interfaces