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.
Contains the ResultData
and the duration of the execution.
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 asQVMResultData
qpu
: Data returned from the QPU, stored asQPUResultData
Methods (each per variant):
is_*
: if the underlying values are that type.as_*
: if the underlying values are that type, then those values, otherwiseNone
.to_*
: the underlying values as that type, raisesValueError
if they are not.from_*
: wrap underlying values as this enum type.
Create a new ResultData from either QVM or QPU result data.
Returns x
if this [PyResultData
] wraps a ResultData::qpu
(x); otherwise returns (Python) None
. On the Rust side, this corresponds to either Some(x)
or [None
].
Returns x
if this [PyResultData
] wraps a ResultData::qpu
(x); otherwise raises a ValueError
. On the Rust side, this corresponds to either Ok(x)
or Err(...)
.
Returns x
if this [PyResultData
] wraps a ResultData::qvm
(x); otherwise returns (Python) None
. On the Rust side, this corresponds to either Some(x)
or [None
].
Returns x
if this [PyResultData
] wraps a ResultData::qvm
(x); otherwise raises a ValueError
. On the Rust side, this corresponds to either Ok(x)
or Err(...)
.
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.
A map of register names (ie. "ro") to a RegisterMatrix
containing the values of the register.
Get the RegisterMatrix
for the given register. Returns None
if the register doesn't exist.
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 QuilBIT
,OCTET
, orINTEGER
types.real
: Corresponds to the QuilREAL
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, otherwiseNone
.to_*
: the underlying values as that type, raisesValueError
if they are not.from_*
: wrap underlying values as this enum type.
Get the RegisterMatrix as numpy ndarray
.
The builder interface for executing Quil programs on QVMs and QPUs.
Execute on a QVM which is accessible via the provided client.
Raises
ExecutionError
: If the job fails to execute.
Execute on a QVM which is accessible via the provided client.
(async analog of Executable.execute_on_qvm
.)
Raises
ExecutionError
: If the job fails to execute.
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
ExecutionError
: If the job fails to execute.
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
ExecutionError
: If the job fails to execute.
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
ExecutionError
: If the job fails to execute.
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
ExecutionError
: If the job fails to execute.
Wait for the results of a job to complete.
(async analog of Executable.retrieve_results
)
Raises
ExecutionError
: If the job fails to execute.
Program execution parameters.
Note: The validity of parameters is not checked until execution.
The result of submitting a job to a QPU.
Used to retrieve the results of a job.
Values present in a register that are one of a set of variants.
Variants:
i8
: Corresponds to the QuilBIT
orOCTET
types.i16
: Corresponds to the QuilINTEGER
type.f64
: Corresponds to the QuilREAL
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, otherwiseNone
.to_*
: the underlying values as that type, raisesValueError
if they are not.from_*
: wrap underlying values as this enum type.
The Python wrapper for [RegisterData::I8
], creating a [PyRegisterData
] and taking a Python argument.
The Python wrapper for [RegisterData::F64
], creating a [PyRegisterData
] and taking a Python argument.
The Python wrapper for [RegisterData::I16
], creating a [PyRegisterData
] and taking a Python argument.
The Python wrapper for [RegisterData::Complex32
], creating a [PyRegisterData
] and taking a Python argument.
Returns the inner value.
Returns x
if this [PyRegisterData
] wraps a RegisterData::i8
(x); otherwise returns (Python) None
. On the Rust side, this corresponds to either Some(x)
or [None
].
Returns x
if this [PyRegisterData
] wraps a RegisterData::i8
(x); otherwise raises a ValueError
. On the Rust side, this corresponds to either Ok(x)
or Err(...)
.
Returns x
if this [PyRegisterData
] wraps a RegisterData::f64
(x); otherwise returns (Python) None
. On the Rust side, this corresponds to either Some(x)
or [None
].
Returns x
if this [PyRegisterData
] wraps a RegisterData::f64
(x); otherwise raises a ValueError
. On the Rust side, this corresponds to either Ok(x)
or Err(...)
.
Returns x
if this [PyRegisterData
] wraps a RegisterData::i16
(x); otherwise returns (Python) None
. On the Rust side, this corresponds to either Some(x)
or [None
].
Returns x
if this [PyRegisterData
] wraps a RegisterData::i16
(x); otherwise raises a ValueError
. On the Rust side, this corresponds to either Ok(x)
or Err(...)
.
Tests if this [PyRegisterData
] wraps a [RegisterData::complex32
] value
Returns x
if this [PyRegisterData
] wraps a RegisterData::complex32
(x); otherwise returns (Python) None
. On the Rust side, this corresponds to either Some(x)
or [None
].
Error encountered when executing a program.
Error that may occur when building a RegisterMatrix
from execution data.
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.