Gate-based programming

The Qaptiva 800s provides a powerful semantic to create your own quantum circuit / job. Qaptiva defines several type of objects one could use to define a quantum circuit, these tools are accessible from the qat.lang module:

  • The QRoutine class defines a sequence of pure quantum gates. These quantum routines can be used to build another QRoutine or a Program. A routine can also be built by using the qrout() decorator

  • The Program class defines a sequence of instructions that will be executed on the QPU. These instructions can be purely quantum (a quantum gate), hybrid (e.g. intermediate measurement returning a classical value, a quantum gate controlled by a classical bit) or purely classical (e.g. bit operations)

  • The qfunc() decorator defines a quantum job wrapped inside a function. This decorator is used to create a quantum routine by using the same syntax as a Python function

Quantum Programs (and Quantum Routines built without the qrout() decorator) must be compiled into a Circuit object. The Circuit class provides a nice API to manipulate the sequence of instructions. Usually, Circuit are directly fed to QPUs via a Python interface

Please note that this framework can be used to define a combinatorial problems from which QAOA instances can be generated. This feature is discussed in another section of the documentation

Creating a custom quantum circuit

A pure quantum circuit is a Quantum Routine. These objects can be built using QRoutine or the qrout() decorator.

This decorator is used to build a quantum routine using a Python function. This Python function executes the quantum gates one by one. For instance, a Bell pair can be created using:

from qat.lang import qrout, H, CNOT

@qrout
def bell_pair():
    H(0)
    CNOT(0, 1)

This quantum routine can then be displayed, as any quantum circuit:

bell_pair.display(batchmode=True)
 ┌─┐   
─┤H├─●─
 └─┘ │ 
     │ 
    ┌┴┐
────┤X├
    └─┘
       

A quantum program provides tools to create advanced quantum circuits. These circuits can be composed of intermediate measurement, classical instructions, etc. Quantum bits and Classical bits must be allocated manually. For instance:

from qat.lang import Program, H, CNOT

prog = Program()
qbits = prog.qalloc(2)  # Allocate 2 qubits
H(qbits[0])
CNOT(qbits[0], qbits[1])

circ = prog.to_circ()
circ.display(batchmode=True)
 ┌─┐   
─┤H├─●─
 └─┘ │ 
     │ 
    ┌┴┐
────┤X├
    └─┘
       

A quantum circuit can be wrapped into a Python function. This Python function executes the quantum gates one by one and returns a list of qubits or an Observable (if a list of qubits is returned, these qubits are sampled; if an Observable is returned, this observable is measured)

from qat.lang import qfunc, H, CNOT

@qfunc
def bell_pair():
    H(0)
    CNOT(0, 1)

    return [0, 1]

for sample in bell_pair():
    print(f"State {sample.state} amplitude {sample.amplitude}")
State |00> amplitude (0.7071067811865475+0j)
State |11> amplitude (0.7071067811865475+0j)
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)

In this example, this function performs a call to the default QPU to simulate the quantum circuit

Creating and adding quantum gates to a circuit
Creating variational circuits
Quantum programs
Quantum routines (and Oracles)
Atos Quantum Assembler (AQASM)

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