---
title: OpenQASM 2 and the Qiskit SDK
description: How to convert code between OpenQASM 2 and the Qiskit SDK.
source: https://quantum.cloud.ibm.com/docs/en/guides/interoperate-qiskit-qasm2
---

# OpenQASM 2 and the Qiskit SDK

### Package versions

The code on this page was developed using the following requirements.
We recommend using these versions or newer.

```
qiskit[all]~=2.5.1
```

The Qiskit SDK provides some tools for converting between OpenQASM representations of quantum programs, and the [QuantumCircuit](/docs/api/qiskit/qiskit.circuit.QuantumCircuit) class.

## Import an OpenQASM 2 program into Qiskit

Two functions import OpenQASM 2 programs into Qiskit.
These are [`qasm2.load()`](/docs/guides/../api/qiskit/qasm2#load), which takes a filename, and [`qasm2.loads()`](/docs/guides/../api/qiskit/qasm2#loads), which takes the OpenQASM 2 program as a string.

```python
import qiskit.qasm2

qiskit.qasm2.load(filename, include_path=('.',), include_input_directory='append', custom_instructions=(), custom_classical=(), strict=False)
qiskit.qasm2.loads(program, include_path=('.',), custom_instructions=(), custom_classical=(), strict=False)
```

See the [OpenQASM 2 Qiskit API](/docs/api/qiskit/qasm2) for more information.

### Import simple programs

For most OpenQASM 2 programs, you can simply use `qasm2.load` and `qasm2.loads` with a single argument.

#### Example: import an OpenQASM 2 program as a string

Use `qasm2.loads()` to import an OpenQASM 2 program as a string into a QuantumCircuit:

```python
import qiskit.qasm2

program = """
    OPENQASM 2.0;
    include "qelib1.inc";
    qreg q[2];
    creg c[2];

    h q[0];
    cx q[0], q[1];

    measure q -> c;
"""
circuit = qiskit.qasm2.loads(program)
circuit.draw()
```

Output:

```
     ┌───┐     ┌─┐   
q_0: ┤ H ├──■──┤M├───
     └───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
          └───┘ ║ └╥┘
c: 2/═══════════╩══╩═
                0  1 
```

#### Example: import an OpenQASM 2 program from a file

Use `load()` to import an OpenQASM 2 program from a file into a QuantumCircuit:

```python
import qiskit.qasm2
circuit = qiskit.qasm2.load("myfile.qasm")
```

### Link OpenQASM 2 gates with Qiskit gates

By default, Qiskit's OpenQASM 2 importer treats the include file `"qelib1.inc"` as a *de facto* standard library.
The importer treats this file as containing precisely the gates it is described to contain in [the original paper defining OpenQASM 2](https://arxiv.org/abs/1707.03429).
Qiskit will use the built-in gates in [the circuit library](/docs/guides/../api/qiskit/circuit_library) to represent the gates in `"qelib1.inc"`.
Gates defined in the program by manual OpenQASM 2 `gate` statements will, by default, be constructed as custom [Qiskit `Gate` subclasses](/docs/guides/../api/qiskit/qiskit.circuit.Gate).

You can tell the importer to use specific [`Gate`](/docs/guides/../api/qiskit/qiskit.circuit.Gate) classes for the given `gate` statements it encounters.
You can also use this mechanism to treat additional gate names as "built-in", that is, not requiring an explicit definition.
If you specify which gate classes to use for `gate` statements outside of `"qelib1.inc"`, the resulting circuit will typically be more efficient to work with.

> **Warning**
>
> As of Qiskit SDK v1.0, Qiskit's OpenQASM 2 *exporter* (see [Export a Qiskit circuit to OpenQASM 2](#qasm2-export)) still behaves as if `"qelib1.inc"` has more gates than it really does.
> This means that the default settings of the importer might not be able to import a program exported by our importer.
> See [the specific example on working with the legacy exporter](#qasm2-import-legacy) to resolve this problem.
>
> This discrepancy is legacy behavior of Qiskit, and [it will be resolved in a later release of Qiskit](https://github.com/Qiskit/qiskit/issues/10737).

To pass information about a custom instruction to the OpenQASM 2 importer, use [the `qasm2.CustomInstruction` class](/docs/guides/../api/qiskit/qasm2#qiskit.qasm2.CustomInstruction).
This has four required pieces of information, in order:

- The **name** of the gate, used in the OpenQASM 2 program
- The **number of angle parameters** that the gate takes
- The **number of qubits** that the gate acts on
- The Python **constructor** class or function for the gate, which takes the gate parameters (but not qubits) as individual arguments

If the importer encounters a `gate` definition that matches a given custom instruction, it will use that custom information to reconstruct the gate object.
If a `gate` statement is encountered that matches the `name` of a custom instruction, but does not match both the number of parameters and the number of qubits, the importer will raise a [`QASM2ParseError`](/docs/guides/../api/qiskit/qasm2#qasm2parseerror), to indicate the mismatch between the supplied information and program.

In addition, a fifth argument `builtin` can be optionally set to `True` to make the gate automatically available within the OpenQASM 2 program, even if it is not explicitly defined.
If the importer does encounter an explicit `gate` definition for a built-in custom instruction, it will accept it silently.
As before, if an explicit definition of the same name is not compatible with the provided custom instruction, a [`QASM2ParseError`](/docs/guides/../api/qiskit/qasm2#qasm2parseerror) will be raised.
This is useful for compatibility with older OpenQASM 2 exporters, and with certain other quantum platforms that treat the "basis gates" of their hardware as built-in instructions.

Qiskit provides a data attribute for working with OpenQASM 2 programs produced by legacy versions of [Qiskit's OpenQASM 2 exporting capabilities](#qasm2-export).
This is [`qasm2.LEGACY_CUSTOM_INSTRUCTIONS`](/docs/guides/../api/qiskit/qasm2#legacy-compatibility), which can be given as the `custom_instructions` argument to [`qasm2.load()`](/docs/guides/../api/qiskit/qasm2#load) and [`qasm2.loads()`](/docs/guides/../api/qiskit/qasm2#loads).

#### Example: import a program created by Qiskit's legacy exporter

This OpenQASM 2 program uses gates that are not in the original version of `"qelib1.inc"` without declaring them, but are standard gates in Qiskit's library.
You can use [`qasm2.LEGACY_CUSTOM_INSTRUCTIONS`](/docs/guides/../api/qiskit/qasm2#legacy-compatibility) to easily tell the importer to use the same set of gates that Qiskit's OpenQASM 2 exporter previously used.

```python
from qiskit import qasm2

program = """
    OPENQASM 2.0;
    include "qelib1.inc";

    qreg q[4];
    creg c[4];

    h q[0];
    cx q[0], q[1];

    // 'rxx' is not actually in `qelib1.inc`,
    // but Qiskit used to behave as if it were.
    rxx(0.75) q[2], q[3];

    measure q -> c;
"""
circuit = qasm2.loads(
    program,
    custom_instructions=qasm2.LEGACY_CUSTOM_INSTRUCTIONS,
)
```

#### Example: use a particular gate class when importing an OpenQASM 2 program

Qiskit cannot, in general, verify if the definition in an OpenQASM 2 `gate` statement corresponds exactly to a Qiskit standard-library gate.
Instead, Qiskit chooses a custom gate using the precise definition supplied.
This can be less efficient that using one of the built-in standard gates, or a user-defined custom gate.
You can manually define `gate` statements with particular classes.

```python
from qiskit import qasm2
from qiskit.circuit import Gate
from qiskit.circuit.library import RZXGate


# Define a custom gate that takes one qubit and two angles.
class MyGate(Gate):
    def __init__(self, theta, phi):
        super().__init__("my", 1, [theta, phi])


custom_instructions = [
    # Link the OpenQASM 2 name 'my' with our custom gate.
    qasm2.CustomInstruction("my", 2, 1, MyGate),
    # Link the OpenQASM 2 name 'rzx' with Qiskit's
    # built-in RZXGate.
    qasm2.CustomInstruction("rzx", 1, 2, RZXGate),
]

program = """
    OPENQASM 2.0;

    gate my(theta, phi) q {
        U(theta / 2, phi, -theta / 2) q;
    }
    gate rzx(theta) a, b {
        // It doesn't matter what definition is
        // supplied, if the parameters match;
        // Qiskit will still use `RZXGate`.
    }

    qreg q[2];
    my(0.25, 0.125) q[0];
    rzx(pi) q[0], q[1];
"""

circuit = qasm2.loads(
    program,
    custom_instructions=custom_instructions,
)
```

#### Example: define a new built-in gate in an OpenQASM 2 program

If the argument `builtin=True` is set, a custom gate does not need to have an associated definition.

```python
from qiskit import qasm2
from qiskit.circuit import Gate


# Define a custom gate that takes one qubit and two angles.
class MyGate(Gate):
    def __init__(self, theta, phi):
        super().__init__("my", 1, [theta, phi])


custom_instructions = [
    qasm2.CustomInstruction("my", 2, 1, MyGate, builtin=True),
]

program = """
    OPENQASM 2.0;
    qreg q[1];

    my(0.25, 0.125) q[0];
"""

circuit = qasm2.loads(
    program,
    custom_instructions=custom_instructions,
)
```

### Define custom classical functions

OpenQASM 2 includes some built-in classical functions to use in gate arguments.
You can extend the language with more functions by using the `custom_classical` argument to [`qasm2.load()`](/docs/guides/../api/qiskit/qasm2#load) and [`qasm2.loads()`](/docs/guides/../api/qiskit/qasm3#loads), with the [`qasm2.CustomClassical`](/docs/guides/../api/qiskit/qasm2#qiskit.qasm2.CustomClassical) class.

To define a custom classical function, you must supply:

- The *name* of the function as it appears in the OpenQASM 2 program
- The number of floating-point arguments it accepts
- A callable Python object that evaluates the function

All defined custom classical functions are treated as built-in to the OpenQASM 2 language by the importer.
There is no official way within the OpenQASM 2 language to define new functions; this is a Qiskit extension.

#### Example: use custom classical instructions

Here we provide two custom classical functions.
The first is simple, and just adds one to its input.
The second is the function `math.atan2`, which represents the mathematical operation $\arctan(y/x)$ in a quadrant-aware manner.

```python
import math
from qiskit import qasm2

program = """
    include "qelib1.inc";
    qreg q[2];
    rx(arctan(pi, 3 + add_one(0.2))) q[0];
    cx q[0], q[1];
"""


def add_one(x):
    return x + 1


customs = [
    # Our `add_one` takes only one parameter.
    qasm2.CustomClassical("add_one", 1, add_one),
    # `arctan` takes two parameters, and `math.atan2` implements it.
    qasm2.CustomClassical("arctan", 2, math.atan2),
]
circuit = qasm2.loads(program, custom_classical=customs)
```

### Strict mode

By default, this parser is more relaxed than the official specification.
It allows trailing commas in parameter lists; unnecessary (empty-statement) semicolons; omission of the `OPENQASM 2.0;` version statement; and several other quality-of-life improvements without emitting any errors.
However, you can use the "letter-of-the-spec" mode with `strict=True`.

## Export a Qiskit circuit to OpenQASM 2

Qiskit can also export a [`QuantumCircuit`](/docs/guides/../api/qiskit/qiskit.circuit.QuantumCircuit) to OpenQASM 2.
You use the function [`qasm2.dump()`](/docs/guides/../api/qiskit/qasm2#dump) to write to a file, and [`qasm2.dumps()`](/docs/guides/../api/qiskit/qasm2#dumps) to write to a string.
These functions currently have a very simple interface: they accept a circuit and, only in the case of [`qasm2.dump()`](/docs/guides/../api/qiskit/qasm2#dump), a location to write the output to.

> **Warning**
>
> Qiskit's OpenQASM 2 exporter still assumes a legacy, non-standard version of the `"qelib1.inc"` include file.
> [This will be resolved in a later release of Qiskit](https://github.com/Qiskit/qiskit/issues/10737), but in the meantime, if you need to re-import an OpenQASM 2 program created with Qiskit, use [the example above for how to tell the importer about the legacy gates](#qasm2-import-legacy).

### Example: export a circuit to OpenQASM 2

```python
from qiskit import QuantumCircuit, qasm2

# Define any circuit.
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0, 1], [0, 1])

# Export to a string.
program = qasm2.dumps(circuit)

# Export to a file.
qasm2.dump(circuit, "my_file.qasm")
```

## Next steps

> **Recommendations**
>
> - Learn how to generate OpenQASM code in the [IBM Quantum Composer](/docs/guides/composer) guide.
> - See the [OpenQASM 2 Qiskit API](/docs/api/qiskit/qasm2) reference.
> - Review the [Verify your program](/docs/guides/debugging-tools) topic.
> - Visit the [OpenQASM Live Specification](https://openqasm.com/).
