量子线路构建
使用 pyqpanda3 中的 QProg、QCircuit 和 << 运算符构建量子程序和可复用线路。
概述
pyqpanda3 提供两个主要的线路构建容器:
- QProg -- 顶层量子程序(quantum program)容器,持有门、线路、测量和控制流。它是你传递给模拟器或云后端执行的单元。
- QCircuit -- 可复用的、可组合的线路模块(linear module),封装一组量子门序列。可以将它想象为可嵌入任意多个程序中的命名子程序。
两个容器共享相同的追加机制:<<(左移)运算符。该运算符将门、线路甚至其他程序链接为单一的线性操作序列。
graph TD
subgraph "Container Hierarchy"
QProg["QProg<br/><i>executable program</i>"]
QCircuit["QCircuit<br/><i>reusable module</i>"]
QGate["QGate<br/><i>single gate</i>"]
Measure["measure()<br/><i>measurement</i>"]
end
QProg -->|"<< gate"| QGate
QProg -->|"<< circuit"| QCircuit
QProg -->|"<< prog"| QProg
QProg -->|"<< measure"| Measure
QCircuit -->|"<< gate"| QGate
QCircuit -->|"<< circuit"| QCircuit
style QProg fill:#4a90d9,color:#fff
style QCircuit fill:#50b86c,color:#fff
style QGate fill:#e8913a,color:#fff
style Measure fill:#c0392b,color:#fff1. QProg -- 量子程序
QProg 是可执行量子程序的主容器。你创建门,将它们追加到程序中,然后在模拟器或云后端上执行该程序。
1.1 创建 QProg
from pyqpanda3 import core
# 空程序 -- 量子比特数从你添加的门中推断
prog = core.QProg()
# 预分配 3 个量子比特(和 0 个经典比特)的程序
prog = core.QProg(3)当你创建空的 QProg() 时,系统会根据你追加的门和测量自动跟踪你使用的量子比特。使用 QProg(n) 预分配会提前预留 n 个量子比特。
1.2 使用 << 追加操作
<< 运算符是构建程序的主要方式。它追加门、线路、测量甚至其他程序,并始终返回程序本身以支持链式调用:
from pyqpanda3 import core
# 创建程序并构建贝尔态
prog = core.QProg()
prog << core.H(0) # Hadamard on qubit 0
prog << core.CNOT(0, 1) # CNOT: control=0, target=1
prog << core.measure([0, 1], [0, 1]) # Measure qubits [0,1] into cbits [0,1]
# 等效写法:在一个表达式中链式调用
prog2 = core.QProg()
prog2 << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])数据通过运算符链的流程如下图所示:
graph LR
A["prog"] -->|"<<"| B["core.H(0)"]
B -->|"returns prog"| C["prog"]
C -->|"<<"| D["core.CNOT(0, 1)"]
D -->|"returns prog"| E["prog"]
E -->|"<<"| F["core.measure(...)"]
F -->|"returns prog"| G["prog (complete)"]
style A fill:#4a90d9,color:#fff
style G fill:#4a90d9,color:#fff你也可以嵌入可复用线路或吸收其他程序:
# 嵌入 QCircuit
bell = core.QCircuit()
bell << core.H(0) << core.CNOT(0, 1)
prog = core.QProg()
prog << bell # append a circuit
prog << core.measure([0, 1], [0, 1])
# 吸收另一个 QProg
prep = core.QProg()
prep << core.H(0)
main_prog = core.QProg()
main_prog << prep # absorb a sub-program
main_prog << core.CNOT(0, 1)1.3 QProg 方法
构建程序后,有多个方法可以检查和转换它。
qubits_num() 和 cbits_num()
返回程序使用的量子比特数和经典比特数:
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])
print(f"Qubits: {prog.qubits_num()}") # Qubits: 2
print(f"Cbits: {prog.cbits_num()}") # Cbits: 2运行结果:
Qubits: 2
Cbits: 2```
#### depth()
返回线路深度(depth)——即顺序门层数。作用于不同量子比特的门可以并行执行,计为同一层。使用 `only_q2=True` 仅计算两量子比特门的深度:
```python
prog = core.QProg()
prog << core.H(0) << core.H(1) # depth 1: both H act on different qubits
prog << core.CNOT(0, 1) # depth 2: CNOT depends on both qubits
print(f"Depth: {prog.depth()}") # Depth: 2
print(f"Depth (2Q only): {prog.depth(only_q2=True)}") # Depth: 1运行结果:
Depth: 2
Depth (2Q only): 1```
#### count_ops()
按类型统计门操作数量,返回字典(门名称 → 计数)。使用 `only_q2=True` 仅统计两量子比特门:
```python
prog = core.QProg()
prog << core.H(0) << core.H(1) << core.CNOT(0, 1) << core.RX(0, 1.57)
print(f"All gates: {prog.count_ops()}") # All gates: {'H': 2, 'CNOT': 1, 'RX': 1}
print(f"2-qubit only: {prog.count_ops(only_q2=True)}") # 2-qubit only: {'CNOT': 1}运行结果:
All gates: {'RX': 1, 'CNOT': 1, 'H': 2}
2-qubit only: {'CNOT': 1}```
#### flatten()
递归展开所有嵌套线路和子程序为单一平面操作序列:
```python
inner = core.QCircuit()
inner << core.H(0) << core.CNOT(0, 1)
prog = core.QProg()
prog << inner << core.H(2)
flat = prog.flatten() # new QProg with all nesting removedto_circuit()
将程序转换为 QCircuit 对象,用于需要线路格式的分析工具:
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
circuit = prog.to_circuit()
print(f"Circuit qubits: {list(circuit.qubits())}")运行结果:
Circuit qubits: [0, 1]```
#### gate_operations() 和 operations()
获取程序中门和操作的详细信息:
```python
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])
# 门级详情
for g in prog.gate_operations():
print(f"Gate: {g.name()}, qubits: {g.qubits()}")
# 所有操作(包括测量)
for op in prog.operations():
print(f"Op type: {type(op).__name__}")运行结果:
Gate: H, qubits: [0]
Gate: CNOT, qubits: [0, 1]
Op type: QGate
Op type: QGate
Op type: MeasureNode
Op type: MeasureNode```
#### get_measure_nodes()
从程序中提取测量节点,查看哪些量子比特被测量并存入哪些经典比特:
```python
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])
for node in prog.get_measure_nodes():
print(f"Measure node: {node}")运行结果:
Measure node: <pyqpanda3.core.core.MeasureNode object at 0x00000272A9562A30>
Measure node: <pyqpanda3.core.core.MeasureNode object at 0x00000272A9562CB0>```
#### remap()
重映射程序中的量子比特索引。当在不同物理量子比特上运行相同逻辑线路时很有用:
```python
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
remapped = prog.remap({0: 3, 1: 5}) # qubit 0 -> 3, qubit 1 -> 5
print(f"Remapped qubits: {remapped.qubits_num()}")运行结果:
Remapped qubits: 6```
#### originir()
将程序序列化为 OriginIR 字符串格式——pyqpanda3 使用的原生中间表示(intermediate representation):
```python
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])
print(prog.originir())
# QINIT 2
# CREG 2
# H(q[0])
# CNOT(q[0], q[1])
# MEASURE(q[0], c[0])
# MEASURE(q[1], c[1])运行结果:
QINIT 2
CREG 2
H q[0]
CNOT q[0],q[1]
MEASURE q[0],c[0]
MEASURE q[1],c[1]2. QCircuit -- 可复用线路模块
QCircuit 是用于量子门序列的可组合容器。与 QProg 不同,它不持有测量或经典控制流。它的主要目的是让你定义可复用的构建块,嵌入到多个程序中。
2.1 创建和构建 QCircuit
from pyqpanda3 import core
# 空线路
circ = core.QCircuit()
# 预分配 3 个量子比特的线路
circ = core.QCircuit(3)
# 使用 << 或 append() 构建
bell = core.QCircuit()
bell << core.H(0) << core.CNOT(0, 1)
# append() 是编程式构建的替代方法
circ2 = core.QCircuit()
circ2.append(core.H(0))
circ2.append(core.CNOT(0, 1))2.2 QCircuit 方法
size() 和 depth()
circ = core.QCircuit()
circ << core.H(0) << core.H(1) << core.CNOT(0, 1)
print(f"Gate count: {circ.size()}") # Gate count: 3
print(f"Depth: {circ.depth()}") # Depth: 2运行结果:
Gate count: 3
Depth: 2```
#### qubits()
返回线路使用的量子比特索引集合:
```python
circ = core.QCircuit()
circ << core.H(0) << core.CNOT(0, 2)
print(f"Qubits used: {list(circ.qubits())}") # Qubits used: [0, 2]运行结果:
Qubits used: [0, 2]```
#### count_ops() 和 num_2q_gate()
```python
circ = core.QCircuit()
circ << core.H(0) << core.H(1) << core.CNOT(0, 1) << core.SWAP(1, 2)
print(f"All gates: {circ.count_ops()}") # All gates: {'H': 2, 'CNOT': 1, 'SWAP': 1}
print(f"2-qubit only: {circ.count_ops(only_q2=True)}") # 2-qubit only: {'CNOT': 1, 'SWAP': 1}
print(f"num_2q_gate: {circ.num_2q_gate()}") # num_2q_gate: 2运行结果:
All gates: {'CNOT': 1, 'H': 2, 'SWAP': 1}
2-qubit only: {'CNOT': 1, 'SWAP': 1}
num_2q_gate: 2```
#### dagger()
返回线路的伴随(adjoint)(共轭转置)。这会反转门的顺序并将每个门替换为其伴随——对反计算(uncomputation)很有用:
```python
circ = core.QCircuit()
circ << core.H(0) << core.S(1) << core.CNOT(0, 1)
inv_circ = circ.dagger()
# inv_circ = CNOT(0,1) -> Sdg(1) -> H(0)control()
返回线路的受控版本。每个门获得一个额外的控制量子比特:
circ = core.QCircuit()
circ << core.H(0) << core.CNOT(0, 1)
controlled = circ.control([2])
# 整个线路仅在量子比特 2 为 |1> 时执行expand()
递归展开嵌套线路为平面门序列:
inner = core.QCircuit()
inner << core.H(0) << core.CNOT(0, 1)
outer = core.QCircuit()
outer << inner << core.H(2)
expanded = outer.expand()matrix()
计算线路的酉矩阵表示(仅对小线路可行,因为维度以
circ = core.QCircuit()
circ << core.H(0) << core.CNOT(0, 1)
U = circ.matrix()
print(f"Matrix shape: {U.shape}") # Matrix shape: (4, 4)运行结果:
Matrix shape: (4, 4)```
对于贝尔态线路,酉矩阵为:
$$
U_{\text{Bell}} = \text{CNOT} \cdot (H \otimes I) = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \\ 0 & 1 & 0 & -1 \\ 1 & 0 & -1 & 0 \end{pmatrix}
$$
#### set_name(), draw() 和 originir()
```python
circ = core.QCircuit(3)
circ << core.H(0) << core.CNOT(0, 1) << core.CNOT(1, 2)
circ.set_name("GHZ-3")
print(circ) # text visualization
print(circ.originir()) # H q[0]\nCNOT q[0],q[1]\nCNOT q[1],q[2]运行结果:
┌─┐
q_0: |0>─┤H├ ───*── ──────
└─┘ ┌──┴─┐
q_1: |0>──── ┤CNOT├ ───*──
└────┘ ┌──┴─┐
q_2: |0>──── ────── ┤CNOT├
└────┘
c : / ══════════════════
QINIT 3
CREG 1
H q[0]
CNOT q[0],q[1]
CNOT q[1],q[2]2.3 复用线路
定义一次构建块,随处使用:
from pyqpanda3 import core
def rotation_block(qc: int, qt: int, angle: float) -> core.QCircuit:
block = core.QCircuit()
block << core.H(qt)
block << core.CU(qc, qt, 0, 0, angle, 0)
return block
# 使用可复用构建块构建 3 量子比特 QFT
qft = core.QCircuit(3)
qft << core.H(0)
qft << rotation_block(0, 1, 1.5708) # pi/2
qft << rotation_block(0, 2, 0.7854) # pi/4
qft << core.H(1)
qft << rotation_block(1, 2, 1.5708) # pi/2
qft << core.H(2)
qft << core.SWAP(0, 2)
# 在不同程序中使用相同的 QFT
prog1 = core.QProg()
prog1 << qft << core.measure([0, 1, 2], [0, 1, 2])
prog2 = core.QProg()
prog2 << core.X(0) << qft << core.measure([0, 1, 2], [0, 1, 2])3. << 运算符 -- 追加操作
<< 运算符是构建量子程序和线路的核心机制。它在 QProg 和 QCircuit 上都有定义,接受多种类型的右侧操作数。
3.1 可以追加的内容
| 右侧操作数 | 示例 | 描述 |
|---|---|---|
QGate | prog << core.H(0) | 追加单个量子门 |
QCircuit | prog << circuit | 追加线路中的所有门 |
QProg | prog << other_prog | 吸收另一个程序的操作 |
| 测量结果 | prog << core.measure([0], [0]) | 追加测量操作 |
3.2 追加门
from pyqpanda3 import core
prog = core.QProg()
prog << core.H(0)
prog << core.X(1) << core.Y(2) << core.Z(3)
prog << core.RX(0, 3.14159)
prog << core.U3(1, 0.5, 0.3, 0.1)3.3 追加线路和程序
# 追加线路
swap_circ = core.QCircuit()
swap_circ << core.CNOT(0, 1) << core.CNOT(1, 0) << core.CNOT(0, 1)
prog = core.QProg()
prog << core.H(0) << swap_circ
# 追加子程序
prep = core.QProg()
prep << core.H(0) << core.H(1) << core.H(2)
main = core.QProg()
main << prep << core.CNOT(0, 1)3.4 追加测量
core.measure() 函数创建将量子比特映射到经典比特的测量节点:
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
# 测量量子比特 [0, 1] 存入经典比特 [0, 1]
prog << core.measure([0, 1], [0, 1])
# 测量单个量子比特
prog << core.measure(0, 0)3.5 运算符链流程
在内部,每次 << 调用的工作方式如下:
sequenceDiagram
participant P as QProg
participant G1 as H(0)
participant G2 as CNOT(0,1)
participant M as measure(...)
P->>G1: prog << core.H(0)
G1-->>P: 返回 prog(现在包含 H(0))
P->>G2: prog << core.CNOT(0, 1)
G2-->>P: 返回 prog(现在包含 H(0), CNOT)
P->>M: prog << core.measure(...)
M-->>P: 返回 prog(完整程序)4. 门构造
pyqpanda3 提供 37+ 种量子门,组织为单量子比特、两量子比特和多量子比特类别。所有门都作为 core 模块中的工厂函数构造。
4.1 单量子比特门
无参数门
from pyqpanda3 import core
# 泡利门
core.X(0) # Pauli-X (bit flip)
core.Y(0) # Pauli-Y
core.Z(0) # Pauli-Z (phase flip)
# Clifford 门
core.H(0) # Hadamard
core.S(0) # S gate (sqrt of Z)
core.T(0) # T gate (sqrt of S)
# 恒等门和变体
core.I(0) # Identity
core.X1(0) # X1 gate
core.Y1(0) # Y1 gate
core.Z1(0) # Z1 gate
# 特殊门
core.ECHO(0) # Echo gate (with optional parameter)
core.BARRIER([0]) # Barrier (prevents optimization across this point)参数化门
from pyqpanda3 import core
import math
# 旋转门
core.RX(0, math.pi / 2) # Rotation around X axis
core.RY(0, math.pi / 4) # Rotation around Y axis
core.RZ(0, math.pi / 3) # Rotation around Z axis
# 相位门
core.P(0, math.pi / 6) # Phase gate (diag(1, e^{i\theta}))
# 通用酉门
core.U1(0, math.pi / 4) # 1-parameter unitary
core.U2(0, 0, math.pi / 2) # 2-parameter unitary
core.U3(0, 0.1, 0.2, 0.3) # 3-parameter unitary
core.U4(0, 0.1, 0.2, 0.3, 0.4) # 4-parameter unitary (most general 1Q gate)旋转门遵循标准定义:
4.2 两量子比特门
无参数门
core.CNOT(0, 1) # Controlled-X: control=0, target=1
core.CZ(0, 1) # Controlled-Z
core.SWAP(0, 1) # Swap qubits 0 and 1
core.ISWAP(0, 1) # iSWAP gate
core.SQISWAP(0, 1) # Square root of iSWAP
core.MS(0, 1) # Molmer-Sorensen (ion trap)参数化门
from pyqpanda3 import core
import math
core.CRX(0, 1, math.pi / 2) # Controlled-RX
core.CRY(0, 1, math.pi / 3) # Controlled-RY
core.CRZ(0, 1, math.pi / 4) # Controlled-RZ
core.CP(0, 1, math.pi / 6) # Controlled phase
core.CU(0, 1, 0.1, 0.2, 0.3, 0.4) # 4-parameter controlled unitary
core.RXX(0, 1, math.pi / 4) # XX rotation
core.RYY(0, 1, math.pi / 4) # YY rotation
core.RZZ(0, 1, math.pi / 4) # ZZ rotation
core.RZX(0, 1, math.pi / 4) # ZX rotation两量子比特旋转门:
4.3 多量子比特门
core.TOFFOLI(0, 1, 2) # CCX: flips target=2 if controls 0,1 are both |1>4.4 特殊门
BARRIER 阻止编译器在屏障点之间合并或重排门:
prog = core.QProg()
prog << core.H(0) << core.H(1)
prog << core.BARRIER([0, 1]) # no optimization across this line
prog << core.CNOT(0, 1)RESET(0.5.0 新增)是原生非幺正重置信道:它将量子比特确定性地坍缩到 |0>,且不影响经典寄存器——不再需要 measure 加条件 X 的模拟写法。它在 CPU 态矢量与密度矩阵模拟器上受支持,并可经 OriginIR 双向往返:
from pyqpanda3.core import CPUQVM, QProg, RESET, X, measure
prog = QProg() << X(0) << RESET(0) << measure(0, 0)
qvm = CPUQVM()
qvm.run(prog, 100)
print(qvm.result().get_counts()) # {'0': 100}——X 门的效果被 RESET 撤销ECHO 是用于某些脉冲级校准的专用门。它接受可选参数:
echo_gate = core.ECHO(0)
echo_gate.set_parameters([1.5]) # set custom parameterOracle 从酉矩阵构造量子预言机(oracle)。矩阵维度必须为
import numpy as np
from pyqpanda3 import core
# Oracle from a unitary matrix (e.g., marking |11>)
oracle_matrix = np.eye(4, dtype=complex)
oracle_matrix[3, 3] = -1 # flip phase for |11>
prog = core.QProg()
prog << core.H(0) << core.H(1)
prog << core.Oracle([0, 1], oracle_matrix)create_gate() 从类型枚举和参数构造门:
gate = core.create_gate("H", [0], []) # H gate on qubit 0
gate = core.create_gate("RX", [0], [1.57]) # RX gate with angle4.5 门自省和变换
每个门对象都支持自省(introspection):
gate = core.RX(0, 1.57)
print(gate.name()) # "RX"
print(gate.gate_type()) # GateType.RX
print(gate.target_qubits()) # [0]
print(gate.control_qubits()) # []
print(gate.parameters()) # [1.57]
print(gate.qubits()) # [0]运行结果:
RX
GateType.RX
[0]
[]
[1.57]
[0]每个门也支持 dagger()、control() 和 matrix():
from pyqpanda3 import core
import numpy as np
# dagger() 返回伴随(逆)
gate = core.H(0) # H is self-adjoint: H.dagger() = H
inv = gate.dagger()
m1, m2 = gate.matrix(), inv.matrix()
print(np.allclose(np.dot(m1, m2), np.eye(2))) # True
# control() 返回受控版本
ch = core.H(0).control([2])
print(ch.qubits()) # [2, 0]
# matrix() 计算酉矩阵
print(f"H matrix:\n{core.H(0).matrix()}")
print(f"CNOT matrix shape: {core.CNOT(0, 1).matrix().shape}") # (4, 4)运行结果:
True
[2, 0]
H matrix:
[[ 0.70710678+0.j 0.70710678+0.j]
[ 0.70710678+0.j -0.70710678+0.j]]
CNOT matrix shape: (4, 4)```
---
## 5. 基于 DAG 的线路分析
pyqpanda3 提供 [`DAGQCircuit`](../api/core/dag.md) 用于有向无环图(Directed Acyclic Graph)分析量子线路。这支持层分解(layer decomposition)、依赖分析和关键路径计算。
### 5.1 什么是 DAG?
DAG 表示线路中门的依赖结构。每个门是一个节点,边表示量子比特依赖:如果门 B 使用门 A 在同一量子比特上的输出,则从 A 到 B 有一条边。
```mermaid
graph TD
subgraph "Circuit: H(0), H(1), CNOT(0,1), X(2)"
H0["H(0)"] --> CNOT["CNOT(0,1)"]
H1["H(1)"] --> CNOT
X2["X(2)"]
end
subgraph "DAG Layers"
L1["Layer 0<br/>H(0), H(1), X(2)"]
L2["Layer 1<br/>CNOT(0,1)"]
L1 --> L2
end
style H0 fill:#e8913a,color:#fff
style H1 fill:#e8913a,color:#fff
style X2 fill:#e8913a,color:#fff
style CNOT fill:#4a90d9,color:#fff5.2 构建 DAGQCircuit
from pyqpanda3 import core
circ = core.QCircuit()
circ << core.H(0) << core.H(1) << core.CNOT(0, 1) << core.X(2)
# 直接从 QCircuit
dag = core.DAGQCircuit()
dag.from_circuit(circ)
dag.build()
# 通过 to_circuit() 从 QProg
prog = core.QProg()
prog << circ
dag2 = core.DAGQCircuit()
c = prog.to_circuit()
if c is not None:
dag2.from_circuit(c)
dag2.build()5.3 检查 DAG
# 所有门
for gate in dag.gates():
print(f"{gate.name()} on qubits {gate.qubits()}")
# 节点和边
print(f"Nodes: {list(dag.nodes())}")
print(f"Edges: {list(dag.edges())}")
# 特定节点索引处的门
for idx in dag.nodes():
gate = dag.get_gate(idx)
print(f"Node {idx}: {gate.name()}{gate.qubits()}")运行结果:
H on qubits [0]
H on qubits [1]
CNOT on qubits [0, 1]
X on qubits [2]
Nodes: [0, 1, 2, 3]
Edges: [(0, 2), (1, 2)]
Node 0: H[0]
Node 1: H[1]
Node 2: CNOT[0, 1]
Node 3: X[2]```
### 5.4 层分析
```python
dag = core.DAGQCircuit()
circ = core.QCircuit()
circ << core.H(0) << core.H(1) << core.H(2)
circ << core.CNOT(0, 1) << core.CNOT(1, 2)
dag.from_circuit(circ)
dag.build()
print(f"DAG depth: {dag.get_depth()}") # 3
for i, layer in enumerate(dag.layers()):
names = [dag.get_gate(idx).name() for idx in layer]
print(f"Layer {i}: {names}")
# 层 0: ['H', 'H', 'H']
# 层 1: ['CNOT']
# 层 2: ['CNOT']运行结果:
DAG depth: 3
Layer 0: ['H', 'H', 'H']
Layer 1: ['CNOT']
Layer 2: ['CNOT']```
### 5.5 关键路径和两量子比特门分析
```python
# 最长路径 = 关键路径
path = dag.longest_path()
for node in path:
gate = dag.get_gate(node)
print(f" {gate.name()} on qubits {gate.qubits()}")
# 两量子比特门分析
two_q_gates = dag.two_qubit_gates()
for gate in two_q_gates:
if gate.is_controlled():
print(f" Controlled: ctrl={gate.control_qubits()}, tgt={gate.target_qubits()}")
else:
print(f" Non-controlled: qubits={gate.target_qubits()}")
two_q_nodes = list(dag.two_qubit_gate_nodes())运行结果:
H on qubits [0]
CNOT on qubits [0, 1]
CNOT on qubits [1, 2]
Non-controlled: qubits=[0, 1]
Non-controlled: qubits=[1, 2]```
### 5.6 实际示例:比较线路
```python
from pyqpanda3 import core
# 使用 3 个 CNOT 的朴素 SWAP 与原生 SWAP 门
swap_naive = core.QCircuit()
swap_naive << core.CNOT(0, 1) << core.CNOT(1, 0) << core.CNOT(0, 1)
swap_native = core.QCircuit()
swap_native << core.SWAP(0, 1)
for name, circ in [("Naive SWAP", swap_naive), ("Native SWAP", swap_native)]:
dag = core.DAGQCircuit()
dag.from_circuit(circ)
dag.build()
print(f"--- {name} ---")
print(f" Gates: {len(dag.gates())}, Depth: {dag.get_depth()}, "
f"2Q gates: {len(dag.two_qubit_gates())}")运行结果:
--- Naive SWAP ---
Gates: 3, Depth: 3, 2Q gates: 3
--- Native SWAP ---
Gates: 1, Depth: 1, 2Q gates: 1```
---
## 6. 完整示例
### 6.1 带完整分析的贝尔态
```python
from pyqpanda3 import core
bell = core.QCircuit()
bell << core.H(0) << core.CNOT(0, 1)
prog = core.QProg()
prog << bell << core.measure([0, 1], [0, 1])
# 统计
print(f"Qubits: {prog.qubits_num()}, Depth: {prog.depth()}, "
f"Gates: {prog.count_ops()}, 2Q: {prog.count_ops(only_q2=True)}")
# 门数: {'CNOT': 1, 'H': 1}, 两量子比特门: {'CNOT': 1}
# DAG 分析
dag = core.DAGQCircuit()
dag.from_circuit(bell)
dag.build()
print(f"DAG depth: {dag.get_depth()}")
for i, layer in enumerate(dag.layers()):
print(f" Layer {i}: {[dag.get_gate(idx).name() for idx in layer]}")
# 在模拟器上运行
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")
print(f"OriginIR:\n{prog.originir()}")运行结果:
Qubits: 2, Depth: 2, Gates: {'CNOT': 1, 'H': 1}, 2Q: {'CNOT': 1}
DAG depth: 2
Layer 0: ['H']
Layer 1: ['CNOT']
Results: {'00': 512, '11': 488}
OriginIR:
QINIT 2
CREG 2
H q[0]
CNOT q[0],q[1]
MEASURE q[0],c[0]
MEASURE q[1],c[1]6.2 反计算模式
from pyqpanda3 import core
compute = core.QCircuit()
compute << core.CNOT(0, 2) << core.CNOT(1, 2) # XOR onto qubit 2
use = core.QCircuit()
use << core.Z(2)
uncompute = compute.dagger()
prog = core.QProg()
prog << compute << use << uncompute
prog << core.measure([0, 1, 2], [0, 1, 2])
machine = core.CPUQVM()
machine.run(prog, 1000)
# 辅助量子比特 2 应该总是回到 |0>6.3 受控线路
from pyqpanda3 import core
sub = core.QCircuit()
sub << core.H(0) << core.RX(1, 0.5) << core.CNOT(0, 1)
controlled_sub = sub.control([3])
prog = core.QProg()
prog << core.H(3) << controlled_sub
prog << core.measure([0, 1, 3], [0, 1, 3])6.4 量子比特重映射
from pyqpanda3 import core
logical = core.QProg()
logical << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])
physical = logical.remap({0: 5, 1: 7}) # map to physical qubits 5, 7
print(f"Physical OriginIR:\n{physical.originir()}")运行结果:
Physical OriginIR:
QINIT 8
CREG 2
H q[5]
CNOT q[5],q[7]
MEASURE q[5],c[0]
MEASURE q[7],c[1]```
---
## 7. API 快速参考
### QProg
| 方法 | 返回值 | 描述 |
|---|---|---|
| `core.QProg()` / `core.QProg(n)` | `QProg` | 创建空或预分配程序 |
| `prog << x` | `QProg` | 追加门、线路、程序或测量 |
| `prog.qubits_num()` | `int` | 使用的量子比特数 |
| `prog.cbits_num()` | `int` | 使用的经典比特数 |
| `prog.depth(only_q2)` | `int` | 线路深度(可选仅计算两量子比特门) |
| `prog.count_ops(only_q2)` | `dict[str, int]` | 按名称统计门计数(可选仅两量子比特) |
| `prog.flatten()` | `QProg` | 展平所有嵌套子线路 |
| `prog.to_circuit()` | `QCircuit` | 转换为 QCircuit |
| `prog.gate_operations()` | `list` | 门操作列表 |
| `prog.operations()` | `list` | 所有操作列表 |
| `prog.get_measure_nodes()` | `list` | 提取测量节点 |
| `prog.remap(mapping)` | `QProg` | 重映射量子比特索引 |
| `prog.originir()` | `str` | 序列化为 OriginIR 字符串 |
### QCircuit
| 方法 | 返回值 | 描述 |
|---|---|---|
| `core.QCircuit()` / `core.QCircuit(n)` | `QCircuit` | 创建空或预分配线路 |
| `circ << x` / `circ.append(gate)` | `QCircuit` | 追加门、线路或程序 |
| `circ.size()` | `int` | 总门数 |
| `circ.depth()` | `int` | 线路深度 |
| `circ.qubits()` | `set` | 使用的量子比特索引集合 |
| `circ.count_ops(only_q2)` | `dict[str, int]` | 按名称统计门计数(可选仅两量子比特) |
| `circ.num_2q_gate()` | `int` | 两量子比特门数 |
| `circ.dagger()` | `QCircuit` | 伴随(逆)线路 |
| `circ.control(qubits)` | `QCircuit` | 线路的受控版本 |
| `circ.expand()` | `QCircuit` | 展开嵌套子线路 |
| `circ.matrix()` | `ndarray` | 酉矩阵表示 |
| `circ.set_name(name)` | None | 设置人类可读名称 |
| `circ.originir()` | `str` | 序列化为 OriginIR |
### DAGQCircuit
| 方法 | 返回值 | 描述 |
|---|---|---|
| `dag.from_circuit(circ)` | None | 从 QCircuit 加载门 |
| `dag.build()` | None | 构建 DAG 边 |
| `dag.gates()` | `list` | 所有门对象 |
| `dag.nodes()` / `dag.edges()` | `list` | 节点索引 / 边对 |
| `dag.get_gate(idx)` | [`QGate`](../api/core/circuit.md) | 节点索引处的门 |
| `dag.layers()` | `iterator` | 门层(并行组) |
| `dag.get_depth()` | `int` | DAG 深度(层数) |
| `dag.longest_path()` | `list` | 通过 DAG 的关键路径 |
| `dag.two_qubit_gates()` | `list` | 所有两量子比特门对象 |
| `dag.two_qubit_gate_nodes()` | `list` | 两量子比特门的节点索引 |
### 门工厂函数
| 类别 | 门 |
|---|---|
| 1Q 无参数 | [`H`](../api/core/gates.md)、[`X`](../api/core/gates.md)、[`Y`](../api/core/gates.md)、[`Z`](../api/core/gates.md)、[`S`](../api/core/gates.md)、[`T`](../api/core/gates.md)、[`I`](../api/core/gates.md)、[`X1`](../api/core/gates.md)、[`Y1`](../api/core/gates.md)、[`Z1`](../api/core/gates.md)、[`ECHO`](../api/core/gates.md) |
| 1Q 参数化 | [`RX`](../api/core/gates.md)、[`RY`](../api/core/gates.md)、[`RZ`](../api/core/gates.md)、[`P`](../api/core/gates.md)、`RPhi`、[`U1`](../api/core/gates.md)、[`U2`](../api/core/gates.md)、[`U3`](../api/core/gates.md)、[`U4`](../api/core/gates.md) |
| 2Q 无参数 | [`CNOT`](../api/core/gates.md)、[`CZ`](../api/core/gates.md)、[`SWAP`](../api/core/gates.md)、[`ISWAP`](../api/core/gates.md)、[`SQISWAP`](../api/core/gates.md)、[`MS`](../api/core/gates.md) |
| 2Q 参数化 | [`CP`](../api/core/gates.md)、[`CR`](../api/core/gates.md)、[`CRX`](../api/core/gates.md)、[`CRY`](../api/core/gates.md)、[`CRZ`](../api/core/gates.md)、[`CU`](../api/core/gates.md)、[`RXX`](../api/core/gates.md)、[`RYY`](../api/core/gates.md)、[`RZZ`](../api/core/gates.md)、[`RZX`](../api/core/gates.md) |
| 多量子比特 | [`TOFFOLI`](../api/core/gates.md) |
| 特殊 | [`BARRIER`](../api/core/gates.md)、[`ECHO`](../api/core/gates.md)、[`Oracle`](../api/core/gates.md)、`create_gate()` |
---
## 总结
在本教程中你学到了:
1. **QProg** 是可执行量子程序容器。使用 `<<` 追加门、线路、测量和其他程序。用 `depth()`、`count_ops()`、`qubits_num()` 等方法检查它。
2. **QCircuit** 是可复用线路模块。它支持相同的 `<<` 运算符以及额外方法如 `dagger()`、`control()`、`matrix()` 和 `num_2q_gate()`。
3. **`<<` 运算符** 是通用追加机制。它返回容器本身,支持流式链式调用如 `prog << core.H(0) << core.CNOT(0, 1)`。
4. **门构造** 涵盖 37+ 种门,从单量子比特([`H`](../api/core/gates.md)、[`X`](../api/core/gates.md)、[`RX`](../api/core/gates.md)、[`U3`](../api/core/gates.md))到两量子比特([`CNOT`](../api/core/gates.md)、[`SWAP`](../api/core/gates.md)、[`CU`](../api/core/gates.md))再到多量子比特([`TOFFOLI`](../api/core/gates.md)),加上特殊门如 [`BARRIER`](../api/core/gates.md) 和 [`Oracle`](../api/core/gates.md)。
5. **DAGQCircuit** 支持高级线路分析:通过有向无环图表示进行层分解、关键路径查找、两量子比特门提取和深度计算。
系列中的下一个教程是[模拟](simulation.md),你将学习如何在各种模拟器后端上执行这里构建的程序。
---
## 知识检查
测试你对 pyqpanda3 中线路构建的理解。
<strong>Q1: `QProg` 和 `QCircuit` 有什么区别?分别在什么场景使用?</strong>
A1: `QProg` 是顶层可执行量子程序容器——它可以持有门、线路、测量和控制流。`QCircuit` 是可复用线路模块,支持额外操作如 `dagger()`、`control()` 和 `matrix()`。使用 `QProg` 作为主程序包装器,使用 `QCircuit` 构建可反转、受控或组合的可复用子线路。
<strong>Q2: `<<` 运算符返回什么?为什么它有用?</strong>
A2: `<<` 运算符返回容器(QProg 或 QCircuit)本身,支持方法链式调用。这允许流式构建如 `prog << H(0) << CNOT(0, 1) << measure([0, 1], [0, 1])`,无需为每一步使用中间变量。
<strong>Q3: 如何创建线路的伴随(逆)?给出一个实际用例的例子。</strong>
A3: 在 `QCircuit` 上调用 `.dagger()`:`inverse_cir = cir.dagger()`。这对于反计算(uncomputation)至关重要——在使用辅助量子比特(ancilla qubit)进行计算后,施加逆线路将它们恢复到 $|0\rangle$ 以便重用。例如,在 Grover 算法中,预言机和扩散算子都使用了 `dagger()`。
<strong>Q4: 解释 `BARRIER`、`ECHO` 和 [`IDLE`](../api/core/gates.md) 门之间的关系。为什么它们没有数学效果?</strong>
A4: 三者都是具有恒等酉矩阵($I$)的元操作。`BARRIER` 阻止优化期间跨它的门融合,`ECHO` 表示用于噪声抑制的自旋回波序列,[`IDLE`](../api/core/gates.md) 表示时间延迟。它们影响编译和调度,但不影响数学态演化。
<strong>Q5: 什么是 [`DAGQCircuit`](../api/core/dag.md)?与平面线路表示相比,它有什么优势?</strong>
A5: `DAGQCircuit` 将线路表示为有向无环图,其中门是节点,依赖(共享量子比特)是边。这支持高级分析:寻找关键路径(线路深度)、层分解用于并行门执行、计算两量子比特门、以及在转译期间进行拓扑感知路由。
<strong>Q6: 如何使用现有 pyqpanda3 原语构建受控 SWAP(Fredkin)门?</strong>
A6: Fredkin 门(受控 SWAP)可以分解为:`CNOT(b, c) << TOFFOLI(a, c, b) << CNOT(b, c)`,其中 `a` 是控制,`b`、`c` 是 SWAP 目标。或者,使用 `SWAP(1, 2).control(0)` 创建 SWAP 线路的受控版本。
---
**练习 1:可复用线路模块**
创建一个参数化"量子半加器"线路,并在程序中演示使用 `dagger()` 进行反计算。
<strong>解答:</strong>
```python
from pyqpanda3.core import CPUQVM, QProg, QCircuit, CNOT, TOFFOLI, X, measure
def quantum_half_adder(a, b, carry):
"""1-bit quantum half-adder (TOFFOLI first to preserve original values).
Input: a, b (1-qubit inputs), carry (initialized to |0>)
Output: b = a XOR b (sum), carry = a AND b
"""
cir = QCircuit()
cir << TOFFOLI(a, b, carry) # carry = a AND b (original values)
cir << CNOT(a, b) # b = a XOR b (sum)
return cir
qvm = CPUQVM()
# 测试所有四种输入组合
for a_val, b_val in [(0, 0), (0, 1), (1, 0), (1, 1)]:
prog = QProg()
if a_val:
prog << X(0) # Set a=1
if b_val:
prog << X(1) # Set b=1
adder = quantum_half_adder(0, 1, 2)
prog << adder
prog << measure([1, 2], [0, 1])
qvm.run(prog, shots=100)
counts = qvm.result().get_counts()
# 结果位:(sum=b, carry=c) — 例如 "10" 表示 sum=1, carry=0
print(f"{a_val}+{b_val}: {counts}")
# 演示反计算
prog2 = QProg()
prog2 << X(0) << X(1) # a=1, b=1 → 1+1
adder = quantum_half_adder(0, 1, 2)
prog2 << adder
prog2 << adder.dagger() # Uncompute
prog2 << measure([0, 1, 2], [0, 1, 2])
qvm.run(prog2, shots=100)
counts2 = qvm.result().get_counts()
print(f"After uncompute (1+1): {counts2}")运行结果:
0+0: {'00': 100}
0+1: {'01': 100}
1+0: {'01': 100}
1+1: {'10': 100}
After uncompute (1+1): {'011': 100}注意: 扩展到完整的 2 位行波进位加法器需要额外的门(MAJ/UMA 块)来正确传播中间进位。上述半加器演示了关键原则:在用
CNOT修改输入值之前,先用TOFFOLI对原始输入值计算进位。
练习 2:DAGQCircuit 分析
构建一个 4 量子比特线路,将其转换为 DAGQCircuit,并分析其属性:深度、两量子比特门数和层结构。
解答:
from pyqpanda3.core import QProg, QCircuit, DAGQCircuit
from pyqpanda3.core import H, X, CNOT, SWAP, CZ, TOFFOLI, measure
# 构建混合门类型的线路
cir = QCircuit()
cir << H(0) << H(1) << CNOT(0, 1) << CNOT(2, 3)
cir << SWAP(1, 2) << CZ(0, 3)
cir << TOFFOLI(0, 1, 2) << H(3)
dag = DAGQCircuit()
dag.from_circuit(cir)
dag.build()
# 分析属性
print("DAG Circuit Analysis:")
print(f" Depth: {dag.get_depth()}")
print(f" Total gates: {dag.get_num_gates()}")
print(f" Two-qubit gates: {len(dag.two_qubit_gates())}")
# 层分解
layers = dag.layers()
for i, layer in enumerate(layers):
gate_names = [dag.get_gate(idx).name() for idx in layer]
print(f" Layer {i}: {gate_names}")运行结果:
DAG Circuit Analysis:
Depth: 3
Total gates: 8
Two-qubit gates: 4
Layer 0: ['H', 'H', 'CNOT', 'X', 'H']
Layer 1: ['CNOT']
Layer 2: ['SWAP', 'CZ']```