예제 #1
0
def test_boolean_to_spin():

    assert boolean_to_spin(0) == 1
    assert boolean_to_spin(1) == -1
    assert boolean_to_spin((0, 1)) == (1, -1)
    assert boolean_to_spin([0, 1]) == [1, -1]
    assert boolean_to_spin({"a": 0, "b": 1}) == {"a": 1, "b": -1}
예제 #2
0
def test_qubosimulation_vs_qusosimulation():

    ising = sum(-spin_var(i) * spin_var(i + 1) for i in range(15))
    qubo = quso_to_qubo(ising)

    schedule = [(T, 20) for T in range(3, 0, -1)]

    spin = QUSOSimulation(ising)
    boolean = QUBOSimulation(qubo)

    assert spin.initial_state == boolean_to_spin(boolean.initial_state)

    spin.schedule_update(schedule, seed=4)
    boolean.schedule_update(schedule, seed=4)
    assert spin.state == boolean_to_spin(boolean.state)

    initial_state = [0] * 8 + [1] * 8
    spin = QUSOSimulation(ising, boolean_to_spin(initial_state))
    boolean = QUBOSimulation(qubo, initial_state)

    assert spin.initial_state == boolean_to_spin(boolean.initial_state)

    spin.schedule_update(schedule, seed=4)
    boolean.schedule_update(schedule, seed=4)
    assert spin.state == boolean_to_spin(boolean.state)
예제 #3
0
def test_qubo_quso_equal():

    random.seed(815)
    qubo = {(i, j): random.random() for i in range(7) for j in range(7)}
    qubo.update({(i, ): random.random() for i in range(7)})
    qubo[()] = random.random()
    for sol in itertools.product((0, 1), repeat=7):
        assert_allclose(qubo_value(sol, qubo),
                        quso_value(boolean_to_spin(sol), qubo_to_quso(qubo)))
예제 #4
0
def test_pubo_puso_equal():

    random.seed(518)
    pubo = {(i, j, k): random.random()
            for i in range(7) for j in range(7) for k in range(7)}
    pubo.update({(i, j): random.random() for i in range(7) for j in range(7)})
    pubo.update({(i, ): random.random() for i in range(7)})
    pubo[()] = random.random()
    for sol in itertools.product((0, 1), repeat=7):
        assert_allclose(pubo_value(sol, pubo),
                        puso_value(boolean_to_spin(sol), pubo_to_puso(pubo)))
예제 #5
0
    def to_spin(self):
        """to_spin.

        Convert the result to a spin result.

        Returns
        -------
        res : AnnealResult object.
            A spin version of ``self``. If ``self.spin == True``, then
            ``res`` will be the same as ``self``.

        """
        if self.spin:
            return self.copy()
        return AnnealResult(boolean_to_spin(self.state), self.value, True)
예제 #6
0
def test_pcso_le_constraint():

    lam = Symbol("lam")

    H = PCSO(
        pubo_to_puso({
            ('a', ): -1,
            ('b', ): 2,
            ('a', 'b'): -3,
            ('b', 'c'): -4,
            (): -2,
            ('d', ): -1
        }))
    H.add_constraint_le_zero(pubo_to_puso({
        ('a', ): 1,
        ('b', ): 1,
        ('b', 'c'): 1,
        ('d', ): 1,
        (): -3
    }),
                             lam=lam,
                             log_trick=False)
    solution = boolean_to_spin({'c': 1, 'b': 1, 'a': 1, 'd': 0})
    obj = -8

    problem = H.subs(lam, .5)
    sol = problem.remove_ancilla_from_solution(problem.solve_bruteforce())
    assert all((problem.is_solution_valid(sol), sol == solution))

    e, sol = solve_pubo_bruteforce(problem.to_pubo())
    sol = problem.convert_solution(sol, spin=False)
    sol = problem.remove_ancilla_from_solution(sol)
    assert all((not problem.is_solution_valid(sol), sol != solution,
                not allclose(e, obj)))

    problem = H.subs(lam, 10)
    sol = problem.solve_bruteforce()
    sol = problem.remove_ancilla_from_solution(sol)
    assert all((problem.is_solution_valid(sol), sol == solution))

    e, sol = solve_pubo_bruteforce(problem.to_pubo())
    sol = problem.convert_solution(sol)
    sol = problem.remove_ancilla_from_solution(sol)
    assert all(
        (problem.is_solution_valid(sol), sol == solution, allclose(e, obj)))
