qat.lang : Programming tools

The Program class

class qat.lang.AQASM.Program(default_gate_set=True)

Class for quantum programs.

Parameters

default_gate_set (bool, optional) – If set to False, the Program is initialized with an empty gate set. The gate set is updated dynamically when one applies gates to the Program via the apply method. Default to True.

apply(gate, *args)

Applies a Gate to a list of qbits.

Parameters
  • gate (Gate) – The quantum gate to apply.

  • *args – Variable length qbit list. Accepts any iterator over Qbit objects.

calloc(size=1)

Allocates a new classical bit register of the given size. Returns the register.

Parameters

size (int) – The number of classical bits to allocate.

Returns

A fresh classical bit register of size size

Return type

CRegister

cbreak(formula)

Conditional break. The program execution will stop if and only if the formula given as argument evaluates to 1.

Parameters

formula (BoolFormula) – a boolean formula

cc_apply(cbit, gate, *args)

Conditional application of a quantum gate. The quantum gate will be applied if and only if the control classical bit given as first argument evaluates to 1.

Parameters
  • ctrlbit (Cbit) – The classical bit

  • gate (Gate) – The quantum gate

  • *args – Variable length qbit list (see apply()).

comment(message)

Add a comment inside the circuit. The comment will appear in the AQASM export of the circuit.

Parameters

message (str) – a string containing the comment

conjugate(gate1, gate2, *args)

Apply a sequence of 3 gates. gate2 will be conjugated by gate1. The two gates are required to have the same arity.

Parameters
  • gate1 (Gate) – a gate

  • gate2 (Gate) – another gate

display(**kwargs)

Transforms the program into a circuit and displays it.

Parameters

kwargs – key word arguments passed to the display method of the circuit

export(fname)

Exports the Program in AQASM text format.

Parameters

fname (str) – A file name

free_ancillae(args)

Releases a set of ancillae

get_free_ancillae(size=1, class_name=None)

Returns a collection of free ancillae

logic(cbit, formula)

Performs a classical logic operation using classical bits and stores the result in a classical bit.

Parameters
  • cbit (Cbit) – the cbit that will store the result

  • formula (BoolFormula) – A boolean formula.

measure(qbits, cbits=None)

Applies a measurement operator. All measurements are \(Z\) measurements (i.e in the computational basis). Qbits are simply collapsed and not destroyed (i.e they are still usable afterward).

Parameters
  • qbits (list<Qbit>) – The qubits to measure specified as a list/register/array

  • cbits – (list<Cbit>, optional): The classical bits in which to store the result. Default to None. If defaulted/set to None, the results will be stored in classical bits with matching indices.

new_var(var_type, var_name)

Constructs a new variable bound to the circuit.

Parameters
  • var_type (type) – The type of the variable.

  • var_name (str) – The name of the variable. Raises a VariableNameNotAvailable if a variable with the same name is already bound to the circuit.

Returns

A variable

Return type

Variable

qalloc(size=1, class_type=None, **kwargs)

Allocates a new qbit register of the given size. Returns the register.

If no constructor is provided, the register will simply behave as an array of qubits.

The two implemented quantum types are QInt and QBoolArray.

from qat.lang.AQASM import Program, QInt, QBoolArray
prog = Program()
qbits = prog.qalloc(5)
print(qbits)
qint = prog.qalloc(5, QInt)
print(qint)
qbools = prog.qalloc(5, QBoolArray)
print(qbools)
QReg(q[0]..q[4])
QInt(q[5]..q[9])
QBoolArray(q[10]..q[14])

The main purpose of this wrapping process is to provide a higher level interface for some quantum register, depending on the application. This allows to generate complicated quantum circuits without having to deal with low level administrative constraints.

Parameters
  • size (int) – the number of qbits to allocate.

  • class_type (type) – the quantum type of the register

  • kwargs – any keyword argument is passed to the constructor of the quantum type

Returns

A fresh qbit register of size size

Return type

QRegister

reset(qblist, cblist=None)

Resets the value of a set of qbits to \(|0\rangle\). and/or a set of cbits to 0.

Parameters
  • qblist (list<Qbit>) – The list of qbits

  • cblist (list<Cbit>, optional) – The list of cbits. Default to [].

