Esempio n. 1
0
 def sample(self, bqm, *args, **kwargs):
     msg = ("PolySampler.sample is deprecated and will be removed in dimod "
            "0.9.0. In the future, when using PolySamplers, you should use "
            ".sample_poly")
     warnings.warn(msg, DeprecationWarning)
     poly = BinaryPolynomial(bqm.quadratic)
     poly.update(((v, ), bias) for v, bias in bqm.linear.items())
     return self.sample_poly(poly, *args, **kwargs)
Esempio n. 2
0
    def sample_hubo(self, H, **kwargs):
        """Sample from a higher-order unconstrained binary optimization problem.

        Convert the given higher-order unconstrained binary optimization
        problem to a :obj:`.BinaryPolynomial` and then call
        :meth:`.sample_poly`.

        Args:
            H (dict):
                Coefficients of the HUBO as a dict of the form
                {(u, v, ...): bias, ...}, where `u`, `v`, are binary-valued
                variables in the polynomial and `bias` their associated
                coefficient.

            **kwargs:
                See :meth:`.sample_poly` for additional keyword definitions.

        Returns:
            :obj:`.SampleSet`

        See also:
            :meth:`.sample_poly`, :meth:`.sample_hising`

        """
        return self.sample_poly(BinaryPolynomial.from_hubo(H), **kwargs)
Esempio n. 3
0
    def sample_hising(self, h, J, **kwargs):
        """Sample from a higher-order Ising model.

        Convert the given higher-order Ising model to a :obj:`.BinaryPolynomial`
        and call :meth:`.sample_poly`.

        Args:
            h (dict):
                Variable biases of the Ising problem as a dict of
                the form `{v: bias, ...}`, where `v` is a variable in the
                polynomial and `bias` its associated coefficient.

            J (dict):
                Interaction biases of the Ising problem as a dict of
                the form `{(u, v, ...): bias}`, where `u`, `v`, are spin-valued
                variables in the polynomial and `bias` their associated
                coefficient.

            **kwargs:
                See :meth:`.sample_poly` for additional keyword definitions.

        Returns:
            :obj:`.SampleSet`

        See also:
            :meth:`.sample_poly`, :meth:`.sample_hubo`

        """
        return self.sample_poly(BinaryPolynomial.from_hising(h, J), **kwargs)
Esempio n. 4
0
def poly_energy(sample_like, poly):
    """Calculates energy of a sample from a higher order polynomial.

    Args:
         sample (samples_like):
            A raw sample. `samples_like` is an extension of NumPy's
            array_like structure. See :func:`.as_samples`.

        poly (dict):
            Polynomial as a dict of form {term: bias, ...}, where `term` is a
            tuple of variables and `bias` the associated bias.

    Returns:
        float: The energy of the sample.

    """
    return BinaryPolynomial(poly, 'SPIN').energy(sample_like)
Esempio n. 5
0
def poly_energies(samples_like, poly):
    """Calculates energy of samples from a higher order polynomial.

    Args:
        sample (samples_like):
            A collection of raw samples. `samples_like` is an extension of
            NumPy's array_like structure. See :func:`.as_samples`.

        poly (dict):
            Polynomial as a dict of form {term: bias, ...}, where `term` is a
            tuple of variables and `bias` the associated bias. Variable
            labeling/indexing of terms in poly dict must match that of the
            sample(s).

    Returns:
        list/:obj:`numpy.ndarray`: The energy of the sample(s).

    """
    return BinaryPolynomial(poly, 'SPIN').energies(samples_like)
Esempio n. 6
0
def fix_variables(poly, fixed_variables):
    if () in poly.keys():
        offset = poly[()]
    else:
        offset = 0.0
    poly_copy = defaultdict(float)
    for k, v in poly.items():
        k = set(k)
        for var, value in fixed_variables.items():
            if var in k:
                k -= {var}
                v *= value
        k = frozenset(k)
        if len(k) > 0:
            poly_copy[k] += v
        else:
            offset += v
    poly_copy[()] = offset
    return BinaryPolynomial(poly_copy, poly.vartype)