예제 #7
0
    def set_state(self, state):
        """set_state.

        Set the state of the spin system to ``state``.

        Parameters
        ----------
        state : dict or iterable.
            ``state`` maps the spin variable labels to their corresponding
            values. In other words ``state[v]`` is the value of variable ``v``.
            A value must be either 0 or 1.

        """
        # if we call super then we get the wrong errors
        state = {v: state[v] for v in self._variables}
        if any(v not in {0, 1} for v in state.values()):
            raise ValueError("State must contain only 0's and 1's")
        self._state = boolean_to_spin(state)
예제 #8
0
    def convert_solution(self, solution, spin=False):
        """convert_solution.

        Convert the solution to the QUBO or QUSO to the solution to the
        Alternating Sectors Chain problem.

        Parameters
        ----------
        solution : iterable or dict.
            The QUBO or QUSO solution output. The QUBO solution output
            is either a list or tuple where indices specify the label of the
            variable and the element specifies whether it's 0 or 1 for QUBO
            (or 1 or -1 for QUSO), or it can be a dictionary that maps the
            label of the variable to is value.
        spin : bool (optional, defaults to False).
            `spin` indicates whether ``solution`` is the solution to the
            boolean {0, 1} formulation of the problem or the spin {1, -1}
            formulation of the problem. This parameter usually does not matter,
            and it will be ignored if possible. The only time it is used is if
            ``solution`` contains all 1's. In this case, it is unclear whether
            ``solution`` came from a spin or boolean formulation of the
            problem, and we will figure it out based on the ``spin`` parameter.

        Return
        ------
        res : tuple.
            Value of each spin, -1 or 1.

        Examples
        --------
        >>> problem = AlternatingSectorsChain(5)
        >>> problem.convert_solution([0, 0, 1, 0, 1])
        (1, 1, -1, 1, -1)
        >>> problem.convert_solution([-1, -1, 1, -1, 1])
        (-1, -1, 1, -1, 1)

        """
        if isinstance(solution, dict):
            solution = tuple(v for _, v in sorted(solution.items()))
        sol_type = solution_type(solution, 'spin' if spin else 'bool')
        if sol_type == 'bool':
            return boolean_to_spin(solution)
        return solution
예제 #9
0
def test_pcso_eq_constraint():

    lam = Symbol('lam')

    H = PCSO(
        pubo_to_puso({
            ('a', ): -1,
            ('b', ): 2,
            ('a', 'b'): -3,
            ('b', 'c'): -4,
            (): -2
        }))
    H.add_constraint_eq_zero(pubo_to_puso({
        ('a', ): 1,
        ('b', ): 1,
        ('b', 'c'): -1
    }),
                             lam=lam)
    solution = boolean_to_spin({'c': 1, 'b': 1, 'a': 0})
    obj = -4

    problem = H.subs(lam, 1)
    sol = problem.solve_bruteforce()
    assert all((problem.is_solution_valid(sol), sol == solution))

    e, sol = solve_pubo_bruteforce(problem.to_pubo())
    sol = problem.convert_solution(sol, False)
    assert all((not problem.is_solution_valid(sol), sol != solution,
                not allclose(e, obj)))

    problem = H.subs(lam, 10)
    sol = problem.solve_bruteforce()
    assert all((problem.is_solution_valid(sol), sol == solution))

    e, sol = solve_pubo_bruteforce(problem.to_pubo())
    sol = problem.convert_solution(sol)
    assert all(
        (problem.is_solution_valid(sol), sol == solution, allclose(e, obj)))
