Ejemplo n.º 1
0
def test_puso_to_pubo_to_puso():

    puso = {
        (0, 1): -4,
        (0, 2): 3,
        (): -2,
        (0, ): 1,
        (2, ): -2,
        (0, 1, 2): 3,
        (0, 2, 3): -1
    }
    assert puso == pubo_to_puso(puso_to_pubo(puso))

    # type asserting
    assert type(puso_to_pubo(puso)) == PUBO
    assert type(puso_to_pubo(PUSOMatrix(puso))) == PUBOMatrix
    assert type(puso_to_pubo(PUSO(puso))) == PUBO

    puso = {
        ('0', 1): -4,
        ('0', '2'): 3,
        (): -2,
        ('0', ): 1,
        ('2', ): -2,
        ('0', 1, '2'): 3,
        ('0', '2', 3): -1,
        ('2', 0, 0, '1', 0): -2,
        (0, 1, 1, 0, 3, 0, 1, 1, 3, 2, 3): -8
    }
    # need to reformat qubo so it is sorted with the same hash
    assert PUSO(puso) == pubo_to_puso(puso_to_pubo(puso))

    # type asserting
    assert type(puso_to_pubo(puso)) == PUBO
    assert type(puso_to_pubo(PUSO(puso))) == PUBO
Ejemplo n.º 2
0
def test_puso_addition():

    temp = PUSO({('0', '0'): 1, ('0', 1): 2})
    temp1 = {('0', ): -1, (1, '0'): 3}
    temp2 = {
        (1, '0'): 5,
        (): 1,
        ('0', ): -1
    }, {
        ('0', 1): 5,
        (): 1,
        ('0', ): -1
    }
    temp3 = {
        (): 1,
        (1, '0'): -1,
        ('0', ): 1
    }, {
        (): 1,
        ('0', 1): -1,
        ('0', ): 1
    }

    # constant
    d = temp.copy()
    d += 5
    assert d in ({(1, '0'): 2, (): 6}, {('0', 1): 2, (): 6})

    # __add__
    d = temp.copy()
    g = d + temp1
    assert g in temp2

    # __iadd__
    d = temp.copy()
    d += temp1
    assert d in temp2

    # __radd__
    d = temp.copy()
    g = temp1 + d
    assert g in temp2

    # __sub__
    d = temp.copy()
    g = d - temp1
    assert g in temp3

    # __isub__
    d = temp.copy()
    d -= temp1
    assert d in temp3

    # __rsub__
    d = temp.copy()
    g = temp1 - d
    assert g == PUSO(temp3[0]) * -1
Ejemplo n.º 3
0
def test_set_mapping():

    d = PUSO({('a', 'b'): 1, ('a', ): 2})
    d.set_mapping({'a': 0, 'b': 2})
    assert d.to_puso() == {(0, 2): 1, (0, ): 2}

    d = PUSO({('a', 'b'): 1, ('a', ): 2})
    d.set_reverse_mapping({0: 'a', 2: 'b'})
    assert d.to_puso() == {(0, 2): 1, (0, ): 2}
Ejemplo n.º 4
0
def test_symbols():

    a, b = Symbol('a'), Symbol('b')
    d = PUSO()
    d[(0, )] -= a
    d[(0, 1)] += 2
    d[(1, )] += b
    assert d == {(0, ): -a, (0, 1): 2, (1, ): b}
    assert d.subs(a, 2) == {(0, ): -2, (0, 1): 2, (1, ): b}
    assert d.subs(b, 1) == {(0, ): -a, (0, 1): 2, (1, ): 1}
    assert d.subs({a: -3, b: 4}) == {(0, ): 3, (0, 1): 2, (1, ): 4}
Ejemplo n.º 5
0
def test_create_var():

    d = PUSO.create_var(0)
    assert d == {(0, ): 1}
    assert d.name == 0
    assert type(d) == PUSO

    d = PUSO.create_var('x')
    assert d == {('x', ): 1}
    assert d.name == 'x'
    assert type(d) == PUSO
Ejemplo n.º 6
0
def test_puso_default_valid():

    d = PUSO()
    assert d[(0, 0)] == 0
    d[(0, 0)] += 1
    assert d == {(): 1}

    d = PUSO()
    assert d[(0, 1)] == 0
    d[(0, 1)] += 1
    assert d == {(0, 1): 1}
