Skip to content

Commit

Permalink
Mathgates (#270)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people committed Feb 17, 2021
1 parent 44342ad commit dff6adc
Show file tree
Hide file tree
Showing 10 changed files with 1,751 additions and 68 deletions.
10 changes: 8 additions & 2 deletions projectq/libs/math/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from ._default_rules import all_defined_decomposition_rules
from ._gates import (AddConstant,
SubConstant,
AddConstantModN,
SubConstantModN,
MultiplyByConstantModN)
MultiplyByConstantModN,
AddQuantum,
SubtractQuantum,
ComparatorQuantum,
DivideQuantum,
MultiplyQuantum)

from ._default_rules import all_defined_decomposition_rules
14 changes: 7 additions & 7 deletions projectq/libs/math/_constantmath.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017 ProjectQ-Framework (www.projectq.ch)
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -15,11 +15,11 @@
import math
try:
from math import gcd
except ImportError:
except ImportError: # pragma: no cover
from fractions import gcd

from projectq.ops import R, X, Swap, Measure, CNOT, QFT
from projectq.meta import Control, Compute, Uncompute, CustomUncompute, Dagger
from projectq.ops import R, X, Swap, CNOT, QFT
from projectq.meta import Control, Compute, Uncompute, CustomUncompute
from ._gates import AddConstant, SubConstant, AddConstantModN, SubConstantModN


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

AddConstant(c) | quint

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

n = len(quint_in)
quint_out = eng.allocate_qureg(n + 1)
Expand Down
49 changes: 22 additions & 27 deletions projectq/libs/math/_constantmath_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017 ProjectQ-Framework (www.projectq.ch)
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -11,23 +11,20 @@
# 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.

"""Tests for projectq.libs.math_constantmath.py."""

import pytest

from projectq import MainEngine
from projectq.cengines import (InstructionFilter,
AutoReplacer,
from projectq.cengines import (InstructionFilter, AutoReplacer,
DecompositionRuleSet)
from projectq.backends import Simulator
from projectq.ops import (All, BasicMathGate, ClassicalInstructionGate,
Measure, X)

import projectq.libs.math
from projectq.setups.decompositions import qft2crandhadamard, swap2cnot
from projectq.libs.math import (AddConstant,
AddConstantModN,
from projectq.libs.math import (AddConstant, AddConstantModN,
MultiplyByConstantModN)


Expand All @@ -44,72 +41,70 @@ def no_math_emulation(eng, cmd):
return True
try:
return len(cmd.gate.matrix) == 2
except:
except AttributeError:
return False


@pytest.fixture
def eng():
return MainEngine(backend=Simulator(),
engine_list=[
AutoReplacer(rule_set),
InstructionFilter(no_math_emulation)
])


rule_set = DecompositionRuleSet(
modules=[projectq.libs.math, qft2crandhadamard, swap2cnot])


def test_adder():
sim = Simulator()
eng = MainEngine(sim, [AutoReplacer(rule_set),
InstructionFilter(no_math_emulation)])
def test_adder(eng):
qureg = eng.allocate_qureg(4)
init(eng, qureg, 4)

AddConstant(3) | qureg

assert 1. == pytest.approx(abs(sim.cheat()[1][7]))
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][7]))

init(eng, qureg, 7) # reset
init(eng, qureg, 2)

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

All(Measure) | qureg


def test_modadder():
sim = Simulator()
eng = MainEngine(sim, [AutoReplacer(rule_set),
InstructionFilter(no_math_emulation)])

def test_modadder(eng):
qureg = eng.allocate_qureg(4)
init(eng, qureg, 4)

AddConstantModN(3, 6) | qureg

assert 1. == pytest.approx(abs(sim.cheat()[1][1]))
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][1]))

init(eng, qureg, 1) # reset
init(eng, qureg, 7)

AddConstantModN(10, 13) | qureg
assert 1. == pytest.approx(abs(sim.cheat()[1][4]))
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][4]))

All(Measure) | qureg


def test_modmultiplier():
sim = Simulator()
eng = MainEngine(sim, [AutoReplacer(rule_set),
InstructionFilter(no_math_emulation)])

def test_modmultiplier(eng):
qureg = eng.allocate_qureg(4)
init(eng, qureg, 4)

MultiplyByConstantModN(3, 7) | qureg

assert 1. == pytest.approx(abs(sim.cheat()[1][5]))
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][5]))

init(eng, qureg, 5) # reset
init(eng, qureg, 7)

MultiplyByConstantModN(4, 13) | qureg
assert 1. == pytest.approx(abs(sim.cheat()[1][2]))
assert 1. == pytest.approx(abs(eng.backend.cheat()[1][2]))

