Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented classical adder in QFT paper #13

Merged
merged 24 commits into from
Apr 6, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
277d986
Merge branch 'master' of github.com:Qiskit/qiskit-terra into master
Cryoris Oct 22, 2020
005acab
Merge branch 'master' of github.com:Qiskit/qiskit-terra into master
Cryoris Oct 26, 2020
478bb01
empty
Cryoris Mar 9, 2021
8563889
empty
Cryoris Mar 9, 2021
9148f90
Implemented classical adder in QFT paper
ManjulaGandhi Mar 15, 2021
b160788
Implemented classical adder in QFT paper
ManjulaGandhi Mar 15, 2021
cc909f4
Merge commit 'refs/pull/13/head' of github.com:Cryoris/qiskit-terra i…
Cryoris Mar 15, 2021
c7990e6
fix classicaladd imports
Cryoris Mar 15, 2021
d44fbed
fix missing imports
Cryoris Mar 15, 2021
15d4099
Merge branch 'master' into manjulas_adder
Cryoris Mar 15, 2021
2b8d2c4
Merge pull request #1 from Cryoris/manjulas_adder
ManjulaGandhi Mar 16, 2021
a3a4680
Added the tests part for ClassicalAdd
ManjulaGandhi Mar 22, 2021
3b9d7e0
Merge branch 'master' into manjulas_adder
Cryoris Mar 23, 2021
55fdc4b
move cin to bottom
Cryoris Mar 23, 2021
841c593
Merge pull request #2 from Cryoris/manjulas_adder
ManjulaGandhi Mar 23, 2021
7c05fee
Merge branch 'adders' into adders
ManjulaGandhi Apr 2, 2021
e9820bf
Updated the documentation and test parts for ClassicalAdder
ManjulaGandhi Apr 5, 2021
39ea4bb
Updated init files
ManjulaGandhi Apr 5, 2021
6252ded
Updated the ClassicalAdder circuit with Documentation
ManjulaGandhi Apr 5, 2021
8f54d9e
Deleted adder folder from the git repository
ManjulaGandhi Apr 6, 2021
ba7af70
Deleted test_classicaladd.py
ManjulaGandhi Apr 6, 2021
57c3b6a
Deleted old classicaladder file
ManjulaGandhi Apr 6, 2021
d2a7d34
Deleted __init__.py file from repository
ManjulaGandhi Apr 6, 2021
d502184
Updated classical_adder file
ManjulaGandhi Apr 6, 2021
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
3 changes: 3 additions & 0 deletions qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
.. autosummary::
:toctree: ../stubs/

ClassicalAdder
WeightedAdder

Comparators
Expand Down Expand Up @@ -311,9 +312,11 @@
WeightedAdder,
QuadraticForm,
LinearAmplitudeFunction,
ClassicalAdder,
RippleCarryAdder,
QFTAdder
)

from .n_local import (
NLocal,
TwoLocal,
Expand Down
6 changes: 4 additions & 2 deletions qiskit/circuit/library/arithmetic/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2020.
# (C) Copyright IBM 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand All @@ -21,4 +21,6 @@
from .weighted_adder import WeightedAdder
from .quadratic_form import QuadraticForm
from .linear_amplitude_function import LinearAmplitudeFunction
from .adders import RippleCarryAdder, QFTAdder
from .adders import ClassicalAdder, RippleCarryAdder, QFTAdder


16 changes: 16 additions & 0 deletions qiskit/circuit/library/arithmetic/adder/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This code is part of Qiskit.
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
#
# (C) Copyright IBM 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""The arithmetic circuit library."""


from .classicaladd import ClassicalAdd
70 changes: 70 additions & 0 deletions qiskit/circuit/library/arithmetic/adder/classicaladd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This code is part of Qiskit.
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals

"""Module-level docstring describing what the file content is."""

from qiskit.circuit import QuantumCircuit, QuantumRegister, AncillaRegister


class ClassicalAdd(QuantumCircuit):
"""To implement Classical Addtion in QFT Adder paper.

Based on the information given in [1].

**References**

[1] Thomas G.Draper, 2000. "Addition on a Quantum Computer"
`Journal https://arxiv.org/pdf/quant-ph/0008033.pdf`_
"""

def __init__(self, num_state_qubits: int, name: str = 'ClassicalAdd') -> None:
"""
Args:
num_state_qubits: The size of the register.
name: The name of the circuit.
"""
# define the registers
qr_a = QuantumRegister(num_state_qubits, name='a')
qr_b = QuantumRegister(num_state_qubits, name='b')
qr_cin = AncillaRegister(num_state_qubits, name='cin')
qr_cout = QuantumRegister(1, name='cout')

# initialize the circuit
super().__init__(qr_a, qr_b, qr_cout, qr_cin, name=name)

qc_carry = QuantumCircuit(4, name='Carry')
qc_carry.ccx(1, 2, 3)
qc_carry.cx(1, 2)
qc_carry.ccx(0, 2, 3)
qc_instruction_carry = qc_carry.to_instruction()

qc_sum = QuantumCircuit(3, name='Sum')
qc_sum.cx(1, 2)
qc_sum.cx(0, 2)
qc_instruction_sum = qc_sum.to_instruction()

# Build a temporary subcircuit that adds a to b,
# storing the result in b

for j in range(num_state_qubits - 1):
self.append(qc_instruction_carry, [qr_cin[j], qr_a[j], qr_b[j], qr_cin[j+1]])

self.append(qc_instruction_carry, [qr_cin[num_state_qubits - 1],
qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1],
qr_cout])
self.cx(qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1])
self.append(qc_instruction_sum, [qr_cin[num_state_qubits - 1],
qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1]])

