Пример #1
0
def test_composed_op():
    from random import randrange
    for N in range(100):
        while 1:
            D1 = randrange(10)
            D2 = randrange(10)
            F = fmpz_poly([randrange(-2, 3) for n in range(D1)])
            G = fmpz_poly([randrange(-2, 3) for n in range(D2)])
            if F.degree() >= 1 and G.degree() >= 1:
                break
        H = composed_op(F, G, operator.add)
        for x, r in F.roots():
            for y, r in G.roots():
                v = H(x + y)
                assert v.contains(0)
        H = composed_op(F, G, operator.sub)
        for x, r in F.roots():
            for y, r in G.roots():
                v = H(x - y)
                assert v.contains(0)
        H = composed_op(F, G, operator.mul)
        for x, r in F.roots():
            for y, r in G.roots():
                v = H(x * y)
                assert v.contains(0)
        if G[0] != 0:
            H = composed_op(F, G, operator.truediv)
            for x, r in F.roots():
                for y, r in G.roots():
                    v = H(x / y)
                    assert v.contains(0)
Пример #2
0
    def __init__(self, v=0, _minpoly=None, _enclosure=None):
        """
        An *alg* instance can be created from an existing *alg*
        (this creates a copy), from a Python integer, or from
        a FLINT *fmpz* or *fmpq*:

            >>> alg(3)
            3.00000 (deg 1)
            >>> alg(alg(3))
            3.00000 (deg 1)
            >>> alg(fmpq(2,3))
            0.666667 (deg 1)

        It is also possible to create an *alg* instance *unsafely* from the
        internal representation consisting of a minimal polynomial
        and an enclosure:

            >>> alg(_minpoly=fmpz_poly([-1,-1,1]), _enclosure=arb("1.618 +/- 0.001"))
            1.61803 (deg 2)

        The minimal polynomial must be an *fmpz_poly* that is irreducible and
        normalized (no factors, GCD content removed, positive leading
        coefficient), and the enclosure must isolate a unique root
        of this polynomial. Warning: these properties are *not* checked.
        Providing invalid input will silently produce wrong results
        in subsequent computations.
        """
        if _minpoly is not None:
            assert type(_minpoly) == fmpz_poly
            self._minpoly = _minpoly
            self._enclosure = _enclosure
        elif isinstance(v, (int, fmpz)):
            self._minpoly = fmpz_poly([-v, 1])
            self._enclosure = None
        elif isinstance(v, fmpq):
            self._minpoly = fmpz_poly([-v.p, v.q])
            self._enclosure = None
        elif isinstance(v, alg):
            self._minpoly = v._minpoly
            self._enclosure = v._enclosure
        elif isinstance(v, float):
            import math
            m, e = math.frexp(v)
            m = int(m * 2.0**53)
            e -= 53
            v = alg(m) * alg(2)**e
            self._minpoly = v._minpoly
            self._enclosure = v._enclosure
        elif isinstance(v, complex):
            v = alg(v.real) + alg(v.imag) * alg.i()
            self._minpoly = v._minpoly
            self._enclosure = v._enclosure
        else:
            raise NotImplementedError
        self._hash = None
Пример #3
0
 def root(self, n):
     assert n >= 0
     if n == 0:
         raise ZeroDivisionError
     if n == 1:
         return self
     F = self._minpoly
     d = F.degree()
     check_degree_limit(d * n)
     H = [0] * (d * n + 1)
     H[::n] = list(F)
     H = fmpz_poly(H)
     c, factors = H.factor()
     prec = 64
     orig_prec = ctx.prec
     try:
         while 1:
             ctx.prec = prec
             x = self.enclosure(pretty=True)
             z = acb(x).root(n)
             #if not z.imag == 0:
             #    eps = arb(0, z.rad())
             #    z += acb(eps,eps)
             maybe_root = [
                 fac for fac, mult in factors if fac(z).contains(0)
             ]
             if len(maybe_root) == 1:
                 fac = maybe_root[0]
                 z2 = alg._validate_root_enclosure(fac, z)
                 if z2 is not None:
                     return alg(_minpoly=fac, _enclosure=z2)
             prec *= 2
     finally:
         ctx.prec = orig_prec
