Skip to content

Commit dff6adc

Browse files
peter-janderksPeter-JanTakishima
authored
Mathgates (#270)
* added QuantumAdd __init__ * added test for superposition * quantum addition decomposition added * quantum addition decomposition added * quantum adder working * wrote test for quantum adder * fixed decomposition rule for quantumaddition * added subtract quantum * added comparator * added conditional add * fixed conditional add * added quantum division * fixed division * added comments * additional comments * fixed multiplication algorithm * added hash function testing * pep8 * added complexity information * adding test * add comments in python example code * Update shor.py * Update shor.py * Update _factoring_test.py * Update _constantmath.py * Update _constantmath.py * Update _constantmath.py * Update _constantmath_test.py * Update _constantmath_test.py * Update _constantmath_test.py * Update _constantmath_test.py * Update _constantmath_test.py * Update _quantummath.py * fixed quantum division mathfunction * add test for math functions in _gates.py * file _gates_mathtest.py complete * added tests * control add quantum * quantum_division same as QuantumDivision * added inverse quantum gate * added get_inverse() to subtract quantum * fixed error in inversequantum division * added inverse multiplication * added gate test * Cleanup some tests * Some more rewriting - Renamed all new gate classes to XXXQuantumGate - Create gate instances corresponding to each XXXQuantumGate class - Fixed addition function name in _replace_subtractquantum - Fixed missing get_inverse() method in MultiplyQuantumGate - Updated documentation - Expanded test cases to test both emulation and decomposition of XXXQuantum gates * Fix failing tests for addition and division emulation * Some more cleanup + update year in license headers * Some more cleanup * Remove unneeded function * Some more code cleanup * Revert change by commit a3f572b - Revert changes made to AddQuantum.get_math_function and _InverseAddQuantum.get_math_function * Minor adjustments to math gate tests * Fix pytest.ini * Adding missing __str__ methods Co-authored-by: Peter-Jan <peter-jan.derks@student.auc.nl> Co-authored-by: Damien Nguyen <ngn.damien@gmail.com>
1 parent 44342ad commit dff6adc

File tree

10 files changed

+1751
-68
lines changed

10 files changed

+1751
-68
lines changed

projectq/libs/math/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from ._default_rules import all_defined_decomposition_rules
1615
from ._gates import (AddConstant,
1716
SubConstant,
1817
AddConstantModN,
1918
SubConstantModN,
20-
MultiplyByConstantModN)
19+
MultiplyByConstantModN,
20+
AddQuantum,
21+
SubtractQuantum,
22+
ComparatorQuantum,
23+
DivideQuantum,
24+
MultiplyQuantum)
25+
26+
from ._default_rules import all_defined_decomposition_rules

projectq/libs/math/_constantmath.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2017 ProjectQ-Framework (www.projectq.ch)
1+
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -15,11 +15,11 @@
1515
import math
1616
try:
1717
from math import gcd
18-
except ImportError:
18+
except ImportError: # pragma: no cover
1919
from fractions import gcd
2020

21-
from projectq.ops import R, X, Swap, Measure, CNOT, QFT
22-
from projectq.meta import Control, Compute, Uncompute, CustomUncompute, Dagger
21+
from projectq.ops import R, X, Swap, CNOT, QFT
22+
from projectq.meta import Control, Compute, Uncompute, CustomUncompute
2323
from ._gates import AddConstant, SubConstant, AddConstantModN, SubConstantModN
2424

2525

@@ -51,7 +51,7 @@ def add_constant_modN(eng, c, N, quint):
5151
using Draper addition and the construction from
5252
https://arxiv.org/abs/quant-ph/0205095.
5353
"""
54-
assert(c < N and c >= 0)
54+
assert (c < N and c >= 0)
5555

5656
AddConstant(c) | quint
5757

@@ -84,8 +84,8 @@ def mul_by_constant_modN(eng, c, N, quint_in):
8484
(only works if a and N are relative primes, otherwise the modular inverse
8585
does not exist).
8686
"""
87-
assert(c < N and c >= 0)
88-
assert(gcd(c, N) == 1)
87+
assert (c < N and c >= 0)
88+
assert (gcd(c, N) == 1)
8989

9090
n = len(quint_in)
9191
quint_out = eng.allocate_qureg(n + 1)
Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2017 ProjectQ-Framework (www.projectq.ch)
1+
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -11,23 +11,20 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
1514
"""Tests for projectq.libs.math_constantmath.py."""
1615

1716
import pytest
1817

