From 549e4c667da7787a0bec4246f0e58a02663d5945 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Mon, 13 Mar 2023 16:38:36 +0000 Subject: [PATCH] Fix explicitly calibrated gates in `GateDirection` (#9786) If there is an explicit calibration given, this overrides the generic information from the `CouplingMap` or the `Target` for that particular instance, since one can use pulse-level control to define gates on a circuit-by-circuit basis that are not generically available in a way that can be specified in the coupling or target. --- .../transpiler/passes/utils/gate_direction.py | 4 +++ ...irection-calibration-c51202358d86e18f.yaml | 5 +++ test/python/transpiler/test_gate_direction.py | 31 +++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-gate-direction-calibration-c51202358d86e18f.yaml diff --git a/qiskit/transpiler/passes/utils/gate_direction.py b/qiskit/transpiler/passes/utils/gate_direction.py index 101f4e1a70bc..412d0daffb79 100644 --- a/qiskit/transpiler/passes/utils/gate_direction.py +++ b/qiskit/transpiler/passes/utils/gate_direction.py @@ -155,6 +155,8 @@ def _run_coupling_map(self, dag, wire_map, edges=None): continue if len(node.qargs) != 2: continue + if dag.has_calibration_for(node): + continue qargs = (wire_map[node.qargs[0]], wire_map[node.qargs[1]]) if qargs not in edges and (qargs[1], qargs[0]) not in edges: raise TranspilerError( @@ -198,6 +200,8 @@ def _run_target(self, dag, wire_map): continue if len(node.qargs) != 2: continue + if dag.has_calibration_for(node): + continue qargs = (wire_map[node.qargs[0]], wire_map[node.qargs[1]]) swapped = (qargs[1], qargs[0]) if node.name in self._static_replacements: diff --git a/releasenotes/notes/fix-gate-direction-calibration-c51202358d86e18f.yaml b/releasenotes/notes/fix-gate-direction-calibration-c51202358d86e18f.yaml new file mode 100644 index 000000000000..140ff5b71028 --- /dev/null +++ b/releasenotes/notes/fix-gate-direction-calibration-c51202358d86e18f.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + The :class:`.GateDirection` transpiler pass will no longer reject gates that have been given + explicit calibrations, but do not exist in the generic coupling map or target. diff --git a/test/python/transpiler/test_gate_direction.py b/test/python/transpiler/test_gate_direction.py index 4ab9a8bfb9d0..69e7a2b8ccaf 100644 --- a/test/python/transpiler/test_gate_direction.py +++ b/test/python/transpiler/test_gate_direction.py @@ -17,8 +17,8 @@ import ddt -from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit -from qiskit.circuit import Parameter +from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit, pulse +from qiskit.circuit import Parameter, Gate from qiskit.circuit.library import CXGate, CZGate, ECRGate, RXXGate, RYYGate, RZXGate, RZZGate from qiskit.compiler import transpile from qiskit.transpiler import TranspilerError, CouplingMap, Target @@ -430,6 +430,33 @@ def test_target_control_flow(self): pass_ = GateDirection(None, target) self.assertEqual(pass_(circuit), expected) + def test_allows_calibrated_gates_coupling_map(self): + """Test that the gate direction pass allows a gate that's got a calibration to pass through + without error.""" + cm = CouplingMap([(1, 0)]) + + gate = Gate("my_2q_gate", 2, []) + circuit = QuantumCircuit(2) + circuit.append(gate, (0, 1)) + circuit.add_calibration(gate, (0, 1), pulse.ScheduleBlock()) + + pass_ = GateDirection(cm) + self.assertEqual(pass_(circuit), circuit) + + def test_allows_calibrated_gates_target(self): + """Test that the gate direction pass allows a gate that's got a calibration to pass through + without error.""" + target = Target(num_qubits=2) + target.add_instruction(CXGate(), properties={(0, 1): None}) + + gate = Gate("my_2q_gate", 2, []) + circuit = QuantumCircuit(2) + circuit.append(gate, (0, 1)) + circuit.add_calibration(gate, (0, 1), pulse.ScheduleBlock()) + + pass_ = GateDirection(None, target) + self.assertEqual(pass_(circuit), circuit) + if __name__ == "__main__": unittest.main()