Skip to content

Inversion

Inversion is the operation taking a function \(f\) implemented by some unitary \(U_{f}\) to the function implemented by \(U_{f} ^{\dagger}\). Many quantum algorithms take the form \(U^{\dagger} V U\), In which \(U\) implements some computation, \(V\) uses the results of \(U\) to arrive at the final result, then, the no-longer necessary intermediate result of \(U\) is uncomputed to release qubits for future use. Hence, the inversion of general functions is critical in implementing many algorithms.

One should note that calls to inverted functions do not necessarily release hardware resources. Suppose the implementation of \(U\) requires extra qubits, assumed to begin at state \(|z=0\rangle\), but are not released at the end (do not end at \(|0\rangle\)). Acting on some states, \(U^ {\dagger}\) might not return the qubits starting at zero to the initial zero state. That's because the Hilbert space of the result is larger than that of the input (due to the added qubits at zero). Therefore, there must be states with sources for which \(|z \neq 0 \rangle\). Not knowing which states we operate on, we may not assume \(U^ {\dagger}\) releases qubits. As a result, released qubit identification must be left to the quantum developer, and may be done manually.

Mathematically speaking, we are promised \(U_{f}|x, z \rangle\) computes \(f(x)\) only on the subspace for which \(|z \rangle\) are indeed zero qubits. Inversion of \(f\) is properly defined only on \(Im{f}\). Inversion of the unitary operator however, is done on the entire result Hilbert space. Hence it is not guaranteed that \(U_{f} ^{\dagger}\) computes \(f^{-1}\).

Usage

Any function, built-in or not, may be inverted on the Classiq platform. When calling the function, set the 'is_inverse' flag to 'True' to get the inverse version. The incoming and outgoing wires should match the inputs and outputs of the inverted function, for which inputs and outputs switch roles. In the following example, negation is followed by its inverse. Note that the result register "negated" switches roles from output to input.

{
"logic_flow": [
    {
    "function": "Negation",
    "function_params": {
        "arg": { "size": 3, "name": "arg_name" },
        "output_name": "negated"
    },
    "outputs": { "negated": "inner_wire_name" }
    },
    {
    "function": "Negation",
    "function_params": {
        "arg": { "size": 3, "name": "arg_name" },
        "output_name": "negated"
    },
    "is_inverse": true,
    "inputs": { "negated": "inner_wire_name" }
    }
]
}
from classiq import ModelDesigner, QReg
from classiq.builtin_functions import Negation
from classiq.interface.generator.arith.arithmetic import RegisterUserInput

arg = RegisterUserInput(size=3, name="arg_name", is_signed=True)
params = Negation(arg=arg, inplace=True, output_name="negated")

x = QReg(size=3)
model_designer = ModelDesigner()
model_designer.Negation(params=params, out_wires={"negated": x})
model_designer.Negation(params=params, is_inverse=True, in_wires={"negated": x})