Skip to content

量子态制备

学习如何使用 pyqpanda3 中的 Encode 类将经典数据编码为量子态。本教程涵盖 13 种编码方法——从简单的基础编码到高级的稀疏和近似 MPS 技术——包括数学基础、代码示例以及选择合适方法的实用指南。


目录


为什么量子态制备很重要

量子态制备——也称为数据编码或数据嵌入——是将经典数据映射到量子态的过程。它几乎是所有量子算法的基本步骤:

  • 量子机器学习——核方法、变分类器和量子神经网络都需要将经典数据加载到量子寄存器中。
  • 量子模拟——需要先制备被研究物理系统的初始态。
  • 量子算法——Grover 搜索、量子相位估计和哈密顿量模拟都假设特定的输入态。

编码方法的选择直接影响线路深度、量子比特数、表达能力,并最终影响算法性能。pyqpanda3 通过 Encode 类提供了 13 种编码方法,每种方法针对不同的数据特性进行了优化。


Encode 类

pyqpanda3.core 中的 Encode 类是所有量子态制备方法的统一接口。你创建一个实例,调用编码方法,然后提取结果。

python
from pyqpanda3 import core

enc = core.Encode()

核心方法

get_circuit()——返回实现编码的 QCircuit

python
enc = core.Encode()
enc.amplitude_encode([0, 1], [0.5, 0.5, 0.5, 0.5])
circuit = enc.get_circuit()
prog = core.QProg()
prog << circuit

get_out_qubits()——返回输出量子比特索引。某些方法内部使用辅助量子比特,因此输出量子比特可能与输入量子比特不同:

python
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(相同):

F=ψencodedψtarget2
python
fidelity = enc.get_fidelity([0.5, 0.5, 0.5, 0.5])  # 精确方法返回 1.0

工作流程


方法选择指南


1. 基础编码

方法: basic_encode(qubits, data: str)

将二进制字符串直接映射到计算基态。字符串中的每个字符对应一个量子比特:'1' 施加 X 门(比特翻转),'0' 使量子比特保持基态 |0。这是最简单的编码方式——最多使用 n 个单量子比特门,不产生纠缠。

给定长度为 n 的二进制字符串 b=bn1b0,编码制备:

b=bn1b0,gatei={Xbi=1Ibi=0
属性
量子比特数n(字符串长度)
深度1
精确
python
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),并通过旋转轴的选择提供可调的表达能力。

对于数据向量 x=(x0,,xn1)

ψ=i=0n1Rg(xi)0

使用默认的 RY 门:RY(θ)|0=cos(θ/2)|0+sin(θ/2)|1。其他支持的类型包括 GateType.RXGateType.RZ

属性
量子比特数n(数据长度)
深度1
精确否(信息压缩)
python
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)

使用 RYRZ 两种旋转将两个数据值打包到每个量子比特中,与标准角度编码相比,将每个量子比特存储的信息量翻倍。这在量子比特数量有限时非常有吸引力。

对于偶数长度 2n 的数据向量,编码使用 n 个量子比特,每个量子比特施加两次旋转:

ψ=i=0n1RZ(x2i+1)RY(x2i)0

量子比特 i 的最终单量子比特态为:

RZ(β)RY(α)0=cos(α2)eiβ/20+sin(α2)eiβ/21
属性
量子比特数m/2(数据长度的一半)
深度2
精确
python
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)

将归一化的经典向量直接映射到多量子比特量子态的振幅上。这是信息密度最高的精确编码方式:n 个量子比特可以表示 2n 个振幅。线路使用受控旋转和均匀受控门来精确设置每个振幅。

给定归一化的 x=(x0,,x2n1),其中 |x|=1

ψ=i=02n1xii

接受 List[float](实数)或 List[complex](复数振幅)。数据会自动归一化。对于实数输入,态矢量与输入完全匹配。对于复数输入 xC2n,每个元素的幅值和相位都会被编码。

属性
量子比特数log2(N)
门数实数 O(N),复数 O(NlogN)
精确
python
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]

给定归一化的 x,定义:

α=i=02n11xi2,β=i=2n12n1xi2

第一次旋转设置 RY(θ)|0=α|0+β|1,然后对每一半递归处理:

ψ=α0ψupper+β1ψlower

接受 List[float]List[complex]

属性
量子比特数log2(N)
深度O(N),递归结构
精确
python
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 线路被认为在经典上难以模拟。

线路为 U=HnUDHn,其中:

UD=(i,j)ERZZij(ϕij)k=0n1RZk(xk)

E 是来自 control_list 的边集。参数:control_list(RZZ 门的量子比特对)、bool_inverse(是否施加逆操作)、repeats(线路重复次数)。