to_circ(include_matrices=True, include_locks=False, inline=False, do_link=True, comparison_eps=1e-20, box_routines=False, **kwargs)

Return a Circuit implementing the program.

The circuit extraction consists of three stages:

  • Circuit generation: a simple circuit is extracted from the Program object. Any call to an abstract gate will be left untouched. All circuit implementation attached to abstract gates definition will be ignored at this stage.

  • Linking: this simple circuit is then linked against:

    • the gate set aggregated by the program during its construction

    • any other gate set/abstract gate/python module passed as argument.

    The linking process simply attach to each abstract gate a circuit implementation using the function specified at definition of the abstract gate.

  • Inlining: these implementations are then inlined in place, turning the circuit into a (potentially) very long sequence of gates/operations. By default this step is skipped, as it is very demanding.

All these steps can be controlled using various parameters detailed below.

Parameters
  • include_matrices (bool, optional) – if set to True, matrices will be generated and included in the circuit. Defaults to True.

  • include_locks (bool) – If set to True, additional gates will be added on the ancilla wire to signify lock and release of the ancilla. Defaults to False. This can be used to debug ancilla usage or further optimize the circuit later on. Lock/release operations can be removed from the circuit via the .remove_locks() method.

  • do_link (bool) – if set to False, skips the linking step. Default to True.

  • inline (bool) – if set to False, no inlining/linking will happen. Default to False.

  • comparison_eps (float) – Optional argument to set the matrix/gate parameters comparison threshold. If two parameters are comparison_eps close, they will be considered as identical, resulting in the indentification of their correspondig gates (thus saving space and time). Default value is 1e-20.

  • box_routines (bool) – If set to True, routines will be systematically boxed before being included inside the initial circuit (the one generated during the Circuit generation step). Setting this option to True can save up a lot of time for repetitive circuits.

  • **kwargs – other arguments passed to the linker. See below.

Keyword Arguments
  • submatrices_only (bool) –

    if set to True, only submatrices will be generated and included in the circuit. Default to False.

    Warning

    Setting this argument to True will decrease (by a lot) the circuit generation time. For instance, using the default settings, a RZ rotation controlled 10 times will end up generating a matrix of size (\(2^{11} \times 2^{11}\)). By setting this argument to True, only a \(2\times 2\) matrix will be generated. However, not all simulators are able to infer a matrix from the structure of the gate. In particular, this means that you should set this option to True to simulate circuits on PyLinalg.

  • keep (list<str>) – if set to a list of gate names, these gates won’t be inlined by the linker. Default to None.

  • link (list) – a list of AbstractGate, GateSet, or python packages to pass to the linker.

Returns

A circuit implementing the program

Return type

Circuit

Gate structures

All classes describing unitary operators inherit from the Gate class. This parent class contains very little information. Its primary function is to store information about control, dagger and other high-level gate operations. Since this class is not made to be used directly, we skip some part of its documentation.

class qat.lang.AQASM.gates.Gate(arity, matrix=None, name=None)

Mother class for all quantum gates/unitary operators. This class should never be instantiated directly.

conj()

Builds a new gate that is the complex conjugate of the initial gate.

Returns

The conjugate of the gate.

Return type

Gate

ctrl(nbctrls=1)

Builds a new gate that is a controlled version of the initial gate.

Returns

The same gate, but controlled.

Return type

Gate

dag()

Builds a new gate that is the dagger of the initial gate.

Returns

The dagger of the gate.

Return type

Gate

trans()

Builds a new gate that is the transpose of the initial gate.

Returns

The transpose of the gate.

Return type

Gate

Another important class is the AbstractGate class. This class provides a way to define new parametrized gates. Basically, an abstract gate describes a family of gates parametrized by a list of values of various types. The current list of admissible types contains: int, float, str

For instance, to declare a new AbstractGate that describes a \(R_z\) rotation, we would write:

my_rz = AbstractGate("RZ", [float], arity=1)

and use this new abstract gate as follows:

my_rz(0.4)(qbits_reg[0])

It is possible to attach a matrix generator to the abstract gate in order to generate and include a matrix in the final circuit (if you want to be able to simulate the circuit for instance).

