qcs_sdk

The qcs_sdk package provides a Python interface to the Rigetti Quantum Cloud Services (QCS) platform.

For more information about QCS, see the QCS documentation.

⚠️ This package is still in early development and breaking changes should be expected between minor versions.

1# type: ignore
2# See the following documentation for why this file is necessary:
3# https://pyo3.rs/v0.18.0/python_typing_hints#__init__py-content
4
5from .qcs_sdk import *
6
7__doc__ = qcs_sdk.__doc__
8__all__ = getattr(qcs_sdk, "__all__", []) + ["diagnostics"]
class ExecutionData:

Contains the ResultData and the duration of the execution.

result_data: ResultData
duration: Optional[datetime.timedelta]
class ResultData:

Represents the two possible types of data returned from either the QVM or a real QPU. Each variant contains the original data returned from its respective executor.

Usage

Your usage of ResultData will depend on the types of programs you are running and where. The ResultData.to_register_map() method will attempt to build RegisterMap out of the data, where each register name is mapped to a 2-dimensional rectangular RegisterMatrix where each row represents the final values in each register index for a particular shot. This is often the desired form of the data and it is probably what you want. This transformation isn't always possible, in which case to_register_map() will return an error.

To understand why this transformation can fail, we need to understand a bit about how readout data is returned from the QVM and from a real QPU:

The QVM treats each DECLARE statement as initialzing some amount of memory. This memory works as one might expect it to. It is zero-initalized, and subsequent writes to the same region overwrite the previous value. The QVM returns memory at the end of every shot. This means we get the last value in every memory reference for each shot, which is exactly the representation we want for a RegisterMatrix. For this reason, to_register_map() should always succeed for ResultData::Qvm.

The QPU on the other hand doesn't use the same memory model as the QVM. Each memory reference (ie. "ro[0]") is more like a stream than a value in memory. Every MEASURE to a memory reference emits a new value to said stream. This means that the number of values per memory reference can vary per shot. For this reason, it's not always clear what the final value in each shot was for a particular reference. When this is the case, to_register_map() will return an error as it's impossible to build a correct RegisterMatrix from the data without knowing the intent of the program that was run. Instead, it's recommended to build the RegisterMatrix you need from the inner QPUResultData data using the knowledge of your program to choose the correct readout values for each shot.

For more information on QPU readout data, refer to the QCS Documentation.

Variants:

  • qvm: Data returned from the QVM, stored as QVMResultData
  • qpu: Data returned from the QPU, stored as QPUResultData

Methods (each per variant):

  • is_*: if the underlying values are that type.
  • as_*: if the underlying values are that type, then those values, otherwise None.
  • to_*: the underlying values as that type, raises ValueError if they are not.
  • from_*: wrap underlying values as this enum type.
ResultData(inner: Union[QPUResultData, QVMResultData])

Create a new ResultData from either QVM or QPU result data.

def from_qpu(inner: QPUResultData) -> ResultData:
def from_qvm(inner: QVMResultData) -> ResultData:
def inner(self) -> Union[QVMResultData, QPUResultData]:

Returns the inner result data

def is_qpu(self) -> bool:
def as_qpu(self) -> Optional[QPUResultData]:
def to_qpu(self) -> QPUResultData:
def is_qvm(self) -> bool:
def as_qvm(self) -> Optional[QVMResultData]:
def to_qvm(self) -> QVMResultData:
def to_register_map(self) -> qcs_sdk.RegisterMap:

Convert ResultData from its inner representation as QVMResultData or QPUResultData into a RegisterMap. The RegisterMatrix for each register will be constructed such that each row contains all the final values in the register for a single shot.

Errors

Raises a RegisterMatrixConversionError if the inner execution data for any of the registers would result in a jagged matrix. QPUResultData data is captured per measure, meaning a value is returned for every measure to a memory reference, not just once per shot. This is often the case in programs that use mid-circuit measurement or dynamic control flow, where measurements to the same memory reference might occur multiple times in a shot, or be skipped conditionally. In these cases, building a rectangular RegisterMatrix would necessitate making assumptions about the data that could skew the data in undesirable ways. Instead, it's recommended to manually build a matrix from QPUResultData that accurately selects the last value per-shot based on the program that was run.

def to_raw_readout_data(self) -> Union[RawQPUReadoutData, RawQVMReadoutData]:

Get the raw data returned from the QVM or QPU. See RawQPUReadoutData and RawQVMReadoutData for more information.

