예제 #1
0
def field_isomorphism_pslq(a, b):
    """Construct field isomorphism using PSLQ algorithm."""
    if not all(_.domain.is_RationalField and _.ext.is_real for _ in (a, b)):
        raise NotImplementedError("PSLQ doesn't support complex coefficients")

    f = a.minpoly
    x = f.gen

    g = b.minpoly.replace(x)
    m = g.degree()

    a, b = a.ext, b.ext

    for n in mpmath.libmp.libintmath.giant_steps(32, 256):  # pragma: no branch
        with mpmath.workdps(n):
            A, B = lambdify((), [a, b], 'mpmath')()
            basis = [B**i for i in range(m)] + [A]
            coeffs = mpmath.pslq(basis, maxcoeff=10**10, maxsteps=10**3)

        if coeffs:
            assert coeffs[-1]  # basis[:-1] elements are linearly independent

            h = -Poly(coeffs[:-1], x, field=True).quo_ground(coeffs[-1])

            if f.compose(h).rem(g).is_zero:
                return h.rep.all_coeffs()
        else:
            break
 def nsimplify_real(x):
     orig = mpmath.mp.dps
     xv = x._to_mpmath(bprec)
     try:
         # We'll be happy with low precision if a simple fraction
         if not (tolerance or full):
             mpmath.mp.dps = 15
             rat = mpmath.pslq([xv, 1])
             if rat is not None:
                 return Rational(-int(rat[1]), int(rat[0]))
         mpmath.mp.dps = prec
         newexpr = mpmath.identify(xv, constants=constants_dict,
             tol=tolerance, full=full)
         if not newexpr:
             raise ValueError
         if full:
             newexpr = newexpr[0]
         expr = sympify(newexpr)
         if x and not expr:  # don't let x become 0
             raise ValueError
         if expr.is_finite is False and not xv in [mpmath.inf, mpmath.ninf]:
             raise ValueError
         return expr
     finally:
         # even though there are returns above, this is executed
         # before leaving
         mpmath.mp.dps = orig
예제 #3
0
 def nsimplify_real(x):
     orig = mpmath.mp.dps
     xv = x._to_mpmath(bprec)
     try:
         # We'll be happy with low precision if a simple fraction
         if not (tolerance or full):
             mpmath.mp.dps = 15
             rat = mpmath.pslq([xv, 1])
             if rat is not None:
                 return Rational(-int(rat[1]), int(rat[0]))
         mpmath.mp.dps = prec
         newexpr = mpmath.identify(xv, constants=constants_dict,
             tol=tolerance, full=full)
         if not newexpr:
             raise ValueError
         if full:
             newexpr = newexpr[0]
         expr = sympify(newexpr)
         if x and not expr:  # don't let x become 0
             raise ValueError
         if expr.is_finite is False and not xv in [mpmath.inf, mpmath.ninf]:
             raise ValueError
         return expr
     finally:
         # even though there are returns above, this is executed
         # before leaving
         mpmath.mp.dps = orig
예제 #4
0
def field_isomorphism_pslq(a, b):
    """Construct field isomorphism using PSLQ algorithm. """
    if not all(_.domain.is_RationalField and _.ext.is_real for _ in (a, b)):
        raise NotImplementedError("PSLQ doesn't support complex coefficients")

    f = a.minpoly
    g = b.minpoly.replace(f.gen)
    m = b.minpoly.degree()

    for n in mpmath.libmp.libintmath.giant_steps(32, 256):  # pragma: no branch
        with mpmath.workdps(n):
            A = lambdify((), a.ext, "mpmath")()
            B = lambdify((), b.ext, "mpmath")()
            basis = [B**i for i in range(m)] + [A]
            coeffs = mpmath.pslq(basis, maxcoeff=int(1e10), maxsteps=1000)

        if coeffs is None:
            break

        coeffs = [QQ(c, coeffs[-1]) for c in coeffs[:-1]]
        while not coeffs[-1]:
            coeffs.pop()
        coeffs.reverse()

        h = Poly(coeffs, f.gen, domain='QQ')

        if f.compose(h).rem(g).is_zero or f.compose(-h).rem(g).is_zero:
            return [-c for c in coeffs]
    def _improve_results_precision(self, intermediate_results, verbose=True):
        """
        Calculates GCFs to a higher depth using RelativeGCFEnumerator's implementation.
        We then feed those results and the constant given to a PSLQ, that tries to find a suitable LHS.

        Notice-
        The second part of this function (PSLQ), logically belongs to the next step of the algorithm - the 
        result refinement part. It is implemented here, because the next function is not parallelized over
        different processes or clients, and we want the PSLQ to be parallelized as well. 
        """
        precise_intermediate_results = super()._improve_results_precision(intermediate_results, verbose)
        for i in precise_intermediate_results:
            print(i)
        pslq_results = []
        const = self.constants_generator[0]() # using only one constant for now.
        for match, val, precision in precise_intermediate_results:
            mpf_val = mpmath.mpf(val)
            print(match)
            try:
                pslq_res = mpmath.pslq(
                    [1, const, const**2, -mpf_val, -const * mpf_val, -(const**2) * mpf_val],
                    tol=10 ** (1 - precision))
            except Exception as e:
                import ipdb
                ipdb.set_trace()
            if pslq_res:
                # Sometimes, PSLQ can find several results for the same value (e.g. z(3)/(z(3)^2) = 1/z(3))
                # we'll reduce fraction found to get uniform results
                reduced_num, reduced_denom = get_reduced_fraction(pslq_res[:3], pslq_res[3:], 2)
                print(reduced_num, reduced_denom)
                pslq_results.append(RefinedMatch(*match, val, reduced_num, reduced_denom, precision))
            else:
                pslq_results.append(RefinedMatch(*match, val, None, None, precision))

        return pslq_results
