qat.lang.QRoutine
Finally, the notion of gate is also extended to subcircuits via the QRoutine
class.
- class qat.lang.QRoutine(arity=0, routop_l=None, max_wire=None, ancillae=None)
QRoutine
represent subcircuits that behave as a Gate object.The constructor takes no required arguments.
Applying a Gate or a
QRoutine
inside another routine is done through theapply()
method. Since aQRoutine
can exist independently from any Program there are is no notion of qbit allocation in aQRoutine
. Gates are thus applied on indices referring to the inbound wires of the routine.Example
The following example shows how to create a QRoutine containing two gates and use it repeatedly within a quantum circuit
from qat.lang.AQASM import Program, QRoutine, H, CNOT routine = QRoutine() routine.apply(H, 0) routine.apply(CNOT, 0, 1) prog = Program() qbits = prog.qalloc(4) for _ in range(3): for bl in range(2): prog.apply(routine, qbits[2*bl:2*bl+2]) circ = prog.to_circ() print("total number of gates: ", len(circ.ops))
total number of gates: 12
- apply(gate, *args)
Apply a quantum gate on a set of wires. Wires are refered using integers.
- Parameters
gate (
Gate
) – the quantum gate to apply*args (any iterator over int) – the wires to apply the gate on
- compute()
Opens a computation scope and returns a reference to this fresh scope.
Warning
All scopes are lost when controlling/daggering a QRoutine.
Note
This method is designed to be called inside a with statement in order for the scope to be cleanly closed.
with rout.compute(): rout.apply(CNOT, 0, 1) # here the scope is closed rout.uncompute()
Directly calling the method will result in the scope never being closed.
- free_ancillae(args)
Return the ancillae qubits to an unused pool so that they can be reused again in the routine. It is important that the ancilla qubits are in product \(|0\rangle\) state when they are freed.
- Parameters
args (int/list<int>/quantum register) – the set of ancillae to release
- get_free_ancillae(size=1, class_name=None)
Returns a list of ancillae qubits of length length. If there are currently unused ancillae qubits in the list freed_ancillae, they will be returned first. Then, allocate new wires if needed and set them as ancillae.
- Parameters
length (optional, int) – the number of ancillae to allocate (default to 1)
class_name (optional, type) – optionally, a quantum type to wrap the allocated ancillae (e.g QInt, QBool, etc)
- new_wires(length, class_name=None, **kwargs)
Returns a list of fresh wires of length length.
- Parameters
length (int) – the number of fresh wires to return
class_name (type) – a quantum type (optional)
kwargs – additinal arguments are passed to the quantum type
- Returns
a quantum register
- Return type
- set_ancillae(*args)
Tags some wires as ancillae. This has two effects:
the public arity of the routine will be reduced to only consider the non-tagged wires as input/output wires
ancillae will be allocated at circuit generation (in consequence, the final number of qubits of the circuit might be larger than the number of qubits allocated inside the program)
For example, in the following code:
rout = QRoutine() w1, w2 = rout.new_wires() rout.set_ancillae(w1)
rout is a routine of arity 1 (since w1 has been tagged as ancilla). In particular the following code will be a valid program:
prog = Program() qbits = prog.qalloc(1) prog.apply(rout, qbits) circuit = prog.to_circ()
Moreover, the resulting circuit will be a circuit over 2 qubits (the ancilla will be allocated during the contruction of the circuit).
- uncompute()
Uncomputes the first computation scope on the scope stack and pops it from the scope stack.