0.4.1
pyqpanda3 0.4.1 continues and deepens the 0.4.0 hardware workflow. The focus of this release is making fidelity data actually drive transpilation decisions (fidelity-driven approximate decomposition, LightSABRE routing, recoverable transpilation metrics), and filling two long-standing simulator gaps — a matrix-product-state (MPS) simulator and a Heisenberg-picture expectation simulator.
1. Strongly-typed transpilation options and metrics
In 0.4.0, transpile() used positional arguments to control the optimization level and layout strategy. 0.4.1 adds TranspilationOptions, which groups every tunable into a single object, and pairs it with TranspilationResult, which returns the transpiled program, compile time, and metrics in one call.
from pyqpanda3.core import QProg, H, CZ, measure
from pyqpanda3.transpilation import (
ChipBackend,
LayoutMethod,
RoutingMethod,
Transpiler,
TranspilationOptions,
)
prog = QProg()
prog << H(0) << CZ(0, 1) << measure(0, 0) << measure(1, 1)
backend = ChipBackend()
backend.chip_topology_edges = [[0, 1], [1, 2]]
backend.basic_gates = ["RPhi", "CZ"]
backend.single_gate_fidelity = {0: 0.99, 1: 0.99, 2: 0.99}
backend.readout_fidelity = {0: 0.90, 1: 0.90, 2: 0.99}
backend.double_gate_fidelity = {(0, 1): 0.90, (1, 2): 0.99}
options = TranspilationOptions()
options.optimization_level = 2
options.layout_method = LayoutMethod.FIDELITY
options.routing_method = RoutingMethod.LIGHT_SABRE
options.approximation_degree = 0.99
options.execution.routing_trials = 8
options.execution.seed = 42
result = Transpiler().transpile(prog, backend, options)
print(type(result).__name__)
print(result.compile_time_ns > 0)
print(sorted(result.metrics.keys()))
print(len(result.program.operations()) > 0)Example output shape:
TranspilationResult
True
['depth', 'fidelity_exact', 'fidelity_fallback', 'fidelity_unknown', 'log_expected_fidelity', 'two_qubit_gate_count']
Trueresult.metrics has the same shape as the dict returned by the standalone function transpilation_metrics(prog, backend), with these fields:
| Field | Type | Description |
|---|---|---|
two_qubit_gate_count | int | Number of two-qubit gates in the transpiled program. |
depth | int | Gate depth of the transpiled program. |
log_expected_fidelity | float or None | Logarithm of the expected fidelity, accumulated as log(1 - error) over every gate plus one readout per measured qubit; None when any gate or readout fidelity is unknown. |
fidelity_exact | int | Number of gates whose fidelity data was matched exactly. |
fidelity_fallback | int | Number of gates that fell back to an aggregate estimate. |
fidelity_unknown | int | Number of gates with no fidelity data at all. |
2. LightSABRE routing
RoutingMethod.LIGHT_SABRE (the string "light_sabre") enables the new layered-lookahead router. It expands the interaction graph layer by layer while routing, which tends to reduce two-qubit gate insertion and swap depth — useful for backends with limited connectivity or deeper circuits.
Besides the strongly-typed entry point, it can also be enabled directly via the positional-argument overload:
from pyqpanda3.core import QProg, H, CZ, measure
from pyqpanda3.transpilation import ChipBackend, Transpiler
prog = QProg()
prog << H(0) << CZ(0, 1) << measure(0, 0) << measure(1, 1)
backend = ChipBackend()
backend.chip_topology_edges = [[0, 1], [1, 2]]
backend.basic_gates = ["RPhi", "CZ"]
transpiled = Transpiler().transpile(
prog,
backend,
{},
2,
"fidelity",
"light_sabre",
"default",
approximation_degree=0.99,
)
print(type(transpiled).__name__)
print(len(transpiled.operations()) > 0)Output:
QProg
True3. Heisenberg-picture expectation simulator
SparseHeisenbergSimulator computes the expectation value of a Pauli Hamiltonian using a sparse Heisenberg-picture algorithm. It is not a shot-based QVM and does not return a state vector; it is well suited to quickly estimating <H> when the gate set is supported and the initial state is a product state. When the number of operator terms grows, you can truncate with max_terms and truncation_norm.
from pyqpanda3.core import QProg, CZ, SparseHeisenbergSimulator
zero = (1 + 0j, 0 + 0j) # (|0> amplitude, |1> amplitude) for each qubit
prog = QProg() << CZ(0, 1) # |00> unchanged
sim = SparseHeisenbergSimulator(num_qubits=2)
sim.set_initial_product_state([zero, zero])
sim.add_observable("ZZ", 1.0)
sim.evolve_backward(prog)
print(round(sim.expectation(), 6))Output:
1.0The free function sparse_heisenberg_expectation(prog, hamiltonian, initial_product_state=...) is equivalent to the flow above and does it in one step:
from pyqpanda3.core import QProg, CZ, sparse_heisenberg_expectation
from pyqpanda3.hamiltonian import Hamiltonian
zero = (1 + 0j, 0 + 0j)
prog = QProg() << CZ(0, 1)
ham = Hamiltonian({"Z0 Z1": 1.0})
print(round(sparse_heisenberg_expectation(prog, ham, initial_product_state=[zero, zero]), 6))Output:
1.04. Matrix-product-state (MPS) simulator
MPSQVM runs quantum programs on a matrix-product-state backend, keeping memory usage low for weakly-entangled circuits even at large qubit counts. After running, retrieve measurement results via result().
from pyqpanda3.core import H, MPSQVM, QProg, measure
prog = QProg() << H(0) << measure(0, 0) << measure(1, 1)
qvm = MPSQVM()
qvm.run(prog, 1000)
result = qvm.result()
print(type(result).__name__)
print(sum(result.get_counts().values()) == 1000)Example output shape:
QResult
True5. Initial state: CPUQVM.init_state
0.4.1 adds init_state() to CPUQVM, letting you set the simulator's initial quantum state before running. The simulator resets to this state before each run() (and each evolve()); calling without arguments restores the default |0...0> state.
import numpy as np
from pyqpanda3.core import CPUQVM, QProg, measure
qvm = CPUQVM()
qvm.init_state([1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)])
prog = QProg() << measure([0, 1], [0, 1])
qvm.run(prog, 1000)
print(qvm.result().get_counts())
qvm.init_state() # restore default |0...0>
qvm.run(prog, 1000)
print(qvm.result().get_counts())Output (counts fluctuate slightly due to random sampling):
{'00': 524, '11': 476}
{'00': 1000}Note: MPSQVM's C++
init_stateis not exposed in the Python bindings (0.4.1); useCPUQVM.init_stateon the Python side.
6. Cloud task cancellation
QCloudJob gains cancellation: you can now actively cancel a submitted cloud task.
QCloudJob.cancel(self) -> bool
QCloudJob.cancel_task(task_id: str) -> boolcancel() cancels the current job; the static method cancel_task(task_id) cancels the task with the given ID. Both return True when the cloud service accepted the cancellation request and False when the service responded that the task cannot be cancelled.
Cancelling tasks requires cloud credentials and a real task, so it cannot be executed locally:
from pyqpanda3.qcloud import QCloudJob, QCloudService
# Requires cloud credentials and a real task; cannot run locally
service = QCloudService("your_api_key")
job = QCloudJob("your_job_id")
print(job.cancel()) # cancel the current job
print(QCloudJob.cancel_task("your_task_id")) # cancel by task ID (static)API changes
- Added
pyqpanda3.transpilation.TranspilationOptions(optimization_level,layout_method,routing_method,optimization_method,init_mapping,execution,approximation_degree). - Added
pyqpanda3.transpilation.TranspilationExecutionConfig(max_threads,routing_trials,seed,compile_time_budget_ms). - Added
pyqpanda3.transpilation.TranspilationResult(program,compile_time_ns,metrics). - Added enums
LayoutMethod,RoutingMethod(includingLIGHT_SABRE),OptimizationMethod. - Added the strongly-typed overload
Transpiler.transpile(prog, backend, options) -> TranspilationResult, plus advanced overloads takingrouting_method/optimization_method/approximation_degree/execution_config. - Added
pyqpanda3.transpilation.transpilation_metrics(prog, backend). - The transpiler internals gained fidelity-driven ORACLE KAK synthesis:
level 0forces exact synthesis; atoptimization_level >= 1,approximation_degreedecides whether two-qubit gate synthesis is exact or approximate.level 1runsunitary_synthesisonce, whilelevel 2iterates it to a fixed point. - Added
pyqpanda3.core.MPSQVM(run,result). - Added
CPUQVM.init_state(), which sets the initial quantum state before running; calling without arguments restores the default|0...0>state. - Added
pyqpanda3.core.SparseHeisenbergSimulator,SparseHeisenbergStats,sparse_heisenberg_expectation(). - Added
pyqpanda3.quantum_info.state_fidelity()(the four density-matrix / state-vector combinations). - Added
QCloudJob.cancel()and the static methodQCloudJob.cancel_task(task_id)to cancel submitted cloud tasks. - Added
ndarray()toChoi,SuperOp,PTM. - Added
QProg.get_measure_qubits_cbits(). - Removed
instructions_to_qprogs(): multi-stream input is now handled byinstruction_to_qprog(), which returnsQProgorlist[QProg]. PartialAmplitudeQVMdecimal-index arguments are now bounds- and validity-checked.- Fixed a segfault when
VQCircuit.append(vqc)was self-referential. - Fixed a segfault when VF2 layout was partial (did not cover all qubits).
- Fixed a
ParamExpressioncrash on empty expressions. - Fixed the orientation of dephasing-noise Kraus matrices.
- Fixed a memory leak in
get_matrix/ unitary extraction.