Exemplo n.º 1
0
def moebius_sum(n):
    r"""Returns the value of the sum of moebius(k) for k = 1, 2, ..., n.

    Parameters
    ----------
    n : int (n > 0)

    Returns
    -------
    s : int

    Raises
    ------
    ValueError
        If n <= 0.

    Notes
    -----
    The formula used here is based on the relationship \sum_{d = 1}^{n}
    M(n/d) = 1, where M(n) = \sum_{k = 1}^{n} moebius(k).  We convert this
    to a recursive formula, whereby using some form of Dirichlet's
    hyperbola method and memoizing the recursion gives us a sublinear
    runtime.

    Examples
    --------
    >>> moebius_sum(10)
    -1
    >>> sum(lists.moebius_list(10))
    -1
    >>> moebius_sum(0)
    Traceback (most recent call last):
    ...
    ValueError: moebius_sum: Must have n > 0.
    """
    if n <= 0:
        raise ValueError("moebius_sum: Must have n > 0.")

    sqrt = int(n**(0.5))
    mu_list = lists.moebius_list(sqrt)

    # for i <= sqrt(n), compute the sum directly
    cache = {1: 1}
    for i in xrange(2, sqrt + 1):
        cache[i] = cache[i - 1] + mu_list[i]

    def M(n):
        if n in cache:
            return cache[n]
        sqrt_n = int(n**(0.5)) + 1
        value = n - 1
        for d in xrange(2, sqrt_n):
            value += M(n//d) - M(d - 1)
            value += mu_list[d]*(n//d - d)
        cache[n] = 1 - value
        return cache[n]

    return M(n)
Exemplo n.º 2
0
    def test_moebius_list(self):
        self.assertRaisesRegexp(ValueError, "moebius_list: Must have n > 0.", moebius_list, 0)

        values = [
            0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1, 0, -1, 0, 1, 1, -1, 0, 0, 1, 0, 0, -1, -1, -1,
            0, 1, 1, 1, 0, -1, 1, 1, 0, -1, -1, -1, 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 1, 0, 1, 1, -1, 0, -1, 1, 0, 0,
            1, -1, -1, 0, 1, -1, -1, 0, -1, 1, 0, 0, 1, -1, -1, 0, 0, 1, -1, 0, 1, 1, 1, 0, -1, 0, 1, 0, 1, 1, 1, 0, -1,
            0, 0, 0, -1, -1, -1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, -1, 0, 1,
            -1, -1, 0, 1, 1, 0, 0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 0, 0, -1, 0, -1, 0, 0, -1, 1, 0, -1, 1, 1, 0, 1, 0,
            -1, 0, -1, 1, -1, 0, 0, -1, 0, 0, -1, -1, 0, 0, 1, 1, -1, 0, -1, -1, 1, 0, 1, -1, 1, 0, 0, -1, -1, 0, -1, 1,
            -1, 0, -1, 0, -1, 0
        ]

        self.assertEqual(moebius_list(200), values)