提交 eadbc3eb 编写于 作者: Q Quleaf

update to v2.1.1

上级 fbcf1296
# Byte-compiled / optimized / DLL files
.idea
.DS_Store
.vscode/
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# .dat file
*.dat
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# qchem_data folder when run psi4 calculation
qchem_data/
output
*.egg-info
.ipynb_checkpoints
\ No newline at end of file
......@@ -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.0-orange.svg?style=flat-square&logo=pypi"/>
<img src="https://img.shields.io/badge/pypi-v2.1.1-orange.svg?style=flat-square&logo=pypi"/>
</a>
<!-- Python -->
<a href="https://www.python.org/">
......@@ -71,7 +71,7 @@ Paddle Quantum aims at establishing a bridge between artificial intelligence (AI
### Install PaddlePaddle
This dependency will be automatically satisfied when users install Paddle Quantum. Please refer to [PaddlePaddle](https://www.paddlepaddle.org.cn/install/quick)'s official installation and configuration page. This project requires PaddlePaddle 2.0.1+.
This dependency will be automatically satisfied when users install Paddle Quantum. Please refer to [PaddlePaddle](https://www.paddlepaddle.org.cn/install/quick)'s official installation and configuration page. This project requires PaddlePaddle 2.1.1+.
### Install Paddle Quantum
......@@ -147,6 +147,9 @@ We provide tutorials covering quantum simulation, machine learning, combinatoria
2. [Solving Max-Cut Problem with QAOA](./tutorial/combinatorial_optimization/MAXCUT_EN.ipynb)
3. [Large-scale QAOA via Divide-and-Conquer](./tutorial/combinatorial_optimization/DC-QAOA_EN.ipynb)
4. [Travelling Salesman Problem](./tutorial/combinatorial_optimization/TSP_EN.ipynb)
5. [Quantum Finance Application on Arbitrage Opportunity Optimization](./tutorial/combinatorial_optimization/ArbitrageOpportunityOptimation_EN.ipynb)
6. [Quantum Finance Application on Portfolio Optimization](./tutorial/combinatorial_optimization/PortfolioOptimization_EN.ipynb)
7. [Quantum Finance Application on Portfolio Diversification](./tutorial/combinatorial_optimization/PortfolioDiversification_EN.ipynb)
- [LOCC with QNN (LOCCNet)](./tutorial/locc)
1. [Local Operations and Classical Communication in QNN (LOCCNet)](./tutorial/locc/LOCCNET_Tutorial_EN.ipynb)
......@@ -159,6 +162,7 @@ We provide tutorials covering quantum simulation, machine learning, combinatoria
- [QNN Research](./tutorial/qnn_research)
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)
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).
......
......@@ -34,7 +34,7 @@
</a>
<!-- PyPI -->
<a href="https://pypi.org/project/paddle-quantum/">
<img src="https://img.shields.io/badge/pypi-v2.1.0-orange.svg?style=flat-square&logo=pypi"/>
<img src="https://img.shields.io/badge/pypi-v2.1.1-orange.svg?style=flat-square&logo=pypi"/>
</a>
<!-- Python -->
<a href="https://www.python.org/">
......@@ -71,7 +71,7 @@
### 安装 PaddlePaddle
当用户安装 Paddle Quantum 时会自动下载安装这个关键依赖包。关于 PaddlePaddle 更全面的安装信息请参考 [PaddlePaddle](https://www.paddlepaddle.org.cn/install/quick) 安装配置页面。此项目需求 PaddlePaddle 2.0.1+。
当用户安装 Paddle Quantum 时会自动下载安装这个关键依赖包。关于 PaddlePaddle 更全面的安装信息请参考 [PaddlePaddle](https://www.paddlepaddle.org.cn/install/quick) 安装配置页面。此项目需求 PaddlePaddle 2.1.1+。
### 安装 Paddle Quantum
......@@ -153,6 +153,9 @@ Paddle Quantum(量桨)建立起了人工智能与量子计算的桥梁,为
2. [QAOA 求解最大割问题](./tutorial/combinatorial_optimization/MAXCUT_CN.ipynb)
3. [大规模量子近似优化分治算法(DC-QAOA)](./tutorial/combinatorial_optimization/DC-QAOA_CN.ipynb)
4. [旅行商问题](./tutorial/combinatorial_optimization/TSP_CN.ipynb)
5. [量子金融应用:最佳套利机会](./tutorial/combinatorial_optimization/ArbitrageOpportunityOptimation_CN.ipynb)
6. [量子金融应用:投资组合优化](./tutorial/combinatorial_optimization/PortfolioOptimization_CN.ipynb)
7. [量子金融应用:投资组合分散化](./tutorial/combinatorial_optimization/PortfolioDiversification_CN.ipynb)
- [LOCC 量子神经网络(LOCCNet)](./tutorial/locc)
1. [LOCC 量子神经网络](./tutorial/locc/LOCCNET_Tutorial_CN.ipynb)
......@@ -165,6 +168,7 @@ Paddle Quantum(量桨)建立起了人工智能与量子计算的桥梁,为
- [量子神经网络研究](./tutorial/qnn_research)
1. [量子神经网络的贫瘠高原效应(Barren Plateaus)](./tutorial/qnn_research/BarrenPlateaus_CN.ipynb)
2. [噪声模型与量子信道](./tutorial/qnn_research/Noise_CN.ipynb)
3. [使用量子电路计算梯度](./tutorial/qnn_research/Gradient_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)
......
......@@ -981,7 +981,7 @@
"theta = np.random.randn(DEPTH, N, 1)\n",
"\n",
"# 调用内置的 |00..0> 初始态\n",
"initial_state1 = vec(N)\n",
"initial_state1 = vec(0, N)\n",
"# 调用内置的随机量子态 |psi>\n",
"initial_state2 = vec_random(N)\n",
" \n",
......
......@@ -788,7 +788,7 @@
"theta = np.random.randn(DEPTH, N, 1)\n",
"\n",
"# Call the built-in |00..0> initial state\n",
"initial_state1 = vec(N)\n",
"initial_state1 = vec(0, N)\n",
"# Call the built-in random quantum state |psi>\n",
"initial_state2 = vec_random(N)\n",
" \n",
......
......@@ -71,15 +71,15 @@ class Net(paddle.nn.Layer):
# Use computational basis to calculate each expectation value, which is the same
# as a diagonal element in U^dagger*H*U
loss_components = [
loss_struct[0][0],
loss_struct[1][1],
loss_struct[2][2],
loss_struct[3][3]
]
loss_components = []
for i in range(len(loss_struct)):
loss_components.append(loss_struct[i][i])
# Calculate the weighted loss function
loss = 4 * loss_components[0] + 3 * loss_components[1] + 2 * loss_components[2] + 1 * loss_components[3]
loss = 0
for i in range(len(loss_components)):
weight = 4 - i
loss += weight * loss_components[i]
return loss, loss_components
......@@ -128,17 +128,36 @@ def main():
loss_components = Paddle_SSVQE(H)
print('The estimated ground state energy is: ', loss_components[0].numpy())
print('The theoretical ground state energy: ', numpy.linalg.eigh(H)[0][0])
print('The estimated 1st excited state energy is: ', loss_components[1].numpy())
print('The theoretical 1st excited state energy: ', numpy.linalg.eigh(H)[0][1])
print('The estimated 2nd excited state energy is: ', loss_components[2].numpy())
print('The theoretical 2nd excited state energy: ', numpy.linalg.eigh(H)[0][2])
print('The estimated 3rd excited state energy is: ', loss_components[3].numpy())
print('The theoretical 3rd excited state energy: ', numpy.linalg.eigh(H)[0][3])
def output_ordinalvalue(num):
r"""
Convert to ordinal value
Args:
num (int): input number
Return:
(str): output ordinal value
"""
if num == 1:
return str(num) + "st"
elif num == 2:
return str(num) + "nd"
elif num == 3:
return str(num) + "rd"
else:
return str(num) + 'th'
for i in range(len(loss_components)):
if i == 0:
print('The estimated ground state energy is: ', loss_components[i].numpy())
print('The theoretical ground state energy is: ', numpy.linalg.eigh(H)[0][i])
else:
print('The estimated {} excited state energy is: {}'.format(
output_ordinalvalue(i), loss_components[i].numpy())
)
print('The theoretical {} excited state energy is: {}'.format(
output_ordinalvalue(i), numpy.linalg.eigh(H)[0][i])
)
if __name__ == '__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.
"""
ExpecVal Class
"""
import paddle
from paddle.autograd import PyLayer
__all__ = [
"ExpecVal"
]
class ExpecVal(PyLayer):
r"""PaddlePaddle 自定义 Python 算子,用来计算量子电路输出的量子态关于可观测量 H 的期望值。
"""
@staticmethod
def forward(ctx, cir, theta, grad_func, hamiltonian, delta=None, shots=0):
r"""前向函数。
Hint:
如果想输入的可观测量的矩阵为 :math:`0.7Z\otimes X\otimes I+0.2I\otimes Z\otimes I` 。则 ``H`` 的 ``list`` 形式为 ``[[0.7, 'Z0, X1'], [0.2, 'Z1']]`` 。
Args:
cir (UAnsatz): 目标量子电路
theta (paddle.Tensor): 量子电路中的需要被优化的参数
grad_func (string): 用于计算梯度的函数名,应为 ``'finite_diff'`` 或 ``'param_shift'``
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
delta (float): 差分法中需要用到的 delta,默认为 ``None``
shots (int, optional): 表示测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
Returns:
paddle.Tensor: 量子电路输出的量子态关于可观测量 H 的期望值
代码示例:
.. code-block:: python
import numpy as np
import paddle
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.expecval import ExpecVal
N = 2
D = 2
theta = paddle.uniform(shape=[N * D], dtype='float64', min=0.0, max=np.pi * 2)
theta.stop_gradient = False
cir = UAnsatz(N)
cir.real_entangled_layer(theta, D)
cir.run_state_vector()
H = [[1.0, 'z0,z1']]
delta = 0.01
shots = 0
z = ExpecVal.apply(cir, cir.get_param(), 'finite_diff', H, delta, shots)
print(z)
::
Tensor(shape=[1], dtype=float64, place=CPUPlace, stop_gradient=False,
[0.61836319])
"""
assert grad_func in {'finite_diff', 'param_shift'}, "grad_func must be one of 'finite_diff' or 'param_shift'"
# Pass grad_func, cir, theta, delta, shots, and Hamiltonian into the backward function by adding temporary attributes
ctx.grad_func = grad_func
ctx.cir = cir
ctx.theta = theta
ctx.delta = delta
ctx.shots = shots
ctx.Hamiltonian = hamiltonian
# Compute the expectation value
cir.update_param(theta)
expec_val = cir.expecval(ctx.Hamiltonian, shots)
return expec_val
@staticmethod
def backward(ctx, dy):
r"""反向函数。
Args:
dy (paddle.Tensor): 前向函数输出的期望值的梯度
Returns:
paddle.Tensor: 前向函数中输入的参数 ``theta`` 的梯度
代码示例:
.. code-block:: python
import numpy as np
import paddle
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.expecval import ExpecVal
N = 2
D = 2
theta = paddle.uniform(shape=[N * D], dtype='float64', min=0.0, max=np.pi * 2)
theta.stop_gradient = False
cir = UAnsatz(N)
cir.real_entangled_layer(theta, D)
cir.run_state_vector()
H = [[1.0, 'z0,z1']]
delta = 0.01
shots = 0
z = ExpecVal.apply(cir, cir.get_param(), 'finite_diff', H, delta, shots)
temp = paddle.square(z)
temp.backward()
"""
# Get expec_func, grad_func, theta, delta, and args
cir = ctx.cir
grad_func = ctx.grad_func
delta = ctx.delta
shots = ctx.shots
Hamiltonian = ctx.Hamiltonian
# Compute the gradient
if grad_func == "finite_diff":
assert delta is not None, "Finite difference gradient requires an input 'delta'"
grad = dy * cir.finite_difference_gradient(Hamiltonian, delta, shots)
else:
grad = dy * cir.param_shift_gradient(Hamiltonian, shots)
grad.stop_gradient = False
return paddle.reshape(grad, ctx.theta.shape)
# 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.
"""
Functions and data simulator class of quantum finance
"""
import fastdtw
import numpy as np
from paddle_quantum.utils import Hamiltonian
__all__ = [
"DataSimulator",
"portfolio_optimization_hamiltonian",
"portfolio_diversification_hamiltonian",
"arbitrage_opportunities_hamiltonian"
]
class DataSimulator:
r"""用于生成和计算投资组合优化和投资分散化问题要用的数据和相关参数
"""
def __init__(self, stocks, start=None, end=None):
r"""构造函数,用于实例化一个 ``DataSimulator`` 对象。
Args:
stocks (list): 表示所有可投资股票的名字
start (datetime): 默认为 ``None``,表示随机生成股票数据时交易日的起始日期
end (datetime): 默认为 ``None``,表示随机生成股票数据时交易日的结束日期
"""
self._n = len(stocks)
self._stocks = stocks
if start and end:
self._start = start
self._end = end
self._data = []
self.asset_return_mean = None
self.asset_return_cov = None
def set_data(self, data):
r"""决定实验使用的数据是随机生成的还是用户本地输入的
Args:
data (list): 用户输入的股票数据
"""
if len(data) == self._n:
self._data = data
else:
print("invalid data, data is still empty.")
self._data = []
def randomly_generate(self):
r"""根据开始日期和结束日期随机生成用于实验的股票数据
Note:
若要随机生成股票数据,需要以 ``datetime`` 包中的格式指定开始日期和结束日期,如 ``start = datetime.datetime(2016, 1, 1)``
"""
if self._start and self._end:
num_days = (self._end - self._start).days
for _ in self._stocks:
fluctuation = np.random.standard_normal(num_days)
fluctuation = np.cumsum(fluctuation)
data_i = np.random.randint(1, 101, size=1) + fluctuation
trimmed_data_i = [max(data_i[j], 0) for j in range(num_days)]
if 0 in trimmed_data_i:
zero_ind = trimmed_data_i.index(0)
trimmed_data_i = trimmed_data_i[:zero_ind] + [0 for _ in range(num_days - zero_ind)]
self._data.append(trimmed_data_i)
else:
print("Please provide the start time and the end time you want to generate stock data.")
def get_asset_return_mean_vector(self):
r"""用于计算所有可投资股票的平均投资回报率
Returns:
list: 所有可投资的股票的平均投资回报率
"""
returns = []
for i in range(self._n):
return_i = [self._data[i][j + 1] / self._data[i][j] - 1
if self._data[i][j] != 0
else np.nan for j in range(len(self._data[i]) - 1)]
returns.append(return_i)
self.asset_return_mean = np.mean(returns, axis=1)
return self.asset_return_mean
def get_asset_return_covariance_matrix(self):
r"""用于计算所有可投资股票回报率之间的协方差矩阵
Returns:
list: 所有可投资股票回报率之间的协方差矩阵
"""
returns = []
for i in range(self._n):
return_i = [self._data[i][j + 1] / self._data[i][j] - 1
if self._data[i][j] != 0
else np.nan for j in range(len(self._data[i]) - 1)]
returns.append(return_i)
self.asset_return_cov = np.cov(returns)
return self.asset_return_cov
def get_similarity_matrix(self):
r"""计算各股票之间的相似矩阵
通过动态时间规整算法(Dynamic Time Warping, DTW)计算两股票之间的相似性
Returns:
list: 各股票间的相似矩阵
"""
self.rho = np.zeros((self._n, self._n))
for i in range(0, self._n):
self.rho[i, i] = 1
for j in range(i + 1, self._n):
curr_rho, _ = fastdtw.fastdtw(self._data[i], self._data[j])
curr_rho = 1 / curr_rho
self.rho[i, j] = curr_rho
self.rho[j, i] = curr_rho
return self.rho
def portfolio_optimization_hamiltonian(penalty, mu, sigma, q, budget):
r"""构建投资组合优化问题的哈密顿量
Args:
penalty (int): 惩罚参数
mu (list): 各股票的预期回报率
sigma (list): 各股票回报率间的协方差矩阵
q (float): 投资股票的风险
budget (int): 投资预算, 即要投资的股票数量
.. math::
C(x) = q \sum_i \sum_j S_{ji}x_ix_j - \sum_{i}x_i \mu_i + A \left(B - \sum_i x_i\right)^2
Hint:
将布尔变量 :math:`x_i` 映射到哈密顿矩阵上,:math:`x_i \mapsto \frac{I-Z_i}{2}`
Returns:
Hamiltonian: 投资组合优化问题的哈密顿量
"""
n = len(mu)
H_C_list1 = []
for i in range(n):
for j in range(n):
sigma_ij = sigma[i][j]
H_C_list1.append([sigma_ij / 4, 'I'])
if i != j:
H_C_list1.append([sigma_ij / 4, 'Z' + str(i) + ',Z' + str(j)])
else:
H_C_list1.append([sigma_ij / 4, 'I'])
H_C_list1.append([- sigma_ij / 4, 'Z' + str(i)])
H_C_list1.append([- sigma_ij / 4, 'Z' + str((j))])
H_C_list1 = [[q * c, s] for (c, s) in H_C_list1]
H_C_list2 = []
for i in range(n):
H_C_list2.append([- mu[i] / 2, 'I'])
H_C_list2.append([mu[i] / 2, 'Z' + str(i)])
H_C_list3 = [[budget ** 2, 'I']]
for i in range(n):
H_C_list3.append([- 2 * budget / 2, 'I'])
H_C_list3.append([2 * budget / 2, 'Z' + str(i)])
H_C_list3.append([2 / 4, 'I'])
H_C_list3.append([- 2 / 4, 'Z' + str(i)])
for ii in range(i):
H_C_list3.append([2 / 4, 'I'])
H_C_list3.append([2 / 4, 'Z' + str(i) + ',Z' + str(ii)])
H_C_list3.append([- 2 / 4, 'Z' + str(i)])
H_C_list3.append([- 2 / 4, 'Z' + str(ii)])
H_C_list3 = [[penalty * c, s] for (c, s) in H_C_list3]
H_C_list = H_C_list1 + H_C_list2 + H_C_list3
po_hamiltonian = Hamiltonian(H_C_list)
return po_hamiltonian
def portfolio_diversification_hamiltonian(penalty, rho, q):
r"""构建投资组合分散化问题的哈密顿量
Args:
penalty (int): 惩罚参数
rho (list): 各股票间的相似矩阵
q (int): 股票聚类的类别数
.. 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 \\
&\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}
Hint:
将布尔变量 :math:`x_{ij}` 映射到哈密顿矩阵上,:math:`x_{ij} \mapsto \frac{I-Z_{ij}}{2}`
Returns:
Hamiltonian: 投资组合分散化问题的哈密顿量
"""
n = len(rho)
H_C_list1 = []
for i in range(n):
for j in range(n):
rho_ij = - rho[i][j]
H_C_list1.append([rho_ij / 2, 'I'])
H_C_list1.append([- rho_ij / 2, 'Z' + str(i * n + j)])
H_C_list2 = [[q ** 2, 'I']]
for j in range(n):
H_C_list2.append([- q, 'I'])
H_C_list2.append([q, 'Z' + str(n ** 2 + j)])
H_C_list2.append([1 / 2, 'I'])
H_C_list2.append([- 1 / 2, 'Z' + str(n ** 2 + j)])
for jj in range(j):
H_C_list2.append([1 / 2, 'I'])
H_C_list2.append([1 / 2, 'Z' + str(n ** 2 + j) + ',Z' + str(n ** 2 + jj)])
H_C_list2.append([- 1 / 2, 'Z' + str(n ** 2 + j)])
H_C_list2.append([- 1 / 2, 'Z' + str(n ** 2 + jj)])
H_C_list2 = [[penalty * c, s] for (c, s) in H_C_list2]
H_C_list3 = []
for i in range(n):
H_C_list3.append([1, 'I'])
for j in range(n):
H_C_list3.append([- 1, 'I'])
H_C_list3.append([1, 'Z' + str(i * n + j)])
H_C_list3.append([1 / 2, 'I'])
H_C_list3.append([- 1 / 2, 'Z' + str(i * n + j)])
for jj in range(j):
H_C_list3.append([1 / 2, 'I'])
H_C_list3.append([- 1 / 2, 'Z' + str(i * n + j)])
H_C_list3.append([1 / 2, 'Z' + str(i * n + j) + ',Z' + str(i * n + jj)])
H_C_list3.append([- 1 / 2, 'Z' + str(i * n + jj)])
H_C_list3 = [[penalty * c, s] for (c, s) in H_C_list3]
H_C_list4 = []
for j in range(n):
H_C_list4.append([1 / 2, 'I'])
H_C_list4.append([- 1 / 2, 'Z' + str(j * n + j) + ',Z' + str(n ** 2 + j)])
H_C_list4 = [[penalty * c, s] for (c, s) in H_C_list4]
H_C_list5 = []
for i in range(n):
for j in range(n):
H_C_list5.append([1 / 4, 'I'])
H_C_list5.append([- 1 / 4, 'Z' + str(i * n + j)])
H_C_list5.append([1 / 4, 'Z' + str(n ** 2 + j)])
H_C_list5.append([- 1 / 4, 'Z' + str(i * n + j) + ',Z' + str(n ** 2 + j)])
H_C_list5 = [[penalty * c, s] for (c, s) in H_C_list5]
H_C_list = H_C_list1 + H_C_list2 + H_C_list3 + H_C_list4 + H_C_list5
pd_hamiltonian = Hamiltonian(H_C_list)
return pd_hamiltonian
def arbitrage_opportunities_hamiltonian(g, penalty, n, K):
r"""构建最佳套利机会问题的哈密顿量
Args:
g (networkx.DiGraph): 不同货币市场间转换的图形化表示
A (int): 惩罚参数
n (int): 货币种类的数量,即图 g 中的顶点数量
K (int): 套利回路中包含的顶点数
.. math::
C(x) = - P(x) + A\sum_{k=0}^{K-1} \left(1 - \sum_{i=0}^{n-1} x_{i,k}\right)^2 + A\sum_{k=0}^{K-1}\sum_{(i,j)\notin E}x_{i,k}x_{j,k+1}
Hint:
将布尔变量 :math:`x_{i,k}` 映射到哈密顿矩阵上,:math:`x_{i,k} \mapsto \frac{I-Z_{i,k}}{2}`
Returns:
Hamiltonian: 最佳套利机会问题的哈密顿量
"""
nodes = list(g.nodes)
H_C_list1 = []
for (i, c) in enumerate(nodes):
for (j, cc) in enumerate(nodes):
if i != j:
c_ij = np.log2(g[c][cc]['weight'])
for t in range(K):
H_C_list1.append([c_ij / 4, 'I'])
H_C_list1.append([c_ij / 4, 'Z' + str(i * n + t) + ',Z' + str((j * n + (t + 1) % K))])
H_C_list1.append([- c_ij / 4, 'Z' + str(i * n + t)])
H_C_list1.append([- c_ij / 4, 'Z' + str((j * n + (t + 1) % K))])
H_C_list1 = [[-c, s] for (c, s) in H_C_list1]
H_C_list2 = []
for t in range(K):
H_C_list2.append([1, 'I'])
for i in range(n):
H_C_list2.append([- 2 * 1 / 2, 'I'])
H_C_list2.append([2 * 1 / 2, 'Z' + str(i * n + t)])
H_C_list2.append([2 / 4, 'I'])
H_C_list2.append([- 2 / 4, 'Z' + str(i * n + t)])
for ii in range(i):
H_C_list2.append([2 / 4, 'I'])
H_C_list2.append([2 / 4, 'Z' + str(i * n + t) + ',Z' + str(ii * n + t)])
H_C_list2.append([- 2 / 4, 'Z' + str(i * n + t)])
H_C_list2.append([- 2 / 4, 'Z' + str(ii * n + t)])
H_C_list2 = [[penalty * c, s] for (c, s) in H_C_list2]
H_C_list3 = []
for t in range(K):
for (i, c) in enumerate(nodes):
for (j, cc) in enumerate(nodes):
if (c, cc) not in g.edges and c != cc:
H_C_list3.append([1 / 4, "I"])
H_C_list3.append([- 1 / 4, 'Z' + str(i * n + t)])
H_C_list3.append([- 1 / 4, 'Z' + str((j * n + (t + 1) % K))])
H_C_list3.append([- 1 / 4, 'Z' + str(i * n + t) + ',Z' + str((j * n + (t + 1) % K))])
H_C_list3 = [[penalty * c, s] for (c, s) in H_C_list3]
H_C_list4 = []
for i in range(n):
H_C_list4.append([1, 'I'])
for t in range(K):
H_C_list4.append([- 2 * 1 / 2, 'I'])
H_C_list4.append([2 * 1 / 2, 'Z' + str(i * n + t)])
H_C_list4.append([2 / 4, 'I'])
H_C_list4.append([- 2 / 4, 'Z' + str(i * n + t)])
for tt in range(t):
H_C_list4.append([2 / 4, 'I'])
H_C_list4.append([2 / 4, 'Z' + str(i * n + t) + ',Z' + str(i * n + tt)])
H_C_list4.append([- 2 / 4, 'Z' + str(i * n + t)])
H_C_list4.append([- 2 / 4, 'Z' + str(i * n + tt)])
H_C_list4 = [[penalty * c, s] for (c, s) in H_C_list4]
H_C_list = H_C_list1 + H_C_list2 + H_C_list3 + H_C_list4
ao_hamiltonian = Hamiltonian(H_C_list)
return ao_hamiltonian
......@@ -16,10 +16,11 @@ import math
from functools import wraps
import numpy as np
from numpy import binary_repr
import re
import paddle
from paddle import multiply, add, to_tensor
from paddle import multiply, add, to_tensor, matmul, real, trace
from paddle_quantum.simulator import StateTransfer
from paddle_quantum import utils
def dic_between2and10(n):
......@@ -52,11 +53,14 @@ def single_H_vec_i(H, target_vec):
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
op_list = H.split(',')
op_list = re.split(r',\s*', H.lower())
coef = 1 + 0*1j # Coefficient for the vector
new_vec = list(target_vec)
for op in op_list:
pos = int(op[1:])
if len(op) >= 2:
pos = int(op[1:])
elif op[0] != 'i':
raise ValueError('only operator "I" can be used without identifying its position')
if op[0] == 'x':
new_vec[pos] = '0' if target_vec[pos] == '1' else '1'
elif op[0] == 'y':
......@@ -119,7 +123,7 @@ def vec_expecval(H, vec):
return result
def transfer_by_history(state, history):
def transfer_by_history(state, history, params):
r"""
It transforms the input state according to the history given.
......@@ -127,14 +131,18 @@ def transfer_by_history(state, history):
这是内部函数,你并不需要直接调用到该函数。
"""
for history_ele in history:
if history_ele[0] != 'channel':
if history_ele[0] in {'s', 't', 'ry', 'rz', 'rx'}:
state = StateTransfer(state, 'u', history_ele[1], params=history_ele[2])
elif history_ele[0] == 'MS_gate':
state = StateTransfer(state, 'RXX_gate', history_ele[1], params=history_ele[2])
if history_ele['gate'] != 'channel':
which_qubit = history_ele['which_qubits']
parameter = [params[i] for i in history_ele['theta']] if history_ele['theta'] else None
if history_ele['gate'] in {'s', 't', 'ry', 'rz', 'rx', 'sdg', "tdg"}:
state = StateTransfer(state, 'u', which_qubit, params=parameter)
elif history_ele['gate'] == 'MS_gate':
state = StateTransfer(state, 'RXX_gate', which_qubit, params=parameter)
elif history_ele['gate'] in {'crx', 'cry', 'crz'}:
state = StateTransfer(state, 'CU', which_qubit, params=parameter)
else:
state = StateTransfer(state, history_ele[0], history_ele[1], params=history_ele[2])
state = StateTransfer(state, history_ele['gate'], which_qubit, params=parameter)
return state
......@@ -154,6 +162,6 @@ def apply_channel(func):
assert 0 <= which_qubit < self.n, "the qubit's index should >= 0 and < n(the number of qubit)"
self._UAnsatz__has_channel = True
ops = func(self, *args)
self._UAnsatz__history.append(['channel', ops, [which_qubit]])
self._UAnsatz__history.append({'gate': 'channel', 'operators': ops, 'which_qubits': [which_qubit]})
return inner
return inner
\ No newline at end of file
......@@ -251,7 +251,7 @@ class LoccAnsatz(UAnsatz):
which_qubit (int): 添加该门量子比特编号
"""
which_qubit = self.party[which_qubit]
super(LoccAnsatz, self).z(which_qubit)
super(LoccAnsatz, self).t(which_qubit)
def u3(self, theta, phi, lam, which_qubit):
r"""添加一个单量子比特的旋转门。
......
# 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.
"""
Export the SciPy optimizers
"""
from .custom_optimizer import CustomOptimizer
from .conjugate_gradient import ConjugateGradient
from .newton_cg import NewtonCG
from .powell import Powell
from .slsqp import SLSQP
from .powell import Powell
__all__ = [
'CustomOptimizer',
'ConjugateGradient',
'NewtonCG',
'Powell',
'SLSQP'
]
# 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.
"""
CG optimizer
"""
from scipy import optimize
from .custom_optimizer import CustomOptimizer
class ConjugateGradient(CustomOptimizer):
r"""ConjugateGradient Optimizer
继承 ``CustomOptimizer`` 类,使用 SciPy 里 ConjugateGradient (CG) 的方法优化。此优化器需要说明计算梯度的方法。
Attributes:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
grad_func_name (string): 用来计算梯度的函数的函数名,可以选择 'linear_comb'、'finite_diff' 或 'param_shift',默认为 ``None``
delta (float): 差分法中的 delta,默认为 0.01
"""
def __init__(self, cir, hamiltonian, shots, grad_func_name=None, delta=0.01):
r"""``ConjugateGradient`` 的构造函数。
Args:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
grad_func_name (string, optional): 用来计算梯度的函数的函数名,可以选择 'linear_comb'、'finite_diff' 或 'param_shift',默认为 ``None``
delta (float, optional): 差分法中的 delta,默认为 0.01
"""
super().__init__(cir, hamiltonian, shots, grad_func_name, delta)
def minimize(self, iterations):
r"""最小化给定的损失函数。
Args:
iterations (int): 迭代的次数
"""
opt_res = optimize.minimize(
self.loss_func,
self.cir.get_param().numpy(),
args=(self.cir, self.hamiltonian, self.shots),
method='CG',
jac=self.grad_func,
options={'maxiter': iterations},
callback=lambda xk: print('loss: ', (self.loss_func(xk, self.cir, self.hamiltonian, self.shots)))
)
print(opt_res.message)
# 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.
"""
Custom optimizer
"""
from abc import ABC, abstractmethod
class CustomOptimizer(ABC):
r"""所有 SciPy 优化器的基类。
定义了在用 SciPy 优化器优化时所需的基本功能,如计算期望值和计算梯度的函数。
Attributes:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
grad_func_name (string, optional): 用来计算梯度的函数的函数名,可以选择 'linear_comb'、'finite_diff' 或 'param_shift'。
只有特定需要梯度的 optimizer 如 ``ConjugateGradient`` 需要,默认为 ``None``
delta (float, optional): 差分法中的 delta,默认为 0.01
"""
def __init__(self, cir, hamiltonian, shots, grad_func_name=None, delta=0.01):
r"""``CustomOptimizer`` 的构造函数。
Args:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 Hamiltonian 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
grad_func_name (string, optional): 用来计算梯度的函数的函数名,可以选择 'linear_comb'、'finite_diff' 或 'param_shift'。
只有特定需要梯度的 optimizer 如 ``ConjugateGradient`` 需要,默认为 ``None``
delta (float, optional): 差分法中的 delta,默认为 0.01
"""
self.cir = cir
self.grad_func_name = grad_func_name
self.hamiltonian = hamiltonian
self.shots = shots
self.delta = delta
self.loss_func = self._get_expec_val_scipy
self.grad_func = None
if self.grad_func_name == 'linear_comb':
self.grad_func = self._linear_combinations_gradient_scipy
elif self.grad_func_name == 'finite_diff':
self.grad_func = self._finite_difference_gradient_scipy
elif self.grad_func_name == 'param_shift':
self.grad_func = self._param_shift_gradient_scipy
else:
assert self.grad_func_name == None, \
"grad_func_name should be None or one of 'linear_comb', 'finite_diff', 'param_shift'"
def _get_expec_val_scipy(self, theta, cir, H, shots=0):
r"""计算关于哈密顿量 H 的期望的理论值。
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
cir.update_param(theta)
return cir.expecval(H, shots).numpy()
def _linear_combinations_gradient_scipy(self, theta, cir, H, shots):
r"""用 linear combination 的方法计算参数的梯度。
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
grad = cir.linear_combinations_gradient(H, shots)
return grad
def _finite_difference_gradient_scipy(self, theta, cir, H, shots):
r"""用差分法计算参数的梯度。
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
grad = cir.finite_difference_gradient(H, self.delta, shots)
return grad
def _param_shift_gradient_scipy(self, theta, cir, H, shots):
r"""用 parameter shift 的方法计算参数的梯度。
Note:
这是内部函数,你并不需要直接调用到该函数。
"""
grad = cir.param_shift_gradient(H, shots)
return grad
@abstractmethod
def minimize(self, iterations):
r"""最小化给定的损失函数。
Args:
iterations (int): 迭代的次数
"""
raise NotImplementedError
# 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.
"""
Newton-CG optimizer
"""
from scipy import optimize
from .custom_optimizer import CustomOptimizer
class NewtonCG(CustomOptimizer):
r"""Newton-CG Optimizer
继承 ``CustomOptimizer`` 类,使用 SciPy 里 Newton conjugate gradient 的方法优化。此优化器需要说明计算梯度的方法。
Attributes:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
grad_func_name (string): 用来计算梯度的函数的函数名,可以选择 'linear_comb'、'finite_diff' 或 'param_shift',默认为 ``None``
delta (float): 差分法中的 delta,默认为 0.01
"""
def __init__(self, cir, hamiltonian, shots, grad_func_name=None, delta=0.01):
r"""``NewtonCG`` 的构造函数。
Args:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
grad_func_name (string): 用来计算梯度的函数的函数名,可以选择 'linear_comb'、'finite_diff' 或 'param_shift',默认为 ``None``
delta (float): 差分法中的 delta,默认为 0.01
"""
super().__init__(cir, hamiltonian, shots, grad_func_name, delta)
def minimize(self, iterations):
r"""最小化给定的损失函数。
Args:
iterations (int): 迭代的次数
"""
opt_res = optimize.minimize(
self.loss_func,
self.cir.get_param().numpy(),
args=(self.cir, self.hamiltonian, self.shots),
method='Newton-CG',
jac=self.grad_func,
options={'maxiter': iterations},
callback=lambda xk: print('loss: ', (self.loss_func(xk, self.cir, self.hamiltonian, self.shots)))
)
print(opt_res.message)
# 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.
"""
Powell optimizer
"""
from scipy import optimize
from .custom_optimizer import CustomOptimizer
class Powell(CustomOptimizer):
r"""Powell Optimizer
继承 ``CustomOptimizer`` 类,使用 SciPy 里 Powell 方法优化。该方法不需要传入计算 gradient 的方式。
Attributes:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
"""
def __init__(self, cir, hamiltonian, shots):
r"""``Powell`` 的构造函数。
Args:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
"""
super().__init__(cir, hamiltonian, shots)
def minimize(self, iterations):
r"""最小化给定的损失函数。
Args:
iterations (int): 迭代的次数
"""
opt_res = optimize.minimize(
self.loss_func,
self.cir.get_param().numpy(),
args=(self.cir, self.hamiltonian, self.shots),
method='Powell',
options={'maxiter': iterations},
callback=lambda xk: print('loss: ', self.loss_func(xk, self.cir, self.hamiltonian, self.shots))
)
print(opt_res.message)
# 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.
"""
SLSQP optimizer
"""
from scipy import optimize
from .custom_optimizer import CustomOptimizer
class SLSQP(CustomOptimizer):
r"""SLSQP Optimizer
继承 ``CustomOptimizer`` 类,使用 SciPy 里 SLSQP 方法优化。该方法不需要传入计算 gradient 的方式。
Attributes:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
"""
def __init__(self, cir, hamiltonian, shots):
r"""``SLSQP`` 的构造函数。
Args:
cir (UAnsatz): 带可训练参数的量子电路
hamiltonian (list or Hamiltonian): 记录哈密顿量信息的列表或 ``Hamiltonian`` 类的对象
shots (int): 测量次数;默认为 0,表示返回期望值的精确值,即测量无穷次后的期望值
"""
super().__init__(cir, hamiltonian, shots)
def minimize(self, iterations):
r"""最小化给定的损失函数。
Args:
iterations (int): 迭代的次数
"""
opt_res = optimize.minimize(
self.loss_func,
self.cir.get_param().numpy(),
args=(self.cir, self.hamiltonian, self.shots),
method='SLSQP',
options={'maxiter': iterations},
callback=lambda xk: print('loss: ', self.loss_func(xk, self.cir, self.hamiltonian, self.shots))
)
print(opt_res.message)
此差异已折叠。
......@@ -186,6 +186,50 @@ def u_gate_matrix(params):
# paddle.to_tensor(np.array([3.0]))])
# print(a.numpy())
def cu_gate_matrix(params):
"""
Control U3
:return:
"""
theta, phi, lam = params
if (type(theta) is paddle.Tensor and
type(phi) is paddle.Tensor and
type(lam) is paddle.Tensor):
re_a = paddle.cos(theta / 2)
re_b = - paddle.cos(lam) * paddle.sin(theta / 2)
re_c = paddle.cos(phi) * paddle.sin(theta / 2)
re_d = paddle.cos(phi + lam) * paddle.cos(theta / 2)
im_a = paddle.zeros([1], 'float64')
im_b = - paddle.sin(lam) * paddle.sin(theta / 2)
im_c = paddle.sin(phi) * paddle.sin(theta / 2)
im_d = paddle.sin(phi + lam) * paddle.cos(theta / 2)
re = paddle.reshape(paddle.concat([re_a, re_b, re_c, re_d]), [2, 2])
im = paddle.reshape(paddle.concat([im_a, im_b, im_c, im_d]), [2, 2])
id = paddle.eye(2, dtype='float64')
z2 = paddle.zeros(shape=[2,2], dtype='float64')
re = paddle.concat([paddle.concat([id, z2], -1), paddle.concat([z2, re], -1)])
im = paddle.concat([paddle.concat([z2, z2], -1), paddle.concat([z2, im], -1)])
return re + im * paddle.to_tensor([1j], 'complex128')
elif (type(theta) is float and
type(phi) is float and
type(lam) is float):
u3 = np.array([[np.cos(theta / 2),
-np.exp(1j * lam) * np.sin(theta / 2)],
[np.exp(1j * phi) * np.sin(theta / 2),
np.exp(1j * phi + 1j * lam) * np.cos(theta / 2)]])
return np.block([
[np.eye(2, dtype=float), np.zeros((2, 2), dtype=float)], [np.zeros((2, 2), dtype=float), u3]
]).reshape((2,2,2,2))
else:
assert False
def cx_gate_matrix():
"""
......@@ -198,6 +242,28 @@ def cx_gate_matrix():
[0, 0, 1, 0]], dtype=complex).reshape((2, 2, 2, 2))
def cy_gate_matrix():
"""
Control Y
:return:
"""
return np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, -1j],
[0, 0, 1j, 0]], dtype=complex).reshape((2, 2, 2, 2))
def cz_gate_matrix():
"""
Control Z
:return:
"""
return np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, -1]], dtype=complex).reshape((2, 2, 2, 2))
def swap_gate_matrix():
"""
Swap gate
......@@ -214,7 +280,7 @@ def rxx_gate_matrix(params):
RXX gate
:return:
"""
theta = params
theta = params[0]
re_a = paddle.cos(theta / 2)
re_b = paddle.zeros([1], 'float64')
im_a = paddle.sin(theta / 2)
......@@ -236,7 +302,7 @@ def ryy_gate_matrix(params):
RYY gate
:return:
"""
theta = params
theta = params[0]
re_a = paddle.cos(theta / 2)
re_b = paddle.zeros([1], 'float64')
im_a = paddle.sin(theta / 2)
......@@ -258,7 +324,7 @@ def rzz_gate_matrix(params):
RZZ gate
:return:
"""
theta = params
theta = params[0]
re_a = paddle.cos(theta / 2)
re_b = paddle.zeros([1], 'float64')
im_a = paddle.sin(theta / 2)
......@@ -274,6 +340,7 @@ def rzz_gate_matrix(params):
return re + im * paddle.to_tensor([1j], 'complex128')
# PaddleE
def normalize_axis(axis, ndim):
if axis < 0:
......@@ -366,6 +433,86 @@ def complex_moveaxis(m, source, destination):
#
# return m
def get_cswap_state(state, bits):
"""
Transfer to the next state after applying CSWAP gate
:param state:
:param bits:
:return:
"""
q0 = bits[0]
q1 = bits[1]
q2 = bits[2]
# helper angles
theta0 = paddle.to_tensor(np.array([0.0]))
thetan2 = paddle.to_tensor(np.array([-np.pi / 2], np.float64))
theta2 = paddle.to_tensor(np.array([np.pi / 2], np.float64))
thetan4 = paddle.to_tensor(np.array([-np.pi / 4], np.float64))
theta4 = paddle.to_tensor(np.array([np.pi / 4], np.float64))
# implements cswap gate using cnot and Single-qubit gates
state = transfer_state(state, cx_gate_matrix(), [q2, q1])
state = transfer_state(state, u_gate_matrix([thetan2, theta0, theta0]), [q2]) # ry
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q0]) # rz
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q1]) # rz
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q2]) # rz
state = transfer_state(state, cx_gate_matrix(), [q0, q1])
state = transfer_state(state, cx_gate_matrix(), [q1, q2])
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q1]) # rz
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q2]) # rz
state = transfer_state(state, cx_gate_matrix(), [q0, q1])
state = transfer_state(state, cx_gate_matrix(), [q1, q2])
state = transfer_state(state, cx_gate_matrix(), [q0, q1])
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q2]) # rz
state = transfer_state(state, cx_gate_matrix(), [q1, q2])
state = transfer_state(state, u_gate_matrix([theta2, thetan2, theta2]), [q1]) # rx
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q2]) # rz
state = transfer_state(state, cx_gate_matrix(), [q0, q1])
state = transfer_state(state, cx_gate_matrix(), [q1, q2])
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta2]), [q2]) # rz
state = transfer_state(state, u_gate_matrix([theta2, thetan2, theta2]), [q1]) # rx
state = transfer_state(state, u_gate_matrix([thetan2, thetan2, theta2]), [q2]) # rx
return state
def get_ccx_state(state, bits):
"""
Transfer to the next state after applying CCX gate
:param state:
:param bits:
:return:
"""
q0 = bits[0]
q1 = bits[1]
q2 = bits[2]
# helper angles
theta0 = paddle.to_tensor(np.array([0.0]))
theta2 = paddle.to_tensor(np.array([np.pi / 2], np.float64))
thetan4 = paddle.to_tensor(np.array([-np.pi / 4], np.float64))
theta4 = paddle.to_tensor(np.array([np.pi / 4], np.float64))
# implements ccx gate using cnot and Single-qubit gates
state = transfer_state(state, h_gate_matrix(), [q2]) #h
state = transfer_state(state, cx_gate_matrix(), [q1, q2]) # cx
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q2]) # tdagger
state = transfer_state(state, cx_gate_matrix(), [q0, q2]) #cx
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q2]) # t
state = transfer_state(state, cx_gate_matrix(), [q1, q2]) #cx
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q2]) # tdagger
state = transfer_state(state, cx_gate_matrix(), [q0, q2]) # cx
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q1]) # tdagger
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q2]) # t
state = transfer_state(state, h_gate_matrix(), [q2]) # h
state = transfer_state(state, cx_gate_matrix(), [q0, q1]) #cx
state = transfer_state(state, u_gate_matrix([theta0, theta0, thetan4]), [q1]) # tdagger
state = transfer_state(state, cx_gate_matrix(), [q0, q1]) #cx
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta4]), [q0]) # t
state = transfer_state(state, u_gate_matrix([theta0, theta0, theta2]), [q1]) # s
return state
# TransferProcess
def transfer_state(state, gate_matrix, bits):
......@@ -394,8 +541,10 @@ def transfer_state(state, gate_matrix, bits):
# compressed moveaxis
# compress the continuous dim before moveaxis
# e.g. single operand: before moveaxis 2*2*[2]*2*2 -compress-> 4*[2]*4, after moveaxis [2]*2*2*2*2 -compress-> [2]*4*4
# double operands: before moveaxis 2*2*[2]*2*2*[2]*2*2 -compress-> 4*[2]*4*[2]*4, after moveaxis [2]*[2]*2*2*2*2*2*2 -compress-> [2]*[2]*4*4*4
# e.g. single operand: before moveaxis 2*2*[2]*2*2 -compress-> 4*[2]*4,
# after moveaxis [2]*2*2*2*2 -compress-> [2]*4*4
# double operands: before moveaxis 2*2*[2]*2*2*[2]*2*2 -compress-> 4*[2]*4*[2]*4,
# after moveaxis [2]*[2]*2*2*2*2*2*2 -compress-> [2]*[2]*4*4*4
# the peak rank is 5 when the number of operands is 2
assert len(source_pos) == 1 or len(source_pos) == 2
compressed_shape_before_moveaxis = [1]
......@@ -469,6 +618,15 @@ def StateTransfer(state, gate_name, bits, params=None):
elif gate_name == 'CNOT':
# print('----------', gate_name, bits, '----------')
gate_matrix = cx_gate_matrix()
elif gate_name == 'CU':
# print('----------', gate_name, bits, '----------')
gate_matrix = cu_gate_matrix(params)
elif gate_name == 'cy':
# print('----------', gate_name, bits, '----------')
gate_matrix = cy_gate_matrix()
elif gate_name == 'cz':
# print('----------', gate_name, bits, '----------')
gate_matrix = cz_gate_matrix()
elif gate_name == 'SWAP':
# print('----------', gate_name, bits, '----------')
gate_matrix = swap_gate_matrix()
......@@ -484,6 +642,14 @@ def StateTransfer(state, gate_name, bits, params=None):
elif gate_name == 'RZZ_gate':
# print('----------', gate_name, bits, '----------')
gate_matrix = rzz_gate_matrix(params)
elif gate_name == 'CSWAP':
# print('----------', gate_name, bits, '----------')
state = get_cswap_state(state, bits)
return state
elif gate_name == 'CCX':
# print('----------', gate_name, bits, '----------')
state = get_ccx_state(state, bits)
return state
else:
raise Exception("Gate name error")
......
......@@ -13,7 +13,6 @@
# limitations under the License.
import numpy as np
from numpy import concatenate
from numpy import trace as np_trace
from numpy import matmul as np_matmul
from numpy import random as np_random
......@@ -36,29 +35,32 @@ __all__ = [
]
def vec(n):
r"""生成量子态 :math:`|00...0\rangle` 的numpy形式
def vec(i, n):
r"""生成计算基态 :math:`|e_{i}\rangle` 的 numpy 形式,其中 :math:`|e_{i}\rangle` 的第 :math:`i` 个元素为 1,其余元素为 0
Args:
n(int): 量子比特数量
i(int): 计算基态 :math`|e_{i}\rangle` 的下标 :math:`i`
n(int): 生成的量子态的量子比特数量
Returns:
numpy.ndarray: 一个形状为 ``(1, 2**n)`` 的numpy数组 ``[[1, 0, 0, ..., 0]]``
numpy.ndarray: 计算基态 :math:`|e_{i}\rangle` 的态矢量形式。
代码示例:
.. code-block:: python
from paddle_quantum.state import vec
vector = vec(3)
vector = vec(1, 3)
print(vector)
::
[[1.+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 1.+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)
assert 0 <= i <= 2 ** n - 1, 'i should >= 0 and < 2**n (the dimension of the Hilbert space)'
state = np_zeros([1, 2 ** n])
state[0][i] = 1
return state.astype("complex128")
......
此差异已折叠。
paddlepaddle>=2.0.1
paddlepaddle>=2.1.1
scipy
networkx>=2.5
matplotlib
interval
tqdm
\ No newline at end of file
tqdm
fastdtw
\ No newline at end of file
......@@ -23,7 +23,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
setuptools.setup(
name='paddle-quantum',
version='2.1.0',
version='2.1.1',
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.',
......@@ -34,7 +34,7 @@ setuptools.setup(
'paddle_quantum.VQE', 'paddle_quantum.VQSD', 'paddle_quantum.GIBBS.example',
'paddle_quantum.QAOA.example', 'paddle_quantum.SSVQE.example', 'paddle_quantum.VQE.example',
'paddle_quantum.VQSD.example'],
install_requires=['paddlepaddle>=2.0.1', 'scipy', 'networkx>=2.5', 'matplotlib', 'interval', 'tqdm'],
install_requires=['paddlepaddle>=2.1.1', 'scipy', 'networkx>=2.5', 'matplotlib', 'interval', 'tqdm', 'fastdtw'],
python_requires='>=3.6, <4',
classifiers=[
'Programming Language :: Python :: 3',
......
......@@ -17,7 +17,7 @@
"\n",
"旅行商问题(travelling salesman problem, TSP)是组合优化中最经典的 NP–困难的问题之一,它指的是以下这个问题:\"已知一系列的城市和它们之间的距离,这个旅行商想造访所有城市各一次,并最后返回出发地,求他的最短路线规划。\"\n",
"\n",
"这个问题也可以用图论的语言来描述。已知一个有权重的完全图 $G = (V,E)$。它的每个顶点 $i \\in V$ 都对应一个城市 $i$,并且每一条边 $(i,j) \\in E$ 的权重 $w_{i,j}$ 对应城市 $i$ 和城市 $j$ 的距离。需要注意的是,$G$ 是个无向图,所以权重是对称的,即 $w_{i,j}= w_{j,i}$。根据以上定义,旅行商问题可以转化为找这个图中最短的哈密顿回路(Hamiltonian cycle)的问题。哈密顿回路为一个通过且仅通过每一个顶点一次的回路。"
"这个问题也可以用图论的语言来描述。已知一个有权重的完全图 $G = (V,E)$。它的每个顶点 $i \\in V$ 都对应一个城市 $i$,并且每一条边 $(i,j) \\in E$ 的权重 $w_{i,j}$ 对应城市 $i$ 和城市 $j$ 的距离。需要注意的是,$G$ 是个无向图,所以权重是对称的,即 $w_{i,j}= w_{j,i}$。根据以上定义,旅行商问题可以转化为找这个图中最短的哈密顿回路(Hamiltonian cycle)的问题。哈密顿回路为一个通过且仅通过每一个顶点一次的回路。 "
]
},
{
......@@ -68,7 +68,7 @@
"x_{i,t} \\mapsto \\frac{I-Z_{i,t}}{2}, \\tag{5}\n",
"$$\n",
"\n",
"这里 $Z_{i,t} = I \\otimes I \\otimes \\ldots \\otimes Z \\otimes \\ldots \\otimes I$,也就是说 $Z$ 作用在位置在 $(i,t)$ 的量子比特上。通过这个映射,如果一个编号为 $(i,t)$ 的量子比特的量子态为 $|1\\rangle$,那么对应的二进制变量的取值为 $x_{i,t} = \\frac{I-Z_{i,t}}{2} |1\\rangle = 1$,也就是说顶点 $i$ 在最短哈密顿回路中的位置是 $t$。同样地,对于量子态为 $|0\\rangle$的量子比特 $(i,t)$,它所对应的二进制变量的取值为 $x_{i,t} = \\frac{I-Z_{i,t}}{2} |1\\rangle = 0$。\n",
"这里 $Z_{i,t} = I \\otimes I \\otimes \\ldots \\otimes Z \\otimes \\ldots \\otimes I$,也就是说 $Z$ 作用在位置在 $(i,t)$ 的量子比特上。通过这个映射,如果一个编号为 $(i,t)$ 的量子比特的量子态为 $|1\\rangle$,那么对应的二进制变量的取值为 $x_{i,t} |1\\rangle = \\frac{I-Z_{i,t}}{2} |1\\rangle = 1 |1\\rangle$,也就是说顶点 $i$ 在最短哈密顿回路中的位置是 $t$。同样地,对于量子态为 $|0\\rangle$的量子比特 $(i,t)$,它所对应的二进制变量的取值为 $x_{i,t} |0\\rangle = \\frac{I-Z_{i,t}}{2} |0\\rangle = 0 |0\\rangle$。\n",
"\n",
"我们用上述映射将 $C(x)$ 转化成量子比特数为 $n^2$ 的系统的哈密顿矩阵 $H_C$,从而实现了旅行商问题的量子化。这个哈密顿矩阵 $H_C$ 的基态即为旅行商问题的最优解。在接下来的章节中,我们将展示怎么用参数化量子电路找到这个矩阵的基态,即对应最小本征值的本征态。"
]
......@@ -529,7 +529,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.10"
"version": "3.8.8"
},
"toc": {
"base_numbering": 1,
......
......@@ -17,7 +17,7 @@
"\n",
"One of the most famous NP-hard problems in combinatorial optimization, the travelling salesman problem (TSP) considers the following question: \"Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns to the origin city?\" \n",
"\n",
"This question can also be formulated in the language of graph theory. Given a weighted undirected complete graph $G = (V,E)$, where each vertex $i \\in V$ corresponds to city $i$ and the weight $w_{i,j}$ of each edge $(i,j,w_{i,j}) \\in E$ represents the distance between cities $i$ and $j$, the TSP is to find the shortest Hamiltonian cycle in $G$, where a Hamiltonian cycle is a closed loop on a graph in which every vertex is visited exactly once. Note that because $G$ is an undirected graph, weights are symmetric, i.e., $w_{i,j} = w_{j,i}$."
"This question can also be formulated in the language of graph theory. Given a weighted undirected complete graph $G = (V,E)$, where each vertex $i \\in V$ corresponds to city $i$ and the weight $w_{i,j}$ of each edge $(i,j,w_{i,j}) \\in E$ represents the distance between cities $i$ and $j$, the TSP is to find the shortest Hamiltonian cycle in $G$, where a Hamiltonian cycle is a closed loop on a graph in which every vertex is visited exactly once. Note that because $G$ is an undirected graph, weights are symmetric, i.e., $w_{i,j} = w_{j,i}$. "
]
},
{
......@@ -68,7 +68,7 @@
"x_{i,t} \\mapsto \\frac{I-Z_{i,t}}{2}, \\tag{5}\n",
"$$\n",
"\n",
"where $Z_{i,t} = I \\otimes I \\otimes \\ldots \\otimes Z \\otimes \\ldots \\otimes I$ with $Z$ operates on the qubit at position $(i,t)$. Under this mapping, if a qubit $(i,t)$ is in state $|1\\rangle$, then $x_{i,t} = \\frac{I-Z_{i,t}}{2} |1\\rangle = 1$, which means vertex $i$ is visited at time $t$. Also, for a qubit $(i,t)$ in state $|0\\rangle$, $x_{i,t} = \\frac{I-Z_{i,t}}{2} |1\\rangle = 0$.\n",
"where $Z_{i,t} = I \\otimes I \\otimes \\ldots \\otimes Z \\otimes \\ldots \\otimes I$ with $Z$ operates on the qubit at position $(i,t)$. Under this mapping, if a qubit $(i,t)$ is in state $|1\\rangle$, then $x_{i,t}|1\\rangle = \\frac{I-Z_{i,t}}{2} |1\\rangle = 1 |1\\rangle$, which means vertex $i$ is visited at time $t$. Also, for a qubit $(i,t)$ in state $|0\\rangle$, $x_{i,t} |0\\rangle= \\frac{I-Z_{i,t}}{2} |0\\rangle = 0|0\\rangle$.\n",
"\n",
"Thus using the above mapping, we can transform the cost function $C(x)$ into a Hamiltonian $H_C$ for the system of $n^2$ qubits and realize the quantumization of the TSP. Then the ground state of $H_C$ is the optimal solution to the TSP. In the following section, we will show how to use a parametrized quantum circuit to find the ground state, i.e., the eigenvector with the smallest eigenvalue.\n",
"\n"
......@@ -530,7 +530,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.10"
"version": "3.8.8"
},
"toc": {
"base_numbering": 1,
......
closePrice0,closePrice1,closePrice2,closePrice3,closePrice4,closePrice5,closePrice6,closePrice7,closePrice8,closePrice9,closePrice10,closePrice11
16.87,32.56,5.4,3.71,5.72,7.62,3.7,6.94,5.43,3.46,8.22,4.56
17.18,32.05,5.48,3.75,5.75,7.56,3.7,6.89,5.37,3.45,8.14,4.54
17.07,31.51,5.46,3.73,5.74,7.68,3.68,6.91,5.37,3.41,8.1,4.55
17.15,31.76,5.49,3.79,5.81,7.75,3.7,6.97,5.42,3.5,8.16,4.58
16.66,31.68,5.39,3.72,5.69,7.79,3.63,6.85,5.29,3.42,7.93,4.48
16.79,32.2,5.47,3.77,5.79,7.84,3.66,6.94,5.41,3.46,8.02,4.56
16.69,31.46,5.46,3.76,5.77,7.82,3.63,7.01,5.42,3.48,8,4.53
16.99,31.68,5.53,3.74,5.8,7.8,3.63,7.03,5.39,3.47,8.03,4.53
16.76,31.39,5.5,3.78,5.89,7.92,3.66,7.04,5.45,3.48,8.05,4.56
16.52,30.49,5.47,3.71,5.78,7.96,3.63,7.01,5.43,3.45,7.95,4.47
16.33,30.53,5.39,3.61,5.7,7.93,3.6,6.99,5.35,3.4,7.92,4.42
16.39,30.46,5.35,3.58,5.69,7.87,3.59,6.95,5.26,3.41,7.93,4.38
16.45,29.87,5.37,3.61,5.75,7.86,3.63,6.96,5.54,3.42,7.99,4.35
16,29.21,5.24,3.53,5.7,7.82,3.6,6.87,6.09,3.32,7.9,4.32
16.09,30.11,5.26,3.5,5.71,7.9,3.61,6.87,6.7,3.33,8.01,4.34
15.54,28.98,5.08,3.42,5.54,7.7,3.54,6.58,7.37,3.23,7.73,4.13
13.99,26.63,4.57,3.08,4.99,6.93,3.19,5.92,8.11,2.91,6.96,3.72
14.6,27.62,4.44,2.95,4.89,6.91,3.27,5.78,8.1,2.96,7.01,3.51
14.63,27.64,4.5,3.04,4.94,7.18,3.27,5.89,8.91,3.02,7.06,3.61
14.77,27.9,4.56,3.05,5.08,7.31,3.31,5.94,9.8,3.06,7.08,3.88
14.62,27.5,4.52,3.05,5.39,7.35,3.3,5.93,10.78,3.05,7.07,3.87
14.5,28.67,4.59,3.13,5.35,7.53,3.32,6.06,11.86,3.13,7.15,3.9
14.79,29.08,4.66,3.12,5.23,7.47,3.33,6.16,10.67,3.15,7.17,3.91
14.77,29.08,4.67,3.14,5.26,7.48,3.38,6.18,11.36,3.17,7.21,3.95
14.65,29.95,4.66,3.11,5.19,7.35,3.36,6.15,10.56,3.14,7.19,3.94
15.03,30.8,4.72,3.07,5.18,7.33,3.34,6.11,9.56,3.15,7.29,3.96
15.37,30.42,4.84,3.23,5.31,7.46,3.39,6.35,9.15,3.18,7.41,4.04
15.2,29.7,4.81,3.3,5.33,7.47,3.39,6.34,9.11,3.17,7.4,4.06
15.24,29.65,4.84,3.31,5.31,7.39,3.37,6.26,8.89,3.12,7.34,3.99
15.59,29.85,4.88,3.3,5.38,7.47,3.42,6.44,8.36,3.15,7.42,4.04
15.58,29.25,4.89,3.33,5.39,7.48,3.43,6.46,8.68,3.16,7.52,4.03
15.23,28.9,4.82,3.31,5.41,8.06,3.37,6.41,8.77,3.12,7.41,3.97
15.04,29.33,4.74,3.22,5.28,8.02,3.32,6.32,9.65,3.06,7.31,3.9
14.99,30.11,4.84,3.31,5.3,8.01,3.36,6.32,9.11,3.13,7.51,3.9
15.11,29.67,4.79,3.25,5.38,8.11,3.37,6.42,8.41,3.15,7.5,3.88
14.5,29.59,4.63,3.12,5.12,7.87,3.3,6.15,8.4,3.08,7.18,3.76
\ No newline at end of file
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册