qrisp.cuccaro_adder#

cuccaro_adder(a: int | str | BigInteger | QuantumRegister, b: QuantumRegister, c_in: OptionalQubit | None = None, c_out: OptionalQubit | None = None, ctrl: OptionalQubit | None = None) → None[source]#

In-place adder as introduced in https://arxiv.org/abs/quant-ph/0410184

This function works in both static and dynamic modes.

The two inputs may both be quantum, or one may be quantum and the other classical. All supported quantum types (e.g. QuantumFloat, QuantumBool, QuantumModulus, …) can be used as quantum inputs, along with lists of Qubits and DynamicQubitArray objects.

  • A DynamicQubitArray is simply an array of qubits that is created automatically in Jasp mode; you never need to construct one yourself.

  • A quantum input can also be a list of bare Qubits. Bare Qubits are obtained by indexing a quantum variable, e.g. qv[0] yields a single Qubit and qv[0:2] yields a list of Qubits; a bare Qubit may likewise be passed directly as the carry or control argument.

The table below lists the accepted input forms and the behaviour in the special cases.

Input

Behaviour

Quantum first input a

Any quantum type, list[Qubit] or DynamicQubitArray. It is adjusted to the size of b before the addition.

Quantum second input b

Must be a quantum register (QuantumVariable, list[Qubit] or DynamicQubitArray); it holds the result in place and its size sets the modulus of the addition.

Classical first input

An int, a little-endian binary str, or a BigInteger (dynamic mode only). It is encoded into a temporary quantum variable of the same size as b and uncomputed afterwards, so no ancilla is left over. The second input cannot be classical, since the addition is performed in place on it.

Classical addend larger than b

Truncated modulo 2**len(b) before it is encoded.

Quantum a larger than b

a is truncated by slicing off its high-order qubits, so the addition is performed modulo 2**len(b). No qubits are added or removed and a keeps its value and size.

Quantum a smaller than b

a is padded with ancilla qubits in the |0> state so it can be processed at the size of b. The ancillas are deleted once the addition is done, and a itself is not modified.

QuantumBool

A single-qubit register, so the addition wraps around modulo 2.

QuantumModulus

Works as long as the sum stays below the modulus.

c_in and c_out

Optional carry-in and carry-out; each accepts a QuantumBool or a bare Qubit. c_in adds an extra 1 to the sum, and c_out records the overflow.

ctrl

Optional control qubit; accepts a QuantumBool or a bare Qubit. The addition is only applied when the control is in the |1> state. Equivalently, the call can be wrapped in a control() environment.

Dynamic mode

Inside a jaspify() function the quantum inputs may be DynamicQubitArray objects such as a.reg or a full slice a[:]. The result is read out with measure.

The custom control implementation is based on Theorem 2.12 of https://arxiv.org/abs/2407.20167

Note

If the first input is quantum and the second classical, the function cannot work as addition is performed “in-place” on the second input.

Parameters:
aint, str, BigInteger, QuantumVariable, list[Qubit] or DynamicQubitArray

The value that should be added. A str is interpreted as a little-endian binary string ("10" means bit 0 is 1, i.e. the value 1). A BigInteger is only supported in dynamic (tracing) mode.

bQuantumVariable or list[Qubit] or DynamicQubitArray

The value that should be modified in the in-place addition.

c_inQuantumBool or Qubit, optional

An optional carry in value. The default is None.

c_outQuantumBool or Qubit, optional

An optional carry out value. The default is None.

ctrlQuantumBool or Qubit, optional

An optional control qubit. If provided, the addition is only applied when the control qubit is in the |1> state. The default is None.

Returns:
None

The function modifies the second input in place.

Raises:
AttributeError

If ctrl is not a QuantumBool or Qubit. The custom_control decorator inspects the control qubit before the function body runs.

TypeError

If carry in or carry out is not of type QuantumBool or Qubit in static mode.

TypeError

If the first argument is classical but not an integer, binary string or BigInteger in static mode.

ValueError

If the first argument is a str that is not a valid binary string.

ValueError

If the second argument is not a quantum register, i.e. if b is not a QuantumVariable, DynamicQubitArray or a non-empty list[Qubit].

ValueError

If the first argument is a list that does not contain only Qubits.

ValueError

If a or b is a QuantumChar or QuantumString, which are not supported numeric register types.

Examples

The examples below use QuantumFloat inputs; any other supported quantum type works the same way. In static mode, print already simulates and shows the outcome:

>>> from qrisp import QuantumFloat, cuccaro_adder
>>> a = QuantumFloat(4)
>>> b = QuantumFloat(4)
>>> a[:] = 4
>>> b[:] = 5
>>> cuccaro_adder(a, b)
>>> print(b)
{9: 1.0}

In dynamic mode, the call is wrapped in a jaspify() function and the result is collapsed with measure before it is returned:

>>> from qrisp import QuantumFloat, cuccaro_adder, measure
>>> from qrisp.jasp import jaspify
>>> @jaspify
... def main():
...     a = QuantumFloat(4)
...     b = QuantumFloat(4)
...     a[:] = 4
...     b[:] = 5
...     cuccaro_adder(a, b)
...     return measure(b)
>>> main()
Array(9., dtype=float64)