Ejemplo n.º 7
0
def test_round():

    d = PUSO({(0, ): 3.456, (1, ): -1.53456})

    assert round(d) == {(0, ): 3, (1, ): -2}
    assert round(d, 1) == {(0, ): 3.5, (1, ): -1.5}
    assert round(d, 2) == {(0, ): 3.46, (1, ): -1.53}
    assert round(d, 3) == {(0, ): 3.456, (1, ): -1.535}
Ejemplo n.º 8
0
def test_normalize():

    temp = {(0, ): 4, (1, ): -2}
    d = PUSO(temp)
    d.normalize()
    assert d == {k: v / 4 for k, v in temp.items()}

    temp = {(0, ): -4, (1, ): 2}
    d = PUSO(temp)
    d.normalize()
    assert d == {k: v / 4 for k, v in temp.items()}
Ejemplo n.º 9
0
def test_puso_update():

    d = PUSO({('0', ): 1, ('0', 1): 2})
    d.update({('0', '0'): 0, (1, '0'): 1, (1, 1): -1})
    assert d in ({
        ('0', ): 1,
        (): -1,
        (1, '0'): 1
    }, {
        ('0', ): 1,
        (): -1,
        ('0', 1): 1
    })

    d = PUSO({(0, 0): 1, (0, 1): 2})
    d.update(PUSO({(1, 0): 1, (1, 1): -1}))
    d -= 1
    assert d == PUSO({(0, 1): 1, (): -2})

    assert d.offset == -2
Ejemplo n.º 10
0
def test_convert_solution_all_1s():

    d = PUSO({(0, ): 1})
    assert d.convert_solution({0: 0}) == {0: 1}
    assert d.convert_solution({0: -1}) == {0: -1}
    assert d.convert_solution({0: 1}) == {0: 1}
    assert d.convert_solution({0: 1}, False) == {0: -1}
Ejemplo n.º 11
0
def test_puso_on_quso():

    problem = PUSO({
        ('a', ): -1,
        ('b', ): 2,
        ('a', 'b'): -3,
        ('b', 'c'): -4,
        (): -2
    })
    solution = {'c': -1, 'b': -1, 'a': -1}
    obj = -10

    Problem(problem, solution, obj).runtests()
Ejemplo n.º 12
0
def test_puso_degree():

    d = PUSO()
    assert d.degree == 0
    d[(0, )] += 2
    assert d.degree == 1
    d[(1, )] -= 3
    assert d.degree == 1
    d[(1, 2)] -= 2
    assert d.degree == 2
    d[(1, 2, 4)] -= 2
    assert d.degree == 3
    d[(1, 2, 4, 5, 6)] += 2
    assert d.degree == 5
Ejemplo n.º 13
0
def test_puso_on_deg_3_puso():

    problem = PUSO({
        ('a', ): -1,
        ('b', ): 2,
        ('a', 'b'): -3,
        ('b', 'c'): -4,
        (): -2,
        (0, 1, 2): 1,
        (0, ): 1,
        (1, ): 1,
        (2, ): 1
    })
    solution = {'c': -1, 'b': -1, 'a': -1, 0: -1, 1: -1, 2: -1}
    obj = -14

    Problem(problem, solution, obj).runtests()
Ejemplo n.º 14
0
def test_pretty_str():
    def equal(expression, string):
        assert expression.pretty_str() == string

    z = [PUSO() + {(i, ): 1} for i in range(3)]
    a, b = Symbol('a'), Symbol('b')

    equal(z[0], "z(0)")
    equal(-z[0], "-z(0)")
    equal(z[0] * 0, "0")
    equal(2 * z[0] * z[1] - 3 * z[2], "2 z(0) z(1) - 3 z(2)")
    equal(0 * z[0] + 1, "1")
    equal(0 * z[0] - 1, "-1")
    equal(0 * z[0] + a, "(a)")
    equal(0 * z[0] + a * b, "(a*b)")
    equal((a + b) * (z[0] * z[1] - z[2]), "(a + b) z(0) z(1) + (-a - b) z(2)")
    equal(2 * z[0] * z[1] - z[2], "2 z(0) z(1) - z(2)")
    equal(-z[2] + z[0] * z[1], "-z(2) + z(0) z(1)")
    equal(-2 * z[2] + 2 * z[0] * z[1], "-2 z(2) + 2 z(0) z(1)")
