def test_retrieval(self):
        eq = {(-1, -1), (1, 1)}

        spec = pm.Specification(nx.path_graph(2), (0, 1), eq, vartype=pm.SPIN)
        widget = pm.get_penalty_model(spec)

        self.assert_dict_almost_equal(widget.model.linear, {0: 0, 1: 0})
        self.assert_dict_almost_equal(widget.model.quadratic, {(0, 1): -1})
Example #2
0
def gate_model(gate_type, fault=True):
    labels, configurations = GATES[gate_type]
    if fault:
        configurations = fault_gate(configurations, FAULT_GAP)
    num_variables = len(next(iter(configurations)))
    for size in range(num_variables, num_variables + 4):  # reasonable margin
        G = nx.complete_graph(size)
        nx.relabel_nodes(G, dict(enumerate(labels)), copy=False)
        spec = pm.Specification(G, labels, configurations, dimod.SPIN)
        try:
            pmodel = pm.get_penalty_model(spec)
            if pmodel is not None:
                return pmodel
        except pm.ImpossiblePenaltyModel:
            pass

    raise ValueError("unable to get the penalty model from factories")
    def test_retrieval(self):
        # put some stuff in the database

        spec = pm.Specification(nx.path_graph(2), (0, 1), {(-1, -1), (1, 1)},
                                vartype=pm.SPIN)
        model = dimod.BinaryQuadraticModel({
            0: 0,
            1: 0
        }, {(0, 1): -1},
                                           0.0,
                                           vartype=pm.SPIN)
        widget = pm.PenaltyModel.from_specification(spec, model, 2, -1)

        for cache in pm.iter_caches():
            cache(widget)

        # now try to get it back
        new_widget = pm.get_penalty_model(spec)

        self.assertEqual(widget, new_widget)
Example #4
0
    def test_one_variable_insert_retrieve(self):
        """Test case when there is no quadratic contribution (i.e. cache will
        receive an empty value for the quadratic contribution)
        """
        dbfile = self.database

        # generate one variable model (i.e. no quadratic terms)
        spec = pm.Specification(graph=nx.complete_graph(1),
                                decision_variables=[0],
                                feasible_configurations=[(-1, )],
                                min_classical_gap=2,
                                vartype='SPIN')
        pmodel = pm.get_penalty_model(spec)

        # insert model into cache
        pmc.cache_penalty_model(pmodel, database=dbfile)

        # retrieve model back from cache
        retrieved_model = pmc.get_penalty_model(spec, database=dbfile)
        self.assertEqual(pmodel, retrieved_model)
Example #5
0
def gate_model(gate_type, fault=True):
    labels, configurations = GATES[gate_type]
    if fault:
        configurations = fault_gate(configurations, FAULT_GAP)
    size = len(next(iter(configurations)))
    while True:
        G = nx.complete_graph(size)
        nx.relabel_nodes(G, dict(enumerate(labels)), copy=False)
        spec = pm.Specification(G, labels, configurations, dimod.SPIN)
        try:
            pmodel = pm.get_penalty_model(spec)
            if not pmodel:
                raise LookupError("failed to get penalty model from factory")
            # print("penalty model fits on K{}".format(size))
            break
        except pm.ImpossiblePenaltyModel:
            # print("penalty model does not fit on K{}".format(size))
            size += 1

    # print('h: {}'.format(pmodel.model.linear))
    # print('J: {}\n'.format(pmodel.model.quadratic))
    return pmodel
