Qubit Release¶
This page describes how to release qubits on the Classiq platform. Indicating which qubits may be released allows the synthesis engine to reuse them to provide better, narrower quantum circuits.
CAUTION! Release qubits with care since incorrect instructions will most likely lead to malfunctioning circuits.
You can release used qubits implicitly (via aiding zero qubits) or explicitly (via functional qubits). The following sections describe the differences between the two and their respective release methods.
Implicit Qubit Release¶
Aiding zero qubits are qubits used implicitly to match input and output sizes. Note that these are distinct from auxiliary qubits and play a different role. Auxiliary qubits enter a function in a zero state and exit as such. On the other hand, aiding zero qubits enter in a zero state and exit as outputs. Auxiliary qubits are implementation-dependent, in contrast to aiding zero inputs.
Consider, for example, the case of an addition function, to which you add two unsigned integer registers. Generally speaking, the result is larger and requires more qubits for its representation. Even if the computation is done "in place," one more qubit is required as an MSB. Note that the added MSB qubit is independent of the choice of the addition implementation. This new qubit is called an aiding zero qubit. The Classiq engine adds it implicitly.
Suppose you perform an addition operation, use the result,
and—with the intent of writing efficient code—uncompute the addition operation to release the added MSB qubit.
Inversion does not automatically release the qubit, as described in the inversion documentation.
In fact, the qubit necessarily returns to a zero state after uncomputation
if the entire operation between computation and uncomputation is "quantum free".
You can request to release the addition MSB qubit using the release_by_inverse
flag together with the is_inverse
flag,
as shown.
Usage¶
{
"function_library": {
"functions": [
{
"name": "main",
"port_declarations": {
"model_arg": {
"name": "model_arg",
"size": {"expr": "3"},
"direction": "inout"
},
"result": {
"name": "result",
"size": {"expr": "4"},
"direction": "output"
}
},
"input_ports_wiring": { "model_arg": "arg_in_wire" },
"output_ports_wiring": { "model_arg": "arg_out_wire", "result": "multiplier_result_wire" },
"logic_flow": [
{
"function": "Adder",
"function_params": {
"left_arg": { "size": 3, "name": "adder_arg" },
"right_arg": 1,
"inplace_arg": "left",
"output_name": "adder_result"
},
"inputs": { "adder_arg": "arg_in_wire" },
"outputs": { "adder_result": "adder_to_multiplier_wire" },
"is_inverse": false
},
{
"function": "Multiplier",
"function_params": {
"left_arg": { "size": 4, "name": "multiplier_arg" },
"right_arg": 2,
"output_name": "multiplier_result"
},
"inputs": { "multiplier_arg": "adder_to_multiplier_wire" },
"outputs": {
"multiplier_result": "multiplier_result_wire",
"multiplier_arg": "multiplier_to_adder_uncomp_wire"
}
},
{
"function": "Adder",
"function_params": {
"left_arg": { "size": 3, "name": "adder_arg" },
"right_arg": 1,
"inplace_arg": "left",
"output_name": "adder_result"
},
"inputs": { "adder_result": "multiplier_to_adder_uncomp_wire" },
"outputs": { "adder_arg": "arg_out_wire" },
"is_inverse": true,
"release_by_inverse": true
}
]
}
]
}
}
from classiq import Model, RegisterUserInput, QUInt
from classiq.builtin_functions import Adder, Multiplier
from classiq.builtin_functions.binary_ops import ArgToInplace
input_size: int = 3
model_arg = RegisterUserInput(size=input_size, name="adder_arg")
adder_params = Adder(
left_arg=model_arg,
right_arg=1,
inplace_arg=ArgToInplace.LEFT,
output_name="adder_result",
)
multiplier_params = Multiplier(
left_arg=RegisterUserInput(size=input_size + 1, name="multiplier_arg"),
right_arg=2,
output_name="multiplier_result",
)
model = Model()
model_inputs = model.create_inputs({"model_arg": QUInt[input_size]})
adder_outputs = model.Adder(
params=adder_params, in_wires={"adder_arg": model_inputs["model_arg"]}
)
multiplier_outputs = model.Multiplier(
params=multiplier_params, in_wires={"multiplier_arg": adder_outputs["adder_result"]}
)
adder_uncomp_outputs = model.Adder(
params=adder_params,
in_wires={"adder_result": multiplier_outputs["multiplier_arg"]},
is_inverse=True,
release_by_inverse=True,
)
model.set_outputs(
{
"model_arg": adder_uncomp_outputs["adder_arg"],
"result": multiplier_outputs["multiplier_result"],
}
)
Explicit Qubit Release¶
Explicit qubit release refers to the release of functional registers; the outputs of any function. Wiring an output to zero forces its release.
To declare that an output register is in the zero state, wire it to "0"
in the textual model or use Model.release_qregs
in the SDK.
The functionality is available for any function, inverted or not.
However, as stressed above, it must be done with caution.
The following example uses explicit outputs
to convert a Boolean function. The result is coded on qubits, using Oracle CCX gates that code the result on phases.
The X
and H
gates create a minus state for a phase kickback.
Usage¶
{
"function_library": {
"functions": [
{
"name": "main",
"port_declarations": {
"ARG": {
"name": "ARG",
"size": {"expr": "2"},
"direction": "inout"
}
},
"input_ports_wiring": { "ARG": "argument_in_wire" },
"output_ports_wiring": { "ARG": "argument_out_wire" },
"logic_flow": [
{
"function": "XGate",
"function_params": {},
"outputs": { "TARGET": "minus_state_inner_wire" }
},
{
"function": "HGate",
"function_params": {},
"inputs": { "TARGET": "minus_state_inner_wire" },
"outputs": { "TARGET": "minus_state_wire" }
},
{
"function": "CCXGate",
"function_params": {},
"inputs": { "TARGET": "minus_state_wire", "CTRL": "argument_in_wire" },
"outputs": {
"TARGET": "minus_state_uncomp_wire",
"CTRL": "argument_out_wire"
}
},
{
"function": "HGate",
"function_params": {},
"inputs": { "TARGET": "minus_state_uncomp_wire" },
"outputs": { "TARGET": "minus_state_uncomp_inner_wire" }
},
{
"function": "XGate",
"function_params": {},
"inputs": { "TARGET": "minus_state_uncomp_inner_wire" },
"outputs": { "TARGET": "0" }
}
]
}
]
}
}
from classiq import Model, RegisterUserInput, QUInt
from classiq.builtin_functions import CCXGate, XGate, HGate
model = Model()
model_inputs = model.create_inputs({"ARG": QUInt[2]})
x_outputs = model.XGate(params=XGate())
h_outputs = model.HGate(params=HGate(), in_wires=x_outputs)
ccx_params = CCXGate()
ccx_outputs = model.CCXGate(
params=ccx_params,
in_wires={"TARGET": h_outputs["TARGET"], "CTRL": model_inputs["ARG"]},
)
h_uncomp_outputs = model.HGate(
params=HGate(), in_wires={"TARGET": ccx_outputs["TARGET"]}
)
out = model.XGate(
params=XGate(),
in_wires=h_uncomp_outputs,
)["TARGET"]
model.release_qregs(out)
model.set_outputs({"ARG": ccx_outputs["CTRL"]})