diff --git a/Dockerfile-notebook b/Dockerfile-notebook index 141f63242..585bd0f84 100644 --- a/Dockerfile-notebook +++ b/Dockerfile-notebook @@ -24,8 +24,8 @@ RUN rm -r ./qs WORKDIR /home/$NB_USER USER $NB_UID -COPY --chown=$NB_UID:$NB_UID ./docs/running/notebooks/ ./serverless/running/ -COPY --chown=$NB_UID:$NB_UID ./docs/development/examples/ ./serverless/examples/ -COPY --chown=$NB_UID:$NB_UID ./docs/development/guides/ ./serverless/guides/ +COPY --chown=$NB_UID:$NB_UID ./docs/getting_started/basic/ ./serverless/getting_started/basic/ +COPY --chown=$NB_UID:$NB_UID ./docs/getting_started/experimental/ ./serverless/getting_started/experimental/ +COPY --chown=$NB_UID:$NB_UID ./docs/examples/ ./serverless/examples/ ENV JUPYTER_ENABLE_LAB=no diff --git a/README.md b/README.md index 6d8fb64fa..65f6dfb26 100644 --- a/README.md +++ b/README.md @@ -72,13 +72,13 @@ For user convenience, this section assumes that users will deploy the infrastruc 1. Access the JupyterLab environment Open `localhost:8888` in your web browser. The default token for the JupyterLab is `123` 1. Write your first example program - In the JupyterLab, create a new file `program.py` in the `serverless/running/source_files/` directory (Note: the directory is inside the containerized environment) + In the JupyterLab, create a new file, `program.py`, in the `work` directory. Save [this example python code](https://qiskit-extensions.github.io/quantum-serverless/quickstart/index.html#id8). Now, you are ready to run the first program. 1. Run the program - In the JupyterLab, create a New Notebook and execute [this python code](https://qiskit-extensions.github.io/quantum-serverless/quickstart/index.html#id9). + In the JupyterLab, create a new notebook in the same directory as your program, and execute [this python code](https://qiskit-extensions.github.io/quantum-serverless/quickstart/index.html#id9). You can check the job status and get the result. @@ -97,8 +97,8 @@ For user convenience, this section assumes that users will deploy the infrastruc That's all! For more detailed examples and explanations refer to the [Guide](https://qiskit-extensions.github.io/quantum-serverless/index.html): +[Getting Started](https://qiskit-extensions.github.io/quantum-serverless/getting_started/index.html#), [Deployment](https://qiskit-extensions.github.io/quantum-serverless/deployment/index.html), -[Running](https://qiskit-extensions.github.io/quantum-serverless/running/index.html#), [Development](https://qiskit-extensions.github.io/quantum-serverless/development/index.html). ---------------------------------------------------------------------------------------------------- diff --git a/docs/conf.py b/docs/conf.py index b1cda2693..d791cd3e8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,7 +8,7 @@ from pathlib import Path from importlib.metadata import version as metadata_version -sys.path.append(os.path.abspath('../client')) +sys.path.append(os.path.abspath("../client")) project = "Quantum serverless" copyright = "2022" # pylint: disable=redefined-builtin @@ -58,4 +58,3 @@ nbsphinx_execute = "never" nbsphinx_widgets_path = "" exclude_patterns = ["_build", "**.ipynb_checkpoints"] - diff --git a/docs/deployment/cloud.rst b/docs/deployment/cloud.rst index 6c8f52429..b6d77578c 100644 --- a/docs/deployment/cloud.rst +++ b/docs/deployment/cloud.rst @@ -21,11 +21,10 @@ This guide contains: Installation requirements ========================= -To deploy the infrastructure required for ``Quantum Serverless`` you need to have installed three main tools: +To deploy the infrastructure required for ``Quantum Serverless`` you need to have installed two main tools: * `Docker `_ * `Helm `_ -* `Terraform `_ Each of these tools' webpages contain instructions for installing on Windows, MacOS, and Linux. @@ -40,9 +39,7 @@ Once you have these tools installed, you can check the installation by running t $ $ helm version $ > version.BuildInfo{Version:"X", GitCommit:"Y", GitTreeState:"Z", GoVersion:"T"} - $ - $ terraform version - $ > Terraform X + If all the commands return the correct versions, then congratulations, you have the tools installed! @@ -133,56 +130,3 @@ Optionally, you can install an observability package to handle logging and monit :caption: run this commands with the release version like 0.6.3 in x.y.z (2 places) using the same namespace as in the previous helm command $ helm -n install qs-observability https://github.com/Qiskit-Extensions/quantum-serverless/releases/download/vx.y.z/qs-observability-x.y.z.tgz - -.. _terraform-deployment: - -Quantum Serverless configuration -================================== - -Once your resources are deployed, we can configure the Quantum Serverless ``client`` package. -There are a couple of simple ways to do this. - -One option is to pass the configuration as arguments to the constructor of a ``QuantumServerless`` instance: - -.. code-block:: - :caption: constructor arguments example - - serverless = QuantumServerless({ - "providers": [{ - "name": "my_provider", # provider name - "compute_resource": { # main computational resource - "name": "my_resource", # cluster name - "host": "HOST_ADDRESS_OF_CLUSTER_HEAD_NODE", # cluster host address, if you are using helm it will be DEPLOYMENT_NAME-kuberay-head-svc - } - }] - }) - -Another option is to create an instance from a configuration file, which has exactly the same structure as the constructor argument in the above example. - -.. code-block:: - :caption: config.json example - - { - "providers": [{ - "name": "my_provider", - "compute_resource": { - "name": "my_cluster", - "host": "HOST_ADDRESS_OF_CLUSTER_HEAD_NODE", - } - }] - } - -Instantiate the ``QuantumServerless`` instance from the configuration file: - -.. code-block:: - :caption: verify the name and the path to load the file - - serverless = QuantumServerless.load_configuration("./config.json") - -And use it as follows: - -.. code-block:: - :caption: remember to use the same provider name - - with serverless.provider("my_provider"): - ... diff --git a/docs/development/examples/07_benchmark_program.ipynb b/docs/development/examples/07_benchmark_program.ipynb deleted file mode 100644 index 6a32e2e19..000000000 --- a/docs/development/examples/07_benchmark_program.ipynb +++ /dev/null @@ -1,150 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "604850c4-053a-4b78-bff2-f5f0c9250ed8", - "metadata": {}, - "source": [ - "# Example: complex workflows\n", - "\n", - "In order to test compute resources we need to have a benchmark.\n", - "\n", - "In this benchmark program we demonstrate parallel workflows, recursion, parameter handling, etc.\n", - "\n", - "Below you can see an execution graph. Each of these boxes is a task in a program. This benchmark is designed to test vertical and horizontal scalability of compute resources.\n", - "\n", - "![benchmark flow](./images/benchmark_flow.png)\n", - "\n", - "The benchmark accepts a list of arguments to control stress levels:\n", - "- `n_entries` - number of circuits and observables will be used in each iteration on generation task.\n", - "- `depth_of_recursion` - defines how many recursive iterations generation task will have. (Number of generated circuits will be n_entries * depth_of_recursion).\n", - "- `n_backends` - number of backends, which defines how many parallel transpilations and estimations will happen.\n", - "- `num_qubits` - number of qubits will be used in a program. Affects backends, circuits and observables.\n", - "- `circuit_depth` - depth of generated circuits.\n", - "- `size_of_observable` - size of generated observables.\n", - "- `n_graphs` - number of times graph above will be executed within one program.\n", - "\n", - "\n", - "------\n", - "\n", - "\n", - "Now let's create serverless object and lunch execution of our benchmark." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "b031e9c4-8503-4535-8517-22f445593eb5", - "metadata": {}, - "outputs": [], - "source": [ - "from quantum_serverless import QuantumServerless, Program, Provider\n", - "import os" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "3694d35b-6ad7-4a60-9edc-9c674be56908", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gateway_provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", - " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", - ")\n", - "serverless = QuantumServerless(gateway_provider)\n", - "serverless" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "030ccde4-d18b-43fc-979e-68df797f5977", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "program = Program(\n", - " title=\"benchmark_program\",\n", - " entrypoint=\"benchmark.py\",\n", - " working_dir=\"./source_files\",\n", - " description=\"Benchmark program to test compute resources.\"\n", - ")\n", - "\n", - "job = serverless.run(program, arguments={\n", - " \"num_qubits\": 2,\n", - " \"n_entries\": 2,\n", - " \"depth_of_recursion\": 4,\n", - " \"n_backends\": 3,\n", - " \"n_graphs\": 1\n", - "})\n", - "job" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "316d3bdd-c9ed-404e-bf76-afca850920f5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'SUCCEEDED'" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "job.status()" - ] - } - ], - "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.7.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/development/examples/images/benchmark_flow.png b/docs/development/examples/images/benchmark_flow.png deleted file mode 100644 index 9916a346f..000000000 Binary files a/docs/development/examples/images/benchmark_flow.png and /dev/null differ diff --git a/docs/development/examples/images/diagram_get.png b/docs/development/examples/images/diagram_get.png deleted file mode 100644 index b9481bcf3..000000000 Binary files a/docs/development/examples/images/diagram_get.png and /dev/null differ diff --git a/docs/development/examples/images/diagrams_compute_resource.png b/docs/development/examples/images/diagrams_compute_resource.png deleted file mode 100644 index df7f42b37..000000000 Binary files a/docs/development/examples/images/diagrams_compute_resource.png and /dev/null differ diff --git a/docs/development/examples/images/diagrams_context_management.png b/docs/development/examples/images/diagrams_context_management.png deleted file mode 100644 index 4978678a0..000000000 Binary files a/docs/development/examples/images/diagrams_context_management.png and /dev/null differ diff --git a/docs/development/examples/images/diagrams_function.png b/docs/development/examples/images/diagrams_function.png deleted file mode 100644 index 78c3e1d5f..000000000 Binary files a/docs/development/examples/images/diagrams_function.png and /dev/null differ diff --git a/docs/development/examples/images/diagrams_infra.png b/docs/development/examples/images/diagrams_infra.png deleted file mode 100644 index 5c0b53c20..000000000 Binary files a/docs/development/examples/images/diagrams_infra.png and /dev/null differ diff --git a/docs/development/examples/images/diagrams_put.png b/docs/development/examples/images/diagrams_put.png deleted file mode 100644 index 9f7a61caf..000000000 Binary files a/docs/development/examples/images/diagrams_put.png and /dev/null differ diff --git a/docs/development/examples/images/diagrams_resource_allocation.png b/docs/development/examples/images/diagrams_resource_allocation.png deleted file mode 100644 index 03cc65630..000000000 Binary files a/docs/development/examples/images/diagrams_resource_allocation.png and /dev/null differ diff --git a/docs/development/examples/images/electronic_structure_problem.png b/docs/development/examples/images/electronic_structure_problem.png deleted file mode 100644 index 5756b86a2..000000000 Binary files a/docs/development/examples/images/electronic_structure_problem.png and /dev/null differ diff --git a/docs/development/examples/images/qr_demo1.png b/docs/development/examples/images/qr_demo1.png deleted file mode 100644 index a5f1e995b..000000000 Binary files a/docs/development/examples/images/qr_demo1.png and /dev/null differ diff --git a/docs/development/examples/images/qr_docs.png b/docs/development/examples/images/qr_docs.png deleted file mode 100644 index 472fd3a25..000000000 Binary files a/docs/development/examples/images/qr_docs.png and /dev/null differ diff --git a/docs/development/examples/images/qr_repo.png b/docs/development/examples/images/qr_repo.png deleted file mode 100644 index 920bbb595..000000000 Binary files a/docs/development/examples/images/qr_repo.png and /dev/null differ diff --git a/docs/development/examples/serverless_config.json b/docs/development/examples/serverless_config.json deleted file mode 100644 index 3d38dafd3..000000000 --- a/docs/development/examples/serverless_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "providers": [{ - "name": "docker", - "compute_resource": { - "name": "docker", - "host": "localhost" - } - }] -} diff --git a/docs/development/examples/source_files/benchmark.py b/docs/development/examples/source_files/benchmark.py deleted file mode 100644 index 2a9eed6ed..000000000 --- a/docs/development/examples/source_files/benchmark.py +++ /dev/null @@ -1,183 +0,0 @@ -# This code is a Qiskit project. -# -# (C) Copyright IBM 2023. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - - -"""This is benchmark program for stress testing compute resources.""" -import argparse -import time -from typing import List - -from qiskit import QuantumCircuit, transpile -from qiskit.circuit.random import random_circuit -from qiskit.primitives import Estimator -from qiskit.providers import Backend -from qiskit.providers.fake_provider import ConfigurableFakeBackend -from qiskit.quantum_info.random import random_pauli_list -from quantum_serverless import QuantumServerless, get, distribute_task, put - - -@distribute_task() -def generate_circuits( - depth_of_recursion: int, num_qubits: int, depth_of_circuit: int, n_circuits: int -): - """Generates random circuits.""" - circuits = [random_circuit(num_qubits, depth_of_circuit) for _ in range(n_circuits)] - if depth_of_recursion <= 1: - return circuits - else: - return circuits + get( - generate_circuits( - depth_of_recursion - 1, num_qubits, depth_of_circuit, n_circuits - ) - ) - - -@distribute_task() -def generate_observables( - depth_of_recursion: int, num_qubits: int, size: int, n_observables: int -): - """Generated random observables.""" - observables = [random_pauli_list(num_qubits, size) for _ in range(n_observables)] - if depth_of_recursion <= 1: - return observables - else: - return observables + get( - generate_observables(depth_of_recursion - 1, num_qubits, size, n_observables) - ) - - -@distribute_task() -def generate_data( - depth_of_recursion: int, - num_qubits: int, - n_entries: int, - circuit_depth: int = 2, - size_of_observable: int = 2, -): - return get( - generate_circuits( - depth_of_recursion=depth_of_recursion, - num_qubits=num_qubits, - n_circuits=n_entries, - depth_of_circuit=circuit_depth, - ) - ), get( - generate_observables( - depth_of_recursion=depth_of_recursion, - num_qubits=num_qubits, - size=size_of_observable, - n_observables=n_entries, - ) - ) - - -def get_backends(n_backends: int, num_qubits: int): - """Returns list of backends for program.""" - backend = ConfigurableFakeBackend("Tashkent", n_qubits=num_qubits, version=1) - - return [backend for _ in range(n_backends)] - - -@distribute_task() -def transpile_remote( - circuits: List[QuantumCircuit], backend: Backend -) -> List[QuantumCircuit]: - """Transpiles circuits against backend.""" - return transpile(circuits, backend) - - -@distribute_task() -def estimate(circuits: list, observables: list): - """Estimates expectation values of given circuit.""" - return Estimator().run(circuits, observables).result() - - -@distribute_task() -def run_graph( - depth_of_recursion: int, - num_qubits: int, - n_entries: int, - circuit_depth: int, - size_of_observable: int, - n_backends: int, -): - backends = get_backends(n_backends, num_qubits) - - circuits, observables = get( - generate_data( - depth_of_recursion=depth_of_recursion, - num_qubits=num_qubits, - n_entries=n_entries, - circuit_depth=circuit_depth, - size_of_observable=size_of_observable, - ) - ) - - observables_ref = put(observables) - - results = [] - for backend in backends: - results.append(estimate(transpile_remote(circuits, backend), observables_ref)) - - return get(results) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "--depth_of_recursion", - help="Depth of recursion in generating data.", - default=3, - type=int, - ) - parser.add_argument( - "--num_qubits", help="Number of qubits used in program.", default=2, type=int - ) - parser.add_argument("--n_entries", help="Number of circuits.", default=10, type=int) - parser.add_argument( - "--circuit_depth", help="Depth of circuits.", default=3, type=int - ) - parser.add_argument( - "--size_of_observable", - help="Size of observables in program.", - default=3, - type=int, - ) - parser.add_argument("--n_backends", help="Number of backends", default=3, type=int) - parser.add_argument( - "--n_graphs", help="Number of graphs to run", default=1, type=int - ) - - args = parser.parse_args() - - with QuantumServerless().context(): - - t0 = time.time() - - results = get( - [ - run_graph( - depth_of_recursion=args.depth_of_recursion, - num_qubits=args.num_qubits, - n_entries=args.n_entries, - circuit_depth=args.circuit_depth, - size_of_observable=args.size_of_observable, - n_backends=args.n_backends, - ) - for _ in range(args.n_graphs) - ] - ) - - runtime = time.time() - t0 - - print(f"Execution time: {runtime}") - print(f"Results: {results}") diff --git a/docs/development/guides/07_working_with_datasets.ipynb b/docs/development/guides/07_working_with_datasets.ipynb deleted file mode 100644 index b48d0f082..000000000 --- a/docs/development/guides/07_working_with_datasets.ipynb +++ /dev/null @@ -1,296 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "4e3e385b-b7a3-4e16-b503-3216e26e92fa", - "metadata": {}, - "source": [ - "# Guide: working with large datasets\n", - "\n", - "There are a lot of cases when you need to work with large datasets, that needs to be processed in parallel.\n", - "\n", - "For this usecase we will be using [Ray datasets](https://docs.ray.io/en/latest/data/getting-started.html#datasets-getting-started). As QuantumServerless if fully compatible with Ray, we can do so without any interuption for our workflows." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "be98ac75-ade5-4241-ac65-3a43b4d62ea9", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import List, Tuple\n", - "\n", - "from qiskit import QuantumCircuit\n", - "from qiskit.circuit.random import random_circuit\n", - "from qiskit.primitives import Sampler\n", - "from quantum_serverless import QuantumServerless, distribute_task, get\n", - "\n", - "from ray import data # let's import data from ray" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "db8ca5ae-c2ab-4f83-9d8c-7439cbbdbbeb", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture\n", - "\n", - "serverless = QuantumServerless()\n", - "\n", - "serverless.context()" - ] - }, - { - "cell_type": "markdown", - "id": "e44249e8-3221-40ed-b996-47a607c467e3", - "metadata": {}, - "source": [ - "Let's create our first dataset of circuits" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "id": "e60c5b42-4cf8-4050-bfb1-5f9244501346", - "metadata": {}, - "outputs": [], - "source": [ - "ds = data.from_items([\n", - " random_circuit(1, 2, measure=True)\n", - " for idx in range(100)\n", - "])" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "id": "3dc76b7c-6019-4714-a7f8-b25e55021867", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ┌───┐┌───┐┌─┐\n", - " q: ┤ T ├┤ Y ├┤M├\n", - " └───┘└───┘└╥┘\n", - "c: 1/═══════════╩═\n", - " 0 \n" - ] - } - ], - "source": [ - "ds.show(1)" - ] - }, - { - "cell_type": "markdown", - "id": "68354c07-952b-4f05-8d1f-0cb460f95b1d", - "metadata": {}, - "source": [ - "Now we can repartition it into 5 blocks, in order to provide parallel execution capabilities to data handlers" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "id": "2be2a162-ea93-4303-9330-802d4f4a13ba", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Repartition: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 315.78it/s]\n" - ] - } - ], - "source": [ - "ds = ds.repartition(5)" - ] - }, - { - "cell_type": "markdown", - "id": "889161b2-dc8a-4ac8-8eb8-3f3c77446e1d", - "metadata": {}, - "source": [ - "We can apply different mapping operations to data in order to process it. \n", - "\n", - "Let's calculate depth of circuit for the sake of example. " - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "id": "54bb05ce-a840-4171-bffa-8aabddbbd331", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Map_Batches: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 178.15it/s]\n" - ] - } - ], - "source": [ - "def mapping_operation(circuits: List[QuantumCircuit]) -> List[QuantumCircuit]:\n", - " return [\n", - " {\"depth\": circuit.depth(), \"circuit\": circuit}\n", - " for circuit in circuits\n", - " ]\n", - "\n", - "ds = ds.map_batches(mapping_operation)" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "id": "d4d8854d-f8b2-4b7a-8c03-2faa5ae8d5c1", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'depth': 3, 'circuit': }\n" - ] - } - ], - "source": [ - "ds.show(1)" - ] - }, - { - "cell_type": "markdown", - "id": "0ea90f33-a7d5-407d-9201-9375ccdc2a02", - "metadata": {}, - "source": [ - "Now let's split our dataset into chunks and process them in parallel." - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "id": "f6321a04-21e8-45af-afac-d21ade4e8796", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Dataset(num_blocks=2, num_rows=40, schema=),\n", - " Dataset(num_blocks=2, num_rows=40, schema=),\n", - " Dataset(num_blocks=1, num_rows=20, schema=)]" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "split_ds = ds.split(3)\n", - "split_ds" - ] - }, - { - "cell_type": "markdown", - "id": "89d36de4-c5ad-4822-903d-dc94ccae4259", - "metadata": {}, - "source": [ - "Here we can use our decorator to create remote function for dataset" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "id": "d9f1465d-58e5-4e32-acd3-59de357d4fbc", - "metadata": {}, - "outputs": [], - "source": [ - "@distribute_task()\n", - "def sample(data):\n", - " sampler = Sampler()\n", - " circuits = [r[\"circuit\"] for r in data.iter_rows()]\n", - " return sampler.run(circuits).result()" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "id": "7a740429-01d7-4871-bb43-036f392086c3", - "metadata": {}, - "outputs": [], - "source": [ - "sample_tasks = [sample(shard) for shard in split_ds]" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "id": "fbc14578-1c9f-420f-a3d9-5dd792e272ef", - "metadata": {}, - "outputs": [], - "source": [ - "results = get(sample_tasks)" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "id": "b352242f-3c9d-4d01-beb1-a4fbd21ac3d5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[SamplerResult(quasi_dists=[{0: 0.0, 1: 1.0}, {0: 0.9999999999999998, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.7942974242374243, 1: 0.20570257576257575}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.05264990006648206, 1: 0.947350099933518}, {0: 0.9999999999999998, 1: 0.0}, {0: 0.0, 1: 1.0}, {0: 0.45480275093681083, 1: 0.5451972490631892}, {0: 0.10050746991952836, 1: 0.8994925300804716}, {0: 0.0, 1: 1.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.4999999999999999, 1: 0.5000000000000001}, {0: 1.0, 1: 0.0}, {0: 0.0, 1: 1.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.4999999999999999, 1: 0.4999999999999999}, {0: 0.0, 1: 1.0}, {0: 0.0010733773936409123, 1: 0.9989266226063591}, {0: 1.0, 1: 0.0}, {0: 0.5000000000000001, 1: 0.4999999999999999}, {0: 0.3381703724219888, 1: 0.6618296275780112}, {0: 0.0, 1: 1.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.4999999999999999, 1: 0.4999999999999999}, {0: 0.7612155887733825, 1: 0.23878441122661753}, {0: 0.9867103753194477, 1: 0.013289624680552321}, {0: 0.0, 1: 1.0}, {0: 0.6099564121852018, 1: 0.39004358781479825}, {0: 0.4999999999999999, 1: 0.4999999999999999}, {0: 1.0, 1: 0.0}], metadata=[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]),\n", - " SamplerResult(quasi_dists=[{0: 0.12795259919782143, 1: 0.8720474008021781}, {0: 0.4999999999999999, 1: 0.4999999999999998}, {0: 0.9357243481634924, 1: 0.06427565183650708}, {0: 0.02972604393004547, 1: 0.9702739560699544}, {0: 0.934973901454463, 1: 0.06502609854553694}, {0: 0.38227178780582916, 1: 0.6177282121941707}, {0: 0.0, 1: 1.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.4972276539331164, 1: 0.5027723460668833}, {0: 0.0, 1: 1.0}, {0: 0.48185218535091934, 1: 0.5181478146490803}, {0: 0.9999999999999998, 1: 0.0}, {0: 0.4999999999999999, 1: 0.4999999999999999}, {0: 1.0, 1: 0.0}, {0: 0.9524126766158624, 1: 0.047587323384137625}, {0: 0.4397232362097549, 1: 0.560276763790245}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.9941721396739035, 1: 0.005827860326096393}, {0: 0.9996719296771142, 1: 0.00032807032288587014}, {0: 0.23773460688749493, 1: 0.7622653931125051}, {0: 1.0, 1: 0.0}, {0: 0.4999999999999999, 1: 0.4999999999999998}, {0: 0.8644561069606984, 1: 0.13554389303930164}, {0: 1.0, 1: 0.0}, {0: 0.4999999999999999, 1: 0.4999999999999998}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.2074440315388495, 1: 0.7925559684611505}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.0, 1: 0.9999999999999998}, {0: 0.7726813621162862, 1: 0.22731863788371373}, {0: 0.9658904330278909, 1: 0.03410956697210917}, {0: 0.9986956240692265, 1: 0.0013043759307734466}, {0: 0.7715677605871707, 1: 0.2284322394128294}, {0: 0.3575022999056873, 1: 0.6424977000943127}, {0: 0.4999999999999999, 1: 0.4999999999999999}, {0: 0.884028160019632, 1: 0.11597183998036796}], metadata=[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]),\n", - " SamplerResult(quasi_dists=[{0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.9853139837530858, 1: 0.014686016246914237}, {0: 0.9495503960132063, 1: 0.050449603986793566}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.5910753802059651, 1: 0.40892461979403494}, {0: 0.0, 1: 1.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.06555922271102001, 1: 0.9344407772889799}, {0: 0.9631003186864411, 1: 0.03689968131355884}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.03458133797332779, 1: 0.9654186620266719}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 1.0, 1: 0.0}, {0: 0.10009741459099618, 1: 0.8999025854090039}, {0: 1.0, 1: 0.0}], metadata=[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}])]" - ] - }, - "execution_count": 65, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "results" - ] - }, - { - "cell_type": "markdown", - "id": "39edb77d-f799-450b-ac98-b1a8b0a95e36", - "metadata": {}, - "source": [ - "-----\n", - "\n", - "For large datasets we can use s3 to read data from or any storage that supports Arrow. For more info refer to https://docs.ray.io/en/latest/data/dataset.html" - ] - } - ], - "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.7.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/development/index.rst b/docs/development/index.rst deleted file mode 100644 index b4b62590c..000000000 --- a/docs/development/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -=========== -Development -=========== - -This section includes both end-to-end tutorials and short guides -that provide specific explanations of functions and features in Quantum Serverless. - -**Examples** - -.. toctree:: - :maxdepth: 2 - - Examples - -**Guides** - -.. toctree:: - :maxdepth: 2 - - Guides diff --git a/docs/development/examples/01_vqe.ipynb b/docs/examples/01_vqe.ipynb similarity index 50% rename from docs/development/examples/01_vqe.ipynb rename to docs/examples/01_vqe.ipynb index 307fbd4ea..b3cc49ca0 100644 --- a/docs/development/examples/01_vqe.ipynb +++ b/docs/examples/01_vqe.ipynb @@ -51,7 +51,7 @@ " - if runtime service was not passed then use stantard qiskit estimator\n", "4. save results from vqe\n", "\n", - "Roughly our VQE program will look like this\n", + "Roughly our VQE program will look like this. Full code can be found in [vqe.py](./source_files/vqe/vqe.py) file.\n", "\n", "```python\n", "# vqe.py\n", @@ -116,20 +116,20 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'ansatz': ,\n", + "{'ansatz': ,\n", " 'operator': SparsePauliOp(['YZ', 'ZI', 'ZZ', 'XX'],\n", " coeffs=[ 0.398 +0.j, -0.398 +0.j, -0.0113+0.j, 0.181 +0.j]),\n", " 'method': 'COBYLA',\n", " 'service': None}" ] }, - "execution_count": 9, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -154,12 +154,12 @@ " [(\"YZ\", 0.3980), (\"ZI\", -0.3980), (\"ZZ\", -0.0113), (\"XX\", 0.1810)]\n", ")\n", "ansatz = EfficientSU2(operator.num_qubits)\n", - " \n", + "\n", "input_arguments = {\n", " \"ansatz\": ansatz,\n", " \"operator\": operator,\n", " \"method\": \"COBYLA\",\n", - " \"service\": service\n", + " \"service\": service,\n", "}\n", "\n", "input_arguments" @@ -174,7 +174,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -184,24 +184,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -211,16 +201,16 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 12, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -228,11 +218,7 @@ "source": [ "from quantum_serverless import Program\n", "\n", - "program = Program(\n", - " title=\"VQE\",\n", - " entrypoint=\"vqe.py\",\n", - " working_dir=\"./source_files/vqe/\"\n", - ")\n", + "program = Program(title=\"VQE\", entrypoint=\"vqe.py\", working_dir=\"./source_files/vqe/\")\n", "\n", "job = serverless.run(program, arguments=input_arguments)\n", "job" @@ -240,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -249,7 +235,7 @@ "'QUEUED'" ] }, - "execution_count": 13, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -260,16 +246,16 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'{\"optimal_point\": [-0.1792519774478331, 3.3690480121526396, 1.6216764077351256, 6.143139398511981, 0.49676653977835655, 2.374640057808242, 2.866200187127509, 2.50489457612712, 4.51800489248977, 4.78248888078524, 3.9586762267597324, 1.546113269910704, 7.685938511231928, 3.5731988425909336, 5.8298921420484, 5.098391668394297], \"optimal_value\": -0.7029303876247736, \"optimizer_evals\": 333, \"optimizer_history\": [-0.04397814147886023, -0.21348287749873493, -0.22682388084126995, -0.0683804070674735, -0.1669472475207855, 0.12409922698608211, -0.15487584379443692, -0.327011760994988, -0.3363001318119229, -0.02402793432805797, -0.3611931556726908, -0.3243501135790306, -0.6175274347223443, -0.20340618574430092, -0.6123428914378356, -0.500483771804176, -0.6838933249049571, -0.6619993124369523, -0.35369252630659076, -0.6230531482647764, -0.6931105208984558, -0.6255650373224049, -0.49365214652959305, -0.692786557513045, -0.6251937967963399, -0.6268364701131495, -0.5144299664153748, -0.65411062451384, -0.5670701719178565, -0.6264158884605353, -0.47477497833967386, -0.679389075117403, -0.4740019587571814, -0.6175090134469513, -0.6905499765931707, -0.6432119192906125, -0.6820180758460491, -0.6874614456543693, -0.6935027975901289, -0.6401835502738081, -0.6795189093220679, -0.6569185978814718, -0.6792626403948445, -0.696770394504601, -0.6708544307872115, -0.6969960945846222, -0.6972497299079178, -0.6948584441083129, -0.6717713135699235, -0.6854102741683281, -0.6891548311186999, -0.6945601469817042, -0.6999952473708992, -0.6974146309193814, -0.677998077606288, -0.696891146783136, -0.6916440724774446, -0.6976380005636541, -0.6894416287103026, -0.6986941632529274, -0.6823688821348957, -0.694864966854258, -0.7004592988493247, -0.6989743445697921, -0.7001594792581207, -0.6991139001914473, -0.7007655665722707, -0.696255155419552, -0.6994678698960157, -0.6989713174857625, -0.7005504927790727, -0.6944606090259453, -0.6994602502056282, -0.6916028630517455, -0.7002081157769577, -0.7014254909865938, -0.7008246041663696, -0.7012933374348937, -0.6999046424113916, -0.7014085259146398, -0.7013533346991633, -0.7012272860858414, -0.7007261843125872, -0.7007994461103211, -0.7012304845706723, -0.7017742419347879, -0.7016107892732413, -0.7016951426443706, -0.7017268813430744, -0.7015567200001617, -0.7008649402814956, -0.7017663402472233, -0.7015631130827765, -0.7016465236866949, -0.7020995225700731, -0.7018614305569834, -0.7020477942697387, -0.7023892702351403, -0.7023990412338837, -0.7023656741702398, -0.7024552481046129, -0.7025206201567449, -0.7025177897372736, -0.7025719068691536, -0.7018238636827354, -0.7025826960103998, -0.702500072043901, -0.7024297371203715, -0.7025692275422513, -0.7025014187116293, -0.702711731689825, -0.7026062006407707, -0.7027103382666664, -0.7026770481098255, -0.7024301310975475, -0.70260441683975, -0.7026579001104193, -0.7026515892876324, -0.70270925199648, -0.7027172652291916, -0.7026926380670343, -0.702624107678798, -0.70269959663675, -0.7027664917175473, -0.70273393498008, -0.7027381757781915, -0.7027468917232644, -0.702704906880945, -0.7027253912165569, -0.702812797200903, -0.7028148540307412, -0.702809448073612, -0.7027524830392556, -0.7028064841444404, -0.7027909007460554, -0.7027515587282595, -0.7027944788242675, -0.7027949659660996, -0.7028329091484335, -0.7028198286848419, -0.7028128617089417, -0.7027806577073044, -0.7028714702377796, -0.7028422839965411, -0.7028670304503906, -0.7028830706580037, -0.7028082520390025, -0.7028602999777678, -0.7028478645809965, -0.7028671889352709, -0.7028756961501635, -0.7028679030856091, -0.7028735972596323, -0.7028909225294675, -0.7028855059176545, -0.7029010099799626, -0.7029001572526876, -0.7028869672379768, -0.7029056661554376, -0.7028871028378428, -0.7029110073851119, -0.7029063194887776, -0.7029062654491571, -0.7029105398929961, -0.702908603232512, -0.7028994377598883, -0.702915020275393, -0.7029132447768385, -0.7029160322857662, -0.7029152353059465, -0.7029106482912917, -0.7029165708926267, -0.702917277028048, -0.7029143499907341, -0.7029181782760837, -0.7029183874366298, -0.7029163128348952, -0.7029181604188943, -0.7029195499781087, -0.7029202569655216, -0.7029054800000456, -0.7029170879279043, -0.7029218636220049, -0.7029178230763415, -0.7029192500997213, -0.7029225014205889, -0.7029243874851913, -0.7029222096767433, -0.7029216634925248, -0.7029241602863124, -0.7029173124191483, -0.7029258576499638, -0.7029253742379449, -0.7029265343991647, -0.7029291182467565, -0.7029229015296343, -0.7029293389976417, -0.7029292181121954, -0.7029290694656916, -0.7029230493865856, -0.7029289362910527, -0.702926633188639, -0.7029289030036057, -0.7029257628740304, -0.7029277007505356, -0.7029265018644009, -0.7029292571131626, -0.7029287847439245, -0.70292847249336, -0.7029292625116346, -0.7029293648557619, -0.7029292936328776, -0.7029277868962794, -0.702928772826895, -0.7029280818233331, -0.7029293922984274, -0.7029280667250666, -0.7029292998638179, -0.7029282645990759, -0.7029295725696942, -0.7029291926969943, -0.7029294298968247, -0.7029289472834184, -0.702929244129149, -0.7029287658598594, -0.7029292842500592, -0.7029293832336918, -0.7029296489048669, -0.7029295955574872, -0.7029295625932599, -0.7029294414690663, -0.7029295426771472, -0.702929420447517, -0.7029299736345551, -0.7029297282129936, -0.7029300066710784, -0.70293000755544, -0.7029300287588149, -0.7029297735590516, -0.702929927899523, -0.7029298566324722, -0.7029300609982513, -0.7029300364589769, -0.7029298188527465, -0.7029302456045512, -0.7029298733863887, -0.7029302571275897, -0.7029301740046512, -0.7029302325962599, -0.7029301330657033, -0.7029301335146549, -0.7029300986694382, -0.7029302592025224, -0.7029300748176016, -0.7029301842919968, -0.7029299271130727, -0.7029301943707938, -0.7029302491777494, -0.7029302972236408, -0.7029302805774069, -0.7029302619413662, -0.7029303066599168, -0.702930231361913, -0.702930273498495, -0.7029302939156039, -0.7029303015311239, -0.7029303249946162, -0.7029302761400877, -0.7029303242075179, -0.7029303174237895, -0.7029302258336585, -0.7029303348027747, -0.7029303188045002, -0.7029303372311442, -0.7029303421264661, -0.7029303674933416, -0.7029303693300926, -0.7029303696700391, -0.7029303637575712, -0.7029303601304836, -0.7029303626078439, -0.7029303721046616, -0.7029303689857045, -0.7029303480107785, -0.7029303637145116, -0.7029303730076216, -0.7029303709496464, -0.7029303634887147, -0.702930377379293, -0.7029303675480185, -0.7029303733923016, -0.7029303594309971, -0.7029303733738694, -0.70293036781742, -0.7029303709742837, -0.7029303701068392, -0.7029303778748296, -0.702930378055018, -0.7029303724038554, -0.7029303836191281, -0.702930383144692, -0.7029303856306329, -0.7029303859779228, -0.7029303863665576, -0.7029303857055706, -0.7029303853677988, -0.7029303853892616, -0.7029303877965029, -0.702930387454812, -0.7029303889444978, -0.7029303890864742, -0.7029303827676237, -0.7029303899133102, -0.7029303901401825, -0.7029303896766894, -0.7029303913170851, -0.7029303927420356, -0.7029303935610621, -0.70293039327265, -0.7029303933341333, -0.7029303917076948, -0.7029303933592024, -0.7029303930878406, -0.702930391045046, -0.7029303933519839, -0.7029303896519363, -0.7029303932975347, -0.7029303918248553, -0.702930392731893, -0.7029303921749024, -0.7029303930335884, -0.7029303876247736, -0.7029303876247736], \"optimizer_time\": 3.5547554999993736}'" + "'{\"result\": {\"0\": 0.4285, \"1\": 0.351, \"2\": 0.1125, \"3\": 0.108}, \"optimal_point\": [2.892220117301835, 2.474653475445254, 2.5156199602369202, 3.3849094458844857, 0.1694958538232856, 3.655821265585715, 2.9936100331465494, 1.5278501424812023, 2.0039753506950837, 3.3523741719792515, 5.119840869627582, 4.0803877524554535, 1.283219520340234, 2.965257255909468, 1.6420489273053434, 2.583666555864834], \"optimal_value\": -0.7029303878802236, \"optimizer_time\": 6.884704999974929}'" ] }, - "execution_count": 14, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } diff --git a/docs/development/examples/02_qaoa.ipynb b/docs/examples/02_qaoa.ipynb similarity index 94% rename from docs/development/examples/02_qaoa.ipynb rename to docs/examples/02_qaoa.ipynb index 50adb95fe..f5cbf0aab 100644 --- a/docs/development/examples/02_qaoa.ipynb +++ b/docs/examples/02_qaoa.ipynb @@ -48,7 +48,7 @@ " - if runtime service was not passed then use stantard qiskit sampler\n", "4. save results from qaoa\n", "\n", - "Roughly our QAOA program will look like this\n", + "Roughly our QAOA program will look like this. Full code can be found in [qaoa.py](./source_files/qaoa/qaoa.py) file.\n", "\n", "```python\n", "# qaoa.py\n", @@ -99,7 +99,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -131,7 +131,7 @@ " └─────────────┘ └──────────────┘ └──────────────┘" ] }, - "execution_count": 83, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -146,7 +146,9 @@ "from qiskit_ibm_runtime import QiskitRuntimeService\n", "\n", "\n", - "operator = SparsePauliOp.from_list([(\"IIIZZ\", 1), (\"IIZIZ\", 1), (\"IZIIZ\", 1), (\"ZIIIZ\", 1)])\n", + "operator = SparsePauliOp.from_list(\n", + " [(\"IIIZZ\", 1), (\"IIZIZ\", 1), (\"IZIIZ\", 1), (\"ZIIIZ\", 1)]\n", + ")\n", "ansatz = QAOAAnsatz(operator, reps=2)\n", "ansatz = ansatz.decompose(reps=3)\n", "ansatz.draw(fold=-1)" @@ -154,21 +156,21 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'initial_point': None,\n", - " 'ansatz': ,\n", + " 'ansatz': ,\n", " 'operator': SparsePauliOp(['IIIZZ', 'IIZIZ', 'IZIIZ', 'ZIIIZ'],\n", " coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j]),\n", " 'service': None,\n", " 'backend': 'ibmq_qasm_simulator'}" ] }, - "execution_count": 84, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -186,14 +188,14 @@ " \"ansatz\": ansatz,\n", " \"operator\": operator,\n", " \"service\": service,\n", - " \"backend\": backend\n", + " \"backend\": backend,\n", "}\n", "input_arguments" ] }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -203,7 +205,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -212,15 +214,16 @@ "" ] }, - "execution_count": 86, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -230,16 +233,16 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 87, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -248,9 +251,7 @@ "from quantum_serverless import Program\n", "\n", "program = Program(\n", - " title=\"QAOA\",\n", - " entrypoint=\"qaoa.py\",\n", - " working_dir=\"./source_files/qaoa/\"\n", + " title=\"QAOA\", entrypoint=\"qaoa.py\", working_dir=\"./source_files/qaoa/\"\n", ")\n", "\n", "job = serverless.run(program, arguments=input_arguments)\n", @@ -259,7 +260,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -268,7 +269,7 @@ "'QUEUED'" ] }, - "execution_count": 88, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -279,16 +280,16 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'{\"optimal_point\": [3.6344805751647185, 5.046785824446347, 2.551360649472253, 5.842713967678677], \"optimal_value\": -3.2939251920544805}'" + "'{\"optimal_point\": [2.063751310873999, 1.905159239117952, -0.5901924329493166, 2.701191390563265], \"optimal_value\": -3.293925059652345}'" ] }, - "execution_count": 89, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } diff --git a/docs/examples/index.rst b/docs/examples/index.rst new file mode 100644 index 000000000..4502ed218 --- /dev/null +++ b/docs/examples/index.rst @@ -0,0 +1,10 @@ +======== +Examples +======== + +This section includes end-to-end examples of how to apply Quantum Serverless to actual quantum algorithms. + +.. nbgallery:: + :glob: + + * diff --git a/docs/development/examples/source_files/__init__.py b/docs/examples/source_files/__init__.py similarity index 100% rename from docs/development/examples/source_files/__init__.py rename to docs/examples/source_files/__init__.py diff --git a/docs/development/examples/source_files/qaoa/qaoa.py b/docs/examples/source_files/qaoa/qaoa.py similarity index 77% rename from docs/development/examples/source_files/qaoa/qaoa.py rename to docs/examples/source_files/qaoa/qaoa.py index 62211317d..7f1e62f5d 100644 --- a/docs/development/examples/source_files/qaoa/qaoa.py +++ b/docs/examples/source_files/qaoa/qaoa.py @@ -10,7 +10,13 @@ from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Session, Options -from quantum_serverless import QuantumServerless, distribute_task, get_arguments, get, save_result +from quantum_serverless import ( + QuantumServerless, + distribute_task, + get_arguments, + get, + save_result, +) def cost_func(params, ansatz, hamiltonian, estimator): @@ -25,7 +31,9 @@ def cost_func(params, ansatz, hamiltonian, estimator): Returns: float: Energy estimate """ - cost = estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0] + cost = ( + estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0] + ) return cost @@ -34,27 +42,29 @@ def run_qaoa( estimator: BaseEstimator, operator: PauliSumOp, initial_point: np.array, - method: str + method: str, ): - return minimize(cost_func, initial_point, args=(ansatz, operator, estimator), method=method) + return minimize( + cost_func, initial_point, args=(ansatz, operator, estimator), method=method + ) -if __name__ == '__main__': +if __name__ == "__main__": arguments = get_arguments() - + service = arguments.get("service") - + operator = arguments.get("operator") ansatz = arguments.get("ansatz") initial_point = arguments.get("initial_point") method = arguments.get("method", "COBYLA") - + if initial_point is None: initial_point = 2 * np.pi * np.random.rand(ansatz.num_parameters) if service is not None: # if we have service we need to open a session and create sampler - service = arguments.get("service") + service = arguments.get("service") backend = arguments.get("backend", "ibmq_qasm_simulator") with Session(service=service, backend=backend) as session: options = Options() @@ -64,10 +74,7 @@ def run_qaoa( else: # if we do not have a service let's use standart local sampler estimator = QiskitEstimator() - + result = run_qaoa(ansatz, estimator, operator, initial_point, method) - - save_result({ - "optimal_point": result.x.tolist(), - "optimal_value": result.fun - }) + + save_result({"optimal_point": result.x.tolist(), "optimal_value": result.fun}) diff --git a/docs/development/examples/source_files/vqe/vqe.py b/docs/examples/source_files/vqe/vqe.py similarity index 69% rename from docs/development/examples/source_files/vqe/vqe.py rename to docs/examples/source_files/vqe/vqe.py index 2abe1b49a..4ace2d34d 100644 --- a/docs/development/examples/source_files/vqe/vqe.py +++ b/docs/examples/source_files/vqe/vqe.py @@ -5,12 +5,28 @@ from scipy.optimize import minimize from qiskit import QuantumCircuit -from qiskit.primitives import BaseEstimator, Estimator as QiskitEstimator +from qiskit.primitives import ( + BaseEstimator, + Estimator as QiskitEstimator, + Sampler as QiskitSampler, +) from qiskit.opflow import PauliSumOp -from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Session, Options +from qiskit_ibm_runtime import ( + QiskitRuntimeService, + Estimator, + Session, + Options, + Sampler, +) -from quantum_serverless import QuantumServerless, distribute_task, get_arguments, get, save_result +from quantum_serverless import ( + QuantumServerless, + distribute_task, + get_arguments, + get, + save_result, +) def build_callback(ansatz, hamiltonian, estimator, callback_dict): @@ -44,7 +60,9 @@ def callback(current_vector): callback_dict["prev_vector"] = current_vector # Compute the value of the cost function at the current vector callback_dict["cost_history"].append( - estimator.run(ansatz, hamiltonian, parameter_values=current_vector).result().values[0] + estimator.run(ansatz, hamiltonian, parameter_values=current_vector) + .result() + .values[0] ) # Grab the current time current_time = time.perf_counter() @@ -61,7 +79,9 @@ def callback(current_vector): ) # Print to screen on single line print( - "Iters. done: {} [Avg. time per iter: {}]".format(callback_dict["iters"], time_str), + "Iters. done: {} [Avg. time per iter: {}]".format( + callback_dict["iters"], time_str + ), end="\r", flush=True, ) @@ -81,17 +101,13 @@ def cost_func(params, ansatz, hamiltonian, estimator): Returns: float: Energy estimate """ - energy = estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0] + energy = ( + estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0] + ) return energy -def run_vqe( - initial_parameters, - ansatz, - operator, - estimator, - method -): +def run_vqe(initial_parameters, ansatz, operator, estimator, method): callback_dict = { "prev_vector": None, "iters": 0, @@ -110,29 +126,27 @@ def run_vqe( return result, callback_dict -if __name__ == '__main__': +if __name__ == "__main__": arguments = get_arguments() - + service = arguments.get("service") - + ansatz = arguments.get("ansatz") operator = arguments.get("operator") method = arguments.get("method", "COBYLA") initial_parameters = arguments.get("initial_parameters") if initial_parameters is None: initial_parameters = 2 * np.pi * np.random.rand(ansatz.num_parameters) - - print(initial_parameters) - + if service is not None: # if we have service we need to open a session and create estimator - service = arguments.get("service") + service = arguments.get("service") backend = arguments.get("backend", "ibmq_qasm_simulator") with Session(service=service, backend=backend) as session: options = Options() options.optimization_level = 3 - estimator = Estimator(session=session, options=options) + estimator = Estimator(options=options) else: # if we do not have a service let's use standart local estimator estimator = QiskitEstimator() @@ -142,13 +156,32 @@ def run_vqe( ansatz=ansatz, operator=operator, estimator=estimator, - method=method + method=method, ) - save_result({ - "optimal_point": vqe_result.x.tolist(), - "optimal_value": vqe_result.fun, - "optimizer_evals": vqe_result.nfev, - "optimizer_history": callback_dict.get("cost_history", []), - "optimizer_time": callback_dict.get("_total_time", 0) - }) + qc = ansatz.assign_parameters(vqe_result.x) + qc.measure_all() + + if service is not None: + # if we have service we need to open a session and create estimator + service = arguments.get("service") + backend = arguments.get("backend", "ibmq_qasm_simulator") + with Session(service=service, backend=backend) as session: + options = Options() + options.optimization_level = 3 + + sampler = Sampler(session=session, options=options) + else: + sampler = QiskitSampler() + samp_dist = sampler.run(qc, shots=int(1e4)).result().quasi_dists[0] + + save_result( + { + "result": samp_dist, + "optimal_point": vqe_result.x.tolist(), + "optimal_value": vqe_result.fun, + # "optimizer_evals": vqe_result.nfev, + # "optimizer_history": callback_dict.get("cost_history", []), + "optimizer_time": callback_dict.get("_total_time", 0), + } + ) diff --git a/docs/running/notebooks/01_running_program.ipynb b/docs/getting_started/basic/01_running_program.ipynb similarity index 57% rename from docs/running/notebooks/01_running_program.ipynb rename to docs/getting_started/basic/01_running_program.ipynb index e28195e38..bc6a3a4ff 100644 --- a/docs/running/notebooks/01_running_program.ipynb +++ b/docs/getting_started/basic/01_running_program.ipynb @@ -11,33 +11,35 @@ "\n", "### Writing the Program\n", "\n", - "First, we need to write the program code and save it to a file called [program_1.py](./source_files/program_1.py). This program creates a two-qubit quantum circuit that prepares a Bell state, measures the result, and saves the measured probability distribution.\n", + "First, we need to write the program code and save it to a file called [program.py](./source_files/program.py). This program creates a two-qubit quantum circuit that prepares a Bell state, measures the result, and saves the measured probability distribution.\n", "\n", "The code for the program is shown below:\n", "\n", "```python\n", - "# source_files/program_1.py\n", + "# source_files/program.py\n", "\n", "from qiskit import QuantumCircuit\n", "from qiskit.primitives import Sampler\n", "\n", "from quantum_serverless import save_result\n", "\n", - "# Create a circuit\n", + "# all print statement will be available in job logs\n", + "print(\"Running program 1...\")\n", + "\n", + "# creating circuit\n", "circuit = QuantumCircuit(2)\n", "circuit.h(0)\n", "circuit.cx(0, 1)\n", "circuit.measure_all()\n", - "circuit.draw()\n", "\n", - "# Instantiate a Sampler to generate a quasi-distribution of the circuit's outputs\n", + "# running Sampler primitive\n", "sampler = Sampler()\n", - "\n", - "# Run the circuit and retrieve the quasi-distribution\n", "quasi_dists = sampler.run(circuit).result().quasi_dists\n", "\n", - "# Save the result to the serverless client\n", + "# save results of program execution, \n", + "# which will be accessible by calling `.result()`\n", "save_result(quasi_dists)\n", + "print(\"Completed running program 1.\")\n", "```\n", "\n", "### Running the Program\n", @@ -49,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "81dd7807-7180-4b87-bbf9-832b7cf29d69", "metadata": {}, "outputs": [], @@ -58,16 +60,36 @@ "import os" ] }, + { + "cell_type": "markdown", + "id": "7ac24f62-8487-47fb-9805-66f2192953d4", + "metadata": {}, + "source": [ + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "acdec789-4967-48ee-8f6c-8d2b0ff57e91", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -86,22 +108,32 @@ "- title - name of the program\n", "- entrypoint - name of python file you want to execute\n", "- working_dir - directory where your script is located (directory size must be less than 50MB). This is optional parameter and will be current folder by default.\n", - "\n" + "\n", + "> Warning! All content of `working_dir` will be shipped to cluster for execution" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "d51df836-3f22-467c-b637-5803145d5d8a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from quantum_serverless import Program\n", "\n", "program = Program(\n", - " title=\"First program\",\n", - " entrypoint=\"program_1.py\",\n", - " working_dir=\"./source_files/\"\n", + " title=\"First program\", entrypoint=\"program.py\", working_dir=\"./source_files/\"\n", ")\n", "\n", "job = serverless.run(program)\n", @@ -118,10 +150,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "cc7ccea6-bbae-4184-ba7f-67b6c20a0b0b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'QUEUED'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job.status()" ] @@ -136,10 +179,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "1dc78690-f61a-4dfe-bc0e-7007cf561a5b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'[{\"0\": 0.4999999999999999, \"3\": 0.4999999999999999}]'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job.result()" ] @@ -154,13 +208,61 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "eb5ec85f", "metadata": {}, - "outputs": [], + "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", + "Running program 1...\n", + "Completed running program 1.\n", + "\n" + ] + } + ], "source": [ "print(job.logs())" ] + }, + { + "cell_type": "markdown", + "id": "9784597b-9377-4d26-8ab9-a8a9b363c924", + "metadata": {}, + "source": [ + "`QuantumServerless` object has method `.widget` which renders Jupyter widget to see list of executed programs.\n", + "\n", + "![widget](./images/widget.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f24023e1-6ce4-481e-b43d-3e19bff81d57", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b385710d381c42e8b6f43e7d14539eea", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Tab(children=(GridspecLayout(children=(Output(layout=Layout(grid_area='widget001')), Output(layout=Layout(grid…" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "serverless.widget()" + ] } ], "metadata": { @@ -179,7 +281,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.17" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/running/notebooks/03_arguments_and_results.ipynb b/docs/getting_started/basic/02_arguments_and_results.ipynb similarity index 58% rename from docs/running/notebooks/03_arguments_and_results.ipynb rename to docs/getting_started/basic/02_arguments_and_results.ipynb index e35e61c3c..ccb71862c 100644 --- a/docs/running/notebooks/03_arguments_and_results.ipynb +++ b/docs/getting_started/basic/02_arguments_and_results.ipynb @@ -4,18 +4,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Programs with arguments\n", + "# Passing input arguments to your program\n", "\n", "In this document, we will learn how to pass arguments to our program.\n", "\n", - "Let's create another file with our program [./source_files/program_3.py](./source_files/program_3.py). \n", + "Let's create another file with our program [./source_files/program_with_arguments.py](./source_files/program_with_arguments.py). \n", "\n", "Instead of having the circuit defined inside the program (like we did in first example), we will pass it as an argument. We will also save the results, so we can access them later by calling [save_result](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.save_result.html#quantum_serverless.core.save_result).\n", "\n", "Here is the program:\n", "\n", "```python\n", - "# source_files/program_3.py\n", + "# source_files/program_with_arguments.py\n", "\n", "from quantum_serverless import get_arguments, save_result\n", "\n", @@ -51,9 +51,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
        ┌───┐      ░ ┌─┐   \n",
+       "   q_0: ┤ H ├──■───░─┤M├───\n",
+       "        └───┘┌─┴─┐ ░ └╥┘┌─┐\n",
+       "   q_1: ─────┤ X ├─░──╫─┤M├\n",
+       "             └───┘ ░  ║ └╥┘\n",
+       "meas: 2/══════════════╩══╩═\n",
+       "                      0  1 
" + ], + "text/plain": [ + " ┌───┐ ░ ┌─┐ \n", + " q_0: ┤ H ├──■───░─┤M├───\n", + " └───┘┌─┴─┐ ░ └╥┘┌─┐\n", + " q_1: ─────┤ X ├─░──╫─┤M├\n", + " └───┘ ░ ║ └╥┘\n", + "meas: 2/══════════════╩══╩═\n", + " 0 1 " + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from qiskit import QuantumCircuit\n", "\n", @@ -73,7 +99,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "tags": [] }, @@ -83,34 +109,42 @@ "\n", "program = Program(\n", " title=\"Program with arguments\",\n", - " entrypoint=\"program_3.py\",\n", - " working_dir=\"./source_files/\"\n", + " entrypoint=\"program_with_arguments.py\",\n", + " working_dir=\"./source_files/\",\n", ")" ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "jupyter": { - "outputs_hidden": false - } - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "from quantum_serverless import QuantumServerless, Provider\n", - "import os" + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "from quantum_serverless import QuantumServerless, Provider\n", + "import os\n", + "\n", "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -127,7 +161,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -143,9 +177,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"quasi_dists\": {\"0\": 0.4999999999999999, \"3\": 0.4999999999999999}}'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job.result()" ] @@ -167,7 +212,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/running/notebooks/04_dependencies.ipynb b/docs/getting_started/basic/03_dependencies.ipynb similarity index 67% rename from docs/running/notebooks/04_dependencies.ipynb rename to docs/getting_started/basic/03_dependencies.ipynb index b315151b4..c3b5fb3b5 100644 --- a/docs/running/notebooks/04_dependencies.ipynb +++ b/docs/getting_started/basic/03_dependencies.ipynb @@ -6,18 +6,18 @@ "tags": [] }, "source": [ - "# Dependency management for programs\n", + "# Using python packages with your programs\n", "\n", "In this document, we will learn how to install custom dependencies to your program.\n", "\n", - "Let's create another file with our new program [./source_files/program_4.py](./source_files/program_4.py). \n", + "Let's create another file with our new program [./source_files/program_with_dependencies.py](./source_files/program_with_dependencies.py). \n", "\n", "For the sake of this example, let's use the `qiskit-experiments` package as our custom dependency. We will use randomized benchmarking (RB) circuits from `qiskit-experiments`, composed with the circuit from the input arguments for measurement.\n", "\n", "Here's what the file would look like:\n", "\n", "```python\n", - "# source_files/program_4.py\n", + "# source_files/program_with_dependencies.py\n", "\n", "from quantum_serverless import get_arguments, save_result\n", "\n", @@ -64,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "tags": [] }, @@ -74,31 +74,43 @@ "\n", "program = Program(\n", " title=\"Program with dependencies\",\n", - " entrypoint=\"program_4.py\",\n", + " entrypoint=\"program_with_dependencies.py\",\n", " working_dir=\"./source_files/\",\n", - " dependencies=[\"qiskit-experiments==0.5.2\"]\n", + " dependencies=[\"qiskit-experiments==0.5.2\"],\n", ")" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from quantum_serverless import QuantumServerless, Provider\n", - "import os" + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "from quantum_serverless import QuantumServerless, Provider\n", + "import os\n", + "\n", "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -108,17 +120,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from qiskit.circuit.random import random_circuit\n", + "\n", "circuit = random_circuit(2, 2)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -127,20 +140,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'QUEUED'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job.status()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"quasi_dists\": {\"0\": 0.6107159035567002, \"1\": 0.3892840964432998}}'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "print(job.logs())" + "job.result()" ] } ], @@ -160,7 +195,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/running/notebooks/02_distributed_workloads.ipynb b/docs/getting_started/basic/04_distributed_workloads.ipynb similarity index 67% rename from docs/running/notebooks/02_distributed_workloads.ipynb rename to docs/getting_started/basic/04_distributed_workloads.ipynb index fc6798d98..395eca7a0 100644 --- a/docs/running/notebooks/02_distributed_workloads.ipynb +++ b/docs/getting_started/basic/04_distributed_workloads.ipynb @@ -8,10 +8,10 @@ "\n", "In this document, we will learn how to run distributed workflows inside a program. In this case, we will compute the quasi-probability distribution in parallel for a list of quantum circuits.\n", "\n", - "Let's take a look at the program file [./source_files/program_2.py](./source_files/program_2.py). \n", + "Let's take a look at the program file [./source_files/program_with_parallel_workflow.py](./source_files/program_with_parallel_workflow.py). \n", "\n", "```python\n", - "# source_files/program_2.py\n", + "# source_files/program_with_parallel_workflow.py\n", "\n", "from quantum_serverless import get_arguments, save_result, distribute_task, get\n", "\n", @@ -64,28 +64,36 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "jupyter": { - "outputs_hidden": false - } - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "from quantum_serverless import QuantumServerless, Provider\n", - "import os" + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "from quantum_serverless import QuantumServerless, Provider\n", + "import os\n", + "\n", "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -97,14 +105,27 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's create list of random circuit which we will be using as arguments" + "Let's create a list of random circuits which we will be passed as arguments to the program." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[,\n", + " ,\n", + " ]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from qiskit.circuit.random import random_circuit\n", "\n", @@ -117,21 +138,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Run program as usual" + "Run program as usual, but pass the circuits in as a keyword argument, `circuits`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from quantum_serverless import Program\n", "\n", "program = Program(\n", - " title=\"Program with distributed workflow\",\n", - " entrypoint=\"program_2.py\",\n", - " working_dir=\"./source_files/\"\n", + " title=\"Program with parallel workflow\",\n", + " entrypoint=\"program_with_parallel_workflow.py\",\n", + " working_dir=\"./source_files/\",\n", ")\n", "\n", "job = serverless.run(program, arguments={\"circuits\": circuits})\n", @@ -140,18 +172,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'QUEUED'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job.status()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"results\": [{\"2\": 0.4999999999999999, \"3\": 0.4999999999999999}, {\"0\": 0.410199670072165, \"1\": 0.410199670072165, \"2\": 0.0898003299278348, \"3\": 0.0898003299278349}, {\"0\": 0.4999999999999999, \"2\": 0.4999999999999999}]}'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job.result()" ] @@ -173,7 +227,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/running/notebooks/05_retrieving_past_results.ipynb b/docs/getting_started/basic/05_retrieving_past_results.ipynb similarity index 63% rename from docs/running/notebooks/05_retrieving_past_results.ipynb rename to docs/getting_started/basic/05_retrieving_past_results.ipynb index 4dff7d800..be2704a76 100644 --- a/docs/running/notebooks/05_retrieving_past_results.ipynb +++ b/docs/getting_started/basic/05_retrieving_past_results.ipynb @@ -10,35 +10,30 @@ "In this tutorial, we will run two programs and then retrieve the results of each program using the job IDs and the serverless client." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "81dd7807-7180-4b87-bbf9-832b7cf29d69", - "metadata": {}, - "outputs": [], - "source": [ - "from quantum_serverless import QuantumServerless, Provider\n", - "import os" - ] - }, { "cell_type": "markdown", "id": "37322958-a029-46bb-bc46-82b7ded329b5", "metadata": {}, "source": [ - "First, create [Provider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Provider.html#quantum_serverless.core.Provider) and [QuantumServerless](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.QuantumServerless.html#quantum_serverless.QuantumServerless) instances." + "First, create [Provider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Provider.html#quantum_serverless.core.Provider) and [QuantumServerless](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.QuantumServerless.html#quantum_serverless.QuantumServerless) instances.\n", + "\n", + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "acdec789-4967-48ee-8f6c-8d2b0ff57e91", "metadata": {}, "outputs": [], "source": [ + "from quantum_serverless import QuantumServerless, Provider\n", + "import os\n", + "\n", "provider = Provider(\n", - " username=\"user\",\n", - " password=\"password123\",\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", ")\n", "\n", @@ -55,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "d51df836-3f22-467c-b637-5803145d5d8a", "metadata": {}, "outputs": [], @@ -63,14 +58,10 @@ "from quantum_serverless import Program\n", "\n", "program1 = Program(\n", - " title=\"Program 1\",\n", - " entrypoint=\"program_1.py\",\n", - " working_dir=\"./source_files/\"\n", + " title=\"Program 1\", entrypoint=\"program.py\", working_dir=\"./source_files/\"\n", ")\n", "program2 = Program(\n", - " title=\"Program 2\",\n", - " entrypoint=\"program_2.py\",\n", - " working_dir=\"./source_files/\"\n", + " title=\"Program 2\", entrypoint=\"program.py\", working_dir=\"./source_files/\"\n", ")\n", "\n", "job1 = serverless.run(program1)\n", @@ -87,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "f621f786-6ba7-4ef1-8121-741f21f70233", "metadata": {}, "outputs": [], @@ -106,10 +97,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "cc7ccea6-bbae-4184-ba7f-67b6c20a0b0b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'[{\"0\": 0.4999999999999999, \"3\": 0.4999999999999999}]'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "job1.result()\n", "job2.result()" @@ -125,7 +127,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "1dc78690-f61a-4dfe-bc0e-7007cf561a5b", "metadata": {}, "outputs": [], @@ -144,10 +146,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "ca1cbfee-df32-4306-988f-ef0fa31605ee", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Job 1 results: [{\"0\": 0.4999999999999999, \"3\": 0.4999999999999999}]\n", + "Job 2 results: [{\"0\": 0.4999999999999999, \"3\": 0.4999999999999999}]\n" + ] + } + ], "source": [ "print(f\"Job 1 results: {retrieved_job1.result()}\")\n", "print(f\"Job 2 results: {retrieved_job2.result()}\")" @@ -163,13 +174,54 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "5e39caf1-1506-44de-9fbc-248e106be6b5", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Job 1 logs: Running program 1...\n", + "Completed running program 1.\n", + "\n" + ] + } + ], "source": [ "print(f\"Job 1 logs: {retrieved_job1.logs()}\")" ] + }, + { + "cell_type": "markdown", + "id": "15983446-497e-487b-b92d-5c5096f911d7", + "metadata": {}, + "source": [ + "To get a list of all previously executed programs, use the `.get_jobs()` method of the `QuantumServerless` object. \n", + "The `get_jobs` method accepts 2 optional parameters, `limit` and `offset`, which control the size of returned results." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "53f63569-3b80-4ebe-a181-1aa5b3537a7f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[,\n", + " ]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "serverless.get_jobs(limit=2, offset=1)" + ] } ], "metadata": { @@ -188,7 +240,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/getting_started/basic/images/widget.png b/docs/getting_started/basic/images/widget.png new file mode 100644 index 000000000..cf7d9bacd Binary files /dev/null and b/docs/getting_started/basic/images/widget.png differ diff --git a/docs/development/examples/index.rst b/docs/getting_started/basic/index.rst similarity index 100% rename from docs/development/examples/index.rst rename to docs/getting_started/basic/index.rst diff --git a/docs/running/notebooks/source_files/circuit_utils.py b/docs/getting_started/basic/source_files/circuit_utils.py similarity index 100% rename from docs/running/notebooks/source_files/circuit_utils.py rename to docs/getting_started/basic/source_files/circuit_utils.py diff --git a/docs/running/notebooks/source_files/program_1.py b/docs/getting_started/basic/source_files/program.py similarity index 54% rename from docs/running/notebooks/source_files/program_1.py rename to docs/getting_started/basic/source_files/program.py index fa630dea8..ed50a2499 100644 --- a/docs/running/notebooks/source_files/program_1.py +++ b/docs/getting_started/basic/source_files/program.py @@ -3,16 +3,20 @@ from quantum_serverless import save_result -print("Running program 1...") +# all print statement will be available in job logs +print("Running program...") + +# creating circuit circuit = QuantumCircuit(2) circuit.h(0) circuit.cx(0, 1) circuit.measure_all() -circuit.draw() +# running Sampler primitive sampler = Sampler() - quasi_dists = sampler.run(circuit).result().quasi_dists +# saves results of program execution, +# which will be accessible by calling `.result()` save_result(quasi_dists) -print("Completed running program 1.") \ No newline at end of file +print("Completed running program.") diff --git a/docs/running/notebooks/source_files/program_3.py b/docs/getting_started/basic/source_files/program_with_arguments.py similarity index 89% rename from docs/running/notebooks/source_files/program_3.py rename to docs/getting_started/basic/source_files/program_with_arguments.py index 7bd033970..9f5d73c65 100644 --- a/docs/running/notebooks/source_files/program_3.py +++ b/docs/getting_started/basic/source_files/program_with_arguments.py @@ -17,6 +17,4 @@ print(f"Quasi distribution: {quasi_dists[0]}") # saving results of a program -save_result({ - "quasi_dists": quasi_dists[0] -}) +save_result({"quasi_dists": quasi_dists[0]}) diff --git a/docs/running/notebooks/source_files/program_4.py b/docs/getting_started/basic/source_files/program_with_dependencies.py similarity index 75% rename from docs/running/notebooks/source_files/program_4.py rename to docs/getting_started/basic/source_files/program_with_dependencies.py index 95c318f5e..6f4c73169 100644 --- a/docs/running/notebooks/source_files/program_4.py +++ b/docs/getting_started/basic/source_files/program_with_dependencies.py @@ -10,11 +10,7 @@ circuit = arguments.get("circuit") -rb = StandardRB( - physical_qubits=(1,), - lengths=list(range(1, 300, 30)), - seed=42 -) +rb = StandardRB(physical_qubits=(1,), lengths=list(range(1, 300, 30)), seed=42) composed = circuit.compose(rb.circuits()[0]) sampler = Sampler() @@ -24,6 +20,4 @@ print(f"Quasi distribution: {quasi_dists[0]}") # saving results of a program -save_result({ - "quasi_dists": quasi_dists[0] -}) +save_result({"quasi_dists": quasi_dists[0]}) diff --git a/docs/running/notebooks/source_files/program_2.py b/docs/getting_started/basic/source_files/program_with_parallel_workflow.py similarity index 69% rename from docs/running/notebooks/source_files/program_2.py rename to docs/getting_started/basic/source_files/program_with_parallel_workflow.py index 142d3f956..d6c776a9b 100644 --- a/docs/running/notebooks/source_files/program_2.py +++ b/docs/getting_started/basic/source_files/program_with_parallel_workflow.py @@ -1,4 +1,4 @@ -# source_files/program_2.py +# source_files/program_with_parallel_workflow.py from quantum_serverless import get_arguments, save_result, distribute_task, get @@ -6,26 +6,21 @@ from qiskit.primitives import Sampler from qiskit.circuit.random import random_circuit + @distribute_task() def distributed_sample(circuit: QuantumCircuit): """Distributed task that returns quasi distribution for given circuit.""" return Sampler().run(circuit).result().quasi_dists[0] -circuits = [random_circuit(2, 2) for _ in range(3)] -[circuit.measure_all() for circuit in circuits] - +arguments = get_arguments() +circuits = arguments.get("circuits") # run distributed tasks as async function # we get task references as a return type -sample_task_references = [ - distributed_sample(circuit) - for circuit in circuits -] +sample_task_references = [distributed_sample(circuit) for circuit in circuits] # now we need to collect results from task references results = get(sample_task_references) -save_result({ - "results": results -}) +save_result({"results": results}) diff --git a/docs/development/guides/08_file_download.ipynb b/docs/getting_started/experimental/experimental_file_download.ipynb similarity index 91% rename from docs/development/guides/08_file_download.ipynb rename to docs/getting_started/experimental/experimental_file_download.ipynb index f1661fb36..c4b55b71f 100644 --- a/docs/development/guides/08_file_download.ipynb +++ b/docs/getting_started/experimental/experimental_file_download.ipynb @@ -16,7 +16,9 @@ "> Limitations:\n", "> - only `tar` files are supported\n", "> - `tar` file should be saved in `/data` directory during your program execution to be visible by `.files()` method call\n", - "> - only `/data` directory is supported, `/data/other_folder` will not be visible" + "> - only `/data` directory is supported, `/data/other_folder` will not be visible\n", + "\n", + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." ] }, { @@ -84,9 +86,7 @@ ], "source": [ "program = Program(\n", - " title=\"File producer\",\n", - " entrypoint=\"produce_files.py\",\n", - " working_dir=\"./src/\"\n", + " title=\"File producer\", entrypoint=\"produce_files.py\", working_dir=\"./source_files/\"\n", ")\n", "\n", "job = serverless.run(program)\n", @@ -188,7 +188,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/running/notebooks/06_running_programs_using_decorators.ipynb b/docs/getting_started/experimental/experimental_running_programs_using_decorators.ipynb similarity index 94% rename from docs/running/notebooks/06_running_programs_using_decorators.ipynb rename to docs/getting_started/experimental/experimental_running_programs_using_decorators.ipynb index c7c0b8ec2..0ab73b97e 100644 --- a/docs/running/notebooks/06_running_programs_using_decorators.ipynb +++ b/docs/getting_started/experimental/experimental_running_programs_using_decorators.ipynb @@ -5,7 +5,7 @@ "id": "f6fb114d-af27-4a89-83b4-b3806dfa8c1a", "metadata": {}, "source": [ - "# Running program using decorators [Experimental] \n", + "# Running program using decorators (Experimental)\n", "\n", "In this tutorial we will describe alternative way (interface) of running your programs.\n", "\n", @@ -18,7 +18,8 @@ "> 1. functions decorated with distribute_program, can only accept named arguments for now. E.g do not use `my_program(argument1)`, instead specify name of the argument `my_program(argument1=argument1)`\n", "> 2. function return will run `quantum_serverless.save_result` function under the hood, which means return values must be json serializable values in form of dictionary (with values as all Python native types, like strings, lists, dicts, `numpy` arrays, `QuantumCircuit`, `Operator`, etc.)\n", "> 3. when using local folder/modules user must specify `working_dir` as `./` (current folder), which will be archiving and sending content of entire folder for remote execution. Make sure that folder does not have large files. \n", - "\n" + "\n", + "> ⚠ This provider is set up with default credentials to a test cluster intended to run on your machine. For information on setting up infrastructure on your local machine, check out the guide on [local infrastructure setup](https://qiskit-extensions.github.io/quantum-serverless/deployment/local.html)." ] }, { @@ -97,7 +98,8 @@ " quasi_dists = sampler.run(circuit).result().quasi_dists\n", "\n", " return quasi_dists\n", - " \n", + "\n", + "\n", "job = hello_qiskit()\n", "job" ] @@ -165,13 +167,11 @@ "\n", "@distribute_program(provider)\n", "def program_with_distributed_tasks(circuits):\n", - " sample_task_references = [\n", - " distributed_sample(circuit)\n", - " for circuit in circuits\n", - " ]\n", + " sample_task_references = [distributed_sample(circuit) for circuit in circuits]\n", " results = get(sample_task_references)\n", " print(results)\n", "\n", + "\n", "circuits = []\n", "for _ in range(3):\n", " circuit = random_circuit(2, 2)\n", @@ -245,12 +245,12 @@ "\n", "from source_files.circuit_utils import create_hello_world_circuit\n", "\n", + "\n", "@distribute_program(provider, working_dir=\"./\")\n", "def my_program_with_modules():\n", " quasi_dists = Sampler().run(create_hello_world_circuit()).result().quasi_dists\n", - " return {\n", - " \"quasi_dists\": quasi_dists\n", - " } \n", + " return {\"quasi_dists\": quasi_dists}\n", + "\n", "\n", "job = my_program_with_modules()\n", "job" @@ -294,7 +294,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/docs/development/guides/index.rst b/docs/getting_started/experimental/index.rst similarity index 100% rename from docs/development/guides/index.rst rename to docs/getting_started/experimental/index.rst diff --git a/docs/getting_started/experimental/source_files/circuit_utils.py b/docs/getting_started/experimental/source_files/circuit_utils.py new file mode 100644 index 000000000..0408d2df7 --- /dev/null +++ b/docs/getting_started/experimental/source_files/circuit_utils.py @@ -0,0 +1,9 @@ +from qiskit import QuantumCircuit + + +def create_hello_world_circuit() -> QuantumCircuit: + circuit = QuantumCircuit(2) + circuit.h(0) + circuit.cx(0, 1) + circuit.measure_all() + return circuit diff --git a/docs/development/guides/src/produce_files.py b/docs/getting_started/experimental/source_files/produce_files.py similarity index 100% rename from docs/development/guides/src/produce_files.py rename to docs/getting_started/experimental/source_files/produce_files.py diff --git a/docs/getting_started/index.rst b/docs/getting_started/index.rst new file mode 100644 index 000000000..2c422a86a --- /dev/null +++ b/docs/getting_started/index.rst @@ -0,0 +1,19 @@ +=============== +Getting started +=============== + +This section includes guides for using the basic features of Quantum Serverless to run a program remotely. + +**Basic Usage** + +.. toctree:: + :maxdepth: 2 + + Basic Usage + +**Experimental Features** + +.. toctree:: + :maxdepth: 2 + + Experimental diff --git a/docs/index.rst b/docs/index.rst index a5f4bb278..40700c112 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -25,9 +25,10 @@ system and receive the results when they are ready. :maxdepth: 2 About Quantum Serverless - Quickstart - Running - Development + Installation + Getting started + Examples + Migration guides Deployment .. toctree:: diff --git a/docs/installation/index.rst b/docs/installation/index.rst new file mode 100644 index 000000000..9a3c6063c --- /dev/null +++ b/docs/installation/index.rst @@ -0,0 +1,39 @@ +============ +Installation +============ + +Step 0 [Optional]: Pre-Installation + +.. code-block:: + :caption: Create a minimal environment with only Python installed in it. We recommend using `Python virtual environments `_. + + python3 -m venv /path/to/virtual/environment + +.. code-block:: + :caption: Activate your new environment. + + source /path/to/virtual/environment/bin/activate + +.. code-block:: + :caption: Note: If you are using Windows, use the following commands in PowerShell. + + python3 -m venv c:\path\to\virtual\environment + c:\path\to\virtual\environment\Scripts\Activate.ps1 + +.. code-block:: + :caption: Clone the Quantum Serverless repository. + + cd /path/to/workspace/ + git clone git@github.com:Qiskit-Extensions/quantum-serverless.git + +Step 1: Install the quantum serverless package. + +.. code-block:: + :caption: Install quantum_serverless via pip. + + pip install --upgrade pip + pip install quantum_serverless + + +Note: if you want to deploy your own infrastructure locally or in cloud environment, refer to this document :doc:`/deployment/local`. + diff --git a/docs/running/notebooks/index.rst b/docs/migration/index.rst similarity index 50% rename from docs/running/notebooks/index.rst rename to docs/migration/index.rst index b7aba0a31..9fe5ef7f4 100644 --- a/docs/running/notebooks/index.rst +++ b/docs/migration/index.rst @@ -1,3 +1,7 @@ +========= +Migration +========= + .. nbgallery:: :glob: diff --git a/docs/migration/migration_from_qiskit_runtime_programs.ipynb b/docs/migration/migration_from_qiskit_runtime_programs.ipynb new file mode 100644 index 000000000..710cb5f0a --- /dev/null +++ b/docs/migration/migration_from_qiskit_runtime_programs.ipynb @@ -0,0 +1,234 @@ +{ + "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 Quantum Serverless `Program`.\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 Quantum Serverless programs.\n", + "\n", + "Quantum Serverless handles backends, logging, and input arguments a bit differently than Qiskit Runtime:\n", + "- `backend`. For Quantum Serverless programs you are not limited to single backend for a program. You can call any 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. Quantum Serverless does not require passing such an object. Instead, all contents of `stdout` (e.g. print statements, logging messages) will be provided to the user via the Quantum Serverless job handler.\n", + "- `**kwargs` was a variable used to capture program inputs from the user. Users should now input their arguments to the `Program` constructor, and the arguments should be retrieved within the program using the `get_arguments` function from Quantum Serverless.\n", + "- To save the results of a program, 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 Quantum Serverless Program.\n", + "\n", + "```python\n", + "# migrated_program.py\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", + "from qiskit.primitives import Sampler\n", + "\n", + "from quantum_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_program.py` and execute it using the `Program` class from the `quantum_serverless` package." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "50fb2a64-751d-40fb-bac8-db49dc92fbca", + "metadata": {}, + "outputs": [], + "source": [ + "from quantum_serverless import Program\n", + "\n", + "program = Program(\n", + " title=\"Migrated program\", entrypoint=\"migrated_program.py\", working_dir=\"./src/\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "162c482e-8f86-4224-a9b9-f6567b34acf4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from quantum_serverless import QuantumServerless, Provider\n", + "import os\n", + "\n", + "provider = Provider(\n", + " username=os.environ.get(\"GATEWAY_USER\", \"user\"),\n", + " password=os.environ.get(\"GATEWAY_PASSWORD\", \"password123\"),\n", + " # token=os.environ.get(\"GATEWAY_TOKEN\", \"\"), # token can be used instead of user/password combination\n", + " host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n", + ")\n", + "\n", + "serverless = QuantumServerless(provider)\n", + "serverless" + ] + }, + { + "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 ``Program`` class allows users to send a job for remote execution in a single step." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "9f6eddae-a889-4958-8f0a-7e9f8ec29800", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "job = serverless.run(program, arguments={\"iterations\": 3})\n", + "job" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "2223b57b-1dbc-45c7-8fd6-8e2ebfb843aa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"result\": \"Hello, World!\"}'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "job.result()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "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': [{8: 0.0044464220610969, 9: 0.0714788704988803, 10: 0.0025387094251744, 11: 0.0408112589724704, 12: 0.0044464220610969, 13: 0.0714788704988803, 14: 0.0025387094251744, 15: 0.0408112589724704, 24: 0.0323482396235251, 25: 0.2100040886340835, 26: 0.018469407467762, 27: 0.1199030033170077, 28: 0.0323482396235251, 29: 0.2100040886340835, 30: 0.018469407467762, 31: 0.1199030033170077}]}\n", + "{'iteration': 1, 'dists': [{0: 0.0029658828912998, 1: 0.0237036789902499, 4: 0.0150644475889747, 5: 0.1203968069211296, 8: 0.0061806907129902, 9: 0.0493967948055204, 10: 0.0035529476369869, 11: 0.0283955683157122, 12: 0.0313932460322799, 13: 0.2508984520575557, 14: 0.0144443775915554, 15: 0.1154411358076723, 16: 2.64895095504e-05, 17: 0.0002117072231119, 20: 6.5157421817e-06, 21: 5.20745648832e-05, 24: 5.52022691625e-05, 25: 0.0004411829177743, 26: 0.0074040922276745, 27: 0.0591743611636965, 28: 1.35783470443e-05, 29: 0.0001085197195414, 30: 0.0301010639013888, 31: 0.2405711830620639}]}\n", + "{'iteration': 2, 'dists': [{0: 0.0039688421058765, 1: 0.1105278404952374, 2: 0.0010364406823262, 3: 0.0288637207938572, 8: 0.2163089101542446, 9: 0.0656597293669953, 10: 0.0564878492146483, 11: 0.0171466671868148, 16: 0.0053863259939914, 17: 0.1091103566071225, 18: 0.0014066085874713, 19: 0.0284935528887121, 24: 0.2177263940423595, 25: 0.0642422454788804, 26: 0.0568580171197935, 27: 0.0167764992816696}]}\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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/migration/src/migrated_program.py b/docs/migration/src/migrated_program.py new file mode 100644 index 000000000..a184534bf --- /dev/null +++ b/docs/migration/src/migrated_program.py @@ -0,0 +1,27 @@ +"""A sample runtime program that submits random circuits for user-specified iterations.""" + +import random + +from qiskit import transpile +from qiskit.circuit.random import random_circuit +from qiskit.primitives import Sampler + +from quantum_serverless import get_arguments, save_result + + +def prepare_circuits(): + circuit = random_circuit( + num_qubits=5, depth=4, measure=True, seed=random.randint(0, 1000) + ) + return transpile(circuit) + + +arguments = get_arguments() +iterations = arguments.get("iterations", 5) + +for it in range(iterations): + qc = prepare_circuits() + result = Sampler().run([qc]).result() + print({"iteration": it, "dists": result.quasi_dists}) + +save_result({"result": "Hello, World!"}) diff --git a/docs/quickstart/index.rst b/docs/quickstart/index.rst deleted file mode 100644 index 24c974a85..000000000 --- a/docs/quickstart/index.rst +++ /dev/null @@ -1,159 +0,0 @@ -========== -Quickstart -========== - -.. note:: - - These instructions describe a fully local workflow. To run on remote - resources, users may either `configure their resources themselves `_ or ask - their provider or dev ops team. - -Step 0 [Optional]: Pre-Installation - -.. code-block:: - :caption: Create a minimal environment with only Python installed in it. We recommend using `Python virtual environments `_. - - python3 -m venv /path/to/virtual/environment - -.. code-block:: - :caption: Activate your new environment. - - source /path/to/virtual/environment/bin/activate - -.. code-block:: - :caption: Note: If you are using Windows, use the following commands in PowerShell. - - python3 -m venv c:\path\to\virtual\environment - c:\path\to\virtual\environment\Scripts\Activate.ps1 - -.. code-block:: - :caption: Clone the Quantum Serverless repository. - - cd /path/to/workspace/ - git clone git@github.com:Qiskit-Extensions/quantum-serverless.git - -Step 1: Install Docker. - - If Docker is not installed on your system, following the directions - on the `Docker website `_ to install Docker on your system. - -Step 2: Stop any running jupyter notebook servers. - -Step 3: Install the quantum serverless package. - -.. code-block:: - :caption: Install quantum_serverless via pip. - - pip install --upgrade pip - pip install quantum_serverless - - -Step 4: Run infrastructure. - -.. code-block:: - :caption: Run docker compose from the root of the quantum serverless project. - - cd quantum-serverless/ - docker compose --profile jupyter up - -Step 5: Open the jupyter lab environment by going to ``localhost:8888``. The default token is ``123``. - -Step 6: Write your program in containerized environment. - -.. code-block:: - :caption: Create a Python file using a text editor. Here we use vim. - - vim program.py - -.. code-block:: python - :caption: program.py - - from quantum_serverless import distribute_task, get, get_arguments, save_result - - from qiskit import QuantumCircuit - from qiskit.circuit.random import random_circuit - from qiskit.primitives import Sampler - from qiskit.quantum_info import SparsePauliOp - - # 1. Define a distributed function using the `distribute_task` decorator - @distribute_task() - def distributed_sample(circuit: QuantumCircuit): - """Calculates quasi dists as a distributed function.""" - return Sampler().run(circuit).result().quasi_dists[0] - - - # 2. Get the program arguments using `get_arguments` - arguments = get_arguments() - circuits = arguments.get("circuits", []) - - # 3. Run the distributed function for each circuit in parallel and get execution references - function_references = [ - distributed_sample(circuit) - for circuit in circuits - ] - - # 4. Collect all results using `get` - collected_results = get(function_references) - - # 5. Save the results using `save_result` - save_result({ - "quasi_dists": collected_results - }) - -Step 5: Run the program. - -.. code-block:: python - :caption: in jupyter notebook - - from quantum_serverless import QuantumServerless, Provider, Program - from qiskit.circuit.random import random_circuit - - serverless = QuantumServerless(Provider( - username="user", # this username has already been defined in local docker setup and does not need to be changed - password="password123", # this password has already been defined in local docker setup and does not need to be changed - host="http://gateway:8000", # address of provider - )) - - # create program - program = Program( - title="Quickstart", - entrypoint="program.py", - working_dir="./" # or where your program file is located - ) - - # create inputs to our program - circuits = [] - for _ in range(3): - circuit = random_circuit(3, 2) - circuit.measure_all() - circuits.append(circuit) - - # run program - job = serverless.run( - program=program, - arguments={ - "circuits": circuits - } - ) - -Step 6: Monitor the job status. - -.. code-block:: python - :caption: in jupyter notebook - - job.status() - # - - job.logs() - -Step 7: Get the results. - -.. code-block:: python - :caption: in jupyter notebook - - job.result() - # {"quasi_dists": [ - # {"0": 0.25, "1": 0.25, "2": 0.2499999999999999, "3": 0.2499999999999999}, - # {"0": 0.1512273969460124, "1": 0.0400459556274728, "6": 0.1693190975212014, "7": 0.6394075499053132}, - # {"0": 0.25, "1": 0.25, "4": 0.2499999999999999, "5": 0.2499999999999999} - # ]} diff --git a/docs/running/index.rst b/docs/running/index.rst deleted file mode 100644 index 5cf5890e1..000000000 --- a/docs/running/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -======= -Running -======= - -This section contains a series of short examples that demonstrate how to run serverless programs and showcase the main features of this package. - -.. toctree:: - :maxdepth: 2 - - Running \ No newline at end of file diff --git a/docs/running/notebooks/source_files/__init__.py b/docs/running/notebooks/source_files/__init__.py deleted file mode 100644 index e69de29bb..000000000