class RegisterMap:

A map of register names (ie. "ro") to a RegisterMatrix containing the values of the register.

def get_register_matrix(self, register_name: str) -> Optional[qcs_sdk.RegisterMatrix]:

Get the RegisterMatrix for the given register. Returns None if the register doesn't exist.

def keys(self) -> Iterable[str]:
def values(self) -> Iterable[qcs_sdk.RegisterMatrix]:
def items(self) -> Iterable[Tuple[str, qcs_sdk.RegisterMatrix]]:
def get( self, key: str, default: Optional[qcs_sdk.RegisterMatrix] = None) -> Optional[qcs_sdk.RegisterMatrix]:
class RegisterMatrix:

Values in a 2-dimensional ndarray representing the final shot value in each memory reference across all shots. Each variant corresponds to the possible data types a register can contain.

Variants:

  • integer: Corresponds to the Quil BIT, OCTET, or INTEGER types.
  • real: Corresponds to the Quil REAL type.
  • complex: Registers containing complex numbers.

Methods (each per variant):

  • is_*: if the underlying values are that type.
  • as_*: if the underlying values are that type, then those values, otherwise None.
  • to_*: the underlying values as that type, raises ValueError if they are not.
  • from_*: wrap underlying values as this enum type.
def to_ndarray( self) -> Union[numpy.ndarray[Any, numpy.dtype[numpy.complex128]], numpy.ndarray[Any, numpy.dtype[numpy.int64]], numpy.ndarray[Any, numpy.dtype[numpy.float64]]]:

Get the RegisterMatrix as numpy ndarray.

def from_integer( inner: numpy.ndarray[typing.Any, numpy.dtype[numpy.int64]]) -> qcs_sdk.RegisterMatrix:
def to_integer(self) -> numpy.ndarray[typing.Any, numpy.dtype[numpy.int64]]:
def as_integer(self) -> Optional[numpy.ndarray[Any, numpy.dtype[numpy.int64]]]:
def is_integer(self) -> bool:
def from_real( inner: numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]) -> qcs_sdk.RegisterMatrix:
def to_real(self) -> numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]:
def as_real(self) -> Optional[numpy.ndarray[Any, numpy.dtype[numpy.float64]]]:
def is_real(self) -> bool:
def from_complex( inner: numpy.ndarray[typing.Any, numpy.dtype[numpy.complex128]]) -> qcs_sdk.RegisterMatrix:
def to_complex(self) -> numpy.ndarray[typing.Any, numpy.dtype[numpy.complex128]]:
def as_complex(self) -> Optional[numpy.ndarray[Any, numpy.dtype[numpy.complex128]]]:
def is_complex(self) -> bool:
class Executable:

The builder interface for executing Quil programs on QVMs and QPUs.

def execute_on_qvm(self, client: QVMClient) -> ExecutionData:

Execute on a QVM which is accessible via the provided client.

Raises
async def execute_on_qvm_async(self, client: QVMClient) -> ExecutionData:

Execute on a QVM which is accessible via the provided client. (async analog of Executable.execute_on_qvm.)

Raises
def execute_on_qpu( self, quantum_processor_id: str, endpoint_id: Optional[str] = None, translation_options: Optional[TranslationOptions] = None, execution_options: Optional[ExecutionOptions] = None) -> ExecutionData:

Compile the program and execute it on a QPU, waiting for results.

Parameters
  • endpoint_id: execute the compiled program against an explicitly provided endpoint. If None, the default endpoint for the given quantum_processor_id is used.
Raises
async def execute_on_qpu_async( self, quantum_processor_id: str, endpoint_id: Optional[str] = None, translation_options: Optional[TranslationOptions] = None, execution_options: Optional[ExecutionOptions] = None) -> ExecutionData:

Compile the program and execute it on a QPU, waiting for results. (async analog of Executable.execute_on_qpu)

Parameters
  • endpoint_id: execute the compiled program against an explicitly provided endpoint. If None, the default endpoint for the given quantum_processor_id is used.
Raises
def submit_to_qpu( self, quantum_processor_id: str, endpoint_id: Optional[str] = None, translation_options: Optional[TranslationOptions] = None, execution_options: Optional[ExecutionOptions] = None) -> qcs_sdk.JobHandle:

Compile the program and execute it on a QPU, without waiting for results.

Parameters
  • endpoint_id: execute the compiled program against an explicitly provided endpoint. If None, the default endpoint for the given quantum_processor_id is used.
