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

raise an exception with a custom gate with clbits or no qubits #10438

Merged
merged 10 commits into from
Jul 24, 2023
15 changes: 14 additions & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -5025,7 +5025,9 @@ def _qasm2_define_custom_operation(operation, existing_gate_names, gates_to_defi

Returns a potentially new :class:`.Instruction`, which should be used for the
:meth:`~.Instruction.qasm` call (it may have been renamed)."""
from qiskit.circuit import library as lib # pylint: disable=cyclic-import
# pylint: disable=cyclic-import
from qiskit.circuit import library as lib
from qiskit.qasm2 import QASM2ExportError

if operation.name in existing_gate_names:
return operation
Expand Down Expand Up @@ -5086,6 +5088,17 @@ def _qasm2_define_custom_operation(operation, existing_gate_names, gates_to_defi
)
else:
parameters_qasm = ""

if operation.num_qubits == 0:
raise QASM2ExportError(
f"OpenQASM 2 cannot represent '{operation.name}, which acts on zero qubits."
)
if operation.num_clbits != 0:
raise QASM2ExportError(
f"OpenQASM 2 cannot represent '{operation.name}', which acts on {operation.num_clbits}"
" classical bits."
)

qubits_qasm = ",".join(f"q{i}" for i in range(parameterized_operation.num_qubits))
parameterized_definition = getattr(parameterized_operation, "definition", None)
if parameterized_definition is None:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
fixes:
- |
Qiskit can represent custom instructions that act on zero qubits, or on a non-zero number of
classical bits. These cannot be exported to OpenQASM 2, but previously :meth:`.QuantumCircuit.qasm`
would try, and output invalid OpenQASM 2. Instead, a :exc:`.QASM2ExportError` will now correctly
be raised. See `#7351 <https://github.com/Qiskit/qiskit-terra/issues/7351>`__ and
`#10435 <https://github.com/Qiskit/qiskit-terra/issues/10435>`__.
24 changes: 24 additions & 0 deletions test/python/circuit/test_circuit_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,30 @@ def test_circuit_raises_on_single_bit_condition(self):
with self.assertRaisesRegex(QasmError, "OpenQASM 2 can only condition on registers"):
qc.qasm()

def test_circuit_raises_invalid_custom_gate_no_qubits(self):
"""OpenQASM 2 exporter of custom gates with no qubits.
See: https://github.com/Qiskit/qiskit-terra/issues/10435"""
legit_circuit = QuantumCircuit(5, name="legit_circuit")
empty_circuit = QuantumCircuit(name="empty_circuit")
legit_circuit.append(empty_circuit)

with self.assertRaisesRegex(QasmError, "acts on zero qubits"):
legit_circuit.qasm()

def test_circuit_raises_invalid_custom_gate_clbits(self):
"""OpenQASM 2 exporter of custom instruction.
See: https://github.com/Qiskit/qiskit-terra/issues/7351"""
instruction = QuantumCircuit(2, 2, name="inst")
instruction.cx(0, 1)
instruction.measure([0, 1], [0, 1])
custom_instruction = instruction.to_instruction()

qc = QuantumCircuit(2, 2)
qc.append(custom_instruction, [0, 1], [0, 1])

with self.assertRaisesRegex(QasmError, "acts on 2 classical bits"):
qc.qasm()

def test_circuit_qasm_with_permutations(self):
"""Test circuit qasm() method with Permutation gates."""

Expand Down