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 the apply() method. Since a QRoutine can exist independently from any Program there are is no notion of qbit allocation in a QRoutine. 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

QRegister

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.