This repository has been archived by the owner on Jun 12, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 160
WIP Discriminator #238
Merged
Merged
WIP Discriminator #238
Changes from 39 commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
683bc70
* First draft of API for the abstract discriminator class.
eggerdj a10ba30
* Added diclaimer to discriminator.py
eggerdj cb42110
* Added calibration circuits and expected results as input to Abstra…
eggerdj 5ee9b58
* Added a list of data circuits (i.e. circuits for which we do not know
eggerdj 353880e
* created folder measurement and move the discriminator related class…
eggerdj 31bd583
* deleted discriminator.py.
eggerdj 8e9832c
* Added a skeleton for testing
eggerdj be6a722
* Made linear._calc_data() consistent with data structure.
eggerdj 89c5468
* Cleaned up code style in discriminator.py and unit tests.
eggerdj 8e0426d
* added .ipynb_checkpoints to .gitignore.
eggerdj a7c37cd
* Added quadratic discriminant analysis.
eggerdj f714ad7
* renamed linear.py to iq_discrimination.py.
eggerdj 5befe5a
* Added a filter for discrimination.
eggerdj 3bc9774
* Made small style changes to please pylint.
eggerdj f4da602
* Renamed IQDiscriminationFitter to ScikitIQDiscriminationFitter and:
eggerdj 8216279
* schedules is now an optional argument. Default is to use all results.
eggerdj 80addba
* Adapted the unit tests to the new arguments ordering.
eggerdj 73345c0
* Added the option to rescale the qubit IQ data.
eggerdj 75dbfb0
* Refactored the code so that the scaling parameters are calculated b…
eggerdj 75fe39f
* Added discriminate function to Discriminator.
eggerdj c090c12
* Switched sclaing in discriminator to the sklearn preprocessing scaler.
eggerdj cfbf1ca
* Added the filter to the jupyter notebook.
eggerdj 630aa1b
* Fixed style in ignis.utils.py
eggerdj c36e611
* Fixed style in Utils.py
eggerdj 928fca2
* Small change in docstring.
eggerdj 159fe43
* Added more details in the markdown of the notebook.
eggerdj 5d9aa6e
* Moved utils.py to test folder.
eggerdj bf6b374
* Added y_data into memory of the discriminated level 2 data. See fil…
eggerdj dab3908
* Changed method extract_xdata of ScikitIQDiscriminatorFitter to hand…
eggerdj 88202b4
* Small refactor of extract_xdata to improve readability.
eggerdj af47c16
* Refactored _calc_data in discriminator to handle 'single' and 'avg'…
eggerdj 34e08eb
* Implemented a BaseDiscriminator that is independent of BaseFitter.
eggerdj 4c5dae5
* Refactored the unit tests to the new Discriminator methodology.
eggerdj 507df2b
* Renamed iq_discrimination.py to discriminators.py
eggerdj 0395d50
* Made BaseDiscriminationFitter inherite from ABC.
eggerdj a2d47e4
* IDDiscrimnationFitter inherits from ABC.
eggerdj 85e6095
* Refactored docstrings, e.g. better description and type hints every…
eggerdj f0cd0b0
Merge branch 'master' into discriminator
eggerdj 4917952
* Move the IQ discriminators to their own python file.
eggerdj e3d847a
* Removed ABC from IQDiscriminationFitter.
eggerdj 1fca249
* Improved docstrings.
eggerdj 2842813
Add inits to test
dcmckayibm 5c93932
* Added module docstrings.
eggerdj 81d8f81
* Added class and method docstrings to test methods.
eggerdj c5a4543
move the discriminator tutorial
dcmckayibm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
233 changes: 233 additions & 0 deletions
233
qiskit/ignis/measurement/discriminator/discriminators.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2019. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
from abc import ABC, abstractmethod | ||
from typing import Union, List | ||
|
||
from qiskit.exceptions import QiskitError | ||
from qiskit.result import Result | ||
from qiskit.pulse.schedule import Schedule | ||
|
||
|
||
class BaseDiscriminationFitter(ABC): | ||
""" | ||
IQDiscriminatorFitter takes IQ level 1 data produced by calibration | ||
measurements with a known expected state. It fits a discriminator | ||
that can be used to produce level 2 data, i.e. counts of quantum states. | ||
""" | ||
|
||
def __init__(self, cal_results: Union[Result, List[Result]], | ||
qubit_mask: List[int], expected_states: List[str], | ||
standardize: bool = False, | ||
schedules: Union[List[str], List[Schedule]] = None): | ||
""" | ||
Args: | ||
cal_results (Union[Result, List[Result]]): calibration results, | ||
Result or list of Result used to fit the discriminator. | ||
qubit_mask (List[int]): determines which qubit's level 1 data to | ||
use in the discrimination process. | ||
expected_states (List[str]): a list that should have the same | ||
length as schedules. All results in cal_results are used if | ||
schedules is None. expected_states must have the corresponding | ||
length. | ||
standardize (bool): if true the discriminator will standardize the | ||
xdata using the internal method _scale_data. | ||
schedules (Union[List[str], List[Schedule]]): The schedules or a | ||
subset of schedules in cal_results used to train the | ||
discriminator. The user may also pass the name of the schedules | ||
instead of the schedules. If schedules is None, then all the | ||
schedules in cal_results are used. | ||
""" | ||
|
||
# Use all results in cal_results if schedules is None | ||
if schedules is None: | ||
schedules = self._get_schedules(cal_results) | ||
|
||
self._expected_state = {} | ||
self._add_expected_states(expected_states, schedules) | ||
|
||
# Used to rescale the xdata qubit by qubit. | ||
self._description = None | ||
self._standardize = standardize | ||
self._scaler = None | ||
self._qubit_mask = qubit_mask | ||
self._schedules = schedules | ||
self._backend_result_list = [] | ||
self._fitted = False | ||
|
||
if cal_results is not None: | ||
if isinstance(cal_results, list): | ||
for result in cal_results: | ||
self._backend_result_list.append(result) | ||
else: | ||
self._backend_result_list.append(cal_results) | ||
|
||
self._xdata = self.get_xdata(self._backend_result_list, schedules) | ||
self._ydata = self.get_ydata(self._backend_result_list, schedules) | ||
|
||
def _add_ydata(self, schedule: Union[Schedule, str]): | ||
""" | ||
Adds the expected state of schedule to self._ydata. | ||
Args: | ||
schedule (Union[Schedule, str]): schedule or schedule name. | ||
Used to get the expected state. | ||
""" | ||
if isinstance(schedule, Schedule): | ||
self._ydata.append(self._expected_state[schedule.name]) | ||
else: | ||
self._ydata.append(self._expected_state[schedule]) | ||
|
||
def add_data(self, result: Result, expected_states: List[str], | ||
refit: bool = True, | ||
schedules: Union[List[Schedule], List[str]] = None): | ||
""" | ||
Args: | ||
result (Result): a Result containing new data to be used to | ||
train the discriminator. | ||
expected_states (List[str]): the expected states of the results in | ||
result. | ||
refit (bool): refit the discriminator if True. | ||
schedules (Union[List[Schedule], List[str]]): | ||
""" | ||
eggerdj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if schedules is None: | ||
schedules = self._get_schedules(result) | ||
|
||
self._backend_result_list.append(result) | ||
self._add_expected_states(expected_states, schedules) | ||
self._schedules.extend(schedules) | ||
self._xdata = self.get_xdata(self._backend_result_list, schedules) | ||
self._ydata = self.get_ydata(self._backend_result_list, schedules) | ||
|
||
if refit: | ||
self.fit() | ||
|
||
def _add_expected_states(self, expected_states: List[str], | ||
schedules: Union[List[Schedule], List[str]]): | ||
""" | ||
Adds the given expected states to self._expected_states. | ||
Args: | ||
expected_states (List[str]): list of expected states. Must have the | ||
same length as the number of schedules. | ||
schedules (Union[List[Schedule], List[str]]): schedules or their | ||
names corresponding to the expected states. | ||
""" | ||
if len(expected_states) != len(schedules): | ||
raise QiskitError('Number of input schedules and assigned ' | ||
'states must be equal.') | ||
|
||
for idx, schedule in enumerate(schedules): | ||
if isinstance(schedule, Schedule): | ||
name = schedule.name | ||
else: | ||
name = schedule | ||
expected_state = expected_states[idx] | ||
self._expected_state[name] = expected_state | ||
|
||
@staticmethod | ||
def _get_schedules(results: Union[Result, List[Result]]) -> List[str]: | ||
""" | ||
Extracts the names of all Schedules in a Result or a list of Result. | ||
Args: | ||
results (Union[Result, List[Result]]): the results for which to | ||
extract the names, | ||
Returns (List[str]): | ||
The name of the schedules in results. | ||
""" | ||
schedules = [] | ||
if isinstance(results, Result): | ||
for res in results.results: | ||
schedules.append(res.header.name) | ||
else: | ||
for result in results: | ||
schedules.extend([_.header.name for _ in result.results]) | ||
|
||
return schedules | ||
|
||
@property | ||
def expected_states(self): | ||
"""Returns the expected states used to train the discriminator.""" | ||
return self._expected_state | ||
|
||
@property | ||
def schedules(self): | ||
"""Returns the schedules with which the discriminator was fitted.""" | ||
return self._schedules | ||
|
||
@property | ||
def fitted(self): | ||
"""True if the discriminator has been fitted to calibration data.""" | ||
return self._fitted | ||
|
||
@abstractmethod | ||
def _scale_data(self, xdata: List[List[float]], | ||
refit: bool = False) -> List[List[float]]: | ||
""" | ||
Scales xdata, for instance, by transforming it to zero mean and unit | ||
variance data. | ||
Args: | ||
xdata (List[List[float]]): data as a list of features. Each | ||
feature is itself a list. | ||
refit (bool): if true than self._scaler is refit using the given | ||
xdata. | ||
Returns (List[List[float]]): the scaled xdata as a list of features. | ||
""" | ||
pass | ||
|
||
@abstractmethod | ||
def get_xdata(self, results: Union[Result, List[Result]], | ||
schedules: Union[List[str], List[Schedule]] = None) \ | ||
-> List[List[float]]: | ||
""" | ||
Retrieves feature data (xdata) for the discriminator. | ||
Args: | ||
results (Union[Result, List[Result]]): the get_memory() method is | ||
used to retrieve the level 1 data. If result is a list of | ||
Result then the first Result to return the data of schedule in | ||
schedules is used. | ||
schedules (Union[List[str], List[Schedule]]): Either the names of | ||
the schedules or the schedules themselves. | ||
Returns (List[List[float]]): data as a list of features. Each feature | ||
is a list. | ||
""" | ||
pass | ||
|
||
@abstractmethod | ||
def get_ydata(self, results: Union[Result, List[Result]], | ||
schedules: Union[List[str], List[Schedule]] = None) \ | ||
-> List[str]: | ||
""" | ||
Args: | ||
results (Union[Result, List[Result]]): results for which to | ||
retrieve the y data (i.e. expected states). | ||
schedules (Union[List[str], List[Schedule]]): the schedules for | ||
which to get the y data. | ||
Returns (List[str]): the y data, i.e. expected states. get_ydata is | ||
designed to produce y data with the same length as the x data. | ||
""" | ||
pass | ||
|
||
@abstractmethod | ||
def fit(self): | ||
""" Fits the discriminator using self._xdata and self._ydata. """ | ||
pass | ||
|
||
@abstractmethod | ||
def discriminate(self, x_data: List[List[float]]) -> List[str]: | ||
""" | ||
Applies the discriminator to x_data | ||
Args: | ||
x_data (List[List[float]]): list of features. Each feature is | ||
itself a list. | ||
Returns (List[str]): the discriminated x_data as a list of labels. | ||
""" | ||
pass |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the examples be pure python examples rather than a notebook? I think notebooks should be reserved for
qiskit-tutorials
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For ignis I put these in the PR for testing then we pull them out into tutorials after (a way to do both concurrently without having to deal with branches in multiple repos)