Fidelity Layout with QCloud
This tutorial shows the complete pyqpanda3 0.4.0 hardware-aware path:
- Fetch live QCloud chip metadata.
- Convert the metadata into a
ChipBackend. - Use the same
ChipBackendfor fidelity-aware layout and transpilation. - Export a scheduled instruction stream with timing derived from the chip metadata.
- Preview the timing diagram locally.
- Submit the exact instruction stream with
run_instruction().
Do not hard-code API keys in source files. The examples below read QPANDA_QCLOUD_API_KEY from the environment.
Why chip_info() Matters
run_instruction() accepts instruction JSON, so it is tempting to hand-write a short instruction list. That is useful for debugging, but it is not the recommended hardware workflow.
For a real QCloud backend, build the instruction stream from chip_info() instead:
chip_info().get_chip_backend()supplies the physical topology and native gates.single_gate_fidelity,readout_fidelity, anddouble_gate_fidelityguidefidelity_layout().single_gate_timing,double_gate_timing, andecho_gate_timingdrive scheduled instruction timestamps.- CZ compensation data is kept on the same backend object.
The important invariant is simple: the backend used for layout should also be the backend used for instruction export and schedule drawing.
One-Step Fidelity Transpile, Schedule, and Submit
This path lets Transpiler call fidelity layout internally through layout_method="fidelity".
import os
from pyqpanda3.core import CZ, H, QProg, measure
from pyqpanda3.qcloud import QCloudOptions, QCloudService
from pyqpanda3.transpilation import Transpiler, decompose
from pyqpanda3.visualization import draw_time_scheduling
def build_program():
prog = QProg()
prog << H(0)
prog << H(1)
prog << CZ(0, 1)
prog << CZ(1, 2)
prog << measure(0, 0)
prog << measure(1, 1)
prog << measure(2, 2)
return prog
service = QCloudService(os.environ["QPANDA_QCLOUD_API_KEY"])
qcloud_backend = service.backend(os.environ.get("QPANDA_QCLOUD_BACKEND", "WK_C180"))
chip_info = qcloud_backend.chip_info()
chip_backend = chip_info.get_chip_backend()
print("backend:", qcloud_backend.name())
print("timing:", chip_backend.single_gate_timing, chip_backend.double_gate_timing)
prog = build_program()
decomposed = decompose(prog, ["U3", "CZ"])
transpiled = Transpiler().transpile(decomposed, chip_backend, {}, 2, "fidelity")
# is_scheduling=True makes to_instruction use timing from chip_backend, including
# single_gate_timing and double_gate_timing, instead of relying on hand-written timestamps.
instruction = transpiled.to_instruction(
chip_backend,
offset=1,
is_scheduling=True,
compensate_pulse=False,
)
figures = draw_time_scheduling(instruction, backend=chip_backend, output="plotly")
print("schedule figure:", type(figures).__name__)
options = QCloudOptions()
options.set_mapping(False)
options.set_optimization(False)
options.set_amend(False)
job = qcloud_backend.run_instruction([instruction], 1000, options)
result = job.result()
print(result.get_counts_list())Example output shape:
backend: WK_C180
timing: 40 80
schedule figure: Figure
[{'000': 263, '001': 229, '010': 241, '011': 227, '100': 6, '101': 4, '110': 15, '111': 15}]Timing and counts vary by backend and calibration snapshot. The key point is that the instruction timestamps are generated from the ChipBackend returned by QCloud, not from constants in the document.
Inspect the Layout Before Routing
Call fidelity_layout() directly when you want to inspect, store, or adjust the initial mapping before routing. The same chip_backend should still be passed to transpile(), to_instruction(), and draw_time_scheduling().
from pyqpanda3.transpilation import Transpiler, decompose, fidelity_layout
decomposed = decompose(prog, ["U3", "CZ"])
init_mapping = fidelity_layout(
decomposed,
chip_backend.chip_topology_edges,
chip_backend.single_gate_fidelity,
chip_backend.readout_fidelity,
chip_backend.double_gate_fidelity,
)
print("initial mapping:", init_mapping)
transpiled = Transpiler().transpile(
decomposed,
chip_backend,
init_mapping,
2,
)
instruction = transpiled.to_instruction(
chip_backend,
offset=1,
is_scheduling=True,
compensate_pulse=False,
)
figures = draw_time_scheduling(instruction, backend=chip_backend, output="plotly")
job = qcloud_backend.run_instruction([instruction], 1000, options)
print(type(figures).__name__)
print(job.result().get_counts_list())Example output shape:
initial mapping: {1: 106, 0: 96, 2: 115}
Figure
[{'000': 229, '001': 203, '010': 210, '011': 189, '100': 39, '101': 50, '110': 45, '111': 35}]init_mapping is a Python dictionary whose keys are logical qubits and whose values are physical chip qubits.
How Fidelity Layout Works
Build the Virtual Interaction Graph
The layout pass scans the decomposed program. Single-qubit gates increase the importance of their logical qubits. Measurements make readout fidelity relevant. Two-qubit gates create weighted virtual interaction edges, and repeated interactions receive higher weight.
Search Connected Physical Blocks
The chip topology comes from chip_backend.chip_topology_edges. Instead of trying every possible assignment on the full chip, the algorithm first searches connected physical candidate blocks with the same size as the active logical qubit set.
Score Candidate Mappings
Each candidate mapping is scored by minimizing the estimated error cost:
- Single-gate error matters more for logical qubits with many single-qubit operations.
- Readout error matters for logical qubits that are measured.
- Two-qubit gate error matters for logical edges with frequent two-qubit gates.
- Non-adjacent physical distance adds a penalty when frequently interacting logical qubits are far apart.
cost =
one_qubit_count * single_gate_error(physical_qubit)
+ measure_count * readout_error(physical_qubit)
+ two_qubit_count * pair_cost(logical_edge, physical_qubits)where pair_cost depends on whether the logical qubits are mapped to adjacent physical qubits:
- If the two physical qubits are adjacent,
pair_cost = double_gate_error(adjacent_physical_edge). - If they are farther apart, the pair cost adds a nonlocal-interaction penalty, a distance penalty, and the average two-qubit error.
Missing fidelity values use the average error from the available values of the same fidelity class. If that class is empty, the average is 0.0.
Hand the Mapping to Routing
Fidelity layout chooses the initial mapping only. It does not replace routing. If the selected mapping places the main interactions on adjacent, high-fidelity edges, routing usually inserts fewer SWAPs. If the circuit interaction graph and chip topology differ substantially, routing may still need SWAPs.
Tuning Search Parameters
init_mapping = fidelity_layout(
decomposed,
chip_backend.chip_topology_edges,
chip_backend.single_gate_fidelity,
chip_backend.readout_fidelity,
chip_backend.double_gate_fidelity,
max_candidate_blocks=32,
max_mappings_per_block=256,
distance_penalty_weight=1.0,
)| Parameter | Meaning |
|---|---|
max_candidate_blocks | Number of connected physical blocks to consider. Larger values search more thoroughly and take longer. |
max_mappings_per_block | Number of mappings tried inside each candidate block. Larger values can find better mappings but increase combinatorial cost. |
distance_penalty_weight | Penalty for physical distance. Larger values favor fewer routing SWAPs; smaller values favor fidelity more directly. |
Run the Sample
The source package includes a runnable sample:
$env:QPANDA_QCLOUD_API_KEY="your_api_key"
$env:QPANDA_QCLOUD_BACKEND="WK_C180"
python samples/python/fidelity_layout_qcloud.pyIf QPANDA_QCLOUD_BACKEND is not set, the sample uses WK_C180.
Beyond 0.4.0: fidelity-driven approximation and metrics (0.4.1)
This tutorial focuses on the 0.4.0 fidelity_layout() positional-argument workflow. 0.4.1 builds on it to actually let fidelity data drive transpilation decisions:
TranspilationOptionsgroups the layout / routing / optimization strategies into one object, andTranspilationResult.metricsrecovers the two-qubit gate count, depth, log-expected fidelity, and more.- At
optimization_level >= 1,approximation_degreedecides whether ORACLE KAK synthesis is exact or approximate (1.0exact,Noneuses the target two-qubit gate error rate). ChipBackend.gate_fidelity(per-instruction fidelity) is auto-populated from cloud metadata and matched first bytranspilation_metrics().RoutingMethod.LIGHT_SABREenables layered-lookahead routing, which usually reduces two-qubit gate insertion.
See Transpilation tutorial §4.5 and the Transpilation Options & Metrics API.