def test_branch_with_single_component(self): """Traits requirements from inner runnable must be reflected in branch.""" class ValidSISO(Runnable, traits.SISO): def next(self, state): return state with self.assertRaises(traits.StateDimensionalityError): Branch(components=(ValidSISO(),)).run(States()).result() self.assertEqual(Branch(components=(ValidSISO(),)).run(State(x=1)).result().x, 1) class InvalidSISO(Runnable, traits.SISO): def next(self, state): return States(state, state) with self.assertRaises(traits.StateDimensionalityError): Branch(components=(InvalidSISO(),)).run(State()).result() Branch(components=(InvalidSISO(),)).run(States()).result() # input: list of states with subproblem # output: list of states with subsamples class SubproblemSamplerMIMO(Runnable, traits.MIMO, traits.SubproblemSampler): def next(self, states): return States(State(subsamples=1), State(subsamples=2)) with self.assertRaises(traits.StateDimensionalityError): Branch(components=(SubproblemSamplerMIMO(),)).run(State()).result() with self.assertRaises(traits.StateTraitMissingError): Branch(components=(SubproblemSamplerMIMO(),)).run(States(State())).result() r = Branch(components=(SubproblemSamplerMIMO(),)).run(States(State(subproblem=True))).result() self.assertEqual(r[0].subsamples, 1) self.assertEqual(r[1].subsamples, 2)
def next(self, state, **runopts): runopts.update(racing_context=True) futures = [ branch.run(state.updated(), **runopts) for branch in self.branches ] # as soon as one is done, stop all others done, _ = concurrent.futures.wait( futures, return_when=concurrent.futures.FIRST_COMPLETED) logger.trace( "RacingBranches done set: {}. Stopping remaining.".format(done)) self.stop() # debug info idx = futures.index(done.pop()) branch = self.branches[idx] logger.debug("{name} won idx={idx} branch={branch!r}".format( name=self.name, idx=idx, branch=branch)) # collect resolved states (in original order, not completion order!) states = States() for f in futures: states.append(f.result()) return states
def next(self, state): output = States() while True: try: state = self.runnable.run(state).result() output.append(state) except EndOfStream: break return output
def test_set_states_var(self): """All States have variable set.""" wrk = Const(x=1) inp = States(State(), State(x=0), State(x=None)) exp = States(State(x=1), State(x=1), State(x=1)) self.assertEqual(wrk.run(inp).result(), exp) wrk = Const(x=None) inp = States(State(), State(x=1)) exp = States(State(x=None), State(x=None)) self.assertEqual(wrk.run(inp).result(), exp)
def next(self, state, **runopts): samples = state.samples if not samples: raise ValueError("no input samples") states = States() n = len(samples) for start, stop in zip(range(n), range(1, n + 1)): sample = samples.slice(start, stop, sorted_by=None) states.append(state.updated(samples=sample)) return states
def next(self, state, **runopts): output = States() runopts.update(executor=immediate_executor, silent_rewind=False) while True: try: state = self.runnable.run(state, **runopts).result() output.append(state) except EndOfStream: break return output
def next(self, state, **runopts): futures = [ branch.run(state.updated(), **runopts) for branch in self.branches ] # wait for all branches to finish concurrent.futures.wait(futures, return_when=concurrent.futures.ALL_COMPLETED) # collect resolved states (in original order, not completion order) states = States() for f in futures: states.append(f.result()) return states
def test_mimo_with_specific_state_traits(self): # input: list of states with subproblem # output: list of states with subsamples class SubproblemSamplerMIMO(Runnable, traits.MIMO, traits.SubproblemSampler): def next(self, states): return States(State(subsamples=1), State(subsamples=2)) with self.assertRaises(traits.StateDimensionalityError): SubproblemSamplerMIMO().run(State()).result() with self.assertRaises(traits.StateTraitMissingError): SubproblemSamplerMIMO().run(States(State())).result() r = SubproblemSamplerMIMO().run(States(State(subproblem=True))).result() self.assertEqual(r[0].subsamples, 1) self.assertEqual(r[1].subsamples, 2)
def test_validation(self): bqm1 = dimod.BinaryQuadraticModel({'a': 1}, {}, 0, dimod.SPIN) bqm2 = dimod.BinaryQuadraticModel({'b': 1}, {}, 0, dimod.SPIN) s1 = State.from_sample({'a': +1}, bqm1) s2 = State.from_sample({'b': -1}, bqm2) # two input states required with self.assertRaises(ValueError): inp = States(s1, s1, s1) IsoenergeticClusterMove().run(inp).result() # variables must match with self.assertRaises(ValueError): inp = States(s1, s2) IsoenergeticClusterMove().run(inp).result()
def next(self, state, **runopts): output = States() runopts.update(executor=immediate_executor, silent_rewind=False) logger.debug("{} unwinding {!r}".format(self.name, self.runnable)) while True: try: state = self.runnable.run(state, **runopts).result() output.append(state) except EndOfStream: break logger.debug("{} collected {} states".format(self.name, len(output))) return output
def test_map_lambda(self): states = States(State(cnt=1), State(cnt=2)) result = Map(Lambda(lambda _, s: s.updated(cnt=s.cnt + 1))).run( states).result() self.assertEqual(result[0].cnt, states[0].cnt + 1) self.assertEqual(result[1].cnt, states[1].cnt + 1)
def test_not_validated(self): class NotValidated(Runnable, traits.NotValidated): def next(self, state): return state self.assertEqual(NotValidated().run(State(x=1)).result().x, 1) self.assertEqual(NotValidated().run(States(State(x=1))).result()[0].x, 1)
def test_dynamic_validation(self): class simo(traits.SIMO, Runnable): def next(self, state): return States(state, state) with self.assertRaises(StateDimensionalityError): Unwind(simo()).run(States()).result()
def next(self, states): self._futures = [self.runnable.run(state) for state in states] concurrent.futures.wait(self._futures, return_when=concurrent.futures.ALL_COMPLETED) return States(*(f.result() for f in self._futures))
def test_bimodal_cluster_sampling_statistics(self): bqm = dimod.BQM.from_qubo({'ab': 1, 'bd': 1, 'dc': 1, 'ca': 1}) nodes = sorted(bqm.variables) s1 = State.from_samples(dict(zip(nodes, [0, 1, 0, 0])), bqm) s2 = State.from_samples(dict(zip(nodes, [0, 0, 1, 0])), bqm) exp1 = SampleSet.from_samples_bqm(dict(zip(nodes, [0, 0, 0, 0])), bqm) exp2 = SampleSet.from_samples_bqm(dict(zip(nodes, [0, 1, 1, 0])), bqm) icm = IsoenergeticClusterMove(seed=None) inp = States(s1, s2) exp = [exp1, exp2] # split between [exp1, exp2] and [exp2, exp1] as output samples # should be ~50% cnt = 0 n = 100 for _ in range(n): res = icm.run(inp).result() r1, r2 = pluck(res, 'samples') # test responses are valid self.assertIn(r1, exp) self.assertIn(r2, exp) # verify total samples energy doesn't change after ICM self.assertEqual(self.total_energy(inp), self.total_energy(res)) # count responses if r1 == exp1 and r2 == exp2: cnt += 1 self.assertLess(cnt, 0.75 * n) self.assertGreater(cnt, 0.25 * n)
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_unstructured_runnable(self): initial = State(val=10) states = States(State(val=2), State(val=3)) multiply = Lambda(next=lambda self, s: s[0].updated(val=s[0].val * s[1].val)) result = Reduce(multiply, initial_state=initial).run(states).result() self.assertEqual(result.val, 10*2*3)
def test_validated(self): class Validated(traits.SISO, Runnable): def next(self, state): return state with self.assertRaises(traits.StateDimensionalityError): Validated().run(States()).result() self.assertEqual(Validated().run(State(x=1)).result().x, 1)
def test_single(self): bqm = dimod.BinaryQuadraticModel({}, {'ab': 1}, 0, dimod.SPIN) states = States(State.from_sample({'a': 1, 'b': -1}, bqm)) state = MergeSamples().run(states).result() self.assertEqual(state, states[0])
def test_siso(self): class ValidSISO(traits.SISO, Runnable): def next(self, state): return state with self.assertRaises(traits.StateDimensionalityError): ValidSISO().run(States()).result() self.assertEqual(ValidSISO().run(State(x=1)).result().x, 1) class InvalidSISO(traits.SISO, Runnable): def next(self, state): # should return a single State() return States(state, state) with self.assertRaises(traits.StateDimensionalityError): InvalidSISO().run(State()).result() InvalidSISO().run(States()).result()
def test_invalid_mimo(self): class InvalidMIMO(traits.MIMO, Runnable): def next(self, states): # should return States() return State() with self.assertRaises(traits.StateDimensionalityError): InvalidMIMO().run(States()).result()
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 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)
def next(self, states): """ICM between two first samples in the first two input states.""" if len(states) > 2: raise ValueError("exactly two input states required") inp1, inp2 = states bqm = inp1.problem ss1 = inp1.samples.change_vartype(dimod.BINARY, inplace=False) ss2 = inp2.samples.change_vartype(dimod.BINARY, inplace=False) # sanity check: we operate on the same set of variables if ss1.variables ^ ss2.variables: raise ValueError( "input samples not over the same set of variables") # reorder variables, if necessary # (use sequence comparison, not set) variables = list(ss1.variables) if ss2.variables != variables: reorder = [ss2.variables.index(v) for v in variables] record = ss2.record[:, reorder] ss2 = dimod.SampleSet(record, variables, ss2.info, ss2.vartype) # samples' symmetric difference (XOR) # (form clusters of input variables with opposite values) sample1 = ss1.record.sample[0] sample2 = ss2.record.sample[0] symdiff = sample1 ^ sample2 # for cluster detection we'll use a reduced problem graph graph = bqm.to_networkx_graph() # note: instead of numpy mask indexing of `notcluster`, we enumerate # non-cluster variables manually to avoid conversion of potentially # unhashable variable names to numpy types notcluster = [v for v, d in zip(variables, symdiff) if d == 0] graph.remove_nodes_from(notcluster) # pick a random variable that belongs to a cluster, then select the cluster node = self.random.choice(list(graph.nodes)) cluster = nx.node_connected_component(graph, node) # flip variables from `cluster` in both input samples flipper = np.array([1 if v in cluster else 0 for v in variables]) ss1.record.sample[0] ^= flipper ss2.record.sample[0] ^= flipper # change vartype back to input's type ss1.change_vartype(inp1.samples.vartype) ss2.change_vartype(inp2.samples.vartype) # update sampleset's energies ss1.record.energy = bqm.energies(ss1) ss2.record.energy = bqm.energies(ss2) return States(inp1.updated(samples=ss1), inp2.updated(samples=ss2))
def test_map(self): class A(Runnable, traits.ProblemDecomposer): def next(self, state): return state.updated(subproblem=state.problem) a = A() m = Map(a) r = m.run(States(State(problem=1))).result() self.assertSetEqual(m.inputs, a.inputs) self.assertSetEqual(m.outputs, a.outputs)
def next(self, states, **runopts): self._futures = [self.runnable.run(state, **runopts) for state in states] logger.debug("{} running {!r} on {} input states".format( self.name, self.runnable, len(states))) concurrent.futures.wait(self._futures, return_when=concurrent.futures.ALL_COMPLETED) return States(*(f.result() for f in self._futures))
def test_branch(self): class Inc(Runnable): def next(self, state): return state.updated(cnt=state.cnt + 1) states = States(State(cnt=1), State(cnt=2)) branch = Map(Inc()) | ArgMin('cnt') result = branch.run(states).result() self.assertEqual(result.cnt, states[0].cnt + 1)
def test_isolated(self): class Inc(Runnable): def next(self, state): return state.updated(cnt=state.cnt + 1) states = States(State(cnt=1), State(cnt=2)) result = Map(Inc()).run(states).result() self.assertEqual(result[0].cnt, states[0].cnt + 1) self.assertEqual(result[1].cnt, states[1].cnt + 1)
def test_mimo(self): """Parallel should support branches with States inputs""" inp = States(State(x=1), State(x=2)) wrk = ParallelBranches(Identity(), Identity(), Identity()) out = wrk.run(inp).result() self.assertEqual(len(out), 3) self.assertIsInstance(out, States) self.assertEqual(out.first, inp)
def next(self, states, **runopts): futures = [ branch.run(state.updated(), **runopts) for branch, state in zip(self.branches, states) ] logger.debug("{} running {} branches in parallel".format( self.name, len(futures))) # wait for all branches to finish concurrent.futures.wait(futures, return_when=concurrent.futures.ALL_COMPLETED) # collect resolved states (in original order, not completion order) states = States() for f in futures: states.append(f.result()) return states