Notebook Author: Sidhant Saraogi(sid1397@gmail.com)
This notebook introduces the OpenQASM import and export functions. It can also serve as a short introduction to the QASM format. The Quantum Assembly Language(QASM) acts as an intermediate representation for Quantum Circuits. This is one way to export/import from/to with QuTiP. In this way, we can make the QIP module of QuTiP compatible with Qiskit and Cirq.
import numpy as np
from qutip import about, basis, rand_ket, tensor
from qutip_qip.operations import Measurement
from qutip_qip.operations.gates import gate_sequence_product
from qutip_qip.qasm import read_qasm, print_qasm
The process is quite simple and only requires the user to store the .qasm
file in an appropriate location and maintain the absolute path of the file. This will reading the file simpler. For this demonstration, we already saved a few qasm circuit examples in the directory qasm_files. You can find more examples at OpenQASM repository Let's start off by reading one of the examples:
path = "qasm_files/swap.qasm"
qasm_file = open(path, "r")
print(qasm_file.read())
// SWAP gate impemented in terms of cx's OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; cx q[1], q[0]; cx q[0], q[1]; cx q[1], q[0];
This QASM file imitates the SWAP gate native to QuTiP in the QASM format. To import it, we use the read_qasm
function with the arguments being the file path, the mode
which defaults to "qiskit" and the version
which defaults to "2.0".
We can check that the circuit indeed implements the swap gate by checking the unitary matrix corresponding
to the circuit. This can be done by using the gate_sequence_product
function and the propagators
function of the
QubitCircuit
class.
qc = read_qasm(path, mode="qiskit", version="2.0")
gate_sequence_product(qc.propagators())
The mode
refers to the internal way in which QuTiP processes the QASM files.
With "qiskit" mode, QASM skips the include command for the file qelib1.inc and maps all custom gates defined in it to QuTiP gates without parsing the gate definitions.
Note: "qelib1.inc" is a "header" file that contains some QASM gate definitions. It is available in the OpenQASM repository (as a standard file) and is included with QASM exports by QuTiP (and also by Qiskit/Cirq).
The version
refers to the version of the OpenQASM standard being processed. The documentation for the same can be found in the OpenQASM repository. Currently, only OpenQASM 2.0 is supported which is the most popular QASM standard.
We can also convert a QubitCircuit
to the QASM format. This can be particularly useful when we are trying to export quantum circuits to other quantum packages such as Qiskit and Cirq. There are three different ways to output QASM files, print_qasm
, str_qasm
and write_qasm
.
print_qasm(qc)
// QASM 2.0 file generated by QuTiP OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; cx q[1],q[0]; cx q[0],q[1]; cx q[1],q[0];
QASM also offers the option to define custom gates in terms of already defined gates using the "gate" keyword. In "qiskit" mode, our QASM interpreter can be assumed to already allow for all the gates defined in the file stdgates.inc provided by the OpenQASM repository.
In the file swap_custom.qasm
, we define the swap
gate in terms of the pre-defined cx
gates.
path = "qasm_files/swap_custom.qasm"
qasm_file = open(path, "r")
print(qasm_file.read())
// SWAP gate defined as a custom gate. OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; creg c[2]; gate swap a, b{ cx b, a; cx a, b; cx b, a; } swap q[0], q[1] measure q -> c
Furthermore, the circuit also measures the two qubits q[0] and q[1] and stores the results in the classical registers c[0] and c[1]
qc = read_qasm(path)
We can now run the circuit to confirm that the circuit is correctly loaded and performs the correct operations. To do this, we can use the QubitCircuit.run
function with the appropriate input state. In our case, we can take the state |01⟩
.
qc.run(tensor(basis(2, 0), basis(2, 1)))
As predicted the output is the state after swapping which is |10⟩
The QASM format also allows for other circuit features such as measurement and control of gates by classical bits. This is also supported by QuTiP. For an example, we can refer to the example of quantum teleportation. A more complete explanation of teleportation can be found in the notebook on quantum teleportation.
path = "qasm_files/teleportation.qasm"
qasm_file = open(path, "r")
qasm_str = qasm_file.read()
print(qasm_str)
OPENQASM 2.0; include "qelib1.inc"; qreg q[3]; creg c0[1]; creg c1[1]; h q[1]; cx q[1], q[2]; cx q[0], q[1]; h q[0]; measure q[0] -> c1[0] measure q[1] -> c0[0] if(c0==1) x q[2] if(c1==1) z q[2]
We can also read in a QASM file from a string by specifying strmode=True
to read_qasm
teleportation = read_qasm(qasm_str, strmode=True)
/home/runner/work/qutip-tutorials/qutip-tutorials/qutip-qip/src/qutip_qip/qasm.py:826: UserWarning: Information about individual registers is not preserved in QubitCircuit warnings.warn(
Note: The above warning is expected to inform the user that the import from QASM to QuTiP does not retain any information about the different qubit/classical bit register names. This could potentially be an issue when the circuit is exported if the user wants to maintain the consistency.
We can quickly check that the teleportation circuit works properly by teleporting the first qubit into the third qubit.
state = tensor(rand_ket(2), basis(2, 0), basis(2, 0))
initial_measurement = Measurement("start", targets=[0])
_, initial_probabilities = initial_measurement.measurement_comp_basis(state)
state_final = teleportation.run(state)
final_measurement = Measurement("start", targets=[2])
_, final_probabilities = final_measurement.measurement_comp_basis(state_final)
np.testing.assert_allclose(initial_probabilities, final_probabilities)
Note: Custom gates imported in the QASM format cannot be easily exported. Currently, only gates that are defined native to QuTiP can be exported. QuTiP also produces custom gate definitions for gates not provided in the qelib1.inc
"header" file. In these cases, QuTiP will add it's own gate definitions directly to the the exported .qasm
file but this is restricted only to already gates native to QuTiP.
Export from QuTiP handles both gates and measurements. However, it does not allow for export of controlled gates.
about()
QuTiP: Quantum Toolbox in Python ================================ Copyright (c) QuTiP team 2011 and later. Current admin team: Alexander Pitchford, Nathan Shammah, Shahnawaz Ahmed, Neill Lambert, Eric Giguère, Boxi Li, Jake Lishman, Simon Cross and Asier Galicia. Board members: Daniel Burgarth, Robert Johansson, Anton F. Kockum, Franco Nori and Will Zeng. Original developers: R. J. Johansson & P. D. Nation. Previous lead developers: Chris Granade & A. Grimsmo. Currently developed through wide collaboration. See https://github.com/qutip for details. QuTiP Version: 4.7.1 Numpy Version: 1.22.4 Scipy Version: 1.8.1 Cython Version: 0.29.33 Matplotlib Version: 3.5.2 Python Version: 3.10.4 Number of CPUs: 2 BLAS Info: Generic OPENMP Installed: False INTEL MKL Ext: False Platform Info: Linux (x86_64) Installation path: /home/runner/work/qutip-tutorials/qutip-tutorials/qutip/qutip ================================================================================ Please cite QuTiP in your publication. ================================================================================ For your convenience a bibtex reference can be easily generated using `qutip.cite()`