Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data processor with uncertainties package #481

Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
b3e7fbd
fix SVD shape
nkanazawa1989 Nov 1, 2021
05e27d4
fix docs
nkanazawa1989 Nov 1, 2021
714080c
fix comment
nkanazawa1989 Nov 1, 2021
7323449
fix var name
nkanazawa1989 Nov 2, 2021
1981b6e
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 2, 2021
c4b8823
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 2, 2021
159d3a2
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 2, 2021
a7e7b9c
comments
nkanazawa1989 Nov 2, 2021
326e95c
update except for SVD
nkanazawa1989 Nov 2, 2021
ccd5a1b
Merge branch 'fix/svd_node' into upgrade/data_processor_uncertainties
nkanazawa1989 Nov 2, 2021
7c2088a
update note tests
nkanazawa1989 Nov 2, 2021
1507c45
fix processor logic
nkanazawa1989 Nov 2, 2021
02e7126
documentation
nkanazawa1989 Nov 2, 2021
8eaedaf
lint
nkanazawa1989 Nov 2, 2021
ef5ae6b
add reno
nkanazawa1989 Nov 2, 2021
f397a87
fix test
nkanazawa1989 Nov 3, 2021
e243a87
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Nov 3, 2021
f4ab97f
Update qiskit_experiments/data_processing/data_action.py
nkanazawa1989 Nov 12, 2021
fc1cacf
Update qiskit_experiments/data_processing/data_action.py
nkanazawa1989 Nov 12, 2021
4296bbf
Update qiskit_experiments/data_processing/data_action.py
nkanazawa1989 Nov 12, 2021
6374a43
Update qiskit_experiments/data_processing/data_action.py
nkanazawa1989 Nov 12, 2021
df8bd60
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 12, 2021
2de64ff
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 12, 2021
25252b6
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 12, 2021
f7c1455
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 12, 2021
d1bc09e
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 12, 2021
74de5c0
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 12, 2021
11c3a16
add description for correlation
nkanazawa1989 Nov 12, 2021
458e761
remove typehint for trainable node
nkanazawa1989 Nov 12, 2021
e491469
update return doc
nkanazawa1989 Nov 12, 2021
a1389e9
add type check
nkanazawa1989 Nov 12, 2021
811e87f
detail for full array
nkanazawa1989 Nov 13, 2021
7ad5f19
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 13, 2021
0290ca7
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 13, 2021
0940330
add comment
nkanazawa1989 Nov 13, 2021
4177cc8
fix document
nkanazawa1989 Nov 13, 2021
9cab07d
black
nkanazawa1989 Nov 13, 2021
4159d7a
Update qiskit_experiments/data_processing/__init__.py
nkanazawa1989 Nov 15, 2021
571b30b
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 15, 2021
248cf25
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 15, 2021
1b3aea0
update docs
nkanazawa1989 Nov 15, 2021
653d941
Merge branch 'upgrade/data_processor_uncertainties' of github.com:nka…
nkanazawa1989 Nov 15, 2021
ff19191
update docs
nkanazawa1989 Nov 15, 2021
45003dc
restrict count validation
nkanazawa1989 Nov 15, 2021
006964f
update return type of data processor
nkanazawa1989 Nov 20, 2021
452bf90
lint
nkanazawa1989 Nov 20, 2021
c26033b
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Nov 20, 2021
504c371
add svd test
nkanazawa1989 Nov 26, 2021
19ff8f1
update average node
nkanazawa1989 Nov 26, 2021
eeb1faa
Merge branch 'main' into upgrade/data_processor_uncertainties
nkanazawa1989 Nov 26, 2021
350f724
Update qiskit_experiments/data_processing/data_processor.py
nkanazawa1989 Nov 29, 2021
417c218
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 29, 2021
0a98309
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 29, 2021
aa414a7
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 29, 2021
151e135
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 29, 2021
a3272e8
Update qiskit_experiments/data_processing/nodes.py
nkanazawa1989 Nov 29, 2021
5f49f5f
add comment
nkanazawa1989 Nov 29, 2021
a3b731f
add handling for level2 memory
nkanazawa1989 Nov 30, 2021
10ed781
black
nkanazawa1989 Nov 30, 2021
4cd8c74
lint
nkanazawa1989 Nov 30, 2021
0244d91
Merge branch 'main' into upgrade/data_processor_uncertainties
nkanazawa1989 Nov 30, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions qiskit_experiments/curve_analysis/curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import warnings
from abc import ABC
from typing import Any, Dict, List, Tuple, Callable, Union, Optional
from uncertainties import unumpy as unp

import numpy as np
from qiskit.providers import Backend
Expand Down Expand Up @@ -577,30 +578,29 @@ def _is_target_series(datum, **filters):

x_key = self._get_option("x_key")
try:
x_values = [datum["metadata"][x_key] for datum in data]
x_values = np.asarray([datum["metadata"][x_key] for datum in data], dtype=float)
except KeyError as ex:
raise DataProcessorError(
f"X value key {x_key} is not defined in circuit metadata."
) from ex

if isinstance(data_processor, DataProcessor):
y_values, y_sigmas = data_processor(data)
if y_sigmas is None:
y_sigmas = np.full(y_values.shape, np.nan)
y_data = data_processor(data)

y_nominals = unp.nominal_values(y_data)
y_stderrs = unp.std_devs(y_data)
else:
y_values, y_sigmas = zip(*map(data_processor, data))
y_nominals, y_stderrs = zip(*map(data_processor, data))

y_nominals = np.asarray(y_nominals, dtype=float)
y_stderrs = np.asarray(y_stderrs, dtype=float)

