量子态制备
学习如何使用 pyqpanda3 中的 Encode 类将经典数据编码为量子态。本教程涵盖 13 种编码方法——从简单的基础编码到高级的稀疏和近似 MPS 技术——包括数学基础、代码示例以及选择合适方法的实用指南。
目录
- 为什么量子态制备很重要
- Encode 类
- 方法选择指南
- 1. 基础编码
- 2. 角度编码
- 3. 密集角度编码
- 4. 振幅编码
- 5. 递归振幅编码
- 6. IQP 编码
- 7. Schmidt 编码
- 8. 分治振幅编码
- 9. BID 振幅编码
- 10. 双稀疏态制备
- 11. 稀疏等距编码
- 12. 高效稀疏编码
- 13. 近似 MPS 编码
- 编码方法比较
- 完整示例
- API 快速参考
- 总结
为什么量子态制备很重要
量子态制备——也称为数据编码或数据嵌入——是将经典数据映射到量子态的过程。它几乎是所有量子算法的基本步骤:
- 量子机器学习——核方法、变分类器和量子神经网络都需要将经典数据加载到量子寄存器中。
- 量子模拟——需要先制备被研究物理系统的初始态。
- 量子算法——Grover 搜索、量子相位估计和哈密顿量模拟都假设特定的输入态。
编码方法的选择直接影响线路深度、量子比特数、表达能力,并最终影响算法性能。pyqpanda3 通过 Encode 类提供了 13 种编码方法,每种方法针对不同的数据特性进行了优化。
Encode 类
pyqpanda3.core 中的 Encode 类是所有量子态制备方法的统一接口。你创建一个实例,调用编码方法,然后提取结果。
from pyqpanda3 import core
enc = core.Encode()核心方法
get_circuit()——返回实现编码的 QCircuit:
enc = core.Encode()
enc.amplitude_encode([0, 1], [0.5, 0.5, 0.5, 0.5])
circuit = enc.get_circuit()
prog = core.QProg()
prog << circuitget_out_qubits()——返回输出量子比特索引。某些方法内部使用辅助量子比特,因此输出量子比特可能与输入量子比特不同:
enc.dc_amplitude_encode([0, 1, 2], [0.5, 0.3, 0.2, 0.4, 0.1, 0.6, 0.3, 0.5])
out_qubits = enc.get_out_qubits()get_fidelity(data)——计算编码态与目标态之间的保真度。接受 List[float] 或 List[complex]。保真度范围从 0(正交)到 1(相同):
fidelity = enc.get_fidelity([0.5, 0.5, 0.5, 0.5]) # 精确方法返回 1.0工作流程
方法选择指南
1. 基础编码
方法: basic_encode(qubits, data: str)
将二进制字符串直接映射到计算基态。字符串中的每个字符对应一个量子比特:'1' 施加 X 门(比特翻转),'0' 使量子比特保持基态
给定长度为
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 1 |
| 精确 | 是 |
from pyqpanda3 import core
enc = core.Encode()
enc.basic_encode([0, 1, 2], "101")
prog = core.QProg()
prog << enc.get_circuit() << core.measure([0, 1, 2], [0, 1, 2])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(machine.result().get_counts()) # {'101': 1000}适用场景:编码经典比特串、制备计算基态、测试。
2. 角度编码
方法: angle_encode(qubits, data, gate_type=GateType.RY)
将每个数据值映射到对应量子比特上的旋转角度。这是量子机器学习中最常用的编码方式之一,因为它产生浅层线路(深度 1),并通过旋转轴的选择提供可调的表达能力。
对于数据向量
使用默认的 GateType.RX 和 GateType.RZ。
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 1 |
| 精确 | 否(信息压缩) |
from pyqpanda3 import core
# 默认使用 RY 门
enc = core.Encode()
enc.angle_encode([0, 1, 2], [0.5, 1.0, 1.5])
# 使用 RX 门
enc2 = core.Encode()
enc2.angle_encode([0, 1, 2], [0.5, 1.0, 1.5], core.GateType.RX)适用场景:QML 特征编码、变分线路初始层、浅层线路。
3. 密集角度编码
方法: dense_angle_encode(qubits, data)
使用
对于偶数长度
量子比特
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 2 |
| 精确 | 否 |
enc = core.Encode()
# 6 个值编码到 3 个量子比特
enc.dense_angle_encode([0, 1, 2], [3.14, 3.14, 0.5, 1.0, 0.3, 0.7])适用场景:量子比特数量有限、高维特征向量。
4. 振幅编码
方法: amplitude_encode(qubits, data)
将归一化的经典向量直接映射到多量子比特量子态的振幅上。这是信息密度最高的精确编码方式:
给定归一化的
接受 List[float](实数)或 List[complex](复数振幅)。数据会自动归一化。对于实数输入,态矢量与输入完全匹配。对于复数输入
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 门数 | 实数 |
| 精确 | 是 |
import numpy as np
# 实数值:等叠加态
enc = core.Encode()
enc.amplitude_encode([0, 1], [0.5, 0.5, 0.5, 0.5])
print(f"Fidelity: {enc.get_fidelity([0.5, 0.5, 0.5, 0.5])}")
# 复数值
enc2 = core.Encode()
data = [0.5+0j, 0.5j, -0.5, 0.5-0.5j]
norm = np.linalg.norm(data)
enc2.amplitude_encode([0, 1], [x/norm for x in data])
# 运行
prog = core.QProg()
prog << enc.get_circuit() << core.measure([0, 1], [0, 1])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(machine.result().get_counts())适用场景:精确数据表示、中等规模数据(最多约 16 个量子比特)、为量子算法加载经典数据。
5. 递归振幅编码
方法: amplitude_encode_recursive(qubits, data)
与标准振幅编码结果相同,但使用自顶向下的递归分解策略。线路结构与标准方法不同,这在具有特定连接模式的硬件上可能具有更好的并行性。接受 List[float] 和 List[complex]。
给定归一化的
第一次旋转设置
接受 List[float] 和 List[complex]。
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | |
| 精确 | 是 |
enc = core.Encode()
data = [0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25]
enc.amplitude_encode_recursive([0, 1, 2], data)
print(f"Fidelity: {enc.get_fidelity(data)}")适用场景:与振幅编码相同,但线路结构更适合硬件执行。
6. IQP 编码
方法: iqp_encode(qubits, data, control_list=[], bool_inverse=False, repeats=1)
施加由 Hadamard 门、对角旋转和纠缠相位门组成的结构化模式。IQP 线路被认为在经典上难以模拟。
线路为
control_list 的边集。参数:control_list(RZZ 门的量子比特对)、bool_inverse(是否施加逆操作)、repeats(线路重复次数)。
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 每次重复 |
| 精确 | 否(概率性) |
# 基本 IQP
enc = core.Encode()
enc.iqp_encode([0, 1, 2], [0.5, 1.0, 1.5])
# 带纠缠和重复
enc2 = core.Encode()
enc2.iqp_encode([0, 1, 2], [0.5, 1.0, 1.5],
control_list=[(0,1), (1,2)], repeats=2)
prog = core.QProg()
prog << enc.get_circuit() << core.measure([0,1,2], [0,1,2])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(machine.result().get_counts())适用场景:QML 核方法、基于纠缠的特征映射、经典难模拟线路。
7. Schmidt 编码
方法: schmidt_encode(qubits, data, cutoff=0)
使用 Schmidt 分解将目标态递归地分解为双分部组件。cutoff 参数截断较小的奇异值,以更少的门实现近似编码。
对于
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 取决于 Schmidt 秩 |
| 精确 | cutoff=0 时精确 |
enc = core.Encode()
data = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
norm = np.linalg.norm(data)
data = [x/norm for x in data]
# 精确编码
enc.schmidt_encode([0, 1, 2], data, cutoff=0)
print(f"Fidelity (exact): {enc.get_fidelity(data):.6f}")
# 近似编码
enc2 = core.Encode()
enc2.schmidt_encode([0, 1, 2], data, cutoff=1e-6)
print(f"Fidelity (cutoff): {enc2.get_fidelity(data):.6f}")适用场景:低 Schmidt 秩态、以精度换取深度、层次化数据。
8. 分治振幅编码
方法: dc_amplitude_encode(qubits, data)
将数据向量分成两半,递归编码每一半。使用辅助量子比特进行分解,产生比标准振幅编码更浅的线路,但需要更多量子比特。始终使用 get_out_qubits() 来确定哪些量子比特承载最终的编码态。
算法计算每次分割的范数
| 属性 | 值 |
|---|---|
| 量子比特数 | 数据长度 |
| 深度 | |
| 精确 | 是 |
enc = core.Encode()
data = [0.5, 0.3, 0.2, 0.4, 0.1, 0.6, 0.3, 0.5]
norm = np.linalg.norm(data)
enc.dc_amplitude_encode(list(range(7)), [x/norm for x in data])
out_qubits = enc.get_out_qubits()
prog = core.QProg()
prog << enc.get_circuit()
prog << core.measure(out_qubits, list(range(len(out_qubits))))
machine = core.CPUQVM()
machine.run(prog, 1000)
print(machine.result().get_counts())适用场景:线路深度比量子比特数更重要时、NISQ 硬件。
9. BID 振幅编码
方法: bid_amplitude_encode(qubits, data, split=-1)
块逆分解:将数据向量划分为 split 参数控制块大小;-1 为自动选择。与 dc_amplitude_encode 类似,输出量子比特可能与输入量子比特不同,因此始终使用 get_out_qubits() 检查。
对于归一化向量
其中
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 每块 |
| 精确 | 是 |
enc = core.Encode()
data = [0.1, 0.3, 0.2, 0.4, 0.15, 0.25, 0.35, 0.45]
norm = np.linalg.norm(data)
enc.bid_amplitude_encode([0, 1, 2], [x/norm for x in data], split=2)适用场景:具有自然分块结构的结构化数据、可调的编码复杂度。
10. 双稀疏态制备
方法: ds_quantum_state_preparation(qubits, data)
处理大多数元素为零的稀疏数据。复杂度取决于非零元素的数量
给定稀疏态
接受四种数据类型:
| 类型 | 描述 |
|---|---|
Dict[str, float] | 稀疏实数值态 |
Dict[str, complex] | 稀疏复数值态 |
List[float] | 稠密向量(自动检测稀疏性) |
List[complex] | 稠密向量(自动检测稀疏性) |
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | |
| 精确 | 是 |
# 稀疏字典格式
enc = core.Encode()
enc.ds_quantum_state_preparation([0,1,2,3,4,5], {
"000": 0.40, "001": 0.91, "111": 0.08
})
out_qubits = enc.get_out_qubits()
# 稠密向量格式(自动检测稀疏性)
enc2 = core.Encode()
enc2.ds_quantum_state_preparation([0,1,2],
[0.0, 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5])适用场景:含有大量零的数据、以 ket 符号表示的态。
11. 稀疏等距编码
方法: sparse_isometry(qubits, data)
使用 Givens 旋转和受控操作构建等距映射,将 ds_quantum_state_preparation 不同,此方法使用直接的等距方法而非双稀疏分解。
等距被分解为一系列 Givens 旋转和受控操作。复杂度随非零振幅数量
接受与 ds_quantum_state_preparation 相同的四种数据类型。
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | |
| 精确 | 是 |
enc = core.Encode()
state = {
"000": complex(0.37, 0.44),
"001": complex(0.20, 0.34),
"010": complex(0.53, 0.25),
"100": complex(0.20, 0.35)
}
norm = sum(abs(v)**2 for v in state.values()) ** 0.5
state = {k: v/norm for k, v in state.items()}
enc.sparse_isometry([0, 1, 2], state)
prog = core.QProg()
prog << enc.get_circuit() << core.measure([0,1,2], [0,1,2])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(machine.result().get_counts())适用场景:稀疏态的精确编码、具有已知基态标签的态。
12. 高效稀疏编码
方法: efficient_sparse(qubits, data)
通过寻找唯一标识所有非零基态的最小区分比特集 sparse_isometry 实现更好的门计数。
线路首先在区分量子比特上编码振幅分布,然后使用条件操作设置剩余量子比特。这避免了编码完整的
接受与 sparse_isometry 相同的数据类型。
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | 最佳情况 |
| 精确 | 是 |
enc = core.Encode()
enc.efficient_sparse([0, 1, 2], {
"000": 0.40, "001": 0.91, "111": 0.08
})
# 或使用稠密向量
enc2 = core.Encode()
data = [0.5, 0.3, 0.2, 0.4, 0.1, 0.6, 0.3, 0.5]
norm = sum(x**2 for x in data) ** 0.5
enc2.efficient_sparse([0,1,2], [x/norm for x in data])适用场景:门计数关键的稀疏态、具有共享比特前缀的模式。
13. 近似 MPS 编码
方法: approx_mps_encode(qubits, data, layers=3, sweeps=100, double2float=False)
将目标态表示为矩阵乘积态(MPS),并迭代优化线路以近似它。以牺牲精确精度为代价大幅减少线路深度。
每个 MPS 张量被映射到单量子比特和双量子比特门,在 sweeps 次迭代中进行优化。更多的 layers 产生更高的保真度但更深的线路。接受 List[float] 和 List[complex]。
| 参数 | 默认值 | 描述 |
|---|---|---|
layers | 3 | MPS 层数(表达能力) |
sweeps | 100 | 优化迭代次数 |
double2float | False | 转换为 float32 以加速 |
| 属性 | 值 |
|---|---|
| 量子比特数 | |
| 深度 | |
| 精确 | 否(近似) |
import numpy as np
np.random.seed(42)
data = np.random.randn(8)
data = (data / np.linalg.norm(data)).tolist()
# 默认参数
enc = core.Encode()
enc.approx_mps_encode([0,1,2], data, layers=3, sweeps=100)
print(f"Fidelity (3 layers): {enc.get_fidelity(data):.6f}")
# 更高保真度
enc2 = core.Encode()
enc2.approx_mps_encode([0,1,2], data, layers=5, sweeps=200)
print(f"Fidelity (5 layers): {enc2.get_fidelity(data):.6f}")
# 复数数据
enc3 = core.Encode()
cdata = [0.3+0.1j, 0.2-0.1j, 0.4+0.2j, 0.1-0.3j,
0.25+0.15j, 0.35-0.05j, 0.1+0.3j, 0.15-0.2j]
norm = sum(abs(x)**2 for x in cdata) ** 0.5
enc3.approx_mps_encode([0,1,2], [x/norm for x in cdata], layers=3, sweeps=100)适用场景:大规模数据向量、低纠缠态、NISQ 设备、近似编码可接受时。
编码方法比较
| 方法 | 量子比特数 | 深度 | 精确 | 数据类型 | 最适合 |
|---|---|---|---|---|---|
basic_encode | 1 | 是 | str | 基态 | |
angle_encode | 1 | 否 | float[] | QML 特征 | |
dense_angle_encode | 2 | 否 | float[] | 紧凑特征 | |
amplitude_encode | 是 | float[], complex[] | 精确加载 | ||
amplitude_encode_recursive | 是 | float[], complex[] | 结构化态 | ||
iqp_encode | 否 | float[] | QML 核方法 | ||
schmidt_encode | 可变 | 精确/近似 | float[] | 低秩态 | |
dc_amplitude_encode | 是 | float[] | 浅层线路 | ||
bid_amplitude_encode | 可变 | 是 | float[] | 分块数据 | |
ds_quantum_state_preparation | 是 | Dict, float[], complex[] | 稀疏态 | ||
sparse_isometry | 是 | Dict, float[], complex[] | 稀疏精确 | ||
efficient_sparse | 是 | Dict, float[], complex[] | 高效稀疏 | ||
approx_mps_encode | 否 | float[], complex[] | 大规模态 |
决策流程图
以下流程图根据你的数据特性和约束条件,引导你选择最合适的编码方法:
量子比特和门代价汇总
对于长度为
| 方法 | 所需量子比特 | 门数 | 线路深度 |
|---|---|---|---|
basic_encode | |||
angle_encode | |||
dense_angle_encode | |||
amplitude_encode | |||
amplitude_encode_recursive | |||
iqp_encode | |||
schmidt_encode | |||
dc_amplitude_encode | |||
bid_amplitude_encode | |||
ds_quantum_state_preparation | |||
sparse_isometry | |||
efficient_sparse | |||
approx_mps_encode |
其中
完整示例
本示例使用多种方法编码真实分类数据,并比较线路统计信息和保真度:
from pyqpanda3 import core
import numpy as np
# 样本特征向量(归一化)
samples = [
[0.50, 0.35, 0.60, 0.50],
[0.80, 0.20, 0.30, 0.45],
[0.15, 0.70, 0.55, 0.40],
]
for i, raw in enumerate(samples):
norm = np.linalg.norm(raw)
data = [x / norm for x in raw]
print(f"\n--- 样本 {i+1} ---")
# 角度编码(4 个量子比特)
enc1 = core.Encode()
enc1.angle_encode([0,1,2,3], raw)
c1 = enc1.get_circuit()
# 振幅编码(2 个量子比特)
enc2 = core.Encode()
enc2.amplitude_encode([0,1], data)
c2 = enc2.get_circuit()
# IQP 编码(4 个量子比特,带纠缠)
enc3 = core.Encode()
enc3.iqp_encode([0,1,2,3], raw, control_list=[(0,1),(1,2),(2,3)])
c3 = enc3.get_circuit()
# MPS 近似(2 个量子比特)
enc4 = core.Encode()
enc4.approx_mps_encode([0,1], data, layers=3, sweeps=100)
c4 = enc4.get_circuit()
# Schmidt 编码(2 个量子比特)
enc5 = core.Encode()
enc5.schmidt_encode([0,1], data, cutoff=0)
c5 = enc5.get_circuit()
print(f" 角度: {c1.size()} 个门, 深度 {c1.depth()}")
print(f" 振幅: {c2.size()} 个门, 深度 {c2.depth()}, "
f"保真度 {enc2.get_fidelity(data):.4f}")
print(f" IQP: {c3.size()} 个门, 深度 {c3.depth()}")
print(f" MPS: {c4.size()} 个门, 深度 {c4.depth()}, "
f"保真度 {enc4.get_fidelity(data):.4f}")
print(f" Schmidt: {c5.size()} 个门, 深度 {c5.depth()}, "
f"保真度 {enc5.get_fidelity(data):.4f}")
# 运行振幅编码线路
prog = core.QProg()
prog << c2 << core.measure([0,1], [0,1])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f" 计数: {machine.result().get_counts()}")保真度基准测试
对于近似方法,可以扫描参数以找到最佳的精度-深度权衡:
np.random.seed(42)
data = np.random.randn(8)
data = (data / np.linalg.norm(data)).tolist()
qubits = [0, 1, 2]
# 精确方法(保真度 = 1.0)
for name, fn in [
("amplitude_encode", lambda e: e.amplitude_encode(qubits, data)),
("amplitude_encode_recursive", lambda e: e.amplitude_encode_recursive(qubits, data)),
("schmidt_encode", lambda e: e.schmidt_encode(qubits, data)),
]:
enc = core.Encode()
fn(enc)
print(f"{name}: fidelity = {enc.get_fidelity(data):.6f}, "
f"gates = {enc.get_circuit().size()}")
# 不同参数的近似 MPS
for layers in [1, 2, 3, 5, 10]:
enc = core.Encode()
enc.approx_mps_encode(qubits, data, layers=layers, sweeps=200)
print(f"approx_mps_encode (layers={layers}): "
f"fidelity = {enc.get_fidelity(data):.6f}, "
f"gates = {enc.get_circuit().size()}")API 快速参考
Encode 类方法
| 方法 | 签名 | 描述 |
|---|---|---|
basic_encode | (qubits, data: str) | 二进制字符串到基态 |
angle_encode | (qubits, data, gate_type=RY) | 基于旋转的单量子比特编码 |
dense_angle_encode | (qubits, data) | 每量子比特两个角度 |
amplitude_encode | (qubits, data) | 精确振幅(实数/复数) |
amplitude_encode_recursive | (qubits, data) | 递归分解 |
iqp_encode | (qubits, data, control_list=[], bool_inverse=False, repeats=1) | IQP 线路 |
schmidt_encode | (qubits, data, cutoff=0) | Schmidt 分解 |
dc_amplitude_encode | (qubits, data) | 分治法 |
bid_amplitude_encode | (qubits, data, split=-1) | 基于分块的编码 |
ds_quantum_state_preparation | (qubits, data) | 双稀疏(字典/向量) |
sparse_isometry | (qubits, data) | 稀疏等距(字典/向量) |
efficient_sparse | (qubits, data) | 高效稀疏(字典/向量) |
approx_mps_encode | (qubits, data, layers=3, sweeps=100, double2float=False) | 近似 MPS |
get_circuit | () | 返回 QCircuit |
get_out_qubits | () | 返回输出量子比特索引 |
get_fidelity | (data) | 编码保真度 |
数据类型支持
| 方法 | str | float[] | complex[] | Dict[str,float] | Dict[str,complex] |
|---|---|---|---|---|---|
basic_encode | 是 | -- | -- | -- | -- |
angle_encode | -- | 是 | -- | -- | -- |
dense_angle_encode | -- | 是 | -- | -- | -- |
amplitude_encode | -- | 是 | 是 | -- | -- |
amplitude_encode_recursive | -- | 是 | 是 | -- | -- |
iqp_encode | -- | 是 | -- | -- | -- |
schmidt_encode | -- | 是 | -- | -- | -- |
dc_amplitude_encode | -- | 是 | -- | -- | -- |
bid_amplitude_encode | -- | 是 | -- | -- | -- |
ds_quantum_state_preparation | -- | 是 | 是 | 是 | 是 |
sparse_isometry | -- | 是 | 是 | 是 | 是 |
efficient_sparse | -- | 是 | 是 | 是 | 是 |
approx_mps_encode | -- | 是 | 是 | -- | -- |
总结
在本教程中你学到了:
量子态制备将经典数据映射到量子态。你选择的编码方法直接影响线路资源和算法性能。
Encode 类(
core.Encode())是统一接口。调用编码方法,然后使用get_circuit()、get_out_qubits()和get_fidelity(data)提取结果。13 种编码方法覆盖了广泛的设计空间:
- 基态编码:
basic_encode用于二进制字符串 - 基于角度:
angle_encode、dense_angle_encode用于 QML 特征映射 - 基于振幅:
amplitude_encode、amplitude_encode_recursive用于精确态加载 - 纠缠型:
iqp_encode用于经典难模拟线路 - 分解型:
schmidt_encode、dc_amplitude_encode、bid_amplitude_encode用于结构化态 - 稀疏型:
ds_quantum_state_preparation、sparse_isometry、efficient_sparse用于稀疏数据 - 近似型:
approx_mps_encode用于大规模问题
- 基态编码:
保真度评估通过
get_fidelity()量化编码精度,对于近似方法至关重要。方法选择取决于数据类型、精度要求和硬件约束。
下一个教程介绍 哈密顿量与 Pauli 算符,你将学习如何构造和操作用于变分量子算法的哈密顿量。
知识检验
测试你对 pyqpanda3 中量子态制备的理解。
Q1:振幅编码和角度编码有什么区别?你会在什么情况下优先选择其中一种?
A1:振幅编码将数据值直接映射到量子态的概率振幅:
Q2:振幅编码的输入数据必须满足什么归一化条件?如果不满足会怎样?
A2:数据必须满足 amplitude_encode 方法会在内部对输入数据进行归一化,除以总范数。这意味着你可以传递未归一化的数据,方法会自动处理,但你应该注意隐式归一化的存在。
Q3:解释 schmidt_encode 中 cutoff 参数的作用。为什么你可能需要非零的 cutoff?
A3:schmidt_encode 中的 cutoff 参数在 Schmidt 分解中截断低于阈值的奇异值。cutoff=0(默认值)时不进行截断,编码是精确的。非零的 cutoff 会移除较小的奇异值,以降低编码保真度为代价减少线路深度。这种权衡对于精确编码需要太多门的大规模问题非常有用。
Q4:ds_quantum_state_preparation 和 sparse_isometry 有什么区别?两者都处理稀疏数据。
A4:两种方法都针对稀疏量子态,但使用不同的算法。ds_quantum_state_preparation 使用双稀疏方法,针对计算基中具有少量非零振幅的态进行优化。sparse_isometry 使用基于等距的方法,保持内积关系。选择取决于稀疏模式:ds_quantum_state_preparation 通常对均匀稀疏态更高效,而 sparse_isometry 更好地处理结构化稀疏性。
Q5:approx_mps_encode 中的 layers 参数控制什么?增大它会发生什么?
A5:layers 参数控制用于编码的矩阵乘积态(MPS)拟设中的变分层数量。更多的层增加了拟设的表达能力,允许以更高的保真度编码复杂的数据分布。然而,更多的层也会增加线路深度和需要优化的参数数量,需要更多的 sweeps 和可能更长的计算时间。默认的 3 层为大多数用例提供了良好的平衡。
Q6:在 Encode 对象上调用编码方法后,如何在量子程序中使用结果?
A6:在调用编码方法(例如 enc.amplitude_encode(qubits, data))后,使用 enc.get_circuit() 提取线路,使用 enc.get_out_qubits() 获取输出量子比特。然后使用 << 运算符将线路追加到 QProg:prog << enc.get_circuit()。输出量子比特可用于后续操作或测量。
Q7:为什么 approx_mps_encode 有一个 double2float 参数?权衡是什么?
A7:double2float 参数在编码前将双精度(64 位)输入数据转换为单精度(32 位浮点数)。这降低了优化的数值精度,可能导致稍低的保真度但更快的计算速度。权衡是精度与速度。对于大多数量子硬件本身精度有限的应用来说,单精度可能就足够了。
练习 1:编码比较
使用三种不同的方法(角度编码、振幅编码和 Schmidt 编码)编码相同的 4 元素数据向量,然后比较它们的保真度和线路深度。
解答:
import numpy as np
from pyqpanda3.core import Encode, CPUQVM, QProg, measure
data = [0.5, 0.5, 0.5, 0.5]
qubits = [0, 1]
# --- 角度编码 ---
enc_angle = Encode()
enc_angle.angle_encode(qubits, data[:2]) # 2 个量子比特只用 2 个值
angle_circuit = enc_angle.get_circuit()
print("Angle encoding circuit:", angle_circuit)
# --- 振幅编码 ---
enc_amp = Encode()
enc_amp.amplitude_encode(qubits, data)
amp_circuit = enc_amp.get_circuit()
amp_fidelity = enc_amp.get_fidelity(data)
print(f"Amplitude encoding fidelity: {amp_fidelity:.6f}")
# --- Schmidt 编码 ---
enc_schmidt = Encode()
enc_schmidt.schmidt_encode(qubits, data, cutoff=0)
schmidt_circuit = enc_schmidt.get_circuit()
schmidt_fidelity = enc_schmidt.get_fidelity(data)
print(f"Schmidt encoding fidelity: {schmidt_fidelity:.6f}")
# --- 运行并比较 ---
qvm = CPUQVM()
for name, circuit in [("Amplitude", amp_circuit), ("Schmidt", schmidt_circuit)]:
prog = QProg()
prog << circuit << measure(qubits, [0, 1])
qvm.run(prog, shots=1000)
counts = qvm.result().get_counts()
print(f"{name} encoding results: {counts}")练习 2:稀疏态制备
使用 ds_quantum_state_preparation 和 sparse_isometry 制备一个仅有 2 个非零振幅的 3 量子比特态,比较结果。
解答:
from pyqpanda3.core import Encode, CPUQVM, QProg, measure
import numpy as np
# 稀疏态:只有 |000> 和 |111>
sparse_data = {"000": 0.6, "111": 0.8}
qubits = [0, 1, 2]
# 归一化
norm = np.sqrt(sum(v**2 for v in sparse_data.values()))
sparse_data_norm = {k: v/norm for k, v in sparse_data.items()}
# 方法 1:ds_quantum_state_preparation
enc1 = Encode()
enc1.ds_quantum_state_preparation(qubits, sparse_data_norm)
fidelity1 = enc1.get_fidelity(list(sparse_data_norm.values()))
print(f"ds_quantum_state_preparation fidelity: {fidelity1:.6f}")
# 方法 2:sparse_isometry
enc2 = Encode()
enc2.sparse_isometry(qubits, sparse_data_norm)
fidelity2 = enc2.get_fidelity(list(sparse_data_norm.values()))
print(f"sparse_isometry fidelity: {fidelity2:.6f}")
# 在模拟器上运行两种方法
qvm = CPUQVM()
for name, enc in [("DS Preparation", enc1), ("Sparse Isometry", enc2)]:
prog = QProg()
prog << enc.get_circuit() << measure(qubits, [0, 1, 2])
qvm.run(prog, shots=1000)
counts = qvm.result().get_counts()
print(f"{name}: {counts}")练习 3:近似 MPS 参数扫描
使用 approx_mps_encode 编码 8 元素数据向量,使用不同的 layers(1、3、5)和 sweeps(50、100、200),报告每种组合的保真度。
解答:
import numpy as np
from pyqpanda3.core import Encode
# 8 元素数据(需要 3 个量子比特)
data = [0.1, 0.3, 0.5, 0.2, 0.4, 0.6, 0.15, 0.25]
qubits = [0, 1, 2]
print(f"{'Layers':<8} {'Sweeps':<8} {'Fidelity':<12}")
print("-" * 28)
for layers in [1, 3, 5]:
for sweeps in [50, 100, 200]:
enc = Encode()
try:
enc.approx_mps_encode(qubits, data, layers=layers, sweeps=sweeps)
fidelity = enc.get_fidelity(data)
print(f"{layers:<8} {sweeps:<8} {fidelity:.6f}")
except Exception as e:
print(f"{layers:<8} {sweeps:<8} Error: {e}")