Source code for tno.quantum.optimization.qubo.solvers._dwave._simulated_annealing_solver

"""This module contains the ``SimulatedAnnealingSolver`` class."""

from __future__ import annotations

from typing import Any, SupportsInt

from dwave.samplers import SimulatedAnnealingSampler
from numpy.random import RandomState

from tno.quantum.optimization.qubo.components import QUBO, Solver
from tno.quantum.optimization.qubo.solvers._dwave._dimod_sample_set_result import (
    DimodSampleSetResult,
)
from tno.quantum.optimization.qubo.solvers._dwave._utils import get_singleton
from tno.quantum.utils.validation import check_int, check_random_state


[docs]class SimulatedAnnealingSolver(Solver[DimodSampleSetResult]): """D-Wave simulated annealing solver. The :py:class:`SimulatedAnnealingSolver` class solves QUBOs using the D-Wave implementation (:py:class:`~dwave.samplers.SimulatedAnnealingSampler`) of simulated annealing. Example: >>> from tno.quantum.optimization.qubo.components import QUBO >>> from tno.quantum.optimization.qubo.solvers import SimulatedAnnealingSolver >>> >>> qubo = QUBO([[1, 2, 3], [4, -50, 6], [7, 8, 9]]) >>> solver = SimulatedAnnealingSolver() >>> result = solver.solve(qubo) >>> result.best_bitvector BitVector(010) """
[docs] def __init__( self, *, random_state: int | RandomState | None = None, num_reads: SupportsInt = 1, num_sweeps: SupportsInt = 1000, **sample_kwargs: Any, ) -> None: """Init :py:class:`SimulatedAnnealingSolver`. Args: random_state: Random state for reproducibility. Overrides the D-Waves ``'seed'`` argument. Default is ``None``. num_reads: Maximum number of random samples to be drawn. Default is 1. num_sweeps: Number of sweeps used in annealing. Default is 1000. sample_kwargs: Additional keyword arguments that can be used for the sampler. See the D-Wave documentation of :py:meth:`~dwave.samplers.SimulatedAnnealingSampler.sample` for possible additional keyword definitions. Raises: ValueError: If `random_state` has invalid value, or if `num_reads` or `num_sweeps` is less than 1. TypeError: If `num_reads` or `num_sweeps` is not an integer. """ self.sampler = get_singleton(SimulatedAnnealingSampler) self.random_state = check_random_state(random_state, "random_state") self.num_reads = check_int(num_reads, "num_reads", l_bound=1) self.num_sweeps = check_int(num_sweeps, "num_sweeps", l_bound=1) self.sample_kwargs = sample_kwargs
def _solve(self, qubo: QUBO) -> DimodSampleSetResult: """Solve QUBO using ``SimulatedAnnealingSampler``.""" # Use seed from sample_kwargs, or generate one using random_state seed = self.sample_kwargs.get("seed", self.random_state.randint(2**31)) kwargs = dict(self.sample_kwargs) kwargs.pop("seed", None) kwargs.pop("num_reads", None) kwargs.pop("num_sweeps", None) response = self.sampler.sample( qubo.to_bqm(), seed=seed, num_reads=self.num_reads, num_sweeps=self.num_sweeps, **kwargs, ) return DimodSampleSetResult.from_result(qubo, response)