Raises
async def submit_to_qpu_async( self, quantum_processor_id: str, endpoint_id: Optional[str] = None, translation_options: Optional[TranslationOptions] = None, execution_options: Optional[ExecutionOptions] = None) -> qcs_sdk.JobHandle:

Compile the program and execute it on a QPU, without waiting for results. (async analog of Executable.execute_on_qpu)

Parameters
  • endpoint_id: execute the compiled program against an explicitly provided endpoint. If None, the default endpoint for the given quantum_processor_id is used.
Raises
def retrieve_results(self, job_handle: qcs_sdk.JobHandle) -> ExecutionData:

Wait for the results of a job to complete.

Raises
async def retrieve_results_async(self, job_handle: qcs_sdk.JobHandle) -> ExecutionData:

Wait for the results of a job to complete. (async analog of Executable.retrieve_results)

Raises
class ExeParameter:

Program execution parameters.

Note: The validity of parameters is not checked until execution.

value: float
index: int
name: str
class JobHandle:

The result of submitting a job to a QPU.

Used to retrieve the results of a job.

job_id: str

Unique ID associated with a single job execution.

readout_map: Dict[str, str]

The readout map from source readout memory locations to the filter pipeline node which publishes the data.

class Service:

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access::
>>> Color.RED
<Color.RED: 1>
  • value lookup:
>>> Color(1)
<Color.RED: 1>
  • name lookup:
>>> Color['RED']
<Color.RED: 1>

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes -- see the documentation for details.

Quilc = Service.Quilc
QVM = Service.QVM
QCS = Service.QCS
QPU = Service.QPU
class RegisterData:

Values present in a register that are one of a set of variants.

Variants:

  • i8: Corresponds to the Quil BIT or OCTET types.
  • i16: Corresponds to the Quil INTEGER type.
  • f64: Corresponds to the Quil REAL type.
  • complex32: Results containing complex numbers.

Methods (each per variant):

  • is_*: if the underlying values are that type.
  • as_*: if the underlying values are that type, then those values, otherwise None.
  • to_*: the underlying values as that type, raises ValueError if they are not.
  • from_*: wrap underlying values as this enum type.
def from_i8(inner: Sequence[Sequence[int]]) -> qcs_sdk.RegisterData:
def from_f64(inner: Sequence[Sequence[float]]) -> qcs_sdk.RegisterData:
def from_i16(inner: Sequence[Sequence[int]]) -> qcs_sdk.RegisterData:
def from_complex32(inner: Sequence[Sequence[complex]]) -> qcs_sdk.RegisterData:
def inner(self) -> Union[List[List[int]], List[List[float]], List[List[complex]]]:

Returns the inner value.

def is_i8(self) -> bool:
def as_i8(self) -> Optional[List[List[int]]]:
def to_i8(self) -> List[List[int]]:
def is_f64(self) -> bool:
def as_f64(self) -> Optional[List[List[float]]]:
def to_f64(self) -> List[List[float]]:
def is_i16(self) -> bool:
def as_i16(self) -> Optional[List[List[int]]]:
def to_i16(self) -> List[List[int]]:
def is_complex32(self) -> bool:
def as_complex32(self) -> Optional[List[List[complex]]]:
def to_complex32(self) -> List[List[complex]]:
def as_ndarray( self) -> Union[numpy.ndarray[Any, numpy.dtype[numpy.int64]], numpy.ndarray[Any, numpy.dtype[numpy.float64]], numpy.ndarray[Any, numpy.dtype[numpy.complex128]]]:

Returns the values as an ndarray.

class QCSClient:
def load(profile_name=None):
def load_async(profile_name=None):
api_url
grpc_api_url
quilc_url
qvm_url
class ExecutionError(builtins.RuntimeError):

Error encountered when executing a program.

Inherited Members
builtins.RuntimeError
RuntimeError
builtins.BaseException
with_traceback
add_note
args
class RegisterMatrixConversionError(builtins.ValueError):

Error that may occur when building a RegisterMatrix from execution data.

Inherited Members
builtins.ValueError
ValueError
builtins.BaseException
with_traceback
add_note
args
def reset_logging():

Reset all caches for logging configuration within this library, allowing the most recent Python-side changes to be applied.

See https://docs.rs/pyo3-log/latest/pyo3_log/ for more information.

def _gather_diagnostics():
__version__ = '0.17.7'