OpenQASMConversions

code
Authors

Claudia Zendejas-Morales

Adapted by Elisabeth Welizky

Published

June 21, 2024

In this tutorial, we’ll introduce OpenQASM, a key language for quantum programming and its use within IBM’s Qiskit framework.

Open Quantum Assembly Language

OpenQASM is an intermediate representation for quantum instructions. The language was first described in a paper published in July 2017, and a reference source code implementation was released as part of IBM’s Quantum Information Software Kit (Qiskit) for use with their IBM Q Experience cloud quantum computing platform.

OpenQASM defines its version at the head of a source file as a real number, as in the declaration:

OPENQASM 2.0;

The level of OpenQASM’s original published implementations (e.g., Qiskit, infra) is OpenQASM 2.0. The 3.0 level of the specification is currently work in progress and can be viewed at the OpenQASM repository on GitHub.

Tequila functions export_open_qasm, import_open_qasm, and import_open_qasm_from_file work with current OpenQASM version = 2.0

Example

The following is an example of OpenQASM source code from the official library. The program adds two four-bit numbers.

// quantum ripple-carry adder from Cuccaro et al, quant-ph/0410184
OPENQASM 2.0;
include "qelib1.inc";
gate majority a,b,c 
{ 
  cx c,b; 
  cx c,a; 
  ccx a,b,c; 
}
gate unmaj a,b,c 
{ 
  ccx a,b,c; 
  cx c,a; 
  cx a,b; 
}
qreg cin[1];
qreg a[4];
qreg b[4];
qreg cout[1];
creg ans[5];
// set input states
x a[0]; // a = 0001
x b;    // b = 1111
// add a to b, storing result in b
majority cin[0],b[0],a[0];
majority a[0],b[1],a[1];
majority a[1],b[2],a[2];
majority a[2],b[3],a[3];
cx a[3],cout[0];
unmaj a[2],b[3],a[3];
unmaj a[1],b[2],a[2];
unmaj a[0],b[1],a[1];
unmaj cin[0],b[0],a[0];
measure b[0] -> ans[0];
measure b[1] -> ans[1];
measure b[2] -> ans[2];
measure b[3] -> ans[3];
measure cout[0] -> ans[4];

Export to OpenQASM

Once you have a circuit in Tequila, it is possible to generate its equivalent in OpenQASM code, using the export_open_qasm function, for example:

import tequila as tq
from numpy import pi
circuit = tq.gates.H(target=[0,1]) + \
          tq.gates.Y(target=0) + \
          tq.gates.Z(target=2) + \
          tq.gates.CX(target=3, control=0) + \
          tq.gates.Ry(target=2, angle=pi)
circuit.export_to(filename="C1_new.qpic")
1
A circuit is being created
2
The corresponding qpic-file to this circuit is being created. For generating the corresponding png one has to write “qpic -f png C1_new.qpic” into the command line

Code
openqasmcode = tq.export_open_qasm(circuit)

#print(opencasmcode)
1
Shows the circuit of openqasmcode

It is possible to generate the OpenQASM code for ZX-Calculus, that is, without Y gates (Y, Ry, Cy, CRy), if you want to activate this option you need to use the zx_calculus flag. If enabled, the OpenQASM code will be generated without Y gates and will instead place their equivalents for each gate.

openqasmcode_no_y = tq.export_open_qasm(circuit, zx_calculus=True)

If the Tequila circuit is created with variables, the corresponding values must be indicated when exporting it to OpenQASM code:

Code
circuit_var = tq.gates.H(target=[0,1]) + \
              tq.gates.Y(target=0) + \
              tq.gates.Z(target=2) + \
              tq.gates.CX(target=3, control=0) + \
              tq.gates.Ry(target=2, angle="var1") + \
              tq.gates.Rx(target=0, angle="var2")

circuit_var.export_to(filename="C2_new.qpic")

Code
variables = {"var1":2.8, "var2": pi/7}

openqasmcode_var = tq.export_open_qasm(circuit_var, variables=variables)

For convenience, it is possible to generate the code in OpenQASM and send the result to a file for external use. The name of the file must be indicated in the filename parameter:

Code
openqasmcode = tq.export_open_qasm(circuit, filename="MyOpenQASMCode.qasm")

#print(opencasmcode)
1
Shows the circuit of openqasmcode

Now the MyOpenQASMCode.qasm file has been created

Import from OpenQASM

It is possible to take a code in OpenQASM and use it to generate a circuit in Tequila, using the import_open_qasm function, for example:

