Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 38 additions & 47 deletions pyqpanda-algorithm/pyqpanda_alg/QAE/QAE.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,36 +79,30 @@ def __init__(self, operator_in=None,
if type(self.res_index) != list:
self.res_index = [self.res_index]

def __del__(self):
pass

def _Q_cir(self, q_operator):
if type(self.res_index) != list:
self.res_index = [self.res_index]
q_target = []
q_else = []
q1 = []
index = []
for i in self.res_index:
index += [(list(range(self.qnumber)))[i]]
for i in range(self.qnumber):
if i in index:
q_target += [q_operator[i]]
else:
q_else += [q_operator[i]]
if i != index[-1]:
q1 += [q_operator[i]]
def __del__(self):
pass

def _target_indices(self):
return [(list(range(self.qnumber)))[i] for i in self.res_index]

def _Q_cir(self, q_operator):
index = self._target_indices()
q_target = [q_operator[i] for i in index]
q1 = []
for i in range(self.qnumber):
if i != index[-1]:
q1 += [q_operator[i]]

Qcir = QCircuit()
if len(q_target) == 1:
Qcir << Z(q_target[0]) << RX(q_target[0], 2 * pi)
elif len(q_target) > 1:
Qcir << Z(q_target[-1]).control(q_target[:-1]) << RX(q_target[-1], 2 * pi)
for k in range(len(self.target_state)):
if self.target_state[k] == '0':
Qcir << X(q_target[-k-1])
Qcir << self.operator(q_operator).dagger()

for k in range(len(self.target_state)):
if self.target_state[k] == '0':
Qcir << X(q_target[k])
Qcir << self.operator(q_operator).dagger()

for q1idx in q1:
Qcir << X(q1idx)
Expand All @@ -117,11 +111,11 @@ def _Q_cir(self, q_operator):
for q1idx in q1:
Qcir << X(q1idx)

Qcir << self.operator(q_operator)
for k in range(len(self.target_state)):
if self.target_state[k] == '0':
Qcir << X(q_target[-k-1])
return Qcir
Qcir << self.operator(q_operator)
for k in range(len(self.target_state)):
if self.target_state[k] == '0':
Qcir << X(q_target[k])
return Qcir

def run(self):
"""
Expand Down Expand Up @@ -154,20 +148,15 @@ def run(self):
"""
q_operator = QProg(self.qnumber + self.n_anc).qubits()

q_target = []
index = []
for i in self.res_index:
index += [(list(range(self.qnumber)))[i]]
for i in range(self.qnumber):
if i in index:
q_target += [q_operator[i]]
index = self._target_indices()
q_target = [q_operator[i] for i in index]

prog = QProg()

prog << self.operator(q_operator[:self.qnumber])
for k in range(len(self.target_state)):
if self.target_state[k] == '0':
prog << X(q_target[-k-1])
prog << self.operator(q_operator[:self.qnumber])
for k in range(len(self.target_state)):
if self.target_state[k] == '0':
prog << X(q_target[k])

for qidx in q_operator[self.qnumber:]:
prog << H(qidx)
Expand Down Expand Up @@ -229,9 +218,9 @@ def __init__(self, operator_in=None,
self.alpha = alpha
self.method = method
self.ratio = ratio
self.qnumber = qnumber
self.res_index = res_index
self.machine_type = machine_type
self.qnumber = qnumber
self.res_index = (list(range(self.qnumber)))[res_index]
self.machine_type = machine_type
self.n_sum = 0

if machine_type == 'CPU':
Expand Down Expand Up @@ -349,16 +338,18 @@ def run(self):
def _measure(self, k: int, n_round: int) -> int:
machine = self.machine
qlist = self.qlist
clist = self.clist

operator_g = amp_operator(in_operator=self.operatorA, q_input=qlist)
operator_g = amp_operator(
in_operator=self.operatorA,
q_input=qlist,
q_flip=[qlist[self.res_index]],
)
prog = QProg()
prog << self.operatorA(qlist)
for i in range(k):
prog << operator_g
if self.draw:
print(prog)
prog << measure_all([qlist[self.res_index]], [qlist[self.qnumber - 1]])
prog << measure_all([qlist[self.res_index]], [0])
if self.machine_type == 'CPU':
machine.run(prog, n_round)
res = machine.result().get_counts()
Expand Down
74 changes: 44 additions & 30 deletions test/QAlgBase/Test_QAE_IQAE.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
# import pytest
# import numpy as np
# from pyqpanda_alg.QAE.QAE import IQAE
# from pyqpanda3.core import QCircuit, RY, X, RZ
#
#
# class Test_QAE_IQAE:
#
# def create_cir_basic(self, qlist):
# cir = QCircuit()
# cir << RY(qlist[0], np.pi / 3) << X(qlist[1]).control(qlist[0])
# return cir
#
# def test_iqae_basic_functionality(self):
# W = IQAE(
# operator_in=self.create_cir_basic,
# qnumber=2,
# epsilon=0.01,
# res_index=-1
# ).run()
#
# # 断言验证
# assert W is not None, "振幅估计结果不应为None"
# assert isinstance(W, (float, np.floating)), f"振幅应为数值类型,实际为{type(W)}"
# assert 0.2 <= W <= 0.3, f"振幅应在[0,1]范围内,实际为{W}"
#
#
# if __name__ == "__main__":
# # 运行测试
# pytest.main([__file__, "-v", "-s"])
import numpy as np
from pyqpanda3.core import QCircuit, RY

from pyqpanda_alg.QAE import IQAE


def asymmetric_two_qubit_state(qlist):
cir = QCircuit()
cir << RY(qlist[0], np.pi / 5)
cir << RY(qlist[1], np.pi / 3)
return cir


def test_iqae_estimates_non_last_result_qubit():
prob = IQAE(
operator_in=asymmetric_two_qubit_state,
qnumber=2,
epsilon=0.005,
res_index=0,
).run()

assert np.isclose(prob, np.sin(np.pi / 10) ** 2, atol=0.08)


def test_iqae_estimates_last_result_qubit():
prob = IQAE(
operator_in=asymmetric_two_qubit_state,
qnumber=2,
epsilon=0.005,
res_index=1,
).run()

assert np.isclose(prob, np.sin(np.pi / 6) ** 2, atol=0.08)


def test_iqae_negative_index_keeps_last_qubit_default():
prob = IQAE(
operator_in=asymmetric_two_qubit_state,
qnumber=2,
epsilon=0.005,
res_index=-1,
).run()

assert np.isclose(prob, np.sin(np.pi / 6) ** 2, atol=0.08)
109 changes: 74 additions & 35 deletions test/QAlgBase/Test_QAE_QAE.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,74 @@
# import math
#
# import pytest
# import numpy as np
# from pyqpanda_alg.QAE import QAE
# from pyqpanda3.core import QCircuit, RY, X, H
#
#
# def create_cir_basic(qlist):
# """基础测试量子线路"""
# cir = QCircuit()
# cir << RY(qlist[0], np.pi / 3) << X(qlist[1]).control(qlist[0])
# return cir
#
#
# class Test_QAE_QAE:
#
# def test_qae_basic_functionality(self):
# W = QAE(
# operator_in=create_cir_basic,
# qnumber=2,
# epsilon=0.01,
# res_index=[0, 1],
# target_state='11'
# ).run()
#
# assert W is not None, "振幅估计结果不应为None"
# assert isinstance(W, (float, np.floating)), f"振幅应为数值类型,实际为{type(W)}"
# assert 0.2 <= W <= 0.3, f"振幅应在[0,1]范围内,实际为{W}"
#
#
#
# if __name__ == "__main__":
# # 运行所有测试
# pytest.main([__file__, "-v", "-s"])
import numpy as np
from pyqpanda3.core import QCircuit, RY

from pyqpanda_alg.QAE import QAE


def single_qubit_state(qlist):
cir = QCircuit()
cir << RY(qlist[0], np.pi / 3)
return cir


def asymmetric_two_qubit_state(qlist):
cir = QCircuit()
cir << RY(qlist[0], np.pi / 3)
cir << RY(qlist[1], np.pi / 5)
return cir


def test_qae_single_qubit_target_states():
prob_one = QAE(
operator_in=single_qubit_state,
qnumber=1,
epsilon=0.005,
res_index=0,
target_state="1",
).run()
prob_zero = QAE(
operator_in=single_qubit_state,
qnumber=1,
epsilon=0.005,
res_index=0,
target_state="0",
).run()

assert np.isclose(prob_one, 0.25, atol=0.02)
assert np.isclose(prob_zero, 0.75, atol=0.02)


def test_qae_target_state_follows_res_index_order():
p0 = np.sin(np.pi / 6) ** 2
p1 = np.sin(np.pi / 10) ** 2
expected = {
"00": (1 - p0) * (1 - p1),
"01": (1 - p0) * p1,
"10": p0 * (1 - p1),
"11": p0 * p1,
}

for target_state, target_prob in expected.items():
prob = QAE(
operator_in=asymmetric_two_qubit_state,
qnumber=2,
epsilon=0.005,
res_index=[0, 1],
target_state=target_state,
).run()

assert np.isclose(prob, target_prob, atol=0.02)


def test_qae_non_natural_res_index_order():
p0 = np.sin(np.pi / 6) ** 2
p1 = np.sin(np.pi / 10) ** 2

prob = QAE(
operator_in=asymmetric_two_qubit_state,
qnumber=2,
epsilon=0.005,
res_index=[1, 0],
target_state="01",
).run()

assert np.isclose(prob, (1 - p1) * p0, atol=0.02)