diff --git a/docs/guides/serverless-manage-resources.ipynb b/docs/guides/serverless-manage-resources.ipynb
index 33813a01eb4..d00a6870c69 100644
--- a/docs/guides/serverless-manage-resources.ipynb
+++ b/docs/guides/serverless-manage-resources.ipynb
@@ -16,7 +16,28 @@
"version-info"
]
},
- "source": []
+ "source": [
+ "\n",
+ "Package versions
\n",
+ "\n",
+ "The code on this page was developed using the following requirements.\n",
+ "We recommend using these versions or newer.\n",
+ "\n",
+ "```\n",
+ "qiskit[all]~=1.2.4\n",
+ "qiskit-ibm-runtime~=0.33.2\n",
+ "qiskit-aer~=0.15.1\n",
+ "qiskit-serverless~=0.18.0\n",
+ "qiskit-ibm-catalog~=0.2\n",
+ "qiskit-addon-sqd~=0.8.1\n",
+ "qiskit-addon-utils~=0.1.0\n",
+ "qiskit-addon-aqc-tensor~=0.1.2\n",
+ "qiskit-addon-obp~=0.1.0\n",
+ "scipy~=1.14.1\n",
+ "pyscf~=2.7.0\n",
+ "```\n",
+ " "
+ ]
},
{
"cell_type": "markdown",
@@ -33,15 +54,40 @@
"id": "b2d40a63-3359-46e9-8f1b-4746b449b407",
"metadata": {},
"source": [
- "For classical tasks that can be parallelized, use the `@distribute_task` decorater to define compute requirements needed to perform a task. Start by recalling the `transpile_parallel.py` example from the [Write your first Qiskit Serverless program](./serverless-first-program) topic:"
+ "For classical tasks that can be parallelized, use the `@distribute_task` decorater to define compute requirements needed to perform a task. Start by recalling the `transpile_remote.py` example from the [Write your first Qiskit Serverless program](./serverless-first-program) topic:"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
+ "id": "9e41cd2f-bce6-4c8a-8e44-537c18b3023c",
+ "metadata": {
+ "tags": [
+ "remove-cell"
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "# This cell is hidden from users, it just creates a new folder\n",
+ "from pathlib import Path\n",
+ "\n",
+ "Path(\"./source_files\").mkdir(exist_ok=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
"id": "475d82f0-15cc-4db3-b3b0-54b07822b2a0",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Writing ./source_files/transpile_remote.py\n"
+ ]
+ }
+ ],
"source": [
"%%writefile ./source_files/transpile_remote.py\n",
"\n",
@@ -71,11 +117,19 @@
]
},
{
- "id": "74fdcd4a-01cd-46ca-aa24-2a8a3605346f",
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
+ "id": "74fdcd4a-01cd-46ca-aa24-2a8a3605346f",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Appending to ./source_files/transpile_remote.py\n"
+ ]
+ }
+ ],
"source": [
"%%writefile --append ./source_files/transpile_remote.py\n",
"\n",
@@ -104,11 +158,19 @@
]
},
{
- "id": "ac99b4a0-4a42-4c43-869d-265344b70359",
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 4,
+ "id": "ac99b4a0-4a42-4c43-869d-265344b70359",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Appending to ./source_files/transpile_remote.py\n"
+ ]
+ }
+ ],
"source": [
"%%writefile --append ./source_files/transpile_remote.py\n",
"\n",
@@ -121,6 +183,172 @@
"save_result(results) # Overwrites any previously saved results"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "757f81e9-3981-4358-a1a2-d3262c7cddcd",
+ "metadata": {
+ "tags": [
+ "remove-cell"
+ ]
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Appending to ./source_files/transpile_remote.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile --append ./source_files/transpile_remote.py\n",
+ "# This cell is hidden from users. It checks the transpilation ran correctly.\n",
+ "from qiskit import QuantumCircuit\n",
+ "assert all(isinstance(result, QuantumCircuit) for result in results)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "df28a92c-3585-49f0-a2ea-828a34638684",
+ "metadata": {
+ "tags": [
+ "remove-cell"
+ ]
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'QUEUED')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'QUEUED')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'QUEUED')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'QUEUED')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'INITIALIZING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'INITIALIZING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Job completed successfully\n"
+ ]
+ }
+ ],
+ "source": [
+ "# This cell is hidden from users.\n",
+ "# It uploads the serverless program and checks it runs.\n",
+ "\n",
+ "\n",
+ "def test_serverless_job(title, entrypoint):\n",
+ " # Import in function to stop them interfering with user-facing code\n",
+ " from qiskit.circuit.random import random_circuit\n",
+ " from qiskit_serverless import IBMServerlessClient, QiskitFunction\n",
+ " import time\n",
+ " import uuid\n",
+ "\n",
+ " title += \"_\" + uuid.uuid4().hex[:8]\n",
+ " serverless = IBMServerlessClient()\n",
+ " transpile_remote_demo = QiskitFunction(\n",
+ " title=title,\n",
+ " entrypoint=entrypoint,\n",
+ " working_dir=\"./source_files/\",\n",
+ " )\n",
+ " serverless.upload(transpile_remote_demo)\n",
+ " job = serverless.get(title).run(\n",
+ " circuit=random_circuit(3, 3),\n",
+ " circuit_list=[random_circuit(3, 3) for _ in range(3)],\n",
+ " backend=\"ibm_kyiv\",\n",
+ " optimization_level=1,\n",
+ " )\n",
+ " for retry in range(25):\n",
+ " time.sleep(5)\n",
+ " status = job.status()\n",
+ " if status == \"DONE\":\n",
+ " print(\"Job completed successfully\")\n",
+ " return\n",
+ " if status not in [\"QUEUED\", \"INITIALIZING\", \"RUNNING\", \"DONE\"]:\n",
+ " raise Exception(\n",
+ " f\"Unexpected job status '{status}'.\\nHere's the logs:\\n\"\n",
+ " + job.logs()\n",
+ " )\n",
+ " print(f\"Waiting for job (status '{status}')\")\n",
+ " raise Exception(\"Job did not complete in time\")\n",
+ "\n",
+ "\n",
+ "test_serverless_job(\n",
+ " title=\"transpile_remote_serverless_test\", entrypoint=\"transpile_remote.py\"\n",
+ ")"
+ ]
+ },
{
"cell_type": "markdown",
"id": "611fe030-4494-46b5-9ea1-9678ac513210",
@@ -137,10 +365,18 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 7,
"id": "cea90969-cfbf-4181-9ffa-524f3709dc69",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Appending to ./source_files/transpile_remote.py\n"
+ ]
+ }
+ ],
"source": [
"%%writefile --append ./source_files/transpile_remote.py\n",
"\n",
@@ -152,118 +388,100 @@
" return None"
]
},
- {
- "cell_type": "markdown",
- "id": "6bc45489-56d0-4f46-8659-9df4d1555516",
- "metadata": {},
- "source": [
- "## Manage data across your program\n",
- "\n",
- "Qiskit Serverless allows you to manage files in the `/data` directory across all your programs. This includes several limitations:\n",
- "\n",
- "- Only `tar` and `h5` files are supported today\n",
- "- This is only a flat `/data` storage, and cannot have `/data/folder/` subdirectories\n",
- "\n",
- "The following shows how to upload files. Be sure you have authenticated to Qiskit Serverless with your [IBM Quantum account](https://quantum.ibm.com/account) (see [Deploy to IBM Quantum Platform](./serverless-first-program#deploy-to-ibm-quantum-platform) for instructions)."
- ]
- },
{
"cell_type": "code",
"execution_count": 8,
- "id": "0183278f-8ce3-4466-9255-097b2d211052",
- "metadata": {},
+ "id": "55163053-2cd8-4e5d-8470-d08055a6f401",
+ "metadata": {
+ "tags": [
+ "remove-cell"
+ ]
+ },
"outputs": [
{
- "data": {
- "text/plain": [
- "'{\"message\":\"/usr/src/app/media/5f37582aa306c50013fac285/transpile_demo.tar\"}'"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import tarfile\n",
- "from qiskit_serverless import IBMServerlessClient\n",
- "\n",
- "# Create a tar\n",
- "filename = \"transpile_demo.tar\"\n",
- "file = tarfile.open(filename, \"w\")\n",
- "file.add(\"./source_files/transpile_remote.py\")\n",
- "file.close()\n",
- "\n",
- "# Upload the tar to Serverless data directory\n",
- "serverless = IBMServerlessClient()\n",
- "serverless.file_upload(filename)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4f762470-945f-48d5-a65b-c60d3b2dae3f",
- "metadata": {},
- "source": [
- "Next, you can list all the files in your `data` directory. This data is accessible to all programs."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "id": "14241fc4-d0cb-4803-8752-a460e1f48708",
- "metadata": {},
- "outputs": [
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'QUEUED')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'QUEUED')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'INITIALIZING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'INITIALIZING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
{
- "data": {
- "text/plain": [
- "['transpile_demo.tar']"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Waiting for job (status 'RUNNING')\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Job completed successfully\n"
+ ]
}
],
"source": [
- "serverless.files()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a97bd83e-8250-43bb-b1c4-d40d822c7ba2",
- "metadata": {},
- "source": [
- "This can be done from a program by using `file_download()` to download the file to the program environment, and uncompressing the `tar`."
- ]
- },
- {
- "cell_type": "code",
- "id": "ef649b2a-ed95-4dd2-89d9-61438faa7c1e",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%%writefile ./source_files/extract_tarfile.py\n",
- "\n",
- "import tarfile\n",
- "from qiskit_serverless import IBMServerlessClient\n",
- "\n",
- "serverless = IBMServerlessClient(token=\"\")\n",
- "files = serverless.files()\n",
- "demo_file = files[0]\n",
- "downloaded_tar = serverless.file_download(demo_file)\n",
- "\n",
- "\n",
- "with tarfile.open(downloaded_tar, 'r') as tar:\n",
- " tar.extractall()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5b93dbdb-2060-468b-8496-ba98142a780b",
- "metadata": {},
- "source": [
- "At this point, your program can interact with the files, as you would a local experiment. `file_upload()` , `file_download()`, and `file_delete()` can be called from your local experiment, or your uploaded program, for consistent and flexible data management."
+ "# This cell is hidden from users.\n",
+ "# It checks the distributed program works.\n",
+ "test_serverless_job(\n",
+ " title=\"transpile_remote_serverless_test\", entrypoint=\"transpile_remote.py\"\n",
+ ")"
]
},
{
diff --git a/scripts/config/notebook-testing.toml b/scripts/config/notebook-testing.toml
index 6af53638592..a97b354d5eb 100644
--- a/scripts/config/notebook-testing.toml
+++ b/scripts/config/notebook-testing.toml
@@ -30,6 +30,7 @@ notebooks_normal_test = [
"docs/guides/operator-class.ipynb",
"docs/guides/error-mitigation-and-suppression-techniques.ipynb",
"docs/guides/serverless-first-program.ipynb",
+ "docs/guides/serverless-manage-resources.ipynb",
"docs/guides/serverless-run-first-workload.ipynb",
"docs/guides/specify-observables-pauli.ipynb",
"docs/guides/qiskit-addons-aqc-get-started.ipynb",
@@ -62,7 +63,6 @@ notebooks_that_submit_jobs = [
notebooks_no_mock = [
"docs/guides/get-started-with-primitives.ipynb",
"docs/guides/hello-world.ipynb",
- "docs/guides/serverless-manage-resources.ipynb",
"docs/guides/noise-learning.ipynb",
"docs/guides/qiskit-addons-obp-get-started.ipynb",
]