# Store metadata
metadata = np.asarray([datum["metadata"] for datum in data], dtype=object)

# Store shots
shots = np.asarray([datum.get("shots", np.nan) for datum in data])

# Format data
x_values = np.asarray(x_values, dtype=float)
y_values = np.asarray(y_values, dtype=float)
y_sigmas = np.asarray(y_sigmas, dtype=float)

# Find series (invalid data is labeled as -1)
data_index = np.full(x_values.size, -1, dtype=int)
for idx, series_def in enumerate(self.__series__):
Expand All @@ -613,8 +613,8 @@ def _is_target_series(datum, **filters):
raw_data = CurveData(
label="raw_data",
x=x_values,
y=y_values,
y_err=y_sigmas,
y=y_nominals,
y_err=y_stderrs,
shots=shots,
data_index=data_index,
metadata=metadata,
Expand Down
30 changes: 26 additions & 4 deletions qiskit_experiments/data_processing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,32 @@

.. currentmodule:: qiskit_experiments.data_processing

Data processing is the act of taking taking the data returned by the backend and
converting it into a format that can be analyzed. For instance, counts can be
converted to a probability while two-dimensional IQ data may be converted to a
one-dimensional signal.
Data processing is the act of taking the data returned by the backend and
converting it into a format that can be analyzed.
It is implemented as a chain of data processing steps that transform various input data,
e.g. IQ data, into a desired format, e.g. population, which can be analyzed.

These data transformations may consist of multiple steps, such as kerneling and discrimination.
Each step is implemented by a :class:`~qiskit_experiments.data_processing.data_action.DataAction`
also called a `node`.

The data processor implements the :meth:`__call__` method. Once initialized, it
can thus be used as a standard python function:

.. code-block:: python

processor = DataProcessor(input_key="memory", [Node1(), Node2(), ...])
out_data = processor(in_data)

The data input to the processor is a sequence of dictionaries each representing the result
of a single circuit. The output of the processor is a numpy array whose shape and data type
depend on the combination of the nodes in the data processor.

Uncertainties that arise from quantum measurements or finite sampling can be taken into account
in the nodes: a standard error can be generated in a node and can be propagated
through the subsequent nodes in the data processor.
Correlation between computed values is also considered.


Classes
=======
Expand Down
61 changes: 31 additions & 30 deletions qiskit_experiments/data_processing/data_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,65 @@
"""Defines the steps that can be used to analyse data."""

from abc import ABCMeta, abstractmethod
from typing import Any, List, Optional, Tuple

import numpy as np


class DataAction(metaclass=ABCMeta):
"""
Abstract action done on measured data to process it. Each subclass of DataAction must
define the way it formats, validates and processes data.
"""Abstract action done on measured data to process it.

Each subclass of DataAction must define the way it formats, validates and processes data.
"""

def __init__(self, validate: bool = True):
"""
"""Create new node.

Args:
validate: If set to False the DataAction will not validate its input.
"""
self._validate = validate

@abstractmethod
def _process(self, datum: Any, error: Optional[Any] = None) -> Tuple[Any, Any]:
"""
Applies the data processing step to the datum.
def _process(self, data: np.ndarray) -> np.ndarray:
"""Applies the data processing step to the data.

Args:
datum: A single item of data which will be processed.
error: An optional error estimation on the datum that can be further propagated.
data: A data array to process. This is a single numpy array containing
all circuit results input to the data processor.
If the elements are ufloat objects consisting of a nominal value and
a standard error, then the error propagation is automatically computed.

Returns:
processed data: The data that has been processed along with the propagated error.
The processed data.
"""

@abstractmethod
def _format_data(self, datum: Any, error: Optional[Any] = None) -> Tuple[Any, Any]:
def _format_data(self, data: np.ndarray) -> np.ndarray:
"""Format and validate the input.

Check that the given data and error has the correct structure. This method may
Check that the given data has the correct structure. This method may
additionally change the data type, e.g. converting a list to a numpy array.

Args:
datum: The data instance to check and format.
error: An optional error estimation on the datum to check and format.
data: A data array to format. This is a single numpy array containing
all circuit results input to the data processor.

Returns:
datum, error: The formatted datum and its optional error.

Raises:
DataProcessorError: If either the data or the error do not have the proper format.
The data that has been validated and formatted.
"""
return data

def __call__(self, data: Any, error: Optional[Any] = None) -> Tuple[Any, Any]:
"""Call the data action of this node on the data and propagate the error.
def __call__(self, data: np.ndarray) -> np.ndarray:
"""Call the data action of this node on the data.

Args:
data: The data to process. The action nodes in the data processor will
raise errors if the data does not have the appropriate format.
error: An optional error estimation on the datum that can be further processed.
data: A numpy array with arbitrary dtype. If the elements are ufloat objects
consisting of a nominal value and a standard error, then the error propagation
is done automatically.

Returns:
processed data: The data processed by self as a tuple of processed datum and
optionally the propagated error estimate.
The processed data.
"""
return self._process(*self._format_data(data, error))
return self._process(self._format_data(data))

def __repr__(self):
"""String representation of the node."""
Expand All @@ -94,11 +93,13 @@ def is_trained(self) -> bool:
"""

@abstractmethod
def train(self, data: List[Any]):
def train(self, data: np.ndarray):
"""Train a DataAction.

Certain data processing nodes, such as a SVD, require data to first train.

Args:
data: A list of datum. Each datum is a point used to train the node.
data: A data array for training. This is a single numpy array containing
all circuit results input to the data processor :meth:`~qiskit_experiments.\
data_processing.data_processor.DataProcessor#train` method.
"""
Loading