属性
量子比特数n(数据长度)
深度每次重复 O(1)(可交换门)
精确否(概率性)
python
# 基本 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 参数截断较小的奇异值,以更少的门实现近似编码。

对于 n 量子比特态分解为子系统 AB

ψ=k=1rσkukAvkB

σk<cutoff 的项被丢弃,以深度换取精度。

属性
量子比特数log2(N)
深度取决于 Schmidt 秩
精确cutoff=0 时精确
python
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() 来确定哪些量子比特承载最终的编码态。

算法计算每次分割的范数 α=|x(0)|β=|x(1)|,在控制量子比特上施加旋转编码 (α,β),然后对两半递归处理。对于长度为 2n 的数据,所需总量子比特数为 2n1

属性
量子比特数数据长度 2n 需要 2n1
深度O(logN)
精确
python
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)

块逆分解:将数据向量划分为 2s 个块,独立编码每个块,然后通过多路旋转进行组合。split 参数控制块大小;-1 为自动选择。与 dc_amplitude_encode 类似,输出量子比特可能与输入量子比特不同,因此始终使用 get_out_qubits() 检查。

对于归一化向量 xC2n 划分为 2s 个块:

ψ=k=02s1xkkx~k

其中 |x~k=xk/|xk| 是归一化的块态。

属性
量子比特数log2(N)
深度每块 O(N/2s)
精确
python
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)

处理大多数元素为零的稀疏数据。复杂度取决于非零元素的数量 s,而不是 2n

给定稀疏态 {(bk,αk)}|ψ=kαk|bk

接受四种数据类型:

类型描述
Dict[str, float]稀疏实数值态
Dict[str, complex]稀疏复数值态
List[float]稠密向量(自动检测稀疏性)
List[complex]稠密向量(自动检测稀疏性)
属性
量子比特数n + 可能的辅助比特
深度O(sn)
精确
python
# 稀疏字典格式
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 旋转和受控操作构建等距映射,将 |0n 映射到目标稀疏态。与 ds_quantum_state_preparation 不同,此方法使用直接的等距方法而非双稀疏分解。

V0n=kαkbk

等距被分解为一系列 Givens 旋转和受控操作。复杂度随非零振幅数量 s 缩放,而非希尔伯特空间维度 2n

接受与 ds_quantum_state_preparation 相同的四种数据类型。

属性
量子比特数n
深度O(sn)
精确
python
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)

通过寻找唯一标识所有非零基态的最小区分比特集 D,然后仅编码缩减的 2|D| 维空间来优化稀疏制备。对于聚集的稀疏模式,比 sparse_isometry 实现更好的门计数。

线路首先在区分量子比特上编码振幅分布,然后使用条件操作设置剩余量子比特。这避免了编码完整的 2n 维空间。

接受与 sparse_isometry 相同的数据类型。

属性
量子比特数n
深度最佳情况 O(s+n)
精确
python
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),并迭代优化线路以近似它。以牺牲精确精度为代价大幅减少线路深度。

ψ=i1,,inTr(A1i1A2i2Anin)i1in

每个 MPS 张量被映射到单量子比特和双量子比特门,在 sweeps 次迭代中进行优化。更多的 layers 产生更高的保真度但更深的线路。接受 List[float]List[complex]

参数默认值描述
layers3MPS 层数(表达能力)
sweeps100优化迭代次数
double2floatFalse转换为 float32 以加速
属性
量子比特数log2(N)
深度O(nlayers)
精确否(近似)
python
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_encoden1str基态
angle_encoden1float[]QML 特征
dense_angle_encoden/22float[]紧凑特征
amplitude_encodelog2NO(N)float[], complex[]精确加载
amplitude_encode_recursivelog2NO(N)float[], complex[]结构化态
iqp_encodenO(1)float[]QML 核方法
schmidt_encodelog2N可变精确/近似float[]低秩态
dc_amplitude_encode2n1O(logN)float[]浅层线路
bid_amplitude_encodelog2N可变float[]分块数据
ds_quantum_state_preparationn+辅助O(sn)Dict, float[], complex[]稀疏态
sparse_isometrynO(sn)Dict, float[], complex[]稀疏精确
efficient_sparsenO(s+n)Dict, float[], complex[]高效稀疏
approx_mps_encodelog2NO(nL)float[], complex[]大规模态

决策流程图

以下流程图根据你的数据特性和约束条件,引导你选择最合适的编码方法:

量子比特和门代价汇总

对于长度为 N=2n 的数据向量:

