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
13 changes: 13 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/QCmp/QCmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,12 @@ def qft_qubit_comparator(q_state_1, q_state_2, q_cmp, function='geq'):

cir = QCircuit()

# the borrow bit gives q_state_1 > q_state_2, so 'geq' and 's' need the
# subtracted value shifted by one, same as the value += 1 in qft_comparator
if function == 'geq' or function == 's':
offset = 1
else:
offset = 0

if not hasattr(q_cmp, '__len__'):
q_cmp = [q_cmp]
Expand All @@ -572,13 +578,20 @@ def qft_qubit_comparator(q_state_1, q_state_2, q_cmp, function='geq'):
for j, qj in enumerate(qlist):
cir << U1(qj, -factor_all * 2 ** j * wi).control(q_state_1[i])

if offset:
for j, qj in enumerate(qlist):
cir << U1(qj, -factor_all * 2 ** j * offset)

cir << QFT(qlist).dagger()

cir << QFT(q_state_2)
for i, wi in enumerate(bit_weights):
for j, qj in enumerate(qlist):
cir << U1(qj, factor_remain * 2 ** j * wi).control(q_state_1[i])

if offset:
for j, qj in enumerate(q_state_2):
cir << U1(qj, factor_remain * 2 ** j * offset)

cir << QFT(q_state_2).dagger()

Expand Down
150 changes: 120 additions & 30 deletions test/QAlgBase/Test_comparator_qft_qubit_comparator.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,120 @@
# import pytest
# from pyqpanda_alg.QCmp import qft_qubit_comparator
# from pyqpanda3.core import *
#
# class Test_comparator_qft_qubit_comparator:
#
# def setup_method(self):
# self.machine = CPUQVM()
#
# def test_qft_qubit_comparator_example_from_doc(self):
# prog = QProg()
# prog << H(0) << H(1)
# prog << X(3)
#
# cir = qft_qubit_comparator([0, 1], [2, 3], [4], function='g')
# prog << cir
#
# self.machine.run(prog, 1000)
# prob_dict_result = self.machine.result().get_prob_dict([4])
# prob_high = prob_dict_result.get('1', 0.0)
# expected_prob = 0.5
# tolerance = 0.3
#
# assert abs(prob_high - expected_prob) < tolerance, (
# f"期望概率 {expected_prob:.4f}, 实际概率 {prob_high:.4f}, 超出容忍范围"
# )
#
#
# if __name__ == "__main__":
# pytest.main([__file__, "-v", "-s"])
import pytest
from pyqpanda_alg.QCmp import qft_qubit_comparator
from pyqpanda3.core import *


PREDICATES = {
'g': lambda a, b: a > b,
'geq': lambda a, b: a >= b,
's': lambda a, b: a < b,
'seq': lambda a, b: a <= b,
}


class Test_comparator_qft_qubit_comparator:

def setup_method(self):
self.machine = CPUQVM()

def _prob_high(self, prog, q_cmp):
self.machine.run(prog, 1000)
return self.machine.result().get_prob_dict([q_cmp]).get('1', 0.0)

def _basis_prob(self, n, a, b, function):
# q_state_1 = 0..n-1, q_state_2 = n..2n-1, q_cmp = 2n, lowest index is LSB
q_state_1 = list(range(n))
q_state_2 = list(range(n, 2 * n))
q_cmp = 2 * n

prog = QProg()
for j in range(n):
if (a >> j) & 1:
prog << X(q_state_1[j])
if (b >> j) & 1:
prog << X(q_state_2[j])
prog << qft_qubit_comparator(q_state_1, q_state_2, [q_cmp], function=function)
return self._prob_high(prog, q_cmp)

def test_qft_qubit_comparator_example_from_doc(self):
prog = QProg()
prog << H(0) << H(1)
prog << X(3)

cir = qft_qubit_comparator([0, 1], [2, 3], [4], function='g')
prog << cir

prob_high = self._prob_high(prog, 4)
# uniform state over 0..3 compared with 2, only 3 is greater
assert abs(prob_high - 0.25) < 1e-6, (
f"expected 0.2500, got {prob_high:.4f}"
)

@pytest.mark.parametrize("function, expected", [
('g', 0.25),
('geq', 0.50),
('s', 0.50),
('seq', 0.75),
])
def test_superposition_all_functions(self, function, expected):
prog = QProg()
prog << H(0) << H(1)
prog << X(3)

prog << qft_qubit_comparator([0, 1], [2, 3], [4], function=function)

prob_high = self._prob_high(prog, 4)
assert abs(prob_high - expected) < 1e-6, (
f"function={function}: expected {expected:.4f}, got {prob_high:.4f}"
)

@pytest.mark.parametrize("function", ['g', 'geq', 's', 'seq'])
def test_equality_boundary(self, function):
# a == b separates g from geq and s from seq
expected = 1.0 if PREDICATES[function](2, 2) else 0.0
prob_high = self._basis_prob(2, 2, 2, function)
assert abs(prob_high - expected) < 1e-6, (
f"function={function}, a=b=2: expected {expected:.4f}, got {prob_high:.4f}"
)

@pytest.mark.parametrize("function", ['g', 'geq', 's', 'seq'])
def test_all_basis_pairs_two_qubits(self, function):
for a in range(4):
for b in range(4):
expected = 1.0 if PREDICATES[function](a, b) else 0.0
prob_high = self._basis_prob(2, a, b, function)
assert abs(prob_high - expected) < 1e-6, (
f"function={function}, a={a}, b={b}: "
f"expected {expected:.4f}, got {prob_high:.4f}"
)

@pytest.mark.parametrize("function", ['g', 'geq', 's', 'seq'])
def test_all_basis_pairs_three_qubits(self, function):
for a in range(8):
for b in range(8):
expected = 1.0 if PREDICATES[function](a, b) else 0.0
prob_high = self._basis_prob(3, a, b, function)
assert abs(prob_high - expected) < 1e-6, (
f"function={function}, a={a}, b={b}: "
f"expected {expected:.4f}, got {prob_high:.4f}"
)

def test_state_registers_restored(self):
prog = QProg()
prog << H(0) << H(1) << H(2) << X(3)
prog << qft_qubit_comparator([0, 1], [2, 3], [4], function='geq')

self.machine.run(prog, 1000)
prob_dict = self.machine.result().get_prob_dict([0, 1, 2, 3])
for state, prob in prob_dict.items():
expected = 0.125 if state[0] == '1' else 0.0
assert abs(prob - expected) < 1e-6, (
f"state {state}: expected {expected:.4f}, got {prob:.4f}"
)

def test_unknown_function_raises(self):
with pytest.raises(NameError):
qft_qubit_comparator([0, 1], [2, 3], [4], function='eq')


if __name__ == "__main__":
pytest.main([__file__, "-v", "-s"])