Skip to content

quast_decisiontree.algorithms.quantum.lr_qaoa

quast_decisiontree.algorithms.quantum.lr_qaoa

Linear Ramp QAOA (LR-QAOA) — non-variational QAOA with deterministic parameters.

LR-QAOA runs a standard QAOA circuit at a given depth (reps) with fixed parameters determined by a linear ramp schedule:

gamma_p = p * delta_gamma / reps     (p = 1, ..., reps)  — increasing
beta_p  = (reps + 1 - p) * delta_beta / reps             — decreasing

No optimization loop is involved. As a fixed-parameter quantum algorithm it is modeled as a HybridAlgorithm with a trivial (empty) classical part: it shares the backend-driven execution interface but performs no classical optimization. Useful as: - A fast heuristic for combinatorial optimization - An initialization strategy for variational QAOA (warm-start) - A baseline for benchmarking variational approaches

LRQAOA

Bases: HybridAlgorithm

Linear Ramp QAOA algorithm.

Constructs and executes a QAOA circuit with deterministic linear ramp parameters. No classical optimization is performed.

Tunable settings (reps, delta_gamma, delta_beta, shots, mixer) are hyperparameters configurable via the builder system. Problem-specific inputs (cost_operator, num_qubits) are provided at execution time.

The cost_operator must be a Qrisp-compatible callable
  • cost_operator(qv, gamma) — applies exp(-i * gamma * C)

The mixer, if provided, must have signature mixer(qv, beta). If left as None, the standard RX mixer is used.

Compatible with the decision tree node flow

LRQAOASetupNode → instantiates this class HybridAlgorithmExecuteNode → calls execute()

Example usage (standalone)::

lr = LRQAOA(reps=3, delta_gamma=0.5, delta_beta=0.5, shots=1024)
counts = lr.execute(
    backend=my_backend,
    cost_operator=my_cost_operator,
    num_qubits=4,
)
Source code in src/quast_decisiontree/algorithms/quantum/lr_qaoa.py
 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
class LRQAOA(HybridAlgorithm):
    """Linear Ramp QAOA algorithm.

    Constructs and executes a QAOA circuit with deterministic linear ramp
    parameters. No classical optimization is performed.

    Tunable settings (reps, delta_gamma, delta_beta, shots, mixer) are
    hyperparameters configurable via the builder system. Problem-specific
    inputs (cost_operator, num_qubits) are provided at execution time.

    The cost_operator must be a Qrisp-compatible callable:
        - cost_operator(qv, gamma) — applies exp(-i * gamma * C)

    The mixer, if provided, must have signature mixer(qv, beta). If left as
    None, the standard RX mixer is used.

    Compatible with the decision tree node flow:
        LRQAOASetupNode → instantiates this class
        HybridAlgorithmExecuteNode → calls execute()

    Example usage (standalone)::

        lr = LRQAOA(reps=3, delta_gamma=0.5, delta_beta=0.5, shots=1024)
        counts = lr.execute(
            backend=my_backend,
            cost_operator=my_cost_operator,
            num_qubits=4,
        )
    """

    HYPERPARAMS: ClassVar[list] = [
        HyperParam(
            name="reps",
            hparam_type=int,
            description="Number of QAOA layers (depth parameter p)",
            default=1,
            test=lambda x: x > 0,
        ),
        HyperParam(
            name="delta_gamma",
            hparam_type=float,
            description="Scale factor for the (increasing) gamma ramp schedule",
            default=0.5,
        ),
        HyperParam(
            name="delta_beta",
            hparam_type=float,
            description="Scale factor for the (decreasing) beta ramp schedule",
            default=0.5,
        ),
        HyperParam(
            name="shots",
            hparam_type=int,
            description="Number of measurement shots",
            default=128,
            test=lambda x: x > 0,
        ),
        HyperParam(
            name="mixer",
            hparam_type=None,
            description=(
                "Mixer callable with signature mixer(qv, beta). "
                "If None, the standard RX mixer is used."
            ),
            default=None,
        ),
    ]

    INPUT_KEYS: ClassVar[Sequence[str]] = (
        "cost_operator",
        "num_qubits",
    )

    @classmethod
    def check_input(cls, cost_operator) -> bool:
        """Check if the input is a valid cost operator (callable).

        Args:
            cost_operator: The cost operator to validate.

        Returns:
            True if cost_operator is callable, False otherwise.
        """
        return callable(cost_operator)

    def get_parameters(self) -> tuple:
        """Compute the linear ramp parameter schedule.

        Returns:
            Tuple of (gammas, betas) where each is a 1-D ndarray of length
            ``reps``. Gammas increase linearly; betas decrease linearly.
        """
        gamma_params = np.arange(1, self.reps + 1) * self.delta_gamma / self.reps
        beta_params = np.arange(1, self.reps + 1)[::-1] * self.delta_beta / self.reps
        return gamma_params, beta_params

    def run_algorithm(self, backend: Backend, input: dict[str, Any]) -> dict:
        """Execute LR-QAOA on the given backend and return measurement counts.

        Called by :meth:`HybridAlgorithm.execute`, which has already validated
        that all INPUT_KEYS are present and non-None.

        Args:
            backend: The quantum backend to submit the circuit to. If None or
                without a working submit function, Qrisp's built-in simulator
                is used.
            input: Dict with keys ``"cost_operator"`` (a phase separation
                callable ``cost_operator(qv, gamma) -> None``) and
                ``"num_qubits"``.

        Returns:
            Dict mapping bitstrings to counts.

        Raises:
            TypeError: If cost_operator is not callable.
        """
        cost_operator = input["cost_operator"]
        if not self.check_input(cost_operator):
            raise TypeError(
                f"Invalid input for LRQAOA. "
                f"Expected a callable cost_operator, got {type(cost_operator)!r}."
            )

        num_qubits = input["num_qubits"]
        mixer = self._resolve_mixer()
        gamma_params, beta_params = self.get_parameters()

        qv = QuantumVariable(num_qubits)

        for i in range(num_qubits):
            h(qv[i])

        for p in range(self.reps):
            cost_operator(qv, gamma_params[p])
            mixer(qv, beta_params[p])

        mes_kwargs = {}
        if backend is not None and backend.has_submit:
            backend_name = backend.get("name", "")
            if backend_name != "qrisp_simulator":
                mes_kwargs["backend"] = backend

        return qv.get_measurement(shots=self.shots, **mes_kwargs)

    def _resolve_mixer(self) -> Callable:
        """Resolve the mixer to use.

        Returns the configured mixer, or falls back to the standard RX mixer.
        """
        if self.mixer is not None:
            return self.mixer
        return RX_mixer