for j in reversed(range(num_state_qubits - 1)):
self.append(qc_instruction_carry, [qr_cin[j], qr_a[j], qr_b[j], qr_cin[j+1]])
self.append(qc_instruction_sum, [qr_cin[j], qr_a[j], qr_b[j]])
119 changes: 119 additions & 0 deletions qiskit/circuit/library/arithmetic/adder/classicaladder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals

"""Module-level docstring describing what the file content is."""

from qiskit.circuit import QuantumCircuit, QuantumRegister, AncillaRegister


class ClassicalAdder(QuantumCircuit):
r"""A ClassicalAdd Circuit to perform in-place addition on two qubit registers.
Circuit to compute the sum of two qubit registers using the Classical Addition Part from [1].

Given two equally sized input registers that store quantum states
:math:`|a\rangle` and :math:`|b\rangle`, performs addition of numbers that
can be represented by the states, storing the resulting state in-place in the second register:
.. math::
|a\rangle |b\rangle \mapsto |a\rangle |a+b\rangle
Here :math:`|a\rangle` (and correspondingly :math:`|b\rangle`) stands for the direct product
:math:`|a_n\rangle \otimes |a_{n-1}\rangle \ldots |a_{1}\rangle \otimes |a_{0}\rangle`
which denotes a quantum register prepared with the value :math:`a = 2^{0}a_{0} + 2^{1}a_{1} +
\ldots 2^{n}a_{n}` [2].
As an example, a classical add circuit that performs addition on two 3-qubit sized
registers is as follows:
.. parsed-literal::
┌────────┐ ┌────────┐┌──────┐
input_a_0: ┤1 ├───────────────────────────────────────────────────┤1 ├┤1 ├
│ │┌────────┐ ┌────────┐┌──────┐│ ││ │
input_a_1: ┤ ├┤1 ├───────────────────────┤1 ├┤1 ├┤ ├┤ ├
│ ││ │┌────────┐ ┌──────┐│ ││ ││ ││ │
input_a_2: ┤ ├┤ ├┤1 ├──■──┤1 ├┤ ├┤ ├┤ ├┤ ├
│ ││ ││ │ │ │ ││ ││ ││ ││ │
input_b_0: ┤2 ├┤ ├┤ ├──┼──┤ ├┤ ├┤ ├┤2 ├┤2 ├
│ ││ ││ │ │ │ ││ ││ ││ ││ Sum │
input_b_1: ┤ Carry ├┤2 ├┤ ├──┼──┤ ├┤2 ├┤2 ├┤ Carry ├┤ ├
│ ││ ││ │┌─┴─┐│ ││ ││ Sum ││ ││ │
input_b_2: ┤ ├┤ Carry ├┤2 ├┤ X ├┤2 ├┤ Carry ├┤ ├┤ ├┤ ├
│ ││ ││ Carry │└───┘│ Sum ││ ││ ││ ││ │
cout_0: ┤ ├┤ ├┤3 ├─────┤ ├┤ ├┤ ├┤ ├┤ ├
│ ││ ││ │ │ ││ ││ ││ ││ │
cin_0: ┤0 ├┤ ├┤ ├─────┤ ├┤ ├┤ ├┤0 ├┤0 ├
│ ││ ││ │ │ ││ ││ ││ │└──────┘
cin_1: ┤3 ├┤0 ├┤ ├─────┤ ├┤0 ├┤0 ├┤3 ├────────
└────────┘│ ││ │ │ ││ │└──────┘└────────┘
cin_2: ──────────┤3 ├┤0 ├─────┤0 ├┤3 ├──────────────────────────
└────────┘└────────┘ └──────┘└────────┘


Here *Carry* and *Sum* gates correspond to the gates introduced in [1]. Note that
in this implementation the input register qubits are ordered as all qubits from
the first input register, followed by all qubits from the second input register.
This is different ordering as compared to Figure 2 in [1], which leads to a different
drawing of the circuit.
**References**

[1] Thomas G.Draper, 2000. "Addition on a Quantum Computer"
`Journal https://arxiv.org/pdf/quant-ph/0008033.pdf`_
"""

