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 anotherQRoutine
or aProgram
. A routine can also be built by using theqrout()
decoratorThe
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
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
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 operationsarithmetic
provides a unified interface for all arithmetic operations