def test_data(self): response = dimod.Response(dimod.BINARY) response.add_sample({'a': +1, 'b': +1}, -1, num_spin_up=2) self.assertTrue(len(list(response.data())) == 1) for datum in response.data(): self.assertEqual(datum.num_spin_up, 2) self.assertEqual(({'a': +1, 'b': +1}, -1, 2), datum) for datum in response.data(['sample', 'num_spin_up'], name=None): self.assertEqual(({'a': +1, 'b': +1}, 2), datum) for datum in response.data(['sample', 'num_spin_up'], sample_type=pd.Series): self.assertTrue(datum.sample.equals(pd.Series({'a': +1, 'b': +1}, dtype=object))) # # references a found bug response = dimod.Response(dimod.SPIN) response.add_sample({0: -1, 4: 1}, energy=0.0, num_occurences=1) for sample, energy in response.data(['sample', 'energy']): # there should be only one self.assertEqual(sample, {0: -1, 4: 1}) self.assertEqual(energy, 0.0)
def test_retrieving_additional_fields(self): response = dimod.Response(dimod.SPIN) response.add_sample({'a': 1, 'b': -1}, 1.3, num_occurences=1) for sample, num_occurences in response.data(['sample', 'num_occurences']): self.assertEqual(sample, {'a': 1, 'b': -1}) self.assertEqual(num_occurences, 1) response.add_sample({'a': 1, 'b': -1}, 1.3, num_occurences=1) self.assertEqual(len(response), 2) for sample, num_occurences in response.data(['sample', 'num_occurences']): self.assertEqual(sample, {'a': 1, 'b': -1}) self.assertEqual(num_occurences, 1) # # index-labelled # response = dimod.Response(dimod.BINARY) response.add_sample({0: 1, 4: 0}, 1.3, num_occurences=1) for sample, num_occurences in response.data(['sample', 'num_occurences']): self.assertEqual(sample, {0: 1, 4: 0}) self.assertEqual(num_occurences, 1) response.add_sample({0: 1, 4: 0}, 1.3, num_occurences=1) self.assertEqual(len(response), 2) for sample, num_occurences in response.data(['sample', 'num_occurences']): self.assertEqual(sample, {0: 1, 4: 0}) self.assertEqual(num_occurences, 1)
def test_change_vartype_inplace(self): response = dimod.Response(dimod.SPIN) bqm = dimod.BinaryQuadraticModel({'a': .1}, {('a', 'b'): -1}, 0.0, dimod.SPIN) samples = [{'a': -1, 'b': +1}, {'a': +1, 'b': -1}, {'a': +1, 'b': +1}, {'a': -1, 'b': -1}] energies = [bqm.energy(sample) for sample in samples] response.add_samples_from(samples, energies) for sample, energy in response.data(['sample', 'energy']): self.assertAlmostEqual(bqm.energy(sample), energy) response.change_vartype(dimod.SPIN) # should do nothing for sample, energy in response.data(['sample', 'energy']): self.assertAlmostEqual(bqm.energy(sample), energy) response.change_vartype(dimod.BINARY) # change to binary for sample, energy in response.data(['sample', 'energy']): self.assertAlmostEqual(bqm.binary.energy(sample), energy) response.change_vartype(dimod.SPIN) # change to back to spin for sample, energy in response.data(['sample', 'energy']): self.assertAlmostEqual(bqm.spin.energy(sample), energy) # finally change with an offset response.change_vartype(dimod.BINARY, offset=1) for sample, energy in response.data(['sample', 'energy']): self.assertAlmostEqual(bqm.binary.energy(sample) + 1, energy)
def test_add_samples_future(self, __): # don't need to do anything other than magic mock the micro client, wait_multiple just won't # block response = dimod.Response(dimod.SPIN) qubits = [0, 1, 2, 4, 5] self.assertTrue(response.done()) # submit some problems and add the future objects to the response for __ in range(10): # wait .5s response.add_samples_future(MockFuture(.5, qubits, 10)) # now try to read from it self.assertEqual(len(response), 100) for sample in response: for v, val in sample.items(): self.assertIn(v, qubits) self.assertTrue(val in {-1, 1}) self.assertTrue(response.done()) for __ in range(1): # wait one second response.add_samples_future(MockFuture(.1, qubits, 10)) # try to acces the data df response.df_data # now try to read from it self.assertEqual(len(response), 110)
def test_add_samples_from_dict(self): # typical case response = dimod.Response(dimod.SPIN) bqm = dimod.BinaryQuadraticModel({'a': .1}, {('a', 'b'): -1}, 0.0, dimod.SPIN) samples = [{'a': -1, 'b': +1}, {'a': +1, 'b': -1}, {'a': +1, 'b': +1}, {'a': -1, 'b': -1}] energies = [bqm.energy(sample) for sample in samples] response.add_samples_from(samples, energies) response.add_samples_from(samples, energies) self.assertEqual(len(response), 8) self.assertTrue(response.df_samples.equals(pd.concat([pd.DataFrame(samples, dtype='int8', index=range(4)), pd.DataFrame(samples, dtype='int8', index=range(4, 8))]))) # try adding other fields response.add_samples_from(samples, energies, other=[1] * 4) self.assertEqual(len(response), 12) # try adding from pandas array samples_df = pd.DataFrame(samples) response.add_samples_from(samples_df, energies)
def test_instantiation_without_energy(self): samples_matrix = np.matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) with self.assertRaises(ValueError): dimod.Response(samples_matrix, {}, dimod.BINARY)
def test__iter__(self): response = dimod.Response(dimod.BINARY) samples = [{'a': 0, 'b': 1}, {'a': 1, 'b': 0}, {'a': 1, 'b': 1}, {'a': 0, 'b': 0}] energies = [0, 1, 2, 3] for s0, s1 in zip(response, samples): self.assertEqual(s0, s1)
def sample(self, bqm): # All bqm's passed in will be a subgraph of the sampler's structure variable_list = list(bqm.linear) response = dimod.Response(bqm.vartype) for values in itertools.product(bqm.vartype.value, repeat=len(bqm)): sample = dict(zip(variable_list, values)) energy = bqm.energy(sample) response.add_sample(sample, energy) return response
def test_data_vector_copy(self): samples_matrix = np.matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) energies = np.asarray([2, 2, 0, 4], dtype=float) data_vectors = {'energy': energies} response = dimod.Response(samples_matrix, data_vectors, dimod.BINARY) self.assertIsNot(response.data_vectors, data_vectors)
def test_instantiation(self): samples_matrix = np.matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) energies = np.asarray([2, 2, 0, 4], dtype=float) response = dimod.Response(samples_matrix, {'energy': energies}, dimod.BINARY) npt.assert_equal(samples_matrix, response.samples_matrix) npt.assert_allclose(energies, response.data_vectors['energy'])
def test_instantiation_missing_field(self): samples = [[-1, 1, 1], [1, 1, 1]] num_occurrences = [1, 1] datatypes = [('sample', np.dtype(np.int8), (3,)), ('num_occurrences', np.dtype(np.int8))] num_samples = 2 record = np.rec.array(np.zeros(num_samples, dtype=datatypes)) with self.assertRaises(ValueError): dimod.Response(record, ['a', 'b', 'c'], {}, dimod.SPIN)
def test_samples(self): # all defaults, given in energy order response = dimod.Response(dimod.SPIN) samples = [{'a': -1, 'b': +1}, {'a': +1, 'b': -1}, {'a': +1, 'b': +1}, {'a': -1, 'b': -1}] energies = [0, 1, 2, 3] response.add_samples_from(samples, energies) # should return itself, check twice because iterator self.assertEqual(list(response.samples()), samples) self.assertEqual(list(response.samples()), samples) self.assertTrue(all(isinstance(sample, dict) for sample in response.samples())) # # reverse energy ordering response = dimod.Response(dimod.SPIN) samples = [{'a': -1, 'b': +1}, {'a': +1, 'b': -1}, {'a': +1, 'b': +1}, {'a': -1, 'b': -1}] energies = [3, 2, 1, 0] response.add_samples_from(samples, energies) # should return itself reversed, check twice because iterator self.assertEqual(list(response.samples()), list(reversed(samples))) self.assertEqual(list(response.samples(sorted_by_energy=False)), samples) self.assertEqual(list(response.samples()), list(reversed(samples))) self.assertEqual(list(response.samples(sorted_by_energy=False)), samples) # response = dimod.Response(dimod.SPIN) samples = [{'a': -1, 'b': +1}, {'a': +1, 'b': -1}, {'a': +1, 'b': +1}, {'a': -1, 'b': -1}] energies = [0, 1, 2, 3] response.add_samples_from(samples, energies) for sample in response.samples(sample_type=pd.Series): self.assertIsInstance(sample, pd.Series)
def test_data_vectors_wrong_length(self): samples_matrix = np.matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) energies = [2, 2, 0, 4] num_occurrences = [1, 1, 2, 1, 1] objects = [object() for __ in range(4)] data_vectors = {'energy': energies, 'occurences': num_occurrences, 'objects': objects} with self.assertRaises(ValueError): response = dimod.Response(samples_matrix, data_vectors, dimod.BINARY)
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 sample_qubo(self, Q, **kwargs): """Sample from the provided QUBO. Args: Q (dict): The coefficients of the QUBO. **kwargs: Parameters for the sampling method, specified per solver. Returns: :class:`.FutureResponse` """ future = self.solver.sample_qubo(Q, **kwargs) response = dimod.Response(dimod.BINARY) response.add_samples_future(future) return response
def test_add_sample(self): response = dimod.Response(dimod.SPIN) sample = {'a': -1, 'b': 1} energy = 1 response.add_sample(sample, energy) self.assertEqual(len(response), 1) # add a sample with additional info response.add_sample(sample, energy, num_occurences=1) self.assertEqual(len(response), 2) # add a pandas series response.add_sample(pd.Series(sample), energy) self.assertEqual(len(response), 3)
def sample_ising(self, linear, quadratic, **kwargs): """Sample from the provided Ising model. Args: linear (list/dict): Linear terms of the model. quadratic (dict of (int, int):float): Quadratic terms of the model. **kwargs: Parameters for the sampling method, specified per solver. Returns: :class:`.FutureResponse` """ future = self.solver.sample_ising(linear, quadratic, **kwargs) response = dimod.Response(dimod.SPIN) response.add_samples_future(future) return response
def sample_ising(self, h, J, **kwargs): """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. **kwargs: Parameters for the sampling method, specified per solver. Returns: :class:`dimod.SpinResponse` """ # 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, **kwargs) # 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) 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_change_vartype_copy(self): response = dimod.Response(dimod.SPIN) bqm = dimod.BinaryQuadraticModel({'a': .1}, {('a', 'b'): -1}, 0.0, dimod.SPIN) samples = [{'a': -1, 'b': +1}, {'a': +1, 'b': -1}, {'a': +1, 'b': +1}, {'a': -1, 'b': -1}] energies = [bqm.energy(sample) for sample in samples] response.add_samples_from(samples, energies) for sample, energy in response.data(['sample', 'energy']): self.assertAlmostEqual(bqm.energy(sample), energy) response_copy = response.change_vartype(dimod.SPIN, inplace=False) # should do nothing self.assertIsNot(response, response_copy) for sample, energy in response_copy.data(['sample', 'energy']): self.assertAlmostEqual(bqm.energy(sample), energy)
def test__repr__(self): alpha = list('abcdefghijklmnopqrstuvwxyz') num_variables = 3 # needs to be small enough to not snip the matrix when printed num_samples = 2 ** num_variables samples = list(itertools.product((-1, 1), repeat=num_variables)) energies = [0.0]*num_samples num_occurrences = [1] * num_samples record = dimod.response.data_struct_array(samples, energy=energies, num_occurrences=num_occurrences) labels = alpha[:num_variables] resp = dimod.Response(record, labels, {}, dimod.SPIN) from dimod import Response from numpy import rec new_resp = eval(resp.__repr__()) np.testing.assert_array_equal(resp.record, new_resp.record)
def test_samples_num_limited(self): samples_matrix = np.matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) energies = [2, 2, 0, 4] num_occurrences = [1, 1, 2, 1] objects = [object() for __ in range(4)] data_vectors = {'energy': energies, 'occurences': num_occurrences, 'objects': objects} response = dimod.Response(samples_matrix, data_vectors, dimod.BINARY) samples_list = list(response.samples()) self.assertEqual(len(samples_list), 4) shortened_samples_list = list(response.samples(3)) self.assertEqual(len(shortened_samples_list), 3) self.assertEqual(shortened_samples_list, samples_list[0:3])
def test_data_vectors_are_arrays(self): samples_matrix = np.matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) energies = [2, 2, 0, 4] num_occurrences = [1, 1, 2, 1] objects = [object() for __ in range(4)] data_vectors = {'energy': energies, 'occurences': num_occurrences, 'objects': objects} response = dimod.Response(samples_matrix, data_vectors, dimod.BINARY) self.assertEqual(len(response.data_vectors), 3) for key in data_vectors: self.assertIn(key, response.data_vectors) vector = response.data_vectors[key] self.assertIsInstance(vector, np.ndarray) self.assertEqual(vector.shape, (4,))
def test_embedding_superset(self): # source graph in the embedding is a superset of the bqm response = dimod.Response( 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 = dimod.unembed_response(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 sample(self, bqm, **kwargs): """Sample from the provided binary quadratic model Args: bqm (:obj:`dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. **kwargs: Optional keyword arguments for the sampling method, specified per solver. Returns: :class:`dimod.Response` Examples: This example uses :class:`.TilingComposite` to instantiate a composed sampler that submits a simple Ising problem of just two variables that map to qubits 0 and 1 on the D-Wave solver selected by the user's default :std:doc:`D-Wave Cloud Client configuration file <cloud-client:reference/intro>`. (The simplicity of this example obviates the need for an embedding composite.) Because the problem fits in a single :std:doc:`Chimera <system:reference/intro>` unit cell, it is tiled across the solver's entire Chimera graph, resulting in multiple samples. >>> from dwave.system.samplers import DWaveSampler >>> from dwave.system.composites import EmbeddingComposite, TilingComposite >>> sampler = TilingComposite(DWaveSampler(), 1, 1, 4) >>> response = sampler.sample_ising({0: -1, 1: 1}, {}) >>> for sample in response.samples(): # doctest: +SKIP ... print(sample) ... {0: 1, 1: -1} {0: 1, 1: -1} {0: 1, 1: -1} {0: 1, 1: -1} {0: 1, 1: -1} {0: 1, 1: -1} {0: 1, 1: -1} {0: 1, 1: -1} >>> # Snipped above response for brevity See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/latest/glossary.html>`_ for explanations of technical terms in descriptions of Ocean tools. """ # apply the embeddings to the given problem to tile it across the child sampler embedded_bqm = dimod.BinaryQuadraticModel.empty(bqm.vartype) __, __, target_adjacency = self.child.structure for embedding in self.embeddings: embedded_bqm.update( dimod.embed_bqm(bqm, embedding, target_adjacency)) # solve the problem on the child system tiled_response = self.child.sample(embedded_bqm, **kwargs) responses = [] for embedding in self.embeddings: embedding = { v: chain for v, chain in embedding.items() if v in bqm.linear } responses.append( dimod.unembed_response(tiled_response, embedding, bqm)) # stack the records record = np.rec.array(np.hstack((resp.record for resp in responses))) vartypes = set(resp.vartype for resp in responses) if len(vartypes) > 1: raise RuntimeError("inconsistent vartypes returned") vartype = vartypes.pop() info = {} for resp in responses: info.update(resp.info) labels = responses[0].variable_labels return dimod.Response(record, labels, info, vartype)
def sample(self, bqm, **kwargs): """Sample from the specified binary quadratic model. Args: bqm (:obj:`dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. **kwargs: Optional keyword arguments for the sampling method, specified per solver. Returns: :class:`dimod.Response`: A `dimod` :obj:`~dimod.Response` object. Examples: This example submits a simple Ising problem of just two variables on a D-Wave system selected by the user's default :std:doc:`D-Wave Cloud Client configuration file <cloud-client:reference/intro>`. Because the problem fits in a single :term:`Chimera` unit cell, it is tiled across the solver's entire Chimera graph, resulting in multiple samples (the exact number depends on the working Chimera graph of the D-Wave system). >>> from dwave.system.samplers import DWaveSampler >>> from dwave.system.composites import EmbeddingComposite >>> from dwave.system.composites import EmbeddingComposite, TilingComposite ... >>> sampler = EmbeddingComposite(TilingComposite(DWaveSampler(), 1, 1, 4)) >>> response = sampler.sample_ising({},{('a', 'b'): 1}) >>> len(response) # doctest: +SKIP 246 See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/latest/glossary.html>`_ for explanations of technical terms in descriptions of Ocean tools. """ # apply the embeddings to the given problem to tile it across the child sampler embedded_bqm = dimod.BinaryQuadraticModel.empty(bqm.vartype) __, __, target_adjacency = self.child.structure for embedding in self.embeddings: embedded_bqm.update( dimod.embed_bqm(bqm, embedding, target_adjacency)) # solve the problem on the child system tiled_response = self.child.sample(embedded_bqm, **kwargs) responses = [] for embedding in self.embeddings: embedding = { v: chain for v, chain in embedding.items() if v in bqm.linear } responses.append( dimod.unembed_response(tiled_response, embedding, bqm)) # stack the records record = np.rec.array(np.hstack((resp.record for resp in responses))) vartypes = set(resp.vartype for resp in responses) if len(vartypes) > 1: raise RuntimeError("inconsistent vartypes returned") vartype = vartypes.pop() info = {} for resp in responses: info.update(resp.info) labels = responses[0].variable_labels return dimod.Response(record, labels, info, vartype)
def test_instantiation(self): # test empty spin bqm response = dimod.Response(dimod.SPIN)