257 lines
9.1 KiB
Plaintext
257 lines
9.1 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "7d054012-24ae-4249-8263-ba857939e9ca",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Converting from Qiskit Runtime Programs\n",
|
|
"\n",
|
|
"This tutorial will be a demonstation of converting your custom Qiskit Runtime Program into a Qiskit Serverless `QiskitPattern`.\n",
|
|
"\n",
|
|
"If you were using Qiskit Runtime Programs before, your code probably looks similar to the following example:\n",
|
|
"\n",
|
|
"```python\n",
|
|
"\"\"\"A sample runtime program that submits random circuits for user-specified iterations.\"\"\"\n",
|
|
"\n",
|
|
"import random\n",
|
|
"\n",
|
|
"from qiskit import transpile\n",
|
|
"from qiskit.circuit.random import random_circuit\n",
|
|
"\n",
|
|
"\n",
|
|
"def prepare_circuits(backend):\n",
|
|
" circuit = random_circuit(\n",
|
|
" num_qubits=5, depth=4, measure=True, seed=random.randint(0, 1000)\n",
|
|
" )\n",
|
|
" return transpile(circuit, backend)\n",
|
|
"\n",
|
|
"\n",
|
|
"def main(backend, user_messenger, **kwargs):\n",
|
|
" \"\"\"Main entry point of the program.\n",
|
|
"\n",
|
|
" Args:\n",
|
|
" backend: Backend to submit the circuits to.\n",
|
|
" user_messenger: Used to communicate with the program consumer.\n",
|
|
" kwargs: User inputs.\n",
|
|
" \"\"\"\n",
|
|
" iterations = kwargs.pop(\"iterations\", 5)\n",
|
|
" for it in range(iterations):\n",
|
|
" qc = prepare_circuits(backend)\n",
|
|
" result = backend.run(qc).result()\n",
|
|
" user_messenger.publish({\"iteration\": it, \"counts\": result.get_counts()})\n",
|
|
"\n",
|
|
" return \"Hello, World!\"\n",
|
|
"```\n",
|
|
"\n",
|
|
"\n",
|
|
"All Qiskit Runtime Programs have a `main` method which accepts `backend`, `user_messenger` and `**kwargs`. This method is not required for Qiskit Serverless patterns.\n",
|
|
"\n",
|
|
"Qiskit Serverless handles backends, logging, and input arguments a bit differently than Qiskit Runtime:\n",
|
|
"\n",
|
|
"- `backend`. For Qiskit Serverless programs you are not limited to single backend for a program. You can call any\n",
|
|
" number of backends from single program. Since `Backend.run` is deprecated, we will be using Qiskit Primitives to do our calculation.\n",
|
|
"- `user_messenger` were used in Qiskit Runtime Programs to facilitate retrieving logs from the program. Qiskit Serverless does not\n",
|
|
" require passing such an object. Instead, all contents of `stdout` (e.g. print statements, logging messages) will be provided to the\n",
|
|
" user via the Qiskit Serverless job handler.\n",
|
|
"- `**kwargs` was a variable used to capture program inputs from the user. Users should now input their arguments to the `ServerlessProvider.run` method,\n",
|
|
" and the arguments should be retrieved within the pattern using the `get_arguments` function from Qiskit Serverless.\n",
|
|
"- To save the results of a pattern, the `save_result` function should be used. It accepts a python dictionary and can be accessed via the job handler.\n",
|
|
"\n",
|
|
"Let's use the guidelines above to transform the above Qiskit Runtime Program into a Qiskit Serverless QiskitPattern.\n",
|
|
"\n",
|
|
"```python\n",
|
|
"# migrated_pattern.py\n",
|
|
"\"\"\"A sample runtime pattern that submits random circuits for user-specified iterations.\"\"\"\n",
|
|
"\n",
|
|
"import random\n",
|
|
"\n",
|
|
"from qiskit import transpile\n",
|
|
"from qiskit.circuit.random import random_circuit\n",
|
|
"from qiskit.primitives import Sampler\n",
|
|
"\n",
|
|
"from qiskit_serverless import get_arguments, save_result\n",
|
|
"\n",
|
|
"\n",
|
|
"def prepare_circuits():\n",
|
|
" circuit = random_circuit(\n",
|
|
" num_qubits=5, depth=4, measure=True, seed=random.randint(0, 1000)\n",
|
|
" )\n",
|
|
" return transpile(circuit)\n",
|
|
"\n",
|
|
"\n",
|
|
"arguments = get_arguments()\n",
|
|
"iterations = arguments.get(\"iterations\", 5)\n",
|
|
"\n",
|
|
"for it in range(iterations):\n",
|
|
" qc = prepare_circuits()\n",
|
|
" result = Sampler.run(qc).result()\n",
|
|
" print({\"iteration\": it, \"dists\": result.quasi_dists})\n",
|
|
"\n",
|
|
"save_result({\"result\": \"Hello, World!\"})\n",
|
|
"```\n",
|
|
"\n",
|
|
"Let's save this code as `./src/migrated_pattern.py` and execute it using the `QiskitPattern` class from the `qiskit_serverless` package."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "50fb2a64-751d-40fb-bac8-db49dc92fbca",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from qiskit_serverless import QiskitPattern\n",
|
|
"\n",
|
|
"pattern = QiskitPattern(\n",
|
|
" title=\"migrated-pattern\", entrypoint=\"migrated_pattern.py\", working_dir=\"./src/\"\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "162c482e-8f86-4224-a9b9-f6567b34acf4",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<ServerlessProvider: gateway-provider>"
|
|
]
|
|
},
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"from qiskit_serverless import ServerlessProvider\n",
|
|
"import os\n",
|
|
"\n",
|
|
"serverless = ServerlessProvider(\n",
|
|
" token=os.environ.get(\"GATEWAY_TOKEN\", \"awesome_token\"),\n",
|
|
" host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n",
|
|
")\n",
|
|
"serverless"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "0e88737d-a94c-487a-881c-c884ba0a3099",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"'migrated-pattern'"
|
|
]
|
|
},
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"serverless.upload(pattern)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "31e22bdd-2625-494a-a697-b1e26fcd066a",
|
|
"metadata": {},
|
|
"source": [
|
|
"While Qiskit Runtime programs required users to upload their program and call it in two separate steps, the ``QiskitPattern`` class allows users to send a job for remote execution in a single step."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "9f6eddae-a889-4958-8f0a-7e9f8ec29800",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<Job | 0ae02e24-859a-43c1-a9e9-038dcb7dc296>"
|
|
]
|
|
},
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"job = serverless.run(\"migrated-pattern\", arguments={\"iterations\": 3})\n",
|
|
"job"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "2223b57b-1dbc-45c7-8fd6-8e2ebfb843aa",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'result': 'Hello, World!'}"
|
|
]
|
|
},
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"job.result()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "314e7716-8495-41e0-92dc-b2404ec860d4",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\n",
|
|
"OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\n",
|
|
"{'iteration': 0, 'dists': [{0: 0.01953568379784, 1: 0.003434588839427, 2: 0.000962772320948, 3: 0.022007500316319, 4: 0.018613812117662, 5: 0.003272513622768, 6: 0.000917339944671, 7: 0.020968985795759, 8: 0.089342856396779, 9: 0.100647254570651, 10: 0.004403062114611, 11: 0.015707460288483, 12: 0.085126845839344, 13: 0.095897799438366, 14: 0.004195285498675, 15: 0.014966239097696, 16: 0.018613812117662, 17: 0.003272513622768, 18: 0.007093750939097, 19: 0.014792574801333, 20: 0.01953568379784, 21: 0.003434588839427, 22: 0.007445077580607, 23: 0.01552519505666, 24: 0.085126845839344, 25: 0.067651119863038, 26: 0.032441965074003, 27: 0.014966239097696, 28: 0.089342856396779, 29: 0.071001623840398, 30: 0.034048692844864, 31: 0.015707460288483}]}\n",
|
|
"{'iteration': 1, 'dists': [{0: 0.179254126288168, 1: 0.382666923582299, 4: 0.031208803971925, 5: 0.066623721595232, 16: 0.092444479011949, 17: 0.197348005974499, 20: 0.016094924471265, 21: 0.034359015104663}]}\n",
|
|
"{'iteration': 2, 'dists': [{0: 0.003593062771524, 2: 0.037032118667734, 4: 0.032043767985561, 6: 0.330261031899324, 8: 0.005805731220397, 10: 0.059837119799466, 12: 0.002779551551986, 14: 0.028647616104007, 16: 0.003593062771524, 18: 0.037032118667734, 20: 0.032043767985561, 22: 0.330261031899324, 24: 0.005805731220397, 26: 0.059837119799466, 28: 0.002779551551986, 30: 0.028647616104007}]}\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print(job.logs())"
|
|
]
|
|
}
|
|
],
|
|
"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.16"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|