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

[WIP] Arithmetic circuit library subtractors #6490

Closed
wants to merge 4 commits into from
Closed
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
11 changes: 11 additions & 0 deletions qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@
VBERippleCarryAdder
WeightedAdder

Subtractors
+++++++++++

.. autosummary::
:toctree: ../stubs/

Subtractor

Comparators
+++++++++++

Expand Down Expand Up @@ -188,6 +196,7 @@
QuantumVolume
PhaseEstimation
GroverOperator
TwosComplement
PhaseOracle
EvolvedOperatorAnsatz

Expand Down Expand Up @@ -362,6 +371,8 @@
CDKMRippleCarryAdder,
DraperQFTAdder,
PiecewiseChebyshev,
TwosComplement,
Subtractor,
)

from .n_local import (
Expand Down
1 change: 1 addition & 0 deletions qiskit/circuit/library/arithmetic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
from .linear_amplitude_function import LinearAmplitudeFunction
from .adders import VBERippleCarryAdder, CDKMRippleCarryAdder, DraperQFTAdder
from .piecewise_chebyshev import PiecewiseChebyshev
from .subtractors import TwosComplement, Subtractor
16 changes: 16 additions & 0 deletions qiskit/circuit/library/arithmetic/subtractors/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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.

"""The Subtractor circuit library."""

from .twos_complement import TwosComplement
from .twos_complement_subtractor import Subtractor
122 changes: 122 additions & 0 deletions qiskit/circuit/library/arithmetic/subtractors/twos_complement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 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

"""Compute Two's Complement of a given qubit."""
from typing import Optional
from qiskit.circuit import QuantumCircuit, QuantumRegister, AncillaRegister
#from qiskit.circuit.library.arithmetic import DraperQFTAdder


class TwosComplement(QuantumCircuit):
r"""A circuit that obtains Two's Complement on one qubit register.
Circuit to compute the two's complement of one qubit register Part from [1].

As an example, a Two's Complement circuit that performs two's complement on a 3-qubit sized
register is as follows:
.. parsed-literal::


░ ░ ┌───┐┌─────────────────┐
input_b_0: ─░───────░─┤ X ├┤3 ├─────
░ ░ ├───┤│ │
input_b_1: ─░───────░─┤ X ├┤4 ├─────
░ ░ ├───┤│ │
input_b_2: ─░───────░─┤ X ├┤5 ├─────
░ ░ └───┘│ │
carry_0: ─░───────░──────┤6 DraperQFTAdder ├─────
░ ┌───┐ ░ │ │┌───┐
help_0: ─░─┤ X ├─░──────┤0 ├┤ X ├
░ └───┘ ░ │ │└───┘
help_1: ─░───────░──────┤1 ├─────
░ ░ │ │
help_2: ─░───────░──────┤2 ├─────
░ ░ └─────────────────┘


**Reference**
[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, adder=None, name: str = "TwosComplement") -> None:
def __init__(
self,
num_state_qubits: int,
adder: Optional[QuantumCircuit]=None,
name: str = "TwosComplement"
) -> None:
"""
Args:
num_state_qubits: The size of the register.
adder: The adder used to add 1 to the input state. This must be a modular adder.
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.")

if adder is None:
#adder = DraperQFTAdder(num_state_qubits, modular=False)
from qiskit.circuit.library import DraperQFTAdder

adder = DraperQFTAdder(num_state_qubits, kind="half")
else:
_check_adder_is_compatible(num_state_qubits, adder)
# get the number of qubits needed
#num_qubits = adder.num_qubits
num_helper_qubits = adder.num_ancillas

# define the registers
b_qr = QuantumRegister(num_state_qubits, name="input_b")
carry_qr = QuantumRegister(1, name="carry")
#one_qr = AncillaRegister(num_state_qubits, name="cin")
one_qr = AncillaRegister(num_state_qubits, name="help")
if num_helper_qubits != 0:
qr_h = AncillaRegister(num_helper_qubits)
else:
qr_h = []

# initialize the circuit
if num_helper_qubits != 0:
super().__init__(b_qr, carry_qr, one_qr, qr_h, name=name)
else:
super().__init__(b_qr, carry_qr, one_qr, name=name)
# if num_carry_qubits > 0:
# qr_c = QuantumRegister(num_carry_qubits)
# self.add_register(qr_c)
# adder helper qubits if required
# if num_helper_qubits > 0:
# qr_h = AncillaRegister(num_helper_qubits) # helper/ancilla qubits
# self.add_register(qr_h)

# Build a temporary subcircuit that obtains two's complement of b,

# flippling circuit and adding 1
self.barrier()
self.x(one_qr[0])
self.barrier()
for j in range(num_state_qubits):
self.x(b_qr[j])
#self.append(adder, one_qr[:] + b_qr[:] + carry_qr[:])
self.append(adder, one_qr[:] + b_qr[:] + carry_qr[:]+qr_h[:])
self.x(one_qr[0])


def _check_adder_is_compatible(num_state_qubits, adder):
target_num_state_qubits = 2 * num_state_qubits + 1 # inplace half adder
actual_num_state_qubits = adder.num_qubits - adder.num_ancillas
if target_num_state_qubits != actual_num_state_qubits:
raise ValueError("The number of state qubits (= all non-ancilla qubits) of the input "
f"adder ({actual_num_state_qubits}) does not match the expected "
f"number ({target_num_state_qubits}). Make sure to pass a half adder.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# 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

"""Compute the difference of two qubit registers using Two's Complement Subtraction."""

from typing import Optional

from qiskit.circuit import QuantumCircuit, QuantumRegister, AncillaRegister

# from qiskit.circuit.library.arithmetic.adders.adder import Adder
from qiskit.circuit.library.arithmetic.adders import (
CDKMRippleCarryAdder,
DraperQFTAdder,
VBERippleCarryAdder,
)
#from qiskit.circuit.library.arithmetic.subtractors import TwosComplement
from qiskit.circuit.library.arithmetic.adders import DraperQFTAdder
from .twos_complement import TwosComplement

class Subtractor(QuantumCircuit):
r"""A circuit that uses 2s Complement Subtraction to perform in-place subtraction on two qubit registers.

Given two equally sized input registers that store quantum states
:math:`|a\rangle` and :math:`|b\rangle`, performs subtraction 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}`[1].
As an example, a subtractor circuit that performs 2s complement on :math:`|b\rangle`and
performs addition on two 3-qubit sized registers is as follows:

.. parsed-literal::



┌─────────────────┐
a_0: ───────────────────────────────────┤0 ├
│ │
a_1: ───────────────────────────────────┤1 ├
│ │
a_2: ───────────────────────────────────┤2 ├
░ ░ ┌───┐┌─────────────────┐│ │
b_0: ─░───────░─┤ X ├┤3 ├┤4 ├
░ ░ ├───┤│ ││ DraperQFTAdder │
b_1: ─░───────░─┤ X ├┤4 ├┤5 ├
░ ░ ├───┤│ ││ │
b_2: ─░───────░─┤ X ├┤5 ├┤6 ├
░ ░ └───┘│ ││ │
carry_b_0: ─░───────░──────┤6 ├┤7 ├
░ ░ │ DraperQFTAdder ││ │
carry_a_0: ────────────────┤ ├┤3 ├
░ ┌───┐ ░ │ │└──────┬───┬──────┘
a0_0: ─░─┤ X ├─░──────┤0 ├───────┤ X ├───────
░ └───┘ ░ │ │ └───┘
a0_1: ─░───────░──────┤1 ├───────────────────
░ ░ │ │
a0_2: ─░───────░──────┤2 ├───────────────────
░ ░ └─────────────────┘



**References**

[1] Vedral et al., Quantum Networks for Elementary Arithmetic Operations, 1995.
`arXiv:quant-ph/9511018 <https://arxiv.org/pdf/quant-ph/9511018.pdf>`_
"""

# def __init__(self, num_state_qubits: int, adder: Optional[adder] = None):
#def __init__(self, num_state_qubits: int, adder=None, name: str = "Subtractor"):
def __init__(
self,
num_state_qubits: int,
adder: Optional[QuantumCircuit] = None,
name: str="Subtractor"
):
if adder is None:
adder = DraperQFTAdder(num_state_qubits + 1, kind="fixed")
#adder = DraperQFTAdder(num_state_qubits + 1, kind=fixed)
##adder = RippleCarryAdder(num_state_qubits+1,modular=True)
else:
_check_adder_is_compatible(num_state_qubits, adder)

twos_complement = TwosComplement(num_state_qubits)
# get the number of qubits needed
#num_qubits = adder.num_qubits
num_helper_qubits = max(adder.num_ancillas, twos_complement.num_ancillas)

# construct the registers
qr_a = QuantumRegister(num_state_qubits, "a") # input a
qr_b = QuantumRegister(num_state_qubits, "b") # input b
carry_b = QuantumRegister(1, "carry_b")
carry_a = AncillaRegister(1, "carry_a")
qr_h = AncillaRegister(num_helper_qubits)

super().__init__(qr_a, qr_b, carry_b, carry_a, qr_h, name=name)

self.compose(
twos_complement,
qubits=qr_b[:] + carry_b[:] + qr_h[: twos_complement.num_ancillas],
inplace=True,
)

# adder
self.compose(
#adder,
adder.to_gate(), #wrap in gate nicer visualization
qubits=qr_a[:] + carry_a[:] + qr_b[:] + carry_b[:] + qr_h[: adder.num_ancillas],
inplace=True,
)


def _check_adder_is_compatible(num_state_qubits, adder):
target_num_state_qubits = 2 * (num_state_qubits + 1) # inplace addition modulo 2^n
actual_num_state_qubits = adder.num_qubits - adder.num_ancillas
if target_num_state_qubits != actual_num_state_qubits:
raise ValueError("The number of state qubits (= all non-ancilla qubits) of the input "
f"adder ({actual_num_state_qubits}) does not match the expected "
f"number ({target_num_state_qubits}). Make sure to pass a modular adder.")
Loading