2. qib Extending the Backend Interface¶
In this section we explain how someone could extend the backend interface of qib to support their Quantum Backend Architecture. First we explain how the current classes and relations are configured and what their role is, then we explicitly offer a how-to guide on what abstract classes should be implemented in order to support one’s custom backend.
Note: For a hands-on demonstration on how the backend module of qib can be used in order to execute circuits, one can check the WMI backend example, at
📂examples/backend/qib_backend_wmi.ipynb
2.1. The Current Configuration¶
The core components of qib’s backend module are represented by the following classes :
QuantumProcessor(abstract): The actual representation of the given quantum processor. This class defines the functionality of interacting with the targeted quantum backend (usually over a networking request-response mechanism), in order to generate and submit experiment objects.Experiment(abstract): This component defines the behaviour of a quantum experiment performed on the given processor. It acts as both a data class and a behaviour class, defining how the experiment gets initialized, validated, controlled, and queried (i.e. how the results of the experiment are obtained).ExperimentResults(abstract): A purely data-class responsible for representing and interpreting quantum experiment results of an experiment already performed on the given processor.Options(abstract): The (configurable) options that the clients of qib are able to dynamically modify in order to run experiments in different configurations or with different properties. Each quantum processor defines its own available options.ProcessorConfiguration(abstract): The configuration of theQuantumProcessor. This class can also be extended on need, but it should more or less follow the same base principles. It represents the immutable properties of a quantum processor (such as qubits and gates configuration, if it is a simulator or not, etc.). These properties are hardcoded when defining the quantum processor, and thus should not (frequently) change.
Have a look at the architecture below for a more detailed understanding of the components and how they interconnect with each other:

2.2. How to Extend the Interface¶
In order to extend the currently available backend interface, one must:
2.2.1. Create Provider Sub-Module¶
Create a new python sub-module with the provider name:
Create a new folder under
src/backendwith the provider name (e.g.src/backend/myprov)Create a
__init__.pyfile within the folder, where to import all python implementations
📂src/backend/myprov/__init__.py
from qib.backend.myprov.myprov_options import MyProvOptions
from qib.backend.myprov.myprov_experiment import MyProvExperiment, MyProvExperimentResults
# Backend A
from qib.backend.myprov.myprov_backend_a import MyProvBackendA
# Backend B
from qib.backend.myprov.myprov_backend_b import MyProvBackendB
# ...
2.2.2. Implement the core abstract classes:¶
Implement qib.backend.Options
📂src/backend/myprov/myprov_options.py
from qib.backend.options import Options
class MyProvOptions(Options):
def __init__(self,
option1: str = "default_value1", # required option
option2: str = None # optional option
# ...
):
self.option1: str = option1
self.option2: str = option2
def optional(self) -> dict:
optional: dict = {}
if self.option2: optional['option2'] = self.option2
return optional
Implement qib.backend.Experiment and qib.backend.ExperimentResults
📂src/backend/myprov/myprov_experiment.py
from qib.circuit import Circuit
from qib.backend.myprov import MyProvOptions
from qib.backend import ExperimentStatus, Experiment, ExperimentResults, ExperimentType
class MyProvExperiment(Experiment):
def __init__(self, circuit: Circuit, options: MyProvOptions, exp_type: ExperimentType)
self.circuit: Circuit = circuit
self.options: MyProvOptions = options
self.exp_type: ExperimentType = exp_type
self._initialize()
self._validate()
def results(self) -> MyProvExperimentResults | None:
# implement accordingly
# ...
class MyProvExperimentResults(ExperimentResults):
# ...
Note:
OptionsorExperimentimplementations might be also implemented separately for each backend (if this is necessary). Example:BackendAExperiment,BackendBExperiment, etc.
2.2.3. Implement Backend Processors¶
For each new quantum backend processor that one would like to implement within their provider module, implement qib.backend.Processor
📂src/backend/myprov/myprov_backend_a.py
from qib.circuit import Circuit
from qib.backend import QuantumProcessor, ProcessorConfiguration
from qib.backend.myprov import MyProvOptions, MyProvExperiment
class MyProvBackendA(QuantumProcessor):
def __init__(self):
# implement accordingly
@staticmethod
def configuration() -> ProcessorConfiguration:
return ProcessorConfiguration(
backend_name = 'BackendA'
backend_version = 'v1.5.6'
# ...
)
def submit_experiment(circuit: Circuit, options: MyProvOptions = MyProvOptions()) -> MyProvExperiment:
# implement accordingly