def __init__(self,
num_state_qubits: int,
name: str = 'ClassicalAdder'
) -> None:
"""
Args:
num_state_qubits: The size of the register.
name: The name of the circuit.
Raises:
ValueError: If ``num_state_qubits`` is lower than 1.
"""
if num_state_qubits < 1:
raise ValueError('The number of qubits must be at least 1.')
# define the registers
qr_a = QuantumRegister(num_state_qubits, name='input_a')
qr_b = QuantumRegister(num_state_qubits, name='input_b')
qr_cin = AncillaRegister(num_state_qubits, name='cin')
qr_cout = QuantumRegister(1, name='cout')

# initialize the circuit
super().__init__(qr_a, qr_b, qr_cout, qr_cin, name=name)

#corresponds to Carry gate in [1]
qc_carry = QuantumCircuit(4, name='Carry')
qc_carry.ccx(1, 2, 3)
qc_carry.cx(1, 2)
qc_carry.ccx(0, 2, 3)
qc_instruction_carry = qc_carry.to_instruction()

#corresponds to Sum gate in [1]
qc_sum = QuantumCircuit(3, name='Sum')
qc_sum.cx(1, 2)
qc_sum.cx(0, 2)
qc_instruction_sum = qc_sum.to_instruction()

# Build a temporary subcircuit that adds a to b,
# storing the result in b

for j in range(num_state_qubits - 1):
self.append(qc_instruction_carry, [qr_cin[j], qr_a[j], qr_b[j], qr_cin[j+1]])

self.append(qc_instruction_carry, [qr_cin[num_state_qubits - 1],
qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1],
qr_cout])
self.cx(qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1])
self.append(qc_instruction_sum, [qr_cin[num_state_qubits - 1],
qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1]])

for j in reversed(range(num_state_qubits - 1)):
self.append(qc_instruction_carry, [qr_cin[j], qr_a[j], qr_b[j], qr_cin[j+1]])
self.append(qc_instruction_sum, [qr_cin[j], qr_a[j], qr_b[j]])

1 change: 1 addition & 0 deletions qiskit/circuit/library/arithmetic/adders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@

from .ripple_carry_adder import RippleCarryAdder
from .qft_adder import QFTAdder
from .classicaladder import ClassicalAdder
119 changes: 119 additions & 0 deletions qiskit/circuit/library/arithmetic/adders/classicaladder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals

"""Module-level docstring describing what the file content is."""
Cryoris marked this conversation as resolved.
Show resolved Hide resolved

from qiskit.circuit import QuantumCircuit, QuantumRegister, AncillaRegister


