Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V4: feat!: Use ExecutionOptions parameter to configure how jobs are submitted and retrieved from a QPU #1598

Merged
merged 8 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ rpcq = "^3.10.0"
pydantic = "^1.10.7"
networkx = ">=2.5"
importlib-metadata = { version = ">=3.7.3,<5", python = "<3.8" }
qcs-sdk-python = "0.9.1"
qcs-sdk-python = "0.10.0"
quil = "0.1.1"
tenacity = "^8.2.2"
types-python-dateutil = "^2.8.19"
Expand Down
2 changes: 2 additions & 0 deletions pyquil/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"AbstractCompiler",
"BenchmarkConnection",
"EncryptedProgram",
"ExecutionOptions",
"get_qc",
"list_quantum_computers",
"local_forest_runtime",
Expand All @@ -40,6 +41,7 @@
]

from qcs_sdk import QCSClient
from qcs_sdk.qpu.api import ExecutionOptions

from pyquil.api._benchmark import BenchmarkConnection
from pyquil.api._compiler import (
Expand Down
9 changes: 4 additions & 5 deletions pyquil/api/_qam.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
##############################################################################
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Generic, Mapping, Optional, TypeVar, Sequence, Union
from typing import Any, Generic, Mapping, Optional, TypeVar, Sequence, Union

import numpy as np
from pyquil.api._abstract_compiler import QuantumExecutable
Expand Down Expand Up @@ -55,6 +55,7 @@ def execute(
self,
executable: QuantumExecutable,
memory_map: Optional[MemoryMap] = None,
**kwargs: Any,
) -> T:
"""
Run an executable on a QAM, returning a handle to be used to retrieve
Expand All @@ -74,11 +75,9 @@ def get_result(self, execute_response: T) -> QAMExecutionResult:
"""

def run(
self,
executable: QuantumExecutable,
memory_map: Optional[MemoryMap] = None,
self, executable: QuantumExecutable, memory_map: Optional[MemoryMap] = None, **kwargs: Any
) -> QAMExecutionResult:
"""
Run an executable to completion on the QAM.
"""
return self.get_result(self.execute(executable, memory_map))
return self.get_result(self.execute(executable, memory_map, **kwargs))
41 changes: 32 additions & 9 deletions pyquil/api/_qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
##############################################################################
from dataclasses import dataclass
from collections import defaultdict
from typing import Dict, Optional, Union
from typing import Any, Dict, Optional, Union

import numpy as np
from numpy.typing import NDArray
Expand All @@ -28,7 +28,14 @@
MemoryReference,
)
from qcs_sdk import QCSClient
from qcs_sdk.qpu.api import submit, retrieve_results, ExecutionResult
from qcs_sdk.qpu.api import (
submit,
retrieve_results,
ConnectionStrategy,
ExecutionResult,
ExecutionOptions,
ExecutionOptionsBuilder,
)
from qcs_sdk.qpu.rewrite_arithmetic import build_patch_values


Expand Down Expand Up @@ -102,6 +109,7 @@ def alloc(spec: ParameterSpec) -> np.ndarray:
class QPUExecuteResponse:
job_id: str
_executable: EncryptedProgram
execution_options: Optional[ExecutionOptions]


class QPU(QAM[QPUExecuteResponse]):
Expand All @@ -113,7 +121,7 @@ def __init__(
timeout: float = 10.0,
client_configuration: Optional[QCSClient] = None,
endpoint_id: Optional[str] = None,
use_gateway: bool = True,
execution_options: Optional[ExecutionOptions] = None,
) -> None:
"""
A connection to the QPU.
Expand All @@ -134,20 +142,34 @@ def __init__(
self._last_results: Dict[str, np.ndarray] = {}
self._memory_results: Dict[str, Optional[np.ndarray]] = defaultdict(lambda: None)
self._quantum_processor_id = quantum_processor_id
self._endpoint_id = endpoint_id

self._use_gateway = use_gateway
if execution_options is None:
execution_options_builder = ExecutionOptionsBuilder.default()
if endpoint_id is not None:
execution_options_builder.connection_strategy(ConnectionStrategy.endpoint_id(endpoint_id))
execution_options = execution_options_builder.build()
self.execution_options = execution_options

@property
def quantum_processor_id(self) -> str:
"""ID of quantum processor targeted."""
return self._quantum_processor_id

def execute(self, executable: QuantumExecutable, memory_map: Optional[MemoryMap] = None) -> QPUExecuteResponse:
def execute(
self,
executable: QuantumExecutable,
memory_map: Optional[MemoryMap] = None,
execution_options: Optional[ExecutionOptions] = None,
**__: Any,
) -> QPUExecuteResponse:
"""
Enqueue a job for execution on the QPU. Returns a ``QPUExecuteResponse``, a
job descriptor which should be passed directly to ``QPU.get_result`` to retrieve
results.

