提交 ae59b7d7 编写于 作者: Q Quleaf

update to v2.1.2

上级 71f45820
......@@ -6,7 +6,7 @@ English | [简体中文](README_CN.md)
- [Install](#install)
- [Install PaddlePaddle](#install-paddlepaddle)
- [Install Paddle Quantum](#install-paddle-quantum)
- [Use OpenFermion to read .xyz molecule configuration file](#use-openfermion-to-read-xyz-molecule-configuration-file)
- [Environment setup for Quantum Chemistry module](#environment_setup_for_quantum_chemistry_module)
- [Run programs](#run-programs)
- [Introduction and developments](#introduction-and-developments)
- [Quick start](#quick-start)
......@@ -33,7 +33,7 @@ English | [简体中文](README_CN.md)
</a>
<!-- PyPI -->
<a href="https://pypi.org/project/paddle-quantum/">
<img src="https://img.shields.io/badge/pypi-v2.1.1-orange.svg?style=flat-square&logo=pypi"/>
<img src="https://img.shields.io/badge/pypi-v2.1.2-orange.svg?style=flat-square&logo=pypi"/>
</a>
<!-- Python -->
<a href="https://www.python.org/">
......@@ -88,18 +88,31 @@ cd quantum
pip install -e .
```
### Environment setup for Quantum Chemistry module
### Use OpenFermion to read .xyz molecule configuration file
Our qchem module is based on `Openfermion` and `Psi4`, so before executing quantum chemistry, we have to install the two Python packages first.
> Only macOS and linux users can use OpenFermion to read .xyz description files.
> It is recommended that these Python packages be installed in a Python 3.8 environment.
Once the user confirms the above OS constraint, OpenFermion can be installed with the following command. These packages are used for quantum chemistry calculations and could be potentially used in the VQE tutorial.
`Openfermion` can be installed with the following command:
```bash
pip install openfermion
pip install openfermionpyscf
```
We highly recommend you to install `Psi4` via conda. **MacOS/Linux** user can use the command:
```bash
conda install psi4-c psi4
```
For **Windows** user, the command is:
```bash
conda install psi4 -c psi4 -c conda-forge
```
**Note:** Please refer to [Psi4](https://psicode.org/installs/v14/) for more download options.
### Run example
Now, you can try to run a program to verify whether Paddle Quantum has been installed successfully. Here we take quantum approximate optimization algorithm (QAOA) as an example.
......@@ -128,10 +141,15 @@ python main.py
We provide tutorials covering quantum simulation, machine learning, combinatorial optimization, local operations and classical communication (LOCC), and other popular QML research topics. Each tutorial currently supports reading on our website and running Jupyter Notebooks locally. For interested developers, we recommend them to download Jupyter Notebooks and play around with it. Here is the tutorial list,
- [Quantum Simulation](./tutorial/quantum_simulation)
1. [Variational Quantum Eigensolver (VQE)](./tutorial/quantum_simulation/VQE_EN.ipynb)
2. [Subspace Search-Quantum Variational Quantum Eigensolver (SSVQE)](./tutorial/quantum_simulation/SSVQE_EN.ipynb)
3. [Variational Quantum State Diagonalization (VQSD)](./tutorial/quantum_simulation/VQSD_EN.ipynb)
4. [Gibbs State Preparation](./tutorial/quantum_simulation/GibbsState_EN.ipynb)
1. [Building Molecular Hamiltonian](./tutorial/quantum_simulation/BuildingMolecule_EN.ipynb)
2. [Variational Quantum Eigensolver (VQE)](./tutorial/quantum_simulation/VQE_EN.ipynb)
3. [Subspace Search-Quantum Variational Quantum Eigensolver (SSVQE)](./tutorial/quantum_simulation/SSVQE_EN.ipynb)
4. [Variational Quantum State Diagonalization (VQSD)](./tutorial/quantum_simulation/VQSD_EN.ipynb)
5. [Gibbs State Preparation](./tutorial/quantum_simulation/GibbsState_EN.ipynb)
6. [The Classical Shadow of Unknown Quantum States](./tutorial/quantum_simulation/ClassicalShadow_Intro_EN.ipynb)
7. [Estimation of Quantum State Properties Based on the Classical Shadow](./tutorial/quantum_simulation/ClassicalShadow_Application_EN.ipynb)
8. [Hamiltonian Simulation with Product Formula](./tutorial/quantum_simulation/HamiltonianSimulation_EN.ipynb)
9. [Simulate the Spin Dynamics on a Heisenberg Chain](./tutorial/quantum_simulation/SimulateHeisenberg_EN.ipynb)
- [Machine Learning](./tutorial/machine_learning)
1. [Encoding Classical Data into Quantum States](./tutorial/machine_learning/DataEncoding_EN.ipynb)
......@@ -163,9 +181,13 @@ We provide tutorials covering quantum simulation, machine learning, combinatoria
1. [The Barren Plateaus Phenomenon on Quantum Neural Networks (Barren Plateaus)](./tutorial/qnn_research/BarrenPlateaus_EN.ipynb)
2. [Noise Model and Quantum Channel](./tutorial/qnn_research/Noise_EN.ipynb)
3. [Calculating Gradient Using Quantum Circuit](./tutorial/qnn_research/Gradient_EN.ipynb)
4. [Expressibility of Quantum Neural Network](./tutorial/qnn_research/Expressibility_EN.ipynb)
5. [Variational Quantum Circuit Compiling](./tutorial/qnn_research/VQCC_EN.ipynb)
With the latest LOCCNet module, Paddle Quantum can efficiently simulate distributed quantum information processing tasks. Interested readers can start with this [tutorial on LOCCNet](./tutorial/locc/LOCCNET_Tutorial_EN.ipynb). In addition, Paddle Quantum supports QNN training on GPU. For users who want to get into more details, please check out the tutorial [Use Paddle Quantum on GPU](./introduction/PaddleQuantum_GPU_EN.ipynb). Moreover, Paddle Quantum could design robust quantum algorithms under noise. For more information, please see [Noise tutorial](./tutorial/qnn_research/Noise_EN.ipynb).
In a recent update, the measurement-based quantum computation (MBQC) module has been added to Paddle Quantum. Unlike the conventional quantum circuit model, MBQC has its unique way of computing. Interested readers are welcomed to read our [tutorials](./tutorial/mbqc) on how to use the MBQC module and its use cases.
### API documentation
For those who are looking for explanation on the python class and functions provided in Paddle Quantum, we refer to our [API documentation page](https://qml.baidu.com/api/introduction.html).
......
......@@ -6,7 +6,7 @@
- [安装步骤](#安装步骤)
- [安装 PaddlePaddle](#安装-paddlepaddle)
- [安装 Paddle Quantum](#安装-paddle-quantum)
- [使用 openfermion 读取 xyz 描述文件](#使用-openfermion-读取-xyz-描述文件)
- [量子化学模块的环境设置](#量子化学模块的环境设置)
- [运行](#运行)
- [入门与开发](#入门与开发)
- [教程入门](#教程入门)
......@@ -34,7 +34,7 @@
</a>
<!-- PyPI -->
<a href="https://pypi.org/project/paddle-quantum/">
<img src="https://img.shields.io/badge/pypi-v2.1.1-orange.svg?style=flat-square&logo=pypi"/>
<img src="https://img.shields.io/badge/pypi-v2.1.2-orange.svg?style=flat-square&logo=pypi"/>
</a>
<!-- Python -->
<a href="https://www.python.org/">
......@@ -89,17 +89,32 @@ pip install -e .
```
### 使用 OpenFermion 读取 .xyz 描述文件
### 量子化学模块的环境设置
> 仅在 macOS 和 linux 下可以使用 OpenFermion 读取 .xyz 描述文件
我们的量子化学模块是基于 `Openfermion``Psi4` 进行开发的,所以在运行量子化学模块之前需要先行安装这两个Python包
VQE中调用 OpenFermion 读取分子 .xyz 文件并计算,因此需要安装 openfermion 和 openfermionpyscf。
> 推荐在 Python3.8 环境中安装这些 Python包。
`Openfermion` 可以用如下指令进行安装。
```bash
pip install openfermion
pip install openfermionpyscf
```
在安装 `psi4` 时,我们建议您使用 conda。对于 **MacOS/Linux** 的用户,可以使用如下指令。
```bash
conda install psi4 -c psi4
```
对于 **Windows** 用户,请使用
```bash
conda install psi4 -c psi4 -c conda-forge
```
**注意:** 更多的下载方法请参考 [Psi4](https://psicode.org/installs/v14/)
### 运行
现在,可以试着运行一段程序来验证量桨是否已安装成功。这里我们运行量桨提供的量子近似优化算法 (QAOA) 的例子。
......@@ -134,10 +149,15 @@ Paddle Quantum(量桨)建立起了人工智能与量子计算的桥梁,为
在这里,我们提供了涵盖量子模拟、机器学习、组合优化、本地操作与经典通讯(local operations and classical communication, LOCC)、量子神经网络等多个领域的案例供大家学习。每个教程目前支持网页阅览和运行 Jupyter Notebook 两种方式。我们推荐用户下载 Notebook 后,本地运行进行实践。
- [量子模拟](./tutorial/quantum_simulation)
1. [变分量子特征求解器(VQE)](./tutorial/quantum_simulation/VQE_CN.ipynb)
2. [子空间搜索 - 量子变分特征求解器(SSVQE)](./tutorial/quantum_simulation/SSVQE_CN.ipynb)
3. [变分量子态对角化算法(VQSD)](./tutorial/quantum_simulation/VQSD_CN.ipynb)
4. [吉布斯态的制备(Gibbs State Preparation)](./tutorial/quantum_simulation/GibbsState_CN.ipynb)
1. [哈密顿量的构造](./tutorial/quantum_simulation/BuildingMolecule_CN.ipynb)
2. [变分量子特征求解器(VQE)](./tutorial/quantum_simulation/VQE_CN.ipynb)
3. [子空间搜索 - 量子变分特征求解器(SSVQE)](./tutorial/quantum_simulation/SSVQE_CN.ipynb)
4. [变分量子态对角化算法(VQSD)](./tutorial/quantum_simulation/VQSD_CN.ipynb)
5. [吉布斯态的制备(Gibbs State Preparation)](./tutorial/quantum_simulation/GibbsState_CN.ipynb)
6. [未知量子态的经典影子](./tutorial/quantum_simulation/ClassicalShadow_Intro_CN.ipynb)
7. [基于经典影子的量子态性质估计](./tutorial/quantum_simulation/ClassicalShadow_Application_CN.ipynb)
8. [利用 Product Formula 模拟时间演化](./tutorial/quantum_simulation/HamiltonianSimulation_CN.ipynb)
9. [模拟一维海森堡链的自旋动力学](./tutorial/quantum_simulation/SimulateHeisenberg_CN.ipynb)
- [机器学习](./tutorial/machine_learning)
1. [量子态编码经典数据](./tutorial/machine_learning/DataEncoding_CN.ipynb)
......@@ -169,9 +189,13 @@ Paddle Quantum(量桨)建立起了人工智能与量子计算的桥梁,为
1. [量子神经网络的贫瘠高原效应(Barren Plateaus)](./tutorial/qnn_research/BarrenPlateaus_CN.ipynb)
2. [噪声模型与量子信道](./tutorial/qnn_research/Noise_CN.ipynb)
3. [使用量子电路计算梯度](./tutorial/qnn_research/Gradient_CN.ipynb)
4. [量子神经网络的表达能力](./tutorial/qnn_research/Expressibility_CN.ipynb)
5. [变分量子电路编译](./tutorial/qnn_research/VQCC_CN.ipynb)
随着 LOCCNet 模组的推出,量桨现已支持分布式量子信息处理任务的高效模拟和开发。感兴趣的读者请参见[教程](./tutorial/locc/LOCCNET_Tutorial_CN.ipynb)。Paddle Quantum 也支持在 GPU 上进行量子机器学习的训练,具体的方法请参考案例:[在 GPU 上使用 Paddle Quantum](./introduction/PaddleQuantum_GPU_CN.ipynb)。此外,量桨可以基于噪声模块进行含噪算法的开发以及研究,详情请见[噪声模块教程](./tutorial/qnn_research/Noise_CN.ipynb)
在最近的更新中,量桨还加入了基于测量的量子计算(measurement-based quantum computation, MBQC)模块。与传统的量子电路模型不同,MBQC 具有其独特的运行方式,感兴趣的读者请参见我们提供的[多篇教程](./tutorial/mbqc)以了解量桨 MBQC 模块的使用方法和应用案例。
### API 文档
我们为 Paddle Quantum 提供了独立的 [API 文档页面](https://qml.baidu.com/api/introduction.html),包含了供用户使用的所有函数和类的详细说明与用法。
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -17,4 +17,4 @@ Paddle Quantum Library
"""
name = "paddle_quantum"
__version__ = "2.1.1"
__version__ = "2.1.2"
......@@ -535,6 +535,9 @@ class UAnsatz:
Args:
state (paddle.Tensor): 输入的量子态,表示要把选定的量子比特重置为该量子态
which_qubits (list): 需要被重置的量子比特编号
Returns:
paddle.Tensor: 重置后的量子态
"""
qubits_list = which_qubits
n = self.n
......@@ -577,6 +580,7 @@ class UAnsatz:
else:
raise ValueError("Can't recognize the mode of quantum state.")
self.__state = _state
return _state
@property
def U(self):
......@@ -676,12 +680,30 @@ class UAnsatz:
Args:
x (Tensor): 待编码的向量
which_qubits (list): 用于编码的量子比特
mode (str): 生成的量子态的表示方式,``"state_vector"`` 代表态矢量表示, ``"density_matrix"`` 代表密度矩阵表示
which_qubits (list): 用于编码的量子比特
Returns:
Tensor: 一个形状为 ``(2 ** n, )`` 或 ``(2 ** n, 2 ** n)`` 的张量,表示编码之后的量子态。
代码示例:
.. code-block:: python
import paddle
from paddle_quantum.circuit import UAnsatz
n = 3
built_in_amplitude_enc = UAnsatz(n)
# 经典信息 x 需要是 Tensor 的形式
x = paddle.to_tensor([0.3, 0.4, 0.5, 0.6])
state = built_in_amplitude_enc.amplitude_encoding(x, 'state_vector', [0,2])
print(state.numpy())
::
[0.32349834+0.j 0.4313311 +0.j 0. +0.j 0. +0.j
0.53916389+0.j 0.64699668+0.j 0. +0.j 0. +0.j]
"""
assert x.size <= 2 ** self.n, \
"the number of classical data should less than or equal to the number of qubits"
......
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Class for randomly generating a Clifford operator
"""
import numpy as np
from paddle_quantum.circuit import UAnsatz
__all__ = [
"Clifford",
"compose_clifford_circuit"
]
class Clifford:
r"""用户可以通过实例化该 ``class`` 来随机生成一个 Clifford operator。
Attributes:
n (int): 该 Clifford operator 作用的量子比特数目
References:
1. Sergey Bravyi and Dmitri Maslov, Hadamard-free circuits expose the structure of the clifford group. arXiv preprint arXiv:2003.09412, 2020.
"""
def __init__(self, n):
r"""Clifford 的构造函数,用于实例化一个 Clifford 对象
Args:
n (int): 该 Clifford operator 作用的量子比特数目
"""
# number of qubit
self.n = n
self.__table, self.__Gamma, self.__Delta, self.__h, self.__s = _random_clifford(n)
self.phase = []
for qbit in range(2 * self.n):
self.phase.append(np.random.randint(0, 2))
# Initialize stabilizer table
self.x = np.transpose(self.__table)[0:n, :]
# Initialize destabilizer table
self.z = np.transpose(self.__table)[n:2 * n, :]
def print_clifford(self):
r"""输出该 Clifford 在 Pauli 基上的作用关系,来描述这个 Clifford
"""
base = []
base_out = []
n = 2 * self.n
# Initialize Pauli basis
for position in range(self.n):
base.append('X' + str(position + 1))
for position in range(self.n):
base.append('Z' + str(position + 1))
# Compute stabilizer table
for i in range(self.n):
temp = ''
for jx in range(n):
if self.x[i][jx] == 1:
temp += base[jx]
base_out.append(temp)
# Compute destabilizer table
temp = ''
for jz in range(n):
if self.z[i][jz] == 1:
temp += base[jz]
base_out.append(temp)
for i in range(n):
if i % 2 == 0:
# Fix the phase
if self.phase[i // 2] == 1:
print(base[i // 2] + ' |-> ' + '+' + base_out[i])
else:
print(base[i // 2] + ' |-> ' + '-' + base_out[i])
else:
if self.phase[self.n + (i - 1) // 2] == 1:
print(base[self.n + (i - 1) // 2] + ' |-> ' + '+' + base_out[i])
else:
print(base[self.n + (i - 1) // 2] + ' |-> ' + '-' + base_out[i])
def sym(self):
r"""获取该 Clifford operator 所对应的辛矩阵
Returns:
numpy.ndarray: Clifford 对应的辛矩阵
"""
sym = []
for i in range(self.n):
tempx = []
temp = self.x[i][self.n:2 * self.n]
for jx in range(0, self.n):
tempx.append(self.x[i][jx])
tempx.append(temp[jx])
sym.append(tempx)
tempz = []
temp = self.z[i][self.n:2 * self.n]
for jz in range(0, self.n):
tempz.append(self.z[i][jz])
tempz.append(temp[jz])
sym.append(tempz)
return np.array(sym).T
def tableau(self):
r"""获取该 Clifford operator 所对应的 table,对 n 个 qubits 情况,前 n 行对应 X_i 的结果,后 n 行对应 Z_i 的结果。
Returns:
numpy.ndarray: 该 Clifford 的 table
"""
return np.transpose(self.__table)
def circuit(self):
r"""获取该 Clifford operator 所对应的电路
Returns:
UAnsatz: 该 Clifford 对应的电路
"""
cir = UAnsatz(self.n)
gamma1 = self.__Gamma[0]
gamma2 = self.__Gamma[1]
delta1 = self.__Delta[0]
delta2 = self.__Delta[1]
# The second cnot layer
for bitindex in range(self.n):
for j in range(bitindex + 1, self.n):
if delta2[j][bitindex] == 1:
cir.cnot([bitindex, j])
# The second cz layer
for bitindex in range(self.n):
for j in range(bitindex + 1, self.n):
if gamma2[bitindex][j] == 1:
cir.cz([bitindex, j])
# The second P layer
for bitindex in range(self.n):
if gamma2[bitindex][bitindex] == 1:
cir.s(bitindex)
# Pauli layer
for bitindex in range(self.n):
if self.phase[bitindex] == 1 and self.phase[bitindex + self.n] == 0:
cir.x(bitindex)
elif self.phase[bitindex] == 0 and self.phase[bitindex + self.n] == 1:
cir.z(bitindex)
elif self.phase[bitindex] == 0 and self.phase[bitindex + self.n] == 0:
cir.y(bitindex)
# S layer
swapped = []
for bitindex in range(self.n):
if self.__s[bitindex] == bitindex:
continue
swapped.append(self.__s[bitindex])
if bitindex in swapped:
continue
cir.swap([bitindex, self.__s[bitindex]])
# Hadamard layer
for bitindex in range(self.n):
if self.__h[bitindex] == 1:
cir.h(bitindex)
# cnot layer
for bitindex in range(self.n):
for j in range(bitindex + 1, self.n):
if delta1[j][bitindex] == 1:
cir.cnot([bitindex, j])
# cz layer
for bitindex in range(self.n):
for j in range(bitindex + 1, self.n):
if gamma1[bitindex][j] == 1:
cir.cz([bitindex, j])
# P layer
for bitindex in range(self.n):
if gamma1[bitindex][bitindex] == 1:
cir.s(bitindex)
return cir
def compose_clifford_circuit(clif1, clif2):
r"""计算两个指定的 Clifford 的复合,得到复合后的电路
Args:
clif1 (Clifford): 需要复合的第 1 个 Clifford
clif2 (Clifford): 需要复合的第 2 个 Clifford
Returns:
UAnsatz: 复合后的 Clifford 所对应的电路,作用的顺序为 clif1、clif2
"""
assert clif1.n == clif2.n, "the number of qubits of two cliffords should be the same"
return clif1.circuit() + clif2.circuit()
def _sample_qmallows(n):
r"""n 量子比特的 quantum mallows 采样,来获得随机采样 Clifford 时所需要的 S 和 h
Args:
n (int): 量子比特数目
Returns:
tuple: 包含
numpy.ndarray: Clifford 采样时需要的参数 h
numpy.ndarray: Clifford 采样时需要的参数 S
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
# Hadamard layer
h = np.zeros(n, dtype=int)
# S layer
S = np.zeros(n, dtype=int)
A = list(range(n))
for i in range(n):
m = n - i
r = np.random.uniform(0, 1)
index = int(2 * m - np.ceil(np.log(r * (4 ** m - 1) + 1) / np.log(2.0)))
h[i] = 1 * (index < m)
if index < m:
k = index
else:
k = 2 * m - index - 1
S[i] = A[k]
del A[k]
return h, S
def _random_clifford(n):
r"""随机生成一个指定量子比特数目 n 的 Clifford 所对应的 table 及 canonical form 中的参数
Args:
n (int): 量子比特数目
Returns:
tuple: 包含
numpy.ndarray: 随机生成的 Clifford 所对应的 table
list: 随机生成的 Clifford 所对应的参数 Gamma
list: 随机生成的 Clifford 所对应的参数 Delta
numpy.ndarray: 随机生成的 Clifford 所对应的参数 h
numpy.ndarray: 随机生成的 Clifford 所对应的参数 S
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
assert (n <= 100), "too many qubits"
# Some constant matrices
bigzero = np.zeros((2 * n, 2 * n), dtype=int)
nzero = np.zeros((n, n), dtype=int)
I = np.identity(n, dtype=int)
h, S = _sample_qmallows(n)
Gamma1 = np.copy(nzero)
Delta1 = np.copy(I)
Gamma2 = np.copy(nzero)
Delta2 = np.copy(I)
for i in range(n):
Gamma2[i, i] = np.random.randint(2)
if h[i] == 1:
Gamma1[i, i] = np.random.randint(2)
# Constraints for canonical form
for j in range(n):
for i in range(j + 1, n):
b = np.random.randint(2)
Gamma2[i, j] = b
Gamma2[j, i] = b
Delta2[i, j] = np.random.randint(2)
if h[i] == 1 and h[j] == 1:
b = np.random.randint(2)
Gamma1[i, j] = b
Gamma1[j, i] = b
if h[i] == 1 and h[j] == 0 and S[i] < S[j]:
b = np.random.randint(2)
Gamma1[i, j] = b
Gamma1[j, i] = b
if h[i] == 0 and h[j] == 1 and S[i] > S[j]:
b = np.random.randint(2)
Gamma1[i, j] = b
Gamma1[j, i] = b
if h[i] == 0 and h[j] == 1:
Delta1[i, j] = np.random.randint(2)
if h[i] == 1 and h[j] == 1 and S[i] > S[j]:
Delta1[i, j] = np.random.randint(2)
if h[i] == 0 and h[j] == 0 and S[i] < S[j]:
Delta1[i, j] = np.random.randint(2)
# Compute stabilizer table
st1 = np.matmul(Gamma1, Delta1)
st2 = np.matmul(Gamma2, Delta2)
inv1 = np.linalg.inv(np.transpose(Delta1))
inv2 = np.linalg.inv(np.transpose(Delta2))
f_1 = np.block([[Delta1, nzero], [st1, inv1]])
f_2 = np.block([[Delta2, nzero], [st2, inv2]])
f_1 = f_1.astype(int) % 2
f_2 = f_2.astype(int) % 2
U = np.copy(bigzero)
for i in range(n):
U[i, :] = f_2[S[i], :]
U[i + n, :] = f_2[S[i] + n, :]
# Apply Hadamard layer to the stabilizer table
for i in range(n):
if h[i] == 1:
U[(i, i + n), :] = U[(i + n, i), :]
Gamma = [Gamma1, Gamma2]
Delta = [Delta1, Delta2]
return np.matmul(f_1, U) % 2, Gamma, Delta, h, S
......@@ -13,7 +13,7 @@
# limitations under the License.
"""
Functions and data simulator class of quantum finance
Functions and data simulator class of quantum finance.
"""
import fastdtw
......@@ -209,7 +209,7 @@ def portfolio_diversification_hamiltonian(penalty, rho, q):
.. math::
\begin{aligned}
C_x &= -\sum_{i=1}^{n}\sum_{j=1}^{n}\rho_{ij}x_{ij} + A\left(K- \sum_{j=1}^n y_j \right)^2 + \sum_{i=1}^n A\left(\sum_{j=1}^n 1- x_{ij} \right)^2 \\
C_x &= -\sum_{i=1}^{n}\sum_{j=1}^{n}\rho_{ij}x_{ij} + A\left(q- \sum_{j=1}^n y_j \right)^2 + \sum_{i=1}^n A\left(\sum_{j=1}^n 1- x_{ij} \right)^2 \\
&\quad + \sum_{j=1}^n A\left(x_{jj} - y_j\right)^2 + \sum_{i=1}^n \sum_{j=1}^n A\left(x_{ij}(1 - y_j)\right).\\
\end{aligned}
......
......@@ -739,14 +739,14 @@ class LoccNet(paddle.nn.Layer):
target_seq = [idx for idx in origin_seq if idx not in qubits_list]
target_seq = qubits_list + target_seq
swaped = [False] * n
swapped = [False] * n
swap_list = []
for idx in range(0, n):
if not swaped[idx]:
if not swapped[idx]:
next_idx = idx
swaped[next_idx] = True
while not swaped[target_seq[next_idx]]:
swaped[target_seq[next_idx]] = True
swapped[next_idx] = True
while not swapped[target_seq[next_idx]]:
swapped[target_seq[next_idx]] = True
swap_list.append((next_idx, target_seq[next_idx]))
next_idx = target_seq[next_idx]
......@@ -809,14 +809,14 @@ class LoccNet(paddle.nn.Layer):
target_seq = [idx for idx in origin_seq if idx not in qubits_list]
target_seq = qubits_list + target_seq
swaped = [False] * n
swapped = [False] * n
swap_list = []
for idx in range(0, n):
if not swaped[idx]:
if not swapped[idx]:
next_idx = idx
swaped[next_idx] = True
while not swaped[target_seq[next_idx]]:
swaped[target_seq[next_idx]] = True
swapped[next_idx] = True
while not swapped[target_seq[next_idx]]:
swapped[target_seq[next_idx]] = True
swap_list.append((next_idx, target_seq[next_idx]))
next_idx = target_seq[next_idx]
......
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
MaxCut main
"""
from networkx.generators.random_graphs import gnp_random_graph
from paddle_quantum.mbqc.QAOA.maxcut import mbqc_maxcut, is_graph_valid, circuit_maxcut
def main():
r"""MaxCut 主函数。
"""
# Generate a random graph
qubit_number = 5 # Number of qubits
probability_to_generate_edge = 0.7 # The probability to generate an edge randomly
rand_graph = gnp_random_graph(qubit_number, probability_to_generate_edge)
V = list(rand_graph.nodes)
E = list(rand_graph.edges)
# Make the vertex labels start from 1
V = [v + 1 for v in V]
E = [(e[0] + 1, e[1] + 1) for e in E]
G = [V, E]
# Note: As the graph is generated randomly,
# some invalid conditions might EXIST when there is at least one isolated vertex
# So before our MaxCut solution, we need to check the validity of the generated graph
print("Input graph is: \n", G)
is_graph_valid(G)
# MaxCut under MBQC
mbqc_result = mbqc_maxcut(
GRAPH=G, # Input graph
DEPTH=4, # Depth
SEED=1024, # Plant Seed
LR=0.1, # Learning Rate
ITR=120, # Training Iters
EPOCH=1, # Epoch Times
SHOTS=1024 # Shots to get the bit string
)
# Print the result from MBQC model
print("Optimal solution by MBQC: ", mbqc_result[0])
print("Optimal value by MBQC: ", mbqc_result[1])
# MaxCut under circuit model
circuit_result = circuit_maxcut(
GRAPH=G, # Input graph, G = [V, E]
DEPTH=4, # Depth
SEED=1024, # Plant Seed
LR=0.1, # Learning Rate
ITR=120, # Training Iters
EPOCH=1, # Epoch Times
SHOTS=1024 # Shots to get the bit string
)
# Print the result from circuit model
print("Optimal solution by circuit: ", circuit_result)
if __name__ == '__main__':
main()
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
PUBO main
"""
from paddle_quantum.mbqc.QAOA.pubo import mbqc_pubo, brute_force_search, is_poly_valid, random_poly
def main():
r"""PUBO 主函数。
"""
# Randomly generate an objective function
var_num = 4
polynomial = random_poly(var_num)
# A standard form of input polynomial x_1 + x_2 - x_3 + x_1 * x_2 - x_1 * x_2 * x_3
# should be {'x_1': 1, 'x_2':1, 'x_3':-1, 'x_1,x_2': 1, 'x_1,x_2,x_3': -1}
# var_num = 3
# poly_dict = {'x_1': 1, 'x_2':1, 'x_3':-1, 'x_1,x_2': 1, 'x_1,x_2,x_3': -1}
# polynomial = [n, func_dict]
print("The input polynomial is: ", polynomial)
is_poly_valid(polynomial)
# Do the training and obtain the result
mbqc_result = mbqc_pubo(
OBJ_POLY=polynomial, # Objective Function
DEPTH=6, # QAOA Depth
SEED=1024, # Plant Seed
LR=0.1, # Learning Rate
ITR=120, # Training Iters
EPOCH=1 # Epoch Times
)
print("Optimal solution by MBQC: " + str(mbqc_result[0]))
print("Optimal value by MBQC: " + str(mbqc_result[1]))
# Compute the optimal result by a brute-force method and print the result
brute_result = brute_force_search(polynomial)
print("Optimal solution by brute force search: " + str(brute_result[0]))
print("Optimal value by brute force search: " + str(brute_result[1]))
print("Difference of optimal values from MBQC and brute force search: " +
str(mbqc_result[1] - brute_result[1]))
if __name__ == '__main__':
main()
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Use MBQC-QAOA algorithm to solve MaxCut problem and compare the solution with the circuit model
"""
from time import perf_counter
from sympy import symbols
from networkx import draw, Graph, circular_layout
import matplotlib.pyplot as plt
from paddle import seed, optimizer
from paddle_quantum.mbqc.QAOA.qaoa import get_solution_string, MBQC_QAOA_Net, Circuit_QAOA_Net
__all__ = [
"is_graph_valid",
"plot_graph",
"graph_to_poly",
"plot_solution",
"mbqc_maxcut"
]
def is_graph_valid(graph):
r"""检查输入的图是否符合规范。
为了规范输入标准,我们约定输入的图没有孤立节点,即每个节点至少有边与之相连。图的节点编号为连续的自然数 ``"[1, ..., n]"``。
Args:
graph (list): 输入的图 ``"G = [V, E]"``,其中,``"V"`` 为节点集合,``"E"`` 为边集合
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.maxcut import is_graph_valid
V = [1,2,3,4]
E = [(1,2), (2, 3)]
G = [V, E]
is_graph_valid(G)
::
ValueError: input graph is not valid!
The input graph is not valid: there is at least one isolated vertex.
"""
# Obtain flat list
V = graph[0]
E = graph[1]
flat_list = []
for edge in E:
flat_list += list(edge)
# Check if there are isolated vertices
if len(set(V).difference(flat_list)) != 0:
print("The input graph is not valid: there is at least one isolated vertex.")
raise ValueError("input graph is not valid!")
else:
print("The input graph is valid.")
def plot_graph(graph, title, pos=None, node_color=None, style=None):
r"""定义画图函数。
Args:
graph (list): 输入的图 ``G = [V, E]``,其中,``V`` 为节点集合,``E`` 为边集合
title (str): 画图对应的标题
pos (dict): 图中各个节点的坐标,以字典的形式输入,例如:{'G': (0, 1)}
node_color (list): 节点的颜色,与节点的标签的顺序一一对应,例如:['blue', 'red'] 对应节点 ['G1', 'G2']
style (list): 边的样式,与边的标签的顺序一一对应,例如:['solid', 'solid'] 对应边[('G1', 'G2'), ('G3', 'G4')]
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.maxcut import plot_graph
V = ['0', '1', '2', '3']
E = [('0', '1'), ('1', '2'), ('2', '3'), ('3', '0')]
G = [V, E]
node_color = ['blue', 'yellow', 'red', 'black']
style = ['-', '--', ':', 'solid']
pos = {'0': (0, 1),'1': (1, 1), '2': (1, 0), '3': (0, 0)}
title = 'A demo of "plot_graph"'
plot_graph(G, title, pos, node_color, style)
"""
# Obtain graph
V = graph[0]
E = graph[1]
qubit_num = len(V)
G = Graph()
G.add_nodes_from(V)
G.add_edges_from(E)
# Open the plot figure
plt.figure()
plt.ion()
plt.cla()
plt.title(title)
# Set parameters for nodes
pos = circular_layout(G) if pos is None else pos
node_color = ["blue" for _ in list(range(qubit_num))] if node_color is None else node_color
style = ["solid" for (_, _) in E] if style is None else style
options = {
"with_labels": True,
"font_size": 20,
"font_weight": "bold",
"font_color": "white",
"node_size": 2000,
"width": 2
}
# Draw the graph
draw(G=G, pos=pos, node_color=node_color, style=style, **options)
ax = plt.gca()
ax.margins(0.20)
plt.axis("off")
plt.pause(1)
# plt.ioff()
# plt.show()
def graph_to_poly(graph):
r"""将图转化为对应 PUBO 问题的目标多项式。
为了代码规范,我们要求输入的图的节点编号为 ``"[1,...,n]"``。
Args:
graph (list): 用户输入的图,图的形式为 ``"[V, E]"``, ``"V" `` 为点集合, ``"E"`` 为边集合
Returns:
list: 列表第一个元素为多项式的变量个数,第二个元素为符号化的目标多项式
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.maxcut import graph_to_poly
graph = [[1, 2, 3, 4], [(1, 2), (2, 3), (3, 4), (4, 1)]]
polynomial = graph_to_poly(graph)
print("Corresponding objective polynomial of the graph is: \r\n", polynomial)
::
Corresponding objective polynomial of the graph is:
[4, -2*x_1*x_2 - 2*x_1*x_4 + 2*x_1 - 2*x_2*x_3 + 2*x_2 - 2*x_3*x_4 + 2*x_3 + 2*x_4]
"""
# Get the vertices and edges
V = graph[0]
E = graph[1]
qubit_num = len(V)
# Set symbol variables
vars_x = {i: symbols('x_' + str(i)) for i in range(1, qubit_num + 1)}
# Get the objective polynomial
poly_symbol = 0
for edge in E:
poly_symbol += vars_x[edge[0]] + vars_x[edge[1]] - 2 * vars_x[edge[0]] * vars_x[edge[1]]
# Set the polynomial
polynomial = [qubit_num, poly_symbol]
return polynomial
def plot_solution(graph, string):
r"""画出对应最大割问题的解。
Args:
graph (list): 用户输入的图,图的形式为 ``"[V, E]"``, ``"V"`` 为点集合, ``"E"`` 为边集合
string (str): 得到的最终解对应的比特串,列如:``"010101"`` ...
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.maxcut import plot_solution
V = [0, 1, 2, 3]
E = [(0, 1), (1, 2), (2, 3), (3, 0)]
G = [V, E]
plot_solution(G, '1010')
"""
# Plot the figure of bitstring using matplotlib and networkx
V = graph[0]
E = graph[1]
n = len(V)
title = "MaxCut solution"
node_cut = ["blue" if string[v - 1] == "1" else "red" for v in list(range(1, n + 1))]
edge_cut = ["solid" if string[u - 1] == string[v - 1] else "dashed" for (u, v) in E]
plot_graph(graph=graph, title=title, node_color=node_cut, style=edge_cut)
def mbqc_maxcut(GRAPH, DEPTH, SEED, LR, ITR, EPOCH, SHOTS=1024):
r"""定义 MBQC 模型下的 MaxCut 主函数。
Args:
GRAPH (list): 输入的图 ``G = [V, E]``,其中,``V`` 为节点集合,``E`` 为边集合
DEPTH (int): QAOA 算法的深度
SEED (int): paddle 的训练种子
LR (float): 学习率
ITR (int): 单次轮回的迭代次数
EPOCH (int): 轮回数
SHOTS (int): 获得最终比特串时设定的测量次数
Returns:
list: 列表第一个元素为求得的最优解,第二个元素为对应的目标函数的值
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.maxcut import mbqc_maxcut
V = [1, 2, 3, 4]
E = [(1, 2), (2, 3), (3, 4), (4, 1)]
GRAPH = [V, E]
mbqc_opt = mbqc_maxcut(GRAPH=GRAPH, P=2, SEED=1024, LR=0.1, ITR=120, EPOCH=1, shots=1024)
print("Optimal solution from MBQC: ", mbqc_opt[0])
print("Optimal value from MBQC", mbqc_opt[1])
::
Corresponding polynomial is:
-2*x_1*x_2 - 2*x_1*x_4 + 2*x_1 - 2*x_2*x_3 + 2*x_2 - 2*x_3*x_4 + 2*x_3 + 2*x_4
iter: 10 loss_MBQC: -3.3919
iter: 20 loss_MBQC: -3.8858
iter: 30 loss_MBQC: -3.9810
iter: 40 loss_MBQC: -3.9582
iter: 50 loss_MBQC: -3.9967
iter: 60 loss_MBQC: -3.9972
iter: 70 loss_MBQC: -3.9999
iter: 80 loss_MBQC: -3.9997
iter: 90 loss_MBQC: -3.9999
iter: 100 loss_MBQC: -4.0000
iter: 110 loss_MBQC: -4.0000
iter: 120 loss_MBQC: -4.0000
训练得到的最优参数 gamma: [1.57244132 0.78389509]
训练得到的最优参数 beta: [5.105461 0.78446647]
MBQC 模型下训练用时为: 8.373932838439941
MBQC 模型得到的最优解为: 1010
MBQC 模型得到的最优值为: 4
"""
plot_graph(graph=GRAPH, title="Graph to be cut")
# Obtain the objective polynomial
polynomial = graph_to_poly(GRAPH)
print("Corresponding polynomial is:\r\n", polynomial[1])
start_time = perf_counter()
seed(SEED)
mbqc_net = MBQC_QAOA_Net(DEPTH)
# Choose Adams optimizer (or SGD optimizer)
opt = optimizer.Adam(learning_rate=LR, parameters=mbqc_net.parameters())
# opt = optimizer.SGD(learning_rate = LR, parameters = mbqc_net.parameters())
# Start training
for epoch in range(EPOCH):
for itr in range(1, ITR + 1):
loss, state_out = mbqc_net(poly=polynomial)
loss.backward()
opt.minimize(loss)
opt.clear_grad()
if itr % 10 == 0:
print("iter:", itr, " loss_MBQC:", "%.4f" % loss.numpy())
print("Optimal parameter gamma: ", mbqc_net.gamma.numpy())
print("Optimal parameter beta: ", mbqc_net.beta.numpy())
end_time = perf_counter()
print("MBQC running time: ", end_time - start_time)
# Decode the MaxCut solution from the final state
mbqc_solution = get_solution_string(state_out, SHOTS)
plot_solution(GRAPH, mbqc_solution)
# Evaluate the number of cuts
var_num, poly_symbol = polynomial
relation = {symbols('x_' + str(j + 1)): int(mbqc_solution[j]) for j in range(var_num)}
mbqc_value = int(poly_symbol.evalf(subs=relation))
mbqc_opt = [mbqc_solution, mbqc_value]
return mbqc_opt
def circuit_maxcut(SEED, GRAPH, DEPTH, LR, ITR, EPOCH, SHOTS):
r"""定义电路模型下的 MaxCut 主函数。
Args:
SEED (int): paddle 的训练种子
GRAPH (list): 输入的图 ``G = [V, E]``,其中,``V`` 为节点集合,``E`` 为边集合
DEPTH (int): QAOA 算法的深度
LR (float): 学习率
ITR (int): 单次轮回的迭代次数
EPOCH (int): 轮回数
SHOTS (int): 获得最终比特串时设定的测量次数
Returns:
str: 最大割问题最优解对应的比特串
"""
plot_graph(graph=GRAPH, title="Graph to be cut")
start_time_PQ = perf_counter()
# Set cost Hamiltonian
H_D_list = [[-0.5, 'z' + str(u - 1) + ',z' + str(v - 1)] for (u, v) in GRAPH[1]]
# Initialize
seed(SEED)
pq_net = Circuit_QAOA_Net(DEPTH)
opt = optimizer.Adam(learning_rate=LR, parameters=pq_net.parameters())
for epoch in range(EPOCH):
for itr in range(1, ITR + 1):
loss, cir = pq_net(GRAPH, H_D_list)
loss.backward()
opt.minimize(loss)
opt.clear_grad()
if itr % 10 == 0:
print("iter:", itr, " loss_cir:", "%.4f" % loss.numpy())
print("Optimal parameter gamma: ", pq_net.gamma.numpy())
print("Optimal parameter beta: ", pq_net.beta.numpy())
end_time_PQ = perf_counter()
print("Circuit running time: ", end_time_PQ - start_time_PQ)
# Obtain the bit string
prob_measure = cir.measure(shots=SHOTS, plot=False)
cut_bitstring = max(prob_measure, key=prob_measure.get)
plot_solution(GRAPH, cut_bitstring)
return cut_bitstring
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Use MBQC-QAOA algorithm to solve PUBO problem and compare with the solution by brute-force search
"""
from numpy import random
from time import perf_counter
from sympy import symbols
from copy import deepcopy
from paddle import seed, optimizer
from paddle_quantum.mbqc.QAOA.qaoa import get_solution_string, MBQC_QAOA_Net
__all__ = [
"random_poly",
"is_poly_valid",
"dict_to_symbol",
"brute_force_search",
"mbqc_pubo"
]
def random_poly(var_num):
r"""随机生成一个多项式函数。
Args:
var_num (int): 多项式变量个数
Returns:
list: 列表的第一个元素为变量个数,第二个元素为各单项式构成的字典
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.pubo import random_poly
polynomial = random_poly(3)
print("The random polynomial is: \n", polynomial)
::
The random polynomial is:
[3, {'cons': 0.8634473818565477, 'x_3': 0.10521510553668978, 'x_2': 0.7519767805645575,
'x_2,x_3': -0.20826424036741054, 'x_1': -0.2795543099640111, 'x_1,x_3': -0.06628925930094798,
'x_1,x_2': -0.6094165475879592, 'x_1,x_2,x_3': 0.175938331955921}]
"""
# Random a constant item in the function
poly_dict = {'cons': random.rand()}
# Random the other items
for bit in range(1, 2 ** var_num):
item = bin(bit)[2:].zfill(var_num)
var_str = []
for j in range(1, var_num + 1):
if int(item[j - 1]) == 1:
var_str.append('x_' + str(j))
var_str = ",".join(var_str)
poly_dict[var_str] = random.rand() - random.rand()
poly = [var_num, poly_dict]
# Return polynomial
return poly
def is_poly_valid(poly):
r"""检查用户输入的多项式是否符合规范。
Args:
poly (list): 列表第一个元素为变量个数,第二个元素为用户输入的字典类型的多项式
Note:
为了代码规范,我们要求用户输入的多项式满足下列要求:1. 单项式中每个变量指数最多为一,2. 多项式变量个数与用户输入的变量个数一致,
3.变量为连续编号的 ``x_1,...,x_n``,另外,常熟项的键为 `cons`,多项式字典的键值不能重复,否则后面的条目会覆盖之前的条目。
Returns:
list: 列表的第一个元素为变量个数,第二个元素为各单项式构成的字典
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.pubo import random_poly, is_poly_valid
polynomial = random_poly(3)
print("The random polynomial is: \n", polynomial)
is_poly_valid(polynomial)
::
The random polynomial is:
[3, {'cons': 0.3166178352704635, 'x_3': -0.30850205546468723, 'x_2': 0.1938147859698406,
'x_2,x_3': 0.5722646368431439, 'x_1': 0.03709620256724111, 'x_1,x_3': 0.3273727561299321,
'x_1,x_2': -0.4544731299546062, 'x_1,x_2,x_3': -0.1406736501192053}]
The polynomial is valid.
"""
# Check the validity of the input polynomial
# Take a copy of the polynomial,
# as we do not want to change the polynomial by the latter pop action of the 'cons' term
poly_copy = deepcopy(poly)
var_num = poly_copy[0]
poly_dict = poly_copy[1]
# Remove the cons term first and then check the variables
# If there is no 'cons' term, it will do nothing
poly_dict.pop('cons', None)
# Obtain the dict keys
keys_list = list(poly_dict.keys())
# Extract all the input variables
input_vars_list = []
for key in keys_list:
key_sep = key.split(',')
# We do not allow input like {'x_1,x_1': 2}
if len(list(set(key_sep))) != len(key_sep):
print("The input polynomial contains at least one not valid monomial:" + str(key) +
". Each key of input polynomial dictionary should only consist of different variables.")
raise KeyError(key)
input_vars_list += key_sep
# Check the number of input variables
input_vars_set = list(set(input_vars_list))
if len(input_vars_set) != var_num:
input_vars_set.sort()
print("The polynomial variables are: " + str(input_vars_set) +
", but the expected number of input variables is: " + str(var_num) + ".")
raise ValueError("the number of input variables ", var_num, " is not correct.")
# Check the subscript of the variables
std_vars_list = ['x_' + str(i) for i in range(1, var_num + 1)]
input_diff_std = list(set(input_vars_set).difference(std_vars_list))
if len(input_diff_std) != 0:
input_vars_set.sort()
print("The polynomial variables are: " + str(input_vars_set) +
", but the expected variables are: " + str(std_vars_list) + ".")
raise ValueError("the subscript of input variable does not range from 1 to " + str(var_num) + ".")
# If the input polynomial is a valid one
print("The polynomial is valid.")
def dict_to_symbol(poly):
r"""将用户输入的多项式字典处理成符号多项式。
用户输入为以 ``x_i`` 为自变量的目标函数,第一步需要对目标函数进行处理,处理成 sympy 所接受的符号多项式,便于后续的变量替换和计算。
Args:
poly (list): 列表第一个元素为变量个数,第二个元素为用户输入的字典类型的多项式
Returns:
list: 列表第一个元素为变量个数,第二个元素为符号化的多项式
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.pubo import dict_to_symbol
var_num = 4
poly_dict = {"cons": 0.5, 'x_1': 2, 'x_1,x_2': -2, 'x_2,x_3': -2, 'x_3,x_4': -2, 'x_4,x_1': -2}
polynomial = [var_num, poly_dict]
new_poly = dict_to_symbol(polynomial)
print("The symbolized polynomial is: \n", new_poly)
::
The symbolized polynomial is: [4, -2*x_1*x_2 - 2*x_1*x_4 + 2*x_1 - 2*x_2*x_3 - 2*x_3*x_4 + 0.5]
"""
var_num, poly_dict = poly
# Transform the dict to a symbolized function
poly_symbol = 0
for key in poly_dict:
value = poly_dict[key]
if key == 'cons':
poly_symbol += value
else:
key_sep = key.split(',')
sym_var = 1
for var in key_sep:
sym_var *= symbols(var)
poly_symbol += value * sym_var
new_poly = [var_num, poly_symbol]
return new_poly
def brute_force_search(poly):
r"""用遍历的算法在解空间里暴力搜索 PUBO 问题的解,作为标准答案和其他算法的结果作比较。
Args:
poly (list): 列表第一个元素为变量个数,第二个元素为单项式构成的字典
Returns:
list: 列表第一个元素为 PUBO 问题的解,第二个元素为对应的目标函数的值
代码示例:
.. code-block:: python
from paddle_quantum.mbqc.QAOA.pubo import brute_force_search
n = 4
func_dict = {"cons":0.5, 'x_1': 2, 'x_1,x_2': -2, 'x_2,x_3': -2, 'x_3,x_4': -2, 'x_4,x_1':-2}
polynomial = [n, func_dict]
opt = brute_force_search(polynomial)
print("The optimal solution by brute force search is: ", opt[0])
print("The optimal value by brute force search is: ", opt[1])
::
The optimal solution by brute force search is: 1000
The optimal value by brute force search is: 2.50000000000000
"""
# Transform the dict of objective function to a symbolic function
var_num, poly_symbol = dict_to_symbol(poly)
feasible_values = []
feasible_set = []
# Scan the solution space
for bit in range(2 ** var_num):
feasible_solution = bin(bit)[2:].zfill(var_num)
feasible_set += [feasible_solution]
relation = {symbols('x_' + str(j + 1)): int(feasible_solution[j]) for j in range(var_num)}
feasible_values += [poly_symbol.evalf(subs=relation)]
opt_value = max(feasible_values)
opt_solution = feasible_set[feasible_values.index(opt_value)]
opt = [opt_solution, opt_value]
return opt
def mbqc_pubo(OBJ_POLY, DEPTH, SEED, LR, ITR, EPOCH, SHOTS=1024):
r"""定义 MBQC 模型下的 PUBO 主函数。
选择 Adams 优化器,梯度下降算法最小化目标函数。
Args:
OBJ_POLY (list): 输入为以 x 为自变量的目标函数,列表第一个元素为变量个数,第二个元素为单项式构成的字典
DEPTH (int): QAOA 算法的深度
SEED (int): paddle 的训练种子
LR (float): 学习率
ITR (int): 单次轮回的迭代次数
EPOCH (int): 轮回数
SHOTS (int): 获得最终比特串时设定的测量次数
Returns:
list: 列表第一个元素为求得的最优解,第二个元素为对应的目标函数的值
代码示例:
.. code-block:: python
from pubo import mbqc_pubo
n = 4
poly_dict = {'x_1': 2, 'x_2': 2, 'x_3': 2, 'x_4': 2, 'x_1,x_2': -2, 'x_2,x_3': -2, 'x_3,x_4': -2, 'x_4,x_1': -2}
polynomial = [n, poly_dict]
mbqc_opt = mbqc_pubo(OBJ_POLY=polynomial, DEPTH=4, SEED=1024, LR=0.1, ITR=120, EPOCH=1, shots=1024)
print("The optimal solution by MBQC is: ", mbqc_opt[0])
print("The optimal value by MBQC is: ", mbqc_opt[1])
::
QAOA Ansatz depth is: 4
iter: 10 loss_MBQC: -3.8231
iter: 20 loss_MBQC: -3.9038
iter: 30 loss_MBQC: -3.9840
iter: 40 loss_MBQC: -3.9970
iter: 50 loss_MBQC: -3.9990
iter: 60 loss_MBQC: -3.9993
iter: 70 loss_MBQC: -3.9997
iter: 80 loss_MBQC: -3.9999
iter: 90 loss_MBQC: -4.0000
iter: 100 loss_MBQC: -4.0000
iter: 110 loss_MBQC: -4.0000
iter: 120 loss_MBQC: -4.0000
MBQC running time is: 16.864049434661865
Optimal parameter gamma: [3.15639021 0.23177807 4.99173672 0.69199477]
Optimal parameter beta: [0.13486116 2.22551912 5.10371187 2.4004731 ]
The optimal solution by MBQC is: 0101
The optimal value by MBQC is: 4.00000000000000
"""
obj_poly = dict_to_symbol(OBJ_POLY)
var_num, poly_symbol = obj_poly
# Initialize
print("QAOA Ansatz depth is:", DEPTH)
# Initialize MBQC - PUBO optimization net
start_time = perf_counter()
seed(SEED)
mbqc_net = MBQC_QAOA_Net(DEPTH)
# Choose Adams optimizer (or SGD optimizer)
opt = optimizer.Adam(learning_rate=LR, parameters=mbqc_net.parameters())
# opt = optimizer.SGD(learning_rate = LR, parameters = mbqc_net.parameters())
# Start training
for epoch in range(EPOCH):
# Update parameters for each iter
for itr in range(1, ITR + 1):
# Train with mbqc_net and return the loss
loss, state_out = mbqc_net(poly=obj_poly)
# Propagate loss backwards and optimize the parameters
loss.backward()
opt.minimize(loss)
opt.clear_grad()
if itr % 10 == 0:
print("iter:", itr, " loss_MBQC:", "%.4f" % loss.numpy())
end_time = perf_counter()
print("MBQC running time is: ", end_time - start_time)
# Print the optimization parameters
print("Optimal parameter gamma: ", mbqc_net.gamma.numpy())
print("Optimal parameter beta: ", mbqc_net.beta.numpy())
solu_str = get_solution_string(state_out, SHOTS)
# Evaluate the corresponding value
relation = {symbols('x_' + str(j + 1)): int(solu_str[j]) for j in range(var_num)}
value = poly_symbol.evalf(subs=relation)
# Return the solution and its corresponding value
opt = [solu_str, value]
return opt
此差异已折叠。
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
from paddle_quantum.mbqc.QKernel.qkernel import qkernel, compare_time, compare_result
def main():
r"""Kernel 主函数。
"""
# From 3 to 24, plot time
start_width = 3
end_width = 24
qkernel(start_width, end_width)
compare_time(start_width, end_width)
# Compare the probability distribution of outcome bit strings by multiple samplings
compare_result(3, 1024)
if __name__ == '__main__':
main()
The current example is: Quantum kernel method with 3 X 9 size.
The qubit number is: 3
MBQC running time is: 0.19433109999999987 s
Circuit model running time is: 0.1034025999999999 s
The current example is: Quantum kernel method with 4 X 9 size.
The qubit number is: 4
MBQC running time is: 0.28153490000000003 s
Circuit model running time is: 0.10754960000000002 s
The current example is: Quantum kernel method with 5 X 9 size.
The qubit number is: 5
MBQC running time is: 0.38240870000000005 s
Circuit model running time is: 0.12117860000000036 s
The current example is: Quantum kernel method with 6 X 9 size.
The qubit number is: 6
MBQC running time is: 0.49848729999999986 s
Circuit model running time is: 0.12079530000000016 s
The current example is: Quantum kernel method with 7 X 9 size.
The qubit number is: 7
MBQC running time is: 0.6529012000000001 s
Circuit model running time is: 0.1332924999999996 s
The current example is: Quantum kernel method with 8 X 9 size.
The qubit number is: 8
MBQC running time is: 0.7972115000000004 s
Circuit model running time is: 0.14146310000000017 s
The current example is: Quantum kernel method with 9 X 9 size.
The qubit number is: 9
MBQC running time is: 0.9908808999999996 s
Circuit model running time is: 0.15193749999999984 s
The current example is: Quantum kernel method with 10 X 9 size.
The qubit number is: 10
MBQC running time is: 1.2111211999999991 s
Circuit model running time is: 0.16549000000000014 s
The current example is: Quantum kernel method with 11 X 9 size.
The qubit number is: 11
MBQC running time is: 1.4613236 s
Circuit model running time is: 0.17382679999999873 s
The current example is: Quantum kernel method with 12 X 9 size.
The qubit number is: 12
MBQC running time is: 1.7479014999999993 s
Circuit model running time is: 0.19296899999999972 s
The current example is: Quantum kernel method with 13 X 9 size.
The qubit number is: 13
MBQC running time is: 2.0869981000000006 s
Circuit model running time is: 0.21488890000000005 s
The current example is: Quantum kernel method with 14 X 9 size.
The qubit number is: 14
MBQC running time is: 2.4556445999999976 s
Circuit model running time is: 0.25365719999999925 s
The current example is: Quantum kernel method with 15 X 9 size.
The qubit number is: 15
MBQC running time is: 2.8709384999999976 s
Circuit model running time is: 0.32052579999999864 s
The current example is: Quantum kernel method with 16 X 9 size.
The qubit number is: 16
MBQC running time is: 3.371537 s
Circuit model running time is: 0.46659409999999824 s
The current example is: Quantum kernel method with 17 X 9 size.
The qubit number is: 17
MBQC running time is: 3.850072300000001 s
Circuit model running time is: 0.7888110000000026 s
The current example is: Quantum kernel method with 18 X 9 size.
The qubit number is: 18
MBQC running time is: 4.468373900000003 s
Circuit model running time is: 1.5083874000000037 s
The current example is: Quantum kernel method with 19 X 9 size.
The qubit number is: 19
MBQC running time is: 5.124628200000004 s
Circuit model running time is: 2.865450800000005 s
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Use MBQC to simulate the circuit in quantum Kernel method and compare with the circuit model
"""
from paddle import to_tensor
from paddle_quantum.mbqc.utils import print_progress, plot_results
from paddle_quantum.mbqc.utils import write_running_data, read_running_data
from time import perf_counter
from paddle_quantum.mbqc.simulator import simulate_by_mbqc, sample_by_mbqc
from numpy import random
from paddle_quantum.mbqc.qobject import Circuit
from paddle_quantum.circuit import UAnsatz
__all__ = [
"qkernel_circuit",
"cir_uansatz",
"cir_mbqc",
"qkernel",
"compare_time",
"compare_result"
]
def qkernel_circuit(alpha, cir):
r"""输入量子核方法的电路。
Args:
alpha (Tensor): 旋转门的角度
cir (Circuit or UAnsatz): Circuit 或者 UAnsatz 的实例
Returns:
Circuit / UAnsatz: 构造的量子电路
"""
qubit_number = alpha.shape[0]
# U
for i in range(qubit_number):
if not isinstance(cir, Circuit):
cir.h(i)
cir.rx(alpha[i, 1], i)
cir.rz(alpha[i, 2], i)
cir.rx(alpha[i, 3], i)
# cz
for i in range(qubit_number - 1):
cir.h(i + 1)
cir.cnot([i, i + 1])
cir.h(i + 1)
# U^{\dagger}
for i in range(qubit_number):
cir.rx(alpha[i, 5], i)
cir.rz(alpha[i, 6], i)
cir.rx(alpha[i, 7], i)
cir.h(i)
# Measure
if isinstance(cir, Circuit):
cir.measure()
return cir
def cir_uansatz(alpha, shots=1):
r"""定义量子核方法的 UAnsatz 电路模型。
Args:
alpha (Tensor): 旋转门的角度
shots (int): 重复次数
Returns:
list: 列表中的第一项为测量结果,第二项为 UAnsatz 电路模型模拟方式运行量子核方法需要的时间
"""
qubit_number = alpha.shape[0]
# If bit_num >= 25, the UAnsatz could not support it
if qubit_number >= 25:
raise ValueError("the UAnsatz model could not support qubit number larger than 25 on a laptop.")
else:
cir = UAnsatz(qubit_number)
cir = qkernel_circuit(alpha, cir)
uansatz_start_time = perf_counter()
cir.run_state_vector()
outcome = cir.measure(shots=shots)
uansatz_end_time = perf_counter()
# As the outcome dictionary is in a messy order, we need to reorder the outcome
outcome_in_order = {bin(i)[2:].zfill(qubit_number): outcome[bin(i)[2:].zfill(qubit_number)]
if bin(i)[2:].zfill(qubit_number) in list(outcome.keys())
else 0 for i in range(2 ** qubit_number)}
result_and_time = [outcome_in_order, uansatz_end_time - uansatz_start_time]
return result_and_time
def cir_mbqc(alpha, shots=1):
r"""定义量子核方法的 MBQC 翻译电路模型。
Args:
alpha (Tensor): 旋转门的角度
shots (int): 重复次数
Returns:
list: 列表中的第一项为测量结果,第二项为依据行序优先算法优化翻译 MBQC 模型模拟量子核方法电路需要的时间
"""
# Input circuit
width = alpha.shape[0]
cir = Circuit(width)
cir = qkernel_circuit(alpha, cir)
# Start running
start_time = perf_counter()
# No sampling
if shots == 1:
simulate_by_mbqc(cir)
sample_outcomes = {}
# Sampling
else:
sample_outcomes, all_output = sample_by_mbqc(cir, shots=shots, print_or_not=True)
end_time = perf_counter()
result_and_time = [sample_outcomes, end_time - start_time]
return result_and_time
def qkernel(start_width, end_width):
r"""定义量子核方法的主函数。
在主函数中,我们比较了在不同宽度下 UAnsatz 电路模型模拟量子核方法和基于行序优先原则算法翻译为 MBQC 模型模拟量子核方法的时间。
Args:
start_width (int): 电路的起始宽度
end_width (int): 电路的终止宽度
"""
# Initialize
depth = 9 # Set the depth of circuit to 9
time_text = open("record_time.txt", 'w')
all_width = list(range(start_width, end_width))
# Start running Kernel under different qubit numbers
counter = 0
for width in all_width:
eg = "Quantum kernel method with " + str(width) + " X " + str(depth) + " size."
print_progress((counter + 1) / len(all_width), "Current Plot Progress")
counter += 1
alpha = random.randn(width, depth)
alpha_tensor = to_tensor(alpha, dtype='float64')
mbqc_result, mbqc_time = cir_mbqc(alpha_tensor)
uansatz_result, uansatz_time = cir_uansatz(alpha_tensor)
write_running_data(time_text, eg, width, mbqc_time, uansatz_time)
time_text.close()
def compare_time(start_width, end_width):
r"""定义量子核方法的画图函数。
此函数用于将 UAnsatz 电路模型模拟运行量子核方法的时间成本和基于行序优先原则算法翻译为 MBQC 模型模拟的时间画出来。
"""
time_comparison = read_running_data("record_time.txt")
bar_labels = ["MBQC", "UAnsatz"]
xticklabels = list(range(start_width, end_width))
title = "Kernel Example: Time comparison between MBQC and UAnsatz"
xlabel = "Circuit width"
ylabel = "Running time (s)"
plot_results(time_comparison, bar_labels, title, xlabel, ylabel, xticklabels)
def compare_result(qubit_number, shots=1024):
r"""定义量子核方法获得最终比特串的函数。
此函数的调用是为了获得量子核方法输出的最终比特串对应的字符。
对于量子电路模型,只需要获得演化后的量子态,并重复对该量子态进行多次测量,就可以获得输出比特串的概率分布。
MBQC 模型则与之不同,前文中所有 MBQC 模型的量子核方法都是仅运算一次得到的输出比特串,而并没有输出演化后量子态的信息。
因此,为了获得输出比特串的概率分布,我们需要对 MBQC 模型的整个过程重复执行多次,
统计这些次数中各个比特串出现的频率,从而用频率信息估算概率信息。
Note:
由于采样的次数有限,统计出的输出比特串频率分布会稍有偏差。
Args:
qubit_number (int): 比特数
shots (int, optional): 采样次数
"""
# Initialize
depth = 9
CRED = '\033[91m'
CEND = '\033[0m'
alpha = random.randn(qubit_number, depth)
alpha_tensor = to_tensor(alpha, dtype="float64")
mbqc_result, mbqc_time = cir_mbqc(alpha_tensor, shots)
uansatz_result, uansatz_time = cir_uansatz(alpha_tensor, shots)
print(CRED + "MBQC sampling results:" + CEND, mbqc_result)
print(CRED + "UAnsatz sampling results:" + CEND, uansatz_result)
result_comparison = [mbqc_result, uansatz_result]
bar_labels = ["MBQC", "UAnsatz"]
title = "Kernel Example: Comparison between MBQC and UAnsatz"
xlabel = "Measurement outcomes"
ylabel = "Distribution"
plot_results(result_comparison, bar_labels, title, xlabel, ylabel)
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
from paddle_quantum.mbqc.VQSVD.vqsvd import vqsvd, compare_time, compare_result
def main():
r"""VQSVD 主函数。
"""
# From 3 to 24, plot time
start_qubit = 3
end_qubit = 24
vqsvd(start_qubit, end_qubit)
compare_time(start_qubit, end_qubit)
# Compare the probability distribution of outcome bit strings by multiple samplings
compare_result(3, 1024)
if __name__ == '__main__':
main()
The current example is: VQSVD with 3 X 2 size.
The qubit number is: 3
MBQC running time is: 0.13685639999999966 s
Circuit model running time is: 0.10096300000000014 s
The current example is: VQSVD with 4 X 2 size.
The qubit number is: 4
MBQC running time is: 0.18013259999999987 s
Circuit model running time is: 0.09092929999999999 s
The current example is: VQSVD with 5 X 2 size.
The qubit number is: 5
MBQC running time is: 0.2437035999999999 s
Circuit model running time is: 0.09389560000000019 s
The current example is: VQSVD with 6 X 2 size.
The qubit number is: 6
MBQC running time is: 0.32366709999999976 s
Circuit model running time is: 0.11702480000000026 s
The current example is: VQSVD with 7 X 2 size.
The qubit number is: 7
MBQC running time is: 0.3896693 s
Circuit model running time is: 0.09745869999999979 s
The current example is: VQSVD with 8 X 2 size.
The qubit number is: 8
MBQC running time is: 0.46406170000000024 s
Circuit model running time is: 0.1019085000000004 s
The current example is: VQSVD with 9 X 2 size.
The qubit number is: 9
MBQC running time is: 0.5693280999999999 s
Circuit model running time is: 0.10031949999999945 s
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Use MBQC to simulate VQSVD circuit and compare with the circuit model
"""
from paddle import to_tensor
from paddle_quantum.mbqc.utils import print_progress, write_running_data, read_running_data, plot_results
from time import perf_counter
from paddle_quantum.mbqc.simulator import simulate_by_mbqc, sample_by_mbqc
from numpy import random
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.mbqc.qobject import Circuit
__all__ = [
"vqsvd_circuit",
"cir_uansatz",
"cir_mbqc",
"vqsvd",
"compare_time",
"compare_result"
]
def vqsvd_circuit(cir, alpha):
r"""输入 VQSVD 算法的电路。
Args:
cir (Circuit or UAnsatz): Circuit 为 MBQC 电路模块中的类,UAnsatz 为量桨平台 UAnsatz 电路模型中的类,
二者都具有相同的量子门输入方式
alpha (Tensor): 旋转门的角度
Returns:
Circuit / UAnsatz: 输入了量子门信息的电路
"""
width = alpha.shape[0]
depth = alpha.shape[1]
if not isinstance(cir, Circuit):
for which_qubit in range(width):
cir.h(which_qubit)
for layer_num in range(depth):
for which_qubit in range(width):
cir.ry(alpha[which_qubit, layer_num], which_qubit)
for which_qubit in range(width - 1):
cir.cnot([which_qubit, which_qubit + 1])
if isinstance(cir, Circuit):
cir.measure()
return cir
def cir_uansatz(alpha, shots=1):
r"""定义 VQSVD 算法的 UAnsatz 电路模型。
Args:
alpha (Tensor): 旋转门的角度
shots (int, optional): 重复次数
Returns:
list: 列表中的第一项为测量结果或运算后得到的量子态,第二项为电路模拟方式运行 VQSVD 算法需要的时间
"""
qubit_number = alpha.shape[0]
# If bit_num >= 25, the UAnsatz could not support it
if qubit_number >= 25:
raise ValueError("the UAnsatz model could not support qubit number larger than 25 on a laptop.")
else:
# Input information of circuits
cir = UAnsatz(qubit_number)
cir = vqsvd_circuit(cir, alpha)
# Start running
uansatz_start_time = perf_counter()
cir.run_state_vector()
outcome = cir.measure(shots=shots)
uansatz_end_time = perf_counter()
# As the outcome dictionary is in a messy order, we need to reorder the outcome
outcome_in_order = {bin(i)[2:].zfill(qubit_number): outcome[bin(i)[2:].zfill(qubit_number)]
if bin(i)[2:].zfill(qubit_number) in list(outcome.keys())
else 0 for i in range(2 ** qubit_number)}
result_and_time = [outcome_in_order, uansatz_end_time - uansatz_start_time]
return result_and_time
def cir_mbqc(alpha, shots=1):
r"""定义 VQSVD 算法的 MBQC 翻译模拟方式。
Args:
alpha (Tensor): 旋转门的角度
Returns:
list: 列表中的第一项为测量结果或运算后得到的量子态,第二项为依据行序优先算法优化翻译 MBQC 模型模拟 VQSVD 电路需要的时间
"""
qubit_number = alpha.shape[0]
# Run MBQC
cir = Circuit(qubit_number)
cir = vqsvd_circuit(cir, alpha)
start_time = perf_counter()
# No sampling
if shots == 1:
simulate_by_mbqc(cir)
sample_outcomes = {}
# Sampling
else:
sample_outcomes, all_output = sample_by_mbqc(cir, shots=shots, print_or_not=True)
end_time = perf_counter()
result_list = [sample_outcomes, end_time - start_time]
return result_list
def vqsvd(start_width, end_width):
r"""定义 VQSVD 算法的主函数。
在主函数中,我们比较了在不同宽度下 UAnsatz 电路模型模拟 VQSVD 和基于行序优先原则算法翻译为 MBQC 模型模拟 VQSVD 的时间。
Args:
start_width (int): 电路的起始宽度
end_width (int): 电路的终止宽度
"""
# Initialize
depth = 2 # Set the depth of circuit to 2
time_text = open("record_time.txt", 'w')
all_width = list(range(start_width, end_width))
# Start running VQSVD under different qubit numbers
counter = 0
for width in all_width:
eg = "VQSVD with " + str(width) + " X " + str(depth) + " size."
print_progress((counter + 1) / len(all_width), "Current Plot Progress")
counter += 1
alpha = random.randn(width, depth)
alpha_tensor = to_tensor(alpha, dtype='float64')
mbqc_result, mbqc_time = cir_mbqc(alpha_tensor)
uansatz_result, uansatz_time = cir_uansatz(alpha_tensor)
write_running_data(time_text, eg, width, mbqc_time, uansatz_time)
time_text.close()
def compare_time(start_width, end_width):
r"""定义 VQSVD 的画图函数。
此函数用于将 UAnsatz 电路模型模拟运行 VQSVD 的时间成本和基于行序优先原则算法翻译为 MBQC 模型模拟的时间画出来。
"""
time_comparison = read_running_data("record_time.txt")
bar_labels = ['MBQC', 'UAnsatz']
xticklabels = list(range(start_width, end_width))
title = 'VQSVD Example: Time comparison between MBQC and UAnsatz'
xlabel = 'Circuit width'
ylabel = 'Running time (s)'
plot_results(time_comparison, bar_labels, title, xlabel, ylabel, xticklabels)
def compare_result(qubit_number, shots=1024):
r"""定义 VQSVD 获得最终比特串的函数。
此函数的调用是为了获得 VQSVD 输出的最终比特串对应的字符。
对于量子电路模型,只需要获得演化后的量子态,并重复对该量子态进行测量多次,就可以获得输出比特串的概率分布。
MBQC 模型则与之不同,前文中所有 MBQC 模型的 VQSVD 都是仅运算一次得到的输出比特串,而并没有输出演化后量子态的信息。
因此,为了获得输出比特串的概率分布,我们需要对 MBQC 模型的整个过程重复执行多次,
统计这些次数中各个比特串出现的频率,从而用频率信息估算概率信息。
Note:
由于采样的次数有限,统计出的输出比特串频率分布会稍有偏差。
Args:
qubit_number (int): 比特数
shots (int, optional): 采样次数
"""
# Initialize
depth = 2 # Set the depth of circuit to 2
CRED = '\033[91m'
CEND = '\033[0m'
alpha = random.randn(qubit_number, depth)
alpha_tensor = to_tensor(alpha, dtype="float64")
mbqc_result, mbqc_time = cir_mbqc(alpha_tensor, shots)
uansatz_result, uansatz_time = cir_uansatz(alpha_tensor, shots)
print(CRED + "MBQC sampling results:" + CEND, mbqc_result, "s")
print(CRED + "UAnsatz sampling results:" + CEND, uansatz_result, "s")
result_comparison = [mbqc_result, uansatz_result]
bar_labels = ['MBQC', 'UAnsatz']
title = "VQSVD Example: Comparison btween MBQC and UAnsatz"
xlabel = "Measurement outcomes"
ylabel = "Distribution"
plot_results(result_comparison, bar_labels, title, xlabel, ylabel)
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
CNOT test
"""
from paddle_quantum.mbqc.utils import random_state_vector, compare_by_vector, compare_by_density
from paddle_quantum.mbqc.simulator import MBQC
from paddle_quantum.mbqc.qobject import Circuit, State
from paddle_quantum.mbqc.mcalculus import MCalculus
from paddle_quantum.circuit import UAnsatz
n = 2 # Set the circuit width
# Generate a random state vector
input_psi = random_state_vector(2, is_real=False)
# Instantiate a Circuit class
cir = Circuit(n)
# There are two patterns for CNOT gate, one is the 4-nodes pattern, the other is the 15-nodes pattern
# We can use CNOT gate in definite pattern that we want
# cir.cnot([0,1]) # CNOT pattern with 4 - nodes
cir.cnot_15([0, 1]) # CNOT pattern with 15 - nodes
# Instantiate a MCalculus class
mc = MCalculus()
mc.set_circuit(cir)
# If we want to do pattern standardization, signal shifting, measurement order optimization,
# we can use the following lines in order. However, as one CNOT gate is already a standardized pattern itself,
# there is no need to do so.
# mc.standardize()
# mc.shift_signals()
# mc.optimize_by_row()
pattern = mc.get_pattern()
# Instantiate a MBQC class
mbqc = MBQC()
mbqc.set_pattern(pattern)
# mbqc.draw_process(draw=True)
mbqc.set_input_state(State(input_psi, [0, 1]))
# Run computation by pattern
mbqc.run_pattern()
# Obtain the output state
state_out = mbqc.get_quantum_output()
# Find the standard result
cir_std = UAnsatz(n)
cir_std.cnot([0, 1])
vec_std = cir_std.run_state_vector(input_psi.astype("complex128"))
system_std = state_out.system
state_std = State(vec_std, system_std)
# Compare with the standard result in UAnsatz
compare_by_vector(state_out, state_std)
compare_by_density(state_out, state_std)
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from numpy import random, pi
from paddle import to_tensor
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.mbqc.simulator import MBQC
from paddle_quantum.mbqc.transpiler import transpile
from paddle_quantum.mbqc.qobject import Circuit, State
from paddle_quantum.mbqc.utils import random_state_vector, compare_by_vector, compare_by_density
n = 5 # Set the circuit width
theta = to_tensor(random.rand(n) * 2 * pi, dtype='float64') # Generate random angles
# Instantiate a Circuit class
cir_mbqc = Circuit(n)
# Instantiate a UAnsatz class
cir_ansatz = UAnsatz(n)
# Construct a circuit
for cir in [cir_mbqc, cir_ansatz]:
for i in range(n):
cir.h(i)
cir.rx(theta[i], i)
cir.cnot([0, 1])
for i in range(n):
cir.ry(theta[i], i)
cir.rz(theta[i], i)
# Generate a random state vector
input_psi = random_state_vector(n, is_real=False)
# Transpile circuit to measurement pattern
pattern = transpile(cir_mbqc)
mbqc = MBQC()
mbqc.set_pattern(pattern)
mbqc.set_input_state(State(input_psi, list(range(n))))
mbqc.run_pattern()
# Obtain the output state
state_out = mbqc.get_quantum_output()
# Find the standard result
vec_ansatz = cir_ansatz.run_state_vector(input_psi.astype("complex128"))
system_ansatz = state_out.system
state_ansatz = State(vec_ansatz, system_ansatz)
compare_by_vector(state_out, state_ansatz)
compare_by_density(state_out, state_ansatz)
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Single qubit unitary gate test with random angle
"""
from numpy import pi, random
from paddle import to_tensor, matmul
from paddle_quantum.mbqc.utils import random_state_vector, rotation_gate, compare_by_vector
from paddle_quantum.mbqc.simulator import MBQC
from paddle_quantum.mbqc.qobject import Circuit, State
from paddle_quantum.mbqc.mcalculus import MCalculus
# Set qubit number
n = 1
# Input vector and label
# If we want to choose an input state randomly, we can use ``random_state_vector``
input_psi = random_state_vector(1, is_real=False)
# To be simplify, here we choose "|+>" as the input vector
# input_vec = plus_state()
# Default that 'alpha' represents the initial rotation gates' angles without adaptive constants
# Default that 'theta' represents the adaptive measurement angles
# Set 'alpha'
alpha = to_tensor([2 * pi * random.uniform()], dtype='float64')
beta = to_tensor([2 * pi * random.uniform()], dtype='float64')
gamma = to_tensor([2 * pi * random.uniform()], dtype='float64')
# Note: Here the parameters are not equal to those in UAnsatz circuit's "U3".
# Indeed, we decompose unitary matrix as U = Rz Rx Rz instead of U = Rz Ry Rz in UAnsatz
params = [alpha, beta, gamma]
# Initialize circuit
cir = Circuit(n)
cir.u(params, 0)
# circuit = cir.get_circuit()
# Initialize pattern
pat = MCalculus()
pat.set_circuit(cir)
# If we want to standardize the circuit, shift signals or optimize the circuit, we can use the following lines
# Note: As one CNOT gate has already been a standardized pattern, there is no need to do so.
# pat.standardize()
# pat.shift_signals()
# pat.optimize_by_row()
pattern = pat.get_pattern()
# Initialize MBQC
mbqc = MBQC()
mbqc.set_pattern(pattern)
mbqc.set_input_state(State(input_psi, [0]))
# If we want to plot the process of measurement, we can call th function ``mbqc.plot()``
# mbqc.plot(pause_time=1.0)
# Run by pattern
mbqc.run_pattern()
# Acquire the output state
state_out = mbqc.get_quantum_output()
# Compare with the standard result
vec_std = matmul(rotation_gate('z', gamma),
matmul(rotation_gate('x', beta),
matmul(rotation_gate('z', alpha), input_psi)))
system_label = state_out.system
state_std = State(vec_std, system_label)
compare_by_vector(state_out, state_std)
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
CNOT test
"""
from paddle import to_tensor, matmul
from paddle_quantum.mbqc.utils import pauli_gate, cnot_gate, basis, random_state_vector
from paddle_quantum.mbqc.utils import compare_by_vector, compare_by_density
from paddle_quantum.mbqc.simulator import MBQC
from paddle_quantum.mbqc.qobject import State
X = pauli_gate('X')
Z = pauli_gate('Z')
X_basis = basis('X')
Y_basis = basis('Y')
# Construct the underlying graph of CNOT implementation in MBQC
V = [str(i) for i in range(1, 16)]
E = [('1', '2'), ('2', '3'), ('3', '4'), ('4', '5'),
('5', '6'), ('6', '7'), ('4', '8'), ('8', '12'),
('9', '10'), ('10', '11'), ('11', '12'),
('12', '13'), ('13', '14'), ('14', '15')]
G = [V, E]
# Generate a random state vector
input_psi = random_state_vector(2, is_real=False)
# Instantiate a MBQC class
mbqc = MBQC()
# Set the underlying graph for computation
mbqc.set_graph(G)
# Set the input state
mbqc.set_input_state(State(input_psi, ['1', '9']))
# Watch the computational process
# mbqc.draw_process()
# Start measurement process
mbqc.measure('1', X_basis)
mbqc.measure('2', Y_basis)
mbqc.measure('3', Y_basis)
mbqc.measure('4', Y_basis)
mbqc.measure('5', Y_basis)
mbqc.measure('6', Y_basis)
mbqc.measure('8', Y_basis)
mbqc.measure('9', X_basis)
mbqc.measure('10', X_basis)
mbqc.measure('11', X_basis)
mbqc.measure('12', Y_basis)
mbqc.measure('13', X_basis)
mbqc.measure('14', X_basis)
# Obtain byproduct's exponents
cx = mbqc.sum_outcomes(['2', '3', '5', '6'])
tx = mbqc.sum_outcomes(['2', '3', '8', '10', '12', '14'])
cz = mbqc.sum_outcomes(['1', '3', '4', '5', '8', '9', '11'], 1)
tz = mbqc.sum_outcomes(['9', '11', '13'])
# Correct byproducts
mbqc.correct_byproduct('X', '7', cx)
mbqc.correct_byproduct('X', '15', tx)
mbqc.correct_byproduct('Z', '7', cz)
mbqc.correct_byproduct('Z', '15', tz)
# Obtain the output state
state_out = mbqc.get_quantum_output()
# Find the standard result
vec_std = matmul(to_tensor(cnot_gate()), input_psi)
system_std = ['7', '15']
state_std = State(vec_std, system_std)
# Compare with the standard result
compare_by_vector(state_out, state_std)
compare_by_density(state_out, state_std)
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Single qubit unitary gate test with random angle
"""
from numpy import pi, random
from paddle import to_tensor, matmul
from paddle_quantum.mbqc.utils import random_state_vector, rotation_gate, basis
from paddle_quantum.mbqc.utils import compare_by_vector, compare_by_density
from paddle_quantum.mbqc.simulator import MBQC
from paddle_quantum.mbqc.qobject import State
# Construct the underlying graph of single-qubit implementation in MBQC
G = [['1', '2', '3', '4', '5'], [('1', '2'), ('2', '3'), ('3', '4'), ('4', '5')]]
# Generate a random state vector
input_vec = random_state_vector(1, is_real=False)
# Suppose the single-qubit gate is decomposed by Rx(alpha_4) Rz(alpha_3) Rx(alpha_2)
alpha_1 = 0
alpha_2 = pi * random.uniform()
alpha_3 = pi * random.uniform()
alpha_4 = pi * random.uniform()
# Instantiate a MBQC class
mbqc = MBQC()
# Set the underlying graph for computation
mbqc.set_graph(G)
# Set the input state
mbqc.set_input_state(State(input_vec, ['1']))
# Watch the computational process
# mbqc.draw_process(pause_time=1.0)
# Set the measurement angles
# Measure qubit '1', with "theta = alpha"
theta_1 = alpha_1
theta_1 = to_tensor([theta_1], dtype='float64')
mbqc.measure('1', basis('XY', theta_1))
# Measure qubit '2', with "theta = (-1)^{s_1 + 1} * alpha"
theta_2 = (-1) ** mbqc.sum_outcomes(['1'], 1) * alpha_2
theta_2 = to_tensor([theta_2], dtype='float64')
mbqc.measure('2', basis('XY', theta_2))
# Measure qubit '3', with "theta = (-1)^{s_2 + 1} * alpha"
theta_3 = (-1) ** mbqc.sum_outcomes(['2'], 1) * alpha_3
theta_3 = to_tensor([theta_3], dtype='float64')
mbqc.measure('3', basis('XY', theta_3))
# Measure qubit '4', with "theta = (-1)^{s_1 + s_3 + 1} * alpha"
theta_4 = (-1) ** mbqc.sum_outcomes(['1', '3'], 1) * alpha_4
theta_4 = to_tensor([theta_4], dtype='float64')
mbqc.measure('4', basis('XY', theta_4))
# Correct byproduct operators
mbqc.correct_byproduct('X', '5', mbqc.sum_outcomes(['2', '4']))
mbqc.correct_byproduct('Z', '5', mbqc.sum_outcomes(['1', '3']))
# Obtain the output state
state_out = mbqc.get_quantum_output()
# Find the standard result
vec_std = matmul(rotation_gate('x', to_tensor([alpha_4], dtype='float64')),
matmul(rotation_gate('z', to_tensor([alpha_3], dtype='float64')),
matmul(rotation_gate('x', to_tensor([alpha_2], dtype='float64')), input_vec)))
system_std = ['5']
state_std = State(vec_std, system_std)
# Compare with the standard result
compare_by_vector(state_out, state_std)
compare_by_density(state_out, state_std)
此差异已折叠。
此差异已折叠。
此差异已折叠。
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
此模块包含电路模型和 MBQC 测量模式的转义工具。
"""
from paddle_quantum.mbqc.qobject import Circuit
from paddle_quantum.mbqc.mcalculus import MCalculus
__all__ = [
"transpile"
]
def transpile(circuit, track=False):
r"""将输入的量子电路翻译为等价的测量模式。
Args:
circuit (Circuit): 量子电路,包含可能的测量部分
track (bool): 是否显示翻译进度条的开关
Returns:
pattern (Pattern): 等价的测量模式
"""
assert isinstance(circuit, Circuit), "'circuit' must be of type 'Circuit'."
assert isinstance(track, bool), "'track' must be a 'bool'."
mc = MCalculus()
if track:
mc.track_progress()
mc.set_circuit(circuit)
mc.standardize()
mc.shift_signals()
mc.optimize_by_row()
pattern = mc.get_pattern()
return pattern
此差异已折叠。
此差异已折叠。
......@@ -44,6 +44,7 @@ def shadow_sample(state, num_qubits, sample_shots, mode, hamiltonian=None, metho
代码示例:
.. code-block:: python
from paddle_quantum.shadow import shadow_sample
from paddle_quantum.state import vec_random
from paddle_quantum.utils import Hamiltonian
......@@ -55,8 +56,8 @@ def shadow_sample(state, num_qubits, sample_shots, mode, hamiltonian=None, metho
ham = [[0.1, 'x1'], [0.2, 'y0']]
ham = Hamiltonian(ham)
sample_data_lbcs, beta_lbcs = shadow_sample(state, n_qubit, sample_shots, 'state_vector', "LBCS", ham)
sample_data_aps = shadow_sample(state, n_qubit, sample_shots, 'state_vector', "APS", ham)
sample_data_lbcs, beta_lbcs = shadow_sample(state, n_qubit, sample_shots, 'state_vector', ham, "LBCS")
sample_data_aps = shadow_sample(state, n_qubit, sample_shots, 'state_vector', ham, "APS")
print('sample data CS = ', sample_data_cs)
print('sample data LBCS = ', sample_data_lbcs)
......
此差异已折叠。
此差异已折叠。
paddlepaddle>=2.1.1
scipy
networkx>=2.5
matplotlib
matplotlib>=3.3.0
interval
tqdm
\ No newline at end of file
fastdtw
\ No newline at end of file
此差异已折叠。
......@@ -153,7 +153,8 @@
"source": [
"num_assets = 3 #可选择股票数目\n",
"stocks = [(\"TICKER%s\" % i) for i in range(num_assets)]\n",
"data = DataSimulator( stocks = stocks, start = datetime.datetime(2016, 1, 1), end = datetime.datetime(2016, 1, 30)) # 根据指定的条件,随机生成测试所需的数据"
"data = DataSimulator( stocks = stocks, start = datetime.datetime(2016, 1, 1), end = datetime.datetime(2016, 1, 30)) \n",
"data.randomly_generate() # 随机生成实验数据"
],
"outputs": [],
"metadata": {}
......
......@@ -132,8 +132,8 @@
"source": [
"num_assets = 7 # 可投资的项目数量\n",
"stocks = [(\"STOCK%s\" % i) for i in range(num_assets)] \n",
"data = DataSimulator(stocks=stocks, start=datetime.datetime(2016, 1, 1), end=datetime.datetime(2016, 1, 30)) # 根据指定的条件,随机生成测试所需的数据\n",
"ds = data.randomly_generate()"
"data = DataSimulator(stocks=stocks, start=datetime.datetime(2016, 1, 1), end=datetime.datetime(2016, 1, 30)) \n",
"data.randomly_generate() # 随机生成实验数据"
],
"outputs": [],
"metadata": {}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册