Requirement already satisfied: qiskit in /usr/local/lib/python3.12/dist-packages (2.4.1)
Requirement already satisfied: rustworkx>=0.15.0 in /usr/local/lib/python3.12/dist-packages (from qiskit) (0.17.1)
Requirement already satisfied: numpy<3,>=1.21 in /usr/local/lib/python3.12/dist-packages (from qiskit) (2.0.2)
Requirement already satisfied: scipy>=1.5 in /usr/local/lib/python3.12/dist-packages (from qiskit) (1.16.3)
Requirement already satisfied: dill>=0.3 in /usr/local/lib/python3.12/dist-packages (from qiskit) (0.3.8)
Requirement already satisfied: stevedore>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from qiskit) (5.7.0)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.12/dist-packages (from qiskit) (4.15.0)
Requirement already satisfied: qiskit_aer in /usr/local/lib/python3.12/dist-packages (0.17.2)
Requirement already satisfied: qiskit>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from qiskit_aer) (2.4.1)
Requirement already satisfied: numpy>=1.16.3 in /usr/local/lib/python3.12/dist-packages (from qiskit_aer) (2.0.2)
Requirement already satisfied: scipy>=1.0 in /usr/local/lib/python3.12/dist-packages (from qiskit_aer) (1.16.3)
Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.12/dist-packages (from qiskit_aer) (5.9.5)
Requirement already satisfied: python-dateutil>=2.8.0 in /usr/local/lib/python3.12/dist-packages (from qiskit_aer) (2.9.0.post0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.0->qiskit_aer) (1.17.0)
Requirement already satisfied: rustworkx>=0.15.0 in /usr/local/lib/python3.12/dist-packages (from qiskit>=1.1.0->qiskit_aer) (0.17.1)
Requirement already satisfied: dill>=0.3 in /usr/local/lib/python3.12/dist-packages (from qiskit>=1.1.0->qiskit_aer) (0.3.8)
Requirement already satisfied: stevedore>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from qiskit>=1.1.0->qiskit_aer) (5.7.0)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.12/dist-packages (from qiskit>=1.1.0->qiskit_aer) (4.15.0)
def _run(qc, shots):
  simulator = AerSimulator()
  tqc = transpile(qc, simulator, optimization_level=3)

  job = simulator.run(tqc, shots=shots)
  result = job.result()

  return dict(sorted(result.get_counts().items()))

Fedoriaka implements the \(MAJ\) and \(MAJ^{-1}\) gates efficiently by incorporating the \(AND\) and \(AND^{-1}\) gates described in “Halving the cost of quantum addition” (Gidney). Below is the implementation of said gates.

Screenshot 2026-04-09 224839.png

The \(AND^{-1}\) implementation is particularly unique as it uses classical measurement to skip practically every expensive operation used in the \(AND\) implementation. The phase is preserved by a \(CZ\) controlled on the result of the measurement.

Testing \(AND\) and \(AND^{-1}\)

qc = QuantumCircuit(3,3)
qc.h(2)
qc.t(2)
qc.x(0)
qc.x(1)
qc.compose(_AND(), qubits=[0,1,2], inplace=True)
qc.measure([0,1,2], [0,1,2])
assert _run(qc,8) == {'111': 8}, "AND gate does not work correctly"

qc = QuantumCircuit(3,3)
qc.h(2)
qc.t(2)
qc.x(0)
qc.compose(_AND(), qubits=[0,1,2], inplace=True)
qc.compose(_ANDdg(), qubits=[0,1,2], clbits=[0], inplace=True)
qc.measure([0,1,2],[0,1,2])
assert _run(qc,8) == {'001': 8}, "ANDdg fails to undo AND gate"

Algorithmically generalized implementation, following the fully-optimized Adder Design from the paper, shown below: image.png

Fedoriaka Adder Export


FedoriakaConstantAdder


def FedoriakaConstantAdder(
    constant:int, size:int
)->QuantumCircuit:

Implements |b> -> |(b + a) mod 2^N> Where a is a fixed classical constant Via the method outlined in: “New Circuit for Quantum Adder by Constant” (Dmytro Fedoriaka)

Args: constant (int): Fixed classical value to add, where 0 <= constant < 2^size and constant%2 == 1 If even constant, add constant/2 to the first size-1 bits instead so that constant becomes odd size (int): Number of qubits in the register b (0<size)

Result: QuantumCircuit object implementing in-place constant addition Takes size-3 additional ancillae qubits (or 0 for size<4) and 1 classical bit (used in uncomputation through venting) Can be applied to circuits via .compose() - .append() will not work