예제 #10
0
def anneal_qubo(Q, num_anneals=1, anneal_duration=1000, initial_state=None,
                temperature_range=None, schedule='geometric',
                in_order=True, seed=None):
    """anneal_qubo.

    Run a simulated annealing algorithm to try to find the minimum of the QUBO
    given by ``Q``. ``anneal_qubo`` uses a cooling schedule with the
    ``qubovert.sim.PUBOSimulation`` object. Please see all of the parameters
    for details.

    Parameters
    ----------
    Q : dict, ``qubovert.utils.QUBOMatrix`` or ``qubovert.QUBO``.
        Maps boolean labels to their values in the objective function.
        Please see the docstring of ``qubovert.QUBO`` for more info on how to
        format ``Q``.
    num_anneals : int >= 1 (optional, defaults to 1).
        The number of times to run the simulated annealing algorithm.
    anneal_duration : int >= 1 (optional, defaults to 1000).
        The total number of updates to the simulation during the anneal.
        This is related to the amount of time we spend in the cooling schedule.
        If an explicit schedule is provided, then ``anneal_duration`` will be
        ignored.
    initial_state : dict (optional, defaults to None).
        The initial state to start the anneal in. ``initial_state`` must map
        the boolean label names to their values in {0, 1}. If ``initial_state``
        is None, then a random state will be chosen to start each anneal.
        Otherwise, ``initial_state`` will be the starting state for all of the
        anneals.
    temperature_range : tuple (optional, defaults to None).
        The temperature to start and end the anneal at.
        ``temperature = (T0, Tf)``. ``T0`` must be >= ``Tf``. To see more
        details on picking a temperature range, please see the function
        ``qubovert.sim.anneal_temperature_range``. If ``temperature_range`` is
        None, then it will by default be set to
        ``T0, Tf = qubovert.sim.anneal_temperature_range(Q, spin=False)``.
    schedule : str or iterable of tuple (optional, defaults to ``'geometric'``)
        What type of cooling schedule to use. If ``schedule == 'linear'``, then
        the cooling schedule will be a linear interpolation between the values
        in ``temperature_range``. If ``schedule == 'geometric'``, then the
        cooling schedule will be a geometric interpolation between the values
        in ``temperature_range``. Otherwise, you can supply an explicit
        schedule. In this case, ``schedule`` should be an iterable of tuples,
        where each tuple is a ``(T, n)`` pair, where ``T`` denotes the
        temperature to update the simulation, and ``n`` denote the number of
        times to update the simulation at that temperature. This schedule
        will be sent directly into the
        ``qubovert.sim.PUBOSimulation.schedule_update`` method.
    in_order : bool (optional, defaults to True).
        Whether to iterate through the variables in order or randomly
        during an update step. When ``in_order`` is False, the simulation
        is more physically realistic, but when using the simulation for
        annealing, often it is better to have ``in_order = True``.
    seed : number (optional, defaults to None).
        The number to seed Python's builtin ``random`` module with. If
        ``seed is None``, then ``random.seed`` will not be called.

    Returns
    -------
    res : qubovert.sim.AnnealResults object.
        ``res`` contains information on the final states of the simulations.
        See Examples below for an example of how to read from ``res``.
        See ``help(qubovert.sim.AnnealResults)`` for more info.

    Raises
    ------
    ValueError
        If the ``schedule`` argument provided is formatted incorrectly. See the
        Parameters section.
    ValueError
        If the initial temperature is less than the final temperature.

    Warns
    -----
    qubovert.utils.QUBOVertWarning
        If both the ``temperature_range`` and explicit ``schedule`` arguments
        are provided.

    Example
    -------
    Consider the example of finding the ground state of the 1D
    antiferromagnetic Ising chain of length 5 in boolean form.

    >>> import qubovert as qv
    >>>
    >>> H = sum(qv.spin_var(i) * qv.spin_var(i+1) for i in range(4))
    >>> Q = H.to_qubo()
    >>> anneal_res = qv.sim.anneal_qubo(Q, num_anneals=3)
    >>>
    >>> print(anneal_res.best.value)
    -4
    >>> print(anneal_res.best.state)
    {0: 0, 1: 1, 2: 0, 3: 1, 4: 0}
    >>> # now sort the results
    >>> anneal_res.sort_by_value()
    >>>
    >>> # now iterate through all of the results in the sorted order
    >>> for res in anneal_res:
    >>>     print(res.value, res.state)
    -4, {0: 0, 1: 1, 2: 0, 3: 1, 4: 0}
    -4, {0: 1, 1: 0, 2: 1, 3: 0, 4: 1}
    -4, {0: 0, 1: 1, 2: 0, 3: 1, 4: 0}

    """
    return anneal_quso(
        qubo_to_quso(Q), num_anneals, anneal_duration,
        None if initial_state is None else boolean_to_spin(initial_state),
        temperature_range, schedule, in_order, seed
    ).to_boolean()