Skip to content

Results are limited to the current section: Application solving tools

Product news

qubosolver.solving.hybrid

Hybrid quantum-classical solvers combining Pasqal devices with classical optimization.

Modules:

  • drive_bayesian_search –

    Hybrid quantum-classical QUBO solver using Bayesian optimization of drive schedules.

Hybrid quantum-classical QUBO solver using Bayesian optimization of drive schedules.

Runs a Bayesian search (via skopt.gp_minimize (external)) over analog drive waveform parameters, executing a quantum simulation at each evaluation and minimizing a configurable objective of the resulting solution. Can be used as a standalone hybrid solving algorithm, or as a drive-shaping method to produce a tuned qoolqit.Drive (external) for another solver.

Classes:

  • Config –

    Configuration for the Bayesian-optimization hybrid solver / drive shaper.

Functions:

  • solve –

    Solve a QUBO instance via Bayesian optimization of a drive schedule.

Config(initial_amplitude_knots: list[float] = (lambda: [0.5, 0.9, 0.5])(), initial_detuning_knots: list[float] = (lambda: [-0.8, 0.0, 0.8])(), n_evaluations: int = 20, seed: int | None = None, objective_fn: Callable[[ Solution
dataclass
(qubosolver.types.Solution)" href="../qubosolver/#qubosolver.Solution">Solution], float] = _default_objective, default_sequence_duration: int = 50000)

Configuration for the Bayesian-optimization hybrid solver / drive shaper.

Attributes:

  • initial_amplitude_knots (list (external)[float (external)]) –

    Initial guess for the amplitude waveform's three interior knots, each normalized in [0, 1].

  • initial_detuning_knots (list (external)[float (external)]) –

    Initial guess for the detuning waveform's three knots, each normalized in [-1, 1].

  • n_evaluations (int (external)) –

    Number of Bayesian optimization evaluations.

  • seed (int (external) | None) –

    Random seed for reproducibility.

  • objective_fn (Callable (external)[[Solution], float (external)]) –

    Function to minimize: takes a Solution and returns a number. Defaults to the minimum cost among the sampled bitstrings; override to minimize something else, e.g. the average cost.

  • default_sequence_duration (int (external)) –

    Fallback maximum sequence duration (ns) injected when the target device has no max_duration cap.

solve(instance: Instance (qubosolver.types.Instance)" href="../qubosolver/#qubosolver.Instance">Instance, register: qoolqit.Register, *, backend: qubosolver.protocols (qubosolver.types.protocols)" href="../protocols/#qubosolver.protocols">protocols. Backend (qubosolver.types.protocols.Backend)" href="../protocols/#qubosolver.protocols.Backend">Backend, device: qoolqit.Device, dmm: bool = True, config: Config
dataclass
(qubosolver.solving.hybrid.drive_bayesian_search.Config)" href="#qubosolver.solving.hybrid.drive_bayesian_search.Config">Config | None = None) -> tuple[ Solution
dataclass
(qubosolver.types.Solution)" href="../qubosolver/#qubosolver.Solution">Solution, qoolqit.Drive]

Solve a QUBO instance via Bayesian optimization of a drive schedule.

Uses skopt.gp_minimize (external) to search over waveform parameters, running a quantum simulation at each evaluation and minimizing config.objective_fn of the resulting Solution. This is a hybrid quantum-classical solving algorithm in its own right, and its returned drive can also be reused as the output of a drive-shaping step for another solver.

Parameters:

Returns:

Source code in qubosolver/solving/hybrid/drive_bayesian_search.py
def solve(
instance: Instance,
register: qoolqit.Register,
*,
backend: protocols.Backend,
device: qoolqit.Device,
dmm: bool = True,
config: Config | None = None,
) -> tuple[Solution, qoolqit.Drive]:
"""Solve a QUBO instance via Bayesian optimization of a drive schedule.
Uses [`skopt.gp_minimize`](https://scikit-optimize.github.io/stable/modules/generated/skopt.gp_minimize.html)
to search over waveform parameters, running a
quantum simulation at each evaluation and minimizing [`config.objective_fn`][Config]
of the resulting [`Solution`][]. This is a hybrid quantum-classical solving
algorithm in its own right, and its returned drive can also be reused as
the output of a drive-shaping step for another solver.
Args:
instance: The QUBO [`Instance`][] to solve.
register: The physical atom register.
backend: Execution backend for running simulations during optimization.
device: Target quantum device.
dmm: Whether to use the Detuning Map Modulator.
config: Optimization parameters, including the initial waveform knots,
number of evaluations, and objective function.
Returns:
A tuple of the best [`qoolqit.Drive`][] found and the corresponding
[`Solution`][].
"""
config = config or Config()
if dmm and not support_dmm(device):
logging.warning(
"dmm=True was requested but device %r does not support a DMM channel; "
"falling back to a global detuning drive.",
device,
)
dmm = False
n_amp = 3
n_det = 3
eps = 0.0001
zero = eps
one = 1.0 - eps
bounds = [(zero, one)] * n_amp + [(-one, -zero)] + [(-one, one)] * (n_det - 2) + [(zero, one)]
initial_params = config.initial_amplitude_knots + config.initial_detuning_knots
def run(x: list[float], eval: bool = True) -> tuple[float, Solution, qoolqit.Drive]:
solution = Solution()
drive = _build_drive(
instance,
x,
dmm=dmm,
device=device,
register=register,
)
try:
solution = _run_simulation(
instance.matrix,
register,
drive,
device,
backend,
config,
)
if eval:
cost_eval = config.objective_fn(solution)
if not np.isfinite(cost_eval):
print(f"[Warning] Non-finite cost encountered: {cost_eval} at x={x}")
cost_eval = 1e4
else:
cost_eval = float("nan")
except Exception as e:
print(f"[Exception] Error during simulation at x={x}: {e}")
cost_eval = 1e4
return cost_eval, solution, drive
def objective(x: list[float]) -> float:
cost_eval, _, _ = run(x)
config._callback_fn(_CallbackInfo(x=x, cost_eval=cost_eval))
return cost_eval
opt_result = gp_minimize(
objective,
bounds,
x0=initial_params,
n_calls=config.n_evaluations,
random_state=config.seed,
)
best_params = opt_result.x if opt_result else initial_params
_, solution, drive = run(best_params, eval=False)
return solution, drive