diff --git a/client/README.md b/client/README.md index cf178e279..1250597a1 100644 --- a/client/README.md +++ b/client/README.md @@ -21,7 +21,7 @@ Full docs can be found at https://qiskit-extensions.github.io/quantum-serverless ## Usage -### Step 1: write program +### Step 1: write pattern ```python from quantum_serverless import distribute_task, get, get_arguments, save_result @@ -67,22 +67,22 @@ Full docs can be found at https://qiskit-extensions.github.io/quantum-serverless ``` -### Step 2: run program +### Step 2: run pattern ```python - from quantum_serverless import QuantumServerless, GatewayProvider + from quantum_serverless import ServerlessProvider, QiskitPattern from qiskit.circuit.random import random_circuit - serverless = QuantumServerless(GatewayProvider( + serverless = ServerlessProvider( username="", password="", host="", - )) + ) # create program - program = Program( + program = QiskitPattern( title="Quickstart", - entrypoint="program.py", + entrypoint="pattern.py", working_dir="./src" ) diff --git a/client/quantum_serverless/__init__.py b/client/quantum_serverless/__init__.py index 86303d964..f1d78d06b 100644 --- a/client/quantum_serverless/__init__.py +++ b/client/quantum_serverless/__init__.py @@ -26,7 +26,7 @@ from .core import ( BaseProvider, distribute_task, - distribute_program, + distribute_qiskit_pattern, get, put, get_refs_by_status, @@ -41,7 +41,7 @@ get_auto_discovered_provider, QuantumServerlessException, ) -from .core.program import Program +from .core.pattern import QiskitPattern from .serializers import get_arguments try: diff --git a/client/quantum_serverless/core/__init__.py b/client/quantum_serverless/core/__init__.py index 79d9b7fdb..c808caee8 100644 --- a/client/quantum_serverless/core/__init__.py +++ b/client/quantum_serverless/core/__init__.py @@ -37,6 +37,7 @@ BaseJobClient RayJobClient save_result + QiskitPattern Program ProgramStorage ProgramRepository @@ -46,6 +47,7 @@ fetch_execution_meta distribute_task distribute_program + distribute_qiskit_pattern get put get_refs_by_status @@ -61,7 +63,8 @@ RayProvider, ) from .job import BaseJobClient, RayJobClient, GatewayJobClient, Job, save_result -from .program import ( +from .pattern import ( + QiskitPattern, Program, ProgramStorage, ProgramRepository, @@ -74,6 +77,7 @@ get_refs_by_status, fetch_execution_meta, distribute_task, + distribute_qiskit_pattern, distribute_program, Target, CircuitMeta, diff --git a/client/quantum_serverless/core/decorators.py b/client/quantum_serverless/core/decorators.py index a04fd374f..791f77fd9 100644 --- a/client/quantum_serverless/core/decorators.py +++ b/client/quantum_serverless/core/decorators.py @@ -34,6 +34,7 @@ import inspect import os import shutil +import warnings from dataclasses import dataclass from typing import Optional, Dict, Any, Union, List, Callable, Sequence from uuid import uuid4 @@ -332,15 +333,15 @@ def wrapper(*args, **kwargs): """ -def distribute_program( +def distribute_qiskit_pattern( provider: Optional[Any] = None, dependencies: Optional[List[str]] = None, working_dir: Optional[str] = None, ): - """[Experimental] Program decorator to turn function into remotely executable program. + """[Experimental] QiskitPattern decorator to turn function into remotely executable program. Example: - >>> @distribute_program(provider=ServerlessProvider(...), dependencies=[...]) + >>> @distribute_qiskit_pattern(provider=ServerlessProvider(...), dependencies=[...]) >>> def my_program(): >>> print("Hola!") >>> @@ -356,7 +357,7 @@ def distribute_program( """ # pylint: disable=import-outside-toplevel,cyclic-import from quantum_serverless import QuantumServerlessException - from quantum_serverless.core.program import Program + from quantum_serverless.core.pattern import QiskitPattern from quantum_serverless.core.provider import ServerlessProvider # create provider @@ -411,12 +412,12 @@ def wrapper(*args, **kwargs): file.write(ENTRYPOINT_CONTENT.format(file_name=pickle_file_name)) # create program - wrapped_program = Program( + wrapped_program = QiskitPattern( title=function.__name__, entrypoint=entrypoint_file_name, working_dir=working_directory, dependencies=dependencies, - description="Program execution using @distribute_program decorator.", + description="QiskitPattern execution using @distribute_program decorator.", ) # run program @@ -434,3 +435,17 @@ def wrapper(*args, **kwargs): return wrapper return decorator + + +def distribute_program( + provider: Optional[Any] = None, + dependencies: Optional[List[str]] = None, + working_dir: Optional[str] = None, +): + """Decorator for distributed program.""" + warnings.warn( + "`distribute_program` has been deprecated " + "and will be removed in future releases. " + "Please, use `distribute_qiskit_pattern` instead." + ) + return distribute_qiskit_pattern(provider, dependencies, working_dir) diff --git a/client/quantum_serverless/core/job.py b/client/quantum_serverless/core/job.py index 3f42e65e4..8e693e4c2 100644 --- a/client/quantum_serverless/core/job.py +++ b/client/quantum_serverless/core/job.py @@ -53,7 +53,7 @@ MAX_ARTIFACT_FILE_SIZE_MB, ENV_JOB_ARGUMENTS, ) -from quantum_serverless.core.program import Program +from quantum_serverless.core.pattern import QiskitPattern from quantum_serverless.exception import QuantumServerlessException from quantum_serverless.serializers.program_serializers import ( QiskitObjectsEncoder, @@ -68,17 +68,19 @@ class BaseJobClient: """Base class for Job clients.""" def run( - self, program: Program, arguments: Optional[Dict[str, Any]] = None + self, program: QiskitPattern, arguments: Optional[Dict[str, Any]] = None ) -> "Job": """Runs program.""" raise NotImplementedError - def upload(self, program: Program): + def upload(self, program: QiskitPattern): """Uploads program.""" raise NotImplementedError def run_existing( - self, program: Union[str, Program], arguments: Optional[Dict[str, Any]] = None + self, + program: Union[str, QiskitPattern], + arguments: Optional[Dict[str, Any]] = None, ): """Executes existing program.""" raise NotImplementedError @@ -144,7 +146,7 @@ def list(self, **kwargs) -> List["Job"]: Job(job.job_id, job_client=self) for job in self._job_client.list_jobs() ] - def run(self, program: Program, arguments: Optional[Dict[str, Any]] = None): + def run(self, program: QiskitPattern, arguments: Optional[Dict[str, Any]] = None): arguments = arguments or {} entrypoint = f"python {program.entrypoint}" @@ -166,11 +168,13 @@ def run(self, program: Program, arguments: Optional[Dict[str, Any]] = None): ) return Job(job_id=job_id, job_client=self) - def upload(self, program: Program): + def upload(self, program: QiskitPattern): raise NotImplementedError("Upload is not available for RayJobClient.") def run_existing( - self, program: Union[str, Program], arguments: Optional[Dict[str, Any]] = None + self, + program: Union[str, QiskitPattern], + arguments: Optional[Dict[str, Any]] = None, ): raise NotImplementedError("Run existing is not available for RayJobClient.") @@ -191,7 +195,7 @@ def __init__(self, host: str, token: str, version: str): self._token = token def run( # pylint: disable=too-many-locals - self, program: Program, arguments: Optional[Dict[str, Any]] = None + self, program: QiskitPattern, arguments: Optional[Dict[str, Any]] = None ) -> "Job": tracer = trace.get_tracer("client.tracer") with tracer.start_as_current_span("job.run") as span: @@ -249,7 +253,7 @@ def run( # pylint: disable=too-many-locals return Job(job_id, job_client=self) - def upload(self, program: Program): + def upload(self, program: QiskitPattern): tracer = trace.get_tracer("client.tracer") with tracer.start_as_current_span("job.run") as span: span.set_attribute("program", program.title) @@ -304,9 +308,11 @@ def upload(self, program: Program): return program_title def run_existing( - self, program: Union[str, Program], arguments: Optional[Dict[str, Any]] = None + self, + program: Union[str, QiskitPattern], + arguments: Optional[Dict[str, Any]] = None, ): - if isinstance(program, Program): + if isinstance(program, QiskitPattern): title = program.title else: title = str(program) @@ -441,7 +447,7 @@ def get_programs(self, **kwargs): ) ) return [ - Program(program.get("title"), raw_data=program) + QiskitPattern(program.get("title"), raw_data=program) for program in response_data.get("results", []) ] diff --git a/client/quantum_serverless/core/program.py b/client/quantum_serverless/core/pattern.py similarity index 76% rename from client/quantum_serverless/core/program.py rename to client/quantum_serverless/core/pattern.py index 4a7d3e43b..e9fed2982 100644 --- a/client/quantum_serverless/core/program.py +++ b/client/quantum_serverless/core/pattern.py @@ -24,13 +24,14 @@ .. autosummary:: :toctree: ../stubs/ - Program + QiskitPattern """ import dataclasses import json import logging import os import tarfile +import warnings from abc import ABC from dataclasses import dataclass from pathlib import Path @@ -46,8 +47,8 @@ @dataclass -class Program: # pylint: disable=too-many-instance-attributes - """Serverless Program. +class QiskitPattern: # pylint: disable=too-many-instance-attributes + """Serverless QiskitPattern. Args: title: program name @@ -72,12 +73,12 @@ class Program: # pylint: disable=too-many-instance-attributes @classmethod def from_json(cls, data: Dict[str, Any]): - """Reconstructs Program from dictionary.""" - field_names = set(f.name for f in dataclasses.fields(Program)) - return Program(**{k: v for k, v in data.items() if k in field_names}) + """Reconstructs QiskitPattern from dictionary.""" + field_names = set(f.name for f in dataclasses.fields(QiskitPattern)) + return QiskitPattern(**{k: v for k, v in data.items() if k in field_names}) def __str__(self): - return f"Program({self.title})" + return f"QiskitPattern({self.title})" def __repr__(self): return self.__str__() @@ -86,7 +87,7 @@ def __repr__(self): class ProgramStorage(ABC): """Base program backend to save and load programs from.""" - def save_program(self, program: Program) -> bool: + def save_program(self, program: QiskitPattern) -> bool: """Save program in specified backend. Args: @@ -108,7 +109,7 @@ def get_programs(self, **kwargs) -> List[str]: """ raise NotImplementedError - def get_program(self, title: str, **kwargs) -> Optional[Program]: + def get_program(self, title: str, **kwargs) -> Optional[QiskitPattern]: """Returns program by name and other query criteria. Args: @@ -116,11 +117,44 @@ def get_program(self, title: str, **kwargs) -> Optional[Program]: **kwargs: other args Returns: - Program + QiskitPattern """ raise NotImplementedError +class Program(QiskitPattern): # pylint: disable=too-few-public-methods + """[Deprecated] Program""" + + def __init__( + self, + title: str, + entrypoint: Optional[str] = None, + working_dir: Optional[str] = "./", + env_vars: Optional[Dict[str, str]] = None, + dependencies: Optional[List[str]] = None, + description: Optional[str] = None, + version: Optional[str] = None, + tags: Optional[List[str]] = None, + raw_data: Optional[Dict[str, Any]] = None, + ): + """Program.""" + warnings.warn( + "`Program` has been deprecated and will be removed in future releases. " + "Please, use `QiskitPattern` instead." + ) + super().__init__( + title, + entrypoint, + working_dir, + env_vars, + dependencies, + description, + version, + tags, + raw_data, + ) + + class ProgramRepository(ProgramStorage): """ProgramRepository.""" @@ -131,7 +165,7 @@ def __init__( token: Optional[str] = None, folder: Optional[str] = None, ): - """Program repository implementation. + """QiskitPattern repository implementation. Args: host: host of backend @@ -145,7 +179,7 @@ def __init__( self._token = token self._base_url = f"{self._host}:{self._port}/api/v1/programs/" - def save_program(self, program: Program) -> bool: + def save_program(self, program: QiskitPattern) -> bool: raise NotImplementedError("Not implemented yet.") def get_programs(self, **kwargs) -> List[str]: @@ -156,7 +190,7 @@ def get_programs(self, **kwargs) -> List[str]: result = [entry.get("title") for entry in response_data.get("results", [])] return result - def get_program(self, title: str, **kwargs) -> Optional[Program]: + def get_program(self, title: str, **kwargs) -> Optional[QiskitPattern]: result = None response = requests.get( url=f"{self._base_url}", @@ -169,7 +203,7 @@ def get_program(self, title: str, **kwargs) -> Optional[Program]: results = response_data.get("results", []) if len(results) > 0: artifact = results[0].get("artifact") - result = Program.from_json(results[0]) + result = QiskitPattern.from_json(results[0]) result.working_dir = download_and_unpack_artifact( artifact_url=artifact, program=result, folder=self.folder ) @@ -180,7 +214,7 @@ def get_program(self, title: str, **kwargs) -> Optional[Program]: def download_and_unpack_artifact( artifact_url: str, - program: Program, + program: QiskitPattern, folder: str, headers: Optional[Dict[str, Any]] = None, ) -> str: @@ -201,7 +235,7 @@ def download_and_unpack_artifact( # check if program path already exist on the disc if os.path.exists(program_folder_path): - logging.warning("Program folder already exist. Will be overwritten.") + logging.warning("QiskitPattern folder already exist. Will be overwritten.") # download file response = requests.get(url=artifact_url, stream=True, headers=headers, timeout=100) diff --git a/client/quantum_serverless/core/provider.py b/client/quantum_serverless/core/provider.py index 03c05dd52..4f7e8cba4 100644 --- a/client/quantum_serverless/core/provider.py +++ b/client/quantum_serverless/core/provider.py @@ -53,7 +53,7 @@ GatewayJobClient, BaseJobClient, ) -from quantum_serverless.core.program import Program +from quantum_serverless.core.pattern import QiskitPattern from quantum_serverless.core.tracing import _trace_env_vars from quantum_serverless.exception import QuantumServerlessException from quantum_serverless.utils import JsonSerializable @@ -261,13 +261,15 @@ def get_job_by_id(self, job_id: str) -> Optional[Job]: return Job(job_id=job_id, job_client=job_client) def run( - self, program: Union[Program, str], arguments: Optional[Dict[str, Any]] = None + self, + program: Union[QiskitPattern, str], + arguments: Optional[Dict[str, Any]] = None, ) -> Job: """Execute a program as a async job. Example: >>> serverless = QuantumServerless() - >>> program = Program( + >>> program = QiskitPattern( >>> "job.py", >>> arguments={"arg1": "val1"}, >>> dependencies=["requests"] @@ -294,7 +296,7 @@ def run( return job_client.run(program, arguments) - def upload(self, program: Program): + def upload(self, program: QiskitPattern): """Uploads program.""" raise NotImplementedError @@ -409,17 +411,19 @@ def get_job_by_id(self, job_id: str) -> Optional[Job]: return self._job_client.get(job_id) def run( - self, program: Union[Program, str], arguments: Optional[Dict[str, Any]] = None + self, + program: Union[QiskitPattern, str], + arguments: Optional[Dict[str, Any]] = None, ) -> Job: tracer = trace.get_tracer("client.tracer") with tracer.start_as_current_span("Provider.run"): - if isinstance(program, Program) and program.entrypoint is not None: + if isinstance(program, QiskitPattern) and program.entrypoint is not None: job = self._job_client.run(program, arguments) else: job = self._job_client.run_existing(program, arguments) return job - def upload(self, program: Program): + def upload(self, program: QiskitPattern): tracer = trace.get_tracer("client.tracer") with tracer.start_as_current_span("Provider.upload"): response = self._job_client.upload(program) @@ -440,7 +444,7 @@ def file_delete(self, file: str): def file_upload(self, file: str): return self._files_client.upload(file) - def get_programs(self, **kwargs) -> List[Program]: + def get_programs(self, **kwargs) -> List[QiskitPattern]: return self._job_client.get_programs(**kwargs) def _fetch_token(self, username: str, password: str): @@ -576,7 +580,9 @@ def __init__(self, host: str): self.client = RayJobClient(JobSubmissionClient(host)) def run( - self, program: Union[Program, str], arguments: Optional[Dict[str, Any]] = None + self, + program: Union[QiskitPattern, str], + arguments: Optional[Dict[str, Any]] = None, ) -> Job: if isinstance(program, str): raise NotImplementedError("Ray provider only supports full Programs.") diff --git a/client/quantum_serverless/quantum_serverless.py b/client/quantum_serverless/quantum_serverless.py index 2abe49442..6dfb5e0d2 100644 --- a/client/quantum_serverless/quantum_serverless.py +++ b/client/quantum_serverless/quantum_serverless.py @@ -42,7 +42,7 @@ from opentelemetry.instrumentation.requests import RequestsInstrumentor from quantum_serverless.core.job import Job -from quantum_serverless.core.program import Program +from quantum_serverless.core.pattern import QiskitPattern from quantum_serverless.core.provider import BaseProvider, ComputeResource from quantum_serverless.exception import QuantumServerlessException @@ -103,13 +103,13 @@ def job_client(self): return self._selected_provider.job_client() def run( - self, program: Program, arguments: Optional[Dict[str, Any]] = None + self, program: QiskitPattern, arguments: Optional[Dict[str, Any]] = None ) -> Optional[Job]: """Execute a program as a async job Example: >>> serverless = QuantumServerless() - >>> program = Program( + >>> program = QiskitPattern( >>> "job.py", >>> dependencies=["requests"] >>> ) @@ -128,11 +128,11 @@ def run( job = self._selected_provider.run(program, arguments) return job - def upload(self, program: Program): + def upload(self, program: QiskitPattern): """Uploads program. Args: - program: Program + program: QiskitPattern Returns: program title diff --git a/client/quantum_serverless/visualizaiton/widget.py b/client/quantum_serverless/visualizaiton/widget.py index fb0096f1e..e77595786 100644 --- a/client/quantum_serverless/visualizaiton/widget.py +++ b/client/quantum_serverless/visualizaiton/widget.py @@ -134,7 +134,7 @@ def render_program_list(self): """Renders list of jobs.""" def render_program_row(program): - title = program.raw_data.get("title", "Program") + title = program.raw_data.get("title", "QiskitPattern") date = datetime.strptime( program.raw_data.get("created", "2011-11-11T11:11:11.000Z"), "%Y-%m-%dT%H:%M:%S.%fZ", @@ -322,7 +322,7 @@ def show(self): program_list_widget, self.render_information(), ] - tab_nest.set_title(0, "Program jobs") + tab_nest.set_title(0, "QiskitPattern jobs") tab_nest.set_title(1, "Programs") tab_nest.set_title(2, "Info") diff --git a/client/tests/core/test_program.py b/client/tests/core/test_pattern.py similarity index 95% rename from client/tests/core/test_program.py rename to client/tests/core/test_pattern.py index 73b7d35ad..68f3e9034 100644 --- a/client/tests/core/test_program.py +++ b/client/tests/core/test_pattern.py @@ -7,7 +7,7 @@ from quantum_serverless import QuantumServerless, BaseProvider from quantum_serverless.core import ComputeResource from quantum_serverless.core.job import Job -from quantum_serverless.core.program import Program +from quantum_serverless.core.pattern import QiskitPattern from tests.utils import wait_for_job_client, wait_for_job_completion resources_path = os.path.join( @@ -34,7 +34,7 @@ def test_program(): wait_for_job_client(serverless) - program = Program( + program = QiskitPattern( title="simple_job", entrypoint="job.py", working_dir=resources_path, diff --git a/client/tests/core/test_program_repository.py b/client/tests/core/test_program_repository.py index f338a4b0e..ac0c91b63 100644 --- a/client/tests/core/test_program_repository.py +++ b/client/tests/core/test_program_repository.py @@ -5,9 +5,9 @@ from pathlib import Path from unittest import TestCase, mock -from quantum_serverless.core.program import ( +from quantum_serverless.core.pattern import ( ProgramRepository, - Program, + QiskitPattern, ) responses = { @@ -143,5 +143,5 @@ def test_repository_get_program(self, mock_get): program = repository.get_program("hello_world") self.assertEqual(program.title, "hello_world") self.assertEqual(program.version, "0.0.0") - self.assertIsInstance(program, Program) + self.assertIsInstance(program, QiskitPattern) self.assertEqual(len(mock_get.call_args_list), 2) diff --git a/client/tests/serializers/test_program_serializers.py b/client/tests/serializers/test_program_serializers.py index ac7f85684..0f45780ab 100644 --- a/client/tests/serializers/test_program_serializers.py +++ b/client/tests/serializers/test_program_serializers.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Program serializers tests.""" +"""QiskitPattern serializers tests.""" import json import os from unittest import TestCase, skip diff --git a/docs/examples/01_vqe.ipynb b/docs/examples/01_vqe.ipynb index dc685c7b5..c0fd685d4 100644 --- a/docs/examples/01_vqe.ipynb +++ b/docs/examples/01_vqe.ipynb @@ -4,9 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Example: VQE program\n", + "# Example: VQE as QiskitPattern\n", "\n", - "This tutorial will be demonstation of creating VQE Program as well as migration guide on how you can replicate IBM Quantum VQE custom runtime program.\n", + "This tutorial will be demonstation of creating VQE as QiskitPattern as well as migration guide on how you can replicate IBM Quantum VQE custom runtime program.\n", "\n", "Let's first get information on what is VQE runtime program and what inputs and outputs it has.\n", "\n", @@ -41,9 +41,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "With that information we can start drafting our program implementation in `vqe.py` file.\n", + "With that information we can start drafting our pattern implementation in `vqe.py` file.\n", "\n", - "What our program should do:\n", + "What our pattern should do:\n", "\n", "1. parse input arguments\n", "2. create run_vqe function that accepts estimator instance, creates VQE and runs calculation\n", @@ -52,7 +52,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. Full code can be found in [vqe.py](./source_files/vqe/vqe.py) file.\n", + "Roughly our VQE pattern 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", @@ -112,25 +112,25 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "At this point we have our program implemented. Now we need to actually run it. But before let's prepare input arguments from our VQE program." + "At this point we have our pattern implemented. Now we need to actually run it. But before let's prepare input arguments from our VQE pattern." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 12, "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": 1, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -170,12 +170,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "With arguments prepared we can create our quantum serverless client, setup provider and run our program" + "With arguments prepared we can create our quantum serverless client, setup provider and run our pattern" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -185,7 +185,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -194,7 +194,7 @@ "" ] }, - "execution_count": 3, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -211,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -220,31 +220,31 @@ "'vqe'" ] }, - "execution_count": 6, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(title=\"vqe\", entrypoint=\"vqe.py\", working_dir=\"./source_files/vqe/\")\n", + "pattern = QiskitPattern(title=\"vqe\", entrypoint=\"vqe.py\", working_dir=\"./source_files/vqe/\")\n", "\n", - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 7, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -256,7 +256,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -265,7 +265,7 @@ "'QUEUED'" ] }, - "execution_count": 8, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -276,34 +276,34 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'result': {'0': 0.4266, '1': 0.3574, '2': 0.104, '3': 0.112},\n", - " 'optimal_point': [2.400955119274195,\n", - " 2.717799958252893,\n", - " 1.3628585897978087,\n", - " 2.4311917260940845,\n", - " 5.754283033860017,\n", - " 1.1224006163027451,\n", - " 6.624675068668877,\n", - " 4.76802186154173,\n", - " 0.7666935155193715,\n", - " 3.627167675726581,\n", - " 1.6068996965600872,\n", - " -0.07959435779430134,\n", - " 2.790199999683474,\n", - " 4.248957104589368,\n", - " 2.961996372880535,\n", - " 5.240096622392362],\n", - " 'optimal_value': -0.702930389778663,\n", - " 'optimizer_time': 5.314694999993662}" + "{'result': {'0': 0.4223, '1': 0.3604, '2': 0.1073, '3': 0.11},\n", + " 'optimal_point': [2.51762813907937,\n", + " 1.532634671366952,\n", + " 6.968201754881848,\n", + " 1.8258529400009142,\n", + " 1.5453234923701027,\n", + " 3.905921764150066,\n", + " 1.6694898480396192,\n", + " 1.075020301957671,\n", + " 0.8048376424004327,\n", + " 2.823196594205023,\n", + " 2.9665234835014846,\n", + " 4.143832547893007,\n", + " 4.382722375425133,\n", + " 4.582108812661252,\n", + " 6.596830693043498,\n", + " 4.716678649450963],\n", + " 'optimal_value': -0.7029303910686284,\n", + " 'optimizer_time': 3.4171429999987595}" ] }, - "execution_count": 9, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } diff --git a/docs/examples/02_qaoa.ipynb b/docs/examples/02_qaoa.ipynb index 0b1a531b4..c5c93f484 100644 --- a/docs/examples/02_qaoa.ipynb +++ b/docs/examples/02_qaoa.ipynb @@ -4,17 +4,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Example: QAOA program\n", + "# Example: QAOA as QiskitPattern\n", "\n", - "This tutorial will be demonstation of creating QAOA Program as well as migration guide on how you can replicate IBM Quantum QAOA custom runtime program.\n", + "This tutorial will be demonstation of creating QAOA as QiskitPattern as well as migration guide on how you can replicate IBM Quantum QAOA custom runtime program.\n", "\n", "Let's first get information on what is QAOA runtime program and what inputs and outputs it has. We will not be implementing full set of input/outputs, but we will cover most important ones. Later on we can recover full functionality if needed.\n", "\n", "**Description**: Qiskit Runtime QAOA program.\n", "\n", "\n", - "\n", - "\n", "**Inputs**:\n", "\n", "| name | type | description |\n", @@ -38,9 +36,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "With that information we can start drafting our program implementation in `qaoa.py` file.\n", + "With that information we can start drafting our pattern implementation in `qaoa.py` file.\n", "\n", - "What our program should do:\n", + "What our pattern should do:\n", "\n", "1. parse input arguments\n", "2. create run_qaoa function that accepts estimator instance, creates VQE and runs calculation\n", @@ -49,7 +47,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. Full code can be found in [qaoa.py](./source_files/qaoa/qaoa.py) file.\n", + "Roughly our QAOA pattern 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", @@ -95,7 +93,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "At this point we have our program implemented. Now we need to actually run it. But before let's prepare input arguments from our QAOA program." + "At this point we have our pattern implemented. Now we need to actually run it. But before let's prepare input arguments from our QAOA pattern." ] }, { @@ -164,7 +162,7 @@ "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", @@ -247,13 +245,13 @@ } ], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", + "pattern = QiskitPattern(\n", " title=\"qaoa\", entrypoint=\"qaoa.py\", working_dir=\"./source_files/qaoa/\"\n", ")\n", "\n", - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { @@ -264,7 +262,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -305,11 +303,11 @@ { "data": { "text/plain": [ - "{'optimal_point': [3.6344739798886234,\n", - " 3.4759935906160773,\n", - " 5.693162784013941,\n", - " 2.701144211922929],\n", - " 'optimal_value': -3.293924670389971}" + "{'optimal_point': [3.6344694882728,\n", + " 1.9051953195174722,\n", + " 2.5515024534598467,\n", + " 2.701136388288486],\n", + " 'optimal_value': -3.2939248998743915}" ] }, "execution_count": 8, diff --git a/docs/getting_started/basic/01_running_program.ipynb b/docs/getting_started/basic/01_running_program.ipynb index 3e7b5014c..59856aaf3 100644 --- a/docs/getting_started/basic/01_running_program.ipynb +++ b/docs/getting_started/basic/01_running_program.ipynb @@ -5,18 +5,18 @@ "id": "66030e20-b384-4dcf-9c5f-7664f7ad1693", "metadata": {}, "source": [ - "# Running a program remotely\n", + "# Running a QiskitPattern remotely\n", "\n", - "In this tutorial, we will write a basic program using Quantum Serverless. We will show how to run the program remotely and retrieve the results from the serverless client.\n", + "In this tutorial, we will write a basic QiskitPattern using Quantum Serverless. We will show how to run the pattern remotely and retrieve the results from the serverless client.\n", "\n", - "### Writing the Program\n", + "### Writing the QiskitPattern\n", "\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", + "First, we need to write the pattern code and save it to a file called [pattern.py](./source_files/pattern.py). This pattern 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", + "The code for the pattern is shown below:\n", "\n", "```python\n", - "# source_files/program.py\n", + "# source_files/pattern.py\n", "\n", "from qiskit import QuantumCircuit\n", "from qiskit.primitives import Sampler\n", @@ -24,7 +24,7 @@ "from quantum_serverless import save_result\n", "\n", "# all print statement will be available in job logs\n", - "print(\"Running program 1...\")\n", + "print(\"Running pattern...\")\n", "\n", "# creating circuit\n", "circuit = QuantumCircuit(2)\n", @@ -36,22 +36,22 @@ "sampler = Sampler()\n", "quasi_dists = sampler.run(circuit).result().quasi_dists\n", "\n", - "# save results of program execution, \n", + "# save results of pattern execution, \n", "# which will be accessible by calling `.result()`\n", "save_result(quasi_dists)\n", - "print(\"Completed running program 1.\")\n", + "print(\"Completed running pattern.\")\n", "```\n", "\n", - "### Deploying the Program\n", + "### Deploying the QiskitPattern\n", "\n", - "To run the program, we need to import the necessary classes and configure them. One of these classes is QuantumServerless, which is a client class for interacting with compute resources.\n", + "To run the pattern, we need to import the necessary classes and configure them. One of these classes is QuantumServerless, which is a client class for interacting with compute resources.\n", "\n", - "QuantumServerless takes a [BaseProvider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.BaseProvider.html) instance as a constructor argument. The provider stores configuration information about our compute resources, such as where they are located and how to connect to them. In this example, we will use a provider that is connected to a local Docker Compose setup. In this case, it allows us to run the program locally on our machine. If you want to run the program elsewhere, you will need to provide the corresponding host and authentication details." + "QuantumServerless takes a [BaseProvider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.BaseProvider.html) instance as a constructor argument. The provider stores configuration information about our compute resources, such as where they are located and how to connect to them. In this example, we will use a provider that is connected to a local Docker Compose setup. In this case, it allows us to run the pattern locally on our machine. If you want to run the pattern elsewhere, you will need to provide the corresponding host and authentication details." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 9, "id": "81dd7807-7180-4b87-bbf9-832b7cf29d69", "metadata": {}, "outputs": [], @@ -70,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 10, "id": "acdec789-4967-48ee-8f6c-8d2b0ff57e91", "metadata": {}, "outputs": [ @@ -80,7 +80,7 @@ "" ] }, - "execution_count": 2, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -102,7 +102,7 @@ "source": [ "\n", "\n", - "[Program](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Program.html#quantum_serverless.core.Program) accepts couple of required parameters:\n", + "`QiskitPattern` accepts couple of required parameters:\n", "\n", "- title - name of the program\n", "- entrypoint - name of python file you want to execute\n", @@ -113,29 +113,29 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 17, "id": "d51df836-3f22-467c-b637-5803145d5d8a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'my-first-program'" + "'my-first-pattern'" ] }, - "execution_count": 50, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", - " title=\"my-first-program\", entrypoint=\"program.py\", working_dir=\"./source_files/\"\n", + "pattern = QiskitPattern(\n", + " title=\"my-first-pattern\", entrypoint=\"pattern.py\", working_dir=\"./source_files/\"\n", ")\n", "\n", - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { @@ -143,30 +143,30 @@ "id": "3e5326e2-9ff8-48e8-a8a9-18716633fd01", "metadata": {}, "source": [ - "### Running the Program\n", + "### Running the QiskitPattern\n", "\n", - "After deploying the Program, we can run the program by calling the `run()` method of the [ServerlessProvider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.ServerlessProvider.html#quantum_serverless.core.ServerlessProvider) object:" + "After deploying the QiskitPattern, we can run the pattern by calling the `run()` method of the [ServerlessProvider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.ServerlessProvider.html#quantum_serverless.core.ServerlessProvider) object:" ] }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 18, "id": "d55e3b06-8ab4-42d6-ad47-0f974d8d2247", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 51, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "job = serverless.run(\"my-first-program\")\n", + "job = serverless.run(\"my-first-pattern\")\n", "job" ] }, @@ -175,12 +175,12 @@ "id": "39ee31d2-3553-4e19-bcb9-4cccd0df0e4c", "metadata": {}, "source": [ - "[Job](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Job.html#quantum_serverless.core.Job) instances have a `status()` method to check status of program execution." + "[Job](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Job.html#quantum_serverless.core.Job) instances have a `status()` method to check status of pattern execution." ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 19, "id": "cc7ccea6-bbae-4184-ba7f-67b6c20a0b0b", "metadata": {}, "outputs": [ @@ -190,7 +190,7 @@ "'QUEUED'" ] }, - "execution_count": 52, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -204,12 +204,12 @@ "id": "f496adbe-3d82-4aad-b86b-6adb3b9d287d", "metadata": {}, "source": [ - "`Job` instances also have a `result()` method for retrieving results. The `result()` method will not return until the job is done running the program." + "`Job` instances also have a `result()` method for retrieving results. The `result()` method will not return until the job is done running the pattern." ] }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 20, "id": "1dc78690-f61a-4dfe-bc0e-7007cf561a5b", "metadata": {}, "outputs": [ @@ -219,7 +219,7 @@ "[{'0': 0.4999999999999999, '3': 0.4999999999999999}]" ] }, - "execution_count": 53, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -233,12 +233,12 @@ "id": "719d3572", "metadata": {}, "source": [ - "To inspect the logs from a program, access them from the ``Job`` instance." + "To inspect the logs from a pattern, access them from the ``Job`` instance." ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 21, "id": "eb5ec85f", "metadata": {}, "outputs": [ @@ -248,8 +248,8 @@ "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...\n", - "Completed running program.\n", + "Running pattern...\n", + "Completed running pattern.\n", "\n" ] } @@ -270,10 +270,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "f24023e1-6ce4-481e-b43d-3e19bff81d57", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "2a03914d42184f73ba897535e1f5d1a3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Tab(children=(GridspecLayout(children=(Output(layout=Layout(grid_area='widget001')), Output(layout=Layout(grid…" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "serverless.widget()" ] diff --git a/docs/getting_started/basic/02_arguments_and_results.ipynb b/docs/getting_started/basic/02_arguments_and_results.ipynb index e08891517..d2bb91cbe 100644 --- a/docs/getting_started/basic/02_arguments_and_results.ipynb +++ b/docs/getting_started/basic/02_arguments_and_results.ipynb @@ -4,24 +4,24 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Passing input arguments to your program\n", + "# Passing input arguments to your QiskitPattern\n", "\n", - "In this document, we will learn how to pass arguments to our program.\n", + "In this document, we will learn how to pass arguments to our pattern.\n", "\n", - "Let's create another file with our program [./source_files/program_with_arguments.py](./source_files/program_with_arguments.py). \n", + "Let's create another file with our pattern [./source_files/pattern_with_arguments.py](./source_files/pattern_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", + "Instead of having the circuit defined inside the pattern (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", + "Here is the pattern:\n", "\n", "```python\n", - "# source_files/program_with_arguments.py\n", + "# source_files/pattern_with_arguments.py\n", "\n", "from quantum_serverless import get_arguments, save_result\n", "\n", "from qiskit.primitives import Sampler\n", "\n", - "# get all arguments passed to this program\n", + "# get all arguments passed to this pattern\n", "arguments = get_arguments()\n", "\n", "# get specific argument that we are interested in\n", @@ -33,20 +33,20 @@ "\n", "print(f\"Quasi distribution: {quasi_dists[0]}\")\n", "\n", - "# saving results of a program\n", + "# saving results of a pattern\n", "save_result({\n", " \"quasi_dists\": quasi_dists[0]\n", "})\n", "```\n", "\n", - "As you can see, the circuit construction is not inside the program anymore. Instead, we parse the arguments by calling the [get_arguments](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.serializers.get_arguments.html#quantum_serverless.serializers.get_arguments) function." + "As you can see, the circuit construction is not inside the pattern anymore. Instead, we parse the arguments by calling the [get_arguments](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.serializers.get_arguments.html#quantum_serverless.serializers.get_arguments) function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "First, we will create circuit that we want to pass as an argument to the program." + "First, we will create circuit that we want to pass as an argument to the pattern." ] }, { @@ -135,46 +135,46 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'program-with-arguments'" + "'pattern-with-arguments'" ] }, - "execution_count": 4, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", - " title=\"program-with-arguments\",\n", - " entrypoint=\"program_with_arguments.py\",\n", + "pattern = QiskitPattern(\n", + " title=\"pattern-with-arguments\",\n", + " entrypoint=\"pattern_with_arguments.py\",\n", " working_dir=\"./source_files/\",\n", ")\n", "\n", - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Run the program using the `run` method and by passing an `arguments` parameter in form of a dictionary with the \"circuit\" string as a key and our `QuantumCircuit` as the value" + "Run the pattern using the `run` method and by passing an `arguments` parameter in form of a dictionary with the \"circuit\" string as a key and our `QuantumCircuit` as the value" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "job = serverless.run(\"program-with-arguments\", arguments={\"circuit\": circuit})" + "job = serverless.run(\"pattern-with-arguments\", arguments={\"circuit\": circuit})" ] }, { @@ -186,7 +186,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -195,7 +195,7 @@ "{'quasi_dists': {'0': 0.4999999999999999, '3': 0.4999999999999999}}" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } diff --git a/docs/getting_started/basic/03_dependencies.ipynb b/docs/getting_started/basic/03_dependencies.ipynb index 0f7b88d16..948880aec 100644 --- a/docs/getting_started/basic/03_dependencies.ipynb +++ b/docs/getting_started/basic/03_dependencies.ipynb @@ -6,18 +6,18 @@ "tags": [] }, "source": [ - "# Using python packages with your programs\n", + "# Using python packages with your QiskitPattern\n", "\n", - "In this document, we will learn how to install custom dependencies to your program.\n", + "In this document, we will learn how to install custom dependencies to your pattern.\n", "\n", - "Let's create another file with our new program [./source_files/program_with_dependencies.py](./source_files/program_with_dependencies.py). \n", + "Let's create another file with our new pattern [./source_files/pattern_with_dependencies.py](./source_files/pattern_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_with_dependencies.py\n", + "# source_files/pattern_with_dependencies.py\n", "\n", "from quantum_serverless import get_arguments, save_result\n", "\n", @@ -42,7 +42,7 @@ "\n", "print(f\"Quasi distribution: {quasi_dists[0]}\")\n", "\n", - "# saving results of a program\n", + "# saving results of a pattern\n", "save_result({\n", " \"quasi_dists\": quasi_dists[0]\n", "})\n", @@ -58,7 +58,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To install a custom dependency that our program might use we need to pass it as the `dependencies` argument to the [Program](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Program.html#quantum_serverless.core.Program) class constructor. \n", + "To install a custom dependency that our pattern might use we need to pass it as the `dependencies` argument to the `QiskitPattern` class constructor. \n", "You can pass multiple dependencies and specify versions. " ] }, @@ -70,11 +70,11 @@ }, "outputs": [], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", - " title=\"program-with-dependencies\",\n", - " entrypoint=\"program_with_dependencies.py\",\n", + "pattern = QiskitPattern(\n", + " title=\"pattern-with-dependencies\",\n", + " entrypoint=\"pattern_with_dependencies.py\",\n", " working_dir=\"./source_files/\",\n", " dependencies=[\"qiskit-experiments==0.5.2\"],\n", ")" @@ -135,7 +135,7 @@ { "data": { "text/plain": [ - "'program-with-dependencies'" + "'pattern-with-dependencies'" ] }, "execution_count": 4, @@ -144,7 +144,7 @@ } ], "source": [ - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { @@ -153,7 +153,7 @@ "metadata": {}, "outputs": [], "source": [ - "job = serverless.run(\"program-with-dependencies\", arguments={\"circuit\": circuit})" + "job = serverless.run(\"pattern-with-dependencies\", arguments={\"circuit\": circuit})" ] }, { @@ -184,7 +184,7 @@ { "data": { "text/plain": [ - "{'quasi_dists': {'0': 1.0}}" + "{'quasi_dists': {'0': 0.552393590859813, '1': 0.4476064091401866}}" ] }, "execution_count": 7, diff --git a/docs/getting_started/basic/04_distributed_workloads.ipynb b/docs/getting_started/basic/04_distributed_workloads.ipynb index d1bbb5159..ae24f478a 100644 --- a/docs/getting_started/basic/04_distributed_workloads.ipynb +++ b/docs/getting_started/basic/04_distributed_workloads.ipynb @@ -4,14 +4,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Parallel workflows in programs\n", + "# Parallel workflows in QiskitPatterns\n", "\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", + "In this document, we will learn how to run distributed workflows inside a pattern. 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_with_parallel_workflow.py](./source_files/program_with_parallel_workflow.py). \n", + "Let's take a look at the pattern file [./source_files/pattern_with_parallel_workflow.py](./source_files/pattern_with_parallel_workflow.py). \n", "\n", "```python\n", - "# source_files/program_with_parallel_workflow.py\n", + "# source_files/pattern_with_parallel_workflow.py\n", "\n", "from quantum_serverless import get_arguments, save_result, distribute_task, get\n", "\n", @@ -44,15 +44,15 @@ "})\n", "```\n", "\n", - "There are a lot of new concepts introduced in this program, so let's go over them in more detail:\n", + "There are a lot of new concepts introduced in this pattern, so let's go over them in more detail:\n", "\n", - "The [distribute_task](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.distribute_task.html#quantum_serverless.core.distribute_task) decorator converts a function into a distributed task. This means that the function will be executed on compute resources asynchronously and in parallel to the main context of the program.\n", + "The [distribute_task](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.distribute_task.html#quantum_serverless.core.distribute_task) decorator converts a function into a distributed task. This means that the function will be executed on compute resources asynchronously and in parallel to the main context of the pattern.\n", "\n", "When you call a converted function, it will return a reference to the function execution instead of the result. In order to get the result back, you need to call the [get](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.get.html#quantum_serverless.core.get) function on the function reference. `get` will wait until the function is finished and return the result of the function execution.\n", "\n", - "In the program above, we have applied the `distribute_task` decorator to the `distributed_sample` function. This function takes a `QuantumCircuit` as input and returns the quasi distribution for that circuit.\n", + "In the pattern above, we have applied the `distribute_task` decorator to the `distributed_sample` function. This function takes a `QuantumCircuit` as input and returns the quasi distribution for that circuit.\n", "\n", - "After we have defined the `distributed_sample` function, we read the circuits from the program arguments using the [get_arguments](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.serializers.get_arguments.html#quantum_serverless.serializers.get_arguments) function. We then call the `distributed_sample` function for each of the circuits, which creates a reference to each of the function executions.\n", + "After we have defined the `distributed_sample` function, we read the circuits from the pattern arguments using the [get_arguments](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.serializers.get_arguments.html#quantum_serverless.serializers.get_arguments) function. We then call the `distributed_sample` function for each of the circuits, which creates a reference to each of the function executions.\n", "\n", "These function executions will run in parallel on compute resources, and we get task references as the return type. We store these task references in the `sample_task_references` list.\n", "\n", @@ -60,7 +60,7 @@ "\n", "Once we have the results, we can save them using the [save_result](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.save_result.html#quantum_serverless.core.save_result) function.\n", "\n", - "Essentially, this program reads the circuits from the program arguments, executes the `distributed_sample` function on each circuit in parallel, collects the results from the function executions, and saves the results." + "Essentially, this pattern reads the circuits from the pattern arguments, executes the `distributed_sample` function on each circuit in parallel, collects the results from the function executions, and saves the results." ] }, { @@ -104,7 +104,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's create a list of random circuits which we will be passed as arguments to the program." + "Let's create a list of random circuits which we will be passed as arguments to the pattern." ] }, { @@ -115,9 +115,9 @@ { "data": { "text/plain": [ - "[,\n", - " ,\n", - " ]" + "[,\n", + " ,\n", + " ]" ] }, "execution_count": 2, @@ -137,61 +137,61 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Run program as usual, but pass the circuits in as a keyword argument, `circuits`." + "Run pattern as usual, but pass the circuits in as a keyword argument, `circuits`." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'program-with-parallel-workflow'" + "'pattern-with-parallel-workflow'" ] }, - "execution_count": 4, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", - " title=\"program-with-parallel-workflow\",\n", - " entrypoint=\"program_with_parallel_workflow.py\",\n", + "pattern = QiskitPattern(\n", + " title=\"pattern-with-parallel-workflow\",\n", + " entrypoint=\"pattern_with_parallel_workflow.py\",\n", " working_dir=\"./source_files/\",\n", ")\n", "\n", - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "job = serverless.run(\"program-with-parallel-workflow\", arguments={\"circuits\": circuits})\n", + "job = serverless.run(\"pattern-with-parallel-workflow\", arguments={\"circuits\": circuits})\n", "job" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -200,7 +200,7 @@ "'QUEUED'" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -211,18 +211,18 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'results': [{'1': 0.4999999999999999, '3': 0.4999999999999999},\n", - " {'0': 1.0},\n", - " {'0': 0.25, '1': 0.2499999999999999, '2': 0.25, '3': 0.25}]}" + "{'results': [{'0': 0.3712824936292008, '3': 0.6287175063707992},\n", + " {'0': 0.6959127899870515, '2': 0.3040872100129484},\n", + " {'0': 0.4999999999999999, '1': 0.5000000000000001}]}" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } diff --git a/docs/getting_started/basic/05_retrieving_past_results.ipynb b/docs/getting_started/basic/05_retrieving_past_results.ipynb index 1e2da0d0f..d1c3217d1 100644 --- a/docs/getting_started/basic/05_retrieving_past_results.ipynb +++ b/docs/getting_started/basic/05_retrieving_past_results.ipynb @@ -7,7 +7,7 @@ "source": [ "# Retrieving Results from Old Jobs\n", "\n", - "In this tutorial, we will run two programs and then retrieve the results of each program using the job IDs and the serverless client." + "In this tutorial, we will run two patterns and then retrieve the results of each pattern using the job IDs and the serverless client." ] }, { @@ -55,7 +55,7 @@ "id": "e076c12a-b372-4335-bd4a-7e3e24fcca73", "metadata": {}, "source": [ - "Run two programs in parallel." + "Run two patterns in parallel." ] }, { @@ -65,15 +65,15 @@ "metadata": {}, "outputs": [], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", - " title=\"program-to-fetch-results\", entrypoint=\"program.py\", working_dir=\"./source_files/\"\n", + "pattern = QiskitPattern(\n", + " title=\"pattern-to-fetch-results\", entrypoint=\"pattern.py\", working_dir=\"./source_files/\"\n", ")\n", - "serverless.upload(program)\n", + "serverless.upload(pattern)\n", "\n", - "job1 = serverless.run(\"program-to-fetch-results\")\n", - "job2 = serverless.run(\"program-to-fetch-results\")" + "job1 = serverless.run(\"pattern-to-fetch-results\")\n", + "job2 = serverless.run(\"pattern-to-fetch-results\")" ] }, { @@ -81,7 +81,7 @@ "id": "59a49dc9-cbad-4c05-a831-b0e9dc882ca0", "metadata": {}, "source": [ - "Retrieve the job IDs for each of the running programs." + "Retrieve the job IDs for each of the running patterns." ] }, { @@ -177,7 +177,7 @@ "id": "24942f00-680e-4cea-b0e7-bc75b19565fe", "metadata": {}, "source": [ - "To inspect the logs from a program, access them from the [Job](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Job.html#quantum_serverless.core.Job) instance." + "To inspect the logs from a pattern, access them from the [Job](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.Job.html#quantum_serverless.core.Job) instance." ] }, { @@ -192,8 +192,8 @@ "text": [ "Job 1 logs: 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...\n", - "Completed running program.\n", + "Running pattern...\n", + "Completed running pattern.\n", "\n" ] } @@ -207,7 +207,7 @@ "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", + "To get a list of all previously executed patterns, 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." ] }, @@ -220,8 +220,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 8, diff --git a/docs/getting_started/basic/source_files/program.py b/docs/getting_started/basic/source_files/pattern.py similarity index 88% rename from docs/getting_started/basic/source_files/program.py rename to docs/getting_started/basic/source_files/pattern.py index ed50a2499..fcc9d8629 100644 --- a/docs/getting_started/basic/source_files/program.py +++ b/docs/getting_started/basic/source_files/pattern.py @@ -4,7 +4,7 @@ from quantum_serverless import save_result # all print statement will be available in job logs -print("Running program...") +print("Running pattern...") # creating circuit circuit = QuantumCircuit(2) @@ -19,4 +19,4 @@ # saves results of program execution, # which will be accessible by calling `.result()` save_result(quasi_dists) -print("Completed running program.") +print("Completed running pattern.") diff --git a/docs/getting_started/basic/source_files/program_with_arguments.py b/docs/getting_started/basic/source_files/pattern_with_arguments.py similarity index 100% rename from docs/getting_started/basic/source_files/program_with_arguments.py rename to docs/getting_started/basic/source_files/pattern_with_arguments.py diff --git a/docs/getting_started/basic/source_files/program_with_dependencies.py b/docs/getting_started/basic/source_files/pattern_with_dependencies.py similarity index 100% rename from docs/getting_started/basic/source_files/program_with_dependencies.py rename to docs/getting_started/basic/source_files/pattern_with_dependencies.py diff --git a/docs/getting_started/basic/source_files/program_with_parallel_workflow.py b/docs/getting_started/basic/source_files/pattern_with_parallel_workflow.py similarity index 100% rename from docs/getting_started/basic/source_files/program_with_parallel_workflow.py rename to docs/getting_started/basic/source_files/pattern_with_parallel_workflow.py diff --git a/docs/getting_started/experimental/file_download.ipynb b/docs/getting_started/experimental/file_download.ipynb index ffacea7df..c1604d576 100644 --- a/docs/getting_started/experimental/file_download.ipynb +++ b/docs/getting_started/experimental/file_download.ipynb @@ -7,14 +7,14 @@ "source": [ "# File download (Experimental)\n", "\n", - "In this tutorial we will describe a way to retrieve files produced by programs.\n", + "In this tutorial we will describe a way to retrieve files produced by patterns.\n", "\n", - "This function provides a way to download files produced by programs during execution. All you need is to call `QuantumServerless.download` function and pass `tar` file name to start downloading the file. Or you can list all available file to you by calling `QuantumServerless.files`.\n", + "This function provides a way to download files produced by patterns during execution. All you need is to call `QuantumServerless.download` function and pass `tar` file name to start downloading the file. Or you can list all available file to you by calling `QuantumServerless.files`.\n", "\n", "Limitations:\n", "\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", + "- `tar` file should be saved in `/data` directory during your pattern execution to be visible by `.files()` method call\n", "- only `/data` directory is supported, `/data/other_folder` will not be visible\n", "\n", "> ⚠ This interface is experimental, therefore it is subjected to breaking changes.\n", @@ -41,7 +41,7 @@ ], "source": [ "import os\n", - "from quantum_serverless import ServerlessProvider, Program\n", + "from quantum_serverless import ServerlessProvider, QiskitPattern\n", "\n", "serverless = ServerlessProvider(\n", " username=\"user\",\n", @@ -56,7 +56,7 @@ "id": "fc30a74a-2100-40b8-a283-30bd51875b45", "metadata": {}, "source": [ - "Let's create a program to write `tar` file into `/data` folder" + "Let's create a pattern to write `tar` file into `/data` folder" ] }, { @@ -77,11 +77,11 @@ } ], "source": [ - "program = Program(\n", + "pattern = QiskitPattern(\n", " title=\"file-producer\", entrypoint=\"produce_files.py\", working_dir=\"./source_files/\"\n", ")\n", "\n", - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { @@ -93,7 +93,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 3, diff --git a/docs/getting_started/experimental/running_programs_using_decorators.ipynb b/docs/getting_started/experimental/running_programs_using_decorators.ipynb index deebb6e20..9efe5dfb2 100644 --- a/docs/getting_started/experimental/running_programs_using_decorators.ipynb +++ b/docs/getting_started/experimental/running_programs_using_decorators.ipynb @@ -5,17 +5,17 @@ "id": "f6fb114d-af27-4a89-83b4-b3806dfa8c1a", "metadata": {}, "source": [ - "# Running program using decorators (Experimental)\n", + "# Running QiskitPattern using decorators (Experimental)\n", "\n", - "In this tutorial we will describe alternative way (interface) of running your programs.\n", + "In this tutorial we will describe alternative way (interface) of running your patterns.\n", "\n", - "This new interface provides a way to define program as python function and run it in a single file, using `@distribute_program` decorator.\n", - "All you need to do is annotate function with `@distribute_program` decorator and call it. \n", + "This new interface provides a way to define pattern as python function and run it in a single file, using `@distribute_qiskit_pattern` decorator.\n", + "All you need to do is annotate function with `@distribute_qiskit_pattern` decorator and call it. \n", "As a result of the call of the function you will get `Job` handle to check it's progress like we did in previous tutorials.\n", "\n", "Limitations of this interface:\n", "\n", - "- 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", + "- Functions decorated with distribute_qiskit_pattern, can only accept named arguments for now. E.g do not use `my_pattern(argument1)`, instead specify name of the argument `my_pattern(argument1=argument1)`\n", "- 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", "- 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", @@ -26,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "2bf315de-a4fe-429b-9fdd-7a2f2efe2278", "metadata": {}, "outputs": [ @@ -60,8 +60,8 @@ "source": [ "## Hello, Qiskit!\n", "\n", - "Let's create simpliest program by writing a funtion `hello_qiskit` and annotating it with `@distribute_program` decorator. \n", - "The ``distribute_program`` decorator accepts a [BaseProvider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.BaseProvider.html) instance for the ``provider`` argument. Other arguments are `dependencies` to specify extra packages to install during execution and `working_dir` to specify working directory that will be shiped for remote execution if needed." + "Let's create simpliest pattern by writing a funtion `hello_qiskit` and annotating it with `@distribute_qiskit_pattern` decorator. \n", + "The ``distribute_qiskit_pattern`` decorator accepts a [BaseProvider](https://qiskit-extensions.github.io/quantum-serverless/stubs/quantum_serverless.core.BaseProvider.html) instance for the ``provider`` argument. Other arguments are `dependencies` to specify extra packages to install during execution and `working_dir` to specify working directory that will be shiped for remote execution if needed." ] }, { @@ -73,7 +73,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -85,10 +85,10 @@ "from qiskit import QuantumCircuit\n", "from qiskit.primitives import Sampler\n", "\n", - "from quantum_serverless import distribute_program, distribute_task, get, save_result\n", + "from quantum_serverless import distribute_qiskit_pattern, distribute_task, get, save_result\n", "\n", "\n", - "@distribute_program(provider)\n", + "@distribute_qiskit_pattern(provider)\n", "def hello_qiskit():\n", " circuit = QuantumCircuit(2)\n", " circuit.h(0)\n", @@ -132,9 +132,9 @@ "id": "d5192fa3-70a7-4b22-b2de-04d4b1816323", "metadata": {}, "source": [ - "## Program with distributed tasks\n", + "## QiskitPattern with distributed tasks\n", "\n", - "As in previous examples you can define distributed tasks and call them within a program." + "As in previous examples you can define distributed tasks and call them within a pattern." ] }, { @@ -146,7 +146,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 4, @@ -167,8 +167,8 @@ " return Sampler().run(circuit).result().quasi_dists\n", "\n", "\n", - "@distribute_program(provider)\n", - "def program_with_distributed_tasks(circuits):\n", + "@distribute_qiskit_pattern(provider)\n", + "def pattern_with_distributed_tasks(circuits):\n", " sample_task_references = [distributed_sample(circuit) for circuit in circuits]\n", " results = get(sample_task_references)\n", " print(results)\n", @@ -180,7 +180,7 @@ " circuit.measure_all()\n", " circuits.append(circuit)\n", "\n", - "job = program_with_distributed_tasks(circuits=circuits)\n", + "job = pattern_with_distributed_tasks(circuits=circuits)\n", "job" ] }, @@ -196,12 +196,12 @@ "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", - "2023-08-28 07:03:09,887\tINFO worker.py:1313 -- Using address 172.19.0.2:6379 set in the environment variable RAY_ADDRESS\n", - "2023-08-28 07:03:09,887\tINFO worker.py:1431 -- Connecting to existing Ray cluster at address: 172.19.0.2:6379...\n", - "2023-08-28 07:03:09,906\tINFO worker.py:1612 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32m172.19.0.2:8265 \u001b[39m\u001b[22m\n", - "\u001b[2m\u001b[36m(pid=839)\u001b[0m OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\n", - "[[{0: 1.0}], [{0: 0.71546027866628, 2: 0.2845397213337199}], [{0: 0.1898694337207903, 1: 0.4050652831396046, 3: 0.4050652831396046}]]\n", - "\u001b[2m\u001b[36m(pid=841)\u001b[0m OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\u001b[32m [repeated 5x across cluster] (Ray deduplicates logs by default. Set RAY_DEDUP_LOGS=0 to disable log deduplication, or see https://docs.ray.io/en/master/ray-observability/ray-logging.html#log-deduplication for more options.)\u001b[0m\n", + "2023-10-27 12:46:57,031\tINFO worker.py:1329 -- Using address 10.42.0.245:6379 set in the environment variable RAY_ADDRESS\n", + "2023-10-27 12:46:57,032\tINFO worker.py:1458 -- Connecting to existing Ray cluster at address: 10.42.0.245:6379...\n", + "2023-10-27 12:46:57,063\tINFO worker.py:1633 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32m10.42.0.245:8265 \u001b[39m\u001b[22m\n", + "\u001b[2m\u001b[36m(pid=119, ip=10.42.0.246)\u001b[0m OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\n", + "[[{0: 1.0}], [{0: 1.0}], [{0: 0.065352163370718, 1: 0.434647836629282, 2: 0.065352163370718, 3: 0.434647836629282}]]\n", + "\u001b[2m\u001b[36m(pid=119, ip=10.42.0.246)\u001b[0m OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\u001b[32m [repeated 3x across cluster] (Ray deduplicates logs by default. Set RAY_DEDUP_LOGS=0 to disable log deduplication, or see https://docs.ray.io/en/master/ray-observability/ray-logging.html#log-deduplication for more options.)\u001b[0m\n", "\n" ] } @@ -216,65 +216,43 @@ "id": "ca90f9be-aac9-4ed1-8384-463698914994", "metadata": {}, "source": [ - "## Program with local modules/folders\n", + "## QiskitPattern with local modules/folders\n", "\n", - "Situation with local folders is a little bit trickier. In order to make local imports work in remote execution of a program we need to specify `working_dir` argument for `distribute_program` decorator. It will tell quantum serverless to ship all content of current folder to remote cluster, which will make local folders discoverable by Python interpreter during remote execution.\n", + "Situation with local folders is a little bit trickier. In order to make local imports work in remote execution of a pattern we need to specify `working_dir` argument for `distribute_qiskit_pattern` decorator. It will tell quantum serverless to ship all content of current folder to remote cluster, which will make local folders discoverable by Python interpreter during remote execution.\n", "\n", "In this example we will use local folder `source_files` with `circuit_utils.py` file, which has implementation of `create_hello_world_circuit` function. " ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "8acd98bc-3443-447a-b8a1-c5e34a292f3b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import os\n", - "from quantum_serverless import distribute_program, distribute_task, get, save_result\n", + "from quantum_serverless import distribute_qiskit_pattern, distribute_task, get, save_result\n", "from qiskit.primitives import Sampler\n", "\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", + "@distribute_qiskit_pattern(provider, working_dir=\"./\")\n", + "def my_pattern_with_modules():\n", " quasi_dists = Sampler().run(create_hello_world_circuit()).result().quasi_dists\n", " return {\"quasi_dists\": quasi_dists}\n", "\n", "\n", - "job = my_program_with_modules()\n", + "job = my_pattern_with_modules()\n", "job" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "258c7495-3c4f-4dbd-8fe0-1bc46f881cbe", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'{\"quasi_dists\": [{\"0\": 0.4999999999999999, \"3\": 0.4999999999999999}]}'" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "job.result()" ] diff --git a/docs/migration/migration_from_qiskit_runtime_programs.ipynb b/docs/migration/migration_from_qiskit_runtime_programs.ipynb index 25c1be32c..82dd3bd75 100644 --- a/docs/migration/migration_from_qiskit_runtime_programs.ipynb +++ b/docs/migration/migration_from_qiskit_runtime_programs.ipynb @@ -7,7 +7,7 @@ "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", + "This tutorial will be a demonstation of converting your custom Qiskit Runtime Program into a Quantum Serverless `QiskitPattern`.\n", "\n", "If you were using Qiskit Runtime Programs before, your code probably looks similar to the following example:\n", "\n", @@ -45,7 +45,7 @@ "```\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", + "All Qiskit Runtime Programs have a `main` method which accepts `backend`, `user_messenger` and `**kwargs`. This method is not required for Quantum Serverless patterns.\n", "\n", "Quantum Serverless handles backends, logging, and input arguments a bit differently than Qiskit Runtime:\n", "\n", @@ -54,15 +54,15 @@ "- `user_messenger` were used in Qiskit Runtime Programs to facilitate retrieving logs from the program. Quantum Serverless does not\n", " require passing such an object. Instead, all contents of `stdout` (e.g. print statements, logging messages) will be provided to the\n", " user via the 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,\n", - " 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", + "- `**kwargs` was a variable used to capture program inputs from the user. Users should now input their arguments to the `ServerlessProvider.run` method,\n", + " and the arguments should be retrieved within the pattern using the `get_arguments` function from Quantum Serverless.\n", + "- To save the results of a pattern, the `save_result` function should be used. It accepts a python dictionary and can be accessed via the job handler.\n", "\n", - "Let's use the guidelines above to transform the above Qiskit Runtime Program into a Quantum Serverless Program.\n", + "Let's use the guidelines above to transform the above Qiskit Runtime Program into a Quantum Serverless QiskitPattern.\n", "\n", "```python\n", - "# migrated_program.py\n", - "\"\"\"A sample runtime program that submits random circuits for user-specified iterations.\"\"\"\n", + "# migrated_pattern.py\n", + "\"\"\"A sample runtime pattern that submits random circuits for user-specified iterations.\"\"\"\n", "\n", "import random\n", "\n", @@ -91,26 +91,26 @@ "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." + "Let's save this code as `./src/migrated_pattern.py` and execute it using the `QiskitPattern` class from the `quantum_serverless` package." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "id": "50fb2a64-751d-40fb-bac8-db49dc92fbca", "metadata": {}, "outputs": [], "source": [ - "from quantum_serverless import Program\n", + "from quantum_serverless import QiskitPattern\n", "\n", - "program = Program(\n", - " title=\"migrated-program\", entrypoint=\"migrated_program.py\", working_dir=\"./src/\"\n", + "pattern = QiskitPattern(\n", + " title=\"migrated-pattern\", entrypoint=\"migrated_pattern.py\", working_dir=\"./src/\"\n", ")" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "id": "162c482e-8f86-4224-a9b9-f6567b34acf4", "metadata": {}, "outputs": [ @@ -120,7 +120,7 @@ "" ] }, - "execution_count": 5, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -140,23 +140,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "0e88737d-a94c-487a-881c-c884ba0a3099", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'migrated-program'" + "'migrated-pattern'" ] }, - "execution_count": 6, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "serverless.upload(program)" + "serverless.upload(pattern)" ] }, { @@ -164,34 +164,34 @@ "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." + "While Qiskit Runtime programs required users to upload their program and call it in two separate steps, the ``QiskitPattern`` class allows users to send a job for remote execution in a single step." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "id": "9f6eddae-a889-4958-8f0a-7e9f8ec29800", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 7, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "job = serverless.run(\"migrated-program\", arguments={\"iterations\": 3})\n", + "job = serverless.run(\"migrated-pattern\", arguments={\"iterations\": 3})\n", "job" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "id": "2223b57b-1dbc-45c7-8fd6-8e2ebfb843aa", "metadata": {}, "outputs": [ @@ -201,7 +201,7 @@ "{'result': 'Hello, World!'}" ] }, - "execution_count": 8, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -212,7 +212,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 6, "id": "314e7716-8495-41e0-92dc-b2404ec860d4", "metadata": {}, "outputs": [ @@ -222,9 +222,9 @@ "text": [ "OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\n", "OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k\n", - "{'iteration': 0, 'dists': [{0: 0.0870879477472883, 1: 0.0924709553907342, 4: 0.0870879477472882, 5: 0.0924709553907341, 8: 0.0363341145102879, 9: 0.0341069823516897, 12: 0.0363341145102879, 13: 0.0341069823516897, 16: 0.0870879477472883, 17: 0.0924709553907342, 20: 0.0870879477472882, 21: 0.0924709553907341, 24: 0.0363341145102879, 25: 0.0341069823516897, 28: 0.0363341145102879, 29: 0.0341069823516897}]}\n", - "{'iteration': 1, 'dists': [{0: 0.1788234278657898, 4: 0.1788234278657898, 8: 0.0410003465204518, 12: 0.0410003465204518, 16: 0.22791926492318, 20: 0.22791926492318, 24: 0.0522569606905783, 28: 0.0522569606905783}]}\n", - "{'iteration': 2, 'dists': [{0: 0.1850255799964094, 1: 0.100389938487105, 4: 0.139108126852289, 5: 0.0754763546641966, 16: 0.1850255799964094, 17: 0.100389938487105, 20: 0.139108126852289, 21: 0.0754763546641966}]}\n", + "{'iteration': 0, 'dists': [{0: 3.11944954662e-05, 1: 1.7472255688e-06, 2: 0.0023491864962565, 3: 0.0001315795832142, 4: 3.11944954662e-05, 5: 1.7472255688e-06, 6: 0.0023491864962565, 7: 0.0001315795832142, 8: 0.0003717494511414, 9: 2.08219474781e-05, 10: 0.0279956055566758, 11: 0.0015680535014343, 12: 0.0003717494511414, 13: 2.08219474781e-05, 14: 0.0279956055566758, 15: 0.0015680535014343, 16: 0.0311265176657353, 17: 0.0017434180844706, 18: 0.0031482525298452, 19: 0.0001763358321658, 20: 0.0015223386227183, 21: 0.0313475971274875, 22: 0.000153975027715, 23: 0.003170613334296, 24: 0.3709393495626852, 25: 0.0207765731205209, 26: 0.0018349433509674, 27: 0.0377846715963741, 28: 0.0181419362290861, 29: 0.3735739864541202, 30: 0.0375181945574789, 31: 0.0021014203898626}]}\n", + "{'iteration': 1, 'dists': [{0: 0.0069643522753237, 2: 0.0019338542834274, 4: 0.0069643522753237, 6: 0.0019338542834274, 8: 0.1437387217328721, 10: 0.0399132226125896, 12: 0.1437387217328721, 14: 0.0399132226125896, 16: 0.0111201629603674, 18: 0.0030878355837216, 20: 0.0111201629603673, 22: 0.0030878355837216, 24: 0.2295113667710234, 26: 0.0637304837806736, 28: 0.2295113667710234, 30: 0.0637304837806736}]}\n", + "{'iteration': 2, 'dists': [{0: 0.1660856424846436, 1: 0.1169352848951222, 3: 0.1169352848951222, 4: 0.0001612756514029, 5: 0.0001135487328183, 7: 0.0001135487328183, 8: 0.0413427186633533, 9: 0.0291080102585333, 11: 0.0291080102585333, 12: 4.01453959743e-05, 13: 2.82650158392e-05, 15: 2.82650158392e-05, 16: 0.1660856424846435, 17: 0.1169352848951222, 19: 0.1169352848951222, 20: 0.0001612756514029, 21: 0.0001135487328183, 23: 0.0001135487328183, 24: 0.0413427186633533, 25: 0.0291080102585333, 27: 0.0291080102585333, 28: 4.01453959743e-05, 29: 2.82650158392e-05, 31: 2.82650158392e-05}]}\n", "\n" ] } diff --git a/docs/migration/src/migrated_program.py b/docs/migration/src/migrated_pattern.py similarity index 100% rename from docs/migration/src/migrated_program.py rename to docs/migration/src/migrated_pattern.py