Example #6
0
def stitch(csp, min_classical_gap=2.0, max_graph_size=8):
    """Build a binary quadratic model with minimal energy levels at solutions to the specified constraint satisfaction
    problem.

    Args:
        csp (:obj:`.ConstraintSatisfactionProblem`):
            Constraint satisfaction problem.

        min_classical_gap (float, optional, default=2.0):
            Minimum energy gap from ground. Each constraint violated by the solution increases
            the energy level of the binary quadratic model by at least this much relative
            to ground energy.

        max_graph_size (int, optional, default=8):
            Maximum number of variables in the binary quadratic model that can be used to
            represent a single constraint.

    Returns:
        :class:`~dimod.BinaryQuadraticModel`

    Notes:
        For a `min_classical_gap` > 2 or constraints with more than two variables, requires
        access to factories from the penaltymodel_ ecosystem to construct the binary quadratic
        model.

    .. _penaltymodel: https://github.com/dwavesystems/penaltymodel

    Examples:
        This example creates a binary-valued constraint satisfaction problem
        with two constraints, :math:`a = b` and :math:`b \\ne c`, and builds
        a binary quadratic model such that
        each constraint violation by a solution adds the default minimum energy gap.

        >>> import operator
        >>> csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY)
        >>> csp.add_constraint(operator.eq, ['a', 'b'])  # a == b
        >>> csp.add_constraint(operator.ne, ['b', 'c'])  # b != c
        >>> bqm = dwavebinarycsp.stitch(csp)

        Variable assignments that satisfy the CSP above, violate one, then two constraints,
        produce energy increases of the default minimum classical gap:

        >>> bqm.energy({'a': 0, 'b': 0, 'c': 1})  # doctest: +SKIP
        -2.0
        >>> bqm.energy({'a': 0, 'b': 0, 'c': 0})  # doctest: +SKIP
        0.0
        >>> bqm.energy({'a': 1, 'b': 0, 'c': 0}) #  doctest: +SKIP
        2.0

        This example creates a binary-valued constraint satisfaction problem
        with two constraints, :math:`a = b` and :math:`b \\ne c`, and builds
        a binary quadratic model with a minimum energy gap of 4.
        Note that in this case the conversion to binary quadratic model adds two
        ancillary variables that must be minimized over when solving.

        >>> import operator
        >>> import itertools
        >>> csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY)
        >>> csp.add_constraint(operator.eq, ['a', 'b'])  # a == b
        >>> csp.add_constraint(operator.ne, ['b', 'c'])  # b != c
        >>> bqm = dwavebinarycsp.stitch(csp, min_classical_gap=4.0)
        >>> list(bqm)   # doctest: +SKIP
        ['a', 'aux1', 'aux0', 'b', 'c']

        Variable assignments that satisfy the CSP above, violate one, then two constraints,
        produce energy increases of the specified minimum classical gap:

        >>> min([bqm.energy({'a': 0, 'b': 0, 'c': 1, 'aux0': aux0, 'aux1': aux1}) for
        ... aux0, aux1 in list(itertools.product([0, 1], repeat=2))])  # doctest: +SKIP
        -6.0
        >>> min([bqm.energy({'a': 0, 'b': 0, 'c': 0, 'aux0': aux0, 'aux1': aux1}) for
        ... aux0, aux1 in list(itertools.product([0, 1], repeat=2))])  # doctest: +SKIP
        -2.0
        >>> min([bqm.energy({'a': 1, 'b': 0, 'c': 0, 'aux0': aux0, 'aux1': aux1}) for
        ... aux0, aux1 in list(itertools.product([0, 1], repeat=2))])  # doctest: +SKIP
        2.0

        This example finds for the previous example the minimum graph size.

        >>> import operator
        >>> csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY)
        >>> csp.add_constraint(operator.eq, ['a', 'b'])  # a == b
        >>> csp.add_constraint(operator.ne, ['b', 'c'])  # b != c
        >>> for n in range(8, 1, -1):
        ...     try:
        ...         bqm = dwavebinarycsp.stitch(csp, min_classical_gap=4.0, max_graph_size=n)
        ...     except dwavebinarycsp.exceptions.ImpossibleBQM:
        ...         print(n+1)
        ...
        3

    """

    # ensure we have penaltymodel factory available
    try:
        dwavebinarycsp.assert_penaltymodel_factory_available()
    except AssertionError as e:
        raise RuntimeError(e)

    def aux_factory():
        for i in count():
            yield 'aux{}'.format(i)

    aux = aux_factory()

    bqm = dimod.BinaryQuadraticModel.empty(csp.vartype)

    # developer note: we could cache them and relabel, for now though let's do the simple thing
    # penalty_models = {}
    for const in csp.constraints:
        configurations = const.configurations

        if len(const.variables) > max_graph_size:
            msg = (
                "The given csp contains a constraint {const} with {num_var} variables. "
                "This cannot be mapped to a graph with {max_graph_size} nodes. "
                "Consider checking whether your constraint is irreducible."
                "").format(const=const,
                           num_var=len(const.variables),
                           max_graph_size=max_graph_size)
            raise ImpossibleBQM(msg)

        pmodel = None

        if len(const) == 0:
            # empty constraint
            continue

        # at the moment, penaltymodel-cache cannot handle 1-variable PMs, so
        # we handle that case here
        if min_classical_gap <= 2.0 and len(
                const) == 1 and max_graph_size >= 1:
            bqm.update(_bqm_from_1sat(const))
            continue

        # developer note: we could cache them and relabel, for now though let's do the simple thing
        # if configurations in penalty_models:
        #     raise NotImplementedError

        for G in iter_complete_graphs(const.variables, max_graph_size + 1,
                                      aux):

            # construct a specification
            spec = pm.Specification(graph=G,
                                    decision_variables=const.variables,
                                    feasible_configurations=configurations,
                                    min_classical_gap=min_classical_gap,
                                    vartype=csp.vartype)

            # try to use the penaltymodel ecosystem
            try:
                pmodel = pm.get_penalty_model(spec)
            except pm.ImpossiblePenaltyModel:
                # hopefully adding more variables will make it possible
                continue

            if pmodel.classical_gap >= min_classical_gap:
                break

        # developer note: we could cache them and relabel, for now though let's do the simple thing
        # penalty_models[configurations] = pmodel

        else:
            msg = ("No penalty model can be built for constraint {}".format(
                const))
            raise ImpossibleBQM(msg)

        bqm.update(pmodel.model)

    return bqm