def matrix_gen(theta):
    return np.array([[1, 0], [0, np.exp(1j * theta)])

my_rz = AbstractGate("RZ", [float], arity=1,
                     matrix_generator=matrix_gen)
class qat.lang.AQASM.gates.AbstractGate(*args, **kwargs)

Warning

This class is for advanced usage.

Abstract gate class. Abstract gates are used to define gate constructors such as Rx, Ry, Rz, etc.

They behave as quantum gate constructing functions.

This class extends qat.core.gate_set.GateSignature.

set_dag(func)

Attaches a dagger recipe to the abstract gate. The function passed as argument should:

  • take as argument a sequence of parameters

  • return a new sequence of parameters corresponding to the dagger of the gate.

my_rz = AbstractGate("MY_RZ", [float])
my_rz.set_dag(lambda theta: [-theta])

This function will be called when a .dag() method is called on some ParamGate.

If the dag is not set, the abstract gate will make no assumption on the structure of the dagger, and the standard recursive structure from Gate will be used.

ParamGate is generated through AbstractGate. An abstract gate instantiated by a set of parameters (such as the my_rz(0.4) from above) returns a ParamGate carrying all the necessary information to build the correct abstract syntax tree of the gate.

class qat.lang.AQASM.gates.ParamGate(abstract_gate, arity, *parameters)

Class for parametrized gates instantiated by some set of parameters. Members of this class should be automatically instantiated by the AbstractGate structure. Only instantiate if you know what you are doing.

Parameters
  • abstract_gate (AbstractGate) – the mother abstract gate

  • arity (int) – the arity of the gate (can be set to None)

  • *parameters (list<any>) – the list of parameters of the gate

dag()

Builds a new gate that is the dagger of the initial gate.

Returns

The dagger of the gate.

Return type

Gate

display(**kwargs)

Displays the param gate (if the gate has a circuit generator).

Parameters

kwargs – key word arguments passed to the display method of the circuit

Finally, the notion of gate is also extended to subcircuits via the QRoutine class.

class qat.lang.AQASM.routines.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(length=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.

Quantum Types

Quantum boolean and expressions

class qat.lang.AQASM.qbool.QBool(index, scope=None)

Class for quantum boolean type.

This class is not designed to be instantiated by hand, but rather via the .qalloc method of the Program class or the .new_wires method of the QRoutine class.

Moreover, since allocation happens at the register level, the QBoolArray class should be used.

from qat.lang.AQASM.qbool import QBoolArray
from qat.lang.AQASM import QRoutine

rout = QRoutine()
qbool_array = rout.new_wires(2, QBoolArray)
print(type(qbool_array))
print(type(qbool_array[0]))
<class 'qat.lang.AQASM.qbool.QBoolArray'>
<class 'qat.lang.AQASM.qbool.QBool'>

See documentation of the QClause class for more information.

Parameters
  • index (int) – the qubit index

  • scope (Program/QRoutine) – the scope in which the allocation happened

Instance attributes:

  • index (int): the index of the underlying qbit

  • scope (Program/QRoutine): the scope in which the underlying qbit was declared

cast(val)

Cast an integer value as a boolean.

This method is used when casting execution samples to proper python values.

Parameters

val (int) – some integer

Returns

a boolean value

Return type

bool

cast_to(cls, **kwargs)

Cast the register to another type.

Parameters

cls (type) – another quantum type class

Returns

some object constructed via cls

Return type

object

For instance, the following piece of code casts a quantum boolean to a quantum integer:

from qat.lang.AQASM.qbool import QBoolArray
from qat.lang.AQASM.qint import QInt
from qat.lang.AQASM import QRoutine

rout = QRoutine()
array = rout.new_wires(2, QBoolArray)
qbool = array[0]
qint = qbool.cast_to(QInt)
evaluate(output=None)

Evaluate the QBool as an expression. Since QBools are trivial expression, this simply returns self and the output argument is ignored (it is here simply for compatibility with more complicated expressions).

Parameters

output (Qbit) – an optional output qubit (ignored)

Returns

a QBool object

Return type

QBool

phase()

Flips the phase of the state if and only if the QBool is set to True. Effectively applies a \(Z\) gate on self.

qbits_list()

Returns the list of underlying qubits (i.e [self])

class qat.lang.AQASM.qbool.QBoolArray(start=0, length=1, scope=None, qbits_list=None)

Class describing an array of QBool.

This class is not designed to be instantiated by hand, but rather via the .qalloc method of the Program class or the .new_wires method of the QRoutine class.

See documentation of the QClause class for more information.

from qat.lang.AQASM.qbool import QBoolArray
from qat.lang.AQASM import QRoutine

rout = QRoutine()
qbool_array = rout.new_wires(2, QBoolArray)
print(type(qbool_array))
<class 'qat.lang.AQASM.qbool.QBoolArray'>
Parameters
  • start (int) – the starting index of the underlying register

  • length (int) – the length of the underlying register

  • scope (Program/QRoutine) – the scope in which the allocation happened

  • qbit_list (list of int) – optionally a list of indexes of underlying qbits

Instance attributes:
  • index (int): the index of the underlying qbit

  • qbits (list of QBool): a list of quantum booleans

cast(val)

Cast some integer value as a list of bools.

This method is used when casting execution samples to proper python values.

Parameters

val (int) – some integer

Returns

a list of boolean values

Return type

list of bools

evaluate()

Evaluates the register as a boolean expression (i.e does nothing and returns a list of the underlying qubits).

Returns

a list of quantum booleans

Return type

list of QBool

qbits_list()

Returns the list of underlying qubits.

Returns

a list of quantum booleans

Return type

list of QBool

class qat.lang.AQASM.qbool.QClause(scope, operator, operand=None)

Class describing boolean formulae to manipulate qubits.

This class is not designed to be instantiated by hand.

Clauses are created by using the boolean operators (and, or, xor, neg) applied on (an)other formula(e) or qubits. Qubits are implicitly cast toward boolean formulae.

Example:

from qat.lang.AQASM import QRoutine
from qat.lang.AQASM.qbool import QBoolArray

rout = QRoutine()
wires = rout.new_wires(2, QBoolArray)

and_formula = wires[0] & wires[1]
print(type(and_formula))
<class 'qat.lang.AQASM.qbool.QClause'>

A formula should be manipulated via:

  • the .evaluate method, in order to compute its value in superposition

  • the .phase method in order to perform a phase flip of all the basis states that evaluate the formula to true

  • a with statement (see the example below)

Example of evaluate:

from qat.lang.AQASM import QRoutine
from qat.lang.AQASM.qbool import QBoolArray

rout = QRoutine()
wires = rout.new_wires(2, QBoolArray)

and_formula = wires[0] & wires[1]

# By directly allocating an ancilla
result = and_formula.evaluate()

# Or by prior allocation of a result qubit
result = rout.new_wires(1)
and_formula.evaluate(output=result)

# At this stage, `result` carries the logical AND between our two inputs

Example of phase:

from qat.lang.AQASM import QRoutine
from qat.lang.AQASM.qbool import QBoolArray

rout = QRoutine()
wires = rout.new_wires(2, QBoolArray)

and_formula = wires[0] & wires[1]

and_formula.phase()
# At this stage, all classical states such that the first two qubits
# are set to 1 have their phase flipped

Example of with statement conditional:

from qat.lang.AQASM import QRoutine, CNOT
from qat.lang.AQASM.qbool import QBoolArray

rout = QRoutine()
wires = rout.new_wires(2, QBoolArray)

and_formula = wires[0] & wires[1]
output = rout.new_wires(1)

with and_formula as condition:
    CNOT(condition, output)

# We evaluated the expression, got a qbit `condition` carrying the result
# and store the result in `output`
evaluate(output=None)

Builds a circuit evaluating the expression.

Parameters

output (optional, Qbit) – an output qbit

Returns

a quantum boolean carrying the

result of the evaluation

Return type

Qbit

phase()

Flips the phase if and only if the expression/qbits evaluates to True.

qbits_list()

Returns a list of underlying qbits.

Returns

a list of qbits

Return type

list of Qbits

Quantum integers

class qat.lang.AQASM.qint.QInt(start=0, length=1, scope=None, reverse_bit_order=False, qbits_list=None)

Class for quantum integer type. The qubit list in a QInt is by default encoded such that the most significant bit is on the left. The order can be reversed using the reverse_bit_order argument.

As other quantum types, this class is not designed to be constructed by hand, but rather via the .qalloc method of the Program class or the .new_wires method of the QRoutine class.

Example:

from qat.lang.AQASM.qint import QInt
from qat.lang.AQASM import QRoutine

rout = QRoutine()
qint = rout.new_wires(10, QInt)
print(qint, type(qint))

# or, with reversed bit order:
qint = rout.new_wires(10, QInt, reverse_bit_order=True)
QInt(q[0]..q[9]) <class 'qat.lang.AQASM.qint.QInt'>

Quantum integers have two sets of overloaded operators:

  • arithmetic operators (+ and *): combine QInt and/or QArithExp to produce a QArithExp. See documentation of QArithExp for more details.

  • comparison operators (<,>,<=,>=,==,!=): combine a QInt/QArithExp and or a classical int in order to produce a comparison expression, QCompExp, that behave similarly to a QClause and can be thus used to construct oracles or conditionals.

Moreover, the += and -= operators are also overloaded and triggers a circuit evaluating the right-hand term and adding it to the quantum integer.

from qat.lang.AQASM.qint import QInt
from qat.lang.AQASM import QRoutine

rout = QRoutine()
qint1 = rout.new_wires(10, QInt)
qint2 = rout.new_wires(10, QInt)
qint3 = rout.new_wires(10, QInt)

# This does nothing
qint1 + qint2

# This generates a circuit that adds qint1 in qint3 and qint2 in qint3
qint3 += qint1 + qint2

# This generates a circuit that adds -qint1 in qint3 and -qint2 in qint3
qint3 -= qint1 + qint2

Comparisons results can be used exactly as QClause:

from qat.lang.AQASM.qint import QInt
from qat.lang.AQASM import QRoutine

rout = QRoutine()
qint1 = rout.new_wires(10, QInt)
qint2 = rout.new_wires(10, QInt)

# Flips the phase of states such that qint1 is smaller than 3
(qint1 < 3).phase()

# Flips the phase of states such that qint1 + qint2 is smaller than 14
(qint1 + qint2 < 14).phase()
Parameters
  • start (int) – the start index of the underlying register

  • length (int) – the length of the integer

  • scope (Program/QRoutine) – the scope in which the allocation happened

  • reverse_bit_order (bool) – if set to True, reverse the bit order of the integer.

Instance attributes:

  • scope (Program/QRoutine): the scope in which the underlying qbit was declared

cast(val)

Casts some integer value into some other integer value with the correct bit-order. This is used when casting execution samples.

Parameters

val (int) – some integer

evaluate(nbqbit=None)

Evaluate the QInt as a formula. Effectively does nothing and returns a copy of self.

qbits_list()

Returns the underlying list of qubits.

Returns

a list of quantum booleans

Return type

list of Qbit

set_value(val)

Sets the QInt to some classical value.

Note

This method assumes that the QInt is unitialized (i.e is still in state \(|0\rangle\)). Effectively, the register is xored with the classical value.

Parameters

val (int) – some integer value

class qat.lang.AQASM.qint.QArithExp(scope, operator, operands=None, reverse_bit_order=True)

Class describing arithmetic expressions whose operands contain quantum integers.

This class is not designed to be instantiated by hand, but rather built via the addition, substraction, and multiplication of quantum integers with other quantum integers or python integers.

from qat.lang.AQASM import QRoutine, QInt

rout = QRoutine()
qint = rout.new_wires(10, QInt)
print(type(qint + 33))
<class 'qat.lang.AQASM.qint.QArithExp'>
evaluate(nbqbit=None)

Builds a piece of circuit evaluating the arithmetic expression.

Parameters

nbqbits (optional, int) – the number of qbits of the output register.

class qat.lang.AQASM.qint.QCompExp(scope, operator, left, right)

Class describing quantum comparison expressions to manipulate quantum integers.

This class is not designed to be instantiated by hand, but rather built via comparison of quantum integers (with other quantum integers or classical values) using the standard comparison operators.

from qat.lang.AQASM import QRoutine, QInt

rout = QRoutine()
qint = rout.new_wires(10, QInt)
print(type(qint < 33))
<class 'qat.lang.AQASM.qint.QCompExp'>
evaluate(output=None)

Evaluates the comparison operator and stores the result in a temporary Qbit.

Parameters

output (optional, Qbit) – an optional output qubit. If no output is specified, a temporary Qbit will be used and returned.

Returns

the output qbit

Return type

Qbit

phase()

Flips the phase if and only if the expression evaluates to True.

qbits_list()

Returns the underlying list of qubits

Other structures

class qat.lang.AQASM.bits.Qbit(index, scope=None)

Class for qbits.

class qat.lang.AQASM.bits.QRegister(offset, length=1, scope=None, qbits_list=None)

Class for registers of qbits. They should only be declared through the qalloc method of the Program class. Qbits inside a register can be accessed similarly to elements of an array (i.e using brackets and slices).

class qat.lang.AQASM.bits.CRegister(offset, length=1)

Class for registers of classical bits. They should only be declared through the calloc method of the AQASM class Cbits inside a register can be accessed similarly to elements of an array (i.e using brackets and slices).

Classical bits and Boolean formulae

class qat.lang.AQASM.bits.Cbit(index)

Class for cbits.

Cbits can be composed via logical operator to form Boolean formulae.

See BoolFormula for examples.

Parameters

index (int) – the index of the classical bit

class qat.lang.AQASM.bits.BoolFormula(operator, left, right=None)

Class describing boolean formulae to manipulate classical bits.

This class is not designed to be instantiated by hand, but rather via composition of Cbit via logical operators.

Formulae are created by using the classical boolean operators (and, or, xor, neg) applied on (an)other formula(e) or classical bits.

from qat.lang.AQASM import Program

prog = Program()
cbits = prog.calloc(2)

and_expr = cbits[0] & cbits[1]
print(type(and_expr))
print(and_expr)
<class 'qat.lang.AQASM.bits.BoolFormula'>
(c[0] & c[1])

These objects are used in various pyAQASM instructions.

cbits_list()

Returns the list of cbits appearing in the formula.

Returns

a list of Cbit

Return type

list

to_thrift()

Returns a thrift compatible string representation of the formula.

This method is called in order to produce a seralizable representation of the expression.

Returns

a string representation of the formula

Return type

str

Exceptions

This exception is defined in qat.core but related to qat.lang:

class qat.core.circuit_builder.builder.VariableNameNotAvailable(name)

Exception raised when a variable is redefined using the same name.

Utilities

This module contains a few utilitaries

qat.lang.AQASM.util.suppr_ctrl(rout, depth=1)

Builds a functionally equivalent quantum routine such that no gate in this routine has more that “depth” control qbits. It uses an ancillary register to Toffoli-fold the control qbits. The number of ancillas to add is (in the worst case) equal to (maximum number of ctrl to remove) -1.

Parameters
  • rout (QRoutine) – a quantum routine

  • depth (int, optional) – the maximal number of control to tolerate (default = 1)

Returns

a quantum routine

Return type

QRoutine

qat.lang.AQASM.util.toffoli_fold(nb_qbits)

Returns a quantum routine that, given a data register of length \(n\) and an ancilla register, applies Toffoli gates on the data register in order to compute a logical AND of all its qbits inside a single ancillary qbit. May use up to \(n-1\) ancillary qbits (worst case scenario). The resulting qbits is always the last qbit (hence of index arity - 1).

Parameters

nb_qbits (int) – the size of the register to fold

Returns

a quantum routine performing the fold

Return type

QRoutine

Gate set management and generation

This module contains various tools and decorator to turn functions into gates

class qat.lang.AQASM.misc.build_gate(name, signature, arity=None)

A wrapper class lifting functions into AbstractGates with a circuit implementation.

Parameters

func (function) – an annotated function returning a QRoutine

Note

Calling the decorated function will return an AbstractGate.

The underlying QRoutine can be referred to by using a tilde before the function:

@build_gate
def my_gate(a : int) -> 'FOO':
    rout = QRoutine()
    return rout

my_gate(10) # will return an AbstractGate object, instantiated
            # with parameter 10
(~my_gate)(10) # will return a QRoutine object
qat.lang.AQASM.misc.generate_gate_set(*args, safe=False)

Generates a gate set from a list of various arguments. Arguments can be:

  • GateSignature/AbstractGates

  • build_gates wrappers

  • python modules

In this case it iterates through its scope and gathers all the build_gate objects (i.e all the decorated functions).

Quantum libraries

Linker and low level circuit manipulation

In pyAQASM, gates can be specified using various representations. They can be purely abstract (a name and a set of parameter values, such as RZ, [PI/2]). To this abstract syntax, one can attach a matrix, or even a subcircuit that implements this gate (this is the case of adders of the arithmetic library for instance).

Circuits are generated in two steps: - first a skeleton of the circuit is generated (for instance adders will be gates called ADD in this skeleton) - then a subcircuit is generated and attached to this abtract gate.

This second step is handled by a class called Linker. It can be useful in some settings to manipulate this Linker object in order to replace gates by subcircuits, or to generate matrices in order to simulate the circuit.

class qat.lang.linking.linker.Linker(gate_set=None, include_matrices=True, keep=None, link=None, submatrices_only=False, inline=False, include_locks=False)

The purpose of a linker is to crawl a circuit and attach implementations to gates. These implementations are specified via a GateSet object (more or less a collection of AbstractGate).

The main method of this class is the .link method.

The following example uses a linker to replace CNOT gates by H and CZ gates:

from qat.lang.AQASM import *
from qat.core.gate_set import GateSet
from qat.lang.linking.linker import Linker

prog = Program()
qbits = prog.qalloc(2)
CNOT(qbits)
circuit = prog.to_circ()

@build_gate('CNOT', [], arity=2)
def my_cnot_implementation():
    rout = QRoutine()
    wires = rout.new_wires(2)
    with rout.compute():
        H(wires[1])
    CSIGN(wires)
    rout.uncompute()
    return rout

# We initialize a Linker with an empty gate set since we want
# to override the default CNOT implementation
linker = Linker(gate_set=GateSet())
linker.add_signature(my_cnot_implementation)

print("Before linking:")
for op in circuit.iterate_simple():
    print(op)

linker.link(circuit)
print("After linking:")
for op in circuit.iterate_simple():
    print(op)
Before linking:
('CNOT', [], [0, 1])
After linking:
('H', [], [1])
('CSIGN', [], [0, 1])
('H', [], [1])
Parameters
  • gate_set (GateSet) – A gate set to start the linking with. Optional. Defaults to the default pyAQASM gate set.

  • include_matrices (bool, optional) – if set to True, matrices will be generated and included in the circuit. Defaults to True.

  • keep (list<str>) – if set to a list of gate names, these gates will be skipped by the linker. Default to None.

  • link (list) – a list of AbstractGate, GateSet, or python modules to pass to the linker.

  • submatrices_only (bool) – if set to True, only submatrices will be generated and included in the circuit. For instance a CTRL(Y) will only generate the matrix for Y, thus saving memory. Default to True.

  • inline (bool, optional) – if set to True, subcircuit implementations will be inlined in the main body of the circuit. This might increase the memory footprint of the circuit and linking cost. Default to False.

  • include_locks (bool, optional) – if set to False, removes all lock/release operators after the linking process. If set to True, these operators will remain. These operators are here for debug purpose only. Defaults to False.

add_signature(gate_signature)

Adds a gate signature to the current gate set of the Linker. This gate should not be present in the current gate set.

Parameters

gate_signature (GateSignature) – a gate signature

clear_gate_set(default_gates=True)

Resets the content of the internal gate set of the Linker.

Parameters

default_gates (bool) – If set to True, the default gate set of pyAQASM will be included in the fresh gate set. Optional. Defaults to True.

compile(batch, _specs)

Compiles a Batch into another Batch according to some hardware specs

Uses the internal gate set of the Linker to link gate implementations.

Warning

The linking happens in place (thus modifies the input circuit).

Parameters

circuit (qat.core.Circuit) – a quantum circuit

Uses the internal gate set of the Linker to instantiate the gates of a circuit.

Warning

The linking happens in place (thus modifies the input circuit).

Parameters

circuit (qat.core.Circuit) – a quantum circuit

Link the matrix implementations to the gate definitions of a circuit.

Warning

The linking happens in place (thus modifies the input circuit).

Parameters

circuit (qat.core.Circuit) – a quantum circuit

set_gate_set(gate_set)

Overrides the internal gate set with a new gate set.

Parameters

gate_set (GateSet) – a gate set

Basic algorithms

There are a few basic algorithms present in the qat.lang.algorithms module:

qat.lang.algorithms.amplification_step(oracle, state_prep=None)

Builds a routine that performs a single amplification step. By default the diffusion operator is Grover’s diffusion.

If the state_prep argument is specified, it will be used to perform the following Householder transform instead:

\[2\left(U|0\rangle\langle 0|U^\dagger\right) - I\]

where \(U\) is the unitary operator implemented by state_prep.

This method can be used to easily build a Grover search program:

from qat.lang.AQASM import Program, QInt, QRoutine, H
from qat.lang.algorithms import amplification_step


nbits = 2

oracle = QRoutine()
reg1 = oracle.new_wires(nbits, QInt)
reg2 = oracle.new_wires(nbits, QInt)
(reg1 == reg2).phase()

step = amplification_step(oracle)

grover = Program()
reg1 = grover.qalloc(nbits, QInt)
reg2 = grover.qalloc(nbits, QInt)
for qbit in reg1:
    H(qbit)
for qbit in reg2:
    H(qbit)
for _ in range(1):
    step(reg1, reg2)
job = grover.to_circ().to_job(qubits=[reg1, reg2])

from qat.qpus import get_default_qpu
qpu = get_default_qpu()

result = qpu.submit(job)
for sample in result:
    print(sample.state.value, sample.probability)
(0, 0) 0.24999999999999956
(1, 1) 0.24999999999999956
(2, 2) 0.24999999999999956
(3, 3) 0.24999999999999956
Parameters
  • oracle (Gate) – a quantum gate or routine implementing the oracle

  • state_prep (optional, Gate) – a quantum gate or routine

Returns

a routine

Return type

QRoutine

qat.lang.algorithms.phase_estimation(operator, nbits)

Generates a routine that performs phase estimation of some unitary operator.

The number of qubits of the resulting routine is \(n+k\) where \(n\) is the arity of operator and \(k\) is nbits. The routine assumes that the first \(n\) qubits are already prepared and contain the states on which the phase estimation should be performed. The result will be stored in the last \(k\) qubits.

Parameters
  • operator (Gate) – a quantum gate or routine

  • nbits (int) – the number of bits to store the result in

Returns

a routine

Return type

QRoutine

qat.lang.algorithms.quantum_counting(oracle, nbits, prepare=True)

Performs a quantum counting on some oracle.

The number of qubits of the resulting routine is \(n+k\) where \(n\) is the arity of oracle and \(k\) is nbits. The routine assumes that the first \(n\) qubits are already prepared and contain the states on which the counting should be performed. The result will be stored in the last \(k\) qubits.

Parameters
  • oracle (Gate) – a quantum gate or routine implementing the oracle

  • nbits (int) – the number of bits to store the result in

  • prepare (optional, bool) – if set to False, omits the preparation of the data register. Defaults to True.

Returns

a routine

Return type

QRoutine

Additionally, the submodule qat.lang.algorithms.amplification contains some functions that might be useful:

qat.lang.algorithms.amplification.uniform_distribution(nbits)

Prepares a uniform distribution from state \(|0\rangle\)

Parameters

nbits (int) – the number of qbits

Returns

a routine

Return type

QRoutine

qat.lang.algorithms.amplification.householder(state_prep)

Given some state preparation circuit implementing a unitary operator \(U\), builds a Householder transform of the form:

\[2\left(U|0\rangle\langle 0|U^\dagger\right) - I\]
Parameters

state_prep (Gate) – a quantum gate or routine

Returns

a routine

Return type

QRoutine

qat.lang.algorithms.amplification.grover_diffusion(nbits)

An implementation of Grover’s diffusion.

The returned routine implements the following Householder transform:

\[2|s\rangle\langle s| - I\]

where \(|s\rangle\) is the uniform distribution.

Parameters

nbits (int) – the arity of the diffusion

Returns

a routine

Return type

QRoutine