├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── format.yml ├── .gitignore ├── LICENSE ├── README.md ├── algorithms └── quantum_opt_rl │ ├── QCO.ipynb │ ├── gym-examples │ ├── .pre-commit-config.yaml │ ├── README.md │ ├── gym_examples │ │ ├── __init__.py │ │ ├── envs │ │ │ ├── __init__.py │ │ │ └── quantum_env.py │ │ └── wrappers │ │ │ ├── __init__.py │ │ │ ├── clip_reward.py │ │ │ ├── discrete_actions.py │ │ │ ├── reacher_weighted_reward.py │ │ │ └── relative_position.py │ └── setup.py │ └── images │ ├── input_tensor.png │ └── mario.png ├── pyqasm ├── deutsch_josza_unroll.ipynb ├── qasm_processing.ipynb └── qasm_unroll.ipynb ├── qbraid_lab ├── bloqade │ ├── README.md │ └── assets │ │ ├── Step0.1.png │ │ ├── Step0.2.png │ │ ├── Step1.png │ │ └── Step2.png ├── fire_opal │ └── get-started.ipynb ├── gpu │ ├── cirq_VQE_cuQuantum.ipynb │ └── lightning_gpu_benchmark.ipynb └── quantum_jobs │ ├── aws_iqm_quantum_jobs.ipynb │ ├── aws_oqc_quantum_jobs.ipynb │ └── aws_quantum_jobs.ipynb ├── qbraid_qir ├── autoqasm_deutsch_jozsa.ipynb ├── microsoft_resource_estimatation.ipynb ├── qbraid-autoqasm-poc.ipynb ├── qbraid_transpiler_braket_to_qir.ipynb └── rigetti_qvm_sim.ipynb └── qbraid_sdk ├── README.md ├── aws_sim_qiskit_bernstein_vazirani.ipynb ├── bell_circuit_examples.ipynb ├── ibm_batch_jobs_grovers.ipynb ├── ibm_quantum_jobs_with_runtime.ipynb ├── img └── ibm_api_token.png ├── legacy └── qbraid_sdk_devices_and_jobs.ipynb ├── qbraid_provider_ionq_devices.ipynb ├── qbraid_qir_sim_batch_jobs.ipynb ├── qbraid_runtime_bloqade_aquila.ipynb ├── qbraid_runtime_ionq_provider.ipynb ├── qbraid_runtime_ionq_qiskit_qpe_native_gates.ipynb ├── qbraid_runtime_nec.ipynb ├── qbraid_runtime_quera_qasm_simulator.ipynb ├── qbraid_sdk_providers.ipynb ├── qbraid_sdk_transpiler.ipynb ├── qbraid_sdk_transpiler_braket_qiskit.ipynb ├── qbraid_sdk_transpiler_cirq_stim.ipynb └── qbraid_visualization.ipynb /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: bug 6 | 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **System information (please complete the following information as applicable):** 26 | - Package Versions [e.g. qbraid==0.8.4] 27 | - Working Environment: [e.g. Local, qBraid Lab Instances] 28 | - Browser [e.g. chrome, safari] 29 | - Operating System [e.g. Ubuntu 20.04] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Notebook request 3 | about: Suggest a new notebook, update, or topic for this collection 4 | title: Example notebook 5 | labels: enhancement 6 | 7 | --- 8 | 9 | **Outline the Notebook Example or Topic Requested** 10 | Describe the topic or type of example notebook you’d like added to the collection. Include any specific goals, concepts, or tools (e.g., a feature of qBraid-QIR, a use case for qBraid-SDK, or specific quantum algorithms) that should be covered. 11 | 12 | **Additional context** 13 | Add any other details, context, references that would be helpful in developing the requested example notebook. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Summary of changes -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Format 2 | 3 | on: 4 | pull_request: 5 | branches: ['main'] 6 | types: [opened, reopened, ready_for_review, synchronize] 7 | workflow_dispatch: 8 | 9 | jobs: 10 | check: 11 | if: github.event.pull_request.draft == false 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python-version: ["3.11"] 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v5 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | - name: Install dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install "black[jupyter]" 26 | - name: Check formating with black 27 | run: | 28 | black algorithms qbraid_lab qbraid_sdk qbraid_qir --line-length=100 --check -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | ./DS_Store 132 | **/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # qBraid Demos and Tutorials 3 | 4 | Welcome to the qBraid Demos Repository! This repository contains a collection of Jupyter Notebooks showcasing how to use **qBraid's open-source SDKs** for quantum computing. It includes hands-on examples that demonstrate the integration of various tools with **qBraid-Lab**, making it easier to run quantum computing experiments seamlessly in the cloud. 5 | 6 | [](https://account.qbraid.com?gitHubUrl=https://github.com/qBraid/qbraid-lab-demo.git&utm_source=github&redirectUrl=README.md) 7 | 8 | ## Contents 9 | 10 | This repository features tutorials and examples for the following: 11 | 12 | - [**qBraid-SDK**](https://docs.qbraid.com/sdk/): Learn how to interact with quantum devices using the qBraid Runtime framework. 13 | - [**qBraid-QIR**](https://docs.qbraid.com/qir/): Explore qBraid's Quantum Intermediate Representation (QIR) interface using familiar frameworks like OpenQASM 3 and Cirq. 14 | - [**PyQASM**](https://docs.qbraid.com/pyqasm/): Discover new ways to integrate with OpenQASM, featuring methods for program validation, compilation, inlining, and unrolling. 15 | - [**qBraid-CLI**](https://docs.qbraid.com/cli/): Understand how to manage quantum jobs and resources using qBraid's Command Line Interface. 16 | - [**qBraid-Lab**](https://docs.qbraid.com/lab/) Integration: 17 | - [**Quantum Jobs**](https://docs.qbraid.com/lab/user-guide/quantum-jobs): Learn how to submit and manage quantum jobs in qBraid Lab. 18 | - [**GPUs**](https://docs.qbraid.com/lab/user-guide/gpus): Learn how to accelerate your quantum simulations using GPUs available through qBraid Lab. 19 | 20 | ## Documentation and Resources 21 | 22 | For more information on qBraid and its tools, check out: 23 | 24 | - **qBraid Platform Documentation**: Comprehensive user guides and resources at [docs.qbraid.com](https://docs.qbraid.com/). 25 | - **qBraid Software API Reference**: Detailed API documentation for the qBraid-SDK at [sdk.qbraid.com](https://sdk.qbraid.com/). 26 | - **qBraid GitHub Community**: Join the discussion and contribute at [GitHub Community Page](https://github.com/qBraid/community). 27 | 28 | ## Contribution 29 | 30 | Contributions to this repository are welcome! If you encounter any issues or would like to contribute improvements or new examples, please open an issue or submit a pull request. 31 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/python/black 4 | rev: 22.3.0 5 | hooks: 6 | - id: black 7 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/README.md: -------------------------------------------------------------------------------- 1 | This repository is no longer maintained, as Gym is not longer maintained and all future maintenance of it will occur in the replacing [Gymnasium](https://github.com/Farama-Foundation/Gymnasium) library. You can contribute Gymnasium examples to the Gymnasium repository and docs directly if you would like to. If you'd like to learn more about the transition from Gym to Gymnasium, you can read more about it [here](https://farama.org/Announcing-The-Farama-Foundation). 2 | 3 | # Gym Examples 4 | Some simple examples of Gym environments and wrappers. 5 | For some explanations of these examples, see the [Gym documentation](https://gymnasium.farama.org). 6 | 7 | ### Environments 8 | This repository hosts the examples that are shown [on the environment creation documentation](https://gymnasium.farama.org/tutorials/environment_creation/). 9 | - `GridWorldEnv`: Simplistic implementation of gridworld environment 10 | 11 | ### Wrappers 12 | This repository hosts the examples that are shown [on wrapper documentation](https://gymnasium.farama.org/api/wrappers/). 13 | - `ClipReward`: A `RewardWrapper` that clips immediate rewards to a valid range 14 | - `DiscreteActions`: An `ActionWrapper` that restricts the action space to a finite subset 15 | - `RelativePosition`: An `ObservationWrapper` that computes the relative position between an agent and a target 16 | - `ReacherRewardWrapper`: Allow us to weight the reward terms for the reacher environment 17 | 18 | ### Contributing 19 | If you would like to contribute, follow these steps: 20 | - Fork this repository 21 | - Clone your fork 22 | - Set up pre-commit via `pre-commit install` 23 | 24 | PRs may require accompanying PRs in [the documentation repo](https://github.com/Farama-Foundation/Gymnasium/tree/main/docs). 25 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/__init__.py: -------------------------------------------------------------------------------- 1 | from gymnasium.envs.registration import register 2 | 3 | register( 4 | id="gym_examples/Quantum-v0", 5 | entry_point="gym_examples.envs:QuantumEnv", 6 | ) 7 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/envs/__init__.py: -------------------------------------------------------------------------------- 1 | from gym_examples.envs.quantum_env import QuantumEnv 2 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/envs/quantum_env.py: -------------------------------------------------------------------------------- 1 | import string 2 | import time 3 | from collections import OrderedDict 4 | from typing import List, Optional, Tuple 5 | 6 | import numpy as np 7 | import torch 8 | from gymnasium import Env 9 | from gymnasium.spaces import Box, Discrete 10 | from qiskit import QuantumCircuit 11 | from qiskit.circuit.library import iSwapGate, standard_gates 12 | from qiskit.circuit.random import random_circuit 13 | from qiskit.converters import circuit_to_dag 14 | from qiskit.quantum_info import Statevector 15 | from qiskit.transpiler import PassManager 16 | from qiskit.transpiler.passes import CommutativeCancellation # Unroller, 17 | from qiskit.transpiler.passes import ( 18 | CommutativeInverseCancellation, 19 | CXCancellation, 20 | Optimize1qGatesDecomposition, 21 | UnitarySynthesis, 22 | ) 23 | from qiskit.visualization import dag_drawer 24 | from torch.utils.tensorboard import SummaryWriter 25 | 26 | 27 | class QuantumEnv(Env): 28 | def __init__( 29 | self, 30 | basis=["cx", "u3", "u", "id"], 31 | num_qubits=12, 32 | actions=None, 33 | render=False, 34 | min_depth=500, 35 | max_depth=600, 36 | ): 37 | """Initializes a quantum environment 38 | 39 | Args: 40 | basis (list, optional): The basis gates to decompose to. Defaults to ["cx", "u3", "u", "id"]. 41 | num_qubits (int, optional) The number of qubits in the circuit. Defaults to 12. 42 | actions (_type_, optional): The dict of otpimization that can be performed. Defaults to None. 43 | render (bool, optional): Boolean to set render. Defaults to False. 44 | min_depth (int, optional): Minimum depth in random circuit. Defaults to 30. 45 | max_depth (int, optional): Maximum depth in random circuit. Defaults to 90. 46 | """ 47 | 48 | self.device = "cpu" if not torch.has_cuda else "cuda:0" 49 | self.basis = basis 50 | self.num_qubits = num_qubits 51 | self.actions = ( 52 | { 53 | 0: Optimize1qGatesDecomposition(), 54 | 1: CommutativeInverseCancellation(), 55 | 2: CommutativeCancellation(basis_gates=basis), 56 | 3: CXCancellation(), 57 | 4: UnitarySynthesis(basis_gates=basis), 58 | } 59 | if actions is None 60 | else actions 61 | ) 62 | self.num_actions = len(self.actions.keys()) 63 | self.min_depth = min_depth 64 | self.max_depth = max_depth 65 | self.circuit = self.create_random_circuit() # Starting circuit 66 | self.counts_ops = sum(list(self.circuit.count_ops().values())) 67 | self.qiskit_gates = self.get_qiskit_gates() 68 | self.state = self._create_tensor_from_circuit(self.circuit) 69 | self.observation_space = Box( 70 | low=0, 71 | high=len(self.qiskit_gates), 72 | shape=(self.num_qubits, len(self.qiskit_gates), 5), 73 | dtype=np.float32, 74 | ) 75 | self.action_space = Discrete(self.num_actions) 76 | self.alpha = 1 # Gate count weight 77 | self.beta = 0.2 # Depth weight 78 | self.circuit_score_array = [] 79 | self.render_true = render 80 | 81 | def create_random_circuit(self, seed: Optional[int] = None) -> QuantumCircuit: 82 | """Creates a random circuit 83 | 84 | Args: 85 | seed (int, optional): Seed for random circuit. Defaults to None. 86 | 87 | Returns: 88 | QuantumCircuit: A random quantum circuit 89 | """ 90 | if seed is not None: 91 | np.random.seed(seed) 92 | qc_1 = random_circuit(self.num_qubits, np.random.randint(self.min_depth, self.max_depth)) 93 | qc_2 = random_circuit(self.num_qubits, np.random.randint(self.min_depth, self.max_depth)) 94 | 95 | qc_1.compose(qc_2, inplace=True) 96 | 97 | return qc_1 98 | 99 | def _generate_params(self, varnames: List[str], seed: Optional[int] = None): 100 | """Returns a dictionary of random parameters for a given list of variable names""" 101 | if seed is not None: 102 | np.random.seed(seed) 103 | params = { 104 | ra: np.random.rand() * 2 * np.pi 105 | for ra in ["theta", "phi", "lam", "gamma"] 106 | if ra in varnames 107 | } 108 | if "num_ctrl_qubits" in varnames: 109 | params["num_ctrl_qubits"] = np.random.randint(1, 7) 110 | if "phase" in varnames: 111 | params["phase"] = np.random.rand() * 2 * np.pi 112 | return params 113 | 114 | def _create_tensor_from_circuit(self, circuit: QuantumCircuit) -> torch.Tensor: 115 | """Returns a tensor representation of a quantum circuit 116 | The matrix consists of ("num_qubits, all_gates, num_gates, 2) 117 | """ 118 | 119 | # The tensor is of shape (num_qubits, num_gates, num_params) 120 | circuit_tensor = torch.zeros((circuit.num_qubits, len(self.qiskit_gates), self.num_actions)) 121 | 122 | for _, op in enumerate(circuit): 123 | name = op.operation.name 124 | # TODO Add barrier index similar to moments in cirq. 125 | qubits = [qubit.index for qubit in list(op.qubits)] 126 | # Get the index of the gate 127 | gate_index = self.qiskit_gates.keys() 128 | gate_index = list(gate_index).index(name) 129 | # Add operation parameters 130 | if op.operation.params: 131 | for idx, param in enumerate(op.operation.params): 132 | circuit_tensor[qubits, gate_index, 1 + idx] = param 133 | circuit_tensor[qubits, gate_index, 0] += 1 134 | return circuit_tensor 135 | 136 | def get_qiskit_gates(self, seed: Optional[int] = None): 137 | """Returns a dictionary of all qiskit gates with random parameters""" 138 | qiskit_gates = { 139 | attr: None for attr in dir(standard_gates) if attr[0] in string.ascii_uppercase 140 | } 141 | 142 | # Add random parameters to gates for circuit generation 143 | for gate in qiskit_gates: 144 | varnames = [ 145 | v 146 | for v in getattr(standard_gates, gate).__init__.__code__.co_varnames 147 | if v != "self" 148 | ] 149 | params = self._generate_params(varnames, seed=seed) 150 | qiskit_gates[gate] = getattr(standard_gates, gate)(**params) 151 | qiskit_gates = OrderedDict({v.name: v for _, v in qiskit_gates.items() if v is not None}) 152 | # Add iSwap gate 153 | qiskit_gates["iswap"] = iSwapGate() 154 | return qiskit_gates 155 | 156 | def compute_reward( 157 | self, optimized_circuit: QuantumCircuit, prior_circuit: QuantumCircuit 158 | ) -> float: 159 | """Computes the reward for the optimized circuit. 160 | 161 | Args: 162 | optimized_circuit (QuantumCircuit): The circuit which has been optimized by an action. 163 | prior_circuit (QuantumCircuit): The circuit before optimization. 164 | 165 | Returns: 166 | float: The reward for the optimized circuit. 167 | """ 168 | 169 | # Assert the original and optimized circuit are equivalent. 170 | if Statevector.from_instruction(optimized_circuit).equiv( 171 | Statevector.from_instruction(prior_circuit) 172 | ): 173 | # Cacluate gate count and depth of optimized circuit 174 | depth = optimized_circuit.depth() 175 | gate_len = sum(dict(optimized_circuit.count_ops()).values()) 176 | score = self.alpha * depth + self.beta * gate_len 177 | # Calculate the gate count and depth of the prior circuit 178 | prior_depth = prior_circuit.depth() 179 | prior_gate_len = sum(dict(prior_circuit.count_ops()).values()) 180 | 181 | prior_score = self.alpha * prior_depth + self.beta * prior_gate_len 182 | score_diff = -(score - prior_score) 183 | return score_diff 184 | 185 | else: 186 | return ( 187 | -1 188 | ) # Penalize the circuit if it is not equivalent to the prior circuit could be throw as an assertion error 189 | 190 | def step(self, action: float) -> Tuple[torch.Tensor, float, bool, dict]: 191 | """Run one timestep of the environment's dynamics. 192 | 193 | Args: 194 | action (tensor): An action provided by the environment 195 | 196 | Returns: 197 | Tuple[torch.Tensor, float, bool, dict]: observation, reward, done, info 198 | """ 199 | 200 | transformation = self.actions[int(action)] 201 | init = PassManager([transformation]) 202 | self.prior_circuit = self.circuit 203 | if self.render_true: 204 | # Render the circuit and DAG 205 | self.render(self.circuit) 206 | self.circuit = init.run(self.circuit) 207 | 208 | # In the original paper, "soft" and "hard" transformations are applied. 209 | # It is possible to add hard transformations and modify the actions. 210 | 211 | # Compute the reward 212 | reward = self.compute_reward(self.circuit, self.prior_circuit) 213 | self.circuit_score_array.append(reward) 214 | # Set done to true if the circuit is optimized 215 | # This is a hacky way to exit the optimization loop, there are plenty of better ways to do this. 216 | if (np.average(self.circuit_score_array[-5:])) < 0.1: 217 | done = True 218 | 219 | else: 220 | done = False 221 | 222 | # Convert the circuit to a tensor 223 | self.state = self._create_tensor_from_circuit(self.circuit) 224 | 225 | # Set placeholder for info 226 | info = {} 227 | return self.state, reward, done, info 228 | 229 | def render(self, circuit: QuantumCircuit) -> QuantumCircuit: 230 | """Renders the circuit and DAG 231 | 232 | Args: 233 | circuit (QuantumCircuit): The circuit to render 234 | 235 | Returns: 236 | QuantumCircuit: The rendered circuit 237 | """ 238 | # Render the cirq circuit 239 | dag = circuit_to_dag(circuit) 240 | dag_drawer(dag, scale=0.7, filename=f"./run/images/dag-{time.time()}.png") 241 | circuit.draw(output="mpl", filename=f"./run/images/circuit-{time.time()}.png") 242 | # SummaryWriter().add_figure("Circuit", dag_drawer(dag, scale=0.7, filename=f"./run/images/{dag.name}.png")) 243 | return circuit 244 | 245 | def reset(self, seed: int = None, options=None) -> Tuple[torch.Tensor, dict]: 246 | """Resets the environment to the initial state 247 | 248 | Args: 249 | seed (int, optional): Set a specific seed. Defaults to None. 250 | options (optional): Other options. Defaults to None. 251 | 252 | Returns: 253 | torch.Tensor, dict: The initial state and info 254 | """ 255 | super().reset(seed=seed, options=options) 256 | 257 | # Return the initial state 258 | self.circuit = self.create_random_circuit() 259 | info = {} 260 | observation = self._create_tensor_from_circuit(self.circuit) 261 | self.state = observation 262 | return observation, info 263 | 264 | def close(self): 265 | pass 266 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/wrappers/__init__.py: -------------------------------------------------------------------------------- 1 | from gym_examples.wrappers.clip_reward import ClipReward 2 | from gym_examples.wrappers.discrete_actions import DiscreteActions 3 | from gym_examples.wrappers.reacher_weighted_reward import ReacherRewardWrapper 4 | from gym_examples.wrappers.relative_position import RelativePosition 5 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/wrappers/clip_reward.py: -------------------------------------------------------------------------------- 1 | import gym 2 | import numpy as np 3 | 4 | 5 | class ClipReward(gym.RewardWrapper): 6 | def __init__(self, env, min_reward, max_reward): 7 | super().__init__(env) 8 | self.min_reward = min_reward 9 | self.max_reward = max_reward 10 | self.reward_range = (min_reward, max_reward) 11 | 12 | def reward(self, reward): 13 | return np.clip(reward, self.min_reward, self.max_reward) 14 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/wrappers/discrete_actions.py: -------------------------------------------------------------------------------- 1 | import gym 2 | from gym.spaces import Discrete 3 | 4 | 5 | class DiscreteActions(gym.ActionWrapper): 6 | def __init__(self, env, disc_to_cont): 7 | super().__init__(env) 8 | self.disc_to_cont = disc_to_cont 9 | self.action_space = Discrete(len(disc_to_cont)) 10 | 11 | def action(self, act): 12 | return self.disc_to_cont[act] 13 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/wrappers/reacher_weighted_reward.py: -------------------------------------------------------------------------------- 1 | import gym 2 | 3 | 4 | class ReacherRewardWrapper(gym.Wrapper): 5 | def __init__(self, env, reward_dist_weight, reward_ctrl_weight): 6 | super().__init__(env) 7 | self.reward_dist_weight = reward_dist_weight 8 | self.reward_ctrl_weight = reward_ctrl_weight 9 | 10 | def step(self, action): 11 | obs, _, terminated, truncated, info = self.env.step(action) 12 | reward = ( 13 | self.reward_dist_weight * info["reward_dist"] 14 | + self.reward_ctrl_weight * info["reward_ctrl"] 15 | ) 16 | return obs, reward, terminated, truncated, info 17 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/gym_examples/wrappers/relative_position.py: -------------------------------------------------------------------------------- 1 | import gym 2 | import numpy as np 3 | from gym.spaces import Box 4 | 5 | 6 | class RelativePosition(gym.ObservationWrapper): 7 | def __init__(self, env): 8 | super().__init__(env) 9 | self.observation_space = Box(shape=(2,), low=-np.inf, high=np.inf) 10 | 11 | def observation(self, obs): 12 | return obs["target"] - obs["agent"] 13 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/gym-examples/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name="gym_examples", 5 | version="0.0.1", 6 | install_requires=[ 7 | "gymnasium", 8 | "qiskit", 9 | "torch", 10 | "numpy", 11 | "matplotlib", 12 | "tensorboard", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/images/input_tensor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/algorithms/quantum_opt_rl/images/input_tensor.png -------------------------------------------------------------------------------- /algorithms/quantum_opt_rl/images/mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/algorithms/quantum_opt_rl/images/mario.png -------------------------------------------------------------------------------- /pyqasm/deutsch_josza_unroll.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Unrolling the Deutsch-Jozsa Algorithm \n", 8 | "In this notebook, we will see how a quantum program implementing the [Deutsch-Jozsa algorithm](https://en.wikipedia.org/wiki/Deutsch%E2%80%93Jozsa_algorithm) can be unrolled into a sequence of elementary quantum operations. " 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "%pip install pyqasm --quiet" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "data": { 27 | "text/plain": [ 28 | "'0.1.0'" 29 | ] 30 | }, 31 | "execution_count": 1, 32 | "metadata": {}, 33 | "output_type": "execute_result" 34 | } 35 | ], 36 | "source": [ 37 | "import pyqasm\n", 38 | "\n", 39 | "pyqasm.__version__" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "from pyqasm import dumps, loads" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "- We define a 4-qubit quantum circuit that implements the Deutsch-Jozsa algorithm for a given oracle." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 3, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "qasm = \"\"\"\n", 65 | "// A program containing the Deutsch-Josza algorithm in OpenQASM 3\n", 66 | "OPENQASM 3;\n", 67 | "include \"stdgates.inc\";\n", 68 | "\n", 69 | "// Define a custom gate for the Hadamard operation\n", 70 | "gate hgate q {\n", 71 | " h q;\n", 72 | "}\n", 73 | "\n", 74 | "// Define a custom gate for the X operation\n", 75 | "gate xgate q {\n", 76 | " x q;\n", 77 | "}\n", 78 | "\n", 79 | "const int[32] N = 4;\n", 80 | "qubit[4] q;\n", 81 | "qubit ancilla;\n", 82 | "\n", 83 | "\n", 84 | "// Define the Deutsch-Josza algorithm\n", 85 | "def deutsch_jozsa(qubit[N] q_func, qubit[1] ancilla_q) {\n", 86 | "\n", 87 | " // Initialize the ancilla qubit to |1>\n", 88 | " xgate ancilla_q;\n", 89 | "\n", 90 | " // Apply Hadamard gate to all qubits\n", 91 | " for int i in [0:N-1] {\n", 92 | " hgate q_func[i];\n", 93 | " }\n", 94 | "\n", 95 | " hgate ancilla_q;\n", 96 | "\n", 97 | " // Apply the oracle \n", 98 | " for int i in [0:N-1] {\n", 99 | " cx q_func[i], ancilla_q;\n", 100 | " }\n", 101 | "\n", 102 | " // Apply Hadamard gate to all qubits again\n", 103 | " for int i in [0:N-1] {\n", 104 | " hgate q_func[i];\n", 105 | " }\n", 106 | "}\n", 107 | "\n", 108 | "\n", 109 | "// Run the Deutsch-Josza algorithm for N qubits\n", 110 | "deutsch_jozsa(q, ancilla);\n", 111 | "\n", 112 | "// Measure the results \n", 113 | "bit[4] result;\n", 114 | "result = measure q;\n", 115 | "\"\"\"" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 4, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "program = loads(qasm)\n", 125 | "\n", 126 | "program.unroll()" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 5, 132 | "metadata": {}, 133 | "outputs": [ 134 | { 135 | "name": "stdout", 136 | "output_type": "stream", 137 | "text": [ 138 | "OPENQASM 3.0;\n", 139 | "include \"stdgates.inc\";\n", 140 | "qubit[4] q;\n", 141 | "qubit[1] ancilla;\n", 142 | "x ancilla[0];\n", 143 | "h q[0];\n", 144 | "h q[1];\n", 145 | "h q[2];\n", 146 | "h q[3];\n", 147 | "h ancilla[0];\n", 148 | "cx q[0], ancilla[0];\n", 149 | "cx q[1], ancilla[0];\n", 150 | "cx q[2], ancilla[0];\n", 151 | "cx q[3], ancilla[0];\n", 152 | "h q[0];\n", 153 | "h q[1];\n", 154 | "h q[2];\n", 155 | "h q[3];\n", 156 | "bit[4] result;\n", 157 | "result[0] = measure q[0];\n", 158 | "result[1] = measure q[1];\n", 159 | "result[2] = measure q[2];\n", 160 | "result[3] = measure q[3];\n", 161 | "\n" 162 | ] 163 | } 164 | ], 165 | "source": [ 166 | "print(dumps(program))" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": null, 172 | "metadata": {}, 173 | "outputs": [], 174 | "source": [] 175 | } 176 | ], 177 | "metadata": { 178 | "kernelspec": { 179 | "display_name": "sdk311", 180 | "language": "python", 181 | "name": "python3" 182 | }, 183 | "language_info": { 184 | "codemirror_mode": { 185 | "name": "ipython", 186 | "version": 3 187 | }, 188 | "file_extension": ".py", 189 | "mimetype": "text/x-python", 190 | "name": "python", 191 | "nbconvert_exporter": "python", 192 | "pygments_lexer": "ipython3", 193 | "version": "3.11.9" 194 | } 195 | }, 196 | "nbformat": 4, 197 | "nbformat_minor": 2 198 | } 199 | -------------------------------------------------------------------------------- /pyqasm/qasm_processing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### The Capabilities of PyQASM \n", 8 | "Besides unrolling and semantic validation, PyQASM also provides a variety of functionalities to help users analyse and transform their quantum programs. We will highlight them by taking a look at a simple example. \n", 9 | "\n", 10 | "For detailed documentation, please refer to the [official PyQASM documentation](https://sdk.qbraid.com/projects/pyqasm/en/stable/api/pyqasm.html)." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "%pip install pyqasm --quiet" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 1, 25 | "metadata": {}, 26 | "outputs": [ 27 | { 28 | "data": { 29 | "text/plain": [ 30 | "'0.1.0'" 31 | ] 32 | }, 33 | "execution_count": 1, 34 | "metadata": {}, 35 | "output_type": "execute_result" 36 | } 37 | ], 38 | "source": [ 39 | "import pyqasm\n", 40 | "\n", 41 | "pyqasm.__version__" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 2, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "from pyqasm import loads, dumps" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 3, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "qasm_str = \"\"\"\n", 60 | "OPENQASM 3.0;\n", 61 | "include \"stdgates.inc\";\n", 62 | "\n", 63 | "// define qubits and random ops \n", 64 | "qubit[10] q;\n", 65 | "bit[10] c;\n", 66 | "\n", 67 | "h q[0];\n", 68 | "h q[1];\n", 69 | "\n", 70 | "cx q[0], q[1];\n", 71 | "\n", 72 | "rx(0.5) q[3:6];\n", 73 | "ccx q[0], q[1], q[2];\n", 74 | "\n", 75 | "barrier q[:5];\n", 76 | "\n", 77 | "c[:5] = measure q[:5]; \n", 78 | "\"\"\"" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 4, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "module = loads(qasm_str)" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "- Let's start by validating our quantum program." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 5, 100 | "metadata": {}, 101 | "outputs": [], 102 | "source": [ 103 | "module.validate()" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "- Next, we will get the qubit and classical register information. Post this, we will unroll the program and print it." 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 6, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "data": { 120 | "text/plain": [ 121 | "(10, 10)" 122 | ] 123 | }, 124 | "execution_count": 6, 125 | "metadata": {}, 126 | "output_type": "execute_result" 127 | } 128 | ], 129 | "source": [ 130 | "module.num_qubits, module.num_clbits" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 7, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "data": { 140 | "text/plain": [ 141 | "['OPENQASM 3.0;',\n", 142 | " 'include \"stdgates.inc\";',\n", 143 | " 'qubit[10] q;',\n", 144 | " 'bit[10] c;',\n", 145 | " 'h q[0];',\n", 146 | " 'h q[1];',\n", 147 | " 'cx q[0], q[1];',\n", 148 | " 'rx(0.5) q[3];',\n", 149 | " 'rx(0.5) q[4];',\n", 150 | " 'rx(0.5) q[5];',\n", 151 | " 'ccx q[0], q[1], q[2];',\n", 152 | " 'barrier q[0];',\n", 153 | " 'barrier q[1];',\n", 154 | " 'barrier q[2];',\n", 155 | " 'barrier q[3];',\n", 156 | " 'barrier q[4];',\n", 157 | " 'c[0] = measure q[0];',\n", 158 | " 'c[1] = measure q[1];',\n", 159 | " 'c[2] = measure q[2];',\n", 160 | " 'c[3] = measure q[3];',\n", 161 | " 'c[4] = measure q[4];']" 162 | ] 163 | }, 164 | "execution_count": 7, 165 | "metadata": {}, 166 | "output_type": "execute_result" 167 | } 168 | ], 169 | "source": [ 170 | "module.unroll()\n", 171 | "\n", 172 | "dumps(module).splitlines()" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": 8, 178 | "metadata": {}, 179 | "outputs": [ 180 | { 181 | "data": { 182 | "text/plain": [ 183 | "5" 184 | ] 185 | }, 186 | "execution_count": 8, 187 | "metadata": {}, 188 | "output_type": "execute_result" 189 | } 190 | ], 191 | "source": [ 192 | "module.depth()" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "- Let us now remove the idle qubits from our qasm program and get back the optimized qasm code.\n", 200 | "- Note that `q[6]` to `q[9]` are idle qubits in the above qasm code." 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 9, 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "data": { 210 | "text/plain": [ 211 | "" 212 | ] 213 | }, 214 | "execution_count": 9, 215 | "metadata": {}, 216 | "output_type": "execute_result" 217 | } 218 | ], 219 | "source": [ 220 | "module.remove_idle_qubits()" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 10, 226 | "metadata": {}, 227 | "outputs": [ 228 | { 229 | "data": { 230 | "text/plain": [ 231 | "['OPENQASM 3.0;',\n", 232 | " 'include \"stdgates.inc\";',\n", 233 | " 'qubit[6] q;',\n", 234 | " 'bit[10] c;',\n", 235 | " 'h q[0];',\n", 236 | " 'h q[1];',\n", 237 | " 'cx q[0], q[1];',\n", 238 | " 'rx(0.5) q[3];',\n", 239 | " 'rx(0.5) q[4];',\n", 240 | " 'rx(0.5) q[5];',\n", 241 | " 'ccx q[0], q[1], q[2];',\n", 242 | " 'barrier q[0];',\n", 243 | " 'barrier q[1];',\n", 244 | " 'barrier q[2];',\n", 245 | " 'barrier q[3];',\n", 246 | " 'barrier q[4];',\n", 247 | " 'c[0] = measure q[0];',\n", 248 | " 'c[1] = measure q[1];',\n", 249 | " 'c[2] = measure q[2];',\n", 250 | " 'c[3] = measure q[3];',\n", 251 | " 'c[4] = measure q[4];']" 252 | ] 253 | }, 254 | "execution_count": 10, 255 | "metadata": {}, 256 | "output_type": "execute_result" 257 | } 258 | ], 259 | "source": [ 260 | "dumps(module).splitlines()" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": 11, 266 | "metadata": {}, 267 | "outputs": [ 268 | { 269 | "data": { 270 | "text/plain": [ 271 | "(6, 10)" 272 | ] 273 | }, 274 | "execution_count": 11, 275 | "metadata": {}, 276 | "output_type": "execute_result" 277 | } 278 | ], 279 | "source": [ 280 | "module.num_qubits, module.num_clbits" 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "- We can clearly see that the size of the quantum program has decreased to 6 qubits instead of 10\n", 288 | "- Let's check for measurements and barriers now" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "execution_count": 12, 294 | "metadata": {}, 295 | "outputs": [ 296 | { 297 | "data": { 298 | "text/plain": [ 299 | "True" 300 | ] 301 | }, 302 | "execution_count": 12, 303 | "metadata": {}, 304 | "output_type": "execute_result" 305 | } 306 | ], 307 | "source": [ 308 | "module.has_measurements()" 309 | ] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": 13, 314 | "metadata": {}, 315 | "outputs": [ 316 | { 317 | "data": { 318 | "text/plain": [ 319 | "True" 320 | ] 321 | }, 322 | "execution_count": 13, 323 | "metadata": {}, 324 | "output_type": "execute_result" 325 | } 326 | ], 327 | "source": [ 328 | "module.has_barriers()" 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": {}, 334 | "source": [ 335 | "- Barriers and measurements can easily be removed from the qasm code through the `remove_barriers()` and `remove_measurements()` functions respectively.\n", 336 | "- We can also use the `in_place` parameter to specify whether we want to modify the original qasm code or not." 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": 14, 342 | "metadata": {}, 343 | "outputs": [], 344 | "source": [ 345 | "module.remove_barriers()\n", 346 | "\n", 347 | "new_module = module.remove_measurements(in_place=False)" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 15, 353 | "metadata": {}, 354 | "outputs": [ 355 | { 356 | "data": { 357 | "text/plain": [ 358 | "['OPENQASM 3.0;',\n", 359 | " 'include \"stdgates.inc\";',\n", 360 | " 'qubit[6] q;',\n", 361 | " 'bit[10] c;',\n", 362 | " 'h q[0];',\n", 363 | " 'h q[1];',\n", 364 | " 'cx q[0], q[1];',\n", 365 | " 'rx(0.5) q[3];',\n", 366 | " 'rx(0.5) q[4];',\n", 367 | " 'rx(0.5) q[5];',\n", 368 | " 'ccx q[0], q[1], q[2];',\n", 369 | " 'c[0] = measure q[0];',\n", 370 | " 'c[1] = measure q[1];',\n", 371 | " 'c[2] = measure q[2];',\n", 372 | " 'c[3] = measure q[3];',\n", 373 | " 'c[4] = measure q[4];']" 374 | ] 375 | }, 376 | "execution_count": 15, 377 | "metadata": {}, 378 | "output_type": "execute_result" 379 | } 380 | ], 381 | "source": [ 382 | "dumps(module).splitlines()" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": 16, 388 | "metadata": {}, 389 | "outputs": [ 390 | { 391 | "data": { 392 | "text/plain": [ 393 | "['OPENQASM 3.0;',\n", 394 | " 'include \"stdgates.inc\";',\n", 395 | " 'qubit[6] q;',\n", 396 | " 'bit[10] c;',\n", 397 | " 'h q[0];',\n", 398 | " 'h q[1];',\n", 399 | " 'cx q[0], q[1];',\n", 400 | " 'rx(0.5) q[3];',\n", 401 | " 'rx(0.5) q[4];',\n", 402 | " 'rx(0.5) q[5];',\n", 403 | " 'ccx q[0], q[1], q[2];']" 404 | ] 405 | }, 406 | "execution_count": 16, 407 | "metadata": {}, 408 | "output_type": "execute_result" 409 | } 410 | ], 411 | "source": [ 412 | "dumps(new_module).splitlines()" 413 | ] 414 | }, 415 | { 416 | "cell_type": "markdown", 417 | "metadata": {}, 418 | "source": [ 419 | "- We can observe that the barriers have been removed from both the module objects but measurements are only removed in the `new_module`" 420 | ] 421 | }, 422 | { 423 | "cell_type": "markdown", 424 | "metadata": {}, 425 | "source": [ 426 | "\n", 427 | "- We also have the ability to **reverse the qubit order**" 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": 17, 433 | "metadata": {}, 434 | "outputs": [ 435 | { 436 | "data": { 437 | "text/plain": [ 438 | "" 439 | ] 440 | }, 441 | "execution_count": 17, 442 | "metadata": {}, 443 | "output_type": "execute_result" 444 | } 445 | ], 446 | "source": [ 447 | "module.reverse_qubit_order()" 448 | ] 449 | }, 450 | { 451 | "cell_type": "code", 452 | "execution_count": 18, 453 | "metadata": {}, 454 | "outputs": [ 455 | { 456 | "data": { 457 | "text/plain": [ 458 | "['OPENQASM 3.0;',\n", 459 | " 'include \"stdgates.inc\";',\n", 460 | " 'qubit[6] q;',\n", 461 | " 'bit[10] c;',\n", 462 | " 'h q[5];',\n", 463 | " 'h q[4];',\n", 464 | " 'cx q[5], q[4];',\n", 465 | " 'rx(0.5) q[2];',\n", 466 | " 'rx(0.5) q[1];',\n", 467 | " 'rx(0.5) q[0];',\n", 468 | " 'ccx q[5], q[4], q[3];',\n", 469 | " 'c[0] = measure q[5];',\n", 470 | " 'c[1] = measure q[4];',\n", 471 | " 'c[2] = measure q[3];',\n", 472 | " 'c[3] = measure q[2];',\n", 473 | " 'c[4] = measure q[1];']" 474 | ] 475 | }, 476 | "execution_count": 18, 477 | "metadata": {}, 478 | "output_type": "execute_result" 479 | } 480 | ], 481 | "source": [ 482 | "dumps(module).splitlines()" 483 | ] 484 | }, 485 | { 486 | "cell_type": "markdown", 487 | "metadata": {}, 488 | "source": [ 489 | "- Qubits have been reversed in place in the qasm code \n" 490 | ] 491 | }, 492 | { 493 | "cell_type": "markdown", 494 | "metadata": {}, 495 | "source": [ 496 | "- We can finally check for the number of qubits, classical bits and depth of the updated qasm code " 497 | ] 498 | }, 499 | { 500 | "cell_type": "code", 501 | "execution_count": 19, 502 | "metadata": {}, 503 | "outputs": [ 504 | { 505 | "data": { 506 | "text/plain": [ 507 | "(6, 10)" 508 | ] 509 | }, 510 | "execution_count": 19, 511 | "metadata": {}, 512 | "output_type": "execute_result" 513 | } 514 | ], 515 | "source": [ 516 | "module.num_qubits, module.num_clbits" 517 | ] 518 | }, 519 | { 520 | "cell_type": "code", 521 | "execution_count": 20, 522 | "metadata": {}, 523 | "outputs": [ 524 | { 525 | "data": { 526 | "text/plain": [ 527 | "4" 528 | ] 529 | }, 530 | "execution_count": 20, 531 | "metadata": {}, 532 | "output_type": "execute_result" 533 | } 534 | ], 535 | "source": [ 536 | "module.depth()" 537 | ] 538 | } 539 | ], 540 | "metadata": { 541 | "kernelspec": { 542 | "display_name": "sdk311", 543 | "language": "python", 544 | "name": "python3" 545 | }, 546 | "language_info": { 547 | "codemirror_mode": { 548 | "name": "ipython", 549 | "version": 3 550 | }, 551 | "file_extension": ".py", 552 | "mimetype": "text/x-python", 553 | "name": "python", 554 | "nbconvert_exporter": "python", 555 | "pygments_lexer": "ipython3", 556 | "version": "3.11.9" 557 | } 558 | }, 559 | "nbformat": 4, 560 | "nbformat_minor": 2 561 | } 562 | -------------------------------------------------------------------------------- /pyqasm/qasm_unroll.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Unrolling a QASM program\n", 8 | "- We take the example from the `openqasm3` repository and produce the unrolled program. " 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "%pip install pyqasm --quiet" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "data": { 27 | "text/plain": [ 28 | "'0.1.0'" 29 | ] 30 | }, 31 | "execution_count": 1, 32 | "metadata": {}, 33 | "output_type": "execute_result" 34 | } 35 | ], 36 | "source": [ 37 | "import pyqasm\n", 38 | "\n", 39 | "pyqasm.__version__" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "from pyqasm import loads, dumps" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "- [`Adder.qasm`](https://github.com/openqasm/openqasm/blob/9150b157df801702b02ac7c14979ace8aba53a85/examples/adder.qasm)" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 3, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "adder_qasm_str = \"\"\"\n", 65 | "/*\n", 66 | " * quantum ripple-carry adder\n", 67 | " * Cuccaro et al, quant-ph/0410184\n", 68 | " */\n", 69 | "OPENQASM 3.0;\n", 70 | "include 'stdgates.inc';\n", 71 | "\n", 72 | "gate majority a, b, c {\n", 73 | " cx c, b;\n", 74 | " cx c, a;\n", 75 | " ccx a, b, c;\n", 76 | "}\n", 77 | "\n", 78 | "gate unmaj a, b, c {\n", 79 | " ccx a, b, c;\n", 80 | " cx c, a;\n", 81 | " cx a, b;\n", 82 | "}\n", 83 | "\n", 84 | "qubit[1] cin;\n", 85 | "qubit[4] a;\n", 86 | "qubit[4] b;\n", 87 | "qubit[1] cout;\n", 88 | "bit[5] ans;\n", 89 | "array[bool, 4] a_in = {0,0,0,1}; // a = 0001\n", 90 | "array[bool, 4] b_in = {1,1,1,1}; // b = 1111\n", 91 | "// initialize qubits\n", 92 | "reset cin;\n", 93 | "reset a;\n", 94 | "reset b;\n", 95 | "reset cout;\n", 96 | "\n", 97 | "// set input states\n", 98 | "for int i in [0: 3] {\n", 99 | " if(a_in[i]) x a[i];\n", 100 | " if(b_in[i]) x b[i];\n", 101 | "}\n", 102 | "\n", 103 | "// add a to b, storing result in b\n", 104 | "majority cin[0], b[0], a[0];\n", 105 | "for int i in [0: 2] { majority a[i], b[i + 1], a[i + 1]; }\n", 106 | "cx a[3], cout[0];\n", 107 | "for int i in [2: -1: 0] { unmaj a[i],b[i+1],a[i+1]; }\n", 108 | "unmaj cin[0], b[0], a[0];\n", 109 | "measure b[0:3] -> ans[0:3];\n", 110 | "measure cout[0] -> ans[4];\n", 111 | "\"\"\"" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 4, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "module = loads(adder_qasm_str)\n", 121 | "\n", 122 | "module.validate()\n", 123 | "\n", 124 | "module.unroll()" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 5, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "data": { 134 | "text/plain": [ 135 | "['OPENQASM 3.0;',\n", 136 | " 'include \"stdgates.inc\";',\n", 137 | " 'qubit[1] cin;',\n", 138 | " 'qubit[4] a;',\n", 139 | " 'qubit[4] b;',\n", 140 | " 'qubit[1] cout;',\n", 141 | " 'bit[5] ans;',\n", 142 | " 'reset cin[0];',\n", 143 | " 'reset a[0];',\n", 144 | " 'reset a[1];',\n", 145 | " 'reset a[2];',\n", 146 | " 'reset a[3];',\n", 147 | " 'reset b[0];',\n", 148 | " 'reset b[1];',\n", 149 | " 'reset b[2];',\n", 150 | " 'reset b[3];',\n", 151 | " 'reset cout[0];',\n", 152 | " 'x b[0];',\n", 153 | " 'x b[1];',\n", 154 | " 'x b[2];',\n", 155 | " 'x a[3];',\n", 156 | " 'x b[3];',\n", 157 | " 'cx a[0], b[0];',\n", 158 | " 'cx a[0], cin[0];',\n", 159 | " 'ccx cin[0], b[0], a[0];',\n", 160 | " 'cx a[1], b[1];',\n", 161 | " 'cx a[1], a[0];',\n", 162 | " 'ccx a[0], b[1], a[1];',\n", 163 | " 'cx a[2], b[2];',\n", 164 | " 'cx a[2], a[1];',\n", 165 | " 'ccx a[1], b[2], a[2];',\n", 166 | " 'cx a[3], b[3];',\n", 167 | " 'cx a[3], a[2];',\n", 168 | " 'ccx a[2], b[3], a[3];',\n", 169 | " 'cx a[3], cout[0];',\n", 170 | " 'ccx a[2], b[3], a[3];',\n", 171 | " 'cx a[3], a[2];',\n", 172 | " 'cx a[2], b[3];',\n", 173 | " 'ccx a[1], b[2], a[2];',\n", 174 | " 'cx a[2], a[1];',\n", 175 | " 'cx a[1], b[2];',\n", 176 | " 'ccx a[0], b[1], a[1];',\n", 177 | " 'cx a[1], a[0];',\n", 178 | " 'cx a[0], b[1];',\n", 179 | " 'ccx cin[0], b[0], a[0];',\n", 180 | " 'cx a[0], cin[0];',\n", 181 | " 'cx cin[0], b[0];',\n", 182 | " 'ans[0] = measure b[0];',\n", 183 | " 'ans[1] = measure b[1];',\n", 184 | " 'ans[2] = measure b[2];',\n", 185 | " 'ans[4] = measure cout[0];']" 186 | ] 187 | }, 188 | "execution_count": 5, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "dumps(module).splitlines()" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [] 203 | } 204 | ], 205 | "metadata": { 206 | "kernelspec": { 207 | "display_name": "sdk311", 208 | "language": "python", 209 | "name": "python3" 210 | }, 211 | "language_info": { 212 | "codemirror_mode": { 213 | "name": "ipython", 214 | "version": 3 215 | }, 216 | "file_extension": ".py", 217 | "mimetype": "text/x-python", 218 | "name": "python", 219 | "nbconvert_exporter": "python", 220 | "pygments_lexer": "ipython3", 221 | "version": "3.11.9" 222 | } 223 | }, 224 | "nbformat": 4, 225 | "nbformat_minor": 2 226 | } 227 | -------------------------------------------------------------------------------- /qbraid_lab/bloqade/README.md: -------------------------------------------------------------------------------- 1 | # Using Bloqade with qBraid Lab 2 | 3 | Bloqade is available working out-of-the-box through qBraid Lab. 4 | [qBraid](https://www.qbraid.com/) supports Google login, is free-to-use, and requires little to no setup. 5 | 6 | ## qBraid Bloqade Jupyter Lab Image 7 | 8 | Built on top of Ubuntu Server 20.04 LTS, this image includes 9 | - The latest version of Julia and Bloqade 10 | - [Yao.jl](https://yaoquantum.org/) 11 | - [Revise.jl](https://github.com/timholy/Revise.jl) 12 | - [BenchmarkTools.jl](https://juliaci.github.io/BenchmarkTools.jl/stable/) 13 | - [PythonCall.jl](https://cjdoris.github.io/PythonCall.jl/stable/) 14 | - Conda package manager, provided by [Mamba](https://mamba.readthedocs.io/en/latest/index.html) 15 | - Jupyter Lab interface with dedicated Julia and Python kernels 16 | - Integrated Terminal for interactive command-line sessions 17 | 18 | See [qBraid system info](https://docs.qbraid.com/en/latest/lab/system.html) for more. 19 | 20 | ### Step 0: Redeem Access Key 21 | 22 | Login to [account.qbraid.com](https://account.qbraid.com/). On the left side of your dashboard, inside the **Plan** card, click **Manage**. 23 | 24 | ![qBraidStep 0.1](assets/Step0.1.png) 25 | 26 | Scroll down to find the card marked **Access Key**. Enter code `NEUTRALATOM` and click **Submit**. This will grant you access to the Bloqade Lab image as well as a number of other premium features. 27 | 28 | ![qBraidStep 0.2](assets/Step0.2.png) 29 | 30 | 31 | ### Step 1: Select Image & Launch Lab 32 | 33 | At the top of your account page, open the image drop down. Select the option named `Bloqade_2vCPU_4GB`, and then click **Launch Lab**. Pulling the Bloqade image may take 2-3 minutes the first time. The next time you launch Lab, it will load much more quickly. 34 | 35 | ![qBraidStep 2](assets/Step1.png) 36 | 37 | 38 | ### Step 2: Develop with Notebooks or from Command-Line 39 | 40 | Once qBraid Lab is loaded, you are all set! No further setup is required. In the middle of your screen you can click the **Julia 1.9** kernel to open a new Jupyter Notebook configured with the Julia executable. Alternatively, you can click to open **Terminal** and run an interactive `julia` session from the command-line. In this qBraid Lab image, Bloqade is pre-installed and pre-compiled, so you should be able to get started `using Bloqade` right away. 41 | 42 | ![qBraidStep 3](assets/Step2.png) 43 | 44 | 45 | #### Julia Configuration 46 | 47 | In qBraid Lab, the `JULIA_DEPOT_PATH` is set to `/opt/.julia`. This default setting means that any additional Julia packages installed will be stored at the system level, and therefore *will not persist between sessions*. To persist additional packages, caches, configs, and other Julia updates, they must be saved at the user level (e.g. `/home/jovyan/.julia`). This can be done by updating the depot path: 48 | 49 | ```bash 50 | export JULIA_DEPOT_PATH="/foo/bar:$JULIA_DEPOT_PATH" 51 | ``` 52 | 53 | See [Julia environment variables](https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_DEPOT_PATH) for more. 54 | 55 | 56 | ### Step 3: Explore More Features 57 | 58 | The Environment Manager, located in the right sidebar of qBraid Lab, provides a graphical user interface for creating and managing Python virtual environments. This particular Lab image comes with a pre-installed Bloqade Python Wrapper environment. Clicking **Activate** will create a corresponding IPykernel, and allow you to run Jupyter Notebooks using the `bloqade` Python package. 59 | 60 | In the bottom right corner qBraid Lab, click **Start Tour** for an interactive walkthrough. You can re-start the tour and access other useful links from the **Help** drop-down in the top menu bar. To stop and/or restart your session, click **File** > **Hub Control Panel** > **Stop My Server**. For more on qBraid environments, kernels, notebooks, and other features or troubleshooting, see [qBraid Lab Docs](https://docs.qbraid.com/en/latest/index.html). 61 | -------------------------------------------------------------------------------- /qbraid_lab/bloqade/assets/Step0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/qbraid_lab/bloqade/assets/Step0.1.png -------------------------------------------------------------------------------- /qbraid_lab/bloqade/assets/Step0.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/qbraid_lab/bloqade/assets/Step0.2.png -------------------------------------------------------------------------------- /qbraid_lab/bloqade/assets/Step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/qbraid_lab/bloqade/assets/Step1.png -------------------------------------------------------------------------------- /qbraid_lab/bloqade/assets/Step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/qbraid_lab/bloqade/assets/Step2.png -------------------------------------------------------------------------------- /qbraid_lab/gpu/cirq_VQE_cuQuantum.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "e29f3e57-1d73-400d-bd4a-a98a6754458a", 6 | "metadata": {}, 7 | "source": [ 8 | "# qBraid Lab GPU-accelerated VQE Demo\n", 9 | "\n", 10 | "## 2D Ising Model: $H=\\sum\\limits_{(i,j)} J_{ij} Z_i Z_j + \\sum\\limits_{i} h_i Z_i$\n", 11 | "\n", 12 | "##### Based on https://quantumai.google/cirq/experiments/variational_algorithm" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "id": "bd558dce", 18 | "metadata": {}, 19 | "source": [ 20 | "##### First, make sure you have installed the Cirq environment and are using the Cirq python kernel." 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "id": "a2bb3a37-4173-4ae0-988c-851449808818", 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "import cirq, qsimcirq, time, random\n", 31 | "import numpy as np" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "419028e4", 37 | "metadata": {}, 38 | "source": [ 39 | "##### Randomly initialize the necessary Hamiltonian coefficients" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "id": "8f161f1b-ba48-43bd-b675-d7aa8d1fdd9e", 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "def rand2d(rows, cols):\n", 50 | " return [[random.choice([+1, -1]) for _ in range(cols)] for _ in range(rows)]\n", 51 | "\n", 52 | "\n", 53 | "def random_instance(length):\n", 54 | " # transverse field terms\n", 55 | " h = rand2d(length, length)\n", 56 | " # links within a row\n", 57 | " jr = rand2d(length - 1, length)\n", 58 | " # links within a column\n", 59 | " jc = rand2d(length, length - 1)\n", 60 | " return (h, jr, jc)\n", 61 | "\n", 62 | "\n", 63 | "h, jr, jc = random_instance(3)" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 3, 69 | "id": "6af0dc5f-7320-47cf-a796-98e7e81e039b", 70 | "metadata": {}, 71 | "outputs": [ 72 | { 73 | "name": "stdout", 74 | "output_type": "stream", 75 | "text": [ 76 | "[[1, -1, -1], [1, -1, -1], [1, -1, 1]]\n", 77 | "[[1, -1, -1], [1, 1, -1]]\n", 78 | "[[-1, 1], [1, -1], [-1, 1]]\n" 79 | ] 80 | } 81 | ], 82 | "source": [ 83 | "print(h)\n", 84 | "print(jr)\n", 85 | "print(jc)" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "id": "37a9e5a9", 91 | "metadata": {}, 92 | "source": [ 93 | "##### Generate the ansatz" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 4, 99 | "id": "6a990854-8d63-4cdd-a2a1-875c4d83e40d", 100 | "metadata": {}, 101 | "outputs": [], 102 | "source": [ 103 | "def prepare_plus_layer(length):\n", 104 | " for i in range(length):\n", 105 | " for j in range(length):\n", 106 | " yield cirq.H(cirq.GridQubit(i, j))" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 5, 112 | "id": "6e34e3a6-93bd-474a-8424-40319d297a47", 113 | "metadata": {}, 114 | "outputs": [ 115 | { 116 | "name": "stdout", 117 | "output_type": "stream", 118 | "text": [ 119 | "(0, 0): ───H───\n", 120 | "\n", 121 | "(0, 1): ───H───\n", 122 | "\n", 123 | "(1, 0): ───H───\n", 124 | "\n", 125 | "(1, 1): ───H───\n" 126 | ] 127 | } 128 | ], 129 | "source": [ 130 | "circuit = cirq.Circuit()\n", 131 | "circuit.append(prepare_plus_layer(2))\n", 132 | "print(circuit)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 6, 138 | "id": "ffe416d4-9029-4cc2-9376-f8ccc7a0d77e", 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "def rot_x_layer(length, half_turns):\n", 143 | " \"\"\"Yields X rotations by half_turns on a square grid of given length.\"\"\"\n", 144 | "\n", 145 | " # Define the gate once and then re-use it for each Operation.\n", 146 | " rot = cirq.XPowGate(exponent=half_turns)\n", 147 | "\n", 148 | " # Create an X rotation Operation for each qubit in the grid.\n", 149 | " for i in range(length):\n", 150 | " for j in range(length):\n", 151 | " yield rot(cirq.GridQubit(i, j))" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 7, 157 | "id": "289a3cd3-5741-4914-9e9b-55a95e4ff4c9", 158 | "metadata": {}, 159 | "outputs": [ 160 | { 161 | "name": "stdout", 162 | "output_type": "stream", 163 | "text": [ 164 | "(0, 0): ───X^0.1───\n", 165 | "\n", 166 | "(0, 1): ───X^0.1───\n", 167 | "\n", 168 | "(1, 0): ───X^0.1───\n", 169 | "\n", 170 | "(1, 1): ───X^0.1───\n" 171 | ] 172 | } 173 | ], 174 | "source": [ 175 | "circuit = cirq.Circuit()\n", 176 | "circuit.append(rot_x_layer(2, 0.1))\n", 177 | "print(circuit)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 8, 183 | "id": "de711767-f55e-4345-bf6f-19b8bad40ff3", 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "def rot_z_layer(h, half_turns):\n", 188 | " \"\"\"Yields Z rotations by half_turns conditioned on the field h.\"\"\"\n", 189 | " gate = cirq.ZPowGate(exponent=half_turns)\n", 190 | " for i, h_row in enumerate(h):\n", 191 | " for j, h_ij in enumerate(h_row):\n", 192 | " if h_ij == 1:\n", 193 | " yield gate(cirq.GridQubit(i, j))" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 9, 199 | "id": "1546be16-114c-4462-a364-04b0799890c1", 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [ 203 | "circuit = cirq.Circuit()\n", 204 | "circuit.append(rot_z_layer(h, 0.1))" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": 10, 210 | "id": "c84046ef-2687-4290-adce-a6200bc2f904", 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "name": "stdout", 215 | "output_type": "stream", 216 | "text": [ 217 | "(0, 0): ───Z^0.1───\n", 218 | "\n", 219 | "(1, 0): ───Z^0.1───\n", 220 | "\n", 221 | "(2, 0): ───Z^0.1───\n", 222 | "\n", 223 | "(2, 2): ───Z^0.1───\n" 224 | ] 225 | } 226 | ], 227 | "source": [ 228 | "print(circuit)" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": 11, 234 | "id": "ecc049e4-7185-44f6-9c4d-d44b40210fb7", 235 | "metadata": {}, 236 | "outputs": [], 237 | "source": [ 238 | "def rot_11_layer(jr, jc, half_turns):\n", 239 | " \"\"\"Yields rotations about |11> conditioned on the jr and jc fields.\"\"\"\n", 240 | " cz_gate = cirq.CZPowGate(exponent=half_turns)\n", 241 | " for i, jr_row in enumerate(jr):\n", 242 | " for j, jr_ij in enumerate(jr_row):\n", 243 | " q = cirq.GridQubit(i, j)\n", 244 | " q_1 = cirq.GridQubit(i + 1, j)\n", 245 | " if jr_ij == -1:\n", 246 | " yield cirq.X(q)\n", 247 | " yield cirq.X(q_1)\n", 248 | " yield cz_gate(q, q_1)\n", 249 | " if jr_ij == -1:\n", 250 | " yield cirq.X(q)\n", 251 | " yield cirq.X(q_1)\n", 252 | "\n", 253 | " for i, jc_row in enumerate(jc):\n", 254 | " for j, jc_ij in enumerate(jc_row):\n", 255 | " q = cirq.GridQubit(i, j)\n", 256 | " q_1 = cirq.GridQubit(i, j + 1)\n", 257 | " if jc_ij == -1:\n", 258 | " yield cirq.X(q)\n", 259 | " yield cirq.X(q_1)\n", 260 | " yield cz_gate(q, q_1)\n", 261 | " if jc_ij == -1:\n", 262 | " yield cirq.X(q)\n", 263 | " yield cirq.X(q_1)" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 12, 269 | "id": "80695deb-8642-4577-ba52-1c29e530a344", 270 | "metadata": {}, 271 | "outputs": [], 272 | "source": [ 273 | "circuit = cirq.Circuit()\n", 274 | "circuit.append(rot_11_layer(jr, jc, 0.1))" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 13, 280 | "id": "0ac6aed4-4d64-46f3-8978-85e4843c7eaf", 281 | "metadata": {}, 282 | "outputs": [ 283 | { 284 | "name": "stdout", 285 | "output_type": "stream", 286 | "text": [ 287 | " ┌──────┐ ┌───────────────┐ ┌──────┐ ┌──────┐\n", 288 | "(0, 0): ────@──────────X──────────────────────────────────@─────────X───────────────────────────\n", 289 | " │ │\n", 290 | "(0, 1): ────┼────X─────@──────────────────X────X──────────@^0.1─────X───────@───────────────────\n", 291 | " │ │ │\n", 292 | "(0, 2): ────┼────X─────┼────@─────────────X─────────────────────────────────@^0.1───────────────\n", 293 | " │ │ │\n", 294 | "(1, 0): ────@^0.1──────┼────┼────@────────────────────────@─────────────────────────────────────\n", 295 | " │ │ │ │\n", 296 | "(1, 1): ────X──────────@^0.1┼────┼────────X────@──────────@^0.1─────X───────────────@───────X───\n", 297 | " │ │ │ │\n", 298 | "(1, 2): ────X───────────────@^0.1┼────────X────┼────X─────@─────────X───────X───────@^0.1───X───\n", 299 | " │ │ │\n", 300 | "(2, 0): ─────────────────────────@^0.1────X────┼──────────┼─────────@───────X───────────────────\n", 301 | " │ │ │\n", 302 | "(2, 1): ───────────────────────────────────────@^0.1──────┼────X────@^0.1───X───────@───────────\n", 303 | " │ │\n", 304 | "(2, 2): ────X─────────────────────────────────────────────@^0.1─────X───────────────@^0.1───────\n", 305 | " └──────┘ └───────────────┘ └──────┘ └──────┘\n" 306 | ] 307 | } 308 | ], 309 | "source": [ 310 | "print(circuit)" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 14, 316 | "id": "6840bab3-db10-4b86-b922-2d02d2fd7dea", 317 | "metadata": {}, 318 | "outputs": [], 319 | "source": [ 320 | "length = 5\n", 321 | "qubits = cirq.GridQubit.square(length)\n", 322 | "h, jr, jc = random_instance(length)\n", 323 | "\n", 324 | "circuit = cirq.Circuit()\n", 325 | "circuit.append(prepare_plus_layer(length))\n", 326 | "circuit.append(rot_z_layer(h, 0.3))\n", 327 | "circuit.append(rot_11_layer(jr, jc, 0.3))\n", 328 | "circuit.append(rot_x_layer(length, 0.3))\n", 329 | "circuit.append(cirq.measure(*qubits, key=\"x\"))" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 15, 335 | "id": "f2a015fa-675c-4d75-a83c-7ef066a66bb4", 336 | "metadata": {}, 337 | "outputs": [ 338 | { 339 | "name": "stdout", 340 | "output_type": "stream", 341 | "text": [ 342 | " ┌───────────┐ ┌───────────────┐ ┌──────┐ ┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌──────────┐ ┌──────────┐\n", 343 | "(0, 0): ───H───Z^0.3────X───────────────@───────────────────X──────────@───────────────X^0.3────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────M('x')───\n", 344 | " │ │ │\n", 345 | "(0, 1): ───H───X─────────@──────────────┼────X─────────────────────────@^0.3───────────X───────────────────@───────────────────X───────────────────X^0.3────────────────────────────────────────────────────────────────────────────────────────────────────────────────────M────────\n", 346 | " │ │ │ │\n", 347 | "(0, 2): ───H───Z^0.3─────┼────@─────────┼────X─────────────────────────────────────────────────────────────@^0.3───────────────X───────────────────X──────────────@─────────────X───────X^0.3───────────────────────────────────────────────────────────────────────────────M────────\n", 348 | " │ │ │ │ │\n", 349 | "(0, 3): ───H───Z^0.3────X┼────┼─────────┼────@──────────────X──────────X──────────────────────────────────────────────────────────────────────────────────────────@^0.3─────────X───────@───────X^0.3───────────────────────────────────────────────────────────────────────M────────\n", 350 | " │ │ │ │ │ │\n", 351 | "(0, 4): ───H───Z^0.3────X┼────┼─────────┼────┼────@─────────X───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────@^0.3───X^0.3───────────────────────────────────────────────────────────────────────M────────\n", 352 | " │ │ │ │ │ │\n", 353 | "(1, 0): ───H───Z^0.3────X┼────┼─────────@^0.3┼────┼─────────X──────────@───────────────X───────────────────────────────────────@───────────────────X──────────────X^0.3─────────────────────────────────────────────────────────────────────────────────────────────────────M────────\n", 354 | " │ │ │ │ │ │ │\n", 355 | "(1, 1): ───H───X─────────@^0.3┼─────────X────┼────┼─────────X──────────┼────@──────────X───────────────────X───────────────────@^0.3───────────────X──────────────X─────────────@───────X───────X^0.3───────────────────────────────────────────────────────────────────────M────────\n", 356 | " │ │ │ │ │ │ │\n", 357 | "(1, 2): ───H──────────────────@^0.3─────X────┼────┼──────────@─────────┼────┼────X─────X────────────────────────────────────────────────────────────────────────────────────────@^0.3───X───────X───────@───────X───────X^0.3───────────────────────────────────────────────M────────\n", 358 | " │ │ │ │ │ │ │\n", 359 | "(1, 3): ───H───X─────────────────────────────@^0.3┼─────────X┼─────────┼────┼────X──────────@──────────────X───────────────────X────────────────────────────────────────────────────────────────────────@^0.3───X───────X───────@───────X───────X^0.3───────────────────────M────────\n", 360 | " │ │ │ │ │ │ │\n", 361 | "(1, 4): ───H───X──────────────────────────────────@^0.3─────X┼─────────┼────┼────X──────────┼────@─────────X───────────────────X────────────────────────────────────────────────────────────────────────────────────────────────@^0.3───X───────X^0.3───────────────────────M────────\n", 362 | " │ │ │ │ │ │\n", 363 | "(2, 0): ───H─────────────────────────────────────────────────┼─────────@^0.3┼──────────X────┼────┼──────────────@──────────────X───────────────────X──────────────@─────────────X───────X^0.3───────────────────────────────────────────────────────────────────────────────M────────\n", 364 | " │ │ │ │ │ │ │\n", 365 | "(2, 1): ───H───X─────────────────────────────────────────────┼──────────────@^0.3──────X────┼────┼──────────────┼────@─────────X──────────────────────────────────@^0.3─────────X───────X───────@───────X───────X^0.3───────────────────────────────────────────────────────M────────\n", 366 | " │ │ │ │ │ │ │\n", 367 | "(2, 2): ───H───X─────────────────────────────────────────────@^0.3─────X───────────────@────┼────┼─────────X────┼────┼──────────────────────────────────────────────────────────────────────────@^0.3───X───────X───────@───────X───────X^0.3───────────────────────────────M────────\n", 368 | " │ │ │ │ │ │ │\n", 369 | "(2, 3): ───H───X───────────────────────────────────────────────────────────────────────┼────@^0.3┼─────────X────┼────┼──────────────@──────────────X────────────────────────────────────────────────────────────────────@^0.3───X───────@───────X^0.3───────────────────────M────────\n", 370 | " │ │ │ │ │ │ │\n", 371 | "(2, 4): ───H───Z^0.3────X──────────────────────────────────────────────────────────────┼─────────@^0.3─────X────┼────┼──────────────┼────@──────────────────────────────────────────────────────────────────────────────────────────────@^0.3───X^0.3───────────────────────M────────\n", 372 | " │ │ │ │ │ │\n", 373 | "(3, 0): ───H───Z^0.3────X──────────────────────────────────────────────────────────────┼────────────────────────@^0.3┼─────────X────┼────┼─────────X──────────────@─────────────X───────X───────@───────X───────X^0.3───────────────────────────────────────────────────────M────────\n", 374 | " │ │ │ │ │ │ │\n", 375 | "(3, 1): ───H───Z^0.3───────────────────────────────────────────────────────────────────┼─────────────────────────────@^0.3─────X────┼────┼─────────@──────────────┼────X────────X───────────────@^0.3───X───────@───────X^0.3───────────────────────────────────────────────M────────\n", 376 | " │ │ │ │ │ │ │\n", 377 | "(3, 2): ───H───────────────────────────────────────────────────────────────────────────@^0.3───────────────@────────────────────────┼────┼─────────┼──────────────┼─────────────────────────────────────────────@^0.3───X───────@───────X───────X^0.3───────────────────────M────────\n", 378 | " │ │ │ │ │ │ │\n", 379 | "(3, 3): ───H───────────────────────────────────────────────────────────────────────────────────────────────┼────────────────────────@^0.3┼─────────┼────X─────────┼────@────────X───────X───────────────────────────────────────@^0.3───X───────@───────X^0.3───────────────M────────\n", 380 | " │ │ │ │ │ │ │\n", 381 | "(3, 4): ───H───────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────────────────@^0.3─────┼────@─────────┼────┼────────────────────────────────────────────────────────────────────────@^0.3───X^0.3───────────────M────────\n", 382 | " │ │ │ │ │ │\n", 383 | "(4, 0): ───H───Z^0.3────X──────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┼────┼─────────@^0.3┼────────X───────@───────X^0.3───────────────────────────────────────────────────────────────────────M────────\n", 384 | " │ │ │ │ │ │\n", 385 | "(4, 1): ───H───Z^0.3────X──────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────@^0.3┼─────────X────┼────────────────@^0.3───X───────@───────X───────X^0.3───────────────────────────────────────────────M────────\n", 386 | " │ │ │ │ │\n", 387 | "(4, 2): ───H───────────────────────────────────────────────────────────────────────────────────────────────@^0.3───────────────X────────────────────────┼──────────────┼────────────────────────────────@^0.3───X───────X───────@───────X───────X^0.3───────────────────────M────────\n", 388 | " │ │ │ │\n", 389 | "(4, 3): ───H───X────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────@^0.3────X───────X───────────────────────────────────────@^0.3───X───────X───────@───────X───X^0.3───M────────\n", 390 | " │ │ │\n", 391 | "(4, 4): ───H───Z^0.3────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────@^0.3─────X─────────────────────────────────────────────────────────────────────────────────────@^0.3───X───X^0.3───M────────\n", 392 | " └───────────┘ └───────────────┘ └──────┘ └───────────┘ └───────────────┘ └───────────────┘ └───────────────┘ └──────────┘ └──────────┘\n" 393 | ] 394 | } 395 | ], 396 | "source": [ 397 | "print(circuit)" 398 | ] 399 | }, 400 | { 401 | "cell_type": "markdown", 402 | "id": "e2150ddd", 403 | "metadata": {}, 404 | "source": [ 405 | "##### Let's define the CPU and GPU simulators" 406 | ] 407 | }, 408 | { 409 | "cell_type": "code", 410 | "execution_count": 16, 411 | "id": "b6f8f921-8817-4d25-b50c-8ad7196e21ae", 412 | "metadata": {}, 413 | "outputs": [], 414 | "source": [ 415 | "# Default CPU simulator\n", 416 | "simulator = cirq.Simulator()\n", 417 | "\n", 418 | "# cuQuantum GPU simulator\n", 419 | "ngpus = 1\n", 420 | "qsim_options = qsimcirq.QSimOptions(\n", 421 | " max_fused_gate_size=2,\n", 422 | " use_gpu=True,\n", 423 | " gpu_mode=1, # gpu_mode: use CUDA if set to 0 (default value) or use the NVIDIA cuStateVec library if set to any other value.\n", 424 | ")\n", 425 | "\n", 426 | "simulator_cuQ = qsimcirq.QSimSimulator(qsim_options)" 427 | ] 428 | }, 429 | { 430 | "cell_type": "markdown", 431 | "id": "997e399c", 432 | "metadata": {}, 433 | "source": [ 434 | "##### Define function for extracting energy measurements" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": 17, 440 | "id": "5e9e51ca", 441 | "metadata": {}, 442 | "outputs": [], 443 | "source": [ 444 | "def energy_func(length, h, jr, jc):\n", 445 | " def energy(measurements):\n", 446 | " # Reshape measurement into array that matches grid shape.\n", 447 | " meas_list_of_lists = [measurements[i * length : (i + 1) * length] for i in range(length)]\n", 448 | " # Convert true/false to +1/-1.\n", 449 | " pm_meas = 1 - 2 * np.array(meas_list_of_lists).astype(np.int32)\n", 450 | "\n", 451 | " tot_energy = np.sum(pm_meas * h)\n", 452 | " for i, jr_row in enumerate(jr):\n", 453 | " for j, jr_ij in enumerate(jr_row):\n", 454 | " tot_energy += jr_ij * pm_meas[i, j] * pm_meas[i + 1, j]\n", 455 | " for i, jc_row in enumerate(jc):\n", 456 | " for j, jc_ij in enumerate(jc_row):\n", 457 | " tot_energy += jc_ij * pm_meas[i, j] * pm_meas[i, j + 1]\n", 458 | " return tot_energy\n", 459 | "\n", 460 | " return energy" 461 | ] 462 | }, 463 | { 464 | "cell_type": "markdown", 465 | "id": "dcb97e25", 466 | "metadata": {}, 467 | "source": [ 468 | "##### Define the expectation value of the energy" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 18, 474 | "id": "15b77870", 475 | "metadata": {}, 476 | "outputs": [], 477 | "source": [ 478 | "def obj_func(result):\n", 479 | " energy_hist = result.histogram(key=\"x\", fold_func=energy_func(length, h, jr, jc))\n", 480 | " return np.sum([k * v for k, v in energy_hist.items()]) / result.repetitions" 481 | ] 482 | }, 483 | { 484 | "cell_type": "markdown", 485 | "id": "528ec07c", 486 | "metadata": {}, 487 | "source": [ 488 | "##### Run the CPU VQE" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": 19, 494 | "id": "fafcfbba-4121-46d1-8853-9f3a8e3eb898", 495 | "metadata": {}, 496 | "outputs": [ 497 | { 498 | "name": "stdout", 499 | "output_type": "stream", 500 | "text": [ 501 | "CPU runtime: 11.51506900787353515625s\n", 502 | "Simulated ground-state energy expectation value is 8.362\n" 503 | ] 504 | } 505 | ], 506 | "source": [ 507 | "# Default CPU simulator VQE\n", 508 | "\n", 509 | "start = time.time()\n", 510 | "results = simulator.run(circuit, repetitions=10000)\n", 511 | "# print(results.histogram(key='x'))\n", 512 | "cpu_time = time.time() - start\n", 513 | "print(\"CPU runtime: {:.24}s\".format(cpu_time))\n", 514 | "print(f\"Simulated ground-state energy expectation value is {obj_func(results)}\")" 515 | ] 516 | }, 517 | { 518 | "cell_type": "markdown", 519 | "id": "ffa29702", 520 | "metadata": {}, 521 | "source": [ 522 | "##### Run the GPU VQE" 523 | ] 524 | }, 525 | { 526 | "cell_type": "code", 527 | "execution_count": 20, 528 | "id": "39b6c57f-7f8c-4515-bae7-f0e043ce163c", 529 | "metadata": {}, 530 | "outputs": [ 531 | { 532 | "name": "stdout", 533 | "output_type": "stream", 534 | "text": [ 535 | "GPU runtime: 3.359165191650390625s\n", 536 | "Simulated ground-state energy expectation value is 8.3536\n" 537 | ] 538 | } 539 | ], 540 | "source": [ 541 | "# cuQuantum GPU simulator VQE\n", 542 | "\n", 543 | "start = time.time()\n", 544 | "results = simulator_cuQ.run(circuit, repetitions=10000)\n", 545 | "# print(results.histogram(key='x'))\n", 546 | "gpu_time = time.time() - start\n", 547 | "print(\"GPU runtime: {:.24}s\".format(gpu_time))\n", 548 | "print(f\"Simulated ground-state energy expectation value is {obj_func(results)}\")" 549 | ] 550 | }, 551 | { 552 | "cell_type": "markdown", 553 | "id": "0e2e64aa", 554 | "metadata": {}, 555 | "source": [ 556 | "##### Calculate the GPU vs. CPU speedup" 557 | ] 558 | }, 559 | { 560 | "cell_type": "code", 561 | "execution_count": 21, 562 | "id": "826413d6-9ff8-4db5-97ca-1228fe1c9bcd", 563 | "metadata": { 564 | "tags": [] 565 | }, 566 | "outputs": [ 567 | { 568 | "name": "stdout", 569 | "output_type": "stream", 570 | "text": [ 571 | "GPU VQE was 3.428X faster than CPU VQE\n" 572 | ] 573 | } 574 | ], 575 | "source": [ 576 | "print(\"GPU VQE was \" + str(round(cpu_time / gpu_time, 3)) + \"X faster than CPU VQE\")" 577 | ] 578 | } 579 | ], 580 | "metadata": { 581 | "kernelspec": { 582 | "display_name": "Python 3 [Default]", 583 | "language": "python", 584 | "name": "python3" 585 | }, 586 | "language_info": { 587 | "codemirror_mode": { 588 | "name": "ipython", 589 | "version": 3 590 | }, 591 | "file_extension": ".py", 592 | "mimetype": "text/x-python", 593 | "name": "python", 594 | "nbconvert_exporter": "python", 595 | "pygments_lexer": "ipython3", 596 | "version": "3.9.18" 597 | } 598 | }, 599 | "nbformat": 4, 600 | "nbformat_minor": 5 601 | } 602 | -------------------------------------------------------------------------------- /qbraid_lab/gpu/lightning_gpu_benchmark.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "4adb185b-60d3-4054-ae78-13dffab84260", 6 | "metadata": {}, 7 | "source": [ 8 | "# Benchmarking circuit evaluation\n", 9 | "Amazon Braket SV1 vs Pennylane-Lightning-GPU" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "id": "7fc765c0-1f26-4728-8843-37e90b6badea", 16 | "metadata": {}, 17 | "outputs": [ 18 | { 19 | "name": "stdout", 20 | "output_type": "stream", 21 | "text": [ 22 | "\u001b[0;35mSuccessfully enabled qBraid Quantum Jobs in the \u001b[1;35mpennylane_gpu\u001b[0m\u001b[0;35m environment.\u001b[0m\n", 23 | "\u001b[0;35mEvery \u001b[1;35mAWS\u001b[0m\u001b[0;35m job you run will now be submitted through the qBraid API, so no access keys/tokens are necessary. \u001b[0m\n", 24 | "\n", 25 | "\u001b[0;35mTo disable, run:\u001b[0m `qbraid jobs disable pennylane_gpu`\n" 26 | ] 27 | } 28 | ], 29 | "source": [ 30 | "!qbraid jobs enable pennylane_gpu" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 2, 36 | "id": "9edeaa35-a288-4b22-8b58-f41eaaac8f3c", 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "name": "stdout", 41 | "output_type": "stream", 42 | "text": [ 43 | "# installed environments:\n", 44 | "#\n", 45 | "default \u001b[0;31mjobs\u001b[0m /opt/.qbraid/environments/qbraid_000000\n", 46 | "qsharp /opt/.qbraid/environments/qsharp_b54crn\n", 47 | "intel /opt/.qbraid/environments/intel_zr7hfq\n", 48 | "bloqade /opt/.qbraid/environments/bloqade_374m88\n", 49 | "qiskit_gpu /home/jovyan/.qbraid/environments/qiskit_gpu_tyt64d\n", 50 | "tensorflow /home/jovyan/.qbraid/environments/tensorflow_uorhf3\n", 51 | "pennylane_gpu \u001b[0;32mjobs\u001b[0m /home/jovyan/.qbraid/environments/pennylane_gpu_21uik3\n", 52 | "qbraid_sdk \u001b[0;31mjobs\u001b[0m /home/jovyan/.qbraid/environments/qbraid_sdk_9j9sjy\n", 53 | "\n" 54 | ] 55 | } 56 | ], 57 | "source": [ 58 | "!qbraid envs list" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 3, 64 | "id": "dcb438f5-a1cc-477c-83b0-178613e6f9c4", 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "name": "stdout", 69 | "output_type": "stream", 70 | "text": [ 71 | "Thu Jul 20 01:30:43 2023 \n", 72 | "+-----------------------------------------------------------------------------+\n", 73 | "| NVIDIA-SMI 470.182.03 Driver Version: 470.182.03 CUDA Version: 11.5 |\n", 74 | "|-------------------------------+----------------------+----------------------+\n", 75 | "| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\n", 76 | "| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\n", 77 | "| | | MIG M. |\n", 78 | "|===============================+======================+======================|\n", 79 | "| 0 Tesla T4 On | 00000000:00:1E.0 Off | 0 |\n", 80 | "| N/A 36C P8 9W / 70W | 0MiB / 15109MiB | 0% Default |\n", 81 | "| | | N/A |\n", 82 | "+-------------------------------+----------------------+----------------------+\n", 83 | " \n", 84 | "+-----------------------------------------------------------------------------+\n", 85 | "| Processes: |\n", 86 | "| GPU GI CI PID Type Process name GPU Memory |\n", 87 | "| ID ID Usage |\n", 88 | "|=============================================================================|\n", 89 | "| No running processes found |\n", 90 | "+-----------------------------------------------------------------------------+\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "!nvidia-smi" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 4, 101 | "id": "6ff1b488-279c-43d1-8f7c-418643aae70f", 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "name": "stdout", 106 | "output_type": "stream", 107 | "text": [ 108 | "Name: PennyLane\n", 109 | "Version: 0.31.0\n", 110 | "Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.\n", 111 | "Home-page: https://github.com/PennyLaneAI/pennylane\n", 112 | "Author: \n", 113 | "Author-email: \n", 114 | "License: Apache License 2.0\n", 115 | "Location: /home/jovyan/.qbraid/environments/pennylane_gpu_21uik3/pyenv/lib/python3.9/site-packages\n", 116 | "Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml\n", 117 | "Required-by: amazon-braket-pennylane-plugin, PennyLane-Lightning, PennyLane-Lightning-GPU\n", 118 | "\n", 119 | "Platform info: Linux-5.4.247-162.350.amzn2.x86_64-x86_64-with-glibc2.31\n", 120 | "Python version: 3.9.12\n", 121 | "Numpy version: 1.23.5\n", 122 | "Scipy version: 1.10.0\n", 123 | "Installed devices:\n", 124 | "- default.gaussian (PennyLane-0.31.0)\n", 125 | "- default.mixed (PennyLane-0.31.0)\n", 126 | "- default.qubit (PennyLane-0.31.0)\n", 127 | "- default.qubit.autograd (PennyLane-0.31.0)\n", 128 | "- default.qubit.jax (PennyLane-0.31.0)\n", 129 | "- default.qubit.tf (PennyLane-0.31.0)\n", 130 | "- default.qubit.torch (PennyLane-0.31.0)\n", 131 | "- default.qutrit (PennyLane-0.31.0)\n", 132 | "- null.qubit (PennyLane-0.31.0)\n", 133 | "- lightning.qubit (PennyLane-Lightning-0.31.0)\n", 134 | "- lightning.gpu (PennyLane-Lightning-GPU-0.31.0)\n", 135 | "- braket.aws.ahs (amazon-braket-pennylane-plugin-1.17.4)\n", 136 | "- braket.aws.qubit (amazon-braket-pennylane-plugin-1.17.4)\n", 137 | "- braket.local.ahs (amazon-braket-pennylane-plugin-1.17.4)\n", 138 | "- braket.local.qubit (amazon-braket-pennylane-plugin-1.17.4)\n" 139 | ] 140 | } 141 | ], 142 | "source": [ 143 | "import pennylane as qml\n", 144 | "from pennylane import numpy as np\n", 145 | "\n", 146 | "qml.about()" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 5, 152 | "id": "c1fdbb19-554e-4952-a8b6-985e4fa7c5c1", 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "n_wires = 12\n", 157 | "\n", 158 | "dev_braket = dev = qml.device(\n", 159 | " \"braket.aws.qubit\",\n", 160 | " device_arn=\"arn:aws:braket:::device/quantum-simulator/amazon/sv1\",\n", 161 | " wires=n_wires,\n", 162 | ")\n", 163 | "dev_gpu = qml.device(\"lightning.gpu\", wires=n_wires)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 6, 169 | "id": "d8d75ade-9718-4142-ac47-778cdf33df3b", 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "def circuit(params):\n", 174 | " for i in range(n_wires):\n", 175 | " qml.RX(params[i], wires=i)\n", 176 | " for i in range(n_wires):\n", 177 | " qml.CNOT(wires=[i, (i + 1) % n_wires])\n", 178 | "\n", 179 | " # Measure all qubits\n", 180 | " observables = [qml.PauliZ(n_wires - 1)] + [qml.Identity(i) for i in range(n_wires - 1)]\n", 181 | " return qml.expval(qml.operation.Tensor(*observables))" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 7, 187 | "id": "bacb272a-3b6a-4891-8091-bcf50d5a63c3", 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [ 191 | "qnode_braket = qml.QNode(circuit, dev_braket)\n", 192 | "qnode_gpu = qml.QNode(circuit, dev_gpu)" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 8, 198 | "id": "356b4fd7-a81b-4043-b078-95551cb3cb54", 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "name": "stdout", 203 | "output_type": "stream", 204 | "text": [ 205 | "Execution time on Braket SV1 device (seconds): 12.66253662109375\n", 206 | "Execution time on Lightning GPU device (seconds): 0.9639229774475098\n" 207 | ] 208 | } 209 | ], 210 | "source": [ 211 | "import time\n", 212 | "\n", 213 | "params = np.random.random(n_wires)\n", 214 | "\n", 215 | "t_0_braket = time.time()\n", 216 | "qnode_braket(params)\n", 217 | "t_1_braket = time.time()\n", 218 | "\n", 219 | "t_0_gpu = time.time()\n", 220 | "qnode_gpu(params)\n", 221 | "t_1_gpu = time.time()\n", 222 | "\n", 223 | "print(\"Execution time on Braket SV1 device (seconds):\", t_1_braket - t_0_braket)\n", 224 | "\n", 225 | "print(\"Execution time on Lightning GPU device (seconds):\", t_1_gpu - t_0_gpu)" 226 | ] 227 | } 228 | ], 229 | "metadata": { 230 | "kernelspec": { 231 | "display_name": "Python 3 [Lightning]", 232 | "language": "python", 233 | "name": "python3_pennylane_gpu_21uik3" 234 | }, 235 | "language_info": { 236 | "codemirror_mode": { 237 | "name": "ipython", 238 | "version": 3 239 | }, 240 | "file_extension": ".py", 241 | "mimetype": "text/x-python", 242 | "name": "python", 243 | "nbconvert_exporter": "python", 244 | "pygments_lexer": "ipython3", 245 | "version": "3.9.12" 246 | } 247 | }, 248 | "nbformat": 4, 249 | "nbformat_minor": 5 250 | } 251 | -------------------------------------------------------------------------------- /qbraid_lab/quantum_jobs/aws_quantum_jobs.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d46c2073-d5af-4272-b434-f6fc712b1f33", 6 | "metadata": {}, 7 | "source": [ 8 | "# qBraid Quantum Jobs: AWS Devices + Amazon Braket" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "de7f060e", 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "Note: you may need to restart the kernel to use updated packages.\n" 22 | ] 23 | } 24 | ], 25 | "source": [ 26 | "%pip install -q amazon-braket-sdk" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "id": "e668cc2b-2107-4f2a-bc65-1aa6da9b72cf", 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "# !qbraid configure magic" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 3, 42 | "id": "829a72b8", 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "%load_ext qbraid_magic" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 4, 52 | "id": "c962fcc4-6e09-43b9-af3f-13b8bd36bc3e", 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "qbraid-cli/0.9.0a0\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "%qbraid --version" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 5, 70 | "id": "1635d207-9650-4bb5-9f72-9a386021858c", 71 | "metadata": {}, 72 | "outputs": [ 73 | { 74 | "name": "stdout", 75 | "output_type": "stream", 76 | "text": [ 77 | "\n", 78 | "qBraid quantum jobs already \u001b[1;32menabled\u001b[0m for \u001b[35mbraket\u001b[0m.\n", 79 | "\n", 80 | "Check the state of all quantum jobs libraries in this environment with: \n", 81 | "\n", 82 | " $ qbraid jobs state\n", 83 | "\n" 84 | ] 85 | } 86 | ], 87 | "source": [ 88 | "%qbraid jobs enable braket -y" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 6, 94 | "id": "c2faa670-1fe9-47f2-9cfe-d488517914a3", 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "Executable: \u001b[35m/opt/.qbraid/environments/qbraid_000000/pyenv/bin/\u001b[0m\u001b[95mpython\u001b[0m\n", 102 | "\n", 103 | "\u001b[1mLibrary State\u001b[0m\n", 104 | "braket \u001b[32menabled\u001b[0m\n", 105 | "\n" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "%qbraid jobs state" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 7, 116 | "id": "f17a39b3-74b6-4798-9d8c-164d884e1251", 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "name": "stdout", 121 | "output_type": "stream", 122 | "text": [ 123 | "\n", 124 | "qBraid credits remaining: 1912.9763\n", 125 | "\n", 126 | "For more information, visit: \u001b[4;94mhttps://docs.qbraid.com/home/pricing#credits\u001b[0m\n" 127 | ] 128 | } 129 | ], 130 | "source": [ 131 | "%qbraid account credits" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 8, 137 | "id": "e7fb9ec2-0500-4fd7-b9a5-952805764efc", 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "name": "stdout", 142 | "output_type": "stream", 143 | "text": [ 144 | "T : │ 0 │ 1 │\n", 145 | " ┌───┐ \n", 146 | "q0 : ─┤ H ├───●───\n", 147 | " └───┘ │ \n", 148 | " ┌─┴─┐ \n", 149 | "q1 : ───────┤ X ├─\n", 150 | " └───┘ \n", 151 | "T : │ 0 │ 1 │\n" 152 | ] 153 | } 154 | ], 155 | "source": [ 156 | "import boto3\n", 157 | "from braket.aws import AwsDevice\n", 158 | "from braket.circuits import Circuit\n", 159 | "\n", 160 | "# create the Amazon Braket circuit\n", 161 | "bell = Circuit().h(0).cnot(0, 1)\n", 162 | "\n", 163 | "print(bell)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 9, 169 | "id": "9319ff25-f872-4cf4-8943-8453aaaa3ada", 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "# choose the cloud-based on-demand simulator to run your circuit\n", 174 | "device = AwsDevice(\"arn:aws:braket:::device/quantum-simulator/amazon/sv1\")\n", 175 | "\n", 176 | "## UNCOMMENT THE FOLLOWING LINE TO ACCESS ARIA:\n", 177 | "# device = AwsDevice(\"arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1\")" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 10, 183 | "id": "d839f8db-0928-464f-9b26-06d89741bd05", 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "# execute the circuit\n", 188 | "task = device.run(bell, shots=100)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 11, 194 | "id": "602ae9e2-675f-4a7d-8ad2-8dded3c19ca4", 195 | "metadata": {}, 196 | "outputs": [ 197 | { 198 | "name": "stdout", 199 | "output_type": "stream", 200 | "text": [ 201 | "Counter({'00': 56, '11': 44})\n" 202 | ] 203 | } 204 | ], 205 | "source": [ 206 | "# display the results\n", 207 | "print(task.result().measurement_counts)" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 12, 213 | "id": "fb323eeb-2f53-4fa1-b8e4-d915caf57981", 214 | "metadata": {}, 215 | "outputs": [], 216 | "source": [ 217 | "# %qbraid jobs list" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": 13, 223 | "id": "2b0a87d2-865b-4d52-a01b-ccc1cf01c707", 224 | "metadata": {}, 225 | "outputs": [ 226 | { 227 | "name": "stdout", 228 | "output_type": "stream", 229 | "text": [ 230 | "\n", 231 | "qBraid credits remaining: 1909.2263\n", 232 | "\n", 233 | "For more information, visit: \u001b[4;94mhttps://docs.qbraid.com/home/pricing#credits\u001b[0m\n" 234 | ] 235 | } 236 | ], 237 | "source": [ 238 | "# check remaining qBraid credits\n", 239 | "%qbraid account credits" 240 | ] 241 | } 242 | ], 243 | "metadata": { 244 | "kernelspec": { 245 | "display_name": "Python 3 [Default]", 246 | "language": "python", 247 | "name": "python3" 248 | }, 249 | "language_info": { 250 | "codemirror_mode": { 251 | "name": "ipython", 252 | "version": 3 253 | }, 254 | "file_extension": ".py", 255 | "mimetype": "text/x-python", 256 | "name": "python", 257 | "nbconvert_exporter": "python", 258 | "pygments_lexer": "ipython3", 259 | "version": "3.11.9" 260 | } 261 | }, 262 | "nbformat": 4, 263 | "nbformat_minor": 5 264 | } 265 | -------------------------------------------------------------------------------- /qbraid_qir/rigetti_qvm_sim.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# qBraid-QIR: Rigetti QVM simulation example" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Install necessary dependencies" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "%pip install qbraid-qir cirq-core azure-quantum --quiet" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "Develop program with Cirq" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "import cirq\n", 40 | "\n", 41 | "q0, q1 = cirq.LineQubit.range(2)\n", 42 | "circuit = cirq.Circuit(cirq.H(q0), cirq.CNOT(q0, q1), cirq.measure(q0, q1))\n", 43 | "\n", 44 | "print(circuit)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "Compile program to QIR" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "from qbraid_qir.cirq import cirq_to_qir\n", 61 | "\n", 62 | "module = cirq_to_qir(circuit, name=\"bell\")\n", 63 | "\n", 64 | "print(str(module))" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "Submit program to Rigetti via Azure Quantum Cloud" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "
\n", 79 | " Note: You will have to open a terminal and run az login to make sure your Azure credentials are stored.\n", 80 | "
" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "import azure.quantum\n", 90 | "from azure.identity import AzureCliCredential\n", 91 | "\n", 92 | "workspace = azure.quantum.Workspace(\n", 93 | " subscription_id=\"\",\n", 94 | " resource_group=\"AzureQuantum\",\n", 95 | " name=\"qir-demo\",\n", 96 | " location=\"westus\",\n", 97 | " credential=AzureCliCredential(),\n", 98 | ")" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "job = azure.quantum.Job.from_input_data(\n", 108 | " workspace=workspace,\n", 109 | " name=\"qir-demo\",\n", 110 | " provider_id=\"rigetti\",\n", 111 | " target=\"rigetti.sim.qvm\",\n", 112 | " input_data_format=\"qir.v1\",\n", 113 | " output_data_format=\"microsoft.quantum-results.v1\",\n", 114 | " input_data=module.bitcode,\n", 115 | " input_params={\"shots\": 1, \"entryPoint\": \"main\", \"arguments\": []},\n", 116 | ")\n", 117 | "\n", 118 | "info = job.details.as_dict()" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "job.get_results()" 128 | ] 129 | } 130 | ], 131 | "metadata": { 132 | "kernelspec": { 133 | "display_name": "qbraid-qir", 134 | "language": "python", 135 | "name": "python3" 136 | }, 137 | "language_info": { 138 | "codemirror_mode": { 139 | "name": "ipython", 140 | "version": 3 141 | }, 142 | "file_extension": ".py", 143 | "mimetype": "text/x-python", 144 | "name": "python", 145 | "nbconvert_exporter": "python", 146 | "pygments_lexer": "ipython3", 147 | "version": "3.11.5" 148 | } 149 | }, 150 | "nbformat": 4, 151 | "nbformat_minor": 2 152 | } 153 | -------------------------------------------------------------------------------- /qbraid_sdk/README.md: -------------------------------------------------------------------------------- 1 | # qBraid-SDK Examples 2 | 3 | *Note*: Some notebooks run quantum jobs activated via qBraid CLI, available only through qBraid Lab platform. 4 | 5 | -------------------------------------------------------------------------------- /qbraid_sdk/bell_circuit_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from braket.circuits import Circuit\n", 10 | "\n", 11 | "from qbraid import QbraidProvider\n", 12 | "\n", 13 | "circuit = Circuit()\n", 14 | "circuit.h(0)\n", 15 | "circuit.cnot(0, 1)\n", 16 | "circuit.measure([0, 1])\n", 17 | "\n", 18 | "provider = QbraidProvider()\n", 19 | "\n", 20 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 21 | "\n", 22 | "job = device.run(circuit, shots=100)" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "from qiskit import QuantumCircuit\n", 32 | "\n", 33 | "from qbraid import QbraidProvider\n", 34 | "\n", 35 | "circuit = QuantumCircuit(2, 2)\n", 36 | "\n", 37 | "circuit.h(0)\n", 38 | "circuit.cx(0, 1)\n", 39 | "circuit.measure([0, 1], [0, 1])\n", 40 | "\n", 41 | "provider = QbraidProvider()\n", 42 | "\n", 43 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 44 | "\n", 45 | "job = device.run(circuit, shots=100)" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "from cirq import Circuit, LineQubit, ops\n", 55 | "\n", 56 | "from qbraid import QbraidProvider\n", 57 | "\n", 58 | "q0, q1 = LineQubit.range(2)\n", 59 | "circuit = Circuit(ops.H(q0), ops.CNOT(q0, q1), ops.measure(q0, q1))\n", 60 | "\n", 61 | "provider = QbraidProvider()\n", 62 | "\n", 63 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 64 | "\n", 65 | "job = device.run(circuit, shots=100)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "import pennylane as qml\n", 75 | "from pennylane.tape import QuantumTape\n", 76 | "\n", 77 | "from qbraid import QbraidProvider\n", 78 | "\n", 79 | "with QuantumTape() as tape:\n", 80 | " qml.Hadamard(wires=0)\n", 81 | " qml.CNOT(wires=[0, 1])\n", 82 | " qml.sample(wires=[0, 1])\n", 83 | "\n", 84 | "provider = QbraidProvider()\n", 85 | "\n", 86 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 87 | "\n", 88 | "job = device.run(tape, shots=100)" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "from pyquil import Program\n", 98 | "from pyquil.gates import CNOT, MEASURE, H\n", 99 | "\n", 100 | "from qbraid import QbraidProvider\n", 101 | "\n", 102 | "program = Program()\n", 103 | "\n", 104 | "ro = program.declare(\"ro\", \"BIT\", 2)\n", 105 | "program += H(0)\n", 106 | "program += CNOT(0, 1)\n", 107 | "\n", 108 | "program += MEASURE(0, ro[0])\n", 109 | "program += MEASURE(1, ro[1])\n", 110 | "\n", 111 | "provider = QbraidProvider()\n", 112 | "\n", 113 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 114 | "\n", 115 | "job = device.run(program, shots=100)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "from pytket.circuit import Circuit\n", 125 | "\n", 126 | "from qbraid import QbraidProvider\n", 127 | "\n", 128 | "circuit = Circuit(2)\n", 129 | "circuit.H(0)\n", 130 | "circuit.CX(0, 1)\n", 131 | "circuit.measure_all()\n", 132 | "\n", 133 | "provider = QbraidProvider()\n", 134 | "\n", 135 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 136 | "\n", 137 | "job = device.run(circuit, shots=100)" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": null, 143 | "metadata": {}, 144 | "outputs": [], 145 | "source": [ 146 | "from qbraid import QbraidProvider\n", 147 | "\n", 148 | "qasm = \"\"\"\n", 149 | "OPENQASM 3;\n", 150 | "include \"stdgates.inc\";\n", 151 | "qubit[2] q;\n", 152 | "bit[2] b;\n", 153 | "h q[0];\n", 154 | "cx q[0], q[1];\n", 155 | "b[0] = measure q[0];\n", 156 | "b[1] = measure q[1];\n", 157 | "\"\"\"\n", 158 | "\n", 159 | "provider = QbraidProvider()\n", 160 | "\n", 161 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 162 | "\n", 163 | "job = device.run(qasm, shots=100)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "from stim import Circuit\n", 173 | "\n", 174 | "from qbraid import QbraidProvider\n", 175 | "\n", 176 | "circuit = Circuit()\n", 177 | "circuit.append_operation(\"H\", [0])\n", 178 | "circuit.append_operation(\"CNOT\", [0, 1])\n", 179 | "circuit.append_operation(\"M\", [0, 1])\n", 180 | "\n", 181 | "provider = QbraidProvider()\n", 182 | "\n", 183 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 184 | "\n", 185 | "job = device.run(circuit, shots=100)" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": null, 191 | "metadata": {}, 192 | "outputs": [], 193 | "source": [ 194 | "import cudaq\n", 195 | "\n", 196 | "from qbraid import QbraidProvider\n", 197 | "\n", 198 | "kernel = cudaq.make_kernel()\n", 199 | "\n", 200 | "qubits = kernel.qalloc(2)\n", 201 | "\n", 202 | "kernel.h(qubits[0])\n", 203 | "kernel.cx(qubits[0], qubits[1])\n", 204 | "\n", 205 | "kernel.mz(qubits)\n", 206 | "\n", 207 | "provider = QbraidProvider()\n", 208 | "\n", 209 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 210 | "\n", 211 | "job = device.run(kernel, shots=100)" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": null, 217 | "metadata": {}, 218 | "outputs": [], 219 | "source": [ 220 | "from pyqir import BasicQisBuilder, SimpleModule\n", 221 | "\n", 222 | "from qbraid import QbraidProvider\n", 223 | "\n", 224 | "bell = SimpleModule(\"bell_pair\", num_qubits=2, num_results=2)\n", 225 | "\n", 226 | "qis = BasicQisBuilder(bell.builder)\n", 227 | "\n", 228 | "qis.h(bell.qubits[0])\n", 229 | "qis.cx(bell.qubits[0], bell.qubits[1])\n", 230 | "qis.mz(bell.qubits[0], bell.results[0])\n", 231 | "qis.mz(bell.qubits[1], bell.results[1])\n", 232 | "\n", 233 | "bell.builder.ret(None)\n", 234 | "\n", 235 | "module = bell._module\n", 236 | "module.verify()\n", 237 | "\n", 238 | "provider = QbraidProvider()\n", 239 | "\n", 240 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 241 | "\n", 242 | "job = device.run(module, shots=100)" 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": null, 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "from qibo import Circuit\n", 252 | "from qibo.gates import CNOT, H, M\n", 253 | "\n", 254 | "from qbraid import QbraidProvider\n", 255 | "\n", 256 | "circuit = Circuit(2)\n", 257 | "circuit.add(H(0))\n", 258 | "circuit.add(CNOT(0, 1))\n", 259 | "circuit.add(M(0, 1))\n", 260 | "\n", 261 | "provider = QbraidProvider()\n", 262 | "\n", 263 | "device = provider.get_device(\"qbraid_qir_simulator\")\n", 264 | "\n", 265 | "job = device.run(circuit, shots=100)" 266 | ] 267 | } 268 | ], 269 | "metadata": { 270 | "kernelspec": { 271 | "display_name": "Python 3 [qBraid]", 272 | "language": "python", 273 | "name": "python3_qbraid_sdk_9j9sjy" 274 | }, 275 | "language_info": { 276 | "codemirror_mode": { 277 | "name": "ipython", 278 | "version": 3 279 | }, 280 | "file_extension": ".py", 281 | "mimetype": "text/x-python", 282 | "name": "python", 283 | "nbconvert_exporter": "python", 284 | "pygments_lexer": "ipython3", 285 | "version": "3.11.9" 286 | } 287 | }, 288 | "nbformat": 4, 289 | "nbformat_minor": 4 290 | } 291 | -------------------------------------------------------------------------------- /qbraid_sdk/ibm_batch_jobs_grovers.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "ac6f7b61-1fa3-476d-b6ce-48b1237e8df5", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "# This notebook is derived from Qiskit and includes modifications by qBraid.\n", 11 | "#\n", 12 | "# (C) Copyright IBM 2020.\n", 13 | "# (C) Copyright qBraid 2024.\n", 14 | "#\n", 15 | "# This code is licensed under the Apache License, Version 2.0. You may\n", 16 | "# obtain a copy of this license in the LICENSE.txt file in the root directory\n", 17 | "# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.\n", 18 | "#\n", 19 | "# Any modifications or derivative works of this code must retain this\n", 20 | "# copyright notice, and modified files need to carry a notice indicating\n", 21 | "# that they have been altered from the originals." 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "id": "88b49726-b1d6-4bbf-b3eb-aaa9a384b811", 27 | "metadata": {}, 28 | "source": [ 29 | "# qBraid-SDK IBM Batch Jobs Demo: Grover's Algorithm\n" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "id": "c58a6923-26f6-4d27-8a6e-32323e4484d1", 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "import qbraid\n", 40 | "\n", 41 | "qbraid.__version__" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "id": "2408ab07-9f93-461a-9384-b5e4436411e8", 47 | "metadata": {}, 48 | "source": [ 49 | "## Creating the Circuits" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "id": "984a0746-808a-4d06-9adb-2d7513dead36", 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "import numpy as np\n", 60 | "\n", 61 | "from qiskit import QuantumCircuit" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "id": "a43474a4-5880-47af-9701-498d2e8d658b", 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "%pip install pylatexenc #Install pylatexenc to use the \"mpl\" circuit visualization sytle." 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "7b97a410-48ff-4b68-96d0-1e0e63de92ae", 77 | "metadata": {}, 78 | "source": [ 79 | "The code for this circuit was taken from IBMs [Qiskit Textbook](https://learn.qiskit.org/course/ch-algorithms/grovers-algorithm). Grover's algorithm let's us find a marked item in a box in √N steps as opposed to N steps classicaly. In this case we'll run Grover's algorithm for various numbers of steps to observe how the performance varies." 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "id": "1eba1979-e8c7-4388-aa3a-29e3a1ff7cef", 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "n = 3\n", 90 | "marked_entry = np.random.randint(0, 2**n - 1)\n", 91 | "print(\"marked entry: \", marked_entry)" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "id": "17c2cef0-5746-4558-a3af-51890b7ebd8c", 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "# Circuit from qiskit textbook\n", 102 | "def initialize_s(qc, qubits):\n", 103 | " \"\"\"Apply a H-gate to 'qubits' in qc\"\"\"\n", 104 | " for q in qubits:\n", 105 | " qc.h(q)\n", 106 | " return qc\n", 107 | "\n", 108 | "\n", 109 | "def diffuser(nqubits):\n", 110 | " qc = QuantumCircuit(nqubits)\n", 111 | " # Apply transformation |s> -> |00..0> (H-gates)\n", 112 | " for qubit in range(nqubits):\n", 113 | " qc.h(qubit)\n", 114 | " # Apply transformation |00..0> -> |11..1> (X-gates)\n", 115 | " for qubit in range(nqubits):\n", 116 | " qc.x(qubit)\n", 117 | " # Do multi-controlled-Z gate\n", 118 | " qc.h(nqubits - 1)\n", 119 | " qc.mcx(list(range(nqubits - 1)), nqubits - 1) # multi-controlled-toffoli\n", 120 | " qc.h(nqubits - 1)\n", 121 | " # Apply transformation |11..1> -> |00..0>\n", 122 | " for qubit in range(nqubits):\n", 123 | " qc.x(qubit)\n", 124 | " # Apply transformation |00..0> -> |s>\n", 125 | " for qubit in range(nqubits):\n", 126 | " qc.h(qubit)\n", 127 | " # We will return the diffuser as a gate\n", 128 | " U_s = qc.to_gate()\n", 129 | " U_s.name = \"U$_s$\"\n", 130 | " return U_s\n", 131 | "\n", 132 | "\n", 133 | "qc = QuantumCircuit(3)\n", 134 | "qc.cz(0, 2)\n", 135 | "qc.cz(1, 2)\n", 136 | "oracle_ex3 = qc.to_gate()\n", 137 | "oracle_ex3.name = \"U$_\\omega$\"\n", 138 | "\n", 139 | "grover_circuit = QuantumCircuit(n)\n", 140 | "\n", 141 | "grover_circuit.append(oracle_ex3, [0, 1, 2])\n", 142 | "grover_circuit.append(diffuser(n), [0, 1, 2])\n", 143 | "\n", 144 | "grover_circuit.draw(\"mpl\")" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "id": "2cc8b575-f61f-456c-b185-340a909aa6fe", 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [ 154 | "# create list of circuits to run\n", 155 | "n_steps = 3\n", 156 | "grover_init = QuantumCircuit(grover_circuit.num_qubits, grover_circuit.num_qubits)\n", 157 | "grover_init.h(range(n)) # add the Hadamards\n", 158 | "circuits = [grover_init] # circuits[j] will have (VW)**j:\n", 159 | "for _ in range(n_steps):\n", 160 | " circuits.append(circuits[-1].compose(grover_circuit))\n", 161 | "for grover in circuits:\n", 162 | " grover.measure(range(n), range(n)) # add measurements" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "id": "d5196c00-47e9-42d8-932d-31cf6c6757de", 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "from qbraid.visualization import circuit_drawer\n", 173 | "\n", 174 | "circuit_drawer(circuits[3], output=\"mpl\")" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "id": "879a9d4e-88d2-4bd6-8681-2e67a93f075d", 180 | "metadata": {}, 181 | "source": [ 182 | "Now that we've created our Grover circuit for n = 0, 1, 2, and 3, we can simply pass the `circuits` array" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "id": "43dfd23a-29b4-40fb-9b8b-b14f9c83621e", 188 | "metadata": {}, 189 | "source": [ 190 | "# Running the Circuits" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "id": "ac24da6b", 196 | "metadata": {}, 197 | "source": [ 198 | "Now let's load in our IBM account. Note that you'll have to have IBM credentials to run this notebook. You can follow the instructions [here](https://github.com/Qiskit/qiskit-ibm-provider#provider-setup) to set them up." 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "id": "653f5850", 204 | "metadata": {}, 205 | "source": [ 206 | "Check which devices are online:" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "id": "0cfd0932-88fe-4d64-b3a8-ec6eb806b999", 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "from qbraid.runtime.ibm import QiskitRuntimeProvider\n", 217 | "\n", 218 | "provider = QiskitRuntimeProvider(\"YOUR_API_KEY\")\n", 219 | "provider.get_devices()" 220 | ] 221 | }, 222 | { 223 | "cell_type": "markdown", 224 | "id": "4e4f1c13-9949-4d6f-a887-b87afbb95407", 225 | "metadata": {}, 226 | "source": [ 227 | "In this tutorial we'll use IBM's Kyiv computer, since we see that it's online. Now we can use qBraid's `QuantumDevice` to run this job. The device wrapper adds a layer of abstraction, allowing us to run more types of circuits on more devices, and in this case letting us use the `run_batch` method. " 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "id": "cd3a76cc-5ec0-4139-910a-0cc21269b128", 233 | "metadata": {}, 234 | "source": [ 235 | "Batch experiments combine individual experiments on any subset of qubits into a single composite experiment which appends all the circuits from each component experiment into a single batch of circuits to be executed as one experiment job. This is useful because it allows us to run multiple circuits in parallel. It is especially useful for situations like this, where we want to run many similar circuits and collectively analyze their results" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": null, 241 | "id": "31c1b440-6c79-4b97-b7a6-9a0aa6703c4d", 242 | "metadata": {}, 243 | "outputs": [], 244 | "source": [ 245 | "device = provider.get_device(\"ibm_kyiv\")\n", 246 | "\n", 247 | "print(device)" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "id": "1ba007b5-ae3c-4223-92ee-e2fe5ee2653e", 254 | "metadata": {}, 255 | "outputs": [], 256 | "source": [ 257 | "job = device.run(circuits, shots=100)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "id": "8e5895a1-c977-4e8a-bd5a-e365a66d17c5", 264 | "metadata": {}, 265 | "outputs": [], 266 | "source": [ 267 | "job.status()" 268 | ] 269 | }, 270 | { 271 | "cell_type": "markdown", 272 | "id": "a85c3e7d", 273 | "metadata": {}, 274 | "source": [ 275 | "Since it takes awhile to run, we grab the id directly after it finishes. You can use the [qBraid API](https://docs.qbraid.com/api-reference/api-reference/get-quantum-jobs#get-jobs) to find the job ID for your job. " 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": null, 281 | "id": "aaf0e4fa-f163-4b9b-9b25-629c44424d4b", 282 | "metadata": {}, 283 | "outputs": [], 284 | "source": [ 285 | "from qbraid.runtime.ibm import QiskitJob\n", 286 | "\n", 287 | "job = QiskitJob(\"YOUR_JOB_ID\", device=device)\n", 288 | "\n", 289 | "job.status()" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "id": "23bab44e-ab8f-443a-a9ec-d23c2b244345", 296 | "metadata": {}, 297 | "outputs": [], 298 | "source": [ 299 | "batch_result = job.result()\n", 300 | "batch_counts = batch_result.measurement_counts()\n", 301 | "\n", 302 | "for count in batch_counts:\n", 303 | " print(count)" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "id": "ea1ad431-980f-4b8e-a131-cd923e3f5163", 309 | "metadata": {}, 310 | "source": [ 311 | "We see that our results line up roughly with the theoretical prediction in the textbook. With 0 grover steps, the probability is basically evenly distributed. At one step, we see it is roughly 80% correct, as we expect. The probability then peaks at 2 steps and dips again at 3 steps." 312 | ] 313 | } 314 | ], 315 | "metadata": { 316 | "kernelspec": { 317 | "display_name": "Python 3 [qBraid]", 318 | "language": "python", 319 | "name": "python3_qbraid_sdk_9j9sjy" 320 | }, 321 | "language_info": { 322 | "codemirror_mode": { 323 | "name": "ipython", 324 | "version": 3 325 | }, 326 | "file_extension": ".py", 327 | "mimetype": "text/x-python", 328 | "name": "python", 329 | "nbconvert_exporter": "python", 330 | "pygments_lexer": "ipython3", 331 | "version": "3.11.9" 332 | } 333 | }, 334 | "nbformat": 4, 335 | "nbformat_minor": 5 336 | } 337 | -------------------------------------------------------------------------------- /qbraid_sdk/img/ibm_api_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qBraid/qbraid-lab-demo/e3ebac3e181894128da8f8f4ec3c3487246c2be8/qbraid_sdk/img/ibm_api_token.png -------------------------------------------------------------------------------- /qbraid_sdk/qbraid_runtime_ionq_provider.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# qbraid.runtime.ionq\n", 8 | "\n", 9 | "The [qBraid-SDK](https://github.com/qBraid/qBraid) is platform-agnostic quantum runtime framework. Distinguishing itself through a streamlined and highly-configurable approach to cross-platform integration, the qBraid-SDK does not assume a fixed target software framework. Instead, it allows providers to dynamically register any desired run input program type as the target, depending on their specific needs." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%%capture\n", 19 | "\n", 20 | "# First, we install the essential libraries to our current Python runtime.\n", 21 | "# \"%%capture\" (above) captures and in this case, hides the output of this\n", 22 | "# cell, so you can comment it out if you need help debugging this step.\n", 23 | "\n", 24 | "%pip install 'qbraid[ionq,visualization]'" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [ 32 | { 33 | "name": "stdin", 34 | "output_type": "stream", 35 | "text": [ 36 | "Enter your IonQ API key: ········\n" 37 | ] 38 | } 39 | ], 40 | "source": [ 41 | "import os\n", 42 | "from getpass import getpass\n", 43 | "from qbraid.runtime import IonQProvider\n", 44 | "\n", 45 | "# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n", 46 | "\n", 47 | "# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n", 48 | "# should find it. Otherwise you'll be prompted to enter your API key manually.\n", 49 | "\n", 50 | "api_key = os.getenv(\"IONQ_API_KEY\") or getpass(\"Enter your IonQ API key: \")\n", 51 | "\n", 52 | "provider = IonQProvider(api_key=api_key)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 3, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "# Now we set up our circuit. In this case, we're creating a circuit with two\n", 62 | "# qubits, applying an H gate to qubit-0, a CXGate to both,.\n", 63 | "\n", 64 | "program = \"\"\"\n", 65 | "OPENQASM 2;\n", 66 | "include \"stdgates.inc\";\n", 67 | "qubit[2] q;\n", 68 | "h q[0];\n", 69 | "cx q[0], q[1];\n", 70 | "\"\"\"" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 4, 76 | "metadata": {}, 77 | "outputs": [ 78 | { 79 | "name": "stdout", 80 | "output_type": "stream", 81 | "text": [ 82 | " |---|\n", 83 | "q0---| h |-----■---\n", 84 | " |---| |\n", 85 | " |----|\n", 86 | "q1----------| cx |-\n", 87 | " |----|\n" 88 | ] 89 | } 90 | ], 91 | "source": [ 92 | "# Before submitting the job, we can visualize the circuit using qasm3_drawer().\n", 93 | "from qbraid.visualization import qasm3_drawer\n", 94 | "\n", 95 | "qasm3_drawer(program)" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [ 103 | { 104 | "name": "stdout", 105 | "output_type": "stream", 106 | "text": [ 107 | "{'00': 50, '11': 50}\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "device = provider.get_device(\"simulator\")\n", 113 | "job = device.run(program, name=\"qBraid example\", shots=100)\n", 114 | "results = job.result()\n", 115 | "\n", 116 | "counts = results.data.get_counts()\n", 117 | "\n", 118 | "print(counts)" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 6, 124 | "metadata": {}, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "image/png": "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Zz9TS0tLtzUHAABwNl0KMnfffbeKiookSaWlpZo5c6YuueQSrVmzRvfee2+3NggAAHAmXQoyRUVFysrKkiStWbNGV199tVauXKkVK1Zo7dq13dkfAADAGXUpyHi9Xnk8HknShg0bdMMNN0iSEhISVFdX133dAQAAnEWXgszo0aP161//Wi+88II2bdqkKVOmSJIOHDggh8PRrQ0CAACcSZeCzOOPP67t27frnnvu0c9//nMNHjxYkvTyyy/rqquu6tYGAQAAziSoK3caMWJEp08tfeHf//3fFRTUpU0CAACcty6dkUlNTdXRo0dPqTc3N2vIkCFfuSkAAIBz0aUgc/DgQbnd7lPqLpdLhw8f/spNAQAAnIvzeh/ojTfe8P373XffVWRkpO+22+1WXl6eUlJSuq87AACAszivIHPLLbdIkgzD0OzZszstCw4OVnJysn7/+993W3MAAABnc15B5ovvjklJSVF+fr5iYmIuSFMAAADnoksfMTpw4EB39wEAAHDeuvxZ6by8POXl5ammpsZ3puYLzz333FduDAAA4Mt0KcgsXrxYDz/8sEaPHq24uDgZhtHdfQEAAHypLgWZZ555RitWrNDtt9/e3f0AAACcsy59j0xLSws/RQAAAAKuS0Hm+9//vlauXNndvQAAAJyXLr211NzcrD/84Q/asGGDhg8fruDg4E7LH3vssXPaztNPP62nn35aBw8elCRdeumlevDBB3X99df7xvnxj3+sVatWyeVyKTc3V0899RS/sA0AACR1Mcjs2rVLWVlZkqQ9e/Z0WnY+F/4OHDhQjzzyiNLS0uT1evU///M/uvnmm/XZZ5/p0ksv1cKFC7Vu3TqtWbNGkZGRuueeezR16lR98sknXWkbAABcZLoUZP73f/+3Wwa/8cYbO93+zW9+o6efflpbtmzRwIED9eyzz2rlypWaOHGiJGn58uUaOnSotmzZojFjxnRLDwAAwLq6dI3MheB2u7Vq1So1NTUpJydHBQUFam1t1eTJk33rZGRkKDExUZs3bz7jdlwul5xOZ6c/AABwcerSGZkJEyac9S2kDz744Jy3tXv3buXk5Ki5uVkRERF69dVXNWzYMO3YsUMhISHq06dPp/UdDoeqqqrOuL0lS5Zo8eLFp9S3bdumiIgISVJWVpYaGhpUUlLiW56RkSGbzaa9e/f6asnJyYqOjlZB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+bXXXquCgoKv3BQAAMC5OK8gU11dfdqPXX8hKChItbW1X7kpAACAc3FeQWbAgAHas2fPGZfv2rVLcXFxX7kpAACAc3FeQeaGG27QAw88oObm5lOWnTx5Ug899JC+9a1vdVtzAAAAZ3NeH7/+xS9+oVdeeUVDhgzRPffco/T0dEnS3//+dy1btkxut1s///nPL0ijAAAA/9d5BRmHw6G//vWv+td//Vfdf//98nq9kiTDMJSbm6tly5bJ4XBckEYBAAD+r/P+QrykpCS9/fbbOn78uIqLi+X1epWWlqaoqKgL0R8AAMAZdembfSUpKipK2dnZ3dkLAADAeenSby0BAAD0BAQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQENMkuWLFF2drZ69+6t/v3765ZbblFhYWGndZqbmzVv3jxFR0crIiJC06ZNU3V1dYA6BgAAPUlAg8ymTZs0b948bdmyRe+//75aW1t17bXXqqmpybfOwoUL9eabb2rNmjXatGmTKioqNHXq1AB2DQAAeoqgQA6+fv36TrdXrFih/v37q6CgQFdffbXq6+v17LPPauXKlZo4caIkafny5Ro6dKi2bNmiMWPGBKJtAADQQ/Soa2Tq6+slSX379pUkFRQUqLW1VZMnT/atk5GRocTERG3evDkgPQIAgJ4joGdkOvJ4PFqwYIHGjh2ryy67TJJUVVWlkJAQ9enTp9O6DodDVVVVp92Oy+WSy+Xy3XY6nResZwAAEFg9JsjMmzdPe/bs0ccff/yVtrNkyRItXrz4lPq2bdsUEREhScrKylJDQ4NKSkp8yzMyMmSz2bR3715fLTk5WdHR0SooKPDVHA6HkpKStGPHDn1viFuSdLjJ0HtHTF030K34S9rWa2iV1hywKae/R0P7eH33X15kamgfr8b099deOWiqV5CUO9Djq+VVmDraLE1P9dcK6gztPGZqTppbptFW2+809FGVqW8nuRUV2laraZbeKrNp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evXVV3XLLbdIkv76179q7NixqqioUFxcnG+96dOnyzAMrV69+rTbcblcvoOVJDmdTiUkJKi+vl52u71be06+b123bg+42Bx8ZEqgW+gW7OvAmV2o/dzpdCoyMvJLn7977FtLsbGxktTpldEXt79YdjqhoaGy2+2d/gAAwMWpxwaZlJQUxcbGKi8vz1dzOp369NNPlZOTE8DOAABATxHQa2QaGxs7ved94MAB7dixQ3379lViYqIWLFigX//610pLS1NKSooeeOABxcfH+95+AgAA/9wCGmS2bdumCRMm+G4vWrRIkjR79mytWLFC9957r5qamvSDH/xAJ06c0Lhx47R+/XqFhYUFqmUAANCDBDTIjB8/Xme71tgwDD388MN6+OGHv8auAACAVfTYa2QAAAC+DEEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYliWCzLJly5ScnKywsDBdeeWV2rp1a6BbAgAAPUCPDzKrV6/WokWL9NBDD2n79u0aMWKEcnNzVVNTE+jWAABAgPX4IPPYY4/prrvu0ty5czVs2DA988wzuuSSS/Tcc88FujUAABBgQYFu4GxaWlpUUFCg+++/31czTVOTJ0/W5s2bT3sfl8sll8vlu11fXy9Jcjqd3d6fx/WPbt8mcDG5EPtdILCvA2d2ofbzL7br9XrPul6PDjJ1dXVyu91yOByd6g6HQ3//+99Pe58lS5Zo8eLFp9QTEhIuSI8AzixyaaA7AHChXej9vKGhQZGRkWdc3qODTFfcf//9WrRoke+2x+PRsWPHFB0dLcMwAtgZLjSn06mEhASVl5fLbrcHuh0AFwD7+T8P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", 129 | "text/plain": [ 130 | "
" 131 | ] 132 | }, 133 | "metadata": {}, 134 | "output_type": "display_data" 135 | } 136 | ], 137 | "source": [ 138 | "from qbraid.visualization import plot_histogram\n", 139 | "\n", 140 | "plot_histogram(counts)" 141 | ] 142 | } 143 | ], 144 | "metadata": { 145 | "kernelspec": { 146 | "display_name": "Python 3 [Default]", 147 | "language": "python", 148 | "name": "python3" 149 | }, 150 | "language_info": { 151 | "codemirror_mode": { 152 | "name": "ipython", 153 | "version": 3 154 | }, 155 | "file_extension": ".py", 156 | "mimetype": "text/x-python", 157 | "name": "python", 158 | "nbconvert_exporter": "python", 159 | "pygments_lexer": "ipython3", 160 | "version": "3.11.9" 161 | } 162 | }, 163 | "nbformat": 4, 164 | "nbformat_minor": 4 165 | } 166 | -------------------------------------------------------------------------------- /qbraid_sdk/qbraid_runtime_nec.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Running QUBO Problems on the NEC Vector Annelaer\n", 8 | "\n", 9 | "The NEC Vector Annealer leverages a proprietary algorithm for annealing processes on NEC’s vector supercomputer, **SX-Aurora TSUBASA**.\n", 10 | "\n", 11 | "This notebook demonstrates how to use the **qBraid-SDK** to write an annealing problem using **pyqubo** and execute it on the NEC Vector Annealer backend." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "%%capture\n", 21 | "\n", 22 | "# First, we install the essential libraries to our current Python runtime.\n", 23 | "# \"%%capture\" (above) captures and in this case, hides the output of this\n", 24 | "# cell, so you can comment it out if you need help debugging this step.\n", 25 | "\n", 26 | "%pip install 'qbraid[pyqub,visualization]>=0.8.6'" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "from pyqubo import Spin\n", 36 | "from qbraid import ConversionGraph, ExperimentType, QbraidProvider\n", 37 | "from qbraid.runtime.schemas import QuboSolveParams" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "provider = QbraidProvider()\n", 47 | "\n", 48 | "device = provider.get_device(\"nec_vector_annealer\")\n", 49 | "\n", 50 | "print(device.status())\n", 51 | "print(device.profile.experiment_type)\n", 52 | "print(device.profile.program_spec)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "graph = ConversionGraph()\n", 62 | "\n", 63 | "graph.plot(experiment_type=ExperimentType.ANNEALING)" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "s1, s2, s3, s4 = [Spin(f\"s{i}\") for i in range(1, 5)]\n", 73 | "H = (4 * s1 + 2 * s2 + 7 * s3 + s4) ** 2\n", 74 | "model = H.compile()\n", 75 | "qubo, offset = model.to_qubo()\n", 76 | "\n", 77 | "params = QuboSolveParams(offset=offset)" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "job = device.run(qubo, params=params)\n", 87 | "\n", 88 | "print(job.id)\n", 89 | "\n", 90 | "job.wait_for_final_state()" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "result = job.result()\n", 100 | "\n", 101 | "solutions = result.data.solutions()\n", 102 | "\n", 103 | "for solution in solutions:\n", 104 | " print(solution)" 105 | ] 106 | } 107 | ], 108 | "metadata": { 109 | "kernelspec": { 110 | "display_name": "sdk311", 111 | "language": "python", 112 | "name": "python3" 113 | }, 114 | "language_info": { 115 | "codemirror_mode": { 116 | "name": "ipython", 117 | "version": 3 118 | }, 119 | "file_extension": ".py", 120 | "mimetype": "text/x-python", 121 | "name": "python", 122 | "nbconvert_exporter": "python", 123 | "pygments_lexer": "ipython3", 124 | "version": "3.11.9" 125 | } 126 | }, 127 | "nbformat": 4, 128 | "nbformat_minor": 4 129 | } 130 | -------------------------------------------------------------------------------- /qbraid_sdk/qbraid_runtime_quera_qasm_simulator.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Running Quantum Jobs on the QuEra QASM Simulator\n", 8 | "\n", 9 | "This notebook demonstrates how to use the qBraid-SDK to run jobs on QuEra's noisy, OpenQASM-based simulator with backend options including \"cirq\" (CPU) and \"cirq-gpu\" (NVIDIA H100)." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%%capture\n", 19 | "\n", 20 | "%pip install 'qbraid[quera,cirq,visualization]>=0.8.8' -q" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "import cirq\n", 30 | "\n", 31 | "qubits = [cirq.LineQubit(i) for i in range(5)]\n", 32 | "\n", 33 | "circuit = cirq.Circuit()\n", 34 | "\n", 35 | "circuit.append(cirq.H(qubits[0]))\n", 36 | "\n", 37 | "for qubit in qubits[1:]:\n", 38 | " circuit.append(cirq.CNOT(qubits[0], qubit))\n", 39 | "\n", 40 | "# Note: No measurement gates are added to the circuit\n", 41 | "\n", 42 | "print(circuit)" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "from qbraid import QbraidProvider\n", 52 | "\n", 53 | "provider = QbraidProvider(api_key=\"YOUR_API_KEY\")\n", 54 | "provider.save_config()" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "device = provider.get_device(\"quera_qasm_simulator\")\n", 64 | "\n", 65 | "print(device.status())" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "device.metadata()" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# Use backend=\"cirq\" to run on CPU, or backend=\"cirq-gpu\" to run on GPU\n", 84 | "job = device.run(circuit, shots=100, tags={\"batch\": \"test_1\"}, backend=\"cirq-gpu\")\n", 85 | "\n", 86 | "print(job.id)" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "import time\n", 96 | "\n", 97 | "status_final = False\n", 98 | "\n", 99 | "while not status_final:\n", 100 | " status = job.status()\n", 101 | " print(status)\n", 102 | " status_final = job.is_terminal_state()\n", 103 | " time.sleep(3)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "result = job.result()" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": null, 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "result.success" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "result.details[\"timeStamps\"] # executionDuration in milliseconds" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": null, 136 | "metadata": {}, 137 | "outputs": [], 138 | "source": [ 139 | "result.details[\"cost\"] # cost in qBraid credits (free)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "result.details[\"tags\"]" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "print(result.details[\"metadata\"][\"openQasm\"])" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "counts_bin = result.data.get_counts()\n", 167 | "probs_bin = result.data.get_probabilities()\n", 168 | "probs_dec = result.data.get_probabilities(decimal=True)\n", 169 | "shots = result.data.to_dict()[\"shots\"]\n", 170 | "\n", 171 | "print(f\"shots: {shots}\")\n", 172 | "\n", 173 | "print(f\"probabilities:\")\n", 174 | "probs_bin" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "from qbraid.visualization import plot_histogram, plot_distribution, animate_qpu_state\n", 184 | "\n", 185 | "counts_dec = result.data.get_counts(decimal=True)\n", 186 | "\n", 187 | "plot_histogram(counts_dec)" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "plot_distribution(counts_dec)" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "logs = result.data.get_logs()\n", 206 | "\n", 207 | "logs" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "qpu_state = result.data.get_qpu_state()\n", 217 | "\n", 218 | "type(qpu_state)" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "%matplotlib inline\n", 228 | "\n", 229 | "animate_qpu_state(qpu_state)" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": null, 235 | "metadata": {}, 236 | "outputs": [], 237 | "source": [ 238 | "quera_sim_program_spec = device.profile.program_spec\n", 239 | "\n", 240 | "quera_sim_program_spec" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [ 249 | "from qbraid import ConversionGraph, QPROGRAM_REGISTRY, ExperimentType\n", 250 | "\n", 251 | "graph = ConversionGraph()\n", 252 | "\n", 253 | "print(\n", 254 | " \"Based on your currently installed packages, you can submit \"\n", 255 | " \"to the Quera QASM simulator from the following program types:\\n\"\n", 256 | ")\n", 257 | "\n", 258 | "for program_type in QPROGRAM_REGISTRY:\n", 259 | " if graph.has_path(program_type, quera_sim_program_spec.alias):\n", 260 | " print(f\"'{program_type}': {QPROGRAM_REGISTRY[program_type]}\")\n", 261 | "\n", 262 | "\n", 263 | "print(\n", 264 | " \"\\n\\nNote: Only a limited subset of features within these program types will be supported, specifically \"\n", 265 | " \"\\nthose that can be directly converted to an OpenQASM 2 format compatible with the QuEra simulator.\"\n", 266 | ")\n", 267 | "\n", 268 | "graph.plot(experiment_type=ExperimentType.GATE_MODEL)" 269 | ] 270 | } 271 | ], 272 | "metadata": { 273 | "kernelspec": { 274 | "display_name": "sdk311", 275 | "language": "python", 276 | "name": "python3" 277 | }, 278 | "language_info": { 279 | "codemirror_mode": { 280 | "name": "ipython", 281 | "version": 3 282 | }, 283 | "file_extension": ".py", 284 | "mimetype": "text/x-python", 285 | "name": "python", 286 | "nbconvert_exporter": "python", 287 | "pygments_lexer": "ipython3", 288 | "version": "3.11.9" 289 | } 290 | }, 291 | "nbformat": 4, 292 | "nbformat_minor": 2 293 | } 294 | -------------------------------------------------------------------------------- /qbraid_sdk/qbraid_sdk_providers.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c7b38b09-44f5-46b5-9809-23de47ada6c5", 6 | "metadata": {}, 7 | "source": [ 8 | "# qBraid Runtime Provider Extras and Authentication" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "2626ba66", 14 | "metadata": {}, 15 | "source": [ 16 | "This notebook demonstrates how to:\n", 17 | "- **Authenticate** with various qBraid Runtime providers.\n", 18 | "- **Instantiate** provider objects.\n", 19 | "- **Retrieve availabe devices** for each provider.\n", 20 | "\n", 21 | "*Note*: The \"native\" `QbraidProvider` is the only qBraid Runtime provider that accepts qBraid credentials directly. For all other providers, you must have the appropriate credentials for the respective platform prior to use." 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "id": "f5c3ef91", 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "%%capture\n", 32 | "\n", 33 | "%pip install qbraid" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 2, 39 | "id": "e8290318", 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "import os\n", 44 | "import logging\n", 45 | "\n", 46 | "logging.basicConfig(level=logging.ERROR)" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 3, 52 | "id": "e0349a48", 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "0.8.8\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "from qbraid import __version__\n", 65 | "\n", 66 | "print(__version__)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "id": "852ccc34-8193-49f4-a3c5-59bbdabf296f", 72 | "metadata": {}, 73 | "source": [ 74 | "## QbraidProvider" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 4, 80 | "id": "ba79a19a", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "%%capture\n", 85 | "\n", 86 | "%pip install 'qbraid[qir]' # Required for: qbraid_qir_simulator\n", 87 | "%pip install 'qbraid[quera]' # Required for: qbraid_qasm_simulator\n", 88 | "%pip install 'qbraid[pyqubo]' # Required for: nec_vector_annealer\n", 89 | "%pip install 'qbraid[braket]' # Required for: aws_sv1, aws_dm1, aws_tn1, quera_aquila\n", 90 | "%pip install 'qbraid[ionq]' # Required for: ionq_simulator, ionq_aria_1, ionq_aria_2, ionq_forte_1" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 5, 96 | "id": "1c5a92d6-c400-4c84-b558-23eb3a724785", 97 | "metadata": { 98 | "tags": [] 99 | }, 100 | "outputs": [ 101 | { 102 | "data": { 103 | "text/plain": [ 104 | "[,\n", 105 | " ,\n", 106 | " ,\n", 107 | " ,\n", 108 | " ,\n", 109 | " ,\n", 110 | " ,\n", 111 | " ,\n", 112 | " ,\n", 113 | " ,\n", 114 | " ,\n", 115 | " ]" 116 | ] 117 | }, 118 | "execution_count": 5, 119 | "metadata": {}, 120 | "output_type": "execute_result" 121 | } 122 | ], 123 | "source": [ 124 | "from qbraid.runtime import QbraidProvider\n", 125 | "\n", 126 | "api_key = os.getenv(\"QBRAID_API_KEY\")\n", 127 | "\n", 128 | "provider = QbraidProvider(api_key=api_key)\n", 129 | "\n", 130 | "provider.get_devices()" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "id": "9d781221-9c07-42eb-bcad-63a666221356", 136 | "metadata": {}, 137 | "source": [ 138 | "## BraketProvider" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 6, 144 | "id": "c953afff", 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "%%capture\n", 149 | "\n", 150 | "%pip install 'qbraid[braket]'" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 7, 156 | "id": "b464cc6a-236b-4dae-b913-4dd263926a61", 157 | "metadata": { 158 | "tags": [] 159 | }, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "[,\n", 165 | " ,\n", 166 | " ,\n", 167 | " ,\n", 168 | " ,\n", 169 | " ,\n", 170 | " ,\n", 171 | " ,\n", 172 | " ]" 173 | ] 174 | }, 175 | "execution_count": 7, 176 | "metadata": {}, 177 | "output_type": "execute_result" 178 | } 179 | ], 180 | "source": [ 181 | "from qbraid.runtime import BraketProvider\n", 182 | "\n", 183 | "aws_access_key_id = os.getenv(\"AWS_ACCESS_KEY_ID\")\n", 184 | "aws_secret_access_key = os.getenv(\"AWS_SECRET_ACCESS_KEY\")\n", 185 | "\n", 186 | "provider = BraketProvider(\n", 187 | " aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key\n", 188 | ")\n", 189 | "\n", 190 | "provider.get_devices()" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "id": "648d4dea-9a60-43e0-9e67-4d7144936061", 196 | "metadata": {}, 197 | "source": [ 198 | "## QiskitRuntimeProvider" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 8, 204 | "id": "759cafb5", 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "%%capture\n", 209 | "\n", 210 | "%pip install 'qbraid[ibm]' -q" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "id": "8c288074-ff7f-4048-920d-61ff1c0d611f", 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "data": { 221 | "text/plain": [ 222 | "[,\n", 223 | " ,\n", 224 | " ]" 225 | ] 226 | }, 227 | "execution_count": 9, 228 | "metadata": {}, 229 | "output_type": "execute_result" 230 | } 231 | ], 232 | "source": [ 233 | "from qbraid.runtime import QiskitRuntimeProvider\n", 234 | "\n", 235 | "token = os.getenv(\"QISKIT_IBM_TOKEN\")\n", 236 | "channel = os.getenv(\"QISKIT_IBM_CHANNEL\", \"ibm_quantum\")\n", 237 | "\n", 238 | "provider = QiskitRuntimeProvider(token=token, channel=channel)\n", 239 | "\n", 240 | "provider.get_devices()" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "id": "c37ca6a9-8976-4b35-96fc-1c63d8668466", 246 | "metadata": {}, 247 | "source": [ 248 | "## IonQProvider" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 10, 254 | "id": "7bdd57ac", 255 | "metadata": {}, 256 | "outputs": [], 257 | "source": [ 258 | "%%capture\n", 259 | "\n", 260 | "%pip install 'qbraid[ionq]'" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": 11, 266 | "id": "1683b86c-41d1-440b-b8a0-5cf5bd81db2c", 267 | "metadata": { 268 | "tags": [] 269 | }, 270 | "outputs": [ 271 | { 272 | "data": { 273 | "text/plain": [ 274 | "[,\n", 275 | " ,\n", 276 | " ,\n", 277 | " ,\n", 278 | " ]" 279 | ] 280 | }, 281 | "execution_count": 11, 282 | "metadata": {}, 283 | "output_type": "execute_result" 284 | } 285 | ], 286 | "source": [ 287 | "from qbraid.runtime import IonQProvider\n", 288 | "\n", 289 | "api_key = os.getenv(\"IONQ_API_KEY\")\n", 290 | "\n", 291 | "provider = IonQProvider(api_key=api_key)\n", 292 | "\n", 293 | "provider.get_devices()" 294 | ] 295 | }, 296 | { 297 | "cell_type": "markdown", 298 | "id": "54fd5ec8", 299 | "metadata": {}, 300 | "source": [ 301 | "## AzureQuantumProvider" 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": 12, 307 | "id": "9698fd2f", 308 | "metadata": {}, 309 | "outputs": [], 310 | "source": [ 311 | "%%capture\n", 312 | "\n", 313 | "%pip install 'qbraid[azure]'" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": 13, 319 | "id": "dcaaf9df", 320 | "metadata": {}, 321 | "outputs": [ 322 | { 323 | "data": { 324 | "text/plain": [ 325 | "[,\n", 326 | " ,\n", 327 | " ,\n", 328 | " ,\n", 329 | " ,\n", 330 | " ,\n", 331 | " ,\n", 332 | " ,\n", 333 | " ]" 334 | ] 335 | }, 336 | "execution_count": 13, 337 | "metadata": {}, 338 | "output_type": "execute_result" 339 | } 340 | ], 341 | "source": [ 342 | "from qbraid.runtime import AzureQuantumProvider\n", 343 | "from azure.quantum._constants import ConnectionConstants, EnvironmentVariables\n", 344 | "from azure.identity import ClientSecretCredential\n", 345 | "from azure.quantum import Workspace\n", 346 | "\n", 347 | "tenant_id = os.getenv(EnvironmentVariables.AZURE_TENANT_ID)\n", 348 | "client_id = os.getenv(EnvironmentVariables.AZURE_CLIENT_ID)\n", 349 | "client_secret = os.getenv(EnvironmentVariables.AZURE_CLIENT_SECRET)\n", 350 | "credential = ClientSecretCredential(\n", 351 | " tenant_id=tenant_id, client_id=client_id, client_secret=client_secret\n", 352 | ")\n", 353 | "\n", 354 | "subscription_id = os.getenv(EnvironmentVariables.QUANTUM_SUBSCRIPTION_ID)\n", 355 | "resource_group = os.getenv(EnvironmentVariables.QUANTUM_RESOURCE_GROUP, \"AzureQuantum\")\n", 356 | "workspace_name = os.getenv(EnvironmentVariables.WORKSPACE_NAME)\n", 357 | "resource_id = ConnectionConstants.VALID_RESOURCE_ID(\n", 358 | " subscription_id=subscription_id,\n", 359 | " resource_group=resource_group,\n", 360 | " workspace_name=workspace_name,\n", 361 | ")\n", 362 | "\n", 363 | "location = os.getenv(EnvironmentVariables.QUANTUM_LOCATION, \"eastus\")\n", 364 | "workspace = Workspace(resource_id=resource_id, location=location, credential=credential)\n", 365 | "\n", 366 | "provider = AzureQuantumProvider(workspace)\n", 367 | "\n", 368 | "provider.get_devices()" 369 | ] 370 | }, 371 | { 372 | "cell_type": "markdown", 373 | "id": "49296f95", 374 | "metadata": {}, 375 | "source": [ 376 | "## OQCProvider" 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": 14, 382 | "id": "2f92a10f", 383 | "metadata": {}, 384 | "outputs": [], 385 | "source": [ 386 | "%%capture\n", 387 | "\n", 388 | "%pip install 'qbraid[oqc]'" 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": 15, 394 | "id": "68cf23e1", 395 | "metadata": {}, 396 | "outputs": [ 397 | { 398 | "data": { 399 | "text/plain": [ 400 | "[,\n", 401 | " ]" 402 | ] 403 | }, 404 | "execution_count": 15, 405 | "metadata": {}, 406 | "output_type": "execute_result" 407 | } 408 | ], 409 | "source": [ 410 | "from qbraid.runtime import OQCProvider\n", 411 | "\n", 412 | "token = os.getenv(\"OQC_AUTH_TOKEN\")\n", 413 | "\n", 414 | "provider = OQCProvider(token=token)\n", 415 | "\n", 416 | "provider.get_devices()" 417 | ] 418 | }, 419 | { 420 | "cell_type": "code", 421 | "execution_count": null, 422 | "id": "f632294e", 423 | "metadata": {}, 424 | "outputs": [], 425 | "source": [] 426 | } 427 | ], 428 | "metadata": { 429 | "kernelspec": { 430 | "display_name": "sdk311", 431 | "language": "python", 432 | "name": "python3" 433 | }, 434 | "language_info": { 435 | "codemirror_mode": { 436 | "name": "ipython", 437 | "version": 3 438 | }, 439 | "file_extension": ".py", 440 | "mimetype": "text/x-python", 441 | "name": "python", 442 | "nbconvert_exporter": "python", 443 | "pygments_lexer": "ipython3", 444 | "version": "3.11.9" 445 | } 446 | }, 447 | "nbformat": 4, 448 | "nbformat_minor": 5 449 | } 450 | -------------------------------------------------------------------------------- /qbraid_sdk/qbraid_sdk_transpiler.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "98528633", 6 | "metadata": {}, 7 | "source": [ 8 | "# qBraid-SDK: Transpiler" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "331a496f", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import numpy as np\n", 19 | "\n", 20 | "from qbraid.programs import QPROGRAM_REGISTRY\n", 21 | "from qbraid.interface import (\n", 22 | " circuits_allclose,\n", 23 | " assert_allclose_up_to_global_phase,\n", 24 | " random_circuit,\n", 25 | ")\n", 26 | "from qbraid.transpiler import transpile" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "id": "f8360d49", 32 | "metadata": {}, 33 | "source": [ 34 | "The qBraid transpiler supports all-to-all connectivity between the following quantum program types:" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 2, 40 | "id": "0c41ae38", 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/plain": [ 46 | "{'cirq': cirq.circuits.circuit.Circuit,\n", 47 | " 'qiskit': qiskit.circuit.quantumcircuit.QuantumCircuit,\n", 48 | " 'pennylane': pennylane.tape.tape.QuantumTape,\n", 49 | " 'pyquil': pyquil.quil.Program,\n", 50 | " 'pytket': pytket._tket.circuit.Circuit,\n", 51 | " 'braket': braket.circuits.circuit.Circuit,\n", 52 | " 'braket_ahs': braket.ahs.analog_hamiltonian_simulation.AnalogHamiltonianSimulation,\n", 53 | " 'openqasm3': openqasm3.ast.Program,\n", 54 | " 'pyqir': Module,\n", 55 | " 'cpp_pyqubo': cpp_pyqubo.Model,\n", 56 | " 'qasm2': str,\n", 57 | " 'qasm3': str,\n", 58 | " 'ionq': ~IonQDict,\n", 59 | " 'bloqade': bloqade.builder.assign.BatchAssign}" 60 | ] 61 | }, 62 | "execution_count": 2, 63 | "metadata": {}, 64 | "output_type": "execute_result" 65 | } 66 | ], 67 | "source": [ 68 | "QPROGRAM_REGISTRY" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "id": "ac83d0b6", 74 | "metadata": {}, 75 | "source": [ 76 | "## Basic usage example: Qiskit $\\leftrightarrow$ Amazon Braket $\\leftrightarrow$ Cirq" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "id": "da3079f7", 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "from qiskit import QuantumCircuit\n", 87 | "\n", 88 | "\n", 89 | "def test_circuit():\n", 90 | " circuit = QuantumCircuit(4)\n", 91 | "\n", 92 | " circuit.h([0, 1, 2, 3])\n", 93 | " circuit.x([0, 1])\n", 94 | " circuit.y(2)\n", 95 | " circuit.z(3)\n", 96 | " circuit.s(0)\n", 97 | " circuit.sdg(1)\n", 98 | " circuit.t(2)\n", 99 | " circuit.tdg(3)\n", 100 | " circuit.rx(np.pi / 4, 0)\n", 101 | " circuit.ry(np.pi / 2, 1)\n", 102 | " circuit.rz(3 * np.pi / 4, 2)\n", 103 | " circuit.p(np.pi / 8, 3)\n", 104 | " circuit.sx(0)\n", 105 | " circuit.sxdg(1)\n", 106 | " circuit.iswap(2, 3)\n", 107 | " circuit.swap([0, 1], [2, 3])\n", 108 | " circuit.cx(0, 1)\n", 109 | " circuit.cp(np.pi / 4, 2, 3)\n", 110 | "\n", 111 | " return circuit" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "id": "a55cf255", 117 | "metadata": {}, 118 | "source": [ 119 | "We'll start with a 4-qubit qiskit circuit that uses 15 unique gates" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 4, 125 | "id": "8710a671", 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "data": { 130 | "text/html": [ 131 | "
     ┌───┐┌───┐ ┌───┐ ┌─────────┐   ┌────┐                 \n",
132 |        "q_0: ┤ H ├┤ X ├─┤ S ├─┤ Rx(π/4) ├───┤ √X ├───X────────■────\n",
133 |        "     ├───┤├───┤┌┴───┴┐├─────────┤  ┌┴────┴┐  │      ┌─┴─┐  \n",
134 |        "q_1: ┤ H ├┤ X ├┤ Sdg ├┤ Ry(π/2) ├──┤ √Xdg ├──┼──X───┤ X ├──\n",
135 |        "     ├───┤├───┤└┬───┬┘├─────────┴┐┌┴──────┴┐ │  │   └───┘  \n",
136 |        "q_2: ┤ H ├┤ Y ├─┤ T ├─┤ Rz(3π/4) ├┤0       ├─X──┼──■───────\n",
137 |        "     ├───┤├───┤┌┴───┴┐└┬────────┬┘│  Iswap │    │  │P(π/4) \n",
138 |        "q_3: ┤ H ├┤ Z ├┤ Tdg ├─┤ P(π/8) ├─┤1       ├────X──■───────\n",
139 |        "     └───┘└───┘└─────┘ └────────┘ └────────┘               
" 140 | ], 141 | "text/plain": [ 142 | " ┌───┐┌───┐ ┌───┐ ┌─────────┐ ┌────┐ \n", 143 | "q_0: ┤ H ├┤ X ├─┤ S ├─┤ Rx(π/4) ├───┤ √X ├───X────────■────\n", 144 | " ├───┤├───┤┌┴───┴┐├─────────┤ ┌┴────┴┐ │ ┌─┴─┐ \n", 145 | "q_1: ┤ H ├┤ X ├┤ Sdg ├┤ Ry(π/2) ├──┤ √Xdg ├──┼──X───┤ X ├──\n", 146 | " ├───┤├───┤└┬───┬┘├─────────┴┐┌┴──────┴┐ │ │ └───┘ \n", 147 | "q_2: ┤ H ├┤ Y ├─┤ T ├─┤ Rz(3π/4) ├┤0 ├─X──┼──■───────\n", 148 | " ├───┤├───┤┌┴───┴┐└┬────────┬┘│ Iswap │ │ │P(π/4) \n", 149 | "q_3: ┤ H ├┤ Z ├┤ Tdg ├─┤ P(π/8) ├─┤1 ├────X──■───────\n", 150 | " └───┘└───┘└─────┘ └────────┘ └────────┘ " 151 | ] 152 | }, 153 | "execution_count": 4, 154 | "metadata": {}, 155 | "output_type": "execute_result" 156 | } 157 | ], 158 | "source": [ 159 | "qiskit_circuit = test_circuit()\n", 160 | "qiskit_circuit.draw()" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 5, 166 | "id": "7f1ef479", 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "name": "stdout", 171 | "output_type": "stream", 172 | "text": [ 173 | "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │\n", 174 | " ┌───┐ ┌───┐ ┌───┐ ┌──────────┐ ┌───┐ \n", 175 | "q0 : ─┤ H ├─┤ X ├─┤ S ├───┤ Rx(0.79) ├─────┤ V ├──────x─────────────────────●────────\n", 176 | " └───┘ └───┘ └───┘ └──────────┘ └───┘ │ │ \n", 177 | " ┌───┐ ┌───┐ ┌────┐ ┌──────────┐ ┌────┐ │ ┌─┴─┐ \n", 178 | "q1 : ─┤ H ├─┤ X ├─┤ Si ├──┤ Ry(1.57) ├────┤ Vi ├──────┼────────x──────────┤ X ├──────\n", 179 | " └───┘ └───┘ └────┘ └──────────┘ └────┘ │ │ └───┘ \n", 180 | " ┌───┐ ┌───┐ ┌───┐ ┌──────────┐ ┌───────┐ │ │ \n", 181 | "q2 : ─┤ H ├─┤ Y ├─┤ T ├───┤ Rz(2.36) ├───┤ ISWAP ├────x────────┼────────────●────────\n", 182 | " └───┘ └───┘ └───┘ └──────────┘ └───┬───┘ │ │ \n", 183 | " ┌───┐ ┌───┐ ┌────┐ ┌─────────────┐ ┌───┴───┐ │ ┌──────┴──────┐ \n", 184 | "q3 : ─┤ H ├─┤ Z ├─┤ Ti ├─┤ PHASE(0.39) ├─┤ ISWAP ├─────────────x─────┤ PHASE(0.79) ├─\n", 185 | " └───┘ └───┘ └────┘ └─────────────┘ └───────┘ └─────────────┘ \n", 186 | "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │\n" 187 | ] 188 | } 189 | ], 190 | "source": [ 191 | "braket_circuit = transpile(qiskit_circuit, \"braket\")\n", 192 | "print(braket_circuit)" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 6, 198 | "id": "2a6eb7e7", 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "name": "stdout", 203 | "output_type": "stream", 204 | "text": [ 205 | "q_0: ───H───X───S──────Rx(0.25π)───X^0.5────────────────×───────@────────\n", 206 | " │ │\n", 207 | "q_1: ───H───X───S^-1───Ry(0.5π)────X^-0.5───────────────┼───×───X────────\n", 208 | " │ │\n", 209 | "q_2: ───H───Y───T──────Rz(0.75π)───S────────H───@───X───×───┼───@────────\n", 210 | " │ │ │ │\n", 211 | "q_3: ───H───Z───T^-1───Z^(1/8)─────S────────────X───@───H───×───@^0.25───\n" 212 | ] 213 | } 214 | ], 215 | "source": [ 216 | "cirq_circuit = transpile(qiskit_circuit, \"cirq\")\n", 217 | "print(cirq_circuit)" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "id": "0963d29d", 223 | "metadata": {}, 224 | "source": [ 225 | "Qubit indexing varies between packages, so some circuit diagrams appear flipped, but the matrix representations are equivalent.\n", 226 | "\n", 227 | "To verify, we'll use the sdk's `circuits_allclose` function, which applies the agnostic `qbraid.interface.to_unitary` function to each of two input circuits, checks the matricies against `np.allclose`, and returns the result." 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 7, 233 | "id": "665c6c0b", 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "data": { 238 | "text/plain": [ 239 | "True" 240 | ] 241 | }, 242 | "execution_count": 7, 243 | "metadata": {}, 244 | "output_type": "execute_result" 245 | } 246 | ], 247 | "source": [ 248 | "circuits_allclose(qiskit_circuit, braket_circuit) and circuits_allclose(\n", 249 | " braket_circuit, cirq_circuit\n", 250 | ")" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "id": "5359d22b", 256 | "metadata": {}, 257 | "source": [ 258 | "## Stress-testing against randomly generated circuits" 259 | ] 260 | }, 261 | { 262 | "cell_type": "markdown", 263 | "id": "31a3cbc8", 264 | "metadata": {}, 265 | "source": [ 266 | "For a second example, we'll generate some even larger circuits, and do so randomly, to test the limits of the transpiler.\n", 267 | "\n", 268 | "The qBraid-SDK has its own `random_circuit` function that takes in any supported package as an argument, but to show that there's no pre-processing or filtering going on behind the scenes, we'll use functions from cirq's testing module to generate circuits and to check equivalance after transpiling." 269 | ] 270 | }, 271 | { 272 | "cell_type": "code", 273 | "execution_count": 8, 274 | "id": "afe95c34", 275 | "metadata": {}, 276 | "outputs": [ 277 | { 278 | "name": "stdout", 279 | "output_type": "stream", 280 | "text": [ 281 | "num_qubits: 10\n", 282 | "depth: 10\n", 283 | "op_density: 0.85\n", 284 | "matrix dimension: (1024, 1024)\n", 285 | "\n", 286 | " ┌──┐ ┌──┐ ┌──────────┐ ┌────┐ ┌───────┐ ┌───┐ ┌───┐ ┌────┐ ┌────────┐\n", 287 | "0: ─────×─────Z──────@─────────────@───────@───────────────────@──────@───────@───────────────────\n", 288 | " │ │ │ │ │ │ │\n", 289 | "1: ────Y┼─────T──────┼────iSwap────┼─────×─┼──────×────────────┼──────┼───────┼X───────×──────────\n", 290 | " │ │ │ │ │ │ │ │ │ ││ │\n", 291 | "2: ────Z┼────────────┼────iSwap────X─────┼×┼─────X┼────────────┼──────┼@─────×┼┼───────┼iSwap─────\n", 292 | " │ │ │││ ││ │ ││ │││ ││\n", 293 | "3: ────T┼─────@──────X─────────────S────S┼┼┼─────┼┼iSwap──────×┼─────Z┼┼─────┼┼┼T──────┼┼─────────\n", 294 | " │ │ │││ │││ ││ ││ │││ ││\n", 295 | "4: ────Z┼─────┼@─────iSwap─────────Y────Z┼┼┼─────@┼┼─────────Z┼┼─────X┼┼─────┼@┼───────┼┼────×────\n", 296 | " │ ││ │ │││ ││ ││ ││ │ │ ││ │\n", 297 | "5: ────T┼─────┼X─────┼────X────────Y────H┼┼┼──────┼iSwap──────┼@─────H┼┼─────┼─┼──────Y┼┼────┼────\n", 298 | " │ │ │ │ │││ │ │ ││ │ │ ││ │\n", 299 | "6: ─────┼─────@──────┼────┼────────X─────×┼┼──────┼───────────┼───────┼@─────×─┼───────┼┼────×────\n", 300 | " │ │ │ ││ │ │ │ │ ││\n", 301 | "7: ─────×────────────┼────@────────Z──────┼X─────T┼───────────×──────@┼──────Y─┼───────┼iSwap─────\n", 302 | " │ │ │ ││ │ │\n", 303 | "8: ────Y──────T──────┼────T────────X────T─┼───────┼──────────X───────X┼────────┼───────×──────────\n", 304 | " │ │ │ │ │ │ │\n", 305 | "9: ───────────Z──────iSwap─────────@──────×───────×──────────@────────@────────@──────H───────────\n", 306 | " └──┘ └──┘ └──────────┘ └────┘ └───────┘ └───┘ └───┘ └────┘ └────────┘\n" 307 | ] 308 | } 309 | ], 310 | "source": [ 311 | "import cirq\n", 312 | "\n", 313 | "kwargs = {\n", 314 | " \"num_qubits\": np.random.randint(8, 11),\n", 315 | " \"depth\": np.random.randint(8, 11),\n", 316 | " \"op_density\": np.random.randint(80, 100) / 100,\n", 317 | " \"random_state\": np.random.randint(1, 11),\n", 318 | "}\n", 319 | "\n", 320 | "circuit_start = random_circuit(\"cirq\", **kwargs)\n", 321 | "start_u = circuit_start.unitary()\n", 322 | "print(\"num_qubits:\", len(circuit_start.all_qubits()))\n", 323 | "print(\"depth:\", len(circuit_start))\n", 324 | "print(\"op_density:\", kwargs[\"op_density\"])\n", 325 | "print(f\"matrix dimension: {start_u.shape}\\n\")\n", 326 | "print(circuit_start)" 327 | ] 328 | }, 329 | { 330 | "cell_type": "markdown", 331 | "id": "5818071d", 332 | "metadata": {}, 333 | "source": [ 334 | "Starting with this randomly generated circuit, we'll repeatedly apply the qbraid circuit wrapper and transpile from one supported package to the next until we arrive all the way back at a cirq circuit." 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": 9, 340 | "id": "bbe4be5f", 341 | "metadata": {}, 342 | "outputs": [ 343 | { 344 | "name": "stdout", 345 | "output_type": "stream", 346 | "text": [ 347 | "\n" 348 | ] 349 | } 350 | ], 351 | "source": [ 352 | "braket_circuit = transpile(circuit_start, \"braket\")\n", 353 | "print(type(braket_circuit))" 354 | ] 355 | }, 356 | { 357 | "cell_type": "code", 358 | "execution_count": 10, 359 | "id": "d2813ee0", 360 | "metadata": {}, 361 | "outputs": [ 362 | { 363 | "name": "stdout", 364 | "output_type": "stream", 365 | "text": [ 366 | "\n" 367 | ] 368 | } 369 | ], 370 | "source": [ 371 | "pyquil_circuit = transpile(braket_circuit, \"pyquil\")\n", 372 | "print(type(pyquil_circuit))" 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": 11, 378 | "id": "fbb476fb", 379 | "metadata": {}, 380 | "outputs": [ 381 | { 382 | "name": "stdout", 383 | "output_type": "stream", 384 | "text": [ 385 | "\n" 386 | ] 387 | } 388 | ], 389 | "source": [ 390 | "qiskit_circuit = transpile(pyquil_circuit, \"qiskit\")\n", 391 | "print(type(qiskit_circuit))" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 12, 397 | "id": "fc405e6e", 398 | "metadata": {}, 399 | "outputs": [ 400 | { 401 | "name": "stdout", 402 | "output_type": "stream", 403 | "text": [ 404 | "\n" 405 | ] 406 | } 407 | ], 408 | "source": [ 409 | "pytket_circuit = transpile(qiskit_circuit, \"pytket\")\n", 410 | "print(type(pytket_circuit))" 411 | ] 412 | }, 413 | { 414 | "cell_type": "code", 415 | "execution_count": 13, 416 | "id": "072f6aeb", 417 | "metadata": {}, 418 | "outputs": [ 419 | { 420 | "name": "stdout", 421 | "output_type": "stream", 422 | "text": [ 423 | "\n" 424 | ] 425 | } 426 | ], 427 | "source": [ 428 | "circuit_finish = transpile(pytket_circuit, \"cirq\")\n", 429 | "print(type(circuit_finish))" 430 | ] 431 | }, 432 | { 433 | "cell_type": "markdown", 434 | "id": "b621daed", 435 | "metadata": {}, 436 | "source": [ 437 | "Computing the final unitary and checking its shape" 438 | ] 439 | }, 440 | { 441 | "cell_type": "code", 442 | "execution_count": 14, 443 | "id": "5f6f3633", 444 | "metadata": {}, 445 | "outputs": [ 446 | { 447 | "name": "stdout", 448 | "output_type": "stream", 449 | "text": [ 450 | "(1024, 1024)\n" 451 | ] 452 | } 453 | ], 454 | "source": [ 455 | "finish_u = circuit_finish.unitary()\n", 456 | "print(finish_u.shape)" 457 | ] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "execution_count": 15, 462 | "id": "9f461918", 463 | "metadata": {}, 464 | "outputs": [ 465 | { 466 | "name": "stdout", 467 | "output_type": "stream", 468 | "text": [ 469 | "Test passed!\n" 470 | ] 471 | } 472 | ], 473 | "source": [ 474 | "try:\n", 475 | " assert_allclose_up_to_global_phase(start_u, finish_u, atol=1e-7)\n", 476 | " print(\"Test passed!\")\n", 477 | "except AssertionError:\n", 478 | " print(\"Test failed\")" 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": null, 484 | "id": "5d7dd657-c7ec-425e-9036-7109aa4c07e2", 485 | "metadata": {}, 486 | "outputs": [], 487 | "source": [] 488 | } 489 | ], 490 | "metadata": { 491 | "kernelspec": { 492 | "display_name": "Python 3 [qBraid]", 493 | "language": "python", 494 | "name": "python3_qbraid_sdk_9j9sjy" 495 | }, 496 | "language_info": { 497 | "codemirror_mode": { 498 | "name": "ipython", 499 | "version": 3 500 | }, 501 | "file_extension": ".py", 502 | "mimetype": "text/x-python", 503 | "name": "python", 504 | "nbconvert_exporter": "python", 505 | "pygments_lexer": "ipython3", 506 | "version": "3.11.9" 507 | } 508 | }, 509 | "nbformat": 4, 510 | "nbformat_minor": 5 511 | } 512 | --------------------------------------------------------------------------------