Skip to content

quast_decisiontree.nodes.qrisp_ansatz

quast_decisiontree.nodes.qrisp_ansatz

Node for selecting Qrisp-compatible VQE ansatz functions.

logger module-attribute

logger = logging.getLogger('dt_logger')

QrispAnsatzNode

Bases: Node

Selects and builds a Qrisp-compatible ansatz function for VQE.

Produces
  • ansatz_function: callable(qv, params) applying one ansatz layer
  • num_params: number of variational parameters per layer
  • ansatz_type: name of the selected ansatz
Parameters

children : list Child node names. ansatz_modules : str or list of str, optional One or more fully qualified module paths containing additional ansatz registrations. Modules are imported at node construction time, allowing them to call register_ansatz() to extend the available choices.

Example YAML::

    QrispAnsatzNode:
      children: ["SelectOptimizerNode"]
      ansatz_modules:
        - "my_project.custom_ansatze"
Modifications at runtime
  • ansatz_type : str Name of the selected ansatz (e.g., 'EfficientSU2', 'TwoLocal').
  • ansatz_hyperparams : dict, optional Extra hyperparameter values for configurable ansatze.
Source code in src/quast_decisiontree/nodes/qrisp_ansatz.py
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
class QrispAnsatzNode(Node):
    """Selects and builds a Qrisp-compatible ansatz function for VQE.

    Produces:
        - ansatz_function: callable(qv, params) applying one ansatz layer
        - num_params: number of variational parameters per layer
        - ansatz_type: name of the selected ansatz

    Parameters
    ----------
    children : list
        Child node names.
    ansatz_modules : str or list of str, optional
        One or more fully qualified module paths containing additional ansatz
        registrations. Modules are imported at node construction time, allowing
        them to call ``register_ansatz()`` to extend the available choices.

        Example YAML::

            QrispAnsatzNode:
              children: ["SelectOptimizerNode"]
              ansatz_modules:
                - "my_project.custom_ansatze"

    Modifications at runtime
    ------------------------
    - ansatz_type : str
        Name of the selected ansatz (e.g., 'EfficientSU2', 'TwoLocal').
    - ansatz_hyperparams : dict, optional
        Extra hyperparameter values for configurable ansatze.
    """

    _known_children = ["SelectOptimizerNode"]
    _path_keys = dict(
        ansatz_type=PathKey(str),
        ansatz_hyperparams=PathKey(dict),
    )

    def __init__(
        self,
        children: list,
        ansatz_modules: Sequence[str] | None = None,
    ) -> None:
        super().__init__(
            requires=[["num_qubits", "qubo_matrix"]],
            creates=["ansatz_type", "ansatz_function", "num_params"],
            children=children,
        )

        if ansatz_modules is not None:
            if isinstance(ansatz_modules, str):
                ansatz_modules = [ansatz_modules]
            load_ansatz_modules(ansatz_modules)

        self.ansatz_options = get_registry_descriptions()
        self.ansatz_query = MultiChoiceQuery(
            question="Choose a Qrisp-compatible ansatz:",
            answers=self.ansatz_options,
            default="EfficientSU2",
            name="ansatz_type",
        )

    def execute(self, problem_data: dict, path_info: dict) -> dict:
        if "num_qubits" not in problem_data:
            if "qubo_matrix" in problem_data:
                problem_data["num_qubits"] = len(problem_data["qubo_matrix"])
            else:
                raise ValueError(
                    "Cannot determine num_qubits: neither num_qubits nor "
                    "qubo_matrix found in problem_data."
                )

        ansatz_type = path_info.get("ansatz_type")
        if ansatz_type is None:
            ansatz_type = self.ansatz_query.input()
        path_info["ansatz_type"] = ansatz_type
        problem_data["ansatz_type"] = ansatz_type

        extra_kwargs = self._resolve_hyperparams(ansatz_type, path_info)

        ansatz_function, num_params = get_ansatz(
            ansatz_type,
            num_qubits=problem_data["num_qubits"],
            **extra_kwargs,
        )
        problem_data["ansatz_function"] = ansatz_function
        problem_data["num_params"] = num_params

        logger.debug(
            "Built ansatz %r with %d params/layer for %d qubits. Extra kwargs: %r",
            ansatz_type,
            num_params,
            problem_data["num_qubits"],
            extra_kwargs,
        )

        return dict(ansatz_type=ansatz_type)

    def _resolve_hyperparams(self, ansatz_type: str, path_info: dict) -> dict:
        """Resolve extra hyperparameters for a configurable ansatz.

        Values already present in path_info (automatic mode) are used as-is;
        any missing hyperparams fall back to interactive queries. All values
        are normalized consistently (allow_multiple comma-strings -> tuples).

        Returns
        -------
        dict
            Keyword arguments to pass to the ansatz factory.
        """
        hyperparams = get_ansatz_hyperparams(ansatz_type)
        if not hyperparams:
            return {}

        stored = path_info.get("ansatz_hyperparams") or {}
        missing = [hp for hp in hyperparams if hp.name not in stored]

        answers = {}
        if missing:
            queries = QueryTree(queries=[HyperParamQuery(hp) for hp in missing])
            answers = queries.input()

        extra_kwargs = {}
        for hp in hyperparams:
            val = stored[hp.name] if hp.name in stored else answers.get(hp.name)
            if val is None:
                continue
            if hp.allow_multiple and isinstance(val, str) and "," in val:
                extra_kwargs[hp.name] = tuple(v.strip() for v in val.split(","))
            else:
                extra_kwargs[hp.name] = val

        path_info["ansatz_hyperparams"] = extra_kwargs
        return extra_kwargs