class ClassicalAdder(QuantumCircuit):
r"""A ClassicalAdd Circuit to perform in-place addition on two qubit registers.
Circuit to compute the sum of two qubit registers using the Classical Addition Part from [1].

Given two equally sized input registers that store quantum states
:math:`|a\rangle` and :math:`|b\rangle`, performs addition of numbers that
can be represented by the states, storing the resulting state in-place in the second register:
.. math::
|a\rangle |b\rangle \mapsto |a\rangle |a+b\rangle
Here :math:`|a\rangle` (and correspondingly :math:`|b\rangle`) stands for the direct product
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
:math:`|a_n\rangle \otimes |a_{n-1}\rangle \ldots |a_{1}\rangle \otimes |a_{0}\rangle`
which denotes a quantum register prepared with the value :math:`a = 2^{0}a_{0} + 2^{1}a_{1} +
\ldots 2^{n}a_{n}` [2].
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
As an example, a classical add circuit that performs addition on two 3-qubit sized
registers is as follows:
.. parsed-literal::
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
┌────────┐ ┌────────┐┌──────┐
input_a_0: ┤1 ├───────────────────────────────────────────────────┤1 ├┤1 ├
│ │┌────────┐ ┌────────┐┌──────┐│ ││ │
input_a_1: ┤ ├┤1 ├───────────────────────┤1 ├┤1 ├┤ ├┤ ├
│ ││ │┌────────┐ ┌──────┐│ ││ ││ ││ │
input_a_2: ┤ ├┤ ├┤1 ├──■──┤1 ├┤ ├┤ ├┤ ├┤ ├
│ ││ ││ │ │ │ ││ ││ ││ ││ │
input_b_0: ┤2 ├┤ ├┤ ├──┼──┤ ├┤ ├┤ ├┤2 ├┤2 ├
│ ││ ││ │ │ │ ││ ││ ││ ││ Sum │
input_b_1: ┤ Carry ├┤2 ├┤ ├──┼──┤ ├┤2 ├┤2 ├┤ Carry ├┤ ├
│ ││ ││ │┌─┴─┐│ ││ ││ Sum ││ ││ │
input_b_2: ┤ ├┤ Carry ├┤2 ├┤ X ├┤2 ├┤ Carry ├┤ ├┤ ├┤ ├
│ ││ ││ Carry │└───┘│ Sum ││ ││ ││ ││ │
cout_0: ┤ ├┤ ├┤3 ├─────┤ ├┤ ├┤ ├┤ ├┤ ├
│ ││ ││ │ │ ││ ││ ││ ││ │
cin_0: ┤0 ├┤ ├┤ ├─────┤ ├┤ ├┤ ├┤0 ├┤0 ├
│ ││ ││ │ │ ││ ││ ││ │└──────┘
cin_1: ┤3 ├┤0 ├┤ ├─────┤ ├┤0 ├┤0 ├┤3 ├────────
└────────┘│ ││ │ │ ││ │└──────┘└────────┘
cin_2: ──────────┤3 ├┤0 ├─────┤0 ├┤3 ├──────────────────────────
└────────┘└────────┘ └──────┘└────────┘
Cryoris marked this conversation as resolved.
Show resolved Hide resolved


Here *Carry* and *Sum* gates correspond to the gates introduced in [1]. Note that
in this implementation the input register qubits are ordered as all qubits from
the first input register, followed by all qubits from the second input register.
This is different ordering as compared to Figure 2 in [1], which leads to a different
drawing of the circuit.
**References**
Cryoris marked this conversation as resolved.
Show resolved Hide resolved

[1] Thomas G.Draper, 2000. "Addition on a Quantum Computer"
`Journal https://arxiv.org/pdf/quant-ph/0008033.pdf`_
"""

def __init__(self,
num_state_qubits: int,
name: str = 'ClassicalAdder'
) -> None:
"""
Args:
num_state_qubits: The size of the register.
name: The name of the circuit.
Raises:
ValueError: If ``num_state_qubits`` is lower than 1.
"""
if num_state_qubits < 1:
raise ValueError('The number of qubits must be at least 1.')
# define the registers
qr_a = QuantumRegister(num_state_qubits, name='input_a')
qr_b = QuantumRegister(num_state_qubits, name='input_b')
qr_cin = AncillaRegister(num_state_qubits, name='cin')
qr_cout = QuantumRegister(1, name='cout')

# initialize the circuit
super().__init__(qr_a, qr_b, qr_cout, qr_cin, name=name)

#corresponds to Carry gate in [1]
qc_carry = QuantumCircuit(4, name='Carry')
qc_carry.ccx(1, 2, 3)
qc_carry.cx(1, 2)
qc_carry.ccx(0, 2, 3)
qc_instruction_carry = qc_carry.to_instruction()

#corresponds to Sum gate in [1]
qc_sum = QuantumCircuit(3, name='Sum')
qc_sum.cx(1, 2)
qc_sum.cx(0, 2)
qc_instruction_sum = qc_sum.to_instruction()

# Build a temporary subcircuit that adds a to b,
# storing the result in b

for j in range(num_state_qubits - 1):
self.append(qc_instruction_carry, [qr_cin[j], qr_a[j], qr_b[j], qr_cin[j+1]])

self.append(qc_instruction_carry, [qr_cin[num_state_qubits - 1],
qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1],
qr_cout])
self.cx(qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1])
self.append(qc_instruction_sum, [qr_cin[num_state_qubits - 1],
qr_a[num_state_qubits - 1], qr_b[num_state_qubits - 1]])

for j in reversed(range(num_state_qubits - 1)):
self.append(qc_instruction_carry, [qr_cin[j], qr_a[j], qr_b[j], qr_cin[j+1]])
self.append(qc_instruction_sum, [qr_cin[j], qr_a[j], qr_b[j]])

Loading