MyQLM provides different tools and approaches to design your own quantum circuits.

The main component is a Python library for building quantum circuits, called PyAQASM (Python + Atos QASM).

The following picture gives an overview of the circuit generation process from the PyAQASM library.

images/circuit_gen.png

Quantum circuits can be stored under two formats:

  1. in a serialized format (.circ) - it is under this format that circuits are sent to simulation or optimization services, when command-line tools are used

  2. as .aqasm text files (human readable)

Therefore, there are two ways to generate a .circ file from a Program instance by:

  1. directly generating a Circuit instance and serializing it (right path in the figure)

  2. exporting your program to an .aqasm text file (human readable text format), and compiling it using the command-line tool aqasm2circ (left path in the figure)

Since the core of the QLM is purely based on Python, serialization is NOT a mandatory step, and is here only to facilitate advanced applications. Usually the Circuit objects are directly fed to QPUs via a Python interface (see documentation of qat-core for examples).

If you still need a text format to describe your quantum circuits, please refer to the AQASM section : The AQASM format.

Writing quantum circuits

The pyAQASM library (qat.lang.AQASM) provides a high-level interface to design quantum circuits.

The central class of this library is Program . This class provides an interface to build and generate a Circuit object.

from qat.lang.AQASM import Program
my_program = Program()

Allocating qubit and classical registers:

Qubit registers are allocated by the Program using the qalloc() method.

qbits_reg = my_program.qalloc(10)

Similarly, registers that hold classical bits can be allocated using the calloc() method.

cbits_reg = my_program.calloc(10)

Quantum gates

Native gates, controls and daggers

The pyAQASM library provides a basic gate set to write your programs. Their names are rather self-explanatory:

  • Constant gates: X, Y, Z, H, S, T, CNOT, CCNOT, CSIGN, SWAP, SQRTSWAP, ISWAP

  • Parametrized gates: RX, RY, RZ, PH (phase shift)

(The mathematical definition of these gates is given in The AQASM format.)

These gates can be applied to the qubits from the qubit register:

CNOT(qbits_reg[0], qbits_reg[1])
H(qbits_reg[2])
RZ(np.pi/2.)(qbits_reg[0]

From this initial gate set, one can also build new gates using control and dagger operations:

PH(np.pi/2).ctrl()(qbits_reg[0], qbits_reg[1])
RX(np.pi/4).dag()(qbits_reg[0])

Of course, controls can be stacked:

PH(np.pi/2).ctrl().ctrl().ctrl()(qbits_reg[0:4])

By convention, the outermost control qubit is always the first argument in when calling a gate.

# Here qbits_reg[0] is the control qbit:
H.ctrl()(qbits_reg[0], qbits_reg[2])
# And here, qbits_reg[0] and qbits_reg[2] are the controls:
H.ctrl().ctrl()(qbits_reg[0], qbits_reg[2], qbits_reg[9])

Defining new parametrized gates: Abstract Gates

One might want to define new family of gates parametrized by some angle, or even by some vector (think about state preparation for instance). This can be done through the AbstractGate class.

Your code would look like this:

# A new 1-qbit gate parametrized by 2 angles
C = AbstractGate("C", [float, float], arity=1)

C(np.pi/2, np.pi/4)(qbits_reg[0])

Of course, you can also provide a way to generate the matrix corresponding to the gate:

def c_matrix(theta, phi):
    return np.cos(theta/2) * I - 1j * np.sin(theta/2) * (np.cos(phi) * X + np.sin(phi) * Y)

C = AbstractGate("C", [float, float],
                 arity=1,
                 matrix_generator=c_matrix)

The resulting circuit contains the matrix and can be simulated on most of the available simulators in the QLM.

Custom gates

Warning

Custom gates are deprecated. Consider using constant valued AbstractGate instead (defined in the previous section).

PyAQASM offers the possibility to define your own gates from a matrix. This is done via the CustomGate class.

mat = np.array([[-1, 0], [0, 1]])
my_minus_z = CustomGate(mat)
my_minus_z(qbits_reg[0])

Quantum routines

PyAQASM provides a structure to describe subcircuits that can then be used as quantum gates. This interface is provided by the QRoutine object. Inside these routines, qubits are inexistant: a routine is just a gate, thus it only knows about the incoming/outgoing wires. Wires are referred to using integers. The arity of the routine is updated dynamically depending on the used wires.

my_routine = QRoutine()
wires = my_routine.new_wires(2)
H(wires[0])
CNOT(wires)

my_routine(qbits_reg[0], qbits_reg[1])

# Since QRoutine are Gates, one can control/dagger them
my_routine.ctrl()(qbits_reg[0:3])
my_routine.dag()(qbits_reg[0:2])

Other operations

The Program structure supports various instructions:

  • measure(): measure a qubit during the computation (not to be used for final measurements)

  • reset(): reset a qubit or classical bit: it consists in measuring the qubit, and applying a bit flip (X gate) if the outcome is 1

  • cc_apply(): apply a gate conditionally, depending on the state of a classical bit

  • cbreak(): interrupt the computation depending on a condition on a set of classical bits

Quantum routine librairies

Some submodules of the pyAQASM library provide high-level routines or algorithms:

  • qftarith provides QFT-based implementation of various arithmetic operations (including QFT itself)

  • classarith provides carry-arithmetic operations

  • arithmetic provides a unified interface for all arithmetic operations

Generating the circuit

Once you are satisfied with your Program, it can be exported to a circuit format that can be simulated. This is done using the to_circ() method. This method has parameters and can be fine-tuned to meet your needs. Please refer to the source code documentation for more information.

Exporting the circuit

The Program object can also be exported to a human-readable AQASM format. This is done using the export() method.

More advanced usage

Please refer to section Advanced programming using pyAQASM for more features.