Skip to main content

Cram sheet — Section 8: Operate with OpenQASM

One-screen review layer for this section: short background primers per objective, then the key facts — each backed by an official source or by an executed proof from the question bank.

Structure types in OpenQASM 3 programs​

OpenQASM 3 is a typed language​

OpenQASM 2 knew only two aggregate declarations, qreg and creg. OpenQASM 3 replaces them with a real type system: quantum registers become qubit[n] name;, classical registers become bit[n] name;, and a family of classical types joins them.

TypeNotes
bool, int[n], uint[n], float[n]the C-like scalars, each sized by its designator
complex[float[n]]the designator is a FLOAT type, never a bare bit width: complex[float[64]] c;
bit[n], angle[n], duration, stretchthe four "special" types, the ones with no C equivalent
not in the languagestring, char, real, unsigned

Two things matter for the exam. First, what Qiskit EMITS: circuits export their registers as bit[n]/qubit[n], loose clbits as bare bit. Second, what Qiskit can PARSE BACK: the importer supports only a subset of the type system, and the official feature table is the authority on which types survive the round trip.

Sources: qasm-feature-table · qasm3 · types.html

Must know:

  • Qiskit exports classical registers as bit[n] c; even at width 1; loose Clbits become bare bit _bit0;. — ⚙️ proven in s8-q010
  • An unbound Parameter exports to OpenQASM 3 as an input float[64] declaration — the circuit becomes a parameterized program. — ⚙️ proven in s8-q020
  • Casting rules: in a binary operation the LESSER type is promoted (complex > float > int/uint, wider beats narrower); bool and scalar bit are interchangeable as values; bit[n] converts to int[m]/uint[m]/angle[m] only when m == n; nothing casts to or from duration; and a width designator must be a const expression. — 📖 types.html

Traps:

  • The feature table's Qiskit column documents bit as supported (mapped to Clbit/ClassicalRegister) while duration and stretch declarations are unparseable. — 📖 qasm-feature-table

Interpret OpenQASM semantics​

Reading v2 and v3 programs side by side​

The same circuit reads differently in the two versions, and four tells answer every "which version is this?" question.

FeatureOpenQASM 2OpenQASM 3
headerOPENQASM 2.0;OPENQASM 3.0;
standard includeinclude "qelib1.inc";include "stdgates.inc";
registersqreg q[2]; creg c[2];qubit[2] q; bit[2] c;
measurementmeasure q[0] -> c[0]; (arrow)c[0] = measure q[0]; (assignment)
conditionalswhole-register equality only: if (c == 1) ...real if/else, loops, per-bit conditions
global phasenot expressiblegphase

Control flow is the deepest semantic difference, and exporters enforce these language limits at export time: OpenQASM 2 cannot express a per-bit if_test condition or a global phase.

Sources: interoperate-qiskit-qasm2 · interoperate-qiskit-qasm3