方法所需量子比特门数线路深度
basic_encodenO(n)O(1)
angle_encodenO(n)O(1)
dense_angle_encoden/2O(n)O(1)
amplitude_encodenO(2n)O(2n)
amplitude_encode_recursivenO(2n)O(n)
iqp_encodenO(n2)O(1)
schmidt_encodenO(2nr)O(2nr)
dc_amplitude_encodenO(n2n)O(n)
bid_amplitude_encodenO(n2n/2)O(n2n/2)
ds_quantum_state_preparationn+O(1)O(sn)O(sn)
sparse_isometrynO(sn)O(sn)
efficient_sparsenO(s+n)O(s+n)
approx_mps_encodenO(nL)O(nL)

其中 s 是非零振幅的数量,r 是 Schmidt 秩,L 是 MPS 层数。


完整示例

本示例使用多种方法编码真实分类数据,并比较线路统计信息和保真度:

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

保真度基准测试

对于近似方法,可以扫描参数以找到最佳的精度-深度权衡:

python
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)编码保真度

数据类型支持

方法strfloat[]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------

总结

在本教程中你学到了:

  1. 量子态制备将经典数据映射到量子态。你选择的编码方法直接影响线路资源和算法性能。

  2. Encode 类core.Encode())是统一接口。调用编码方法,然后使用 get_circuit()get_out_qubits()get_fidelity(data) 提取结果。

  3. 13 种编码方法覆盖了广泛的设计空间:

    • 基态编码basic_encode 用于二进制字符串
    • 基于角度angle_encodedense_angle_encode 用于 QML 特征映射
    • 基于振幅amplitude_encodeamplitude_encode_recursive 用于精确态加载
    • 纠缠型iqp_encode 用于经典难模拟线路
    • 分解型schmidt_encodedc_amplitude_encodebid_amplitude_encode 用于结构化态
    • 稀疏型ds_quantum_state_preparationsparse_isometryefficient_sparse 用于稀疏数据
    • 近似型approx_mps_encode 用于大规模问题
  4. 保真度评估通过 get_fidelity() 量化编码精度,对于近似方法至关重要。

  5. 方法选择取决于数据类型、精度要求和硬件约束。

下一个教程介绍 哈密顿量与 Pauli 算符,你将学习如何构造和操作用于变分量子算法的哈密顿量。


知识检验

测试你对 pyqpanda3 中量子态制备的理解。

Q1:振幅编码和角度编码有什么区别?你会在什么情况下优先选择其中一种?

A1:振幅编码将数据值直接映射到量子态的概率振幅:|ψ=ixi|i(归一化后)。对于 n 个数据值,它使用 log2(n) 个量子比特,但产生深度较大的线路。角度编码将每个数据值映射到独立量子比特上的旋转角度:Ry(xi),需要 n 个量子比特表示 n 个值,但产生浅层线路。当量子比特稀缺时优先选择振幅编码,当需要最小化线路深度时优先选择角度编码(例如在 NISQ 硬件上)。

Q2:振幅编码的输入数据必须满足什么归一化条件?如果不满足会怎样?

A2:数据必须满足 i|xi|2=1(单位范数)。amplitude_encode 方法会在内部对输入数据进行归一化,除以总范数。这意味着你可以传递未归一化的数据,方法会自动处理,但你应该注意隐式归一化的存在。

Q3:解释 schmidt_encodecutoff 参数的作用。为什么你可能需要非零的 cutoff?

A3:schmidt_encode 中的 cutoff 参数在 Schmidt 分解中截断低于阈值的奇异值。cutoff=0(默认值)时不进行截断,编码是精确的。非零的 cutoff 会移除较小的奇异值,以降低编码保真度为代价减少线路深度。这种权衡对于精确编码需要太多门的大规模问题非常有用。

Q4:ds_quantum_state_preparationsparse_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() 获取输出量子比特。然后使用 << 运算符将线路追加到 QProgprog << enc.get_circuit()。输出量子比特可用于后续操作或测量。

Q7:为什么 approx_mps_encode 有一个 double2float 参数?权衡是什么?

A7:double2float 参数在编码前将双精度(64 位)输入数据转换为单精度(32 位浮点数)。这降低了优化的数值精度,可能导致稍低的保真度但更快的计算速度。权衡是精度与速度。对于大多数量子硬件本身精度有限的应用来说,单精度可能就足够了。


练习 1:编码比较

使用三种不同的方法(角度编码、振幅编码和 Schmidt 编码)编码相同的 4 元素数据向量,然后比较它们的保真度和线路深度。

解答:

python
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_preparationsparse_isometry 制备一个仅有 2 个非零振幅的 3 量子比特态,比较结果。

解答:

python
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),报告每种组合的保真度。

解答:

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

Released under the MIT License.