Classical Solvers
Classical solvers tackle a QUBO Instance entirely on CPU, without going through the quantum pipeline. Each one is a standalone function under solving, callable directly with the instance and its own set of keyword arguments — no Solver/SolverConfig wiring required. They differ in the trade-off between solution quality, runtime, and whether they need a starting point.
Without an initial solution
Section titled “Without an initial solution”These solvers start from scratch:
solving.cplex.solve— exact MIP solve via IBM CPLEX.solving.random_sampling.solve— uniform random sampling baseline.
With an initial solution
Section titled “With an initial solution”These solvers take a starting point. Because they accept a starting point, they can also be used to refine a previous solution — for example, post-processing a quantum solver's output:
solving.tabu_search.solve— neighborhood search with a tabu memory. See example below.solving.simulated_annealing.solve— stochastic temperature-cooling search.solving.iterative_bitflip_local_search.solve— greedy local search that iteratively flips bits until no single flip improves the solution.
Example: Tabu Search
Section titled “Example: Tabu Search”from qubosolver import Instance, solving, matrix, bitstrings, torch_rng, analysis
instance = Instance( matrix.tensor( [ [-2.0, 1.0, 0.0, 1.5, 0.0], [1.0, -1.5, 1.0, 0.0, 0.5], [0.0, 1.0, -2.0, 1.0, 1.0], [1.5, 0.0, 1.0, -1.0, 0.5], [0.0, 0.5, 1.0, 0.5, -1.5], ] ))
starts = bitstrings.rand(5, instance.size, rng=torch_rng(15))solution = solving.tabu_search.solve(instance, starts=starts, time_limit=10.0)
print("Tabu Search solution:")print(analysis.to_dataframe([solution]))Tabu Search solution: labels bitstrings costs counts probs0 0 10100 -4.0 5 1.0Example: refining a quantum solution
Section titled “Example: refining a quantum solution”Run the quantum pipeline (see quantum solving), then try local bitflips for refinement:
from qubosolver import ( Instance, Solution, LocalEmulator, embedding, drive_shaping, solving, matrix, analysis,)import qoolqit
instance = Instance( matrix.tensor( [ [-2.0, 1.0, 0.0, 1.5, 0.0], [1.0, -1.5, 1.0, 0.0, 0.5], [0.0, 1.0, -2.0, 1.0, 1.0], [1.5, 0.0, 1.0, -1.0, 0.5], [0.0, 0.5, 1.0, 0.5, -1.5], ] ))device = qoolqit.AnalogDeviceWithDMM()backend = LocalEmulator()
register = embedding.blade.embed_for_device(instance, device)drive = drive_shaping.proportional_diagonal.build_drive(instance, register, device=device, dmm=True)program = solving.analog_quantum_sampling.compile(register, drive, device)job = backend.run(program)quantum_solution = Solution.from_results(job.results(), instance)
print("Quantum solution:")print(analysis.to_dataframe([quantum_solution]))
# Refine the quantum solution classically.refined_solution = solving.iterative_bitflip_local_search.solve(instance, starts=quantum_solution)
print("Refined solution:")print(analysis.to_dataframe([refined_solution]))Quantum solution: labels bitstrings costs counts probs0 0 10100 -4.0 374 0.3741 0 10001 -3.5 342 0.3422 0 10101 -3.5 172 0.1723 0 11001 -2.0 69 0.0694 0 01001 -2.0 36 0.0365 0 10000 -2.0 4 0.0046 0 01011 -2.0 3 0.003Refined solution: labels bitstrings costs counts probs0 0 10100 -4.0 550 0.5501 0 10001 -3.5 411 0.4112 0 01010 -2.5 3 0.0033 0 01001 -2.0 36 0.036For full parameter details, see the classical solvers API reference.
The Solver shortcut
Section titled “The Solver shortcut”For the common case, SolverConfig and Solver wrap solver selection through ClassicalSolvingConfig, and (optionally) the initial-solution sampling into a single call:
from qubosolver import ( Instance, Solver, SolverConfig, ClassicalSolvingConfig, matrix, analysis,)from dataclasses import asdictimport pprint
instance = Instance( matrix.tensor( [ [-2.0, 1.0, 0.0, 1.5, 0.0], [1.0, -1.5, 1.0, 0.0, 0.5], [0.0, 1.0, -2.0, 1.0, 1.0], [1.5, 0.0, 1.0, -1.0, 0.5], [0.0, 0.5, 1.0, 0.5, -1.5], ] ))
classical_config = ClassicalSolvingConfig( algorithm="tabu_search", # algorithm="simulated_annealing", # algorithm="cplex",)solver_config = SolverConfig(solving=classical_config)solver = Solver(instance, solver_config)solution = solver.solve()
print(pprint.pformat(asdict(solver_config.solving)))print()print(analysis.to_dataframe([solution])){'algorithm': 'tabu_search', 'max_bitstrings': 1, 'max_iter': 100, 'time_limit': inf}
labels bitstrings costs counts probs0 0 10100 -4.0 1 1.0