Esempio n. 7
0
def poly_energy(sample_like, poly):
    """Calculates energy of a sample from a higher order polynomial.

    Args:
         sample (samples_like):
            A raw sample. `samples_like` is an extension of NumPy's
            array_like structure. See :func:`.as_samples`.

        poly (dict):
            Polynomial as a dict of form {term: bias, ...}, where `term` is a
            tuple of variables and `bias` the associated bias.

    Returns:
        float: The energy of the sample.

    """

    msg = ("poly_energy is deprecated and will be removed in dimod 0.9.0."
           "In the future, use BinaryPolynomial.energy")
    warnings.warn(msg, DeprecationWarning)
    # dev note the vartype is not used in the energy calculation and this will
    # be deprecated in the future
    return BinaryPolynomial(poly, 'SPIN').energy(sample_like)
Esempio n. 8
0
def poly_energies(samples_like, poly):
    """Calculates energy of samples from a higher order polynomial.

    Args:
        sample (samples_like):
            A collection of raw samples. `samples_like` is an extension of
            NumPy's array_like structure. See :func:`.as_samples`.

        poly (dict):
            Polynomial as a dict of form {term: bias, ...}, where `term` is a
            tuple of variables and `bias` the associated bias. Variable
            labeling/indexing of terms in poly dict must match that of the
            sample(s).

    Returns:
        list/:obj:`numpy.ndarray`: The energy of the sample(s).

    """
    msg = ("poly_energies is deprecated and will be removed in dimod 0.9.0."
           "In the future, use BinaryPolynomial.energies")
    warnings.warn(msg, DeprecationWarning)
    # dev note the vartype is not used in the energy calculation and this will
    # be deprecated in the future
    return BinaryPolynomial(poly, 'SPIN').energies(samples_like)
Esempio n. 9
0
    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)
Esempio n. 10
0
def _init_binary_polynomial(poly, vartype):
    if not (isinstance(poly, BinaryPolynomial) and
            (vartype in (poly.vartype, None))):
        poly = BinaryPolynomial(poly, vartype=vartype)
    return poly
Esempio n. 11
0
def reduce_binary_polynomial(
    poly: BinaryPolynomial
) -> Tuple[List[Tuple[FrozenSet[Hashable], Number]], List[Tuple[
        FrozenSet[Hashable], Hashable]]]:
    """ Reduce a Binary polynomial to a list of quadratic terms and constraints
    by introducing auxillary variables and creating costraints.
    
    Args:
        poly: BinaryPolynomial

    Returns:
        ([(term, bias)*], [((orig_var1, orig_var2), aux_var)*])

    Example:
        >>> poly = dimod.BinaryPolynomial({(0,): -1, (1,): 1, (2,): 1.5, (0, 1): -1, (0, 1, 2): -2}, dimod.BINARY)
        >>> reduce_binary_polynomial(poly) # doctest: +SKIP
        ([(frozenset({0}), -1),
          (frozenset({1}), 1),
          (frozenset({2}), 1.5),
          (frozenset({0, 1}), -1),
          (frozenset({'0*1', 2}), -2)],
         [(frozenset({0, 1}), '0*1')])
    """

    variables = poly.variables
    constraints = []

    reduced_terms = []
    idx = defaultdict(dict)
    for item in poly.items():
        term, bias = item
        if len(term) <= 2:
            reduced_terms.append(item)
        else:
            for pair in itertools.combinations(term, 2):
                idx[frozenset(pair)][term] = bias

    que = defaultdict(set)
    for pair, terms in idx.items():
        que[len(terms)].add(pair)

    while idx:
        new_pairs = set()
        most = max(que)
        que_most = que[most]
        pair = que_most.pop()
        if not que_most:
            del que[most]
        terms = idx.pop(pair)

        prod_var = _new_product(variables, *pair)
        constraints.append((pair, prod_var))
        prod_var_set = {prod_var}

        for old_term, bias in terms.items():
            common_subterm = (old_term - pair)
            new_term = common_subterm | prod_var_set

            for old_pair in map(frozenset,
                                itertools.product(pair, common_subterm)):
                _decrement_count(idx, que, old_pair)
                _remove_old(idx, old_term, old_pair)

            for common_pair in map(frozenset,
                                   itertools.combinations(common_subterm, 2)):
                idx[common_pair][new_term] = bias
                _remove_old(idx, old_term, common_pair)

            if len(new_term) > 2:
                for new_pair in (frozenset((prod_var, v))
                                 for v in common_subterm):
                    idx[new_pair][new_term] = bias
                    new_pairs.add(new_pair)
            else:
                reduced_terms.append((new_term, bias))

        for new_pair in new_pairs:
            que[len(idx[new_pair])].add(new_pair)

    return reduced_terms, constraints
