PyQASM 1.0.4
Release 1.0.4 (July 15, 2026)
Summary
Added
- Added support for the
c3x(3-controlled X) andrc3x/rcccx(relative-phase 3-controlled X) gates, decomposed into basis gates following qiskit'sC3XGate/RC3XGatedefinitions. Also extended thectrl @modifier chain so that 3- and 4-control stacks onx(e.g.ctrl @ ctrl @ ctrl @ x,ctrl(4) @ x) resolve toc3x/c4x. (#320)
Improved / Modified
- Consolidated the hardcoded
"__PYQASM_QUBITS__"string literals scattered acrossvisitor.py,transformer.pyandpulse/utils.pyinto a singleINTERNAL_QUBIT_REGISTERconstant inelements.py, alongside anis_internal_qubit_register()helper that is now the one place the internal register is recognised. (#325)
Fixed
- Fixed
reseton a physical qubit rewriting the operand to the internal pulse register, e.g.reset $2;unrolled toreset __PYQASM_QUBITS__[2];. That names a register the program never declares, so the unrolled output did not round-trip throughdumps()/loads(), and the qubit was never registered (a program whose only operation wasreset $3;reportednum_qubits == 0). Physical qubits are now kept as-is in plain QASM programs, matching how gate and measurement operands already treat them; the rename is still applied for OpenPulse programs, where the pulse visitor expects it. (#325) - Fixed
measureandreseton a user register whose name merely starts with the reserved internal register name (e.g.__PYQASM_QUBITS__foo) being mistaken for the internal register itself. Such statements were short-circuited out of unrolling and emitted verbatim, soc = measure __PYQASM_QUBITS__foo;was never expanded per qubit andreset __PYQASM_QUBITS__foo;silently reset nothing. The register is now matched on its exact name, or on the name followed by an index or slice. (#325) - Fixed the
c4x(4-controlled X) gate, which previously raisedTypeError: c4x_gate() takes 4 positional arguments but 5 were givenbecause it was declared with four parameters for a five-qubit gate. It is now implemented via qiskit's structuredrc3x/c3sx/cphaseshiftdecomposition. (#320) - Added
inv @(inverse modifier) support for the multi-controlled-X family:inv @ c3x/inv @ c4xresolve to the (self-inverse) gate, andinv @ rc3x/inv @ rcccxresolve to the correct relative-phase dagger. These previously raisedUnsupported / undeclared QASM operation. (#320) - Fixed the
ctrl @modifier not resolving gate aliases:ctrl @ toffoli/ctrl @ ccnot(aliases ofccx) andctrl @ cnot/ctrl @ CX(aliases ofcx) now escalate controls identically to their canonical gate instead of raisingUnsupported controlled QASM operation. (#320) - Fixed the backend-dependent
dtduration unit being incorrectly relabeled asnswhen unrollingdelayandboxstatements without adevice_cycle_time. Sincedtcannot be converted to SI units without a sample rate, it is now preserved asdt. (#317)
Dependencies
- Migrated the Linux wheel build container from
manylinux2014tomanylinux_2_28. NumPy stopped publishingmanylinux2014(glibc 2.17) wheels for CPython 3.12+, sopipfell back to building NumPy from source inside the build container, whose GCC is older than NumPy requires — failing every Linux wheel job for cp312/cp313/cp314. The published wheels are unaffected: auditwheel tags them from the extension's actual symbol requirements, so they remainmanylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64and still install on glibc 2.17 systems.
Full Changelog: v1.0.3...v1.0.4