def chain_break_frequency(samples_like, embedding): """Determine the frequency of chain breaks in the given samples. Args: samples_like (samples_like/:obj:`dimod.SampleSet`): A collection of raw samples. 'samples_like' is an extension of NumPy's array_like. See :func:`dimod.as_samples`. embedding (dict): Mapping from source graph to target graph as a dict of form {s: {t, ...}, ...}, where s is a source-model variable and t is a target-model variable. Returns: dict: Frequency of chain breaks as a dict in the form {s: f, ...}, where s is a variable in the source graph and float f the fraction of broken chains. Examples: This example embeds a single source node, 'a', as a chain of two target nodes (0, 1) and uses :func:`.chain_break_frequency` to show that out of two synthetic samples, one ([-1, +1]) represents a broken chain. >>> import numpy as np ... >>> samples = np.array([[-1, +1], [+1, +1]]) >>> embedding = {'a': {0, 1}} >>> print(dwave.embedding.chain_break_frequency(samples, embedding)['a']) 0.5 """ if isinstance(samples_like, dimod.SampleSet): labels = samples_like.variables samples = samples_like.record.sample num_occurrences = samples_like.record.num_occurrences else: samples, labels = dimod.as_samples(samples_like) num_occurrences = np.ones(samples.shape[0]) if not all(v == idx for idx, v in enumerate(labels)): labels_to_idx = {v: idx for idx, v in enumerate(labels)} embedding = { v: {labels_to_idx[u] for u in chain} for v, chain in embedding.items() } if not embedding: return {} variables, chains = zip(*embedding.items()) broken = broken_chains(samples, chains) return { v: float(np.average(broken[:, cidx], weights=num_occurrences)) for cidx, v in enumerate(variables) }
def chain_break_frequency(samples_like, embedding): """Determine the frequency of chain breaks in the given samples. Args: samples_like (samples_like/:obj:`dimod.SampleSet`): A collection of raw samples. 'samples_like' is an extension of NumPy's array_like. See :func:`dimod.as_samples`. embedding (dict): Mapping from source graph to target graph as a dict of form {s: {t, ...}, ...}, where s is a source-model variable and t is a target-model variable. Returns: dict: Frequency of chain breaks as a dict in the form {s: f, ...}, where s is a variable in the source graph, and frequency, a float, is the fraction of broken chains. Examples: This example embeds a single source node, 'a', as a chain of two target nodes (0, 1) and uses :func:`.chain_break_frequency` to show that out of two synthetic samples, one ([-1, +1]) represents a broken chain. >>> import dimod >>> import numpy as np >>> samples = np.array([[-1, +1], [+1, +1]]) >>> embedding = {'a': {0, 1}} >>> print(dimod.chain_break_frequency(samples, embedding)['a']) 0.5 This example embeds a single source node (0) as a chain of two target nodes (a, b) and uses :func:`.chain_break_frequency` to show that out of two samples in a dimod response, one ({'a': 1, 'b': 0}) represents a broken chain. >>> import dimod ... >>> response = dimod.SampleSet.from_samples([{'a': 1, 'b': 0}, {'a': 0, 'b': 0}], ... {'energy': [1, 0]}, {}, dimod.BINARY) >>> embedding = {0: {'a', 'b'}} >>> print(dimod.chain_break_frequency(response, embedding)[0]) 0.5 """ if isinstance(samples_like, dimod.SampleSet): labels = samples_like.variables samples = samples_like.record.sample else: samples, labels = dimod.as_samples(samples_like) if not all(v == idx for idx, v in enumerate(labels)): labels_to_idx = {v: idx for idx, v in enumerate(labels)} embedding = { v: {labels_to_idx[u] for u in chain} for v, chain in embedding.items() } if not embedding: return {} variables, chains = zip(*embedding.items()) broken = broken_chains(samples, chains) freq = { v: float(broken[:, cidx].mean()) for cidx, v in enumerate(variables) } return freq
def unembed_sampleset(target_sampleset, embedding, source_bqm, chain_break_method=None, chain_break_fraction=False, return_embedding=False): """Unembed a sample set. Given samples from a target binary quadratic model (BQM), construct a sample set for a source BQM by unembedding. Args: target_sampleset (:obj:`dimod.SampleSet`): Sample set from the target BQM. embedding (dict): Mapping from source graph to target graph as a dict of form {s: {t, ...}, ...}, where s is a source variable and t is a target variable. source_bqm (:obj:`~dimod.BinaryQuadraticModel`): Source BQM. chain_break_method (function/list, optional): Method or methods used to resolve chain breaks. If multiple methods are given, the results are concatenated and a new field called "chain_break_method" specifying the index of the method is appended to the sample set. Defaults to :func:`~dwave.embedding.chain_breaks.majority_vote`. See :mod:`dwave.embedding.chain_breaks`. chain_break_fraction (bool, optional, default=False): Add a `chain_break_fraction` field to the unembedded :obj:`dimod.SampleSet` with the fraction of chains broken before unembedding. return_embedding (bool, optional, default=False): If True, the embedding is added to :attr:`dimod.SampleSet.info` of the returned sample set. Note that if an `embedding` key already exists in the sample set then it is overwritten. Returns: :obj:`.SampleSet`: Sample set in the source BQM. Examples: This example unembeds from a square target graph samples of a triangular source BQM. >>> # Triangular binary quadratic model and an embedding >>> J = {('a', 'b'): -1, ('b', 'c'): -1, ('a', 'c'): -1} >>> bqm = dimod.BinaryQuadraticModel.from_ising({}, J) >>> embedding = {'a': [0, 1], 'b': [2], 'c': [3]} >>> # Samples from the embedded binary quadratic model >>> samples = [{0: -1, 1: -1, 2: -1, 3: -1}, # [0, 1] is unbroken ... {0: -1, 1: +1, 2: +1, 3: +1}] # [0, 1] is broken >>> energies = [-3, 1] >>> embedded = dimod.SampleSet.from_samples(samples, dimod.SPIN, energies) >>> # Unembed >>> samples = dwave.embedding.unembed_sampleset(embedded, embedding, bqm) >>> samples.record.sample # doctest: +SKIP array([[-1, -1, -1], [ 1, 1, 1]], dtype=int8) """ if chain_break_method is None: chain_break_method = majority_vote elif isinstance(chain_break_method, abc.Sequence): # we want to apply multiple CBM and then combine samplesets = [ unembed_sampleset(target_sampleset, embedding, source_bqm, chain_break_method=cbm, chain_break_fraction=chain_break_fraction) for cbm in chain_break_method ] sampleset = dimod.sampleset.concatenate(samplesets) # Add a new data field tracking which came from # todo: add this functionality to dimod cbm_idxs = np.empty(len(sampleset), dtype=int) start = 0 for i, ss in enumerate(samplesets): cbm_idxs[start:start + len(ss)] = i start += len(ss) new = np.lib.recfunctions.append_fields(sampleset.record, 'chain_break_method', cbm_idxs, asrecarray=True, usemask=False) return type(sampleset)(new, sampleset.variables, sampleset.info, sampleset.vartype) variables = list(source_bqm.variables) # need this ordered try: chains = [embedding[v] for v in variables] except KeyError: raise ValueError("given bqm does not match the embedding") record = target_sampleset.record unembedded, idxs = chain_break_method(target_sampleset, chains) reserved = {'sample', 'energy'} vectors = { name: record[name][idxs] for name in record.dtype.names if name not in reserved } if chain_break_fraction: broken = broken_chains(target_sampleset, chains) if broken.size: vectors['chain_break_fraction'] = broken.mean(axis=1)[idxs] else: vectors['chain_break_fraction'] = 0 info = target_sampleset.info.copy() if return_embedding: embedding_context = dict( embedding=embedding, chain_break_method=chain_break_method.__name__) info.update(embedding_context=embedding_context) return dimod.SampleSet.from_samples_bqm((unembedded, variables), source_bqm, info=info, **vectors)
def unembed_sampleset(target_sampleset, embedding, source_bqm, chain_break_method=None, chain_break_fraction=False, return_embedding=False): """Unembed a samples set. Given samples from a target binary quadratic model (BQM), construct a sample set for a source BQM by unembedding. Args: target_sampleset (:obj:`dimod.SampleSet`): Sample set from the target BQM. embedding (dict): Mapping from source graph to target graph as a dict of form {s: {t, ...}, ...}, where s is a source variable and t is a target variable. source_bqm (:obj:`dimod.BinaryQuadraticModel`): Source BQM. chain_break_method (function, optional): Method used to resolve chain breaks. See :mod:`dwave.embedding.chain_breaks`. chain_break_fraction (bool, optional, default=False): Add a `chain_break_fraction` field to the unembedded :obj:`dimod.SampleSet` with the fraction of chains broken before unembedding. return_embedding (bool, optional, default=False): If True, the embedding is added to :attr:`dimod.SampleSet.info` of the returned sample set. Note that if an `embedding` key already exists in the sample set then it is overwritten. Returns: :obj:`.SampleSet`: Sample set in the source BQM. Examples: This example unembeds from a square target graph samples of a triangular source BQM. >>> # Triangular binary quadratic model and an embedding >>> J = {('a', 'b'): -1, ('b', 'c'): -1, ('a', 'c'): -1} >>> bqm = dimod.BinaryQuadraticModel.from_ising({}, J) >>> embedding = {'a': [0, 1], 'b': [2], 'c': [3]} >>> # Samples from the embedded binary quadratic model >>> samples = [{0: -1, 1: -1, 2: -1, 3: -1}, # [0, 1] is unbroken ... {0: -1, 1: +1, 2: +1, 3: +1}] # [0, 1] is broken >>> energies = [-3, 1] >>> embedded = dimod.SampleSet.from_samples(samples, dimod.SPIN, energies) >>> # Unembed >>> samples = dwave.embedding.unembed_sampleset(embedded, embedding, bqm) >>> samples.record.sample # doctest: +SKIP array([[-1, -1, -1], [ 1, 1, 1]], dtype=int8) """ if chain_break_method is None: chain_break_method = majority_vote variables = list(source_bqm.variables) # need this ordered try: chains = [embedding[v] for v in variables] except KeyError: raise ValueError("given bqm does not match the embedding") record = target_sampleset.record unembedded, idxs = chain_break_method(target_sampleset, chains) reserved = {'sample', 'energy'} vectors = { name: record[name][idxs] for name in record.dtype.names if name not in reserved } if chain_break_fraction: vectors['chain_break_fraction'] = broken_chains( target_sampleset, chains).mean(axis=1)[idxs] info = target_sampleset.info.copy() if return_embedding: embedding_context = dict( embedding=embedding, chain_break_method=chain_break_method.__name__) info.update(embedding_context=embedding_context) return dimod.SampleSet.from_samples_bqm((unembedded, variables), source_bqm, info=info, **vectors)