Code
openqasmcode = "OPENQASM 2.0;\n" \
               "include \"qelib1.inc\";\n" \
               "qreg q1[3];\n" \
               "qreg q2[4];\n" \
               "creg c[3];\n" \
               "x q1[0];\n" \
               "y q1[1];\n" \
               "h q2[2];\n" \
               "cz q1[0],q2[2];\n" \
               "ch q2[1],q2[3];\n" \
               "ccx q1[0],q1[1],q2[1];\n" \
               "rx(pi) q1[1];\n" \
               "rz(pi/7) q1[0];\n" \
               "cry(1.6*pi) q2[0],q2[1];\n" \

circuit = tq.import_open_qasm(openqasmcode)
circuit.export_to(filename="C3_new.qpic")

You can import an OpenQASM code that is not written strictly, but only has the instructions of the gates without containing the definition lines, for this the rigorous flag is used, for example:

Code
openqasmcode_not_rigorous = "qreg q1[3];\n" \
                            "qreg q2[4];\n" \
                            "creg c[3];\n" \
                            "x q1[0];\n" \
                            "y q1[1];\n" \
                            "cz q1[0],q2[2];\n" \
                            "ccx q1[0],q1[1],q2[1];\n" \
                            "rz(pi/7) q1[0];\n" \
                            "cry(1.6*pi) q2[0],q2[1];\n" \

circuit_nr = tq.import_open_qasm(openqasmcode_not_rigorous, rigorous=False)
circuit_from_file = tq.import_open_qasm_from_file(filename="MyOpenQASMCode.qasm")
circuit_from_file.export_to(filename="C8_new.qpic")
1
In the case of having the OpenQASM code in a file, it is possible to load that file to generate the Tequila circuit from there, for this the import_open_qasm_from_file function is used

Code
openqasmcode_not_rigorous = "qreg q1[3];\n" \
                            "qreg q2[4];\n" \
                            "creg c[3];\n" \
                            "x q1[0];\n" \
                            "y q1[1];\n" \
                            "cz q1[0],q2[2];\n" \
                            "ccx q1[0],q1[1],q2[1];\n" \
                            "rz(pi/7) q1[0];\n" \
                            "cry(1.6*pi) q2[0],q2[1];\n" \

circuit_nr = tq.import_open_qasm(openqasmcode_not_rigorous, rigorous=False)             
circuit_nr.export_to(filename="C4_new.qpic")

If the OpenQASM code contains custom gates, importing into a Tequila circuit will generate the equivalent with the gates in the proper place with their corresponding parameters, for example:

Code
openqasmcode_custom = "OPENQASM 2.0;\n" \
                      "include \"qelib1.inc\";\n" \
                      "gate mycustom a,b,c\n" \
                      "{\n" \
                      "cx c,b;\n" \
                      "cx c,a;\n" \
                      "}\n" \
                      "qreg q1[3];\n" \
                      "qreg q2[4];\n" \
                      "creg c[3];\n" \
                      "y q1[1];\n" \
                      "z q2[2];\n" \
                      "mycustom q1[0],q2[0],q1[2];\n" \
                      "h q2[1];\n" \
                      "mycustom q2[3],q1[1],q2[2];\n" \
                      "y q2[1];\n"

circuit_cg = tq.import_open_qasm(openqasmcode_custom)
circuit_cg.export_to(filename="C5_new.qpic")

Code
openqasmcode = tq.export_open_qasm(circuit)

print(openqasmcode)

It is possible to generate the OpenQASM code for ZX-Calculus, that is, without Y gates (Y, Ry, Cy, CRy), if you want to activate this option you need to use the zx_calculus flag. If enabled, the OpenQASM code will be generated without Y gates and will instead place their equivalents for each gate.

If the Tequila circuit is created with variables, the corresponding values must be indicated when exporting it to OpenQASM code:

Code
openqasmcode_no_y = tq.export_open_qasm(circuit, zx_calculus=True)
#print(opencasmcode)
circuit_var = tq.gates.H(target=[0,1]) + \
              tq.gates.Y(target=0) + \
              tq.gates.Z(target=2) + \
              tq.gates.CX(target=3, control=0) + \
              tq.gates.Ry(target=2, angle="var1") + \
              tq.gates.Rx(target=0, angle="var2")
circuit_var.export_to(filename="C6_new.qpic")
1
Shows the circuit of openqasmcode_no_y

Code
variables = {"var1":2.8, "var2": pi/7}

openqasmcode_var = tq.export_open_qasm(circuit_var, variables=variables)

print(openqasmcode_var)

For convenience, it is possible to generate the code in OpenQASM and send the result to a file for external use. The name of the file must be indicated in the filename parameter:

Code
openqasmcode = tq.export_open_qasm(circuit, filename="MyOpenQASMCode.qasm")

#print(opencasmcode)
1
Shows the circuit of openqasmcode