Skip to content

pyqpanda3 v0.4.1:让保真度真正驱动转译决策

pyqpanda3 v0.4.0 把硬件工作流的"链路"打通了:从云端芯片元数据到保真度布局、指令导出和时序可视化。v0.4.1 想解决的是这条链路里更靠"内核"的一层问题——当后端已经能给出保真度数据时,转译器有没有真的用它来做决策?

答案是:现在有了。本版本的主题是让保真度数据真正贯穿到转译决策里,同时补齐两类长期缺失的模拟器。

强类型转译选项与指标回收 ​

0.4.0 的 transpile() 用位置参数控制优化等级与布局策略。0.4.1 新增 TranspilationOptions,把所有可调项集中到一个对象里,并通过 TranspilationResult 一次性返回转译后的程序、编译耗时和指标。

python
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()))

示例输出形态:

text
TranspilationResult
True
['depth', 'fidelity_exact', 'fidelity_fallback', 'fidelity_unknown', 'log_expected_fidelity', 'two_qubit_gate_count']

result.metrics 与独立函数 transpilation_metrics(prog, backend) 返回的字典结构一致,包含双比特门数量、深度、对数期望保真度,以及保真度数据精确命中 / 回退 / 未知的门数计数。这意味着转译质量终于可以量化、可比对,而不仅仅是"跑通了"。

LightSABRE 路由 ​

RoutingMethod.LIGHT_SABRE(字符串 "light_sabre")启用新的分层前瞻路由器。它在路由时按层扩展交互图,能减少双比特门插入与交换深度,适合耦合度受限或线路较深的后端。

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

输出:

text
QProg
True

海森堡绘景期望模拟器 ​

很多场景下,你并不需要完整的态矢量,而只想知道某个泡利哈密顿量的期望值 <H>。SparseHeisenbergSimulator 在海森堡绘景里直接算这件事,不用采样、也不返回态矢量,因此对"受支持门集 + 直积初态"这类问题远比完整模拟便宜。

python
from pyqpanda3.core import QProg, CZ, SparseHeisenbergSimulator

zero = (1 + 0j, 0 + 0j)  # 每个比特的 (|0> 振幅, |1> 振幅)

prog = QProg() << CZ(0, 1)  # |00> 不变

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

输出:

text
1.0

<ZZ> 在 |00> 上为 1.0,与解析值一致。当算符项数膨胀时,可以用 max_terms 与 truncation_norm="l1" 截断,并通过 stats() 看被丢弃的项。

矩阵乘积态(MPS)模拟器 ​

MPSQVM 用矩阵乘积态后端运行量子程序,对纠缠较弱的线路在比特数较大时仍保持较低内存占用。

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

示例输出形态:

text
QResult
True

还有这些值得注意 ​

  • state_fidelity() 进入 quantum_info,支持密度矩阵与态矢量四种组合,填补了"直接比较两个量子态"的空白。
  • Choi、SuperOp、PTM 三个信道表示都补上了 ndarray(),方便与 NumPy 生态对接。
  • QProg.get_measure_qubits_cbits() 按程序顺序返回测量对,便于在提交云端前核对测量映射。
  • 一批稳定性修复:VQCircuit.append(vqc) 自引用段错误、VF2 布局部分覆盖段错误、ParamExpression 空表达式崩溃、退相干噪声 Kraus 矩阵方向、get_matrix 内存泄漏、PartialAmplitudeQVM 下标越界校验。

0.4.1 后半程:初态、Heisenberg 与任务取消 ​

v0.4.1 的功能在发布周期里分两批合入:前半程是保真度驱动的转译链路与两个模拟器,后半程又补上了模拟器的初态控制、海森堡绘景的截断统计,以及云端任务取消。

初态:CPUQVM.init_state ​

CPUQVM 在 0.4.1 新增 init_state(state):运行前把模拟器设置到任意初始态,无参调用则恢复默认的 |0...0>。例如把两个比特放在叠加态上再测量:

python
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()  # 恢复默认 |0...0>
qvm.run(prog, 1000)
print(qvm.result().get_counts())

示例输出形态:

text
{'00': 524, '11': 476}
{'00': 1000}

注意:MPSQVM 的 C++ init_state 未在 Python 绑定中暴露(0.4.1),Python 侧请使用 CPUQVM.init_state。

海森堡绘景的截断与统计 ​

前面提到 SparseHeisenbergSimulator 可以用 max_terms 与 truncation_norm 截断。实际效果如何?RX 旋转会把算符项数从 1 膨胀到 8,设 max_terms=4 后多余的项按 l1 范数丢弃,stats() 给出被丢弃项的统计:

python
from pyqpanda3.core import QProg, H, CNOT, RX, SparseHeisenbergSimulator

zero = (1 + 0j, 0 + 0j)
prog = QProg() << H(0) << CNOT(0, 1) << RX(0, 0.7) << RX(1, 1.3) << RX(2, 2.1)

# 不截断:观察算符项数膨胀到多少
full = SparseHeisenbergSimulator(num_qubits=3)
full.set_initial_product_state([zero, zero, zero])
full.add_observable("ZZZ", 1.0)
full.evolve_backward(prog)
print("no truncation terms:", full.stats().active_terms)

# 截断:最多保留 4 项,多余项按 l1 范数丢弃
trunc = SparseHeisenbergSimulator(num_qubits=3, max_terms=4, truncation_norm="l1")
trunc.set_initial_product_state([zero, zero, zero])
trunc.add_observable("ZZZ", 1.0)
trunc.evolve_backward(prog)
s = trunc.stats()
print("expectation:", round(trunc.expectation(), 6))
print("active_terms:", s.active_terms)
print("truncated_terms:", s.truncated_terms)
print("truncated_l1:", round(s.truncated_l1, 6))
print("coefficient_l1:", round(s.coefficient_l1, 6))

输出:

text
no truncation terms: 8
expectation: 0.400378
active_terms: 4
truncated_terms: 4
truncated_l1: 0.51565
coefficient_l1: 2.373074

云端任务取消 ​

QCloudJob 新增 cancel() 与静态方法 cancel_task(task_id),可以主动取消已提交的云端任务,返回 True 表示云服务接受了取消请求。取消需要云端凭据与真实任务,无法本地执行:

python
from pyqpanda3.qcloud import QCloudJob, QCloudService

# 需云端凭据与真实任务,无法本地执行
service = QCloudService("your_api_key")
job = QCloudJob("your_job_id")

print(job.cancel())                          # 取消当前任务
print(QCloudJob.cancel_task("your_task_id"))  # 按任务 id 取消(静态方法)

完整的 API 变更清单见 v0.4.1 发布说明。

Released under the MIT License.