HYPERPARAMS class-attribute

HYPERPARAMS = [
    HyperParam(
        name="reps",
        hparam_type=int,
        description="Number of QAOA layers (depth parameter p)",
        default=1,
        test=lambda x: x > 0,
    ),
    HyperParam(
        name="delta_gamma",
        hparam_type=float,
        description="Scale factor for the (increasing) gamma ramp schedule",
        default=0.5,
    ),
    HyperParam(
        name="delta_beta",
        hparam_type=float,
        description="Scale factor for the (decreasing) beta ramp schedule",
        default=0.5,
    ),
    HyperParam(
        name="shots",
        hparam_type=int,
        description="Number of measurement shots",
        default=128,
        test=lambda x: x > 0,
    ),
    HyperParam(
        name="mixer",
        hparam_type=None,
        description="Mixer callable with signature mixer(qv, beta). If None, the standard RX mixer is used.",
        default=None,
    ),
]

INPUT_KEYS class-attribute

INPUT_KEYS = ('cost_operator', 'num_qubits')

check_input classmethod

check_input(cost_operator)

Check if the input is a valid cost operator (callable).

Parameters:

Name Type Description Default
cost_operator

The cost operator to validate.

required

Returns:

Type Description
bool

True if cost_operator is callable, False otherwise.

Source code in src/quast_decisiontree/algorithms/quantum/lr_qaoa.py
111
112
113
114
115
116
117
118
119
120
121
@classmethod
def check_input(cls, cost_operator) -> bool:
    """Check if the input is a valid cost operator (callable).

    Args:
        cost_operator: The cost operator to validate.

    Returns:
        True if cost_operator is callable, False otherwise.
    """
    return callable(cost_operator)

get_parameters

get_parameters()

Compute the linear ramp parameter schedule.

Returns:

Type Description
tuple

Tuple of (gammas, betas) where each is a 1-D ndarray of length

tuple

reps. Gammas increase linearly; betas decrease linearly.

Source code in src/quast_decisiontree/algorithms/quantum/lr_qaoa.py
123
124
125
126
127
128
129
130
131
132
def get_parameters(self) -> tuple:
    """Compute the linear ramp parameter schedule.

    Returns:
        Tuple of (gammas, betas) where each is a 1-D ndarray of length
        ``reps``. Gammas increase linearly; betas decrease linearly.
    """
    gamma_params = np.arange(1, self.reps + 1) * self.delta_gamma / self.reps
    beta_params = np.arange(1, self.reps + 1)[::-1] * self.delta_beta / self.reps
    return gamma_params, beta_params

run_algorithm

run_algorithm(backend, input)

Execute LR-QAOA on the given backend and return measurement counts.

Called by :meth:HybridAlgorithm.execute, which has already validated that all INPUT_KEYS are present and non-None.

Parameters:

Name Type Description Default
backend Backend

The quantum backend to submit the circuit to. If None or without a working submit function, Qrisp's built-in simulator is used.

required
input dict[str, Any]

Dict with keys "cost_operator" (a phase separation callable cost_operator(qv, gamma) -> None) and "num_qubits".

required

Returns:

Type Description
dict

Dict mapping bitstrings to counts.

Raises:

Type Description
TypeError

If cost_operator is not callable.

Source code in src/quast_decisiontree/algorithms/quantum/lr_qaoa.py
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def run_algorithm(self, backend: Backend, input: dict[str, Any]) -> dict:
    """Execute LR-QAOA on the given backend and return measurement counts.

    Called by :meth:`HybridAlgorithm.execute`, which has already validated
    that all INPUT_KEYS are present and non-None.

    Args:
        backend: The quantum backend to submit the circuit to. If None or
            without a working submit function, Qrisp's built-in simulator
            is used.
        input: Dict with keys ``"cost_operator"`` (a phase separation
            callable ``cost_operator(qv, gamma) -> None``) and
            ``"num_qubits"``.

    Returns:
        Dict mapping bitstrings to counts.

    Raises:
        TypeError: If cost_operator is not callable.
    """
    cost_operator = input["cost_operator"]
    if not self.check_input(cost_operator):
        raise TypeError(
            f"Invalid input for LRQAOA. "
            f"Expected a callable cost_operator, got {type(cost_operator)!r}."
        )

    num_qubits = input["num_qubits"]
    mixer = self._resolve_mixer()
    gamma_params, beta_params = self.get_parameters()

    qv = QuantumVariable(num_qubits)

    for i in range(num_qubits):
        h(qv[i])

    for p in range(self.reps):
        cost_operator(qv, gamma_params[p])
        mixer(qv, beta_params[p])

    mes_kwargs = {}
    if backend is not None and backend.has_submit:
        backend_name = backend.get("name", "")
        if backend_name != "qrisp_simulator":
            mes_kwargs["backend"] = backend

    return qv.get_measurement(shots=self.shots, **mes_kwargs)