Skip to content

quast_decisiontree.nodes.backend

quast_decisiontree.nodes.backend

Backend selection node.

The backend selection architecture is plugin-based:

  1. BackendNode subclasses (e.g., QrispBackendNode) register themselves in the decision tree and provide backends via get_backends().

  2. SelectBackendNode collects all available backends from the tree (via request_info("backends")) and presents them to the user.

  3. Custom backend providers can be added by implementing a BackendNode and adding it to the YAML config:

.. code-block:: yaml

   MyCloudBackendNode:
       init_args:
           api_key_env: "MY_API_KEY"

The node just needs to inherit from BackendNode and register backends in its constructor or via a lazy property.

logger module-attribute

logger = logging.getLogger('dt_logger')

SelectBackendNode

Bases: Node

Selects the quantum backend for algorithm execution.

Collects all backends registered by BackendNode instances in the tree and presents them as a choice to the user.

Modifications at runtime: - backend: - {str} : name of the chosen backend

Source code in src/quast_decisiontree/nodes/backend.py
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
class SelectBackendNode(Node):
    """Selects the quantum backend for algorithm execution.

    Collects all backends registered by BackendNode instances in the tree
    and presents them as a choice to the user.

    Modifications at runtime:
    - backend:
        - {str} : name of the chosen backend
    """

    _known_children = [
        "LRQAOASetupNode",
        "QrispQAOASetupNode",
        "QrispVQESetupNode",
    ]
    _path_keys = dict(backend=PathKey(str))

    def __init__(self, children: list) -> None:
        super().__init__(
            requires=["algorithm_setup_node"],
            creates=["backend"],
            children=children,
        )
        self._backends = None
        self._default = None
        self._query = None

    @property
    def backends(self) -> BackendProvider:
        if self._backends is None:
            try:
                self._backends = self.request_info("backends")
            except NoRequestFunctionError as exc:
                raise InvalidDecisionTreeSetupError(
                    "Trying to retrieve backend information from decision tree, "
                    "but no BackendNode is configured."
                ) from exc
        return self._backends

    @backends.setter
    def backends(self, val):
        if isinstance(val, BackendProvider):
            self._backends = val
        else:
            raise ValueError(f"Backends need to be given as BackendProvider, not {type(val)!r}")

    @property
    def default(self) -> str:
        if self._default is None:
            return self.backends.default.name
        return self._default

    @default.setter
    def default(self, default: str):
        if default in self.backends.names:
            self._default = default
        else:
            raise ValueError(f"No valid backend for name {default!r} found.")

    def default_backend(self):
        """Return the default backend object."""
        return self.backends[self.default]

    @property
    def query(self):
        if self._query is None:
            try:
                self._query = self._construct_backend_query()
            except InvalidDecisionTreeSetupError as exc:
                raise InvalidDecisionTreeSetupError(
                    "Cannot construct backend query without backends being set."
                ) from exc
        return self._query

    def _construct_backend_query(self):
        answers = {backend.name: backend.description for backend in self.backends}
        if not self.backends.has_unique_names:
            logger.warning(
                "BackendProvider has non-unique names; this may cause non-deterministic behavior."
            )
        return MultiChoiceQuery(
            question="Which backend do you want to use?",
            answers=answers,
            default=self.default,
            name="backend",
        )

    def execute(self, problem_data: dict, path_info: dict) -> dict:
        backend_name = path_info.get("backend")
        if backend_name is None:
            backend_name = self.query.input()
            path_info["backend"] = backend_name

        problem_data["backend"] = self.backends[backend_name]

        return dict(algorithm_setup_node=problem_data["algorithm_setup_node"])

    def next_node(self, next_node_info: dict) -> str:
        return next_node_info["algorithm_setup_node"]

backends property writable

backends

default property writable

default

query property

query

__init__

__init__(children)
Source code in src/quast_decisiontree/nodes/backend.py
64
65
66
67
68
69
70
71
72
def __init__(self, children: list) -> None:
    super().__init__(
        requires=["algorithm_setup_node"],
        creates=["backend"],
        children=children,
    )
    self._backends = None
    self._default = None
    self._query = None

default_backend

default_backend()

Return the default backend object.

Source code in src/quast_decisiontree/nodes/backend.py
106
107
108
def default_backend(self):
    """Return the default backend object."""
    return self.backends[self.default]

execute

execute(problem_data, path_info)
Source code in src/quast_decisiontree/nodes/backend.py
134
135
136
137
138
139
140
141
142
def execute(self, problem_data: dict, path_info: dict) -> dict:
    backend_name = path_info.get("backend")
    if backend_name is None:
        backend_name = self.query.input()
        path_info["backend"] = backend_name

    problem_data["backend"] = self.backends[backend_name]

    return dict(algorithm_setup_node=problem_data["algorithm_setup_node"])

next_node

next_node(next_node_info)
Source code in src/quast_decisiontree/nodes/backend.py
144
145
def next_node(self, next_node_info: dict) -> str:
    return next_node_info["algorithm_setup_node"]