예제 #6
0
def real_to_simple_algebraic_maybe(x, **param):
    ''' Tries to turn a float into a rational combination of roots.
        If it succeeds, returns a sympy number
        If it fails, returns directly the float
        We return a number, a certificate, and a latex string
        It would be nice to also take into account other constants like pi?
        NB : this is very expensive. Can it be improved?
    '''
    list_roots = nonsquare_int(param['root_max'])
    L = [np.sqrt(n) for n in list_roots]
    L.append(x)
    coeff = pslq(L, tol=param['tol'])  # TOO EXPENSIVE
    #coeff = [1,2,3,5,6,7,-1]
    if coeff is None:  # we found no algebraic combination
        return x, False, ''
    denominator = -coeff[-1]
    if denominator == 0:  # this shouldn't happen, but who knows..
        return x, False, ''
    fracs = [Fraction(c, denominator) for c in coeff[:-1]]
    for frac in fracs:
        if frac.denominator > param['denominator_max']:
            return x, False, ''
    approx = 0
    latex = ''
    for k in range(len(fracs)):
        if fracs[k] != 0:
            approx = approx + fracs[k] * sympy.sqrt(list_roots[
                k])  # it is expensive to use sympy.sqrt. Maybe hard code it?
            latex = latex + fraction_x_root_to_latex(
                (0, fracs[k], list_roots[k]), **param) + '+'
    return approx, True, latex[:-1]
예제 #7
0
def field_isomorphism_pslq(a, b):
    """Construct field isomorphism using PSLQ algorithm."""
    if not all(_.domain.is_RationalField and _.ext.is_real for _ in (a, b)):
        raise NotImplementedError("PSLQ doesn't support complex coefficients")

    f = a.minpoly
    g = b.minpoly.replace(f.gen)
    m = b.minpoly.degree()

    for n in mpmath.libmp.libintmath.giant_steps(32, 256):  # pragma: no branch
        with mpmath.workdps(n):
            A = lambdify((), a.ext, "mpmath")()
            B = lambdify((), b.ext, "mpmath")()
            basis = [B**i for i in range(m)] + [A]
            coeffs = mpmath.pslq(basis, maxcoeff=int(1e10), maxsteps=1000)

        if coeffs is None:
            break

        coeffs = [QQ(c, coeffs[-1]) for c in coeffs[:-1]]
        while not coeffs[-1]:
            coeffs.pop()
        coeffs.reverse()

        h = Poly(coeffs, f.gen, domain='QQ')

        if f.compose(h).rem(g).is_zero or f.compose(-h).rem(g).is_zero:
            return [-c for c in coeffs]
예제 #8
0
def find_simple_recurrence_vector(v, maxcoeff=1024):
    """
    This function is used internally by other functions from the
    sympy.concrete.guess module. While most users may want to rather use the
    function find_simple_recurrence when looking for recurrence relations
    among rational numbers, the current function may still be useful when
    some post-processing has to be done.

    The function returns a vector of length n when a recurrence relation of
    order n is detected in the sequence of rational numbers v.

    If the returned vector has a length 1, then the returned value is always
    the list [0], which means that no relation has been found.

    While the functions is intended to be used with rational numbers, it should
    work for other kinds of real numbers except for some cases involving
    quadratic numbers; for that reason it should be used with some caution when
    the argument is not a list of rational numbers.

    Examples
    ========

    >>> from sympy.concrete.guess import find_simple_recurrence_vector
    >>> from sympy import fibonacci
    >>> find_simple_recurrence_vector([fibonacci(k) for k in range(12)])
    [1, -1, -1]

    See also
    ========

    See the function sympy.concrete.guess.find_simple_recurrence which is more
    user-friendly.

    """
    l = len(v) >> 1

    previous = mp.prec  # save current precision
    mp.prec = 128
    b = [
        sum(sqrt((l >> 1)**2 + k) * v[-1 - k - i] for k in range(l))
        for i in range(l)
    ]
    p = pslq(b, maxcoeff=maxcoeff, maxsteps=128 + 4 * l)
    mp.prec = previous  # restore current precision
    if p == None: return [0]

    first, last = 0, l - 1
    while p[first] == 0:
        first += 1
    while p[last] == 0:
        last -= 1
        if first == last: return [0]  # TODO: probably never occuring
    return p[first:last + 1]
