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

Arithmetic circuit library: Adders #6164

Merged
merged 29 commits into from
May 21, 2021
Merged
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
be646c0
Implement ripple-carry adder circuit (#11)
mantcep Mar 28, 2021
e86916e
Merge branch 'master' into adders
Cryoris Mar 28, 2021
be569a3
Implement QFT adder (#22)
mantcep Mar 29, 2021
b2dab3f
Implemented classical adder in QFT paper (#13)
ManjulaGandhi Apr 6, 2021
38a759f
unify tests
Cryoris Apr 6, 2021
8768780
inject base class ``Adder``
Cryoris Apr 6, 2021
ccee887
add reno
Cryoris Apr 6, 2021
d74b1d6
fix lint
Cryoris Apr 6, 2021
a544a2e
Merge branch 'master' into adders
Cryoris Apr 6, 2021
11da532
Merge branch 'master' into adders
Cryoris Apr 14, 2021
599af6f
fix trailing whitespace in line beginning
Cryoris Apr 20, 2021
0abbaa4
rework docstrings for less duplication
Cryoris Apr 20, 2021
e95d660
Merge branch 'main' into adders
Cryoris Apr 24, 2021
f0bdb97
several updates
Cryoris Apr 27, 2021
335b2ce
lint
Cryoris Apr 27, 2021
a0cc65c
rename classical to plain, make plain modular
Cryoris May 2, 2021
89535de
Renamed PlainAdder to VBERippleCarryAdder (#29)
ManjulaGandhi May 7, 2021
ac5463e
rename modular->fixed point
Cryoris May 7, 2021
5e93a37
add author names to adders
Cryoris May 7, 2021
1b096ec
add comment on how the test works
Cryoris May 7, 2021
ba9e100
Merge branch 'main' into adders
Cryoris May 7, 2021
b5079b8
black
Cryoris May 7, 2021
6196144
add fixed/half/full, misses test for full
Cryoris May 19, 2021
d6a72df
add test for "full"
Cryoris May 20, 2021
b488399
black
Cryoris May 20, 2021
b5887b0
update docstrings
Cryoris May 20, 2021
ceedc70
fix sphinx
Cryoris May 20, 2021
456020a
rename fixed-point to fixed-sized
Cryoris May 20, 2021
9061abd
Merge branch 'main' into adders
mergify[bot] May 21, 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
Prev Previous commit
Next Next commit
several updates
* modular RippleCarryAdder
* test that ancillas are uncomputed
* fix ClassicalAdder ancilla uncompute
* replace all to_instruction by to_gate
Cryoris committed Apr 27, 2021
commit f0bdb977e9b6584c9ca251e72fb4feffa38552b3
6 changes: 3 additions & 3 deletions qiskit/circuit/library/arithmetic/adders/classical_adder.py
Original file line number Diff line number Diff line change
@@ -92,13 +92,13 @@ def __init__(self,
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_instruction_carry = qc_carry.to_gate()

# 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()
qc_instruction_sum = qc_sum.to_gate()

# Build a temporary subcircuit that adds a to b,
# storing the result in b
@@ -114,5 +114,5 @@ def __init__(self,
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_carry.inverse(), [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]])
4 changes: 2 additions & 2 deletions qiskit/circuit/library/arithmetic/adders/qft_adder.py
Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ def __init__(self,
num_qubits_qft = num_state_qubits if modular else num_state_qubits + 1

# build QFT adder circuit
self.append(QFT(num_qubits_qft, do_swaps=False).to_instruction(), qr_sum[:])
self.append(QFT(num_qubits_qft, do_swaps=False).to_gate(), qr_sum[:])

for j in range(num_state_qubits):
for k in range(num_state_qubits - j):
@@ -106,4 +106,4 @@ def __init__(self,
lam = np.pi / (2 ** (j + 1))
self.cp(lam, qr_a[num_state_qubits - j - 1], qr_z[0])

self.append(QFT(num_qubits_qft, do_swaps=False).inverse().to_instruction(), qr_sum[:])
self.append(QFT(num_qubits_qft, do_swaps=False).inverse().to_gate(), qr_sum[:])
16 changes: 11 additions & 5 deletions qiskit/circuit/library/arithmetic/adders/ripple_carry_adder.py
Original file line number Diff line number Diff line change
@@ -61,6 +61,7 @@ class RippleCarryAdder(Adder):

def __init__(self,
num_state_qubits: int,
modular: bool = False,
name: str = 'RippleCarryAdder'
) -> None:
r"""
@@ -79,35 +80,40 @@ def __init__(self,

qr_a = QuantumRegister(num_state_qubits, name='a')
qr_b = QuantumRegister(num_state_qubits, name='b')
qr_z = QuantumRegister(1, name='cout')
qr_c = AncillaRegister(1, name='cin')

# initialize quantum circuit with register list
self.add_register(qr_a, qr_b, qr_z, qr_c)
self.add_register(qr_a, qr_b)
if not modular:
qr_z = QuantumRegister(1, name='cout')
self.add_register(qr_z)

self.add_register(qr_c)

# build carry circuit for majority of 3 bits in-place
# corresponds to MAJ gate in [1]
qc_maj = QuantumCircuit(3, name='MAJ')
qc_maj.cx(0, 1)
qc_maj.cx(0, 2)
qc_maj.ccx(2, 1, 0)
qc_instruction_mac = qc_maj.to_instruction()
qc_instruction_mac = qc_maj.to_gate()

# build circuit for reversing carry operation
# corresponds to UMA gate in [1]
qc_uma = QuantumCircuit(3, name='UMA')
qc_uma.ccx(2, 1, 0)
qc_uma.cx(0, 2)
qc_uma.cx(2, 1)
qc_instruction_uma = qc_uma.to_instruction()
qc_instruction_uma = qc_uma.to_gate()

# build ripple-carry adder circuit
self.append(qc_instruction_mac, [qr_a[0], qr_b[0], qr_c[0]])

for i in range(num_state_qubits-1):
self.append(qc_instruction_mac, [qr_a[i+1], qr_b[i+1], qr_a[i]])

self.cx(qr_a[-1], qr_z[0])
if not modular:
self.cx(qr_a[-1], qr_z[0])

for i in reversed(range(num_state_qubits-1)):
self.append(qc_instruction_uma, [qr_a[i+1], qr_b[i+1], qr_a[i]])
19 changes: 11 additions & 8 deletions test/python/circuit/library/test_adders.py
Original file line number Diff line number Diff line change
@@ -44,18 +44,19 @@ def assertAdditionIsCorrect(self,
``2^num_state_qubits``.
"""
circuit = QuantumCircuit(*adder.qregs)

# create equal superposition
circuit.h(range(2 * num_state_qubits))

# apply adder circuit
circuit.compose(adder, inplace=True)
# obtain the statevector

# obtain the statevector and the probabilities, we don't trace out the ancilla qubits
# as we verify that all ancilla qubits have been uncomputed to state 0 again
statevector = Statevector(circuit)
# trace out the ancillas if necessary
if circuit.num_ancillas > 0:
ancillas = list(range(circuit.num_qubits - circuit.num_ancillas, circuit.num_qubits))
probabilities = np.diagonal(partial_trace(statevector, ancillas))
else:
probabilities = np.abs(statevector) ** 2
probabilities = np.abs(statevector) ** 2
pad = '0' * circuit.num_ancillas # state of the ancillas

# compute the expected results
expectations = np.zeros_like(probabilities)
num_bits_sum = num_state_qubits + 1
@@ -68,14 +69,16 @@ def assertAdditionIsCorrect(self,
bin_x = bin(x)[2:].zfill(num_state_qubits)
bin_y = bin(y)[2:].zfill(num_state_qubits)
bin_res = bin(addition)[2:].zfill(num_bits_sum)
bin_index = bin_res + bin_x if inplace else bin_res + bin_y + bin_x
bin_index = pad + bin_res + bin_x if inplace else pad + bin_res + bin_y + bin_x
index = int(bin_index, 2)
expectations[index] += 1 / 2 ** (2 * num_state_qubits)
np.testing.assert_array_almost_equal(expectations, probabilities)

@data(
(3, RippleCarryAdder, True),
(5, RippleCarryAdder, True),
(3, RippleCarryAdder, True, True),
(5, RippleCarryAdder, True, True),
(3, QFTAdder, True),
(5, QFTAdder, True),
(3, QFTAdder, True, True),