-
Notifications
You must be signed in to change notification settings - Fork 131
Spectroscopy #31
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
Merged
Merged
Spectroscopy #31
Changes from all commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
1a68a65
* First draft of spectroscopy.
eggerdj c6497e9
* Changed counts to memory for Level1 data.
eggerdj fa1ee89
* Switched to _physical_qubits[0]
eggerdj 2e54b61
* Added user provided initial guesses.
eggerdj 21b9c74
* Black.
eggerdj 8eaccf0
* Added fit boundaries.
eggerdj 7f7e8aa
* Black and Lint.
eggerdj fbb81f5
* Improved docstring.
eggerdj 3c33538
* Fixed default parameters.
eggerdj b60de51
* Fixed array bug.
eggerdj 1f19f3d
* Added optional to type hints.
eggerdj c9791c8
* Black.
eggerdj a8ba063
* Added tests
eggerdj 3301a17
* Updated guesses.
eggerdj b167e23
* Changed default to / 4 instead of / 5
eggerdj fa334da
* Added circuit information to the metadata.
eggerdj 846af31
* Made frequency a parameter in the gate.
eggerdj 2937795
* Added dt to metadata and improved docstring.
eggerdj 44f7400
* Improved algorithmic criteria for the fit quality.
eggerdj 4ddb9b9
Merge branch 'main' into spectroscopy
eggerdj 9dd5bf8
* Moved spectroscopy to characterization.
eggerdj 3b0f35d
* Added better defaults for fit quality.
eggerdj 47f4e50
* Black.
eggerdj 7f9a5b1
* Updated to recent ExperimentData change.
eggerdj 1bfe7d6
* Test.
eggerdj de6eac3
* Added trailling kwargs
eggerdj aaa0c40
* Lint.
eggerdj cb1f52b
* Temporary commit to debug CI.
eggerdj 887f012
* Removing previous commit.
eggerdj 7a80b2a
* Added TestJob to the test.
eggerdj 43d1603
Merge branch 'main' into spectroscopy
eggerdj 6466f0a
* Removed self._absolute in the metadata.
eggerdj e8fbbf5
Merge branch 'spectroscopy' of github.com:eggerdj/qiskit-experiments …
eggerdj 6173531
* physical_qubits.
eggerdj 66b49ca
* Changed bounds from list to tuple.
eggerdj fa13a8a
* Temporarily removed Excpet to figure out why CI is failing.
eggerdj 3cf6c6e
* Added HAS_MATPLOTLIB
eggerdj fd934a1
* Added back the exception.
eggerdj d1b1c9b
* Fixed sqrt issue on sigma.
eggerdj 7138dae
Merge branch 'main' into spectroscopy
eggerdj 6c7275f
* Small refactoring of fitting.
eggerdj fcc0489
Merge branch 'main' into spectroscopy
eggerdj 4085945
* Built in SVD.
eggerdj ec81cb5
* Working on tests.
eggerdj 5307ae6
* Improved tests.
eggerdj 58a53db
* Doctrings.
eggerdj 3cf9d65
* Lint and plotting.
eggerdj 42886fa
* Fixed docstring in tests.
eggerdj 69087dd
* Made sure data processor error returns the standard deviation.
eggerdj d4b8670
* Singled out reusable part of spectroscopy test.
eggerdj 10aeb05
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into spec…
eggerdj c7de4c1
* Added pulse parameters as kwargs.
eggerdj cb8e5e2
* Drive channel.
eggerdj 3f43c74
* Renamed Spectroscopy to QubitSpectroscopy.
eggerdj 717dce0
* Outsourced the getting of a data processor to a class method in Dat…
eggerdj d5b1128
* Fixed the docs.
eggerdj 37a6d5c
* Obtaining dt from the backend.
eggerdj 0ca6ce1
Merge branch 'main' into spectroscopy
eggerdj b7521b6
Merge branch 'main' into spectroscopy
eggerdj 75e4063
* Moved pulse options into experiment options and out of run options.
eggerdj 4409442
Merge branch 'spectroscopy' of github.com:eggerdj/qiskit-experiments …
eggerdj 9b14031
* Started a data processor library.
eggerdj 42b5cc6
* Added test for the average on spectroscopy.
eggerdj c83a2fc
Merge branch 'main' into spectroscopy
eggerdj 026b71d
Update qiskit_experiments/characterization/qubit_spectroscopy.py
eggerdj dd23d10
* removed np.random.seed(0).
eggerdj 1b5641b
Merge branch 'main' into spectroscopy
eggerdj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
455 changes: 455 additions & 0 deletions
455
qiskit_experiments/characterization/qubit_spectroscopy.py
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2021. | ||
# | ||
# 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 collection of functions that return various data processors.""" | ||
|
||
from qiskit.qobj.utils import MeasLevel | ||
|
||
from qiskit_experiments.data_processing.exceptions import DataProcessorError | ||
from qiskit_experiments.data_processing.data_processor import DataProcessor | ||
from qiskit_experiments.data_processing.nodes import AverageData, Probability, SVD | ||
|
||
|
||
def get_to_signal_processor( | ||
meas_level: MeasLevel = MeasLevel.CLASSIFIED, meas_return: str = "avg" | ||
) -> DataProcessor: | ||
"""Get a DataProcessor that produces a continuous signal given the options. | ||
|
||
Args: | ||
meas_level: The measurement level of the data to process. | ||
meas_return: The measurement return (single or avg) of the data to process. | ||
|
||
Returns: | ||
An instance of DataProcessor capable of dealing with the given options. | ||
|
||
Raises: | ||
DataProcessorError: if the measurement level is not supported. | ||
""" | ||
if meas_level == MeasLevel.CLASSIFIED: | ||
return DataProcessor("counts", [Probability("1")]) | ||
|
||
if meas_level == MeasLevel.KERNELED: | ||
if meas_return == "single": | ||
return DataProcessor("memory", [AverageData(), SVD()]) | ||
else: | ||
return DataProcessor("memory", [SVD()]) | ||
|
||
raise DataProcessorError(f"Unsupported measurement level {meas_level}.") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2021. | ||
# | ||
# 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. | ||
|
||
""" | ||
Test tools for experiment. | ||
""" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2021. | ||
# | ||
# 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. | ||
|
||
"""An mock IQ backend for testing.""" | ||
|
||
from typing import Dict, List, Tuple | ||
import numpy as np | ||
|
||
from qiskit.providers.backend import BackendV1 as Backend | ||
from qiskit.providers import JobV1 | ||
from qiskit.providers.models import QasmBackendConfiguration | ||
from qiskit.result import Result | ||
|
||
|
||
class TestJob(JobV1): | ||
"""Job for testing.""" | ||
|
||
def __init__(self, backend: Backend, result: Dict): | ||
"""Setup a job for testing.""" | ||
super().__init__(backend, "test-id") | ||
self._result = result | ||
|
||
def result(self) -> Result: | ||
"""Return a result.""" | ||
return Result.from_dict(self._result) | ||
|
||
def submit(self): | ||
pass | ||
|
||
def status(self): | ||
pass | ||
|
||
def cancel(self): | ||
pass | ||
|
||
|
||
class IQTestBackend(Backend): | ||
"""An abstract backend for testing that can mock IQ data.""" | ||
|
||
__configuration__ = { | ||
"backend_name": "simulator", | ||
"backend_version": "0", | ||
"n_qubits": int(1), | ||
"basis_gates": [], | ||
"gates": [], | ||
"local": True, | ||
"simulator": True, | ||
"conditional": False, | ||
"open_pulse": False, | ||
"memory": True, | ||
"max_shots": int(1e6), | ||
"coupling_map": [], | ||
"dt": 0.1, | ||
} | ||
|
||
def __init__( | ||
self, | ||
iq_cluster_centers: Tuple[float, float, float, float] = (1.0, 1.0, -1.0, -1.0), | ||
iq_cluster_width: float = 1.0, | ||
): | ||
""" | ||
Initialize the backend. | ||
""" | ||
self._iq_cluster_centers = iq_cluster_centers | ||
self._iq_cluster_width = iq_cluster_width | ||
|
||
self._rng = np.random.default_rng(0) | ||
|
||
super().__init__(QasmBackendConfiguration(**self.__configuration__)) | ||
|
||
def _default_options(self): | ||
"""Default options of the test backend.""" | ||
|
||
def _draw_iq_shot(self, prob) -> List[List[float]]: | ||
"""Produce an IQ shot.""" | ||
|
||
rand_i = self._rng.normal(0, self._iq_cluster_width) | ||
rand_q = self._rng.normal(0, self._iq_cluster_width) | ||
|
||
if self._rng.binomial(1, prob) > 0.5: | ||
return [[self._iq_cluster_centers[0] + rand_i, self._iq_cluster_centers[1] + rand_q]] | ||
else: | ||
return [[self._iq_cluster_centers[2] + rand_i, self._iq_cluster_centers[3] + rand_q]] | ||
|
||
def run(self, run_input, **options) -> TestJob: | ||
"""Subclasses will need to override this.""" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2021. | ||
# | ||
# 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. | ||
|
||
"""Spectroscopy tests.""" | ||
|
||
from typing import Tuple | ||
|
||
import numpy as np | ||
from qiskit.qobj.utils import MeasLevel | ||
from qiskit.test import QiskitTestCase | ||
|
||
from qiskit_experiments.characterization.qubit_spectroscopy import QubitSpectroscopy | ||
from qiskit_experiments.test.mock_iq_backend import TestJob, IQTestBackend | ||
|
||
|
||
class SpectroscopyBackend(IQTestBackend): | ||
""" | ||
A simple and primitive backend to test spectroscopy experiments. | ||
""" | ||
|
||
def __init__( | ||
self, | ||
line_width: float = 2e6, | ||
freq_offset: float = 0.0, | ||
iq_cluster_centers: Tuple[float, float, float, float] = (1.0, 1.0, -1.0, -1.0), | ||
iq_cluster_width: float = 0.2, | ||
): | ||
"""Initialize the spectroscopy backend.""" | ||
|
||
self.__configuration__["basis_gates"] = ["spec"] | ||
|
||
self._linewidth = line_width | ||
self._freq_offset = freq_offset | ||
|
||
super().__init__(iq_cluster_centers, iq_cluster_width) | ||
|
||
# pylint: disable = arguments-differ | ||
def run( | ||
self, circuits, shots=1024, meas_level=MeasLevel.KERNELED, meas_return="single", **options | ||
): | ||
"""Run the spectroscopy backend.""" | ||
|
||
result = { | ||
"backend_name": "spectroscopy backend", | ||
"backend_version": "0", | ||
"qobj_id": 0, | ||
"job_id": 0, | ||
"success": True, | ||
"results": [], | ||
} | ||
|
||
for circ in circuits: | ||
|
||
run_result = { | ||
"shots": shots, | ||
"success": True, | ||
"header": {"metadata": circ.metadata}, | ||
} | ||
|
||
set_freq = float(circ.data[0][0].params[0]) | ||
delta_freq = set_freq - self._freq_offset | ||
prob = np.exp(-(delta_freq ** 2) / (2 * self._linewidth ** 2)) | ||
|
||
if meas_level == MeasLevel.CLASSIFIED: | ||
counts = {"1": 0, "0": 0} | ||
|
||
for _ in range(shots): | ||
counts[str(self._rng.binomial(1, prob))] += 1 | ||
|
||
run_result["data"] = {"counts": counts} | ||
else: | ||
memory = [self._draw_iq_shot(prob) for _ in range(shots)] | ||
|
||
if meas_return == "avg": | ||
memory = np.average(np.array(memory), axis=0).tolist() | ||
|
||
run_result["data"] = {"memory": memory} | ||
|
||
result["results"].append(run_result) | ||
|
||
return TestJob(self, result) | ||
|
||
|
||
class TestQubitSpectroscopy(QiskitTestCase): | ||
"""Test spectroscopy experiment.""" | ||
|
||
def test_spectroscopy_end2end_classified(self): | ||
eggerdj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""End to end test of the spectroscopy experiment.""" | ||
|
||
backend = SpectroscopyBackend(line_width=2e6) | ||
|
||
spec = QubitSpectroscopy(3, np.linspace(-10.0, 10.0, 21), unit="MHz") | ||
spec.set_run_options(meas_level=MeasLevel.CLASSIFIED) | ||
result = spec.run(backend).analysis_result(0) | ||
|
||
self.assertTrue(abs(result["value"]) < 1e6) | ||
self.assertTrue(result["success"]) | ||
self.assertEqual(result["quality"], "computer_good") | ||
|
||
# Test if we find still find the peak when it is shifted by 5 MHz. | ||
backend = SpectroscopyBackend(line_width=2e6, freq_offset=5.0e6) | ||
|
||
spec = QubitSpectroscopy(3, np.linspace(-10.0, 10.0, 21), unit="MHz") | ||
spec.set_run_options(meas_level=MeasLevel.CLASSIFIED) | ||
result = spec.run(backend).analysis_result(0) | ||
|
||
self.assertTrue(result["value"] < 5.1e6) | ||
self.assertTrue(result["value"] > 4.9e6) | ||
self.assertEqual(result["quality"], "computer_good") | ||
|
||
def test_spectroscopy_end2end_kerneled(self): | ||
"""End to end test of the spectroscopy experiment on IQ data.""" | ||
|
||
backend = SpectroscopyBackend(line_width=2e6) | ||
|
||
spec = QubitSpectroscopy(3, np.linspace(-10.0, 10.0, 21), unit="MHz") | ||
result = spec.run(backend).analysis_result(0) | ||
|
||
self.assertTrue(abs(result["value"]) < 1e6) | ||
self.assertTrue(result["success"]) | ||
self.assertEqual(result["quality"], "computer_good") | ||
|
||
# Test if we find still find the peak when it is shifted by 5 MHz. | ||
backend = SpectroscopyBackend(line_width=2e6, freq_offset=5.0e6) | ||
|
||
spec = QubitSpectroscopy(3, np.linspace(-10.0, 10.0, 21), unit="MHz") | ||
result = spec.run(backend).analysis_result(0) | ||
|
||
self.assertTrue(result["value"] < 5.1e6) | ||
self.assertTrue(result["value"] > 4.9e6) | ||
self.assertEqual(result["quality"], "computer_good") | ||
self.assertTrue(result["ydata_err"] is not None) | ||
|
||
spec.set_run_options(meas_return="avg") | ||
result = spec.run(backend).analysis_result(0) | ||
|
||
self.assertTrue(result["value"] < 5.1e6) | ||
self.assertTrue(result["value"] > 4.9e6) | ||
self.assertEqual(result["quality"], "computer_good") | ||
self.assertTrue(result["ydata_err"] is None) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.