提交 01bee618 编写于 作者: Q Quleaf

update to v1.2.0

上级 166e0cbd
......@@ -18,25 +18,53 @@ English | [简体中文](README_CN.md)
- [Copyright and License](#copyright-and-license)
- [References](#references)
Paddle Quantum (量桨) is a quantum machine learning (QML) toolkit developed based on Baidu PaddlePaddle. It provides a platform to construct and train quantum neural networks (QNNs) with easy-to-use QML development kits suporting combinatorial optimization, quantum chemistry and other cutting-edge quantum applications, making PaddlePaddle the first and only deep learning framework in China that supports quantum machine learning.
[Paddle Quantum (量桨)](https://qml.baidu.com/) is a quantum machine learning (QML) toolkit developed based on Baidu PaddlePaddle. It provides a platform to construct and train quantum neural networks (QNNs) with easy-to-use QML development kits suporting combinatorial optimization, quantum chemistry and other cutting-edge quantum applications, making PaddlePaddle the first and only deep learning framework in China that supports quantum machine learning.
<p align="center">
<a href="https://qml.baidu.com/">
<img width=80% src="https://release-data.cdn.bcebos.com/Paddle%20Quantum.png">
</a>
</p>
<p align="center">
<!-- docs -->
<a href="https://qml.baidu.com/api/paddle_quantum.circuit.html">
<img src="https://img.shields.io/badge/docs-link-green.svg?style=flat-square&logo=read-the-docs"/>
</a>
<!-- PyPI -->
<a href="https://pypi.org/project/paddle-quantum/">
<img src="https://img.shields.io/badge/pypi-v1.2.0-orange.svg?style=flat-square&logo=pypi"/>
</a>
<!-- Python -->
<a href="https://www.python.org/">
<img src="https://img.shields.io/badge/Python-3.6+-blue.svg?style=flat-square&logo=python"/>
</a>
<!-- License -->
<a href="./LICENSE">
<img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square&logo=apache"/>
</a>
<!-- Platform -->
<a href="https://github.com/PaddlePaddle/Quantum">
<img src="https://img.shields.io/badge/OS-MacOS%20|%20Windows%20|%20Linux-lightgrey.svg?style=flat-square"/>
</a>
</p>
![](https://release-data.cdn.bcebos.com/Paddle%20Quantum.png)
Paddle Quantum aims at establishing a bridge between artificial intelligence (AI) and quantum computing (QC). It has been utilized for developing several quantum machine learning applications. With the PaddlePaddle deep learning platform empowering QC, Paddle Quantum provides strong support for scientific research community and developers in the field to easily develop QML applications. Moreover, it provides a learning platform for quantum computing enthusiasts.
## Features
- Easy-to-use
- Build quantum neural networks efficiently
- Various quantum neural network templates
- 10+ QML algorithm tutorials
- Scalability
- Support universal quantum circuit model
- Provide multiple optimization tools and GPU mode
- High-performance simulator that supports more than 20 qubits
- Many online learning resources (16+ tutorials)
- High efficiency in building QNN with various QNN templates
- Automatic differentiation
- Versatile
- Multiple optimization tools and GPU mode
- Simulation with 25+ qubits
- Featured Toolkits
- Provides computational toolboxes in cutting-edge fields such as combinatorial optimization and quantum chemistry
- Self-innovated quantum machine learning algorithms
- Toolboxes for Chemistry & Optimization
- LOCCNet for distributed quantum information processing
- Self-developed QML algorithms
## Install
......@@ -72,7 +100,7 @@ pip install openfermion==0.11.0
pip install openfermionpyscf==0.4
```
### Run programs
### 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.
......@@ -97,20 +125,26 @@ python main.py
### Tutorials
We provide tutorials covering combinatorial optimization, quantum chemistry, quantum classification 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,
1. [Quantum Approximation Optimization Algorithm (QAOA)](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/QAOA)
2. [Variational Quantum Eigensolver (VQE)](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/VQE)
3. [Quantum Classifier](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/Q-Classifier)
4. [The Barren Plateaus Phenomenon on Quantum Neural Networks (Barren Plateaus)](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/Barren)
5. [Quantum Autoencoder](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/Q-Autoencoder)
6. [Quantum GAN](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/Q-GAN)
7. [Subspace Search-Quantum Variational Quantum Eigensolver (SSVQE)](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/SSVQE)
8. [Variational Quantum State Diagonalization (VQSD)](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/VQSD)
9. [Gibbs State Preparation](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/Gibbs)
10. [Variational Quantum Singular Value Decomposition (VQSVD)](https://github.com/PaddlePaddle/Quantum/blob/master/tutorial/VQSVD)
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](https://github.com/PaddlePaddle/Quantum/blob/master/introduction/PaddleQuantum_GPU_EN.ipynb).
We provide tutorials covering combinatorial optimization, quantum chemistry, quantum classification, quantum entanglement manipulation 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,
1. [Quantum Approximation Optimization Algorithm (QAOA)](./tutorial/QAOA)
2. [Variational Quantum Eigensolver (VQE)](./tutorial/VQE)
3. [Quantum Classifier](./tutorial/Q-Classifier)
4. [The Barren Plateaus Phenomenon on Quantum Neural Networks (Barren Plateaus)](./tutorial/Barren)
5. [Quantum Autoencoder](./tutorial/Q-Autoencoder)
6. [Quantum GAN](./tutorial/Q-GAN)
7. [Subspace Search-Quantum Variational Quantum Eigensolver (SSVQE)](./tutorial/SSVQE)
8. [Variational Quantum State Diagonalization (VQSD)](./tutorial/VQSD)
9. [Gibbs State Preparation](./tutorial/Gibbs)
10. [Variational Quantum Singular Value Decomposition (VQSVD)](./tutorial/VQSVD)
11. [Local Operations and Classical Communication in QNN (LOCCNet)](./tutorial/LOCC/LOCCNET_Tutorial_EN.ipynb)
12. [Entanglement Distillation -- the BBPSSW protocol](./tutorial/LOCC)
13. [Entanglement Distillation -- the DEJMPS protocol](./tutorial/LOCC)
14. [Entanglement Distillation -- Protocol design with LOCCNet](./tutorial/LOCC)
15. [Quantum Teleportation](./tutorial/LOCC)
16. [Quantum State Discrimination](./tutorial/LOCC)
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).
### API documentation
......
......@@ -19,24 +19,51 @@
- [Copyright and License](#copyright-and-license)
- [References](#references)
Paddle Quantum(量桨)是基于百度飞桨开发的量子机器学习工具集,支持量子神经网络的搭建与训练,提供易用的量子机器学习开发套件与量子优化、量子化学等前沿量子应用工具集,使得百度飞桨也因此成为国内首个目前也是唯一一个支持量子机器学习的深度学习框架。
![](https://release-data.cdn.bcebos.com/Paddle%20Quantum.png)
[Paddle Quantum(量桨)](https://qml.baidu.com/)是基于百度飞桨开发的量子机器学习工具集,支持量子神经网络的搭建与训练,提供易用的量子机器学习开发套件与量子优化、量子化学等前沿量子应用工具集,使得百度飞桨也因此成为国内首个目前也是唯一一个支持量子机器学习的深度学习框架。
<p align="center">
<a href="https://qml.baidu.com/">
<img width=80% src="https://release-data.cdn.bcebos.com/Paddle%20Quantum.png">
</a>
</p>
<p align="center">
<!-- docs -->
<a href="https://qml.baidu.com/api/paddle_quantum.circuit.html">
<img src="https://img.shields.io/badge/docs-link-green.svg?style=flat-square&logo=read-the-docs"/>
</a>
<!-- PyPI -->
<a href="https://pypi.org/project/paddle-quantum/">
<img src="https://img.shields.io/badge/pypi-v1.2.0-orange.svg?style=flat-square&logo=pypi"/>
</a>
<!-- Python -->
<a href="https://www.python.org/">
<img src="https://img.shields.io/badge/Python-3.6+-blue.svg?style=flat-square&logo=python"/>
</a>
<!-- License -->
<a href="./LICENSE">
<img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square&logo=apache"/>
</a>
<!-- Platform -->
<a href="https://github.com/PaddlePaddle/Quantum">
<img src="https://img.shields.io/badge/OS-MacOS%20|%20Windows%20|%20Linux-lightgrey.svg?style=flat-square"/>
</a>
</p>
量桨建立起了人工智能与量子计算的桥梁,不但可以快速实现量子神经网络的搭建与训练,还提供易用的量子机器学习开发套件与量子优化、量子化学等前沿量子应用工具集,并提供多项自研量子机器学习应用。通过百度飞桨深度学习平台赋能量子计算,量桨为领域内的科研人员以及开发者便捷地开发量子人工智能的应用提供了强有力的支撑,同时也为广大量子计算爱好者提供了一条可行的学习途径。
## 特色
- 易用性
- 高效搭建量子神经网络
- 多种量子神经网络模板
- 丰富的量子算法教程(10+用例)
- 可拓展性
- 支持通用量子电路模型
- 高性能模拟器支持20多个量子比特的模拟运算
- 提供多种优化工具和 GPU 加速
- 轻松上手
- 丰富的在线学习资源(16+ 教程案例)
- 通过模板高效搭建量子神经网络
- 自动微分框架
- 功能丰富
- 提供多种优化工具和 GPU 模式
- 高性能模拟器支持25+量子比特的模拟运算
- 特色工具集
- 提供组合优化和量子化学等前沿领域的计算工具箱
- 分布式量子信息处理模组 LOCCNet
- 自研多种量子机器学习算法
## 安装步骤
......@@ -61,11 +88,11 @@ pip install -e .
```
### 使用 openfermion 读取 xyz 描述文件
### 使用 OpenFermion 读取 .xyz 描述文件
> 仅在 macOS 和 linux 下可以使用 openfermion 读取 xyz 描述文件。
> 仅在 macOS 和 linux 下可以使用 OpenFermion 读取 .xyz 描述文件。
VQE中调用 openfermion 读取分子 xyz 文件并计算,因此需要安装 openfermion 和 openfermionpyscf。
VQE中调用 OpenFermion 读取分子 .xyz 文件并计算,因此需要安装 openfermion 和 openfermionpyscf。
```bash
pip install openfermion==0.11.0
......@@ -103,20 +130,26 @@ python main.py
Paddle Quantum(量桨)建立起了人工智能与量子计算的桥梁,为量子机器学习领域的研发提供强有力的支撑,也提供了丰富的案例供开发者学习。
在这里,我们提供了涵盖量子优化、量子化学、量子机器学习等多个领域的案例供大家学习。每个教程目前支持网页阅览和运行 Jupyter Notebook 两种方式。我们推荐用户下载 Notebook 后,本地运行进行实践。
在这里,我们提供了涵盖量子优化、量子化学、量子机器学习、量子纠缠处理等多个领域的案例供大家学习。每个教程目前支持网页阅览和运行 Jupyter Notebook 两种方式。我们推荐用户下载 Notebook 后,本地运行进行实践。
- [量子近似优化算法 (QAOA)](./tutorial/QAOA)
- [变分量子特征求解器 (VQE)](./tutorial/VQE)
- [量子神经网络的贫瘠高原效应 (Barren Plateaus)](./tutorial/Barren)
- [量子分类器 (Quantum Classifier)](./tutorial/Q-Classifier)
- [量子神经网络的贫瘠高原效应 (Barren Plateaus)](./tutorial/Barren)
- [量子变分自编码器 (Quantum Autoencoder)](./tutorial/Q-Autoencoder)
- [量子生成对抗网络 (Quantum GAN)](./tutorial/Q-GAN)
- [子空间搜索 - 量子变分特征求解器 (SSVQE)](./tutorial/SSVQE)
- [变分量子态对角化算法 (VQSD)](./tutorial/VQSD)
- [吉布斯态的制备 (Gibbs State Preparation)](./tutorial/Gibbs)
- [变分量子奇异值分解 (VQSVD)](./tutorial/VQSVD)
此外,Paddle Quantum 也支持在 GPU 上进行量子机器学习的训练,具体的方法请参考案例:[在 GPU 上使用 Paddle Quantum](./introduction/PaddleQuantum_GPU_CN.ipynb)
- [LOCC 量子神经网络](./tutorial/LOCC/LOCCNET_Tutorial_CN.ipynb)
- [纠缠蒸馏 -- BBPSSW 协议](./tutorial/LOCC)
- [纠缠蒸馏 -- DEJMPS 协议](./tutorial/LOCC)
- [纠缠蒸馏 -- LOCCNet 设计协议](./tutorial/LOCC)
- [量子隐态传输](./tutorial/LOCC)
- [量子态分辨](./tutorial/LOCC)
随着 LOCCNet 模组的推出,量桨现已支持分布式量子信息处理任务的高效模拟和开发。感兴趣的读者请参见[教程](./tutorial/LOCC/LOCCNET_Tutorial_CN.ipynb)。此外,Paddle Quantum 也支持在 GPU 上进行量子机器学习的训练,具体的方法请参考案例:[在 GPU 上使用 Paddle Quantum](./introduction/PaddleQuantum_GPU_CN.ipynb)
### API 文档
......
......@@ -1503,7 +1503,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.8"
"version": "3.7.9"
},
"toc": {
"base_numbering": 1,
......
......@@ -17,3 +17,4 @@ Paddle Quantum Library
"""
name = "paddle_quantum"
__version__= "1.2.0"
\ No newline at end of file
此差异已折叠。
此差异已折叠。
# 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.
"""
This simulator uses statevector(Tensor) to simulate quantum behaviors.
Basically, the core of the algorithm is tensor contraction with one-way calculation that each gate is
......@@ -185,6 +199,16 @@ def cx_gate_matrix():
[0, 0, 0, 1],
[0, 0, 1, 0]], dtype=complex).reshape(2, 2, 2, 2)
def swap_gate_matrix():
"""
Control Not
:return:
"""
return np.array([[1, 0, 0, 0],
[0, 0, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 1]], dtype=complex).reshape(2, 2, 2, 2)
### PaddleE ###
def normalize_axis(axis, ndim):
......@@ -359,7 +383,7 @@ def StateTranfer(state, gate_name, bits, params=None):
"""
To transfer state by only gate name and bits
:param state: the last step state, can be init vector or the last step vector.
:param gate_name:x,y,z,h,CNOT
:param gate_name:x,y,z,h,CNOT, SWAP
:param bits: the gate working on the bits.
:param params: params for u gate.
:return: the updated state
......@@ -379,6 +403,9 @@ def StateTranfer(state, gate_name, bits, params=None):
elif gate_name == 'CNOT':
# print('----------', gate_name, bits, '----------')
gate_matrix = cx_gate_matrix()
elif gate_name == 'SWAP':
# print('----------', gate_name, bits, '----------')
gate_matrix = swap_gate_matrix()
elif gate_name == 'u':
# print('----------', gate_name, bits, '----------')
gate_matrix = u_gate_matrix(params)
......
......@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy
import numpy as np
from numpy import concatenate
from numpy import trace as np_trace
from numpy import matmul as np_matmul
......@@ -26,7 +26,12 @@ __all__ = [
"w_state",
"density_op",
"density_op_random",
"completely_mixed_computational"
"completely_mixed_computational",
"bell_state",
"bell_diagonal_state",
"R_state",
"S_state",
"isotropic_state"
]
......@@ -52,19 +57,19 @@ def vec(n):
[[1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]]
"""
assert n > 0, 'qubit number must be larger than 1'
state = concatenate(([[1.0]], np_zeros([1, 2**n- 1])), axis=1)
state = concatenate(([[1.0]], np_zeros([1, 2**n - 1])), axis=1)
return state.astype("complex128")
def vec_random(n, real_or_complex=2):
r"""随机生成一个量子态的numpy形式。
r"""随机生成一个量子态的 numpy 形式。
Args:
n (int): 量子比特数量
real_or_complex (int, optional): 默认为2,即生成复数组;若为1,则生成实数组
real_or_complex (int, optional): 默认为 2,即生成复数组;若为 1,则生成实数组
Returns:
numpy.ndarray: 一个形状为 ``(1, 2**n)`` 的numpy数组
numpy.ndarray: 一个形状为 ``(1, 2**n)`` 的 numpy 数组
"""
assert n > 0, 'qubit number must be larger than 1'
assert real_or_complex == 1 or real_or_complex == 2, 'real_or_complex must be 1 or 2'
......@@ -74,20 +79,20 @@ def vec_random(n, real_or_complex=2):
# complex
else:
psi = np_random.randn(1, 2**n) + 1j * np_random.randn(1, 2**n)
psi = psi/numpy.linalg.norm(psi)
psi = psi/np.linalg.norm(psi)
return psi.astype("complex128")
def w_state(n, coeff=None):
r"""生成一个W-state的numpy形式。
r"""生成一个 W-state 的 numpy 形式。
Args:
n (int): 量子比特数量
coeff (numpy.ndarray, optional): 默认为 ``None`` ,即生成平均概率幅(系数)
Returns:
numpy.ndarray: 一个形状为 ``(1, 2**n)`` 的numpy数组
numpy.ndarray: 一个形状为 ``(1, 2**n)`` 的 numpy 数组
代码示例:
......@@ -104,7 +109,7 @@ def w_state(n, coeff=None):
"""
assert n > 0, 'qubit number must be larger than 1'
c = coeff if coeff is not None else numpy.ones((1, 2**n))/numpy.sqrt(n)
c = coeff if coeff is not None else np.ones((1, 2**n))/np.sqrt(n)
assert c.shape[0] == 1 and c.shape[1] == 2**n, 'The dimension of coeff is not right'
state = np_zeros((1, 2**n))
......@@ -115,13 +120,13 @@ def w_state(n, coeff=None):
def density_op(n):
r"""生成密度矩阵 :math:`|00..0\rangle \langle00..0|` 的numpy形式。
r"""生成密度矩阵 :math:`|00..0\rangle \langle00..0|` 的 numpy 形式。
Args:
n (int): 量子比特数量
Returns:
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的numpy数组
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的 numpy 数组
代码示例:
......@@ -147,15 +152,15 @@ def density_op(n):
def density_op_random(n, real_or_complex=2, rank=None):
r"""随机生成一个密度矩阵的numpy形式。
r"""随机生成一个密度矩阵的 numpy 形式。
Args:
n (int): 量子比特数量
real_or_complex (int, optional): 默认为2,即生成复数组,若为1,则生成实数组
real_or_complex (int, optional): 默认为 2,即生成复数组,若为 1,则生成实数组
rank (int, optional): 矩阵的秩,默认为 :math:`2^n` (当 ``rank`` 为 ``None`` 时)
Returns:
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的numpy数组
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的 numpy 数组
"""
assert n > 0, 'qubit number must be positive'
rank = rank if rank is not None else 2**n
......@@ -174,13 +179,19 @@ def density_op_random(n, real_or_complex=2, rank=None):
def completely_mixed_computational(n):
r"""生成完全混合态的密度矩阵的numpy形式。
r"""生成完全混合态的密度矩阵的 numpy 形式。
其矩阵形式为:
.. math::
\frac{I}{2^n}
Args:
n (int): 量子比特数量
Returns:
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的numpy数组
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的 numpy 数组
代码示例:
......@@ -201,3 +212,225 @@ def completely_mixed_computational(n):
rho = np_eye(2**n)/2**n
return rho.astype('complex128')
def bell_state(n):
r"""生成(推广)贝尔态的密度矩阵的 numpy 形式。
其数学表达形式为:
.. math::
|\Phi_{D}\rangle=\frac{1}{\sqrt{D}} \sum_{j=0}^{D-1}|j\rangle_{A}|j\rangle_{B}
Args:
n (int): 量子比特数量。必须为大于等于 2 的偶数
Returns:
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的 numpy 数组
代码示例:
.. code-block:: python
from paddle_quantum.state import bell_state
state = bell_state(2)
print(state)
::
[[0.5+0.j 0. +0.j 0. +0.j 0.5+0.j]
[0. +0.j 0. +0.j 0. +0.j 0. +0.j]
[0. +0.j 0. +0.j 0. +0.j 0. +0.j]
[0.5+0.j 0. +0.j 0. +0.j 0.5+0.j]]
"""
assert n > 0, "Qubit number must be positive"
assert n % 2 == 0, "Qubit number must be even"
dim = 2**n
local_dim = 2**int(n/2)
coeff = 1 / local_dim
state = np.zeros((dim, dim))
for i in range(0, dim, local_dim + 1):
for j in range(0, dim, local_dim + 1):
state[i, j] = coeff
return state.astype("complex128")
def bell_diagonal_state(p1, p2, p3, p4):
r"""生成对角贝尔态的密度矩阵的 numpy 形式。
其数学表达形式为:
.. math::
p_{1}|\Phi^{+}\rangle\langle\Phi^{+}|+p_{2}| \Psi^{+}\rangle\langle\Psi^{+}|+p_{3}| \Phi^{-}\rangle\langle\Phi^{-}| +
p4|\Psi^{-}\rangle\langle\Psi^{-}|
Args:
p1 (float): 第一个分量。
p2 (float): 第二个分量。
p3 (float): 第三个分量。
p4 (float): 第四个分量。
Note:
四个参数构成了一个概率分布,因此它们是非负数,加起来必为 1。
Returns:
numpy.ndarray: 一个形状为 ``(4, 4)`` 的 numpy 数组
代码示例:
.. code-block:: python
from paddle_quantum.state import bell_diagonal_state
state = bell_diagonal_state(0.25, 0.25, 0.25, 0.25)
print(state)
::
[[0.25+0.j 0. +0.j 0. +0.j 0. +0.j]
[0. +0.j 0.25+0.j 0. +0.j 0. +0.j]
[0. +0.j 0. +0.j 0.25+0.j 0. +0.j]
[0. +0.j 0. +0.j 0. +0.j 0.25+0.j]]
"""
# p4 = 1 - p1 - p2 - p3
# assert 0 <= p1 <= 1 and 0 <= p2 <= 1 and 0 <= p3 <= 1 and 0 <= p4 <= 1, "Probability must be in [0, 1]"
coeff = np.sqrt(0.5)
phi_p_vec = np.array([[coeff, 0, 0, coeff]])
phi_p_mat = np.matmul(phi_p_vec.T, phi_p_vec)
phi_m_vec = np.array([[coeff, 0, 0, -coeff]])
phi_m_mat = np.matmul(phi_m_vec.T, phi_m_vec)
psi_p_vec = np.array([[0, coeff, coeff, 0]])
psi_p_mat = np.matmul(psi_p_vec.T, psi_p_vec)
psi_m_vec = np.array([[0, coeff, -coeff, 0]])
psi_m_mat = np.matmul(psi_m_vec.T, psi_m_vec)
state = p1*phi_p_mat + p2*psi_p_mat + p3*phi_m_mat + p4*psi_m_mat
return state.astype("complex128")
def R_state(p):
r"""生成 R-state 的密度矩阵的 numpy 形式。
其数学表达形式为:
.. math::
p|\Psi^{+}\rangle\langle\Psi^{+}| + (1 - p)|11\rangle\langle11|
Args:
p (float): 控制生成 R-state 的参数。属于 :math:`[0, 1]` 区间内
Returns:
numpy.ndarray: 一个形状为 ``(4, 4)`` 的 numpy 数组
代码示例:
.. code-block:: python
from paddle_quantum.state import R_state
state = R_state(0.5)
print(state)
::
[[0. +0.j 0. +0.j 0. +0.j 0. +0.j]
[0. +0.j 0.25+0.j 0.25+0.j 0. +0.j]
[0. +0.j 0.25+0.j 0.25+0.j 0. +0.j]
[0. +0.j 0. +0.j 0. +0.j 0.5 +0.j]]
"""
assert 0 <= p <= 1, "Probability must be in [0, 1]"
coeff = np.sqrt(0.5)
psi_p_vec = np.array([[0, coeff, coeff, 0]])
psi_p_mat = np.matmul(psi_p_vec.T, psi_p_vec)
state_11 = np.zeros((4, 4))
state_11[3, 3] = 1
state = p*psi_p_mat + (1-p)*state_11
return state.astype("complex128")
def S_state(p):
r"""生成 S-state 的密度矩阵的 numpy 形式。
其数学表达形式为:
.. math::
p|\Phi^{+}\rangle\langle\Phi^{+}| + (1 - p)|00\rangle\langle00|
Args:
p (float): 控制生成 S-state 的参数。属于 :math:`[0, 1]` 区间内
Returns:
numpy.ndarray: 一个形状为 ``(4, 4)`` 的 numpy 数组
代码示例:
.. code-block:: python
from paddle_quantum.state import S_state
state = S_state(0.5)
print(state)
::
[[0.75+0.j 0. +0.j 0. +0.j 0.25+0.j]
[0. +0.j 0. +0.j 0. +0.j 0. +0.j]
[0. +0.j 0. +0.j 0. +0.j 0. +0.j]
[0.25+0.j 0. +0.j 0. +0.j 0.25+0.j]]
"""
assert 0 <= p <= 1, "Probability must be in [0, 1]"
phi_p = bell_state(2)
psi0 = np.zeros_like(phi_p)
psi0[0, 0] = 1
state = p * phi_p + (1-p) * psi0
return state.astype("complex128")
def isotropic_state(n, p):
r"""生成 isotropic state 的密度矩阵的 numpy 形式。
其数学表达形式为:
.. math::
p(\frac{1}{\sqrt{D}} \sum_{j=0}^{D-1}|j\rangle_{A}|j\rangle_{B}) + (1 - p)\frac{I}{2^n}
Args:
n (int): 量子比特数量。
p (float): 控制生成 isotropic state 的参数。属于 :math:`[0, 1]` 区间内
Returns:
numpy.ndarray: 一个形状为 ``(2**n, 2**n)`` 的 numpy 数组
代码示例:
.. code-block:: python
from paddle_quantum.state import isotropic_state
state = isotropic_state(2, 0.5)
print(state)
::
[[0.375+0.j 0. +0.j 0. +0.j 0.25 +0.j]
[0. +0.j 0.125+0.j 0. +0.j 0. +0.j]
[0. +0.j 0. +0.j 0.125+0.j 0. +0.j]
[0.25 +0.j 0. +0.j 0. +0.j 0.375+0.j]]
"""
assert 0 <= p <= 1, "Probability must be in [0, 1]"
dim = 2**n
state = p*bell_state(n) + (1-p)*np.eye(dim)/dim
return state
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
# 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.
......@@ -48,7 +48,12 @@ __all__ = [
"NKron",
"dagger",
"random_pauli_str_generator",
"pauli_str_to_matrix"
"pauli_str_to_matrix",
"partial_transpose_2",
"partial_transpose",
"negativity",
"logarithmic_negativity",
"is_ppt"
]
......@@ -266,12 +271,12 @@ def random_pauli_str_generator(n, terms=3):
"""
pauli_str = []
for sublen in np_random.randint(1, high=n+1, size=terms):
# Tips: -1 <= coef < 1
coef = np_random.rand()*2-1
# Tips: -1 <= coeff < 1
coeff = np_random.rand()*2-1
ops = np_random.choice(['x', 'y', 'z'], size=sublen)
pos = np_random.choice(range(n), size=sublen, replace=False)
op_list = [ops[i]+str(pos[i]) for i in range(sublen)]
pauli_str.append([coef, ','.join(op_list)])
pauli_str.append([coeff, ','.join(op_list)])
return pauli_str
......@@ -315,3 +320,154 @@ def pauli_str_to_matrix(pauli_str, n):
matrices.append(coeff * NKron(sub_matrices[0], sub_matrices[1], *sub_matrices[2:]))
return sum(matrices)
def partial_transpose_2(density_op, sub_system=None):
r"""计算输入量子态的 partial transpose :math:`\rho^{T_A}`
Args:
density_op (numpy.ndarray): 量子态的密度矩阵形式
sub_system (int): 1或2,表示关于哪个子系统进行 partial transpose,默认为第二个
Returns:
float: 输入的量子态的 partial transpose
代码示例:
.. code-block:: python
from paddle_quantum.utils import partial_transpose_2
rho_test = np.arange(1,17).reshape(4,4)
partial_transpose_2(rho_test, sub_system=1)
::
[[ 1, 2, 9, 10],
[ 5, 6, 13, 14],
[ 3, 4, 11, 12],
[ 7, 8, 15, 16]]
"""
sys_idx = 2 if sub_system is None else 1
# Copy the density matrix and not corrupt the original one
transposed_density_op = numpy.copy(density_op)
if sys_idx == 2:
for j in [0, 2]:
for i in [0, 2]:
transposed_density_op[i:i+2, j:j+2] = density_op[i:i+2, j:j+2].transpose()
else:
transposed_density_op[2:4, 0:2] = density_op[0:2, 2:4]
transposed_density_op[0:2, 2:4] = density_op[2:4, 0:2]
return transposed_density_op
def partial_transpose(density_op, n):
r"""计算输入量子态的 partial transpose :math:`\rho^{T_A}`。
Args:
density_op (numpy.ndarray): 量子态的密度矩阵形式
Returns:
float: 输入的量子态的 partial transpose
"""
# Copy the density matrix and not corrupt the original one
transposed_density_op = numpy.copy(density_op)
for j in range(0, 2**n, 2):
for i in range(0, 2**n, 2):
transposed_density_op[i:i+2, j:j+2] = density_op[i:i+2, j:j+2].transpose()
return transposed_density_op
def negativity(density_op):
r"""计算输入量子态的 Negativity :math:`N = ||\frac{\rho^{T_A}-1}{2}||`。
Args:
density_op (numpy.ndarray): 量子态的密度矩阵形式
Returns:
float: 输入的量子态的 Negativity
代码示例:
.. code-block:: python
from paddle_quantum.utils import negativity
from paddle_quantum.state import bell_state
rho = bell_state(2)
print("Negativity of the Bell state is:", negativity(rho))
::
Negativity of the Bell state is: 0.5
"""
# Implement the partial transpose
density_op_T = partial_transpose_2(density_op)
# Calculate through the equivalent expression N = sum(abs(\lambda_i)) when \lambda_i<0
n = 0
eigen_val, _ = numpy.linalg.eig(density_op_T)
for val in eigen_val:
if val < 0:
n = n + numpy.abs(val)
return n
def logarithmic_negativity(density_op):
r"""计算输入量子态的 Logarithmic Negativity :math:`E_N = ||\rho^{T_A}||`。
Args:
density_op (numpy.ndarray): 量子态的密度矩阵形式
Returns:
float: 输入的量子态的 Logarithmic Negativity
代码示例:
.. code-block:: python
from paddle_quantum.utils import logarithmic_negativity
from paddle_quantum.state import bell_state
rho = bell_state(2)
print("Logarithmic negativity of the Bell state is:", logarithmic_negativity(rho))
::
Logarithmic negativity of the Bell state is: 1.0
"""
# Calculate the negativity
n = negativity(density_op)
# Calculate through the equivalent expression
log2_n = numpy.log2(2*n + 1)
return log2_n
def is_ppt(density_op):
r"""计算输入量子态是否满足 PPT 条件。
Args:
density_op (numpy.ndarray): 量子态的密度矩阵形式
Returns:
bool: 输入的量子态是否满足 PPT 条件
代码示例:
.. code-block:: python
from paddle_quantum.utils import is_ppt
from paddle_quantum.state import bell_state
rho = bell_state(2)
print("Whether the Bell state satisfies PPT condition:", is_ppt(rho))
::
Whether the Bell state satisfies PPT condition: False
"""
# By default the PPT condition is satisfied
ppt = True
# Detect negative eigenvalues from the partial transposed density_op
if negativity(density_op) > 0:
ppt = False
return ppt
\ No newline at end of file
# Copyright (c) 2020 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
# 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.
......@@ -23,7 +23,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
setuptools.setup(
name='paddle-quantum',
version='1.1.1',
version='1.2.0',
author='Institute for Quantum Computing, Baidu INC.',
author_email='quantum@baidu.com',
description='Paddle Quantum is a quantum machine learning (QML) toolkit developed based on Baidu PaddlePaddle.',
......
此差异已折叠。
此差异已折叠。
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 纠缠蒸馏 -- DEJMPS 协议\n",
"\n",
"\n",
"<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 概述\n",
"\n",
"如果读者对纠缠蒸馏的基本概念不熟悉,请浏览我们之前关于 [BBPSSW](./EntanglementDistillation_BBPSSW_CN.ipynb) 的教程。在之前的教程中,我们对纠缠蒸馏的 BBPSSW 协议 [1] 进行了介绍。本教程将介绍 DEJMPS 协议,该协议是由 Deutsch 等人提出的 [2],和 BBPSSW 协议有着类似的原理。这两种协议最主要的区别是:DEJMPS 协议可以对贝尔对角态(Bell-diagonal state)进行蒸馏,而 BBPSSW 只能保证在 isotropic 态上有效。下面,我们对 DEJMPS 协议进行详细介绍。\n",
"\n",
"在纠缠蒸馏中,我们关心的问题是:如何通过 LOCC 操作,从多个含有噪声的纠缠量子比特对中生成一个高保真度的**最大纠缠态(maximally-entangled state)** $|\\Phi^+\\rangle$,也称之为贝尔态。让我们先回顾一下贝尔态的定义,\n",
"\n",
"$$ \n",
"\\begin{align*}\n",
"|\\Phi^{\\pm}\\rangle_{AB} &= \\frac{1}{\\sqrt{2}}(|0\\rangle_A\\otimes|0\\rangle_B \\pm |1\\rangle_A\\otimes|1\\rangle_B), \\\\\n",
"|\\Psi^{\\pm}\\rangle_{AB} &= \\frac{1}{\\sqrt{2}}(|0\\rangle_A\\otimes|1\\rangle_B \\pm |1\\rangle_A\\otimes|0\\rangle_B). \n",
"\\tag{1}\n",
"\\end{align*}\n",
"$$\n",
"\n",
"$A$ 和 $B$ 代表的是共享纠缠对的双方 Alice 和 Bob。根据贝尔对角态(Bell-digonal state)的定义,在贝尔态作为基底的密度矩阵可以表示为如下对角形式,\n",
"\n",
"$$\n",
"\\rho_{\\text{diag}} = p_1 | \\Phi^+\\rangle \\langle \\Phi^+ | + p_2 | \\Psi^+\\rangle \\langle \\Psi^+ | + \n",
"p_3 | \\Phi^-\\rangle \\langle \\Phi^- | + p_4 | \\Psi^-\\rangle \\langle \\Psi^- |.\n",
"\\tag{2}\n",
"$$\n",
"\n",
"这里我们假设 $p_1 > p_2 \\geq p_3 \\geq p_4$,并且满足 $p_1 + p_2+ p_3+ p_4 = 1$。那么,我们可以通过以下方式刻画贝尔对角态的纠缠度:\n",
"\n",
"* 保真度 (State fidelity):$F = \\langle \\Phi^+|\\rho_{\\text{diag}}|\\Phi^+\\rangle = p_1$\n",
"* Negativity: $\\mathcal{N}(\\rho_{\\text{diag}}) = p_1 - 1/2$\n",
"\n",
"**提示:** 贝尔对角态仅能在 $p_1 > 1/2$ 时才能通过蒸馏提高保真度。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## DEJMPS 协议\n",
"\n",
"假设 Alice ($A$) 和 Bob ($B$) 持有两对纠缠量子比特,我们分别将它们标记为 $\\{ A_0, B_0 \\}, \\{ A_1, B_1 \\}$。并且这两对量子比特都分别处于相同的贝尔对角态 $\\rho_{diag}$,它们的 $p_1 > 0.5$。那么我们就可以通过如下的流程来蒸馏这两对量子比特,使得输出态和贝尔态 $|\\Phi^+\\rangle$ 之间的保真度更高:\n",
"\n",
"1. Alice 和 Bob 先选择任意一对量子比特,**这对量子比特将作为最终的输出比特**。这里假设他们选择了 $A_0$ 和 $B_0$。\n",
"2. 首先,Alice 对她的两个量子比特施加旋转门 $R_x(\\pi/2)$ ,Bob对他的量子比特施加旋转门 $R_x(-\\pi/2)$。\n",
"3. 之后,Alice 和 Bob 对他们手中的量子比特施加受控非门 (CNOT 门)。这里, $A_0$ 和 $B_0$ 作为控制比特,$A_1$ 和 $B_1$ 作为目标比特。\n",
"4. 接下来双方分别对 $A_1$ 和 $B_1$ 进行测量,并通过**经典通讯**来交换他们的测量结果 $m_{A_1}, m_{B_1}$。\n",
"5. 如果Alice和Bob的结果一致(00或11),那么他们可以宣布本次蒸馏过程成功,同时 $A_0$ 和 $B_0$ 作为输出比特,输出态为 $\\rho_{out}$。相反,如果他们的测量结果不一致(01或10),那么本次蒸馏过程失败,丢弃量子比特 $A_0$ 和 $B_0$。\n",
"\n",
"<center><img src=\"figures/distillation-fig-DEJMPS.jpg\" height=\"250\" width=\"300\"></center>\n",
"<div style=\"text-align:center\">图1:DEJMPS 纠缠蒸馏过程电路图 </div>\n",
"\n",
"在蒸馏成功的情况下,$A_0$ 和 $B_0$ 作为输出比特,他们的输出态 $\\rho_{out}$ 的和目标态之间的保真度将会提升。输出态的保真度 $F_{out}$ 为\n",
"\n",
"$$\n",
"F_{out} = \\frac{p_1^2 + p_4^2}{(p_1 + p_4)^2 + (p_2 + p_3)^2},\n",
"\\tag{3}\n",
"$$\n",
"\n",
"与 BBPSSW 协议相似, DEJMPS 协议并不能保证每次蒸馏都会成功,他的成功率 $p_{succ}$ 是\n",
"\n",
"$$ \n",
"p_{succ} = (p_1 + p_4)^2 + (p_2 + p_3)^2.\n",
"\\tag{4}\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Paddle Quantum 代码实现\n",
"\n",
"首先,我们导入相关的包"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-27T06:10:17.461722Z",
"start_time": "2021-01-27T06:10:09.975500Z"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"import paddle.fluid as fluid\n",
"from paddle_quantum.locc import LoccNet\n",
"from paddle.complex import matmul, trace\n",
"from paddle_quantum.state import bell_state, isotropic_state, bell_diagonal_state\n",
"from paddle_quantum.utils import negativity, logarithmic_negativity, is_ppt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在使用量子电路模拟之前,先计算一下对于如下输入态的蒸馏结果的理论值:\n",
"\n",
"$$\n",
"\\rho = p_1 | \\Phi^+\\rangle \\langle \\Phi^+ | + \\frac{1-p_1}{2} | \\Psi^+\\rangle \\langle \\Psi^+ |+ \n",
"\\frac{1-p_1}{3}| \\Phi^-\\rangle \\langle \\Phi^- | + \\frac{1-p_1}{6} | \\Psi^-\\rangle \\langle \\Psi^- |.\n",
"\\tag{5}\n",
"$$\n",
"\n",
"假设我们令 $p_1 = 0.7$,那么保真度的提升以及蒸馏成功的概率可以可以被如下函数计算:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-27T06:10:17.561117Z",
"start_time": "2021-01-27T06:10:17.465773Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"输入保真度是: 0.7\n",
"蒸馏后的保真度的理论值为: 0.7879999999999999\n",
"蒸馏成功率的理论值为: 0.625\n",
"输入态是否满足 PPT 条件并因而无法进行蒸馏? False\n"
]
}
],
"source": [
"def DEJMPS_metrics(*p):\n",
" \"\"\"\n",
" 返回 DEJMPS 协议蒸馏成功后的保真度以及成功率的理论值.\n",
" \"\"\"\n",
" F_in = p[0]\n",
" p_succ = (p[0] + p[3]) ** 2 + (p[1] + p[2]) ** 2\n",
" F_out = (p[0] ** 2 + p[3] ** 2)/p_succ\n",
" \n",
" return F_in, F_out, p_succ\n",
"\n",
"p = 0.7\n",
"F_in, F_out, p_succ = DEJMPS_metrics(p, (1-p)/2, (1-p)/3, (1-p)/6)\n",
"print(\"输入保真度是:\", F_in)\n",
"print(\"蒸馏后的保真度的理论值为:\", F_out)\n",
"print(\"蒸馏成功率的理论值为:\", p_succ)\n",
"print(\"输入态是否满足 PPT 条件并因而无法进行蒸馏?\", \n",
" is_ppt(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"接下来,我们用 Paddle Quantum 中的 LOCCNet 模块创建 DEJMPS 协议对应的电路,并观察他的输出结果:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-27T06:10:17.887395Z",
"start_time": "2021-01-27T06:10:17.588579Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"输入态的保真度为: 0.70000\n",
"蒸馏后的保真度为: 0.78800\n",
"蒸馏的成功率为: 62.500%\n",
"========================================================\n",
"蒸馏后的态是:\n",
" [[ 0.45 +0.j 0. -0.j -0. +0.j 0.338-0.j]\n",
" [ 0. +0.j 0.05 +0.j 0.002-0.j 0. -0.j]\n",
" [ 0. +0.j 0.002+0.j 0.05 -0.j 0. -0.j]\n",
" [ 0.338+0.j -0. -0.j 0. +0.j 0.45 +0.j]]\n",
"初始态的 negativity: 0.19999999999999993\n",
"输出态的 negativity: 0.28800000000000003\n"
]
}
],
"source": [
"class LOCC(LoccNet):\n",
" def __init__(self):\n",
" super(LOCC, self).__init__()\n",
" \n",
" # 添加第一个持有者 Alice\n",
" # 第一个参数 2 表明该持有者有多少个量子比特\n",
" # 第二个参数用来标明该持有者的名字\n",
" self.add_new_party(2, party_name='Alice')\n",
" \n",
" # 添加第二个持有者 Bob\n",
" self.add_new_party(2, party_name='Bob')\n",
" \n",
" # 定义一个贝尔对角态,四个系数对应 p1, p2, p3, p4\n",
" _state = fluid.dygraph.to_variable(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6))\n",
" \n",
" # ('Alice', 0) 表示 Alice 的第一个量子比特 A0\n",
" # ('Bob', 0) 表示 Bob 的第一个量子比特 B0\n",
" self.set_init_status(_state, [('Alice', 0), ('Bob', 0)]) \n",
" \n",
" # ('Alice', 1) 表示 Alice 的第二个量子比特 A1\n",
" # ('Bob', 1) 表示 Bob 的第二个量子比特 B1\n",
" self.set_init_status(_state, [('Alice', 1), ('Bob', 1)]) \n",
" \n",
" # 创建两个参数 theta1 和 theta2 用来分别存储 Alice 和 Bob 的本地旋转门的角度\n",
" self.theta1 = fluid.dygraph.to_variable(np.array([np.pi/2, np.pi/2], dtype='float64'))\n",
" self.theta2 = fluid.dygraph.to_variable(np.array([-np.pi/2, -np.pi/2], dtype='float64'))\n",
" \n",
" def DEJMPS(self):\n",
" status = self.init_status\n",
" \n",
" # 用电路模拟 Alice 的本地操作 \n",
" cir1 = self.create_ansatz('Alice')\n",
" cir1.rx(self.theta1[0], 0)\n",
" cir1.rx(self.theta1[1], 1)\n",
" cir1.cnot([0, 1])\n",
"\n",
" # 用电路模拟 Bob 的本地操作 \n",
" cir2 = self.create_ansatz('Bob')\n",
" cir2.rx(self.theta2[0], 0)\n",
" cir2.rx(self.theta2[1], 1)\n",
" cir2.cnot([0, 1])\n",
" \n",
" # 运行电路\n",
" status = cir1.run(status)\n",
" status_mid = cir2.run(status)\n",
" \n",
" # 参数 ('Alice', 1) 表示测量 Alice 的第二个比特 A1\n",
" # 参数 ('Bob', 1) 表示测量 Bob 的第二个比特 B1\n",
" # 参数 ['00','11'] 表示我们希望的测量结果\n",
" # status_mid 保留了测量得到 '00' 和 '11' 之后的四比特态\n",
" status_mid = self.measure(status_mid, [('Alice', 1), ('Bob', 1)], [\"00\", \"11\"])\n",
" \n",
" # 对 A1&B1 求偏迹,用数组 [('Alice', 0), ('Bob', 0)] 表示想要保留的系统\n",
" # status_fin 即为 A0 和 B0 的二比特态\n",
" status_fin = self.partial_state(status_mid, [('Alice', 0), ('Bob', 0)])\n",
" \n",
" return status_fin\n",
" \n",
"\n",
"# 开启动态计算图\n",
"with fluid.dygraph.guard():\n",
" \n",
" # 运行 DEJMPS 协议\n",
" status_fin = LOCC().DEJMPS()\n",
" \n",
" # 生成我们想要的目标态\n",
" target_state = fluid.dygraph.to_variable(bell_state(2))\n",
" \n",
" # 计算他们之间的保真度\n",
" fidelity = 0\n",
" for status in status_fin:\n",
" fidelity += trace(matmul(target_state, status.state)).real\n",
" fidelity /= len(status_fin)\n",
" \n",
" # 计算成功率\n",
" suc_rate = sum([status.prob for status in status_fin])\n",
" \n",
" # 输出结果\n",
" print(f\"输入态的保真度为: {p:.5f}\")\n",
" print(f\"蒸馏后的保真度为: {fidelity.numpy()[0]:.5f}\")\n",
" print(f\"蒸馏的成功率为: {suc_rate.numpy()[0]:#.3%}\")\n",
" \n",
" # 输出终态\n",
" rho_out = status_fin[0].state.numpy()\n",
" print(\"========================================================\")\n",
" print(f\"蒸馏后的态是:\\n {np.around(rho_out, 4)}\")\n",
" print(f\"初始态的 negativity: {negativity(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6))}\")\n",
" print(f\"输出态的 negativity: {negativity(rho_out)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"我们可以看到,模拟电路的输出结果和理论预期一致。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 结论\n",
"\n",
"DEJMPS 协议可以高效地从两对含有噪声的纠缠量子对中蒸馏出一对具有更高保真度的纠缠对。和只能蒸馏 isotropic 态的 BBPSSW 协议相比,DEJMPS 协议可以应用在任意贝尔对角态上。因为贝尔对角态本身包含了 isotropic 态,所以 DEJMPS 协议是一种比 BBPSSW 协议更通用的蒸馏协议。然而,他也和 BBPSSW 协议具有相同的缺点:仍然不能对任意输入态进行蒸馏,并且在多对量子比特的场景下没有良好的拓展性。\n",
"\n",
"我们建议感兴趣的读者可以接着浏览以下教程学习 [如何通过 LOCCNet 设计全新的纠缠蒸馏方案](./EntanglementDistillation_LOCCNET_CN.ipynb)。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## 参考资料\n",
"\n",
"[1] Bennett, Charles H., et al. \"Purification of noisy entanglement and faithful teleportation via noisy channels.\" [Physical Review Letters 76.5 (1996): 722.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.722)\n",
"\n",
"[2] Deutsch, David, et al. \"Quantum privacy amplification and the security of quantum cryptography over noisy channels.\" [Physical Review Letters 77.13 (1996): 2818.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.77.2818)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.9"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Entanglement Distillation -- DEJMPS Protocol\n",
"\n",
"\n",
"<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Overview\n",
"\n",
"Before reading this tutorial, we highly recommend you to read the [BBPSSW protocol](./EntanglementDistillation_BBPSSW_EN.ipynb) first if you are not familiar with entanglement distillation. The DEJMPS protocol, introduced by Deutsch et al. [1], is similar to the BBPSSW protocol. The main difference between these two protocols is the state for distillation: the DEJMPS protocol can distill Bell-diagonal states, while the BBPSSW protocol could distill isotropic states. In entanglement distillation, the main purpose is to generate a **maximally entangled state** $|\\Phi^+\\rangle$ from many copies of imperfect entangled states, using only LOCC operations. Recall the four Bell states,\n",
"\n",
"$$ \n",
"\\begin{align*}\n",
"|\\Phi^{\\pm}\\rangle_{AB} &= \\frac{1}{\\sqrt{2}}(|0\\rangle_A\\otimes|0\\rangle_B \\pm |1\\rangle_A\\otimes|1\\rangle_B), \\\\\n",
"|\\Psi^{\\pm}\\rangle_{AB} &= \\frac{1}{\\sqrt{2}}(|0\\rangle_A\\otimes|1\\rangle_B \\pm |1\\rangle_A\\otimes|0\\rangle_B). \n",
"\\tag{1}\n",
"\\end{align*}\n",
"$$\n",
"\n",
"where $A$ and $B$ represent the bi-party Alice and Bob. The Bell-diagonal state, by definition, is diagonal in the Bell basis that can be expressed as\n",
"\n",
"$$\n",
"\\rho_{\\text{diag}} = p_1 | \\Phi^+\\rangle \\langle \\Phi^+ | + p_2 | \\Psi^+\\rangle \\langle \\Psi^+ | + \n",
"p_3 | \\Phi^-\\rangle \\langle \\Phi^- | + p_4 | \\Psi^-\\rangle \\langle \\Psi^- |.\n",
"\\tag{2}\n",
"$$\n",
"\n",
"with $p_1 > p_2 \\geq p_3 \\geq p_4$ and $p_1 + p_2+ p_3+ p_4 = 1$. Then the entanglement quantification of a Bell-diagonal state can be described as:\n",
"\n",
"* State fidelity $F = \\langle \\Phi^+|\\rho_{\\text{diag}}|\\Phi^+\\rangle = p_1$\n",
"* Negativity $\\mathcal{N}(\\rho_{\\text{diag}}) = p_1 - 1/2$\n",
"\n",
"**Note:** The Bell-diagonal state is distillable when $p_1 > 1/2$."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## DEJMPS protocol\n",
"\n",
"Suppose that two parties, namely Alice($A$) and Bob($B$), possess two copies of entangled qubit: $\\{ A_0, B_0 \\}, \\{ A_1, B_1 \\}$. If these two pairs are all in the same Bell-diagonal state $\\rho_{\\text{diag}}$, with $p_1 > 0.5$. We can apply the following workflow to purify the input states and leads to an output state has fidelity closer to $|\\Phi^+\\rangle$:\n",
"1. Alice and Bob firstly choose the qubit pair **they want to keep as the memory qubit pair after distillation**. Here, they choose $A_0$ and $B_0$. \n",
"2. Alice performs $R_x(\\pi/2)$ gates on both qubits, and Bob performs $R_x(-\\pi/2)$ gates on both qubits.\n",
"3. Then, Alice and Bob both apply a CNOT gate on their qubits. Here, they choose $A_0,B_0$ as the control qubits and $A_1,B_1$ as the target qubits.\n",
"4. Two remote parties measure the target qubits and use a classical communication channel to exchange their measurement results $m_{A_1}, m_{B_1}$.\n",
"5. If the measurement results of Alice and Bob are the same (00 or 11), the distillation is successful, and the qubit pair $A_0, B_0$ is stored as state $\\rho_{out}$; If the measurement results are different (01 or 10), they claim the distillation failed and the qubit pair $A_0, B_0$ will be discarded.\n",
"\n",
"<center><img src=\"figures/distillation-fig-DEJMPS.jpg\" height=\"250\" width=\"300\"></center>\n",
"<div style=\"text-align:center\">Figure 1: Schematic diagram of the DEJMPS protocol </div>\n",
"\n",
"After the distillation, the final state $\\rho_{out}$ of entangled pair $A_0, B_0$ will have higher fidelity than the initial state $\\rho$. The fidelity of the final state $F_{out}$ is\n",
"\n",
"$$\n",
"F_{out} = \\frac{p_1^2 + p_4^2}{(p_1 + p_4)^2 + (p_2 + p_3)^2},\n",
"\\tag{3}\n",
"$$\n",
"\n",
"Similar to the BBPSSW protocol, the DEJMPS protocol is probabilistic, with the probability of a successful distillation being \n",
"\n",
"$$ \n",
"p_{succ} = (p_1 + p_4)^2 + (p_2 + p_3)^2.\n",
"\\tag{4}\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulation with Paddle Quantum\n",
"First, we need to import relevant packages"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-25T16:59:07.977165Z",
"start_time": "2021-01-25T16:59:06.564863Z"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"import paddle.fluid as fluid\n",
"from paddle_quantum.locc import LoccNet\n",
"from paddle.complex import matmul, trace\n",
"from paddle_quantum.state import bell_state, isotropic_state, bell_diagonal_state\n",
"from paddle_quantum.utils import negativity, logarithmic_negativity, is_ppt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, let us see the theoretical result of applying the **DEJMPS protocol** to the state\n",
"\n",
"$$\n",
"\\rho = p_1 | \\Phi^+\\rangle \\langle \\Phi^+ | + \\frac{1-p_1}{2} | \\Psi^+\\rangle \\langle \\Psi^+ |+ \n",
"\\frac{1-p_1}{3}| \\Phi^-\\rangle \\langle \\Phi^- | + \\frac{1-p_1}{6} | \\Psi^-\\rangle \\langle \\Psi^- |.\n",
"\\tag{5}\n",
"$$\n",
"\n",
"Suppose we take $p_1 = 0.7$, then the theoretical improvement of fidelity can be calculated by the following block:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-25T16:59:11.804714Z",
"start_time": "2021-01-25T16:59:11.771952Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The input fidelity is: 0.7\n",
"The output fidelity is: 0.7879999999999999\n",
"With a probability of success: 0.625\n",
"The input state satisfies the PPT condition and hence not distillable? False\n"
]
}
],
"source": [
"def DEJMPS_metrics(*p):\n",
" \"\"\"\n",
" Returns output fidelity and probability of success of the DEJMPS protocol.\n",
" \"\"\"\n",
" F_in = p[0]\n",
" p_succ = (p[0] + p[3]) ** 2 + (p[1] + p[2]) ** 2\n",
" F_out = (p[0] ** 2 + p[3] ** 2)/p_succ\n",
" \n",
" return F_in, F_out, p_succ\n",
"\n",
"p = 0.7\n",
"F_in, F_out, p_succ = DEJMPS_metrics(p, (1-p)/2, (1-p)/3, (1-p)/6)\n",
"print(\"The input fidelity is:\", F_in)\n",
"print(\"The output fidelity is:\", F_out)\n",
"print(\"With a probability of success:\", p_succ)\n",
"print(\"The input state satisfies the PPT condition and hence not distillable?\", \n",
" is_ppt(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we can simulate the DEJMPS protocol and check if the results match with the theory."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-25T16:59:15.223963Z",
"start_time": "2021-01-25T16:59:14.574124Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The fidelity of the input quantum state is: 0.70000\n",
"The fidelity of the purified quantum state is: 0.78800\n",
"The probability of successful purification is: 62.500%\n",
"========================================================\n",
"The output state is:\n",
" [[0.45 -0.j 0. +0.j 0. -0.j 0.338-0.j]\n",
" [0. -0.j 0.05 +0.j 0.002-0.j 0. +0.j]\n",
" [0. -0.j 0.002+0.j 0.05 -0.j 0. -0.j]\n",
" [0.338+0.j 0. +0.j 0. +0.j 0.45 -0.j]]\n",
"The initial negativity is: 0.19999999999999993\n",
"The final negativity is: 0.2880000000000001\n"
]
}
],
"source": [
"class LOCC(LoccNet):\n",
" def __init__(self):\n",
" super(LOCC, self).__init__()\n",
" \n",
" # Add the first party Alice \n",
" # The first parameter 2 stands for how many qubits A holds\n",
" # The second parameter records the name of this qubit holder\n",
" self.add_new_party(2, party_name='Alice')\n",
" \n",
" # Add the second party Bob\n",
" # The first parameter 2 stands for how many qubits A holds\n",
" # The second parameter records the name of this qubit holder\n",
" self.add_new_party(2, party_name='Bob')\n",
" \n",
" # Define the input quantum states rho_in\n",
" _state = fluid.dygraph.to_variable(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6))\n",
" \n",
" # ('Alice', 0) means Alice's first qubit A0\n",
" # ('Bob', 0) means Bob's first qubit B0\n",
" self.set_init_status(_state, [('Alice', 0), ('Bob', 0)]) \n",
" \n",
" # ('Alice', 1) means Alice's second qubit A1\n",
" # ('Bob', 1) means Bob's second qubit B1\n",
" self.set_init_status(_state, [('Alice', 1), ('Bob', 1)]) \n",
" \n",
" # Set the angles of the Rx gates\n",
" self.theta1 = fluid.dygraph.to_variable(np.array([np.pi/2, np.pi/2], dtype='float64'))\n",
" self.theta2 = fluid.dygraph.to_variable(np.array([-np.pi/2, -np.pi/2], dtype='float64'))\n",
" \n",
" def DEJMPS(self):\n",
" status = self.init_status\n",
" \n",
" # Create Alice's local operations \n",
" cir1 = self.create_ansatz('Alice')\n",
" cir1.rx(self.theta1[0], 0)\n",
" cir1.rx(self.theta1[1], 1)\n",
" cir1.cnot([0, 1])\n",
"\n",
" # Create Bob's local operations \n",
" cir2 = self.create_ansatz('Bob')\n",
" cir2.rx(self.theta2[0], 0)\n",
" cir2.rx(self.theta2[1], 1)\n",
" cir2.cnot([0, 1])\n",
" \n",
" # Run circuit\n",
" status = cir1.run(status)\n",
" status_mid = cir2.run(status)\n",
" \n",
" # ('Alice', 1) means measuring Alice's second qubit A1\n",
" # ('Bob', 1) means measuring Bob's second qubit B1\n",
" # ['00','11'] specifies the success condition for distillation\n",
" # Means Alice and Bob both measure '00' or '11'\n",
" status_mid = self.measure(status_mid, [('Alice', 1), ('Bob', 1)], [\"00\", \"11\"])\n",
" \n",
" # Trace out the measured qubits A1&B1\n",
" # Leaving only Alice’s first qubit and Bob’s first qubit A0&B0 as the memory register\n",
" status_fin = self.partial_state(status_mid, [('Alice', 0), ('Bob', 0)])\n",
" \n",
" return status_fin\n",
" \n",
"\n",
"# Turn on dynamic computational graph\n",
"with fluid.dygraph.guard():\n",
" \n",
" # Run DEJMPS protocol\n",
" status_fin = LOCC().DEJMPS()\n",
" \n",
" # Calculate fidelity\n",
" target_state = fluid.dygraph.to_variable(bell_state(2))\n",
" fidelity = 0\n",
" for status in status_fin:\n",
" fidelity += trace(matmul(target_state, status.state)).real\n",
" fidelity /= len(status_fin)\n",
" \n",
" # Calculate success rate\n",
" suc_rate = sum([status.prob for status in status_fin])\n",
" \n",
" # Output simulation results\n",
" print(f\"The fidelity of the input quantum state is: {p:.5f}\")\n",
" print(f\"The fidelity of the purified quantum state is: {fidelity.numpy()[0]:.5f}\")\n",
" print(f\"The probability of successful purification is: {suc_rate.numpy()[0]:#.3%}\")\n",
" \n",
" # Print the output state\n",
" rho_out = status_fin[0].state.numpy()\n",
" print(\"========================================================\")\n",
" print(f\"The output state is:\\n {np.around(rho_out,4)}\")\n",
" print(f\"The initial negativity is: {negativity(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6))}\")\n",
" print(f\"The final negativity is: {negativity(rho_out)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One can observe that the simulation result is in exact accordance with the theoretical values."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"The DEJMPS protocol can effectively extract one entangled pair with higher fidelity from two noisy pairs. And compared to the BBPSSW protocol [2], it can be applied to Bell-diagonal states instead of isotropic states. Note that isotropic state is a special case of Bell-diagonal state. So in this sense, the DEJMPS protocol is more general than the BBPSSW protocol. However, it also shares the same disadvantages of the BBPSSW protocol including the limited type of input states and poor scalability. \n",
"\n",
"Next, We suggest interested readers to check the tutorial on [how to design a new distillation protocol with LOCCNet](./EntanglementDistillation_LOCCNet_EN.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## References\n",
"\n",
"[1] Deutsch, David, et al. \"Quantum privacy amplification and the security of quantum cryptography over noisy channels.\" [Physical Review Letters 77.13 (1996): 2818.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.77.2818)\n",
"\n",
"[2] Bennett, Charles H., et al. \"Purification of noisy entanglement and faithful teleportation via noisy channels.\" [Physical Review Letters 76.5 (1996): 722.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.722)\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.9"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": true
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 纠缠蒸馏 -- LOCCNet 设计协议\n",
"\n",
"<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 概述\n",
"\n",
"量子纠缠在量子通信,量子计算和其他许多量子技术中起着至关重要的作用。因此,如果我们想在这些领域构建实际应用,探测、传输和分发量子纠缠是必不可少的任务。但是在实际操作中,误差是不可避免的。这些误差可能来自于生产纠缠设备的缺陷,也可能是传输量子纠缠时的信道噪声。随着传输距离的增加,噪声会导致纠缠资源的不断减少。而纠缠蒸馏(entanglement distillation)这项技术的开发目的正是为了补偿各种噪声引起的纠缠资源消耗。基本的实现原理为通过操作多对含噪的纠缠态将纠缠资源集中在其中一对纠缠态上,并使之尽可能的接近**最大纠缠态**(qubit 情况下,通常是大家熟知的贝尔态)。从这个意义上讲,也可以将纠缠蒸馏看作一种提纯/纠错协议。此过程通常由 Alice 和 Bob 两个远程参与方执行,由于双方在空间上会相隔一定的距离,因此仅允许本地操作和经典通信(LOCC)[1]。纠缠蒸馏的概念最早由 Bennett 等人于 1996 年提出 [2],最初的协议被称为 **BBPSSW 协议**。后来 Deutsch 等人提出了一个新的蒸馏协议,即 DEJMPS 协议 [3]。\n",
"\n",
"但是,BBPSSW 协议和 DEJMPS 协议都是针对特定噪声态设计的,比如:BBPSSW 是针对 isotropic 态设计而 DEJMPS 协议是针对贝尔对角态(Bell-diagonal state)设计的。实际上,设计出一个通用的能够应对所有噪声进行提纯的协议几乎是不可能的。同时,由于 LOCC 协议结构的复杂性,每次遇到新种类的噪声时用纸和笔重新设计一个蒸馏协议是非常困难的。LOCCNet 作为一个设计 LOCC 协议的机器学习框架,就是为了解决上述问题而存在的。在 LOCCNet 的加持下,只要给定纠缠态中噪声的数学形式,设计对应的蒸馏方案就会变成一件十分简单的事情。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 预备知识\n",
"\n",
"在谈论纠缠蒸馏的时候,我们通常使用蒸馏后的输出态 $\\rho_{out}$ 和贝尔态 $|\\Phi^+\\rangle$ 之间的**保真度** $F$ 来量化纠缠蒸馏协议的好坏,保真度 $F$ 定义为\n",
"\n",
"$$\n",
"F(\\rho_{out}, \\Phi^+) \\equiv \\langle \\Phi^+|\\rho_{out}|\\Phi^+\\rangle.\n",
"\\tag{1}\n",
"$$\n",
"\n",
"**注意:** 通常情况下,LOCC 纠缠蒸馏协议并不是在所有测量结果下都算成功,一般记成功概率为 $p_{succ}$。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 协议的设计逻辑\n",
"\n",
"在本教程中,我们用4份相同的 **Isotropic 态** (也被称为 Werner 态)蒸馏出一份具有更高保真度输出态(相较于初始态,输出态更接近贝尔态 $|\\Phi^+\\rangle$)。这种协议被称为 $4\\rightarrow 1$ LOCC 蒸馏协议。相对应的,BBPSSW 和 DEJMPS 协议属于 $2\\rightarrow 1$ LOCC 蒸馏协议(因为一开始使用了2份相同的初始态)。\n",
"Isotropic 态是由 $|\\Phi^+\\rangle$ 和完全混合态(白噪声)$I/4$ 组成,\n",
"\n",
"$$\n",
"\\rho_{\\text{iso}}(p) = p\\lvert\\Phi^+\\rangle \\langle\\Phi^+\\rvert + (1-p)\\frac{I}{4}, \\quad p \\in [0,1]\n",
"\\tag{2}\n",
"$$\n",
"\n",
"在我们的例子中 $p=0.7$,于是输入态就是\n",
"\n",
"$$\n",
"\\rho_{in} = \\rho_{\\text{iso}}(0.7)= 0.7\\lvert\\Phi^+\\rangle \\langle\\Phi^+\\rvert + 0.075 I.\n",
"\\tag{3}\n",
"$$\n",
"\n",
"为了通过 LOCC 完成纠缠蒸馏,我们需要两位身处于两个地方的参与者 $A$ (Alice) 和 $B$ (Bob)。在最开始的时候,他们共享四份纠缠量子比特对 $\\rho_{A_0B_0}, \\rho_{A_1B_1}, \\rho_{A_2B_2}$ 和 $\\rho_{A_3B_3}$,每一份的初始态都为 $\\rho_{in} = \\rho_{\\text{iso}}(p =0.7)$。如此,Alice 手中有四个量子比特,分别是 $A_0, A_1, A_2, A_3$;对应地,Bob 手中也有四个量子比特,$B_0, B_1, B_2, B_3$。完成上述初始化后,Alice 和 Bob 需要选择通讯的轮数(communication round)$r$,即他们需要交换经典信息(可以是各自的测量结果)多少次。为了方便讨论,这里我们选择通讯轮数为 1。接下来, Alice 和 Bob 需要进行下述操作使得 LOCCNet 学习出最优的本地操作(Local Operation)。更准确的说法是学习出代表本地操作的量子神经网络(Quantum Neural Network, QNN)的最优参数。\n",
"\n",
"1. 设计一个 QNN 架构 $U(\\boldsymbol\\theta)$ 如图 1所示,其中 $R(\\theta)$ 表示单比特通用门。我们可以通过调用 Paddle Quantum 中的 `u3(theta, phi, lam, which_qubit)` 来实现该旋转门。\n",
"2. 在量子比特通过步骤 1. 中设计的 QNN 电路后,Alice 和 Bob 需要对除去 $A_0$ and $B_0$ 的剩余量子比特进行测量。测量结果 $M = \\{m_{A_1}m_{B_1}, m_{A_2}m_{B_2}, m_{A_3}m_{B_3}\\}$ 需要通过经典方式告知对方。\n",
"3. 如果每对的测量结果都相同,即 $m_{A_1}m_{B_1}, m_{A_2}m_{B_2}, m_{A_3}m_{B_3}$ 的结果要么为 00, 要么为 11。这种情况下,我们称蒸馏成功,然后剩余的一对量子比特 $A_0B_0$ 作为输出态被保存,标记为 $\\rho_{AB}'$。如果测量结果不满足上述判定结果,则蒸馏失败,需要丢弃量子比特 $A_0B_0$。\n",
"4. 这里,我们在所以蒸馏成功的情况下定义一个累积的损失函数 $L = \\sum_{m_{A_j}m_{B_j}\\in \\{00,11\\}} \\big(1- \\text{Tr}(\\rho_{tar}\\rho_{AB}')\\big)$,其中 $\\text{Tr}(\\rho_{tar}\\rho_{AB}')$ 表示当前态 $\\rho_{AB}'$ 和目标态 $\\rho_{tar}=\\lvert\\Phi^+\\rangle \\langle \\Phi^+\\rvert$ 之间的态重叠。\n",
"5. 使用梯度下降的优化方案来更新 QNN 中的参数使得损失函数最小化。\n",
"6. 重复步骤 1-5 直至损失函数收敛。\n",
"7. 输出蒸馏后的态 $\\rho_{out} = \\rho'_{A_0B_0}$。\n",
"\n",
"<center><img src=\"figures/distillation-fig-LOCCNet4.png\" height=\"200\" width=\"400\"></center>\n",
"<div style=\"text-align:center\">图 1: 由 LOCCNet 设计的纠缠蒸馏方案示意图 </div>\n",
"\n",
"**注释:** 图 1中的 QNN 架构设计仅是一个示意图,并不固定。感兴趣的读者可以设计一个自己的 QNN 架构。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Paddle Quantum 代码实现\n",
"\n",
"首先,我们需要导入所有依赖包:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-27T07:03:59.029140Z",
"start_time": "2021-01-27T07:03:52.520296Z"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"import paddle.fluid as fluid\n",
"from paddle.complex import matmul, trace\n",
"from paddle_quantum.locc import LoccAnsatz, LoccNet, LoccParty, LoccStatus\n",
"from paddle_quantum.state import isotropic_state, bell_state\n",
"from paddle_quantum.utils import logarithmic_negativity"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"然后,我们需要定义 QNN 和 损失函数"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-27T07:03:59.082475Z",
"start_time": "2021-01-27T07:03:59.036365Z"
}
},
"outputs": [],
"source": [
"class LOCC(LoccNet):\n",
" def __init__(self):\n",
" super(LOCC, self).__init__()\n",
" \n",
" # 添加第一个参与方 Alice\n",
" # 第一个参数 4 代表着 Alice 手里有几个量子比特\n",
" # 第二个参数代表着参与方的名字\n",
" self.add_new_party(4, party_name=\"Alice\")\n",
" \n",
" # 添加第二个参与方 Bob\n",
" self.add_new_party(4, party_name=\"Bob\")\n",
" \n",
" # Alice 的参数\n",
" self.theta_1 = self.create_parameter(shape=[8, 3], attr=fluid.initializer.Uniform(low=0.0, high=2 * np.pi), dtype=\"float64\")\n",
" \n",
" # Bob 的参数\n",
" self.theta_2 = self.create_parameter(shape=[8, 3], attr=fluid.initializer.Uniform(low=0.0, high=2 * np.pi), dtype=\"float64\")\n",
" \n",
" # 生成输入态 isotropic state\n",
" _state = fluid.dygraph.to_variable(isotropic_state(2, 0.7))\n",
" \n",
" # 初始化量子态\n",
" # ('Alice', 0) 代表 Alice 的第一个量子比特 A0\n",
" # ('Bob', 0) 代表 Bob 的第一个量子比特 B0\n",
" self.set_init_status(_state, [[\"Alice\", 0], [\"Bob\", 0]])\n",
" self.set_init_status(_state, [[\"Alice\", 1], [\"Bob\", 1]])\n",
" self.set_init_status(_state, [[\"Alice\", 2], [\"Bob\", 2]])\n",
" self.set_init_status(_state, [[\"Alice\", 3], [\"Bob\", 3]])\n",
"\n",
" def QNN(self, cir, theta):\n",
" '''\n",
" 定义图 1 中的 QNN\n",
" '''\n",
" cir.u3(*theta[0], 0)\n",
" cir.u3(*theta[1], 1)\n",
" cir.u3(*theta[2], 2)\n",
" cir.u3(*theta[3], 3)\n",
" cir.cnot([0, 1])\n",
" cir.cnot([1, 2])\n",
" cir.cnot([2, 3])\n",
" cir.cnot([3, 0])\n",
" cir.u3(*theta[4], 0)\n",
" cir.u3(*theta[5], 1)\n",
" cir.u3(*theta[6], 2)\n",
" cir.u3(*theta[7], 3)\n",
"\n",
" def New_Protocol(self):\n",
" status = self.init_status\n",
"\n",
" # 创建 Alice 的局部操作\n",
" cir1 = self.create_ansatz(\"Alice\")\n",
" self.QNN(cir1, self.theta_1)\n",
"\n",
" # 创建 Bob 的局部操作\n",
" cir2 = self.create_ansatz(\"Bob\")\n",
" self.QNN(cir2, self.theta_2)\n",
"\n",
" # 运行 Alice 的电路\n",
" status = cir1.run(status)\n",
" \n",
" # 运行 Bob 的电路\n",
" status = cir2.run(status)\n",
" \n",
" # 测量量子比特,[\"000000\", \"000011\",\"001100\",\"110000\",\"001111\",\"111100\",\"110011\",\"111111\"] 代表蒸馏成功的情况\n",
" status1 = self.measure(status, [[\"Alice\", 1], [\"Bob\", 1],[\"Alice\", 2], [\"Bob\", 2], [\"Alice\", 3], [\"Bob\", 3]], \n",
" [\"000000\", \"000011\", \"001100\", \"110000\", \"001111\", \"111100\", \"110011\", \"111111\"])\n",
" \n",
" # 取偏迹除去测量后的量子比特,只留下 A0&B0 \n",
" status_fin = self.partial_state(status1, [[\"Alice\", 0], [\"Bob\", 0]])\n",
" target_state = fluid.dygraph.to_variable(bell_state(2))\n",
" \n",
" # 计算损失函数\n",
" loss = 0\n",
" for idx in range(0, len(status_fin)):\n",
" loss += 1 - trace(matmul(target_state, status_fin[idx].state)).real[0]\n",
" return loss, status_fin\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"最后,通过基于梯度的优化方法使得损失函数最小化。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-27T07:12:19.023140Z",
"start_time": "2021-01-27T07:03:59.103836Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"itr 0: 5.974937567506047\n",
"itr 10: 1.3569325419999818\n",
"itr 20: 1.1205194635673945\n",
"itr 30: 0.951684388970055\n",
"itr 40: 0.5876979234625004\n",
"itr 50: 0.5372695244330837\n",
"itr 60: 0.5199700730199454\n",
"itr 70: 0.5110181973259903\n",
"itr 80: 0.5064717635676458\n",
"itr 90: 0.5051218758007482\n",
"输入态的保真度为:0.77500\n",
"输出态的保真度为:0.93688\n",
"提纯成功率为:0.38654\n",
"========================================================\n",
"输出态为:\n",
" [[ 4.790e-01+0.j 3.000e-04+0.0003j -3.000e-04+0.0003j\n",
" 4.579e-01+0.0004j]\n",
" [ 3.000e-04-0.0003j 2.100e-02-0.j -0.000e+00+0.j\n",
" 3.000e-04-0.0003j]\n",
" [-3.000e-04-0.0003j -0.000e+00-0.j 2.100e-02+0.j\n",
" -3.000e-04-0.0003j]\n",
" [ 4.579e-01-0.0004j 3.000e-04+0.0003j -3.000e-04+0.0003j\n",
" 4.790e-01+0.j ]]\n",
"初始态的 logarithmic negativity 为: 0.6322682154995127\n",
"输出态的 logarithmic negativity 为: 0.9059439306384385\n"
]
}
],
"source": [
"ITR = 100 # 循环次数\n",
"LR = 0.2 # 学习率\n",
"\n",
"# 开启动态图模式\n",
"with fluid.dygraph.guard(fluid.CPUPlace()):\n",
" net = LOCC()\n",
"\n",
" # 选择 Adam 优化器\n",
" opt = fluid.optimizer.AdamOptimizer(learning_rate=LR, parameter_list=net.parameters())\n",
" loss_list = [] \n",
" \n",
" # 优化循环\n",
" for itr in range(ITR):\n",
" loss, status_fin = net.New_Protocol()\n",
" # 反向传播\n",
" loss.backward() \n",
" opt.minimize(loss)\n",
" # 清除梯度\n",
" net.clear_gradients() \n",
" loss_list.append(loss.numpy()[0])\n",
" \n",
" # 打印训练结果\n",
" if itr % 10 == 0:\n",
" print(\"itr \" + str(itr) + \":\", loss.numpy()[0])\n",
"\n",
" # 计算输入态的保真度\n",
" fidelity_in = (3 * 0.7 + 1) / 4\n",
" # 计算输出态的保真度\n",
" fidelity = (len(status_fin) - loss) / len(status_fin)\n",
" # 计算成功率\n",
" suc_rate = sum([s.prob for s in status_fin])\n",
"\n",
" print(\"输入态的保真度为:%.5f\" % fidelity_in)\n",
" print(\"输出态的保真度为:%.5f\" % fidelity.numpy()[0])\n",
" print(\"提纯成功率为:%.5f\" % suc_rate.numpy()[0])\n",
" rho_out = status_fin[0].state.numpy()\n",
" print(\"========================================================\")\n",
" print(f\"输出态为:\\n {np.around(rho_out, 4)}\")\n",
" print(f\"初始态的 logarithmic negativity 为: {logarithmic_negativity(isotropic_state(2, 0.7))}\")\n",
" print(f\"输出态的 logarithmic negativity 为: {logarithmic_negativity(rho_out)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 结论\n",
"\n",
"如同数值结果所示,由 LOCCNet 设计出新型蒸馏协议可以把4份保真度为0.775的 isotropic 态蒸馏出1份保真度为0.937的两比特量子态。在相同条件下,扩展版的 DEJMPS 协议 [3] 只能够提纯出保真度为 0.924 的量子态,低于新的蒸馏协议。除了能够获得高保真度外,我们框架有着更广的适用范围和良好的可扩展性。对蒸馏的感兴趣的读者可以尝试多轮通讯会对蒸馏结果产生什么样的结果。当然,我们也欢迎读者用该框架来蒸馏含有不同噪声的态。\n",
"\n",
"LOCCNet 有着广泛的应用,纠缠蒸馏仅仅是其中的一小部分。此外,我们想要强调的是通过 LOCCNet 训练出来的协议是可以在近期量子设备上实现从而进行验证的。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## 参考文献\n",
"\n",
"[1] Chitambar, Eric, et al. \"Everything you always wanted to know about LOCC (but were afraid to ask).\" [Communications in Mathematical Physics 328.1 (2014): 303-326.](https://link.springer.com/article/10.1007/s00220-014-1953-9)\n",
"\n",
"[2] Bennett, Charles H., et al. \"Purification of noisy entanglement and faithful teleportation via noisy channels.\" [Physical Review Letters 76.5 (1996): 722.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.722)\n",
"\n",
"[3] Deutsch, David, et al. \"Quantum privacy amplification and the security of quantum cryptography over noisy channels.\" [Physical Review Letters 77.13 (1996): 2818.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.77.2818)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.9"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -4561,7 +4561,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.8"
"version": "3.7.9"
},
"toc": {
"base_numbering": 1,
......
......@@ -79,7 +79,7 @@
"output_type": "stream",
"text": [
"Random Hamiltonian in Pauli string format = \n",
" [[0.2053246312210153, 'y1'], [0.8007921371055502, 'y0'], [-0.005452633476696667, 'y1'], [0.6584698440348358, 'z0'], [0.8231741294360668, 'y0,x1'], [-0.9500264430442884, 'z1,z0'], [0.500344392541574, 'x1,z0'], [0.26774681450914084, 'z1'], [-0.6560070288135618, 'y0,z1'], [-0.24860662455587024, 'x1']]\n"
" [[-0.12086078882948925, 'z0,y1'], [0.8520481243020479, 'x0'], [0.7311915310296655, 'x1'], [0.8878180549783599, 'x1'], [-0.07152647722934247, 'z0'], [0.36890035805078325, 'z1,z0'], [-0.47650461185021764, 'z1,y0'], [0.957686278969355, 'z0,y1'], [-0.4742145513250544, 'y0'], [-0.30811279345705755, 'x1']]\n"
]
}
],
......@@ -124,7 +124,7 @@
" cir = UAnsatz(N)\n",
" \n",
" # 调用内置的量子神经网络模板\n",
" cir.universal_2_qubit_gate(theta)\n",
" cir.universal_2_qubit_gate(theta, [0, 1])\n",
"\n",
" # 返回量子神经网络所模拟的酉矩阵 U\n",
" return cir.U"
......@@ -239,11 +239,11 @@
"name": "stdout",
"output_type": "stream",
"text": [
"iter: 10 loss: -5.3321\n",
"iter: 20 loss: -7.4093\n",
"iter: 30 loss: -7.6601\n",
"iter: 40 loss: -7.8402\n",
"iter: 50 loss: -8.0516\n"
"iter: 10 loss: -6.1446\n",
"iter: 20 loss: -7.7827\n",
"iter: 30 loss: -8.0978\n",
"iter: 40 loss: -8.4615\n",
"iter: 50 loss: -8.4589\n"
]
}
],
......@@ -303,14 +303,14 @@
"name": "stdout",
"output_type": "stream",
"text": [
"The estimated ground state energy is: [-2.89029006]\n",
"The theoretical ground state energy: -2.914376077505768\n",
"The estimated 1st excited state energy is: [-0.05679422]\n",
"The theoretical 1st excited state energy: -0.07729623846713303\n",
"The estimated 2nd excited state energy is: [0.73281967]\n",
"The theoretical 2nd excited state energy: 0.7671454582095175\n",
"The estimated 3rd excited state energy is: [2.21426461]\n",
"The theoretical 3rd excited state energy: 2.2245268577633834\n"
"The estimated ground state energy is: [-2.3665305]\n",
"The theoretical ground state energy: -2.385744737010799\n",
"The estimated 1st excited state energy is: [-1.34818389]\n",
"The theoretical 1st excited state energy: -1.3356376227295346\n",
"The estimated 2nd excited state energy is: [1.337023]\n",
"The theoretical 2nd excited state energy: 1.3356376227295335\n",
"The estimated 3rd excited state energy is: [2.37769139]\n",
"The theoretical 3rd excited state energy: 2.3857447370107985\n"
]
}
],
......@@ -365,7 +365,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.10"
"version": "3.7.0"
},
"toc": {
"base_numbering": 1,
......
此差异已折叠。
......@@ -15,7 +15,7 @@
"source": [
"## Overview\n",
"\n",
"It is widely believed that one of the most promising applications of quantum computing in the near future is solving quantum chemistry problems [1-2]. **Variational Quantum Eigensolver** (VQE) is a strong proof to this possibility of studying quantum chemistry with **Noisy Intermediate-Scale Quantum** (NISQ) devices [1-4]. The core task is to solve the energy ground state of any molecular Hamiltonian $\\hat{H}$ by preparing a parametrized wave function ansatz $|\\Psi(\\boldsymbol\\theta)\\rangle$ on a quantum computer and adopt classical optimization methods (e.g. gradient descent) to adjust the parameters $\\boldsymbol\\theta$ to minimize the expectation value $\\langle \\Psi(\\boldsymbol\\theta)|\\hat{H}|\\Psi(\\boldsymbol\\theta)\\rangle$. This approach is based on the **Rayleigh-Ritz variational principle**. \n",
"It is widely believed that one of the most promising applications of quantum computing in the near future is solving quantum chemistry problems [1-2]. **Variational Quantum Eigensolver** (VQE) is a strong proof to this possibility of studying quantum chemistry with **Noisy Intermediate-Scale Quantum** (NISQ) devices [1-4]. The core task is to solve the ground state of any molecular Hamiltonian $\\hat{H}$ by preparing a parametrized wave function ansatz $|\\Psi(\\boldsymbol\\theta)\\rangle$ on a quantum computer and adopt classical optimization methods (e.g. gradient descent) to adjust the parameters $\\boldsymbol\\theta$ to minimize the expectation value $\\langle \\Psi(\\boldsymbol\\theta)|\\hat{H}|\\Psi(\\boldsymbol\\theta)\\rangle$. This approach is based on the **Rayleigh-Ritz variational principle**. \n",
"\n",
"$$\n",
"E_0 = \\min_{\\boldsymbol\\theta} \\langle \\Psi(\\boldsymbol\\theta)|\\hat{H}|\\Psi(\\boldsymbol\\theta)\\rangle.\n",
......@@ -88,7 +88,7 @@
"\n",
"\n",
"\n",
"**Note:** A detailed review on quantum chemistry and existing classical computational methods are far beyond the scope of this tutorial, we refer the enthusiastic readers to the standard textbooks *'Molecular Electronic-Structure Theory'* [5] by Helgaker and *'Modern Quantum Chemistry: Introduction to Advanced Electronic Structure Theory'* [7] by Szabo & Ostlund. To bridge to knowledge gap between quantum chemistry and quantum computing, please check the following review papers [Quantum computational chemistry](https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.92.015003) [2] and [Quantum chemistry in the age of quantum computing](https://pubs.acs.org/doi/10.1021/acs.chemrev.8b00803) [1].\n",
"**Note:** A detailed review on quantum chemistry and existing classical computational methods are far beyond the scope of this tutorial, we refer the enthusiastic readers to the standard textbooks *'Molecular Electronic-Structure Theory'* [5] by Helgaker and *'Modern Quantum Chemistry: Introduction to Advanced Electronic Structure Theory'* [7] by Szabo & Ostlund. To bridge to knowledge gap between quantum chemistry and quantum computing, please check the following review papers [Quantum computational chemistry](https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.92.015003) [2] and [Quantum Chemistry in the Age of Quantum Computing](https://pubs.acs.org/doi/10.1021/acs.chemrev.8b00803) [1].\n",
"\n",
"**Note:** For energy calculation, it is desired to reach the **chemical accuracy** of $1.6\\times10^{-3}$ Hartree or 1 kcal/mol . "
]
......@@ -97,7 +97,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Energy ground state of the hydrogen molecule $H_2$\n",
"## Ground state of the hydrogen molecule $H_2$\n",
"\n",
"### Building electronic Hamiltonian\n",
"\n",
......@@ -1834,7 +1834,7 @@
"\n",
"## References\n",
"\n",
"[1] [Cao, Yudong, et al. Quantum chemistry in the age of quantum computing. Chemical reviews 119.19 (2019): 10856-10915.](https://pubs.acs.org/doi/10.1021/acs.chemrev.8b00803)\n",
"[1] [Cao, Yudong, et al. Quantum Chemistry in the Age of Quantum Computing. Chemical reviews 119.19 (2019): 10856-10915.](https://pubs.acs.org/doi/10.1021/acs.chemrev.8b00803)\n",
"\n",
"[2] [McArdle, Sam, et al. Quantum computational chemistry. Reviews of Modern Physics 92.1 (2020): 015003.](https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.92.015003)\n",
"\n",
......@@ -1868,7 +1868,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
"version": "3.7.9"
},
"toc": {
"base_numbering": 1,
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册