From 6d605a0d6ab493002729b8db1e5d36d3738078af Mon Sep 17 00:00:00 2001 From: Zachary Schoenfeld <15254979+zachschoenfeld33@users.noreply.github.com> Date: Mon, 14 Jun 2021 13:34:32 -0400 Subject: [PATCH] Add ESP readout support to Qiskit (#6543) * Add tests for esp support * Add reno note * Fix comments and run black * Update docs * Remove explicit use_measure_esp from execute --- qiskit/compiler/assembler.py | 21 ++++++++++++++- qiskit/execute_function.py | 2 +- .../providers/models/backendconfiguration.py | 9 ++++++- .../schemas/backend_configuration_schema.json | 7 ++++- .../notes/esp-readout-3aa5fff772ddbab1.yaml | 23 ++++++++++++++++ test/python/compiler/test_assembler.py | 27 +++++++++++++++++++ 6 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/esp-readout-3aa5fff772ddbab1.yaml diff --git a/qiskit/compiler/assembler.py b/qiskit/compiler/assembler.py index 537cff92b1c0..14988c55ee5a 100644 --- a/qiskit/compiler/assembler.py +++ b/qiskit/compiler/assembler.py @@ -75,6 +75,7 @@ def assemble( parameter_binds: Optional[List[Dict[Parameter, float]]] = None, parametric_pulses: Optional[List[str]] = None, init_qubits: bool = True, + use_measure_esp: Optional[bool] = None, **run_config: Dict, ) -> Qobj: """Assemble a list of circuits or pulse schedules into a ``Qobj``. @@ -140,7 +141,12 @@ def assemble( ['gaussian', 'constant'] init_qubits: Whether to reset the qubits to the ground state for each shot. - Default: ``True``. + Default: ``True``. + use_measure_esp: Whether to use excited state promoted (ESP) readout for the final + measurement in each circuit. ESP readout discriminates between the ``|0>`` and higher + transmon states to improve readout fidelity. See + `here `_. + Default: ``True`` if the backend supports ESP readout, else ``False``. **run_config: Extra arguments used to configure the run (e.g., for Aer configurable backends). Refer to the backend documentation for details on these arguments. @@ -163,6 +169,7 @@ def assemble( max_credits, seed_simulator, init_qubits, + use_measure_esp, rep_delay, qubit_lo_freq, meas_lo_freq, @@ -230,6 +237,7 @@ def _parse_common_args( max_credits, seed_simulator, init_qubits, + use_measure_esp, rep_delay, qubit_lo_freq, meas_lo_freq, @@ -258,6 +266,8 @@ def _parse_common_args( - If any of qubit or meas lo's, or associated ranges do not have length equal to ``n_qubits``. - If qubit or meas lo's do not fit into perscribed ranges. + - If ``use_measure_esp`` is set to ``True`` on a device which does not support ESP + readout. """ # grab relevant info from backend if it exists backend_config = None @@ -343,6 +353,14 @@ def _parse_common_args( for lo_config in schedule_los ] + measure_esp_enabled = getattr(backend_config, "measure_esp_enabled", False) + use_measure_esp = use_measure_esp or measure_esp_enabled # default to backend support value + if use_measure_esp and not measure_esp_enabled: + raise QiskitError( + "ESP readout not supported on this device. Please make sure the flag " + "'use_measure_esp' is unset or set to 'False'." + ) + # create run configuration and populate run_config_dict = dict( shots=shots, @@ -350,6 +368,7 @@ def _parse_common_args( max_credits=max_credits, seed_simulator=seed_simulator, init_qubits=init_qubits, + use_measure_esp=use_measure_esp, rep_delay=rep_delay, qubit_lo_freq=qubit_lo_freq, meas_lo_freq=meas_lo_freq, diff --git a/qiskit/execute_function.py b/qiskit/execute_function.py index aea9daef4c4d..d090ab1811c2 100644 --- a/qiskit/execute_function.py +++ b/qiskit/execute_function.py @@ -242,7 +242,7 @@ def execute( Optionally specify a particular scheduling method. init_qubits (bool): Whether to reset the qubits to the ground state for each shot. - Default: ``True``. + Default: ``True``. run_config (dict): Extra arguments used to configure the run (e.g. for Aer configurable backends). diff --git a/qiskit/providers/models/backendconfiguration.py b/qiskit/providers/models/backendconfiguration.py index 20221d9ecbc5..d5af35603793 100644 --- a/qiskit/providers/models/backendconfiguration.py +++ b/qiskit/providers/models/backendconfiguration.py @@ -245,6 +245,7 @@ def __init__( dtm=None, processor_type=None, parametric_pulses=None, + measure_esp_enabled=False, **kwargs, ): """Initialize a QasmBackendConfiguration Object @@ -300,7 +301,10 @@ def __init__( - segment: Segment this processor belongs to within a larger chip. parametric_pulses (list): A list of pulse shapes which are supported on the backend. For example: ``['gaussian', 'constant']`` - + measure_esp_enabled (bool): Whether excited state promoted (ESP) readout is enabled on + this device. ESP readout discriminates between the ``|0>`` and higher transmon + states to improve readout fidelity. See + `here `_. Defaults to ``False``. **kwargs: optional fields """ self._data = {} @@ -360,6 +364,8 @@ def __init__( if parametric_pulses is not None: self.parametric_pulses = parametric_pulses + self.measure_esp_enabled = measure_esp_enabled + # convert lo range from GHz to Hz if "qubit_lo_range" in kwargs.keys(): kwargs["qubit_lo_range"] = [ @@ -421,6 +427,7 @@ def to_dict(self): "max_shots": self.max_shots, "coupling_map": self.coupling_map, "dynamic_reprate_enabled": self.dynamic_reprate_enabled, + "measure_esp_enabled": self.measure_esp_enabled, } if hasattr(self, "supported_instructions"): diff --git a/qiskit/schemas/backend_configuration_schema.json b/qiskit/schemas/backend_configuration_schema.json index 0b2deb698a99..884da310548e 100644 --- a/qiskit/schemas/backend_configuration_schema.json +++ b/qiskit/schemas/backend_configuration_schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://www.qiskit.org/schemas/backend_config_schema.json", "description": "Qiskit device backend configuration", - "version": "1.4.3", + "version": "1.4.4", "definitions": { "hamiltonian": { "type": "object", @@ -157,6 +157,11 @@ "description": "Whether delay between programs can be set dynamically using 'rep_delay').", "default": false }, + "measure_esp_enabled": { + "type": "boolean", + "description": "Whether ESP readout is supported by the backend.", + "default": false + }, "supported_instructions": { "type": "array", "minItems": 0, diff --git a/releasenotes/notes/esp-readout-3aa5fff772ddbab1.yaml b/releasenotes/notes/esp-readout-3aa5fff772ddbab1.yaml new file mode 100644 index 000000000000..c539976aa709 --- /dev/null +++ b/releasenotes/notes/esp-readout-3aa5fff772ddbab1.yaml @@ -0,0 +1,23 @@ +--- +features: + - | + Support for Excited State Promoted (ESP) readout from Qiskit has been added. ESP readout + discriminates between ``|0>`` and higher order energy states of transmon qubits in order to + improve readout fidelity. Further details may be found + `here `_. + + To check whether the backend supports ESP readout, one can query:: + + measure_esp_enabled = getattr(backend.configuration(), "measure_esp_enabled", False) + + If the flag ``measure_esp_enabled`` is not in the backend configuration, we return ``False`` + by default. + + A user can request usage of ESP readout via the ``use_measure_esp`` flag in + :meth:`~qiskit.compiler.assemble`. This tells the backend to use ESP readout on the final + measurement of each circuit. This is done via:: + + qobj = assemble(circ, backend, use_measure_esp=True) + + If ``measure_esp_enabled=False`` and ``use_measure_esp=True``, a ``QiskitError`` is raised. If + ``use_measure_esp`` is not set, it will default to the value of ``measure_esp_enabled``. diff --git a/test/python/compiler/test_assembler.py b/test/python/compiler/test_assembler.py index 99d71821dc0d..ab0d9ff19665 100644 --- a/test/python/compiler/test_assembler.py +++ b/test/python/compiler/test_assembler.py @@ -471,6 +471,33 @@ def test_init_qubits_false(self): qobj = assemble(self.circ, init_qubits=False) self.assertEqual(qobj.config.init_qubits, False) + def test_measure_esp_not_enabled(self): + """Check that an error is raised if ``use_measure_esp=True`` on a device which does not + support ESP readout.""" + setattr(self.backend_config, "measure_esp_enabled", False) + with self.assertRaises(QiskitError): + assemble(self.circ, self.backend, use_measure_esp=True) + + def test_measure_esp_defaults(self): + """Check that ``use_measure_esp`` defaults to True if ESP readout is enabled on the device + and false otherwise.""" + # esp readout enabled + setattr(self.backend_config, "measure_esp_enabled", True) + qobj = assemble(self.circ, self.backend) + self.assertEqual(qobj.config.use_measure_esp, True) + + # esp readout not enabled + setattr(self.backend_config, "measure_esp_enabled", False) + qobj = assemble(self.circ, self.backend) + self.assertEqual(qobj.config.use_measure_esp, False) + + def test_measure_esp(self): + """Test that ``use_measure_esp=True`` works on a device that supports ESP readout.""" + # esp readout enabled + setattr(self.backend_config, "measure_esp_enabled", True) + qobj = assemble(self.circ, self.backend, use_measure_esp=True) + self.assertEqual(qobj.config.use_measure_esp, True) + def test_circuit_with_global_phase(self): """Test that global phase for a circuit is handled correctly.""" circ = QuantumCircuit(2)