From 9740b29bc21d7ae07b470cc1a3ba72efef466806 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 27 May 2020 06:36:40 -0400 Subject: [PATCH 01/21] Add Counts object This commit adds a new class qiskit.result.Counts which is a dict subclass for dealing with count results from experiment. It takes in a counts dictionary with hexadecimal string keys and it's data is a binary string, like the output of get_counts(). The idea is that this class contains extra attributes about the execution and helper methods for interacting with counts results. It can be used as a direct replacment anywhere a counts dictionary was used previously. It is also now the return type for qiskit.quantum_info.QuantumState.sample_counts(). This commit is part of the v2 providers interface work and will be a key part of the new providers interface. This class is split out as a seperate commit/PR from #4485. --- qiskit/quantum_info/states/quantum_state.py | 5 +- qiskit/result/__init__.py | 4 + qiskit/result/counts.py | 80 +++++++++++++++++++ qiskit/result/exceptions.py | 5 ++ qiskit/result/result.py | 4 +- .../add-counts-class-7c75bd94d12a161a.yaml | 14 ++++ 6 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 qiskit/result/counts.py create mode 100644 releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml diff --git a/qiskit/quantum_info/states/quantum_state.py b/qiskit/quantum_info/states/quantum_state.py index eddca4b22c51..2f64c2d5303e 100644 --- a/qiskit/quantum_info/states/quantum_state.py +++ b/qiskit/quantum_info/states/quantum_state.py @@ -26,6 +26,7 @@ from qiskit.quantum_info.operators.base_operator import BaseOperator from qiskit.quantum_info.operators.operator import Operator from qiskit.quantum_info.operators.predicates import ATOL_DEFAULT, RTOL_DEFAULT +from qiskit.result.counts import Counts class QuantumState(ABC): @@ -383,7 +384,7 @@ def sample_counts(self, shots, qargs=None): subsystems (Default: None). Returns: - dict: sampled counts dictionary. + Counts: sampled counts dictionary. Additional Information: @@ -400,7 +401,7 @@ def sample_counts(self, shots, qargs=None): # Combine all samples into a counts dictionary inds, counts = np.unique(samples, return_counts=True) - return dict(zip(inds, counts)) + return Counts(zip(inds, counts)) def measure(self, qargs=None): """Measure subsystems and return outcome and post-measure state. diff --git a/qiskit/result/__init__.py b/qiskit/result/__init__.py index ca9973185eea..49c1f3550b9c 100644 --- a/qiskit/result/__init__.py +++ b/qiskit/result/__init__.py @@ -24,8 +24,12 @@ Result ResultError + Counts + NoMostFrequentCount """ from .result import Result from .exceptions import ResultError from .utils import marginal_counts +from .counts import Counts +from .exceptions import NoMostFrequentCount diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py new file mode 100644 index 000000000000..c4b4b728ab1d --- /dev/null +++ b/qiskit/result/counts.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020. +# +# 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. + +"""A container class for counts from a circuit execution.""" + +from qiskit.result import postprocess +from qiskit.result import exceptions + + +class Counts(dict): + """A class to store a counts result from a circuit execution.""" + + def __init__(self, data, name=None, shots=None, time_taken=None, + creg_sizes=None, memory_slots=None, **metadata): + """Build a counts object + + data (dict): The dictionary input for the counts. The key should be a + hexademical string of the form ``"0x4a"`` representing the measured + classical value from the experiment and the dictionary's value is + an integer representing the number of shots with that result. + name (str): A string name for the counts object + shots (int): The number of shots used in the experiment + time_take (float): The duration of the experiment that generated the + counts + creg_sizes (list): a nested list where the inner element is a list + of tuples containing both the classical register name and classical + register size. For example, ``[('c_reg', 2), ('my_creg', 4)]``. + memory_slots (int): The number of total ``memory_slots`` in the + experiment. + metadata: Any arbitrary key value metadata passed in as kwargs. + """ + self.hex_raw = dict(data) + header = {} + self.creg_sizes = creg_sizes + if self.creg_sizes: + header['creg_sizes'] = self.creg_sizes + self.memory_slots = memory_slots + if self.memory_slots: + header['memory_slots'] = self.memory_slots + bin_data = postprocess.format_counts(self.hex_raw, header=header) + super().__init__(bin_data) + self.name = name + self.shots = shots + self.time_taken = time_taken + self.metadata = metadata + + def most_frequent(self): + """Return the most frequent count + + Returns: + str: The bit string for the most frequent result + Raises: + NoMostFrequentCount: when there is >1 count with the same max counts + """ + max_value = max(self.values()) + max_values_counts = [x[0] for x in self.items() if x[1] == max_value] + if len(max_values_counts) != 1: + raise exceptions.NoMostFrequentCount( + "Multiple values have the same maximum counts: %s" % + ','.join(max_values_counts)) + return max_values_counts[0] + + def int_outcomes(self): + """Build a counts dictionary with integer keys instead of count strings + + Returns: + dict: A dictionary with the keys as integers instead of + """ + return {int(key, 0): value for key, value in self.hex_raw.items()} diff --git a/qiskit/result/exceptions.py b/qiskit/result/exceptions.py index d778647bb94c..b06ccdd91226 100644 --- a/qiskit/result/exceptions.py +++ b/qiskit/result/exceptions.py @@ -39,3 +39,8 @@ def __init__(self, error): def __str__(self): return '{}: {}'.format(self.code, self.message) + + +class NoMostFrequentCount(QiskitError): + """Error raised by Counts.most_frequent if there is no most frequent result.""" + pass diff --git a/qiskit/result/result.py b/qiskit/result/result.py index 99bfcd294ed3..6eab40925548 100644 --- a/qiskit/result/result.py +++ b/qiskit/result/result.py @@ -19,7 +19,7 @@ from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.pulse.schedule import Schedule from qiskit.exceptions import QiskitError -from qiskit.quantum_info.states import Statevector +from qiskit.quantum_info.states import statevector from qiskit.result.models import ExperimentResult from qiskit.result import postprocess from qiskit.qobj.utils import MeasLevel @@ -245,7 +245,7 @@ def get_counts(self, experiment=None): dict_list.append(postprocess.format_counts(self.data(key)['counts'], header)) elif 'statevector' in self.data(key).keys(): vec = postprocess.format_statevector(self.data(key)['statevector']) - dict_list.append(Statevector(vec).probabilities_dict(decimals=15)) + dict_list.append(statevector.Statevector(vec).probabilities_dict(decimals=15)) else: raise QiskitError('No counts for experiment "{0}"'.format(key)) diff --git a/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml b/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml new file mode 100644 index 000000000000..68edc2e0c29d --- /dev/null +++ b/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + A new class, :class:`qiskit.result.Counts` has been added. This class + is a subclass of ``dict`` and . It is created by passing a dictionary + of counts with the keys being hexademical strings of the form ``'0x4a'`` + and the value is the number of shots. For example:: + + from qiskit.result import Counts + + counts = Counts({"0x0': 1, '0x1', 3, '0x2': 1020}) + + A Counts object can be treated as a dictionary of binary string keys + like the output of :meth:`qiskit.result.Result.get_counts`. From 46254a05fa8e9aedc9b6b93ab7559c273bff5c03 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 27 May 2020 07:28:45 -0400 Subject: [PATCH 02/21] Fix docs build --- qiskit/result/counts.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index c4b4b728ab1d..d80c8fa0b907 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -25,20 +25,23 @@ def __init__(self, data, name=None, shots=None, time_taken=None, creg_sizes=None, memory_slots=None, **metadata): """Build a counts object - data (dict): The dictionary input for the counts. The key should be a - hexademical string of the form ``"0x4a"`` representing the measured - classical value from the experiment and the dictionary's value is - an integer representing the number of shots with that result. - name (str): A string name for the counts object - shots (int): The number of shots used in the experiment - time_take (float): The duration of the experiment that generated the - counts - creg_sizes (list): a nested list where the inner element is a list - of tuples containing both the classical register name and classical - register size. For example, ``[('c_reg', 2), ('my_creg', 4)]``. - memory_slots (int): The number of total ``memory_slots`` in the - experiment. - metadata: Any arbitrary key value metadata passed in as kwargs. + Args: + data (dict): The dictionary input for the counts. The key should + be a hexademical string of the form ``"0x4a"`` representing the + measured classical value from the experiment and the + dictionary's value is an integer representing the number of + shots with that result. + name (str): A string name for the counts object + shots (int): The number of shots used in the experiment + time_take (float): The duration of the experiment that generated + the counts + creg_sizes (list): a nested list where the inner element is a list + of tuples containing both the classical register name and + classical register size. For example, + ``[('c_reg', 2), ('my_creg', 4)]``. + memory_slots (int): The number of total ``memory_slots`` in the + experiment. + metadata: Any arbitrary key value metadata passed in as kwargs. """ self.hex_raw = dict(data) header = {} From 57c251ccfe12caf10bb9b29bab0200cc4d627418 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 27 May 2020 07:45:23 -0400 Subject: [PATCH 03/21] Fix lint --- qiskit/result/counts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index d80c8fa0b907..4c0d8a847033 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -33,7 +33,7 @@ def __init__(self, data, name=None, shots=None, time_taken=None, shots with that result. name (str): A string name for the counts object shots (int): The number of shots used in the experiment - time_take (float): The duration of the experiment that generated + time_taken (float): The duration of the experiment that generated the counts creg_sizes (list): a nested list where the inner element is a list of tuples containing both the classical register name and From f433cbd8ea25d95bbac6670061e8791a2d7b027f Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 27 May 2020 12:50:04 -0400 Subject: [PATCH 04/21] Add missing test file --- test/python/result/test_counts.py | 69 +++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/python/result/test_counts.py diff --git a/test/python/result/test_counts.py b/test/python/result/test_counts.py new file mode 100644 index 000000000000..9f108c8ba64a --- /dev/null +++ b/test/python/result/test_counts.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 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. + +# pylint: disable=missing-class-docstring,missing-function-docstring + +"""Test Counts class.""" + +import unittest + +from qiskit.result import counts +from qiskit.result import exceptions +from qiskit.result import utils + + +class TestCounts(unittest.TestCase): + + def test_just_counts(self): + raw_counts = {'0x0': 21, '0x2': 12} + expected = {'0': 21, '10': 12} + result = counts.Counts(raw_counts) + self.assertEqual(expected, result) + + def test_counts_with_exta_formatting_data(self): + raw_counts = {'0x0': 4, '0x2': 10} + expected = {'0 0 00': 4, '0 0 10': 10} + result = counts.Counts(raw_counts, 'test_counts', shots=14, + creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], + memory_slots=4) + self.assertEqual(result, expected) + + def test_marginal_counts(self): + raw_counts = {'0x0': 4, '0x1': 7, '0x2': 10, '0x6': 5, '0x9': 11, + '0xD': 9, '0xE': 8} + expected = {'00': 4, '01': 27, '10': 23} + counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + memory_slots=4) + result = utils.marginal_counts(counts_obj, [0, 1]) + self.assertEqual(expected, result) + + def test_int_outcomes(self): + raw_counts = {'0x0': 21, '0x2': 12, '0x3': 5, '0x2E': 265} + expected = {0: 21, 2: 12, 3: 5, 46: 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.int_outcomes() + self.assertEqual(expected, result) + + def test_most_frequent(self): + raw_counts = {'0x0': 21, '0x2': 12, '0x3': 5, '0x2E': 265} + expected = '101110' + counts_obj = counts.Counts(raw_counts) + result = counts_obj.most_frequent() + self.assertEqual(expected, result) + + def test_most_frequent_duplicate(self): + raw_counts = {'0x0': 265, '0x2': 12, '0x3': 5, '0x2E': 265} + counts_obj = counts.Counts(raw_counts) + self.assertRaises(exceptions.NoMostFrequentCount, + counts_obj.most_frequent) From a4e5ce59dd54b388666408a3a7da1b96cdebb59f Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 28 May 2020 06:22:40 -0400 Subject: [PATCH 05/21] Switch custom exception class to QiskitError --- qiskit/result/__init__.py | 2 -- qiskit/result/counts.py | 6 +++--- qiskit/result/exceptions.py | 5 ----- test/python/result/test_counts.py | 4 ++-- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/qiskit/result/__init__.py b/qiskit/result/__init__.py index 49c1f3550b9c..d2f4351178f7 100644 --- a/qiskit/result/__init__.py +++ b/qiskit/result/__init__.py @@ -25,11 +25,9 @@ Result ResultError Counts - NoMostFrequentCount """ from .result import Result from .exceptions import ResultError from .utils import marginal_counts from .counts import Counts -from .exceptions import NoMostFrequentCount diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index 4c0d8a847033..560d89b4a21b 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -15,7 +15,7 @@ """A container class for counts from a circuit execution.""" from qiskit.result import postprocess -from qiskit.result import exceptions +from qiskit import exceptions class Counts(dict): @@ -64,12 +64,12 @@ def most_frequent(self): Returns: str: The bit string for the most frequent result Raises: - NoMostFrequentCount: when there is >1 count with the same max counts + QiskitError: when there is >1 count with the same max counts """ max_value = max(self.values()) max_values_counts = [x[0] for x in self.items() if x[1] == max_value] if len(max_values_counts) != 1: - raise exceptions.NoMostFrequentCount( + raise exceptions.QiskitError( "Multiple values have the same maximum counts: %s" % ','.join(max_values_counts)) return max_values_counts[0] diff --git a/qiskit/result/exceptions.py b/qiskit/result/exceptions.py index b06ccdd91226..d778647bb94c 100644 --- a/qiskit/result/exceptions.py +++ b/qiskit/result/exceptions.py @@ -39,8 +39,3 @@ def __init__(self, error): def __str__(self): return '{}: {}'.format(self.code, self.message) - - -class NoMostFrequentCount(QiskitError): - """Error raised by Counts.most_frequent if there is no most frequent result.""" - pass diff --git a/test/python/result/test_counts.py b/test/python/result/test_counts.py index 9f108c8ba64a..9a00a4422cd2 100644 --- a/test/python/result/test_counts.py +++ b/test/python/result/test_counts.py @@ -19,7 +19,7 @@ import unittest from qiskit.result import counts -from qiskit.result import exceptions +from qiskit import exceptions from qiskit.result import utils @@ -65,5 +65,5 @@ def test_most_frequent(self): def test_most_frequent_duplicate(self): raw_counts = {'0x0': 265, '0x2': 12, '0x3': 5, '0x2E': 265} counts_obj = counts.Counts(raw_counts) - self.assertRaises(exceptions.NoMostFrequentCount, + self.assertRaises(exceptions.QiskitError, counts_obj.most_frequent) From 3a07fc7d8c2aa83cbc8ee67d7daf01a3be764e8a Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 28 May 2020 06:23:03 -0400 Subject: [PATCH 06/21] Cleanup release note --- .../notes/add-counts-class-7c75bd94d12a161a.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml b/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml index 68edc2e0c29d..560ca4707245 100644 --- a/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml +++ b/releasenotes/notes/add-counts-class-7c75bd94d12a161a.yaml @@ -2,13 +2,17 @@ features: - | A new class, :class:`qiskit.result.Counts` has been added. This class - is a subclass of ``dict`` and . It is created by passing a dictionary - of counts with the keys being hexademical strings of the form ``'0x4a'`` - and the value is the number of shots. For example:: + is a subclass of ``dict`` and can be interacted with like any other + dictionary. But, it includes helper methods and attributes for dealing + with counts results from experiments and also handles post processing + and formatting of binary strings at object initialization. A ``Counts`` + object can be created by passing a dictionary of counts with the keys + being hexademical strings of the form ``'0x4a'`` and the value is the + number of shots. For example:: from qiskit.result import Counts counts = Counts({"0x0': 1, '0x1', 3, '0x2': 1020}) - A Counts object can be treated as a dictionary of binary string keys + A ``Counts`` object can be treated as a dictionary of binary string keys like the output of :meth:`qiskit.result.Result.get_counts`. From 05252304cc110fa14b8d7ec96d155515fa3d36c2 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 28 May 2020 06:25:40 -0400 Subject: [PATCH 07/21] Add comment about dict subclassing --- qiskit/result/counts.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index 560d89b4a21b..dd02faa7b5b7 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -18,6 +18,10 @@ from qiskit import exceptions +# NOTE: A dict subclass should not override any dunder methods like __getitem__ +# this can cause unexpected behavior and issues as the cPython dict +# implementation inlines many methods in C for performance and the dunder +# methods are not always used as expected. class Counts(dict): """A class to store a counts result from a circuit execution.""" From 442db9f461b6d71769cd9a7d5024854f18f5fb78 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 28 May 2020 07:54:35 -0400 Subject: [PATCH 08/21] Tweak comment wording slightly --- qiskit/result/counts.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index dd02faa7b5b7..a0c998bc6b92 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -18,10 +18,12 @@ from qiskit import exceptions -# NOTE: A dict subclass should not override any dunder methods like __getitem__ +# NOTE: A dict subclass should not overload any dunder methods like __getitem__ # this can cause unexpected behavior and issues as the cPython dict -# implementation inlines many methods in C for performance and the dunder -# methods are not always used as expected. +# implementation has many standard methods in C for performance and the dunder +# methods are not always used as expected. For example, update() doesn't call +# __setitem__ so overloading __setitem__ would not always provide the expected +# result class Counts(dict): """A class to store a counts result from a circuit execution.""" From f3eaf0804663544c7957f3fed32fb6f8a630451c Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 2 Jun 2020 19:01:23 -0400 Subject: [PATCH 09/21] Add support for int and binary input keys and handle qudits This commit allows for the input key format for the data dict to be hex, binary, or integers and use all the functionality as expected. It also adds handling for dit strings which don't handle the hex or binary output formats or allow for formating across registers. --- qiskit/result/counts.py | 81 ++++++++++++++++-- test/python/result/test_counts.py | 137 ++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 5 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index a0c998bc6b92..27088b3eafdc 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -14,6 +14,8 @@ """A container class for counts from a circuit execution.""" +import re + from qiskit.result import postprocess from qiskit import exceptions @@ -33,7 +35,8 @@ def __init__(self, data, name=None, shots=None, time_taken=None, Args: data (dict): The dictionary input for the counts. The key should - be a hexademical string of the form ``"0x4a"`` representing the + be a hexademical string of the form ``"0x4a"``, a bit string in + little endian format, or an integer representing the measured classical value from the experiment and the dictionary's value is an integer representing the number of shots with that result. @@ -49,7 +52,40 @@ def __init__(self, data, name=None, shots=None, time_taken=None, experiment. metadata: Any arbitrary key value metadata passed in as kwargs. """ - self.hex_raw = dict(data) + bin_data = None + first_key = next(iter(data.keys())) + if isinstance(first_key, int): + self.int_raw = data + self.hex_raw = { + hex(key): value for key, value in self.int_raw.items()} + elif isinstance(first_key, str): + if first_key.startswith('0x'): + self.hex_raw = data + self.int_raw = { + int(key, 0): value for key, value in self.hex_raw.items()} + else: + if not creg_sizes and not memory_slots: + self.hex_raw = None + self.int_raw = None + bin_data = data + else: + bitstring_regex = re.compile(r'^[01\s]+$') + hex_dict = {} + int_dict = {} + for bitstring, value in data.items(): + if not bitstring_regex.search(bitstring): + raise exceptions.QiskitError( + 'Counts objects with qudit bitstrings do not ' + 'currently support bitstring formatting parameters ' + 'creg_sizes or memory_slots') + int_key = int(bitstring.replace(" ", ""), 2) + int_dict[int_key] = value + hex_dict[hex(int_key)] = value + self.hex_raw = hex_dict + self.int_raw = int_dict + else: + raise TypeError("Invalid input key type %s, must be either an int " + "key or string key with hexademical value or bit string") header = {} self.creg_sizes = creg_sizes if self.creg_sizes: @@ -57,7 +93,8 @@ def __init__(self, data, name=None, shots=None, time_taken=None, self.memory_slots = memory_slots if self.memory_slots: header['memory_slots'] = self.memory_slots - bin_data = postprocess.format_counts(self.hex_raw, header=header) + if not bin_data: + bin_data = postprocess.format_counts(self.hex_raw, header=header) super().__init__(bin_data) self.name = name self.shots = shots @@ -80,10 +117,44 @@ def most_frequent(self): ','.join(max_values_counts)) return max_values_counts[0] + def hex_outcomes(self): + """Return a counts dictionary with hexademical string keys + + Returns: + dict: A dictionary with the keys as hexadecimal strings instead of + bitstrings + """ + if self.hex_raw: + return {key.lower(): value for key, value in self.hex_raw.items()} + else: + bitstring_regex = re.compile(r'^[01\s]+$') + out_dict = {} + for bitstring, value in self.items(): + if not bitstring_regex.search(bitstring): + raise exceptions.QiskitError( + 'Counts objects with qudit bitstrings do not ' + 'currently support conversion to hexadecimal') + int_key = int(bitstring.replace(" ", ""), 2) + out_dict[hex(int_key)] = value + return out_dict + + def int_outcomes(self): """Build a counts dictionary with integer keys instead of count strings Returns: - dict: A dictionary with the keys as integers instead of + dict: A dictionary with the keys as integers instead of bitstrings """ - return {int(key, 0): value for key, value in self.hex_raw.items()} + if self.int_raw: + return self.int_raw + else: + bitstring_regex = re.compile(r'^[01\s]+$') + out_dict = {} + for bitstring, value in self.items(): + if not bitstring_regex.search(bitstring): + raise exceptions.QiskitError( + 'Counts objects with qudit bitstrings do not ' + 'currently support conversion to integer') + int_key = int(bitstring.replace(" ", ""), 2) + out_dict[int_key] = value + return out_dict diff --git a/test/python/result/test_counts.py b/test/python/result/test_counts.py index 9a00a4422cd2..565806fc2f34 100644 --- a/test/python/result/test_counts.py +++ b/test/python/result/test_counts.py @@ -67,3 +67,140 @@ def test_most_frequent_duplicate(self): counts_obj = counts.Counts(raw_counts) self.assertRaises(exceptions.QiskitError, counts_obj.most_frequent) + + def test_hex_outcomes(self): + raw_counts = {'0x0': 21, '0x2': 12, '0x3': 5, '0x2E': 265} + expected = {'0x0': 21, '0x2': 12, '0x3': 5, '0x2e': 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.hex_outcomes() + self.assertEqual(expected, result) + + def test_just_int_counts(self): + raw_counts = {0: 21, 2: 12} + expected = {'0': 21, '10': 12} + result = counts.Counts(raw_counts) + self.assertEqual(expected, result) + + def test_int_counts_with_exta_formatting_data(self): + raw_counts = {0: 4, 2: 10} + expected = {'0 0 00': 4, '0 0 10': 10} + result = counts.Counts(raw_counts, 'test_counts', shots=14, + creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], + memory_slots=4) + self.assertEqual(result, expected) + + def test_marginal_int_counts(self): + raw_counts = {0: 4, 1: 7, 2: 10, 6: 5, 9: 11, 13: 9, 14: 8} + expected = {'00': 4, '01': 27, '10': 23} + counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + memory_slots=4) + result = utils.marginal_counts(counts_obj, [0, 1]) + self.assertEqual(expected, result) + + def test_int_outcomes_with_int_counts(self): + raw_counts = {0: 21, 2: 12, 3: 5, 46: 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.int_outcomes() + self.assertEqual(raw_counts, result) + + def test_most_frequent_int_counts(self): + raw_counts = {0: 21, 2: 12, 3: 5, 46: 265} + expected = '101110' + counts_obj = counts.Counts(raw_counts) + result = counts_obj.most_frequent() + self.assertEqual(expected, result) + + def test_most_frequent_duplicate_int_counts(self): + raw_counts = {0: 265, 2: 12, 3: 5, 46: 265} + counts_obj = counts.Counts(raw_counts) + self.assertRaises(exceptions.QiskitError, + counts_obj.most_frequent) + + def test_hex_outcomes_int_counts(self): + raw_counts = {0: 265, 2: 12, 3: 5, 46: 265} + expected = {'0x0': 265, '0x2': 12, '0x3': 5, '0x2e': 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.hex_outcomes() + self.assertEqual(expected, result) + + def test_invalid_input_type(self): + self.assertRaises(TypeError, counts.Counts, {2.4: 1024}) + + def test_just_bitstring_counts(self): + raw_counts = {'0': 21, '10': 12} + expected = {'0': 21, '10': 12} + result = counts.Counts(raw_counts) + self.assertEqual(expected, result) + + def test_bistring_counts_with_exta_formatting_data(self): + raw_counts = {'0': 4, '10': 10} + expected = {'0 0 00': 4, '0 0 10': 10} + result = counts.Counts(raw_counts, 'test_counts', shots=14, + creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], + memory_slots=4) + self.assertEqual(result, expected) + + def test_marginal_bitstring_counts(self): + raw_counts = {'0': 4, '1': 7, '10': 10, '110': 5, '1001': 11, '1101': 9, '1110': 8} + expected = {'00': 4, '01': 27, '10': 23} + counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + memory_slots=4) + result = utils.marginal_counts(counts_obj, [0, 1]) + self.assertEqual(expected, result) + + def test_int_outcomes_with_bitstring_counts(self): + raw_counts = {'0': 21, '10': 12, '11': 5, '101110': 265} + expected = {0: 21, 2: 12, 3: 5, 46: 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.int_outcomes() + self.assertEqual(expected, result) + + def test_most_frequent_bitstring_counts(self): + raw_counts = {'0': 21, '10': 12, '11': 5, '101110': 265} + expected = '101110' + counts_obj = counts.Counts(raw_counts) + result = counts_obj.most_frequent() + self.assertEqual(expected, result) + + def test_most_frequent_duplicate_bitstring_counts(self): + raw_counts = {'0': 265, '10': 12, '11': 5, '101110': 265} + counts_obj = counts.Counts(raw_counts) + self.assertRaises(exceptions.QiskitError, + counts_obj.most_frequent) + + def test_hex_outcomes_bitstring_counts(self): + raw_counts = {'0': 265, '10': 12, '11': 5, '101110': 265} + expected = {'0x0': 265, '0x2': 12, '0x3': 5, '0x2e': 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.hex_outcomes() + self.assertEqual(expected, result) + + def test_qudit_counts(self): + raw_counts = {'00': 121, '01': 109, '02': 114, '10': 113, '11': 106, + '12': 114, '20': 117, '21': 104, '22': 102} + result = counts.Counts(raw_counts) + self.assertEqual(raw_counts, result) + + def test_qudit_counts_raises_with_format(self): + raw_counts = {'00': 121, '01': 109, '02': 114, '10': 113, '11': 106, + '12': 114, '20': 117, '21': 104, '22': 102} + self.assertRaises(exceptions.QiskitError, counts.Counts, raw_counts, + creg_sizes=[['c0', 4]]) + + def test_qudit_counts_hex_outcome(self): + raw_counts = {'00': 121, '01': 109, '02': 114, '10': 113, '11': 106, + '12': 114, '20': 117, '21': 104, '22': 102} + counts_obj = counts.Counts(raw_counts) + self.assertRaises(exceptions.QiskitError, counts_obj.hex_outcomes) + + def test_qudit_counts_int_outcome(self): + raw_counts = {'00': 121, '01': 109, '02': 114, '10': 113, '11': 106, + '12': 114, '20': 117, '21': 104, '22': 102} + counts_obj = counts.Counts(raw_counts) + self.assertRaises(exceptions.QiskitError, counts_obj.int_outcomes) + + def test_qudit_counts_most_frequent(self): + raw_counts = {'00': 121, '01': 109, '02': 114, '10': 113, '11': 106, + '12': 114, '20': 117, '21': 104, '22': 102} + counts_obj = counts.Counts(raw_counts) + self.assertEqual('00', counts_obj.most_frequent()) From c249b64b14cdb89cc687c951bbc0daa3842eabe0 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Jun 2020 09:44:03 -0400 Subject: [PATCH 10/21] Fix tests --- qiskit/result/counts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index 27088b3eafdc..fae7c4a6c3c2 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -53,6 +53,7 @@ def __init__(self, data, name=None, shots=None, time_taken=None, metadata: Any arbitrary key value metadata passed in as kwargs. """ bin_data = None + data = dict(data) first_key = next(iter(data.keys())) if isinstance(first_key, int): self.int_raw = data @@ -138,7 +139,6 @@ def hex_outcomes(self): out_dict[hex(int_key)] = value return out_dict - def int_outcomes(self): """Build a counts dictionary with integer keys instead of count strings From 0612298b92f35ad32277bbf0825672170c5b7011 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Jun 2020 11:15:09 -0400 Subject: [PATCH 11/21] Fix lint --- qiskit/result/counts.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index fae7c4a6c3c2..cf99ff0999de 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -51,6 +51,10 @@ def __init__(self, data, name=None, shots=None, time_taken=None, memory_slots (int): The number of total ``memory_slots`` in the experiment. metadata: Any arbitrary key value metadata passed in as kwargs. + Raises: + TypeError: If the input key type is not an int or string + QiskitError: If a dit string key is input with creg_sizes and/or + memory_slots """ bin_data = None data = dict(data) @@ -76,8 +80,8 @@ def __init__(self, data, name=None, shots=None, time_taken=None, for bitstring, value in data.items(): if not bitstring_regex.search(bitstring): raise exceptions.QiskitError( - 'Counts objects with qudit bitstrings do not ' - 'currently support bitstring formatting parameters ' + 'Counts objects with dit strings do not ' + 'currently support dit string formatting parameters ' 'creg_sizes or memory_slots') int_key = int(bitstring.replace(" ", ""), 2) int_dict[int_key] = value @@ -124,6 +128,8 @@ def hex_outcomes(self): Returns: dict: A dictionary with the keys as hexadecimal strings instead of bitstrings + Raises: + QiskitError: If the Counts object contains counts for dit strings """ if self.hex_raw: return {key.lower(): value for key, value in self.hex_raw.items()} @@ -133,7 +139,7 @@ def hex_outcomes(self): for bitstring, value in self.items(): if not bitstring_regex.search(bitstring): raise exceptions.QiskitError( - 'Counts objects with qudit bitstrings do not ' + 'Counts objects with dit strings do not ' 'currently support conversion to hexadecimal') int_key = int(bitstring.replace(" ", ""), 2) out_dict[hex(int_key)] = value @@ -144,6 +150,8 @@ def int_outcomes(self): Returns: dict: A dictionary with the keys as integers instead of bitstrings + Raises: + QiskitError: If the Counts object contains counts for dit strings """ if self.int_raw: return self.int_raw @@ -153,7 +161,7 @@ def int_outcomes(self): for bitstring, value in self.items(): if not bitstring_regex.search(bitstring): raise exceptions.QiskitError( - 'Counts objects with qudit bitstrings do not ' + 'Counts objects with dit strings do not ' 'currently support conversion to integer') int_key = int(bitstring.replace(" ", ""), 2) out_dict[int_key] = value From 5a09207cda3462852a73b97e6dedded662852643 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Jun 2020 11:17:52 -0400 Subject: [PATCH 12/21] Handle 0b prefixed binary strings --- qiskit/result/counts.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index cf99ff0999de..3ef69540c904 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -68,6 +68,11 @@ def __init__(self, data, name=None, shots=None, time_taken=None, self.hex_raw = data self.int_raw = { int(key, 0): value for key, value in self.hex_raw.items()} + elif first_key.startswith('0b'): + self.int_raw = { + int(key, 0): value for key, value in data.items()} + self.hex_raw = { + hex(key): value for key, value in self.int_raw.items()} else: if not creg_sizes and not memory_slots: self.hex_raw = None From e0c1e8c2d6bec9aaad31a9b4367219e28958f3d1 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Jun 2020 11:24:45 -0400 Subject: [PATCH 13/21] Update init docs --- qiskit/result/counts.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index 3ef69540c904..936891cfe4a0 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -34,12 +34,20 @@ def __init__(self, data, name=None, shots=None, time_taken=None, """Build a counts object Args: - data (dict): The dictionary input for the counts. The key should - be a hexademical string of the form ``"0x4a"``, a bit string in - little endian format, or an integer representing the - measured classical value from the experiment and the - dictionary's value is an integer representing the number of - shots with that result. + data (dict): The dictionary input for the counts. Where the keys + represent a measured classical value and the value is an + integer the number of shots with that result. + The keys can be one of several formats: + + * A hexademical string of the form ``"0x4a"`` + * A bit string prefixed with ``0b`` for example ``'0b1011'`` + * A bit string formatted across register and memory slots. + For example, + * A dit string, for example ``'02'``. Note for objects created + with dit strings the ``creg_sizes``and ``memory_slots`` + kwargs don't work and :meth:`hex_outcomes` and + :meth:`int_outcomes` also do not work. + name (str): A string name for the counts object shots (int): The number of shots used in the experiment time_taken (float): The duration of the experiment that generated From 3acb00be15e30e59002cceac1df5ee7881ca2ddf Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Jun 2020 11:48:30 -0400 Subject: [PATCH 14/21] Fix docs again --- qiskit/result/counts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index 936891cfe4a0..8c86a4b0524e 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -42,7 +42,7 @@ def __init__(self, data, name=None, shots=None, time_taken=None, * A hexademical string of the form ``"0x4a"`` * A bit string prefixed with ``0b`` for example ``'0b1011'`` * A bit string formatted across register and memory slots. - For example, + For example, ``'00 10'``. * A dit string, for example ``'02'``. Note for objects created with dit strings the ``creg_sizes``and ``memory_slots`` kwargs don't work and :meth:`hex_outcomes` and From c8706239047d45a3231cbc6f78aa6745df2de782 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Jun 2020 12:04:32 -0400 Subject: [PATCH 15/21] Add tests for 0b prefixed input --- test/python/result/test_counts.py | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/python/result/test_counts.py b/test/python/result/test_counts.py index 565806fc2f34..d4393ae9890d 100644 --- a/test/python/result/test_counts.py +++ b/test/python/result/test_counts.py @@ -204,3 +204,53 @@ def test_qudit_counts_most_frequent(self): '12': 114, '20': 117, '21': 104, '22': 102} counts_obj = counts.Counts(raw_counts) self.assertEqual('00', counts_obj.most_frequent()) + + def test_just_0b_bitstring_counts(self): + raw_counts = {'0b0': 21, '0b10': 12} + expected = {'0': 21, '10': 12} + result = counts.Counts(raw_counts) + self.assertEqual(expected, result) + + def test_0b_bistring_counts_with_exta_formatting_data(self): + raw_counts = {'0b0': 4, '0b10': 10} + expected = {'0 0 00': 4, '0 0 10': 10} + result = counts.Counts(raw_counts, 'test_counts', shots=14, + creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], + memory_slots=4) + self.assertEqual(result, expected) + + def test_marginal_0b_string_counts(self): + raw_counts = {'0b0': 4, '0b1': 7, '0b10': 10, '0b110': 5, '0b1001': 11, + '0b1101': 9, '0b1110': 8} + expected = {'00': 4, '01': 27, '10': 23} + counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + memory_slots=4) + result = utils.marginal_counts(counts_obj, [0, 1]) + self.assertEqual(expected, result) + + def test_int_outcomes_with_0b_bitstring_counts(self): + raw_counts = {'0b0': 21, '0b10': 12, '0b11': 5, '0b101110': 265} + expected = {0: 21, 2: 12, 3: 5, 46: 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.int_outcomes() + self.assertEqual(expected, result) + + def test_most_frequent_0b_bitstring_counts(self): + raw_counts = {'0b0': 21, '0b10': 12, '0b11': 5, '0b101110': 265} + expected = '101110' + counts_obj = counts.Counts(raw_counts) + result = counts_obj.most_frequent() + self.assertEqual(expected, result) + + def test_most_frequent_duplicate_0b_bitstring_counts(self): + raw_counts = {'0b0': 265, '0b10': 12, '0b11': 5, '0b101110': 265} + counts_obj = counts.Counts(raw_counts) + self.assertRaises(exceptions.QiskitError, + counts_obj.most_frequent) + + def test_hex_outcomes_0b_bitstring_counts(self): + raw_counts = {'0b0': 265, '0b10': 12, '0b11': 5, '0b101110': 265} + expected = {'0x0': 265, '0x2': 12, '0x3': 5, '0x2e': 265} + counts_obj = counts.Counts(raw_counts) + result = counts_obj.hex_outcomes() + self.assertEqual(expected, result) From c1d78603d8557dca72d29fdfbd831f2afb4c9a23 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 16 Jun 2020 13:03:56 -0400 Subject: [PATCH 16/21] Remove metadata from Counts object This commit removes the metadata support from the counts object. There is some debate on wheter we want to enable support for attaching arbitrary key value metadata to a Counts object or not. Until that debate is settled this commit removes it from the object to unblock progress. It will be simple to add in a backwards compat manner if it decided that we want to enable this in the future. --- qiskit/result/counts.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index 8c86a4b0524e..a4b2861f8ab0 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -30,7 +30,7 @@ class Counts(dict): """A class to store a counts result from a circuit execution.""" def __init__(self, data, name=None, shots=None, time_taken=None, - creg_sizes=None, memory_slots=None, **metadata): + creg_sizes=None, memory_slots=None): """Build a counts object Args: @@ -117,7 +117,6 @@ def __init__(self, data, name=None, shots=None, time_taken=None, self.name = name self.shots = shots self.time_taken = time_taken - self.metadata = metadata def most_frequent(self): """Return the most frequent count From b6a5e0504bfd7de4d08f36bfd18e8d624978527b Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 16 Jun 2020 13:48:24 -0400 Subject: [PATCH 17/21] Use Counts instead of dict for Results.get_counts() output --- qiskit/result/result.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/qiskit/result/result.py b/qiskit/result/result.py index 6eab40925548..64c8132f4f8d 100644 --- a/qiskit/result/result.py +++ b/qiskit/result/result.py @@ -22,6 +22,7 @@ from qiskit.quantum_info.states import statevector from qiskit.result.models import ExperimentResult from qiskit.result import postprocess +from qiskit.result.counts import Counts from qiskit.qobj.utils import MeasLevel from qiskit.qobj import QobjHeader @@ -242,7 +243,14 @@ def get_counts(self, experiment=None): header = None if 'counts' in self.data(key).keys(): - dict_list.append(postprocess.format_counts(self.data(key)['counts'], header)) + if header: + counts_header = { + k: v for k, v in header.items() if k in { + 'name', 'shots', 'time_taken', 'creg_sizes', + 'memory_slots'}} + else: + counts_header = {} + dict_list.append(Counts(self.data(key)['counts'], **counts_header)) elif 'statevector' in self.data(key).keys(): vec = postprocess.format_statevector(self.data(key)['statevector']) dict_list.append(statevector.Statevector(vec).probabilities_dict(decimals=15)) From 91cf8fbe192498782fc49656eb0fd2813dc635d8 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 29 Jun 2020 07:51:32 -0400 Subject: [PATCH 18/21] Remove other circuit level metadata --- qiskit/result/counts.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index a4b2861f8ab0..b3aa1575b74f 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -29,8 +29,8 @@ class Counts(dict): """A class to store a counts result from a circuit execution.""" - def __init__(self, data, name=None, shots=None, time_taken=None, - creg_sizes=None, memory_slots=None): + def __init__(self, data, time_taken=None, creg_sizes=None, + memory_slots=None): """Build a counts object Args: @@ -48,8 +48,6 @@ def __init__(self, data, name=None, shots=None, time_taken=None, kwargs don't work and :meth:`hex_outcomes` and :meth:`int_outcomes` also do not work. - name (str): A string name for the counts object - shots (int): The number of shots used in the experiment time_taken (float): The duration of the experiment that generated the counts creg_sizes (list): a nested list where the inner element is a list @@ -58,7 +56,6 @@ def __init__(self, data, name=None, shots=None, time_taken=None, ``[('c_reg', 2), ('my_creg', 4)]``. memory_slots (int): The number of total ``memory_slots`` in the experiment. - metadata: Any arbitrary key value metadata passed in as kwargs. Raises: TypeError: If the input key type is not an int or string QiskitError: If a dit string key is input with creg_sizes and/or From dc1efdcff3c537b576c29724a6c095047f1b8b2a Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 29 Jun 2020 07:58:08 -0400 Subject: [PATCH 19/21] Update results to not include removed metadata --- qiskit/result/result.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/result/result.py b/qiskit/result/result.py index 64c8132f4f8d..bff24c3baecc 100644 --- a/qiskit/result/result.py +++ b/qiskit/result/result.py @@ -246,8 +246,7 @@ def get_counts(self, experiment=None): if header: counts_header = { k: v for k, v in header.items() if k in { - 'name', 'shots', 'time_taken', 'creg_sizes', - 'memory_slots'}} + 'time_taken', 'creg_sizes', 'memory_slots'}} else: counts_header = {} dict_list.append(Counts(self.data(key)['counts'], **counts_header)) From 6c95b6511e4fe0937edbacdd41820993369e307e Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 29 Jun 2020 08:57:30 -0400 Subject: [PATCH 20/21] Fix tests --- test/python/result/test_counts.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/python/result/test_counts.py b/test/python/result/test_counts.py index d4393ae9890d..1625a2c72b36 100644 --- a/test/python/result/test_counts.py +++ b/test/python/result/test_counts.py @@ -34,7 +34,7 @@ def test_just_counts(self): def test_counts_with_exta_formatting_data(self): raw_counts = {'0x0': 4, '0x2': 10} expected = {'0 0 00': 4, '0 0 10': 10} - result = counts.Counts(raw_counts, 'test_counts', shots=14, + result = counts.Counts(raw_counts, 'test_counts', creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], memory_slots=4) self.assertEqual(result, expected) @@ -43,7 +43,7 @@ def test_marginal_counts(self): raw_counts = {'0x0': 4, '0x1': 7, '0x2': 10, '0x6': 5, '0x9': 11, '0xD': 9, '0xE': 8} expected = {'00': 4, '01': 27, '10': 23} - counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + counts_obj = counts.Counts(raw_counts, creg_sizes=[['c0', 4]], memory_slots=4) result = utils.marginal_counts(counts_obj, [0, 1]) self.assertEqual(expected, result) @@ -84,7 +84,7 @@ def test_just_int_counts(self): def test_int_counts_with_exta_formatting_data(self): raw_counts = {0: 4, 2: 10} expected = {'0 0 00': 4, '0 0 10': 10} - result = counts.Counts(raw_counts, 'test_counts', shots=14, + result = counts.Counts(raw_counts, 'test_counts', creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], memory_slots=4) self.assertEqual(result, expected) @@ -92,7 +92,7 @@ def test_int_counts_with_exta_formatting_data(self): def test_marginal_int_counts(self): raw_counts = {0: 4, 1: 7, 2: 10, 6: 5, 9: 11, 13: 9, 14: 8} expected = {'00': 4, '01': 27, '10': 23} - counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + counts_obj = counts.Counts(raw_counts, creg_sizes=[['c0', 4]], memory_slots=4) result = utils.marginal_counts(counts_obj, [0, 1]) self.assertEqual(expected, result) @@ -135,7 +135,7 @@ def test_just_bitstring_counts(self): def test_bistring_counts_with_exta_formatting_data(self): raw_counts = {'0': 4, '10': 10} expected = {'0 0 00': 4, '0 0 10': 10} - result = counts.Counts(raw_counts, 'test_counts', shots=14, + result = counts.Counts(raw_counts, 'test_counts', creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], memory_slots=4) self.assertEqual(result, expected) @@ -143,7 +143,7 @@ def test_bistring_counts_with_exta_formatting_data(self): def test_marginal_bitstring_counts(self): raw_counts = {'0': 4, '1': 7, '10': 10, '110': 5, '1001': 11, '1101': 9, '1110': 8} expected = {'00': 4, '01': 27, '10': 23} - counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + counts_obj = counts.Counts(raw_counts, creg_sizes=[['c0', 4]], memory_slots=4) result = utils.marginal_counts(counts_obj, [0, 1]) self.assertEqual(expected, result) @@ -214,7 +214,7 @@ def test_just_0b_bitstring_counts(self): def test_0b_bistring_counts_with_exta_formatting_data(self): raw_counts = {'0b0': 4, '0b10': 10} expected = {'0 0 00': 4, '0 0 10': 10} - result = counts.Counts(raw_counts, 'test_counts', shots=14, + result = counts.Counts(raw_counts, 'test_counts', creg_sizes=[['c0', 2], ['c0', 1], ['c1', 1]], memory_slots=4) self.assertEqual(result, expected) @@ -223,7 +223,7 @@ def test_marginal_0b_string_counts(self): raw_counts = {'0b0': 4, '0b1': 7, '0b10': 10, '0b110': 5, '0b1001': 11, '0b1101': 9, '0b1110': 8} expected = {'00': 4, '01': 27, '10': 23} - counts_obj = counts.Counts(raw_counts, shots=54, creg_sizes=[['c0', 4]], + counts_obj = counts.Counts(raw_counts, creg_sizes=[['c0', 4]], memory_slots=4) result = utils.marginal_counts(counts_obj, [0, 1]) self.assertEqual(expected, result) From 791c1e784afb40a2721b1d6d7208e613b8d04e18 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 29 Jun 2020 09:39:19 -0400 Subject: [PATCH 21/21] Really remove metadata from class --- qiskit/result/counts.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/qiskit/result/counts.py b/qiskit/result/counts.py index b3aa1575b74f..af85df33827a 100644 --- a/qiskit/result/counts.py +++ b/qiskit/result/counts.py @@ -111,8 +111,6 @@ def __init__(self, data, time_taken=None, creg_sizes=None, if not bin_data: bin_data = postprocess.format_counts(self.hex_raw, header=header) super().__init__(bin_data) - self.name = name - self.shots = shots self.time_taken = time_taken def most_frequent(self):