Ejemplo n.º 15
0
def test_puso_on_deg_5_puso():

    problem = PUSO({
        ('a', ): -1,
        ('b', ): 2,
        ('a', 'b'): -3,
        ('b', 'c'): -4,
        (): -2,
        (0, 1, 2): 1,
        (0, ): -1,
        (1, ): -2,
        (2, ): 1,
        ('a', 0, 4, 'b', 'c'): -3,
        (4, 2, 3, 'a', 'b'): 2,
        (4, 2, 3, 'b'): -1,
        ('c', ): 4,
        (3, ): 1
    })
    solution = {0: 1, 1: 1, 'c': -1, 2: -1, 4: -1, 3: -1, 'b': -1, 'a': -1}
    obj = -26

    Problem(problem, solution, obj).runtests()
Ejemplo n.º 16
0
def anneal_puso(H, num_anneals=1, anneal_duration=1000, initial_state=None,
                temperature_range=None, schedule='geometric',
                in_order=True, seed=None):
    """anneal_puso.

    Run a simulated annealing algorithm to try to find the minimum of the PUSO
    given by ``H``. Please see all of the parameters for details.

    **Please note** that the ``qv.sim.anneal_quso`` function performs
    faster than the ``qv.sim.anneal_puso`` function. If your system has
    degree 2 or less, then you should use the ``qv.sim.anneal_quso``
    function.

    Parameters
    ----------
    H : dict, or any type in ``qubovert.SPIN_MODELS``.
        Maps spin labels to their values in the Hamiltonian.
        Please see the docstrings of any of the objects in
        ``qubovert.SPIN_MODELS`` to see how ``H`` should be formatted.
    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 spin label names to their values in {1, -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(H, spin=True)``.
        Note that a temperature can only be zero if ``schedule`` is explicitly
        given or if ``schedule`` is linear.
    schedule : str, or list of floats (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, ``schedule`` must be an
        iterable of floats being the explicit temperature schedule for the
        anneal to follow.
    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.
    qubovert.utils.QUBOVertWarning
        If the degree of the model is 2 or less then a warning is issued that
        says you should use the ``anneal_qubo`` or ``anneal_quso`` functions.

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

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

    """
    if num_anneals <= 0:
        return AnnealResults()

    Ts = _create_spin_schedule(
        H, anneal_duration, temperature_range, schedule
    )

    # must use type since we don't want errors from inheritance
    if type(H) in (QUSOMatrix, PUSOMatrix):
        N = H.max_index + 1
        model = H
        reverse_mapping = dict(enumerate(range(N)))
    elif type(H) not in (QUSO, PUSO, PCSO):
        H = PUSO(H)

    if type(H) in (QUSO, PUSO, PCSO):
        N = H.num_binary_variables
        model = H.to_puso()
        reverse_mapping = H.reverse_mapping

    if model.degree <= 2:
        QUBOVertWarning.warn(
            "The input problem has degree <= 2; consider using the "
            "``qubovert.sim.anneal_qubo`` or ``qubovert.sim.anneal_quso`` "
            "functions, which are significantly faster than this function "
            "because they take advantage of the low degree."
        )

    # solve `model`, convert solutions back to `H`

    if not N:
        return AnnealResults(
            AnnealResult({}, model.offset, True) for _ in range(num_anneals)
        )

    if initial_state is not None:
        init_state = [1] * N
        for k, v in reverse_mapping.items():
            init_state[k] = initial_state[v]
    else:
        init_state = []

    # create arguments for the C function
    # create terms and couplings
    terms, couplings, num_couplings = [], [], []
    for term, coupling in model.items():
        if term:
            couplings.append(float(coupling))
            terms.extend(term)
            num_couplings.append(len(term))

    states, values = c_anneal_puso(
        N, num_couplings, terms, couplings,  # describe the problem
        Ts, num_anneals, int(in_order), init_state,  # describe the algorithm
        seed if seed is not None else -1
    )
    return _package_spin_results(
        states, values, model.offset, reverse_mapping
    )
Ejemplo n.º 17
0
def test_to_enumerated():

    d = PUSO({('a', 'b'): 1, ('a', ): 2})
    dt = d.to_enumerated()
    assert type(dt) == PUSOMatrix
    assert dt == d.to_puso()
