提交 39ce5851 编写于 作者: Q Quleaf

first commit

first commit

readme update
上级 2718bc2a
.idea
__pycache__/
output
*.egg-info
.ipynb_checkpoints
\ No newline at end of file
- repo: https://github.com/PaddlePaddle/mirrors-yapf.git
sha: 0d79c0c469bab64f7229c9aca2b1186ef47f0e37
hooks:
- id: yapf
files: \.py$
- repo: https://github.com/pre-commit/pre-commit-hooks
sha: a11d9314b22d8f8c7556443875b731ef05965464
hooks:
- id: check-merge-conflict
- id: check-symlinks
- id: detect-private-key
files: (?!.*paddle)^.*$
- id: end-of-file-fixer
files: \.md$
- id: trailing-whitespace
files: \.md$
- repo: https://github.com/Lucas-C/pre-commit-hooks
sha: v1.0.1
hooks:
- id: forbid-crlf
files: \.md$
- id: remove-crlf
files: \.md$
- id: forbid-tabs
files: \.md$
- id: remove-tabs
files: \.md$
- repo: local
hooks:
- id: copyright_checker
name: copyright_checker
entry: python ./tools/copyright.hook
language: system
files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|proto|py)$
exclude: (?!.*third_party)^.*$ | (?!.*book)^.*$
\ No newline at end of file
Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserve.
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.
\ No newline at end of file
# Quantum
\ No newline at end of file
# Paddle Quantum (量桨)
Paddle Quantum(量桨)是基于百度飞桨开发的量子机器学习工具集,支持量子神经网络的搭建与训练,提供易用的量子机器学习开发套件与量子优化、量子化学等前沿量子应用工具集,使得百度飞桨也因此成为国内首个目前也是唯一一个支持量子机器学习的深度学习框架。
![](https://release-data.cdn.bcebos.com/Paddle%20Quantum.png)
量桨建立起了人工智能与量子计算的桥梁,不但可以快速实现量子神经网络的搭建与训练,还提供易用的量子机器学习开发套件与量子优化、量子化学等前沿量子应用工具集,并提供多项自研量子机器学习应用。通过百度飞桨深度学习平台赋能量子计算,量桨为领域内的科研人员以及开发者便捷地开发量子人工智能的应用提供了强有力的支撑,同时也为广大量子计算爱好者提供了一条可行的学习途径。
## 特色
- 易用性:提供简洁的神经网络搭建与丰富的量子机器学习案例。
- 通用性与拓展性:支持常用量子电路模型,提供多项优化工具。
- 特色工具集:提供量子优化、量子化学等前沿量子应用工具集,自研多项量子机器学习应用。
## 安装步骤
### Install PaddlePaddle
请参考 [PaddlePaddle](https://www.paddlepaddle.org.cn/documentation/docs/zh/beginners_guide/index_cn.html) 安装配置页面。此项目需求 PaddlePaddle 1.8.0 或更高版本。
### 下载 Paddle Quantum 并安装
```bash
git clone http://github.com/PaddlePaddle/quantum
```
```bash
cd quantum
pip install -e .
```
### 或使用 requirements.txt 安装依赖包
```bash
python -m pip install --upgrade -r requirements.txt
```
### 使用 openfermion 读取xyz 描述文件 (仅可在linux下安装使用)
VQE中调用 openfermion 读取分子xyz文件并计算,因此需要安装 openfermion 和 openfermionpyscf。
```bash
pip install openfermion
pip install openfermionpyscf
```
### 运行
```bash
cd paddle_quantum/QAOA/example
python main.py
```
## 入门与开发
### 教程入门
量子计算是由量子力学与计算理论交叉而成的全新计算模型,具有强大的信息处理优势和广阔的应用前景,被视作未来计算技术的心脏。量子计算的相关介绍与入门知识可以参考 [1-3]。
量子机器学习是一门结合量子计算与机器学习的交叉学科,一方面利用量子计算的信息处理优势促进人工智能的发展,另一方面也利用现有的人工智能的技术突破量子计算的研发瓶颈。关于量子机器学习的入门资料可以参考 [4-6]。Paddle Quantum(量桨)建立起了人工智能与量子计算的桥梁,为量子机器学习领域的研发提供强有力的支撑,也提供了丰富的案例供开发者学习。
### 案例入门
特别的,我们提供了涵盖量子优化、量子化学、量子机器学习等多个领域的案例供大家学习。比如:
- 量子组合优化(QAOA),完成安装步骤后打开 tutorial\QAOA.ipynb 即可进行研究学习。
```bash
cd tutorial
jupyter notebook QAOA.ipynb
```
- 量子特征求解器(VQE),完成安装步骤后打开 tutorial\VQE.ipynb 即可进行研究学习。
```
cd tutorial
jupyter notebook VQE.ipynb
```
### 开发
Paddle Quantum 使用 setuptools的develop 模式进行安装,相关代码修改可以直接进入`paddle_quantum` 文件夹进行修改。python 文件携带了自说明注释。
## 交流与反馈
- 我们非常欢迎您欢迎您通过[Github Issues](https://github.com/PaddlePaddle/Quantum/issues)来提交问题、报告与建议。
- QQ技术交流群: 1076223166
## 使用Paddle Quantum的工作
我们非常欢迎开发者使用Paddle Quantum进行量子机器学习的研发,如果您的工作有使用Paddle Quantum,也非常欢迎联系我们。目前使用 Paddle Quantum 的代表性工作关于 Gibbs 态制备如下:
[1] Y. Wang, G. Li, and X. Wang, “Variational quantum Gibbs state preparation with a truncated Taylor series,” arXiv:2005.08797, May 2020. [[pdf](https://arxiv.org/pdf/2005.08797.pdf)]
## Copyright and License
Paddle Quantum 使用 [Apache-2.0 license](LICENSE)许可证。
## References
[1] [量子计算 - 百度百科](https://baike.baidu.com/item/量子计算/11035661?fr=aladdin)
[2] M. A. Nielsen and I. L. Chuang, Quantum computation and quantum information. Cambridge university press, 2010.
[3] Phillip Kaye, R. Laflamme, and M. Mosca, An Introduction to Quantum Computing. 2007.
[4] J. Biamonte, P. Wittek, N. Pancotti, P. Rebentrost, N. Wiebe, and S. Lloyd, “Quantum machine learning,” Nature, vol. 549, no. 7671, pp. 195–202, Sep. 2017. [[pdf](https://arxiv.org/pdf/1611.09347)]
[5] M. Schuld, I. Sinayskiy, and F. Petruccione, “An introduction to quantum machine learning,” Contemp. Phys., vol. 56, no. 2, pp. 172–185, 2015. [[pdf](https://arxiv.org/pdf/1409.3097)]
[6] M. Benedetti, E. Lloyd, S. Sack, and M. Fiorentini, “Parameterized quantum circuits as machine learning models,” Quantum Sci. Technol., vol. 4, no. 4, p. 043001, Nov. 2019. [[pdf](https://arxiv.org/pdf/1906.07682)]
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
HGenerator
"""
from numpy import array, kron, trace
import scipy
__all__ = ["H_generator", ]
def H_generator():
"""
Generate a Hamiltonian with trivial descriptions
Returns: A Hamiltonian
"""
beta = 1
sigma_I = array([[1, 0], [0, 1]])
sigma_Z = array([[1, 0], [0, -1]])
H = (-kron(kron(sigma_Z, sigma_Z), sigma_I) - kron(
kron(sigma_I, sigma_Z), sigma_Z) - kron(
kron(sigma_Z, sigma_I), sigma_Z))
rho = scipy.linalg.expm(-1 * beta *
H) / trace(scipy.linalg.expm(-1 * beta * H))
return H.astype("complex64"), rho.astype("complex64")
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Paddle_GIBBS
"""
from numpy import concatenate, zeros
from numpy import pi as PI
from paddle import fluid
from paddle.complex import matmul, transpose, trace
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.utils import compute_fid, partial_trace
from paddle_quantum.GIBBS.HGenerator import H_generator
SEED = 1
__all__ = [
"U_theta",
"Net",
"Paddle_GIBBS",
]
def U_theta(theta, input_state, N, D): # definition of U_theta
"""
:param theta:
:param input_state:
:return:
"""
cir = UAnsatz(N, input_state=input_state)
for i in range(N):
cir.rx(theta=theta[0][0][i], which_qubit=i + 1)
cir.ry(theta=theta[0][1][i], which_qubit=i + 1)
cir.rx(theta=theta[0][2][i], which_qubit=i + 1)
for repeat in range(D):
for i in range(1, N):
cir.cnot(control=[i, i + 1])
for i in range(N):
cir.ry(theta=theta[repeat][0][i], which_qubit=i + 1)
# cir.ry(theta=theta[repeat][1][i], which_qubit=i + 1)
# cir.ry(theta=theta[repeat][2][i], which_qubit=i + 1)
return cir.state
class Net(fluid.dygraph.Layer):
"""
Construct the model net
"""
def __init__(self,
shape,
param_attr=fluid.initializer.Uniform(
low=0.0, high=PI, seed=SEED),
dtype='float32'):
super(Net, self).__init__()
self.theta = self.create_parameter(
shape=shape, attr=param_attr, dtype=dtype, is_bias=False)
def forward(self, input_state, H, N, N_SYS_B, D):
"""
Args:
input_state: The initial state with default |0..>
H: The target Hamiltonian
Returns:
The loss.
"""
out_state = U_theta(self.theta, input_state, N, D)
# rho_AB = utils.matmul(utils.matrix_conjugate_transpose(out_state), out_state)
rho_AB = matmul(
transpose(
fluid.framework.ComplexVariable(out_state.real,
-out_state.imag),
perm=[1, 0]),
out_state)
# compute the partial trace and three losses
rho_B = partial_trace(rho_AB, 2**(N - N_SYS_B), 2**(N_SYS_B), 1)
rho_B_squre = matmul(rho_B, rho_B)
loss1 = (trace(matmul(rho_B, H))).real
loss2 = (trace(rho_B_squre)).real * 2
loss3 = -(trace(matmul(rho_B_squre, rho_B))).real / 2
loss = loss1 + loss2 + loss3 # 损失函数
# option: if you want to check whether the imaginary part is 0, uncomment the following
# print('loss_iminary_part: ', loss.numpy()[1])
return loss - 3 / 2, rho_B
def Paddle_GIBBS(hamiltonian, rho=None, N=5, N_SYS_B=3, D=1, ITR=100, LR=0.5):
"""
Paddle_GIBBS
"""
with fluid.dygraph.guard():
# initial state preparing
_initial_state_np = concatenate(
([[1.]], zeros([1, 2**N - 1])), axis=1).astype('complex64')
initial_state = fluid.dygraph.to_variable(_initial_state_np)
# gibbs Hamiltonian preparing
H = fluid.dygraph.to_variable(hamiltonian)
# net
net = Net(shape=[D + 1, 3, N])
# optimizer
opt = fluid.optimizer.AdamOptimizer(
learning_rate=LR, parameter_list=net.parameters())
# gradient descent loop
for itr in range(1, ITR + 1):
loss, rho_B = net(initial_state, H, N, N_SYS_B, D)
loss.backward()
opt.minimize(loss)
net.clear_gradients()
rho_B = rho_B.numpy()
if rho is not None:
fid = compute_fid(rho_B, rho)
print('iter:', itr, 'loss:', '%.4f' % loss.numpy(), 'fid:',
'%.4f' % fid)
return rho_B
def main():
"""
main
"""
# gibbs Hamiltonian preparing
hamiltonian, rho = H_generator()
rho_B = Paddle_GIBBS(hamiltonian, rho)
print(rho_B)
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
from paddle_quantum.GIBBS.HGenerator import H_generator
from paddle_quantum.GIBBS.Paddle_GIBBS import Paddle_GIBBS
def main():
hamiltonian, rho = H_generator()
rho_B = Paddle_GIBBS(hamiltonian, rho)
print(rho_B)
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
from paddle_quantum.GIBBS.HGenerator import H_generator
from paddle_quantum.GIBBS.Paddle_GIBBS import Paddle_GIBBS
def main():
# gibbs Hamiltonian preparing
hamiltonian, rho = H_generator()
rho_B = Paddle_GIBBS(hamiltonian, rho)
print(rho_B)
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Paddle_QAOA: To learn more about the functions and properties of this application,
you could check the corresponding Jupyter notebook under the Tutorial folder.
"""
import os
from paddle import fluid
from paddle.complex import matmul as pp_matmul
from paddle.complex import transpose
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.QAOA.QAOA_Prefunc import generate_graph, H_generator
from numpy import ones, abs, conjugate, real, savez, sqrt, zeros
from numpy import matmul as np_matmul
from numpy import pi as PI
# Random seed for optimizer
SEED = 1
__all__ = [
"circuit_QAOA",
"circuit_extend_QAOA",
"Net",
"Paddle_QAOA",
]
def circuit_QAOA(theta, input_state, adjacency_matrix, N, P):
"""
This function constructs the parameterized QAOA circuit which is composed of P layers of two blocks:
one block is U_theta[layer][0] based on the problem Hamiltonian H which encodes the classical problem,
and the other is U_theta[layer][1] constructed from the driving Hamiltonian describing the rotation around Pauli X
acting on each qubit. It finally outputs the final state of the QAOA circuit.
Args:
theta: parameters to be optimized in the QAOA circuit
input_state: initial state of the QAOA circuit which usually is the uniform superposition of 2^N bit-strings
in the computational basis $|0\rangle, |1\rangle$
adjacency_matrix: the adjacency matrix of the graph encoding the classical problem
N: number of qubits, or equivalently, the number of nodes in the given graph
P: number of layers of two blocks in the QAOA circuit
Returns:
the final state of the QAOA circuit: cir.state
"""
cir = UAnsatz(N, input_state=input_state)
# The first loop defines the QAOA circuit with P layers of two blocks
for layer in range(P):
# The second and third loops aim to construct the first block U_theta[layer][0] which involves
# two-qubit operation e^{-i\beta Z_iZ_j} acting on a pair of qubits or nodes i and j in the circuit.
for row in range(N):
for col in range(N):
if abs(adjacency_matrix[row, col]) and row < col:
cir.cnot([row + 1, col + 1])
cir.rz(
theta=theta[layer][0] * adjacency_matrix[row, col],
which_qubit=col + 1, )
cir.cnot([row + 1, col + 1])
# This loops constructs the second block U_theta only involving the single-qubit operation e^{-i\beta X}.
for i in range(1, N + 1):
cir.rx(theta=theta[layer][1], which_qubit=i)
return cir.state
def circuit_extend_QAOA(theta, input_state, adjacency_matrix, N, P):
"""
This is an extended version of the QAOA circuit, and the main difference is U_theta[layer]([1]-[3]) constructed
from the driving Hamiltonian describing the rotation around an arbitrary direction on each qubit.
Args:
theta: parameters to be optimized in the QAOA circuit
input_state: input state of the QAOA circuit which usually is the uniform superposition of 2^N bit-strings
in the computational basis
adjacency_matrix: the adjacency matrix of the problem graph encoding the original problem
N: number of qubits, or equivalently, the number of parameters in the original classical problem
P: number of layers of two blocks in the QAOA circuit
Returns:
final state of the QAOA circuit: cir.state
Note: If this U_extend_theta function is used to construct QAOA circuit, then we need to change the parameter layer
in the Net function defined below from the Net(shape=[D, 2]) for U_theta function to Net(shape=[D, 4])
because the number of parameters doubles in each layer in this QAOA circuit.
"""
cir = UAnsatz(N, input_state=input_state)
# The first loop defines the QAOA circuit with P layers of two blocks
for layer in range(P):
# The second and third loops aim to construct the first block U_theta[layer][0] which involves
# two-qubit operation e^{-i\beta Z_iZ_j} acting on a pair of qubits or nodes i and j in the circuit.
for row in range(N):
for col in range(N):
if abs(adjacency_matrix[row, col]) and row < col:
cir.cnot([row + 1, col + 1])
cir.rz(
theta=theta[layer][0] * adjacency_matrix[row, col],
which_qubit=col + 1, )
cir.cnot([row + 1, col + 1])
# This loops constructs the second block U_theta[layer][1]-[3] composed of three single-qubit operation
# e^{-i\beta[1] Z}e^{-i\beta[2] X}e^{-i\beta[3] X} sequentially acting on single qubits.
for i in range(1, N + 1):
cir.rz(theta=theta[layer][1], which_qubit=i)
cir.rx(theta=theta[layer][2], which_qubit=i)
cir.rz(theta=theta[layer][3], which_qubit=i)
return cir.state
class Net(fluid.dygraph.Layer):
"""
It constructs the net for QAOA which combines the QAOA circuit with the classical optimizer which sets rules
to update parameters described by theta introduced in the QAOA circuit.
"""
def __init__(
self,
shape,
param_attr=fluid.initializer.Uniform(
low=0.0, high=PI, seed=SEED),
dtype="float32", ):
super(Net, self).__init__()
self.theta = self.create_parameter(
shape=shape, attr=param_attr, dtype=dtype, is_bias=False)
def forward(self, input_state, adjacency_matrix, out_state_store, N, P,
METHOD):
"""
This function constructs the loss function for the QAOA circuit.
Args:
self: the free parameters to be optimized in the QAOA circuit and defined in the above function
input_state: initial state of the QAOA circuit which usually is the uniform superposition of 2^N bit-strings
in the computational basis $|0\rangle, |1\rangle$
adjacency_matrix: the adjacency matrix generated from the graph encoding the classical problem
out_state_store: the output state of the QAOA circuit
N: number of qubits
P: number of layers
METHOD: which version of QAOA is chosen to solve the problem, i.e., standard version labeled by 1 or
extended version by 2.
Returns:
The loss function for the parameterized QAOA circuit.
"""
# Generate the problem_based quantum Hamiltonian H_problem based on the classical problem in paddle
H, _ = H_generator(N, adjacency_matrix)
H_problem = fluid.dygraph.to_variable(H)
# The standard QAOA circuit: the function circuit_QAOA is used to construct the circuit, indexed by METHOD 1.
if METHOD == 1:
out_state = circuit_QAOA(self.theta, input_state, adjacency_matrix,
N, P)
# The extended QAOA circuit: the function circuit_extend_QAOA is used to construct the net, indexed by METHOD 2.
elif METHOD == 2:
out_state = circuit_extend_QAOA(self.theta, input_state,
adjacency_matrix, N, P)
else:
raise ValueError("Wrong method called!")
out_state_store.append(out_state.numpy())
loss = pp_matmul(
pp_matmul(out_state, H_problem),
transpose(
fluid.framework.ComplexVariable(out_state.real,
-out_state.imag),
perm=[1, 0], ), )
return loss.real
def main(N=4):
"""
This is the main function which maps the classical problem to the quantum version solved by QAOA and outputs
the quantum solution and its corresponding classical ones. Here, N=4 is a 4-qubit example to show how QAOA works.
"""
# Generate the adjacency matrix from the description of the problem-based graph
_, classical_graph_adjacency = generate_graph(N, 1)
Paddle_QAOA(classical_graph_adjacency)
def Paddle_QAOA(classical_graph_adjacency, N=4, P=4, METHOD=1, ITR=120,
LR=0.1):
"""
This is the core function to run QAOA.
Args:
classical_graph_adjacency: adjacency matrix to describe the graph which encodes the classical problem
N: number of qubits (default value N=4)
P: number of layers of blocks in the QAOA circuit (default value P=4)
METHOD: which version of the QAOA circuit is used: 1, standard circuit (default); 2, extended circuit
ITR: number of iteration steps for QAOA (default value ITR=120)
LR: learning rate for the gradient-based optimization method (default value LR=0.1)
Returns:
optimized parameters theta and the bitstrings sampled from the output state with maximal probability
"""
out_state_store = []
with fluid.dygraph.guard():
# Preparing the initial state
_initial_state = ones([1, 2**N]).astype("complex64") / sqrt(2**N)
initial_state = fluid.dygraph.to_variable(_initial_state)
# Construct the net or QAOA circuits based on the standard modules
if METHOD == 1:
net = Net(shape=[P, 2])
# Construct the net or QAOA circuits based on the extended modules
elif METHOD == 2:
net = Net(shape=[P, 4])
else:
raise ValueError("Wrong method called!")
# Classical optimizer
opt = fluid.optimizer.AdamOptimizer(
learning_rate=LR, parameter_list=net.parameters())
# Gradient descent loop
summary_iter, summary_loss = [], []
for itr in range(1, ITR + 1):
loss = net(initial_state, classical_graph_adjacency,
out_state_store, N, P, METHOD)
loss.backward()
opt.minimize(loss)
net.clear_gradients()
print("iter:", itr, " loss:", "%.4f" % loss.numpy())
summary_loss.append(loss[0][0].numpy())
summary_iter.append(itr)
theta_opt = net.parameters()[0].numpy()
print(theta_opt)
os.makedirs("output", exist_ok=True)
savez("./output/summary_data", iter=summary_iter, energy=summary_loss)
# Output the measurement probability distribution sampled from the output state of optimized QAOA circuit.
prob_measure = zeros([1, 2**N]).astype("complex")
rho_out = out_state_store[-1]
rho_out = np_matmul(conjugate(rho_out).T, rho_out).astype("complex")
for index in range(0, 2**N):
comput_basis = zeros([1, 2**N])
comput_basis[0][index] = 1
prob_measure[0][index] = real(
np_matmul(np_matmul(comput_basis, rho_out), comput_basis.T))
return prob_measure
if __name__ == "__main__":
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Aid func
"""
from matplotlib import pyplot
from numpy import abs, array, binary_repr, diag, kron, max, ones, real, where, zeros
import networkx
__all__ = [
"plot_graph",
"generate_graph",
"H_generator",
]
def plot_graph(measure_prob_distribution, graph, N):
"""
This function plots the graph encoding the combinatorial problem such as Max-Cut and the final graph encoding the
approximate solution obtained from QAOA
Args:
measure_prob_distribution: the measurement probability distribution which is sampled from the output state
of optimized QAOA circuit.
graph: graph encoding the topology of the classical combinatorial problem, such as Max-Cut problem
N: number of qubits, or number of nodes in the graph
Return:
three graphs: the first displays the graph topology of the classical problem;
the second is the bar graph for the measurement distribution for each bitstring in the output state
the third plots the graph corresponding to the bitstring with maximal measurement probability
"""
# Find the position of max value in the measure_prob_distribution
max_prob_pos_list = where(
measure_prob_distribution == max(measure_prob_distribution))
# Store the max value from ndarray to list
max_prob_list = max_prob_pos_list[0].tolist()
# Store it in the binary format
solution_list = [binary_repr(index, width=N) for index in max_prob_list]
print("The output bitstring:", solution_list)
# Draw the graph representing the first bitstring in the solution_list to the MaxCut-like problem
head_bitstring = solution_list[0]
node_cut = [
"blue" if head_bitstring[node] == "1" else "red" for node in graph
]
edge_cut = [
"solid"
if head_bitstring[node_row] == head_bitstring[node_col] else "dashed"
for node_row, node_col in graph.edges()
]
pos = networkx.circular_layout(graph)
pyplot.figure(0)
networkx.draw(graph, pos, width=4, with_labels=True, font_weight="bold")
# when N is large, it is not suggested to plot this figure
pyplot.figure(1)
name_list = [binary_repr(index, width=N) for index in range(0, 2**N)]
pyplot.bar(
range(len(real(measure_prob_distribution))),
real(measure_prob_distribution),
width=0.7,
tick_label=name_list, )
pyplot.xticks(rotation=90)
pyplot.figure(2)
networkx.draw(
graph,
pos,
node_color=node_cut,
style=edge_cut,
width=4,
with_labels=True,
font_weight="bold", )
pyplot.show()
def generate_graph(N, GRAPHMETHOD):
"""
This function offers two methods to generate a graph.
Args:
N: number of nodes (vertices) in the graph, which is also the number of qubits
GRAPHMETHOD: which method to generate a graph
Return:
graph description and its adjacency matrix
"""
# Method 1 generates a graph by self-definition. Note that the node label starts from 0 to N-1, while the edges
# could be attributed to weights additionally. If no specific rules are given, then all weights are set to 1.
if GRAPHMETHOD == 1:
print(
"Method 1 generates the graph from self-definition using EDGE description"
)
graph = networkx.Graph()
graph_nodelist = range(N)
graph.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0)])
graph_adjacency = networkx.to_numpy_matrix(
graph, nodelist=graph_nodelist)
# Method 2 generates a graph by using its adjacency matrix directly
elif GRAPHMETHOD == 2:
print(
"Method 2 generates the graph from networks using adjacency matrix")
graph_adjacency = array(
[[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 1, 0]])
graph = networkx.Graph(graph_adjacency)
else:
print("Method doesn't exist ")
output_graph = graph
output_graph_adjacency = graph_adjacency
return output_graph, output_graph_adjacency
def H_generator(N, adjacency_matrix):
"""
This function generates the problem-based Hamiltonian, given the graph with its adjacency matrix description.
Args:
N: number of qubits, or number of nodes in the graph, or number of parameters in the classical problem
adjacency_matrix: the adjacency matrix generated from the graph encoding the classical problem
Return:
H_graph: the problem-based Hamiltonian H generated from the graph_adjacency matrix for the given graph
H_graph_diag: the real part of the problem-based Hamiltonian H_graph
"""
sigma_Z = array([[1, 0], [0, -1]])
H = zeros([2**N, 2**N])
for row in range(N):
for col in range(N):
if abs(adjacency_matrix[N - row - 1, N - col - 1]) and row < col:
identity_1 = diag(ones([2**row]))
identity_2 = diag(ones([2**(col - row - 1)]))
identity_3 = diag(ones([2**(N - col - 1)]))
H += adjacency_matrix[N - row - 1, N - col - 1] * kron(
kron(
kron(kron(identity_1, sigma_Z), identity_2), sigma_Z),
identity_3, )
H_graph = H.astype("complex64")
H_graph_diag = diag(H_graph).real
return H_graph, H_graph_diag
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Benchmark
"""
from matplotlib import pyplot
from numpy import max, min, load, ones
from paddle_quantum.QAOA.QAOA_Prefunc import generate_graph, H_generator
def benchmark_QAOA(classical_graph_adjacency=None, N=None):
"""
This function benchmarks the performance of QAOA. Indeed, it compares its approximate solution obtained
from QAOA with predetermined parameters, such as iteration step = 120 and learning rate = 0.1, to the exact solution
to the classical problem.
"""
# Generate the graph and its adjacency matrix from the classical problem, such as the Max-Cut problem
if all(var is None for var in (classical_graph_adjacency, N)):
N = 4
_, classical_graph_adjacency = generate_graph(N, 1)
# Compute the exact solution of the original problem to benchmark the performance of QAOA
_, H_problem_diag = H_generator(N, classical_graph_adjacency)
H_graph_max = max(H_problem_diag)
H_graph_min = min(H_problem_diag)
print('H_max:', H_graph_max, ' H_min:', H_graph_min)
# Load the data of QAOA
x1 = load('./output/summary_data.npz')
H_min = ones([len(x1['iter'])]) * H_graph_min
# Plot it
pyplot.figure(1)
loss_QAOA, = pyplot.plot(x1['iter'], x1['energy'], \
alpha=0.7, marker='', linestyle="--", linewidth=2, color='m')
benchmark, = pyplot.plot(
x1['iter'],
H_min,
alpha=0.7,
marker='',
linestyle=":",
linewidth=2,
color='b')
pyplot.xlabel('Number of iteration')
pyplot.ylabel('Performance of the loss function for QAOA')
pyplot.legend(
handles=[loss_QAOA, benchmark],
labels=[
r'Loss function $\left\langle {\psi \left( {\bf{\theta }} \right)} '
r'\right|H\left| {\psi \left( {\bf{\theta }} \right)} \right\rangle $',
'The benchmark result',
],
loc='best')
# Show the picture
pyplot.show()
def main():
"""
main
"""
benchmark_QAOA()
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
from paddle_quantum.QAOA.Paddle_QAOA import Paddle_QAOA
from paddle_quantum.QAOA.QAOA_Prefunc import plot_graph, generate_graph
# Random seed for optimizer
SEED = 1
def main(N=4):
"""
QAOA Main
"""
classical_graph, classical_graph_adjacency = generate_graph(N, 1)
print(classical_graph_adjacency)
prob_measure = Paddle_QAOA(classical_graph_adjacency)
# Flatten array[[]] to []
prob_measure = prob_measure.flatten()
# Plot it!
plot_graph(prob_measure, classical_graph, N)
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
from paddle_quantum.QAOA.Paddle_QAOA import Paddle_QAOA
from paddle_quantum.QAOA.QAOA_Prefunc import plot_graph, generate_graph
# Random seed for optimizer
SEED = 1
def main(N=4):
"""
QAOA Main
"""
classical_graph, classical_graph_adjacency = generate_graph(N, 1)
print(classical_graph_adjacency)
prob_measure = Paddle_QAOA(classical_graph_adjacency)
# Flatten array[[]] to []
prob_measure = prob_measure.flatten()
# Plot it!
plot_graph(prob_measure, classical_graph, N)
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
HGenerator
"""
from numpy import array, kron
__all__ = ["H_generator"]
def H_generator():
"""
Generate a Hamiltonian with trivial descriptions
Returns: A Hamiltonian
"""
sigma_I = array([[1, 0], [0, 1]])
sigma_X = array([[0, 1], [1, 0]])
sigma_Y = array([[0, -1j], [1j, 0]])
sigma_Z = array([[1, 0], [0, -1]])
H = 0.4 * kron(sigma_Z, sigma_I) + 0.4 * kron(
sigma_I, sigma_Z) + 0.2 * kron(sigma_X, sigma_X)
# H = numpy.diag([0.1, 0.2, 0.3, 0.4])
return H.astype('complex64')
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Paddle_SSVQE: To learn more about the functions and properties of this application,
you could check the corresponding Jupyter notebook under the Tutorial folder.
"""
import numpy
from paddle.complex import matmul, transpose
from paddle import fluid
from paddle_quantum.circuit import UAnsatz
SEED = 1
__all__ = [
"U_theta",
"Net",
"Paddle_SSVQE",
]
# definition of U_theta
def U_theta(theta, N):
"""
U_theta
"""
cir = UAnsatz(N)
# ============== D1=2 ==============
cir.ry(theta[0], 2)
cir.rz(theta[1], 2)
cir.cnot([2, 1])
cir.ry(theta[2], 2)
cir.rz(theta[3], 2)
cir.cnot([2, 1])
# ============== D2=2 ==============
cir.ry(theta[4], 1)
cir.ry(theta[5], 2)
cir.rz(theta[6], 1)
cir.rz(theta[7], 2)
cir.cnot([1, 2])
cir.ry(theta[8], 1)
cir.ry(theta[9], 2)
cir.rz(theta[10], 1)
cir.rz(theta[11], 2)
cir.cnot([1, 2])
return cir.state
class Net(fluid.dygraph.Layer):
"""
Construct the model net
"""
def __init__(self,
shape,
param_attr=fluid.initializer.Uniform(
low=0.0, high=2 * numpy.pi, seed=SEED),
dtype='float32'):
super(Net, self).__init__()
self.theta = self.create_parameter(
shape=shape, attr=param_attr, dtype=dtype, is_bias=False)
def forward(self, H, N):
"""
Args:
input_state: The initial state with default |0..>
H: The target Hamiltonian
Returns:
The loss.
"""
out_state = U_theta(self.theta, N)
loss_struct = matmul(
matmul(
transpose(
fluid.framework.ComplexVariable(out_state.real,
-out_state.imag),
perm=[1, 0]),
H),
out_state).real
loss_components = [
loss_struct[0][0], loss_struct[1][1], loss_struct[2][2],
loss_struct[3][3]
]
loss = 4 * loss_components[0] + 3 * loss_components[
1] + 2 * loss_components[2] + 1 * loss_components[3]
return loss, loss_components
def Paddle_SSVQE(H, N=2, THETA_SIZE=12, ITR=60, LR=0.2):
"""
main
"""
with fluid.dygraph.guard():
# Harmiltonian preparing
H = fluid.dygraph.to_variable(H)
# net
net = Net(shape=[THETA_SIZE])
# optimizer
opt = fluid.optimizer.AdagradOptimizer(
learning_rate=LR, parameter_list=net.parameters())
# gradient descent loop
for itr in range(1, ITR + 1):
loss, loss_components = net(H, N)
loss.backward()
opt.minimize(loss)
net.clear_gradients()
print('iter:', itr, 'loss:', '%.4f' % loss.numpy()[0])
return loss_components
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
import numpy
from paddle_quantum.SSVQE.HGenerator import H_generator
from paddle_quantum.SSVQE.Paddle_SSVQE import Paddle_SSVQE
def main():
"""
main
"""
hamiltonian = H_generator()
loss_components = Paddle_SSVQE(hamiltonian)
print('The estimated ground state energy is: ', loss_components[0].numpy())
print('The estimated 1st excited state energy is: ',
loss_components[1].numpy())
print('The estimated 2nd excited state energy is: ',
loss_components[2].numpy())
print('The estimated 3rd excited state energy is: ',
loss_components[3].numpy())
print('The theoretical ground state energy: ',
numpy.linalg.eigh(hamiltonian)[0][0])
print('The theoretical 1st excited state energy: ',
numpy.linalg.eigh(hamiltonian)[0][1])
print('The theoretical 2nd excited state energy: ',
numpy.linalg.eigh(hamiltonian)[0][2])
print('The theoretical 3rd excited state energy: ',
numpy.linalg.eigh(hamiltonian)[0][3])
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
import numpy
from paddle_quantum.SSVQE.HGenerator import H_generator
from paddle_quantum.SSVQE.Paddle_SSVQE import Paddle_SSVQE
def main():
"""
main
"""
hamiltonian = H_generator()
loss_components = Paddle_SSVQE(hamiltonian)
print('The estimated ground state energy is: ', loss_components[0].numpy())
print('The estimated 1st excited state energy is: ',
loss_components[1].numpy())
print('The estimated 2nd excited state energy is: ',
loss_components[2].numpy())
print('The estimated 3rd excited state energy is: ',
loss_components[3].numpy())
print('The theoretical ground state energy: ',
numpy.linalg.eigh(hamiltonian)[0][0])
print('The theoretical 1st excited state energy: ',
numpy.linalg.eigh(hamiltonian)[0][1])
print('The theoretical 2nd excited state energy: ',
numpy.linalg.eigh(hamiltonian)[0][2])
print('The theoretical 3rd excited state energy: ',
numpy.linalg.eigh(hamiltonian)[0][3])
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
VQE: To learn more about the functions and properties of this application,
you could check the corresponding Jupyter notebook under the Tutorial folder.
"""
import os
from numpy import concatenate
from numpy import pi as PI
from numpy import savez, zeros
from paddle import fluid
from paddle.complex import matmul, transpose
from paddle_quantum.circuit import UAnsatz
__all__ = [
"U_theta",
"StateNet",
"Paddle_VQE",
]
def U_theta(theta, input_state, N, D):
"""
Circuit
"""
cir = UAnsatz(N, input_state=input_state)
for i in range(N):
cir.rz(theta=theta[0][0][i], which_qubit=i + 1)
cir.ry(theta=theta[0][1][i], which_qubit=i + 1)
cir.rz(theta=theta[0][2][i], which_qubit=i + 1)
for repeat in range(D):
for i in range(1, N):
cir.cnot(control=[i, i + 1])
for i in range(N):
cir.ry(theta=theta[repeat][0][i], which_qubit=i + 1)
cir.ry(theta=theta[repeat][1][i], which_qubit=i + 1)
cir.rz(theta=theta[repeat][2][i], which_qubit=i + 1)
return cir.state
class StateNet(fluid.dygraph.Layer):
"""
Construct the model net
"""
def __init__(
self,
shape,
param_attr=fluid.initializer.Uniform(
low=0.0, high=2 * PI),
dtype="float32", ):
super(StateNet, self).__init__()
self.theta = self.create_parameter(
shape=shape, attr=param_attr, dtype=dtype, is_bias=False)
def forward(self, input_state, H, N, D):
"""
:param input_state: The initial state with default |0..>, 'mat'
:param H: The target Hamiltonian, 'mat'
:return: The loss, 'float'
"""
out_state = U_theta(self.theta, input_state, N, D)
loss = matmul(
matmul(out_state, H),
transpose(
fluid.framework.ComplexVariable(out_state.real,
-out_state.imag),
perm=[1, 0], ), )
return loss.real
def Paddle_VQE(Hamiltonian, N, D=1, ITR=120, LR=0.15):
"""
Main Learning network using dynamic graph
:return: Plot or No return
"""
with fluid.dygraph.guard():
# initial state preparing
_initial_state_np = concatenate(
([[1.0]], zeros([1, 2**N - 1])), axis=1).astype("complex64")
initial_state = fluid.dygraph.to_variable(_initial_state_np)
# Store H
H = fluid.dygraph.to_variable(Hamiltonian)
# net
net = StateNet(shape=[D + 1, 3, N])
# optimizer
opt = fluid.optimizer.AdamOptimizer(
learning_rate=LR, parameter_list=net.parameters())
# gradient descent loop
summary_iter, summary_loss = [], []
for itr in range(1, ITR + 1):
# forward calc, loss
loss = net(initial_state, H, N, D)
# backward calculation for gradient value
loss.backward()
# using gradients to update the variable theta
opt.minimize(loss)
# clear gradients
net.clear_gradients()
summary_loss.append(loss[0][0].numpy())
summary_iter.append(itr)
print("iter:", itr, "loss:", "%.4f" % loss.numpy())
print("iter:", itr, "Ground state energy:",
"%.4f Ha" % loss.numpy())
# print('theta:', net.parameters()[0].numpy())
os.makedirs("output", exist_ok=True)
savez("./output/summary_data", iter=summary_iter, energy=summary_loss)
def main():
"""
:return:
"""
if __name__ == "__main__":
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
benchmark the result
"""
import platform
import matplotlib.pyplot as plt
import numpy
from paddle_quantum.VQE.chemistrysub import H2_generator
def benchmark_result():
"""
benchmark using numpy
"""
# Read H and calc using numpy
sysStr = platform.system()
if sysStr == 'Windows':
# Windows does not support SCF, using H2_generator instead
print('Molecule data will be read from built-in function')
_H, _, _ = H2_generator()
print('Read Process Finished')
elif sysStr == 'Linux' or sysStr == 'Darwin':
# for linux only
from paddle_quantum.VQE.chemistrygen import read_calc_H
# Harmiltonian and cnot module preparing, must be executed under Linux
# Read the H2 molecule data
print('Molecule data will be read from h2.xyz')
_H, _, _ = read_calc_H(geo_fn='h2.xyz')
print('Read Process Finished')
else:
print("Don't support this os.")
# plot
x1 = numpy.load('./output/summary_data.npz')
eig_val, eig_state = numpy.linalg.eig(_H)
min_eig_H = numpy.min(eig_val)
min_loss = numpy.ones([len(x1['iter'])]) * min_eig_H
plt.figure(1)
func1, = plt.plot(
x1['iter'],
x1['energy'],
alpha=0.7,
marker='',
linestyle="--",
color='m')
func_min, = plt.plot(
x1['iter'], min_loss, alpha=0.7, marker='', linestyle=":", color='b')
plt.xlabel('Number of iteration')
plt.ylabel('Energy (Ha)')
plt.legend(
handles=[func1, func_min],
labels=[
r'$\left\langle {\psi \left( {\bf{\theta }} \right)} '
r'\right|H\left| {\psi \left( {\bf{\theta }} \right)} \right\rangle $',
'Minimum energy',
],
loc='best')
# output the picture
plt.show()
def main():
"""
Call the real benchmark function
"""
benchmark_result()
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
chemistry
"""
from numpy import array, kron, trace
import openfermion
import openfermionpyscf
import scipy
import scipy.linalg
__all__ = [
"calc_H_rho_from_qubit_operator",
"read_calc_H",
]
def calc_H_rho_from_qubit_operator(qubit_op, n_qubits):
"""
Generate a Hamiltonian from QubitOperator
Returns: H, rho
"""
# const
beta = 1
sigma_table = {
'I': array([[1, 0], [0, 1]]),
'Z': array([[1, 0], [0, -1]]),
'X': array([[0, 1], [1, 0]]),
'Y': array([[0, -1j], [1j, 0]])
}
# calc Hamiltonian
H = 0
for terms, h in qubit_op.terms.items():
basis_list = ['I'] * n_qubits
for index, action in terms:
basis_list[index] = action
for sigma_symbol in basis_list:
b = sigma_table.get(sigma_symbol, None)
if b is None:
raise Exception('unrecognized basis')
h = kron(h, b)
H = H + h
# calc rho
rho = scipy.linalg.expm(-1 * beta *
H) / trace(scipy.linalg.expm(-1 * beta * H))
return H.astype('complex64'), rho.astype(
'complex64') # the returned dic will have 2 ** n value
def read_calc_H(geo_fn, multiplicity=1, charge=0):
"""
Read and calc the H and rho
return: H,rho matrix
"""
if not isinstance(geo_fn, str): # geo_fn = 'h2.xyz'
raise Exception('filename is a string')
geo = []
with open(geo_fn) as f:
f.readline()
f.readline()
for line in f:
species, x, y, z = line.split()
geo.append([species, (float(x), float(y), float(z))])
# meanfield data
mol = openfermion.hamiltonians.MolecularData(geo, 'sto-3g', multiplicity,
charge)
openfermionpyscf.run_pyscf(mol)
terms_molecular_hamiltonian = mol.get_molecular_hamiltonian(
)
fermionic_hamiltonian = openfermion.transforms.get_fermion_operator(
terms_molecular_hamiltonian)
qubit_op = openfermion.transforms.jordan_wigner(
fermionic_hamiltonian)
# calc H, rho
H, rho = calc_H_rho_from_qubit_operator(qubit_op, mol.n_qubits)
return H, rho, mol.n_qubits
def main():
"""
The main function
Returns:
"""
filename = 'h2.xyz'
H, rho, N = read_calc_H(geo_fn=filename)
print('H', H)
print("-------------------------- ")
print('rho', rho)
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Using a H generator to define the H under WINDOWS
"""
from numpy import array, kron, trace
import scipy
__all__ = [
"H_generator",
"H2_generator",
]
def H_generator():
"""
Generate a Hamiltonian with trivial descriptions
:return: a Hamiltonian, 'mat'
"""
beta = 1
sigma_I = array([[1, 0], [0, 1]])
sigma_Z = array([[1, 0], [0, -1]])
sigma_X = array([[0, 1], [1, 0]])
sigma_Y = array([[0, -1j], [1j, 0]])
# H = kron(kron(sigma_X, sigma_I), sigma_X) + 0.9 * kron(kron(sigma_Z, sigma_I), sigma_I) \
# - 0.3 * kron(kron(sigma_I, sigma_I), sigma_Y)
H = 0.4 * kron(sigma_Z, sigma_I) + 0.4 * kron(
sigma_I, sigma_Z) + 0.2 * kron(sigma_X, sigma_X)
rho = scipy.linalg.expm(-1 * beta *
H) / trace(scipy.linalg.expm(-1 * beta * H))
return H.astype('complex64'), rho.astype('complex64')
def H2_generator():
"""
Generate a Hamiltonian with trivial descriptions
Returns: A Hamiltonian, 'mat'
"""
beta = 1
sigma_I = array([[1, 0], [0, 1]])
sigma_Z = array([[1, 0], [0, -1]])
sigma_X = array([[0, 1], [1, 0]])
sigma_Y = array([[0, -1j], [1j, 0]])
H = (-0.04207897647782276) * kron(kron(kron(sigma_I, sigma_I), sigma_I), sigma_I) \
+ (0.17771287465139946) * kron(kron(kron(sigma_Z, sigma_I), sigma_I), sigma_I) \
+ (0.1777128746513994) * kron(kron(kron(sigma_I, sigma_Z), sigma_I), sigma_I) \
+ (-0.24274280513140462) * kron(kron(kron(sigma_I, sigma_I), sigma_Z), sigma_I) \
+ (-0.24274280513140462) * kron(kron(kron(sigma_I, sigma_I), sigma_I), sigma_Z) \
+ (0.17059738328801052) * kron(kron(kron(sigma_Z, sigma_Z), sigma_I), sigma_I) \
+ (0.04475014401535161) * kron(kron(kron(sigma_Y, sigma_X), sigma_X), sigma_Y) \
+ (-0.04475014401535161) * kron(kron(kron(sigma_Y, sigma_Y), sigma_X), sigma_X) \
+ (-0.04475014401535161) * kron(kron(kron(sigma_X, sigma_X), sigma_Y), sigma_Y) \
+ (0.04475014401535161) * kron(kron(kron(sigma_X, sigma_Y), sigma_Y), sigma_X) \
+ (0.12293305056183798) * kron(kron(kron(sigma_Z, sigma_I), sigma_Z), sigma_I) \
+ (0.1676831945771896) * kron(kron(kron(sigma_Z, sigma_I), sigma_I), sigma_Z) \
+ (0.1676831945771896) * kron(kron(kron(sigma_I, sigma_Z), sigma_Z), sigma_I) \
+ (0.12293305056183798) * kron(kron(kron(sigma_I, sigma_Z), sigma_I), sigma_Z) \
+ (0.17627640804319591) * kron(kron(kron(sigma_I, sigma_I), sigma_Z), sigma_Z)
rho = scipy.linalg.expm(-1 * beta *
H) / trace(scipy.linalg.expm(-1 * beta * H))
N = 4
return H.astype('complex64'), rho.astype('complex64'), N
2
in Angstrom
H 0.00000 0.00000 -0.35000
H 0.00000 0.00000 0.35000
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
import platform
from paddle_quantum.VQE.Paddle_VQE import Paddle_VQE
from paddle_quantum.VQE.benchmark import benchmark_result
from paddle_quantum.VQE.chemistrysub import H2_generator
def main():
"""
Main Learning network using dynamic graph
:return: Plot or No return
"""
# Read data from built-in function or xyz file depending on OS
sysStr = platform.system()
if sysStr == 'Windows':
# Windows does not support SCF, using H2_generator instead
print('Molecule data will be read from built-in function')
_H, _, N = H2_generator()
print('Read Process Finished')
elif sysStr in ('Linux', 'Darwin'):
# for linux only
from paddle_quantum.VQE.chemistrygen import read_calc_H
# Harmiltonian and cnot module preparing, must be executed under Linux
# Read the H2 molecule data
print('Molecule data will be read from h2.xyz')
_H, _, N = read_calc_H(geo_fn='h2.xyz')
print('Read Process Finished')
else:
print("Don't support this OS.")
Paddle_VQE(_H, N)
benchmark_result()
if __name__ == '__main__':
main()
2
in Angstrom
H 0.00000 0.00000 -0.35000
H 0.00000 0.00000 0.35000
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
import platform
from paddle_quantum.VQE.Paddle_VQE import Paddle_VQE
from paddle_quantum.VQE.benchmark import benchmark_result
from paddle_quantum.VQE.chemistrysub import H2_generator
def main():
"""
Main Learning network using dynamic graph
:return: Plot or No return
"""
# Read data from built-in function or xyz file depending on OS
sysStr = platform.system()
if sysStr == 'Windows':
# Windows does not support SCF, using H2_generator instead
print('Molecule data will be read from built-in function')
hamiltonian, _, N = H2_generator()
print('Read Process Finished')
elif sysStr in ('Linux', 'Darwin'):
# for linux only
from paddle_quantum.VQE.chemistrygen import read_calc_H
# Hamiltonian and cnot module preparing, must be executed under Linux
# Read the H2 molecule data
print('Molecule data will be read from h2.xyz')
hamiltonian, _, N = read_calc_H(geo_fn='h2.xyz')
print('Read Process Finished')
else:
print("Don't support this OS.")
Paddle_VQE(hamiltonian, N, D=2, LR=0.1)
benchmark_result()
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
HGenerator
"""
from numpy import diag
import scipy
SEED = 1
__all__ = ["generate_rho_sigma", ]
def generate_rho_sigma():
# V is a 4x4 random Unitary
scipy.random.seed(SEED)
V = scipy.stats.unitary_group.rvs(4)
# generate rho
D = diag([0.1, 0.2, 0.3, 0.4])
sigma = diag([0.4, 0.3, 0.2, 0.1])
V_H = V.conj().T
rho = V @D @V_H
return rho.astype('complex64'), sigma.astype('complex64')
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Paddle_VQSD: To learn more about the functions and properties of this application,
you could check the corresponding Jupyter notebook under the Tutorial folder.
"""
import numpy
from paddle import fluid
from paddle_quantum.circuit import UAnsatz
from paddle.complex import matmul, trace, transpose
SEED = 1
__all__ = [
"U_theta",
"Net",
"Paddle_VQSD",
]
# definition of U_theta
def U_theta(theta, N):
"""
U_theta
"""
cir = UAnsatz(N)
cir.rz(theta[0], 1)
cir.ry(theta[1], 1)
cir.rz(theta[2], 1)
cir.rz(theta[3], 2)
cir.ry(theta[4], 2)
cir.rz(theta[5], 2)
cir.cnot([2, 1])
cir.rz(theta[6], 1)
cir.ry(theta[7], 2)
cir.cnot([1, 2])
cir.rz(theta[8], 1)
cir.ry(theta[9], 1)
cir.rz(theta[10], 1)
cir.rz(theta[11], 2)
cir.ry(theta[12], 2)
cir.rz(theta[13], 2)
return cir.state
class Net(fluid.dygraph.Layer):
"""
Construct the model net
"""
def __init__(self,
shape,
rho,
sigma,
param_attr=fluid.initializer.Uniform(
low=0.0, high=2 * numpy.pi, seed=SEED),
dtype='float32'):
super(Net, self).__init__()
self.rho = fluid.dygraph.to_variable(rho)
self.sigma = fluid.dygraph.to_variable(sigma)
self.theta = self.create_parameter(
shape=shape, attr=param_attr, dtype=dtype, is_bias=False)
def forward(self, N):
"""
Args:
Returns:
The loss.
"""
out_state = U_theta(self.theta, N)
# rho_tilde is what you get after you put self.rho through the circuit
rho_tilde = matmul(
matmul(out_state, self.rho),
transpose(
fluid.framework.ComplexVariable(out_state.real,
-out_state.imag),
perm=[1, 0]))
# record the new loss
loss = trace(matmul(self.sigma, rho_tilde))
return loss.real, rho_tilde
def Paddle_VQSD(rho, sigma, N=2, THETA_SIZE=14, ITR=50, LR=0.1):
"""
Paddle_VQSD
"""
with fluid.dygraph.guard():
# net
net = Net(shape=[THETA_SIZE], rho=rho, sigma=sigma)
# optimizer
opt = fluid.optimizer.AdagradOptimizer(
learning_rate=LR, parameter_list=net.parameters())
# gradient descent loop
for itr in range(ITR):
loss, rho_tilde = net(N)
rho_tilde_np = rho_tilde.numpy()
loss.backward()
opt.minimize(loss)
net.clear_gradients()
print('iter:', itr, 'loss:', '%.4f' % loss.numpy()[0])
return rho_tilde_np
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Main
"""
import numpy
from paddle_quantum.VQSD.HGenerator import generate_rho_sigma
from paddle_quantum.VQSD.Paddle_VQSD import Paddle_VQSD
def main():
"""
Main
:return:
"""
rho, sigma = generate_rho_sigma()
rho_tilde_np = Paddle_VQSD(rho, sigma)
print('spectrum:', numpy.real(numpy.diag(rho_tilde_np)))
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
main
"""
import numpy
from paddle_quantum.VQSD.HGenerator import generate_rho_sigma
from paddle_quantum.VQSD.Paddle_VQSD import Paddle_VQSD
def main():
rho, sigma = generate_rho_sigma()
rho_tilde_np = Paddle_VQSD(rho, sigma)
print('spectrum:', numpy.real(numpy.diag(rho_tilde_np)))
if __name__ == '__main__':
main()
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Paddle Quantum Library
"""
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
circuit
"""
from numpy import binary_repr, eye, identity
from paddle.complex import kron as pp_kron
from paddle.complex import matmul
from paddle.fluid import dygraph
from paddle_quantum.utils import rotation_x, rotation_y, rotation_z
__all__ = [
"dic_between2and10",
"base_2_change",
"cnot_construct",
"identity_generator",
"single_gate_construct",
"UAnsatz",
]
def dic_between2and10(n):
"""
:param n: number of qubits
:return: dictionary between binary and decimal
for example: if n=3, the dictionary is
dic2to10: {'000': 0, '011': 3, '010': 2, '111': 7, '100': 4, '101': 5, '110': 6, '001': 1}
dic10to2: ['000', '001', '010', '011', '100', '101', '110', '111']
"""
dic2to10 = {}
dic10to2 = [None] * 2**n
for i in range(2**n):
binary_text = binary_repr(i, width=n)
dic2to10[binary_text] = i
dic10to2[i] = binary_text
return dic2to10, dic10to2 # the returned dic will have 2 ** n value
def base_2_change(string_n, i_ctrl, j_target):
"""
:param string_n: an n-bit string
:param i_ctrl: i-th bit is control, 'int'
:param j_target: j-th bit is target, 'int'
:return: if i-th bit is 1, j-th bit takes inverse
"""
string_n_list = list(string_n)
if string_n_list[i_ctrl] == "1":
string_n_list[j_target] = str((int(string_n_list[j_target]) + 1) % 2)
return "".join(string_n_list)
def cnot_construct(n, ctrl):
"""
cnot_construct: The controlled-NOT gate
:param n: number of qubits
:param ctrl: a shape [2] vector, in 'int' type. ctrl[0]-th qubit controls the ctrl[1]-qubit
:return: cnot module
"""
mat = eye(2**n)
dummy_mat = eye(2**n)
dic2to10, dic10to2 = dic_between2and10(n)
""" for example: if n=3, the dictionary is
dic2to10: {'000': 0, '011': 3, '010': 2, '111': 7, '100': 4, '101': 5, '110': 6, '001': 1}
dic10to2: ['000', '001', '010', '011', '100', '101', '110', '111']
"""
for row in range(2**n):
""" for each decimal index 'row', transform it into binary,
and use 'base_2_change()' function to compute the new binary index 'row'.
Lastly, use 'dic2to10' to transform this new 'row' into decimal.
For instance, n=3, ctrl=[1,3]. if row = 5,
its process is 5 -> '101' -> '100' -> 4
"""
new_string_base_2 = base_2_change(dic10to2[row], ctrl[0] - 1,
ctrl[1] - 1)
new_int_base_10 = dic2to10[new_string_base_2]
mat[row] = dummy_mat[new_int_base_10]
return mat.astype("complex64")
def identity_generator(n):
"""
identity_generator
"""
idty_np = identity(2**n, dtype="float32")
idty = dygraph.to_variable(idty_np)
return idty
def single_gate_construct(mat, n, which_qubit):
"""
:param mat: the input matrix
:param n: number of qubits
:param which_qubit: indicate which qubit the matrix is placed on
:return: the kronecker product of the matrix and identity
"""
idty = identity_generator(n - 1)
if which_qubit == 1:
mat = pp_kron(mat, idty)
elif which_qubit == n:
mat = pp_kron(idty, mat)
else:
I_top = identity_generator(which_qubit - 1)
I_bot = identity_generator(n - which_qubit)
mat = pp_kron(pp_kron(I_top, mat), I_bot)
return mat
class UAnsatz:
"""
UAnsatz: ansatz for the parameterized quantum circuit or quantum neural network.
"""
def __init__(self, n, input_state=None):
"""
:param input_state: if the input_state is 'None', the self.mat is a matrix,
if the input_state is a row complex vector, the self.mat is a row vector
"""
self.n = n
self.state = input_state if input_state is not None else identity_generator(
self.n)
def rx(self, theta, which_qubit):
"""
Rx: the single qubit X rotation
"""
transform = single_gate_construct(
rotation_x(theta), self.n, which_qubit)
self.state = matmul(self.state, transform)
def ry(self, theta, which_qubit):
"""
Ry: the single qubit Y rotation
"""
transform = single_gate_construct(
rotation_y(theta), self.n, which_qubit)
self.state = matmul(self.state, transform)
def rz(self, theta, which_qubit):
"""
Rz: the single qubit Z rotation
"""
transform = single_gate_construct(
rotation_z(theta), self.n, which_qubit)
self.state = matmul(self.state, transform)
def cnot(self, control):
"""
:param control: [1,3], the 1st qubit controls 3rd qubit
:return: cnot module
"""
cnot = dygraph.to_variable(cnot_construct(self.n, control))
self.state = matmul(self.state, cnot)
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
function
"""
from functools import reduce
from numpy import diag, dot, identity
from numpy import kron as np_kron
from numpy import linalg, sqrt
from numpy import sum as np_sum
from numpy import transpose as np_transpose
from numpy import zeros as np_zeros
from paddle.complex import elementwise_add
from paddle.complex import kron as pp_kron
from paddle.complex import matmul
from paddle.complex import transpose as pp_transpose
from paddle.fluid.dygraph import to_variable
from paddle.fluid.framework import ComplexVariable
from paddle.fluid.layers import concat, cos, ones, reshape, sin
from paddle.fluid.layers import zeros as pp_zeros
__all__ = [
"rotation_x",
"rotation_y",
"rotation_z",
"partial_trace",
"compute_fid",
"NKron",
]
def rotation_x(theta):
"""
:param theta: must be a scale, shape [1], 'float32'
:return:
"""
cos_value = cos(theta/2)
sin_value = sin(theta/2)
zero_pd = pp_zeros([1], "float32")
rx_re = concat([cos_value, zero_pd, zero_pd, cos_value], axis=0)
rx_im = concat([zero_pd, -sin_value, -sin_value, zero_pd], axis=0)
return ComplexVariable(reshape(rx_re, [2, 2]), reshape(rx_im, [2, 2]))
def rotation_y(theta):
"""
:param theta: must be a scale, shape [1], 'float32'
:return:
"""
cos_value = cos(theta/2)
sin_value = sin(theta/2)
ry_re = concat([cos_value, -sin_value, sin_value, cos_value], axis=0)
ry_im = pp_zeros([2, 2], "float32")
return ComplexVariable(reshape(ry_re, [2, 2]), ry_im)
def rotation_z(theta):
"""
:param theta: must be a scale, shape [1], 'float32'
:return:
"""
cos_value = cos(theta/2)
sin_value = sin(theta/2)
zero_pd = pp_zeros([1], "float32")
rz_re = concat([cos_value, zero_pd, zero_pd, cos_value], axis=0)
rz_im = concat([-sin_value, zero_pd, zero_pd, sin_value], axis=0)
return ComplexVariable(reshape(rz_re, [2, 2]), reshape(rz_im, [2, 2]))
def partial_trace(rho_AB, dim1, dim2, A_or_B):
"""
:param rho_AB: the input density matrix
:param dim1: dimension for system A
:param dim2: dimension for system B
:param A_or_B: 1 or 2, choose the system that you want trace out.
:return: partial trace
"""
# dim_total = dim1 * dim2
if A_or_B == 2:
dim1, dim2 = dim2, dim1
idty_np = identity(dim2).astype("complex64")
idty_B = to_variable(idty_np)
zero_np = np_zeros([dim2, dim2], "complex64")
res = to_variable(zero_np)
for dim_j in range(dim1):
row_top = pp_zeros([1, dim_j], dtype="float32")
row_mid = ones([1, 1], dtype="float32")
row_bot = pp_zeros([1, dim1 - dim_j - 1], dtype="float32")
bra_j_re = concat([row_top, row_mid, row_bot], axis=1)
bra_j_im = pp_zeros([1, dim1], dtype="float32")
bra_j = ComplexVariable(bra_j_re, bra_j_im)
if A_or_B == 1:
row_tmp = pp_kron(bra_j, idty_B)
res = elementwise_add(
res,
matmul(
matmul(row_tmp, rho_AB),
pp_transpose(
ComplexVariable(row_tmp.real, -row_tmp.imag),
perm=[1, 0]), ), )
if A_or_B == 2:
row_tmp = pp_kron(idty_B, bra_j)
res += matmul(
matmul(row_tmp, rho_AB),
pp_transpose(
ComplexVariable(row_tmp.real, -row_tmp.imag), perm=[1, 0]),
)
return res
def compute_fid(rho, sigma):
"""
compute_fid: compute the fidelity between two density operators
:param rho:
:param sigma:
:return:
"""
rho_eigenval, rho_eigenmatrix = linalg.eig(rho)
sr_rho = dot(
dot(rho_eigenmatrix, diag(sqrt(rho_eigenval.real + 1e-7))),
np_transpose(rho_eigenmatrix).conjugate(), )
rho_sigma_rho = dot(dot(sr_rho, sigma), sr_rho)
return np_sum(sqrt(linalg.eigvals(rho_sigma_rho).real + 1e-7))
def NKron(AMatrix, BMatrix, *args):
"""
Recursively execute kron n times. This function at least has two matrices.
:param AMatrix: First matrix
:param BMatrix: Second matrix
:param args: If have more matrix, they are delivered by this matrix
:return: The result of tensor product.
"""
return reduce(
lambda result, index: np_kron(result, index),
args,
np_kron(AMatrix, BMatrix), )
paddlepaddle>=1.8.0
networkx
matplotlib
\ No newline at end of file
# Copyright (c) 2020 Paddle Quantum Authors. 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.
"""
Install library to site-packages
"""
from setuptools import setup
setup(
name='paddle_quantum',
version='1.0.0',
description='Paddle Quantum circuit and function',
author='Institute for Quantum Computing, Baidu INC.',
author_email='quantum@baidu.com',
url='http://quantum-hub.baidu.com',
packages=['paddle_quantum'],
install_requires=['paddlepaddle>=1.8.0', 'networkx', 'matplotlib'])
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import io, re
import sys, os
import subprocess
import platform
COPYRIGHT = '''
Copyright (c) 2020 Paddle Quantum Authors. 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.
'''
LANG_COMMENT_MARK = None
NEW_LINE_MARK = None
COPYRIGHT_HEADER = None
if platform.system() == "Windows":
NEW_LINE_MARK = '\r\n'
else:
NEW_LINE_MARK = '\n'
COPYRIGHT_HEADER = COPYRIGHT.split(NEW_LINE_MARK)[1]
p = re.search('(\d{4})', COPYRIGHT_HEADER).group(0)
process = subprocess.Popen(["date", "+%Y"], stdout=subprocess.PIPE)
date, err = process.communicate()
date = date.decode("utf-8").rstrip("\n")
COPYRIGHT_HEADER = COPYRIGHT_HEADER.replace(p, date)
def generate_copyright(template, lang='C'):
if lang == 'Python':
LANG_COMMENT_MARK = "#"
else:
LANG_COMMENT_MARK = "//"
lines = template.split(NEW_LINE_MARK)
BLANK = " "
ans = LANG_COMMENT_MARK + BLANK + COPYRIGHT_HEADER + NEW_LINE_MARK
for lino, line in enumerate(lines):
if lino == 0 or lino == 1 or lino == len(lines) - 1: continue
if len(line) == 0:
BLANK = ""
else:
BLANK = " "
ans += LANG_COMMENT_MARK + BLANK + line + NEW_LINE_MARK
return ans + "\n"
def lang_type(filename):
if filename.endswith(".py"):
return "Python"
elif filename.endswith(".h"):
return "C"
elif filename.endswith(".c"):
return "C"
elif filename.endswith(".hpp"):
return "C"
elif filename.endswith(".cc"):
return "C"
elif filename.endswith(".cpp"):
return "C"
elif filename.endswith(".cu"):
return "C"
elif filename.endswith(".cuh"):
return "C"
elif filename.endswith(".go"):
return "C"
elif filename.endswith(".proto"):
return "C"
else:
print("Unsupported filetype %s", filename)
exit(0)
PYTHON_ENCODE = re.compile("^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)")
def main(argv=None):
parser = argparse.ArgumentParser(
description='Checker for copyright declaration.')
parser.add_argument('filenames', nargs='*', help='Filenames to check')
args = parser.parse_args(argv)
retv = 0
for filename in args.filenames:
fd = io.open(filename, encoding="utf-8")
first_line = fd.readline()
second_line = fd.readline()
if "COPYRIGHT (C)" in first_line.upper(): continue
if first_line.startswith("#!") or PYTHON_ENCODE.match(
second_line) != None or PYTHON_ENCODE.match(first_line) != None:
continue
original_contents = io.open(filename, encoding="utf-8").read()
new_contents = generate_copyright(
COPYRIGHT, lang_type(filename)) + original_contents
print('Auto Insert Copyright Header {}'.format(filename))
retv = 1
with io.open(filename, 'w') as output_file:
output_file.write(new_contents)
return retv
if __name__ == '__main__':
exit(main())
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 概览\n",
"- 在这个案例中,我们将展示如何通过Paddle Quantum训练量子神经网络来求解量子系统的特征。\n",
"\n",
"- 首先,让我们通过下面几行代码引入必要的library和package。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import numpy\n",
"from paddle.complex import matmul, transpose\n",
"from paddle import fluid\n",
"from paddle_quantum.circuit import UAnsatz\n",
"from numpy import array, kron"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 背景\n",
"- 量子计算中在近期非常有前途的一个量子算法是变分量子特征求解器(VQE, variational quantum eigensolver (VQE)) [1-3].\n",
"- VQE是量子化学在近期有噪量子设备(NISQ device)上的核心应用之一,其中一个功能比较强大的版本是SSVQE [4],其核心是去求解一个物理系统的哈密顿量的基态和激发态的性质。数学上,可以理解为求解一个厄米矩阵(Hermitian matrix)的特征值及其对应的特征向量。该哈密顿量的特征值组成的集合我们称其为能谱。\n",
"- 接下来我们将通过一个简单的例子学习如何通过训练量子神经网络解决这个问题,即求解出给定哈密顿量的能谱。\n",
"\n",
"## SSVQE分析物理系统的基态和激发态的能量\n",
"- 对于具体需要分析的分子,我们需要输入其几何、电荷构型等多项信息。具体的,通过我们内置的量子化学工具包可以利用fermionic-to-qubit映射的技术来输出目标分子的量子比特哈密顿量表示。\n",
"- 在这里,作为简单的入门案例,我们提供一个简单的2量子位哈密顿量作为例子。 "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"sigma_I = array([[1, 0], [0, 1]])\n",
"sigma_X = array([[0, 1], [1, 0]])\n",
"sigma_Y = array([[0, -1j], [1j, 0]])\n",
"sigma_Z = array([[1, 0], [0, -1]])\n",
"H = 0.4 * kron(sigma_Z, sigma_I) + 0.4 * kron(sigma_I, sigma_Z) + 0.2 * kron(sigma_X, sigma_X)\n",
"hamiltonian = H.astype('complex64')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 搭建量子神经网络(QNN)\n",
"- 在实现SSVQE的过程中,我们首先需要设计1个量子神经网络QNN(也可以理解为参数化量子电路)。这里,我们提供一个预设的2量子位量子电路。\n",
"\n",
"- 我们预设一些该参数化电路的参数,比如宽度为2量子位。\n",
"\n",
"- 初始化其中的变量参数,${\\bf{\\theta }}$代表我们量子神经网络中的参数组成的向量,一共有12个参数。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"N = 2 # 量子神经网络的宽度\n",
"THETA_SIZE = 12 # 量子神经网络中参数的数量\n",
"\n",
"def U_theta(theta, N):\n",
" \"\"\"\n",
" U_theta\n",
" \"\"\"\n",
"\n",
" cir = UAnsatz(N)\n",
" # ============== D1=2 ==============\n",
" cir.ry(theta[0], 2)\n",
" cir.rz(theta[1], 2)\n",
" cir.cnot([2, 1])\n",
" cir.ry(theta[2], 2)\n",
" cir.rz(theta[3], 2)\n",
" cir.cnot([2, 1])\n",
"\n",
" # ============== D2=2 ==============\n",
" cir.ry(theta[4], 1)\n",
" cir.ry(theta[5], 2)\n",
" cir.rz(theta[6], 1)\n",
" cir.rz(theta[7], 2)\n",
" cir.cnot([1, 2])\n",
"\n",
" cir.ry(theta[8], 1)\n",
" cir.ry(theta[9], 2)\n",
" cir.rz(theta[10], 1)\n",
" cir.rz(theta[11], 2)\n",
" cir.cnot([1, 2])\n",
"\n",
" return cir.state"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 配置训练模型 - 损失函数\n",
"- 现在我们已经有了数据和量子神经网络的架构,我们将进一步定义训练参数、模型和损失函数,具体的理论可以参考 [4].\n",
"- 通过作用量子神经网络$U(\\theta)$在1组正交的初始态上,我们将得到输出态$\\left| {\\psi_k \\left( {\\bf{\\theta }} \\right)} \\right\\rangle $。\n",
"- 进一步,在SSVQE模型中的损失函数一般由哈密顿量H与量子态$\\left| {\\psi_k \\left( {\\bf{\\theta }} \\right)} \\right\\rangle$的内积的加权求和给出。\n",
"- 具体的损失函数定义为\n",
"$$4\\left\\langle {\\psi_1 \\left( {\\bf{\\theta }} \\right)} \\right|H\\left| {\\psi_1 \\left( {\\bf{\\theta }} \\right)} \\right\\rangle + 3\\left\\langle {\\psi_2 \\left( {\\bf{\\theta }} \\right)} \\right|H\\left| {\\psi_2 \\left( {\\bf{\\theta }} \\right)} \\right\\rangle + 2\\left\\langle {\\psi_3 \\left( {\\bf{\\theta }} \\right)} \\right|H\\left| {\\psi_3 \\left( {\\bf{\\theta }} \\right)} \\right\\rangle + \\left\\langle {\\psi_4 \\left( {\\bf{\\theta }} \\right)} \\right|H\\left| {\\psi_4 \\left( {\\bf{\\theta }} \\right)} \\right\\rangle.$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"SEED = 1\n",
"\n",
"class Net(fluid.dygraph.Layer):\n",
" \"\"\"\n",
" Construct the model net\n",
" \"\"\"\n",
"\n",
" def __init__(self, shape, param_attr=fluid.initializer.Uniform(low=0.0, high=2 * numpy.pi, seed=SEED),\n",
" dtype='float32'):\n",
" super(Net, self).__init__()\n",
"\n",
" self.theta = self.create_parameter(shape=shape, attr=param_attr, dtype=dtype, is_bias=False)\n",
"\n",
" def forward(self, H, N):\n",
" \"\"\"\n",
" Args:\n",
" input_state: The initial state with default |0..>\n",
" H: The target Hamiltonian\n",
" Returns:\n",
" The loss.\n",
" \"\"\"\n",
" out_state = U_theta(self.theta, N)\n",
"\n",
" loss_struct = matmul(matmul(\n",
" transpose(fluid.framework.ComplexVariable(out_state.real, -out_state.imag), perm=[1, 0]), H),\n",
" out_state).real\n",
"\n",
" loss_components = [\n",
" loss_struct[0][0],\n",
" loss_struct[1][1],\n",
" loss_struct[2][2],\n",
" loss_struct[3][3]\n",
" ]\n",
"\n",
" loss = 4 * loss_components[0] + 3 * loss_components[1] + 2 * loss_components[2] + 1 * loss_components[3]\n",
" return loss, loss_components\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 配置训练模型 - 模型参数\n",
"在进行量子神经网络的训练之前,我们还需要进行一些训练(超)参数的设置,例如学习速率与迭代次数。\n",
"- 设定学习速率(learning rate)为0.3。\n",
"- 设定迭代次数为50次。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"ITR = 50 # 迭代次数\n",
"\n",
"LR = 0.3 # 学习速率\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 进行训练\n",
"\n",
"- 当训练模型的各项参数都设置完成后,我们将数据转化为Paddle动态图中的变量,进而进行量子神经网络的训练。\n",
"- 过程中我们用的是Adam Optimizer,也可以调用Paddle中提供的其他优化器。\n",
"- 我们将训练过程中的每一轮loss可以打印出来。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"with fluid.dygraph.guard():\n",
" # Harmiltonian preparing\n",
" hamiltonian = fluid.dygraph.to_variable(hamiltonian)\n",
"\n",
" # net\n",
" net = Net(shape=[THETA_SIZE])\n",
"\n",
" # optimizer\n",
" opt = fluid.optimizer.AdagradOptimizer(learning_rate=LR, parameter_list=net.parameters())\n",
"\n",
" # gradient descent loop\n",
" for itr in range(1, ITR + 1):\n",
" loss, loss_components = net(hamiltonian, N)\n",
"\n",
" loss.backward()\n",
" opt.minimize(loss)\n",
" net.clear_gradients()\n",
"\n",
" print('iter:', itr, 'loss:', '%.4f' % loss.numpy()[0])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 测试效果\n",
"我们现在已经完成了量子神经网络的训练,我们将通过与理论值的对比来测试效果。\n",
"- 理论值由numpy中的工具来求解哈密顿量的各个特征值;\n",
"- 我们将训练QNN得到的各个能级的能量和理想情况下的理论值进行比对。\n",
"- 可以看到,SSVQE训练输出的值与理想值高度接近。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"print('The estimated ground state energy is: ', loss_components[0].numpy())\n",
"print('The theoretical ground state energy: ', numpy.linalg.eigh(H)[0][0])\n",
"\n",
"print('The estimated 1st excited state energy is: ', loss_components[1].numpy())\n",
"print('The theoretical 1st excited state energy: ', numpy.linalg.eigh(H)[0][1])\n",
"\n",
"print('The estimated 2nd excited state energy is: ', loss_components[2].numpy())\n",
"print('The theoretical 2nd excited state energy: ', numpy.linalg.eigh(H)[0][2])\n",
"\n",
"print('The estimated 3rd excited state energy is: ', loss_components[3].numpy())\n",
"print('The theoretical 3rd excited state energy: ', numpy.linalg.eigh(H)[0][3])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## 参考文献\n",
"[1] A. Peruzzo et al., “A variational eigenvalue solver on a photonic quantum processor,” Nat. Commun., vol. 5, no. 1, p. 4213, Dec. 2014.\n",
"\n",
"[2] S. McArdle, S. Endo, A. Aspuru-Guzik, S. C. Benjamin, and X. Yuan, “Quantum computational chemistry,” Rev. Mod. Phys., vol. 92, no. 1, p. 015003, Mar. 2020.\n",
"\n",
"[3] Y. Cao et al., “Quantum chemistry in the age of quantum computing,” Chem. Rev., vol. 119, no. 19, pp. 10856–10915, 2019.\n",
"\n",
"[4] K. M. Nakanishi, K. Mitarai, and K. Fujii, “Subspace-search variational quantum eigensolver for excited states,” Phys. Rev. Res., vol. 1, no. 3, p. 033062, Oct. 2019.\n",
"\n",
"\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.7"
},
"pycharm": {
"stem_cell": {
"cell_type": "raw",
"metadata": {
"collapsed": false
},
"source": []
}
}
},
"nbformat": 4,
"nbformat_minor": 1
}
此差异已折叠。
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 概览\n",
"- 在这个案例中,我们将展示如何通过Paddle Quantum训练量子神经网络来将量子态进行对角化。\n",
"\n",
"- 首先,让我们通过下面几行代码引入必要的library和package。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import numpy\n",
"from numpy import diag\n",
"import scipy\n",
"from paddle import fluid\n",
"from paddle_quantum.circuit import UAnsatz\n",
"from paddle.complex import matmul, trace, transpose"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"$\\newcommand{\\ket}[1]{|{#1}\\rangle}$\n",
"$\\newcommand{\\bra}[1]{\\langle{#1}|}$\n",
"\n",
"## 背景\n",
"量子态对角化算法(VQSD)[1-3] 目标是输出一个量子态的特征谱,即其所有特征值。求解量子态的特征值在量子计算中有着诸多应用,比如可以用于计算保真度和冯诺依曼熵,也可以用于主成分分析。\n",
"- 量子态通常是一个混合态,表示如下 $\\rho_{\\text{mixed}} = \\sum_i P_i \\ket{\\psi_i}\\bra{\\psi_i}$\n",
"- 作为一个简单的例子,我们考虑一个2量子位的量子态,它的特征谱为 $(0.5, 0.3, 0.1, 0.1)$, 我们先通过随机作用一个酉矩阵来生成具有这样特征谱的量子态。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"scipy.random.seed(1)\n",
"V = scipy.stats.unitary_group.rvs(4) # 随机生成一个酉矩阵\n",
"D = diag([0.5, 0.3, 0.1, 0.1]) # 输入目标态rho的谱\n",
"V_H = V.conj().T \n",
"rho = V @ D @ V_H # 生成 rho\n",
"print(rho) # 打印量子态 rho\n",
"rho = rho.astype('complex64')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 搭建量子神经网络\n",
"- 在这个案例中,我们将通过训练量子神经网络QNN(也可以理解为参数化量子电路)来学习量子态的特征谱。这里,我们提供一个预设的2量子位量子电路。\n",
"\n",
"- 我们预设一些该参数化电路的参数,比如宽度为2量子位。\n",
"\n",
"- 初始化其中的变量参数,${\\bf{\\theta }}$代表我们量子神经网络中的参数组成的向量。\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%% \n"
}
},
"outputs": [],
"source": [
"N = 2 # 量子神经网络的宽度\n",
"SEED = 1 # 种子\n",
"THETA_SIZE = 14 # 网络中的参数\n",
"\n",
"def U_theta(theta, N):\n",
" \"\"\"\n",
" U_theta\n",
" \"\"\"\n",
"\n",
" cir = UAnsatz(N)\n",
" cir.rz(theta[0], 1)\n",
" cir.ry(theta[1], 1)\n",
" cir.rz(theta[2], 1)\n",
"\n",
" cir.rz(theta[3], 2)\n",
" cir.ry(theta[4], 2)\n",
" cir.rz(theta[5], 2)\n",
"\n",
" cir.cnot([2, 1])\n",
"\n",
" cir.rz(theta[6], 1)\n",
" cir.ry(theta[7], 2)\n",
"\n",
" cir.cnot([1, 2])\n",
"\n",
" cir.rz(theta[8], 1)\n",
" cir.ry(theta[9], 1)\n",
" cir.rz(theta[10], 1)\n",
"\n",
" cir.rz(theta[11], 2)\n",
" cir.ry(theta[12], 2)\n",
" cir.rz(theta[13], 2)\n",
"\n",
" return cir.state\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"## 配置训练模型 - 损失函数\n",
"- 现在我们已经有了数据和量子神经网络的架构,我们将进一步定义训练参数、模型和损失函数。\n",
"- 通过作用量子神经网络$U(\\theta)$在量子态$\\rho$后得到的量子态记为$\\tilde\\rho$,我们设定损失函数为$\\tilde\\rho$与用来标记的量子态$\\sigma=0.1 \\ket{00}\\bra{00} + 0.2 \\ket{01}\\bra{01} + 0.3 \\ket{10}\\bra{10} + 0.4 \\ket{11}\\bra{11}$的内积。\n",
"- 具体的,设定损失函数为 $\\mathcal{L}(\\boldsymbol{\\theta}) = Tr(\\tilde\\rho\\sigma) .$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"sigma = diag([0.1, 0.2, 0.3, 0.4]) # 输入用来标记的量子态sigma\n",
"sigma = sigma.astype('complex64')\n",
"\n",
"class Net(fluid.dygraph.Layer):\n",
" \"\"\"\n",
" Construct the model net\n",
" \"\"\"\n",
"\n",
" def __init__(self, shape, rho, sigma, param_attr=fluid.initializer.Uniform(low=0.0, high=2 * numpy.pi, seed=SEED),\n",
" dtype='float32'):\n",
" super(Net, self).__init__()\n",
"\n",
" self.rho = fluid.dygraph.to_variable(rho)\n",
" self.sigma = fluid.dygraph.to_variable(sigma)\n",
"\n",
" self.theta = self.create_parameter(shape=shape, attr=param_attr, dtype=dtype, is_bias=False)\n",
"\n",
" def forward(self, N):\n",
" \"\"\"\n",
" Args:\n",
" Returns:\n",
" The loss.\n",
" \"\"\"\n",
"\n",
" out_state = U_theta(self.theta, N)\n",
"\n",
" # rho_tilde 是将U_theta作用在rho后得到的量子态 \n",
" rho_tilde = matmul(\n",
" matmul(transpose(\n",
" fluid.framework.ComplexVariable(out_state.real, -out_state.imag),\n",
" perm=[1, 0]\n",
" ), self.rho), out_state\n",
" )\n",
"\n",
" # record the new loss\n",
" loss = trace(matmul(self.sigma, rho_tilde))\n",
"\n",
" return loss.real, rho_tilde"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 配置训练模型 - 模型参数\n",
"在进行量子神经网络的训练之前,我们还需要进行一些训练(超)参数的设置,例如学习速率与迭代次数。\n",
"- 设定学习速率(learning rate)为0.1;\n",
"- 设定迭代次数为50次。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"ITR = 50 #训练的总的迭代次数\n",
"\n",
"LR = 0.1 #学习速率"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 进行训练\n",
"\n",
"- 当训练模型的各项参数都设置完成后,我们将数据转化为Paddle动态图中的变量,进而进行量子神经网络的训练。\n",
"- 过程中我们用的是Adam Optimizer,也可以调用Paddle中提供的其他优化器。\n",
"- 我们将训练过程中的结果依次输出。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%% \n"
}
},
"outputs": [],
"source": [
"with fluid.dygraph.guard():\n",
" # net\n",
" net = Net(shape=[THETA_SIZE], rho=rho, sigma=sigma)\n",
"\n",
" # optimizer\n",
" opt = fluid.optimizer.AdagradOptimizer(learning_rate=LR, parameter_list=net.parameters())\n",
" # gradient descent loop\n",
" for itr in range(ITR):\n",
" loss, rho_tilde = net(N)\n",
"\n",
" rho_tilde_np = rho_tilde.numpy()\n",
" loss.backward()\n",
" opt.minimize(loss)\n",
" net.clear_gradients()\n",
"\n",
" print('iter:', itr, 'loss:', '%.4f' % loss.numpy()[0])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 总结\n",
"根据上面训练得到的结果,通过大概50次迭代,我们就比较好的完成了对角化。\n",
"我们可以通过打印$\n",
"\\tilde{\\rho} = U(\\boldsymbol{\\theta})\\rho U^\\dagger(\\boldsymbol{\\theta})\n",
"$\n",
"的来验证谱分解的效果。特别的,我们可以验证它的对角线与我们目标谱是非常接近的。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"is_executing": false,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"print(rho_tilde_np)\n",
"\n",
"print(\"The estimated spectrum is:\", numpy.real(numpy.diag(rho_tilde_np)))\n",
"print(\"The target spectrum is:\", numpy.diag(D))"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"### 参考文献\n",
"\n",
"[1] R. Larose, A. Tikku, É. O. Neel-judy, L. Cincio, and P. J. Coles, “Variational quantum state diagonalization,” npj Quantum Inf., no. November 2018, 2019.\n",
"\n",
"[2] K. M. Nakanishi, K. Mitarai, and K. Fujii, “Subspace-search variational quantum eigensolver for excited states,” Phys. Rev. Res., vol. 1, no. 3, p. 033062, Oct. 2019.\n",
"\n",
"[3] M. Cerezo, K. Sharma, A. Arrasmith, and P. J. Coles, “Variational Quantum State Eigensolver,” arXiv:2004.01372, no. 1, pp. 1–14, Apr. 2020.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.6.10"
},
"pycharm": {
"stem_cell": {
"cell_type": "raw",
"metadata": {
"collapsed": false
},
"source": []
}
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册