基于 MindQuantum 实现幺正算符重构
设计设计拟设线路,使末态与目标态的保真度尽可能高。其中目标态即为由初态经过待重构的目标幺正算符操作得到。
单比特幺正算符重构演示:
比特初始到
∣
0
⟩
|0\rangle
∣0⟩ 态,之后经过编码线路制备到初态,然后经过拟设线路,将初态制备到目标态,完成算符操作。此时,拟设线路就是重构出的算符。
这里编码线路为
R
Z
(
0.4
)
R
X
(
0.3
)
R
X
(
0.2
)
RZ(0.4)RX(0.3)RX(0.2)
RZ(0.4)RX(0.3)RX(0.2)。拟设用的 U3 门,目标态为
∣
0
⟩
|0\rangle
∣0⟩。
# -*- coding: utf-8 -*-
"""
Created on Mon May 23 15:49:14 2022
@author: Waikikilick
"""
import numpy as np
import mindspore as ms
from mindquantum import *
from mindspore import nn
from mindspore.nn import Adam, TrainOneStepCell
from mindspore.common.parameter import Parameter
from mindspore.common.initializer import initializer
ms.context.set_context(mode=ms.context.PYNATIVE_MODE, device_target="CPU")
ms.set_seed(1)
class My_QLayer(nn.Cell):
def __init__(self, expectation_with_grad, weight='normal'):
super(My_QLayer, self).__init__()
self.evolution = MQN2Ops(expectation_with_grad)
weight_size = len(
self.evolution.expectation_with_grad.ansatz_params_name)
self.weight = Parameter(initializer(weight,
weight_size,
dtype=ms.float32),
name='ansatz_weight')
def construct(self, x, target_state):
return self.evolution(x, self.weight, target_state)
# encoder
encoder = Circuit()
encoder += H.on(0)
encoder += RX(f'alpha{0}').on(0)
encoder += RY(f'alpha{1}').on(0)
encoder += RZ(f'alpha{2}').on(0)
encoder = encoder.no_grad()
# ansatz
ansatz = Circuit()
ansatz += U3('theta','phi','lam',0)
circuit = encoder + ansatz
alpha0, alpha1, alpha2 = 0.2, 0.3, 0.4
encoder_data = np.array([[alpha0, alpha1, alpha2]]).astype(np.float32)
encoder_names = encoder.params_name
ansatz_names = ansatz.params_name
ham = Hamiltonian(QubitOperator(''))
sim = Simulator('projectq', 1)
sim_left = Simulator('projectq', 1)
grad_ops = sim.get_expectation_with_grad(ham,
circuit,
circ_left=Circuit(),
simulator_left=sim_left,
encoder_params_name=encoder_names,
ansatz_params_name=ansatz_names)
QuantumNet = My_QLayer(grad_ops)
opti = Adam(QuantumNet.trainable_params(), learning_rate=0.01) # 需要优化的是Quantumnet中可训练的参数,学习率设为0.5
net = TrainOneStepCell(QuantumNet, opti)
for i in range(500):
# if i%100 == 0:
# paras = list(np.squeeze(encoder_data)) + list(QuantumNet.weight.asnumpy())
# paras_name = encoder_names + ansatz_names
# pr = dict(zip(paras_name, paras))
# state = circuit.get_qs(pr=pr)
# fid = np.abs(np.vdot(state, np.array([1, 0])))**2
# print('验证保真度为:',fid)
res = net(ms.Tensor(encoder_data),ms.Tensor(np.array([1,0])))
if i % 10 == 0:
print('step:',i, '训练保真度为: ', res[0,0])
paras = list(np.squeeze(encoder_data)) + list(QuantumNet.weight.asnumpy())
paras_name = encoder_names + ansatz_names
pr = dict(zip(paras_name, paras))
state = circuit.get_qs(pr=pr, ket=True)
print('最终量子态为\n',state)
state = circuit.get_qs(pr=pr)
fid = np.abs(np.vdot(state, np.array([1, 0])))**2
print('最终保真度为:',fid)
ansatz_paras = list(QuantumNet.weight.asnumpy())
print('重构出来的幺正算符为:\n',ansatz.matrix(pr=dict(zip(ansatz_names, ansatz_paras))))
step: 0 训练保真度为: 0.3461229
step: 10 训练保真度为: 0.39110067
step: 20 训练保真度为: 0.4406182
step: 30 训练保真度为: 0.49330464
step: 40 训练保真度为: 0.54629815
step: 50 训练保真度为: 0.5975355
step: 60 训练保真度为: 0.64704996
step: 70 训练保真度为: 0.6942862
step: 80 训练保真度为: 0.73834836
step: 90 训练保真度为: 0.7788622
step: 100 训练保真度为: 0.81543946
step: 110 训练保真度为: 0.8479178
step: 120 训练保真度为: 0.8762677
step: 130 训练保真度为: 0.90060383
step: 140 训练保真度为: 0.9211542
step: 150 训练保真度为: 0.93823075
step: 160 训练保真度为: 0.95220006
step: 170 训练保真度为: 0.96345496
step: 180 训练保真度为: 0.97238994
step: 190 训练保真度为: 0.9793825
step: 200 训练保真度为: 0.9847798
step: 210 训练保真度为: 0.98889023
step: 220 训练保真度为: 0.99198025
step: 230 训练保真度为: 0.994274
step: 240 训练保真度为: 0.9959559
step: 250 训练保真度为: 0.9971743
step: 260 训练保真度为: 0.9980467
step: 270 训练保真度为: 0.998664
step: 280 训练保真度为: 0.9990959
step: 290 训练保真度为: 0.99939466
step: 300 训练保真度为: 0.999599
step: 310 训练保真度为: 0.99973714
step: 320 训练保真度为: 0.9998296
step: 330 训练保真度为: 0.9998907
step: 340 训练保真度为: 0.9999306
step: 350 训练保真度为: 0.9999565
step: 360 训练保真度为: 0.999973
step: 370 训练保真度为: 0.99998343
step: 380 训练保真度为: 0.9999899
step: 390 训练保真度为: 0.999994
step: 400 训练保真度为: 0.9999964
step: 410 训练保真度为: 0.9999979
step: 420 训练保真度为: 0.9999988
step: 430 训练保真度为: 0.9999993
step: 440 训练保真度为: 0.9999996
step: 450 训练保真度为: 0.99999976
step: 460 训练保真度为: 0.9999999
step: 470 训练保真度为: 0.99999994
step: 480 训练保真度为: 0.99999994
step: 490 训练保真度为: 1.0
最终量子态为
(0.9943295181888445-0.10634283989171736j)¦0⟩
(9.78670609558259e-05-9.172955750665977e-06j)¦1⟩
最终保真度为: 0.9999999903378951
重构出来的幺正算符为:
[[ 0.58250438+0.11411596j 0.78767193-0.16504279j]
[-0.78767193-0.16504279j 0.58250438-0.11411596j]]
三比特幺正算符重构:
编码器为 18 参数的 3 比特线路,设计拟设线路,使末态与目标态的保真度尽可能高。其中目标态即为由初态经过待重构的目标幺正算符操作得到。
训练集包含 560 组数据,验证集包含 240 组数据。
主代码为:
# -*- coding: utf-8 -*-
"""
Created on Mon May 23 15:49:14 2022
功能:根据始末量子态,重构中间幺正操作
1. 采用卷积神经网络
2. 对 mindquantum 源代码进行了修改,使其支持动态输入目标态
@author: Waikikilick
"""
import numpy as np
import mindspore as ms
from mindquantum import *
from mindspore import nn
from mindspore.nn import Adam, TrainOneStepCell
from mindspore.common.parameter import Parameter
from mindspore.common.initializer import initializer
ms.context.set_context(mode=ms.context.PYNATIVE_MODE, device_target="CPU")
ms.set_seed(1)
train_x = np.load('./new_train_x.npy', allow_pickle=True)
train_y = np.load('./new_train_y.npy', allow_pickle=True)
eval_x = np.load('./new_eval_x.npy', allow_pickle=True)
eval_y = np.load('./new_eval_y.npy', allow_pickle=True)
test_x = np.load('./test_x.npy', allow_pickle=True)
# 自定义网络层
# 本来是不支持传入 target_state 的
class My_QLayer(nn.Cell):
def __init__(self, expectation_with_grad, weight='normal'):
super(My_QLayer, self).__init__()
self.evolution = MQN2Ops(expectation_with_grad)
weight_size = len(self.evolution.expectation_with_grad.ansatz_params_name)
self.weight = Parameter(initializer(weight,
weight_size,
dtype=ms.float32),
name='ansatz_weight')
def construct(self, x, target_state):
return self.evolution(x, self.weight, target_state)
# encoder
def generate_encoder():
enc_layer = Circuit()
for i in range(3):
enc_layer += U3(f'a{i}', f'b{i}', f'c{i}', i)
coupling_layer = UN(X, [1, 2, 0], [0, 1, 2])
encoder = Circuit()
for i in range(2):
encoder += add_prefix(enc_layer, f'l{i}')
encoder += coupling_layer
return encoder, encoder.params_name
encoder, encoder_names = generate_encoder()
encoder.no_grad()
# ansatz
# 卷积神经网络,卷积核为 9b
def Ansatz(layer_num=10):
ansatz = Circuit()
for i in range(layer_num):
ansatz += ansatz_layer(prefix=f'layer{i}')
return ansatz
def ansatz_layer(prefix='0'):
_circ = Circuit()
_circ += BarrierGate()
_circ += conv_circ(prefix='01', bit_up=0, bit_down=1)
_circ += BarrierGate()
_circ += conv_circ(prefix='12', bit_up=1, bit_down=2)
_circ += BarrierGate()
_circ += conv_circ(prefix='20', bit_up=2, bit_down=0)
_circ += BarrierGate()
_circ = add_prefix(_circ, prefix)
return _circ
def conv_circ(prefix='0', bit_up=0, bit_down=1):
_circ = Circuit()
_circ += U3('theta00','phi00','lam00',bit_up)
_circ += U3('theta01','phi01','lam01',bit_down)
_circ += X.on(bit_down,bit_up)
_circ += RY('theta10').on(bit_up)
_circ += RZ('theta11').on(bit_down)
_circ += X.on(bit_up,bit_down)
_circ += RY('theta20').on(bit_up)
_circ += X.on(bit_down,bit_up)
_circ += U3('theta30','phi30','lam30',bit_up)
_circ += U3('theta31','phi31','lam31',bit_down)
_circ = add_prefix(_circ, prefix)
return _circ
ansatz = Circuit()
ansatz = Ansatz(layer_num=4)
ansatz_names = ansatz.params_name
circuit = encoder + ansatz
paras_name = circuit.params_name
ham = Hamiltonian(QubitOperator(''))
sim = Simulator('projectq', 3)
sim_left = Simulator('projectq', 3)
grad_ops = sim.get_expectation_with_grad(ham,
circuit,
circ_left=Circuit(),
simulator_left=sim_left,
encoder_params_name=encoder_names,
ansatz_params_name=ansatz_names)
QuantumNet = My_QLayer(grad_ops)
opti = Adam(QuantumNet.trainable_params(), learning_rate=0.001) # 需要优化的是Quantumnet中可训练的参数,学习率设为0.5
net = TrainOneStepCell(QuantumNet, opti)
for epoch in range(10):
print('\nepoch is:', epoch)
for i in range(len(train_x)):
encoder_data = train_x[i].reshape((1,18)).astype(np.float32)
target_psi = train_y[i]
res = net(ms.Tensor(encoder_data),ms.Tensor(target_psi))
if i%100 == 0: # 每 100 步,用整个验证集验证一下
print('step:', i, '训练保真度:', res[0,0])
state_list = []
for x in eval_x:
paras = list(np.squeeze(x)) + list(QuantumNet.weight.asnumpy())
pr = dict(zip(paras_name, paras))
state = circuit.get_qs(pr=pr)
state_list.append(state)
acc = np.real(np.mean([np.abs(np.vdot(bra, ket)) for bra, ket in zip(np.array(state_list), eval_y)]))
print('对验证集的平均保真度:', np.mean(acc))
ansatz_paras = list(QuantumNet.weight.asnumpy())
print('重构出来的幺正算符为:\n',ansatz.matrix(pr=dict(zip(ansatz_names, ansatz_paras))))
# fid_list = []
# for x, y in zip(eval_x,eval_y):
# paras = list(np.squeeze(x)) + list(QuantumNet.weight.asnumpy())
# pr = dict(zip(paras_name, paras))
# state = circuit.get_qs(pr=pr)
# fid = np.abs(np.vdot(state, y))**2
# fid_list.append(fid)
# print('验证集平均保真度:',np.mean(fid_list))
# np.save('./lala.npy',np.array(state_list))
# print('导出完成啦!')
# state_array = np.load('./lala.npy', allow_pickle=True)
# state_list = []
# for x in test_x:
# paras = list(np.squeeze(x)) + list(QuantumNet.weight.asnumpy())
# pr = dict(zip(paras_name, paras))
# state = circuit.get_qs(pr=pr)
# state_list.append(state)
# np.save('./heihei.npy',np.array(state_list))
# print('导出完成啦!')
epoch is: 0
step: 0 训练保真度: 0.016098816
step: 100 训练保真度: 0.31427863
step: 200 训练保真度: 0.22147878
step: 300 训练保真度: 0.14485279
step: 400 训练保真度: 0.21505353
step: 500 训练保真度: 0.38416347
epoch is: 1
step: 0 训练保真度: 0.31240866
step: 100 训练保真度: 0.50511765
step: 200 训练保真度: 0.5381597
step: 300 训练保真度: 0.7453368
step: 400 训练保真度: 0.7787936
step: 500 训练保真度: 0.8533651
epoch is: 2
step: 0 训练保真度: 0.7847961
step: 100 训练保真度: 0.8193776
step: 200 训练保真度: 0.8875419
step: 300 训练保真度: 0.9086917
step: 400 训练保真度: 0.9761023
step: 500 训练保真度: 0.9693968
epoch is: 3
step: 0 训练保真度: 0.9706415
step: 100 训练保真度: 0.97703516
step: 200 训练保真度: 0.98235166
step: 300 训练保真度: 0.9883929
step: 400 训练保真度: 0.99665827
step: 500 训练保真度: 0.9921469
epoch is: 4
step: 0 训练保真度: 0.99242043
step: 100 训练保真度: 0.99483854
step: 200 训练保真度: 0.9920595
step: 300 训练保真度: 0.9942117
step: 400 训练保真度: 0.9972964
step: 500 训练保真度: 0.9948216
epoch is: 5
step: 0 训练保真度: 0.9944427
step: 100 训练保真度: 0.996896
step: 200 训练保真度: 0.9941251
step: 300 训练保真度: 0.9954542
step: 400 训练保真度: 0.9974259
step: 500 训练保真度: 0.99540913
epoch is: 6
step: 0 训练保真度: 0.99496925
step: 100 训练保真度: 0.9975881
step: 200 训练保真度: 0.99486333
step: 300 训练保真度: 0.9959512
step: 400 训练保真度: 0.9975988
step: 500 训练保真度: 0.99554086
epoch is: 7
step: 0 训练保真度: 0.99527115
step: 100 训练保真度: 0.997855
step: 200 训练保真度: 0.995271
step: 300 训练保真度: 0.99618524
step: 400 训练保真度: 0.99788946
step: 500 训练保真度: 0.9957079
epoch is: 8
step: 0 训练保真度: 0.9958286
step: 100 训练保真度: 0.99798477
step: 200 训练保真度: 0.9958605
step: 300 训练保真度: 0.99661624
step: 400 训练保真度: 0.99830586
step: 500 训练保真度: 0.99669534
epoch is: 9
step: 0 训练保真度: 0.99712235
step: 100 训练保真度: 0.9984253
step: 200 训练保真度: 0.9973581
step: 300 训练保真度: 0.9979845
step: 400 训练保真度: 0.99896777
step: 500 训练保真度: 0.9989337
对验证集的平均保真度: 0.9994351328397008
重构出来的幺正算符为:
[[ 7.59947141e-03+9.05753040e-03j 1.47733732e-02+1.46454241e-01j
-1.76204151e-03+1.01860066e-03j 5.75359216e-01-1.62025345e-01j
-3.11655701e-03+9.30582051e-04j 1.94216566e-01+1.45818288e-02j
3.93564779e-03-2.22415661e-03j 8.99146314e-02-7.58188743e-01j]
[ 3.26981046e-03-1.36537175e-03j 2.94734565e-02+1.58801236e-01j
2.82942844e-03+1.94720863e-03j -4.54290350e-02+3.05537295e-02j
2.88963622e-03-1.97000624e-03j 7.62933467e-01+5.74755663e-01j
2.35065663e-03+4.08336465e-03j -1.64423942e-01+1.77230332e-01j]
[-2.28597647e-02+4.42781317e-02j 1.29962227e-03-3.00651194e-03j
1.63295972e-01+2.06087029e-02j 2.81343629e-04-1.38403944e-03j
1.74484511e-01-1.64950519e-01j 3.39181563e-03+3.60711984e-03j
-5.81983819e-01-7.57630232e-01j 5.19855908e-03-2.61572864e-04j]
[ 1.67136552e-01-5.73888593e-01j -3.93497255e-03+5.51229387e-04j
1.41878155e-01+1.62625094e-02j 8.24727060e-03+7.57564796e-03j
-7.58000767e-01+1.00095476e-01j -1.46463874e-03+3.69237740e-03j
-1.37838342e-02-1.93351641e-01j -1.04859476e-03+2.48670968e-03j]
[-8.35458131e-03-5.83701897e-03j -1.03017118e-01-1.70718518e-01j
-1.63030932e-03+7.25385939e-03j -6.26947472e-01+4.33341682e-01j
-3.26936502e-04+6.62202099e-03j 1.40807008e-01-6.24777236e-02j
6.03524746e-04-3.06087973e-03j -1.23543579e-01-5.83256875e-01j]
[ 4.26501463e-03-1.45696141e-03j -8.73800324e-01+3.85797449e-01j
8.16930617e-03-9.75368119e-04j -1.17630919e-01-2.11568785e-01j
4.57484376e-03-2.05844832e-04j 6.69097174e-02-1.46246522e-01j
2.13024443e-03-1.80877679e-03j 4.43002221e-02+3.30255804e-02j]
[ 2.10867066e-01+1.17668540e-01j 1.24338767e-03-8.68227290e-03j
3.89387785e-01-8.71912392e-01j -5.25851817e-03+3.81962849e-03j
3.04426054e-02+4.97536905e-02j -3.98704631e-04+3.04468088e-03j
1.50983033e-01-5.90468073e-02j -1.69310274e-03-4.36815653e-03j]
[-4.44392299e-01+6.19808264e-01j -3.78712909e-03+2.14050266e-03j
-1.70135126e-01-1.07595979e-01j -6.62428970e-03-7.22342468e-03j
-5.82540411e-01-1.22143209e-01j 3.23754493e-03+7.12349754e-04j
5.74338709e-02-1.41686926e-01j -7.00536244e-03+3.02808423e-03j]]
源代码修改
因原 MindQuantum 不支持动态传入目标量子态,需要对其源码进行一定修改。后面是在源代码中的修改内容。
1. 在 operations.py 中的修改:
class MQN2Ops(nn.Cell):
def __init__(self, expectation_with_grad):
super(MQN2Ops, self).__init__()
_mode_check(self)
_check_grad_ops(expectation_with_grad)
self.expectation_with_grad = expectation_with_grad
self.shape_ops = P.Shape()
def extend_repr(self):
return self.expectation_with_grad.str
def construct(self, enc_data, ans_data, target_state): # target_state 是新加的
check_enc_input_shape(enc_data, self.shape_ops(enc_data), len(self.expectation_with_grad.encoder_params_name))
check_ans_input_shape(ans_data, self.shape_ops(ans_data), len(self.expectation_with_grad.ansatz_params_name))
enc_data = enc_data.asnumpy()
ans_data = ans_data.asnumpy()
target_state = target_state.asnumpy() # 这行是新加的
f, g_enc, g_ans = self.expectation_with_grad(enc_data, ans_data, target_state)
self.f = -f # 新加了一个负号,由梯度下降变成了梯度上升
f = ms.Tensor(np.abs(f)**2, dtype=ms.float32)
self.g_enc = g_enc
self.g_ans = g_ans
return f
def bprop(self, enc_data, ans_data, target_state, out, dout): # 新加了 target_state
dout = dout.asnumpy()
enc_grad = 2 * np.real(np.einsum('smp,sm,sm->sp', self.g_enc, dout, np.conj(self.f)))
ans_grad = 2 * np.real(np.einsum('smp,sm,sm->p', self.g_ans, dout, np.conj(self.f)))
return ms.Tensor(enc_grad, dtype=ms.float32), ms.Tensor(ans_grad, dtype=ms.float32), ms.Tensor(np.zeros(target_state.shape), dtype=ms.float32)
# 返回值中新加了 ms.Tensor(np.zeros(target_state.shape), dtype=ms.float32)
2. 在 simulator.py 中的修改:
def get_expectation_with_grad(self,
hams,
circ_right,
circ_left=None,
simulator_left=None,
encoder_params_name=None,
ansatz_params_name=None,
parallel_worker=None):
if isinstance(hams, Hamiltonian):
hams = [hams]
elif not isinstance(hams, list):
raise TypeError(f"hams requires a Hamiltonian or a list of Hamiltonian, but get {type(hams)}")
for h_tmp in hams:
_check_input_type("hams's element", Hamiltonian, h_tmp)
_check_hamiltonian_qubits_number(h_tmp, self.n_qubits)
_check_input_type("circ_right", Circuit, circ_right)
if circ_right.is_noise_circuit:
raise ValueError("noise circuit not support yet.")
non_hermitian = False
if circ_left is not None:
_check_input_type("circ_left", Circuit, circ_left)
if circ_left.is_noise_circuit:
raise ValueError("noise circuit not support yet.")
non_hermitian = True
if simulator_left is not None:
_check_input_type("simulator_left", Simulator, simulator_left)
if self.backend != simulator_left.backend:
raise ValueError(f"simulator_left should have the same backend as this simulator, \
which is {self.backend}, but get {simulator_left.backend}")
if self.n_qubits != simulator_left.n_qubits:
raise ValueError(f"simulator_left should have the same n_qubits as this simulator, \
which is {self.n_qubits}, but get {simulator_left.n_qubits}")
non_hermitian = True
if non_hermitian and simulator_left is None:
simulator_left = self
if circ_left is None:
circ_left = circ_right
if circ_left.has_measure_gate or circ_right.has_measure_gate:
raise ValueError("circuit for variational algorithm cannot have measure gate")
if parallel_worker is not None:
_check_int_type("parallel_worker", parallel_worker)
if encoder_params_name is None and ansatz_params_name is None:
encoder_params_name = []
ansatz_params_name = [i for i in circ_right.params_name]
for i in circ_left.params_name:
if i not in ansatz_params_name:
ansatz_params_name.append(i)
if encoder_params_name is None:
encoder_params_name = []
if ansatz_params_name is None:
ansatz_params_name = []
_check_input_type("encoder_params_name", list, encoder_params_name)
_check_input_type("ansatz_params_name", list, ansatz_params_name)
for i in encoder_params_name:
_check_input_type("Element of encoder_params_name", str, i)
for i in ansatz_params_name:
_check_input_type("Element of ansatz_params_name", str, i)
s1 = set(circ_right.params_name) | set(circ_left.params_name)
s2 = set(encoder_params_name) | set(ansatz_params_name)
if s1 - s2 or s2 - s1:
raise ValueError("encoder_params_name and ansatz_params_name are different with circuit parameters")
circ_n_qubits = max(circ_left.n_qubits, circ_right.n_qubits)
if self.n_qubits < circ_n_qubits:
raise ValueError(f"Simulator has {self.n_qubits} qubits, but circuit has {circ_n_qubits} qubits.")
version = "both"
if not ansatz_params_name:
version = "encoder"
if not encoder_params_name:
version = "ansatz"
def grad_ops(*inputs):
if version == "both" and len(inputs) != 3: # 因需要多输入一个目标量子态,由原来的 !=2 变成了 != 3.
raise ValueError("Need two inputs!")
if version in ("encoder", "ansatz") and len(inputs) != 1:
raise ValueError("Need one input!")
if version == "both":
_check_encoder(inputs[0], len(encoder_params_name))
_check_ansatz(inputs[1], len(ansatz_params_name))
batch_threads, mea_threads = _thread_balance(inputs[0].shape[0], len(hams), parallel_worker)
inputs0 = inputs[0]
inputs1 = inputs[1]
target_state = inputs[2] # 多加了这一行
if version == "encoder":
_check_encoder(inputs[0], len(encoder_params_name))
batch_threads, mea_threads = _thread_balance(inputs[0].shape[0], len(hams), parallel_worker)
inputs0 = inputs[0]
inputs1 = np.array([])
if version == "ansatz":
_check_ansatz(inputs[0], len(ansatz_params_name))
batch_threads, mea_threads = _thread_balance(1, len(hams), parallel_worker)
inputs0 = np.array([[]])
inputs1 = inputs[0]
if non_hermitian:
simulator_left.sim.set_qs(target_state) # 多加了这一行
f_g1_g2 = self.sim.non_hermitian_measure_with_grad([i.get_cpp_obj() for i in hams],
[i.get_cpp_obj(hermitian=True) for i in hams],
circ_left.get_cpp_obj(),
circ_left.get_cpp_obj(hermitian=True),
circ_right.get_cpp_obj(),
circ_right.get_cpp_obj(hermitian=True), inputs0,
inputs1, encoder_params_name, ansatz_params_name,
batch_threads, mea_threads, simulator_left.sim)
else:
f_g1_g2 = self.sim.hermitian_measure_with_grad([i.get_cpp_obj()
for i in hams], circ_right.get_cpp_obj(),
circ_right.get_cpp_obj(hermitian=True), inputs0, inputs1,
encoder_params_name, ansatz_params_name, batch_threads,
mea_threads)
res = np.array(f_g1_g2)
if version == 'both':
f = res[:, :, 0]
g1 = res[:, :, 1:1 + len(encoder_params_name)]
g2 = res[:, :, 1 + len(encoder_params_name):]
return f, g1, g2
f = res[:, :, 0]
g = res[:, :, 1:]
return f, g
grad_wrapper = GradOpsWrapper(grad_ops, hams, circ_right, circ_left, encoder_params_name, ansatz_params_name,
parallel_worker)
s = f'{self.n_qubits} qubit' + ('' if self.n_qubits == 1 else 's')
s += f' {self.backend} VQA Operator'
grad_wrapper.set_str(s)
return grad_wrapper