1918
from projectq import MainEngine
20-
from projectq.cengines import (InstructionFilter,
21-
AutoReplacer,
19+
from projectq.cengines import (InstructionFilter, AutoReplacer,
2220
DecompositionRuleSet)
2321
from projectq.backends import Simulator
2422
from projectq.ops import (All, BasicMathGate, ClassicalInstructionGate,
2523
Measure, X)
2624

2725
import projectq.libs.math
2826
from projectq.setups.decompositions import qft2crandhadamard, swap2cnot
29-
from projectq.libs.math import (AddConstant,
30-
AddConstantModN,
27+
from projectq.libs.math import (AddConstant, AddConstantModN,
3128
MultiplyByConstantModN)
3229

3330

@@ -44,72 +41,70 @@ def no_math_emulation(eng, cmd):
4441
return True
4542
try:
4643
return len(cmd.gate.matrix) == 2
47-
except:
44+
except AttributeError:
4845
return False
4946

5047

48+
@pytest.fixture
49+
def eng():
50+
return MainEngine(backend=Simulator(),
51+
engine_list=[
52+
AutoReplacer(rule_set),
53+
InstructionFilter(no_math_emulation)
54+
])
55+
56+
5157
rule_set = DecompositionRuleSet(
5258
modules=[projectq.libs.math, qft2crandhadamard, swap2cnot])
5359

5460

55-
def test_adder():
56-
sim = Simulator()
57-
eng = MainEngine(sim, [AutoReplacer(rule_set),
58-
InstructionFilter(no_math_emulation)])
61+
def test_adder(eng):
5962
qureg = eng.allocate_qureg(4)
6063
init(eng, qureg, 4)
6164

6265
AddConstant(3) | qureg
6366

64-
assert 1. == pytest.approx(abs(sim.cheat()[1][7]))
67+
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][7]))
6568

6669
init(eng, qureg, 7) # reset
6770
init(eng, qureg, 2)
6871

6972
# check for overflow -> should be 15+2 = 1 (mod 16)
7073
AddConstant(15) | qureg
71-
assert 1. == pytest.approx(abs(sim.cheat()[1][1]))
74+
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][1]))
7275

7376
All(Measure) | qureg
7477

7578

76-
def test_modadder():
77-
sim = Simulator()
78-
eng = MainEngine(sim, [AutoReplacer(rule_set),
79-
InstructionFilter(no_math_emulation)])
80-
79+
def test_modadder(eng):
8180
qureg = eng.allocate_qureg(4)
8281
init(eng, qureg, 4)
8382

8483
AddConstantModN(3, 6) | qureg
8584

86-
assert 1. == pytest.approx(abs(sim.cheat()[1][1]))
85+
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][1]))
8786

8887
init(eng, qureg, 1) # reset
8988
init(eng, qureg, 7)
9089

9190
AddConstantModN(10, 13) | qureg
92-
assert 1. == pytest.approx(abs(sim.cheat()[1][4]))
91+
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][4]))
9392

9493
All(Measure) | qureg
9594

9695

97-
def test_modmultiplier():
98-
sim = Simulator()
99-
eng = MainEngine(sim, [AutoReplacer(rule_set),
100-
InstructionFilter(no_math_emulation)])
101-
96+
def test_modmultiplier(eng):
10297
qureg = eng.allocate_qureg(4)
10398
init(eng, qureg, 4)
10499

105100
MultiplyByConstantModN(3, 7) | qureg
106101

107-
assert 1. == pytest.approx(abs(sim.cheat()[1][5]))
102+
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][5]))
108103

109104
init(eng, qureg, 5) # reset
110105
init(eng, qureg, 7)
111106

112107
MultiplyByConstantModN(4, 13) | qureg
113-
assert 1. == pytest.approx(abs(sim.cheat()[1][2]))
108+
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][2]))
114109

115110
All(Measure) | qureg

projectq/libs/math/_default_rules.py

Lines changed: 120 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2017 ProjectQ-Framework (www.projectq.ch)
1+
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -11,23 +11,32 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
1514
"""
1615
Registers a few default replacement rules for Shor's algorithm to work
1716
(see Examples).
1817
"""
1918

20-
from projectq.meta import Control, Dagger
19+
from projectq.meta import Control
2120
from projectq.cengines import DecompositionRule
2221

23-
from ._gates import (AddConstant,
24-
SubConstant,
25-
AddConstantModN,
26-
SubConstantModN,
27-
MultiplyByConstantModN)
28-
from ._constantmath import (add_constant,
29-
add_constant_modN,
30-
mul_by_constant_modN)
22+
from ._gates import (AddConstant, AddConstantModN, MultiplyByConstantModN,
23+
AddQuantum, SubtractQuantum, ComparatorQuantum,
24+
DivideQuantum, MultiplyQuantum)
25+
26+
from ._gates import (_InverseAddQuantumGate, _InverseDivideQuantumGate,
27+
_InverseMultiplyQuantumGate)
28+
29+
from ._constantmath import (
30+
add_constant,
31+
add_constant_modN,
32+
mul_by_constant_modN,
33+
)
34+
35+
from ._quantummath import (
36+
add_quantum, subtract_quantum, inverse_add_quantum_carry, comparator,
37+
quantum_conditional_add, quantum_division, inverse_quantum_division,
38+
quantum_conditional_add_carry, quantum_multiplication,
39+
inverse_quantum_multiplication)
3140

