From a306cb67c8fbaab5e3329fa40613d22980aaea29 Mon Sep 17 00:00:00 2001 From: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:40:01 +0200 Subject: [PATCH] Barebone generic backend options (#12747) * Update generic_backend_v2.py * reno * Update barebone-backend-option-675c86df4382a443.yaml * ... * suggestions from code review * Update barebone-backend-option-675c86df4382a443.yaml * tests, typo --- .../fake_provider/generic_backend_v2.py | 63 +++++++++++++------ ...ebone-backend-option-675c86df4382a443.yaml | 8 +++ .../fake_provider/test_generic_backend_v2.py | 20 ++++++ 3 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 releasenotes/notes/barebone-backend-option-675c86df4382a443.yaml diff --git a/qiskit/providers/fake_provider/generic_backend_v2.py b/qiskit/providers/fake_provider/generic_backend_v2.py index 214754080e57..0da1df7eab65 100644 --- a/qiskit/providers/fake_provider/generic_backend_v2.py +++ b/qiskit/providers/fake_provider/generic_backend_v2.py @@ -112,6 +112,8 @@ def __init__( calibrate_instructions: bool | InstructionScheduleMap | None = None, dtm: float | None = None, seed: int | None = None, + pulse_channels: bool = True, + noise_info: bool = True, ): """ Args: @@ -159,6 +161,10 @@ def __init__( None by default. seed: Optional seed for generation of default values. + + pulse_channels: If true, sets default pulse channel information on the backend. + + noise_info: If true, associates gates and qubits with default noise information. """ super().__init__( @@ -175,6 +181,10 @@ def __init__( self._control_flow = control_flow self._calibrate_instructions = calibrate_instructions self._supported_gates = get_standard_gate_name_mapping() + self._noise_info = noise_info + + if calibrate_instructions and not noise_info: + raise QiskitError("Must set parameter noise_info when calibrating instructions.") if coupling_map is None: self._coupling_map = CouplingMap().from_full(num_qubits) @@ -198,7 +208,10 @@ def __init__( self._basis_gates.append(name) self._build_generic_target() - self._build_default_channels() + if pulse_channels: + self._build_default_channels() + else: + self.channels_map = {} @property def target(self): @@ -340,22 +353,31 @@ def _build_generic_target(self): """ # the qubit properties are sampled from default ranges properties = _QUBIT_PROPERTIES - self._target = Target( - description=f"Generic Target with {self._num_qubits} qubits", - num_qubits=self._num_qubits, - dt=properties["dt"], - qubit_properties=[ - QubitProperties( - t1=self._rng.uniform(properties["t1"][0], properties["t1"][1]), - t2=self._rng.uniform(properties["t2"][0], properties["t2"][1]), - frequency=self._rng.uniform( - properties["frequency"][0], properties["frequency"][1] - ), - ) - for _ in range(self._num_qubits) - ], - concurrent_measurements=[list(range(self._num_qubits))], - ) + if not self._noise_info: + self._target = Target( + description=f"Generic Target with {self._num_qubits} qubits", + num_qubits=self._num_qubits, + dt=properties["dt"], + qubit_properties=None, + concurrent_measurements=[list(range(self._num_qubits))], + ) + else: + self._target = Target( + description=f"Generic Target with {self._num_qubits} qubits", + num_qubits=self._num_qubits, + dt=properties["dt"], + qubit_properties=[ + QubitProperties( + t1=self._rng.uniform(properties["t1"][0], properties["t1"][1]), + t2=self._rng.uniform(properties["t2"][0], properties["t2"][1]), + frequency=self._rng.uniform( + properties["frequency"][0], properties["frequency"][1] + ), + ) + for _ in range(self._num_qubits) + ], + concurrent_measurements=[list(range(self._num_qubits))], + ) # Generate instruction schedule map with calibrations to add to target. calibration_inst_map = None @@ -380,8 +402,11 @@ def _build_generic_target(self): f"Provided basis gate {name} needs more qubits than {self.num_qubits}, " f"which is the size of the backend." ) - noise_params = self._get_noise_defaults(name, gate.num_qubits) - self._add_noisy_instruction_to_target(gate, noise_params, calibration_inst_map) + if self._noise_info: + noise_params = self._get_noise_defaults(name, gate.num_qubits) + self._add_noisy_instruction_to_target(gate, noise_params, calibration_inst_map) + else: + self._target.add_instruction(gate, properties=None, name=name) if self._control_flow: self._target.add_instruction(IfElseOp, name="if_else") diff --git a/releasenotes/notes/barebone-backend-option-675c86df4382a443.yaml b/releasenotes/notes/barebone-backend-option-675c86df4382a443.yaml new file mode 100644 index 000000000000..912970845042 --- /dev/null +++ b/releasenotes/notes/barebone-backend-option-675c86df4382a443.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Added two parameters to :class:`.GenericBackendV2` to exclude error (`noise_info`) and + pulse channel information (`pulse_channels`) from the construction of the backend. These parameters + are true by default, replicating the initial default behavior of the constructor. A memory-sensitive + user may set these options to `False` to reduce the memory overhead by 40x when transpiling on large- + scale :class:`.GenericBackendV2`. diff --git a/test/python/providers/fake_provider/test_generic_backend_v2.py b/test/python/providers/fake_provider/test_generic_backend_v2.py index cd7c611b2212..33bf57cf3903 100644 --- a/test/python/providers/fake_provider/test_generic_backend_v2.py +++ b/test/python/providers/fake_provider/test_generic_backend_v2.py @@ -45,6 +45,26 @@ def test_ccx_2Q(self): with self.assertRaises(QiskitError): GenericBackendV2(num_qubits=2, basis_gates=["ccx", "id"]) + def test_calibration_no_noise_info(self): + """Test failing with a backend with calibration and no noise info""" + with self.assertRaises(QiskitError): + GenericBackendV2( + num_qubits=2, + basis_gates=["ccx", "id"], + calibrate_instructions=True, + noise_info=False, + ) + + def test_no_noise(self): + """Test no noise info when parameter is false""" + backend = GenericBackendV2(num_qubits=2, noise_info=False) + self.assertEqual(backend.target.qubit_properties, None) + + def test_no_pulse_channels(self): + """Test no/empty pulse channels when parameter is false""" + backend = GenericBackendV2(num_qubits=2, pulse_channels=False) + self.assertTrue(len(backend.channels_map) == 0) + def test_operation_names(self): """Test that target basis gates include "delay", "measure" and "reset" even if not provided by user."""