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.SampleSet` Examples: This example submits a simple Ising problem of just two variables on a D-Wave system. 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 import DWaveSampler, EmbeddingComposite >>> from dwave.system import TilingComposite ... >>> qpu_2000q = DWaveSampler(solver={'topology__type': 'chimera'}) >>> sampler = EmbeddingComposite(TilingComposite(qpu_2000q, 1, 1, 4)) >>> response = sampler.sample_ising({},{('a', 'b'): 1}) >>> len(response) # doctest: +SKIP 246 See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/stable/concepts/index.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( dwave.embedding.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.variables } responses.append( dwave.embedding.unembed_sampleset(tiled_response, embedding, bqm)) answer = dimod.concatenate(responses) answer.info.update(tiled_response.info) return answer
def _merge_results(self, results): "Merge results into a single SampleSet." sum_keys = [ "total_real_time", "qpu_access_overhead_time", "post_processing_overhead_time", "qpu_sampling_time", "total_post_processing_time", "qpu_programming_time", "run_time_chip", "qpu_access_time" ] avg_keys = [ "anneal_time_per_run", "readout_time_per_run", "qpu_delay_time_per_sample", "qpu_anneal_time_per_sample", "qpu_readout_time_per_sample" ] timing = {} merged = dimod.concatenate(results) nsamples = len(merged) for sk in sum_keys: try: timing[sk] = sum([r.info["timing"][sk] for r in results]) except KeyError: pass for ak in avg_keys: try: timing[ak] = sum( [r.info["timing"][ak] * len(r) for r in results]) // nsamples except KeyError: pass merged.info["timing"] = timing return merged
def test_simple(self): ss0 = dimod.SampleSet.from_samples([-1, +1], dimod.SPIN, energy=-1) ss1 = dimod.SampleSet.from_samples([+1, -1], dimod.SPIN, energy=-1) ss2 = dimod.SampleSet.from_samples([[+1, +1], [-1, -1]], dimod.SPIN, energy=[1, 1]) comb = dimod.concatenate((ss0, ss1, ss2)) out = dimod.SampleSet.from_samples([[-1, +1], [+1, -1], [+1, +1], [-1, -1]], dimod.SPIN, energy=[-1, -1, 1, 1]) self.assertEqual(comb, out) np.testing.assert_array_equal(comb.record.sample, out.record.sample)
def test_variables_order_and_vartype(self): ss0 = dimod.SampleSet.from_samples(([-1, +1], 'ab'), dimod.SPIN, energy=-1) ss1 = dimod.SampleSet.from_samples(([-1, +1], 'ba'), dimod.SPIN, energy=-1) ss2 = dimod.SampleSet.from_samples(([[1, 1], [0, 0]], 'ab'), dimod.BINARY, energy=[1, 1]) comb = dimod.concatenate((ss0, ss1, ss2)) out = dimod.SampleSet.from_samples(([[-1, +1], [+1, -1], [+1, +1], [-1, -1]], 'ab'), dimod.SPIN, energy=[-1, -1, 1, 1]) self.assertEqual(comb, out) np.testing.assert_array_equal(comb.record.sample, out.record.sample)
def relative_k_hamming_trench(samplesets, hamm_k, norm=False, info_key=None): # TODO: Avoid calculating hamming distance twice pockets = [] energies = OrderedDict() union = dimod.concatenate(samplesets) for data in union.data(sorted_by='energy'): value = tuple(data.sample.values()) local = (scipy.spatial.distance.hamming(value, p) <= hamm_k for p in pockets) if not any(local): pockets.append(value) energies[value] = data.energy pockets_i = OrderedDict() pockets_union = OrderedDict([(k, 0) for k in pockets]) for i, sampleset in enumerate(samplesets): bins = OrderedDict([(k, 0) for k in pockets]) for sample in sampleset.samples(sorted_by='energy'): value = tuple(sample.values()) hits = [] k = hamm_k for pocket in pockets: hamm_dist = scipy.spatial.distance.hamming(value, pocket) if hamm_dist < k: hits = [pocket] k = hamm_dist elif hamm_dist == k: hits += [pocket] split = 1 / len(hits) for hit in hits: bins[hit] = split + bins.get(hit, 0) pockets_union[hit] += split name = sampleset.info.get(info_key, str(i)) pockets_i[str(name)] = bins if norm: norm_pockets = OrderedDict() for samples, (name, pockets) in zip(samplesets, pockets_i.items()): nsamples = len(samples) norm_pocket = OrderedDict([(k, v / nsamples) for k, v in pockets.items()]) norm_pockets[name] = norm_pocket norm_union = OrderedDict([(k, v / len(union)) for k, v in pockets_union.items()]) return norm_union, energies, norm_pockets else: return pockets_union, energies, pockets_i
def load_sampleset(self, bqm, target, embedding, tags=[], unembed_args=None, index=None): """ Load a sampleset object from JSON format, filed under: <EmberaDB>/<bqm_id>/<target_id>/<embedding_id>/<tags>/<sampleset_id>.json If more than one sampleset is found, returns the concatenation of all samples found under the given criteria. Arguments: bqm: (BinaryQuadraticModel or networkx.Graph) target: (networkx.Graph, list, or str) Optional Arguments: If none of the optional arguments are given, all samplesets under that path are concatenated. tag: (str, default=[]) If provided, sampleset is read from directory ./<tag>/ embedding: (embera.Embedding, dict, or str, default=None) Dictionary is converted to Embedding, Embedding ID is used. String is taken literally as path. If "", concatenate all under <EmberaDB>/<bqm_id>/<target_id>/<tag> If {}, return `native` sampleset. i.e. <Embedding({}).id>.json """ samplesets = self.load_samplesets(bqm,target,embedding,tags,unembed_args) if not samplesets: return dimod.SampleSet.from_samples([],bqm.vartype,None) if index is not None: return samplesets.pop(index) try: sampleset = dimod.concatenate(samplesets) for s in samplesets: sampleset.info.update(s.info) return sampleset except KeyError: raise RuntimeError("Samplesets don't share the same embedding")
def test_empty(self): with self.assertRaises(ValueError): dimod.concatenate([])
def sample(self, bqm, anneal_schedules=None, **parameters): """Sample the binary quadratic model using reverse annealing along a given set of anneal schedules. Args: bqm (:obj:`dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. anneal_schedules (list of lists, optional, default=[[[0, 1], [1, 0.35], [9, 0.35], [10, 1]]]): Anneal schedules in order of submission. Each schedule is formatted as a list of [time, s] pairs, in which time is in microseconds and s is the normalized persistent current in the range [0,1]. initial_state (dict, optional): The state to reverse anneal from. If not provided, it will be randomly generated. **parameters: Parameters for the sampling method, specified by the child sampler. Returns: :obj:`dimod.SampleSet` that has initial_state and schedule_index fields. Examples: This example runs 100 reverse anneals each for three schedules on a problem constructed by setting random :math:`\pm 1` values on a clique (complete graph) of 15 nodes, minor-embedded on a D-Wave system using the :class:`.DWaveCliqueSampler` sampler. >>> import dimod >>> from dwave.system import DWaveCliqueSampler, ReverseAdvanceComposite ... >>> sampler = DWaveCliqueSampler() # doctest: +SKIP >>> sampler_reverse = ReverseAdvanceComposite(sampler) # doctest: +SKIP >>> schedule = [[[0.0, 1.0], [t, 0.5], [20, 1.0]] for t in (5, 10, 15)] ... >>> bqm = dimod.generators.ran_r(1, 15) >>> init_samples = {i: -1 for i in range(15)} >>> sampleset = sampler_reverse.sample(bqm, ... anneal_schedules=schedule, ... initial_state=init_samples, ... num_reads=100, ... reinitialize_state=True) # doctest: +SKIP """ child = self.child if anneal_schedules is None: anneal_schedules = [[[0, 1], [1, 0.35], [9, 0.35], [10, 1]]] vartype_values = list(bqm.vartype.value) if 'initial_state' not in parameters: initial_state = dict(zip(list(bqm.variables), np.random.choice(vartype_values, len(bqm)))) else: initial_state = parameters.pop('initial_state') if not isinstance(initial_state, abc.Mapping): raise TypeError("initial state provided must be a dict, but received {}".format(initial_state)) if 'reinitialize_state' not in parameters: parameters['reinitialize_state'] = True if "answer_mode" in child.parameters: parameters['answer_mode'] = 'histogram' samplesets = None for schedule_idx, anneal_schedule in enumerate(anneal_schedules): sampleset = child.sample(bqm, anneal_schedule=anneal_schedule, initial_state=initial_state, **parameters) initial_state, _ = dimod.as_samples(initial_state) if 'initial_state' not in sampleset.record.dtype.names: init_state_vect = [] if parameters['reinitialize_state']: init_state_vect = [initial_state[0].copy() for i in range(len(sampleset.record.energy))] else: # each sample is the next sample's initial state init_state_vect.append(initial_state[0].copy()) for sample in sampleset.record.sample[:-1]: init_state_vect.append(sample) sampleset = dimod.append_data_vectors(sampleset, initial_state=init_state_vect) if 'schedule_index' not in sampleset.record.dtype.names: schedule_index_vect = [schedule_idx] * len(sampleset.record.energy) sampleset = dimod.append_data_vectors(sampleset, schedule_index=schedule_index_vect) if samplesets is None: samplesets = sampleset else: samplesets = dimod.concatenate((samplesets, sampleset)) if schedule_idx+1 == len(anneal_schedules): # no need to create the next initial state - last iteration break # prepare the initial state for the next iteration if parameters['reinitialize_state']: # if reinitialize is on, choose the lowest energy, most probable state for next iteration ground_state_energy = sampleset.first.energy lowest_energy_samples = sampleset.record[sampleset.record.energy == ground_state_energy] lowest_energy_samples.sort(order='num_occurrences') initial_state = dict(zip(sampleset.variables, lowest_energy_samples[-1].sample)) else: # if not reinitialized, take the last state as the next initial state initial_state = dict(zip(sampleset.variables, sampleset.record.sample[-1])) samplesets.info['anneal_schedules'] = anneal_schedules return samplesets
def sample(self, bqm, initial_states=None, initial_states_generator='random', num_reads=None, seed=None, **parameters): """Sample the binary quadratic model using reverse annealing from multiple initial states. Args: bqm (:obj:`dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. initial_states (samples-like, optional, default=None): One or more samples, each defining an initial state for all the problem variables. If fewer than `num_reads` initial states are defined, additional values are generated as specified by `initial_states_generator`. See :func:`dimod.as_samples` for a description of "samples-like". initial_states_generator ({'none', 'tile', 'random'}, optional, default='random'): Defines the expansion of `initial_states` if fewer than `num_reads` are specified: * "none": If the number of initial states specified is smaller than `num_reads`, raises ValueError. * "tile": Reuses the specified initial states if fewer than `num_reads` or truncates if greater. * "random": Expands the specified initial states with randomly generated states if fewer than `num_reads` or truncates if greater. num_reads (int, optional, default=len(initial_states) or 1): Equivalent to number of desired initial states. If greater than the number of provided initial states, additional states will be generated. If not provided, it is selected to match the length of `initial_states`. If `initial_states` is not provided, `num_reads` defaults to 1. seed (int (32-bit unsigned integer), optional): Seed to use for the PRNG. Specifying a particular seed with a constant set of parameters produces identical results. If not provided, a random seed is chosen. **parameters: Parameters for the sampling method, specified by the child sampler. Returns: :obj:`dimod.SampleSet` that has initial_state field. Examples: This example runs 100 reverse anneals each from two initial states on a problem constructed by setting random :math:`\pm 1` values on a clique (complete graph) of 15 nodes, minor-embedded on a D-Wave system using the :class:`.DWaveCliqueSampler` sampler. >>> import dimod >>> from dwave.system import DWaveCliqueSampler, ReverseBatchStatesComposite ... >>> sampler = DWaveCliqueSampler() # doctest: +SKIP >>> sampler_reverse = ReverseBatchStatesComposite(sampler) # doctest: +SKIP >>> schedule = [[0.0, 1.0], [10.0, 0.5], [20, 1.0]] ... >>> bqm = dimod.generators.ran_r(1, 15) >>> init_samples = [{i: -1 for i in range(15)}, {i: 1 for i in range(15)}] >>> sampleset = sampler_reverse.sample(bqm, ... anneal_schedule=schedule, ... initial_states=init_samples, ... num_reads=100, ... reinitialize_state=True) # doctest: +SKIP """ child = self.child parsed = self.parse_initial_states(bqm, initial_states=initial_states, initial_states_generator=initial_states_generator, num_reads=num_reads, seed=seed) parsed_initial_states = np.ascontiguousarray(parsed.initial_states.record.sample) # there is gonna be way too much data generated - better to histogram them if possible if 'answer_mode' in child.parameters: parameters['answer_mode'] = 'histogram' # reduce number of network calls if possible by aggregating init states if 'num_reads' in child.parameters: aggreg = parsed.initial_states.aggregate() parsed_initial_states = np.ascontiguousarray(aggreg.record.sample) parameters['num_reads'] = aggreg.record.num_occurrences samplesets = None for initial_state in parsed_initial_states: sampleset = child.sample(bqm, initial_state=dict(zip(bqm.variables, initial_state)), **parameters) if 'initial_state' not in sampleset.record.dtype.names: init_state_vect = [initial_state.copy() for i in range(len(sampleset.record.energy))] sampleset = dimod.append_data_vectors(sampleset, initial_state=init_state_vect) if samplesets is None: samplesets = sampleset else: samplesets = dimod.concatenate((samplesets, sampleset)) return samplesets