All(Measure) | qureg
131 changes: 120 additions & 11 deletions projectq/libs/math/_default_rules.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2017 ProjectQ-Framework (www.projectq.ch)
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -11,23 +11,32 @@
# 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.

"""
Registers a few default replacement rules for Shor's algorithm to work
(see Examples).
"""

from projectq.meta import Control, Dagger
from projectq.meta import Control
from projectq.cengines import DecompositionRule

from ._gates import (AddConstant,
SubConstant,
AddConstantModN,
SubConstantModN,
MultiplyByConstantModN)
from ._constantmath import (add_constant,
add_constant_modN,
mul_by_constant_modN)
from ._gates import (AddConstant, AddConstantModN, MultiplyByConstantModN,
AddQuantum, SubtractQuantum, ComparatorQuantum,
DivideQuantum, MultiplyQuantum)

from ._gates import (_InverseAddQuantumGate, _InverseDivideQuantumGate,
_InverseMultiplyQuantumGate)

from ._constantmath import (
add_constant,
add_constant_modN,
mul_by_constant_modN,
)

from ._quantummath import (
add_quantum, subtract_quantum, inverse_add_quantum_carry, comparator,
quantum_conditional_add, quantum_division, inverse_quantum_division,
quantum_conditional_add_carry, quantum_multiplication,
inverse_quantum_multiplication)


def _replace_addconstant(cmd):
Expand Down Expand Up @@ -58,8 +67,108 @@ def _replace_multiplybyconstantmodN(cmd):
with Control(eng, cmd.control_qubits):
mul_by_constant_modN(eng, c, N, quint)


def _replace_addquantum(cmd):
eng = cmd.engine
if cmd.control_qubits == []:
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
if len(cmd.qubits) == 3:
c = cmd.qubits[2]
add_quantum(eng, quint_a, quint_b, c)
else:
add_quantum(eng, quint_a, quint_b)
else:
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
if len(cmd.qubits) == 3:
c = cmd.qubits[2]
with Control(eng, cmd.control_qubits):
quantum_conditional_add_carry(eng, quint_a, quint_b,
cmd.control_qubits, c)
else:
with Control(eng, cmd.control_qubits):
quantum_conditional_add(eng, quint_a, quint_b,
cmd.control_qubits)


def _replace_inverse_add_quantum(cmd):
eng = cmd.engine
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]

if len(cmd.qubits) == 3:
quint_c = cmd.qubits[2]
with Control(eng, cmd.control_qubits):
inverse_add_quantum_carry(eng, quint_a, [quint_b, quint_c])
else:
with Control(eng, cmd.control_qubits):
subtract_quantum(eng, quint_a, quint_b)


def _replace_comparator(cmd):
eng = cmd.engine
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
c = cmd.qubits[2]

with Control(eng, cmd.control_qubits):
comparator(eng, quint_a, quint_b, c)


def _replace_quantumdivision(cmd):
eng = cmd.engine
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
quint_c = cmd.qubits[2]

with Control(eng, cmd.control_qubits):
quantum_division(eng, quint_a, quint_b, quint_c)


def _replace_inversequantumdivision(cmd):
eng = cmd.engine
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
quint_c = cmd.qubits[2]

with Control(eng, cmd.control_qubits):
inverse_quantum_division(eng, quint_a, quint_b, quint_c)


def _replace_quantummultiplication(cmd):
eng = cmd.engine
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
quint_c = cmd.qubits[2]

with Control(eng, cmd.control_qubits):
quantum_multiplication(eng, quint_a, quint_b, quint_c)


def _replace_inversequantummultiplication(cmd):
eng = cmd.engine
quint_a = cmd.qubits[0]
quint_b = cmd.qubits[1]
quint_c = cmd.qubits[2]

with Control(eng, cmd.control_qubits):
inverse_quantum_multiplication(eng, quint_a, quint_b, quint_c)


all_defined_decomposition_rules = [
DecompositionRule(AddConstant, _replace_addconstant),
DecompositionRule(AddConstantModN, _replace_addconstmodN),
DecompositionRule(MultiplyByConstantModN, _replace_multiplybyconstantmodN),
DecompositionRule(AddQuantum.__class__, _replace_addquantum),
DecompositionRule(_InverseAddQuantumGate, _replace_inverse_add_quantum),
DecompositionRule(SubtractQuantum.__class__, _replace_inverse_add_quantum),
DecompositionRule(ComparatorQuantum.__class__, _replace_comparator),
DecompositionRule(DivideQuantum.__class__, _replace_quantumdivision),
DecompositionRule(_InverseDivideQuantumGate,
_replace_inversequantumdivision),
DecompositionRule(MultiplyQuantum.__class__,
_replace_quantummultiplication),
DecompositionRule(_InverseMultiplyQuantumGate,
_replace_inversequantummultiplication),
]

0 comments on commit dff6adc

Please sign in to comment.