3241

3342
def _replace_addconstant(cmd):
@@ -58,8 +67,108 @@ def _replace_multiplybyconstantmodN(cmd):
5867
with Control(eng, cmd.control_qubits):
5968
mul_by_constant_modN(eng, c, N, quint)
6069

70+
71+
def _replace_addquantum(cmd):
72+
eng = cmd.engine
73+
if cmd.control_qubits == []:
74+
quint_a = cmd.qubits[0]
75+
quint_b = cmd.qubits[1]
76+
if len(cmd.qubits) == 3:
77+
c = cmd.qubits[2]
78+
add_quantum(eng, quint_a, quint_b, c)
79+
else:
80+
add_quantum(eng, quint_a, quint_b)
81+
else:
82+
quint_a = cmd.qubits[0]
83+
quint_b = cmd.qubits[1]
84+
if len(cmd.qubits) == 3:
85+
c = cmd.qubits[2]
86+
with Control(eng, cmd.control_qubits):
87+
quantum_conditional_add_carry(eng, quint_a, quint_b,
88+
cmd.control_qubits, c)
89+
else:
90+
with Control(eng, cmd.control_qubits):
91+
quantum_conditional_add(eng, quint_a, quint_b,
92+
cmd.control_qubits)
93+
94+
95+
def _replace_inverse_add_quantum(cmd):
96+
eng = cmd.engine
97+
quint_a = cmd.qubits[0]
98+
quint_b = cmd.qubits[1]
99+
100+
if len(cmd.qubits) == 3:
101+
quint_c = cmd.qubits[2]
102+
with Control(eng, cmd.control_qubits):
103+
inverse_add_quantum_carry(eng, quint_a, [quint_b, quint_c])
104+
else:
105+
with Control(eng, cmd.control_qubits):
106+
subtract_quantum(eng, quint_a, quint_b)
107+
108+
109+
def _replace_comparator(cmd):
110+
eng = cmd.engine
111+
quint_a = cmd.qubits[0]
112+
quint_b = cmd.qubits[1]
113+
c = cmd.qubits[2]
114+
115+
with Control(eng, cmd.control_qubits):
116+
comparator(eng, quint_a, quint_b, c)
117+
118+
119+
def _replace_quantumdivision(cmd):
120+
eng = cmd.engine
121+
quint_a = cmd.qubits[0]
122+
quint_b = cmd.qubits[1]
123+
quint_c = cmd.qubits[2]
124+
125+
with Control(eng, cmd.control_qubits):
126+
quantum_division(eng, quint_a, quint_b, quint_c)
127+
128+
129+
def _replace_inversequantumdivision(cmd):
130+
eng = cmd.engine
131+
quint_a = cmd.qubits[0]
132+
quint_b = cmd.qubits[1]
133+
quint_c = cmd.qubits[2]
134+
135+
with Control(eng, cmd.control_qubits):
136+
inverse_quantum_division(eng, quint_a, quint_b, quint_c)
137+
138+
139+
def _replace_quantummultiplication(cmd):
140+
eng = cmd.engine
141+
quint_a = cmd.qubits[0]
142+
quint_b = cmd.qubits[1]
143+
quint_c = cmd.qubits[2]
144+
145+
with Control(eng, cmd.control_qubits):
146+
quantum_multiplication(eng, quint_a, quint_b, quint_c)
147+
148+
149+
def _replace_inversequantummultiplication(cmd):
150+
eng = cmd.engine
151+
quint_a = cmd.qubits[0]
152+
quint_b = cmd.qubits[1]
153+
quint_c = cmd.qubits[2]
154+
155+
with Control(eng, cmd.control_qubits):
156+
inverse_quantum_multiplication(eng, quint_a, quint_b, quint_c)
157+
158+
61159
all_defined_decomposition_rules = [
62160
DecompositionRule(AddConstant, _replace_addconstant),
63161
DecompositionRule(AddConstantModN, _replace_addconstmodN),
64162
DecompositionRule(MultiplyByConstantModN, _replace_multiplybyconstantmodN),
163+
DecompositionRule(AddQuantum.__class__, _replace_addquantum),
164+
DecompositionRule(_InverseAddQuantumGate, _replace_inverse_add_quantum),
165+
DecompositionRule(SubtractQuantum.__class__, _replace_inverse_add_quantum),
166+
DecompositionRule(ComparatorQuantum.__class__, _replace_comparator),
167+
DecompositionRule(DivideQuantum.__class__, _replace_quantumdivision),
168+
DecompositionRule(_InverseDivideQuantumGate,
169+
_replace_inversequantumdivision),
170+
DecompositionRule(MultiplyQuantum.__class__,
171+
_replace_quantummultiplication),
172+
DecompositionRule(_InverseMultiplyQuantumGate,
173+
_replace_inversequantummultiplication),
65174
]

0 commit comments

Comments
 (0)