A cQASM program (or any piece of computer code for that matter) needs to be compiled in order to be executed by the underlying hardware (or emulator), which is knows as the
target for execution. Compilation requires knowledge of the hardware that is used for the execution, such as information about the topology of the chip (the connections between the qubits), the native gate set (the gate operations that can be directly executed by the hardware), information about the gate durations and various constraints, such as timing constraints, constraints on the parallel execution of operation etc.
Various compilers for Quantum Computers exist, that all operate at different levels of the stack. Some are low level compilers, used for the generation of micro-instructions of the control hadrware or for the definition of microwave pulse envelopes. And some are more high level compilers, used for instance to convert a program written in a higher level of abstraction to lower levels of abstraction, or to decompose multi-qubit operations into single- and two-qubit operations. Examples of such higher level compilers are OpenQL and LibKet. We refer the user to these manuals to find out all details you need to know on compilation of quantum algorithms. Here we will limit ourselves to some basick compilation steps and we will use the OpenQL compiler as a basis.
Generally, the compilation process consists of the following steps:
decomposition; optimization; mapping; scheduling; and code generation.
How to compile for a given target is known as the compilation strategy. More on compilation strategies can be found in the OpenQL manual.
Decomposition is the act of converting gates that cannot be executed using a single instruction in the target gateset into a list of gates that have the same behavior. For example, a SWAP gate may be decomposed into three CNOT gates.
Optimization tries to reduce the algorithm to a more compact form. This is particularly relevant after decomposition, as the decomposition rules may lead to sequences of gates that trivially cancel each other out.
Mapping is the act of changing the qubit indices in the circuit such that the connectivity constraints of the target device are met. For complex circuits, no single mapping will suffice (or it may be too time-consuming to compute, as this is an NP problem); in this case, a compiler could for instance insert SWAP gates to route non-nearest-neighbor qubits toward each other, although this may not be always the most efficient mapping.
Scheduling is the act of assigning cycle numbers to each gate in a kernel. This can of course be done trivially by assigning monotonously increasing cycle numbers to each gate in the order in which they were written by the user, but this is highly inefficient; instead, heuristics and commutation rules are used to try to find a more optimal solution that makes efficient use of the parallelism provided by the control architecture.
Finally, code generation takes the completed program and converts it to the assembly or machine-code format that the architecture-specific tools expect at their input.
A strategy consists of a list of passes, along with pass-specific configuration options for each pass. OpenQL provides default pass lists for the available architectures, as listed in the architecture reference. You can modify this default strategy using API calls prior to compilation if need be, or you can override the defaults entirely by writing a compiler configuration file.
Using OpenQL and LibKet together with Quantum Inspire
In the current version of Quantum Inspire, LibKet and OpenQl are not integrated with Quantum Inspire. However, both allow compilation of algorithms written in cQASM and compilation to Quantum Inspire targets. The interested user is referred to these programs to get the most out of Quantum Inspire.