qcs_sdk

An interface to Rigetti Quantum Cloud Services (QCS).

These APIs allow users to compile and run Quil programs on Rigetti quantum processors. Internally, it is powered by the QCS Rust SDK.

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

 1"""An interface to Rigetti [Quantum Cloud Services](https://docs.rigetti.com/qcs/) (QCS).
 2
 3These APIs allow users to compile and run Quil programs on Rigetti quantum processors.
 4Internally, it is powered by the [QCS Rust SDK](https://github.com/rigetti/qcs-sdk-rust).
 5
 6This package is still in development and breaking changes should be expected between minor versions.
 7"""
 8
 9from . import _qcs_sdk
10from .client import QCSClient  # noqa: re-export
11
12_additional_exports = [
13    "QCSClient",
14]
15
16# The following code exposes the package contents under the same namespace without the `_` prefix.
17assert isinstance(_qcs_sdk.__all__, list) and all(isinstance(s, str) for s in _qcs_sdk.__all__)
18exec(
19    f"from ._qcs_sdk import {', '.join(_qcs_sdk.__all__)}; "
20    f"__all__ = {_qcs_sdk.__all__ + _additional_exports}"
21)
22del _qcs_sdk
class ExeParameter:

Program execution parameters.

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

name
index
value
class ExecutionData:

The result of executing an Executable

duration

The time it took to execute the program on the QPU, not including any network or queueing time. If paying for on-demand execution, this is the amount you will be billed for.

This will always be None for QVM execution.

result_data

The [ResultData] that was read from the Executable.

class Executable:

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

Example

This example executes a program on a QVM, specified by the qvm_url in the QCSClient:

from qcs_sdk import Executable
from qcs_sdk.client import QCSClient
from qcs_sdk.qvm import QVMClient

PROGRAM = r'''
DECLARE ro BIT[2]

H 0
CNOT 0 1

MEASURE 0 ro[0]
MEASURE 1 ro[1]
'''

async def run():
    client = QVMClient.new_http(QCSClient.load().qvm_url)
    result = await Executable(PROGRAM, shots=4).execute_on_qvm_async()
    let data = result.result_data
                        .to_register_map()
                        .expect("should convert to readout map")
                        .get_register_matrix("ro")
                        .expect("should have data in ro")
                        .as_integer()
                        .expect("should be integer matrix")
                        .to_owned();

    // In this case, we ran the program for 4 shots, so we know the number of rows is 4.
    assert_eq!(data.nrows(), 4);
    for shot in data.rows() {
        // Each shot will contain all the memory, in order, for the vector (or "register") we
        // requested the results of. In this case, "ro" (the default).
        assert_eq!(shot.len(), 2);
        // In the case of this particular program, we know ro[0] should equal ro[1]
        assert_eq!(shot[0], shot[1]);
    }

def main():
    import asyncio
    asyncio.run(run())

    # "ro" is the only source read from by default if you don't specify `registers`.

    # We first convert the readout data to a ``RegisterMap`` to get a mapping of registers
    # (ie. "ro") to a [`RegisterMatrix`], `M`, where M[`shot`][`index`] is the value for
    # the memory offset `index` during shot `shot`.
    # There are some programs where QPU readout data does not fit into a [`RegisterMap`], in
    # which case you should build the matrix you need from [`QpuResultData`] directly. See
    # the [`RegisterMap`] documentation for more information on when this transformation
    # might fail.
def execute_on_qvm(self, /, client):

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

Raises
def execute_on_qvm_async(self, /, client):

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, endpoint_id=None, translation_options=None, execution_options=None):

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
def execute_on_qpu_async( self, /, quantum_processor_id, endpoint_id=None, translation_options=None, execution_options=None):

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, endpoint_id=None, translation_options=None, execution_options=None):

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
def submit_to_qpu_async( self, /, quantum_processor_id, endpoint_id=None, translation_options=None, execution_options=None):

Compile the program and execute it on a QPU, without waiting for results (async analog of Executable.submit_to_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):

Wait for the results of a job to complete.

Raises
def retrieve_results_async(self, /, job_handle):

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

Raises
class JobHandle:

The result of submitting a job to a QPU.

Used to retrieve the results of a job.

job_id

Unique ID associated with a single job execution.

readout_map

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

class RegisterMap:

A mapping of a register name (ie. "ro") to a [RegisterMatrix] containing the values for the register.

def get_register_matrix(self, /, register_name):

Get the RegisterMatrix for the given register.

Returns None if the register doesn't exist.

def keys(self, /):
def values(self, /):
def items(self, /):
def get(self, /, key, default=None):
class RegisterMapItemsIter:
class RegisterMapKeysIter:
class RegisterMapValuesIter:
class Service:

The external services that this SDK may connect to. Used to differentiate between networking issues in [Error::Connection].

QUILC = Service.QUILC
QVM = Service.QVM
QCS = Service.QCS
QPU = Service.QPU
class RegisterMatrix:

A 2-dimensional matrix of register values.

Each variant corresponds to the possible data types a register can contain.

def to_ndarray(self, /):

Get the RegisterMatrix as Numpy ndarray.

class RegisterMatrix.Integer(RegisterMatrix):
class RegisterMatrix.Real(RegisterMatrix):
class RegisterMatrix.Complex(RegisterMatrix):
class RegisterData:

Data resulting from Executable::execute_on_qvm

This represents a single vector (or "register") of typed memory across some number of shots. The register corresponds to the usage of a DECLARE instruction in Quil, and the name of that register should be provided with Executable::read_from.

There is a variant of this enum for each type of data that a register could hold. The register is represented as a 2-dimensional array M where the value M[shot_number][memory_index] represents the value at memory_index for shot_number.

Usage

Typically, you will be interacting with this data through the [crate::ResultData] of an [crate::ExecutionData] returned after running a program. In those cases, you'll probably want to convert it to a readout map using [crate::ResultData.to_register_map()]. This will give you each register in the form of a [crate::RegisterMatrix] which is similar but backed by an [ndarray::Array2] and more convenient for working with matrices.

If you are interacting with [RegisterData] directly, then you should already know what type of data it _should_ have, so you can use the [mod@enum_as_inner] methods (e.g. [RegisterData::into_i8]) in order to convert any variant type to its inner data.

def as_ndarray(self, /):

Return the inner values as a 2D Numpy ndarray.

def inner(self, /):
class RegisterData.I8(RegisterData):
class RegisterData.F64(RegisterData):
class RegisterData.I16(RegisterData):
class RegisterData.Complex32(RegisterData):
class QcsSdkError(builtins.Exception):

Base exception type for errors raised by this package.

class ExecutionError(QcsSdkError):

Errors which can occur when executing a program.

class RegisterMatrixConversionError(QcsSdkError):

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

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__ = $CARGO_MAKE_PROJECT_VERSION
class QCSClient:

A client providing helper functionality for accessing QCS APIs

def load(profile_name=None):

Create a QCSClient configuration using an environment-based configuration.

Parameters
  • profile_name: The QCS setting's profile name to use. If None, the default value configured in your environment is used.
Raises
  • LoadClientError: If there is an issue loading the profile details from the environment.
def load_with_login(profile_name=None):

Create a QCSClient configuration using an environment-based configuration.

If credentials are not found or stale, a PKCE login redirect flow will be initialized. Note that this opens up a TCP port on your system to accept a browser HTTP redirect, so you should not use this in environments where that is not possible, such as hosted JupyterLab sessions.

Parameters
  • profile_name: The QCS setting's profile name to use. If None, the default value configured in your environment is used.
Raises
  • LoadClientError: If there is an issue loading the profile details from the environment or if the PKCE login flow fails.

See the QCS documentation for more details.

def load_with_login_async(profile_name=None):

Create a QCSClient configuration using an environment-based configuration.

If credentials are not found or stale, a PKCE login redirect flow will be initialized. Note that this opens up a TCP port on your system to accept a browser HTTP redirect, so you should not use this in environments where that is not possible, such as hosted JupyterLab sessions.

Parameters
  • profile_name: The QCS setting's profile name to use. If None, the default value configured in your environment is used.
Raises
  • LoadClientError: If there is an issue loading the profile details from the environment or if the PKCE login flow fails.

See the QCS documentation for more details.

def get_oauth_session_async(self, /):

Get a copy of the OAuth session in an async context.

qvm_url

URL to access the QVM.

quilc_url

URL to access the quilc compiler.

oauth_session

Get a copy of the OAuth session.

api_url

URL to access the QCS API.

grpc_api_url

URL to access the QCS gRPC API.