OpenQASM 3¶
Overview¶
QuantumRingsLib can compose a QuantumCircuit from OpenQASM 3.x content.
There are two supported entry points:
QuantumCircuit.from_qasm_file(path)— compose a circuit from an OpenQASM 3 file.QuantumCircuit.from_qasm_str(qasm_str)— compose a circuit from an OpenQASM 3 string.
For the recommended end-to-end workflow (provider → backend → circuit → run), see Circuits.
QuantumRingsLib also provides a OpenQASM helper class for importing qasm3-compliant files/strings
into a quantum circuit. The OpenQASM.load(...) and OpenQASM.loads(...) methods accept additional parameters (for example,
an include path and a strict flag). See the API reference for details.
Existing OpenQASM 3 files can also be submitted directly to BackendV2.run without first
composing a QuantumCircuit. This is required for circuits that contain control flow referencing mid-circuit measurements, or that use
input / output directives.
Note
OpenQASM 3 files use OPENQASM 3; or OPENQASM 3.0; as their version header and
include "stdgates.inc"; (double quotes) for the standard gate library.
Import from a file¶
Use QuantumCircuit.from_qasm_file(...) to compose a circuit from an OpenQASM 3 file. An optional global_phase argument is supported:
import math
from QuantumRingsLib import QuantumCircuit
circuit_name = "my_openQASM_file.qasm"
global_phase = math.pi / 8
qc = QuantumCircuit.from_qasm_file(circuit_name, global_phase)
Or using the OpenQASM helper class:
from QuantumRingsLib import OpenQASM
circuit_name = "my_openQASM_file.qasm"
oq = OpenQASM()
qc = oq.load(circuit_name)
This example creates a 10-qubit GHZ state with a for loop. Because the measurement occurs at the end
and no classical bits are referenced inside the loop, this can be imported using
OpenQASM.load or QuantumCircuit.from_qasm_file:
/*
Creates a 10-qubit GHZ state
File name: ghz.qasm
*/
OPENQASM 3;
include "stdgates.inc";
qubit[10] qreg1;
output bit[10] creg1;
h qreg1[0];
for uint[64] i in [0:sizeof(qreg1)-2]
{
cx qreg1[i], qreg1[i+1];
}
measure qreg1 -> creg1;
This is a full end-to-end version of the GHZ example, including provider setup and Windows CUDA path configuration:
import os
import sys
import platform
#
# Assumes that you have set up the OS environmental variables QR_TOKEN and
# QR_ACCOUNT with your Quantum Rings account information.
#
my_token = os.environ["QR_TOKEN"]
my_name = os.environ["QR_ACCOUNT"]
my_backend = "amber_quantum_rings"
precision = "single"
if platform.system() == "Windows":
cuda_path = os.getenv("CUDA_PATH", "")
if "" == cuda_path:
cuda_path = "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v13.0\\bin\\x64"
else:
if "13" in cuda_path:
cuda_path += "\\bin\\x64"
else:
cuda_path += "\\bin"
os.add_dll_directory(cuda_path)
import QuantumRingsLib
from QuantumRingsLib import QuantumRegister, AncillaRegister, ClassicalRegister
from QuantumRingsLib import QuantumCircuit
from QuantumRingsLib import QuantumRingsProvider
from QuantumRingsLib import job_monitor
from QuantumRingsLib import JobStatus
from QuantumRingsLib import JobV1, Result
provider = QuantumRingsProvider(token=my_token, name=my_name)
backend = provider.get_backend(backend=my_backend)
shots = 1000
program_file = "C:\\OpenQASM\\ghz.qasm"
job = backend.run(program_file, shots=shots, mode="sync")
result = job.result()
counts = result.get_counts()
print(counts)
Import from a string¶
Use QuantumCircuit.from_qasm_str(...) to compose a circuit from an OpenQASM 3 string:
from QuantumRingsLib import QuantumCircuit
qasm_str = open("circuit.qasm", "r", encoding="utf-8").read()
qc = QuantumCircuit.from_qasm_str(qasm_str)
Or using the OpenQASM helper class:
from QuantumRingsLib import OpenQASM
qasm_str = open("circuit.qasm", "r", encoding="utf-8").read()
oq = OpenQASM()
qc = oq.loads(qasm_str)
Direct execution¶
Pass the file path as the first argument:
from QuantumRingsLib import QuantumRingsProvider, job_monitor
provider = QuantumRingsProvider(token=my_token, name=my_name)
backend = provider.get_backend(backend="amber_quantum_rings")
circuit_name = r"C:\\path\\to\\circuit.qasm"
job = backend.run(circuit_name, mode="sync", shots=1000)
job_monitor(job, quiet=True)
result = job.result()
counts = result.get_counts()
print(counts)
Note
BackendV2.run does not return a QuantumCircuit object. If you need to inspect or
modify the circuit before execution, use the import path instead.
The following example circuit references a measured classical bit inside a conditional block, so it
must be submitted directly to BackendV2.run:
OPENQASM 3.0;
include "stdgates.inc";
extern double my_random();
qubit q;
bit c;
h q;
c = measure q;
if (c == 1) {
double r = my_random();
}
Using input and output directives¶
OpenQASM 3 supports input and output keywords to pass parameters into a program
and control which registers are returned. Only the bit data type can be marked as
output. Parameters are passed to BackendV2.run via the inputs argument as a
list of dictionaries.
The following example defines a typed input parameter and an output register:
OPENQASM 3.0;
include "stdgates.inc";
qubit[10] qreg1;
output bit[10] creg1;
input angle my_angle;
rz(my_angle) qreg1[0];
measure qreg1 -> creg1;
The parameters are passed via the inputs argument to BackendV2.run:
import math
data = [
{"param": "my_angle", "values": [math.pi / 2]}
]
job = backend.run("my_circuit.qasm", shots=1000, inputs=data)
This is a longer example with multiple parameters of different types, including arrays and complex numbers:
OPENQASM 3.0;
include "stdgates.inc";
qubit[10] qreg1;
output bit[10] creg1;
bit[5] creg2;
input array[int[64], 2, 3] my_int_array;
input array[uint[64], 2, 3] my_uint_array;
input array[float[64], 2, 2] my_float_array;
input const array[complex[float[64]], 3] my_complex_array;
input angle my_test_angle;
input bool my_bool;
print("Integer Array:", my_int_array, "\n");
print("Unsigned integer Array:", my_uint_array, "\n");
print("Float Array:", my_float_array, "\n");
print("Complex Array:", my_complex_array, "\n");
print("Angle:", my_test_angle, "\n");
print("bool:", my_bool, "\n");
x qreg1[0];
x qreg1[2];
x qreg1[4];
x qreg1[6];
x qreg1[8];
measure qreg1 -> creg1;
import math
data = [
{"param": "my_int_array", "values": [[-1, -2, -3], [1, 2, 3]]},
{"param": "my_uint_array", "values": [[1, 2, 3], [4, 5, 6]]},
{"param": "my_float_array", "values": [[1.1, 2.2], [4.4, 5.5]]},
{"param": "my_complex_array", "values": [(3+4j), (5+6j), (7+8j)]},
{"param": "my_bool", "values": [True]},
{"param": "my_test_angle", "values": [math.pi / 2]},
]
job = backend.run("C:\\OpenQASM\\testinputoutput.qasm", shots=1, inputs=data)
Important
Always mark the bit registers you want returned with the output keyword. If no
output directive is present, mid-circuit measurement results may not be what you expect.
See below.
The output directive and mid-circuit measurements¶
If a circuit performs mid-circuit measurements into multiple bit registers, only registers
marked output are returned. Without the output keyword, all bit registers are
concatenated in the result, which may produce an unexpected bitstring.
Without output (incorrect result):
OPENQASM 3;
include "stdgates.inc";
qubit[10] input_1;
bit[10] output_1; -- not marked output
x input_1[0];
x input_1[1];
output_1[4:5] = measure input_1[0:1];
output_1[0:1] = measure input_1[2:3];
-- Produces: '000011000011' (unexpected)
With output (correct result):
OPENQASM 3;
include "stdgates.inc";
qubit[10] input_1;
output bit[10] output_1; -- marked output
x input_1[0];
x input_1[1];
output_1[4:5] = measure input_1[0:1];
output_1[0:1] = measure input_1[2:3];
-- Produces: '0000111111' (expected)
Exporting OpenQASM 3¶
You can dump a QuantumCircuit to OpenQASM 3 format using qc.qasm3():
qasm3_txt = qc.qasm3()
print(qasm3_txt)
To save directly to a file, pass a filename argument. See the API reference for details.
Note
The exported circuit is always flattened. Any loops, subroutines, or user-defined gates in the original file will not be preserved. The flattened circuit will only represent the executed path.
Common errors¶
E32 — The file does not comply with the OpenQASM 3.0 standard. Check version header, quote style on
include, and register declaration syntax.E83 — Circuit must be run using
BackendV2.run. Occurs when a circuit with control flow referencing mid-circuit classical bits is passed toOpenQASM.loadorQuantumCircuit.from_qasm_file.E101 —
inputparameters declared but not provided. Pass all required parameters via theinputsargument toBackendV2.run.RuntimeError— Can be raised if there is a problem with the instructions in the OpenQASM 3 file or string.