# Quantum Inspire SDK
#
# Copyright 2022 QuTech Delft
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any, Dict, List, Union
from qiskit.exceptions import QiskitError
from qiskit.result import postprocess, Result
from qiskit.result.models import ExperimentResult
from quantuminspire.exceptions import QiskitBackendError
[docs]class QIResult(Result): # type: ignore
"""
A result object returned by QIJob:
qi_backend = QI.get_backend('QX single-node simulator')
job = qi_backend.retrieve_job(job_id)
qi_result = job.result()
"""
def __init__(self, backend_name: str, backend_version: str, qobj_id: str, job_id: str, success: bool,
results: List[ExperimentResult], date: Any = None, status: Any = None, header: Any = None,
**kwargs: Any) -> None:
"""
Construct a new QIResult object. Not normally called directly, use a QIJob to get the QIResult.
Based on Qiskit Result.
:param backend_name: backend name.
:param backend_version: backend version, in the form X.Y.Z.
:param qobj_id: user-generated Qobj id.
:param job_id: unique execution id from the backend.
:param success: True if complete input qobj executed correctly. (Implies each experiment success)
:param results: corresponding results for array of experiments of the input qobj
:param date: date to be added to the result object
:param status: status to be added to the result object
:param header: header to be added to the result object
:param kwargs: other parameters (added as metadata to the result object)
"""
super().__init__(backend_name, backend_version, qobj_id, job_id, success,
results, date, status, header, **kwargs)
[docs] def get_raw_result(self, field_name: str, experiment: Any = None) -> Union[List[Dict[str, Any]],
List[List[List[str]]],
List[List[Dict[str, float]]]]:
"""
Get the specific and unprocessed result data of an experiment.
Can handle single and multi measurement results.
:param field_name: the specific result that is requested
Can be one of 'calibration', 'counts', 'memory', 'probabilities' or the multi measurement results
'counts_multiple_measurement', 'memory_multiple_measurement', 'probabilities_multiple_measurement'
:param experiment: the index of the experiment (str or QuantumCircuit or Schedule or int or None),
as specified by ``get_data()``.
:return:
A list with result structures which holds the specific unprocessed result for each experiment.
:raises QiskitBackendError: raised if the results requested are not in the results for the experiment(s).
"""
results_list = []
if experiment is None:
exp_keys = range(len(self.results))
else:
exp_keys = [experiment] # type: ignore
for key in exp_keys:
if field_name in self.data(key).keys():
result_values = self.data(key)[field_name]
results_list.append(result_values)
else:
raise QiskitBackendError(f'Result does not contain {field_name} data for experiment "{key}"')
return results_list
[docs] def get_probabilities(self, experiment: Any = None) -> Union[Dict[str, float], List[Dict[str, float]]]:
"""Get the probability data of an experiment. The probability data is added as a separate result by
Quantum Inspire backend.
:param experiment: the index of the experiment (str or QuantumCircuit or Schedule or int or None),
as specified by ``get_data()``.
:return:
A single or a list of dictionaries which holds the states and probabilities for respectively 1 or more
experiment result.
:raises QiskitBackendError: raised if there are no probabilities in a result for the experiment(s).
"""
if experiment is None:
exp_keys = range(len(self.results))
else:
exp_keys = [experiment] # type: ignore
dict_list: List[Dict[str, float]] = []
for key in exp_keys:
exp = self._get_experiment(key)
try:
header = exp.header.to_dict()
except (AttributeError, QiskitError): # header is not available
header = None
if "probabilities" in self.data(key).keys():
probabilities = self.data(key)["probabilities"]
dict_list.append(postprocess.format_counts(probabilities, header))
else:
raise QiskitBackendError(f'No probabilities for experiment "{key}"')
# Return first item of dict_list if size is 1
if len(dict_list) == 1:
return dict_list[0]
return dict_list
[docs] def get_probabilities_multiple_measurement(self, experiment: Any = None) -> Union[List[Dict[str, float]],
List[List[Dict[str, float]]]]:
"""
Get the probability data of an experiment for all measurement blocks.
The probability data is added as a separate result by Quantum Inspire backend.
:param experiment: the index of the experiment (str or QuantumCircuit or Schedule or int or None),
as specified by ``get_data()``.
:return:
One list or a list of list of dictionaries which holds the states and probabilities for each measurement
block for respectively 1 or more experiment result.
:raises QiskitBackendError: raised if there are no multi measurement probabilities in a result for the
experiment(s).
"""
if experiment is None:
exp_keys = range(len(self.results))
else:
exp_keys = [experiment] # type: ignore
list_of_dict_list: List[List[Dict[str, float]]] = []
for key in exp_keys:
exp = self._get_experiment(key)
try:
header = exp.header.to_dict()
except (AttributeError, QiskitError): # header is not available
header = None
if "probabilities_multiple_measurement" in self.data(key).keys():
dict_list: List[Dict[str, float]] = []
for probabilities in self.data(key)["probabilities_multiple_measurement"]:
dict_list.append(postprocess.format_counts(probabilities, header))
list_of_dict_list.append(dict_list)
else:
raise QiskitBackendError(f'No probabilities_multiple_measurement for experiment "{key}"')
# Return first item of list_dict_list if size is 1
if len(list_of_dict_list) == 1:
return list_of_dict_list[0]
return list_of_dict_list
[docs] def get_calibration(self, experiment: Any = None) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
"""Get the calibration data of an experiment. The calibration data is added as a separate result item by
Quantum Inspire backend.
:param experiment: the index of the experiment, as specified by ``get_data()``.
experiment can be: str or QuantumCircuit or Schedule or int or None
:return:
Single or a list of dictionaries which holds the calibration data for respectively 1 or more experiment(s).
Exact format depends on the backend. A simulator backend has no calibration data (None is returned)
:raises QiskitBackendError: raised if there is no calibration data in a result for the experiment(s).
"""
if experiment is None:
exp_keys = range(len(self.results))
else:
exp_keys = [experiment] # type: ignore
dict_list: List[Dict[str, float]] = []
for key in exp_keys:
if "calibration" in self.data(key).keys():
calibration = self.data(key)["calibration"]
dict_list.append(calibration)
else:
raise QiskitBackendError(f'No calibration data for experiment "{key}"')
# Return first item of dict_list if size is 1
if len(dict_list) == 1:
return dict_list[0]
return dict_list