Skip to content

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 ​

python
from pyqpanda3.core import (
    CPUQVM,
    DensityMatrixSimulator,
    InvalidPrecisionError,
    MPSQVM,
    PrecisionConversionError,
    UnsupportedPrecisionError,
    simulator_capabilities,
)
from pyqpanda3.core import simd

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

python
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:

text
complex64 (4,) float32 ('float32', 'float64')
complex128 (4,) float64
PropertyTypeDescription
precisionstrThe arithmetic precision this instance was constructed with. Read-only.
supported_precisionstuple[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 ​

python
CPUQVM.current_state() -> numpy.ndarray
MPSQVM.current_state() -> numpy.ndarray

Returns 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:

SimulatorWhat current_state() returns
CPUQVMThe 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().
MPSQVMThe live state produced by the most recent run().
python
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:

text
before init_state: 0
after init_state: complex64 (4,)
after run (result path): 4
mps: complex64 (4,)

DensityMatrixSimulator.density_matrix_native ​

python
DensityMatrixSimulator.density_matrix_native() -> numpy.ndarray

Returns 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 ​

python
MPSQVM(precision: str = "float64", truncation_atol: float | None = None, max_bond_dimension: int | None = None)
ParameterTypeDescription
precisionstr"float32" or "float64". Default "float64".
truncation_atolfloat or NoneSingular values below this weight are discarded after each SVD. Defaults are precision-dependent: 1e-6 for float32, 1e-12 for float64.
max_bond_dimensionint or NoneHard cap on the bond dimension kept after truncation. None means truncation is tolerance-driven only.
python
MPSQVM.stats() -> MPSRunStats

MPSRunStats 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).

python
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:

text
0.024353811677256556 2
1.8613363972962274e-34 4

SingleAmplitudeQVM.stats ​

python
SingleAmplitudeQVM.stats() -> SingleAmplitudeStats

SingleAmplitudeStats 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:

ExceptionRaised when
InvalidPrecisionErrorThe precision string is not a recognized precision name (for any backend).
UnsupportedPrecisionErrorThe precision name is valid but the backend does not support it.
PrecisionConversionErrorA precision conversion requested by the user cannot be performed.
python
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:

text
InvalidPrecisionError - unknown precision 'float16'
UnsupportedPrecisionError - backend 'Stabilizer' does not support precision 'float32'; supported precisions are: exact

BackendUnavailableError (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 ​

python
simulator_capabilities(name: str | None = None) -> SimulatorCapabilities | list[SimulatorCapabilities]
ParameterTypeDescription
namestr or NoneSimulator class name (for example "MPSQVM"). When omitted, records for every registered simulator are returned.

SimulatorCapabilities is a read-only record:

FieldTypeDescription
namestrSimulator class name.
supported_precisionstuple[str, ...]Precisions the class supports.
default_precisionstrPrecision used when precision is not specified.
availableboolWhether the simulator can be constructed on this host (build present, hardware present).
simd_domainstrCompute domain the simulator occupies: StateVector, Density, Tensor, Amplitude, Sparse, or NotApplicable.
python
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:

text
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=NotApplicable

SIMD diagnostics and preference ​

The pyqpanda3.core.simd submodule reports the runtime SIMD dispatch and lets you override it.

simd.capabilities ​

python
simd.capabilities() -> SIMDCapabilities

SIMDCapabilities is an immutable snapshot with:

FieldTypeDescription
architecturestrHost architecture, for example x86_64.
compiled_backendslist[str]Backends compiled into this build: x86_64 — scalar, sse2, avx2, avx512; ARM64 — scalar, neon, sve, sve2.
available_backendslist[str]Compiled backends the host CPU can actually execute.
default_backendstrThe backend the detector selected automatically.
active_backendstrThe backend currently in effect (default or user preference).
fallback_reasonstrWhy a requested backend was not honored; empty when none.

simd.active_backend ​

python
simd.active_backend() -> str

Returns the backend currently in effect.

simd.set_preference ​

python
simd.set_preference(backend: str, strict: bool = False) -> None
ParameterTypeDescription
backendstrOne of "auto", "scalar", "sse2", "avx2", "avx512", "neon", "sve", "sve2" (as compiled/available).
strictboolWhen True, raise UnsupportedSIMDBackendError (a RuntimeError subclass) for unavailable backends instead of recording a fallback. Default False.
python
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):

text
x86_64 ['scalar', 'sse2', 'avx2', 'avx512'] avx2
scalar
avx2

The 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 ​

Released under the MIT License.