From 7312f6e6c4fe905f19dca99e77aac3cb7a1c8c8b Mon Sep 17 00:00:00 2001 From: Gadi Aleksandrowicz Date: Wed, 8 Jan 2025 16:24:56 +0200 Subject: [PATCH 1/3] Fix error in qasm3 exporter when operating on unitary gates --- .../library/generalized_gates/permutation.py | 2 +- .../library/generalized_gates/unitary.py | 2 +- qiskit/qasm2/export.py | 4 ++-- qiskit/qasm3/exporter.py | 9 ++++++--- .../fix-qasm-3-unitary-2da190be6ba25bbd.yaml | 5 +++++ test/python/qasm3/test_export.py | 18 ++++++++++++++++++ 6 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml diff --git a/qiskit/circuit/library/generalized_gates/permutation.py b/qiskit/circuit/library/generalized_gates/permutation.py index bea863f78242..62403e6901cb 100644 --- a/qiskit/circuit/library/generalized_gates/permutation.py +++ b/qiskit/circuit/library/generalized_gates/permutation.py @@ -182,7 +182,7 @@ def inverse(self, annotated: bool = False) -> PermutationGate: return PermutationGate(pattern=_inverse_pattern(self.pattern)) - def _qasm2_decomposition(self): + def _qasm_decomposition(self): # pylint: disable=cyclic-import from qiskit.synthesis.permutation import synth_permutation_basic diff --git a/qiskit/circuit/library/generalized_gates/unitary.py b/qiskit/circuit/library/generalized_gates/unitary.py index 40271ed4f594..a1550d1a7acb 100644 --- a/qiskit/circuit/library/generalized_gates/unitary.py +++ b/qiskit/circuit/library/generalized_gates/unitary.py @@ -202,7 +202,7 @@ def control( ) return gate - def _qasm2_decomposition(self): + def _qasm_decomposition(self): """Return an unparameterized version of ourselves, so the OQ2 exporter doesn't choke on the non-standard things in our `params` field.""" out = self.definition.to_gate() diff --git a/qiskit/qasm2/export.py b/qiskit/qasm2/export.py index 7c655dfd432b..fbe9b533ea9a 100644 --- a/qiskit/qasm2/export.py +++ b/qiskit/qasm2/export.py @@ -314,8 +314,8 @@ def _define_custom_operation(operation, gates_to_define): # definition, but still continue to return the given object as the call-site object. if operation.base_class in known_good_parameterized: parameterized_operation = type(operation)(*_FIXED_PARAMETERS[: len(operation.params)]) - elif hasattr(operation, "_qasm2_decomposition"): - new_op = operation._qasm2_decomposition() + elif hasattr(operation, "_qasm_decomposition"): + new_op = operation._qasm_decomposition() parameterized_operation = operation = new_op.copy(name=_escape_name(new_op.name, "gate_")) else: parameterized_operation = operation diff --git a/qiskit/qasm3/exporter.py b/qiskit/qasm3/exporter.py index 8997770c14e7..b08b2a9719ef 100644 --- a/qiskit/qasm3/exporter.py +++ b/qiskit/qasm3/exporter.py @@ -1180,13 +1180,16 @@ def build_gate_call(self, instruction: CircuitInstruction): This will also push the gate into the symbol table (if required), including recursively defining the gate blocks.""" - ident = self.symbols.get_gate(instruction.operation) + operation = instruction.operation + if hasattr(operation, "_qasm_decomposition"): + operation = operation._qasm_decomposition() + ident = self.symbols.get_gate(operation) if ident is None: - ident = self.define_gate(instruction.operation) + ident = self.define_gate(operation) qubits = [self._lookup_bit(qubit) for qubit in instruction.qubits] parameters = [ ast.StringifyAndPray(self._rebind_scoped_parameters(param)) - for param in instruction.operation.params + for param in operation.params ] if not self.disable_constants: for parameter in parameters: diff --git a/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml b/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml new file mode 100644 index 000000000000..785641ede11d --- /dev/null +++ b/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fix a bug in :class:`qasm3.Exporter` that caused the exporter to crash when + handling a unitary gate due to incorrect processing of its `params` field. diff --git a/test/python/qasm3/test_export.py b/test/python/qasm3/test_export.py index acae1d7d3cd7..489472b1ab73 100644 --- a/test/python/qasm3/test_export.py +++ b/test/python/qasm3/test_export.py @@ -2665,6 +2665,24 @@ def test_switch_v1_expr_target(self): test = dumps(qc, experimental=ExperimentalFeatures.SWITCH_CASE_V1) self.assertEqual(test, expected) + def test_circuit_with_unitary(self): + """Test that circuits with `unitary` gate are correctly handled""" + matrix = [[0, 1], [1, 0]] + qc = QuantumCircuit(1) + qc.unitary(matrix, [0]) + expected = """\ +OPENQASM 3.0; +include "stdgates.inc"; +gate unitary _gate_q_0 { + U(pi, -pi, 0) _gate_q_0; +} +qubit[1] q; +unitary q[0]; +""" + test = dumps(qc) + print(test) + self.assertEqual(test, expected) + @ddt class TestQASM3ExporterFailurePaths(QiskitTestCase): From 3d73765755ba0ef6e3b6adcd2781c4733fa76a53 Mon Sep 17 00:00:00 2001 From: gadial Date: Tue, 14 Jan 2025 16:01:31 +0200 Subject: [PATCH 2/3] Update test/python/qasm3/test_export.py Co-authored-by: Jake Lishman --- test/python/qasm3/test_export.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/python/qasm3/test_export.py b/test/python/qasm3/test_export.py index 489472b1ab73..1b9c24ca5410 100644 --- a/test/python/qasm3/test_export.py +++ b/test/python/qasm3/test_export.py @@ -2680,7 +2680,6 @@ def test_circuit_with_unitary(self): unitary q[0]; """ test = dumps(qc) - print(test) self.assertEqual(test, expected) From d9d66595af67da4490b688cc17440278a24a7f35 Mon Sep 17 00:00:00 2001 From: gadial Date: Tue, 14 Jan 2025 16:01:40 +0200 Subject: [PATCH 3/3] Update releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml Co-authored-by: Jake Lishman --- releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml b/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml index 785641ede11d..3cd59ff5e427 100644 --- a/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml +++ b/releasenotes/notes/fix-qasm-3-unitary-2da190be6ba25bbd.yaml @@ -1,5 +1,5 @@ --- fixes: - | - Fix a bug in :class:`qasm3.Exporter` that caused the exporter to crash when - handling a unitary gate due to incorrect processing of its `params` field. + Fix a bug in :class:`.qasm3.Exporter` that caused the exporter to crash when + handling a unitary gate due to incorrect processing of its ``params`` field.