AQASM is a low level (assembly-like) programming language for universal quantum circuits. It is a common low-level language that can be used in conjunction with our compiler to generate circuit binaries.
An AQASM program must follow the structure:
<definition section>
BEGIN
<program section>
END
The definition section contains all explicit gate definitions. The program section contains the list of gate operations (aka instructions).
The program section should start with the allocation of quantum and classical bits. If you do not allocate the qubits and cbits, the compiler will automatically allocate them during the build process.
qubits <n>
n
is a positive integer number which defines the total number of qubits.
Addressing qubit(s):
q[k]
can be used to address a qubit (q
is a reserved keyword)
cbits <n>
Addressing cbits:
c[k]
Classical bits can be:
$\forall \theta \in\rm I\!R:$ \begin{vmatrix} 1 & 0 \\ 0 & e^{i\theta} \\ \end{vmatrix} |
|||
|
|||
|
|||
$\forall \theta \in\rm I\!R:$ \begin{vmatrix} \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) ~\\ -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) \\ \end{vmatrix} |
|||
$\forall \theta \in\rm I\!R:$ \begin{vmatrix} \cos(\frac{\theta}{2}) & -\sin(\frac{\theta}{2}) ~\\ \sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) \\ \end{vmatrix} |
|||
$\forall \theta \in\rm I\!R:$ \begin{vmatrix} e^{-i\frac{\theta}{2}} & 0 \\ 0 & e^{i\frac{\theta}{2}} \\ \end{vmatrix} |
|||
The following example is a circuit building a Bell pair:
BEGIN
qubits 2
H q[0]
CNOT q[0], q[1]
END
Quantum control:
CTRL (<gate>) <operand>(, <second operand>, ...)
The control qubit is always the first operand Classical control:
?<cbit_operand>: <gate> <operand>
A measurement result is stored in a specified cbit. If no cbit is specified, the default is to store the measurement in the same cbit id as the measured qbit.
A measured qubit remains intact, unlike some other quantum simulators that flatten a measured qubit into a classical bit. The qubit holds the pure state $|0\rangle$ or $|1\rangle$, depending on the measurement results.
Syntax:
MEAS <operand>(,...,<operand_n>) ( <cbit_operand>,..<cbit_operand_n>)
Examples:
MEAS q[2],q[0] c[0],c[1]
MEAS q[2]
Quantum rotation in X,Y, and Z are provided, with an input parameter in radians. Syntax:
RX[<angle>]
RY[<angle>]
RZ[<angle>]
where angle is a valid numeric expression. Recognized operators: +,-,/,*,%,^, as well as scientific notation. For convenience, the PI constant is also recognized.
Examples:
RX[3*PI/4]
RY[4.3e-3/1.6^0.5)
RZ(PI/2.0)
This is a family of single-quibt gates that leave the base state $|0\rangle$ unchanged and map $|1\rangle$ to $e^{i\phi}$|1\rangle. The probability of measuring a $|0\rangle$ or $|1\rangle$ is unchanged after applying this gate, however it modifies the phase of the quantum state. This is equivalent to tracing a horizontal circle (a line of latitude) on the Bloch sphere by $\phi$ radians.
Syntax:
PH[<angle>]
Example:
PH[3*PI/4]
The reset operator re-initializes a qubit to the $|0\rangle$ state. syntax:
RESET<operand>(,...,<operand_n>)
cbits can be combined with boolean operations, using the classical C-like bitwise operators: |,&,^,~. + is also synonym of |, * of &. Direct assignment to a fixed value 0 or 1 is also possible.
syntax:
LOGIC <cbit_operand> <logic formula>
Examples:
LOGIC c[2] 0
LOGIC c[0] (c[1]|c[2)&(c[3]|^c[4])
We introduce a new feature, not common in other QASM-style languages called the conditional break.
If a classical (boolean) condition evaluates to true, the quantum program stops. This can be either because we completed the simulation with a satisfying result or conversely that the current state has become unstable and needs to be discarded. For example the previous measurements lead to projected states that are out of interest.
Syntax:
BREAK[IF] <logic formula>
Example:
BREAKIF c[1] & c[2]
In AQASM, the basis for gate definition is the underlying unitary matrix. New gates can be defined by providing values for the matrix directly. In case the matrix is non unitary, a warning message will be displayed by the compiler. Custom gates can also be defined by combining existing gates and operators. In that case, the compiler will compute a new matrix.
Possible operators are :
TRANS
transposeCONJ
ConjugateDAG
Dag operator (conjugate of transpose)CTRL
ControlDEFINE G(ATE) <gate name> = <gate formula>
where gate name must always be lowercase.
DEFINE GATE ex = [[(1,0) (0,0)] [ (0,0) (1,0) ]]
DEFINE G ph3_4 = PH[3*PI/4]
DEFINE G ex2 = DAG(X)
DEFINE G ex3 = CTRL(CTRL(G ex2))
The AQASM compiler prevents redefinition of an existing gate. In case a gate is already known (that is, the underlying matrices are equal),the DEFINE statement is skipped, and all subsequent calls to the gate are replaced with the pre-existing gate.
A custom gate must always be prefixed by GATE or G for short. Calling custom gates mygate is done through:
GATE mygate <operands>
In the same way, when combined with operators:
DAG G mygate <operands>
Instead of defining all gates at once in the DEFINE section, AQASM enables implicit declarations, by calling a valid gate formula in the execution section. In that case, the compiler creates a matrix defintion, with name starting with _ (underscore), and replace the statement by the corresponding gate operator.
DAG(CTRL(RX[PI/2])) q[2],q[0]
loops (WHILE, FOR, JUMP)
subroutines
We consider these functions non "quantum", and can be misleading for developers. They must be devoted to classical computing.
Hybrid computing is another story, and we address it in our higher-level framework.
AQASM is meant to remain a low-level language, to program circuits on quantum hardware or quantum emulators. Higher-level features for developers like defining macros, storing named variables, etc, should be handled by the higher-level programming languages. Our default higher-level languate is pyAQASM.