Esempio n. 12
0
def make_quadratic(poly, strength, vartype=None, bqm=None):
    """Create a binary 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.

        strength (float):
            The energy penalty for violating the prodcut constraint.
            Insufficient strength can result in the binary quadratic model not
            having the same minimizations as the polynomial.

        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 `bqm` is provided, `vartype` is not required.

        bqm (:class:`.BinaryQuadraticModel`, optional):
            The terms of the reduced polynomial are added to this binary quadratic model.
            If not provided, a new binary quadratic model is created.

    Returns:
        :class:`.BinaryQuadraticModel`

    Examples:

        >>> poly = {(0,): -1, (1,): 1, (2,): 1.5, (0, 1): -1, (0, 1, 2): -2}
        >>> bqm = dimod.make_quadratic(poly, 5.0, dimod.SPIN)

    """
    if vartype is None:
        if bqm is None:
            raise ValueError("one of vartype or bqm must be provided")
        else:
            vartype = bqm.vartype
    else:
        vartype = as_vartype(vartype)  # handle other vartype inputs
        if bqm is None:
            bqm = BinaryQuadraticModel.empty(vartype)
        else:
            bqm = bqm.change_vartype(vartype, inplace=False)

    bqm.info['reduction'] = {}

    # we want to be able to mutate the polynomial so copy. We treat this as a
    # dict but by using BinaryPolynomial we also get automatic handling of
    # square terms
    poly = BinaryPolynomial(poly, vartype=bqm.vartype)
    variables = set().union(*poly)

    while any(len(term) > 2 for term in poly):
        # determine which pair of variables appear most often
        paircounter = Counter()
        for term in poly:
            if len(term) <= 2:
                # we could leave these in but it can lead to cases like
                # {'ab': -1, 'cdef': 1} where ab keeps being chosen for
                # elimination. So we just ignore all the pairs
                continue
            for u, v in itertools.combinations(term, 2):
                pair = frozenset((u, v))  # so order invarient
                paircounter[pair] += 1
        pair, __ = paircounter.most_common(1)[0]
        u, v = pair

        # make a new product variable p == u*v and replace all (u, v) with p
        p = _new_product(variables, u, v)
        terms = [term for term in poly if u in term and v in term]
        for term in terms:
            new = tuple(w for w in term if w != u and w != v) + (p, )
            poly[new] = poly.pop(term)

        # add a constraint enforcing the relationship between p == u*v
        if vartype is Vartype.BINARY:
            constraint = _binary_product([u, v, p])

            bqm.info['reduction'][(u, v)] = {'product': p}
        elif vartype is Vartype.SPIN:
            aux = _new_aux(variables, u, v)  # need an aux in SPIN-space

            constraint = _spin_product([u, v, p, aux])

            bqm.info['reduction'][(u, v)] = {'product': p, 'auxiliary': aux}
        else:
            raise RuntimeError("unknown vartype: {!r}".format(vartype))

        # scale constraint and update the polynomial with it
        constraint.scale(strength)
        for v, bias in constraint.linear.items():
            try:
                poly[v, ] += bias
            except KeyError:
                poly[v, ] = bias
        for uv, bias in constraint.quadratic.items():
            try:
                poly[uv] += bias
            except KeyError:
                poly[uv] = bias
        try:
            poly[()] += constraint.offset
        except KeyError:
            poly[()] = constraint.offset

    # convert poly to a bqm (it already is one)
    for term, bias in poly.items():
        if len(term) == 2:
            u, v = term
            bqm.add_interaction(u, v, bias)
        elif len(term) == 1:
            v, = term
            bqm.add_variable(v, bias)
        elif len(term) == 0:
            bqm.add_offset(bias)
        else:
            # still has higher order terms, this shouldn't happen
            msg = ('Internal error: not all higher-order terms were reduced. '
                   'Please file a bug report.')
            raise RuntimeError(msg)

    return bqm