qubosolver.solving.hybrid
qubosolver.solving.hybrid
Section titled “
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.
drive_bayesian_search
Section titled “
drive_bayesian_search
”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
dataclass
Section titled “
Config
dataclass
”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
Solutionand 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_durationcap.
solve
Section titled “
solve
”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:
-
instance(Instance) –The QUBO
Instanceto solve. -
register(qoolqit (external).Register (external)) –The physical atom register.
-
backend(protocols.Backend) –Execution backend for running simulations during optimization.
-
device(qoolqit (external).Device (external)) –Target quantum device.
-
dmm(bool (external), default:True) –Whether to use the Detuning Map Modulator.
-
config(Config | None, default:None) –Optimization parameters, including the initial waveform knots, number of evaluations, and objective function.
Returns:
-
tuple (external)[Solution, qoolqit (external).Drive (external)]–A tuple of the best
qoolqit.Drive(external) found and the correspondingSolution.
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