CommunicationLayer
A CommunicationLayer is the provider-facing interface used by a RemoteComputer to communicate with a
remote simulator or QPU. Any external provider can integrate its platform with Perceval by implementing this abstract
class and passing an instance to RemoteComputer:
import perceval as pcvl
communication_layer = ProviderCommunicationLayer(...)
computer = pcvl.RemoteComputer(communication_layer)
The RemoteComputer handles Perceval concerns such as validating computations, applying error mitigation,
preparing payloads, waiting for capacity, and exposing synchronous and asynchronous executions. The communication
layer is responsible for translating those operations to the provider API.
See also
The usable implementations of this class: QuandelaCommunicationLayer, ScalewayCommunicationLayer and KipuCommunicationLayer.
Implementation contract
An implementation must provide four groups of operations:
Platform discovery through
get_specs(),get_commands(),get_performances(), andget_remote_status().Job submission through
send(), which returns a serializable provider-defined remote identifier.Job monitoring through
get_job_status()andget_results().Resource management through
get_availability()andcancel().
The optional start_session(), stop_session(), and delete_session() hooks support providers that
require an explicit session. Their default implementations do nothing, which is suitable for stateless providers.
They are called by the corresponding RemoteComputer
lifecycle methods.
Job identity and state
send() returns a remote identifier whose type is chosen by the provider. The same value is later passed to
get_job_status(), get_results(), and cancel(). It must therefore identify the submitted job for
as long as that job can be monitored or its results retrieved.
A communication layer should not store mutable state for individual jobs. A single instance can be shared by several executions, including concurrent ones, so the remote identifier must be sufficient to perform every job-specific operation. Provider-wide caches and session state are allowed, but mutable state must be safe for concurrent access.
Payloads and results
The payload received by send() is generated by
PayloadGenerator. It contains a Computation or
ComputationIterator and may contain error mitigations, a noise model, or provider-specific computer parameters.
Provider implementations can use
PayloadGenerator.get_computation and
PayloadGenerator.read_configuration_from_payload to inspect it before converting
it to the provider’s wire format.
get_results() must return a Perceval result dictionary, as the one returned by any Computer.
Provider-specific performance or diagnostic fields may be included alongside them.
Status refreshes
get_job_status() returns an ExecutionStatus representing the current provider state. Progress, timing,
and failure details should be populated when the provider exposes them.
Transient communication failures can be represented by returning None. Perceval keeps the last known status
and passes the number of consecutive failed refreshes back as refresh_errors on the next call. Implementations
should use that value to distinguish a temporary provider failure from a permanent error and eventually raise when
retrying is no longer appropriate.
Availability
get_availability() reports how many jobs can be submitted immediately. RemoteComputer waits while this
value is 0, so implementations must also return 0 when capacity cannot be determined safely,
or 1 if no such API call exists. The value must never be negative.
Provider implementation outline
The following outline shows how a provider client maps onto the interface. The concrete request and response translation is provider-specific:
import perceval as pcvl
class ProviderCommunicationLayer(pcvl.CommunicationLayer):
def __init__(self, client):
self._client = client
def get_specs(self) -> pcvl.PlatformSpecs:
return self._client.fetch_platform_specs()
def get_commands(self) -> list[pcvl.Command]:
return self.get_specs().commands
def get_performances(self) -> dict:
return self._client.fetch_performances()
def get_remote_status(self) -> str:
return self._client.fetch_platform_status()
def send(self, payload):
provider_payload = self._convert_payload(payload)
return self._client.submit(provider_payload)
def get_job_status(self, remote_id, refresh_errors=0):
response = self._client.fetch_job(remote_id)
return self._convert_status(response)
def get_results(self, remote_id) -> dict:
response = self._client.fetch_results(remote_id)
return self._convert_results(response)
def cancel(self, remote_id) -> None:
self._client.cancel(remote_id)
def get_availability(self) -> int:
return max(0, self._client.available_slots())
If the provider exposes an RPC API compatible with Perceval’s RPC handler protocol,
RPCBasedCommunicationLayer can provide the
common payload serialization, platform discovery, status conversion, result conversion, and cancellation logic.
Persistence
An ExecutionGroup serializes its executions and their remote computers. A provider that wants its executions to survive across Python sessions must register its communication layer and any required client objects with Perceval’s serialization system. Authentication secrets should not be written into execution archives; restore them from the provider’s configuration or environment when deserializing instead (see RemoteConfig).
Class reference
- class perceval.runtime.communication_layer.CommunicationLayer
Provider-facing interface between
RemoteComputerand a remote platform.A communication layer translates Perceval payloads and lifecycle operations into calls to a provider service. Implementations should not retain mutable state for individual jobs: the remote identifier returned by
send()is passed to all later status, result, and cancellation calls. Provider-wide caches and session state are allowed.Implementations may be used concurrently by several executions. They should therefore avoid shared per-job state and make any mutable cache or session state concurrency-safe.
- abstract cancel(remote_id)
Request cancellation of a remote job.
The request need not make cancellation immediate; later calls to
get_job_status()communicate the final state.- Parameters:
remote_id (
TypeVar(RemoteId)) – Identifier returned bysend().- Return type:
None
- delete_session()
Permanently delete the current provider session.
Stateless implementations may keep the default no-op implementation.
- Return type:
None
- abstract get_availability()
Return the number of concurrent jobs that can currently be submitted by the user.
Return
0when the provider has no free capacity or availability cannot be established. Always returns1if there is no API call to get this number. The value must not be negative.- Return type:
int
- abstract get_commands()
Return the commands implemented by the remote platform.
Each command name must identify an operation that the provider can execute, and its signature must describe the parameters accepted by that operation.
- Return type:
list[Command]
- abstract get_job_status(remote_id, refresh_errors=0)
Retrieve the current status of a remote job.
Returning
Nonesignals a transient refresh failure.RemoteComputerkeeps the previous status and passes the number of consecutive failures back on the next call, so an implementation can eventually raise a permanent error.- Parameters:
remote_id (
TypeVar(RemoteId)) – Identifier returned bysend().refresh_errors (
int) – Number of consecutive previous calls that returnedNone.
- Return type:
Optional[ExecutionStatus]- Returns:
The current execution status, or
Noneafter a recoverable refresh failure.
- abstract get_performances()
Return the platform performance characterization.
The mapping is exposed as
RemoteComputer.performanceand may also be used to derive its noise model.- Return type:
dict
- abstract get_platform_details()
Return any kind of information that the platform could provide. No particular field is guaranteed to exist here, nor do their types. This should only be used for information purpose or on specific computers, and always check that the read field exists before accessing it.
- Return type:
dict
- abstract get_remote_status()
Return the provider’s current platform status as a human-readable string.
- Return type:
str
- abstract get_results(remote_id)
Retrieve the results of a completed remote job.
- Parameters:
remote_id (
TypeVar(RemoteId)) – Identifier returned bysend().- Return type:
dict- Returns:
A Perceval result dictionary, normally containing
"results"or"results_list"and any associated performance data.- Raises:
Exception – If the provider cannot retrieve the results.
- abstract get_specs()
Return the capabilities and constraints of the target platform.
- Return type:
- Returns:
The target platform specifications.
- abstract property name: str
The name of the remote platform.
- abstract send(payload)
Submit a Perceval payload to the remote platform.
The payload is produced by
PayloadGeneratorand contains aComputationorComputationIterator, plus optional noise, mitigation, and computer-specific parameters. An implementation is responsible for translating or serializing it into its provider’s request format.- Parameters:
payload (
dict) – The payload to submit.- Return type:
TypeVar(RemoteId)- Returns:
A provider-defined, stable job identifier accepted by the other job methods.
- start_session()
Start or acquire a provider session.
Stateless implementations may keep the default no-op implementation.
- Return type:
None
- stop_session()
Stop or release the current provider session without deleting it.
Stateless implementations may keep the default no-op implementation.
- Return type:
None