예제 #9
0
파일: guess.py 프로젝트: Kanav123/sympy
def find_simple_recurrence_vector(v, maxcoeff=1024):
    """
    This function is used internally by other functions from the
    sympy.concrete.guess module. While most users may want to rather use the
    function find_simple_recurrence when looking for recurrence relations
    among rational numbers, the current function may still be useful when
    some post-processing has to be done.

    The function returns a vector of length n when a recurrence relation of
    order n is detected in the sequence of rational numbers v.

    If the returned vector has a length 1, then the returned value is always
    the list [0], which means that no relation has been found.

    While the functions is intended to be used with rational numbers, it should
    work for other kinds of real numbers except for some cases involving
    quadratic numbers; for that reason it should be used with some caution when
    the argument is not a list of rational numbers.

    Examples
    ========

    >>> from sympy.concrete.guess import find_simple_recurrence_vector
    >>> from sympy import fibonacci
    >>> find_simple_recurrence_vector([fibonacci(k) for k in range(12)])
    [1, -1, -1]

    See also
    ========

    See the function sympy.concrete.guess.find_simple_recurrence which is more
    user-friendly.

    """
    l = len(v)>>1

    previous = mp.prec # save current precision
    mp.prec = 128
    b = [sum(sqrt((l>>1)**2 + k)*v[-1-k-i] for k in range(l))
          for i in range(l)]
    p = pslq(b,
             maxcoeff = maxcoeff,
             maxsteps = 128 + 4*l)
    mp.prec = previous # restore current precision
    if p == None: return [0]

    first, last = 0, l-1
    while p[first]==0: first += 1
    while p[last]==0:
        last -= 1
        if first == last: return [0] # TODO: probably never occuring
    return p[first:last+1]
예제 #10
0
def field_isomorphism_pslq(a, b):
    """Construct field isomorphism using PSLQ algorithm. """
    if not a.root.is_real or not b.root.is_real:
        raise NotImplementedError("PSLQ doesn't support complex coefficients")

    f = a.minpoly
    g = b.minpoly.replace(f.gen)

    n, m, prev = 100, b.minpoly.degree(), None

    for i in range(1, 5):
        A = a.root.evalf(n)
        B = b.root.evalf(n)

        basis = [1, B] + [B**i for i in range(2, m)] + [A]

        dps, mp.dps = mp.dps, n
        coeffs = pslq(basis, maxcoeff=int(1e10), maxsteps=1000)
        mp.dps = dps

        if coeffs is None:
            break

        if coeffs != prev:
            prev = coeffs
        else:
            break

        coeffs = [S(c) / coeffs[-1] for c in coeffs[:-1]]

        while not coeffs[-1]:
            coeffs.pop()

        coeffs = list(reversed(coeffs))
        h = Poly(coeffs, f.gen, domain='QQ')

        if f.compose(h).rem(g).is_zero:
            d, approx = len(coeffs) - 1, 0

            for i, coeff in enumerate(coeffs):
                approx += coeff * B**(d - i)

            if A * approx < 0:
                return [-c for c in coeffs]
            else:
                return coeffs
        elif f.compose(-h).rem(g).is_zero:
            return [-c for c in coeffs]
        else:
            n *= 2

    return None
예제 #11
0
def field_isomorphism_pslq(a, b):
    """Construct field isomorphism using PSLQ algorithm. """
    if not a.root.is_real or not b.root.is_real:
        raise NotImplementedError("PSLQ doesn't support complex coefficients")

    f = a.minpoly
    g = b.minpoly.replace(f.gen)

    n, m, prev = 100, b.minpoly.degree(), None

    for i in range(1, 5):
        A = a.root.evalf(n)
        B = b.root.evalf(n)

        basis = [1, B] + [ B**i for i in range(2, m) ] + [A]

        dps, mp.dps = mp.dps, n
        coeffs = pslq(basis, maxcoeff=int(1e10), maxsteps=1000)
        mp.dps = dps

        if coeffs is None:
            break

        if coeffs != prev:
            prev = coeffs
        else:
            break

        coeffs = [S(c)/coeffs[-1] for c in coeffs[:-1]]

        while not coeffs[-1]:
            coeffs.pop()

        coeffs = list(reversed(coeffs))
        h = Poly(coeffs, f.gen, domain='QQ')

        if f.compose(h).rem(g).is_zero:
            d, approx = len(coeffs) - 1, 0

            for i, coeff in enumerate(coeffs):
                approx += coeff*B**(d - i)

            if A*approx < 0:
                return [ -c for c in coeffs ]
            else:
                return coeffs
        elif f.compose(-h).rem(g).is_zero:
            return [ -c for c in coeffs ]
        else:
            n *= 2

    return None