def test_infinite_loop_over_interruptable_runnable(self): """Stop signal must propagate to child runnable.""" class IntInc(Runnable): def __init__(self): super(IntInc, self).__init__() self.time_to_stop = threading.Event() self.first_run = threading.Event() def next(self, state): self.first_run.set() self.time_to_stop.wait() return state.updated(cnt=state.cnt + 1) def halt(self): self.time_to_stop.set() loop = Loop(IntInc()) s = loop.run(State(cnt=0)) # make sure loop body runnable is run at least once loop.runnable.first_run.wait() loop.stop() self.assertTrue(s.result().cnt >= 1)
def test_finite_loop(self): class Inc(Runnable): def next(self, state): return state.updated(cnt=state.cnt + 1) it = Loop(Inc(), 10) s = it.run(State(cnt=0)).result() self.assertEqual(s.cnt, 10)
def test_memo_in_a_loop(self): inc = TestLog.Inc() log = Log(key=lambda state: state.x, memo=True) wrk = Loop(inc | log, max_iter=3) inp = State(x=0) out = wrk.run(inp).result() self.assertEqual(len(log.records), 3) self.assertEqual([r['data'] for r in log.records], [1, 2, 3])
def test_basic(self): class Inc(Runnable): def next(self, state): return state.updated(cnt=state.cnt + 1) it = Loop(Inc(), max_iter=100, convergence=100, key=lambda _: None) s = it.run(State(cnt=0)).result() self.assertEqual(s.cnt, 100)
def test_infinite_loop_stops_before_first_run(self): """An infinite loop can be preemptively stopped (before starting).""" class Inc(Runnable): def next(self, state): return state.updated(cnt=state.cnt + 1) loop = Loop(Inc()) loop.stop() state = loop.run(State(cnt=0)) self.assertEqual(state.result().cnt, 0)
def test_loop(self): class Identity(Runnable, traits.MIMO): def next(self, states): return states prog = Loop(Identity(), max_iter=10, convergence=10, key=lambda _: None) ss = States(State(idx=0), State(idx=1)) res = prog.run(ss).result() self.assertEqual(res[0].idx, 0) self.assertEqual(res[1].idx, 1) with self.assertRaises(traits.StateDimensionalityError): prog.run(State()).result()
def test_infinite_loop_runs_after_stop(self): """An infinite loop can be started again after being stopped.""" class Inc(Runnable): def __init__(self): super(Inc, self).__init__() self.first_run = threading.Event() def next(self, state): self.first_run.set() return state.updated(cnt=state.cnt + 1) loop = Loop(Inc()) state1 = loop.run(State(cnt=0)) # make sure loop body runnable is run at least once, then issue stop loop.runnable.first_run.wait(timeout=1) loop.stop() # check the state AND make sure next() finishes (see #111) self.assertTrue(state1.result().cnt >= 1) # reset our test event object loop.runnable.first_run.clear() # run loop again state2 = loop.run(State(cnt=0)) # make sure loop body runnable is run at least once, then issue stop loop.runnable.first_run.wait(timeout=1) loop.stop() self.assertTrue(state2.result().cnt >= 1)
def test_validation(self): class simo(Runnable, traits.SIMO): def next(self, state): return States(state, state) with self.assertRaises(TypeError): Loop(simo())
def test_iter_walk(self): flow = Loop(RacingBranches(Runnable(), Runnable()) | ArgMin()) names = [r.name for r in iter_inorder(flow)] self.assertEqual(names, [ 'Loop', 'Branch', 'RacingBranches', 'Runnable', 'Runnable', 'ArgMin' ])
def test_callback_walk(self): flow = Loop(RacingBranches(Runnable(), Runnable()) | ArgMin()) names = [] walk_inorder(flow, visit=lambda r, _: names.append(r.name)) self.assertEqual(names, [ 'Loop', 'Branch', 'RacingBranches', 'Runnable', 'Runnable', 'ArgMin' ])
def test_loop(self): class MIMOIdent(traits.MIMO, Runnable): def next(self, state): return state wrk = Loop(MIMOIdent(), max_iter=10, convergence=10, key=lambda _: None) inp = States(State(idx=0), State(idx=1)) out = wrk.run(inp).result() self.assertEqual(out[0].idx, 0) self.assertEqual(out[1].idx, 1) with self.assertRaises(traits.StateDimensionalityError): wrk.run(State()).result()
def test_infinite_loop_stops(self): """An infinite loop can be stopped after at least one iteration.""" class Inc(Runnable): def __init__(self): super(Inc, self).__init__() self.first_run = threading.Event() def next(self, state): self.first_run.set() return state.updated(cnt=state.cnt + 1) loop = Loop(Inc()) state = loop.run(State(cnt=0)) # make sure loop body runnable is run at least once, then issue stop loop.runnable.first_run.wait(timeout=1) loop.stop() self.assertTrue(state.result().cnt >= 1)
def test_dimensions_match_on_compose(self): class A(Runnable, traits.ProblemSampler): def next(self, state): pass # dimensionality check Map(A()) | ArgMin() with self.assertRaises(TypeError): A() | ArgMin() with self.assertRaises(TypeError): ArgMin() | Map(A()) with self.assertRaises(TypeError): ArgMin() | Map(ArgMin()) with self.assertRaises(TypeError): Loop(ArgMin())
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))
problems = chain( sorted(glob('problems/qbsolv/bqp100_*'))[:5], sorted(glob('problems/qbsolv/bqp2500_*'))[:5], sorted(glob('problems/random-chimera/2048*'))[:5], sorted(glob('problems/random-chimera/8192*'))[:5], sorted(glob('problems/ac3/*'))[:5], ) solver_factories = [ ("10 second Tabu", lambda **kw: TabuProblemSampler(timeout=10000)), ("10k sweeps Simulated Annealing", lambda **kw: IdentityDecomposer() | SimulatedAnnealingSubproblemSampler(sweeps=10000) | SplatComposer()), ("qbsolv-like solver", lambda qpu, **kw: Loop(RacingBranches( InterruptableTabuSampler(quantum_timeout=200), EnergyImpactDecomposer(max_size=50, rolling=True, rolling_history=0.15) | QPUSubproblemAutoEmbeddingSampler(qpu_sampler=qpu) | SplatComposer()) | ArgMin(), max_iter=100, convergence=10)), ("tiling chimera solver", lambda qpu, **kw: Loop(RacingBranches( InterruptableTabuSampler(quantum_timeout=200), TilingChimeraDecomposer(size=(16, 16, 4)) | QPUSubproblemExternalEmbeddingSampler(qpu_sampler=qpu) | SplatComposer(), ) | ArgMin(), max_iter=100, convergence=10)), ("qbsolv-classic", lambda **kw: QBSolvProblemSampler()), ("qbsolv-qpu", lambda qpu, **kw: QBSolvProblemSampler(qpu_sampler=qpu)), ]
def sample(self, bqm, init_sample=None, max_iter=100, convergence=10, num_reads=1, sa_reads=1, sa_sweeps=1000, qpu_reads=100, qpu_sampler=None, max_subproblem_size=50): """Run Tabu search, Simulated annealing and QPU subproblem sampling (for high energy impact problem variables) in parallel and return the best samples. Args: bqm (:obj:`~dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. init_sample (:class:`~dimod.SampleSet`, callable, ``None``): Initial sample set (or sample generator) used for each "read". Use a random sample for each read by default. max_iter (int): Number of iterations in the hybrid algorithm. convergence (int): Number of iterations with no improvement that terminates sampling. num_reads (int): Number of reads. Each sample is the result of a single run of the hybrid algorithm. sa_reads (int): Number of reads in the simulated annealing branch. sa_sweeps (int): Number of sweeps in the simulated annealing branch. qpu_reads (int): Number of reads in the QPU branch. qpu_sampler (:class:`dimod.Sampler`, optional, default=DWaveSampler()): Quantum sampler such as a D-Wave system. max_subproblem_size (int): Maximum size of the subproblem selected in the QPU branch. Returns: :obj:`~dimod.SampleSet`: A `dimod` :obj:`.~dimod.SampleSet` object. """ if callable(init_sample): init_state_gen = lambda: State.from_sample(init_sample(), bqm) elif init_sample is None: init_state_gen = lambda: State.from_sample(random_sample(bqm), bqm) elif isinstance(init_sample, dimod.SampleSet): init_state_gen = lambda: State.from_sample(init_sample, bqm) else: raise TypeError( "'init_sample' should be a SampleSet or a SampleSet generator") subproblem_size = min(len(bqm), max_subproblem_size) iteration = RacingBranches( InterruptableTabuSampler(), InterruptableSimulatedAnnealingProblemSampler(num_reads=sa_reads, sweeps=sa_sweeps), EnergyImpactDecomposer(size=subproblem_size, rolling=True, rolling_history=0.3, traversal='bfs') | QPUSubproblemAutoEmbeddingSampler(num_reads=qpu_reads, qpu_sampler=qpu_sampler) | SplatComposer(), ) | ArgMin() self.runnable = Loop(iteration, max_iter=max_iter, convergence=convergence) samples = [] energies = [] for _ in range(num_reads): init_state = init_state_gen() final_state = self.runnable.run(init_state) # the best sample from each run is one "read" ss = final_state.result().samples ss.change_vartype(bqm.vartype, inplace=True) samples.append(ss.first.sample) energies.append(ss.first.energy) return dimod.SampleSet.from_samples(samples, vartype=bqm.vartype, energy=energies)
class KerberosSampler(dimod.Sampler): """An opinionated dimod-compatible hybrid asynchronous decomposition sampler for problems of arbitrary structure and size. Examples: This example solves a two-variable Ising model. >>> import dimod >>> response = KerberosSampler().sample_ising( ... {'a': -0.5, 'b': 1.0}, {('a', 'b'): -1}) >>> response.data_vectors['energy'] array([-1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5]) """ properties = None parameters = None runnable = None def __init__(self): self.parameters = { 'init_sample': [], 'max_iter': [], 'convergence': [], 'num_reads': [], 'sa_reads': [], 'sa_sweeps': [], 'qpu_reads': [], 'max_subproblem_size': [] } self.properties = {} def sample(self, bqm, init_sample=None, max_iter=100, convergence=10, num_reads=1, sa_reads=1, sa_sweeps=1000, qpu_reads=100, qpu_sampler=None, max_subproblem_size=50): """Run Tabu search, Simulated annealing and QPU subproblem sampling (for high energy impact problem variables) in parallel and return the best samples. Args: bqm (:obj:`~dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. init_sample (:class:`~dimod.SampleSet`, callable, ``None``): Initial sample set (or sample generator) used for each "read". Use a random sample for each read by default. max_iter (int): Number of iterations in the hybrid algorithm. convergence (int): Number of iterations with no improvement that terminates sampling. num_reads (int): Number of reads. Each sample is the result of a single run of the hybrid algorithm. sa_reads (int): Number of reads in the simulated annealing branch. sa_sweeps (int): Number of sweeps in the simulated annealing branch. qpu_reads (int): Number of reads in the QPU branch. qpu_sampler (:class:`dimod.Sampler`, optional, default=DWaveSampler()): Quantum sampler such as a D-Wave system. max_subproblem_size (int): Maximum size of the subproblem selected in the QPU branch. Returns: :obj:`~dimod.SampleSet`: A `dimod` :obj:`.~dimod.SampleSet` object. """ if callable(init_sample): init_state_gen = lambda: State.from_sample(init_sample(), bqm) elif init_sample is None: init_state_gen = lambda: State.from_sample(random_sample(bqm), bqm) elif isinstance(init_sample, dimod.SampleSet): init_state_gen = lambda: State.from_sample(init_sample, bqm) else: raise TypeError( "'init_sample' should be a SampleSet or a SampleSet generator") subproblem_size = min(len(bqm), max_subproblem_size) iteration = RacingBranches( InterruptableTabuSampler(), IdentityDecomposer() | SimulatedAnnealingSubproblemSampler(num_reads=sa_reads, sweeps=sa_sweeps) | SplatComposer(), EnergyImpactDecomposer( size=subproblem_size, rolling=True, rolling_history=0.2) | QPUSubproblemAutoEmbeddingSampler(num_reads=qpu_reads, qpu_sampler=qpu_sampler) | SplatComposer(), ) | ArgMin() self.runnable = Loop(iteration, max_iter=max_iter, convergence=convergence) samples = [] energies = [] for _ in range(num_reads): init_state = init_state_gen() final_state = self.runnable.run(init_state) # the best sample from each run is one "read" ss = final_state.result().samples ss.change_vartype(bqm.vartype, inplace=True) samples.append(ss.first.sample) energies.append(ss.first.energy) return dimod.SampleSet.from_samples(samples, vartype=bqm.vartype, energy=energies)
def test_loop(self): r = Loop(self.RunnableA()) self.assertEqual(self.children(r), ['RunnableA'])