Example #1
0
def _pell_small_minimal_positive_solutions(D, N):
    if D <= 0 or is_square(D) or D * D <= N:
        raise ValueError(
            "pell_small: Must have D > 0 not a perfect square and N < sqrt(D)")

    contfrac = QuadraticIrrational(D)
    terms = []

    # Otherwise, solutions always exist for D not a perfect square.
    for (x, y) in contfrac.convergents():
        if x * x - D * y * y == 1:
            break
        terms.append((x, y))

    sols = []
    for (x, y) in terms:
        k = x * x - D * y * y

        if N % k != 0:
            continue

        f = is_square(N // k)
        if f is not False:
            sols.append((f * x, f * y))

    sols.sort()
    return sols
Example #2
0
 def test_pure_sqrt1(self):
     # Example 5.10 from "Fundamental Number Theory with Applications" by Mollin.
     cf = QuadraticIrrational(425)
     self.assertEqual(str(cf), 'Continued Fraction Expansion of sqrt(425)')
     self.assertEqual((cf.d, cf.p, cf.q), (425, 0, 1))
     self.assertEqual(cf.pre_period, [20])
     self.assertEqual(cf.fundamental_period, [1, 1, 1, 1, 1, 1, 40])
     self.assertEqual(list(itertools.islice(cf.convergents(), 6)),
                      [(20, 1), (21, 1), (41, 2), (62, 3), (103, 5), (165, 8)])
 def test_pure_sqrt1(self):
     # Example 5.10 from "Fundamental Number Theory with Applications" by Mollin.
     cf = QuadraticIrrational(425)
     self.assertEqual(str(cf), "Continued Fraction Expansion of sqrt(425)")
     self.assertEqual((cf.d, cf.p, cf.q), (425, 0, 1))
     self.assertEqual(cf.pre_period, [20])
     self.assertEqual(cf.fundamental_period, [1, 1, 1, 1, 1, 1, 40])
     self.assertEqual(
         list(itertools.islice(cf.convergents(), 6)), [(20, 1), (21, 1), (41, 2), (62, 3), (103, 5), (165, 8)]
     )
Example #4
0
 def test_quadratic_irrational1(self):
     # Example 5.8 from "Fundamental Number Theory with Applications" by Mollin.
     cf = QuadraticIrrational(22, 4, 6)
     self.assertEqual(str(cf), 'Continued Fraction Expansion of (4 + sqrt(22))/6')
     self.assertEqual((cf.d, cf.p, cf.q), (22, 4, 6))
     self.assertEqual(cf.fundamental_period, [1, 2, 4, 2, 1, 8])
     self.assertEqual(cf.pre_period, [])
     self.assertEqual(cf.period_length, 6)
     self.assertEqual(list(itertools.islice(cf.convergents(), 6)),
                      [(1, 1), (3, 2), (13, 9), (29, 20), (42, 29), (365, 252)])
 def test_quadratic_irrational1(self):
     # Example 5.8 from "Fundamental Number Theory with Applications" by Mollin.
     cf = QuadraticIrrational(22, 4, 6)
     self.assertEqual(str(cf), "Continued Fraction Expansion of (4 + sqrt(22))/6")
     self.assertEqual((cf.d, cf.p, cf.q), (22, 4, 6))
     self.assertEqual(cf.fundamental_period, [1, 2, 4, 2, 1, 8])
     self.assertEqual(cf.pre_period, [])
     self.assertEqual(cf.period_length, 6)
     self.assertEqual(
         list(itertools.islice(cf.convergents(), 6)), [(1, 1), (3, 2), (13, 9), (29, 20), (42, 29), (365, 252)]
     )
Example #6
0
 def test_quadratic_irrational5(self):
     # This example is one where (D - P*P) is not divisible by Q, and so they
     # must be modified.
     cf = QuadraticIrrational(10, 1, 2)
     self.assertEqual(str(cf), 'Continued Fraction Expansion of (1 + sqrt(10))/2')
     self.assertEqual((cf.d, cf.p, cf.q), (10, 1, 2))
     self.assertEqual(cf.pre_period, [2])
     self.assertEqual(cf.fundamental_period, [12, 3])
     self.assertEqual(cf.period_length, 2)
     self.assertEqual(list(itertools.islice(cf.convergents(), 6)),
                      [(2, 1), (25, 12), (77, 37), (949, 456), (2924, 1405), (36037, 17316)])
Example #7
0
def pell_small(D, N):
    if D <= 0 or is_square(D) or D * D <= N:
        raise ValueError(
            "pell_small: Must have D > 0 not a perfect square and N < sqrt(D)")

    contfrac = QuadraticIrrational(D)

    # Otherwise, solutions always exist for D not a perfect square.
    for (x, y) in contfrac.convergents():
        print(x, y)
        if x * x - D * y * y == N:
            yield (x, y)
 def test_quadratic_irrational5(self):
     # This example is one where (D - P*P) is not divisible by Q, and so they
     # must be modified.
     cf = QuadraticIrrational(10, 1, 2)
     self.assertEqual(str(cf), "Continued Fraction Expansion of (1 + sqrt(10))/2")
     self.assertEqual((cf.d, cf.p, cf.q), (10, 1, 2))
     self.assertEqual(cf.pre_period, [2])
     self.assertEqual(cf.fundamental_period, [12, 3])
     self.assertEqual(cf.period_length, 2)
     self.assertEqual(
         list(itertools.islice(cf.convergents(), 6)),
         [(2, 1), (25, 12), (77, 37), (949, 456), (2924, 1405), (36037, 17316)],
     )
 def test_quadratic_irrational3(self):
     """Test string representation."""
     cf = QuadraticIrrational(10, 1)
     self.assertEqual(str(cf), "Continued Fraction Expansion of 1 + sqrt(10)")
     pq = cf.partial_quotients()
     self.assertEqual([pq.next() for _ in xrange(10)], [4, 6, 6, 6, 6, 6, 6, 6, 6, 6])
Example #10
0
 def test_quadratic_irrational4(self):
     """Test string representation."""
     cf = QuadraticIrrational(7, 0, 2)
     self.assertEqual(str(cf), 'Continued Fraction Expansion of sqrt(7)/2')
Example #11
0
 def test_quadratic_irrational3(self):
     """Test string representation."""
     cf = QuadraticIrrational(10, 1)
     self.assertEqual(str(cf), 'Continued Fraction Expansion of 1 + sqrt(10)')
     pq = cf.partial_quotients()
     self.assertEqual([pq.next() for _ in xrange(10)], [4, 6, 6, 6, 6, 6, 6, 6, 6, 6])
def pell_fundamental_solution(D, n=1):
    """Returns the fundamental solution to the Pell equation x**2 - D*y**2 == n,
    where n in (-1, 1).

    Given D > 0 not a square, and n in (-1, 1), this method returns the
    fundamental solution to the Pell equation described above. The fundamental
    solution (x, y) is the one with least positive value of x, and
    correspondingly the least positive value of y.

    Input:
        * D: int (D > 0)

        * n: int (n in (-1, 1)).

    Returns:
        * (x, y): tuple

    Raises:
        * ValueError: If D <= 0, D is perfect square, n not in (-1, 1), or if no
        solutions exist.

    Examples:
        >>> pell_fundamental_solution(61)
        (1766319049, 226153980)
        >>> 1766319049**2 - 61*226153980**2
        1
        >>> pell_fundamental_solution(17, -1)
        (4, 1)
        >>> 4**2 - 17*1**2
        -1
        >>> pell_fundamental_solution(15, -1)
        Traceback (most recent call last):
        ...
        ValueError: pell_fundamental_solution: Solution nonexistent.
        >>> pell_fundamental_solution(15, -2)
        Traceback (most recent call last):
        ...
        ValueError: pell_fundamental_solution: Must have D > 0 not a perfect square and n in (-1, 1).

    Details:
        For D > 0 not a perfect square, the equation x**2 - D*y**2 == 1 always
        has solutions, while the equation x**2 - D*y**2 == -1 only has solutions
        when the continued fraction expansion of sqrt(D) has odd period length.

        See Corollary 5.7 of "Fundamental Number Theory with Applications" by
        Mollin for details. See also the article "Simple Continued Fraction
        Solutions for Diophantine Equations" by Mollin.
    """
    if D <= 0 or is_square(D) or n not in (1, -1):
        raise ValueError("pell_fundamental_solution: Must have D > 0 not a perfect square and n in (-1, 1).")

    contfrac = QuadraticIrrational(D)

    # No solution for n == -1 if the period length is even.
    if n == -1 and contfrac.period_length % 2 == 0:
        raise ValueError("pell_fundamental_solution: Solution nonexistent.")

    # Otherwise, solutions always exist for D not a perfect square.
    for (x, y) in contfrac.convergents():
        if x*x - D*y*y == n:
            return (x, y)
Example #13
0
def pell_fundamental_solution(D, n=1):
    r"""Returns the fundamental solution to the Pell equation
    x**2 - D*y**2 == n, where n in (-1, 1).

    Given D > 0 not a square, and n in (-1, 1), this method returns the
    fundamental solution to the Pell equation described above. The
    fundamental solution (x, y) is the one with least positive value of x,
    and correspondingly the least positive value of y.

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

    n : int (n == 1 or n == -1)

    Returns
    -------
    (x, y): tuple

    Raises
    ------
    ValueError : If D <= 0, D is perfect square, n not in (-1, 1), or if no
    solution exists.

    Notes
    -----
    If D is a positive integer that is not a perfect square, then the
    equation x**2 - D*y**2 == 1 has a solution in positive integers.

    On the other hand, of the continued fraction expansion of sqrt(D) has
    even period length, then there are no solutions to the equation
    x**2 - D*y**2 == -1. Otherwise, the equation has a solution.

    See Theorem 3.2.1 in [1] for the positive case and Theorem 3.6.1 in [1]
    for the negative case.

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

    Examples
    --------
    >>> pell_fundamental_solution(61)
    (1766319049, 226153980)
    >>> 1766319049**2 - 61*226153980**2
    1
    >>> pell_fundamental_solution(17, -1)
    (4, 1)
    >>> 4**2 - 17*1**2
    -1
    >>> pell_fundamental_solution(15, -1)
    Traceback (most recent call last):
    ...
    ValueError: pell_fundamental_solution: Solution nonexistent.
    >>> pell_fundamental_solution(15, -2)
    Traceback (most recent call last):
    ...
    ValueError: pell_fundamental_solution: Must have D > 0 not a perfect square and n in (-1, 1).
    """
    if D <= 0 or is_square(D) or n not in (1, -1):
        raise ValueError(
            "pell_fundamental_solution: Must have D > 0 not a perfect square and n in (-1, 1)."
        )

    contfrac = QuadraticIrrational(D)

    # No solution for n == -1 if the period length is even.
    if n == -1 and contfrac.period_length % 2 == 0:
        raise ValueError("pell_fundamental_solution: Solution nonexistent.")

    # Otherwise, solutions always exist for D not a perfect square.
    for (x, y) in contfrac.convergents():
        if x * x - D * y * y == n:
            return (x, y)