pygsti.extras.drift
¶
Drift Detection and Characterization Sub-package
Submodules¶
Package Contents¶
Classes¶
The StabilityAnalyzer is designed to implement a stability analysis on time-series data from quantum |
- class pygsti.extras.drift.StabilityAnalyzer(ds, transform='auto', marginalize='auto', mergeoutcomes=None, constnumtimes='auto', ids=False)¶
Bases:
object
The StabilityAnalyzer is designed to implement a stability analysis on time-series data from quantum circuits. It stores this time-series data, and contains methods for implementing instability detection and characterization, using spectral analysis techniques. These methods work on time-series data from any set of circuits, because they are entirely agnostic to the details of the circuits, e.g., they are not based on the process matrix model of GST.
This object encapsulates stand-alone data analysis methods, but it is also the basis for implementing time-resolved benchmarking or tomography (e.g., time-resolved RB, GST or Ramsey spectroscopy). in pyGSTi.
- __str__(self)¶
Return str(self).
- compute_spectra(self, frequencies='auto', freqpointers={})¶
” Generates and records power spectra. This is the first stage in instability detection and characterization with a StabilityAnalyzer.
- Parameters
frequencies ('auto' or list, optional) –
The frequencies that the power spectra are calculated for. If ‘auto’ these are automatically determined from the meta-data of the time-series data (e.g., using the mean time between data points) and the transform being used. If not ‘auto’, then a list of lists, where each list is a set of frequencies that are the frequencies corresponding to one or more power spectra. The frequencies that should be paired to a given power spectrum are specified by freqpointers.
These frequencies (whether automatically calculated or explicitly input) have a fundmentally different meaning depending on whether the transform is time-stamp aware (here, the LSP) or not (here, the DCT and DFT).
Time-stamp aware transforms take the frequencies to calculate powers at as an input, so the specified frequencies are, explicitly, the frequencies associated with the powers. The task of choosing the frequencies amounts to picking the best set of frequencies at which to interogate the true probability trajectory for components. As there are complex factors involved in this choice that the code has no way of knowing, sometimes it is best to choose them yourself. E.g., if different frequencies are used for different circuits it isn’t possible to (meaningfully) averaging power spectra across circuits, but this might be preferable if the time-step is sufficiently different between different circuits – it depends on your aims.
For time-stamp unaware transforms, these frequencies should be the frequencies that, given that we’re implementing the, e.g., DCT, the generated power spectrum is implicitly with respect to. In the case of data on a fixed time-grid, i.e., equally spaced data, then there is a precise set of frequencies implicit in the transform (which will be accurately extracted with frequencies set to auto). Otherwise, these frequencies are explicitly at least slightly ad hoc, and choosing these frequencies amounts to choosing those frequencies that “best” approximate the properties being interogatted with fitting each, e.g., DCT basis function to the (timestamp-free) data. The ‘auto’ option bases there frequencies solely on the mean time step and the number of times, and is a decent option when the time stamps are roughly equally spaced for each circuit.
These frequencies should be in units of 1/t where ‘t’ is the unit of the time stamps.
freqpointers (dict, optional) – Specifies which frequencies correspond to which power spectra. The keys are power spectra labels, and the values are integers that point to the index of frequencies (a list of lists) that the relevant frquencies are found at. Whenever a power spectra is not included in freqpointers then this defaults to 0. So if frequencies is specified and is a list containing a single list (of frequencies) then freqpointers can be left as the empty dictionary.
- Returns
None
- dof_reduction(self, axislabel)¶
Find the null hypothesis chi2 degree of freedom (DOF) reduction when averaging power spectrum along axislabel.
Under null hypohesis, each base spectrum is distributed according to a chi2/k with a DOF k for some k (obtainable via num_degrees_of_freedom()).
Under the composite null hypothesis the power spectrum, averaged along the axislabel axis is chi2/(numspectra*k - l) with a DOF of (numspectra*k - l) for some l, where numspectra is the number of spectrum along this axis.
This function returns l.
- _check_dofreduction_set(self, axislabel)¶
Checks whether the DOF reduction is set along an axis, i.e., it is not None. If it is None, that means that we do not know how to reduce the DOF when averaging along that axis.
- num_degrees_of_freedom(self, label, adjusted=False)¶
Returns the number of degrees of freedom (DOF) for a power in the power spectrum specified by label. This is the DOF in the chi2 distribution that the powers are (approximately) distributed according to, under the null hypothesis of stable circuits.
- Parameters
label (tuple) – The label specifying power spectrum, or type of power spectrum
adjusted (bool, optional) – Currently does nothing. Placeholder for future improvement
- Returns
float
- num_spectra(self, label)¶
The number of power spectra in the “class” of spectra specified by label, where label is a tuple containing some subset of ‘dataset’, ‘circuit’ and ‘outcome’. The strings it contains specified those axes that are not averaged, and those not contained are axes that are averaged. For example, (‘circuit’,) is the number of power spectra after averaging over DataSets (often 1) and outcomes (often 2), and it is just the total number of circuits.
- same_frequencies(self, dictlabel={})¶
Checks whether all the “base” power spectra defined by dictlabel are all with respect to the same frequencies.
- Parameters
dictlabel (dict, optional) – Specifies the set of “base” power spectra. Keys should be a subset of ‘dataset’, ‘circuit’ and ‘outcome’. For each string included as a key, we restrict to only those power spectra with associated with the corresponding value. For example, if ‘circuit’ is a key the value should be a Circuit and we are looking at only those power spectra obtained from the data for that circuit. So an empty dict means we look at every base spectra
- Returns
Bool – True only if the spectra defined by dictlabel are all with respect to the same frequencies.
- averaging_allowed(self, dictlabel={}, checklevel=2)¶
Checks whether we can average over the specified “base” power spectra.
- Parameters
dictlabel (dict, optional) – Specifies the set of “base” power spectra. Keys should be a subset of ‘dataset’, ‘circuit’ and ‘outcome’. For each string included as a key, we restrict to only those power spectra with associated with the corresponding value. For example, if ‘circuit’ is a key the value should be a Circuit and we are looking at only those power spectra obtained from the data for that circuit. So an empty dict means we look at every base spectra
checklevel (int, optiona;) –
- The degree of checking.
0: the function is trivial, and returns True
- 1: the function checks that all the power spectra to be averaged are associated with the same
frequencies
- 2+: checks that we can calculate the DOF for that averaged power spectrum, so that hypothesis
testing can be implemented on it.
- Returns
Bool – True if the power spectra pass the tests for the validity of averaging over them.
- _index(self, axislabel, key)¶
Returns the spectra array index for a key along a specific axis. For example, axislabel could be ‘circuit’ and ‘key’ and Circuit for the DataSet, and this will return the index in spectra array to find the spectra for that circuit.
- _dictlabel_to_averaging_axes_and_array_indices(self, dictlabel)¶
Returns the axes to average over, and the indices of the reduced array, for a spectrum labelled by the input dictionary
- Parameters
dictlabel (dict) – A dictionary labelling a spectrum, with keys are some subset of ‘dataset’, ‘circuit’ and ‘outcome’, and values that are valid options for those keys. E.g., for ‘circuit’ this is one of the Circuits in the stored DataSet.
- Returns
tuple – The axes to average over. This is the axes corresponding to each of ‘dataset’, ‘circuit’ and ‘outcome’ that aren’t elements of the input dictionary
tuple – The indices for the spectrum after any averaging. This is the indices for the values of the keys.
- power_spectrum(self, dictlabel=None, returnfrequencies=True, checklevel=2)¶
Returns a power spectrum.
- Parameters
dictlabel (dict, optional) – A power spectra has been calculated for each (DataSet, Circuit, circuit) outcome triple of the stored data. We can average over any of these axes. The dictlabel specifies which axes to average over, and which value to specify for the parameters that we are not averaging over. The keys are a subset of ‘dataset’, ‘circuit’ and ‘outcome’. For any of these strings not included, we average over that axis. For each string included, the item should be a key for one of the stored DataSets, a Circuit in the DataSet, and a possible outcome for that Circuit, respectively. If None then defaults to {}, corresponding to the power spectrum obtained by averarging over all the “base” spectra.
returnfrequences (bool, optional) – Whether to also return the corresponding frequencies, as the first argument.
checklevel (int, optional) – The level of checking to do, when averaging over axes, for whether averaging over that axis is a meaningful thing to do. If checklevel = 0 then no checks are performed. If checklevel > 0 then the function checks that all the power spectra to be averaged are associated with the same frequencies. If checklevel > 1 we can also check that we can calculate the DOF for that averaged power spectrum, so that hypothesis testing can be implemented on it.
- Returns
if returnfrequencies –
- array
The frequencies associated with the returned powers.
array – The power spectrum.
- _get_averaged_spectrum(self, dictlabel={}, returnfrequencies=True, checklevel=2)¶
A subroutine of the method power_spectrum(). See the docstring of that method for details.
- maximum_power(self, dictlabel={}, freqsubset=None)¶
Returns the maximum power in a power spectrum.
- Parameters
dictlabel (dict, optional) – The dictionary labelling the spectrum. The same format as in the power_spectrum() method. See the docstring of that method for more details.
freqsubset (list, optional) – A list of indices, that specify the subset of frequency indices to maximize over.
- Returns
float – The maximal power in the spectrum.
- maximum_power_pvalue(self, dictlabel={}, freqsubset=None, cutoff=0)¶
The p-value of the maximum power in a power spectrum.
- Parameters
dictlabel (dict, optional) – The dictionary labelling the spectrum. The same format as in the power_spectrum() method. See the docstring of that method for more details.
freqsubset (list, optional) – A list of indices, that specify the subset of frequency indices to consider.
cutoof (float, optional) – The minimal allowed p-value.
- Returns
float – The p-value of the maximal power in the specified spectrum.
- run_instability_detection(self, significance=0.05, freqstest=None, tests='auto', inclass_correction={}, betweenclass_weighting='auto', saveas='default', default=True, overwrite=False, verbosity=1)¶
Runs instability detection, by performing statistical hypothesis tests on the power spectra generated from the time-series data. Before running this method it is necessary to generate power spectra using the compute_spectra() method.
- Parameters
significance (float, optional) – The global significance level. With defaults for all other inputs (a wide range of non-default options), the family-wise error rate of the set of all hypothesis tests performed is controlled to this value.
freqstest (None or list, optional) – If not not None, a list of the frequency indices at which to test the powers. Leave as None to perform comprehensive testing of the power spectra.
tests ('auto' or tuple, optional) –
Specifies the set of hypothesis tests to perform. If ‘auto’ then an set of tests is automatically chosen. This set of tests will be suitable for most purposes, but sometimes it is useful to override this. If a tuple, the elements are “test classes”, that specifies a set of hypothesis tests to run, and each test class is itself specified by a tuple. The tests specified by each test class in this tuple are all implemented. A test class is a tuple containing some subset of ‘dataset’, ‘circuit’ and ‘outcome’, which specifies a set of power spectra. Specifically, a power spectra has been calculated for the clickstream for every combination of eachinput DataSet (e.g., there are multiple DataSets if there has been marginalization of multi-qubit data), each Circuit in the DataSet, and each possible outcome in the DataSet. For each of “dataset”, “circuit” and “outcome” not included in a tuple defining a test class, the coresponding “axis” of the 3-dimensional array of spectra is averaged over, and these spectra are then tested. So the tuple () specifies the “test class” whereby we test the power spectrum obtained by averaging all power spectra; the tuple (‘dataset’,’circuit’) specifies the “test class” whereby we average only over outcomes, obtaining a single power spectrum for each DataSet and Circuit combination, which we test.
The default option for “tests” is appropriate for most circumstances, and it consists of (), (‘dataset’) and (‘dataset’, ‘circuit’) with duplicates removed (e.g., if there is a single DataSet then () is equivalent to (‘dataset’)).
inclass_correction (dict, optional) – A dictionary with keys ‘dataset’, ‘circuit’, ‘outcome’ and ‘spectrum’, and values that specify the type of multi-test correction used to account for the multiple tests being implemented. This specifies how the statistically significance is maintained within the tests implemented in a single “test class”.
betweenclass_weighting ('auto' or dict, optional) – The weighting to use to maintain statistical significance between the different classes of test being implemented. If ‘auto’ then a standard Bonferroni correction is used.
default (bool, optional) – This method can be run multiple times, to implement independent instability detection runs (if you are doing this, make sure you know what you’re doing! For example, deciding on-the-fly what hypothesis tests to run is statistically very dubious!). One of these is set as the default: unless specified otherwise its results are returned by all of the “get” methods. One the first call to this method, this is is ignored and it is always set to True.
saveas (str, optional) – This string specifies the name under which the results of this run of instability detection is saved. If not implementing multiple calls to this function there is no need to change this from ‘default’.
overwrite (bool, optional) – If this method has already been called, and results saved under the string “saveas”, this specifies whether to overwrite the old results or to raise an error.
verbosity (int, optional) – The amount of print-to-screen.
- Returns
None
- statistical_significance(self, detectorkey=None)¶
The statistical significance level of the instability detection
- Parameters
detectorkey (None or string, optional) – Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
- Returns
float – The statistical significance level of the instability detection
- _equivalent_implemented_test(self, test, detectorkey=None)¶
Finds an equivalent test that was implemented. For example, if () was implemented, the input is (‘dataset’), and self.data contains only 1 DataSet, then () will be returned – because then averaging or not averaging over DataSets is trivial, and so () and (‘dataset’) are equivalent tests. If there is no equivalent test, then None is returned.
- unstable_circuits(self, getmaxtvd=False, detectorkey=None, fromtests='auto', freqindices=False, estimatekey=None, dskey=None)¶
Returns a dictionary, containing all the circuits that instability has been detected for as keys, with the values being the frequencies of the detected instability.
- Parameters
getmaxtvd (bool, optional) – Whether to also return the bound on the TVD deviation, as given by the maximum_tvd_bound() method. If True, then the values of the returned dictionary are a 2-element list: the first element is the frequencies detected for the unstable circuits, and the second element is this TVD bound.
detectorkey (None or string, optional) – Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
fromtests (str or tuple, optional) – The test results to use when deciding what circuits are unstable. If a tuple, it should be a subset of the “test classes” run, each specified by a tuple. If “auto”, then all tests that individually look at the data from each circuit are included. This includes every test implemented of the null hypothesis that that circuit is stable.
freqindices (bool, optional) – If True then the frequencies are returned as a list of integers, which are the indices in the frequency list corresponding to the power spectrum for that circuit. If False then the frequencies are returned in units of 1/t where ‘t’ is the units of the time stamps.
estimatekey (None or tuple, optional) – Only relevant if getmaxtvd is True. The name of the estimate of the probability trajectories to use for calculating the TVD bound.
dskey (None or string, optional) – The DataSet to return the results for. Need if more than one DataSet has been analyzed, but otherwise can be left as None.
- Returns
dict – A dictionary of the unstable circuits.
- instability_indices(self, dictlabel={}, detectorkey=None)¶
Returns the frequency indices that instability has been detected at in the specified power spectrum
- Parameters
dictlabel (dict, optional) – The label for the spectrum to extract the instability frequency indices for.
detectorkey (None or string, optional) – Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
- Returns
list – The instability frequency indices.
- instability_frequencies(self, dictlabel={}, detectorkey=None)¶
Returns the frequencies that instability has been detected at in the specified power spectrum. These frequencies are given in units of 1/t where ‘t’ is the unit of the time stamps.
- Parameters
dictlabel (dict, optional) – The label for the spectrum to extract the instability frequencyies for.
detectorkey (None or string, optional) – Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
- Returns
list – The instability frequencies
- power_threshold(self, test, detectorkey=None)¶
The statistical significance threshold for any power spectrum in the set specified by the tuple test.
- test
A tuple specifying the class of power spectra, to extract the power threshold for. Contains some subset of ‘dataset’, ‘circuit’ and ‘outcome’, and it should correspond to a test that was implemented.
- detectorkeyNone or string, optional
Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
- Returns
float – The power threshold.
string – The type of threshold. This is ‘true’ if it is true threshold, in the sense that it is data-independent and can be precalculated without the data. This is the sort of threshold one obtains when doing a Bonferroni correction. This is ‘pseudo’ if it is a threshold obtained from a p-value ordering procedure, like the Holms’ method or the Benjamini-Hochberg procedure, because it is not a true threshold in the sane that it depends on the data. This is ‘maxpseudo’ if multiple independent p-value ordering procedures have been performed with the test class specified by test. In this case, all the powers that have been deemed to be statistically significant are not necessarily above this threshold.
- pvalue_threshold(self, test, detectorkey=None)¶
The statistical significance threshold for any p-value of a power in the power spectra set specified by the tuple test.
- test
A tuple specifying the class of power spectra, to extract the power threshold for. Contains some subset of ‘dataset’, ‘circuit’ and ‘outcome’, and it should correspond to a test that was implemented.
- detectorkeyNone or string, optional
Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
- Returns
float – The power threshold.
string – The type of threshold. This is ‘true’ if it is true threshold, in the sense that it is data-independent and can be precalculated without the data. This is the sort of threshold one obtains when doing a Bonferroni correction. This is ‘pseudo’ if it is a threshold obtained from a p-value ordering procedure, like the Holms’ method or the Benjamini-Hochberg procedure, because it is not a true threshold in the sane that it depends on the data. This is ‘maxpseudo’ if multiple independent p-value ordering procedures have been performed with the test class specified by test. In this case, all the powers that have been deemed to be statistically significant are not necessarily above this threshold.
- instability_detected(self, detectorkey=None, test=None)¶
Whether instability was detected.
- Parameters
detectorkey (None or string, optional) – Only relevant if more than one set of instability detection was run. The “saveas” key that was used when running run_instability_detection() for the detection results that you wish to access.
test (None or tuple, optional) – If None, then this method returns True if instability was detected in any statistical hypothesis test that we implemented. If a tuple, then it should be a tuple specifying a class of power spectra, so it contains some subset of ‘dataset’, ‘circuit’ and ‘outcome’, and it should correspond to a test that was implemented. If this tuple is specified, then this method returns True iff the tests specified by this tuple detected instability.
- Returns
bool – True if instability was detected, and returns False otherwise
- run_instability_characterization(self, estimator='auto', modelselector=(None, None), default=True, verbosity=1)¶
Run instability characterization: estimates probability trajectories for every circuit. The estimation methods are based on model selection from the results of hypothesis testing, so it is is necessary to first perform this hypothesis testing by running the run_instability_detection method.
- Parameters
estimator (str, optional) –
The name of the estimator to use. This is the method used to estimate the parameters of a parameterized model for each probability trajectory, after that parameterized model has been selected with the model selection methods. Allowed values are:
- ’auto’. The estimation method is chosen automatically, default to the fast method that is also
reasonably reliable.
- ’filter’. Performs a type of signal filtering: implements the transform used for generating power
spectra (e.g., the DCT), sets the amplitudes to zero for all freuquencies that the model selection has not included in the model, inverts the transform, and then performs some minor post-processing to guarantee probabilities within [0, 1]. This method is less statically well-founded than ‘mle’, but it is faster and typically gives similar results. This method is not an option for non-invertable transforms, such as the Lomb-Scargle periodogram.
- ’mle’. Implements maximum likelihood estimation, on the parameterized model chosen by the model
selection. The most statistically well-founded option, but can be slower than ‘filter’ and relies on numerical optimization.
modelselection (tuple, optional) – The model selection method. If not None, the first element of the tuple is a string that is a “detectorkey”, i.e., the saveas string for a set of instability detection results. If None then the default instability detection results are used. If run_instability_detection() has only been called once then there is only one set of results and there is no reason to set this to anything over than None. This is the instability detection resutls that will be used to select the models for the probability trajectories. If not None, the second element of the tuple is a “test class” tuple, specifying which test results to use to decide which frequencies are significant for each circuit. This can be typically set to None, and it will be chosen automatically. But if you wish to use specific test results for the model selection then this should be set.
default (bool, optional) – This method can be called multiple times. This sets whether these results will be the default results used when probability trajectory estimates are later requested.
verbosity (int, optional) – The amount of print-to-screen
- Returns
None
- probability_trajectory_model(self, circuit, dskey=None, estimatekey=None, estimator=None)¶
Returns the probability trajectory for a circuit, in the form of a ProbTrajectory object.
- Parameters
circuit (Circuit) – The circuit to return the probability trajectories for.
dskey (None or string, optional) – The DataSet to return the probability trajectories for. Need if more than one DataSet has been analyzed, but otherwise can be left as None.
estimatekey (None or tuple, optional) – The estimate to return (typically, multiple estimates have been generated). If None, then the default estimate is returned. If run_instability_characterization() has been called only once then it is the estimate obtained by the method specified in that single call (but multiple estimates may have been recorded, and so are accessable, as a side-product of creating that estimate). If not None, a tuple where the first element is the modelselector and the second element is the estimator, as specified as arguments to the run_instability_characterization() method.
estimator (None or string, optional) – Override for the second element of estimatekey’, to easily extract the ‘filter’ and ‘mle’ estimates, if both have been created (if ‘mle’ was chosen then the ‘filter’ estimate is also created as a by-product).
- Returns
ProbTrajectory – The estimated probability trajectory for the specified circuit.
- probability_trajectory(self, circuit, times, dskey=None, estimatekey=None, estimator=None)¶
Returns the probability trajectory for a circuit. See also probability_trajectory_model(), which provides are more complex, but more general-purpose, output.
- Parameters
circuit (Circuit) – The circuit to return the probability trajectories for.
times (list) – The times to obtain the probabilities for.
dskey (None or string, optional) – The DataSet to return the probability trajectories for. Need if more than one DataSet has been analyzed, but otherwise can be left as None.
estimatekey (None or tuple, optional) – The estimate to return (typically, multiple estimates have been generated). If None, then the default estimate is returned. If run_instability_characterization() has been called only once then it is the estimate obtained by the method specified in that single call (but multiple estimates may have been recorded, and so are accessable, as a side-product of creating that estimate). If not None, a tuple where the first element is the modelselector and the second element is the estimator, as specified as arguments to the run_instability_characterization() method.
estimator (None or string, optional) – Override for the second element of estimatekey, to easily extract the ‘filter’ and ‘mle’ estimates, if both have been created (if ‘mle’ was chosen then the ‘filter’ estimate is also created as a by-product).
- Returns
dict – The probability trajectory at the specified times. The keys are the possible circuit outcomes and the value for an outcome is a list, which is the probability trajectory for that outcome.
- maximum_tvd_bound(self, circuit, dskey=None, estimatekey=None, estimator=None)¶
Summarizes the size of the detected instability in the input circuit, as half the sum of the absolute values of the amplitudes in front of the non-constant basis functions in the estimate of the probability trajectories for that circuit.
This is an upper bound on the maximum TVD between the instaneous probability distribution (over circuit outcomes) and the mean of this time-varying probability distribution, with this maximization over all times.
- Parameters
circuit (Circuit) – The circuit to estimate the size of the instability for.
dskey (None or string, optional) – The DataSet to estimate the size of the instability for. Need if more than one DataSet has been analyzed, but otherwise can be left as None.
estimatekey (None or tuple, optional) – The probability trajectory estimate to use. If None, then the default estimate is used.
estimator (None or string, optional) – Overrides the second element of estimatekey, to easily select the ‘filter’ and ‘mle’ estimates.
- Returns
float – The size of the instability in the circuit, as quantified by the amplitudes in the probability trajectory model.
- maxmax_tvd_bound(self, dskey=None, estimatekey=None, estimator=None)¶
The quantity returned by maximum_tvd_bound maximized over circuits. See the docstring of that method for more details.