Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix empty-barrier handling in OpenQASM 2 (backport #10469) #10491

Merged
merged 1 commit into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions crates/qasm2/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,15 @@ impl State {
}
self.check_trailing_comma(comma.as_ref())?;
qubits
} else if self.strict {
return Err(QASM2ParseError::new_err(message_generic(
Some(&Position::new(
self.current_filename(),
barrier_token.line,
barrier_token.col,
)),
"[strict] barrier statements must have at least one argument",
)));
} else if let Some(num_gate_qubits) = num_gate_qubits {
(0..num_gate_qubits).map(QubitId::new).collect::<Vec<_>>()
} else {
Expand Down
4 changes: 4 additions & 0 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1716,6 +1716,10 @@ def qasm(
elif operation.name == "reset":
instruction_qasm = f"reset {bit_labels[instruction.qubits[0]]};"
elif operation.name == "barrier":
if not instruction.qubits:
# Barriers with no operands are invalid in (strict) OQ2, and the statement
# would have no meaning anyway.
continue
qargs = ",".join(bit_labels[q] for q in instruction.qubits)
instruction_qasm = "barrier;" if not qargs else f"barrier {qargs};"
else:
Expand Down
13 changes: 13 additions & 0 deletions releasenotes/notes/qasm2-fix-zero-op-barrier-4af211b119d5b24d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
fixes:
- |
The OpenQASM 2 parser (:func:`.qasm2.load` and :func:`~.qasm2.loads`) running in ``strict`` mode
will now correctly emit an error if a ``barrier`` statement has no arguments. When running in
the (default) more permissive mode, an argument-less ``barrier`` statement will continue to
cause a barrier on all qubits currently in scope (the qubits a gate definition affects, or all
the qubits defined by a program, if the statement is in a gate body or in the global scope,
respectively).
- |
The OpenQASM 2 exporter (:meth:`.QuantumCircuit.qasm`) will now no longer attempt
to output ``barrier`` statements that act on no qubits. Such a barrier statement has no effect
in Qiskit either, but is invalid OpenQASM 2.
17 changes: 17 additions & 0 deletions test/python/circuit/test_circuit_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,23 @@ def test_sequencial_inner_gates_with_same_name(self):

self.assertEqual(qc.qasm(), expected_output)

def test_empty_barrier(self):
"""Test that a blank barrier statement in _Qiskit_ acts over all qubits, while an explicitly
no-op barrier (assuming Qiskit continues to allow this) is not output to OQ2 at all, since
the statement requires an argument in the spec."""
qc = QuantumCircuit(QuantumRegister(2, "qr1"), QuantumRegister(3, "qr2"))
qc.barrier() # In Qiskit land, this affects _all_ qubits.
qc.barrier([]) # This explicitly affects _no_ qubits (so is totally meaningless).

expected = """\
OPENQASM 2.0;
include "qelib1.inc";
qreg qr1[2];
qreg qr2[3];
barrier qr1[0],qr1[1],qr2[0],qr2[1],qr2[2];
"""
self.assertEqual(qc.qasm(), expected)


if __name__ == "__main__":
unittest.main()
7 changes: 7 additions & 0 deletions test/python/qasm2/test_parse_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,3 +865,10 @@ def test_required_version_empty(self):
qiskit.qasm2.QASM2ParseError, r"\[strict\] .*needed a version statement"
):
qiskit.qasm2.loads("", strict=True)

def test_barrier_requires_args(self):
program = "OPENQASM 2.0; qreg q[2]; barrier;"
with self.assertRaisesRegex(
qiskit.qasm2.QASM2ParseError, r"\[strict\] barrier statements must have at least one"
):
qiskit.qasm2.loads(program, strict=True)