def bin_packing( num_items: int, seed: int = 32, weight_range: Tuple[int, int] = (10, 30), ) -> ConstrainedQuadraticModel: """Returns a constrained quadratic model encoding a bin packing problem Given the number of items, the code generates a random bin packing problem formulated as a Constrained Quadratic model. The weights for each item are integers uniformly drawn from in the weight_range. The bin capacity is set to num_items * mean(weights) / 5. Args: num_items: Number of items to choose from. seed: Seed for numpy random number generator. weight_range: The range of the randomly generated weights for each item. Returns: The constrained quadratic model encoding the bin packing problem. Variables are labeled as y_{j} where y_{j} = 1 means that bin j has been used and x_{i}_{j} where x_{i}_{j} = 1 means that item i has been placed in bin j. """ max_num_bins = num_items np.random.seed(seed) weights = list(np.random.randint(*weight_range, num_items)) bin_capacity = int(num_items * np.mean(weights) / 5) model = ConstrainedQuadraticModel() obj = BinaryQuadraticModel(vartype='BINARY') y = {j: obj.add_variable(f'y_{j}') for j in range(max_num_bins)} for j in range(max_num_bins): obj.set_linear(y[j], 1) model.set_objective(obj) x = {(i, j): model.add_variable(f'x_{i}_{j}', vartype='BINARY') for i in range(num_items) for j in range(max_num_bins)} # Each item goes to one bin for i in range(num_items): model.add_constraint([(x[(i, j)], 1) for j in range(max_num_bins)] + [(-1, )], sense="==", label='item_placing_{}'.format(i)) # Bin capacity constraint for j in range(max_num_bins): model.add_constraint([(x[(i, j)], weights[i]) for i in range(num_items)] + [(y[j], -bin_capacity)], sense="<=", label='capacity_bin_{}'.format(j)) return model
def to_json(self): """ Transform an Ising representation of a problem into a dimod.BinaryQuadraticModel (BQM) and return the serialized BQM. Returns ------- bqm.to_serializable(): dict The serialized BQM """ bqm = BinaryQuadraticModel(self.linear_dict, self.quadratic_dict, 0.0, dimod.SPIN) return bqm.to_serializable()
def random_knapsack( num_items: int, seed: int = 32, value_range: Tuple[int, int] = (10, 30), weight_range: Tuple[int, int] = (10, 30), tightness_ratio: float = 0.5, ) -> ConstrainedQuadraticModel: """Returns a Constrained Quadratic Model encoding a knapsack problem. Given the number of items, the code generates a random knapsack problem, formulated as a Constrained Quadratic model. The capacity of the bin is set to be ``tightness_ratio`` times the sum of the weights. Args: num_items: Number of items to choose from. seed: Seed for numpy random number generator. value_range: The range of the randomly generated values for each item. weight_range: The range of the randomly generated weights for each item. tightness_ratio: ratio of capacity over sum of weights. Returns: The quadratic model encoding the knapsack problem. Variables are denoted as ``x_{i}`` where ``x_{i} == 1`` means that the item ``i`` has been placed in the knapsack. """ rng = np.random.RandomState(seed) value = {i: rng.randint(*value_range) for i in range(num_items)} weight = {i: rng.randint(*weight_range) for i in range(num_items)} capacity = int(sum(weight.values()) * tightness_ratio) model = ConstrainedQuadraticModel() obj = BinaryQuadraticModel(vartype='BINARY') x = {i: obj.add_variable(f'x_{i}') for i in range(num_items)} for i in range(num_items): obj.set_linear(x[i], -value[i]) model.set_objective(obj) constraint = [(x[i], weight[i]) for i in range(num_items)] + [(-capacity, )] model.add_constraint(constraint, sense="<=", label='capacity') return model
def from_pandas_dataframe(bqm_df, offset=0.0, interactions=[]): """Build a binary quadratic model from a pandas dataframe. Args: bqm_df (:class:`pandas.DataFrame`): A pandas dataframe. The row and column indices should be that variables of the binary quadratic program. The values should be the coefficients of a qubo. offset (optional, default=0.0): The constant offset for the binary quadratic program. interactions (iterable, optional, default=[]): Any additional 0.0-bias interactions to be added to the binary quadratic model. Returns: :class:`.BinaryQuadraticModel` """ bqm = BinaryQuadraticModel({}, {}, offset, Vartype.BINARY) for u, row in bqm_df.iterrows(): for v, bias in row.iteritems(): if u == v: bqm.add_variable(u, bias) elif bias: bqm.add_interaction(u, v, bias) for u, v in interactions: bqm.add_interaction(u, v, 0.0) return bqm
def sample_ising(self, h, J, **parameters): """Samples from an Ising model using an implemented sample method. Examples: This example implements a placeholder QUBO sampler and samples using the mixin Ising sampler. >>> import dimod >>> class ImplementQuboSampler(dimod.Sampler): ... def sample_qubo(self, Q): ... return dimod.Response.from_dicts([{1: -1, 2: +1}], {'energy': [-1.0]}) # Placeholder ... @property ... def properties(self): ... return self._properties ... @property ... def parameters(self): ... return dict() ... >>> sampler = ImplementQuboSampler() >>> h = {1: 0.5, 2: -1, 3: -0.75} >>> J = {} >>> res = sampler.sample_ising(h, J) >>> print(res) [[-1 1]] """ bqm = BinaryQuadraticModel.from_ising(h, J) response = self.sample(bqm, **parameters) return response
def sample_qubo(self, Q, **parameters): """Sample from a QUBO using the implemented sample method. This method is inherited from the :class:`.Sampler` base class. Converts the QUBO into a :obj:`.BinaryQuadraticModel` and then calls :meth:`.sample`. Args: Q (dict): Coefficients of a quadratic unconstrained binary optimization (QUBO) problem. Should be a dict of the form `{(u, v): bias, ...}` where `u`, `v`, are binary-valued variables and `bias` is their associated coefficient. **kwargs: See the implemented sampling for additional keyword definitions. Returns: :obj:`.SampleSet` See also: :meth:`.sample`, :meth:`.sample_ising` """ bqm = BinaryQuadraticModel.from_qubo(Q) return self.sample(bqm, **parameters)
def bqm_decode_hook(dct): if 'bias' in dct: bias = dct['bias'] if 'label' in dct: u = dct['label'] if isinstance(u, list): u = tuple(u) return (u, bias) else: u = dct['label_head'] v = dct['label_tail'] if isinstance(u, list): u = tuple(u) if isinstance(v, list): v = tuple(v) return ((u, v), bias) elif 'linear_terms' in dct and 'quadratic_terms' in dct: return BinaryQuadraticModel(dict(dct['linear_terms']), dict(dct['quadratic_terms']), dct['offset'], Vartype[dct['variable_type']], **dct['info']) return dct
def _spin_product(variables): """A BQM with a gap of 1 that represents the product of two spin variables. Note that spin-product requires an auxiliary variable. Args: variables (list): multiplier, multiplicand, product, aux Returns: :obj:`.BinaryQuadraticModel` """ multiplier, multiplicand, product, aux = variables return BinaryQuadraticModel( { multiplier: -.5, multiplicand: -.5, product: -.5, aux: -1. }, { (multiplier, multiplicand): .5, (multiplier, product): .5, (multiplier, aux): 1., (multiplicand, product): .5, (multiplicand, aux): 1., (product, aux): 1. }, 2., Vartype.SPIN)
def sample_ising(self, h, J, **parameters): """Sample from an Ising model using the implemented sample method. This method is inherited from the :class:`.Sampler` base class. Converts the Ising model into a :obj:`.BinaryQuadraticModel` and then calls :meth:`.sample`. Args: h (dict/list): Linear biases of the Ising problem. If a dict, should be of the form `{v: bias, ...}` where is a spin-valued variable and `bias` is its associated bias. If a list, it is treated as a list of biases where the indices are the variable labels. J (dict[(variable, variable), bias]): Quadratic biases of the Ising problem. **kwargs: See the implemented sampling for additional keyword definitions. Returns: :obj:`.SampleSet` See also: :meth:`.sample`, :meth:`.sample_qubo` """ bqm = BinaryQuadraticModel.from_ising(h, J) return self.sample(bqm, **parameters)
def sample_qubo(self, Q, **parameters): """Samples from a QUBO using an implemented sample method. Examples: This example implements a placeholder Ising sampler and samples using the mixin QUBO sampler. >>> import dimod >>> class ImplementIsingSampler(dimod.Sampler): ... def sample_ising(self, h, J): ... return dimod.Response.from_dicts([{1: -1, 2: +1}], {'energy': [-1.0]}) # Placeholder ... @property ... def properties(self): ... return self._properties ... @property ... def parameters(self): ... return dict() ... >>> sampler = ImplementIsingSampler() >>> Q = {(0, 0): -0.5, (0, 1): 1, (1, 1): -0.75} >>> res = sampler.sample_qubo(Q) >>> print(res) [[0 1]] """ bqm = BinaryQuadraticModel.from_qubo(Q) response = self.sample(bqm, **parameters) return response
def sample_qubo(self, Q, num_samps=100): """ Sample from the QUBO problem :param qubo: QUBO problem :type qubo: numpy dictionary :return: samples, energy, num_occurrences """ self.num_samps = num_samps if not hasattr(self, 'sampler'): bqm = BinaryQuadraticModel.from_qubo(Q) # apply the embedding to the given problem to map it to the child sampler __, target_edgelist, target_adjacency = self.child.structure # add self-loops to edgelist to handle singleton variables source_edgelist = list(bqm.quadratic) + [(v, v) for v in bqm.linear] # get the embedding embedding = minorminer.find_embedding(source_edgelist, target_edgelist) if bqm and not embedding: raise ValueError("no embedding found") self.sampler = FixedEmbeddingComposite(self.child, embedding) response = self.sampler.sample_qubo(Q, chain_strength=self.chainstrength, num_reads=self.num_samps) return np.array(response.__dict__['_samples_matrix'].tolist()), response.__dict__['_data_vectors']["energy"], \ response.__dict__['_data_vectors']["num_occurrences"]
def to_json(self): """Transform a QUBO dictionary into a dimod.BinaryQuadraticModel (BQM) and return the serialized BQM. Returns ------- bqm.to_serializable(): dict The serialized BQM """ linear = {} quadratic = {} for (a, b) in self.problem_dict.keys(): if a == b: linear[a] = self.problem_dict[(a, b)] else: quadratic[(a, b)] = self.problem_dict[(a, b)] bqm = BinaryQuadraticModel(linear, quadratic, 0.0, dimod.BINARY) return bqm.to_serializable()
def make_quadratic(poly, strength, vartype=None, bqm=None): """Create a binary quadratic model from a higher order polynomial. Args: poly (dict): A polynomial. Should be a dict of the form {term: bias, ...} where term is a tuple of variables and bias is their associated bias. strength (float): The strength of the reduction constraint. Insufficient strength can result in the binary quadratic model not having the same minimizations as the polynomial. vartype (:class:`.Vartype`, optional): The vartype of the polynomial. If a bqm is provided, then vartype is not required. bqm (:class:`.BinaryQuadraticModel`, optional): The terms of the reduced polynomial are added to this bqm. If not provided a new empty binary quadratic model is created. Returns: :class:`.BinaryQuadraticModel` Examples: >>> import dimod ... >>> poly = {(0,): -1, (1,): 1, (2,): 1.5, (0, 1): -1, (0, 1, 2): -2} >>> bqm = make_quadratic(poly, 5.0, dimod.SPIN) """ if bqm is None: if vartype is None: raise ValueError("one of vartype and create_using must be provided") bqm = BinaryQuadraticModel.empty(vartype) else: if not isinstance(bqm, BinaryQuadraticModel): raise TypeError('create_using must be a BinaryQuadraticModel') if vartype is not None and vartype is not bqm.vartype: raise ValueError("one of vartype and create_using must be provided") bqm.info['reduction'] = {} new_poly = {} for term, bias in iteritems(poly): if len(term) == 0: bqm.add_offset(bias) elif len(term) == 1: v, = term bqm.add_variable(v, bias) else: new_poly[term] = bias return _reduce_degree(bqm, new_poly, vartype, strength)
def from_numpy_matrix(mat, variable_order=None, offset=0.0, interactions=[]): """Build a binary quadratic model from a numpy matrix. Args: mat (:class:`numpy.matrix`): A square numpy matrix. The coefficients of a qubo. variable_order (list, optional): If variable_order is provided, provides the labels for the variables in the binary quadratic program, otherwise the row/column indices will be used. If variable_order is longer than the matrix, the extra values are ignored. offset (optional, default=0.0): The constant offset for the binary quadratic program. interactions (iterable, optional, default=[]): Any additional 0.0-bias interactions to be added to the binary quadratic model. Returns: :class:`.BinaryQuadraticModel` """ import numpy as np if mat.ndim != 2: raise ValueError("expected input mat to be a square matrix") # pragma: no cover num_row, num_col = mat.shape if num_col != num_row: raise ValueError("expected input mat to be a square matrix") # pragma: no cover if variable_order is None: variable_order = list(range(num_row)) bqm = BinaryQuadraticModel({}, {}, offset, Vartype.BINARY) for (row, col), bias in np.ndenumerate(mat): if row == col: bqm.add_variable(variable_order[row], bias) elif bias: bqm.add_interaction(variable_order[row], variable_order[col], bias) for u, v in interactions: bqm.add_interaction(u, v, 0.0) return bqm
def make_quadratic_cqm(poly, vartype=None, cqm=None): """Create a constrained quadratic model from a higher order polynomial. Args: poly (dict): Polynomial as a dict of form {term: bias, ...}, where `term` is a tuple of variables and `bias` the associated bias. vartype (:class:`.Vartype`/str/set, optional): Variable type for the binary quadratic model. Accepted input values: * :class:`.Vartype.SPIN`, ``'SPIN'``, ``{-1, 1}`` * :class:`.Vartype.BINARY`, ``'BINARY'``, ``{0, 1}`` If `poly is a BinaryPolynomial , `vartype` is not required. cqm (:class:`.BinaryQuadraticModel`, optional): The terms of the reduced polynomial are added to this constrained quadratic model. If not provided, a new constrained quadratic model is created. Returns: :class:`.ConstrainedQuadraticModel` Examples: >>> poly = {(0,): -1, (1,): 1, (2,): 1.5, (0, 1): -1, (0, 1, 2): -2} >>> cqm = dimod.make_quadratic_cqm(poly, dimod.SPIN) """ if not (vartype or isinstance(poly, BinaryPolynomial)): raise ValueError("can not infer vartype") cqm = cqm or ConstrainedQuadraticModel() vartype = vartype or poly.vartype poly = _init_binary_polynomial(poly, vartype) reduced_terms, constraints = reduce_binary_polynomial(poly) def var(x): return BinaryQuadraticModel({x: 1.0}, {}, 0.0, vartype) for (u, v), p in constraints: cqm.add_constraint(var(u) * var(v) - var(p) == 0, label=f"'{u}'*'{v}' == '{p}'") obj = BinaryQuadraticModel(vartype=vartype) _init_objective(obj, reduced_terms) cqm.set_objective(obj + cqm.objective) return cqm
def dimod_object_hook(obj): """JSON-decoding for dimod objects. See Also: :class:`json.JSONDecoder` for using custom decoders. """ if _is_sampleset_v2(obj): # in the future we could handle subtypes but right now we just have the # one return SampleSet.from_serializable(obj) elif _is_bqm(obj): # in the future we could handle subtypes but right now we just have the # one return BinaryQuadraticModel.from_serializable(obj) return obj
def sample_ising(self, h, J, offset=0, penalty_strength=1.0, keep_penalty_variables=False, discard_unsatisfied=False, **parameters): """ Sample from the problem provided by h, J, offset. Takes in linear variables in h and quadratic and higher order terms in J. Introducing penalties, reduces the higher-order problem into a quadratic problem and send it to its child sampler. Args: h (dict): linear biases corresponding to the HUBO form J (dict): higher order biases corresponding to the HUBO form offset (float, optional): constant energy offset penalty_strength (float, optional): Strength of the reduction constraint. Insufficient strength can result in the binary quadratic model not having the same minimization as the polynomial. keep_penalty_variables (bool, optional): default is True. if False will remove the variables used for penalty from the samples discard_unsatisfied (bool, optional): default is False. If True will discard samples that do not satisfy the penalty conditions. **parameters: Parameters for the sampling method, specified by the child sampler. Returns: :obj:`dimod.SampleSet` """ # solve the problem on the child system bqm = BinaryQuadraticModel.from_ising(h, {}) bqm = make_quadratic(J, penalty_strength, bqm=bqm) response = self.child.sample(bqm, **parameters) return polymorph_response(response, h, J, bqm, offset=offset, penalty_strength=penalty_strength, keep_penalty_variables=keep_penalty_variables, discard_unsatisfied=discard_unsatisfied)
def sample_qubo(self, Q, num_samps=100): """ Sample from the QUBO problem :param qubo: QUBO problem :type qubo: numpy dictionary :return: samples, energy, num_occurrences """ #print(Q) self.num_samps = num_samps if not hasattr(self, 'sampler'): bqm = BinaryQuadraticModel.from_qubo(Q) # apply the embedding to the given problem to map it to the child sampler __, target_edgelist, target_adjacency = self.child.structure # add self-loops to edgelist to handle singleton variables source_edgelist = list(bqm.quadratic) + [(v, v) for v in bqm.linear] # get the embedding embedding = minorminer.find_embedding(source_edgelist, target_edgelist) if bqm and not embedding: raise ValueError("no embedding found") self.sampler = FixedEmbeddingComposite(self.child, embedding) response = EmbeddingComposite( DWaveSampler(token="DEV-db4d47e5313cf3c52cac31dace7c5080a5ffc46d") ).sample_qubo(Q, num_reads=1000) #response = self.sampler.sample_qubo(Q, chain_strength=self.chainstrength, num_reads=self.num_samps) #for sample, energy, num_occurrences, chain_break_fraction in list(response.data()): # print(sample, "Energy: ", energy, "Occurrences: ", num_occurrences) #print(response.samples()[0,[range(0,71)]]) #print(response._asdict()['vectors']['energy']) #print(response._asdict()['vectors']['num_occurrences']) saempeul = np.empty((0, 72)) for sample, in response.data(fields=['sample']): saempeul = np.append(saempeul, sample) #print(saempeul) return saempeul, response._asdict()['vectors']['energy']['data'], \ response._asdict()['vectors']['num_occurrences']['data']
def _binary_product(variables): """Create a bqm with a gap of 2 that represents the product of two variables. Args: variables (list): multiplier, multiplicand, product Returns: :obj:`.BinaryQuadraticModel` """ multiplier, multiplicand, product = variables return BinaryQuadraticModel({multiplier: 0.0, multiplicand: 0.0, product: 3.0}, {(multiplier, multiplicand): 1.0, (multiplier, product): -2.0, (multiplicand, product): -2.0}, 0.0, Vartype.BINARY)
def from_ising(h, J, offset=0.0): """Build a binary quadratic model from an Ising problem. Args: h (dict[variable, bias]/list[bias]): The linear biases of the Ising problem. If a list, the indices of the list are treated as the variable labels. J (dict[(variable, variable), bias]): The quadratic biases of the Ising problem. offset (optional, default=0.0): The constant offset applied to the model. Returns: :class:`.BinaryQuadraticModel` """ if isinstance(h, list): h = dict(enumerate(h)) return BinaryQuadraticModel(h, J, offset, Vartype.SPIN)
def from_qubo(Q, offset=0.0): """Build a binary quadratic model from a qubo. Args: Q (dict): The qubo coefficients. offset (optional, default=0.0): The constant offset applied to the model. Returns: :class:`.BinaryQuadraticModel` """ linear = {} quadratic = {} for (u, v), bias in iteritems(Q): if u == v: linear[u] = bias else: quadratic[(u, v)] = bias return BinaryQuadraticModel(linear, quadratic, offset, Vartype.BINARY)
def sample_ising(self, h, J, offset=0, scalar=None, bias_range=1, quadratic_range=None, ignored_variables=None, ignored_interactions=None, ignore_offset=False, **parameters): """ Scale and sample from the problem provided by h, J, offset if scalar is not given, problem is scaled based on bias and quadratic ranges. Args: h (dict): linear biases J (dict): quadratic or higher order biases offset (float, optional): constant energy offset scalar (number): Value by which to scale the energy range of the binary quadratic model. bias_range (number/pair): Value/range by which to normalize the all the biases, or if `quadratic_range` is provided, just the linear biases. quadratic_range (number/pair): Value/range by which to normalize the quadratic biases. ignored_variables (iterable, optional): Biases associated with these variables are not scaled. ignored_interactions (iterable[tuple], optional): As an iterable of 2-tuples. Biases associated with these interactions are not scaled. ignore_offset (bool, default=False): If True, the offset is not scaled. **parameters: Parameters for the sampling method, specified by the child sampler. Returns: :obj:`dimod.SampleSet` """ if any(len(inter) > 2 for inter in J): # handle HUBO import warnings msg = ("Support for higher order Ising models in ScaleComposite is " "deprecated and will be removed in dimod 0.9.0. Please use " "PolyScaleComposite.sample_hising instead.") warnings.warn(msg, DeprecationWarning) from dimod.reference.composites.higherordercomposites import PolyScaleComposite from dimod.higherorder.polynomial import BinaryPolynomial poly = BinaryPolynomial.from_hising(h, J, offset=offset) ignored_terms = set() if ignored_variables is not None: ignored_terms.update(frozenset(v) for v in ignored_variables) if ignored_interactions is not None: ignored_terms.update(frozenset(inter) for inter in ignored_interactions) if ignore_offset: ignored_terms.add(frozenset()) return PolyScaleComposite(self.child).sample_poly(poly, scalar=scalar, bias_range=bias_range, poly_range=quadratic_range, ignored_terms=ignored_terms, **parameters) bqm = BinaryQuadraticModel.from_ising(h, J, offset=offset) return self.sample(bqm, scalar=scalar, bias_range=bias_range, quadratic_range=quadratic_range, ignored_variables=ignored_variables, ignored_interactions=ignored_interactions, ignore_offset=ignore_offset, **parameters)
def combinations(n, k, strength=1, vartype=BINARY): r"""Generate a BQM that is minimized when k of n variables are selected. More fully, generates a binary quadratic model (BQM) that is minimized for each of the k-combinations of its variables. The energy for the BQM is given by :math:`(\sum_{i} x_i - k)^2`. Args: n (int/list/set): If n is an integer, variables are labelled [0, n-1]. If n is a list or set, variables are labelled accordingly. k (int): The generated BQM has 0 energy when any k of its variables are 1. strength (number, optional, default=1): The energy of the first excited state of the BQM. vartype (:class:`.Vartype`/str/set): Variable type for the BQM. Accepted input values: * :class:`.Vartype.SPIN`, ``'SPIN'``, ``{-1, 1}`` * :class:`.Vartype.BINARY`, ``'BINARY'``, ``{0, 1}`` Returns: :obj:`.BinaryQuadraticModel` Examples: >>> bqm = dimod.generators.combinations(['a', 'b', 'c'], 2) >>> bqm.energy({'a': 1, 'b': 0, 'c': 1}) 0.0 >>> bqm.energy({'a': 1, 'b': 1, 'c': 1}) 1.0 >>> bqm = dimod.generators.combinations(5, 1) >>> bqm.energy({0: 0, 1: 0, 2: 1, 3: 0, 4: 0}) 0.0 >>> bqm.energy({0: 0, 1: 0, 2: 1, 3: 1, 4: 0}) 1.0 >>> bqm = dimod.generators.combinations(['a', 'b', 'c'], 2, strength=3.0) >>> bqm.energy({'a': 1, 'b': 0, 'c': 1}) 0.0 >>> bqm.energy({'a': 1, 'b': 1, 'c': 1}) 3.0 """ if isinstance(n, abc.Sized) and isinstance(n, abc.Iterable): # what we actually want is abc.Collection but that doesn't exist in # python2 variables = n else: try: variables = range(n) except TypeError: raise TypeError('n should be a collection or an integer') if k > len(variables) or k < 0: raise ValueError("cannot select k={} from {} variables".format(k, len(variables))) # (\sum_i x_i - k)^2 # = \sum_i x_i \sum_j x_j - 2k\sum_i x_i + k^2 # = \sum_{i,j} x_ix_j + (1 - 2k)\sum_i x_i + k^2 lbias = float(strength*(1 - 2*k)) qbias = float(2*strength) bqm = BinaryQuadraticModel.empty(BINARY) bqm.add_variables_from(((v, lbias) for v in variables)) bqm.add_interactions_from(((u, v, qbias) for u, v in itertools.combinations(variables, 2))) bqm.offset += strength*(k**2) return bqm.change_vartype(vartype, inplace=True)
def sample_ising(self, h, J, offset=0, scalar=None, bias_range=1, quadratic_range=None, ignored_variables=None, ignored_interactions=None, ignore_offset=False, **parameters): """ Scale and sample from the problem provided by h, J, offset if scalar is not given, problem is scaled based on bias and quadratic ranges. Args: h (dict): linear biases J (dict): quadratic or higher order biases offset (float, optional): constant energy offset scalar (number): Value by which to scale the energy range of the binary quadratic model. bias_range (number/pair): Value/range by which to normalize the all the biases, or if `quadratic_range` is provided, just the linear biases. quadratic_range (number/pair): Value/range by which to normalize the quadratic biases. ignored_variables (iterable, optional): Biases associated with these variables are not scaled. ignored_interactions (iterable[tuple], optional): As an iterable of 2-tuples. Biases associated with these interactions are not scaled. ignore_offset (bool, default=False): If True, the offset is not scaled. **parameters: Parameters for the sampling method, specified by the child sampler. Returns: :obj:`dimod.SampleSet` """ # if quadratic, create a bqm and send to sample if max(map(len, J.keys())) == 2: bqm = BinaryQuadraticModel.from_ising(h, J, offset=offset) return self.sample(bqm, scalar=scalar, bias_range=bias_range, quadratic_range=quadratic_range, ignored_variables=ignored_variables, ignored_interactions=ignored_interactions, ignore_offset=ignore_offset, **parameters) # handle HUBO ignored_variables, ignored_interactions = _check_params( ignored_variables, ignored_interactions) child = self.child h_sc, J_sc, offset_sc = _scaled_hubo(h, J, offset, scalar, bias_range, quadratic_range, ignored_variables, ignored_interactions, ignore_offset) response = child.sample_ising(h_sc, J_sc, offset=offset_sc, **parameters) poly = _relabeled_poly(h, J, response.variables.index) response.record.energy = np.add( poly_energies(response.record.sample, poly), offset) return response
def embed_qubo(source_Q, embedding, target_adjacency, chain_strength=1.0): """Embed a QUBO onto a target graph. Args: source_Q (dict[(variable, variable), bias]): Coefficients of a quadratic unconstrained binary optimization (QUBO) model. 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. target_adjacency (dict/:class:`networkx.Graph`): Adjacency of the target graph as a dict of form {t: Nt, ...}, where t is a target-graph variable and Nt is its set of neighbours. chain_strength (float, optional): Magnitude of the quadratic bias (in SPIN-space) applied between variables to form a chain. Note that the energy penalty of chain breaks is 2 * `chain_strength`. Returns: dict[(variable, variable), bias]: Quadratic biases of the target QUBO. Examples: This example embeds a square source graph onto fully connected :math:`K_5` graph. Embedding is accomplished by an edge deletion operation on the target graph: target-node 0 is not used. >>> import dimod >>> import networkx as nx >>> # QUBO problem for a square graph >>> Q = {(1, 1): -4.0, (1, 2): 4.0, (2, 2): -4.0, (2, 3): 4.0, ... (3, 3): -4.0, (3, 4): 4.0, (4, 1): 4.0, (4, 4): -4.0} >>> # Target graph is a fully connected k5 graph >>> K_5 = nx.complete_graph(5) >>> 0 in K_5 True >>> # Embedding from source to target graph >>> embedding = {1: {4}, 2: {3}, 3: {1}, 4: {2}} >>> # Embed the QUBO >>> target_Q = dimod.embed_qubo(Q, embedding, K_5) >>> (0, 0) in target_Q False >>> target_Q # doctest: +SKIP {(1, 1): -4.0, (1, 2): 4.0, (2, 2): -4.0, (2, 4): 4.0, (3, 1): 4.0, (3, 3): -4.0, (4, 3): 4.0, (4, 4): -4.0} This example embeds a square graph onto the target graph of a dimod reference structured sampler, `StructureComposite`, using the dimod reference `ExactSolver` sampler with a fully connected :math:`K_5` graph specified. >>> import dimod >>> import networkx as nx >>> # QUBO problem for a square graph >>> Q = {(1, 1): -4.0, (1, 2): 4.0, (2, 2): -4.0, (2, 3): 4.0, ... (3, 3): -4.0, (3, 4): 4.0, (4, 1): 4.0, (4, 4): -4.0} >>> # Structured dimod sampler with a structure defined by a K5 graph >>> sampler = dimod.StructureComposite(dimod.ExactSolver(), list(K_5.nodes), list(K_5.edges)) >>> sampler.adjacency # doctest: +SKIP {0: {1, 2, 3, 4}, 1: {0, 2, 3, 4}, 2: {0, 1, 3, 4}, 3: {0, 1, 2, 4}, 4: {0, 1, 2, 3}} >>> # Embedding from source to target graph >>> embedding = {0: [4], 1: [3], 2: [1], 3: [2], 4: [0]} >>> # Embed the QUBO >>> target_Q = dimod.embed_qubo(Q, embedding, sampler.adjacency) >>> # Sample >>> response = sampler.sample_qubo(target_Q) >>> for datum in response.data(): # doctest: +SKIP ... print(datum) ... Sample(sample={1: 0, 2: 1, 3: 1, 4: 0}, energy=-8.0) Sample(sample={1: 1, 2: 0, 3: 0, 4: 1}, energy=-8.0) Sample(sample={1: 1, 2: 0, 3: 0, 4: 0}, energy=-4.0) Sample(sample={1: 1, 2: 1, 3: 0, 4: 0}, energy=-4.0) Sample(sample={1: 0, 2: 1, 3: 0, 4: 0}, energy=-4.0) Sample(sample={1: 1, 2: 1, 3: 1, 4: 0}, energy=-4.0) >>> # Snipped above response for brevity """ source_bqm = BinaryQuadraticModel.from_qubo(source_Q) target_bqm = embed_bqm(source_bqm, embedding, target_adjacency, chain_strength=chain_strength) target_Q, __ = target_bqm.to_qubo() return target_Q
def embed_ising(souce_h, source_J, embedding, target_adjacency, chain_strength=1.0): """Embed an Ising problem onto a target graph. Args: source_h (dict[variable, bias]/list[bias]): Linear biases of the Ising problem. If a list, the list's indices are used as variable labels. source_J (dict[(variable, variable), bias]): Quadratic biases of the Ising problem. 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. target_adjacency (dict/:class:`networkx.Graph`): Adjacency of the target graph as a dict of form {t: Nt, ...}, where t is a target-graph variable and Nt is its set of neighbours. chain_strength (float, optional): Magnitude of the quadratic bias (in SPIN-space) applied between variables to form a chain. Note that the energy penalty of chain breaks is 2 * `chain_strength`. Returns: tuple: A 2-tuple: dict[variable, bias]: Linear biases of the target Ising problem. dict[(variable, variable), bias]: Quadratic biases of the target Ising problem. Examples: This example embeds a fully connected :math:`K_3` graph onto a square target graph. Embedding is accomplished by an edge contraction operation on the target graph: target-nodes 2 and 3 are chained to represent source-node c. >>> import dimod >>> import networkx as nx >>> # Ising problem for a triangular source graph >>> h = {} >>> J = {('a', 'b'): 1, ('b', 'c'): 1, ('a', 'c'): 1} >>> # Target graph is a square graph >>> target = nx.cycle_graph(4) >>> # Embedding from source to target graph >>> embedding = {'a': {0}, 'b': {1}, 'c': {2, 3}} >>> # Embed the Ising problem >>> target_h, target_J = dimod.embed_ising(h, J, embedding, target) >>> target_J[(0, 1)] == J[('a', 'b')] True >>> target_J # doctest: +SKIP {(0, 1): 1.0, (0, 3): 1.0, (1, 2): 1.0, (2, 3): -1.0} This example embeds a fully connected :math:`K_3` graph onto the target graph of a dimod reference structured sampler, `StructureComposite`, using the dimod reference `ExactSolver` sampler with a square graph specified. Target-nodes 2 and 3 are chained to represent source-node c. >>> import dimod >>> # Ising problem for a triangular source graph >>> h = {} >>> J = {('a', 'b'): 1, ('b', 'c'): 1, ('a', 'c'): 1} >>> # Structured dimod sampler with a structure defined by a square graph >>> sampler = dimod.StructureComposite(dimod.ExactSolver(), [0, 1, 2, 3], [(0, 1), (1, 2), (2, 3), (0, 3)]) >>> # Embedding from source to target graph >>> embedding = {'a': {0}, 'b': {1}, 'c': {2, 3}} >>> # Embed the Ising problem >>> target_h, target_J = dimod.embed_ising(h, J, embedding, sampler.adjacency) >>> # Sample >>> response = sampler.sample_ising(target_h, target_J) >>> for sample in response.samples(n=3, sorted_by='energy'): # doctest: +SKIP ... print(sample) ... {0: 1, 1: -1, 2: -1, 3: -1} {0: 1, 1: 1, 2: -1, 3: -1} {0: -1, 1: 1, 2: -1, 3: -1} """ source_bqm = BinaryQuadraticModel.from_ising(souce_h, source_J) target_bqm = embed_bqm(source_bqm, embedding, target_adjacency, chain_strength=chain_strength) target_h, target_J, __ = target_bqm.to_ising() return target_h, target_J
def get_qubo_embedding(self, Q, **parameters): """Retrieve or create a minor-embedding from QUBO """ bqm = BinaryQuadraticModel.from_qubo(Q) embedding = self.get_embedding(bqm, **parameters) return embedding
def get_ising_embedding(self, h, J, **parameters): """Retrieve or create a minor-embedding from Ising model """ bqm = BinaryQuadraticModel.from_ising(h, J) embedding = self.get_embedding(bqm, **parameters) return embedding
def sample_qubo(self, Q, **parameters): """Samples from the given QUBO using the instantiated sample method.""" bqm = BinaryQuadraticModel.from_qubo(Q) response = self.sample(bqm, **parameters) return response
def sample_ising(self, h, J, **parameters): """Samples from the given Ising model using the instantiated sample method.""" bqm = BinaryQuadraticModel.from_ising(h, J) response = self.sample(bqm, **parameters) return response