Ejemplo n.º 18
0
def test_puso_degree_reduction_lam():

    puso = PUSO({
        ('x0', 'x1'): -1,
        ('x1', ): 1,
        ('x1', 'x2'): -1,
        ('x2', ): 1,
        ('x3', 'x2'): -1,
        ('x3', ): 1,
        ('x4', 'x3'): -1,
        ('x4', ): 1,
    })**2

    # just make sure it runs
    puso.to_qubo(lam=4)
    puso.to_qubo(lam=lambda v: v)
    puso.to_qubo(lam=Symbol('lam'))
    puso.to_qubo(lam=lambda v: v * Symbol('lam'))
    puso.to_quso(lam=4)
    puso.to_quso(lam=lambda v: v)
    puso.to_quso(lam=Symbol('lam'))
    puso.to_quso(lam=lambda v: v * Symbol('lam'))
Ejemplo n.º 19
0
def test_puso_remove_value_when_zero():

    d = PUSO()
    d[(0, 1)] += 1
    d[(0, 1)] -= 1
    assert d == {}
Ejemplo n.º 20
0
def test_puso_checkkey():

    with assert_raises(KeyError):
        PUSO({0: -1})
Ejemplo n.º 21
0
def test_puso_reinitialize_dictionary():

    d = PUSO({(0, 0): 1, ('1', 0): 2, (2, 0): 0, (0, '1'): 1})
    assert d in ({(): 1, ('1', 0): 3}, {(): 1, (0, '1'): 3})
Ejemplo n.º 22
0
def test_puso_num_binary_variables():

    d = PUSO({(0, ): 1, (0, 3): 2})
    assert d.num_binary_variables == 2
    assert d.max_index == 1
Ejemplo n.º 23
0
def test_num_terms():

    d = PUSO({(0, ): 1, (0, 3): 2, (0, 2): -1})
    assert d.num_terms == len(d)
Ejemplo n.º 24
0
def test_puso_multiplication():

    temp = PUSO({('0', '0'): 1, ('0', 1): 2})
    temp1 = {(): 3, (1, '0'): 6}, {(): 3, ('0', 1): 6}
    temp2 = {(): .5, (1, '0'): 1}, {(): .5, ('0', 1): 1}
    temp3 = {(1, '0'): 1}, {('0', 1): 1}

    # constant
    d = temp.copy()
    d += 3
    d *= -2
    assert d in ({(1, '0'): -4, (): -8}, {('0', 1): -4, (): -8})

    # __mul__
    d = temp.copy()
    g = d * 3
    assert g in temp1

    d = temp.copy()
    g = d * 0
    assert g == {}

    # __imul__
    d = temp.copy()
    d *= 3
    assert d in temp1

    d = temp.copy()
    d *= 0
    assert d == {}

    # __rmul__
    d = temp.copy()
    g = 3 * d
    assert g in temp1

    d = temp.copy()
    g = 0 * d
    assert g == {}

    # __truediv__
    d = temp.copy()
    g = d / 2
    assert g in temp2

    # __itruediv__
    d = temp.copy()
    d /= 2
    assert d in temp2

    # __floordiv__
    d = temp.copy()
    g = d // 2
    assert g in temp3

    # __ifloordiv__
    d = temp.copy()
    d //= 2
    assert d in temp3

    # __mul__ but with dict
    d = temp.copy()
    d *= {(1, ): 2, ('0', '0'): -1}
    assert d in ({
        (1, ): 2,
        (): -1,
        ('0', ): 4,
        ('0', 1): -2
    }, {
        (1, ): 2,
        (): -1,
        ('0', ): 4,
        (1, '0'): -2
    })

    # __pow__
    d = temp.copy()
    d -= 2
    d **= 2
    assert d in ({(): 5, ('0', 1): -4}, {(): 5, (1, '0'): -4})

    d = temp.copy()
    assert d**2 == d * d
    assert d**3 == d * d * d

    d = PUSO({('0', 1): 1, ('1', 2): -1})**2
    assert d**4 == d * d * d * d
Ejemplo n.º 25
0
def test_properties():

    temp = PUSO({('0', '0'): 1, ('0', 1): 2})
    assert temp.offset == 1

    d = PUSO()
    d[(0, )] += 1
    d[(1, )] += 2
    assert d == d.to_quso() == {(0, ): 1, (1, ): 2}
    assert d.mapping == d.reverse_mapping == {0: 0, 1: 1}

    d.set_mapping({1: 0, 0: 1})
    assert d.to_quso() == {(1, ): 1, (0, ): 2}
    assert d.mapping == d.reverse_mapping == {0: 1, 1: 0}

    # an old bug
    d = PUSO()
    d.set_mapping({0: 0})
    d[(0, )] += 1
    assert d.num_binary_variables == 1
    assert d.variables == {0}