ansatz_options instance-attribute

ansatz_options = get_registry_descriptions()

ansatz_query instance-attribute

ansatz_query = MultiChoiceQuery(
    question="Choose a Qrisp-compatible ansatz:",
    answers=self.ansatz_options,
    default="EfficientSU2",
    name="ansatz_type",
)

__init__

__init__(children, ansatz_modules=None)
Source code in src/quast_decisiontree/nodes/qrisp_ansatz.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def __init__(
    self,
    children: list,
    ansatz_modules: Sequence[str] | None = None,
) -> None:
    super().__init__(
        requires=[["num_qubits", "qubo_matrix"]],
        creates=["ansatz_type", "ansatz_function", "num_params"],
        children=children,
    )

    if ansatz_modules is not None:
        if isinstance(ansatz_modules, str):
            ansatz_modules = [ansatz_modules]
        load_ansatz_modules(ansatz_modules)

    self.ansatz_options = get_registry_descriptions()
    self.ansatz_query = MultiChoiceQuery(
        question="Choose a Qrisp-compatible ansatz:",
        answers=self.ansatz_options,
        default="EfficientSU2",
        name="ansatz_type",
    )

execute

execute(problem_data, path_info)
Source code in src/quast_decisiontree/nodes/qrisp_ansatz.py
 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
def execute(self, problem_data: dict, path_info: dict) -> dict:
    if "num_qubits" not in problem_data:
        if "qubo_matrix" in problem_data:
            problem_data["num_qubits"] = len(problem_data["qubo_matrix"])
        else:
            raise ValueError(
                "Cannot determine num_qubits: neither num_qubits nor "
                "qubo_matrix found in problem_data."
            )

    ansatz_type = path_info.get("ansatz_type")
    if ansatz_type is None:
        ansatz_type = self.ansatz_query.input()
    path_info["ansatz_type"] = ansatz_type
    problem_data["ansatz_type"] = ansatz_type

    extra_kwargs = self._resolve_hyperparams(ansatz_type, path_info)

    ansatz_function, num_params = get_ansatz(
        ansatz_type,
        num_qubits=problem_data["num_qubits"],
        **extra_kwargs,
    )
    problem_data["ansatz_function"] = ansatz_function
    problem_data["num_params"] = num_params

    logger.debug(
        "Built ansatz %r with %d params/layer for %d qubits. Extra kwargs: %r",
        ansatz_type,
        num_params,
        problem_data["num_qubits"],
        extra_kwargs,
    )

    return dict(ansatz_type=ansatz_type)