qrisp.qcla#

qcla(a, b, radix_base=2, radix_exponent=1, t_depth_reduction=True, ctrl=None)[source]#

Implementation of the higher radix quantum carry lookahead adder (QCLA) as described here. This adder stands out for having logarithmic T-depth like Drapers QCLA. Compared to Drapers QCLA, the higher radix QCLA allows a more dynamic structure and the use of customizable “sub-adders” which enables this adder to beat Drapers QCLA in terms of speed (ie. T-depth).

In Python syntax, this function performs the inplace addition:

b += a

Apart from the two quantum arguments, this function supports the specification of the adder-radix R. The adder-radix can be specified in the form of an exponential of integers:

\[R = r^k\]

Where \(r\) is the radix base and \(k\) is the radix exponent.

Calling qcla with radix base \(r\) and radix exponent \(k\), will precalculate the carry values using the Brent-Kung tree with carry-radix \(r\) and cancel the recursion \(k\) layers before conclusion.

An additional compilation option is given with the t_depth_reduction keyword. This compilation option modifies the way the carry values are uncomputed. If t_depth_reduction is set to True the carry values will be uncomputed using the intermediate result of the sub-adder - if set to False they will be uncomputed using the automatic uncomputation algorithm.

The advantage of the automated version is that, both T-depth and CNOT-depth are scaling with the the logarithm of the input size. For t_depth_reduction = True the T-depth is significantly reduced (and still logarithmic) however the CNOT depth becomes linear.

Parameters
aQuantumFloat or List[Qubit] or int

The value that is added.

bQuantumFloat or List[Qubit]

The value that is operated on.

radix_baseinteger, optional

The radix of the Brent-Kung tree. The default is 2.

radix_exponentinteger, optional

The cancellation treshold for the Brent-Kung recursion. The adder-Radix is then \(R = r^k\). The default is 1.

t_depth_reductionbool, optional

A compilation option that reduces T-depth but in turn weakens CNOT depth to linear scaling. The default is True.

Raises
Exception

Tried to add QuantumFloat of higher precision onto QuantumFloat of lower precision.

Examples

We try out several constellations of parameters:

>>> from qrisp import QuantumFloat, qcla
>>> a = QuantumFloat(8)
>>> b = QuantumFloat(8)
>>> a[:] = 4
>>> b[:] = 15
>>> qcla(a, b)
>>> print(b)
{19: 1.0}

We now measure the T-depth. To get the optimal result, we need to tell the compiler that we only care about T-gates. This can be achieved with the gate_speed keyword of the compile method. This keyword allows you to specify a function of Operation objects, which returns the speed of that Operation. For more information check out the compile documentation page.

For T-depth, there is already a pre-coded function: qrisp.t_depth_indicator.

>>> from qrisp import t_depth_indicator
>>> gate_speed = lambda x : t_depth_indicator(x, epsilon = 2**-10)
>>> qc = b.qs.compile(gate_speed = gate_speed, compile_mcm = True)
>>> qc.t_depth()
17

This function contains many allocations/deallocations that can be leveraged into parallelism, implying it can profit a lot from additional workspace:

>>> qc = b.qs.compile(workspace = 10, gate_speed = gate_speed, compile_mcm = True)
>>> qc.t_depth()        
7

We can verify the logarithmic behavior by comparing to the Gidney-adder:

>>> from qrisp import gidney_adder
>>> a = QuantumFloat(40)
>>> b = QuantumFloat(40)
>>> gidney_adder(a, b)
>>> qc = b.qs.compile(gate_speed = gate_speed, compile_mcm = True)
>>> qc.t_depth()
40
>>> a = QuantumFloat(40)
>>> b = QuantumFloat(40)
>>> qcla(a, b)
>>> qc = b.qs.compile(workspace = 50, gate_speed = gate_speed, compile_mcm = True)
>>> qc.t_depth()    
19

The function can also be used to perform semi-classical in-place addition

>>> b = QuantumFloat(10)
>>> b[:] = 20
>>> qcla(22, b)
>>> print(b)
{42: 1.0}