def test_sqrts_mod_n(self):
        self.assertEqual(sqrts_mod_n(3, 178137047), [16152263, 28026114, 150110933, 161984784])
        self.assertEqual(sqrts_mod_n(49, 53**3*61**4), [7, 721465236980, 1339862033577, 2061327270550])
        self.assertEqual(sqrts_mod_n(-1, 5**3*7**2), [])

        for n in xrange(2, 200):
            values = defaultdict(list)
            for a in xrange(n):
                values[a*a % n].append(a)

            for a in xrange(n):
                self.assertEqual(values[a], sqrts_mod_n(a, n))
def _pell_general(D, N, one_solution=False):
    """
    test with D = 1121311213, N = 11889485036288588
    """
    # Find fundamental solution to Pell
    for (t, u) in QuadraticIrrational(D).convergents():
        if t*t - D*u*u == 1:
            break

    # Now find fundamental solution to general Pell
    fundamental_solutions = []
    residues = sqrts_mod_n(N, D)
    L = N*(t - 1)
    print residues

    for r in residues:
        for x in itertools.count(r, D):
            w = (x*x - N)//D

            if w < 0:
                continue
            elif 2*D*w > L:
                break

            y = integer_sqrt(w)

            if y*y == w:
                if one_solution:
                    yield (x, y)
                    return

                fundamental_solutions.append((x, y))
                (r, s) = (-x, y)

                if (x*r - D*y*s) % N != 0 or (x*s - y*r) % N != 0:
                    fundamental_solutions.append((r, s))

    minimal_positive_solutions = []

    for (x, y) in fundamental_solutions:
        if x < 0:
            (r, s) = (-x, -y)
            p = r*t + s*u*D
            q = r*u + s*t
            minimal_positive_solutions.append((p, q))
        else:
            minimal_positive_solutions.append((x, y))

    minimal_positive_solutions.sort()

    if not minimal_positive_solutions:
        return

    print minimal_positive_solutions

    while True:
        for i in xrange(len(minimal_positive_solutions)):
            x, y = minimal_positive_solutions[i]
            yield (x, y)
            minimal_positive_solutions[i] = (x*t + y*u*D, x*u + y*t)
def _mollin(D, N):
    positive_roots = sqrts_mod_n(D, abs(N))

    roots = []
    print positive_roots
    for r in positive_roots:
        for e in [-r, r]:
            if -abs(N) < 2*e <= abs(N):
                roots.append(e)

    return roots
Beispiel #4
0
def pell_minimal_positive_solutions(D, N):
    r"""Returns the minimal positive solutions to the Pell equation
    x**2 - D*y**2 == N.

    Given D > 0 not a square, and N != 0, this method returns a list of the
    minimal positive solutions in each class for the Pell equation
    described above.

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

    N : int (N != 0)

    Returns
    -------
    L : list
        List of the minimal positive solutions of the equation. The list is
        empty if there are no solutions.

    Notes
    -----

    References
    ----------
    .. [1] T. Andreescu, D. Andrica, "Quadratic Diophantine Equations",
    Springer-Verlag, New York, 2015.

    .. [2] R.A. Mollin, "Fundamental Number Theory with Applications",
    Chapman & Hall/CRC, 2008.

    Examples
    --------
    >>> pell_minimal_positive_solutions(13, 27)
    [(12, 3), (40, 11), (220, 61), (768, 213)]
    >>> pell_minimal_positive_solutions(
    """
    (u, v) = pell_fundamental_solution(D, 1)

    # If N == 1, there is only one class of solutions.
    if N == 1:
        return [(u, v)]

    if N > 0:
        # See Theorem 7.1 in [2]
        B = int(((u + 1) * N / 2.0)**(0.5)) + 1
    else:
        # See Theorem 7.2 in [2]
        B = int(((u - 1) * (-N) / 2.0)**(0.5)) + 1

    # We can proceed in two different ways at this point:
    # 1) We can check all values of y in the range described in Theorems
    # 7.1 and 7.2, finding the corresponding valid values of x for each.
    #
    # 2) By solving a quadratic congruence, we get congruences that x must
    # satisfy. By iterating through these progressions, we are able to
    # check the entire range faster than in 1.
    #
    # We use the second method here.

    residues = sqrts_mod_n(N, D)
    fundamental_solutions = []

    # Find the fundamental solutions for each class.
    for r in residues:
        for x in xrange(r, B, D):
            y = is_square((x * x - N) // D)
            if y > 0 and y is not False:
                if (-x * x - D * y * y) % N == 0 and 2 * x * y % N == 0:
                    fundamental_solutions.append((x, y))
                else:
                    fundamental_solutions.append((x, y))
                    fundamental_solutions.append((-x, y))

    # Find the minimal positive solutions for each class.
    minimal_positive_solutions = []
    for (x, y) in fundamental_solutions:
        if x < 0:
            if N > 0:
                (p, q) = (-x, -y)
            else:
                (p, q) = (x, y)
            p, q = p * u + q * v * D, p * v + q * u
        else:
            (p, q) = (x, y)
        minimal_positive_solutions.append((p, q))

    minimal_positive_solutions.sort()

    return minimal_positive_solutions