Circuit Register Layout: [ input_qubits | ancillae_qubits ] [ venting_clbit ]


FedoriakaAdder_AncillaCount


def FedoriakaAdder_AncillaCount(
    constant:int, size:int
)->int:

Call self as a function.

Testing Fedoriaka Adder

qc = QuantumCircuit(2,2)
qc.x(0)
qc.compose(FedoriakaConstantAdder(2,2), qubits=[0,1], inplace=True)
qc.measure([0,1], [0,1])
assert _run(qc,8) == {'11': 8}, "ConstantAdder_Size2 does not work correctly"

qc = QuantumCircuit(3,3)
qc.compose(FedoriakaConstantAdder(3,3), qubits=[0,1,2], inplace=True)
qc.compose(FedoriakaConstantAdder(1,3), qubits=[0,1,2], inplace=True)
qc.measure([0,1,2], [0,1,2])
assert _run(qc,8) == {'100': 8}, "ConstantAdder_Size3 does not work correctly"

qc = QuantumCircuit(5,4)
qc.x(0)
qc.x(1)
qc.compose(FedoriakaConstantAdder(5,4), qubits=[0,1,2,3,4], clbits=[0], inplace=True)
qc.measure([0,1,2,3], [0,1,2,3])
assert _run(qc,8) == {'1000': 8}

qc = QuantumCircuit(6,5)
qc.compose(FedoriakaConstantAdder(10,5), qubits=[0,1,2,3,4,5], clbits=[0], inplace=True)
qc.compose(FedoriakaConstantAdder(4,5), qubits=[0,1,2,3,4], clbits=[0], inplace=True)
qc.measure([0,1,2,3,4], [0,1,2,3,4])
assert _run(qc,8) == {'01110': 8}

Generalizing the Control-Adder design shown in the paper: image.png

Controlled Fedoriaka Adder Export


Controlled_FedoriakaConstantAdder


def Controlled_FedoriakaConstantAdder(
    constant:int, size:int
)->QuantumCircuit:

Implements |c>|b> -> |c>|(b + ca) mod 2^N>* Where a is a fixed classical constant and c is a quantum control bit Via the method for a controlled-adder outlined in: “New Circuit for Quantum Adder by Constant” (Dmytro Fedoriaka)

Args: constant (int): Fixed classical value to add, where 0 <= constant < 2^size and constant%2 == 1 If even constant, add constant/2 to the first size-1 bits instead so that constant becomes odd size (int): Number of qubits in the register b (0<size)

Result: QuantumCircuit object implementing in-place controlled constant addition Takes 1 control bit, size-2 additional ancillae qubits (or 0 for size<3), and 1 classical bit (used in uncomputation through venting) Can be applied to circuits via .compose() - .append() will not work

Circuit Register Layout: [ control_qubit | input_qubits | ancillae_qubits ] [ venting_clbit ]


FedoriakaAdder_AncillaCount


def FedoriakaAdder_AncillaCount(
    constant:int, size:int
)->int:

Call self as a function.

Testing Controlled Fedoriaka Adder

qc = QuantumCircuit(3,2)
qc.x(0) #control on
qc.compose(Controlled_FedoriakaConstantAdder(3,2), qubits=[0,1,2], inplace=True)
qc.measure([1,2], [0,1])
assert _run(qc,8) == {'11': 8}, "Controlled_ConstantAdder_Size2 does not add properly"

qc = QuantumCircuit(3,2)
#control off
qc.compose(Controlled_FedoriakaConstantAdder(2,2), qubits=[0,1,2])
qc.measure([1,2], [0,1])
assert _run(qc,8) == {'00': 8}, "Controlled_ConstantAdder_Size2 is not disabeled by control qubit"

qc = QuantumCircuit(7,4)
#control off
qc.compose(Controlled_FedoriakaConstantAdder(15,4), qubits=[6,0,1,2,3,4,5], clbits=[0], inplace=True)
qc.measure([1,2,3,4], [0,1,2,3])
assert _run(qc,8) == {'0000': 8}, "Controlled_ConstantAdder_Size3 is not disabeled by control qubit"

qc = QuantumCircuit(9,5)
qc.x(8)
qc.compose(Controlled_FedoriakaConstantAdder(13,5), qubits=[8,0,1,2,3,4,5,6,7], clbits=[0], inplace=True)
qc.compose(Controlled_FedoriakaConstantAdder(21,5), qubits=[8,0,1,2,3,4,5,6,7], clbits=[0], inplace=True)
qc.measure([0,1,2,3,4], [0,1,2,3,4])
assert _run(qc,8) == {'00010': 8}, "Controlled_ConstantAdder_Size3 does not add properly"