:param:
execution_options: An optional `ExecutionOptions` enum that can be used
to configure how the job is submitted and retrieved from the QPU. If unset
`ExecutionOptions.default()` will be used.
MarquessV marked this conversation as resolved.
Show resolved Hide resolved
"""
executable = executable.copy()

Expand All @@ -165,11 +187,11 @@ def execute(self, executable: QuantumExecutable, memory_map: Optional[MemoryMap]
program=executable.program,
patch_values=patch_values,
quantum_processor_id=self.quantum_processor_id,
endpoint_id=self._endpoint_id,
client=self._client_configuration,
execution_options=execution_options or self.execution_options,
)

return QPUExecuteResponse(_executable=executable, job_id=job_id)
return QPUExecuteResponse(_executable=executable, job_id=job_id, execution_options=execution_options)

def get_result(self, execute_response: QPUExecuteResponse) -> QAMExecutionResult:
"""
Expand All @@ -180,6 +202,7 @@ def get_result(self, execute_response: QPUExecuteResponse) -> QAMExecutionResult
job_id=execute_response.job_id,
quantum_processor_id=self.quantum_processor_id,
client=self._client_configuration,
execution_options=execute_response.execution_options,
)

ro_sources = execute_response._executable.ro_sources
Expand Down
6 changes: 2 additions & 4 deletions pyquil/api/_quantum_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,7 @@ def to_compiler_isa(self) -> CompilerISA:
return self.compiler.quantum_processor.to_compiler_isa()

def run(
self,
executable: QuantumExecutable,
memory_map: Optional[MemoryMap] = None,
self, executable: QuantumExecutable, memory_map: Optional[MemoryMap] = None, **kwargs: Any
) -> QAMExecutionResult:
"""
Run a quil executable. All parameters in the executable must have values applied using
Expand All @@ -139,7 +137,7 @@ def run(
region for the run.
:return: execution result including readout data.
"""
return self.qam.run(executable, memory_map)
return self.qam.run(executable, memory_map, **kwargs)

def calibrate(self, experiment: Experiment) -> List[ExperimentResult]:
"""
Expand Down
3 changes: 2 additions & 1 deletion pyquil/api/_qvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# limitations under the License.
##############################################################################
from dataclasses import dataclass
from typing import Mapping, Optional, Sequence, Tuple
from typing import Any, Mapping, Optional, Sequence, Tuple

import numpy as np

Expand Down Expand Up @@ -123,6 +123,7 @@ def execute(
self,
executable: QuantumExecutable,
memory_map: Optional[MemoryMap] = None,
**__: Any,
) -> QVMExecuteResponse:
"""
Synchronously execute the input program to completion.
Expand Down
4 changes: 1 addition & 3 deletions pyquil/api/_wavefunction_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,7 @@ def run_and_measure(
trials,
qubits,
)
measured_qubits = qvm.api.run_and_measure(
request, options=QVMOptions(timeout_seconds=self.timeout) # type: ignore[call-arg]
)
measured_qubits = qvm.api.run_and_measure(request, options=QVMOptions(timeout_seconds=self.timeout))
return np.asarray(measured_qubits)

@staticmethod
Expand Down
8 changes: 2 additions & 6 deletions pyquil/pyqvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
##############################################################################
import logging
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Sequence, Type, Union
from typing import Dict, List, Optional, Sequence, Type, Union, Any

import numpy as np
from numpy.random.mtrand import RandomState
Expand Down Expand Up @@ -221,11 +221,7 @@ def _extract_defined_gates(self) -> None:
raise NotImplementedError("PyQVM does not support DEFGATE ... AS MATRIX | PAULI-SUM.")
self.defined_gates[dg.name] = dg.matrix

def execute(
self,
executable: QuantumExecutable,
memory_map: Optional[MemoryMap] = None,
) -> "PyQVM":
def execute(self, executable: QuantumExecutable, memory_map: Optional[MemoryMap] = None, **__: Any) -> "PyQVM":
"""
Execute a program on the PyQVM. Note that the state of the instance is reset on each
call to ``execute``.
Expand Down