diff --git a/qBraid-Runtime/qbraid_runtime_batch_jobs.ipynb b/qBraid-Runtime/qbraid_runtime_batch_jobs.ipynb new file mode 100644 index 0000000..00a2de9 --- /dev/null +++ b/qBraid-Runtime/qbraid_runtime_batch_jobs.ipynb @@ -0,0 +1,141 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Submitting Batch Jobs with the qBraid Runtime\n", + "\n", + "The [qBraid-SDK](https://github.com/qBraid/qBraid) can submit a list of circuits as a single batch job. Passing `as_batch=True` to `QbraidDevice.run()` sends the circuits in one API call and returns a single `BatchResult` instead of a separate job per circuit. This was added in [qBraid-SDK v0.12.1](https://github.com/qBraid/qBraid/releases/tag/v0.12.1).\n", + "\n", + "> **Note:** Batch submission requires a device whose profile reports `batch_job_support = True`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "%pip install --upgrade 'qbraid[qiskit,visualization]'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import qbraid\n", + "\n", + "qbraid.__version__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit import QuantumCircuit\n", + "from qbraid.runtime import QbraidProvider\n", + "from qbraid.visualization import plot_histogram\n", + "\n", + "provider = QbraidProvider()\n", + "device = provider.get_device(\"qbraid:equal1:sim:bell-1\")\n", + "\n", + "if not device.profile.batch_job_support:\n", + " raise RuntimeError(f\"Device {device.id} does not support batch jobs.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build the circuits\n", + "\n", + "A batch needs more than one circuit, so we build two with Qiskit. `bell` is a two-qubit circuit and `ghz` is a three-qubit circuit — both are standard entangled states. Calling `measure_all()` adds a measurement on every qubit so the device returns counts." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bell = QuantumCircuit(2)\n", + "bell.h(0)\n", + "bell.cx(0, 1)\n", + "bell.measure_all()\n", + "\n", + "ghz = QuantumCircuit(3)\n", + "ghz.h(0)\n", + "ghz.cx(0, 1)\n", + "ghz.cx(1, 2)\n", + "ghz.measure_all()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Submit as a single batch\n", + "\n", + "We pass the two circuits as a list with `as_batch=True`, so they run as one job instead of two separate submissions. `job.result()` returns a `BatchResult`: `result.num_circuits` is how many circuits ran, and `result.results` holds each circuit's result on its own. Because the two circuits have different numbers of qubits, we print and plot each circuit's counts separately rather than combining them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "job = device.run([bell, ghz], as_batch=True, shots=100)\n", + "\n", + "result = job.result() # BatchResult\n", + "print(result.num_circuits) # 2\n", + "\n", + "for i, circuit_result in enumerate(result.results):\n", + " counts = circuit_result.data.get_counts()\n", + " print(f\"Circuit {i}: {counts}\")\n", + " display(plot_histogram(counts))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "