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_embedding_superset(self): # source graph in the embedding is a superset of the bqm response = dimod.SampleSet(np.rec.array([([-1, 1, -1, 1, -1, 1, -1, 1], -1.4, 1), ([-1, 1, -1, -1, -1, 1, -1, -1], -1.4, 1), ([+1, -1, -1, -1, 1, -1, -1, -1], -1.6, 1), ([+1, -1, -1, -1, 1, -1, -1, -1], -1.6, 1)], dtype=[('sample', 'i1', (8,)), ('energy', '<f8'), ('num_occurrences', '<i8')]), [0, 1, 2, 3, 4, 5, 6, 7], {}, 'SPIN') embedding = {0: {0, 4}, 1: {1, 5}, 2: {2, 6}, 3: {3, 7}} bqm = dimod.BinaryQuadraticModel.from_ising([.1, .2], {(0, 1): 1.5}, 0.0) unembedded = dwave.embedding.unembed_sampleset(response, embedding, source_bqm=bqm) arr = np.rec.array([([-1, 1], -1.4, 1), ([-1, 1], -1.4, 1), ([+1, -1], -1.6, 1), ([+1, -1], -1.6, 1)], dtype=[('sample', 'i1', (2,)), ('energy', '<f8'), ('num_occurrences', '<i8')]) np.testing.assert_array_equal(arr, unembedded.record)
def next(self, state, **runopts): beta = runopts.get('beta', self.beta) beta = state.get('beta', beta) if beta is None: raise ValueError( 'beta must be given on construction or during run-time') ss = state.samples # calculate weights w = np.exp(-beta * ss.record.energy) p = w / sum(w) # resample idx = self.random.choice(len(ss), len(ss), p=p) record = ss.record[idx] info = ss.info.copy() info.update(beta=beta) new_samples = dimod.SampleSet(record, ss.variables, info, ss.vartype) return state.updated(samples=new_samples)
def next(self, state, **runopts): delta_beta = runopts.get('delta_beta', self.delta_beta) delta_beta = state.get('delta_beta', delta_beta) if delta_beta is None: raise ValueError( 'delta_beta must be given on construction or during run-time') ss = state.samples # calculate weights (note: to avoid overflow, we offset energy, as it # cancels out during probability calc) min_energy = ss.record.energy.min() w = np.exp(-delta_beta * (ss.record.energy - min_energy)) p = w / sum(w) # resample idx = self.random.choice(len(ss), len(ss), p=p) record = ss.record[idx] info = ss.info.copy() info.update(beta=state.beta, delta_beta=delta_beta) new_samples = dimod.SampleSet(record, ss.variables, info, ss.vartype) return state.updated(samples=new_samples)