From 080455aa10602f3eac5d37fee13b9aec50a170f8 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 11:37:41 +0000 Subject: [PATCH] Bug Fix for missing qubit property (#11880) (#11927) (cherry picked from commit c566b3ffa1de885527eb17be1670f023042b3a75) Co-authored-by: Naoki Kanazawa --- qiskit/providers/backend_compat.py | 23 ++++--- ...ing-qubit-properties-35137aa5250d9368.yaml | 6 ++ test/python/providers/faulty_backends.py | 12 ++++ test/python/providers/test_faulty_backend.py | 63 +++++++++++++++---- 4 files changed, 83 insertions(+), 21 deletions(-) create mode 100644 releasenotes/notes/fix-missing-qubit-properties-35137aa5250d9368.yaml diff --git a/qiskit/providers/backend_compat.py b/qiskit/providers/backend_compat.py index fcd82765eeb..de57f3f09fa 100644 --- a/qiskit/providers/backend_compat.py +++ b/qiskit/providers/backend_compat.py @@ -162,15 +162,22 @@ def _get_value(prop_dict, prop_name): faulty_qubits = { q for q in range(configuration.num_qubits) if not properties.is_qubit_operational(q) } - qubit_properties = [ - QubitProperties( - t1=properties.qubit_property(qubit_idx)["T1"][0], - t2=properties.qubit_property(qubit_idx)["T2"][0], - frequency=properties.qubit_property(qubit_idx)["frequency"][0], - ) - for qubit_idx in range(0, configuration.num_qubits) - ] + qubit_properties = [] + for qi in range(0, configuration.num_qubits): + # TODO faulty qubit handling might be needed since + # faulty qubit reporting qubit properties doesn't make sense. + try: + prop_dict = properties.qubit_property(qubit=qi) + except KeyError: + continue + qubit_properties.append( + QubitProperties( + t1=prop_dict.get("T1", (None, None))[0], + t2=prop_dict.get("T2", (None, None))[0], + frequency=prop_dict.get("frequency", (None, None))[0], + ) + ) in_data["qubit_properties"] = qubit_properties for name in all_instructions: diff --git a/releasenotes/notes/fix-missing-qubit-properties-35137aa5250d9368.yaml b/releasenotes/notes/fix-missing-qubit-properties-35137aa5250d9368.yaml new file mode 100644 index 00000000000..e77d292f08d --- /dev/null +++ b/releasenotes/notes/fix-missing-qubit-properties-35137aa5250d9368.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + A bug that crashes the :func:`.convert_to_target` function when qubit properties + (either T1, T2 or frequency) are missing was fixed. + The missing property values in :class:`.QubitProperties` are filled with ``None``. diff --git a/test/python/providers/faulty_backends.py b/test/python/providers/faulty_backends.py index d5acf9f9096..f57cf1b594c 100644 --- a/test/python/providers/faulty_backends.py +++ b/test/python/providers/faulty_backends.py @@ -34,6 +34,18 @@ def properties(self): return BackendProperties.from_dict(props) +class Fake7QV1MissingQ1Property(Fake7QPulseV1): + """A fake 7 qubit backend, with a missing T1 property in q1.""" + + def properties(self): + """Returns a snapshot of device properties as recorded on 8/30/19. + Remove property from qubit 1. + """ + props = super().properties().to_dict() + props["qubits"][1] = filter(lambda q: q["name"] != "T1", props["qubits"][1]) + return BackendProperties.from_dict(props) + + class Fake7QV1FaultyCX01CX10(Fake7QPulseV1): """A fake 5 qubit backend, with faulty CX(Q1, Q0) and CX(Q0, Q1) 0 (↔) 1 ↔ 3 ↔ 4 diff --git a/test/python/providers/test_faulty_backend.py b/test/python/providers/test_faulty_backend.py index bec568aa3ea..e1a3f9fa179 100644 --- a/test/python/providers/test_faulty_backend.py +++ b/test/python/providers/test_faulty_backend.py @@ -17,6 +17,7 @@ from .faulty_backends import ( Fake7QV1FaultyCX01CX10, Fake7QV1FaultyQ1, + Fake7QV1MissingQ1Property, Fake7QV1FaultyCX13CX31, ) @@ -35,7 +36,7 @@ def test_faulty_qubits(self): """Test faulty_qubits method.""" self.assertEqual(self.backend.properties().faulty_qubits(), [1]) - def test_convert_to_target(self): + def test_convert_to_target_with_filter(self): """Test converting legacy data structure to V2 target model with faulty qubits. Measure and Delay are automatically added to the output Target @@ -44,31 +45,40 @@ def test_convert_to_target(self): """ # Filter out faulty Q1 - target_with_filter = convert_to_target( + target = convert_to_target( configuration=self.backend.configuration(), properties=self.backend.properties(), add_delay=True, filter_faulty=True, ) - self.assertFalse( - target_with_filter.instruction_supported(operation_name="measure", qargs=(1,)) - ) - self.assertFalse( - target_with_filter.instruction_supported(operation_name="delay", qargs=(1,)) - ) + self.assertFalse(target.instruction_supported(operation_name="measure", qargs=(1,))) + self.assertFalse(target.instruction_supported(operation_name="delay", qargs=(1,))) + + def test_convert_to_target_without_filter(self): + """Test converting legacy data structure to V2 target model with faulty qubits.""" # Include faulty Q1 even though data could be incomplete - target_without_filter = convert_to_target( + target = convert_to_target( configuration=self.backend.configuration(), properties=self.backend.properties(), add_delay=True, filter_faulty=False, ) - self.assertTrue( - target_without_filter.instruction_supported(operation_name="measure", qargs=(1,)) + self.assertTrue(target.instruction_supported(operation_name="measure", qargs=(1,))) + self.assertTrue(target.instruction_supported(operation_name="delay", qargs=(1,))) + + # Properties are preserved + self.assertEqual( + target.qubit_properties[1].t1, + self.backend.properties().t1(1), + ) + self.assertEqual( + target.qubit_properties[1].t2, + self.backend.properties().t2(1), ) - self.assertTrue( - target_without_filter.instruction_supported(operation_name="delay", qargs=(1,)) + self.assertEqual( + target.qubit_properties[1].frequency, + self.backend.properties().frequency(1), ) @@ -108,3 +118,30 @@ def test_faulty_gates(self): self.assertEqual(len(gates), 2) self.assertEqual([gate.gate for gate in gates], ["cx", "cx"]) self.assertEqual(sorted(gate.qubits for gate in gates), [[0, 1], [1, 0]]) + + +class MissingPropertyQubitBackendTestCase(QiskitTestCase): + """Test operational-related methods of backend.properties() with Fake7QV1MissingQ1Property, + which is like Fake7QV1 but with Q1 with missing T1 property.""" + + backend = Fake7QV1MissingQ1Property() + + def test_convert_to_target(self): + """Test converting legacy data structure to V2 target model with missing qubit property.""" + + target = convert_to_target( + configuration=self.backend.configuration(), + properties=self.backend.properties(), + add_delay=True, + filter_faulty=True, + ) + + self.assertIsNone(target.qubit_properties[1].t1) + self.assertEqual( + target.qubit_properties[1].t2, + self.backend.properties().t2(1), + ) + self.assertEqual( + target.qubit_properties[1].frequency, + self.backend.properties().frequency(1), + )