{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 量桨中的常用函数\n",
"\n",
" Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 概览"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"此处我们列举量桨中常用的函数,对初学者来说已可以处理大多数问题。\n",
"\n",
"其他量桨函数以及具体细节可见 [API](https://qml.baidu.com/api/introduction.html).\n",
"\n",
"在本节末尾,给出制备量子纯态的量桨实现代码,介绍量桨实现量子神经网络算法的基本框架。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 加入模块"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# 1.1 Numpy, Paddle\n",
"import numpy as np\n",
"import paddle\n",
"\n",
"# 1.2 量子电路\n",
"from paddle_quantum.circuit import UAnsatz \n",
"\n",
"# 1.3 量子态 —— np.ndarray 形式\n",
"from paddle_quantum.state import vec, vec_random # 向量\n",
"from paddle_quantum.state import density_op, density_op_random, completely_mixed_computational # 矩阵\n",
"\n",
"# 1.4 矩阵 —— np.ndarray 形式\n",
"from scipy.stats import unitary_group # 随机 U 矩阵\n",
"from paddle_quantum.utils import pauli_str_to_matrix # n 量子比特泡利矩阵\n",
"\n",
"# 1.5 矩阵运算 —— paddle.Tensor 形式\n",
"from paddle import matmul, trace # 计算內积与迹\n",
"from paddle_quantum.utils import dagger # 对 paddle.Tensor 计算复共轭 (注:对 numpy.ndarray 通过“.conj().T”)\n",
"\n",
"# 1.6 画图\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. 常用参数"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# 2.1 用于构造量子电路\n",
"\n",
"N = 3 # 量子电路量子比特数\n",
"DEPTH = 2 # 量子电路深度 (层数)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# 2.2 迭代优化参数\n",
"\n",
"ITR = 200 # 迭代次数 \n",
"LR = 0.2 # 学习速率 \n",
"SEED = 1 # 随机种子 \n",
"paddle.seed(SEED) # paddle种子\n",
"np.random.seed(SEED) # numpy种子"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Numpy 矩阵相关"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# 3.1 随机幺正矩阵\n",
"V = unitary_group.rvs(2) # 随机 2*2 V"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# 3.2 对角矩阵\n",
"D = np.diag([0.2, 0.8])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# 3.3 复共轭\n",
"V_dagger = V.conj().T"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# 3.4 矩阵乘法:@\n",
"H = (V @ D @ V_dagger)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(0.9999999999999998-8.239936510889834e-18j)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 3.5 迹\n",
"H.trace()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0.2, 0.8])"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 3.6 特征值\n",
"np.linalg.eigh(H)[0]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# 3.7 张量积: A \\otimes B\n",
"A = np.eye(2)\n",
"B = H\n",
"T = np.kron(A, B)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- 注:在量桨中,可以通过字符串形式构建 $n$ 量子比特泡利矩阵。"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# 例: 0.4*I⊗Z+0.4*Z⊗I+0.2*X⊗X\n",
"# 文字形式: 0.4*kron(I, Z) + 0.4*kron(Z, I) + 0.2*kron(X, X)\n",
"H_info = [[0.4, 'z0'], [0.4, 'z1'], [0.2, 'x0,x1']]\n",
"H_matrix = pauli_str_to_matrix(H_info, 3) # 3 量子比特泡利矩阵"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. 量子态相关"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# 4.1 得到纯态 (np.ndarray 形式的行向量)\n",
"\n",
"initial_state_pure1 = vec(0, N) # 得到 |00…0>, 2**N 维行向量\n",
"initial_state_pure2 = vec_random(N) # 得到随机纯态,行向量"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"# 4.2 得到混态(np.ndarray 形式)\n",
"\n",
"initial_state_mixed1 = density_op(N) # 得到 |00…0><00…0|\n",
"initial_state_mixed2 = density_op_random(N, real_or_complex=2, rank=4) # 得到随机密度矩阵,可选择为实数或复数,可选择秩\n",
"initial_state_mixed3 = completely_mixed_computational(N) # 得到最大混态 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. 量子电路相关"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# 5.1 创建 N 量子比特电路\n",
"cir = UAnsatz(N)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"# 5.2 添加量子门 —— 具体见第7节\n",
"# 例:添加CNOT门到前两个量子比特\n",
"cir.cnot([0, 1])"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# 5.3 输出量子态\n",
"# 输出向量形式量子态(paddle.Tensor)。\n",
"# 注:此处输出态shape并不是向量,可通过paddle.reshape(final_state, [2**N, 1])转化为列向量 —— 在后续版本中将进一步优化。\n",
"\n",
"# 初始态为 |00...0>\n",
"final_state = cir.run_state_vector()\n",
"# 初始态非 |00...0>\n",
"initial_state_pure = paddle.to_tensor(initial_state_pure2)\n",
"final_state_pure = cir.run_state_vector(initial_state_pure)\n",
"# 化为 numpy 列向量形式\n",
"final_state_pure_np = cir.run_state_vector().reshape([2**N, 1]).numpy()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"# 初始态为 |00…0><00…0|\n",
"cir.run_density_matrix()\n",
"# 初始态非 |00...0><00…0|\n",
"initial_state_mixed = paddle.to_tensor(initial_state_mixed2)\n",
"final_state_mixed = cir.run_density_matrix(initial_state_mixed)\n",
"# 改变为 numpy 矩阵形式\n",
"final_state_mixed_np = cir.run_density_matrix().numpy()"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 0., 0., 0., 0., 0., 0., 0.],\n",
" [0., 1., 0., 0., 0., 0., 0., 0.],\n",
" [0., 0., 1., 0., 0., 0., 0., 0.],\n",
" [0., 0., 0., 1., 0., 0., 0., 0.],\n",
" [0., 0., 0., 0., 0., 0., 1., 0.],\n",
" [0., 0., 0., 0., 0., 0., 0., 1.],\n",
" [0., 0., 0., 0., 1., 0., 0., 0.],\n",
" [0., 0., 0., 0., 0., 1., 0., 0.]])"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 5.4 量子电路对应幺正矩阵 (paddle.Tensor)\n",
"cir.U\n",
"# 改变为 numpy 矩阵形式\n",
"cir.U.numpy()\n",
"# 仅保留实数部分\n",
"cir.U.real()\n",
"cir.U.numpy().real"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--*--\n",
" | \n",
"--x--\n",
" \n",
"-----\n",
" \n"
]
}
],
"source": [
"# 5.5 打印量子电路\n",
"print(cir)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"