Пример #4
0
    def pow(self, n):
        if self.is_rational():
            c0 = self._minpoly[0]
            c1 = self._minpoly[1]
            if abs(n) > 2:
                check_bits_limit(c0.height_bits() * abs(n))
                check_bits_limit(c1.height_bits() * abs(n))
            if n >= 0:
                return alg(fmpq(c0**n) / (-c1)**n)
            else:
                return alg((-c1)**(-n) / fmpq(c0**(-n)))
        if n == 0:
            return alg(1)
        if n == 1:
            return self
        if n < 0:
            return (1 / self).pow(-n)

        # fast detection of perfect powers
        pol, d = self.minpoly().deflation()
        if d % n == 0:
            # todo: is factoring needed here?
            H = list(self.minpoly())
            H = H[::n]
            H = fmpz_poly(H)
            c, factors = H.factor()
            prec = 64
            orig_prec = ctx.prec
            try:
                while 1:
                    ctx.prec = prec
                    x = self.enclosure(pretty=True)
                    z = acb(x)**n
                    maybe_root = [
                        fac for fac, mult in factors if fac(z).contains(0)
                    ]
                    if len(maybe_root) == 1:
                        fac = maybe_root[0]
                        z2 = alg._validate_root_enclosure(fac, z)
                        if z2 is not None:
                            return alg(_minpoly=fac, _enclosure=z2)
                    prec *= 2
            finally:
                ctx.prec = orig_prec

        if n == 2:
            return self * self
        v = self.pow(n // 2)
        v = v * v
        if n % 2:
            v *= self
        return v
Пример #5
0
 def gaussian_integer(a, b):
     if b == 0:
         return alg(a)
     a = fmpz(a)
     b = fmpz(b)
     orig = ctx.prec
     ctx.prec = 64
     try:
         z = acb(a, b)
     finally:
         ctx.prec = orig
     res = alg(_minpoly=fmpz_poly([a**2 + b**2, -2 * a, 1]), _enclosure=z)
     return res
Пример #6
0
 def test_sage_examples_slow(self):
     if 0:
         x = fmpz_poly([0, 1])
         pol = x**10 + x**9 - x**7 - x**6 - x**5 - x**4 - x**3 + x + 1
         root = arb("[1.17628081825991751 +/- 3.46e-18]")
         alpha = alg(_minpoly=pol, _enclosure=root)
         lhs = alpha**630 - 1
         rhs_num = (alpha**315 - 1) * (alpha**210 - 1) * (
             alpha**126 - 1)**2 * (alpha**90 - 1) * (alpha**3 - 1)**3 * (
                 alpha**2 - 1)**5 * (alpha - 1)**3
         rhs_den = (alpha**35 - 1) * (alpha**15 - 1)**2 * (
             alpha**14 - 1)**2 * (alpha**5 - 1)**6 * alpha**68
         rhs = rhs_num / rhs_den
         assert lhs == rhs
Пример #7
0
 def test_sage_examples(self):
     # from the sage qqbar docs
     rt17 = alg(17).sqrt()
     rt2 = alg(2).sqrt()
     eps = (17 + rt17).sqrt()
     epss = (17 - rt17).sqrt()
     delta = rt17 - 1
     alpha = (34 + 6 * rt17 + rt2 * delta * epss - 8 * rt2 * eps).sqrt()
     beta = 2 * (17 + 3 * rt17 - 2 * rt2 * eps - rt2 * epss).sqrt()
     x = rt2 * (15 + rt17 + rt2 * (alpha + epss)).sqrt() / 8
     y = rt2 * (epss**2 - rt2 * (alpha + epss)).sqrt() / 8
     cx, cy = alg(1), alg(0)
     #for i in range(34):    # slow
     for i in range(3):
         cx, cy = x * cx - y * cy, x * cy + y * cx
     ax = fmpz_poly([0, 1])
     x2 = alg.polynomial_roots(256 * ax**8 - 128 * ax**7 - 448 * ax**6 +
                               192 * ax**5 + 240 * ax**4 - 80 * ax**3 -
                               40 * ax**2 + 8 * ax + 1)[0][0]
     y2 = (1 - x2**2).sqrt()
     assert x == x2
     assert y == y2
Пример #8
0
 def imag(self):
     if self.is_real():
         return alg(0)
     return (self - self.conjugate()) / alg(_minpoly=fmpz_poly([4, 0, 1]),
                                            _enclosure=acb(0, 2))
Пример #9
0
 def i():
     return alg(_minpoly=fmpz_poly([1, 0, 1]), _enclosure=acb(0, 1))
Пример #10
0
    def guess(z, deg=None, verbose=False, try_smaller=True, check=True):
        """
        Use LLL to try to find an algebraic number matching the real or
        complex enclosure *z* (given as a *flint.arb* or *flint.acb*).
        Returns *None* if unsuccessful.

        To determine the number of bits to use in the LLL matrix, the
        algorithm accounts for the accuracy of the input as well as the
        current Arb working precision (*flint.ctx.prec*).

        The maximum degree is determined by the *deg* parameter.
        By default the degree is set to roughly the square root of the working
        precision.
        If *try_smaller* is set, then the guessing is attempted recursively
        with lower degree bounds to speed up detection of lower-degree
        numbers.

        If *check* is True (default), the algorithm verifies that the
        result is contained in the complex interval *z*. (At high precision,
        this reduces the likelihood of spurious results.)

        """
        z = acb(z)
        if not z.is_finite():
            return None
        if deg is None:
            deg = max(1, int(ctx.prec**0.5))
        if try_smaller and deg > 8:
            g = alg.guess(z,
                          deg // 4,
                          verbose=verbose,
                          try_smaller=True,
                          check=check)
            if g is not None:
                return g
        # todo: early detect exact (dyadic) real and imaginary parts?
        # (avoid reliance on enclosure(pretty=True)
        prec = ctx.prec
        z = acb(z)
        zpow = [z**i for i in range(deg + 1)]
        magn = max(abs(t) for t in zpow)
        if magn >= arb(2)**prec:
            return None  # too large
        magnrad = max(abs(t.rad()) for t in zpow)
        if magnrad >= 0.125:
            return None  # too imprecise
        magnrad = max(2**(max(1, prec // 20)) * magnrad, arb(2)**(-2 * prec))
        scale = 1 / magnrad
        nonreal = z.imag != 0
        A = fmpz_mat(deg + 1, deg + 2 + nonreal)
        for i in range(deg + 1):
            A[i, i] = 1
        for i in range(deg + 1):
            v = zpow[i] * scale
            # fixme: don't use unique_fmpz
            A[i, deg + 1] = v.real.mid().floor().unique_fmpz()
            if nonreal:
                A[i, deg + 2] = v.imag.mid().floor().unique_fmpz()
        A = A.lll()
        poly = fmpz_poly([A[0, i] for i in range(deg + 1)])
        if verbose:
            print("LLL-reduced matrix:")
            print(A)
            print("poly(z) =", poly(z))
        if not check:
            candidates = alg.polynomial_roots(poly) or [(alg(0), 1)]
            return min([cand for (cand, mult) in candidates],
                       key=lambda x: abs(x.enclosure() - z).mid())
        if not poly(z).contains(0):
            return None
        orig = ctx.prec
        try:
            candidates = alg.polynomial_roots(poly)
            while ctx.prec <= 16 * orig:
                for cand, mult in candidates:
                    r = cand.enclosure(pretty=True)
                    if z.contains(r):
                        return cand
                ctx.prec *= 2
        finally:
            ctx.prec = orig
        return None