├── constraints.txt ├── qiskit_experiments ├── VERSION.txt ├── library │ ├── randomized_benchmarking │ │ ├── data │ │ │ ├── clifford_tensor_1q.npz │ │ │ ├── clifford_compose_1q.npz │ │ │ ├── clifford_inverse_1q.npz │ │ │ ├── clifford_inverse_2q.npz │ │ │ └── clifford_compose_2q_dense_selected.npz │ │ ├── rb_utils.py │ │ └── __init__.py │ ├── tomography │ │ ├── fitters │ │ │ └── __init__.py │ │ ├── basis │ │ │ ├── __init__.py │ │ │ └── cache_method.py │ │ └── __init__.py │ ├── characterization │ │ ├── analysis │ │ │ ├── __init__.py │ │ │ ├── fine_amplitude_analysis.py │ │ │ ├── t2ramsey_analysis.py │ │ │ ├── t2hahn_analysis.py │ │ │ ├── tphi_analysis.py │ │ │ └── readout_angle_analysis.py │ │ └── __init__.py │ └── quantum_volume │ │ └── __init__.py ├── visualization │ ├── drawers │ │ └── __init__.py │ ├── plotters │ │ └── __init__.py │ └── __init__.py ├── framework │ ├── containers │ │ ├── __init__.py │ │ ├── artifact_data.py │ │ └── figure_data.py │ ├── composite │ │ └── __init__.py │ ├── matplotlib.py │ ├── status.py │ └── package_deps.py ├── data_processing │ ├── exceptions.py │ ├── mitigation │ │ ├── __init__.py │ │ └── base_readout_mitigator.py │ └── discriminator.py ├── exceptions.py ├── curve_analysis │ └── standard_analysis │ │ └── __init__.py ├── database_service │ ├── exceptions.py │ ├── __init__.py │ └── device_component.py ├── test │ ├── __init__.py │ ├── utils.py │ ├── noisy_delay_aer_simulator.py │ └── fake_backend.py ├── __init__.py └── version.py ├── tools ├── other-builds.txt ├── check_latest_version.py ├── pylint_incr.py └── bump_version.py ├── .stestr.conf ├── MANIFEST.in ├── docs ├── _static │ ├── api.png │ ├── howtos.png │ ├── manuals.png │ ├── tutorials.png │ └── customstyles.css ├── tutorials │ ├── images │ │ ├── experimentarch.png │ │ ├── compositeexperiments.png │ │ └── curve_analysis_structure.png │ ├── index.rst │ └── intro.rst ├── apidocs │ ├── main.rst │ ├── test.rst │ ├── library.rst │ ├── framework.rst │ ├── visualization.rst │ ├── curve_analysis.rst │ ├── mod_tomography.rst │ ├── data_processing.rst │ ├── database_service.rst │ ├── mod_quantum_volume.rst │ ├── mod_characterization.rst │ ├── mod_randomized_benchmarking.rst │ └── index.rst ├── howtos │ ├── experiment_cloud_service │ │ └── t1_loaded.png │ ├── index.rst │ ├── figure_generation.rst │ ├── runtime_sessions.rst │ ├── experiment_times.rst │ └── job_splitting.rst ├── _templates │ └── autosummary │ │ ├── base.rst │ │ ├── module.rst │ │ ├── drawer.rst │ │ ├── plotter.rst │ │ ├── analysis.rst │ │ ├── experiment.rst │ │ ├── class.rst │ │ └── class_no_inherited_members.rst ├── manuals │ └── index.rst └── _ext │ ├── jupyter_execute_custom.py │ ├── custom_styles │ └── section_parsers.py │ ├── autoref.py │ ├── autodoc_experiment.py │ └── autodoc_analysis.py ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── documentation.md │ ├── FEATURE_REQUEST.md │ └── BUG_REPORT.md ├── workflows │ ├── neko.yml │ ├── release.yml │ ├── docs_dev.yml │ └── docs_stable.yml └── PULL_REQUEST_TEMPLATE.md ├── .mergify.yml ├── releasenotes └── notes │ ├── prepare-0.13.0-167e9b7befc25c7f.yaml │ ├── rb-clifford-10k-3429e74f4a82848e.yaml │ └── average-pub-params-f24fd73f817051ac.yaml ├── CODE_OF_CONDUCT.md ├── test ├── __init__.py ├── curve_analysis │ ├── __init__.py │ └── test_standard_analysis.py ├── library │ ├── __init__.py │ ├── tomography │ │ ├── __init__.py │ │ └── tomo_utils.py │ ├── quantum_volume │ │ ├── __init__.py │ │ ├── qv_ideal_probabilities.json │ │ ├── qv_ideal_probabilities_qiskit_2_0.json │ │ ├── qv_ideal_probabilities_qiskit_1_3.json │ │ └── qv_ideal_probabilities_qiskit_1_1.json │ ├── characterization │ │ ├── __init__.py │ │ ├── test_fine_drag.py │ │ ├── test_fine_frequency.py │ │ ├── test_half_angle.py │ │ ├── test_readout_angle.py │ │ └── test_multi_state_discrimination.py │ └── randomized_benchmarking │ │ ├── __init__.py │ │ ├── mixin.py │ │ └── test_rb_utils.py ├── framework │ ├── __init__.py │ ├── test_version.py │ ├── test_artifacts.py │ └── test_warnings.py ├── visualization │ ├── __init__.py │ ├── test_mpldrawer.py │ └── test_plotter.py ├── database_service │ └── __init__.py ├── data_processing │ └── __init__.py ├── test_base.py └── fake_experiment.py ├── CITATION.cff ├── README.md ├── .gitignore └── pyproject.toml /constraints.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qiskit_experiments/VERSION.txt: -------------------------------------------------------------------------------- 1 | 0.14.0 2 | -------------------------------------------------------------------------------- /tools/other-builds.txt: -------------------------------------------------------------------------------- 1 | dev/** 2 | stable/** -------------------------------------------------------------------------------- /.stestr.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | test_path=./test 3 | parallel_class=True -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune docs/ 2 | prune .github/ 3 | prune releasenotes/ 4 | prune tools/ 5 | -------------------------------------------------------------------------------- /docs/_static/api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/_static/api.png -------------------------------------------------------------------------------- /docs/_static/howtos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/_static/howtos.png -------------------------------------------------------------------------------- /docs/_static/manuals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/_static/manuals.png -------------------------------------------------------------------------------- /docs/_static/tutorials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/_static/tutorials.png -------------------------------------------------------------------------------- /docs/tutorials/images/experimentarch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/tutorials/images/experimentarch.png -------------------------------------------------------------------------------- /docs/tutorials/images/compositeexperiments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/tutorials/images/compositeexperiments.png -------------------------------------------------------------------------------- /docs/apidocs/main.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-main: 2 | 3 | .. automodule:: qiskit_experiments 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/howtos/experiment_cloud_service/t1_loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/howtos/experiment_cloud_service/t1_loaded.png -------------------------------------------------------------------------------- /docs/tutorials/images/curve_analysis_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/docs/tutorials/images/curve_analysis_structure.png -------------------------------------------------------------------------------- /docs/apidocs/test.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-test: 2 | 3 | .. automodule:: qiskit_experiments.test 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: 7 | -------------------------------------------------------------------------------- /docs/apidocs/library.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-library: 2 | 3 | .. automodule:: qiskit_experiments.library 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/apidocs/framework.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-framework: 2 | 3 | .. automodule:: qiskit_experiments.framework 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/apidocs/visualization.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-visualization: 2 | 3 | .. automodule:: qiskit_experiments.visualization 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Check for updates to GitHub Actions 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | -------------------------------------------------------------------------------- /docs/apidocs/curve_analysis.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-curve-analysis: 2 | 3 | .. automodule:: qiskit_experiments.curve_analysis 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/apidocs/mod_tomography.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-tomography: 2 | 3 | .. automodule:: qiskit_experiments.library.tomography 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/apidocs/data_processing.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-data-processing: 2 | 3 | .. automodule:: qiskit_experiments.data_processing 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/apidocs/database_service.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-database-service: 2 | 3 | .. automodule:: qiskit_experiments.database_service 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/apidocs/mod_quantum_volume.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-quantum-volume: 2 | 3 | .. automodule:: qiskit_experiments.library.quantum_volume 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | pull_request_rules: 3 | - name: backport 4 | conditions: 5 | - label=backport stable potential 6 | actions: 7 | backport: 8 | branches: 9 | - stable/0.13 10 | -------------------------------------------------------------------------------- /docs/apidocs/mod_characterization.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-characterization: 2 | 3 | .. automodule:: qiskit_experiments.library.characterization 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/data/clifford_tensor_1q.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/qiskit_experiments/library/randomized_benchmarking/data/clifford_tensor_1q.npz -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation 3 | about: 'Create a report to help us improve the documentation ' 4 | title: '' 5 | labels: documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/data/clifford_compose_1q.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/qiskit_experiments/library/randomized_benchmarking/data/clifford_compose_1q.npz -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/data/clifford_inverse_1q.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/qiskit_experiments/library/randomized_benchmarking/data/clifford_inverse_1q.npz -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/data/clifford_inverse_2q.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/qiskit_experiments/library/randomized_benchmarking/data/clifford_inverse_2q.npz -------------------------------------------------------------------------------- /releasenotes/notes/prepare-0.13.0-167e9b7befc25c7f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Qiskit Experiments 0.13.0 is a small update with a fix for long randomized benchmarking sequences and a new niche feature for averaging parameterized PUBs. 4 | -------------------------------------------------------------------------------- /docs/apidocs/mod_randomized_benchmarking.rst: -------------------------------------------------------------------------------- 1 | .. _qiskit-experiments-randomized-benchmarking: 2 | 3 | .. automodule:: qiskit_experiments.library.randomized_benchmarking 4 | :no-members: 5 | :no-inherited-members: 6 | :no-special-members: -------------------------------------------------------------------------------- /docs/_templates/autosummary/base.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. currentmodule:: {{ module }} 9 | 10 | .. auto{{ objtype }}:: {{ objname }} 11 | -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/data/clifford_compose_2q_dense_selected.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit-experiments/HEAD/qiskit_experiments/library/randomized_benchmarking/data/clifford_compose_2q_dense_selected.npz -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Code of Conduct 4 | All members of this project agree to adhere to the [Qiskit Code of Conduct](https://github.com/Qiskit/qiskit/blob/main/CODE_OF_CONDUCT.md). 5 | 6 | ---- 7 | 8 | License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), 9 | Copyright Contributors to Qiskit. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/rb-clifford-10k-3429e74f4a82848e.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | A workaround was added for a limit on exponentiation imposed by `LMFIT 5 | `__ which prevented 6 | :class:`.RBAnalysis` from working on experiments with Clifford lengths 7 | longer than 10,000. See `#1594 8 | `__. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature request" 3 | about: "Suggest an idea for this project \U0001F4A1!" 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | 13 | ### Suggested feature 14 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | -------------------------------------------------------------------------------- /test/curve_analysis/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | -------------------------------------------------------------------------------- /.github/workflows/neko.yml: -------------------------------------------------------------------------------- 1 | name: Qiskit Neko Integration Tests 2 | on: 3 | push: 4 | pull_request: 5 | branches: ['main'] 6 | concurrency: 7 | group: ${{ github.repository }}-${{ github.ref }}-${{ github.head_ref }}-${{ github.workflow }} 8 | cancel-in-progress: true 9 | jobs: 10 | neko: 11 | if: github.repository_owner == 'Qiskit-Community' 12 | name: Qiskit Neko Integration Tests 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: Qiskit/qiskit-neko@main 16 | with: 17 | test_selection: experiment 18 | -------------------------------------------------------------------------------- /releasenotes/notes/average-pub-params-f24fd73f817051ac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | features: 4 | - | 5 | Enable averaging PUB parameters in :class:`~.ExperimentData` when 6 | the circuit metadata contain "average_params". This feature is undocumented 7 | for now since it is niche. It requires the user to submit parameterized 8 | circuits to a sampler outside of an experiment and then add the results to 9 | an :class:`.ExperimentData` object since Qiskit Experiments does not 10 | currently support running parameterized PUBs directly. 11 | -------------------------------------------------------------------------------- /test/library/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Tests for library experiments""" 13 | -------------------------------------------------------------------------------- /test/framework/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Tests of experiments framework""" 13 | -------------------------------------------------------------------------------- /test/library/tomography/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Tests for tomography experiments""" 13 | -------------------------------------------------------------------------------- /test/visualization/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Test cases for visualization plotting.""" 13 | -------------------------------------------------------------------------------- /test/library/quantum_volume/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Tests for quantum volume experiment""" 13 | -------------------------------------------------------------------------------- /test/database_service/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test cases for database service modules.""" 14 | -------------------------------------------------------------------------------- /test/library/characterization/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Tests for characterization experiments""" 13 | -------------------------------------------------------------------------------- /test/library/randomized_benchmarking/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Tests for randomized benchmarking experiments""" 13 | -------------------------------------------------------------------------------- /test/data_processing/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Data processing tests.""" 14 | from .base_data_processor_test import BaseDataProcessorTest 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: "Create a report to help us improve \U0001F914." 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | 13 | ### Informations 14 | 15 | - **Qiskit Experiments version**: 16 | - **Python version**: 17 | - **Operating system**: 18 | 19 | ### What is the current behavior? 20 | 21 | 22 | 23 | ### Steps to reproduce the problem 24 | 25 | 26 | 27 | ### What is the expected behavior? 28 | 29 | 30 | 31 | ### Suggested solutions 32 | -------------------------------------------------------------------------------- /qiskit_experiments/visualization/drawers/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Drawers submodule, defining interfaces to figure backends.""" 13 | 14 | from .base_drawer import BaseDrawer, SeriesName 15 | from .mpl_drawer import MplDrawer 16 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/containers/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2023. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Container classes for storing data related to experiments.""" 14 | 15 | from .artifact_data import ArtifactData 16 | from .figure_data import FigureData, FigureType 17 | -------------------------------------------------------------------------------- /qiskit_experiments/visualization/plotters/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Plotters submodule, defining interfaces to draw figures.""" 13 | 14 | from .base_plotter import BasePlotter 15 | from .curve_plotter import CurvePlotter 16 | from .iq_plotter import IQPlotter 17 | -------------------------------------------------------------------------------- /qiskit_experiments/data_processing/exceptions.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Exceptions for data processing.""" 14 | 15 | from qiskit.exceptions import QiskitError 16 | 17 | 18 | class DataProcessorError(QiskitError): 19 | """Errors raised by the data processing module.""" 20 | -------------------------------------------------------------------------------- /qiskit_experiments/exceptions.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Exceptions for errors raised by Qiskit Experiments.""" 14 | 15 | from qiskit.exceptions import QiskitError 16 | 17 | 18 | class AnalysisError(QiskitError): 19 | """Class for errors raised by experiment analysis.""" 20 | -------------------------------------------------------------------------------- /docs/howtos/index.rst: -------------------------------------------------------------------------------- 1 | How-To Guides 2 | ============= 3 | 4 | This section of the documentation provides concrete step-by-step instructions for how to 5 | do specific useful actions in Qiskit Experiments. It is recommended that you first 6 | familiarize with :ref:`the basics ` of the package before using these guides. 7 | 8 | .. toctree:: 9 | :caption: How to... 10 | :maxdepth: 1 11 | :glob: 12 | 13 | * 14 | 15 | | 16 | 17 | If there are guides on solving specific problems that you'd like to see added, please 18 | `file an issue on GitHub `_. 19 | 20 | | 21 | 22 | 23 | .. Hiding - Indices and tables 24 | :ref:`genindex` 25 | :ref:`modindex` 26 | :ref:`search` 27 | -------------------------------------------------------------------------------- /qiskit_experiments/library/tomography/fitters/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Tomography fitter functions""" 14 | 15 | from .fitter_data import tomography_fitter_data 16 | from .postprocess_fit import postprocess_fitter 17 | from .lininv import linear_inversion 18 | from .cvxpy_lstsq import cvxpy_linear_lstsq, cvxpy_gaussian_lstsq 19 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Artifacts 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | jobs: 7 | wheel-build: 8 | name: Build and Publish Release Artifacts 9 | runs-on: ubuntu-latest 10 | environment: release 11 | permissions: 12 | id-token: write 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: actions/setup-python@v6 16 | name: Install Python 17 | with: 18 | python-version: '3.13' 19 | - name: Install Deps 20 | run: pip install -U build 21 | - name: Build Artifacts 22 | run: | 23 | python -m build 24 | shell: bash 25 | - uses: actions/upload-artifact@v5 26 | with: 27 | path: ./dist/qiskit* 28 | - name: Publish to PyPi 29 | uses: pypa/gh-action-pypi-publish@release/v1 30 | -------------------------------------------------------------------------------- /qiskit_experiments/library/tomography/basis/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Tomography experiment basis classes.""" 14 | 15 | from .base_basis import MeasurementBasis, PreparationBasis 16 | from .local_basis import LocalPreparationBasis, LocalMeasurementBasis 17 | from .pauli_basis import PauliMeasurementBasis, PauliPreparationBasis, Pauli6PreparationBasis 18 | -------------------------------------------------------------------------------- /docs/apidocs/index.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | The API documentation is organized into two sections below. The package modules include the framework, the 5 | experiment library, experiment modules, and test utilities. Experiment modules are 6 | the main categories of the experiment library itself, such as qubit characterization 7 | and experimental suites like tomography. 8 | 9 | Package Modules 10 | --------------- 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | 15 | main 16 | framework 17 | library 18 | data_processing 19 | curve_analysis 20 | database_service 21 | visualization 22 | test 23 | 24 | Experiment Modules 25 | ------------------ 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | 30 | mod_characterization 31 | mod_randomized_benchmarking 32 | mod_tomography 33 | mod_quantum_volume 34 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/composite/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Composite Experiments""" 14 | 15 | # Base classes 16 | from .composite_experiment import CompositeExperiment 17 | from .composite_analysis import CompositeAnalysis 18 | 19 | # Composite experiment classes 20 | from .parallel_experiment import ParallelExperiment 21 | from .batch_experiment import BatchExperiment 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > The PR title and description will be used as the commit message upon merge. 3 | > 4 | > **Please delete all content in this template** before merging and keep the 5 | > description updated if the PR changes. 6 | > 7 | > Please keep the description concise and focused on the changes to the repository. 8 | > Secondary discussions, such as intermediate testing and bug statuses that do 9 | > not affect the final PR, should be in the PR comments. 10 | 11 | ### PR checklist (delete when all criteria are met) 12 | 13 | - [ ] I have referenced any relevant issue addressed by this change. 14 | - [ ] I have read the contributing guide `CONTRIBUTING.md`. 15 | - [ ] I have added the tests to cover my changes. 16 | - [ ] I have updated the documentation accordingly. 17 | - [ ] I have added a release note file using `reno` if this change needs to be documented in the release notes. 18 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/module.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. automodule:: {{ fullname }} 9 | 10 | {% block functions %} 11 | {% if functions %} 12 | .. rubric:: Functions 13 | 14 | .. autosummary:: 15 | {% for item in functions %} 16 | {{ item }} 17 | {%- endfor %} 18 | {% endif %} 19 | {% endblock %} 20 | 21 | {% block classes %} 22 | {% if classes %} 23 | .. rubric:: Classes 24 | 25 | .. autosummary:: 26 | {% for item in classes %} 27 | {{ item }} 28 | {%- endfor %} 29 | {% endif %} 30 | {% endblock %} 31 | 32 | {% block exceptions %} 33 | {% if exceptions %} 34 | .. rubric:: Exceptions 35 | 36 | .. autosummary:: 37 | {% for item in exceptions %} 38 | {{ item }} 39 | {%- endfor %} 40 | {% endif %} 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /qiskit_experiments/curve_analysis/standard_analysis/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Standard curve analysis library.""" 14 | 15 | from .oscillation import OscillationAnalysis, DampedOscillationAnalysis 16 | from .gaussian import GaussianAnalysis 17 | from .error_amplification_analysis import ErrorAmplificationAnalysis 18 | from .decay import DecayAnalysis 19 | from .bloch_trajectory import BlochTrajectoryAnalysis 20 | -------------------------------------------------------------------------------- /qiskit_experiments/data_processing/mitigation/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2017, 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Readout error mitigation.""" 14 | from .base_readout_mitigator import BaseReadoutMitigator 15 | from .correlated_readout_mitigator import CorrelatedReadoutMitigator 16 | from .local_readout_mitigator import LocalReadoutMitigator 17 | from .utils import ( 18 | counts_probability_vector, 19 | expval_with_stddev, 20 | stddev, 21 | str2diag, 22 | ) 23 | -------------------------------------------------------------------------------- /test/framework/test_version.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test version string generation.""" 14 | 15 | from test.base import QiskitExperimentsTestCase 16 | 17 | from qiskit_experiments import __version__ 18 | 19 | 20 | class TestVersion(QiskitExperimentsTestCase): 21 | """Test version string generation.""" 22 | 23 | def test_version_is_a_string(self): 24 | """Test version string generation.""" 25 | self.assertIsInstance(__version__, str) 26 | -------------------------------------------------------------------------------- /docs/_static/customstyles.css: -------------------------------------------------------------------------------- 1 | /* Wrap text of jupyter-sphinx output blocks */ 2 | 3 | div.output pre{ 4 | white-space: pre-wrap; 5 | } 6 | 7 | /* Styling for pandas dataframes in documentation */ 8 | 9 | div.output table { 10 | border: none; 11 | border-collapse: collapse; 12 | border-spacing: 0; 13 | color: black; 14 | font-size: 12px; 15 | table-layout: fixed; 16 | width: 100%; 17 | } 18 | div.output thead { 19 | border-bottom: 1px solid black; 20 | vertical-align: bottom; 21 | } 22 | div.output tr, 23 | div.output th, 24 | div.output td { 25 | text-align: right; 26 | vertical-align: middle; 27 | padding: 0.5em 0.5em; 28 | line-height: normal; 29 | white-space: normal; 30 | max-width: none; 31 | border: none; 32 | } 33 | div.output th { 34 | font-weight: bold; 35 | } 36 | div.output tbody tr:nth-child(odd) { 37 | background: #f5f5f5; 38 | } 39 | div.output tbody tr:hover { 40 | background: rgba(66, 165, 245, 0.2); 41 | } -------------------------------------------------------------------------------- /test/test_base.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Tests for qiskit-experiments base test module 14 | """ 15 | 16 | from test.base import create_base_test_case 17 | 18 | 19 | UnittestBase = create_base_test_case(use_testtools=False) 20 | 21 | 22 | class TestQiskitExperimentsTestCaseWithUnittest(UnittestBase): 23 | """Test QiskitExperimentsTestCase behavior when not based on testtools.TestCase""" 24 | 25 | def test_test(self): 26 | """Test that a test not based on ``testtools`` can run""" 27 | pass 28 | -------------------------------------------------------------------------------- /docs/tutorials/index.rst: -------------------------------------------------------------------------------- 1 | Tutorials 2 | ========= 3 | 4 | These tutorials assume some familiarity with Qiskit (on the level of 5 | `IBM Quantum Documentation's introductory guides `__) but no knowledge of Qiskit Experiments. 6 | They're suitable for beginners who want to get started with the package. 7 | 8 | .. _basics: 9 | 10 | The Basics 11 | ---------- 12 | 13 | .. This toctree is hardcoded since Getting Started is already included in the sidebar for more visibility. 14 | 15 | .. toctree:: 16 | :maxdepth: 1 17 | 18 | intro 19 | getting_started 20 | 21 | Exploring Modules 22 | ----------------- 23 | 24 | .. toctree:: 25 | :maxdepth: 1 26 | 27 | data_processor 28 | curve_analysis 29 | visualization 30 | 31 | Customizing Experiments 32 | ----------------------- 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | 37 | custom_experiment 38 | 39 | .. Hiding - Indices and tables 40 | :ref:`genindex` 41 | :ref:`modindex` 42 | :ref:`search` 43 | -------------------------------------------------------------------------------- /.github/workflows/docs_dev.yml: -------------------------------------------------------------------------------- 1 | name: Dev Docs Publish 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | deploy: 9 | if: github.repository_owner == 'Qiskit-Community' 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v6 13 | with: 14 | fetch-depth: 0 15 | - name: Set up Python 16 | uses: actions/setup-python@v6 17 | with: 18 | python-version: '3.12' 19 | - name: Install dependencies 20 | run: | 21 | sudo apt-get install graphviz pandoc 22 | - name: Set up uv 23 | uses: astral-sh/setup-uv@v7 24 | - name: Build docs dev 25 | run: EXPERIMENTS_DEV_DOCS=1 PROD_BUILD=1 RELEASE_STRING=`git describe` uvx --with tox-uv tox run -edocs 26 | - name: Bypass Jekyll Processing # Necessary for setting the correct css path 27 | run: touch docs/_build/html/.nojekyll 28 | - name: Deploy 29 | uses: JamesIves/github-pages-deploy-action@v4 30 | with: 31 | folder: docs/_build/html/ 32 | target-folder: dev/ 33 | -------------------------------------------------------------------------------- /test/library/randomized_benchmarking/mixin.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Mixins for randomized benchmarking module tests""" 13 | from qiskit.circuit import QuantumCircuit 14 | from qiskit.quantum_info import Operator 15 | 16 | 17 | class RBTestMixin: 18 | """Mixin for RB tests.""" 19 | 20 | def assertAllIdentity(self, circuits): 21 | """Test if all experiment circuits are identity.""" 22 | for circ in circuits: 23 | num_qubits = circ.num_qubits 24 | qc_iden = QuantumCircuit(num_qubits) 25 | circ.remove_final_measurements() 26 | self.assertTrue(Operator(circ).equiv(Operator(qc_iden))) 27 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/drawer.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. currentmodule:: {{ module }} 9 | 10 | .. autodrawer:: {{ objname }} 11 | :no-members: 12 | :no-inherited-members: 13 | :no-special-members: 14 | 15 | {% block attributes_summary %} 16 | {% if attributes %} 17 | 18 | .. rubric:: Attributes 19 | 20 | {% for item in all_attributes %} 21 | {%- if not item.startswith('_') %} 22 | .. autoattribute:: {{ name }}.{{ item }} 23 | {%- endif -%} 24 | {%- endfor %} 25 | {% endif %} 26 | {% endblock %} 27 | 28 | {% block methods_summary %} 29 | {% if methods %} 30 | 31 | .. rubric:: Methods 32 | 33 | {% for item in all_methods %} 34 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 35 | .. automethod:: {{ name }}.{{ item }} 36 | {%- endif -%} 37 | {%- endfor %} 38 | {% for item in inherited_members %} 39 | {%- if item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 40 | .. automethod:: {{ name }}.{{ item }} 41 | {%- endif -%} 42 | {%- endfor %} 43 | 44 | {% endif %} 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/plotter.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. currentmodule:: {{ module }} 9 | 10 | .. autoplotter:: {{ objname }} 11 | :no-members: 12 | :no-inherited-members: 13 | :no-special-members: 14 | 15 | {% block attributes_summary %} 16 | {% if attributes %} 17 | 18 | .. rubric:: Attributes 19 | 20 | {% for item in all_attributes %} 21 | {%- if not item.startswith('_') %} 22 | .. autoattribute:: {{ name }}.{{ item }} 23 | {%- endif -%} 24 | {%- endfor %} 25 | {% endif %} 26 | {% endblock %} 27 | 28 | {% block methods_summary %} 29 | {% if methods %} 30 | 31 | .. rubric:: Methods 32 | 33 | {% for item in all_methods %} 34 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 35 | .. automethod:: {{ name }}.{{ item }} 36 | {%- endif -%} 37 | {%- endfor %} 38 | {% for item in inherited_members %} 39 | {%- if item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 40 | .. automethod:: {{ name }}.{{ item }} 41 | {%- endif -%} 42 | {%- endfor %} 43 | 44 | {% endif %} 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/analysis.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. currentmodule:: {{ module }} 9 | 10 | .. autoanalysis:: {{ objname }} 11 | :no-members: 12 | :no-inherited-members: 13 | :no-special-members: 14 | 15 | {% block attributes_summary %} 16 | {% if attributes %} 17 | 18 | .. rubric:: Attributes 19 | 20 | {% for item in all_attributes %} 21 | {%- if not item.startswith('_') %} 22 | .. autoattribute:: {{ name }}.{{ item }} 23 | {%- endif -%} 24 | {%- endfor %} 25 | {% endif %} 26 | {% endblock %} 27 | 28 | {% block methods_summary %} 29 | {% if methods %} 30 | 31 | .. rubric:: Methods 32 | 33 | {% for item in all_methods %} 34 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 35 | .. automethod:: {{ name }}.{{ item }} 36 | {%- endif -%} 37 | {%- endfor %} 38 | {% for item in inherited_members %} 39 | {%- if item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 40 | .. automethod:: {{ name }}.{{ item }} 41 | {%- endif -%} 42 | {%- endfor %} 43 | 44 | {% endif %} 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/experiment.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. currentmodule:: {{ module }} 9 | 10 | .. autoexperiment:: {{ objname }} 11 | :no-members: 12 | :no-inherited-members: 13 | :no-special-members: 14 | 15 | {% block attributes_summary %} 16 | {% if attributes %} 17 | 18 | .. rubric:: Attributes 19 | 20 | {% for item in all_attributes %} 21 | {%- if not item.startswith('_') %} 22 | .. autoattribute:: {{ name }}.{{ item }} 23 | {%- endif -%} 24 | {%- endfor %} 25 | {% endif %} 26 | {% endblock %} 27 | 28 | {% block methods_summary %} 29 | {% if methods %} 30 | 31 | .. rubric:: Methods 32 | 33 | {% for item in all_methods %} 34 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 35 | .. automethod:: {{ name }}.{{ item }} 36 | {%- endif -%} 37 | {%- endfor %} 38 | {% for item in inherited_members %} 39 | {%- if item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 40 | .. automethod:: {{ name }}.{{ item }} 41 | {%- endif -%} 42 | {%- endfor %} 43 | 44 | {% endif %} 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/analysis/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Analysis Classes""" 14 | 15 | from .fine_amplitude_analysis import FineAmplitudeAnalysis 16 | from .ramsey_xy_analysis import RamseyXYAnalysis 17 | from .t2ramsey_analysis import T2RamseyAnalysis 18 | from .t2hahn_analysis import T2HahnAnalysis 19 | from .t1_analysis import T1Analysis, T1KerneledAnalysis 20 | from .tphi_analysis import TphiAnalysis 21 | from .readout_angle_analysis import ReadoutAngleAnalysis 22 | from .local_readout_error_analysis import LocalReadoutErrorAnalysis 23 | from .correlated_readout_error_analysis import CorrelatedReadoutErrorAnalysis 24 | from .zz_ramsey_analysis import ZZRamseyAnalysis 25 | from .multi_state_discrimination_analysis import MultiStateDiscriminationAnalysis 26 | -------------------------------------------------------------------------------- /qiskit_experiments/database_service/exceptions.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Exceptions for errors raised by experiment service data.""" 14 | 15 | from qiskit.exceptions import QiskitError 16 | 17 | 18 | class ExperimentDataError(QiskitError): 19 | """Base class for errors raised by experiment service data.""" 20 | 21 | pass 22 | 23 | 24 | class ExperimentEntryNotFound(ExperimentDataError): 25 | """Errors raised when an experiment entry cannot be found.""" 26 | 27 | pass 28 | 29 | 30 | class ExperimentEntryExists(ExperimentDataError): 31 | """Errors raised when an experiment entry already exists.""" 32 | 33 | pass 34 | 35 | 36 | class ExperimentDataSaveFailed(ExperimentDataError): 37 | """Errors raised when an experiment save fails.""" 38 | 39 | pass 40 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {% if referencefile %} 2 | .. include:: {{ referencefile }} 3 | {% endif %} 4 | 5 | {{ objname }} 6 | {{ underline }} 7 | 8 | .. currentmodule:: {{ module }} 9 | 10 | .. autoclass:: {{ objname }} 11 | :no-members: 12 | :no-inherited-members: 13 | :no-special-members: 14 | 15 | {% block attributes_summary %} 16 | 17 | {% set wanted_attributes = [] %} 18 | {% for item in attributes%} 19 | {%- if not item.startswith('_') %} 20 | {% set _ = wanted_attributes.append(item)%} 21 | {%- endif -%} 22 | {%- endfor %} 23 | 24 | {% if wanted_attributes %} 25 | .. rubric:: Attributes 26 | {% for item in wanted_attributes %} 27 | .. autoattribute:: {{ name }}.{{ item }} 28 | {%- endfor %} 29 | {% endif %} 30 | {% endblock %} 31 | 32 | {% block methods_summary %} 33 | 34 | {% set wanted_methods = [] %} 35 | {% for item in all_methods %} 36 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 37 | {% set _ = wanted_methods.append(item)%} 38 | {%- endif -%} 39 | {%- endfor %} 40 | 41 | {% if wanted_methods%} 42 | .. rubric:: Methods 43 | {% for item in wanted_methods %} 44 | .. automethod:: {{ name }}.{{ item }} 45 | {%- endfor %} 46 | 47 | {% endif %} 48 | {% endblock %} -------------------------------------------------------------------------------- /docs/manuals/index.rst: -------------------------------------------------------------------------------- 1 | Experiment Manuals 2 | ================== 3 | 4 | These experiment manuals are in-depth dives into some individual experiments, their 5 | operational principles, and how to run them in Qiskit Experiments. Note that the 6 | experiments below are only a small fraction of the full list of experiments in 7 | the :doc:`package library <../apidocs/library>`. 8 | 9 | .. _verification manuals: 10 | 11 | Verification Experiments 12 | ------------------------ 13 | 14 | These experiments measure and verify your device performance according to a set of 15 | defined metrics, such as the space-time volume of circuits that can be successfully 16 | executed. 17 | 18 | .. nbgallery:: 19 | :glob: 20 | 21 | verification/* 22 | 23 | .. _qubit characterization manuals: 24 | 25 | Qubit Characterization Experiments 26 | ---------------------------------- 27 | 28 | These experiment measure specific properties of a qubit. 29 | 30 | .. nbgallery:: 31 | :glob: 32 | 33 | characterization/* 34 | 35 | .. _measurement-related manuals: 36 | 37 | Measurement-Related Experiments 38 | ------------------------------- 39 | 40 | These experiments postprocess on measurement results to improve some aspect of a 41 | quantum circuit, such as readout fidelity or run time. 42 | 43 | .. nbgallery:: 44 | :glob: 45 | 46 | measurement/* 47 | 48 | 49 | .. Hiding - Indices and tables 50 | :ref:`genindex` 51 | :ref:`modindex` 52 | :ref:`search` 53 | -------------------------------------------------------------------------------- /docs/_templates/autosummary/class_no_inherited_members.rst: -------------------------------------------------------------------------------- 1 | {# This is identical to class.rst, except for the filtering of the inherited_members. -#} 2 | 3 | {% if referencefile %} 4 | .. include:: {{ referencefile }} 5 | {% endif %} 6 | 7 | {{ objname }} 8 | {{ underline }} 9 | 10 | .. currentmodule:: {{ module }} 11 | 12 | .. autoclass:: {{ objname }} 13 | :no-members: 14 | :no-inherited-members: 15 | :no-special-members: 16 | 17 | {% block attributes_summary %} 18 | 19 | {% set wanted_attributes = [] %} 20 | {% for item in attributes%} 21 | {%- if not item.startswith('_') %} 22 | {% set _ = wanted_attributes.append(item)%} 23 | {%- endif -%} 24 | {%- endfor %} 25 | 26 | {% if wanted_attributes%} 27 | .. rubric:: Attributes 28 | {% for item in wanted_attributes %} 29 | .. autoattribute:: {{ name }}.{{ item }} 30 | {%- endfor %} 31 | {% endif %} 32 | {% endblock %} 33 | 34 | {% block methods_summary %} 35 | 36 | {% set wanted_methods = [] %} 37 | {% for item in all_methods %} 38 | {%- if item not in inherited_members %} 39 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 40 | {% set _ = wanted_methods.append(item)%} 41 | {%- endif -%} 42 | {%- endif -%} 43 | {%- endfor %} 44 | 45 | {% if wanted_methods %} 46 | .. rubric:: Methods 47 | {% for item in wanted_methods %} 48 | .. automethod:: {{ name }}.{{ item }} 49 | {%- endfor %} 50 | 51 | {% endif %} 52 | {% endblock %} -------------------------------------------------------------------------------- /qiskit_experiments/library/quantum_volume/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | ======================================================================================= 15 | Quantum Volume Experiment (:mod:`qiskit_experiments.library.quantum_volume`) 16 | ======================================================================================= 17 | 18 | .. currentmodule:: qiskit_experiments.library.quantum_volume 19 | 20 | 21 | Experiments 22 | =========== 23 | .. autosummary:: 24 | :toctree: ../stubs/ 25 | :template: autosummary/experiment.rst 26 | 27 | QuantumVolume 28 | 29 | 30 | Analysis 31 | ======== 32 | 33 | .. autosummary:: 34 | :toctree: ../stubs/ 35 | :template: autosummary/analysis.rst 36 | 37 | QuantumVolumeAnalysis 38 | 39 | 40 | Plotter 41 | ======= 42 | 43 | .. autosummary:: 44 | :toctree: ../stubs/ 45 | :template: autosummary/plotter.rst 46 | 47 | QuantumVolumePlotter 48 | """ 49 | 50 | from .qv_experiment import QuantumVolume 51 | from .qv_analysis import QuantumVolumeAnalysis, QuantumVolumePlotter 52 | -------------------------------------------------------------------------------- /test/library/randomized_benchmarking/test_rb_utils.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | A Tester for the RB utils module 15 | """ 16 | from test.base import QiskitExperimentsTestCase 17 | from ddt import ddt 18 | 19 | import qiskit_experiments.library.randomized_benchmarking as rb 20 | 21 | 22 | @ddt 23 | class TestRBUtilities(QiskitExperimentsTestCase): 24 | """ 25 | A test class for additional functionality provided by the StandardRB 26 | class. 27 | """ 28 | 29 | seed = 42 30 | 31 | def test_coherence_limit(self): 32 | """Test coherence_limit.""" 33 | t1 = 100.0 34 | t2 = 100.0 35 | gate_2_qubits = 0.5 36 | gate_1_qubit = 0.1 37 | twoq_coherence_err = rb.RBUtils.coherence_limit(2, [t1, t1], [t2, t2], gate_2_qubits) 38 | 39 | oneq_coherence_err = rb.RBUtils.coherence_limit(1, [t1], [t2], gate_1_qubit) 40 | 41 | self.assertAlmostEqual(oneq_coherence_err, 0.00049975, 6, "Error: 1Q Coherence Limit") 42 | 43 | self.assertAlmostEqual(twoq_coherence_err, 0.00597, 5, "Error: 2Q Coherence Limit") 44 | -------------------------------------------------------------------------------- /qiskit_experiments/database_service/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | ============================================================= 15 | Database Service (:mod:`qiskit_experiments.database_service`) 16 | ============================================================= 17 | 18 | .. currentmodule:: qiskit_experiments.database_service 19 | 20 | This subpackage provides database-specific utility functions and exceptions which 21 | are used with the :class:`.ExperimentData` and :class:`.AnalysisResult` classes. 22 | 23 | Device Components 24 | ================= 25 | 26 | .. autosummary:: 27 | :toctree: ../stubs/ 28 | 29 | DeviceComponent 30 | Qubit 31 | Resonator 32 | UnknownComponent 33 | to_component 34 | 35 | Exceptions 36 | ========== 37 | 38 | .. autosummary:: 39 | :toctree: ../stubs/ 40 | 41 | ExperimentDataError 42 | ExperimentEntryExists 43 | ExperimentEntryNotFound 44 | """ 45 | 46 | from .exceptions import ExperimentDataError, ExperimentEntryExists, ExperimentEntryNotFound 47 | from .device_component import DeviceComponent, Qubit, Resonator, UnknownComponent, to_component 48 | -------------------------------------------------------------------------------- /docs/howtos/figure_generation.rst: -------------------------------------------------------------------------------- 1 | Control figure generation 2 | ========================= 3 | 4 | Problem 5 | ------- 6 | 7 | You want to change the default behavior where figures are generated with every experiment. 8 | 9 | Solution 10 | -------- 11 | 12 | For a single non-composite experiment, figure generation can be switched off by setting the analysis 13 | option ``plot`` to ``False``: 14 | 15 | .. jupyter-input:: 16 | 17 | experiment.analysis.set_options(plot = False) 18 | 19 | For composite experiments, there is a ``generate_figures`` analysis option which controls how child figures are 20 | generated. There are three options: 21 | 22 | - ``always``: The default behavior, generate figures for each child experiment. 23 | - ``never``: Never generate figures for any child experiment. 24 | - ``selective``: Only generate figures for analysis results where ``quality`` is ``bad``. This is useful 25 | for large composite experiments where you only want to examine qubits with problems. 26 | 27 | This parameter should be set on the analysis of a composite experiment before the analysis runs: 28 | 29 | .. jupyter-input:: 30 | 31 | parallel_exp = ParallelExperiment( 32 | [T1(physical_qubits=(i,), delays=delays) for i in range(2)] 33 | ) 34 | parallel_exp.analysis.set_options(generate_figures="selective") 35 | 36 | Discussion 37 | ---------- 38 | 39 | These options are useful for large composite experiments, where generating all figures incurs a significant 40 | overhead. 41 | 42 | See Also 43 | -------- 44 | 45 | * The :doc:`Visualization tutorial ` discusses how to customize figures 46 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/matplotlib.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Matplotlib helper functions 14 | """ 15 | 16 | from matplotlib.figure import Figure 17 | from matplotlib.backends.backend_svg import FigureCanvasSVG 18 | 19 | default_figure_canvas = FigureCanvasSVG # pylint: disable=invalid-name 20 | """Matplotlib canvas to use when rendering a figure. This needs to be a 21 | canvas for a `non-interactive backend 22 | `_. 23 | The default is `FigureCanvasSVG`.""" 24 | 25 | 26 | def get_non_gui_ax(): 27 | """Return a matplotlib axes that can be used in a child thread. 28 | 29 | Analysis/plotting is done in a separate thread (so it doesn't block the 30 | main thread), but matplotlib doesn't support GUI mode in a child thread. 31 | This function creates a separate Figure and attaches a non-GUI 32 | SVG canvas to it. 33 | 34 | Returns: 35 | matplotlib.axes.Axes: A matplotlib axes that can be used in a child thread. 36 | """ 37 | figure = Figure() 38 | _ = default_figure_canvas(figure) 39 | return figure.subplots(squeeze=False)[0, 0] 40 | -------------------------------------------------------------------------------- /test/visualization/test_mpldrawer.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Test Matplotlib Drawer. 14 | """ 15 | 16 | from test.base import QiskitExperimentsTestCase 17 | 18 | import matplotlib 19 | 20 | from qiskit_experiments.visualization import MplDrawer 21 | 22 | 23 | class TestMplDrawer(QiskitExperimentsTestCase): 24 | """Test MplDrawer.""" 25 | 26 | def test_end_to_end(self): 27 | """Test that MplDrawer generates something.""" 28 | drawer = MplDrawer() 29 | 30 | # Draw dummy data 31 | drawer.initialize_canvas() 32 | drawer.scatter([0, 1, 2], [0, 1, 2], name="seriesA") 33 | drawer.scatter([0, 1, 2], [0, 1, 2], [0.1, 0.1, 0.1], None, name="seriesA") 34 | drawer.line([3, 2, 1], [1, 2, 3], name="seriesB") 35 | drawer.filled_x_area([0, 1, 2, 3], [1, 2, 1, 2], [-1, -2, -1, -2], name="seriesB") 36 | drawer.filled_y_area([-1, 0, 1, 2], [-1, -2, -1, -2], [1, 2, 1, 2], name="seriesB") 37 | drawer.textbox(r"Dummy report text with LaTex $\beta$") 38 | 39 | # Get result 40 | fig = drawer.figure 41 | 42 | # Check that 43 | self.assertTrue(fig is not None) 44 | self.assertTrue(isinstance(fig, matplotlib.pyplot.Figure)) 45 | -------------------------------------------------------------------------------- /.github/workflows/docs_stable.yml: -------------------------------------------------------------------------------- 1 | name: Stable Docs Publish 2 | on: 3 | workflow_dispatch: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | deploy: 10 | if: github.repository_owner == 'Qiskit-Community' 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v6 14 | with: 15 | fetch-depth: 0 16 | - name: Set up Python 17 | uses: actions/setup-python@v6 18 | with: 19 | python-version: '3.13' 20 | - name: Set up uv 21 | uses: astral-sh/setup-uv@v7 22 | - name: Install dependencies 23 | run: | 24 | sudo apt-get install graphviz pandoc 25 | - name: Build docs stable 26 | env: 27 | QISKIT_DOCS_BUILD_TUTORIALS: 'always' 28 | run: PROD_BUILD=1 uvx --with tox-uv tox -e docs 29 | - name: Bypass Jekyll Processing # Necessary for setting the correct css path 30 | run: touch docs/_build/html/.nojekyll 31 | - name: Set current version 32 | run: | 33 | echo "version=$(cat qiskit_experiments/VERSION.txt | cut -d'.' -f1,2)" >> "$GITHUB_ENV" 34 | - name: Deploy stable 35 | uses: JamesIves/github-pages-deploy-action@v4 36 | with: 37 | folder: docs/_build/html 38 | target-folder: stable/${{ env.version }} 39 | - name: Check current tag is the latest 40 | id: check-latest 41 | run: | 42 | python tools/check_latest_version.py 43 | continue-on-error: true 44 | - name: Deploy top level 45 | uses: JamesIves/github-pages-deploy-action@v4 46 | with: 47 | folder: docs/_build/html/ 48 | clean-exclude: | 49 | stable/* 50 | dev/* 51 | if: ${{ steps.check-latest.outcome == 'success' }} 52 | -------------------------------------------------------------------------------- /qiskit_experiments/test/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | =============================================== 15 | Test Utilities (:mod:`qiskit_experiments.test`) 16 | =============================================== 17 | 18 | .. currentmodule:: qiskit_experiments.test 19 | 20 | This module contains classes and functions that are used to enable testing 21 | of Qiskit Experiments. It's primarily composed of mock backends that 22 | simulate real backends. 23 | 24 | .. _backends: 25 | 26 | Fake Backends 27 | ============= 28 | 29 | Mock backends for running simulated jobs. 30 | 31 | .. autosummary:: 32 | :toctree: ../stubs/ 33 | 34 | MockIQBackend 35 | MockIQParallelBackend 36 | T2HahnBackend 37 | NoisyDelayAerBackend 38 | 39 | Helpers 40 | ======= 41 | 42 | Helper classes for supporting test functionality. 43 | 44 | .. autosummary:: 45 | :toctree: ../stubs/ 46 | 47 | MockIQExperimentHelper 48 | MockIQParallelExperimentHelper 49 | 50 | """ 51 | 52 | from .utils import FakeJob 53 | from .mock_iq_backend import MockIQBackend, MockIQParallelBackend 54 | from .mock_iq_helpers import MockIQExperimentHelper, MockIQParallelExperimentHelper 55 | from .noisy_delay_aer_simulator import NoisyDelayAerBackend 56 | from .t2hahn_backend import T2HahnBackend 57 | from .fake_service import FakeService 58 | -------------------------------------------------------------------------------- /docs/howtos/runtime_sessions.rst: -------------------------------------------------------------------------------- 1 | Use Experiments with Sampler 2 | ============================= 3 | 4 | Problem 5 | ------- 6 | 7 | You want to run experiments with a custom :class:`qiskit.primitives.BaseSamplerV2` service. 8 | A sampler can be instantiated with a backend, session or batch, which allows one to 9 | run an experiment in different execution modes. 10 | 11 | .. note:: 12 | All jobs, by default, run using the :class:`qiskit_ibm_runtime.SamplerV2` class. When calling ``exp.run`` a 13 | :class:`qiskit_ibm_runtime.SamplerV2` object will be automatically generated to wrap the specified backend. 14 | 15 | Solution 16 | -------- 17 | 18 | In this example, we will pass in a :class:`qiskit_ibm_runtime.SamplerV2` object to a tomography experiment. 19 | 20 | .. note:: 21 | If a sampler object is passed to :meth:`qiskit_experiments.framework.BaseExperiment.run` then the `run options 22 | `_ of the 23 | sampler object are used. The execution options set by the experiment are ignored. 24 | 25 | .. jupyter-input:: 26 | 27 | from qiskit_ibm_runtime import SamplerV2 as Sampler 28 | from qiskit_experiments.library.tomography import ProcessTomography 29 | from qiskit import QuantumCircuit 30 | 31 | service = QiskitRuntimeService(channel="ibm_quantum") 32 | backend = service.backend("ibm_osaka") 33 | qc = QuantumCircuit(1) 34 | qc.x(0) 35 | 36 | sampler = Sampler(backed) 37 | # set the shots in the sampler object 38 | sampler.options.default_shots = 300 39 | exp = ProcessTomography(qc) 40 | # Artificially lower circuits per job, adjust value for your own application 41 | exp.set_experiment_options(max_circuits=3) 42 | # pass the sampler into the experiment 43 | exp_data = exp.run(sampler=sampler) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/howtos/experiment_times.rst: -------------------------------------------------------------------------------- 1 | Get experiment timing information 2 | ================================= 3 | 4 | Problem 5 | ------- 6 | 7 | You want to know when an experiment started and finished running. 8 | 9 | Solution 10 | -------- 11 | 12 | The :class:`.ExperimentData` class contains timing information in the following attributes, which 13 | are all of type ``datetime.datetime`` and in your local timezone: 14 | 15 | - :attr:`.ExperimentData.start_datetime` is when the :class:`.ExperimentData` was instantiated, 16 | which is also when the experiment began running in the typical workflow by calling 17 | ``experiment_data = exp.run()``. 18 | 19 | - :attr:`.ExperimentData.end_datetime` is the time the most recently completed job was successfully 20 | added to the :class:`.ExperimentData` object. If a job was canceled, did not run successfully, or 21 | could not be added to the :class:`.ExperimentData` object for some other reason, 22 | :attr:`.ExperimentData.end_datetime` will not update. 23 | 24 | .. note:: 25 | The below attributes are only relevant for those who have access to the cloud service. You can 26 | check whether you do by logging into the IBM Quantum interface 27 | and seeing if you can see the `database `__. 28 | 29 | - :attr:`.ExperimentData.creation_datetime` is the time when the experiment data was saved via the 30 | service. This defaults to ``None`` if experiment data has not yet been saved. 31 | 32 | - :attr:`.ExperimentData.updated_datetime` is the time the experiment data entry in the service was 33 | last updated. This defaults to ``None`` if experiment data has not yet been saved. 34 | 35 | Discussion 36 | ---------- 37 | 38 | :attr:`.ExperimentData.start_datetime` can also be set to a custom timestamp when instantiating an 39 | :class:`.ExperimentData` object by passing a value to the ``start_datetime`` field. 40 | -------------------------------------------------------------------------------- /qiskit_experiments/test/utils.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test utility functions.""" 14 | 15 | import uuid 16 | from typing import Optional, Dict 17 | from datetime import datetime, timezone 18 | 19 | from qiskit.providers.job import JobV1 as Job 20 | from qiskit.providers.jobstatus import JobStatus 21 | from qiskit.providers.backend import BackendV2 as Backend 22 | from qiskit.result import Result 23 | 24 | 25 | class FakeJob(Job): 26 | """Fake job.""" 27 | 28 | def __init__(self, backend: Backend, result: Optional[Result] = None): 29 | """Initialize FakeJob.""" 30 | if result: 31 | job_id = result.job_id 32 | else: 33 | job_id = uuid.uuid4().hex 34 | super().__init__(backend, job_id) 35 | self._result = result 36 | 37 | def result(self): 38 | """Return job result.""" 39 | return self._result 40 | 41 | def submit(self): 42 | """Submit the job to the backend for execution.""" 43 | pass 44 | 45 | @staticmethod 46 | def time_per_step() -> Dict[str, datetime]: 47 | """Return the completion time.""" 48 | return {"COMPLETED": datetime.now(timezone.utc)} 49 | 50 | def status(self) -> JobStatus: 51 | """Return the status of the job, among the values of ``JobStatus``.""" 52 | if self._result: 53 | return JobStatus.DONE 54 | return JobStatus.RUNNING 55 | -------------------------------------------------------------------------------- /docs/howtos/job_splitting.rst: -------------------------------------------------------------------------------- 1 | Control the splitting of experiment circuits into jobs 2 | ====================================================== 3 | 4 | Problem 5 | ------- 6 | 7 | You want to manually control how an experiment is split into jobs when running on 8 | a backend. 9 | 10 | Solution 11 | -------- 12 | 13 | There are two experiment options relevant to custom job splitting. 14 | You can set the ``max_circuits`` option manually when running an experiment: 15 | 16 | .. jupyter-input:: 17 | 18 | exp = Experiment((0,)) 19 | exp.set_experiment_options(max_circuits=100) 20 | 21 | The experiment class will split its circuits into jobs such that no job has more than 22 | ``max_circuits`` number of jobs. 23 | 24 | Furthermore, the :class:`.BatchExperiment` class has the experiment option 25 | ``separate_jobs`` which will run circuits of different sub-experiments in different 26 | jobs: 27 | 28 | .. jupyter-input:: 29 | 30 | batch_exp = BatchExperiment([exp, exp]) 31 | batch_exp.set_experiment_options(separate_jobs=True) 32 | 33 | Note that this option is only available to :class:`.BatchExperiment` objects. To manage 34 | job splitting when using :class:`.ParallelExperiment`, you can make a nested batch 35 | experiment of parallel experiments. 36 | 37 | Discussion 38 | ---------- 39 | 40 | Qiskit Experiments will automatically split circuits across jobs for you for backends 41 | that have a maximum circuit number per job, which is given by the ``max_experiments`` 42 | property of :meth:`~qiskit.providers.BackendV1.configuration` for V1 backends and 43 | the :attr:`~qiskit.providers.BackendV2.max_circuits` attribute for V2 backends. This should 44 | work automatically in most cases, but there may be some backends where other limits 45 | exist. When the ``max_circuits`` experiment option is provided, the experiment class 46 | will split the experiment circuits as dictated by the smaller of the backend property 47 | and the experiment option. -------------------------------------------------------------------------------- /tools/check_latest_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This code is part of Qiskit Experiments. 4 | # 5 | # (C) Copyright IBM 2025. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | """Check that the highest git version tag on the repo matches the current version""" 16 | 17 | import re 18 | import subprocess 19 | import sys 20 | from pathlib import Path 21 | 22 | 23 | version_pattern = re.compile(r"^\d+(\.\d+)*$") 24 | 25 | 26 | def _main(): 27 | """Return True if VERSION.txt matches a tag higher than any other version tag 28 | 29 | NOTE: this function is primarily intended for the docs publishing automated 30 | workflow. It retruns true even if the current commit is not tagged with the 31 | latest version tag. It works this way so that a follow up commit can be 32 | pushed to fix a possible error in the docs publishing workflow without 33 | needing to tag again with a higher verison number just for the docs. 34 | """ 35 | proc = subprocess.run( 36 | ["git", "rev-parse", "--show-toplevel"], check=True, text=True, capture_output=True 37 | ) 38 | repo_base = Path(proc.stdout.strip()) 39 | 40 | proc = subprocess.run(["git", "tag", "--list"], check=True, text=True, capture_output=True) 41 | all_tags = [t.strip() for t in proc.stdout.splitlines()] 42 | all_tags = [t for t in all_tags if version_pattern.match(t)] 43 | highest_version = max(all_tags, key=lambda t: tuple(int(p) for p in t.split("."))) 44 | 45 | version = (repo_base / "qiskit_experiments/VERSION.txt").read_text().strip() 46 | 47 | if version != highest_version: 48 | return False 49 | 50 | return True 51 | 52 | 53 | if __name__ == "__main__": 54 | if not _main(): 55 | sys.exit(1) 56 | -------------------------------------------------------------------------------- /docs/_ext/jupyter_execute_custom.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Customizations of :mod:`jupyter-sphinx`. 15 | """ 16 | import os 17 | import time 18 | 19 | from jupyter_sphinx.execute import ExecuteJupyterCells 20 | from jupyter_sphinx import JupyterCell 21 | from sphinx.application import Sphinx 22 | from sphinx.util import logging 23 | 24 | 25 | logger = logging.getLogger(__name__) 26 | 27 | class JupyterCellCheckEnv(JupyterCell): 28 | """This class overrides the JupyterCell class in :mod:`jupyter-sphinx` 29 | to skip cell execution when `QISKIT_DOCS_SKIP_EXECUTE` is true in the environment. 30 | """ 31 | 32 | def run(self): 33 | [cell] = super().run() 34 | if os.getenv("QISKIT_DOCS_SKIP_EXECUTE", False): 35 | cell["execute"] = False 36 | cell["hide_code"] = False 37 | return [cell] 38 | 39 | 40 | class TimedExecuteJupyterCells(ExecuteJupyterCells): 41 | def apply(self): 42 | start_time = time.perf_counter() 43 | super().apply() 44 | execution_time = time.perf_counter() - start_time 45 | if execution_time > 1: 46 | # Only log for significant duration since this runs on every 47 | # document, even ones without jupyter content. 48 | logger.info( 49 | f"Jupyter execution in {self.env.docname} took {execution_time:.2f} seconds" 50 | ) 51 | 52 | 53 | def setup(app: Sphinx): 54 | app.add_directive("jupyter-execute", JupyterCellCheckEnv, override=True) 55 | app.registry.transforms.remove(ExecuteJupyterCells) 56 | app.add_transform(TimedExecuteJupyterCells) 57 | return {"parallel_read_safe": True} 58 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: "1.2.0" 2 | authors: 3 | - family-names: Kanazawa 4 | given-names: Naoki 5 | orcid: "https://orcid.org/0000-0002-4192-5558" 6 | - family-names: Egger 7 | given-names: Daniel J. 8 | orcid: "https://orcid.org/0000-0002-5523-9807" 9 | - family-names: Ben-Haim 10 | given-names: Yael 11 | - family-names: Zhang 12 | given-names: Helena 13 | orcid: "https://orcid.org/0000-0002-7813-7133" 14 | - family-names: Shanks 15 | given-names: William E. 16 | orcid: "https://orcid.org/0000-0002-5045-8808" 17 | - family-names: Aleksandrowicz 18 | given-names: Gadi 19 | - family-names: Wood 20 | given-names: Christopher J. 21 | orcid: "https://orcid.org/0000-0001-7606-7349" 22 | contact: 23 | - family-names: Egger 24 | given-names: Daniel J. 25 | orcid: "https://orcid.org/0000-0002-5523-9807" 26 | doi: 10.5281/zenodo.7844174 27 | message: If you use this software, please cite our article in the 28 | Journal of Open Source Software. 29 | preferred-citation: 30 | authors: 31 | - family-names: Kanazawa 32 | given-names: Naoki 33 | orcid: "https://orcid.org/0000-0002-4192-5558" 34 | - family-names: Egger 35 | given-names: Daniel J. 36 | orcid: "https://orcid.org/0000-0002-5523-9807" 37 | - family-names: Ben-Haim 38 | given-names: Yael 39 | - family-names: Zhang 40 | given-names: Helena 41 | orcid: "https://orcid.org/0000-0002-7813-7133" 42 | - family-names: Shanks 43 | given-names: William E. 44 | orcid: "https://orcid.org/0000-0002-5045-8808" 45 | - family-names: Aleksandrowicz 46 | given-names: Gadi 47 | - family-names: Wood 48 | given-names: Christopher J. 49 | orcid: "https://orcid.org/0000-0001-7606-7349" 50 | date-published: 2023-04-19 51 | doi: 10.21105/joss.05329 52 | issn: 2475-9066 53 | issue: 84 54 | journal: Journal of Open Source Software 55 | publisher: 56 | name: Open Journals 57 | start: 5329 58 | title: "Qiskit Experiments: A Python package to characterize and 59 | calibrate quantum computers" 60 | type: article 61 | url: "https://joss.theoj.org/papers/10.21105/joss.05329" 62 | volume: 8 63 | title: "Qiskit Experiments: A Python package to characterize and 64 | calibrate quantum computers" 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiskit Experiments 2 | 3 | [![License](https://img.shields.io/github/license/Qiskit-Community/qiskit-experiments.svg)](https://opensource.org/licenses/Apache-2.0) 4 | [![Release](https://img.shields.io/github/release/Qiskit-Community/qiskit-experiments.svg)](https://github.com/Qiskit-Community/qiskit-experiments/releases) 5 | ![Python](https://img.shields.io/pypi/pyversions/qiskit-experiments.svg) 6 | [![DOI](https://joss.theoj.org/papers/10.21105/joss.05329/status.svg)](https://doi.org/10.21105/joss.05329) 7 | 8 | **Qiskit Experiments** is a repository that builds tools for building, running, 9 | and analyzing experiments on noisy quantum computers using Qiskit. 10 | 11 | To learn more about the package, you can see the 12 | [most up-to-date documentation](https://qiskit-community.github.io/qiskit-experiments/dev) 13 | corresponding to the main branch of this repository or the 14 | [documentation for the latest stable release](https://qiskit-community.github.io/qiskit-experiments). 15 | 16 | ## Contribution Guidelines 17 | 18 | If you'd like to contribute to Qiskit Experiments, please take a look at our 19 | [contribution guidelines](CONTRIBUTING.md). This project adheres to Qiskit's 20 | [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to 21 | uphold this code. 22 | 23 | We use [GitHub issues](https://github.com/Qiskit-Community/qiskit-experiments/issues) for 24 | tracking requests and bugs. Please 25 | [join the Qiskit Slack community](https://qisk.it/join-slack) 26 | and use the [#experiments](https://qiskit.slack.com/archives/CGZDF48EN) channel for discussion and 27 | simple questions. 28 | For questions that are more suited for a forum we use the Qiskit tag in 29 | [Stack Exchange](https://quantumcomputing.stackexchange.com/questions/tagged/qiskit). 30 | 31 | ## Authors and Citation 32 | 33 | Qiskit Experiments is the work of [many people](https://github.com/Qiskit-Community/qiskit-experiments/graphs/contributors) who contribute 34 | to the project at different levels. If you use Qiskit Experiments, please cite our 35 | [paper](https://doi.org/10.21105/joss.05329) as per the included [citation file](CITATION.cff). 36 | 37 | ## License 38 | 39 | [Apache License 2.0](LICENSE.txt) 40 | 41 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/analysis/fine_amplitude_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Fine Amplitude calibration analysis.""" 14 | 15 | import lmfit 16 | 17 | import qiskit_experiments.curve_analysis as curve 18 | 19 | 20 | class FineAmplitudeAnalysis(curve.ErrorAmplificationAnalysis): 21 | r"""An analysis class for fine amplitude calibrations to define the fixed parameters. 22 | 23 | # section: note 24 | 25 | The following parameters are fixed. 26 | 27 | * :math:`{\rm apg}` The angle per gate is set by the user, for example pi for a pi-pulse. 28 | * :math:`{\rm phase\_offset}` The phase offset in the cosine oscillation, for example, 29 | :math:`\pi/2` if a square-root of X gate is added before the repeated gates. 30 | """ 31 | 32 | # pylint: disable=super-init-not-called 33 | def __init__(self): 34 | 35 | # pylint: disable=non-parent-init-called 36 | curve.CurveAnalysis.__init__( 37 | self, 38 | models=[ 39 | lmfit.models.ExpressionModel( 40 | expr="amp / 2 * (2 * x - 1) + base", 41 | name="spam cal.", 42 | ), 43 | lmfit.models.ExpressionModel( 44 | expr="amp / 2 * cos((d_theta + angle_per_gate) * x - phase_offset) + base", 45 | name="fine amp.", 46 | ), 47 | ], 48 | ) 49 | 50 | @classmethod 51 | def _default_options(cls): 52 | """Return the default analysis options.""" 53 | default_options = super()._default_options() 54 | default_options.data_subfit_map = { 55 | "spam cal.": {"series": "spam-cal"}, 56 | "fine amp.": {"series": 1}, 57 | } 58 | return default_options 59 | -------------------------------------------------------------------------------- /qiskit_experiments/library/tomography/basis/cache_method.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Method decorator for caching regular methods in class instances. 14 | """ 15 | 16 | from typing import Dict, Callable, Optional 17 | import functools 18 | 19 | 20 | def _method_cache_name(instance: any) -> str: 21 | """Attribute name for storing cache in an instance""" 22 | return "_CACHE_" + type(instance).__name__ 23 | 24 | 25 | def _get_method_cache(instance: any) -> Dict: 26 | """Return instance cache for cached methods""" 27 | cache_name = _method_cache_name(instance) 28 | try: 29 | return getattr(instance, cache_name) 30 | except AttributeError: 31 | setattr(instance, cache_name, {}) 32 | return getattr(instance, cache_name) 33 | 34 | 35 | def cache_method(maxsize: Optional[int] = None) -> Callable: 36 | """Decorator for caching class instance methods. 37 | 38 | Args: 39 | maxsize: The maximum size of this method's LRU cache. 40 | 41 | Returns: 42 | The decorator for caching methods. 43 | """ 44 | 45 | def cache_method_decorator(method: Callable) -> Callable: 46 | """Decorator for caching method. 47 | 48 | Args: 49 | method: A method to cache. 50 | 51 | Returns: 52 | The wrapped cached method. 53 | """ 54 | 55 | @functools.wraps(method) 56 | def _cached_method(self, *args, **kwargs): 57 | cache = _get_method_cache(self) 58 | key = method.__name__ 59 | try: 60 | meth = cache[key] 61 | except KeyError: 62 | meth = cache[key] = functools.lru_cache(maxsize)(functools.partial(method, self)) 63 | 64 | return meth(*args, **kwargs) 65 | 66 | return _cached_method 67 | 68 | return cache_method_decorator 69 | -------------------------------------------------------------------------------- /qiskit_experiments/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | ============================================== 15 | Qiskit Experiments (:mod:`qiskit_experiments`) 16 | ============================================== 17 | 18 | .. currentmodule:: qiskit_experiments 19 | 20 | Qiskit Experiments provides both a general 21 | :mod:`~qiskit_experiments.framework` for creating and 22 | running experiments through Qiskit and optionally storing results in an 23 | online :mod:`~qiskit_experiments.database_service`, as well as a 24 | :mod:`~qiskit_experiments.library` of standard 25 | quantum characterization, calibration, and verification experiments. 26 | 27 | 28 | Modules 29 | ======= 30 | 31 | .. list-table:: 32 | 33 | * - :mod:`~qiskit_experiments.library` 34 | - Library of available experiments. 35 | * - :mod:`~qiskit_experiments.framework` 36 | - Core classes for experiments and analysis. 37 | * - :mod:`~qiskit_experiments.data_processing` 38 | - Tools for building data processor workflows of experiment 39 | measurement data. 40 | * - :mod:`~qiskit_experiments.curve_analysis` 41 | - Utility functions for curve fitting and analysis. 42 | * - :mod:`~qiskit_experiments.visualization` 43 | - Classes for creating figures from experiment results. 44 | 45 | Certain experiments also have additional utilities contained which can be 46 | accessed by importing the following modules. 47 | 48 | - :mod:`qiskit_experiments.library.characterization` 49 | - :mod:`qiskit_experiments.library.randomized_benchmarking` 50 | - :mod:`qiskit_experiments.library.tomography` 51 | """ 52 | 53 | from .version import __version__ 54 | 55 | # Modules 56 | from . import framework 57 | from . import library 58 | from . import curve_analysis 59 | from . import data_processing 60 | from . import database_service 61 | from . import visualization 62 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/analysis/t2ramsey_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | T2Ramsey Experiment class. 14 | """ 15 | from typing import Union 16 | import qiskit_experiments.curve_analysis as curve 17 | from qiskit_experiments.framework import Options 18 | 19 | 20 | class T2RamseyAnalysis(curve.DampedOscillationAnalysis): 21 | """T2 Ramsey result analysis class.""" 22 | 23 | @classmethod 24 | def _default_options(cls) -> Options: 25 | """Default analysis options.""" 26 | options = super()._default_options() 27 | options.plotter.set_figure_options( 28 | xlabel="Delay", 29 | ylabel="P(1)", 30 | xval_unit="s", 31 | ) 32 | 33 | options.result_parameters = [ 34 | curve.ParameterRepr("freq", "Frequency", "Hz"), 35 | curve.ParameterRepr("tau", "T2star", "s"), 36 | ] 37 | 38 | return options 39 | 40 | def _evaluate_quality(self, fit_data: curve.CurveFitResult) -> Union[str, None]: 41 | """Algorithmic criteria for whether the fit is good or bad. 42 | 43 | A good fit has: 44 | - a reduced chi-squared lower than three and greater than zero 45 | - relative error of amp is less than 10 percent 46 | - relative error of tau is less than 10 percent 47 | - relative error of freq is less than 10 percent 48 | """ 49 | amp = fit_data.ufloat_params["amp"] 50 | tau = fit_data.ufloat_params["tau"] 51 | freq = fit_data.ufloat_params["freq"] 52 | 53 | criteria = [ 54 | 0 < fit_data.reduced_chisq < 3, 55 | curve.utils.is_error_not_significant(amp, fraction=0.1), 56 | curve.utils.is_error_not_significant(tau, fraction=0.1), 57 | curve.utils.is_error_not_significant(freq, fraction=0.1), 58 | ] 59 | 60 | if all(criteria): 61 | return "good" 62 | 63 | return "bad" 64 | -------------------------------------------------------------------------------- /test/framework/test_artifacts.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test artifacts.""" 14 | 15 | from test.base import QiskitExperimentsTestCase 16 | from datetime import datetime 17 | 18 | from qiskit_experiments.framework import ArtifactData 19 | 20 | 21 | class TestArtifacts(QiskitExperimentsTestCase): 22 | """Test cases for the ArtifactData class.""" 23 | 24 | def test_basic_artifact(self): 25 | """Test artifact properties.""" 26 | timestamp = datetime.now() 27 | artifact = ArtifactData(artifact_id=0, name="test", data="foo", created_time=timestamp) 28 | self.assertEqual(artifact.artifact_id, 0) 29 | self.assertEqual(artifact.name, "test") 30 | self.assertEqual(artifact.experiment, None) 31 | self.assertEqual(artifact.device_components, []) 32 | self.assertEqual(artifact.dtype, "str") 33 | self.assertEqual(artifact.created_time, timestamp) 34 | self.assertEqual( 35 | str(artifact), 36 | "ArtifactData(name=test, dtype=str, uid=0, experiment=None, device_components=[])", 37 | ) 38 | 39 | def test_artifact_equality(self): 40 | """Test artifact equality.""" 41 | timestamp = datetime.now() 42 | artifact1 = ArtifactData(name="test", data="foo") 43 | artifact2 = ArtifactData(name="test", data="foo") 44 | self.assertNotEqual(artifact1, artifact2) 45 | artifact1 = ArtifactData(artifact_id=0, name="test", data="foo", created_time=timestamp) 46 | artifact2 = ArtifactData(artifact_id=0, name="test", data="foo", created_time=timestamp) 47 | self.assertEqual(artifact1, artifact2) 48 | 49 | def test_serialize_artifact(self): 50 | """Test serializing the artifact.""" 51 | obj = ArtifactData(name="test", data="foo") 52 | self.assertRoundTripSerializable(obj) 53 | obj2 = ArtifactData(name="test", data={"foo": 123, "blah": obj}) 54 | self.assertRoundTripSerializable(obj2) 55 | -------------------------------------------------------------------------------- /docs/tutorials/intro.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Introduction 3 | ============ 4 | 5 | What is Qiskit Experiments? 6 | =========================== 7 | 8 | Qiskit Experiments is a package for running device characterization and calibration 9 | experiments on top of the core functionality of Qiskit. 10 | 11 | An **experiment** comprises a series of circuits and associated metadata. 12 | Once the experiment circuits are executed on a quantum backend, either 13 | real or simulated, analysis is run automatically on the jobs and results 14 | in the form of data, fit parameters, and figures are generated. 15 | 16 | In addition to the experiment framework itself, Qiskit Experiments also has a rich 17 | library of experiments for calibrating and characterizing qubits. 18 | 19 | What Qiskit Experiments can do 20 | ============================== 21 | 22 | * Run characterization and calibration experiments such as quantum 23 | volume and randomized benchmarking 24 | * Run built-in or customized experiments with all the options available in Qiskit 25 | * Specify fit series and parameters in the analysis 26 | * Transform the data through the data processor 27 | * Visualize data with support for custom drawing backends 28 | * Save and retrieve timestamped calibration parameters for physical backends 29 | 30 | .. _primer: 31 | 32 | A quick primer 33 | ============== 34 | 35 | The Qiskit Experiments package consists of the experimental framework and the experiment 36 | library. The framework itself consists of ``Experiment`` and ``Analysis`` classes, the 37 | latter of which uses the Data Processor, Curve Analysis, and Visualization modules 38 | to process the data, fit it to specified models, and plot the results, respectively. 39 | 40 | .. figure:: images/experimentarch.png 41 | :width: 400 42 | :align: center 43 | :class: no-scaled-link 44 | 45 | 46 | Experiments start with an ``Experiment`` class, which instantiates the circuits that 47 | will be run and also the metadata and options that will be used for the experiment, 48 | transpilation, execution, and analysis. During execution, circuits are automatically 49 | packaged into one or more jobs for the specified backend device. 50 | 51 | Each ``Experiment`` class is tied to its corresponding ``Analysis`` class. Once jobs 52 | complete execution, the ``Analysis`` class processes and analyzes raw data to output 53 | an ``ExperimentData`` class that contains 54 | the resulting analysis results, figures, metadata, as well as the original raw data. 55 | 56 | -------------------------------------------------------------------------------- /test/library/characterization/test_fine_drag.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test fine drag calibration experiment.""" 14 | 15 | from test.base import QiskitExperimentsTestCase 16 | 17 | from qiskit.circuit import Gate 18 | from qiskit_ibm_runtime.fake_provider import FakeArmonkV2 19 | 20 | from qiskit_experiments.library import FineDrag, FineXDrag 21 | from qiskit_experiments.test.mock_iq_backend import MockIQBackend 22 | from qiskit_experiments.test.mock_iq_helpers import MockIQFineDragHelper as FineDragHelper 23 | 24 | 25 | class TestFineDrag(QiskitExperimentsTestCase): 26 | """Tests of the fine DRAG experiment.""" 27 | 28 | def test_circuits(self): 29 | """Test the circuits of the experiment.""" 30 | 31 | drag = FineDrag([0], Gate("Drag", num_qubits=1, params=[])) 32 | drag.backend = FakeArmonkV2() 33 | for circuit in drag.circuits()[1:]: 34 | for idx, name in enumerate(["Drag", "rz", "Drag", "rz"]): 35 | self.assertEqual(circuit.data[idx].operation.name, name) 36 | 37 | def test_end_to_end(self): 38 | """A simple test to check if the experiment will run and fit data.""" 39 | exp_data = FineXDrag([0]).run(MockIQBackend(FineDragHelper())) 40 | self.assertExperimentDone(exp_data) 41 | 42 | self.assertEqual( 43 | exp_data.analysis_results("d_theta", dataframe=True).iloc[0].quality, "good" 44 | ) 45 | 46 | def test_circuits_roundtrip_serializable(self): 47 | """Test circuits serialization of the experiment.""" 48 | drag = FineXDrag([0]) 49 | drag.backend = FakeArmonkV2() 50 | self.assertRoundTripSerializable(drag._transpiled_circuits()) 51 | 52 | def test_experiment_config(self): 53 | """Test converting to and from config works""" 54 | exp = FineDrag([0], Gate("Drag", num_qubits=1, params=[])) 55 | config = exp.config() 56 | loaded_exp = FineDrag.from_config(config) 57 | self.assertNotEqual(exp, loaded_exp) 58 | self.assertEqual(config, loaded_exp.config()) 59 | -------------------------------------------------------------------------------- /qiskit_experiments/test/noisy_delay_aer_simulator.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Temporary backend to be used to apply T2 and T1 noise. 14 | """ 15 | from typing import List 16 | 17 | from qiskit import QuantumCircuit 18 | from qiskit.circuit import Delay 19 | 20 | from qiskit_aer import AerSimulator 21 | from qiskit_aer.jobs.aerjob import AerJob 22 | from qiskit_aer.noise.passes import RelaxationNoisePass 23 | 24 | from qiskit_experiments.framework import BackendData 25 | 26 | 27 | class NoisyDelayAerBackend(AerSimulator): 28 | """Backend for T1 and T2Ramsey experiments.""" 29 | 30 | def __init__( 31 | self, 32 | t1: List[float] = None, 33 | t2: List[float] = None, 34 | dt: float = None, 35 | backend=None, 36 | **backend_options, 37 | ): 38 | """configure backend noise""" 39 | 40 | super().__init__(**backend_options) 41 | self._t2 = t2 or [1e-4] 42 | self._t1 = t1 or [2e-4] 43 | if backend: 44 | dt = BackendData(backend).dt 45 | if dt is not None: 46 | self._dt_unit = True 47 | self._dt_factor = dt 48 | else: 49 | self._dt_unit = False 50 | self._dt_factor = dt or 1e-9 51 | 52 | self._op_types = [Delay] 53 | 54 | # pylint: disable=arguments-differ 55 | def run(self, run_input: List[QuantumCircuit], **run_options) -> AerJob: 56 | """ 57 | Add noise pass to all circuits and then run the circuits. 58 | 59 | Args: 60 | run_input: List of circuit to run. 61 | run_options (kwargs): additional run time backend options. 62 | 63 | Returns: 64 | AerJob: A job that contains the simulated data. 65 | 66 | """ 67 | relax_pass = RelaxationNoisePass( 68 | self._t1, self._t2, dt=self._dt_factor, op_types=self._op_types 69 | ) 70 | 71 | noisy_circuits = [] 72 | for circ in run_input: 73 | noisy_circuits.append(relax_pass(circ)) 74 | 75 | return super().run(noisy_circuits, **run_options) 76 | -------------------------------------------------------------------------------- /test/library/characterization/test_fine_frequency.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test the fine frequency characterization and calibration experiments.""" 14 | 15 | from test.base import QiskitExperimentsTestCase 16 | import numpy as np 17 | from ddt import ddt, data 18 | 19 | from qiskit_experiments.library import FineFrequency 20 | from qiskit_experiments.test import T2HahnBackend 21 | 22 | 23 | @ddt 24 | class TestFineFreqEndToEnd(QiskitExperimentsTestCase): 25 | """Test the fine freq experiment.""" 26 | 27 | @data(-0.5e6, -0.1e6, 0.1e6, 0.5e6) 28 | def test_end_to_end(self, freq_shift): 29 | """Test the experiment end to end.""" 30 | backend = T2HahnBackend(frequency=freq_shift, dt=1e-9) 31 | # Set delay to be 1% of a period of freqeuncy error 32 | delay_dt = int(0.01 / abs(freq_shift) / backend.dt) 33 | 34 | freq_exp = FineFrequency([0], delay_dt, backend) 35 | 36 | expdata = freq_exp.run(shots=100) 37 | self.assertExperimentDone(expdata) 38 | result = expdata.analysis_results("d_theta", dataframe=True).iloc[0] 39 | d_theta = result.value.n 40 | d_freq = d_theta / (2 * np.pi * (delay_dt * backend.dt)) 41 | 42 | tol = 0.01e6 43 | 44 | self.assertAlmostEqual(d_freq, freq_shift, delta=tol) 45 | self.assertEqual(result.quality, "good") 46 | 47 | def test_experiment_config(self): 48 | """Test converting to and from config works""" 49 | exp = FineFrequency([0], 160) 50 | loaded_exp = FineFrequency.from_config(exp.config()) 51 | self.assertNotEqual(exp, loaded_exp) 52 | self.assertEqualExtended(exp, loaded_exp) 53 | 54 | def test_roundtrip_serializable(self): 55 | """Test round trip JSON serialization""" 56 | exp = FineFrequency([0], 160) 57 | self.assertRoundTripSerializable(exp) 58 | 59 | def test_circuits_roundtrip_serializable(self): 60 | """Test circuits serialization of the experiment.""" 61 | exp = FineFrequency([0], 160) 62 | self.assertRoundTripSerializable(exp._transpiled_circuits()) 63 | -------------------------------------------------------------------------------- /test/library/characterization/test_half_angle.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test the half angle experiment.""" 14 | 15 | from test.base import QiskitExperimentsTestCase 16 | 17 | from qiskit_experiments.test.mock_iq_backend import MockIQBackend 18 | from qiskit_experiments.test.mock_iq_helpers import MockIQHalfAngleHelper as HalfAngleHelper 19 | from qiskit_experiments.library import HalfAngle 20 | 21 | 22 | class TestHalfAngle(QiskitExperimentsTestCase): 23 | """Class to test the half angle experiment.""" 24 | 25 | def test_end_to_end(self): 26 | """Test a full experiment end to end.""" 27 | 28 | tol = 0.005 29 | exp_helper = HalfAngleHelper() 30 | backend = MockIQBackend(exp_helper) 31 | for error in [-0.05, -0.02, 0.02, 0.05]: 32 | exp_helper.error = error 33 | hac = HalfAngle([0]) 34 | exp_data = hac.run(backend) 35 | 36 | self.assertExperimentDone(exp_data) 37 | d_theta = exp_data.analysis_results("d_hac", dataframe=True).iloc[0].value.n 38 | 39 | self.assertTrue(abs(d_theta - error) < tol) 40 | 41 | def test_circuits(self): 42 | """Test that transpiling works.""" 43 | 44 | qubit = 1 45 | 46 | hac = HalfAngle([qubit]) 47 | 48 | for idx, circ in enumerate(hac.circuits()): 49 | self.assertEqual(circ.count_ops()["sx"], idx * 2 + 2) 50 | if idx > 0: 51 | self.assertEqual(circ.count_ops()["x"], idx) 52 | 53 | def test_experiment_config(self): 54 | """Test converting to and from config works""" 55 | exp = HalfAngle([1]) 56 | config = exp.config() 57 | loaded_exp = HalfAngle.from_config(config) 58 | self.assertNotEqual(exp, loaded_exp) 59 | self.assertEqual(config, loaded_exp.config()) 60 | 61 | def test_circuit_roundtrip_serializable(self): 62 | """Test circuits round trip JSON serialization for the Experiment and ExperimentData objects.""" 63 | exp = HalfAngle([0]) 64 | self.assertRoundTripSerializable(exp._transpiled_circuits()) 65 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/containers/artifact_data.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2023. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Entry for artifact data. 15 | """ 16 | 17 | from dataclasses import dataclass, field 18 | from typing import Any, Optional, List 19 | from datetime import datetime 20 | import uuid 21 | 22 | from dateutil import tz 23 | 24 | 25 | @dataclass 26 | class ArtifactData: 27 | """A dataclass for non-analysis result payloads in :class:`.ExperimentData` objects. 28 | 29 | This class can convert results generated by the analysis class into a payload 30 | for saving and retrieving to and from the experiments service, which stores this 31 | as artifacts. Types of objects that may be converted to artifacts include fitted and raw data, 32 | fit status, and any other JSON-based data needed to serialize experiments and experiment data. 33 | 34 | Attributes: 35 | name: The name of the artifact. When saved to the cloud service, this will be the name 36 | of the zipfile this artifact object is stored in. 37 | data: The artifact payload. 38 | artifact_id: Artifact ID. Must be unique inside an :class:`ExperimentData` object. 39 | experiment_id: Experiment ID that the artifact is associated with. 40 | experiment: The name of the experiment. 41 | device_components: The device components of the experiment. 42 | created_time: Time when the artifact was created. 43 | """ 44 | 45 | name: str 46 | data: Any 47 | artifact_id: Optional[str] = field(default_factory=lambda: str(uuid.uuid4())) 48 | experiment_id: Optional[str] = None 49 | experiment: Optional[str] = None 50 | device_components: List = field(default_factory=list) 51 | created_time: Optional[datetime] = field(default_factory=lambda: datetime.now(tz.tzlocal())) 52 | 53 | @property 54 | def dtype(self): 55 | """Data type of the payload.""" 56 | return self.data.__class__.__name__ 57 | 58 | def __repr__(self): 59 | return ( 60 | f"ArtifactData(name={self.name}, dtype={self.dtype}, uid={self.artifact_id}, " 61 | f"experiment={self.experiment}, device_components={self.device_components})" 62 | ) 63 | -------------------------------------------------------------------------------- /qiskit_experiments/test/fake_backend.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Fake backend class for tests.""" 14 | import uuid 15 | from qiskit.circuit.library import Measure 16 | from qiskit.providers.backend import BackendV2 17 | from qiskit.providers.options import Options 18 | from qiskit.transpiler import Target 19 | 20 | from qiskit.result import Result 21 | 22 | from qiskit_experiments.test.utils import FakeJob 23 | 24 | 25 | class FakeBackend(BackendV2): 26 | """ 27 | Fake backend for test purposes only. 28 | """ 29 | 30 | def __init__( 31 | self, 32 | backend_name="fake_backend", 33 | num_qubits=1, 34 | max_experiments=100, 35 | ): 36 | self.simulator = True 37 | super().__init__(name=backend_name) 38 | self._target = Target(num_qubits=num_qubits) 39 | # Add a measure for each qubit so a simple measure circuit works 40 | self.target.add_instruction(Measure()) 41 | self._max_circuits = max_experiments 42 | 43 | @property 44 | def max_circuits(self): 45 | """Maximum circuits to run at once""" 46 | return self._max_circuits 47 | 48 | @classmethod 49 | def _default_options(cls): 50 | return Options() 51 | 52 | @property 53 | def target(self) -> Target: 54 | return self._target 55 | 56 | def run(self, run_input, **options): 57 | shots = options.get("shots", 100) 58 | if not isinstance(run_input, list): 59 | run_input = [run_input] 60 | results = [ 61 | { 62 | "data": {"0": shots}, 63 | "shots": shots, 64 | "success": True, 65 | "header": {"metadata": circ.metadata}, 66 | "meas_level": 2, 67 | } 68 | for circ in run_input 69 | ] 70 | 71 | result = { 72 | "backend_name": "fake_backend", 73 | "backend_version": "0", 74 | "qobj_id": uuid.uuid4().hex, 75 | "job_id": uuid.uuid4().hex, 76 | "success": True, 77 | "results": results, 78 | } 79 | return FakeJob(backend=self, result=Result.from_dict(result)) 80 | -------------------------------------------------------------------------------- /qiskit_experiments/version.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2019. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Functions for getting version information about qiskit experiments.""" 14 | 15 | 16 | import os 17 | import subprocess 18 | 19 | ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) 20 | 21 | 22 | def _minimal_ext_cmd(cmd): 23 | # construct minimal environment 24 | env = {} 25 | for k in ["SYSTEMROOT", "PATH"]: 26 | v = os.environ.get(k) 27 | if v is not None: 28 | env[k] = v 29 | # LANGUAGE is used on win32 30 | env["LANGUAGE"] = "C" 31 | env["LANG"] = "C" 32 | env["LC_ALL"] = "C" 33 | with subprocess.Popen( 34 | cmd, 35 | stdout=subprocess.PIPE, 36 | stderr=subprocess.PIPE, 37 | env=env, 38 | cwd=os.path.join(os.path.dirname(ROOT_DIR)), 39 | ) as proc: 40 | out = proc.communicate()[0] 41 | if proc.returncode > 0: 42 | raise OSError 43 | return out 44 | 45 | 46 | def git_version(): 47 | """Get the current git head sha1.""" 48 | # Determine if we're at master 49 | try: 50 | out = _minimal_ext_cmd(["git", "rev-parse", "HEAD"]) 51 | git_revision = out.strip().decode("ascii") 52 | except OSError: 53 | git_revision = "Unknown" 54 | 55 | return git_revision 56 | 57 | 58 | with open(os.path.join(ROOT_DIR, "VERSION.txt"), "r", encoding="utf-8") as version_file: 59 | VERSION = version_file.read().strip() 60 | 61 | 62 | def get_version_info(): 63 | """Get the full version string.""" 64 | # Adding the git rev number needs to be done inside 65 | # write_version_py(), otherwise the import of scipy.version messes 66 | # up the build under Python 3. 67 | full_version = VERSION 68 | 69 | if not os.path.exists(os.path.join(os.path.dirname(ROOT_DIR), ".git")): 70 | return full_version 71 | try: 72 | release = _minimal_ext_cmd(["git", "tag", "-l", "--points-at", "HEAD"]) 73 | except Exception: # pylint: disable=broad-except 74 | return full_version 75 | if not release: 76 | git_revision = git_version() 77 | full_version += ".dev0+" + git_revision[:7] 78 | return full_version 79 | 80 | 81 | __version__ = get_version_info() 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SDK config file 2 | Qconfig.py 3 | 4 | # ply outputs 5 | qiskit/qasm/parser.out 6 | 7 | # editor files 8 | .vscode/ 9 | .idea/ 10 | 11 | #standard python ignores follow 12 | 13 | # Byte-compiled / optimized / DLL files 14 | __pycache__/ 15 | .pytest_cache/ 16 | *.py[cod] 17 | *$py.class 18 | 19 | # C extensions 20 | *.so 21 | 22 | # Distribution / packaging 23 | .Python 24 | env/ 25 | build/ 26 | develop-eggs/ 27 | dist/ 28 | downloads/ 29 | eggs/ 30 | .eggs/ 31 | parts/ 32 | sdist/ 33 | var/ 34 | wheels/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | 39 | # PyInstaller 40 | # Usually these files are written by a python script from a template 41 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 42 | *.manifest 43 | *.spec 44 | 45 | # Installer logs 46 | pip-log.txt 47 | pip-delete-this-directory.txt 48 | 49 | # Unit test / coverage reports 50 | *.lcov 51 | htmlcov/ 52 | .tox/ 53 | .coverage 54 | .coverage.* 55 | .cache 56 | nosetests.xml 57 | coverage.xml 58 | *,cover 59 | .hypothesis/ 60 | test/python/*.log 61 | test/python/*.pdf 62 | test/python/*.prof 63 | .stestr/ 64 | 65 | # Translations 66 | *.mo 67 | *.pot 68 | 69 | # Django stuff: 70 | *.log 71 | local_settings.py 72 | 73 | # Flask stuff: 74 | instance/ 75 | .webassets-cache 76 | 77 | # Scrapy stuff: 78 | .scrapy 79 | 80 | # Sphinx documentation 81 | docs/_build/ 82 | 83 | # PyBuilder 84 | target/ 85 | 86 | # Jupyter Notebook 87 | .ipynb_checkpoints 88 | 89 | # pyenv 90 | .python-version 91 | 92 | # celery beat schedule file 93 | celerybeat-schedule 94 | 95 | # SageMath parsed files 96 | *.sage.py 97 | 98 | # dotenv 99 | .env 100 | 101 | # virtualenv 102 | .venv 103 | venv/ 104 | ENV/ 105 | 106 | # Spyder project settings 107 | .spyderproject 108 | 109 | # Rope project settings 110 | .ropeproject 111 | 112 | .DS_Store 113 | 114 | dummyscripts/* 115 | 116 | token.json 117 | 118 | tutorial/rst/_build/* 119 | 120 | test/python/test_qasm_python_simulator.pdf 121 | 122 | doc/_build/* 123 | 124 | doc/**/_autodoc 125 | 126 | qiskit/bin/* 127 | 128 | test/python/test_save.json 129 | 130 | test/python/*.tex 131 | 132 | out/* 133 | 134 | # CMake generates this file on the fly 135 | qiskit/providers/local/qasm_simulator_cpp 136 | qiskit/providers/legacysimulators/qasm_simulator_cpp 137 | 138 | src/qasm-simulator-cpp/test/qubit_vector_tests 139 | 140 | *.o 141 | 142 | # Cython pass 143 | qiskit/transpiler/passes/**/cython/**/*.cpp 144 | 145 | docs/stubs/* 146 | 147 | # Notebook testing images 148 | test/ipynb/mpl/*.png 149 | test/ipynb/mpl/*.zip 150 | test/ipynb/mpl/result_test.json 151 | test/Debug_RB.py 152 | -------------------------------------------------------------------------------- /qiskit_experiments/database_service/device_component.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Device component classes.""" 14 | 15 | from abc import ABC, abstractmethod 16 | 17 | 18 | class DeviceComponent(ABC): 19 | """Abstract class representing a device component. Custom components should be subclassed from 20 | this class.""" 21 | 22 | @abstractmethod 23 | def __str__(self): 24 | pass 25 | 26 | def __repr__(self): 27 | return f"<{self.__class__.__name__}({str(self)})>" 28 | 29 | def __eq__(self, value): 30 | return str(self) == str(value) 31 | 32 | 33 | class Qubit(DeviceComponent): 34 | """Class representing a qubit device component.""" 35 | 36 | def __init__(self, index: int): 37 | self.index = index 38 | 39 | def __str__(self): 40 | return f"Q{self.index}" 41 | 42 | def __json_encode__(self): 43 | return {"index": self.index} 44 | 45 | 46 | class Resonator(DeviceComponent): 47 | """Class representing a resonator device component.""" 48 | 49 | def __init__(self, index: int): 50 | self.index = index 51 | 52 | def __str__(self): 53 | return f"R{self.index}" 54 | 55 | def __json_encode__(self): 56 | return {"index": self.index} 57 | 58 | 59 | class UnknownComponent(DeviceComponent): 60 | """Class representing an unknown device component.""" 61 | 62 | def __init__(self, component: str): 63 | self.component = component 64 | 65 | def __str__(self): 66 | return self.component 67 | 68 | def __json_encode__(self): 69 | return {"component": self.component} 70 | 71 | 72 | def to_component(string: str) -> DeviceComponent: 73 | """Convert the input string to a :class:`.DeviceComponent` instance. 74 | 75 | Args: 76 | string: String to be converted. 77 | 78 | Returns: 79 | A :class:`.DeviceComponent` instance. 80 | 81 | Raises: 82 | ValueError: If input string is not a valid device component. 83 | """ 84 | if isinstance(string, DeviceComponent): 85 | return string 86 | if string.startswith("Q"): 87 | return Qubit(int(string[1:])) 88 | if string.startswith("R"): 89 | return Resonator(int(string[1:])) 90 | return UnknownComponent(string) 91 | -------------------------------------------------------------------------------- /test/library/characterization/test_readout_angle.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Test readout angle experiment 14 | """ 15 | 16 | from test.base import QiskitExperimentsTestCase 17 | import numpy as np 18 | 19 | from qiskit_experiments.framework import MeasLevel 20 | from qiskit_experiments.library import ReadoutAngle 21 | from qiskit_experiments.test.mock_iq_backend import MockIQBackend 22 | from qiskit_experiments.test.mock_iq_helpers import MockIQReadoutAngleHelper 23 | 24 | 25 | class TestReadoutAngle(QiskitExperimentsTestCase): 26 | """ 27 | Test the readout angle experiment 28 | """ 29 | 30 | def test_readout_angle_end2end(self): 31 | """ 32 | Test readout angle experiment using a simulator. 33 | """ 34 | 35 | backend = MockIQBackend( 36 | MockIQReadoutAngleHelper(iq_cluster_centers=[((-3.0, 3.0), (5.0, 5.0))]), 37 | ) 38 | exp = ReadoutAngle([0]) 39 | expdata = exp.run(backend, shots=10000) 40 | self.assertExperimentDone(expdata) 41 | 42 | res = expdata.analysis_results("readout_angle", dataframe=True).iloc[0] 43 | self.assertAlmostEqual(res.value % (2 * np.pi), np.pi / 2, places=2) 44 | 45 | backend = MockIQBackend( 46 | MockIQReadoutAngleHelper(iq_cluster_centers=[((0, -3.0), (5.0, 5.0))]), 47 | ) 48 | exp = ReadoutAngle([0]) 49 | expdata = exp.run(backend, shots=10000) 50 | self.assertExperimentDone(expdata) 51 | res = expdata.analysis_results("readout_angle", dataframe=True).iloc[0] 52 | self.assertAlmostEqual(res.value % (2 * np.pi), 15 * np.pi / 8, places=2) 53 | 54 | def test_kerneled_expdata_serialization(self): 55 | """Test experiment data and analysis data JSON serialization""" 56 | backend = MockIQBackend( 57 | MockIQReadoutAngleHelper(iq_cluster_centers=[((-3.0, 3.0), (5.0, 5.0))]), 58 | ) 59 | 60 | exp = ReadoutAngle([0]) 61 | 62 | # Checking serialization of the experiment obj 63 | self.assertRoundTripSerializable(exp._transpiled_circuits()) 64 | 65 | exp.set_run_options(meas_level=MeasLevel.KERNELED, shots=1024) 66 | expdata = exp.run(backend) 67 | self.assertExperimentDone(expdata) 68 | 69 | # Checking serialization of the experiment data 70 | self.assertRoundTripSerializable(expdata) 71 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/status.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2023. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """Status of experiment execution.""" 13 | 14 | from __future__ import annotations 15 | 16 | import dataclasses 17 | import enum 18 | from threading import Event 19 | from typing import Optional 20 | 21 | 22 | class ExperimentStatus(enum.Enum): 23 | """Class for experiment status enumerated type.""" 24 | 25 | EMPTY = "experiment data is empty" 26 | INITIALIZING = "experiment jobs are being initialized" 27 | VALIDATING = "experiment jobs are validating" 28 | QUEUED = "experiment jobs are queued" 29 | RUNNING = "experiment jobs is actively running" 30 | CANCELLED = "experiment jobs or analysis has been cancelled" 31 | POST_PROCESSING = "experiment analysis is actively running" 32 | DONE = "experiment jobs and analysis have successfully run" 33 | ERROR = "experiment jobs or analysis incurred an error" 34 | 35 | def __json_encode__(self): 36 | return self.name 37 | 38 | @classmethod 39 | def __json_decode__(cls, value): 40 | return cls.__members__[value] # pylint: disable=unsubscriptable-object 41 | 42 | 43 | class AnalysisStatus(enum.Enum): 44 | """Class for analysis callback status enumerated type.""" 45 | 46 | QUEUED = "analysis callback is queued" 47 | RUNNING = "analysis callback is actively running" 48 | CANCELLED = "analysis callback has been cancelled" 49 | DONE = "analysis callback has successfully run" 50 | ERROR = "analysis callback incurred an error" 51 | 52 | def __json_encode__(self): 53 | return self.name 54 | 55 | @classmethod 56 | def __json_decode__(cls, value): 57 | return cls.__members__[value] # pylint: disable=unsubscriptable-object 58 | 59 | 60 | @dataclasses.dataclass 61 | class AnalysisCallback: 62 | """Dataclass for analysis callback status""" 63 | 64 | name: str = "" 65 | callback_id: str = "" 66 | status: AnalysisStatus = AnalysisStatus.QUEUED 67 | error_msg: Optional[str] = None 68 | event: Event = dataclasses.field(default_factory=Event) 69 | 70 | def __getstate__(self): 71 | # We need to remove the Event object from state when pickling 72 | # since events are not pickleable 73 | state = self.__dict__ 74 | state["event"] = None 75 | return state 76 | 77 | def __json_encode__(self): 78 | return self.__getstate__() 79 | -------------------------------------------------------------------------------- /qiskit_experiments/data_processing/discriminator.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Discriminator wrappers to make discriminators serializable..""" 14 | 15 | from abc import abstractmethod 16 | from typing import Any, Dict, List 17 | 18 | 19 | class BaseDiscriminator: 20 | """An abstract base class for serializable discriminators used in the 21 | :class:`.DiscriminatorNode` data action nodes. 22 | 23 | This class allows developers to implement their own discriminators or wrap discriminators 24 | from external libraries which therefore ensures that the discriminator fits in 25 | the data processing chain. This class defines an interface for discriminator objects. 26 | Subclasses must implement the following methods: 27 | 28 | - :meth:`predict`: called in the :class:`.Discriminator` data-action class to predict 29 | labels from the input level-one data. 30 | - :meth:`config`: produces the config file to serialize and deserialize the discriminator. 31 | - :meth:`is_trained`: indicates if the discriminator is trained, i.e., fit to training data. 32 | """ 33 | 34 | @abstractmethod 35 | def predict(self, data: List): 36 | """The function used to predict the labels of the data.""" 37 | 38 | @property 39 | def discriminator(self) -> Any: 40 | """Return the discriminator object that is wrapped. 41 | 42 | Sub-classes may not need to implement this method but can chose to 43 | if they are wrapping an object capable of discrimination. 44 | """ 45 | return None 46 | 47 | @abstractmethod 48 | def config(self) -> Dict[str, Any]: 49 | """Return the configuration of the discriminator.""" 50 | 51 | @abstractmethod 52 | def is_trained(self) -> bool: 53 | """Return True if this discriminator has been trained on data.""" 54 | 55 | @classmethod 56 | def from_config(cls, config: Dict[str, Any]) -> "BaseDiscriminator": 57 | """Create a discriminator from the configuration.""" 58 | 59 | def __json_encode__(self): 60 | """Convert to format that can be JSON serialized.""" 61 | return self.config() 62 | 63 | @classmethod 64 | def __json_decode__(cls, value: Dict[str, Any]) -> "BaseDiscriminator": 65 | """Load from JSON compatible format.""" 66 | return cls.from_config(value) 67 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/analysis/t2hahn_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | T2 Hahn echo Analysis class. 14 | """ 15 | from typing import Union 16 | 17 | import numpy as np 18 | 19 | import qiskit_experiments.curve_analysis as curve 20 | from qiskit_experiments.data_processing import DataProcessor, Probability 21 | 22 | from qiskit_experiments.framework import Options 23 | 24 | 25 | class T2HahnAnalysis(curve.DecayAnalysis): 26 | """A class to analyze T2Hahn experiments.""" 27 | 28 | @classmethod 29 | def _default_options(cls) -> Options: 30 | """Default analysis options.""" 31 | options = super()._default_options() 32 | options.plotter.set_figure_options( 33 | xlabel="Delay", 34 | ylabel="P(0)", 35 | xval_unit="s", 36 | ) 37 | options.data_processor = DataProcessor( 38 | input_key="counts", data_actions=[Probability(outcome="0")] 39 | ) 40 | options.bounds = { 41 | "amp": (0.0, 1.0), 42 | "tau": (0.0, np.inf), 43 | "base": (0.0, 1.0), 44 | } 45 | options.result_parameters = [curve.ParameterRepr("tau", "T2", "s")] 46 | 47 | return options 48 | 49 | def _evaluate_quality(self, fit_data: curve.CurveFitResult) -> Union[str, None]: 50 | """Algorithmic criteria for whether the fit is good or bad. 51 | 52 | A good fit has: 53 | - a reduced chi-squared lower than three and greater than zero 54 | - absolute amp is within [0.4, 0.6] 55 | - base is less is within [0.4, 0.6] 56 | - amp error is less than 0.1 57 | - tau error is less than its value 58 | - base error is less than 0.1 59 | """ 60 | amp = fit_data.ufloat_params["amp"] 61 | tau = fit_data.ufloat_params["tau"] 62 | base = fit_data.ufloat_params["base"] 63 | 64 | criteria = [ 65 | 0 < fit_data.reduced_chisq < 3, 66 | abs(amp.nominal_value - 0.5) < 0.1, 67 | abs(base.nominal_value - 0.5) < 0.1, 68 | curve.utils.is_error_not_significant(amp, absolute=0.1), 69 | curve.utils.is_error_not_significant(tau), 70 | curve.utils.is_error_not_significant(base, absolute=0.1), 71 | ] 72 | 73 | if all(criteria): 74 | return "good" 75 | 76 | return "bad" 77 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/package_deps.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2023. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Functions for checking and reporting installed package versions. 14 | """ 15 | 16 | from __future__ import annotations 17 | 18 | import warnings 19 | from functools import lru_cache 20 | from importlib.metadata import version as metadata_version 21 | 22 | from packaging.version import InvalidVersion, Version 23 | 24 | from qiskit.utils.lazy_tester import LazyImportTester 25 | 26 | 27 | __all__ = ["HAS_SKLEARN", "qiskit_version", "version_is_at_least"] 28 | 29 | 30 | HAS_SKLEARN = LazyImportTester( 31 | { 32 | "sklearn.discriminant_analysis": ( 33 | "LinearDiscriminantAnalysis", 34 | "QuadraticDiscriminantAnalysis", 35 | ) 36 | }, 37 | name="scikit-learn", 38 | install="pip install scikit-learn", 39 | ) 40 | 41 | 42 | def qiskit_version() -> dict[str, str]: 43 | """Return a dict with Qiskit names and versions.""" 44 | return {p: metadata_version(p) for p in ("qiskit", "qiskit-experiments")} 45 | 46 | 47 | @lru_cache(maxsize=None) 48 | def version_is_at_least(package: str, version: str) -> bool: 49 | """Return True if the installed version of package greater than minimum version 50 | 51 | Args: 52 | package: Name of the package 53 | version: Minimum version name as a string. This should just include 54 | major, minor, and micro parts. The function will add ``.dev0`` to 55 | also catch any pre-release versions (otherwise ``0.5.0a1`` would 56 | evaluate as less than ``0.5.0``). 57 | 58 | Returns: 59 | True if installed version greater than ``version``. False if it is less 60 | or if the installed version of ``package`` can not be parsed using the 61 | specifications of PEP440. 62 | 63 | Raises: 64 | PackageNotFoundError: 65 | If ``package`` is not installed. 66 | """ 67 | raw_installed_version = metadata_version(package) 68 | try: 69 | installed_version = Version(raw_installed_version) 70 | except InvalidVersion: 71 | warnings.warn( 72 | ( 73 | f"Version string of installed {package} does not match PyPA " 74 | f"specification. Treating as less than {version}." 75 | ), 76 | RuntimeWarning, 77 | ) 78 | return False 79 | return installed_version >= Version(f"{version}.dev0") 80 | -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/rb_utils.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2019-2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | RB Helper functions 15 | """ 16 | import numpy as np 17 | 18 | 19 | class RBUtils: 20 | """A collection of utility functions for computing additional data 21 | from randomized benchmarking experiments""" 22 | 23 | @staticmethod 24 | def coherence_limit(nQ=2, T1_list=None, T2_list=None, gatelen=0.1): 25 | """ 26 | The error per gate (1-average_gate_fidelity) given by the T1,T2 limit. 27 | 28 | Args: 29 | nQ (int): Number of qubits (1 and 2 supported). 30 | T1_list (list): List of T1's (Q1,...,Qn). 31 | T2_list (list): List of T2's (as measured, not Tphi). If not given assume T2=2*T1 . 32 | gatelen (float): Length of the gate. 33 | 34 | Returns: 35 | float: coherence limited error per gate. 36 | Raises: 37 | ValueError: If there are invalid inputs 38 | """ 39 | # pylint: disable = invalid-name 40 | 41 | T1 = np.array(T1_list) 42 | 43 | if T2_list is None: 44 | T2 = 2 * T1 45 | else: 46 | T2 = np.array(T2_list) 47 | 48 | if len(T1) != nQ or len(T2) != nQ: 49 | raise ValueError("T1 and/or T2 not the right length") 50 | 51 | coherence_limit_err = 0 52 | 53 | if nQ == 1: 54 | 55 | coherence_limit_err = 0.5 * ( 56 | 1.0 - 2.0 / 3.0 * np.exp(-gatelen / T2[0]) - 1.0 / 3.0 * np.exp(-gatelen / T1[0]) 57 | ) 58 | 59 | elif nQ == 2: 60 | 61 | T1factor = 0 62 | T2factor = 0 63 | 64 | for i in range(2): 65 | T1factor += 1.0 / 15.0 * np.exp(-gatelen / T1[i]) 66 | T2factor += ( 67 | 2.0 68 | / 15.0 69 | * ( 70 | np.exp(-gatelen / T2[i]) 71 | + np.exp(-gatelen * (1.0 / T2[i] + 1.0 / T1[1 - i])) 72 | ) 73 | ) 74 | 75 | T1factor += 1.0 / 15.0 * np.exp(-gatelen * np.sum(1 / T1)) 76 | T2factor += 4.0 / 15.0 * np.exp(-gatelen * np.sum(1 / T2)) 77 | 78 | coherence_limit_err = 0.75 * (1.0 - T1factor - T2factor) 79 | 80 | else: 81 | raise ValueError("Not a valid number of qubits") 82 | 83 | return coherence_limit_err 84 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | ================================================================================= 15 | Characterization Experiments (:mod:`qiskit_experiments.library.characterization`) 16 | ================================================================================= 17 | 18 | .. currentmodule:: qiskit_experiments.library.characterization 19 | 20 | Experiments 21 | =========== 22 | .. autosummary:: 23 | :toctree: ../stubs/ 24 | :template: autosummary/experiment.rst 25 | 26 | T1 27 | T2Ramsey 28 | T2Hahn 29 | Tphi 30 | HalfAngle 31 | FineAmplitude 32 | FineXAmplitude 33 | FineSXAmplitude 34 | RamseyXY 35 | FineFrequency 36 | ReadoutAngle 37 | FineDrag 38 | FineXDrag 39 | FineSXDrag 40 | LocalReadoutError 41 | CorrelatedReadoutError 42 | MultiStateDiscrimination 43 | ZZRamsey 44 | 45 | 46 | Analysis 47 | ======== 48 | 49 | .. autosummary:: 50 | :toctree: ../stubs/ 51 | :template: autosummary/analysis.rst 52 | 53 | T1Analysis 54 | T1KerneledAnalysis 55 | T2RamseyAnalysis 56 | T2HahnAnalysis 57 | TphiAnalysis 58 | FineAmplitudeAnalysis 59 | RamseyXYAnalysis 60 | ReadoutAngleAnalysis 61 | LocalReadoutErrorAnalysis 62 | CorrelatedReadoutErrorAnalysis 63 | ZZRamseyAnalysis 64 | MultiStateDiscriminationAnalysis 65 | 66 | """ 67 | 68 | from .analysis import ( 69 | FineAmplitudeAnalysis, 70 | RamseyXYAnalysis, 71 | T2RamseyAnalysis, 72 | T1Analysis, 73 | T1KerneledAnalysis, 74 | T2HahnAnalysis, 75 | TphiAnalysis, 76 | ReadoutAngleAnalysis, 77 | LocalReadoutErrorAnalysis, 78 | CorrelatedReadoutErrorAnalysis, 79 | ZZRamseyAnalysis, 80 | MultiStateDiscriminationAnalysis, 81 | ) 82 | 83 | from .t1 import T1 84 | from .t2ramsey import T2Ramsey 85 | from .t2hahn import T2Hahn 86 | from .tphi import Tphi 87 | from .half_angle import HalfAngle 88 | from .fine_amplitude import FineAmplitude, FineXAmplitude, FineSXAmplitude 89 | from .ramsey_xy import RamseyXY 90 | from .fine_frequency import FineFrequency 91 | from .readout_angle import ReadoutAngle 92 | from .fine_drag import FineDrag, FineXDrag, FineSXDrag 93 | from .local_readout_error import LocalReadoutError 94 | from .correlated_readout_error import CorrelatedReadoutError 95 | from .zz_ramsey import ZZRamsey 96 | from .multi_state_discrimination import MultiStateDiscrimination 97 | -------------------------------------------------------------------------------- /test/library/quantum_volume/qv_ideal_probabilities.json: -------------------------------------------------------------------------------- 1 | [[0.06090981922741352, 0.34784828887489516, 0.003440728125794299, 0.17695071101919052, 0.020399173510863133, 0.3133909057297853, 0.025208906876148903, 0.051851466635908984], [0.052795588044998266, 0.2036758692494191, 0.022228933273601266, 0.267947067954847, 0.04662254705199523, 0.23689106637344887, 0.014644198017660856, 0.15519473003402912], [0.33890568849498903, 0.08470251706991236, 0.09032425795803736, 0.1176818050135521, 0.20023444940934337, 0.040376649609833996, 0.07845708684381617, 0.04931754560051594], [0.07843754575087986, 0.21907218041759557, 0.11588111917837404, 0.14344927568779245, 0.07247077881185233, 0.13642212295586695, 0.19928429396422193, 0.03498268323341709], [0.03146764504989369, 0.010672855981310281, 0.0698472783532379, 0.2805983021183489, 0.1697510376611356, 0.34490526483543, 0.05675488127108915, 0.03600273472955497], [0.014712440805189736, 0.20198281763070447, 0.03951483459147206, 0.10661868457522322, 0.028973459527277957, 0.0030555802881049895, 0.1683968533591363, 0.43674532922289167], [0.4652838497088344, 0.1370319640546792, 0.0, 0.0, 0.11184911640086283, 0.2858350698356241, 0.0, 0.0], [0.41691761271850697, 0.09802206331301935, 0.0, 0.0, 0.12170171915272401, 0.36335860481574933, 0.0, 0.0], [0.06040824842131547, 0.22360037606154226, 0.16703416728799328, 0.3155515725112804, 0.00574389769671973, 0.06422576739914752, 0.05653984347944168, 0.10689612714255917], [0.034145937220083696, 0.3275471371847169, 0.0, 0.0, 0.5265934908959305, 0.11171343469926844, 0.0, 0.0], [0.31362955944335913, 0.0012492306942707208, 0.0, 0.0, 0.3045171469773979, 0.380604062884972, 0.0, 0.0], [0.14084298473415383, 0.04241815646129184, 0.2787065997143041, 0.2763086311775977, 0.04767796566311971, 0.04777093880194504, 0.030317360310517225, 0.1359573631370707], [0.10490558188826622, 0.03734373973356664, 0.0846661393845946, 0.012178280925959687, 0.2450469596449601, 0.3830889806436624, 0.0410475620559563, 0.09172275572303307], [0.0721384781481662, 0.2132011346169562, 0.0382461870322736, 0.01006147040056322, 0.0012564152657445, 0.5640473347441018, 0.03581099593386722, 0.06523798385832678], [0.35047461795366364, 0.07295546107526876, 0.11429248870690438, 0.046387738341356205, 0.016403322359457823, 0.11703328502400306, 0.18840822678605898, 0.09404485975328614], [0.12537608375594167, 0.004147254265659097, 0.01888208426232345, 0.127828626942106, 0.20712391654423107, 0.004956839798677847, 0.20103868882942894, 0.31064650560163193], [0.24266832167544544, 0.10171085169237129, 0.6518557453504638, 0.0037650812817186354, 0.0, 0.0, 0.0, 0.0], [0.004496439754867754, 0.03999764295525122, 0.045209067627212385, 0.42243909053043943, 0.23660227820571852, 0.1145783400317101, 0.016512735149122833, 0.12016440574567633], [0.403998318316775, 0.1913339052666593, 0.39512059243880765, 0.009547183977757986, 0.0, 0.0, 0.0, 0.0], [0.046975692653985185, 0.07680806404698703, 0.013699720588740898, 0.1007536179821163, 0.006010045196316757, 0.49827221242540065, 0.0039712903211504315, 0.25350935678530284]] -------------------------------------------------------------------------------- /test/library/tomography/tomo_utils.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Common methods for tomography tests 15 | """ 16 | import numpy as np 17 | from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister 18 | from qiskit_aer.noise import NoiseModel 19 | 20 | 21 | FITTERS = [ 22 | None, 23 | "linear_inversion", 24 | "cvxpy_linear_lstsq", 25 | "cvxpy_gaussian_lstsq", 26 | ] 27 | 28 | 29 | def teleport_circuit(flatten_creg=True): 30 | """Teleport qubit 0 to qubit 2""" 31 | if flatten_creg: 32 | teleport = QuantumCircuit(3, 2) 33 | creg = teleport.cregs[0] 34 | else: 35 | qr = QuantumRegister(3) 36 | c0 = ClassicalRegister(1, "c0") 37 | c1 = ClassicalRegister(1, "c1") 38 | teleport = QuantumCircuit(qr, c0, c1) 39 | creg = [c0, c1] 40 | teleport.h(1) 41 | teleport.cx(1, 2) 42 | teleport.cx(0, 1) 43 | teleport.h(0) 44 | teleport.measure(0, creg[0]) 45 | teleport.measure(1, creg[1]) 46 | # Conditionals 47 | with teleport.if_test((creg[0], True)): 48 | teleport.z(2) 49 | with teleport.if_test((creg[1], True)): 50 | teleport.x(2) 51 | return teleport 52 | 53 | 54 | def teleport_bell_circuit(flatten_creg=True): 55 | """Teleport entangled qubit 0 -> 2""" 56 | if flatten_creg: 57 | teleport = QuantumCircuit(4, 2) 58 | creg = teleport.cregs[0] 59 | else: 60 | qr = QuantumRegister(4) 61 | c0 = ClassicalRegister(1) 62 | c1 = ClassicalRegister(1) 63 | teleport = QuantumCircuit(qr, c0, c1) 64 | creg = [c0, c1] 65 | teleport.h(0) 66 | teleport.cx(0, 3) 67 | teleport.h(1) 68 | teleport.cx(1, 2) 69 | teleport.cx(0, 1) 70 | teleport.h(0) 71 | teleport.measure(0, creg[0]) 72 | teleport.measure(1, creg[1]) 73 | with teleport.if_test((creg[0], True)): 74 | teleport.z(2) 75 | with teleport.if_test((creg[1], True)): 76 | teleport.x(2) 77 | return teleport 78 | 79 | 80 | def readout_noise_model(num_qubits, seed=None): 81 | """Generate noise model of random local readout errors""" 82 | rng = np.random.default_rng(seed=seed) 83 | p1g0s = 0.15 * rng.random(num_qubits) 84 | p0g1s = 0.3 * rng.random(num_qubits) 85 | amats = np.stack([[1 - p1g0s, p1g0s], [p0g1s, 1 - p0g1s]]).T 86 | noise_model = NoiseModel() 87 | for i, amat in enumerate(amats): 88 | noise_model.add_readout_error(amat.T, [i]) 89 | return noise_model 90 | -------------------------------------------------------------------------------- /qiskit_experiments/library/randomized_benchmarking/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | =============================================================================================== 15 | Randomized Benchmarking Experiments (:mod:`qiskit_experiments.library.randomized_benchmarking`) 16 | =============================================================================================== 17 | 18 | .. currentmodule:: qiskit_experiments.library.randomized_benchmarking 19 | 20 | Experiments 21 | =========== 22 | .. autosummary:: 23 | :toctree: ../stubs/ 24 | :template: autosummary/experiment.rst 25 | 26 | StandardRB 27 | InterleavedRB 28 | LayerFidelity 29 | LayerFidelityUnitary 30 | 31 | 32 | Analysis 33 | ======== 34 | 35 | .. autosummary:: 36 | :toctree: ../stubs/ 37 | :template: autosummary/analysis.rst 38 | 39 | RBAnalysis 40 | InterleavedRBAnalysis 41 | LayerFidelityAnalysis 42 | 43 | Synthesis 44 | ========= 45 | 46 | .. autosummary:: 47 | :toctree: ../stubs/ 48 | 49 | RBDefaultCliffordSynthesis 50 | 51 | Utilities 52 | ========= 53 | 54 | .. autosummary:: 55 | :toctree: ../stubs/ 56 | 57 | RBUtils 58 | CliffordUtils 59 | 60 | .. _synth-methods-lbl: 61 | 62 | Synthesis Methods 63 | ================= 64 | 65 | There are a few built-in options for the Clifford synthesis method: 66 | 67 | * ``rb_default`` (default) for n<=2 Cliffords this methods will transpile using ``optimization_level=1``. 68 | For 3 or more qubits the behavior is similar but a custom transpilation sequence is used to avoid 69 | the transpiler changing the layout of the circuit. 70 | 71 | * ``clifford_synthesis_method='basis_only'`` will use ``optimization_level=0``. 72 | 73 | * ``clifford_synthesis_method='1Q_fixed`` will use a ``rz-sx-rz-sx-rz`` decomposition for the 1Q 74 | Cliffords and the default for the 2Q cliffords. This is most relevant for :class:`.LayerFidelity` 75 | experiments because it will keep a fixed structure. 76 | 77 | """ 78 | from .standard_rb import StandardRB 79 | from .interleaved_rb_experiment import InterleavedRB 80 | from .rb_analysis import RBAnalysis 81 | from .interleaved_rb_analysis import InterleavedRBAnalysis 82 | from .clifford_utils import CliffordUtils 83 | from .rb_utils import RBUtils 84 | from .clifford_synthesis import RBDefaultCliffordSynthesis 85 | from .layer_fidelity import LayerFidelity 86 | from .layer_fidelity_unitary import LayerFidelityUnitary 87 | from .layer_fidelity_analysis import LayerFidelityAnalysis 88 | -------------------------------------------------------------------------------- /test/framework/test_warnings.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | # pylint: disable=unused-argument, unused-variable 14 | """Test warning helper.""" 15 | 16 | import subprocess 17 | import sys 18 | import textwrap 19 | from test.base import QiskitExperimentsTestCase 20 | 21 | from qiskit_experiments.framework import BaseExperiment 22 | 23 | 24 | class TempExperiment(BaseExperiment): 25 | """Fake experiment.""" 26 | 27 | def __init__(self, physical_qubits): 28 | super().__init__(physical_qubits) 29 | 30 | def circuits(self): 31 | pass 32 | 33 | 34 | class TestWarningsHelper(QiskitExperimentsTestCase): 35 | """Test case for warnings decorator with tricky behavior.""" 36 | 37 | def test_warn_sklearn(self): 38 | """Test that a suggestion to import scikit-learn is given when appropriate""" 39 | script = """ 40 | import builtins 41 | disallowed_imports = {"sklearn"} 42 | old_import = builtins.__import__ 43 | def guarded_import(name, *args, **kwargs): 44 | if name == "sklearn" or name.startswith("sklearn."): 45 | raise import_error(f"Import of {name} not allowed!") 46 | return old_import(name, *args, **kwargs) 47 | builtins.__import__ = guarded_import 48 | # Raise Exception on imports so that ImportError can't be caught 49 | import_error = Exception 50 | import qiskit_experiments 51 | print("qiskit_experiments imported!") 52 | # Raise ImportError so the guard can catch it 53 | import_error = ImportError 54 | from qiskit_experiments.data_processing.sklearn_discriminators import SkLDA 55 | SkLDA.from_config({}) 56 | """ 57 | script = textwrap.dedent(script) 58 | 59 | proc = subprocess.run( 60 | [sys.executable, "-c", script], check=False, text=True, capture_output=True 61 | ) 62 | 63 | self.assertTrue( 64 | proc.stdout.startswith("qiskit_experiments imported!"), 65 | msg="Failed to import qiskit_experiments without sklearn", 66 | ) 67 | 68 | self.assertNotEqual( 69 | proc.returncode, 70 | 0, 71 | msg="scikit-learn usage did not error without scikit-learn available", 72 | ) 73 | self.assertTrue( 74 | "qiskit.exceptions.MissingOptionalLibraryError" in proc.stderr 75 | and "scikit-learn" in proc.stderr, 76 | msg="scikit-learn import guard did not run on scikit-learn usage", 77 | ) 78 | -------------------------------------------------------------------------------- /qiskit_experiments/visualization/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021, 2022, 2023. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | r""" 13 | ========================================================= 14 | Visualization (:mod:`qiskit_experiments.visualization`) 15 | ========================================================= 16 | 17 | .. currentmodule:: qiskit_experiments.visualization 18 | 19 | The visualization module provides plotting functionality for creating figures from 20 | experiment and analysis results. This includes plotter and drawer classes to plot data 21 | in :class:`.CurveAnalysis` and its subclasses. Plotters inherit from 22 | :class:`BasePlotter` and define a type of figure that may be generated from experiment 23 | or analysis data. For example, the results from :class:`.CurveAnalysis`---or any other 24 | experiment where results are plotted against a single parameter (i.e., :math:`x`)---can 25 | be plotted using the :class:`CurvePlotter` class, which plots X-Y-like values. 26 | 27 | These plotter classes act as a bridge (from the common bridge pattern in software 28 | development) between analysis classes (or even users) and plotting backends such as 29 | Matplotlib. Drawers are the backends, with a common interface defined in 30 | :class:`BaseDrawer`. Though Matplotlib is the only officially supported plotting backend 31 | in Qiskit Experiments (i.e., through :class:`MplDrawer`), custom drawers can be 32 | implemented by users to use alternative backends. As long as the backend is a subclass 33 | of :class:`BaseDrawer`, and implements all the necessary functionality, all plotters 34 | should be able to generate figures with the alternative backend. 35 | 36 | To collate style parameters together, plotters and drawers store instances of the 37 | :class:`PlotStyle` class. These instances can be merged and updated, so that default 38 | styles can have their values overwritten. 39 | 40 | Plotter Library 41 | =============== 42 | 43 | .. autosummary:: 44 | :toctree: ../stubs/ 45 | :template: autosummary/plotter.rst 46 | 47 | BasePlotter 48 | CurvePlotter 49 | IQPlotter 50 | 51 | Drawer Library 52 | ============== 53 | 54 | .. autosummary:: 55 | :toctree: ../stubs/ 56 | :template: autosummary/drawer.rst 57 | 58 | BaseDrawer 59 | MplDrawer 60 | 61 | Plotting Style 62 | ============== 63 | 64 | .. autosummary:: 65 | :toctree: ../stubs/ 66 | :template: autosummary/class.rst 67 | 68 | PlotStyle 69 | """ 70 | 71 | from .drawers import BaseDrawer, MplDrawer 72 | from .plotters import BasePlotter, CurvePlotter, IQPlotter 73 | from .style import PlotStyle 74 | -------------------------------------------------------------------------------- /qiskit_experiments/library/tomography/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | ===================================================================== 15 | Tomography Experiments (:mod:`qiskit_experiments.library.tomography`) 16 | ===================================================================== 17 | 18 | .. currentmodule:: qiskit_experiments.library.tomography 19 | 20 | 21 | Experiments 22 | =========== 23 | .. autosummary:: 24 | :toctree: ../stubs/ 25 | :template: autosummary/experiment.rst 26 | 27 | TomographyExperiment 28 | StateTomography 29 | ProcessTomography 30 | MitigatedStateTomography 31 | MitigatedProcessTomography 32 | 33 | 34 | Analysis 35 | ======== 36 | 37 | .. autosummary:: 38 | :toctree: ../stubs/ 39 | :template: autosummary/analysis.rst 40 | 41 | TomographyAnalysis 42 | StateTomographyAnalysis 43 | ProcessTomographyAnalysis 44 | MitigatedTomographyAnalysis 45 | 46 | Tomography Fitters 47 | ================== 48 | 49 | Fitter functions for state reconstruction in tomography analysis 50 | 51 | .. autosummary:: 52 | :toctree: ../stubs/ 53 | 54 | fitters.linear_inversion 55 | fitters.cvxpy_gaussian_lstsq 56 | fitters.cvxpy_linear_lstsq 57 | 58 | 59 | Basis Classes 60 | ============= 61 | 62 | Built in tomography basis classes 63 | 64 | .. autosummary:: 65 | :toctree: ../stubs/ 66 | 67 | basis.PauliMeasurementBasis 68 | basis.PauliPreparationBasis 69 | basis.Pauli6PreparationBasis 70 | 71 | Custom local tensor product basis classes 72 | 73 | .. autosummary:: 74 | :toctree: ../stubs/ 75 | 76 | basis.LocalMeasurementBasis 77 | basis.LocalPreparationBasis 78 | 79 | Abstract base classes 80 | 81 | .. autosummary:: 82 | :toctree: ../stubs/ 83 | 84 | basis.MeasurementBasis 85 | basis.PreparationBasis 86 | 87 | .. warning:: 88 | The API for tomography fitters and bases is still under development so may 89 | change in a future release. 90 | """ 91 | 92 | # Experiment Classes 93 | from .tomography_experiment import TomographyExperiment 94 | from .qst_experiment import StateTomography, StateTomographyAnalysis 95 | from .qpt_experiment import ProcessTomography, ProcessTomographyAnalysis 96 | from .mit_qst_experiment import MitigatedStateTomography 97 | from .mit_qpt_experiment import MitigatedProcessTomography 98 | from .tomography_analysis import TomographyAnalysis 99 | from .mit_tomography_analysis import MitigatedTomographyAnalysis 100 | 101 | # Basis Classes 102 | from . import basis 103 | from . import fitters 104 | -------------------------------------------------------------------------------- /test/curve_analysis/test_standard_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test standard analysis base classes.""" 14 | 15 | from test.base import QiskitExperimentsTestCase 16 | import numpy as np 17 | from ddt import ddt, data 18 | 19 | from qiskit_experiments.curve_analysis import ErrorAmplificationAnalysis 20 | from qiskit_experiments.data_processing import DataProcessor 21 | from qiskit_experiments.data_processing.nodes import Probability 22 | from qiskit_experiments.framework import Options, ExperimentData 23 | 24 | 25 | @ddt 26 | class TestErrorAmplificationAnalysis(QiskitExperimentsTestCase): 27 | """Test for error amplification analysis.""" 28 | 29 | @staticmethod 30 | def create_data(xvals, d_theta, shots=1000, noise_seed=123): 31 | """Create experiment data for testing.""" 32 | np.random.seed(noise_seed) 33 | noise = np.random.normal(0, 0.03, len(xvals)) 34 | yvals = 0.5 * np.cos((d_theta + np.pi) * xvals - np.pi / 2) + 0.5 + noise 35 | 36 | results = [] 37 | for x, y in zip(xvals, yvals): 38 | n1 = int(shots * y) 39 | results.append({"counts": {"0": shots - n1, "1": n1}, "metadata": {"xval": x}}) 40 | 41 | expdata = ExperimentData() 42 | expdata.add_data(results) 43 | 44 | return expdata 45 | 46 | @data(-0.1, -0.08, -0.06, -0.04, -0.02, -0.01, 0.0, 0.01, 0.02, 0.04, 0.06, 0.08, 0.1) 47 | def test_fit_vals(self, d_theta_targ): 48 | """Test for fitting.""" 49 | 50 | class FakeAmpAnalysis(ErrorAmplificationAnalysis): 51 | """Analysis class for testing.""" 52 | 53 | @classmethod 54 | def _default_options(cls) -> Options: 55 | """Default analysis options.""" 56 | options = super()._default_options() 57 | options.fixed_parameters = { 58 | "angle_per_gate": np.pi, 59 | "phase_offset": np.pi / 2, 60 | "amp": 1.0, 61 | } 62 | 63 | return options 64 | 65 | reps = np.arange(0, 21, 1) 66 | fake_data = self.create_data(reps, d_theta=d_theta_targ) 67 | processor = DataProcessor("counts", data_actions=[Probability("1")]) 68 | 69 | analysis = FakeAmpAnalysis() 70 | analysis.set_options(data_processor=processor) 71 | 72 | fake_data = analysis.run(fake_data) 73 | self.assertExperimentDone(fake_data) 74 | 75 | self.assertAlmostEqual( 76 | fake_data.analysis_results("d_theta", dataframe=True).iloc[0].value.n, 77 | d_theta_targ, 78 | delta=0.01, 79 | ) 80 | -------------------------------------------------------------------------------- /test/library/quantum_volume/qv_ideal_probabilities_qiskit_2_0.json: -------------------------------------------------------------------------------- 1 | [[0.4354534198676485, 0.22262891512793948, 0.10408983081803903, 0.008528240130548951, 0.013343796818990183, 0.12379653457767027, 0.0836079509124482, 0.008551311746715808], [0.07788043805758058, 0.2530303344204691, 0.058262742578192084, 0.06482442429506201, 0.3128253455993438, 0.11426100908573869, 0.09048658679511766, 0.02842911916849869], [0.2186719664893615, 0.3815922247599302, 0.000583843694713377, 0.12920911563666243, 0.0858198387152911, 0.06097582184031965, 0.0673984561093236, 0.0557487327543985], [0.003897068822837867, 0.0016095484703179488, 0.018829897322986747, 0.25219987203921546, 0.09522049447881334, 0.04652861779291838, 0.2874781744055805, 0.29423632666733174], [0.6229736498210389, 0.07847685679165327, 0.0, 0.0, 0.046834240043179785, 0.25171525334412953, 0.0, 0.0], [0.151149944913878, 0.1249651244583814, 0.1946794863797365, 0.1066019725137271, 0.08909116082079165, 0.00884228190584737, 0.14286412954005792, 0.18180589946758033], [0.17551340168478133, 0.03755399630414072, 0.25083249661274554, 0.13863511043235066, 0.048824430353276355, 0.042536698807117156, 0.008468791654733607, 0.29763507415085605], [0.027465028513495082, 0.03839194810323577, 0.1253280113115479, 0.33054254126671456, 0.05104576614516026, 0.21266097447467758, 0.13263351575345472, 0.08193221443171579], [0.04352382635168621, 0.07075317810174925, 0.3652000687337914, 0.23765921217061362, 0.011134250434853337, 0.01665523240437386, 0.12971657157544103, 0.1253576602274936], [0.373562389099596, 0.2653053261621785, 0.03172560521407652, 0.024564074822944322, 0.09445121921831463, 0.053343327915518254, 0.10809206464582552, 0.04895599292154718], [0.16674207926924434, 0.013619484681005937, 0.0922761510450282, 0.04529725529661201, 0.041846753872960996, 0.02453221246142707, 0.5889092312724002, 0.026776832101321476], [0.267586988288187, 0.36565616506047605, 0.0, 0.0, 0.22689159435360165, 0.1398652522977358, 0.0, 0.0], [0.0186995904784679, 0.12997192426309473, 0.17721607321420338, 0.048586421019253895, 0.01409331164574642, 0.43456029397774326, 0.006096818492149609, 0.17077556690934154], [0.25225456157179704, 0.0019066518146095036, 0.06050340774200541, 0.10312608082578481, 0.2831290929651657, 0.12413269298041205, 0.13848913529739962, 0.03645837680282536], [0.36617477405944787, 0.021560748638344195, 0.6115895573416229, 0.0006749199605860473, 0.0, 0.0, 0.0, 0.0], [0.04807485840414659, 0.12981320326584686, 0.21984114586795064, 0.09430255533974663, 0.016828422624588068, 0.36567010434282027, 0.052647618089929495, 0.0728220920649725], [0.10427286449119794, 0.07898578330295439, 0.06933208827268615, 0.12162877295526542, 0.15498965998385178, 0.07423177857764378, 0.1379282473571835, 0.25863080505921904], [0.10741335631181385, 0.15462884700946977, 0.1952802011611909, 0.21643706118042194, 0.028393707781655123, 0.15392469880069715, 0.020345141379612724, 0.12357698637513952], [0.22808509801013765, 0.052647076972947515, 0.0715107180006456, 0.03262956906864945, 0.01721859076861818, 0.04953075016771909, 0.0908571295934774, 0.4575210674178066], [0.1352085352725553, 0.14307526572917453, 0.03778661347377269, 0.031309737384210494, 0.1057246324597863, 0.2614179867904946, 0.20733802596334325, 0.07813920292666376]] -------------------------------------------------------------------------------- /tools/pylint_incr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2017, 2018. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | """Run pylint incrementally on only changed files""" 16 | 17 | import subprocess 18 | import argparse 19 | import os 20 | import sys 21 | 22 | from pylint import lint 23 | 24 | ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) 25 | 26 | 27 | def _minimal_ext_cmd(cmd): 28 | # construct minimal environment 29 | env = {} 30 | for k in ["SYSTEMROOT", "PATH"]: 31 | v = os.environ.get(k) 32 | if v is not None: 33 | env[k] = v 34 | # LANGUAGE is used on win32 35 | env["LANGUAGE"] = "C" 36 | env["LANG"] = "C" 37 | env["LC_ALL"] = "C" 38 | with subprocess.Popen( 39 | cmd, 40 | stdout=subprocess.PIPE, 41 | stderr=subprocess.PIPE, 42 | env=env, 43 | cwd=os.path.join(os.path.dirname(ROOT_DIR)), 44 | ) as proc: 45 | stdout, stderr = proc.communicate() 46 | return proc.returncode, stdout, stderr 47 | 48 | 49 | def _run_pylint(ref, paths, pylint_args): 50 | code, stdout, stderr = _minimal_ext_cmd( 51 | [ 52 | "git", 53 | "diff-index", 54 | "--name-only", 55 | "--diff-filter=d", 56 | "--merge-base", 57 | "-z", 58 | ref, 59 | "--", 60 | *paths, 61 | ] 62 | ) 63 | if code != 0: 64 | print( 65 | f"{__file__}: unable to get list of changed files. Git returncode: {code}\n" 66 | f"Git must be installed, and you need to be in a git tree with a ref `{ref}`\n" 67 | f"{stderr.strip().decode('ascii')}" 68 | ) 69 | sys.exit(128) 70 | changed_paths = [path.decode("ascii") for path in stdout.split(b"\x00") if len(path) > 0] 71 | if len(changed_paths) == 0: 72 | print(f"No changed files in {' '.join(paths)}") 73 | sys.exit(0) 74 | changed_paths_pretty = "\n ".join(changed_paths) 75 | print(f"Running pylint on {len(changed_paths)} changed files:\n {changed_paths_pretty}") 76 | lint.Run([*pylint_args, "--", *changed_paths]) 77 | 78 | 79 | def _main(): 80 | parser = argparse.ArgumentParser( 81 | description="Incremental pylint.", 82 | epilog="Unknown arguments passed through to pylint", 83 | allow_abbrev=False, 84 | ) 85 | parser.add_argument( 86 | "--paths", 87 | required=True, 88 | type=str, 89 | nargs="+", 90 | help="Git s to resolve (and pass any changed files to pylint)", 91 | ) 92 | args, pylint_args = parser.parse_known_args() 93 | _run_pylint("lint_incr_latest", args.paths, pylint_args) 94 | 95 | 96 | if __name__ == "__main__": 97 | _main() 98 | -------------------------------------------------------------------------------- /test/library/quantum_volume/qv_ideal_probabilities_qiskit_1_3.json: -------------------------------------------------------------------------------- 1 | [[0.016967836206746738, 0.11989893254007651, 0.00394654461853002, 0.13589528784677357, 0.20511482048008703, 0.0816791691977386, 0.14060546401643623, 0.2958919450936116], [0.12056007843940977, 0.10070988761274678, 0.41332860589623954, 0.07543734133716322, 0.021096066850169303, 0.1601488559241172, 0.03780114546996992, 0.0709180184701846], [0.10058394660184918, 0.39126225007098714, 0.09012977139125049, 0.02982028558144569, 0.005523508253283623, 0.040983681969626276, 0.2946239196681466, 0.04707263646341052], [0.3688522014926478, 0.09580420366241688, 0.027757018918742504, 0.15826915582072928, 0.13834528025457885, 0.11281057034461814, 0.04713950685498301, 0.05102206265128345], [0.2238855389562393, 0.0177775881962427, 0.0010361793224677451, 0.49743548639570334, 0.14345035837415962, 0.010983952529157095, 0.030086371572847458, 0.07534452465318305], [0.07191730758022169, 0.08577798556935443, 0.05222185324072163, 0.011505080428938406, 0.1506083560400655, 0.07947214515779061, 0.06954659702813472, 0.4789506749547722], [0.02933798117949475, 0.0905804630987942, 0.13414073913728367, 0.3283400904287246, 0.0039327427715444745, 0.06305126971619468, 0.07960132612718543, 0.27101538754077775], [0.10361935285611489, 0.5602661574454084, 0.0033379483277632236, 0.024104300671844853, 0.11180012107386983, 0.018590174540476845, 0.06496224115302754, 0.11331970393149465], [0.28002251748562146, 0.15659108128101512, 0.06931560231414717, 0.015939512694748054, 0.20272160865971692, 0.06437155774108827, 0.17997014329975955, 0.031067976523903224], [0.2583110429786593, 0.39280733849970395, 0.01004465642965845, 0.10112365839530935, 0.04820792916847759, 0.019172100821762683, 0.07396094843817139, 0.09637232526825651], [0.04205005835070806, 0.5982838080237505, 0.24825488091343656, 0.11141125271210575, 0.0, 0.0, 0.0, 0.0], [0.21631173866223324, 0.07201585886194255, 0.19647582952426423, 0.10741584491273042, 0.054982878753641044, 0.021165794683348307, 0.2526914377956466, 0.07894061680619284], [0.04109901108305593, 0.5346418163425509, 0.0, 0.0, 0.19988603142757153, 0.22437314114682205, 0.0, 0.0], [0.1069722912636189, 0.19610594120528163, 0.13827775538043613, 0.12862292833267164, 0.05652810658633324, 0.0979666878234763, 0.15917488848657904, 0.1163514009216026], [0.1599264302659344, 0.32405634292478286, 0.050423144948197246, 0.03657193295081257, 0.13405197214337658, 0.1872187743627101, 0.0005017400591434017, 0.1072496623450432], [0.057428879095657914, 0.07553302531949552, 0.05869499440092844, 0.031696849711854186, 0.20158700775693938, 0.20118430243224272, 0.02391580078822289, 0.34995914049465865], [0.12733557958689173, 0.08478618874152216, 0.032857670388396855, 0.08627573094283553, 0.18807352626751228, 0.2365561765088683, 0.15519965863714033, 0.08891546892683337], [0.05434853562358783, 0.1282198611011262, 0.11416220587356729, 0.049568640406240184, 0.1511891111128068, 0.14032078289874864, 0.3087935419191839, 0.05339732106473909], [0.06135629616886566, 0.25774569674205117, 0.0464794921453153, 0.15917144757251409, 0.1677568850176423, 0.18787259587234334, 0.05248811617198047, 0.0671294703092877], [0.005879541314725802, 0.025021402090856428, 0.44431583322312285, 0.05198340090748109, 0.04211534913258567, 0.013297849871047806, 0.26003956333041356, 0.15734706012976746]] 2 | -------------------------------------------------------------------------------- /docs/_ext/custom_styles/section_parsers.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Documentation section parsers. 15 | """ 16 | 17 | import re 18 | from typing import List 19 | 20 | from .utils import _trim_empty_lines 21 | 22 | 23 | def load_standard_section(docstring_lines: List[str]) -> List[str]: 24 | """Load standard docstring section.""" 25 | return _trim_empty_lines(docstring_lines) 26 | 27 | 28 | def load_fit_parameters(docstring_lines: List[str]) -> List[str]: 29 | """Load fit parameter section.""" 30 | regex_paramdef = re.compile(r"defpar (?P.+):") 31 | 32 | # item finder 33 | description_kind = { 34 | "desc": re.compile(r"desc: (?P.+)"), 35 | "init_guess": re.compile(r"init_guess: (?P.+)"), 36 | "bounds": re.compile(r"bounds: (?P.+)"), 37 | } 38 | 39 | # parse lines 40 | parameter_desc = dict() 41 | current_param = None 42 | current_item = None 43 | for line in docstring_lines: 44 | if not list: 45 | # remove line feed 46 | continue 47 | 48 | # check if line is new parameter definition 49 | match = re.match(regex_paramdef, line) 50 | if match: 51 | current_param = match["param"] 52 | parameter_desc[current_param] = { 53 | "desc": "", 54 | "init_guess": "", 55 | "bounds": "", 56 | } 57 | continue 58 | 59 | # check description 60 | for kind, regex in description_kind.items(): 61 | match = re.search(regex, line) 62 | if match: 63 | current_item = kind 64 | line = match["s"].rstrip() 65 | 66 | # add line if parameter and item are already set 67 | if current_param and current_item: 68 | if parameter_desc[current_param][current_item]: 69 | parameter_desc[current_param][current_item] += " " + line.lstrip() 70 | else: 71 | parameter_desc[current_param][current_item] = line.lstrip() 72 | 73 | section_lines = list() 74 | 75 | def write_description(header: str, kind: str): 76 | section_lines.append(header) 77 | for param, desc in parameter_desc.items(): 78 | if not desc: 79 | section_lines.append( 80 | f" - :math:`{param}`: No description is provided. See source for details." 81 | ) 82 | else: 83 | section_lines.append(f" - :math:`{param}`: {desc[kind]}") 84 | section_lines.append("") 85 | 86 | write_description("Descriptions", "desc") 87 | write_description("Initial Guess", "init_guess") 88 | write_description("Boundaries", "bounds") 89 | 90 | return _trim_empty_lines(section_lines) 91 | -------------------------------------------------------------------------------- /test/library/quantum_volume/qv_ideal_probabilities_qiskit_1_1.json: -------------------------------------------------------------------------------- 1 | [[0.02110822695364887, 0.013936320980929177, 0.06762829067477494, 0.05640378028262168, 0.019434855941263804, 0.01254494041140876, 0.3597504343657043, 0.44919315038964813], [0.1722976165549457, 0.029841680707019494, 0.015656642181112637, 0.22730547539691617, 0.12732050329410488, 0.06013320751345239, 0.23738660274412582, 0.13005827160832278], [0.025330413591789218, 0.05365793634629424, 0.005510054610574176, 0.2659480366696103, 0.06644689405510834, 0.16522547308232338, 0.06550526962201847, 0.35237592202228174], [0.03752531358760119, 0.0639087743319445, 0.05174568892966019, 0.026258899708790133, 0.06025270407432933, 0.4752249297421205, 0.17263176026475763, 0.11245192936079637], [0.31320609444467884, 0.0064025098682649, 0.2454242441765262, 0.11834874135446874, 0.1410876641286843, 0.016731059242565263, 0.09755353034344483, 0.06124615644136609], [0.019448190781865507, 0.05499334515101417, 0.13640962401919648, 0.027348070327303475, 0.048411270171909986, 0.16728339683880306, 0.3206808043538741, 0.225425298356034], [0.00960924565105907, 0.5136650426998607, 0.0011415111620172156, 0.020066510917153436, 0.0010864777624874085, 0.12088859340271874, 0.003926145584809557, 0.32961647281989354], [0.0033843151967825605, 0.0904375862783492, 0.14082024165587934, 0.028700581811163736, 0.5206374518621331, 0.1449007040623369, 0.020747488106116044, 0.050371631027239266], [0.02953881873020507, 0.16412229218641006, 0.0044071010350494825, 0.2837594965902758, 0.015330305509777008, 0.10239055990425917, 0.02799467182995681, 0.37245675421406627], [0.1322823017311934, 0.4458209485696668, 0.0, 0.0, 0.048864936086664826, 0.3730318136124744, 0.0, 0.0], [0.08168205214501269, 0.014301663582061402, 0.031796449397294785, 0.030646878482070747, 0.03347798878280955, 0.30568913585068463, 0.48978086811193544, 0.012624963648130906], [0.10270572333629126, 0.2054021653045906, 0.3214150326296182, 0.06540473121561362, 0.030757362188421174, 0.2211717639672315, 0.04658693468342603, 0.006556286674807662], [0.15936994988625908, 0.10431864042664502, 0.08299765915752665, 0.02804542799741586, 0.06960987222202304, 0.15337460586250898, 0.0958361933378381, 0.3064476511097831], [0.004950387743443303, 0.036932489074513596, 0.03652458327201384, 0.2650570018042196, 0.009291507543548598, 0.10388620362313436, 0.1691098123043206, 0.37424801463480634], [0.05972657537009159, 0.19914118274809703, 0.08779406969022188, 0.25663496507647837, 0.12477975035159891, 0.1996292453671398, 0.012677912029188738, 0.059616299367184024], [0.4809352140937508, 0.1984839027335819, 0.08741344211264122, 0.01856979807616571, 0.020353167602611928, 0.06987732405489348, 0.02366752222163191, 0.10069962910472299], [0.08304167605222394, 0.04112711434346582, 0.06461187209953644, 0.29581303509821427, 0.1801493690994243, 0.15019357344113535, 0.03342178624142832, 0.1516415736245708], [0.11034335151398833, 0.1535142244794561, 0.010924645942967047, 0.1595660489816288, 0.012260755380658836, 0.2373347471191917, 0.25694446799872295, 0.05911175858338647], [0.144941751473959, 0.009237621811653846, 0.016193183621015943, 0.015626036290447263, 0.07939130818210129, 0.1282415772050653, 0.522578062681002, 0.08379045873475498], [0.12323459136182116, 0.04647043553049166, 0.36115923872923944, 0.06606545697235076, 0.14875149834994203, 0.016170939689423118, 0.22211811256352207, 0.01602972680320908]] -------------------------------------------------------------------------------- /test/fake_experiment.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """A FakeExperiment for testing.""" 14 | 15 | import numpy as np 16 | import pandas as pd 17 | from matplotlib.figure import Figure as MatplotlibFigure 18 | from qiskit import QuantumCircuit 19 | from qiskit_experiments.framework import ( 20 | BaseExperiment, 21 | BaseAnalysis, 22 | Options, 23 | AnalysisResultData, 24 | ArtifactData, 25 | ) 26 | from qiskit_experiments.curve_analysis import ScatterTable, CurveFitResult 27 | 28 | 29 | class FakeAnalysis(BaseAnalysis): 30 | """ 31 | Dummy analysis class for test purposes only. 32 | """ 33 | 34 | def __init__(self, **kwargs): 35 | super().__init__() 36 | self._kwargs = kwargs 37 | 38 | def _run_analysis(self, experiment_data): 39 | seed = self.options.get("seed", None) 40 | rng = np.random.default_rng(seed=seed) 41 | analysis_results = [ 42 | AnalysisResultData(f"result_{i}", value) for i, value in enumerate(rng.random(3)) 43 | ] 44 | scatter_table = ScatterTable.from_dataframe(pd.DataFrame(columns=ScatterTable.COLUMNS)) 45 | fit_data = CurveFitResult( 46 | method="some_method", 47 | model_repr={"s1": "par0 * x + par1"}, 48 | success=True, 49 | params={"par0": rng.random(), "par1": rng.random()}, 50 | var_names=["par0", "par1"], 51 | covar=rng.random((2, 2)), 52 | reduced_chisq=rng.random(), 53 | ) 54 | analysis_results.append(ArtifactData(name="curve_data", data=scatter_table)) 55 | analysis_results.append(ArtifactData(name="fit_summary", data=fit_data)) 56 | figures = None 57 | add_figures = self.options.get("add_figures", False) 58 | if add_figures: 59 | figures = [MatplotlibFigure()] 60 | return analysis_results, figures 61 | 62 | 63 | class FakeExperiment(BaseExperiment): 64 | """Fake experiment class for testing.""" 65 | 66 | @classmethod 67 | def _default_experiment_options(cls) -> Options: 68 | options = super()._default_experiment_options() 69 | options.dummyoption = None 70 | return options 71 | 72 | def __init__(self, physical_qubits=None, backend=None, experiment_type=None): 73 | """Initialise the fake experiment.""" 74 | if physical_qubits is None: 75 | physical_qubits = [0] 76 | super().__init__( 77 | physical_qubits, 78 | analysis=FakeAnalysis(), 79 | backend=backend, 80 | experiment_type=experiment_type, 81 | ) 82 | 83 | def circuits(self): 84 | """Fake circuits.""" 85 | circ = QuantumCircuit(len(self.physical_qubits)) 86 | # Add measurement to avoid warnings about no measurements 87 | circ.measure_all() 88 | return [circ] 89 | -------------------------------------------------------------------------------- /tools/bump_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2025. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | """Bump package minor version""" 16 | 17 | # /// script 18 | # requires-python = ">=3.11" 19 | # dependencies = [ 20 | # "packaging", 21 | # ] 22 | # /// 23 | 24 | from pathlib import Path 25 | from subprocess import run 26 | 27 | from packaging.version import Version 28 | 29 | 30 | def replace_text(path: Path, old: str, new: str, count: int = 1): 31 | """Replace old string with new in a file 32 | 33 | Args: 34 | path: Path to the file to edit 35 | old: Old string to replace 36 | new: New string to insert 37 | count: How many replacements to expect 38 | 39 | Raises: 40 | ValueError: the number of replacements does not match ``count`` 41 | """ 42 | lines = path.read_text().splitlines() 43 | 44 | match_num = 0 45 | for idx, line in enumerate(lines): 46 | if old in line: 47 | match_num += 1 48 | start = line.index(old) 49 | lines[idx] = line[:start] + new + line[start + len(old) :] 50 | 51 | if match_num != count: 52 | raise ValueError(f"Expected {count} matches for '{old}' in {path} but found {match_num}") 53 | 54 | path.write_text("\n".join(lines) + "\n") 55 | 56 | 57 | def main(): 58 | """Bump minor version in package files""" 59 | proc = run(["git", "rev-parse", "--show-toplevel"], check=True, capture_output=True, text=True) 60 | git_root = Path(proc.stdout.strip()) 61 | 62 | version_file = git_root / "qiskit_experiments/VERSION.txt" 63 | version_str = version_file.read_text().strip() 64 | old_version = Version(version_str) 65 | old_version_short = f"{old_version.major}.{old_version.minor}" 66 | prev_old_version = f"{old_version.major}.{old_version.minor - 1}.0" 67 | prev_old_version_short = f"{old_version.major}.{old_version.minor - 1}" 68 | 69 | new_version = f"{old_version.major}.{old_version.minor + 1}.0" 70 | new_version_short = f"{old_version.major}.{old_version.minor + 1}" 71 | 72 | version_file.write_text(f"{new_version}\n") 73 | 74 | replace_text( 75 | git_root / "docs/release_notes.rst", 76 | f":earliest-version: {prev_old_version}", 77 | f":earliest-version: {old_version}", 78 | ) 79 | replace_text( 80 | git_root / "docs/conf.py", 81 | f'release = os.getenv("RELEASE_STRING", "{old_version}")', 82 | f'release = os.getenv("RELEASE_STRING", "{new_version}")', 83 | ) 84 | replace_text( 85 | git_root / "docs/conf.py", 86 | f'version = os.getenv("VERSION_STRING", "{old_version_short}")', 87 | f'version = os.getenv("VERSION_STRING", "{new_version_short}")', 88 | ) 89 | replace_text( 90 | git_root / ".mergify.yml", 91 | f"- stable/{prev_old_version_short}", 92 | f"- stable/{old_version_short}", 93 | ) 94 | 95 | 96 | if __name__ == "__main__": 97 | main() 98 | -------------------------------------------------------------------------------- /test/library/characterization/test_multi_state_discrimination.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test the multi state discrimination experiments.""" 14 | from functools import wraps 15 | from test.base import QiskitExperimentsTestCase 16 | from unittest import SkipTest 17 | 18 | from ddt import ddt, data 19 | 20 | from qiskit.exceptions import MissingOptionalLibraryError 21 | 22 | from qiskit_experiments.library import MultiStateDiscrimination 23 | from qiskit_experiments.test.mock_iq_backend import MockMultiStateBackend 24 | 25 | from qiskit_experiments.framework.package_deps import HAS_SKLEARN 26 | 27 | 28 | def requires_sklearn(func): 29 | """Decorator to check for SKLearn.""" 30 | 31 | @wraps(func) 32 | def wrapper(*args, **kwargs): 33 | try: 34 | HAS_SKLEARN.require_now("SKLearn discriminator testing") 35 | except MissingOptionalLibraryError as exc: 36 | raise SkipTest("SKLearn is required for test.") from exc 37 | 38 | func(*args, **kwargs) 39 | 40 | return wrapper 41 | 42 | 43 | @ddt 44 | class TestMultiStateDiscrimination(QiskitExperimentsTestCase): 45 | """Tests of the multi state discrimination experiment.""" 46 | 47 | def setUp(self): 48 | """Setup test variables.""" 49 | super().setUp() 50 | 51 | self.backend = MockMultiStateBackend(iq_centers=[1, 1j, -1], rng_seed=1234) 52 | 53 | # Build x12 schedule 54 | self.qubit = 0 55 | 56 | @data(2, 3) 57 | @requires_sklearn 58 | def test_circuit_generation(self, n_states): 59 | """Test the experiment circuit generation""" 60 | exp = MultiStateDiscrimination([self.qubit], n_states=n_states, backend=self.backend) 61 | self.assertEqual(len(exp.circuits()), n_states) 62 | 63 | # check the metadata 64 | self.assertEqual(exp.circuits()[-1].metadata["label"], n_states - 1) 65 | 66 | @data(2, 3) 67 | @requires_sklearn 68 | def test_discrimination_analysis(self, n_states): 69 | """Test the discrimination analysis""" 70 | exp = MultiStateDiscrimination([self.qubit], n_states=n_states, backend=self.backend) 71 | 72 | exp_data = exp.run() 73 | 74 | fidelity = exp_data.analysis_results("fidelity", dataframe=True) 75 | 76 | self.assertGreaterEqual(fidelity.value.iloc[0], 0.93) 77 | 78 | # check that the discriminator differentiates n different states 79 | discrim_table = exp_data.analysis_results("discriminator_config", dataframe=True) 80 | discrim_lbls = discrim_table.value.iloc[0]["attributes"]["classes_"] 81 | self.assertEqual(len(discrim_lbls), n_states) 82 | 83 | def test_circuit_roundtrip_serializable(self): 84 | """Test round trip JSON serialization for the experiment circuits.""" 85 | exp = MultiStateDiscrimination([self.qubit], n_states=3, backend=self.backend) 86 | self.assertRoundTripSerializable(exp._transpiled_circuits()) 87 | -------------------------------------------------------------------------------- /qiskit_experiments/data_processing/mitigation/base_readout_mitigator.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Base class for readout error mitigation. 14 | """ 15 | 16 | from abc import ABC, abstractmethod 17 | from typing import Optional, List, Iterable, Tuple, Union, Callable 18 | 19 | import numpy as np 20 | 21 | from qiskit.result.counts import Counts 22 | from qiskit.result.distributions.quasi import QuasiDistribution 23 | 24 | 25 | class BaseReadoutMitigator(ABC): 26 | """Base readout error mitigator class.""" 27 | 28 | @abstractmethod 29 | def quasi_probabilities( 30 | self, 31 | data: Counts, 32 | qubits: Iterable[int] = None, 33 | clbits: Optional[List[int]] = None, 34 | shots: Optional[int] = None, 35 | ) -> QuasiDistribution: 36 | """Convert counts to a dictionary of quasi-probabilities 37 | 38 | Args: 39 | data: Counts to be mitigated. 40 | qubits: the physical qubits measured to obtain the counts clbits. 41 | If None these are assumed to be qubits [0, ..., N-1] 42 | for N-bit counts. 43 | clbits: Optional, marginalize counts to just these bits. 44 | shots: Optional, the total number of shots, if None shots will 45 | be calculated as the sum of all counts. 46 | 47 | Returns: 48 | QuasiDistribution: A dictionary containing pairs of [output, mean] where "output" 49 | is the key in the dictionaries, 50 | which is the length-N bitstring of a measured standard basis state, 51 | and "mean" is the mean of non-zero quasi-probability estimates. 52 | """ 53 | 54 | @abstractmethod 55 | def expectation_value( 56 | self, 57 | data: Counts, 58 | diagonal: Union[Callable, dict, str, np.ndarray], 59 | qubits: Iterable[int] = None, 60 | clbits: Optional[List[int]] = None, 61 | shots: Optional[int] = None, 62 | ) -> Tuple[float, float]: 63 | """Calculate the expectation value of a diagonal Hermitian operator. 64 | 65 | Args: 66 | data: Counts object to be mitigated. 67 | diagonal: the diagonal operator. This may either be specified 68 | as a string containing I,Z,0,1 characters, or as a 69 | real valued 1D array_like object supplying the full diagonal, 70 | or as a dictionary, or as Callable. 71 | qubits: the physical qubits measured to obtain the counts clbits. 72 | If None these are assumed to be qubits [0, ..., N-1] 73 | for N-bit counts. 74 | clbits: Optional, marginalize counts to just these bits. 75 | shots: Optional, the total number of shots, if None shots will 76 | be calculated as the sum of all counts. 77 | 78 | Returns: 79 | The mean and an upper bound of the standard deviation of operator 80 | expectation value calculated from the current counts. 81 | """ 82 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/analysis/tphi_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021, 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Tphi Analysis class. 14 | """ 15 | 16 | from typing import List, Tuple 17 | 18 | from qiskit_experiments.framework import ExperimentData, AnalysisResultData 19 | from qiskit_experiments.framework.composite.composite_analysis import CompositeAnalysis 20 | from qiskit_experiments.library.characterization.analysis import ( 21 | T1Analysis, 22 | T2HahnAnalysis, 23 | T2RamseyAnalysis, 24 | ) 25 | from qiskit_experiments.exceptions import QiskitError 26 | 27 | 28 | class TphiAnalysis(CompositeAnalysis): 29 | r"""A class to analyze :math:`T_\phi` experiments. 30 | 31 | # section: see_also 32 | * :py:class:`qiskit_experiments.library.characterization.analysis.T1Analysis` 33 | * :py:class:`qiskit_experiments.library.characterization.analysis.T2HahnAnalysis` 34 | * :py:class:`qiskit_experiments.library.characterization.analysis.T2RamseyAnalysis` 35 | 36 | """ 37 | 38 | def __init__(self, analyses=None): 39 | if analyses is None: 40 | analyses = [T1Analysis(), T2HahnAnalysis()] 41 | 42 | # Validate analyses kwarg 43 | if ( 44 | len(analyses) != 2 45 | or not isinstance(analyses[0], T1Analysis) 46 | or not isinstance(analyses[1], (T2RamseyAnalysis, T2HahnAnalysis)) 47 | ): 48 | raise QiskitError( 49 | "Invalid component analyses for Tphi, analyses must be a pair of " 50 | "T1Analysis and T2HahnAnalysis or T2RamseyAnalysis instances." 51 | ) 52 | super().__init__(analyses, flatten_results=True) 53 | 54 | def _run_analysis( 55 | self, experiment_data: ExperimentData 56 | ) -> Tuple[List[AnalysisResultData], List["matplotlib.figure.Figure"]]: 57 | r"""Run analysis for :math:`T_\phi` experiment. 58 | It invokes CompositeAnalysis._run_analysis that will invoke 59 | _run_analysis for the two sub-experiments. 60 | Based on the results, it computes the result for :math:`T_phi`. 61 | """ 62 | 63 | # Run composite analysis and extract T1 and T2 results 64 | analysis_results, figures = super()._run_analysis(experiment_data) 65 | t1_result = next(filter(lambda res: res.name == "T1", analysis_results)) 66 | t2_result = next(filter(lambda res: res.name in {"T2star", "T2"}, analysis_results)) 67 | 68 | # Calculate Tphi from T1 and T2 69 | tphi = 1 / (1 / t2_result.value - 1 / (2 * t1_result.value)) 70 | quality_tphi = ( 71 | "good" if (t1_result.quality == "good" and t2_result.quality == "good") else "bad" 72 | ) 73 | tphi_result = AnalysisResultData( 74 | name="T_phi", 75 | value=tphi, 76 | chisq=None, 77 | quality=quality_tphi, 78 | extra={"unit": "s"}, 79 | ) 80 | 81 | # Return combined results 82 | analysis_results = [tphi_result] + analysis_results 83 | return analysis_results, figures 84 | -------------------------------------------------------------------------------- /docs/_ext/autoref.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Helper directive to generate reference in convenient form. 15 | """ 16 | import arxiv 17 | 18 | from docutils import nodes 19 | from docutils.parsers.rst import Directive 20 | from sphinx.application import Sphinx 21 | 22 | 23 | class WebSite(Directive): 24 | """A custom helper directive for showing website link. 25 | 26 | This can be used, for example, 27 | 28 | .. code-block:: 29 | 30 | .. ref_website:: qiskit-experiments, https://github.com/Qiskit-Community/qiskit-experiments 31 | 32 | """ 33 | 34 | required_arguments = 1 35 | optional_arguments = 0 36 | final_argument_whitespace = True 37 | 38 | def run(self): 39 | try: 40 | name, url = self.arguments[0].split(",") 41 | except ValueError: 42 | raise ValueError( 43 | f"{self.arguments[0]} is invalid website directive format. " 44 | "Name and URL should be separated by a single comma." 45 | ) 46 | 47 | link_name = nodes.paragraph(text=f"{name} ") 48 | link_name += nodes.reference(text="(open)", refuri=url) 49 | 50 | return [link_name] 51 | 52 | 53 | class Arxiv(Directive): 54 | """A custom helper directive for generating journal information from arXiv id. 55 | 56 | This directive takes two arguments 57 | 58 | - Arbitrary reference name (no white space should be included) 59 | 60 | - arXiv ID 61 | 62 | This can be used, for example, 63 | 64 | .. code-block:: 65 | 66 | .. ref_arxiv:: qasm3-paper 2104.14722 67 | 68 | If an article is not found, no journal information will be shown. 69 | 70 | """ 71 | 72 | required_arguments = 2 73 | optional_arguments = 0 74 | final_argument_whitespace = False 75 | 76 | def run(self): 77 | 78 | # search arXiv database 79 | try: 80 | search = arxiv.Search(id_list=[self.arguments[1]]) 81 | paper = next(search.results()) 82 | except Exception: 83 | return [] 84 | 85 | # generate journal link nodes 86 | ret_node = nodes.paragraph() 87 | 88 | journal = "" 89 | if paper.journal_ref: 90 | journal += f", {paper.journal_ref}, " 91 | if paper.doi: 92 | journal += f"doi: {paper.doi}" 93 | 94 | ret_node += nodes.Text(f"[{self.arguments[0]}] ") 95 | ret_node += nodes.Text(", ".join([author.name for author in paper.authors]) + ", ") 96 | ret_node += nodes.emphasis(text=f"{paper.title}") 97 | if journal: 98 | ret_node += nodes.Text(journal) 99 | ret_node += nodes.Text(" ") 100 | ret_node += nodes.reference(text="(open)", refuri=paper.entry_id) 101 | 102 | return [ret_node] 103 | 104 | 105 | def setup(app: Sphinx): 106 | app.add_directive("ref_arxiv", Arxiv) 107 | app.add_directive("ref_website", WebSite) 108 | 109 | return {"parallel_read_safe": True} 110 | -------------------------------------------------------------------------------- /test/visualization/test_plotter.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2022. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Test integration of plotter. 14 | """ 15 | 16 | from copy import deepcopy 17 | from test.base import QiskitExperimentsTestCase 18 | 19 | from .mock_drawer import MockDrawer 20 | from .mock_plotter import MockPlotter 21 | 22 | 23 | class TestPlotter(QiskitExperimentsTestCase): 24 | """Test the generic plotter interface.""" 25 | 26 | def test_warn_unknown_data_key(self): 27 | """Test that setting an unknown data-key raises a warning.""" 28 | plotter = MockPlotter(MockDrawer()) 29 | 30 | # TODO: Add check for no-warnings. assertNoWarns only available from Python 3.10+ 31 | 32 | # An unknown data-key must raise a warning if it is used to set series data. 33 | with self.assertWarns(UserWarning): 34 | plotter.set_series_data("dummy_series", unknown_data_key=[0, 1, 2]) 35 | 36 | def test_series_data_end_to_end(self): 37 | """Test end-to-end for series data setting and retrieving.""" 38 | plotter = MockPlotter(MockDrawer()) 39 | 40 | series_data = { 41 | "seriesA": { 42 | "x": 0, 43 | "y": "1", 44 | "z": [2], 45 | }, 46 | "seriesB": { 47 | "x": 1, 48 | "y": 0.5, 49 | }, 50 | } 51 | unexpected_data = ["a", True, 0] 52 | expected_series_data = deepcopy(series_data) 53 | expected_series_data["seriesA"]["unexpected_data"] = unexpected_data 54 | 55 | for series, data in series_data.items(): 56 | plotter.set_series_data(series, **data) 57 | 58 | with self.assertWarns(UserWarning): 59 | plotter.set_series_data("seriesA", unexpected_data=unexpected_data) 60 | 61 | for series, data in expected_series_data.items(): 62 | self.assertTrue(series in plotter.series) 63 | self.assertTrue(plotter.data_exists_for(series, list(data.keys()))) 64 | for data_key, value in data.items(): 65 | # Must index [0] for `data_for` as it returns a tuple. 66 | self.assertEqual(value, plotter.data_for(series, data_key)[0]) 67 | 68 | def test_supplementary_data_end_to_end(self): 69 | """Test end-to-end for figure data setting and retrieval.""" 70 | plotter = MockPlotter(MockDrawer()) 71 | 72 | expected_supplementary_data = { 73 | "report_text": "Lorem ipsum", 74 | "supplementary_data_key": 3e9, 75 | } 76 | 77 | plotter.set_supplementary_data(**expected_supplementary_data) 78 | 79 | # Check if figure data has been stored and can be retrieved 80 | for key, expected_value in expected_supplementary_data.items(): 81 | actual_value = plotter.supplementary_data[key] 82 | self.assertEqual( 83 | expected_value, 84 | actual_value, 85 | msg=f"Actual figure data value for {key} data-key is not as expected: {actual_value} " 86 | f"(actual) vs {expected_value} (expected)", 87 | ) 88 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "setuptools_scm"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "qiskit-experiments" 7 | dynamic = ["version"] 8 | description = "Software for developing quantum computing programs" 9 | dependencies = [ 10 | "numpy>=1.17", 11 | "scipy>=1.4", 12 | "qiskit>=1.3", 13 | "qiskit-ibm-experiment>=0.4.6", 14 | "qiskit_ibm_runtime>=0.34.0", 15 | "matplotlib>=3.4", 16 | "uncertainties", 17 | "lmfit", 18 | "rustworkx", 19 | "pandas>=1.1.5", 20 | "packaging", 21 | ] 22 | keywords = ["qiskit sdk quantum"] 23 | readme = "README.md" 24 | authors = [ 25 | {name = "Qiskit Development Team", email = "qiskit@us.ibm.com"}, 26 | ] 27 | classifiers = [ 28 | "Environment :: Console", 29 | "Intended Audience :: Developers", 30 | "Intended Audience :: Science/Research", 31 | "License :: OSI Approved :: Apache Software License", 32 | "Operating System :: MacOS", 33 | "Operating System :: Microsoft :: Windows", 34 | "Operating System :: POSIX :: Linux", 35 | "Programming Language :: Python :: 3 :: Only", 36 | "Programming Language :: Python :: 3.10", 37 | "Programming Language :: Python :: 3.11", 38 | "Programming Language :: Python :: 3.12", 39 | "Programming Language :: Python :: 3.13", 40 | "Programming Language :: Python :: 3.9", 41 | "Topic :: Scientific/Engineering", 42 | ] 43 | requires-python = ">=3.9" 44 | license = {text = "Apache 2.0"} 45 | 46 | [project.urls] 47 | Homepage = "https://github.com/Qiskit-Community/qiskit-experiments" 48 | "Bug Tracker" = "https://github.com/Qiskit-Community/qiskit-experiments/issues" 49 | Documentation = "https://qiskit-community.github.io/qiskit-experiments" 50 | "Source Code" = "https://github.com/Qiskit-Community/qiskit-experiments" 51 | 52 | [project.optional-dependencies] 53 | extras = [ 54 | "cvxpy>=1.3.2", # for tomography 55 | "scikit-learn", # for discriminators 56 | "qiskit-aer>=0.13.2", 57 | ] 58 | 59 | [project.entry-points."qiskit.synthesis"] 60 | "clifford.rb_default" = "qiskit_experiments.library.randomized_benchmarking.clifford_synthesis:RBDefaultCliffordSynthesis" 61 | 62 | [dependency-groups] 63 | formatting = ["black~=22.0"] 64 | devbase = [] 65 | testing = [ 66 | {include-group = "devbase"}, 67 | # Test runner tools 68 | "coverage>=5.5", 69 | "ddt>=1.6.0", 70 | "fixtures", 71 | "stestr", 72 | "testtools", 73 | # Packages only used in tests 74 | "multimethod", 75 | ] 76 | docs = [ 77 | {include-group = "devbase"}, 78 | # Documentation tools 79 | "arxiv", 80 | "jupyter-sphinx>=0.4.0", 81 | "nbsphinx", 82 | "pylatexenc", 83 | "qiskit-sphinx-theme", 84 | "reno>=4.1.0", 85 | "sphinx>=6.2.1", 86 | "sphinx-copybutton", 87 | "sphinx-design", 88 | "sphinx-remove-toctrees", 89 | ] 90 | linting = [ 91 | # Linters 92 | "pylint~=3.3.1", 93 | "astroid~=3.3.4", # Must be kept aligned to what pylint wants 94 | # Test dependencies needed because the test files are linted 95 | {include-group = "testing"}, 96 | ] 97 | dev = [ 98 | {include-group = "docs"}, 99 | {include-group = "formatting"}, 100 | {include-group = "linting"}, 101 | {include-group = "testing"}, 102 | ] 103 | 104 | [tool.setuptools.packages.find] 105 | include = ["qiskit_experiments*"] 106 | 107 | [tool.setuptools.dynamic] 108 | version = {file = ["qiskit_experiments/VERSION.txt"]} 109 | 110 | [tool.black] 111 | line-length = 100 112 | target-version = ['py39'] 113 | -------------------------------------------------------------------------------- /qiskit_experiments/library/characterization/analysis/readout_angle_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | """ 13 | Readout Angle Analysis class. 14 | """ 15 | 16 | from typing import List, Optional 17 | import numpy as np 18 | 19 | from qiskit_experiments.framework import BaseAnalysis, AnalysisResultData, Options 20 | from qiskit_experiments.framework.matplotlib import get_non_gui_ax 21 | 22 | 23 | class ReadoutAngleAnalysis(BaseAnalysis): 24 | """ 25 | A class to analyze readout angle experiments 26 | """ 27 | 28 | @classmethod 29 | def _default_options(cls) -> Options: 30 | """Return default analysis options. 31 | 32 | Analysis Options: 33 | plot (bool): Set ``True`` to create figure for fit result. 34 | ax (AxesSubplot): Optional. A matplotlib axis object to draw. 35 | """ 36 | options = super()._default_options() 37 | options.plot = True 38 | options.ax = None 39 | return options 40 | 41 | def _run_analysis(self, experiment_data): 42 | angles = [] 43 | radii = [] 44 | centers = [] 45 | for i in range(2): 46 | center = complex(*experiment_data.data(i)["memory"][0]) 47 | angles.append(np.angle(center)) 48 | radii.append(np.absolute(center)) 49 | centers.append(center) 50 | 51 | angle = (angles[0] + angles[1]) / 2 52 | if (np.abs(angles[0] - angles[1])) % (2 * np.pi) > np.pi: 53 | angle += np.pi 54 | 55 | extra_results = {} 56 | extra_results["readout_angle_0"] = angles[0] 57 | extra_results["readout_angle_1"] = angles[1] 58 | extra_results["readout_radius_0"] = radii[0] 59 | extra_results["readout_radius_1"] = radii[1] 60 | 61 | analysis_results = [ 62 | AnalysisResultData(name="readout_angle", value=angle, extra=extra_results) 63 | ] 64 | 65 | if self.options.plot: 66 | ax = self._format_plot(centers, ax=self.options.ax) 67 | figures = [ax.get_figure()] 68 | else: 69 | figures = None 70 | 71 | return analysis_results, figures 72 | 73 | @staticmethod 74 | def _format_plot(centers: List[complex], ax: Optional["matplotlib.pyplot.AxesSubplot"] = None): 75 | """Format the readout_angle plot 76 | 77 | Args: 78 | centers: the two centers of the level 1 measurements for 0 and for 1. 79 | ax: matplotlib axis to add plot to. 80 | 81 | Returns: 82 | AxesSubPlot: the matplotlib axes containing the plot. 83 | """ 84 | largest_extent = ( 85 | np.max([np.max(np.abs(np.real(centers))), np.max(np.abs(np.imag(centers)))]) * 1.1 86 | ) 87 | 88 | ax = get_non_gui_ax() 89 | ax.plot(np.real(centers[0]), np.imag(centers[0]), "ro", markersize=24) 90 | ax.plot(np.real(centers[1]), np.imag(centers[1]), "bo", markersize=24) 91 | ax.set_xlim([-largest_extent, largest_extent]) 92 | ax.set_ylim([-largest_extent, largest_extent]) 93 | ax.set_xlabel("I [arb.]") 94 | ax.set_ylabel("Q [arb.]") 95 | ax.set_title("Centroid Positions") 96 | ax.legend(["0", "1"]) 97 | return ax 98 | -------------------------------------------------------------------------------- /docs/_ext/autodoc_experiment.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Documentation extension for experiment class. 15 | """ 16 | 17 | from typing import Any 18 | 19 | from docs._ext.custom_styles.styles import ExperimentDocstring 20 | from docs._ext.custom_styles.option_parser import process_default_options 21 | from qiskit.exceptions import QiskitError 22 | from qiskit_experiments.framework.base_experiment import BaseExperiment 23 | from sphinx.application import Sphinx 24 | from sphinx.ext.autodoc import ClassDocumenter 25 | 26 | 27 | class ExperimentDocumenter(ClassDocumenter): 28 | """Sphinx extension for the custom documentation of the standard experiment class.""" 29 | 30 | objtype = "experiment" 31 | directivetype = "class" 32 | priority = 10 + ClassDocumenter.priority 33 | option_spec = dict(ClassDocumenter.option_spec) 34 | 35 | @classmethod 36 | def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any) -> bool: 37 | return isinstance(member, BaseExperiment) 38 | 39 | def add_content(self, more_content: Any, no_docstring: bool = False) -> None: 40 | sourcename = self.get_sourcename() 41 | 42 | try: 43 | if self.get_doc() is not None: 44 | class_doc, init_doc = self.get_doc() 45 | else: 46 | return 47 | except ValueError: 48 | raise QiskitError( 49 | f"Documentation of {self.fullname} doesn't match with the expected format." 50 | "Please run sphinx build without using the experiment template." 51 | ) 52 | 53 | option_doc = process_default_options( 54 | current_class=self.object, 55 | default_option_method="_default_experiment_options", 56 | section_repr="Experiment Options:", 57 | app=self.env.app, 58 | options=self.options, 59 | config=self.env.app.config, 60 | indent=self.content_indent, 61 | ) 62 | init_doc = list(self.process_doc([init_doc])) 63 | 64 | # format experiment documentation into the experiment style 65 | class_doc_parser = ExperimentDocstring( 66 | target_cls=self.object, 67 | docstring_lines=class_doc, 68 | config=self.env.app.config, 69 | indent=self.content_indent, 70 | experiment_opts=option_doc, 71 | init=init_doc, 72 | ) 73 | 74 | # write introduction 75 | custom_docs = class_doc_parser.generate_class_docs() 76 | for i, line in enumerate(self.process_doc(custom_docs)): 77 | self.add_line(line, sourcename, i) 78 | self.add_line("", sourcename) 79 | 80 | # method and attributes 81 | if more_content: 82 | for line, src in zip(more_content.data, more_content.items): 83 | self.add_line(line, src[0], src[1]) 84 | 85 | 86 | def setup(app: Sphinx): 87 | existing_documenter = app.registry.documenters.get(ExperimentDocumenter.objtype) 88 | if existing_documenter is None or not issubclass(existing_documenter, ExperimentDocumenter): 89 | app.add_autodocumenter(ExperimentDocumenter, override=True) 90 | return {"parallel_read_safe": True} 91 | -------------------------------------------------------------------------------- /qiskit_experiments/framework/containers/figure_data.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2023. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Container of experiment data components.""" 14 | 15 | from __future__ import annotations 16 | 17 | import copy 18 | import io 19 | from typing import Dict, Optional, Union, Any 20 | 21 | from matplotlib.figure import Figure as MatplotlibFigure 22 | 23 | 24 | class FigureData: 25 | """A plot data container. 26 | 27 | .. note:: 28 | Raw figure data can be accessed through the :attr:`.FigureData.figure` attribute. 29 | 30 | """ 31 | 32 | def __init__( 33 | self, 34 | figure, 35 | name: str | None = None, 36 | metadata: dict[str, Any] | None = None, 37 | ): 38 | """Creates a new figure data object. 39 | 40 | Args: 41 | figure: The raw figure itself. Can be SVG or matplotlib.Figure. 42 | name: The name of the figure. 43 | metadata: Any metadata to be stored with the figure. 44 | """ 45 | self.figure = figure 46 | self._name = name 47 | self.metadata = metadata or {} 48 | 49 | def __eq__(self, value): 50 | """Test equality between two instances of FigureData.""" 51 | return vars(self) == vars(value) 52 | 53 | # name is read only 54 | @property 55 | def name(self) -> str: 56 | """The name of the figure""" 57 | return self._name 58 | 59 | @property 60 | def metadata(self) -> dict: 61 | """The metadata dictionary stored with the figure""" 62 | return self._metadata 63 | 64 | @metadata.setter 65 | def metadata(self, new_metadata: dict): 66 | """Set the metadata to new value; must be a dictionary""" 67 | if not isinstance(new_metadata, dict): 68 | raise ValueError("figure metadata must be a dictionary") 69 | self._metadata = new_metadata 70 | 71 | def copy(self, new_name: Optional[str] = None): 72 | """Creates a copy of the figure data""" 73 | name = new_name or self.name 74 | return FigureData(figure=self.figure, name=name, metadata=copy.deepcopy(self.metadata)) 75 | 76 | def __json_encode__(self) -> Dict[str, Any]: 77 | """Return the json representation of the figure data""" 78 | return {"figure": self.figure, "name": self.name, "metadata": self.metadata} 79 | 80 | @classmethod 81 | def __json_decode__(cls, args: Dict[str, Any]) -> "FigureData": 82 | """Initialize a figure data from the json representation""" 83 | return cls(**args) 84 | 85 | def _repr_png_(self): 86 | if isinstance(self.figure, MatplotlibFigure): 87 | b = io.BytesIO() 88 | self.figure.savefig(b, format="png", bbox_inches="tight") 89 | png = b.getvalue() 90 | return png 91 | else: 92 | return None 93 | 94 | def _repr_svg_(self): 95 | if isinstance(self.figure, str): 96 | return self.figure 97 | if isinstance(self.figure, bytes): 98 | return self.figure.decode("utf-8") 99 | return None 100 | 101 | 102 | FigureType = Union[str, bytes, MatplotlibFigure, FigureData] 103 | -------------------------------------------------------------------------------- /docs/_ext/autodoc_analysis.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Documentation extension for analysis class. 15 | """ 16 | 17 | from typing import Any 18 | 19 | from docs._ext.custom_styles.styles import AnalysisDocstring 20 | from docs._ext.custom_styles.option_parser import process_default_options 21 | from qiskit.exceptions import QiskitError 22 | from qiskit_experiments.framework.base_analysis import BaseAnalysis 23 | from sphinx.application import Sphinx 24 | from sphinx.ext.autodoc import ClassDocumenter 25 | 26 | 27 | class AnalysisDocumenter(ClassDocumenter): 28 | """Sphinx extension for the custom documentation of the standard analysis class.""" 29 | 30 | objtype = "analysis" 31 | directivetype = "class" 32 | priority = 10 + ClassDocumenter.priority 33 | option_spec = dict(ClassDocumenter.option_spec) 34 | 35 | @classmethod 36 | def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any) -> bool: 37 | return isinstance(member, BaseAnalysis) 38 | 39 | def add_content(self, more_content: Any, no_docstring: bool = False) -> None: 40 | sourcename = self.get_sourcename() 41 | 42 | # analysis class doesn't have explicit init method. 43 | try: 44 | if self.get_doc() is not None: 45 | class_doc, init_doc = self.get_doc() 46 | else: 47 | return 48 | except ValueError: 49 | raise QiskitError( 50 | f"Documentation of {self.fullname} doesn't match with the expected format." 51 | "Please run sphinx build without using the experiment template." 52 | ) 53 | 54 | option_doc = process_default_options( 55 | current_class=self.object, 56 | default_option_method="_default_options", 57 | section_repr="Analysis Options:", 58 | app=self.env.app, 59 | options=self.options, 60 | config=self.env.app.config, 61 | indent=self.content_indent, 62 | ) 63 | init_doc = list(self.process_doc([init_doc])) 64 | 65 | # format experiment documentation into the analysis style 66 | class_doc_parser = AnalysisDocstring( 67 | target_cls=self.object, 68 | docstring_lines=class_doc, 69 | config=self.env.app.config, 70 | indent=self.content_indent, 71 | analysis_opts=option_doc, 72 | init=init_doc, 73 | ) 74 | 75 | # write introduction 76 | custom_docs = class_doc_parser.generate_class_docs() 77 | for i, line in enumerate(self.process_doc(custom_docs)): 78 | self.add_line(line, sourcename, i) 79 | self.add_line("", sourcename) 80 | 81 | # method and attributes 82 | if more_content: 83 | for line, src in zip(more_content.data, more_content.items): 84 | self.add_line(line, src[0], src[1]) 85 | 86 | 87 | def setup(app: Sphinx): 88 | existing_documenter = app.registry.documenters.get(AnalysisDocumenter.objtype) 89 | if existing_documenter is None or not issubclass(existing_documenter, AnalysisDocumenter): 90 | app.add_autodocumenter(AnalysisDocumenter, override=True) 91 | return {"parallel_read_safe": True} 92 | --------------------------------------------------------------------------------