quantum-serverless/docs/migration/migration_from_qiskit_runti...

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
}