Skip to content

Add Quantum Full Adder circuit for classical integers #2954

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

Merged
merged 2 commits into from
Nov 11, 2020
Merged
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
108 changes: 108 additions & 0 deletions quantum/ripple_adder_classic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# https://github.com/rupansh/QuantumComputing/blob/master/rippleadd.py
# https://en.wikipedia.org/wiki/Adder_(electronics)#Full_adder
# https://en.wikipedia.org/wiki/Controlled_NOT_gate

from qiskit import Aer, QuantumCircuit, execute
from qiskit.providers import BaseBackend


def store_two_classics(val1: int, val2: int) -> (QuantumCircuit, str, str):
"""
Generates a Quantum Circuit which stores two classical integers
Returns the circuit and binary representation of the integers
"""
x, y = bin(val1)[2:], bin(val2)[2:] # Remove leading '0b'

# Ensure that both strings are of the same length
if len(x) > len(y):
y = y.zfill(len(x))
else:
x = x.zfill(len(y))

# We need (3 * number of bits in the larger number)+1 qBits
# The second parameter is the number of classical registers, to measure the result
circuit = QuantumCircuit((len(x) * 3) + 1, len(x) + 1)

# We are essentially "not-ing" the bits that are 1
# Reversed because its easier to perform ops on more significant bits
for i in range(len(x)):
if x[::-1][i] == "1":
circuit.x(i)
for j in range(len(y)):
if y[::-1][j] == "1":
circuit.x(len(x) + j)

return circuit, x, y


def full_adder(
circuit: QuantumCircuit,
input1_loc: int,
input2_loc: int,
carry_in: int,
carry_out: int,
):
"""
Quantum Equivalent of a Full Adder Circuit
CX/CCX is like 2-way/3-way XOR
"""
circuit.ccx(input1_loc, input2_loc, carry_out)
circuit.cx(input1_loc, input2_loc)
circuit.ccx(input2_loc, carry_in, carry_out)
circuit.cx(input2_loc, carry_in)
circuit.cx(input1_loc, input2_loc)


def ripple_adder(
val1: int, val2: int, backend: BaseBackend = Aer.get_backend("qasm_simulator")
) -> int:
"""
Quantum Equivalent of a Ripple Adder Circuit
Uses qasm_simulator backend by default

Currently only adds 'emulated' Classical Bits
but nothing prevents us from doing this with hadamard'd bits :)

Only supports adding +ve Integers

>>> ripple_adder(3, 4)
7
>>> ripple_adder(10, 4)
14
>>> ripple_adder(-1, 10)
Traceback (most recent call last):
...
ValueError: Both Integers must be positive!
"""

if val1 < 0 or val2 < 0:
raise ValueError("Both Integers must be positive!")

# Store the Integers
circuit, x, y = store_two_classics(val1, val2)

"""
We are essentially using each bit of x & y respectively as full_adder's input
the carry_input is used from the previous circuit (for circuit num > 1)

the carry_out is just below carry_input because
it will be essentially the carry_input for the next full_adder
"""
for i in range(len(x)):
full_adder(circuit, i, len(x) + i, len(x) + len(y) + i, len(x) + len(y) + i + 1)
circuit.barrier() # Optional, just for aesthetics

# Measure the resultant qBits
for i in range(len(x) + 1):
circuit.measure([(len(x) * 2) + i], [i])

res = execute(circuit, backend, shots=1).result()

# The result is in binary. Convert it back to int
return int(list(res.get_counts().keys())[0], 2)


if __name__ == "__main__":
import doctest

doctest.testmod()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ numpy
opencv-python
pandas
pillow
qiskit
requests
scikit-fuzzy
sklearn
Expand Down