Skip to content

Releases: qBraid/pyqasm

PyQASM 1.0.1

27 Feb 04:51
347bddc

Choose a tag to compare

Release 1.0.1 (February 27, 2026)

Summary

Added

Improved / Modified

  • Moved the visit_map from the visit_statement function to a class level variable for improved efficiency. (#279)
  • Added SVG light and dark mode versions of PyQASM logo, with and without text, and added dynamic logo mode to README.md based on color palette used on user-side. (#288)
  • Updated docs with new logo, added v2 links, and applied minor Python formatting fixes for style consistency. (#289)

Deprecated

Removed

Fixed

  • Added support for physical qubit identifiers ($0, $1, …) in plain QASM 3 programs, including gates, barriers, measurements, and duplicate-qubit detection. (#291)
  • Updated CI to use macos-15-intel image due to deprecation of macos-13 image. (#283)

Dependencies

  • Update pillow requirement from <11.4.0 to <12.1.0 (#271)
  • Bump actions/download-artifact from 5 to 6 (#272)
  • Bump actions/upload-artifact from 4 to 5 (#273)

New Contributors

Full Changelog: v1.0.0...v1.0.1

PyQASM 1.0.0

19 Sep 06:28
5b21c75

Choose a tag to compare

Release 1.0.0 (September 19, 2025)

Summary

Added

  • Major Update
    Added support for OPENPULSE code in pyqasm. (#246)
    Supported example program:
    OPENQASM 3.0;
    defcalgrammar "openpulse";
      
    complex[float[32]] amp = 1.0 + 2.0im;
    cal {
        port d0;
        frame driveframe = newframe(d0, 5.0e9, 0.0);
        waveform wf = gaussian(amp, 16ns, 4ns);
    }
      
    const float frequency_start = 4.5e9;
    const float frequency_step = 1e6;
    const int frequency_num_steps = 3;
    
    defcal saturation_pulse $0 {
        play(driveframe, constant(amp, 100e-6s));
    }
      
    cal {
        set_frequency(driveframe, frequency_start);
    }
      
    for int i in [1:frequency_num_steps] {
        cal {
            shift_frequency(driveframe, frequency_step);
        }
        saturation_pulse $0;
    }
  • Added a workflow to track changes in the docs/_static/logo.png file to prevent unnecessary modifications. (#257)
  • Added decomposition details for all gates in the docs/gate_decompositions.md file. (#237)

Improved / Modified

  • Modified if statement validation to now include empty blocks as well. See Issue #246 for details. (#251)

Deprecated

Removed

Fixed

  • Fixed Complex value initialization error. (#253)
  • Fixed duplicate qubit argument check in function calls and Error in function call with aliased qubit. (#260)
  • Fixed Gate ordering across registers in pyqasm.draw() function. (#268)

Dependencies

  • Bumps @actions/checkout from 4 to 5 (#250)
  • Bump @codecov/codecov-action from 5.4.3 to 5.5.0 (#254)
  • Bump @actions/upload-pages-artifact from 3 to 4 (#255)
  • Bump @actions/setup-python from 5 to 6 (#262)
  • Bump @codecov/codecov-action from 5.5.0 to 5.5.1 (#263)
  • Bump @actions/github-script from 7 to 8 (#264)

Full Changelog: v0.5.0...v1.0.0

PyQASM 0.5.0

14 Aug 06:13
f2f7e04

Choose a tag to compare

Release 0.5.0 (August 14, 2025)

Summary

Added

  • A new discussion template for issues in pyqasm (#213)
  • A github workflow for validating CHANGELOG updates in a PR (#214)
  • Added unroll command support in PYQASM CLI with options skipping files, overwriting originals files, and specifying output paths.(#224)
  • Added Duration,Stretch type, Delay and Box support for OPENQASM3 code in pyqasm. (#231)
    Example:
    OPENQASM 3.0;
    include "stdgates.inc";
    qubit[3] q;
    duration t1 = 200dt;
    duration t2 = 300ns;
    stretch s1;
    delay[t1] q[0];
    delay[t2] q[1];
    delay[s1] q[0], q[2];
    box [t2] {
      h q[0];
      cx q[0], q[1];
      delay[100ns] q[2];
    }
  • Added a new QasmModule.compare method to compare two QASM modules, providing a detailed report of differences in gates, qubits, and measurements. This method is useful for comparing two identifying differences in QASM programs, their structure and operations. (#233)
  • Added .github/copilot-instructions.md to the repository to document coding standards and design principles for pyqasm. This file provides detailed guidance on documentation, static typing, formatting, error handling, and adherence to the QASM specification for all code contributions. (#234)
  • Added support for custom include statements in OPENQASM3 code in pyqasm. This allows users to include custom files or libraries in their QASM programs, enhancing modularity and reusability of code. (#236)
  • Added support for Angle,extern and Complex type in OPENQASM3 code in pyqasm. (#239)
    Example:
    OPENQASM 3.0;
    include "stdgates.inc";
    angle[8] ang1;
    ang1 = 9 * (pi / 8);
    angle[8] ang1 = 7 * (pi / 8);
    angle[8] ang3 = ang1 + ang2;
    
    complex c1 = -2.5 - 3.5im;
    const complex c2 = 2.0+arccos(π/2) + (3.1 * 5.5im);
    const complex c12 = c1 * c2;
    
    float a = 1.0;
    int b = 2;
    extern func1(float, int) -> bit;
    bit c = 2 * func1(a, b);
    bit fc = -func1(a, b);
    
    bit[4] bd = "0101";
    extern func6(bit[4]) -> bit[4];
    bit[4] be1 = func6(bd);

Improved / Modified

  • Added slots=True parameter to the data classes in elements.py to improve memory efficiency (#218)
  • Updated the documentation to include core features in the README (#219)
  • Added support to device qubit resgister consolidation.(#222)
  • Updated the scoping of variables in QasmVisitor using a ScopeManager. This change is introduced to ensure that the QasmVisitor and the PulseVisitor can share the same ScopeManager instance, allowing for consistent variable scoping across different visitors. No change in the user API is expected. (#232)
  • Enhance function call handling by adding support for nested functions. This change allows for more complex function definitions and calls, enabling better modularity and reusability of code within QASM programs. (#245)

Deprecated

Removed

Fixed

  • Fixed multiple axes error in circuit visualization of decomposable gates in draw method. (#209)
  • Fixed depth calculation for decomposable gates by computing depth of each constituent quantum gate.(#211)
  • Optimized statement copying in _visit_function_call with shallow-copy fallback to deepcopy and added max_loop_iters loop‐limit check in for loops.(#223)

Dependencies

  • Add pillow<11.3.0 dependency for test and visualization to avoid CI errors in Linux builds (#226)
  • Added tabulate to the testing dependencies to support new comparison table tests. (#216)
  • Update docutils requirement from <0.22 to <0.23 (#241)
  • Bumps actions/download-artifact version from 4 to 5 (#243)

New Contributors

Full Changelog: v0.4.0...v0.5.0

PyQASM 0.4.0

17 Jun 06:03
c27b69e

Choose a tag to compare

Release 0.4.0 (June 17, 2025)

Summary

Added

  • Added the pulse extra dependency to the pyproject.toml file, which includes the openpulse package. This allows users to install pulse-related functionality when needed. (#195)
  • Added support for unrolling while loops with compile time condition evaluation. Users can now use unroll on while loops which do not have conditions depending on quantum measurements. (#206) Eg. -
import pyqasm 

qasm_str = """
    OPENQASM 3.0;
    qubit[4] q;
    int i = 0;
    while (i < 3) {
        h q[i];
        cx q[i], q[i+1];
        i += 1;
    }

    """
result = pyqasm.loads(qasm_str)
result.unroll()
print(result)

# **Output**

# OPENQASM 3.0;
# qubit[4] q;
# h q[0];
# cx q[0], q[1];
# h q[1];
# cx q[1], q[2];
# h q[2];
# cx q[2], q[3];

Improved / Modified

  • Refactored analyze_classical_indices method to use @staticmethod instead of @classmethod. (#194)
  • Optimized _visit_generic_gate_operation in QasmVisitor class by using shallow copy instead of deep copy for better performance when processing gate operations. (#180)

Deprecated

Removed

Fixed

  • Fixed the way how depth is calculated when external gates are defined with unrolling a QASM module. (#198)
  • Added separate depth calculation for gates inside branching statements. (#200)
    • Example:
    OPENQASM 3.0;
    include "stdgates.inc";
    qubit[4] q;
    bit[4] c;
    bit[4] c0;
    if (c[0]){
      x q[0];
      h q[0]
      }
    else {
      h q[1];
    }
    Depth = 1
    
    • Previously, each gate inside an if/else block would advance only its own wire depth. Now, when any branching statement is encountered, all qubit‐ and clbit‐depths used inside that block are first incremented by one, then set to the maximum of those new values. This ensures the entire conditional block counts as single “depth” increment, rather than letting individual gates within the same branch float ahead independently.
    • In the above snippet, c[0], q[0], and q[1] all jump together to a single new depth for that branch.
  • Added initial support to explicit casting by converting the declarations into implicit casting logic. (#205)

Dependencies

New Contributors

Full Changelog: v0.3.2...v0.4.0

PyQASM 0.3.2

25 Apr 05:45
fbb4fb6

Choose a tag to compare

Release 0.3.2 (April 25, 2025)

Summary

Added

Improved / Modified

Deprecated

Removed

Fixed

  • Fixed bugs in the PARAMS_OP_SET by adding entries for u1, prx and cphaseshift10 gates. These gates were required to correctly run the tests for qbraid-qir and the qBraid packages. (#176) (#177)

Dependencies

Other

What's Changed

Full Changelog: v0.3.1...v0.3.2

PyQASM 0.3.1

21 Apr 05:49
776e9ef

Choose a tag to compare

Release 0.3.1 (April 21, 2025)

Summary

Added

  • Added support for conditionally unrolling barrier statements in the unroll method with the unroll_barriers flag. (#166) -
In [1]: import pyqasm

In [2]: qasm_str = """
   ...:     OPENQASM 3.0;
   ...:     include "stdgates.inc";
   ...: 
   ...:     qubit[2] q1;
   ...:     qubit[3] q2;
   ...:     qubit q3;
   ...: 
   ...:     // barriers
   ...:     barrier q1, q2, q3;
   ...:     barrier q2[:3];
   ...:     barrier q3[0];
   ...: """

In [3]: module = pyqasm.loads(qasm_str)

In [4]: module.unroll(unroll_barriers = False)

In [5]: print(module)
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q1;
qubit[3] q2;
qubit[1] q3;
barrier q1, q2, q3;
barrier q2[:3];
barrier q3[0];
  • Introduced a new environment variable called PYQASM_EXPAND_TRACEBACK. This variable can be set to true / false to enable / disable the expansion of traceback information in the error messages. The default is set as false. (#171) Eg. -

Script -

import pyqasm

qasm = """
    OPENQASM 3;
    include "stdgates.inc";
    qubit[2] q1;
    rx(a) q1;
    """

program = pyqasm.loads(qasm)
program.unroll()

Execution -

>>> python3 test-traceback.py
ERROR:pyqasm: Error at line 5, column 7 in QASM file

 >>>>>> a

ERROR:pyqasm: Error at line 5, column 4 in QASM file

 >>>>>> rx(a) q1[0], q1[1];


pyqasm.exceptions.ValidationError: Undefined identifier 'a' in expression

The above exception was the direct cause of the following exception:

pyqasm.exceptions.ValidationError: Invalid parameter 'a' for gate 'rx'
>>> export PYQASM_EXPAND_TRACEBACK=true
>>> python3 test-traceback.py
ERROR:pyqasm: Error at line 5, column 7 in QASM file

 >>>>>> a

ERROR:pyqasm: Error at line 5, column 4 in QASM file

 >>>>>> rx(a) q1[0], q1[1];


Traceback (most recent call last):
  .....

  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/expressions.py", line 69, in _check_var_in_scope
    raise_qasm3_error(
  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/exceptions.py", line 103, in raise_qasm3_error
    raise err_type(message)

pyqasm.exceptions.ValidationError: Undefined identifier 'a' in expression

The above exception was the direct cause of the following exception:


Traceback (most recent call last):
  .....

  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/visitor.py", line 2208, in visit_basic_block
    result.extend(self.visit_statement(stmt))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/visitor.py", line 2188, in visit_statement
    result.extend(visitor_function(statement))  # type: ignore[operator]
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/visitor.py", line 1201, in _visit_generic_gate_operation
    result.extend(self._visit_basic_gate_operation(operation, inverse_value, ctrls))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/visitor.py", line 820, in _visit_basic_gate_operation
    op_parameters = self._get_op_parameters(operation)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/visitor.py", line 660, in _get_op_parameters
    raise_qasm3_error(
  File "/Users/thegupta/Desktop/qBraid/repos/pyqasm/src/pyqasm/exceptions.py", line 102, in raise_qasm3_error
    raise err_type(message) from raised_from

pyqasm.exceptions.ValidationError: Invalid parameter 'a' for gate 'rx'

Improved / Modified

  • Improved the error messages for the parameter mismatch errors in basic quantum gates (#169). Following error is raised on parameter count mismatch -
In [1]: import pyqasm
   ...: 
   ...: qasm = """
   ...: OPENQASM 3;
   ...: include "stdgates.inc";
   ...: qubit[2] q;
   ...: rx(0.5, 1) q[1];
   ...: """
   ...: program = pyqasm.loads(qasm)
   ...: program.validate()

......
ValidationError: Expected 1 parameter for gate 'rx', but got 2  
  • Enhanced the verbosity and clarity of pyqasm validation error messages. The new error format logs the line and column number of the error, the line where the error occurred, and the specific error message, making it easier to identify and fix issues in the QASM code. (#171) Eg. -
import pyqasm

qasm = """
    OPENQASM 3;
    include "stdgates.inc";
    qubit[2] q1;
    rx(a) q1;
    """

program = pyqasm.loads(qasm)
program.unroll()
ERROR:pyqasm: Error at line 5, column 7 in QASM file

 >>>>>> a

ERROR:pyqasm: Error at line 5, column 4 in QASM file

 >>>>>> rx(a) q1[0], q1[1];


pyqasm.exceptions.ValidationError: Undefined identifier 'a' in expression

The above exception was the direct cause of the following exception:

pyqasm.exceptions.ValidationError: Invalid parameter 'a' for gate 'rx'

Deprecated

Removed

  • Removed the dependency on Union for typing by replacing it with | (#170).

Fixed

  • Resolved the inconsistency in pyqasm.printer.draw and pyqasm.printer.mpl_draw behaviour for multiple function calls. See issue #165 for bug details. (#168)

Dependencies

PRs Merged

Full Changelog: v0.3.0...v0.3.1

PyQASM 0.3.0

18 Mar 16:35
28c4140

Choose a tag to compare

Release 0.3.0 (Mar 18, 2025)

Summary

Added

  • Added logic to bump-version.yml workflow that automatically updates CITATION.cff upon new release (#147)
  • Added pyqasm.draw() function that draws quantum circuit (#122):
from pyqasm import draw

qasm = """
OPENQASM 3.0;
include "stdgates.inc";

qubit[3] q;
bit[3] b;

h q[0];
z q[1];
rz(pi/1.1) q[0];
cx q[0], q[1];
swap q[0], q[1];
ccx q[0], q[1], q[2];
b = measure q;
"""

draw(qasm, output='mpl')

Screenshot 2025-03-17 at 2 23 14 PM

- Currently, only the mpl (matplotlib) output format is supported.

- Use draw(..., idle_wires=False) to draw circuit without empty qubit/classical bit registers.

- Save the visualization to a file by specifying output='mpl' and a filename:

draw(..., output='mpl', filename='/path/to/circuit.png')

- The draw method accepts either a str (QASM source) or a QasmModule. The following are equivalent:

from pyqasm import loads, draw
from pyqasm.printer import mpl_draw

module = loads(qasm_str)

draw(module, output='mpl')
draw(qasm_str, output='mpl')

draw(module)
draw(qasm_str)

Fixed

  • Fixed bug in release workflow(s) that caused discrepancy between pyqasm.__version__ and importlib.metadata.version (#147)
  • Fixed a bug in broadcast operation for duplicate qubits so that the following -
OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
qubit[2] q2;
cx q[0], q[1], q[1], q[2];
cx q2, q2;

will unroll correctly to -

OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
qubit[2] q2;
// cx q[0], q[1], q[1], q[2];
cx q[0], q[1];
cx q[1], q[2];

// cx q2, q2;
cx q2[0], q2[1];
cx q2[0], q2[1];

The logic for duplicate qubit detection is moved out of the QasmVisitor._get_op_bits into Qasm3Analyzer class and is executed post gate broadcast operation (#155).

Other

  • Updated license from GPL-3.0 to Apache-2.0 (#158)
  • Added GitHub actions for publishing to GitHub pages, and updated docs pages from Readthedocs to GitHub pages links. (#158)

PRs Merged

Full Changelog: v0.2.1...v0.3.0

PyQASM 0.2.1

20 Feb 07:43
b6cb1b4

Choose a tag to compare

Release 0.2.1 (Feb 20, 2025)

Summary

Added

Added support for standalone measurements that do not store the result in a classical register (#141).

Improved / Modified

Re-wrote the QasmAnalyzer.extract_qasm_version method so that it extracts the program version just by looking at the first non-comment line, instead of parsing the entire program (#140).

Deprecated

Removed

Fixed

Solved version discrepancy in release by ensuring no changes are detected by cibuildhweel post checkout (#142).

Dependencies

New Contributors

Full Changelog: v0.2.0...v0.2.1

PyQASM 0.2.0

14 Feb 11:55
0fd2956

Choose a tag to compare

Release 0.2.0 (Feb 14, 2025)

Summary

Added

  • Added support for classical declarations with measurement (#120). Usage example -
In [1]: from pyqasm import loads, dumps

In [2]: module = loads(
   ...: """OPENQASM 3.0;
   ...: qubit q;
   ...: bit b = measure q;
   ...: """)

In [3]: module.unroll()

In [4]: dumps(module).splitlines()
Out[4]: ['OPENQASM 3.0;', 'qubit[1] q;', 'bit[1] b;', 'b[0] = measure q[0];']
  • Added support for unrolling multi-bit branching with ==, >=, <=, >, and < (#112). Usage example -
In [1]: from pyqasm import loads

In [2]: module = loads(
   ...: """OPENQASM 3.0;
   ...: include "stdgates.inc";
   ...: qubit[1] q;
   ...: bit[4] c;
   ...: if(c == 3){
   ...:     h q[0];
   ...: }
   ...: """)

In [3]: module.unroll()

In [4]: dumps(module)
OPENQASM 3.0;
include "stdgates.inc";
qubit[1] q;
bit[4] c;
if (c[0] == false) {
  if (c[1] == false) {
    if (c[2] == true) {
      if (c[3] == true) {
        h q[0];
      }
    }
  }
}
  • Add formatting check for Unix style line endings i.e. \n. For any other line endings, errors are raised. (#130)
  • Add rebase method to the QasmModule. Users now have the ability to rebase the quantum programs to any of the available pyqasm.elements.BasisSet (#123). Usage example -
In [9] : import pyqasm

In [10]: qasm_input = """ OPENQASM 3.0;
    ...: include "stdgates.inc";
    ...: qubit[2] q;
    ...: bit[2] c;
    ...: 
    ...: h q;
    ...: x q;
    ...: cz q[0], q[1];
    ...: 
    ...: c = measure q; 
    ...: """

In [11]: module = pyqasm.loads(qasm_input)

In [12]: from pyqasm.elements import BasisSet

In [13]: module.rebase(target_basis_set=BasisSet.ROTATIONAL_CX)
Out[13]: <pyqasm.modules.qasm3.Qasm3Module at 0x103744e10>

In [14]: print(pyqasm.dumps(module))
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
ry(1.5707963267948966) q[0];
rx(3.141592653589793) q[0];
ry(1.5707963267948966) q[1];
rx(3.141592653589793) q[1];
rx(3.141592653589793) q[0];
rx(3.141592653589793) q[1];
ry(1.5707963267948966) q[1];
rx(3.141592653589793) q[1];
cx q[0], q[1];
ry(1.5707963267948966) q[1];
rx(3.141592653589793) q[1];
c[0] = measure q[0];
c[1] = measure q[1];

Current support for BasisSet.CLIFFORD_T decompositions is limited to non-parameterized gates only.

  • Added .gitattributes file to specify unix-style line endings(\n) for all files (#123)
  • Added support for ctrl modifiers. QASM3 programs with ctrl @ modifiers can now be loaded as QasmModule objects (#121). Usage example -
In [18]: import pyqasm

In [19]: qasm3_string = """
    ...:     OPENQASM 3.0;
    ...:     include "stdgates.inc";
    ...:     qubit[3] q;
    ...:     gate custom a, b, c {
    ...:         ctrl @ x a, b;
    ...:         ctrl(2) @ x a, b, c;
    ...:     }
    ...:     custom q[0], q[1], q[2];
    ...:     """

In [20]: module = pyqasm.loads(qasm3_string)

In [21]: module.unroll()

In [22]: print(pyqasm.dumps(module))
OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
cx q[0], q[1];
ccx q[0], q[1], q[2];

Improved / Modified

  • Bumped qBraid-CLI dep in tox.ini to fix qbraid headers command formatting bug (#129)

Deprecated

Removed

  • Unix-style line endings check in GitHub actions was removed in lieu of the .gitattributes file (#123)

Fixed

Dependencies

  • Update sphinx-autodoc-typehints requirement from <2.6,>=1.24 to >=1.24,<3.1 (#119)

New Contributors

Full Changelog: v0.1.0...v0.2.0

PyQASM 0.1.0

10 Dec 05:28
d8fc16b

Choose a tag to compare

Release 0.1.0 (Dec 10, 2024)

Summary

Added

  • Added support for gphase, toffoli, not, c3sx and c4x gates (#86)
  • Added a remove_includes method to QasmModule to remove include statements from the generated QASM code (#100). Usage example -
In [1]: from pyqasm import loads

In [2]: module = loads(
   ...: """OPENQASM 3.0;
   ...: include "stdgates.inc";
   ...: include "random.qasm";
   ...: 
   ...: qubit[2] q;
   ...: h q;
   ...: """)

In [3]: module.remove_includes()
Out[3]: <pyqasm.modules.qasm3.Qasm3Module at 0x10442b190>

In [4]: from pyqasm import dumps

In [5]: dumps(module).splitlines()
Out[5]: ['OPENQASM 3.0;', 'qubit[2] q;', 'h q;']

Improved / Modified

  • Refactored the initialization of QasmModule to remove default include statements. Only user supplied include statements are now added to the generated QASM code (#86)
  • Update the pre-release.yml workflow to multi-platform builds. Added the pre-release version bump to the pre_build.sh script. (#99)

Deprecated

Removed

Fixed

  • Fixed bugs in implementations of gpi2 and prx gates (#86)

Dependencies

Full Changelog: