350 lines
12 KiB
Plaintext
350 lines
12 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f4e55284-8bd6-4cb2-b044-11816cba1e2d",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Run jobs in a batch"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3f77b9f7-7967-45ad-a68b-3db6e0d36456",
|
|
"metadata": {
|
|
"tags": [
|
|
"version-info"
|
|
]
|
|
},
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "388d0a36-0a7c-4b60-8607-4e535f8adf2c",
|
|
"metadata": {},
|
|
"source": [
|
|
"Use batch mode to submit multiple primitive jobs simultaneously. Following are examples of working with batches.\n",
|
|
"\n",
|
|
"## Set up to use batches\n",
|
|
"\n",
|
|
"Before starting a batch, you must [set up Qiskit Runtime](/docs/guides/install-qiskit) and initialize it as a service:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "340d9d45-9ec0-473f-bf17-9dc7eb0804ed",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from qiskit_ibm_runtime import (\n",
|
|
" QiskitRuntimeService,\n",
|
|
" Batch,\n",
|
|
" SamplerV2 as Sampler,\n",
|
|
" EstimatorV2 as Estimator,\n",
|
|
")\n",
|
|
"\n",
|
|
"\n",
|
|
"service = QiskitRuntimeService()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "fc80a9fa-ffc1-419f-be98-ef36b73eda9a",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Open a batch\n",
|
|
"\n",
|
|
"You can open a runtime batch by using the context manager `with Batch(...)` or by initializing the `Batch`\n",
|
|
"class. When you start a batch, you must specify a QPU by passing a `backend` object. The batch starts when its first job begins execution.\n",
|
|
"\n",
|
|
"\n",
|
|
"**Batch class**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "02e53d53-3410-4e07-9c02-c582b97e15e1",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"backend = service.least_busy(operational=True, simulator=False)\n",
|
|
"batch = Batch(backend=backend)\n",
|
|
"estimator = Estimator(mode=batch)\n",
|
|
"sampler = Sampler(mode=batch)\n",
|
|
"# Close the batch because no context manager was used.\n",
|
|
"batch.close()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ad0927c2-cbba-4392-bced-fddcde738521",
|
|
"metadata": {},
|
|
"source": [
|
|
"**Context manager**\n",
|
|
"\n",
|
|
"The context manager automatically opens and closes the batch."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "fe96e5dd-8237-458d-8657-dd0f71c65f8a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from qiskit_ibm_runtime import (\n",
|
|
" Batch,\n",
|
|
" SamplerV2 as Sampler,\n",
|
|
" EstimatorV2 as Estimator,\n",
|
|
")\n",
|
|
"\n",
|
|
"backend = service.least_busy(operational=True, simulator=False)\n",
|
|
"with Batch(backend=backend):\n",
|
|
" estimator = Estimator()\n",
|
|
" sampler = Sampler()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "285f7538-3abd-4940-bca1-b1a61bc25bd5",
|
|
"metadata": {},
|
|
"source": [
|
|
"<span id=\"specify-batch-length\"></span>\n",
|
|
"## Batch length\n",
|
|
"\n",
|
|
"You can define the batch's maximum time to live (TTL) with the `max_time` parameter. This should exceed the longest job's execution time. This timer starts when the batch starts. When the value is reached, the batch is closed. Any jobs that are running will finish, but jobs still queued are failed.\n",
|
|
"\n",
|
|
"```python\n",
|
|
"with Batch(backend=backend, max_time=\"25m\"):\n",
|
|
" ...\n",
|
|
"```\n",
|
|
"\n",
|
|
"There is also an interactive time to live (interactive TTL) value that cannot be configured (1 minute for all plans). If no batch jobs are queued within that window, the batch is temporarily deactivated.\n",
|
|
"\n",
|
|
"Default maximum TTL values:\n",
|
|
"\n",
|
|
"| Instance type | Default Maximum TTL |\n",
|
|
"|----------------|---------------------|\n",
|
|
"| All paid plans | 8 hours |\n",
|
|
"| Open | 10 minutes |\n",
|
|
"\n",
|
|
"To determine a batch's maximum TTL or interactive TTL, follow the instructions in [Determine batch details](#batch-details) and look for the `max_time` or `interactive_timeout` value, respectively.\n",
|
|
"\n",
|
|
"<span id=\"close\"></span>\n",
|
|
"## Close a batch\n",
|
|
"\n",
|
|
"A batch automatically closes when it exits the context manager. When the batch context manager is exited, the batch is put into \"In progress, not accepting new jobs\" status. This means that the batch finishes processing all running or queued jobs until the maximum TTL value is reached. After all jobs are completed, the batch is immediately closed. You cannot submit jobs to a closed batch."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "bacbd7eb-2245-4a87-91cf-73d1187c788a",
|
|
"metadata": {
|
|
"tags": [
|
|
"remove-cell"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from qiskit.quantum_info import SparsePauliOp\n",
|
|
"from qiskit.circuit import QuantumCircuit, Parameter\n",
|
|
"from qiskit.transpiler import generate_preset_pass_manager\n",
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"# This cell is hidden from users\n",
|
|
"service = QiskitRuntimeService()\n",
|
|
"backend = service.least_busy()\n",
|
|
"\n",
|
|
"# Define two circuits, each with one parameter with two parameters.\n",
|
|
"circuit = QuantumCircuit(2)\n",
|
|
"circuit.h(0)\n",
|
|
"circuit.cx(0, 1)\n",
|
|
"circuit.ry(Parameter(\"a\"), 0)\n",
|
|
"circuit.cx(0, 1)\n",
|
|
"circuit.h(0)\n",
|
|
"circuit.measure_all()\n",
|
|
"\n",
|
|
"\n",
|
|
"pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
|
|
"transpiled_circuit = pm.run(circuit)\n",
|
|
"transpiled_circuit_sampler = transpiled_circuit\n",
|
|
"transpiled_circuit_sampler.measure_all()\n",
|
|
"\n",
|
|
"params = np.random.uniform(size=(2, 3)).T\n",
|
|
"observables = [\n",
|
|
" [\n",
|
|
" SparsePauliOp([\"XX\", \"IY\"], [0.5, 0.5]).apply_layout(\n",
|
|
" transpiled_circuit.layout\n",
|
|
" )\n",
|
|
" ],\n",
|
|
" [SparsePauliOp(\"XX\").apply_layout(transpiled_circuit.layout)],\n",
|
|
" [SparsePauliOp(\"IY\").apply_layout(transpiled_circuit.layout)],\n",
|
|
"]\n",
|
|
"\n",
|
|
"sampler_pub = (transpiled_circuit_sampler, params)\n",
|
|
"estimator_pub = (transpiled_circuit_sampler, observables, params)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "39fa154b-d5f2-411f-8953-367bd5e3c879",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"with Batch(backend=backend) as batch:\n",
|
|
" estimator = Estimator()\n",
|
|
" sampler = Sampler()\n",
|
|
" job1 = estimator.run([estimator_pub])\n",
|
|
" job2 = sampler.run([sampler_pub])\n",
|
|
"\n",
|
|
"# The batch is no longer accepting jobs but the submitted job will run to completion.\n",
|
|
"result = job1.result()\n",
|
|
"result2 = job2.result()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "92515062-ec5e-41a1-8969-59e78c448b1f",
|
|
"metadata": {},
|
|
"source": [
|
|
"<Admonition type=\"tip\">\n",
|
|
"If you are not using a context manager, manually close the batch. If you leave the batch open and submit more jobs to it later, it is possible that the maximum TTL will be reached before the subsequent jobs start running; causing them to be canceled. You can close a batch as soon as you are done submitting jobs to it. When a batch is closed with `batch.close()`, it no longer accepts new jobs, but the already submitted jobs will still run until completion and their results can be retrieved.\n",
|
|
"</Admonition>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d1cb86c0-b397-47a9-ad93-055aa71ca327",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"batch = Batch(backend=backend)\n",
|
|
"\n",
|
|
"# If using qiskit-ibm-runtime earlier than 0.24.0, change `mode=` to `batch=`\n",
|
|
"estimator = Estimator(mode=batch)\n",
|
|
"sampler = Sampler(mode=batch)\n",
|
|
"job1 = estimator.run([estimator_pub])\n",
|
|
"job2 = sampler.run([sampler_pub])\n",
|
|
"print(f\"Result1: {job1.result()}\")\n",
|
|
"print(f\"Result2: {job2.result()}\")\n",
|
|
"\n",
|
|
"# Manually close the batch. Running and queued jobs will run to completion.\n",
|
|
"batch.close()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9594105f-b003-43ee-9a5f-5cf3d6410887",
|
|
"metadata": {},
|
|
"source": [
|
|
"<span id=\"batch-details\"></span>\n",
|
|
"## Determine batch details\n",
|
|
"\n",
|
|
"For a comprehensive overview of a batch's configuration and status, including its interactive and max TTL, use the `batch.details() method`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "8a21ca0e-0373-456c-879f-9bcddda5289a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from qiskit_ibm_runtime import (\n",
|
|
" QiskitRuntimeService,\n",
|
|
" batch,\n",
|
|
" SamplerV2 as Sampler,\n",
|
|
")\n",
|
|
"\n",
|
|
"service = QiskitRuntimeService()\n",
|
|
"backend = service.least_busy(operational=True, simulator=False)\n",
|
|
"\n",
|
|
"with Batch(backend=backend) as batch:\n",
|
|
" print(batch.details())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cbdc7521-7b4c-4e02-a24d-2b5ca0a11abe",
|
|
"metadata": {},
|
|
"source": [
|
|
"<span id=\"partition\"></span>\n",
|
|
"## Reconfigure jobs for parallel processing\n",
|
|
"\n",
|
|
"There are multiple ways you can reconfigure your jobs to take advantage of the parallel processing provided by batching. The following example shows how you can partition a long list of circuits into multiple jobs and run them as a batch to take advantage of the parallel processing."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "31ae3a23-e8bd-4dcd-86c1-10f6d7b5cee4",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from qiskit_ibm_runtime import SamplerV2 as Sampler, Batch\n",
|
|
"from qiskit.circuit.random import random_circuit\n",
|
|
"\n",
|
|
"max_circuits = 100\n",
|
|
"circuits = [random_circuit(5, 5) for _ in range(5 * max_circuits)]\n",
|
|
"all_partitioned_circuits = []\n",
|
|
"for i in range(0, len(circuits), max_circuits):\n",
|
|
" all_partitioned_circuits.append(circuits[i : i + max_circuits])\n",
|
|
"jobs = []\n",
|
|
"start_idx = 0\n",
|
|
"\n",
|
|
"with Batch(backend=backend):\n",
|
|
" sampler = Sampler()\n",
|
|
" for partitioned_circuits in all_partitioned_circuits:\n",
|
|
" job = sampler.run(partitioned_circuits)\n",
|
|
" jobs.append(job)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "5d4420f8-9c8d-4953-8561-1b0bdb8372eb",
|
|
"metadata": {},
|
|
"source": [
|
|
"<Admonition type=\"caution\">\n",
|
|
" If you set `backend=backend` in a primitive, the program is run in job mode, even if it's inside a batch or session context. Setting `backend=backend` is deprecated as of Qiskit Runtime 0.24.0. Instead, use the `mode` parameter.\n",
|
|
"</Admonition>\n",
|
|
"\n",
|
|
"## Next steps\n",
|
|
"\n",
|
|
"<Admonition type=\"tip\" title=\"Recommendations\">\n",
|
|
" - Try an example in the [Combine error mitigation options with the estimator primitive](https://learning.quantum.ibm.com/tutorial/combine-error-mitigation-options-with-the-estimator-primitive) tutorial.\n",
|
|
" - Review the [Batch API](/docs/api/qiskit-ibm-runtime/batch#batch) reference.\n",
|
|
" - Understand the [Job limits](/docs/guides/job-limits) when sending a job to an IBM QPU.\n",
|
|
"</Admonition>"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"description": "How to run quantum computing jobs in batch mode using Qiskit Runtime.",
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"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"
|
|
},
|
|
"title": "Run jobs in a batch"
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|