diff --git a/qbraid_sdk/ibm_quantum_jobs_with_runtime.ipynb b/qbraid_sdk/ibm_quantum_jobs_with_runtime.ipynb new file mode 100644 index 0000000..e3e4afc --- /dev/null +++ b/qbraid_sdk/ibm_quantum_jobs_with_runtime.ipynb @@ -0,0 +1,534 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8b2825fc-4e34-47de-acfc-f755ebdcbc21", + "metadata": {}, + "source": [ + "# qBraid Quantum Labs: IBM Devices with your own credentials\n", + "\n", + "Authors: Sophy Shin, James Weaver, Brian Ingmanson\n", + "\n", + "This tutorial is about using Qiskit Runtime through qBraid Quantum Lab. The `Default` Environment supports most of the up-to-date versions of Qiskit, so the first step will be to bring your own credential from [IBM Quantum Platform](https://quantum.ibm.com/). \n", + "\n", + "If you do not already have a user account, get one at the [IBM Quantum login page](https://quantum.ibm.com/login). Your user account is associated with one or more [instances](https://docs.quantum.ibm.com/run/instances) (in the form hub / group / project) that give access to IBM Quantum services. Additionally, a unique token is assigned to each account, allowing for IBM Quantum access from Qiskit. The instructions in this section use our default instance. For instructions to choose a specific instance, see [Connect to an instance](https://docs.quantum.ibm.com/run/instances#connect-instance).\n", + "\n", + "After logging in, at the top right, you can check the instances that you can use, and you can copy the API Token according to the instance at the right side of the banner by clicking the squared icon.\n", + "\n", + "\n", + "\n", + "If you are using `Open Plan` you can run your quantum circuits on IBM quantum systems for free (up to 10 minutes quantum time per month). See [IBM Quantum access plans](https://www.ibm.com/quantum/pricing) for details.\n", + "\n", + "## 1. Using Qiskit Runtime Provider\n", + "\n", + "Now you can start using IBM Quantum Backends by calling QiskitRuntimeService with your API Credential replace `` by your own token:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "797cf94f-512c-4260-a8de-16246d468467", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#set up service by using open plan instance. you can delete or modify to use another instance\n", + "\n", + "from qiskit_ibm_runtime import QiskitRuntimeService\n", + " \n", + "service = QiskitRuntimeService(channel=\"ibm_quantum\", instance=\"ibm-q/open/main\", token=\"\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "79d463c4-81c6-49b2-9817-1bed7cb98517", + "metadata": {}, + "source": [ + "To view the backends you have access to, you can use the `QiskitRuntimeService.backends()` method. Let's check your backend list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fc011cc-77df-461a-bc99-93ffd22eb672", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "service.backends()" + ] + }, + { + "cell_type": "markdown", + "id": "0f8ba878-89b0-458e-8854-034cb7c7b433", + "metadata": {}, + "source": [ + "The `QiskitRuntimeService.backend()` method (note that this is singular: backend) takes the name of the backend as the input parameter and returns an IBMBackend instance representing that particular backend. The following code will select `ibmq_qasm_simulator` and save it as a `backend_sim`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6bf1f98-b992-47fc-85ea-ff534b7977eb", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "backend_sim = service.backend(\"ibmq_qasm_simulator\")" + ] + }, + { + "cell_type": "markdown", + "id": "231e0279-e1bf-43c0-b77b-01a77b5dbd5e", + "metadata": {}, + "source": [ + "You can also filter the available backends by their properties. For more general filters, you can make advanced functions using a lambda function. Refer to the [API documentation](https://docs.quantum.ibm.com/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#backends) for more details.\n", + "\n", + "As shown here, we will filter least busy real backend and save it to `backend`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67109b11-1157-4356-9e24-5a63bb513795", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "backend = service.least_busy(simulator=False, operational=True)\n", + "backend" + ] + }, + { + "cell_type": "markdown", + "id": "0155d3e0-93f0-4950-bbe7-dfd64a99e26a", + "metadata": {}, + "source": [ + "### Create a toy circuit\n", + "\n", + "Now, let's create a random circuit by using `qiskit.circuit.random.random_circuit` with 5 qubits with depth=3 with measurement. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7610fbe-d2b0-4475-9c7c-e6e0ec751d66", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qiskit.circuit.random import random_circuit\n", + " \n", + "circ = random_circuit(5, 3, measure=True)\n", + "circ.draw(output='mpl', style='iqp')" + ] + }, + { + "cell_type": "markdown", + "id": "bc4dae59-a927-4efb-b030-510505418763", + "metadata": {}, + "source": [ + "### Execute using a quantum primitive function\n", + "\n", + "Quantum computers can produce random results, so you'll often want to collect a sample of the outputs by running the circuit many times. You can use the `Sampler` class to get measured data from a quantum Computer.. `Sampler` is one of our two [primitives](https://docs.quantum.ibm.com/run/primitives-get-started); the other is `Estimator`, which estimates the value of observable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a72b8e00-89e1-492c-860c-775f2e72d68d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qiskit_ibm_runtime import Sampler, Options\n", + " \n", + "options = Options()\n", + "options.resilience_level = 1\n", + "options.optimization_level = 3\n", + " \n", + "# Create an Estimator object\n", + "sampler = Sampler(backend_sim, options=options)\n", + " \n", + "# Submit the circuit to Estimator\n", + "job = sampler.run(circ, shots = 10000)" + ] + }, + { + "cell_type": "markdown", + "id": "5c2996ff-e30b-4e55-82f9-5fe6a7411508", + "metadata": {}, + "source": [ + "You can print the job's id and status by using the job instance. Run below cell to check both." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e873269-7312-4f7c-a4af-cf87c8def5eb", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "jobid = job.job_id()\n", + "print(f\">>> Job ID: {job.job_id()}\")\n", + "print(f\">>> Job Status: {job.status()}\")" + ] + }, + { + "cell_type": "markdown", + "id": "db17081f-a469-4a38-bdec-5500e968a642", + "metadata": {}, + "source": [ + "
\n", + "Note: \n", + " Jobs submitted by using the qiskit_ibm_runtime provider are not visible in the right side panel of qBraid Lab
\n" + ] + }, + { + "cell_type": "markdown", + "id": "23e66477-79dc-4e24-a964-07a486203348", + "metadata": {}, + "source": [ + "### Retrieve job results at a later time\n", + "\n", + "You can call service.job(\\) to retrieve a job you previously submitted. If you don’t have the job ID, or if you want to retrieve multiple jobs at once; including jobs from retired systems, call service.jobs() with optional filters instead. See [QiskitRuntimeService.jobs](https://docs.quantum.ibm.com/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#jobs) for details.\n", + "\n", + "As shown here, we will retrieve the job result and save it as a `retrieve_job` to see the result." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c477078-67be-46d8-8378-962f6a9b9dea", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "retrieve_job = service.job(jobid)\n", + "result = retrieve_job.result()" + ] + }, + { + "cell_type": "markdown", + "id": "945f9635-a576-47cd-94b4-78fd7fadea0f", + "metadata": {}, + "source": [ + "Now we will plot the results. \n", + "\n", + "As sampler returns quasi probability of measurement, let's use `plot_distribution` with a binary expression. See [SamplerResult document](https://docs.quantum.ibm.com/api/qiskit/qiskit.primitives.SamplerResult) for more information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0590e58-9eea-4589-a774-6652c37d2e9f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qiskit.visualization import plot_distribution\n", + "\n", + "plot_distribution(result.quasi_dists[0].binary_probabilities())" + ] + }, + { + "cell_type": "markdown", + "id": "03ec980a-f294-4498-82cf-cb4c35a1f3b6", + "metadata": {}, + "source": [ + "## 2. Using qBraid SDK" + ] + }, + { + "cell_type": "markdown", + "id": "de67207f-3dd5-499e-bb72-0ad0100b3228", + "metadata": {}, + "source": [ + "By following [this lab demo](https://github.com/qBraid/qbraid-lab-demo/blob/045c7a8fbdcae66a7e64533dd9fe0e981dc02cf4/qbraid_sdk/ibm_batch_jobs_grovers.ipynb#L4) provided by qBraid, you can also use qbraid sdk to submit your ibm job and check job status. The following show how to do that.\n", + "\n", + "First, check the qbraid version." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5854118c-2d37-497e-934f-784bdc431b21", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import qbraid\n", + "\n", + "qbraid.__version__" + ] + }, + { + "cell_type": "markdown", + "id": "7d67c858-1ab0-4e46-bf47-f77ccd8f3e87", + "metadata": {}, + "source": [ + "Now import essential libraries and save your ibm api token as an environment variable. Then, set-up your `QiskitProvider` with that token." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1029c085-6e9f-4f56-b525-8d0b294d6dd4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "\n", + "from qbraid import device_wrapper, job_wrapper, get_jobs\n", + "from qbraid.providers import QuantumJob\n", + "from qbraid.providers.exceptions import JobStateError\n", + "from qbraid.providers.ibm import QiskitBackend, QiskitJob, QiskitProvider\n", + "import os\n", + "\n", + "os.environ['QISKIT_IBM_TOKEN'] = ''\n", + "ibmq_token = os.getenv(\"QISKIT_IBM_TOKEN\")\n", + "provider = QiskitProvider(qiskit_ibm_token=ibmq_token)" + ] + }, + { + "cell_type": "markdown", + "id": "aee25386-eb1c-4f11-ab63-38be584e73bc", + "metadata": {}, + "source": [ + "You can also see the device list, accessible with your token." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a79c8520-01f7-4146-860f-996b60cf914c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "provider.get_devices()" + ] + }, + { + "cell_type": "markdown", + "id": "a1fb6069-3a00-4250-ad6f-11851ef9089f", + "metadata": {}, + "source": [ + "`qbraid.providers.ibm` also supports useful filtering by `get_devices()`. You can quickly find the least busy backend by using `ibm_least_busy_gpu()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f562ceb-72d9-4be4-8e8b-15690286c558", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#ibm_device = provider.ibm_least_busy_qpu() #return least busy backend of provider\n", + "#ibm_device = provider.get_devices(operational=True, simulator=False) #return backend list which is now operate and not a simulator\n", + "ibm_device = provider.get_device(\"ibm_kyoto\") #return backend by name\n" + ] + }, + { + "cell_type": "markdown", + "id": "545c1b43-9679-4dd6-ad6c-3dc7a48833df", + "metadata": {}, + "source": [ + "To send the quantum circuit to the backend and check the job status in the right sidebar of qBraid Quantum lab, wrap the ibm backend with `device_wrapper`. If you insert the backend, which does not appear in the right sidebar panel's \"device\" section, this code will return an error." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "086710ef-5cac-4fe3-95f0-d071c8321cea", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#qbraid_ibm_device = device_wrapper(ibm_device) #you and add device called by provider as well\n", + "qbraid_ibm_device = device_wrapper(\"ibm_kyoto\")" + ] + }, + { + "cell_type": "markdown", + "id": "953be90a-d983-444d-8d1f-4ebe9cd9f0e8", + "metadata": {}, + "source": [ + "To send a quantum circuit, you can simply call `wrapped_device.run(circuit, options)`. See [API document](https://docs.qbraid.com/en/stable/sdk/devices.html#device-wrapper) for more information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c92dd6f-c82f-46a5-bf80-07bdfc2f254d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "qbraid_ibm_job = qbraid_ibm_device.run(circ, shots=20000)#works if backend is at Devices list. Error if I try to use premium backend" + ] + }, + { + "cell_type": "markdown", + "id": "52c2510a-2a69-4624-aede-56237b76fe53", + "metadata": {}, + "source": [ + "Shortly afterwards you should see your submitted job in the right side panel. If you cannot see your job, click the circulation icon at the top to refresh or select `All` for Provider.\n", + "\n", + "Also, you can check your job status by using `job_wrapper(job_id).` Please note that the `job_id` for `job_wrapper` must be a qBraidID, which you can get by adding `.id` to your job." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bb09636-cfbf-480d-aa53-734cd5a11c07", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "job = job_wrapper(qbraid_ibm_job.id)\n", + "job.status()" + ] + }, + { + "cell_type": "markdown", + "id": "2c65961f-540e-43dc-b318-c57d86e31751", + "metadata": {}, + "source": [ + "You can use the `get_jobs` function to a return a list of your previously submitted quantum jobs, along with the status of each." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3523429e-3341-4a57-80e3-2ad2fb9d3871", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "get_jobs()" + ] + }, + { + "cell_type": "markdown", + "id": "4dedeb3d-a03c-4b70-b9f9-a7a7000eb045", + "metadata": {}, + "source": [ + "This `qBraidID` can be used to reinstantiate a qBraid QuantumJob object at any time, and even in a separate program, with no loss of information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "848add3e-1059-4726-be73-855fb8a7adad", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "job = job_wrapper(\"\")\n", + "job.status()" + ] + }, + { + "cell_type": "markdown", + "id": "2ceac5e2-6738-473a-b993-cd3cf6da2e19", + "metadata": {}, + "source": [ + "After the job has completed, we’ll gather the result, print the measurement counts, and plot a histogram of the count by using `qbraid.visualization.plot_histogram`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d39b177-e2a5-41d4-8752-a946cb475f7a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ibm_result = job.result()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc1bfa7a-b16e-4b71-b949-662f54a6c141", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qbraid.visualization import plot_histogram, plot_distribution\n", + "\n", + "plot_histogram(ibm_result.measurement_counts())" + ] + }, + { + "cell_type": "markdown", + "id": "b1cb7df6-d68d-4273-b243-98b79f759f11", + "metadata": {}, + "source": [ + "Also, you can plot a histogram of a probability with `plot_distribution`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50af7aa6-bd20-4224-9a94-e447768d869d", + "metadata": {}, + "outputs": [], + "source": [ + "plot_distribution(ibm_result.measurement_counts())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a0395af-a533-41e8-9852-d7af847def13", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qbraid_sdk/img/ibm_api_token.png b/qbraid_sdk/img/ibm_api_token.png new file mode 100644 index 0000000..b040d93 Binary files /dev/null and b/qbraid_sdk/img/ibm_api_token.png differ