Must know:

  • OpenQASM 2 conditionals accept only whole-register equality; exporting a per-clbit if_test raises QASM2ExportError ('OpenQASM 2 only supports register-equality conditions'). — ⚙️ proven in s8-q013
  • Custom gates round-trip as gate mygate ... { ... } declarations in both versions — neither exporter inlines them. — ⚙️ proven in s8-q019
  • qasm3.dumps writes a single-bit condition as a bare bit test: if_test((c[0], 1)) becomes if (c[0]) { and if_test((c[0], 0)) becomes if (!c[0]) {, while a whole-register (c, 0) becomes if (c == 0) {. — ⚙️ proven in s8-q031

Traps:

  • qasm2.dumps SILENTLY drops a circuit's global phase — no error, no warning — while qasm3.dumps emits gphase. — ⚙️ proven in s8-q017
  • qasm2.dumps exports exactly one condition form — if_test((creg, int)) with no else, emitted as if (c == 1) x q[1];. An else branch raises QASM2ExportError, and so does expr.equal(c, 1), although it means the same comparison. — ⚙️ proven in s8-q030

Interoperate different versions of OpenQASM with Qiskit​

The four functions, and the one asymmetry that matters​

Both qiskit.qasm2 and qiskit.qasm3 expose the same quartet, and the argument tells the functions apart.

FunctionDirectionqiskit.qasm2qiskit.qasm3
dumps(qc)circuit to stringnativenative
dump(qc, stream)circuit to an OPEN text streamnativenative
loads(s)string to circuitnativeneeds qiskit-qasm3-import
load(path)filesystem PATH to circuitnativeneeds qiskit-qasm3-import

The one asymmetry to memorize: OpenQASM 3 IMPORT is not part of Qiskit itself, it needs the separate qiskit-qasm3-import package, while OpenQASM 3 export and all of qasm2 ship with Qiskit. Mixing up dump and load arguments — a path where a stream belongs, or the reverse — raises immediately.

Sources: qasm3 · qasm2

Must know:

  • QuantumCircuit.from_qasm_str/from_qasm_file still exist in Qiskit 2.x for OpenQASM 2 input; the instance method .qasm() was removed. — ⚙️ proven in s8-q012
  • QuantumCircuit.from_qasm_str keeps the program's own declarations: qreg a[2]; creg m[2]; gives registers named a and m, never the default q/c, and measure a -> m; expands index by index — a[0] into m[0], a[1] into m[1]. — ⚙️ proven in s8-q029
  • Loading OpenQASM 2 keeps a user gate definition as a named custom gate, not inlined: mix q[2], q[0]; loads as ONE mix instruction on qubits (2, 0) whose .definition holds the h/cx body, and it draws as a single Mix box. — ⚙️ proven in s8-q032

Traps:

  • qasm3.loads/load raise MissingOptionalLibraryError unless qiskit-qasm3-import is installed; qasm3.dumps/dump and all of qasm2 are native. — ⚙️ proven in s8-q021
  • qasm2.loads rejects any header version other than 2.0 — feeding it a v3 program raises QASM2ParseError immediately. — ⚙️ proven in s8-q015

Interact with the Qiskit IBM Runtime REST API​

Runtime over plain HTTPS​

Everything the primitives do through Python can be done over plain HTTPS. Authentication is two-step: exchange your IBM Cloud API key for an IAM bearer token, then send that token plus a Service-CRN header identifying your instance on every Runtime call. Submitting a primitive job is one request, and results are a sub-resource of the job.

RequestWhat it does
POST /api/v1/jobssubmit a primitive job
GET /api/v1/jobs/{id}job details
GET /api/v1/jobs/{id}/resultsthe final result
GET /api/v1/jobs/{id}/logs, /metricsdiagnostics
POST /api/v1/jobs/{id}/cancelcancel the job
DELETE /api/v1/jobs/{id}remove a job already in a terminal state

Sources: cloud-setup-rest-api · sampler-rest-api · jobs

Must know:

  • IAM token exchange: POST the IBM Cloud API key with the apikey grant type; the bearer token expires after 3600 seconds (expires_in: 3600). — 📖 cloud-setup-rest-api
  • Submitting a Sampler job over REST is POST /v1/jobs with 'program_id': 'sampler' and your circuits inside params.pubs. — 📖 sampler-rest-api

Traps:

  • Every Runtime REST call after authentication carries two headers: the IAM bearer token and Service-CRN (the instance identifier — it is not itself a credential). — 📖 cloud-setup-rest-api
Exam checklist
  • Name the version from the header, the include file, the register keywords and the measure syntax.
  • Declare OpenQASM 3 registers as qubit[n] and bit[n]; qreg/creg are OpenQASM 2 only.
  • Give a complex declaration a float designator — complex[float[64]] c; — never a bare bit width.
  • Promote the lesser type in a binary operation, and size a bit[n] cast to the same width.
  • Remember only OpenQASM 3 IMPORT needs qiskit-qasm3-import; export and all of qasm2 are native.
  • Match each function to its argument: dumps/loads strings, dump an open stream, load a path.
  • Expect OpenQASM 2 export to reject a per-bit condition and to drop a global phase silently.
  • Send the IAM bearer token plus the Service-CRN header on every Runtime REST request.

Every fact above is sourced: 📖 links go to official documentation, ⚙️ marks facts observed by executing code against the pinned Qiskit stack (the linked section page shows the proof evidence on its practice questions).