def test_nontrivial_subproblem(self): """Check multi-variable multi-coupler subproblem creation. A 3by3 square lattice, with a 2x2 lattice subsolver, is the simplest non-trivial test with edges in the decomposed problem. """ problem_dims = (3, 3) #Vertical edges edgelist = [((i, j), (i + 1, j)) for i in range(problem_dims[0] - 1) for j in range(problem_dims[1])] #Horizontal edges edgelist += [((i, j), (i, j + 1)) for i in range(problem_dims[0]) for j in range(problem_dims[1] - 1)] bqm = dimod.BinaryQuadraticModel.from_ising( {}, {edge: 1 for edge in edgelist}) origin_embeddings = [{(i, j): None for i in range(2) for j in range(2)}] state = State.from_sample(min_sample(bqm), bqm, origin_embeddings=origin_embeddings, problem_dims=problem_dims) # Creates one of 3x3 different subsubproblems, some of which are # disconnected, and some connected # Run multiple times to prevent coincidental agreement runnable = SublatticeDecomposer() for _ in range(10): state = runnable.next(state) self.assertEqual(len(state.subproblem.variables), 4) self.assertIn(next(iter(state.subproblem.variables)), bqm.variables) self.assertEqual(len(state.embedding), 4) self.assertIn(next(iter(state.embedding.keys())), bqm.variables)
def test_next_on_different_sized_constraints(self): bqm = dimod.BinaryQuadraticModel.empty(dimod.SPIN) variables = list('abcdefg') fixed_variables = list('abc') size = 3 constraints = [] # Set BQM and constraints of varying lengths for triplet in itertools.combinations(variables, size): for u, v in itertools.combinations(triplet, 2): bqm.add_interaction(u, v, -1) non_fixed_variables = set(triplet) - set(fixed_variables) constraints.append(non_fixed_variables) for fixed_variable in fixed_variables: bqm.fix_variable(fixed_variable, 1) # Get new state rcd = RandomConstraintDecomposer(size, constraints) state = State.from_sample(min_sample(bqm), bqm) newstate = rcd.run(state).result() self.assertIn('subproblem', newstate) self.assertTrue(len(newstate.subproblem) <= size) # correct size
def sample(self, bqm, initial_sample=None): """Sample from a binary quadratic model using composed runnable sampler. Args: bqm (:obj:`~dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. initial_sample (dict, default=None): `bqm`-compatible sample used for initial state construction. Defaults to `hybrid.utils.min_sample(bqm)`. Returns: :obj:`~dimod.Response`: A `dimod` :obj:`.~dimod.Response` object. """ if not isinstance(bqm, dimod.BinaryQuadraticModel): raise TypeError("'bqm' should be BinaryQuadraticModel") if initial_sample is None: initial_sample = min_sample(bqm) else: initial_sample = sample_as_dict(initial_sample) if len(initial_sample) != len(bqm): raise ValueError( "size of 'initial_sample' incompatible with 'bqm'") initial_state = State.from_sample(initial_sample, bqm) final_state = self._runnable_solver.run(initial_state) return dimod.Response.from_future( final_state, result_hook=lambda f: f.result().samples)
def test_trivial_subproblem(self): """Check single-variable no-coupler subproblem creation. A 2by2 square lattice (a square), with a single variable subsolver, is the simplest non-trivial test. """ problem_dims = (2, 2) # Vertical edges edgelist = [((i, j), (i + 1, j)) for i in range(problem_dims[0] - 1) for j in range(problem_dims[1])] # Horizontal edges edgelist += [((i, j), (i, j + 1)) for i in range(problem_dims[0]) for j in range(problem_dims[1] - 1)] bqm = dimod.BinaryQuadraticModel.from_ising( {}, {edge: 1 for edge in edgelist}) origin_embeddings = [{(0, 0): [0]}] state = State.from_sample(min_sample(bqm), bqm, origin_embeddings=origin_embeddings, problem_dims=problem_dims) # Creates subproblems located randomly at (0, 0), (0, 1), (1, 0) and # (1, 1). runnable = SublatticeDecomposer() for _ in range(10): state = runnable.next(state) self.assertEqual(len(state.subproblem.variables), 1) self.assertIn(next(iter(state.subproblem.variables)), bqm.variables) self.assertEqual(len(state.embedding), 1) self.assertIn(next(iter(state.embedding.keys())), bqm.variables)
def run(problems, solver_factories): results = OrderedDict() # reuse the cloud client qpu = EmbeddingComposite(DWaveSampler()) for problem in problems: results[problem] = OrderedDict() with open(problem) as fp: bqm = dimod.BinaryQuadraticModel.from_coo(fp) for name, factory in solver_factories: case = '{!r} with {!r}'.format(problem, name) try: solver = factory(qpu=qpu) init_state = State.from_sample(min_sample(bqm), bqm) with tictoc(case) as timer: solution = solver.run(init_state).result() except Exception as exc: print("FAILED {case}: {exc!r}".format(**locals())) results[problem][name] = repr(exc) else: print("case={case!r}" " energy={solution.samples.first.energy!r}," " wallclock={timer.dt!r}".format(**locals())) results[problem][name] = dict( energy=solution.samples.first.energy, wallclock=timer.dt)
def test_basic(self): bqm = dimod.BinaryQuadraticModel({}, {'ab': 1, 'bc': -1, 'ca': 1}, 0, dimod.SPIN) state = State.from_sample(min_sample(bqm), bqm) antistate = State.from_sample(max_sample(bqm), bqm) result = GreedyPathMerge().run(States(state, antistate)).result() self.assertEqual(result.samples.first.energy, -3.0)
def test_default_fold(self): bqm = dimod.BinaryQuadraticModel({'a': 1}, {}, 0, dimod.SPIN) states = States( State.from_sample(min_sample(bqm), bqm), # energy: -1 State.from_sample(max_sample(bqm), bqm), # energy: +1 ) best = ArgMin().run(states).result() self.assertEqual(best.samples.first.energy, -1)
def sample(self, bqm, initial_sample=None, return_state=False, **params): """Sample from a binary quadratic model using composed runnable sampler. Args: bqm (:obj:`~dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. initial_sample (dict, default=None): `bqm`-compatible sample used for initial state construction. Defaults to `hybrid.utils.min_sample(bqm)`. return_state (bool, optional, default=False): If True, the final state is added to :attr:`dimod.SampleSet.info` of the returned sample set. Note that if a `state` key already exists in the sample set then it is overwritten. **params (dict): Sampling parameters passed down to the underlying workflow as run-time parameters. Note: Sampling via hybrid workflow is run asynchronously, and a sample set is returned as soon as workflow starts running. A blocking result resolve occurres on the first attribute access to the returned sample set. Returns: :class:`~dimod.SampleSet`: Possibly yet unresolved sample set. """ if not isinstance(bqm, dimod.BinaryQuadraticModel): raise TypeError("'bqm' should be BinaryQuadraticModel") if initial_sample is None: initial_sample = min_sample(bqm) else: initial_sample = sample_as_dict(initial_sample) if len(initial_sample) != len(bqm): raise ValueError( "size of 'initial_sample' incompatible with 'bqm'") initial_state = State.from_sample(initial_sample, bqm) final_state = self._workflow.run(initial_state, **params) def result_hook(state): resolved = state.result() ss = resolved.samples if return_state: # note: this creates a cyclic reference to `samples` from the # sample set via `info['state']`, but that shouldn't be a # problem for GC ss.info.update(state=resolved) return ss return dimod.SampleSet.from_future(final_state, result_hook=result_hook)
def test_custom_fold(self): bqm = dimod.BinaryQuadraticModel({'a': 1}, {}, 0, dimod.SPIN) states = States( State.from_sample(min_sample(bqm), bqm), # energy: -1 State.from_sample(max_sample(bqm), bqm), # energy: +1 ) fold = ArgMin(key=lambda s: -s.samples.first.energy) best = fold.run(states).result() self.assertEqual(best.samples.first.energy, 1)
class TestHybridRunnable(unittest.TestCase): bqm = dimod.BinaryQuadraticModel({}, { 'ab': 1, 'bc': 1, 'ca': -1 }, 0, dimod.SPIN) init_state = State.from_sample(min_sample(bqm), bqm) def test_generic(self): runnable = HybridRunnable(TabuSampler(), fields=('problem', 'samples')) response = runnable.run(self.init_state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0) def test_validation(self): with self.assertRaises(TypeError): HybridRunnable(1, 'ab') with self.assertRaises(ValueError): HybridRunnable(TabuSampler(), None) with self.assertRaises(ValueError): HybridRunnable(TabuSampler(), ('a')) self.assertIsInstance(HybridRunnable(TabuSampler(), 'ab'), HybridRunnable) self.assertIsInstance(HybridRunnable(TabuSampler(), ('a', 'b')), HybridRunnable) self.assertIsInstance(HybridRunnable(TabuSampler(), ['a', 'b']), HybridRunnable) def test_problem_sampler_runnable(self): runnable = HybridProblemRunnable(TabuSampler()) response = runnable.run(self.init_state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0) def test_subproblem_sampler_runnable(self): runnable = HybridSubproblemRunnable(TabuSampler()) state = self.init_state.updated(subproblem=self.bqm) response = runnable.run(state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().subsamples.record[0].energy, -3.0) def test_runnable_composition(self): runnable = IdentityDecomposer() | HybridSubproblemRunnable( TabuSampler()) | IdentityComposer() response = runnable.run(self.init_state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0)
def test_racing_workflow_with_oracle_subsolver(self): workflow = hybrid.LoopUntilNoImprovement(hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=1) | HybridSubproblemRunnable(dimod.ExactSolver()) | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=3) state = State.from_sample(min_sample(self.bqm), self.bqm) response = workflow.run(state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0)
def test_custom_key(self): """Custom key function works, here best state has the highest energy.""" bqm = dimod.BinaryQuadraticModel({'a': 1}, {}, 0, dimod.SPIN) states = States( State.from_sample(min_sample(bqm), bqm), # energy: -1 State.from_sample(max_sample(bqm), bqm), # energy: +1 ) tracker = TrackMin(key=lambda s: -s.samples.first.energy) for state in states: tracker.run(state).result() self.assertEqual(tracker.best.samples.first.energy, +1)
def test_default_tracking(self): """Best seen state is kept (default: state with sampleset with the lowest energy)""" bqm = dimod.BinaryQuadraticModel({'a': 1}, {}, 0, dimod.SPIN) min_state = State.from_sample(min_sample(bqm), bqm) # energy: -1 max_state = State.from_sample(max_sample(bqm), bqm) # energy: +1 tracker = TrackMin() _ = tracker.run(max_state).result() self.assertEqual(tracker.best.samples.first.energy, +1) _ = tracker.run(min_state).result() self.assertEqual(tracker.best.samples.first.energy, -1) _ = tracker.run(max_state).result() self.assertEqual(tracker.best.samples.first.energy, -1)
class TestRandomSubproblemDecomposer(unittest.TestCase): bqm = dimod.BinaryQuadraticModel({}, {'ab': 1, 'bc': 1}, 0, dimod.SPIN) state = State.from_sample(min_sample(bqm), bqm) def test_simple(self): runnable = RandomSubproblemDecomposer(size=1) state = self.state for _ in range(10): state = runnable.next(state) self.assertEqual(len(state.subproblem.variables), 1) self.assertIn(next(iter(state.subproblem.variables)), self.bqm.variables) def test_look_and_feel(self): self.assertEqual(repr(RandomSubproblemDecomposer(7)), 'RandomSubproblemDecomposer(size=7)')
def test_typical_construction(self): bqm = dimod.BinaryQuadraticModel.empty(dimod.SPIN) variables = list('abcdefg') constraints = [] for triplet in itertools.combinations(variables, 3): for u, v in itertools.combinations(triplet, 2): bqm.add_interaction(u, v, -1) constraints.append(triplet) rcd = RandomConstraintDecomposer(3, constraints) rcd.init(state=State.from_sample(min_sample(bqm), bqm)) # check that the graph is complete G = rcd.constraint_graph for i in range(len(constraints)): self.assertIn(i, G.nodes)
def test_next(self): bqm = dimod.BinaryQuadraticModel.empty(dimod.SPIN) variables = list('abcdefg') constraints = [] for triplet in itertools.combinations(variables, 3): for u, v in itertools.combinations(triplet, 2): bqm.add_interaction(u, v, -1) constraints.append(triplet) rcd = RandomConstraintDecomposer(3, constraints) state = State.from_sample(min_sample(bqm), bqm) newstate = rcd.run(state).result() self.assertIn('subproblem', newstate) self.assertTrue(len(newstate.subproblem) <= 3) # correct size
def test_sampling_parameters_filtering(self): class Sampler(dimod.ExactSolver): """Exact solver that fails if a sampling parameter is provided.""" parameters = {} def sample(self, bqm): return super().sample(bqm) workflow = hybrid.LoopUntilNoImprovement(hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=1) | HybridSubproblemRunnable(Sampler()) | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=3) state = State.from_sample(min_sample(self.bqm), self.bqm) response = workflow.run(state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0)
def test_exclude_dimensions(self): """Check exclude_dims parameter at origin_embedding_index=0. If all dimensions are excluded, ``embedding`` field should match the ``origin_embedding``. """ problem_dims = (3, 3) # Vertical edges edgelist = [((i, j), (i + 1, j)) for i in range(problem_dims[0] - 1) for j in range(problem_dims[1])] # Horizontal edges edgelist += [((i, j), (i, j + 1)) for i in range(problem_dims[0]) for j in range(problem_dims[1] - 1)] bqm = dimod.BinaryQuadraticModel.from_ising( {}, {edge: 1 for edge in edgelist}) origin_embeddings = [{(i, j): None for i in range(2) for j in range(2)}] exclude_dims = list(range(len(problem_dims))) oei = 0 state = State.from_sample(min_sample(bqm), bqm, origin_embeddings=origin_embeddings, problem_dims=problem_dims, exclude_dims=exclude_dims, origin_embedding_index=oei) # Creates a 2x2 subproblem at the origin for 0th embedding # Run multiple times to prevent coincidental agreement runnable = SublatticeDecomposer() for _ in range(10): state = runnable.next(state) self.assertEqual(len(state.subproblem.variables), 4) self.assertIn(next(iter(state.subproblem.variables)), bqm.variables) self.assertEqual(len(state.embedding), 4) self.assertIn(next(iter(state.embedding.keys())), bqm.variables) self.assertIn(next(iter(state.embedding)), state.origin_embeddings[oei])
import dimod from hybrid.samplers import (QPUSubproblemAutoEmbeddingSampler, InterruptableTabuSampler) from hybrid.decomposers import EnergyImpactDecomposer from hybrid.composers import SplatComposer from hybrid.core import State from hybrid.flow import RacingBranches, ArgMin, Loop from hybrid.utils import min_sample # load a problem problem = sys.argv[1] with open(problem) as fp: bqm = dimod.BinaryQuadraticModel.from_coo(fp) # define the solver iteration = RacingBranches( InterruptableTabuSampler(), EnergyImpactDecomposer(max_size=50, rolling=True, rolling_history=0.15) | QPUSubproblemAutoEmbeddingSampler() | SplatComposer()) | ArgMin() main = Loop(iteration, max_iter=10, convergence=3) # run solver init_state = State.from_sample(min_sample(bqm), bqm) solution = main.run(init_state).result() # show results print("Solution: sample={s.samples.first}".format(s=solution))
class TestHybridRunnable(unittest.TestCase): bqm = dimod.BinaryQuadraticModel({}, { 'ab': 1, 'bc': 1, 'ca': -1 }, 0, dimod.SPIN) init_state = State.from_sample(min_sample(bqm), bqm) def test_generic(self): runnable = HybridRunnable(TabuSampler(), fields=('problem', 'samples')) response = runnable.run(self.init_state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0) def test_validation(self): with self.assertRaises(TypeError): HybridRunnable(1, 'ab') with self.assertRaises(ValueError): HybridRunnable(TabuSampler(), None) with self.assertRaises(ValueError): HybridRunnable(TabuSampler(), ('a')) self.assertIsInstance(HybridRunnable(TabuSampler(), 'ab'), HybridRunnable) self.assertIsInstance(HybridRunnable(TabuSampler(), ('a', 'b')), HybridRunnable) self.assertIsInstance(HybridRunnable(TabuSampler(), ['a', 'b']), HybridRunnable) def test_problem_sampler_runnable(self): runnable = HybridProblemRunnable(TabuSampler()) response = runnable.run(self.init_state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0) def test_subproblem_sampler_runnable(self): runnable = HybridSubproblemRunnable(TabuSampler()) state = self.init_state.updated(subproblem=self.bqm) response = runnable.run(state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().subsamples.record[0].energy, -3.0) def test_runnable_composition(self): runnable = IdentityDecomposer() | HybridSubproblemRunnable( TabuSampler()) | IdentityComposer() response = runnable.run(self.init_state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0) def test_racing_workflow_with_oracle_subsolver(self): workflow = hybrid.LoopUntilNoImprovement(hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=1) | HybridSubproblemRunnable(dimod.ExactSolver()) | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=3) state = State.from_sample(min_sample(self.bqm), self.bqm) response = workflow.run(state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0) def test_sampling_parameters_filtering(self): class Sampler(dimod.ExactSolver): """Exact solver that fails if a sampling parameter is provided.""" parameters = {} def sample(self, bqm): return super().sample(bqm) workflow = hybrid.LoopUntilNoImprovement(hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=1) | HybridSubproblemRunnable(Sampler()) | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=3) state = State.from_sample(min_sample(self.bqm), self.bqm) response = workflow.run(state) self.assertIsInstance(response, concurrent.futures.Future) self.assertEqual(response.result().samples.record[0].energy, -3.0)