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

Ancilla-Free Quantum Adder with Sublinear Depth #13975

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
.. autofunction:: adder_qft_d00
.. autofunction:: adder_ripple_c04
.. autofunction:: adder_ripple_v95
.. autofunction:: adder_ripple_rv25

Multipliers
-----------
Expand Down Expand Up @@ -232,6 +233,7 @@
adder_qft_d00,
adder_ripple_c04,
adder_ripple_v95,
adder_ripple_rv25,
multiplier_cumulative_h18,
multiplier_qft_r17,
synth_integer_comparator_greedy,
Expand Down
2 changes: 1 addition & 1 deletion qiskit/synthesis/arithmetic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"""Synthesis for arithmetic circuits."""

from .comparators import synth_integer_comparator_2s, synth_integer_comparator_greedy
from .adders import adder_qft_d00, adder_ripple_c04, adder_ripple_v95
from .adders import adder_qft_d00, adder_ripple_c04, adder_ripple_v95, adder_ripple_rv25
from .multipliers import multiplier_cumulative_h18, multiplier_qft_r17
from .weighted_sum import synth_weighted_sum_carry
1 change: 1 addition & 0 deletions qiskit/synthesis/arithmetic/adders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
from .cdkm_ripple_carry_adder import adder_ripple_c04
from .vbe_ripple_carry_adder import adder_ripple_v95
from .draper_qft_adder import adder_qft_d00
from .rv_ripple_carry_adder import adder_ripple_rv25
131 changes: 131 additions & 0 deletions qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2025.
#
# 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 sum of two qubit registers without any ancillary qubits."""

from __future__ import annotations
from math import ceil
from qiskit.exceptions import QiskitError
from qiskit import QuantumCircuit, QuantumRegister


def _mcx_ladder(n_mcx: int, alpha: int):
r"""Implements a log-depth MCX ladder circuit as outlined in Algorithm 2 of [1]. The circuit
relies on log-depth decomposition of MCX gate that uses conditionally clean ancillae of [2].
Selecting :math:`\alpha=1` creates a CX ladder as shown in Fig. 2 of [1] and selecting
:math:`\alpha=2` creates a Toffoli ladder as shown in Fig. 3 of [1].

Args:
n_mcx: Number of MCX gates in the ladder.
alpha: Number of controls per MCX gate.

Returns:
QuantumCircuit: The MCX ladder circuit.

References:
1. Remaud and Vandaele, Ancilla-free Quantum Adder with Sublinear Depth, 2025.
`arXiv:2501.16802 <https://arxiv.org/abs/2501.16802>`__

2. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
"""

def helper(X, alphas):
k = len(alphas) + 1
if k == 1:
return []
if k == 2:
return [X[: alphas[0] + 1]]

x_bar = [X[alphas[0]]]
alpha_bar = []
right_pairs = [X[0 : alphas[0] + 1]]
left_pairs = [X[alphas[k - 3] : alphas[-1] + 1]]

for i in range(1, ceil(k / 2) - 1):
left_pairs += [X[alphas[2 * i - 2] : alphas[2 * i - 1] + 1]]
right_pairs += [X[alphas[2 * i - 1] : alphas[2 * i] + 1]]
x_bar += (
X[alphas[2 * i - 2] + 1 : alphas[2 * i - 1]]
+ X[alphas[2 * i - 1] + 1 : alphas[2 * i] + 1]
)
alpha_bar.append(alphas[2 * i] - alphas[0] - i)

if k % 2 == 0:
x_bar += X[alphas[k - 4] + 1 : alphas[k - 3] + 1]
alpha_bar.append(alphas[k - 3] - alphas[0] - int(k / 2) + 2)

return left_pairs + helper(x_bar, alpha_bar) + right_pairs

n = n_mcx * alpha + 1
qc = QuantumCircuit(n)
X, alphas = list(range(n)), list(range(alpha, n, alpha))
mcxs = helper(X, alphas)
for mcx in mcxs:
if len(mcx) <= 3: # already a Toffoli
qc.mcx(mcx[:-1], mcx[-1])
else:
# for each mcx with n_ctrls > 2, use 2 qubits above the first ctrl index as ancillae
ancilla_idx = [mcx[0] - 2, mcx[0] - 1]
gate = MCXLogDepth(len(mcx) - 1)
qc.compose(
gate,
# ctrls, targ, anc
mcx[:-1] + [mcx[-1]] + ancilla_idx,
inplace=True,
)

return qc


def adder_ripple_rv25(num_qubits: int) -> QuantumCircuit:
r"""The RV ripple carry adder [1].
Construct an ancilla-free quantum adder circuit with sublinear depth based on the RV ripple-carry
adder shown in [1]. The implementation has a depth of :math:`O(\log^2 n)` and uses :math:`O(n \log n)`
gates.

Args:
num_qubits: The size of the register.

Returns:
QuantumCircuit: The quantum circuit implementing the RV ripple carry adder.

Raises:
QiskitError: If ``num_state_qubits`` is lower than 1.

**References:**

1. Remaud and Vandaele, Ancilla-free Quantum Adder with Sublinear Depth, 2025.
`arXiv:2501.16802 <https://arxiv.org/abs/2501.16802>`__

"""
if num_qubits < 1:
raise QiskitError("The number of qubits must be at least 1.")

qr_a = QuantumRegister(num_qubits, "a")
qr_b = QuantumRegister(num_qubits, "b")
qr_z = QuantumRegister(1, "cout")
qc = QuantumCircuit(qr_a, qr_b, qr_z)

ab_interleaved = [q for pair in zip(qr_a, qr_b) for q in pair]

qc.cx(qr_a[1:], qr_b[1:])
qc.compose(_mcx_ladder(num_qubits - 1, 1), qr_a[1:] + qr_z[:], inplace=True)
qc.compose(_mcx_ladder(num_qubits, 2).inverse(), ab_interleaved + qr_z[:], inplace=True)
qc.cx(qr_a[1:], qr_b[1:])
qc.x(qr_b[1 : num_qubits - 1])
qc.compose(_mcx_ladder(num_qubits - 1, 2), ab_interleaved[:-1], inplace=True)
qc.x(qr_b[1 : num_qubits - 1])
qc.compose(_mcx_ladder(num_qubits - 2, 1).inverse(), qr_a[1:], inplace=True)
qc.cx(qr_a, qr_b)

return qc
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/synthesis/hls_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@
adder_ripple_c04,
adder_qft_d00,
adder_ripple_v95,
adder_ripple_rv25,
multiplier_qft_r17,
multiplier_cumulative_h18,
)
Expand Down
Loading