def test_embed_bad_chain(self): h = {} j = {(0, 1): 1} embeddings = {0: {0, 2}, 1: {1}} # (0, 2) not connected adj = {0: {1}, 1: {0, 2}, 2: {1}} with self.assertRaises(ValueError): eutil.embed_ising(h, j, embeddings, adj)
def test_embed_j_index_too_large(self): """j references a variable not mentioned in embedding""" h = {} j = {(0, 1): -1, (0, 2): 1} embedding = {0: (0, 1), 1: (2, )} adj = nx.Graph() adj.add_edges_from({(0, 1), (1, 2)}) with self.assertRaises(ValueError): eutil.embed_ising(h, j, embedding, adj)
def test_embed_h_embedding_mismatch(self): """there is not a mapping in embedding for every var in h""" h = dict(zip(range(3), [1, 2, 3])) j = {} embedding = {0: (0, 1), 1: (2, )} adj = nx.Graph() adj.add_edges_from({(0, 1), (1, 2)}) with self.assertRaises(ValueError): eutil.embed_ising(h, j, embedding, adj)
def test_embedding_not_in_adj(self): """embedding refers to a variable not in the adjacency""" h = {0: 0, 1: 0} J = {(0, 1): 1} embedding = {0: [0, 1], 1: [2]} adjacency = {0: {1}, 1: {0}} with self.assertRaises(ValueError): eutil.embed_ising(h, J, embedding, adjacency)
def test_embed_nonadj(self): """chain in embedding has non-adjacenct nodes""" h = {} j = {(0, 1): 1} embeddings = {0: {0, 1}, 1: {3, 4}} adj = nx.Graph() adj.add_edges_from({(0, 1), (1, 2), (2, 3), (3, 4)}) with self.assertRaises(ValueError): eutil.embed_ising(h, j, embeddings, adj)
def test_embed_typical(self): h = {0: 1, 1: 10} j = {(0, 1): 15, (2, 1): -8, (0, 2): 5, (2, 0): -2} embeddings = {0: [1], 1: [2, 3], 2: [0]} adj = nx.Graph() adj.add_edges_from({(0, 1), (1, 2), (2, 3), (3, 0), (2, 0)}) expected_h0 = {0: 0, 1: 1, 2: 5, 3: 5} expected_j0 = {(0, 1): 3, (0, 2): -4, (0, 3): -4, (1, 2): 15} expected_jc = {(2, 3): -1} h0, j0, jc = eutil.embed_ising(h, j, embeddings, adj) self.assertEqual(h0, expected_h0) # check j0 for (u, v), bias in j0.items(): self.assertTrue((u, v) in expected_j0 or (v, u) in expected_j0) self.assertFalse((u, v) in expected_j0 and (v, u) in expected_j0) if (u, v) in expected_j0: self.assertEqual(expected_j0[(u, v)], bias) else: self.assertEqual(expected_j0[(v, u)], bias) # check jc for (u, v), bias in jc.items(): self.assertTrue((u, v) in expected_jc or (v, u) in expected_jc) self.assertFalse((u, v) in expected_jc and (v, u) in expected_jc) if (u, v) in expected_jc: self.assertEqual(expected_jc[(u, v)], bias) else: self.assertEqual(expected_jc[(v, u)], bias)
def test_docstring_examples(self): logical_h = {'a': 1, 'b': 1} logical_J = {('a', 'b'): -1} embedding = {'a': [0, 1], 'b': [2]} adjacency = {0: {1, 2}, 1: {0, 2}, 2: {0, 1}} emb_h, emb_J, chain_J = eutil.embed_ising(logical_h, logical_J, embedding, adjacency) self.assertEqual(emb_h, {0: 0.5, 1: 0.5, 2: 1.0}) self.assertEqual(emb_J, {(0, 2): -0.5, (1, 2): -0.5}) self.assertEqual(chain_J, {(0, 1): -1.0})
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 test_embed_ising_components_empty(self): h = {} J = {} embedding = {} adjacency = {} he, Je, Jc = eutil.embed_ising(h, J, embedding, adjacency) self.assertFalse(he) self.assertFalse(Je) self.assertFalse(Jc) self.assertIsInstance(he, dict) self.assertIsInstance(Je, dict) self.assertIsInstance(Jc, dict)
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_embed_typical(self): h = {0: 1, 1: 10} j = {(0, 1): 15, (2, 1): -8, (0, 2): 5, (2, 0): -2} embeddings = {0: [1], 1: [2, 3], 2: [0]} adj = nx.Graph() adj.add_edges_from({(0, 1), (1, 2), (2, 3), (3, 0), (2, 0)}) expected_h0 = {0: 0, 1: 1, 2: 5, 3: 5} expected_j0 = {(0, 1): 3, (0, 2): -4, (0, 3): -4, (1, 2): 15} expected_jc = {(2, 3): -1} h0, j0, jc = eutil.embed_ising(h, j, embeddings, adj) self.assertEqual(h0, expected_h0) self.assertEqual(j0, expected_j0) self.assertEqual(jc, expected_jc)
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)