def test_energy_minimization(self): sample0 = {0: -1, 1: -1, 2: +1, 3: +1} sample1 = {0: +1, 1: -1, 2: +1, 3: -1} samples = [sample0, sample1] embedding = {'a': {0, 1}, 'b': {2}, 'c': {3}} linear = {'a': -1, 'b': 0, 'c': 0} quadratic = {} chain_break_method = eutil.MinimizeEnergy(linear=linear, quadratic=quadratic) source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=chain_break_method) source0, source1 = source_samples # no broken chains self.assertEqual(source0, {'a': -1, 'b': +1, 'c': +1}) # in this case 'a' being spin-up minimizes the energy self.assertEqual(source1, {'a': +1, 'b': +1, 'c': -1}) linear = {'a': 1, 'b': 0, 'c': 0} quadratic = {('a', 'b'): -5} chain_break_method = eutil.MinimizeEnergy(linear=linear, quadratic=quadratic) source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=chain_break_method) source0, source1 = source_samples # no broken chains self.assertEqual(source0, {'a': -1, 'b': +1, 'c': +1}) # in this case 'a' being spin-up minimizes the energy due to the quadratic bias self.assertEqual(source1, {'a': +1, 'b': +1, 'c': -1}) # now we need two broken chains sample = {0: +1, 1: -1, 2: +1, 3: -1, 4: +1} samples = [sample] embedding = {'a': {0, 1}, 'b': {2, 3}, 'c': {4}} quadratic = {('a', 'b'): -1, ('b', 'c'): 1} chain_break_method = eutil.MinimizeEnergy(quadratic=quadratic) source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=chain_break_method) source, = source_samples self.assertEqual(source, {'b': -1, 'c': +1, 'a': -1})
def sample_ising(self, h, J, **parameters): """Sample from the provided unstructured Ising model. Args: h (list/dict): Linear terms of the model. J (dict of (int, int):float): Quadratic terms of the model. **parameters: Parameters for the sampling method, specified by the child sampler. Returns: :class:`dimod.Response` """ if isinstance(h, list): h = dict(enumerate(h)) # solve the problem on the child system child = self.child # apply the embedding to the given problem to map it to the child sampler __, target_edgelist, target_adjacency = child.structure # get the embedding embedding = minorminer.find_embedding(J, target_edgelist) if J and not embedding: raise ValueError("no embedding found") # this should change in later versions if isinstance(embedding, list): embedding = dict(enumerate(embedding)) h_emb, J_emb, J_chain = embutil.embed_ising(h, J, embedding, target_adjacency) J_emb.update(J_chain) response = child.sample_ising(h_emb, J_emb, **parameters) # unembed the problem and save to a new response object samples = embutil.unembed_samples( response, embedding, chain_break_method=embutil.minimize_energy, linear=h, quadratic=J) # needed by minimize_energy # source_response = dimod.Response(dimod.SPIN) data_vectors = response.data_vectors data_vectors['energy'] = [ dimod.ising_energy(sample, h, J) for sample in samples ] return dimod.Response.from_dicts(samples, data_vectors, info=response.info, vartype=dimod.SPIN)
def sample_ising(self, h, J, **kwargs): """Sample from the sub Chimera lattice. Args: h (list/dict): Linear terms of the model. J (dict of (int, int):float): Quadratic terms of the model. **kwargs: Parameters for the sampling method, specified per solver. Returns: :class:`dimod.SpinResponse` """ __, __, adjacency = self.structure if not all(v in adjacency for v in h): raise ValueError( "nodes in linear bias do not map to the structure") if not all(u in adjacency[v] for u, v in J): raise ValueError( "edges in quadratic bias do not map to the structure") # apply the embeddings to the given problem to tile it across the child sampler h_embs = {} J_embs = {} for embedding in self.embeddings: __, __, target_adjacency = self.child.structure h_emb, J_emb, J_chain = embutil.embed_ising( h, J, embedding, target_adjacency) assert (not J_chain) h_embs.update(h_emb) J_embs.update(J_emb) # solve the problem on the child system response = self.child.sample_ising(h_embs, J_embs, **kwargs) # unembed the tiled problem and combine results into one response object source_response = dimod.Response(dimod.SPIN) for embedding in self.embeddings: samples = embutil.unembed_samples( response, embedding, chain_break_method=embutil.minimize_energy, linear=h, quadratic=J) # needed by minimize_energy for sample, (__, data) in zip(samples, response.df_data.iterrows()): data['energy'] = dimod.ising_energy(sample, h, J) source_response.add_sample(sample, **data.to_dict()) return source_response
def test_discard(self): sample0 = {0: -1, 1: -1, 2: +1} sample1 = {0: +1, 1: -1, 2: +1} samples = [sample0, sample1] embedding = {'a': {0, 1, 2}} # specify that majority vote should be used source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=eutil.discard) # no samples should be returned because they are all broken self.assertEqual(len(source_samples), 0) # now set up an embedding that works for one sample and not the other embedding = {'a': {0, 1}, 'b': {2}} # specify that majority vote should be used source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=eutil.discard) # only the first sample should be returned self.assertEqual(len(source_samples), 1) self.assertEqual(source_samples, [{'a': -1, 'b': +1}])
def test_majority_vote(self): """should return the most common value in the chain""" sample0 = {0: -1, 1: -1, 2: +1} sample1 = {0: +1, 1: -1, 2: +1} samples = [sample0, sample1] embedding = {'a': {0, 1, 2}} # specify that majority vote should be used source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=eutil.majority_vote) source0, source1 = source_samples self.assertEqual(source0['a'], -1) self.assertEqual(source1['a'], +1)
def test_discard_with_dimod(self): sample0 = {0: -1, 1: -1, 2: +1} sample1 = {0: +1, 1: -1, 2: +1} samples = [sample0, sample1] # now set up an embedding that works for one sample and not the other embedding = {'a': {0, 1}, 'b': {2}} # load the samples into a dimod response response = dimod.SpinResponse() response.add_samples_from(samples, (0 for __ in samples)) # specify that majority vote should be used source_samples = eutil.unembed_samples( response, embedding, chain_break_method=eutil.discard) # only the first sample should be returned self.assertEqual(len(source_samples), 1) self.assertEqual(source_samples, [{'a': -1, 'b': +1}])
def test_majority_vote_with_dimod(self): sample0 = {0: -1, 1: -1, 2: +1} sample1 = {0: +1, 1: -1, 2: +1} samples = [sample0, sample1] embedding = {'a': {0, 1, 2}} # load the samples into a dimod response response = dimod.SpinResponse() response.add_samples_from(samples, (0 for __ in samples)) # specify that majority vote should be used source_samples = eutil.unembed_samples( response, embedding, chain_break_method=eutil.majority_vote) source0, source1 = source_samples self.assertEqual(source0['a'], -1) self.assertEqual(source1['a'], +1)
def test_typical(self): """simple smoke tests trying to replicate 'normal' usage.""" nodes = range(10) target_samples = [{v: random.choice((-1, 1)) for v in nodes} for __ in range(100)] # embedding is map half the target vars to one source, and the other half to # another embedding = {'a': range(5), 'b': range(5, 10)} source_samples = eutil.unembed_samples(target_samples, embedding) # not checking correctness of samples, just that they have the correct form self.assertEqual(len(source_samples), 100) for sample in source_samples: self.assertIsInstance(sample, dict) self.assertEqual(set(sample), {'a', 'b'}) # maps to source vars self.assertTrue(all(bias in (-1, 1) for bias in sample.values()))
def test_typical_dimod_response(self): """unembed should be compatible with the dimod response object""" nodes = range(10) target_samples = [{v: random.choice((-1, 1)) for v in nodes} for __ in range(100)] # load the samples into a dimod response response = dimod.SpinResponse() response.add_samples_from(target_samples, (0 for __ in target_samples)) # embedding is map half the target vars to one source, and the other half to # another embedding = {'a': range(5), 'b': range(5, 10)} # use the response as the target_samples source_samples = eutil.unembed_samples(response, embedding) # not checking correctness of samples, just that they have the correct form self.assertEqual(len(source_samples), 100) for sample in source_samples: self.assertIsInstance(sample, dict) self.assertEqual(set(sample), {'a', 'b'}) # maps to source vars self.assertTrue(all(bias in (-1, 1) for bias in sample.values()))
def test_energy_minimization(self): sample0 = {0: -1, 1: -1, 2: +1, 3: +1} sample1 = {0: +1, 1: -1, 2: +1, 3: -1} samples = [sample0, sample1] embedding = {'a': {0, 1}, 'b': {2}, 'c': {3}} # minimize energy requires `linear` and `quadratic` keyword args with self.assertRaises(TypeError): eutil.unembed_samples(samples, embedding, chain_break_method=eutil.minimize_energy) linear = {'a': -1, 'b': 0, 'c': 0} quadratic = {} source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=eutil.minimize_energy, linear=linear, quadratic=quadratic) source0, source1 = source_samples # no broken chains self.assertEqual(source0, {'a': -1, 'b': +1, 'c': +1}) # in this case 'a' being spin-up minimizes the energy self.assertEqual(source1, {'a': +1, 'b': +1, 'c': -1}) linear = {'a': 1, 'b': 0, 'c': 0} quadratic = {('a', 'b'): -5} source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=eutil.minimize_energy, linear=linear, quadratic=quadratic) source0, source1 = source_samples # no broken chains self.assertEqual(source0, {'a': -1, 'b': +1, 'c': +1}) # in this case 'a' being spin-up minimizes the energy due to the quadratic bias self.assertEqual(source1, {'a': +1, 'b': +1, 'c': -1}) # now we need two broken chains sample = {0: +1, 1: -1, 2: +1, 3: -1, 4: +1} samples = [sample] embedding = {'a': {0, 1}, 'b': {2, 3}, 'c': {4}} quadratic = {('a', 'b'): -1, ('b', 'c'): 1} source_samples = eutil.unembed_samples( samples, embedding, chain_break_method=eutil.minimize_energy, quadratic=quadratic) source, = source_samples self.assertEqual(source, {'b': -1, 'c': +1, 'a': -1})
def sample_ising(self, h, J, **kwargs): """Sample from the sub-Chimera lattice. Args: h (list/dict): Linear terms of the model. J (dict of (int, int):float): Quadratic terms of the model. **kwargs: Parameters for the sampling method, specified per solver. Returns: :class:`dimod.Response` """ __, __, adjacency = self.structure if not all(v in adjacency for v in h): raise ValueError( "nodes in linear bias do not map to the structure") if not all(u in adjacency[v] for u, v in J): raise ValueError( "edges in quadratic bias do not map to the structure") # apply the embeddings to the given problem to tile it across the child sampler h_embs = {} J_embs = {} for embedding in self.embeddings: __, __, target_adjacency = self.child.structure h_emb, J_emb, J_chain = embutil.embed_ising( h, J, embedding, target_adjacency) assert (not J_chain) h_embs.update(h_emb) J_embs.update(J_emb) # solve the problem on the child system response = self.child.sample_ising(h_embs, J_embs, **kwargs) data_vectors = response.data_vectors.copy() source_response = None for embedding in self.embeddings: samples = embutil.unembed_samples( response, embedding, chain_break_method=embutil.minimize_energy, linear=h, quadratic=J) # needed by minimize_energy # override the energy because it might have changed data_vectors['energy'] = [ dimod.ising_energy(sample, h, J) for sample in samples ] tile_response = dimod.Response.from_dicts(samples, data_vectors) if source_response is None: source_response = tile_response source_response.info.update( response.info) # overwrite the info else: source_response.update(tile_response) return source_response
def sample_ising(self, h, J, apply_flux_bias_offsets=True, **kwargs): """Sample from the given Ising model. Args: h (list/dict): Linear terms of the model. J (dict of (int, int):float): Quadratic terms of the model. apply_flux_bias_offsets (bool, optional): If True, use the calculated flux_bias offsets (if available). **kwargs: Parameters for the sampling method, specified by the child sampler. """ __, __, adjacency = self.structure if not all(v in adjacency for v in h): raise ValueError( "nodes in linear bias do not map to the structure") if not all(u in adjacency[v] for u, v in J): raise ValueError( "edges in linear bias do not map to the structure") # apply the embedding to the given problem to map it to the child sampler __, __, target_adjacency = self.child.structure h_emb, J_emb, J_chain = embutil.embed_ising(h, J, self.embedding, target_adjacency, self.chain_strength) J_emb.update(J_chain) # solve the problem on the child system child = self.child if apply_flux_bias_offsets and self.flux_biases is not None: # If self.flux_biases is in the old format (list of lists) convert it to the new format (flat list). if isinstance(self.flux_biases[0], list): flux_bias_dict = dict(self.flux_biases) kwargs[FLUX_BIAS_KWARG] = [ flux_bias_dict.get(v, 0.) for v in range(child.properties['num_qubits']) ] else: kwargs[FLUX_BIAS_KWARG] = self.flux_biases assert len(kwargs[FLUX_BIAS_KWARG]) == child.properties['num_qubits'], \ "{} must have length {}, the solver's num_qubits."\ .format(FLUX_BIAS_KWARG, child.properties['num_qubits']) # Embed arguments providing initial states for reverse annealing, if applicable. kwargs = _embed_initial_state_kwargs(kwargs, self.embedding, self.child.structure[0]) response = child.sample_ising(h_emb, J_emb, **kwargs) # unembed the problem and save to a new response object samples = embutil.unembed_samples( response.samples(sorted_by=None), self.embedding, chain_break_method=embutil.minimize_energy, linear=h, quadratic=J) # needed by minimize_energy # source_response = dimod.Response(dimod.SPIN) data_vectors = response.data_vectors data_vectors['energy'] = [ dimod.ising_energy(sample, h, J) for sample in samples ] return dimod.Response.from_dicts(samples, data_vectors, info=response.info, vartype=dimod.SPIN)