量子计算:从软件构建到实际应用
1. 构建量子软件并在真实量子计算机上运行
在量子计算中,将作业提交到选定的后端是关键步骤。以下是一个示例,我们选择运行 1000 次采样:
job = sampler.run(qc_transpiled, shots = 1000)
查看结果:
result = job.result()
使用 Qiskit 的内置可视化函数
plot_histogram
可视化结果,绘制结果分布或“准概率”:
quasi_probs = result.quasi_dists
plot_histogram(quasi_probs, figsize=(9,5))
2. 量子助手
为了让学习过程更直观、快速,我们有一个语音控制的 AI 助手。它使用代码实现,能帮助执行多项任务,包括电路构建,还能展示解决方案。例如,我们可以让它解决一个有三个物品的背包问题,指定物品的重量和价值,助手会给出最优选择。我们还能让它展示解决问题的所有步骤,包括状态表可视化和更多计算细节。
3. 重温量子门和蝴蝶模式
量子计算由基本指令(单量子比特门)按特定顺序应用于特定量子比特组成。理解单量子比特门如何转换量子态至关重要。单量子比特门根据特定门公式重新组合由目标和控制量子比特确定的振幅对,该公式由一个 2×2(酉)矩阵定义。受控变换除目标量子比特外还有一个或多个控制量子比特,减少了重新组合的对数。振幅的重新组合可以用蝴蝶图表示,这也用于可视化经典 FFT 算法的步骤。量子并行性允许同时执行任意数量的这些成对操作。
3.1 再看单量子比特门和蝴蝶模式
对于一个有 $n \geq 1$ 个量子比特的量子系统和目标量子比特 $t$($1 \leq t \leq n$),以及由 2×2(酉)矩阵表示的单量子比特门,门对量子系统状态的影响描述如下:
首先,根据目标量子比特确定要重新组合的振幅对。以下代码创建一个包含每对振幅的两行矩阵:
import numpy as np
def get_two_row_matrix_from_state(state, t):
stride = 2**t
chunks = np.array_split(state, int(len(state)/stride))
evens = np.concatenate(chunks[0::2])
odds = np.concatenate(chunks[1::2])
return np.stack((evens, odds))
如果用 $A_t$ 表示这个矩阵,由 $U$ 表示的门的效果可以描述。然后可以使用以下函数从矩阵组装量子态:
def get_state_from_two_row_matrix(matrix_state, t):
chunk_size = int(matrix_state.shape[1] / 2**t)
chunks_0 = np.array_split(matrix_state[0], chunk_size)
chunks_1 = np.array_split(matrix_state[1], chunk_size)
return np.hstack((chunks_0, chunks_1)).flatten()
对于应用于 $m > 0$ 个目标量子比特的 2^m×2^m 酉矩阵 $U$,转换函数如下:
def get_matrix_state(state, t, m):
n = int(np.log2(len(state)))
o_dim = 2**(n-m)
u_dim = 2**m
stride = 2**t
matrix_state = np.zeros((u_dim, o_dim), dtype=complex)
for remainder in range(stride):
for idx in range(u_dim):
matrix_state[idx, remainder::stride] = state[
remainder + idx * stride::u_dim*stride
]
return matrix_state
def get_state_from_matrix(matrix_state, t, m):
n = int(np.log2(matrix_state.shape[0] * matrix_state.shape[1]))
u_dim = 2**m
stride = 2**t
state = np.zeros(2**n, dtype=complex)
for remainder in range(stride):
for idx in range(u_dim):
state[idx * stride + remainder::u_dim*stride] = matrix_state[
idx,
remainder::stride
]
return state
使用这些函数模拟对一个随机生成的 3 量子比特状态应用酉变换(由一个 4×4 酉矩阵表示):
from hume.utils.common import generate_state, print_state_table
from hume.utils.matrix import rvs
n = 3
t = 1
m = 2
state = generate_state(n)
U = rvs(2**m)
matrix = get_matrix_state(state.copy(), t, m)
s1 = get_state_from_matrix(U@matrix, t, m)
4. 量子态作为图像
在量子计算中,我们可以用彩色条或像素说明振幅。复数的方向(相位)决定颜色的色调,幅度决定条的长度或像素的强度。如果电路由两个量子比特寄存器组成,运行电路得到的量子态可以可视化为表格或网格状态。同样,任何量子态都可以可视化为像素数组,每个像素对应一个结果,像素颜色由对应结果的振幅决定。我们可以将一维数组重新排列为二维数组,将量子比特划分为前缀和后缀。
应用门对以图像表示的状态的影响是重新组合列对(如果目标量子比特在前缀中)或行对(如果目标量子比特在后缀中)。使用图像表示,我们可以表述量子比特系统的四个基本量子属性:
- 量子态:量子态可视化为维度是 2 的幂的(强度归一化)图像。
- 系统组成:添加一个量子比特会使列或行的数量加倍。
- 状态演化:量子态可以通过使用 2×2 门重新组合列或行来改变,重新组合遵循复数加法和乘法转换为颜色的规则。
- 量子测量:测量状态揭示像素的坐标,像素被测量的概率是其强度的平方。
4.1 可视化量子态演化
当完全控制模拟器时,更容易创建自定义可视化。例如,我们可以实现一个运行量子电路的版本,产生应用于初始量子态的所有量子变换以及每次变换后状态的演化。使用
QuantumCircuit
类的
run_and_yield
方法:
def run_and_yield(self):
yield None, self.state
for tr in self.transformations:
self.apply_transformation(tr)
yield tr, self.state
self.transformations = []
使用此方法可视化量子态演化,例如:
transformations = qc.run_and_yield()
for idx, (tr, state) in enumerate(transformations):
# save the state as an image
我们还可以将量子态演化捕获为视频。
5. 组合优化问题
我们学习了如何编码二进制变量的多项式,并根据寄存器中编码的约束进行优化,这种技术的正式名称是约束多项式二进制优化(CPBO)。特别是,我们可以解决二次无约束二进制优化(QUBO)类的问题。这类问题的优化函数是二次的,每个项最多包含两个二进制变量,其一般形式为:
[
\sum_{j=0}^{n-1} c_j x_j + \sum_{0 \leq j < l < n} c_{jl} x_j x_l
]
其中 $n > 0$ 是二进制变量的数量,$c_j$ 和 $c_{jl}$ 是实数,$0 \leq j < n$ 且 $0 \leq j < l < n$。
我们只研究了一种优化方法,即 Grover 优化器,但还有其他方法。量子近似优化算法(QAOA)是一种受物理启发的混合算法,在量子计算社区很流行。它需要理解系统的哈密顿量等概念。QAOA 电路比 Grover 优化器电路需要的门更少,但连续量子运行之间需要更多经典处理。
5.1 编码非整数系数的多项式
多项式编码方法可以处理非整数系数。每个输入将有一个对应的离散 sinc 分布来编码其相应的输出。例如,对于函数 $f(k) = 0.4k^2 - 2.3$($0 \leq k < 4$),其函数表如下:
| k | f(k) = 0.4k^2 - 2.3 |
| — | — |
| 0 | -2.3 |
| 1 | -1.9 |
| 2 | -0.7 |
| 3 | 1.3 |
5.2 Shor 因式分解算法
Shor 算法挑战了 RSA 加密的安全性。RSA 加密依赖于分解两个大质数乘积的大整数的计算难度,而 Shor 算法能比已知的经典算法快指数倍地执行这种分解。Shor 算法的结构类似于我们用于编码和搜索多项式函数值的结构,它编码一个指数函数 $a^x \mod N$($a$ 是选定的整数,$N$ 是要分解的数),通过找到编码函数的周期来工作。其电路使用两个寄存器,对第一个寄存器应用 Hadamard 门,使用两个寄存器编码给定的指数函数,然后对第一个寄存器应用 IQFT。
6. 二进制字符串和复数的数学复习
在量子计算中,我们从量子计算得到的唯一信息是测量结果,以二进制字符串表示。因此,理解二进制字符串的解释很重要。
6.1 二进制和十进制值的转换
大多数时候,我们使用十进制(基数 10)形式的整数。十进制形式的整数是一个数字序列,每个数字是 10 个可能值(0 到 9)之一,从右到左数字的位置表示其代表的 10 的幂。例如,数字 104 中,最左边的数字代表 1 个百($10^2$),中间数字代表 0 个十($10^1$),最右边数字代表 4 个一($10^0$)。
二进制(基数 2)形式的整数用两个数字 0 和 1 表示,每个数字表示相应的 2 的幂是否存在,从右到左幂次增加。将二进制字符串转换为十进制形式,我们从右到左考虑每个数字,每个数字代表一个 2 的幂,将每个数字的值乘以其幂并加到总和中。例如,二进制形式的 104 转换为十进制:
[
2^6 \times 1 + 2^5 \times 1 + 2^4 \times 0 + 2^3 \times 1 + 2^2 \times 0 + 2^1 \times 0 + 2^0 \times 0 = 104
]
不同长度的二进制字符串能表示的十进制整数范围不同:
| 二进制位数 | 可表示的十进制整数范围 | 二进制形式示例 |
| — | — | — |
| 2 | 0 到 3 | [‘00’, ‘01’, ‘10’, ‘11’] |
| 3 | 0 到 7 | [‘000’, ‘001’, ‘010’, ‘011’, ‘100’, ‘101’, ‘110’, ‘111’] |
6.2 向二进制字符串添加数字
长度为 $n$ 的二进制字符串有 $2^n$ 个。每次添加一个数字,可能的字符串数量会加倍,因为可以使用另一个 2 的幂。例如,添加一个数字到二进制字符串,能表示的值的数量变为原来的两倍。
mermaid 流程图:
graph TD;
A[开始] --> B[构建量子软件];
B --> C[提交作业到后端];
C --> D[获取结果];
D --> E[可视化结果];
E --> F[使用量子助手];
F --> G[解决问题];
G --> H[重温量子门和蝴蝶模式];
H --> I[量子态作为图像];
I --> J[组合优化问题];
J --> K[编码多项式];
K --> L[Shor 因式分解算法];
L --> M[数学复习];
M --> N[结束];
综上所述,量子计算涵盖了从软件构建、实际运行到解决各种问题的多个方面,同时涉及到二进制字符串和复数等数学知识。通过不断学习和实践,我们能更好地掌握量子计算的原理和应用。
量子计算:从软件构建到实际应用
7. 量子计算工具与代码实践
在量子计算的实际操作中,我们可以借助一些工具和代码来完成各项任务。例如,利用代码将特定操作提交到选定的后端进行运行,并获取最终结果。以下是具体的操作步骤:
1.
提交作业到后端
:
job = sampler.run(qc_transpiled, shots = 1000)
此代码将作业提交到后端,并设置运行 1000 次采样。
2.
获取结果
:
result = job.result()
通过这行代码,我们可以获取作业运行后的结果。
3.
可视化结果
:
quasi_probs = result.quasi_dists
plot_histogram(quasi_probs, figsize=(9,5))
这里使用
plot_histogram
函数将结果以直方图的形式可视化,方便我们直观地观察结果分布。
8. 量子助手的应用
量子助手是一个非常实用的工具,它能帮助我们解决各种量子计算相关的问题。以解决背包问题为例,具体操作如下:
1.
提出问题
:向量子助手表明我们要解决一个有三个物品的背包问题,并指定物品的重量和价值。
2.
获取解决方案
:量子助手会给出该背包问题的最优选择。
3.
查看详细步骤
:我们还可以要求助手展示解决问题的所有步骤,包括状态表可视化和更多计算细节,这有助于我们深入理解问题的解决过程。
9. 量子门与蝴蝶模式的深入理解
量子计算的基本组成部分是单量子比特门,它们按特定顺序作用于特定量子比特,从而改变量子态。单量子比特门的作用遵循蝴蝶模式,这种模式在经典计算的多个场景中也有出现。下面我们详细分析单量子比特门的作用过程及相关代码实现。
9.1 单量子比特门的作用原理
单量子比特门根据特定的门公式重新组合由目标和控制量子比特确定的振幅对,该公式由一个 2×2(酉)矩阵定义。受控变换除了目标量子比特外,还有一个或多个控制量子比特,这会减少重新组合的对数。
9.2 代码实现单量子比特门的操作
以下是根据目标量子比特确定要重新组合的振幅对,并创建包含每对振幅的两行矩阵的代码:
import numpy as np
def get_two_row_matrix_from_state(state, t):
stride = 2**t
chunks = np.array_split(state, int(len(state)/stride))
evens = np.concatenate(chunks[0::2])
odds = np.concatenate(chunks[1::2])
return np.stack((evens, odds))
若用 $A_t$ 表示这个矩阵,由 $U$ 表示的门的效果可以进一步描述。之后,我们可以使用以下函数从矩阵组装量子态:
def get_state_from_two_row_matrix(matrix_state, t):
chunk_size = int(matrix_state.shape[1] / 2**t)
chunks_0 = np.array_split(matrix_state[0], chunk_size)
chunks_1 = np.array_split(matrix_state[1], chunk_size)
return np.hstack((chunks_0, chunks_1)).flatten()
对于应用于 $m > 0$ 个目标量子比特的 2^m×2^m 酉矩阵 $U$,转换函数如下:
def get_matrix_state(state, t, m):
n = int(np.log2(len(state)))
o_dim = 2**(n-m)
u_dim = 2**m
stride = 2**t
matrix_state = np.zeros((u_dim, o_dim), dtype=complex)
for remainder in range(stride):
for idx in range(u_dim):
matrix_state[idx, remainder::stride] = state[
remainder + idx * stride::u_dim*stride
]
return matrix_state
def get_state_from_matrix(matrix_state, t, m):
n = int(np.log2(matrix_state.shape[0] * matrix_state.shape[1]))
u_dim = 2**m
stride = 2**t
state = np.zeros(2**n, dtype=complex)
for remainder in range(stride):
for idx in range(u_dim):
state[idx * stride + remainder::u_dim*stride] = matrix_state[
idx,
remainder::stride
]
return state
我们可以使用这些函数模拟对一个随机生成的 3 量子比特状态应用酉变换(由一个 4×4 酉矩阵表示):
from hume.utils.common import generate_state, print_state_table
from hume.utils.matrix import rvs
n = 3
t = 1
m = 2
state = generate_state(n)
U = rvs(2**m)
matrix = get_matrix_state(state.copy(), t, m)
s1 = get_state_from_matrix(U@matrix, t, m)
10. 量子态的图像表示与属性
在量子计算中,我们可以将量子态可视化为图像,这种表示方式有助于我们更直观地理解量子态的特性。
10.1 量子态的图像表示
任何量子态都可以可视化为像素数组,每个像素对应一个结果,像素颜色由对应结果的振幅决定。我们可以将一维数组重新排列为二维数组,将量子比特划分为前缀和后缀。
10.2 量子态的基本属性
使用图像表示,我们可以清晰地表述量子比特系统的四个基本量子属性:
-
量子态
:量子态可视化为维度是 2 的幂的(强度归一化)图像。
-
系统组成
:添加一个量子比特会使列或行的数量加倍,这体现了量子系统的可扩展性。
-
状态演化
:量子态可以通过使用 2×2 门重新组合列或行来改变,重新组合遵循复数加法和乘法转换为颜色的规则,这反映了量子态的动态变化特性。
-
量子测量
:测量状态揭示像素的坐标,像素被测量的概率是其强度的平方,这是量子测量的基本规则。
11. 量子态演化的可视化
当我们完全控制模拟器时,就可以创建自定义的可视化方式来展示量子态的演化过程。以下是具体的实现步骤:
1.
定义
run_and_yield
方法
:
def run_and_yield(self):
yield None, self.state
for tr in self.transformations:
self.apply_transformation(tr)
yield tr, self.state
self.transformations = []
这个方法可以产生应用于初始量子态的所有量子变换以及每次变换后状态的演化。
2.
可视化量子态演化
:
transformations = qc.run_and_yield()
for idx, (tr, state) in enumerate(transformations):
# save the state as an image
通过上述代码,我们可以将量子态的演化过程以图像的形式保存下来,还可以将其捕获为视频,更直观地展示量子态的变化。
12. 组合优化问题的解决
组合优化问题在量子计算中具有重要地位,我们可以使用特定的技术来解决这类问题。
12.1 约束多项式二进制优化(CPBO)
我们学习了如何编码二进制变量的多项式,并根据寄存器中编码的约束进行优化,这种技术就是 CPBO。特别是对于二次无约束二进制优化(QUBO)类的问题,我们可以使用相应的方法进行求解。
12.2 QUBO 问题的优化函数
QUBO 问题的优化函数是二次的,每个项最多包含两个二进制变量,其一般形式为:
[
\sum_{j=0}^{n-1} c_j x_j + \sum_{0 \leq j < l < n} c_{jl} x_j x_l
]
其中 $n > 0$ 是二进制变量的数量,$c_j$ 和 $c_{jl}$ 是实数,$0 \leq j < n$ 且 $0 \leq j < l < n$。
12.3 优化方法
我们介绍了 Grover 优化器这一优化方法,此外,量子近似优化算法(QAOA)也是当前量子计算社区中流行的方法。QAOA 是一种受物理启发的混合算法,它需要理解系统的哈密顿量等概念。与 Grover 优化器相比,QAOA 电路需要的门更少,但连续量子运行之间需要更多经典处理。
13. 多项式编码与 Shor 因式分解算法
在量子计算中,多项式编码和 Shor 因式分解算法都具有重要的应用价值。
13.1 编码非整数系数的多项式
多项式编码方法可以处理非整数系数的情况。每个输入将有一个对应的离散 sinc 分布来编码其相应的输出。以函数 $f(k) = 0.4k^2 - 2.3$($0 \leq k < 4$)为例,其函数表如下:
| k | f(k) = 0.4k^2 - 2.3 |
| — | — |
| 0 | -2.3 |
| 1 | -1.9 |
| 2 | -0.7 |
| 3 | 1.3 |
13.2 Shor 因式分解算法
Shor 算法挑战了 RSA 加密的安全性。RSA 加密依赖于分解两个大质数乘积的大整数的计算难度,而 Shor 算法能比已知的经典算法快指数倍地执行这种分解。Shor 算法的结构类似于我们用于编码和搜索多项式函数值的结构,它编码一个指数函数 $a^x \mod N$($a$ 是选定的整数,$N$ 是要分解的数),通过找到编码函数的周期来工作。其电路使用两个寄存器,对第一个寄存器应用 Hadamard 门,使用两个寄存器编码给定的指数函数,然后对第一个寄存器应用 IQFT。
14. 二进制字符串与数学知识
在量子计算中,二进制字符串和复数等数学知识是基础。我们需要理解二进制字符串的解释,掌握二进制和十进制值的转换方法,以及向二进制字符串添加数字的影响。
14.1 二进制和十进制值的转换
二进制和十进制值的转换是量子计算中常见的操作。以下是转换的具体方法:
-
十进制转二进制
:将十进制数除以 2,取余数,直到商为 0,然后将余数倒序排列即可得到二进制数。
-
二进制转十进制
:从右到左考虑二进制字符串的每个数字,每个数字代表一个 2 的幂,将每个数字的值乘以其幂并加到总和中。例如,二进制形式的 104 转换为十进制:
[
2^6 \times 1 + 2^5 \times 1 + 2^4 \times 0 + 2^3 \times 1 + 2^2 \times 0 + 2^1 \times 0 + 2^0 \times 0 = 104
]
不同长度的二进制字符串能表示的十进制整数范围不同,具体如下表所示:
| 二进制位数 | 可表示的十进制整数范围 | 二进制形式示例 |
| — | — | — |
| 2 | 0 到 3 | [‘00’, ‘01’, ‘10’, ‘11’] |
| 3 | 0 到 7 | [‘000’, ‘001’, ‘010’, ‘011’, ‘100’, ‘101’, ‘110’, ‘111’] |
14.2 向二进制字符串添加数字
长度为 $n$ 的二进制字符串有 $2^n$ 个。每次添加一个数字,可能的字符串数量会加倍,因为可以使用另一个 2 的幂。例如,添加一个数字到二进制字符串,能表示的值的数量变为原来的两倍。
mermaid 流程图:
graph LR;
A[量子计算工具与代码实践] --> B[量子助手的应用];
B --> C[量子门与蝴蝶模式的深入理解];
C --> D[量子态的图像表示与属性];
D --> E[量子态演化的可视化];
E --> F[组合优化问题的解决];
F --> G[多项式编码与Shor因式分解算法];
G --> H[二进制字符串与数学知识];
总之,量子计算是一个充满挑战和机遇的领域,它涉及到多个方面的知识和技术。通过深入学习和不断实践,我们能够更好地掌握量子计算的原理和应用,为解决各种复杂问题提供有力的支持。
超级会员免费看
1976

被折叠的 条评论
为什么被折叠?



