Example #1
0
    def __init__(self, X, P, codomain = None, check = False):
        r"""
        Create the discrete probability space with probabilities on the
        space X given by the dictionary P with values in the field
        real_field.

        EXAMPLES::

            sage: S = [ i for i in range(16) ]
            sage: P = {}
                   sage: for i in range(15): P[i] = 2^(-i-1)
            sage: P[15] = 2^-16
            sage: X = DiscreteProbabilitySpace(S,P)
            sage: X.domain()
            (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
            sage: X.set()
            {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
            sage: X.entropy()
                   1.9997253418

        A probability space can be defined on any list of elements.

        EXAMPLES::

            sage: AZ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            sage: S = [ AZ[i] for i in range(26) ]
            sage: P = { 'A':1/2, 'B':1/4, 'C':1/4 }
            sage: X = DiscreteProbabilitySpace(S,P)
            sage: X
            Discrete probability space defined by {'A': 1/2, 'C': 1/4, 'B': 1/4}
            sage: X.entropy()
                   1.5
        """
        if codomain is None:
            codomain = RealField()
        if not is_RealField(codomain) and not is_RationalField(codomain):
            raise TypeError("Argument codomain (= %s) must be the reals or rationals" % codomain)
        if check:
            one = sum([ P[x] for x in P.keys() ])
            if is_RationalField(codomain):
                if not one == 1:
                    raise TypeError("Argument P (= %s) does not define a probability function")
            else:
                if not Abs(one-1) < 2^(-codomain.precision()+1):
                    raise TypeError("Argument P (= %s) does not define a probability function")
        ProbabilitySpace_generic.__init__(self, X, codomain)
        DiscreteRandomVariable.__init__(self, self, P, codomain, check)
def theta_by_cholesky(self, q_prec):
    r"""
    Uses the real Cholesky decomposition to compute (the `q`-expansion of) the
    theta function of the quadratic form as a power series in `q` with terms
    correct up to the power `q^{\text{q\_prec}}`. (So its error is `O(q^
    {\text{q\_prec} + 1})`.)

    REFERENCE:

        From Cohen's "A Course in Computational Algebraic Number Theory" book,
        p 102.

    EXAMPLES::

        ## Check the sum of 4 squares form against Jacobi's formula
        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1])
        sage: Theta = Q.theta_by_cholesky(10)
        sage: Theta
        1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10
        sage: Expected =  [1] + [8*sum([d for d in divisors(n) if d%4 != 0])  for n in range(1,11)]
        sage: Expected
        [1, 8, 24, 32, 24, 48, 96, 64, 24, 104, 144]
        sage: Theta.list() == Expected
        True

    ::

        ## Check the form x^2 + 3y^2 + 5z^2 + 7w^2 represents everything except 2 and 22.
        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Theta = Q.theta_by_cholesky(50)
        sage: Theta_list = Theta.list()
        sage: [m  for m in range(len(Theta_list))  if Theta_list[m] == 0]
        [2, 22]

    """
    ## RAISE AN ERROR -- This routine is deprecated!
    #raise NotImplementedError, "This routine is deprecated.  Try theta_series(), which uses theta_by_pari()."


    n = self.dim()
    theta = [0 for i in range(q_prec+1)]
    PS = PowerSeriesRing(ZZ, 'q')

    bit_prec = 53                                       ## TO DO: Set this precision to reflect the appropriate roundoff
    Cholesky = self.cholesky_decomposition(bit_prec)     ## error estimate, to be confident through our desired q-precision.
    Q = Cholesky      ##  <----  REDUNDANT!!!
    R = RealField(bit_prec)
    half = R(0.5)



    ## 1. Initialize
    i = n - 1
    T = [R(0)  for j in range(n)]
    U = [R(0)  for j in range(n)]
    T[i] = R(q_prec)
    U[i] = 0
    L = [0 for j in range (n)]
    x = [0 for j in range (n)]


    ## 2. Compute bounds
    #Z = sqrt(T[i] / Q[i,i])      ## IMPORTANT NOTE: sqrt preserves the precision of the real number it's given... which is not so good... =|
    #L[i] = floor(Z - U[i])       ## Note: This is a Sage Integer
    #x[i] = ceil(-Z - U[i]) - 1   ## Note: This is a Sage Integer too


    done_flag = False
    from_step4_flag = False
    from_step3_flag = True        ## We start by pretending this, since then we get to run through 2 and 3a once. =)

    #double Q_val_double;
    #unsigned long Q_val;                 // WARNING: Still need a good way of checking overflow for this value...



    ## Big loop which runs through all vectors
    while not done_flag:

        ## Loop through until we get to i=1 (so we defined a vector x)
        while from_step3_flag or from_step4_flag:              ## IMPORTANT WARNING:  This replaces a do...while loop, so it may have to be adjusted!

            ## Go to directly to step 3 if we're coming from step 4, otherwise perform step 2.
            if from_step4_flag:
                from_step4_flag = False
            else:
                ## 2. Compute bounds
                from_step3_flag = False
                Z = sqrt(T[i] / Q[i,i])
                L[i] = floor(Z - U[i])
                x[i] = ceil(-Z - U[i]) - 1



            ## 3a. Main loop

            ## DIAGNOSTIC
            #print
            #print "  L = ", L
            #print "  x = ", x

            x[i] += 1
            while (x[i] > L[i]):

                ## DIAGNOSTIC
                #print "  x = ", x

                i += 1
                x[i] += 1


            ## 3b. Main loop
            if (i > 0):
                from_step3_flag = True

                ## DIAGNOSTIC
                #print " i = " + str(i)
                #print " T[i] = " + str(T[i])
                #print " Q[i,i] = " + str(Q[i,i])
                #print " x[i] = " + str(x[i])
                #print " U[i] = " + str(U[i])
                #print " x[i] + U[i] = " + str(x[i] + U[i])
                #print " T[i-1] = " + str(T[i-1])

                T[i-1] = T[i] - Q[i,i] * (x[i] + U[i]) * (x[i] + U[i])

                # DIAGNOSTIC
                #print " T[i-1] = " + str(T[i-1])
                #print

                i += - 1
                U[i] = 0
                for j in range(i+1, n):
                    U[i] += Q[i,j] * x[j]



        ## 4. Solution found (This happens when i=0)
        from_step4_flag = True
        Q_val_double = q_prec - T[0] + Q[0,0] * (x[0] + U[0]) * (x[0] + U[0])
        Q_val = floor(Q_val_double + half)        ## Note: This rounds the value up, since the "round" function returns a float, but floor returns integer.



        ## DIAGNOSTIC
        #print " Q_val_double = ",  Q_val_double
        #print " Q_val = ",  Q_val
        #raise RuntimeError


        ## OPTIONAL SAFETY CHECK:
        eps = 0.000000001
        if (abs(Q_val_double - Q_val) > eps):
            raise RuntimeError("Oh No!  We have a problem with the floating point precision... \n" \
                + " Q_val_double = " + str(Q_val_double) + "\n" \
                + " Q_val = " + str(Q_val) + "\n" \
                + " x = " + str(x) + "\n")


        ## DIAGNOSTIC
        #print " The float value is " + str(Q_val_double)
        #print " The associated long value is " + str(Q_val)
        #print

        if (Q_val <= q_prec):
            theta[Q_val] += 2

        ## 5. Check if x = 0, for exit condition. =)
        done_flag = True
        for j in range(n):
            if (x[j] != 0):
                done_flag = False


    ## Set the value: theta[0] = 1
    theta[0] = 1

    ## DIAGNOSTIC
    #print "Leaving ComputeTheta \n"


    ## Return the series, truncated to the desired q-precision
    return PS(theta)
Example #3
0
    def green_function(self, G,v, **kwds):
        r"""
        Evaluates the local Green's function at the place ``v`` for ``self`` with ``N`` terms of the series
        or, in dimension 1, to within the specified error bound. Defaults to ``N=10`` if no kwds provided

        Use ``v=0`` for the archimedean place. Must be over `\ZZ` or `\QQ`.

        ALGORITHM:

        See Exercise 5.29 and Figure 5.6 of ``The Arithmetic of Dynamics Systems``, Joseph H. Silverman, Springer, GTM 241, 2007.

        INPUT:

        - ``G`` - an endomorphism of self.codomain()

        - ``v`` - non-negative integer. a place, use v=0 for the archimedean place

        kwds:

        - ``N`` - positive integer. number of terms of the series to use

        - ``prec`` - positive integer, float point or p-adic precision, default: 100

        - ``error_bound`` - a positive real number

        OUTPUT:

        - a real number

        Examples::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y]);
            sage: Q=P(5,1)
            sage: f.green_function(Q,0,N=30)
            1.6460930159932946233759277576

        ::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y]);
            sage: Q=P(5,1)
            sage: Q.green_function(f,0,N=200,prec=200)
            1.6460930160038721802875250367738355497198064992657997569827

        .. TODO::

            error bounds for dimension > 1
        """
        N = kwds.get('N', None)                     #Get number of iterates (if entered)
        err = kwds.get('error_bound', None)         #Get error bound (if entered)
        prec = kwds.get('prec', 100)                #Get precision (if entered)
        R=RealField(prec)

        if not (v == 0 or is_prime(v)):
            raise ValueError("Invalid valuation (=%s) entered."%v)
        if v == 0:
            K = R
        else:
            K = Qp(v, prec)

        #Coerce all polynomials in F into polynomials with coefficients in K
        F=G.change_ring(K,False)
        d = F.degree()
        D=F.codomain().ambient_space().dimension_relative()

        if err is not None:
            if D!=1:
                raise NotImplementedError("error bounds only for dimension 1")
            err = R(err)
            if not err>0:
                raise ValueError, "Error bound (=%s) must be positive."%err

            #if doing error estimates, compute needed number of iterates
            res = F.resultant()

            #compute maximum coefficient of polynomials of F
            C = R(G.global_height(prec))

            if v == 0:
                log_fact = R(0)
                for i in range(2*d+1):
                    log_fact += R(i+1).log()
                B = max((R(res.abs()) - R(2*d).log() - (2*d-1)*C - log_fact).log().abs(), (C + R(d+1).log()).abs())
            else:
                B = max(R(res.abs()).log() - ((2*d-1)*C).abs(), C.abs())
            N = R(B/(err*(d-1))).log(d).abs().ceil()

        elif N is None:
            N=10 #default is to do 10 iterations

        #Coerce the coordinates into Q_v
        self.normalize_coordinates()
        if self.codomain().base_ring()==QQ:
            self.clear_denominators()
        P=self.change_ring(K,False)

        #START GREEN FUNCTION CALCULATION

        g = R(0)

        for i in range(N+1):
            m = -1

            #compute the maximum absolute value of entries of a, and where it occurs
            for n in range(D+1):
                a_v = R(P[n].abs())
                if a_v > m:
                    j = n
                    m = a_v

            #add to Greens function
            g += (1/R(d))**(i)*R(m).log()

            #normalize coordinates and evaluate
            P.scale_by(1/P[j])
            P = F(P,False)

        return g
def exponential_integral_1(x, n=0):
    r"""
    Returns the exponential integral `E_1(x)`. If the optional
    argument `n` is given, computes list of the first
    `n` values of the exponential integral
    `E_1(x m)`.

    The exponential integral `E_1(x)` is

    .. math::

                      E_1(x) = \int_{x}^{\infty} e^{-t}/t dt

    INPUT:

    - ``x`` -- a positive real number

    - ``n`` -- (default: 0) a nonnegative integer; if
      nonzero, then return a list of values ``E_1(x*m)`` for m =
      1,2,3,...,n. This is useful, e.g., when computing derivatives of
      L-functions.


    OUTPUT:

    A real number if n is 0 (the default) or a list of reals if n > 0.
    The precision is the same as the input, with a default of 53 bits
    in case the input is exact.

    EXAMPLES::

        sage: exponential_integral_1(2)
        0.0489005107080611
        sage: exponential_integral_1(2,4)  # abs tol 1e-18
        [0.0489005107080611, 0.00377935240984891, 0.000360082452162659, 0.0000376656228439245]
        sage: exponential_integral_1(40,5)
        [1.03677326145166e-19, 2.22854325868847e-37, 6.33732515501151e-55, 2.02336191509997e-72, 6.88522610630764e-90]
        sage: exponential_integral_1(0)
        +Infinity
        sage: r = exponential_integral_1(RealField(150)(1))
        sage: r
        0.21938393439552027367716377546012164903104729
        sage: parent(r)
        Real Field with 150 bits of precision
        sage: exponential_integral_1(RealField(150)(100))
        3.6835977616820321802351926205081189876552201e-46

    TESTS:

    The relative error for a single value should be less than 1 ulp::

        sage: for prec in [20..1000]:  # long time (22s on sage.math, 2013)
        ....:     R = RealField(prec)
        ....:     S = RealField(prec+64)
        ....:     for t in range(8):  # Try 8 values for each precision
        ....:         a = R.random_element(-15,10).exp()
        ....:         x = exponential_integral_1(a)
        ....:         y = exponential_integral_1(S(a))
        ....:         e = float(abs(S(x) - y)/x.ulp())
        ....:         if e >= 1.0:
        ....:             print "exponential_integral_1(%s) with precision %s has error of %s ulp"%(a, prec, e)

    The absolute error for a vector should be less than `c 2^{-p}`, where
    `p` is the precision in bits of `x` and `c = 2 max(1, exponential_integral_1(x))`::

        sage: for prec in [20..128]:  # long time (15s on sage.math, 2013)
        ....:     R = RealField(prec)
        ....:     S = RealField(prec+64)
        ....:     a = R.random_element(-15,10).exp()
        ....:     n = 2^ZZ.random_element(14)
        ....:     x = exponential_integral_1(a, n)
        ....:     y = exponential_integral_1(S(a), n)
        ....:     c = RDF(2 * max(1.0, y[0]))
        ....:     for i in range(n):
        ....:         e = float(abs(S(x[i]) - y[i]) << prec)
        ....:         if e >= c:
        ....:             print "exponential_integral_1(%s, %s)[%s] with precision %s has error of %s >= %s"%(a, n, i, prec, e, c)

    ALGORITHM: use the PARI C-library function ``eint1``.

    REFERENCE:

    - See Proposition 5.6.12 of Cohen's book "A Course in
      Computational Algebraic Number Theory".
    """
    if isinstance(x, Expression):
        if x.is_trivial_zero():
            from sage.rings.infinity import Infinity
            return Infinity
        else:
            raise NotImplementedError(
                "Use the symbolic exponential integral " +
                "function: exp_integral_e1.")
    elif not is_inexact(x):  # x is exact and not an expression
        if not x:  # test if exact x == 0 quickly
            from sage.rings.infinity import Infinity
            return Infinity

    # else x is not an exact 0
    from sage.libs.pari.all import pari
    # Figure out output precision
    try:
        prec = parent(x).precision()
    except AttributeError:
        prec = 53

    R = RealField(prec)
    if n <= 0:
        # Add extra bits to the input.
        # (experimentally verified -- Jeroen Demeyer)
        inprec = prec + math.ceil(math.log(2 * prec))
        x = RealField(inprec)(x)._pari_()
        return R(x.eint1())
    else:
        # PARI's algorithm is less precise as n grows larger:
        # add extra bits.
        # (experimentally verified -- Jeroen Demeyer)
        inprec = prec + 1 + math.ceil(1.4427 * math.log(n))
        x = RealField(inprec)(x)._pari_()
        return [R(z) for z in x.eint1(n)]
Example #5
0
def bdd_height(K, height_bound, tolerance=1e-2, precision=53):
    r""" 
    Compute all elements in the number field `K` which have relative
    multiplicative height at most ``height_bound``.

    The function can only be called for number fields `K` with positive unit
    rank. An error will occur if `K` is `QQ` or an imaginary quadratic field.

    This algorithm computes 2 lists: L containing elements x in `K` such that
    H_k(x) <= B, and a list L' containing elements x in `K` that, due to
    floating point issues,
    may be slightly larger then the bound. This can be controlled
    by lowering the tolerance.

    In current implementation both lists (L,L') are merged and returned in
    form of iterator.

    ALGORITHM:

    This is an implementation of the revised algorithm (Algorithm 4) in
    [DK2013]_.

    INPUT:

    - ``height_bound`` -- real number

    - ``tolerance`` -- (default: 0.01) a rational number in (0,1]

    - ``precision`` -- (default: 53) positive integer

    OUTPUT:

    - an iterator of number field elements

    EXAMPLES:

    There are no elements of negative height::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^5 - x + 7)
        sage: list(bdd_height(K,-3))
        []

    The only nonzero elements of height 1 are the roots of unity::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = QuadraticField(3)
        sage: list(bdd_height(K,1))
        [0, -1, 1]

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = QuadraticField(36865)
        sage: len(list(bdd_height(K,101))) # long time (4 s)
        131

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^6 + 2)
        sage: len(list(bdd_height(K,60))) # long time (5 s)
        1899

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^4 - x^3 - 3*x^2 + x + 1)
        sage: len(list(bdd_height(K,10)))
        99

    TESTS:

    Check that :trac:`22771` is fixed::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<v> = NumberField(x^3 + x + 1)
        sage: len(list(bdd_height(K,3)))
        23
    """
    # global values, used in internal function
    B = height_bound
    theta = tolerance
    if B < 1:
        return
    embeddings = K.places(prec=precision)
    O_K = K.ring_of_integers()
    r1, r2 = K.signature()
    r = r1 + r2 - 1
    RF = RealField(precision)
    lambda_gens_approx = {}
    class_group_rep_norm_log_approx = []
    unit_log_dict = {}

    def rational_in(x, y):
        r"""
        Compute a rational number q, such that x<q<y using Archimedes' axiom
        """
        z = y - x
        if z == 0:
            n = 1
        else:
            n = RR(1 / z).ceil() + 1
        if RR(n * y).ceil() is n * y:  # WHAT !?
            m = n * y - 1
        else:
            m = RR(n * y).floor()
        return m / n

    def delta_approximation(x, delta):
        r"""
        Compute a rational number in range (x-delta, x+delta)
        """
        return rational_in(x - delta, x + delta)

    def vector_delta_approximation(v, delta):
        r"""
        Compute a rational vector w=(w1, ..., wn)
        such that |vi-wi|<delta for all i in [1, n]
        """
        return [delta_approximation(vi, delta) for vi in v]

    def log_map(number):
        r"""
        Compute the image of an element of `K` under the logarithmic map.
        """
        x = number
        x_logs = []
        for i in range(r1):
            sigma = embeddings[i]  # real embeddings
            x_logs.append(sigma(x).abs().log())
        for i in range(r1, r + 1):
            tau = embeddings[i]  # Complex embeddings
            x_logs.append(2 * tau(x).abs().log())
        return vector(x_logs)

    def log_height_for_generators_approx(alpha, beta, Lambda):
        r"""
        Compute the rational approximation of logarithmic height function.
        Return a lambda approximation h_K(alpha/beta)
        """
        delta = Lambda / (r + 2)
        norm_log = delta_approximation(
            RR(O_K.ideal(alpha, beta).norm()).log(), delta)
        log_ga = vector_delta_approximation(log_map(alpha), delta)
        log_gb = vector_delta_approximation(log_map(beta), delta)
        arch_sum = sum([max(log_ga[k], log_gb[k]) for k in range(r + 1)])
        return (arch_sum - norm_log)

    def packet_height(n, pair, u):
        r"""
        Compute the height of the element of `K` encoded by a given packet.
        """
        gens = generator_lists[n]
        i = pair[0]
        j = pair[1]
        Log_gi = lambda_gens_approx[gens[i]]
        Log_gj = lambda_gens_approx[gens[j]]
        Log_u_gi = vector(Log_gi) + unit_log_dict[u]
        arch_sum = sum([max(Log_u_gi[k], Log_gj[k]) for k in range(r + 1)])
        return (arch_sum - class_group_rep_norm_log_approx[n])

    # Step 1
    # Computes ideal class representative and their rational approx norm
    t = theta / (3 * B)
    delta_1 = t / (6 * r + 12)

    class_group_reps = []
    class_group_rep_norms = []

    for c in K.class_group():
        a = c.ideal()
        a_norm = a.norm()
        log_norm = RF(a_norm).log()
        log_norm_approx = delta_approximation(log_norm, delta_1)
        class_group_reps.append(a)
        class_group_rep_norms.append(a_norm)
        class_group_rep_norm_log_approx.append(log_norm_approx)
    class_number = len(class_group_reps)

    # Step 2
    # Find generators for principal ideals of bounded norm
    possible_norm_set = set([])
    for n in range(class_number):
        for m in range(1, (B + 1).ceil()):
            possible_norm_set.add(m * class_group_rep_norms[n])
    bdd_ideals = bdd_norm_pr_ideal_gens(K, possible_norm_set)

    # Stores it in form of an dictionary and gives lambda(g)_approx for key g
    for norm in possible_norm_set:
        gens = bdd_ideals[norm]
        for g in gens:
            lambda_g_approx = vector_delta_approximation(log_map(g), delta_1)
            lambda_gens_approx[g] = lambda_g_approx

    # Step 3
    # Find a list of all generators corresponding to each ideal a_l
    generator_lists = []
    for l in range(class_number):
        this_ideal = class_group_reps[l]
        this_ideal_norm = class_group_rep_norms[l]
        gens = []
        for i in range(1, (B + 1).ceil()):
            for g in bdd_ideals[i * this_ideal_norm]:
                if g in this_ideal:
                    gens.append(g)
        generator_lists.append(gens)

    # Step 4
    # Finds all relevant pair and their height
    gen_height_approx_dictionary = {}
    relevant_pair_lists = []

    for n in range(class_number):
        relevant_pairs = []
        gens = generator_lists[n]
        l = len(gens)
        for i in range(l):
            for j in range(i + 1, l):
                if K.ideal(gens[i], gens[j]) == class_group_reps[n]:
                    relevant_pairs.append([i, j])
                    gen_height_approx_dictionary[(
                        n, i, j)] = log_height_for_generators_approx(
                            gens[i], gens[j], t / 6)
        relevant_pair_lists.append(relevant_pairs)

    # Step 5
    b = rational_in(t / 12 + RR(B).log(), t / 4 + RR(B).log())
    maximum = 0
    for n in range(class_number):
        for p in relevant_pair_lists[n]:
            maximum = max(maximum,
                          gen_height_approx_dictionary[(n, p[0], p[1])])
    d_tilde = b + t / 6 + maximum

    # Step 6
    # computes fundamental units and their value under log map
    fund_units = UnitGroup(K).fundamental_units()
    fund_unit_logs = [log_map(fund_units[i]) for i in range(r)]
    S = column_matrix(fund_unit_logs).delete_rows([r])
    S_inverse = S.inverse()
    S_norm = S.norm(Infinity)
    S_inverse_norm = S_inverse.norm(Infinity)

    upper_bound = (r**2) * max(S_norm, S_inverse_norm)
    m = RR(upper_bound).ceil() + 1

    # Step 7
    # Variables needed for rational approximation
    lambda_tilde = (t / 12) / (d_tilde * r * (1 + m))
    delta_tilde = min(lambda_tilde / ((r**2) * ((m**2) + m * lambda_tilde)),
                      1 / (r**2))
    M = d_tilde * (upper_bound + lambda_tilde * RR(r).sqrt())
    M = RR(M).ceil()
    d_tilde = RR(d_tilde)
    delta_2 = min(delta_tilde, (t / 6) / (r * (r + 1) * M))

    # Step 8, 9
    # Computes relevant points in polytope
    fund_unit_log_approx = [
        vector_delta_approximation(fund_unit_logs[i], delta_2)
        for i in range(r)
    ]
    S_tilde = column_matrix(fund_unit_log_approx).delete_rows([r])
    S_tilde_inverse = S_tilde.inverse()
    U = integer_points_in_polytope(S_tilde_inverse, d_tilde)

    # Step 10
    # tilde suffixed list are used for computing second list (L_primed)
    yield K(0)
    U0 = []
    U0_tilde = []
    L0 = []
    L0_tilde = []

    # Step 11
    # Computes unit height
    unit_height_dict = {}
    U_copy = copy(U)
    inter_bound = b - (5 * t) / 12

    for u in U:
        u_log = sum([u[j] * vector(fund_unit_log_approx[j]) for j in range(r)])
        unit_log_dict[u] = u_log
        u_height = sum([max(u_log[k], 0) for k in range(r + 1)])
        unit_height_dict[u] = u_height
        if u_height < inter_bound:
            U0.append(u)
        if inter_bound <= u_height and u_height < b - (t / 12):
            U0_tilde.append(u)
        if u_height > t / 12 + d_tilde:
            U_copy.remove(u)
    U = U_copy

    relevant_tuples = set(U0 + U0_tilde)

    # Step 12
    # check for relevant packets
    for n in range(class_number):
        for pair in relevant_pair_lists[n]:
            i = pair[0]
            j = pair[1]
            u_height_bound = b + gen_height_approx_dictionary[(n, i,
                                                               j)] + t / 4
            for u in U:
                if unit_height_dict[u] < u_height_bound:
                    candidate_height = packet_height(n, pair, u)
                    if candidate_height <= b - 7 * t / 12:
                        L0.append([n, pair, u])
                        relevant_tuples.add(u)
                    elif candidate_height < b + t / 4:
                        L0_tilde.append([n, pair, u])
                        relevant_tuples.add(u)

    # Step 13
    # forms a dictionary of all_unit_tuples and their value
    tuple_to_unit_dict = {}
    for u in relevant_tuples:
        unit = K.one()
        for k in range(r):
            unit *= fund_units[k]**u[k]
        tuple_to_unit_dict[u] = unit

    # Step 14
    # Build all output numbers
    roots_of_unity = K.roots_of_unity()
    for u in U0 + U0_tilde:
        for zeta in roots_of_unity:
            yield zeta * tuple_to_unit_dict[u]

    # Step 15
    for p in L0 + L0_tilde:
        gens = generator_lists[p[0]]
        i = p[1][0]
        j = p[1][1]
        u = p[2]
        c_p = tuple_to_unit_dict[u] * (gens[i] / gens[j])
        for zeta in roots_of_unity:
            yield zeta * c_p
            yield zeta / c_p
Example #6
0
    def dynatomic_polynomial(self,period):
        r"""
        For a map `f:\mathbb{P}^1 \to \mathbb{P}^1` this function computes the dynatomic polynomial.
        The dynatomic polynomial is the analog of the cyclotomic polynomial and its roots are the points of formal period `n`.

        ALGORITHM:

        For a positive integer `n`, let `[F_n,G_n]` be the coordinates of the `nth` iterate of `f`.
        Then construct

        .. MATH::

            \Phi^{\ast}_n(f)(x,y) = \sum_{d \mid n} (yF_d(x,y) - xG_d(x,y))^{\mu(n/d)}

        where `\mu` is the Moebius function.

        For a pair `[m,n]`, let `f^m = [F_m,G_m]`. Compute

        .. MATH::

            \Phi^{\ast}_{m,n}(f)(x,y) = \Phi^{\ast}_n(f)(F_m,G_m)/\Phi^{\ast}_n(f)(F_{m-1},G_{m-1})

        REFERENCES:

        ..

        - B. Hutz. Efficient determination of rational preperiodic points for endomorphisms of projective space. arxiv:1210.6246, 2012.

        - P. Morton and P. Patel. The Galois theory of periodic points of polynomial maps. Proc. London Math. Soc., 68 (1994), 225-263.

        INPUT:

        - ``period`` -- a positive integer or a list/tuple `[m,n]` where `m` is the preperiod and `n` is the period

        OUTPUT:

        - If possible, a two variable polynomial in the coordinate ring of ``self``.
          Otherwise a fraction field element of the coordinate ring of ``self``

        .. TODO::

            Do the division when the base ring is p-adic or a function field so that the output is a polynomial.

        EXAMPLES::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,y^2])
            sage: f.dynatomic_polynomial(2)
            x^2 + x*y + 2*y^2

        ::

            sage: P.<x,y>=ProjectiveSpace(ZZ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y])
            sage: f.dynatomic_polynomial(4)
            2*x^12 + 18*x^10*y^2 + 57*x^8*y^4 + 79*x^6*y^6 + 48*x^4*y^8 + 12*x^2*y^10 + y^12

        ::

            sage: P.<x,y>=ProjectiveSpace(CC,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,3*x*y])
            sage: f.dynatomic_polynomial(3)
            13.0000000000000*x^6 + 117.000000000000*x^4*y^2 +
            78.0000000000000*x^2*y^4 + y^6

        ::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2-10/9*y^2,y^2])
            sage: f.dynatomic_polynomial([2,1])
            x^4*y^2 - 11/9*x^2*y^4 - 80/81*y^6

        ::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2-29/16*y^2,y^2])
            sage: f.dynatomic_polynomial([2,3])
            x^12 - 95/8*x^10*y^2 + 13799/256*x^8*y^4 - 119953/1024*x^6*y^6 +
            8198847/65536*x^4*y^8 - 31492431/524288*x^2*y^10 +
            172692729/16777216*y^12

        ::

            sage: P.<x,y>=ProjectiveSpace(ZZ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2-y^2,y^2])
            sage: f.dynatomic_polynomial([1,2])
            x^2 - x*y

        ::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^3-y^3,3*x*y^2])
            sage: f.dynatomic_polynomial([0,4])==f.dynatomic_polynomial(4)
            True

        ::

            sage: P.<x,y,z>=ProjectiveSpace(QQ,2)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y,z^2])
            sage: f.dynatomic_polynomial(2)
            Traceback (most recent call last):
            ...
            TypeError: Does not make sense in dimension >1

        ::

            #TODO: it would be nice to get this to actually be a polynomial
            sage: P.<x,y>=ProjectiveSpace(Qp(5),1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,y^2])
            sage: f.dynatomic_polynomial(2)
            (x^4*y + (2 + O(5^20))*x^2*y^3 - x*y^4 + (2 + O(5^20))*y^5)/(x^2*y -
            x*y^2 + y^3)

        ::

            sage: L.<t>=PolynomialRing(QQ)
            sage: P.<x,y>=ProjectiveSpace(L,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+t*y^2,y^2])
            sage: f.dynatomic_polynomial(2)
            x^2 + x*y + (t + 1)*y^2

        ::
            sage: K.<c>=PolynomialRing(ZZ)
            sage: P.<x,y>=ProjectiveSpace(K,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+ c*y^2,y^2])
            sage: f.dynatomic_polynomial([1,2])
            x^2 - x*y + (c + 1)*y^2
       """
        if self.domain() != self.codomain():
            raise TypeError("Must have same domain and codomain to iterate")
        from sage.schemes.projective.projective_space import is_ProjectiveSpace
        if is_ProjectiveSpace(self.domain())==False:
            raise NotImplementedError("Not implemented for subschemes")
        if self.domain().dimension_relative()>1:
            raise TypeError("Does not make sense in dimension >1")

        if (isinstance(period,(list,tuple))==False):
            period=[0,period]
        try:
            period[0]=ZZ(period[0])
            period[1]=ZZ(period[1])
        except TypeError:
            raise TypeError("Period and preperiod must be integers")
        if period[1]<=0:
                raise AttributeError("Period must be at least 1")

        if period[0]!=0:
            m=period[0]
            fm=self.nth_iterate_map(m)
            fm1=self.nth_iterate_map(m-1)
            n=period[1]
            PHI=1;
            x=self.domain().gen(0)
            y=self.domain().gen(1)
            F=self._polys
            f=F
            for d in range(1,n+1):
                if n%d ==0:
                    PHI=PHI*((y*F[0]-x*F[1])**moebius(n/d))
                if d !=n: #avoid extra iteration
                    F=[f[0](F[0],F[1]),f[1](F[0],F[1])]
            if m!=0:
                PHI=PHI(fm._polys)/PHI(fm1._polys)
        else:
            PHI=1;
            x=self.domain().gen(0)
            y=self.domain().gen(1)
            F=self._polys
            f=F
            for d in range(1,period[1]+1):
                if period[1]%d ==0:
                    PHI=PHI*((y*F[0]-x*F[1])**moebius(period[1]/d))
                if d !=period[1]: #avoid extra iteration
                    F=[f[0](F[0],F[1]),f[1](F[0],F[1])]
        from sage.rings.polynomial.polynomial_ring import PolynomialRing_general
        from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic
        if self.domain().base_ring()==RealField() or self.domain().base_ring()==ComplexField():
            PHI=PHI.numerator()._maxima_().divide(PHI.denominator())[0].sage()
        elif isinstance(self.domain().base_ring(),(PolynomialRing_general,MPolynomialRing_generic)):
            from sage.rings.padics.generic_nodes import is_pAdicField, is_pAdicRing
            from sage.rings.function_field.function_field import is_FunctionField
            BR=self.domain().base_ring().base_ring()
            if is_pAdicField(BR) or is_pAdicRing(BR) or is_FunctionField(BR):
                raise NotImplementedError("Not implemented")
            PHI=PHI.numerator()._maxima_().divide(PHI.denominator())[0].sage()
            #do it again to divide out by denominators of coefficients
            PHI=PHI.numerator()._maxima_().divide(PHI.denominator())[0].sage()
        if PHI.denominator()==1:
            PHI=self.coordinate_ring()(PHI)
        return(PHI)
Example #7
0
    def homogenize(self, n, newvar='h'):
        r"""
        Return the homogenization of ``self``. If ``self.domain()`` is a subscheme, the domain of
        the homogenized map is the projective embedding of ``self.domain()``

        INPUT:

        - ``newvar`` -- the name of the homogenization variable (only used when ``self.domain()`` is affine space)

        - ``n`` -- the n-th projective embedding into projective space

        OUTPUT:

        - :class:`SchemMorphism_polynomial_projective_space`

        EXAMPLES::

            sage: A.<x,y>=AffineSpace(ZZ,2)
            sage: H=Hom(A,A)
            sage: f=H([(x^2-2)/x^5,y^2])
            sage: f.homogenize(2,'z')
            Scheme endomorphism of Projective Space of dimension 2 over Integer Ring
              Defn: Defined on coordinates by sending (x : y : z) to
                    (x^2*z^5 - 2*z^7 : x^5*y^2 : x^5*z^2)

        ::

            sage: A.<x,y>=AffineSpace(CC,2)
            sage: H=Hom(A,A)
            sage: f=H([(x^2-2)/(x*y),y^2-x])
            sage: f.homogenize(0,'z')
            Scheme endomorphism of Projective Space of dimension 2 over Complex
            Field with 53 bits of precision
              Defn: Defined on coordinates by sending (x : y : z) to
                    (x*y*z^2 : x^2*z^2 + (-2.00000000000000)*z^4 : x*y^3 - x^2*y*z)

        ::

            sage: A.<x,y>=AffineSpace(ZZ,2)
            sage: X=A.subscheme([x-y^2])
            sage: H=Hom(X,X)
            sage: f=H([9*y^2,3*y])
            sage: f.homogenize(2)
            Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 over Integer Ring defined by:
              -x1^2 + x0*x2
              Defn: Defined on coordinates by sending (x0 : x1 : x2) to
                    (9*x0*x2 : 3*x1*x2 : x2^2)

        ::

            sage: R.<t>=PolynomialRing(ZZ)
            sage: A.<x,y>=AffineSpace(R,2)
            sage: H=Hom(A,A)
            sage: f=H([(x^2-2)/y,y^2-x])
            sage: f.homogenize(0,'z')
            Scheme endomorphism of Projective Space of dimension 2 over Univariate
            Polynomial Ring in t over Integer Ring
              Defn: Defined on coordinates by sending (x : y : z) to
                    (y*z^2 : x^2*z + (-2)*z^3 : y^3 - x*y*z)
        """
        A = self.domain()
        B = self.codomain()
        N = A.ambient_space().dimension_relative()
        NB = B.ambient_space().dimension_relative()
        Vars = list(A.ambient_space().variable_names()) + [newvar]
        S = PolynomialRing(A.base_ring(), Vars)
        try:
            l = lcm([self[i].denominator() for i in range(N)])
        except Exception:  #no lcm
            l = prod([self[i].denominator() for i in range(N)])

        from sage.rings.polynomial.polynomial_ring import PolynomialRing_general
        from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic
        if self.domain().base_ring() == RealField() or self.domain().base_ring(
        ) == ComplexField():
            F = [
                S(((self[i] * l).numerator())._maxima_().divide(
                    self[i].denominator())[0].sage()) for i in range(N)
            ]
        elif isinstance(self.domain().base_ring(),
                        (PolynomialRing_general, MPolynomialRing_generic)):
            F = [
                S(((self[i] * l).numerator())._maxima_().divide(
                    self[i].denominator())[0].sage()) for i in range(N)
            ]
        else:
            F = [S(self[i] * l) for i in range(N)]
        F.insert(n, S(l))
        d = max([F[i].degree() for i in range(N + 1)])
        F = [
            F[i].homogenize(newvar) * S.gen(N)**(d - F[i].degree())
            for i in range(N + 1)
        ]
        from sage.schemes.affine.affine_space import is_AffineSpace
        if is_AffineSpace(A) == True:
            from sage.schemes.projective.projective_space import ProjectiveSpace
            X = ProjectiveSpace(A.base_ring(), NB, Vars)
        else:
            X = A.projective_embedding(n).codomain()
            phi = S.hom(X.ambient_space().gens(),
                        X.ambient_space().coordinate_ring())
            F = [phi(f) for f in F]
        H = Hom(X, X)
        return (H(F))
Example #8
0
def genfiles_mintides(integrator,
                      driver,
                      f,
                      ics,
                      initial,
                      final,
                      delta,
                      tolrel=1e-16,
                      tolabs=1e-16,
                      output=''):
    r"""
    Generate the needed files for the min_tides library.

    INPUT:

    - ``integrator`` -- the name of the integrator file.

    - ``driver`` -- the name of the driver file.

    - ``f`` -- the function that determines the differential equation.

    - ``ics`` -- a list or tuple with the initial conditions.

    - ``initial`` -- the initial time for the integration.

    - ``final`` -- the final time for the integration.

    - ``delta`` -- the step of the output.

    - ``tolrel`` -- the relative tolerance.

    - ``tolabs`` -- the absolute tolerance.

    -  ``output`` -- the name of the file that the compiled integrator will write to

    This function creates two files, integrator and driver, that can be used
    later with the min_tides library [TIDES]_.


    TESTS::

        sage: from sage.interfaces.tides import genfiles_mintides
        sage: import os
        sage: import shutil
        sage: from sage.misc.temporary_file import tmp_dir
        sage: tempdir = tmp_dir()
        sage: intfile = os.path.join(tempdir, 'integrator.c')
        sage: drfile = os.path.join(tempdir ,'driver.c')
        sage: var('t,x,y,X,Y')
        (t, x, y, X, Y)
        sage: f(t,x,y,X,Y)=[X, Y, -x/(x^2+y^2)^(3/2), -y/(x^2+y^2)^(3/2)]
        sage: genfiles_mintides(intfile, drfile, f, [1,0, 0, 0.2], 0, 10, 0.1, output = 'out')
        sage: fileint = open(intfile)
        sage: l = fileint.readlines()
        sage: fileint.close()
        sage: l[5]
        '    #include "minc_tides.h"\n'
        sage: l[15]
        '    double XX[TT+1][MO+1];\n'
        sage: l[25]
        '\n'
        sage: l[35]
        '\t\tXX[1][i+1] = XX[3][i] / (i+1.0);\n'
        sage: filedr = open(drfile)
        sage: l = filedr.readlines()
        sage: filedr.close()
        sage: l[6]
        '    #include "minc_tides.h"\n'
        sage: l[15]
        '    double tolrel, tolabs, tini, tend, dt;\n'
        sage: l[25]
        '\ttolrel = 9.9999999999999998e-17 ;\n'
        sage: shutil.rmtree(tempdir)

    Check that ticket :trac:`17179` is fixed (handle expressions like `\\pi`)::

        sage: from sage.interfaces.tides import genfiles_mintides
        sage: import os
        sage: import shutil
        sage: from sage.misc.temporary_file import tmp_dir
        sage: tempdir = tmp_dir()
        sage: intfile = os.path.join(tempdir, 'integrator.c')
        sage: drfile = os.path.join(tempdir ,'driver.c')
        sage: var('t,x,y,X,Y')
        (t, x, y, X, Y)
        sage: f(t,x,y,X,Y)=[X, Y, -x/(x^2+y^2)^(3/2), -y/(x^2+y^2)^(3/2)]
        sage: genfiles_mintides(intfile, drfile, f, [pi, 0, 0, 0.2], 0, 10, 0.1, output = 'out')
        sage: fileint = open(intfile)
        sage: l = fileint.readlines()
        sage: fileint.close()
        sage: l[30]
        '\t\tXX[8][i] = pow_mc_c(XX[7],-1.5000000000000000,XX[8], i);\n'
        sage: filedr = open(drfile)
        sage: l = filedr.readlines()
        sage: filedr.close()
        sage: l[18]
        '    \tv[0] = 3.1415926535897931 ; \n'
        sage: shutil.rmtree(tempdir)


    """
    RR = RealField()

    l1, l2 = subexpressions_list(f)

    remove_repeated(l1, l2)
    remove_constants(l1, l2)
    l0 = map(str, l1)
    #generate the corresponding c lines

    l3 = []
    var = f[0].arguments()
    lv = map(str, var)
    for i in l2:
        oper = i[0]
        if oper in ["log", "exp", "sin", "cos"]:
            a = i[1]
            if a in var:
                l3.append((oper, 'XX[{}]'.format(lv.index(str(a)))))
            elif a in l1:
                l3.append((oper, 'XX[{}]'.format(l0.index(str(a)) + len(var))))

        else:
            a = i[1]
            b = i[2]
            consta = False
            constb = False

            if str(a) in lv:
                aa = 'XX[{}]'.format(lv.index(str(a)))
            elif str(a) in l0:
                aa = 'XX[{}]'.format(l0.index(str(a)) + len(var))
            else:
                consta = True
                aa = RR(a).str(truncate=False)
            if str(b) in lv:
                bb = 'XX[{}]'.format(lv.index(str(b)))
            elif str(b) in l0:
                bb = 'XX[{}]'.format(l0.index(str(b)) + len(var))
            else:
                constb = True
                bb = RR(b).str(truncate=False)
            if consta:
                oper += '_c'
                if not oper == 'div':
                    bb, aa = aa, bb
            elif constb:
                oper += '_c'
            l3.append((oper, aa, bb))

    n = len(var)
    res = []
    for i in range(len(l3)):
        el = l3[i]
        string = "XX[{}][i] = ".format(i + n)
        if el[0] == 'add':
            string += el[1] + "[i] + " + el[2] + "[i];"
        elif el[0] == 'add_c':
            string += "(i==0)? {}+".format(
                el[2]) + el[1] + "[0] : " + el[1] + "[i];"
        elif el[0] == 'mul':
            string += "mul_mc(" + el[1] + "," + el[2] + ",i);"
        elif el[0] == 'mul_c':
            string += el[2] + "*" + el[1] + "[i];"
        elif el[0] == 'pow_c':
            string += "pow_mc_c(" + el[1] + "," + el[
                2] + ",XX[{}], i);".format(i + n)
        elif el[0] == 'div':
            string += "div_mc(" + el[2] + "," + el[1] + ",XX[{}], i);".format(
                i + n)
        elif el[0] == 'div_c':
            string += "inv_mc(" + el[2] + "," + el[1] + ",XX[{}], i);".format(
                i + n)
        elif el[0] == 'log':
            string += "log_mc(" + el[1] + ",XX[{}], i);".format(i + n)
        elif el[0] == 'exp':
            string += "exp_mc(" + el[1] + ",XX[{}], i);".format(i + n)
        elif el[0] == 'sin':
            string += "sin_mc(" + el[1] + ",XX[{}], i);".format(i + n + 1)
        elif el[0] == 'cos':
            string += "cos_mc(" + el[1] + ",XX[{}], i);".format(i + n - 1)

        res.append(string)

    l0 = lv + l0
    indices = [l0.index(str(i(*var))) + n for i in f]
    for i in range(1, n):
        res.append("XX[{}][i+1] = XX[{}][i] / (i+1.0);".format(
            i, indices[i - 1] - n))

    code = res

    outfile = open(integrator, 'a')
    auxstring = """
    /****************************************************************************
    This file has been created by Sage for its use with TIDES
    *****************************************************************************/

    #include "minc_tides.h"

    void    mincseries(double t,double *v, double *p, double **XVAR,int ORDER, int MO)
    {
    int VAR,PAR,TT,i,j, inext;
    """
    outfile.write(auxstring)

    outfile.write("\tVAR = {};\n".format(n))
    outfile.write("\tPAR = {};\n".format(0))
    outfile.write("\tTT = {};\n".format(len(res)))

    auxstring = """

    double XX[TT+1][MO+1];

    for(j=0; j<=TT; j++)
        for(i=0; i<=ORDER; i++)
            XX[j][i] = 0.e0;
    XX[0][0] = t;
    XX[0][1] = 1.e0;
    for(i=1;i<=VAR;i++) {
        XX[i][0] = v[i-1];
    }

    for(i=0;i<ORDER;i++) {
    """
    outfile.write(auxstring)
    outfile.writelines(["\t\t" + i + "\n" for i in code])

    outfile.write('\t}\n')
    outfile.write('\n')
    outfile.write('\tfor(j=0; j<=VAR; j++)\n')
    outfile.write('\t\tfor(i=0; i<=ORDER; i++)\n')
    outfile.write('\t\t\tXVAR[i][j] = XX[j][i];\n')
    outfile.write('}\n')
    outfile.write('\n')

    outfile = open(driver, 'a')

    auxstring = """
    /****************************************************************************
        Driver file of the minc_tides program
        This file has been automatically created by Sage
    *****************************************************************************/

    #include "minc_tides.h"

    int main() {

        int  i, VARS, PARS;


    VARS = %s ;
    PARS = 1;
    double tolrel, tolabs, tini, tend, dt;
    double v[VARS], p[PARS];

    """ % (n - 1)
    outfile.write(auxstring)
    for i in range(len(ics)):
        outfile.write('\tv[{}] = {} ; \n'.format(
            i,
            RR(ics[i]).str(truncate=False)))
    outfile.write('\ttini = {} ;\n'.format(RR(initial).str(truncate=False)))
    outfile.write('\ttend = {} ;\n'.format(RR(final).str(truncate=False)))
    outfile.write('\tdt   = {} ;\n'.format(RR(delta).str(truncate=False)))
    outfile.write('\ttolrel = {} ;\n'.format(RR(tolrel).str(truncate=False)))
    outfile.write('\ttolabs = {} ;\n'.format(RR(tolabs).str(truncate=False)))
    outfile.write('\textern char ofname[500];')
    outfile.write('\tstrcpy(ofname, "' + output + '");\n')
    outfile.write('\tminc_tides(v,VARS,p,PARS,tini,tend,dt,tolrel,tolabs);\n')
    outfile.write('\treturn 0; \n }')
    outfile.close()
Example #9
0
def bessel_J(nu, z, algorithm="pari", prec=53):
    r"""
    Return value of the "J-Bessel function", or "Bessel function, 1st
    kind", with index (or "order") nu and argument z.

    ::

            Defn:
            Maxima:
                             inf
                            ====          - nu - 2 k  nu + 2 k
                            \     (-1)^k 2           z
                             >    -------------------------
                            /        k! Gamma(nu + k + 1)
                            ====
                            k = 0

            PARI:

                             inf
                            ====          - 2k    2k
                            \     (-1)^k 2      z    Gamma(nu + 1)
                             >    ----------------------------
                            /         k! Gamma(nu + k + 1)
                            ====
                            k = 0

    Sometimes bessel_J(nu,z) is denoted J_nu(z) in the literature.

    .. warning::

       Inaccurate for small values of z.

    EXAMPLES::

        sage: bessel_J(2,1.1)
        0.136564153956658
        sage: bessel_J(0,1.1)
        0.719622018527511
        sage: bessel_J(0,1)
        0.765197686557967
        sage: bessel_J(0,0)
        1.00000000000000
        sage: bessel_J(0.1,0.1)
        0.777264368097005

    We check consistency of PARI and Maxima::

        sage: n(bessel_J(3,10,"maxima"))
        0.0583793793051...
        sage: n(bessel_J(3,10,"pari"))
        0.0583793793051868
        sage: bessel_J(3,10,"scipy")
        0.0583793793052...

    Check whether the return value is real whenever the argument is real (#10251)::
        sage: bessel_J(5, 1.5, algorithm='scipy') in RR
        True
    """

    if algorithm == "pari":
        from sage.libs.pari.all import pari
        try:
            R = RealField(prec)
            nu = R(nu)
            z = R(z)
        except TypeError:
            C = ComplexField(prec)
            nu = C(nu)
            z = C(z)
            K = C
        if nu == 0:
            nu = ZZ(0)
        K = z.parent()
        return K(pari(nu).besselj(z, precision=prec))
    elif algorithm == "scipy":
        if prec != 53:
            raise ValueError, "for the scipy algorithm the precision must be 53"
        import scipy.special
        ans = str(scipy.special.jv(float(nu), complex(real(z), imag(z))))
        ans = ans.replace("(", "")
        ans = ans.replace(")", "")
        ans = ans.replace("j", "*I")
        ans = sage_eval(ans)
        return real(ans) if z in RR else ans
    elif algorithm == "maxima":
        if prec != 53:
            raise ValueError, "for the maxima algorithm the precision must be 53"
        return maxima_function("bessel_j")(nu, z)
    else:
        raise ValueError, "unknown algorithm '%s'" % algorithm
Example #10
0
def bessel_K(nu, z, algorithm="pari", prec=53):
    r"""
    Implements the "K-Bessel function", or "modified Bessel function,
    2nd kind", with index (or "order") nu and argument z. Defn::

                    pi*(bessel_I(-nu, z) - bessel_I(nu, z))
                   ----------------------------------------
                                2*sin(pi*nu)

    if nu is not an integer and by taking a limit otherwise.

    Sometimes bessel_K(nu,z) is denoted K_nu(z) in the literature. In
    PARI, nu can be complex and z must be real and positive.

    EXAMPLES::

        sage: bessel_K(3,2,"scipy")
        0.64738539094...
        sage: bessel_K(3,2)
        0.64738539094...
        sage: bessel_K(1,1)
        0.60190723019...
        sage: bessel_K(1,1,"pari",10)
        0.60
        sage: bessel_K(1,1,"pari",100)
        0.60190723019723457473754000154

    TESTS::

        sage: bessel_K(2,1.1, algorithm="maxima")
        Traceback (most recent call last):
        ...
        NotImplementedError: The K-Bessel function is only implemented for the pari and scipy algorithms

        Check whether the return value is real whenever the argument is real (#10251)::

        sage: bessel_K(5, 1.5, algorithm='scipy') in RR
        True

    """
    if algorithm == "scipy":
        if prec != 53:
            raise ValueError, "for the scipy algorithm the precision must be 53"
        import scipy.special
        ans = str(scipy.special.kv(float(nu), float(z)))
        ans = ans.replace("(", "")
        ans = ans.replace(")", "")
        ans = ans.replace("j", "*I")
        ans = sage_eval(ans)
        return real(ans) if z in RR else ans
    elif algorithm == 'pari':
        from sage.libs.pari.all import pari
        try:
            R = RealField(prec)
            nu = R(nu)
            z = R(z)
        except TypeError:
            C = ComplexField(prec)
            nu = C(nu)
            z = C(z)
            K = C
        K = z.parent()
        return K(pari(nu).besselk(z, precision=prec))
    elif algorithm == 'maxima':
        raise NotImplementedError, "The K-Bessel function is only implemented for the pari and scipy algorithms"
    else:
        raise ValueError, "unknown algorithm '%s'" % algorithm
Example #11
0
def bessel_I(nu, z, algorithm="pari", prec=53):
    r"""
    Implements the "I-Bessel function", or "modified Bessel function,
    1st kind", with index (or "order") nu and argument z.

    INPUT:

    -  ``nu`` - a real (or complex, for pari) number

    -  ``z`` - a real (positive) algorithm - "pari" or
       "maxima" or "scipy" prec - real precision (for PARI only)

    DEFINITION::

            Maxima:
                             inf
                            ====   - nu - 2 k  nu + 2 k
                            \     2          z
                             >    -------------------
                            /     k! Gamma(nu + k + 1)
                            ====
                            k = 0

            PARI:

                             inf
                            ====   - 2 k  2 k
                            \     2      z    Gamma(nu + 1)
                             >    -----------------------
                            /       k! Gamma(nu + k + 1)
                            ====
                            k = 0

    Sometimes ``bessel_I(nu,z)`` is denoted
    ``I_nu(z)`` in the literature.

    .. warning::

       In Maxima (the manual says) i0 is deprecated but
       ``bessel_i(0,*)`` is broken. (Was fixed in recent CVS patch
       though.)

    EXAMPLES::

        sage: bessel_I(1,1,"pari",500)
        0.565159103992485027207696027609863307328899621621092009480294489479255640964371134092664997766814410064677886055526302676857637684917179812041131208121
        sage: bessel_I(1,1)
        0.565159103992485
        sage: bessel_I(2,1.1,"maxima")
        0.16708949925104...
        sage: bessel_I(0,1.1,"maxima")
        1.32616018371265...
        sage: bessel_I(0,1,"maxima")
        1.2660658777520...
        sage: bessel_I(1,1,"scipy")
        0.565159103992...

    Check whether the return value is real whenever the argument is real (#10251)::

        sage: bessel_I(5, 1.5, algorithm='scipy') in RR
        True

    """
    if algorithm == "pari":
        from sage.libs.pari.all import pari
        try:
            R = RealField(prec)
            nu = R(nu)
            z = R(z)
        except TypeError:
            C = ComplexField(prec)
            nu = C(nu)
            z = C(z)
            K = C
        K = z.parent()
        return K(pari(nu).besseli(z, precision=prec))
    elif algorithm == "scipy":
        if prec != 53:
            raise ValueError, "for the scipy algorithm the precision must be 53"
        import scipy.special
        ans = str(scipy.special.iv(float(nu), complex(real(z), imag(z))))
        ans = ans.replace("(", "")
        ans = ans.replace(")", "")
        ans = ans.replace("j", "*I")
        ans = sage_eval(ans)
        return real(
            ans) if z in RR else ans  # Return real value when arg is real
    elif algorithm == "maxima":
        if prec != 53:
            raise ValueError, "for the maxima algorithm the precision must be 53"
        return sage_eval(maxima.eval("bessel_i(%s,%s)" %
                                     (float(nu), float(z))))
    else:
        raise ValueError, "unknown algorithm '%s'" % algorithm
Example #12
0
def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001):
    r"""
    Return the covariant and Julia invariant from Cremona-Stoll [CS2003]_.

    In [CS2003]_ and [HS2018]_ the Julia invariant is denoted as `\Theta(F)`
    or `R(F, z(F))`. Note that you may get faster convergence if you first move
    `z_0(F)` to the fundamental domain before computing the true covariant

    INPUT:

    - ``F`` -- binary form of degree at least 3 with no multiple roots

    - ``z0_cov`` -- boolean, compute only the `z_0` invariant. Otherwise, solve
      the minimization problem

    - ``prec``-- positive integer. precision to use in CC

    - ``emb`` -- embedding into CC

    - ``error_limit`` -- sets the error tolerance (default:0.000001)


    OUTPUT: a complex number, a real number

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import covariant_z0
        sage: R.<x,y> = QQ[]
        sage: F = 19*x^8 - 262*x^7*y + 1507*x^6*y^2 - 4784*x^5*y^3 + 9202*x^4*y^4\
        ....: - 10962*x^3*y^5 + 7844*x^2*y^6 - 3040*x*y^7 + 475*y^8
        sage: covariant_z0(F, prec=80, z0_cov=True)
        (1.3832330115323681438175 + 0.31233552177413614978744*I,
         3358.4074848663492819259)
        sage: F = -x^8 + 6*x^7*y - 7*x^6*y^2 - 12*x^5*y^3 + 27*x^4*y^4\
        ....: - 4*x^3*y^5 - 19*x^2*y^6 + 10*x*y^7 - 5*y^8
        sage: covariant_z0(F, prec=80)
        (0.64189877107807122203366 + 1.1852516565091601348355*I,
         3134.5148284344627168276)

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(x^3 + 2*x^2*y - 3*x*y^2, z0_cov=True)[0]
        0.230769230769231 + 0.799408065031789*I
        sage: -1/covariant_z0(-y^3 + 2*y^2*x + 3*y*x^2, z0_cov=True)[0]
        0.230769230769231 + 0.799408065031789*I

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(2*x^2*y - 3*x*y^2, z0_cov=True)[0]
        0.750000000000000 + 1.29903810567666*I
        sage: -1/covariant_z0(-x^3 - x^2*y + 2*x*y^2, z0_cov=True)[0] + 1
        0.750000000000000 + 1.29903810567666*I

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(x^2*y - x*y^2, prec=100)
         (0.50000000000000000000000000003 + 0.86602540378443864676372317076*I,
         1.5396007178390020386910634147)

    TESTS::

        sage: R.<x,y>=QQ[] 
        sage: covariant_z0(x^2 + 24*x*y + y^2)
        Traceback (most recent call last):
        ...
        ValueError: must be at least degree 3
        sage: covariant_z0((x+y)^3, z0_cov=True)
        Traceback (most recent call last):
        ...
        ValueError: cannot have multiple roots for z0 invariant
        sage: covariant_z0(x^3 + 3*x*y + y)
        Traceback (most recent call last):
        ...
        TypeError: must be a binary form
        sage: covariant_z0(-2*x^2*y^3 + 3*x*y^4 + 127*y^5)
        Traceback (most recent call last):
        ...
        ValueError: cannot have a root with multiplicity >= 5/2
        sage: covariant_z0((x^2+2*y^2)^2)
        Traceback (most recent call last):
        ...
        ValueError: must have at least 3 distinct roots
    """
    R = F.parent()
    d = ZZ(F.degree())
    if R.ngens() != 2 or any([sum(t) != d for t in F.exponents()]):
        raise TypeError('must be a binary form')
    if d < 3:
        raise ValueError('must be at least degree 3')

    f = F.subs({R.gen(1): 1}).univariate_polynomial()
    if f.degree() < d:
        # we have a root at infinity
        if f.constant_coefficient() != 0:
            # invert so we find all roots!
            mat = matrix(ZZ, 2, 2, [0, -1, 1, 0])
        else:
            t = 0
            poly_ring = f.parent()
            while f(t) == 0:
                t += 1
            mat = matrix(ZZ, 2, 2, [t, -1, 1, 0])
    else:
        mat = matrix(ZZ, 2, 2, [1, 0, 0, 1])
    f = F(list(mat * vector(R.gens()))).subs({
        R.gen(1): 1
    }).univariate_polynomial()
    # now we have a single variable polynomial with all the roots of F
    K = ComplexField(prec=prec)
    if f.base_ring() != K:
        if emb == None:
            f = f.change_ring(K)
        else:
            f = f.change_ring(emb)
    roots = f.roots()
    if (max([ex for p,ex in roots]) > 1)\
      or (f.degree() < d-1):
        if z0_cov:
            raise ValueError('cannot have multiple roots for z0 invariant')
        else:
            # just need a starting point for Newton's method
            f = f.lc() * prod([p for p, ex in f.factor()
                               ])  # removes multiple roots
            if f.degree() < 3:
                raise ValueError('must have at least 3 distinct roots')
            roots = f.roots()
    roots = [p for p, ex in roots]

    # finding quadratic Q_0, gives us our covariant, z_0
    dF = f.derivative()
    n = ZZ(f.degree())
    PR = PolynomialRing(K, 'x,y')
    x, y = PR.gens()
    # finds Stoll and Cremona's Q_0
    q  = sum([(1/(dF(r).abs()**(2/(n-2)))) * ((x-(r*y)) * (x-(r.conjugate()*y)))\
              for r in roots])
    # this is Q_0 , always positive def as long as F has distinct roots
    A = q.monomial_coefficient(x**2)
    B = q.monomial_coefficient(x * y)
    C = q.monomial_coefficient(y**2)
    # need positive root
    try:
        z = ((-B + ((B**2) - (4 * A * C)).sqrt()) / (2 * A))
    except ValueError:
        raise ValueError("not enough precision")
    if z.imag() < 0:
        z = (-B - ((B**2) - (4 * A * C)).sqrt()) / (2 * A)

    if z0_cov:
        FM = f  # for Julia's invariant
    else:
        # solve the minimization problem for 'true' covariant
        CF = ComplexIntervalField(
            prec=prec)  # keeps trac of our precision error
        RF = RealField(prec=prec)
        z = CF(z)
        FM = F(list(mat * vector(R.gens()))).subs({
            R.gen(1): 1
        }).univariate_polynomial()
        from sage.rings.polynomial.complex_roots import complex_roots
        L1 = complex_roots(FM, min_prec=prec)
        L = []
        err = z.diameter()
        # making sure multiplicity isn't too large using convergence conditions in paper
        for p, e in L1:
            if e >= d / 2:
                raise ValueError(
                    'cannot have a root with multiplicity >= %s/2' % d)
            for _ in range(e):
                L.append(p)
        RCF = PolynomialRing(CF, 'u,t')
        a = RCF(0)
        c = RCF(0)
        u, t = RCF.gens()
        for l in L:
            a += u**2 / ((t - l) * (t - l.conjugate()) + u**2)
            c += (t - l.real()) / ((t - l) * (t - l.conjugate()) + u**2)
        # Newton's Method, to find solutions. Error bound is less than diameter of our z
        err = z.diameter()
        zz = z.diameter()
        g1 = a.numerator() - d / 2 * a.denominator()
        g2 = c.numerator()
        G = vector([g1, g2])
        J = jacobian(G, [u, t])
        v0 = vector([z.imag(), z.real()])  # z0 as starting point
        # finds our correct z
        while err <= zz:
            NJ = J.subs({u: v0[0], t: v0[1]})
            NJinv = NJ.inverse()
            # inverse for CIF matrix seems to return fractions not CIF elements, fix them
            if NJinv.base_ring() != CF:
                NJinv = matrix(CF, 2, 2, [
                    CF(zw.numerator() / zw.denominator())
                    for zw in NJinv.list()
                ])
            w = z
            v0 = v0 - NJinv * G.subs({u: v0[0], t: v0[1]})
            z = v0[1].constant_coefficient(
            ) + v0[0].constant_coefficient() * CF.gen(0)
            err = z.diameter()  # precision
            zz = (w - z).abs()  # difference in w and z
        else:
            if err > error_limit or err.is_NaN():
                raise ValueError(
                    "accuracy of Newton's root not within tolerance(%s > %s), increase precision"
                    % (err, error_limit))
        if z.imag() <= z.diameter():
            raise ArithmeticError(
                "Newton's method converged to z not in the upper half plane")
        z = z.center()

    # Julia's invariant
    if FM.base_ring() != ComplexField(prec=prec):
        FM = FM.change_ring(ComplexField(prec=prec))
    tF = z.real()
    uF = z.imag()
    th = FM.lc().abs()**2
    for r, ex in FM.roots():
        for _ in range(ex):
            th = th * ((((r - tF).abs())**2 + uF**2) / uF)

    # undo shift and invert (if needed)
    # since F \cdot m ~ m^(-1)\cdot z
    # we apply m to z to undo m acting on F
    l = mat * vector([z, 1])
    return l[0] / l[1], th
Example #13
0
def epsinv(F, target, prec=53, target_tol=0.001, z=None, emb=None):
    """
    Compute a bound on the hyperbolic distance.

    The true minimum will be within the computed bound.
    It is computed as the inverse of epsilon_F from [HS2018]_.
    
    INPUT:

    - ``F`` -- binary form of degree at least 3 with no multiple roots

    - ``target`` --  positive real number. The value we want to attain, i.e.,
      the value we are taking the inverse of

    - ``prec``-- positive integer. precision to use in CC

    - ``target_tol`` -- positive real number. The tolerance with which we
      attain the target value.

    - ``z`` -- complex number. ``z_0`` covariant for F.

    - ``emb`` -- embedding into CC

    OUTPUT: a real number delta satisfying  target + target_tol > eps_F(delta) > target.

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import epsinv
        sage: R.<x,y> = QQ[]
        sage: epsinv(-2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3, 31.5022020249597)
        4.02520895942207       
    """
    def coshdelta(z):
        #The cosh of the hyperbolic distance from z = t+uj to j
        return (z.norm() + 1) / (2 * z.imag())

    def RQ(delta):
        # this is the quotient R(F_0,z)/R(F_0,z(F)) for a generic z
        # at distance delta from j. See Lemma 4.2 in [HS2018].
        cd = cosh(delta).n(prec=prec)
        sd = sinh(delta).n(prec=prec)
        return prod(
            [cd + (cost * phi[0] + sint * phi[1]) * sd for phi in phis])

    def epsF(delta):
        pol = RQ(delta)  #get R quotient in terms of z
        S = PolynomialRing(C, 'v')
        g = S([(i - d) * pol[i - d]
               for i in range(2 * d + 1)])  # take derivative
        drts = [
            e for e in g.roots(ring=C, multiplicities=False)
            if (e.norm() - 1).abs() < 0.1
        ]
        # find min
        return min([pol(r / r.abs()).real() for r in drts])

    C = ComplexField(prec=prec)
    if F.base_ring() != C:
        if emb is None:
            compF = F.change_ring(C)
        else:
            compF = F.change_ring(emb)
    else:
        compF = F

    R = F.parent()
    d = F.degree()
    if z is None:
        z, th = covariant_z0(F, prec=prec, emb=emb)
    else:  #need to do our own input checking
        if R.ngens() != 2 or any([sum(t) != d for t in F.exponents()]):
            raise TypeError('must be a binary form')
        if d < 3:
            raise ValueError('must be at least degree 3')

    f = F.subs({R.gen(1): 1}).univariate_polynomial()
    #now we have a single variable polynomial
    x = f.parent().gen()
    if (max([ex for p,ex in f.roots(ring=C)]) >= QQ(d)/2)\
      or (f.degree() < QQ(d)/2):
        raise ValueError('cannot have root with multiplicity >= deg(F)/2')

    R = RealField(prec=prec)
    PR = PolynomialRing(R, 't')
    t = PR.gen(0)
    # compute phi_1, ..., phi_k
    # first find F_0 and its roots
    # this change of variables on f moves z(f) to j, i.e. produces F_0
    rts = f(z.imag() * t + z.real()).roots(ring=C)
    phis = []  # stereographic projection of roots
    for r, e in rts:
        phis.extend(
            [[2 * r.real() / (r.norm() + 1), (r.norm() - 1) / (r.norm() + 1)]])
    if d != f.degree():  # include roots at infinity
        phis.extend([(d - f.degree()) * [0, 1]])

    # for writing RQ in terms of generic z to minimize
    LC = LaurentSeriesRing(C, 'u', default_prec=2 * d + 2)
    u = LC.gen(0)
    cost = (u + u**(-1)) / 2
    sint = (u - u**(-1)) / (2 * C.gen(0))

    # first find an interval containing the desired value
    # then use regula falsi on log eps_F
    # d -> delta value in interval [0,1]
    # v in value in interval [1,epsF(1)]
    dl = R(0.0)
    vl = R(1.0)
    du = R(1.0)
    vu = epsF(du)
    while vu < target:
        # compute the next value of epsF for delta = 2*delta
        dl = du
        vl = vu
        du *= 2
        vu = epsF(du)
    # now dl < delta <= du
    logt = target.log()
    l2 = (vu.log() - logt).n(prec=prec)
    l1 = (vl.log() - logt).n(prec=prec)
    dn = (dl * l2 - du * l1) / (l2 - l1)
    vn = epsF(dn)
    dl = du
    vl = vu
    du = dn
    vu = vn
    while (du - dl).abs() >= target_tol or max(vl, vu) < target:
        l2 = (vu.log() - logt).n(prec=prec)
        l1 = (vl.log() - logt).n(prec=prec)
        dn = (dl * l2 - du * l1) / (l2 - l1)
        vn = epsF(dn)
        dl = du
        vl = vu
        du = dn
        vu = vn
    return max(dl, du)
Example #14
0
 def extract(cls, obj):
     """
     Takes an object extracted by the json parser and decodes the
     special-formating dictionaries used to store special types.
     """
     if isinstance(obj, dict) and 'data' in obj:
         if len(obj) == 2 and '__ComplexList__' in obj:
             return [complex(*v) for v in obj['data']]
         elif len(obj) == 2 and '__QQList__' in obj:
             return [QQ(tuple(v)) for v in obj['data']]
         elif len(obj) == 3 and '__NFList__' in obj and 'base' in obj:
             base = cls.extract(obj['base'])
             return [cls._extract(base, c) for c in obj['data']]
         elif len(obj) == 2 and '__IntDict__' in obj:
             return {Integer(k): cls.extract(v) for k, v in obj['data']}
         elif len(obj) == 3 and '__Vector__' in obj and 'base' in obj:
             base = cls.extract(obj['base'])
             return vector([cls._extract(base, v) for v in obj['data']])
         elif len(obj) == 2 and '__Rational__' in obj:
             return Rational(*obj['data'])
         elif len(obj) == 3 and '__RealLiteral__' in obj and 'prec' in obj:
             return LmfdbRealLiteral(RealField(obj['prec']), obj['data'])
         elif len(obj) == 2 and '__complex__' in obj:
             return complex(*obj['data'])
         elif len(obj) == 3 and '__Complex__' in obj and 'prec' in obj:
             return ComplexNumber(ComplexField(obj['prec']), *obj['data'])
         elif len(obj) == 3 and '__NFElt__' in obj and 'parent' in obj:
             return cls._extract(cls.extract(obj['parent']), obj['data'])
         elif len(obj) == 3 and ('__NFRelative__' in obj or '__NFAbsolute__'
                                 in obj) and 'vname' in obj:
             poly = cls.extract(obj['data'])
             return NumberField(poly, name=obj['vname'])
         elif len(obj) == 2 and '__NFCyclotomic__' in obj:
             return CyclotomicField(obj['data'])
         elif len(obj) == 2 and '__IntegerRing__' in obj:
             return ZZ
         elif len(obj) == 2 and '__RationalField__' in obj:
             return QQ
         elif len(
                 obj) == 3 and '__RationalPoly__' in obj and 'vname' in obj:
             return QQ[obj['vname']]([QQ(tuple(v)) for v in obj['data']])
         elif len(
                 obj
         ) == 4 and '__Poly__' in obj and 'vname' in obj and 'base' in obj:
             base = cls.extract(obj['base'])
             return base[obj['vname']](
                 [cls._extract(base, c) for c in obj['data']])
         elif len(
                 obj
         ) == 5 and '__PowerSeries__' in obj and 'vname' in obj and 'base' in obj and 'prec' in obj:
             base = cls.extract(obj['base'])
             prec = infinity if obj['prec'] == 'inf' else int(obj['prec'])
             return base[[obj['vname']
                          ]]([cls._extract(base, c) for c in obj['data']],
                             prec=prec)
         elif len(obj) == 2 and '__date__' in obj:
             return datetime.datetime.strptime(obj['data'],
                                               "%Y-%m-%d").date()
         elif len(obj) == 2 and '__time__' in obj:
             return datetime.datetime.strptime(obj['data'],
                                               "%H:%M:%S.%f").time()
         elif len(obj) == 2 and '__datetime__' in obj:
             return datetime.datetime.strptime(obj['data'],
                                               "%Y-%m-%d %H:%M:%S.%f")
     return obj
Example #15
0
def bdd_height(K, height_bound, precision=53, LLL=False):
    r"""
    Computes all elements in the number number field `K` which have relative
    multiplicative height at most ``height_bound``.

    The algorithm requires arithmetic with floating point numbers;
    ``precision`` gives the user the option to set the precision for such
    computations.

    It might be helpful to work with an LLL-reduced system of fundamental
    units, so the user has the option to perform an LLL reduction for the
    fundamental units by setting ``LLL`` to True.

    Certain computations may be faster assuming GRH, which may be done
    globally by using the number_field(True/False) switch.

    The function will only be called for number fields `K` with positive unit
    rank. An error will occur if `K` is `QQ` or an imaginary quadratic field.

    ALGORITHM:

    This is an implementation of the main algorithm (Algorithm 3) in
    [Doyle-Krumm].

    INPUT:

    - ``height_bound`` - real number
    - ``precision`` - (default: 53) positive integer
    - ``LLL`` - (default: False) boolean value

    OUTPUT:

    - an iterator of number field elements

    .. WARNING::

        In the current implementation, the output of the algorithm cannot be
        guaranteed to be correct due to the necessity of floating point
        computations. In some cases, the default 53-bit precision is
        considerably lower than would be required for the algorithm to
        generate correct output.

    .. TODO::

        Should implement a version of the algorithm that guarantees correct
        output. See Algorithm 4 in [Doyle-Krumm] for details of an
        implementation that takes precision issues into account.

    EXAMPLES:

    There are no elements of negative height::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^5 - x + 7)
        sage: list(bdd_height(K,-3))
        []

    The only nonzero elements of height 1 are the roots of unity::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = QuadraticField(3)
        sage: list(bdd_height(K,1))
        [0, -1, 1]

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = QuadraticField(36865)
        sage: len(list(bdd_height(K,101))) # long time (4 s)
        131

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^3 - 197*x + 39)
        sage: len(list(bdd_height(K, 200))) # long time (5 s)
        451

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^6 + 2)
        sage: len(list(bdd_height(K,60,precision=100))) # long time (5 s)
        1899

    ::

        sage: from sage.rings.number_field.bdd_height import bdd_height
        sage: K.<g> = NumberField(x^4 - x^3 - 3*x^2 + x + 1)
        sage: len(list(bdd_height(K,10,LLL=true)))
        99

    """

    B = height_bound
    r1, r2 = K.signature()
    r = r1 + r2 - 1
    if B < 1:
        return
    yield K(0)
    roots_of_unity = K.roots_of_unity()
    if B == 1:
        for zeta in roots_of_unity:
            yield zeta
        return
    RF = RealField(precision)
    embeddings = K.places(prec=precision)
    logB = RF(B).log()

    def log_map(number):
        r"""
        Computes the image of an element of `K` under the logarithmic map.
        """
        x = number
        x_logs = []
        for i in xrange(r1):
            sigma = embeddings[i]
            x_logs.append(abs(sigma(x)).log())
        for i in xrange(r1, r + 1):
            tau = embeddings[i]
            x_logs.append(2 * abs(tau(x)).log())
        return vector(x_logs)

    def log_height_for_generators(n, i, j):
        r"""
        Computes the logarithmic height of elements of the form `g_i/g_j`.
        """
        gen_logs = generator_logs[n]
        Log_gi = gen_logs[i]
        Log_gj = gen_logs[j]
        arch_sum = sum([max(Log_gi[k], Log_gj[k]) for k in range(r + 1)])
        return (arch_sum - class_group_rep_norm_logs[n])

    def packet_height(n, pair, u):
        r"""
        Computes the height of the element of `K` encoded by a given packet.
        """
        gen_logs = generator_logs[n]
        i = pair[0]
        j = pair[1]
        Log_gi = gen_logs[i]
        Log_gj = gen_logs[j]
        Log_u_gi = Log_gi + unit_log_dictionary[u]
        arch_sum = sum([max(Log_u_gi[k], Log_gj[k]) for k in range(r + 1)])
        return (arch_sum - class_group_rep_norm_logs[n])

    class_group_reps = []
    class_group_rep_norms = []
    class_group_rep_norm_logs = []
    for c in K.class_group():
        a = c.ideal()
        a_norm = a.norm()
        class_group_reps.append(a)
        class_group_rep_norms.append(a_norm)
        class_group_rep_norm_logs.append(RF(a_norm).log())
    class_number = len(class_group_reps)

    # Get fundamental units and their images under the log map
    fund_units = UnitGroup(K).fundamental_units()
    fund_unit_logs = [log_map(fund_units[i]) for i in range(r)]
    unit_prec_test = fund_unit_logs
    try:
        [l.change_ring(QQ) for l in unit_prec_test]
    except ValueError:
        raise ValueError(
            'Precision too low.')  # QQ(log(0)) may occur if precision too low

    # If LLL is set to True, find an LLL-reduced system of fundamental units
    if LLL:
        cut_fund_unit_logs = column_matrix(fund_unit_logs).delete_rows([r])
        lll_fund_units = []
        for c in pari(cut_fund_unit_logs).qflll().python().columns():
            new_unit = 1
            for i in xrange(r):
                new_unit *= fund_units[i]**c[i]
            lll_fund_units.append(new_unit)
        fund_units = lll_fund_units
        fund_unit_logs = [log_map(_) for _ in fund_units]
        unit_prec_test = fund_unit_logs
        try:
            [l.change_ring(QQ) for l in unit_prec_test]
        except ValueError:
            raise ValueError('Precision too low.'
                             )  # QQ(log(0)) may occur if precision too low

    # Find generators for principal ideals of bounded norm
    possible_norm_set = set([])
    for n in xrange(class_number):
        for m in xrange(1, B + 1):
            possible_norm_set.add(m * class_group_rep_norms[n])
    bdd_ideals = bdd_norm_pr_ideal_gens(K, possible_norm_set)

    # Distribute the principal ideal generators
    generator_lists = []
    generator_logs = []
    for n in xrange(class_number):
        this_ideal = class_group_reps[n]
        this_ideal_norm = class_group_rep_norms[n]
        gens = []
        gen_logs = []
        for i in xrange(1, B + 1):
            for g in bdd_ideals[i * this_ideal_norm]:
                if g in this_ideal:
                    gens.append(g)
                    gen_logs.append(log_map(g))
        generator_lists.append(gens)
        generator_logs.append(gen_logs)

    # Compute the lists of relevant pairs and corresponding heights
    gen_height_dictionary = dict()
    relevant_pair_lists = []
    for n in xrange(class_number):
        relevant_pairs = []
        gens = generator_lists[n]
        s = len(gens)
        for i in xrange(s):
            for j in xrange(i + 1, s):
                if K.ideal(gens[i], gens[j]) == class_group_reps[n]:
                    relevant_pairs.append([i, j])
                    gen_height_dictionary[(n, i,
                                           j)] = log_height_for_generators(
                                               n, i, j)
        relevant_pair_lists.append(relevant_pairs)

    # Find the bound for units to be computed
    gen_height_list = [
        gen_height_dictionary[x] for x in gen_height_dictionary.keys()
    ]
    if len(gen_height_list) == 0:
        d = logB
    else:
        d = logB + max(gen_height_list)

    # Create the matrix whose columns are the logs of the fundamental units
    S = column_matrix(fund_unit_logs).delete_rows([r])
    try:
        T = S.inverse()
    except ZeroDivisionError:
        raise ValueError('Precision too low.')

    # Find all integer lattice points in the unit polytope
    U = integer_points_in_polytope(T, ceil(d))

    U0 = []
    L0 = []

    # Compute unit heights
    unit_height_dictionary = dict()
    unit_log_dictionary = dict()
    Ucopy = copy(U)

    for u in U:
        u_log = sum([u[j] * fund_unit_logs[j] for j in range(r)])
        unit_log_dictionary[u] = u_log
        u_height = sum([max(u_log[k], 0) for k in range(r + 1)])
        unit_height_dictionary[u] = u_height
        if u_height <= logB:
            U0.append(u)
        if u_height > d:
            Ucopy.remove(u)
    U = Ucopy

    # Sort U by height
    U = sorted(U, key=lambda u: unit_height_dictionary[u])
    U_length = len(U)

    all_unit_tuples = set(copy(U0))

    # Check candidate heights
    for n in xrange(class_number):
        relevant_pairs = relevant_pair_lists[n]
        for pair in relevant_pairs:
            i = pair[0]
            j = pair[1]
            gen_height = gen_height_dictionary[(n, i, j)]
            u_height_bound = logB + gen_height
            for k in xrange(U_length):
                u = U[k]
                u_height = unit_height_dictionary[u]
                if u_height <= u_height_bound:
                    candidate_height = packet_height(n, pair, u)
                    if candidate_height <= logB:
                        L0.append([n, pair, u])
                        all_unit_tuples.add(u)
                else:
                    break

    # Use previous data to build all necessary units
    units_dictionary = dict()
    for u in all_unit_tuples:
        unit = K(1)
        for j in xrange(r):
            unit *= (fund_units[j])**(u[j])
        units_dictionary[u] = unit

    # Build all the output numbers
    for u in U0:
        unit = units_dictionary[u]
        for zeta in roots_of_unity:
            yield zeta * unit
    for packet in L0:
        n = packet[0]
        pair = packet[1]
        u = packet[2]
        i = pair[0]
        j = pair[1]
        relevant_pairs = relevant_pair_lists[n]
        gens = generator_lists[n]
        unit = units_dictionary[u]
        c = unit * gens[i] / gens[j]
        for zeta in roots_of_unity:
            yield zeta * c
            yield zeta / c
def cholesky_decomposition(self, bit_prec=53):
    """
    Give the Cholesky decomposition of this quadratic form `Q` as a real matrix
    of precision ``bit_prec``.

    RESTRICTIONS: 
        Q must be given as a QuadraticForm defined over `\ZZ`, `\QQ`, or some
        real field. If it is over some real field, then an error is raised if
        the precision given is not less than the defined precision of the real
        field defining the quadratic form!

    REFERENCE: 
        From Cohen's "A Course in Computational Algebraic Number Theory" book,
        p 103.

    INPUT:
        ``bit_prec`` -- a natural number (default 53).

    OUTPUT:
        an upper triangular real matrix of precision ``bit_prec``.


    TO DO: 
        If we only care about working over the real double field (RDF), then we
        can use the ``cholesky()`` method present for square matrices over that.

    .. note::

        There is a note in the original code reading

        ::

            ##///////////////////////////////////////////////////////////////////////////////////////////////// 
            ##/// Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix!
            ##/// (It's assumed to be global, hence twice the form it refers to.)  <-- Python revision asks:  Is this true?!? =|
            ##/////////////////////////////////////////////////////////////////////////////////////////////////


    EXAMPLES::
    
        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) 
        sage: Q.cholesky_decomposition()
        [ 1.00000000000000 0.000000000000000 0.000000000000000]
        [0.000000000000000  1.00000000000000 0.000000000000000]
        [0.000000000000000 0.000000000000000  1.00000000000000]

    ::
    
        sage: Q = QuadraticForm(QQ, 3, range(1,7)); Q
        Quadratic form in 3 variables over Rational Field with coefficients: 
        [ 1 2 3 ]
        [ * 4 5 ]
        [ * * 6 ]
        sage: Q.cholesky_decomposition()
        [ 1.00000000000000  1.00000000000000  1.50000000000000]
        [0.000000000000000  3.00000000000000 0.333333333333333]
        [0.000000000000000 0.000000000000000  3.41666666666667]

    """

    ## Check that the precision passed is allowed.
    if isinstance(self.base_ring(),
                  RealField_class) and (self.base_ring().prec() < bit_prec):
        raise RuntimeError, "Oops! The precision requested is greater than that of the given quadratic form!"

    ## 1. Initialization
    n = self.dim()
    R = RealField(bit_prec)
    MS = MatrixSpace(R, n, n)
    Q = MS(R(0.5)) * MS(
        self.matrix()
    )  ## Initialize the real symmetric matrix A with the matrix for Q(x) = x^t * A * x

    ## DIAGNOSTIC
    #print "After 1:  Q is \n" + str(Q)

    ## 2. Loop on i
    for i in range(n):
        for j in range(i + 1, n):
            Q[j, i] = Q[i, j]  ## Is this line redundant?
            Q[i, j] = Q[i, j] / Q[i, i]

        ## 3. Main Loop
        for k in range(i + 1, n):
            for l in range(k, n):
                Q[k, l] = Q[k, l] - Q[k, i] * Q[i, l]

    ## 4. Zero out the strictly lower-triangular entries
    for i in range(n):
        for j in range(i):
            Q[i, j] = 0

    return Q
Example #17
0
    def _coerce_map_from_(self, R):
        r"""
        There is a coercion from anything that has a coercion into the reals.

        The way Sage works is that everything that should be
        comparable with infinity can be coerced into the infinity
        ring, so if you ever compare with infinity the comparison is
        done there. If you don't have a coercion then you will get
        undesirable answers from the fallback comparison (likely
        memory location).

        EXAMPLES::

            sage: InfinityRing.has_coerce_map_from(int) # indirect doctest
            True
            sage: InfinityRing.has_coerce_map_from(AA)
            True
            sage: InfinityRing.has_coerce_map_from(RDF)
            True
            sage: InfinityRing.has_coerce_map_from(RIF)
            True

        As explained above, comparison works by coercing to the
        infinity ring::

            sage: cm = get_coercion_model()
            sage: cm.explain(AA(3), oo, operator.lt)
            Coercion on left operand via
                Coercion map:
                  From: Algebraic Real Field
                  To:   The Infinity Ring
            Arithmetic performed after coercions.
            Result lives in The Infinity Ring
            The Infinity Ring

        The symbolic ring does not coerce to the infinity ring, so
        symbolic comparisons with infinities all happen in the
        symbolic ring::

            sage: SR.has_coerce_map_from(InfinityRing)
            True
            sage: InfinityRing.has_coerce_map_from(SR)
            False

        Complex numbers do not coerce into the infinity ring (what
        would `i \infty` coerce to?). This is fine since they can not
        be compared, so we do not have to enforce consistency when
        comparing with infinity either::

            sage: InfinityRing.has_coerce_map_from(CDF)
            False
            sage: InfinityRing.has_coerce_map_from(CC)
            False
            sage: CC(0, oo) < CC(1)   # does not coerce to infinity ring
            True
        """
        from sage.rings.real_mpfr import mpfr_prec_min, RealField
        if RealField(mpfr_prec_min()).has_coerce_map_from(R):
            return True
        from sage.rings.real_mpfi import RealIntervalField_class
        if isinstance(R, RealIntervalField_class):
            return True
        try:
            from sage.rings.real_arb import RealBallField
            if isinstance(R, RealBallField):
                return True
        except ImportError:
            pass
        return False
Example #18
0
def genfiles_mpfr(integrator,
                  driver,
                  f,
                  ics,
                  initial,
                  final,
                  delta,
                  parameters=None,
                  parameter_values=None,
                  dig=20,
                  tolrel=1e-16,
                  tolabs=1e-16,
                  output=''):
    r"""
        Generate the needed files for the mpfr module of the tides library.

    INPUT:

    - ``integrator`` -- the name of the integrator file.

    - ``driver`` -- the name of the driver file.

    - ``f`` -- the function that determines the differential equation.

    - ``ics`` -- a list or tuple with the initial conditions.

    - ``initial`` -- the initial time for the integration.

    - ``final`` -- the final time for the integration.

    - ``delta`` -- the step of the output.

    - ``parameters`` -- the variables inside the function that should be treated
       as parameters.

    - ``parameter_values`` -- the values of the parameters for the particular
       initial value problem.

    - ``dig`` -- the number of digits of precision that will be used in the integration

    - ``tolrel`` -- the relative tolerance.

    - ``tolabs`` -- the absolute tolerance.

    -  ``output`` -- the name of the file that the compiled integrator will write to

    This function creates two files, integrator and driver, that can be used
    later with the tides library ([TIDES]_).


    TESTS::

        sage: from tempfile import mkdtemp
        sage: from sage.interfaces.tides import genfiles_mpfr
        sage: import os
        sage: import shutil
        sage: from sage.misc.temporary_file import tmp_dir
        sage: tempdir = tmp_dir()
        sage: intfile = os.path.join(tempdir, 'integrator.c')
        sage: drfile = os.path.join(tempdir ,'driver.c')
        sage: var('t,x,y,X,Y')
        (t, x, y, X, Y)
        sage: f(t,x,y,X,Y)=[X, Y, -x/(x^2+y^2)^(3/2), -y/(x^2+y^2)^(3/2)]
        sage: genfiles_mpfr(intfile, drfile, f, [1,0, 0, 0.2], 0, 10, 0.1, output = 'out', dig = 50)
        sage: fileint = open(intfile)
        sage: l = fileint.readlines()
        sage: fileint.close()
        sage: l[5]
        '    #include "mp_tides.h"\n'
        sage: l[15]
        '\tstatic int PARAMETERS = 0;\n'
        sage: l[25]
        '\t\tmpfrts_var_t(itd, link[5], var[3], i);\n'
        sage: l[30]
        '\t\tmpfrts_pow_t_c(itd, link[2], "-1.500000000000000000000000000000000000000000000000000", link[3], i);\n'
        sage: l[35]
        '\n'
        sage: l[36]
        '    }\n'
        sage: l[37]
        '    write_mp_solution();\n'
        sage: filedr = open(drfile)
        sage: l = filedr.readlines()
        sage: filedr.close()
        sage: l[6]
        '    #include "mpfr.h"\n'
        sage: l[16]
        '    int nfun = 0;\n'
        sage: l[26]
        '\tmpfr_set_str(v[2], "0.0000000000000000000000000000000000000000000000000000", 10, TIDES_RND);\n'
        sage: l[30]
        '\tmpfr_init2(tolabs, TIDES_PREC); \n'
        sage: l[34]
        '\tmpfr_init2(tini, TIDES_PREC); \n'
        sage: l[40]
        '\tmp_tides_delta(function_iteration, NULL, nvar, npar, nfun, v, p, tini, dt, nipt, tolrel, tolabs, NULL, fd);\n'
        sage: shutil.rmtree(tempdir)

    Check that ticket :trac:`17179` is fixed (handle expressions like `\\pi`)::

        sage: from sage.interfaces.tides import genfiles_mpfr
        sage: import os
        sage: import shutil
        sage: from sage.misc.temporary_file import tmp_dir
        sage: tempdir = tmp_dir()
        sage: intfile = os.path.join(tempdir, 'integrator.c')
        sage: drfile = os.path.join(tempdir ,'driver.c')
        sage: var('t,x,y,X,Y')
        (t, x, y, X, Y)
        sage: f(t,x,y,X,Y)=[X, Y, -x/(x^2+y^2)^(3/2), -y/(x^2+y^2)^(3/2)]
        sage: genfiles_mpfr(intfile, drfile, f, [pi, 0, 0, 0.2], 0, 10, 0.1, output = 'out', dig = 50)
        sage: fileint = open(intfile)
        sage: l = fileint.readlines()
        sage: fileint.close()
        sage: l[30]
        '\t\tmpfrts_pow_t_c(itd, link[2], "-1.500000000000000000000000000000000000000000000000000", link[3], i);\n'
        sage: filedr = open(drfile)
        sage: l = filedr.readlines()
        sage: filedr.close()
        sage: l[24]
        '\tmpfr_set_str(v[0], "3.141592653589793238462643383279502884197169399375101", 10, TIDES_RND);\n'
        sage: shutil.rmtree(tempdir)

    """
    if parameters == None:
        parameters = []
    if parameter_values == None:
        parameter_values = []
    RR = RealField(ceil(dig * 3.3219))
    l1, l2 = subexpressions_list(f, parameters)
    remove_repeated(l1, l2)
    remove_constants(l1, l2)
    l3 = []
    var = f[0].arguments()
    l0 = map(str, l1)
    lv = map(str, var)
    lp = map(str, parameters)
    for i in l2:
        oper = i[0]
        if oper in ["log", "exp", "sin", "cos", "atan", "asin", "acos"]:
            a = i[1]
            if str(a) in lv:
                l3.append((oper, 'var[{}]'.format(lv.index(str(a)))))
            elif str(a) in lp:
                l3.append((oper, 'par[{}]'.format(lp.index(str(a)))))
            else:
                l3.append((oper, 'link[{}]'.format(l0.index(str(a)))))

        else:
            a = i[1]
            b = i[2]
            sa = str(a)
            sb = str(b)
            consta = False
            constb = False

            if sa in lv:
                aa = 'var[{}]'.format(lv.index(sa))
            elif sa in l0:
                aa = 'link[{}]'.format(l0.index(sa))
            elif sa in lp:
                aa = 'par[{}]'.format(lp.index(sa))
            else:
                consta = True
                aa = RR(a).str(truncate=False)
            if sb in lv:
                bb = 'var[{}]'.format(lv.index(sb))
            elif sb in l0:
                bb = 'link[{}]'.format(l0.index(sb))
            elif sb in lp:
                bb = 'par[{}]'.format(lp.index(sb))
            else:
                constb = True
                bb = RR(b).str(truncate=False)
            if consta:
                oper += '_c'
                if not oper == 'div':
                    bb, aa = aa, bb
            elif constb:
                oper += '_c'
            l3.append((oper, aa, bb))

    n = len(var)
    code = []

    l0 = lv + l0
    indices = [l0.index(str(i(*var))) + n for i in f]
    for i in range(1, n):
        aux = indices[i - 1] - n
        if aux < n:
            code.append('mpfrts_var_t(itd, var[{}], var[{}], i);'.format(
                aux, i))
        else:
            code.append('mpfrts_var_t(itd, link[{}], var[{}], i);'.format(
                aux - n, i))

    for i in range(len(l3)):
        el = l3[i]
        string = "mpfrts_"
        if el[0] == 'add':
            string += 'add_t(itd, ' + el[1] + ', ' + el[
                2] + ', link[{}], i);'.format(i)
        elif el[0] == 'add_c':
            string += 'add_t_c(itd, "' + el[2] + '", ' + el[
                1] + ', link[{}], i);'.format(i)
        elif el[0] == 'mul':
            string += 'mul_t(itd, ' + el[1] + ', ' + el[
                2] + ', link[{}], i);'.format(i)
        elif el[0] == 'mul_c':
            string += 'mul_t_c(itd, "' + el[2] + '", ' + el[
                1] + ', link[{}], i);'.format(i)
        elif el[0] == 'pow_c':
            string += 'pow_t_c(itd, ' + el[1] + ', "' + el[
                2] + '", link[{}], i);'.format(i)
        elif el[0] == 'div':
            string += 'div_t(itd, ' + el[2] + ', ' + el[
                1] + ', link[{}], i);'.format(i)
        elif el[0] == 'div_c':
            string += 'div_t_cv(itd, "' + el[2] + '", ' + el[
                1] + ', link[{}], i);'.format(i)
        elif el[0] == 'log':
            string += 'log_t(itd, ' + el[1] + ', link[{}], i);'.format(i)
        elif el[0] == 'exp':
            string += 'exp_t(itd, ' + el[1] + ', link[{}], i);'.format(i)
        elif el[0] == 'sin':
            string += 'sin_t(itd, ' + el[
                1] + ', link[{}], link[{}], i);'.format(i + 1, i)
        elif el[0] == 'cos':
            string += 'cos_t(itd, ' + el[
                1] + ', link[{}], link[{}], i);'.format(i - 1, i)
        elif el[0] == 'atan':
            indarg = l0.index(str(1 + l2[i][1]**2)) - n
            string += 'atan_t(itd, ' + el[
                1] + ', link[{}], link[{}], i);'.format(indarg, i)
        elif el[0] == 'asin':
            indarg = l0.index(str(sqrt(1 - l2[i][1]**2))) - n
            string += 'asin_t(itd, ' + el[
                1] + ', link[{}], link[{}], i);'.format(indarg, i)
        elif el[0] == 'acos':
            indarg = l0.index(str(-sqrt(1 - l2[i][1]**2))) - n
            string += 'acos_t(itd, ' + el[
                1] + ', link[{}], link[{}], i);'.format(indarg, i)
        code.append(string)

    VAR = n - 1
    PAR = len(parameters)
    TT = len(code) + 1 - VAR

    outfile = open(integrator, 'a')

    auxstring = """
    /****************************************************************************
    This file has been created by Sage for its use with TIDES
    *****************************************************************************/

    #include "mp_tides.h"

    long  function_iteration(iteration_data *itd, mpfr_t t, mpfr_t v[], mpfr_t p[], int ORDER, mpfr_t *cvfd)
    {

    int i;
    int NCONST = 0;
    mpfr_t ct[0];
    """

    outfile.write(auxstring)

    outfile.write("\n\tstatic int VARIABLES = {};\n".format(VAR))
    outfile.write("\tstatic int PARAMETERS = {};\n".format(PAR))
    outfile.write("\tstatic int LINKS = {};\n".format(TT))
    outfile.write('\tstatic int   FUNCTIONS        = 0;\n')
    outfile.write('\tstatic int   POS_FUNCTIONS[1] = {0};\n')
    outfile.write('\n\tinitialize_mp_case();\n')
    outfile.write('\n\tfor(i=0;  i<=ORDER; i++) {\n')
    for i in code:
        outfile.write('\t\t' + i + '\n')

    auxstring = """
    }
    write_mp_solution();
    clear_vpl();
    clear_cts();
    return NUM_COLUMNS;
}
    """
    outfile.write(auxstring)
    outfile.close()

    npar = len(parameter_values)
    outfile = open(driver, 'a')

    auxstring = """
    /****************************************************************************
    Driver file of the mp_tides program
    This file has been created automatically by Sage
    *****************************************************************************/

    #include "mpfr.h"
    #include "mp_tides.h"
    long  function_iteration(iteration_data *itd, mpfr_t t, mpfr_t v[], mpfr_t p[], int ORDER, mpfr_t *cvfd);

    int main() {

        int i;



    int nfun = 0;
    """
    outfile.write(auxstring)
    outfile.write('\tset_precision_digits({});'.format(dig))
    outfile.write('\n\tint npar = {};\n'.format(npar))
    outfile.write('\tmpfr_t p[npar];\n')
    outfile.write('\tfor(i=0; i<npar; i++) mpfr_init2(p[i], TIDES_PREC);\n')

    for i in range(npar):
        outfile.write('\tmpfr_set_str(p[{}], "{}", 10, TIDES_RND);\n'.format(
            i,
            RR(parameter_values[i]).str(truncate=False)))
    outfile.write('\tint nvar = {};\n\tmpfr_t v[nvar];\n'.format(VAR))
    outfile.write('\tfor(i=0; i<nvar; i++) mpfr_init2(v[i], TIDES_PREC);\n')
    for i in range(len(ics)):
        outfile.write('\tmpfr_set_str(v[{}], "{}", 10, TIDES_RND);\n'.format(
            i,
            RR(ics[i]).str(truncate=False)))
    outfile.write('\tmpfr_t tolrel, tolabs;\n')
    outfile.write('\tmpfr_init2(tolrel, TIDES_PREC); \n')
    outfile.write('\tmpfr_init2(tolabs, TIDES_PREC); \n')
    outfile.write('\tmpfr_set_str(tolrel, "{}", 10, TIDES_RND);\n'.format(
        RR(tolrel).str(truncate=False)))
    outfile.write('\tmpfr_set_str(tolabs, "{}", 10, TIDES_RND);\n'.format(
        RR(tolabs).str(truncate=False)))

    outfile.write('\tmpfr_t tini, dt; \n')
    outfile.write('\tmpfr_init2(tini, TIDES_PREC); \n')
    outfile.write('\tmpfr_init2(dt, TIDES_PREC); \n')

    outfile.write('\tmpfr_set_str(tini, "{}", 10, TIDES_RND);;\n'.format(
        RR(initial).str(truncate=False)))
    outfile.write('\tmpfr_set_str(dt, "{}", 10, TIDES_RND);\n'.format(
        RR(delta).str(truncate=False)))
    outfile.write('\tint nipt = {};\n'.format(floor(
        (final - initial) / delta)))
    outfile.write('\tFILE* fd = fopen("' + output + '", "w");\n')
    outfile.write(
        '\tmp_tides_delta(function_iteration, NULL, nvar, npar, nfun, v, p, tini, dt, nipt, tolrel, tolabs, NULL, fd);\n'
    )
    outfile.write('\tfclose(fd);\n\treturn 0;\n}')
    outfile.close()
Example #19
0
    def homogenize(self,n,newvar='h'):
        r"""
        Return the homogenization of ``self``. If ``self.domain()`` is a subscheme, the domain of
        the homogenized map is the projective embedding of ``self.domain()``. The domain and codomain
        can be homogenized at different coordinates: ``n[0]`` for the domain and ``n[1]`` for the codomain.

        INPUT:

        - ``newvar`` -- the name of the homogenization variable (only used when ``self.domain()`` is affine space)

        - ``n`` -- a tuple of nonnegative integers. If ``n`` is an integer, then the two values of
            the tuple are assumed to be the same.

        OUTPUT:

        - :class:`SchemMorphism_polynomial_projective_space`

        EXAMPLES::

            sage: A.<x,y>=AffineSpace(ZZ,2)
            sage: H=Hom(A,A)
            sage: f=H([(x^2-2)/x^5,y^2])
            sage: f.homogenize(2,'z')
            Scheme endomorphism of Projective Space of dimension 2 over Integer Ring
              Defn: Defined on coordinates by sending (x : y : z) to
                    (x^2*z^5 - 2*z^7 : x^5*y^2 : x^5*z^2)

        ::

            sage: A.<x,y>=AffineSpace(CC,2)
            sage: H=Hom(A,A)
            sage: f=H([(x^2-2)/(x*y),y^2-x])
            sage: f.homogenize((2,0),'z')
            Scheme endomorphism of Projective Space of dimension 2 over Complex
            Field with 53 bits of precision
              Defn: Defined on coordinates by sending (x : y : z) to
                    (x*y*z^2 : x^2*z^2 + (-2.00000000000000)*z^4 : x*y^3 - x^2*y*z)

        ::

            sage: A.<x,y>=AffineSpace(ZZ,2)
            sage: X=A.subscheme([x-y^2])
            sage: H=Hom(X,X)
            sage: f=H([9*y^2,3*y])
            sage: f.homogenize(2)
            Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 over Integer Ring defined by:
              -x1^2 + x0*x2
              Defn: Defined on coordinates by sending (x0 : x1 : x2) to
                    (9*x0*x2 : 3*x1*x2 : x2^2)

        ::

            sage: R.<t>=PolynomialRing(ZZ)
            sage: A.<x,y>=AffineSpace(R,2)
            sage: H=Hom(A,A)
            sage: f=H([(x^2-2)/y,y^2-x])
            sage: f.homogenize((2,0),'z')
            Scheme endomorphism of Projective Space of dimension 2 over Univariate
            Polynomial Ring in t over Integer Ring
              Defn: Defined on coordinates by sending (x : y : z) to
                    (y*z^2 : x^2*z + (-2)*z^3 : y^3 - x*y*z)

        ::

            sage: A.<x>=AffineSpace(QQ,1)
            sage: H=End(A)
            sage: f=H([x^2-1])
            sage: f.homogenize((1,0),'y')
            Scheme endomorphism of Projective Space of dimension 1 over Rational
            Field
              Defn: Defined on coordinates by sending (x : y) to
                    (y^2 : x^2 - y^2)
        """
        A=self.domain()
        B=self.codomain()
        N=A.ambient_space().dimension_relative()
        NB=B.ambient_space().dimension_relative()

        #it is possible to homogenize the domain and codomain at different coordinates
        if isinstance(n,(tuple,list)):
            ind=tuple(n)
        else:
            ind=(n,n)

        #homogenize the domain
        Vars=list(A.ambient_space().variable_names())
        Vars.insert(ind[0],newvar)
        S=PolynomialRing(A.base_ring(),Vars)

        #find the denominators if a rational function
        try:
            l=lcm([self[i].denominator() for i in range(N)])
        except Exception:  #no lcm
            l=prod([self[i].denominator() for i in range(N)])

        from sage.rings.polynomial.polynomial_ring import PolynomialRing_general
        from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic
        if self.domain().base_ring()==RealField() or self.domain().base_ring()==ComplexField():
            F=[S(((self[i]*l).numerator())._maxima_().divide(self[i].denominator())[0].sage()) for i in range(N)]
        elif isinstance(self.domain().base_ring(),(PolynomialRing_general,MPolynomialRing_generic)):
            F=[S(((self[i]*l).numerator())._maxima_().divide(self[i].denominator())[0].sage()) for i in range(N)]
        else:
            F=[S(self[i]*l) for i in range(N)]

        #homogenize the codomain
        F.insert(ind[1],S(l))
        d=max([F[i].degree() for i in range(N+1)])
        F=[F[i].homogenize(newvar)*S.gen(N)**(d-F[i].degree()) for i in range(N+1)]
        from sage.schemes.affine.affine_space import is_AffineSpace
        if is_AffineSpace(A)==True:
            from sage.schemes.projective.projective_space import ProjectiveSpace
            X=ProjectiveSpace(A.base_ring(),NB,Vars)
        else:
            X=A.projective_embedding(ind[1]).codomain()
            phi=S.hom(X.ambient_space().gens(),X.ambient_space().coordinate_ring())
            F=[phi(f) for f in F]
        H=Hom(X,X)
        return(H(F))
Example #20
0
def exponential_integral_1(x, n=0):
    r"""
    Returns the exponential integral `E_1(x)`. If the optional
    argument `n` is given, computes list of the first
    `n` values of the exponential integral
    `E_1(x m)`.

    The exponential integral `E_1(x)` is

    .. math::

                      E_1(x) = \int_{x}^{\infty} e^{-t}/t dt

    INPUT:

    - ``x`` -- a positive real number

    - ``n`` -- (default: 0) a nonnegative integer; if
      nonzero, then return a list of values ``E_1(x*m)`` for m =
      1,2,3,...,n. This is useful, e.g., when computing derivatives of
      L-functions.


    OUTPUT:

    A real number if n is 0 (the default) or a list of reals if n > 0.
    The precision is the same as the input, with a default of 53 bits
    in case the input is exact.

    EXAMPLES::

        sage: exponential_integral_1(2)
        0.0489005107080611
        sage: exponential_integral_1(2,4)  # abs tol 1e-18
        [0.0489005107080611, 0.00377935240984891, 0.000360082452162659, 0.0000376656228439245]
        sage: exponential_integral_1(40,5)
        [1.03677326145166e-19, 2.22854325868847e-37, 6.33732515501151e-55, 2.02336191509997e-72, 6.88522610630764e-90]
        sage: exponential_integral_1(0)
        +Infinity
        sage: r = exponential_integral_1(RealField(150)(1))
        sage: r
        0.21938393439552027367716377546012164903104729
        sage: parent(r)
        Real Field with 150 bits of precision
        sage: exponential_integral_1(RealField(150)(100))
        3.6835977616820321802351926205081189876552201e-46

    TESTS:

    The relative error for a single value should be less than 1 ulp::

        sage: for prec in [20..1000]:  # long time (22s on sage.math, 2013)
        ....:     R = RealField(prec)
        ....:     S = RealField(prec+64)
        ....:     for t in range(8):  # Try 8 values for each precision
        ....:         a = R.random_element(-15,10).exp()
        ....:         x = exponential_integral_1(a)
        ....:         y = exponential_integral_1(S(a))
        ....:         e = float(abs(S(x) - y)/x.ulp())
        ....:         if e >= 1.0:
        ....:             print "exponential_integral_1(%s) with precision %s has error of %s ulp"%(a, prec, e)

    The absolute error for a vector should be less than `c 2^{-p}`, where
    `p` is the precision in bits of `x` and `c = 2 max(1, exponential_integral_1(x))`::

        sage: for prec in [20..128]:  # long time (15s on sage.math, 2013)
        ....:     R = RealField(prec)
        ....:     S = RealField(prec+64)
        ....:     a = R.random_element(-15,10).exp()
        ....:     n = 2^ZZ.random_element(14)
        ....:     x = exponential_integral_1(a, n)
        ....:     y = exponential_integral_1(S(a), n)
        ....:     c = RDF(2 * max(1.0, y[0]))
        ....:     for i in range(n):
        ....:         e = float(abs(S(x[i]) - y[i]) << prec)
        ....:         if e >= c:
        ....:             print "exponential_integral_1(%s, %s)[%s] with precision %s has error of %s >= %s"%(a, n, i, prec, e, c)

    ALGORITHM: use the PARI C-library function ``eint1``.

    REFERENCE:

    - See Proposition 5.6.12 of Cohen's book "A Course in
      Computational Algebraic Number Theory".
    """
    if isinstance(x, Expression):
        if x.is_trivial_zero():
            from sage.rings.infinity import Infinity
            return Infinity
        else:
            raise NotImplementedError("Use the symbolic exponential integral " +
                                      "function: exp_integral_e1.")
    elif not is_inexact(x): # x is exact and not an expression
        if not x: # test if exact x == 0 quickly
            from sage.rings.infinity import Infinity
            return Infinity

    # else x is not an exact 0
    from sage.libs.pari.all import pari
    # Figure out output precision
    try:
        prec = parent(x).precision()
    except AttributeError:
        prec = 53

    R = RealField(prec)
    if n <= 0:
        # Add extra bits to the input.
        # (experimentally verified -- Jeroen Demeyer)
        inprec = prec + math.ceil(math.log(2*prec))
        x = RealField(inprec)(x)._pari_()
        return R(x.eint1())
    else:
        # PARI's algorithm is less precise as n grows larger:
        # add extra bits.
        # (experimentally verified -- Jeroen Demeyer)
        inprec = prec + 1 + math.ceil(1.4427 * math.log(n))
        x = RealField(inprec)(x)._pari_()
        return [R(z) for z in x.eint1(n)]
Example #21
0
    def _sage_(self):
        r"""
        Convert a maple expression back to a Sage expression.

        This currently does not implement a parser for the Maple output language,
        therefore only very simple expressions will convert successfully.

        REFERENCE:

        https://www.asc.tuwien.ac.at/compmath/download/Monagan_Maple_Programming.pdf

        EXAMPLES::

            sage: m = maple('x^2 + 5*y')        # optional - maple
            sage: m.sage()                      # optional - maple
            x^2 + 5*y
            sage: m._sage_()                    # optional - maple
            x^2 + 5*y

            sage: m = maple('sin(sqrt(1-x^2)) * (1 - cos(1/x))^2')  # optional - maple
            sage: m.sage()                                          # optional - maple
            (cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))

        Some matrices can be converted back::

            sage: m = matrix(2, 2, [1, 2, x, 3])    # optional - maple
            sage: mm = maple(m)                     # optional - maple
            sage: mm.sage() == m                    # optional - maple
            True

        Some vectors can be converted back::

            sage: m = vector([1, x, 2, 3])          # optional - maple
            sage: mm = maple(m)                     # optional - maple
            sage: mm.sage() == m                    # optional - maple
            True

        Integers and rationals are converted as such::

            sage: maple(33).sage().parent()         # optional - maple
            Integer Ring
            sage: maple(191/5).sage().parent()      # optional - maple
            Rational Field

        Sets, lists, sequences::

            sage: maple("[4,5,6]").sage()           # optional - maple
            [4, 5, 6]
            sage: maple({14,33,6}).sage()           # optional - maple
            {6, 14, 33}
            sage: maple("seq(i**2,i=1..5)").sage()  # optional - maple
            (1, 4, 9, 16, 25)

        Strings::

            sage: maple('"banane"').sage()          # optional - maple
            '"banane"'

        Floats::

            sage: Z3 = maple('evalf(Zeta(3))')   # optional - maple
            sage: Z3.sage().parent()             # optional - maple
            Real Field with 53 bits of precision

            sage: sq5 = maple('evalf(sqrt(5),100)')   # optional - maple
            sage: sq5 = sq5.sage(); sq5               # optional - maple
            2.23606797749978969640...
            sage: sq5.parent()                        # optional - maple
            Real Field with 332 bits of precision

        Functions are not yet converted back correctly::

            sage: maple(hypergeometric([3,4],[5],x))  # optional - maple
            hypergeom([3, 4],[5],x)
            sage: _.sage()                # known bug # optional - maple
            hypergeometric((3, 4), (5,), x)
        """
        from sage.matrix.constructor import matrix
        from sage.modules.free_module_element import vector
        from sage.rings.integer_ring import ZZ
        # The next few lines are a very crude excuse for a maple "parser"
        maple_type = repr(self.whattype())
        result = repr(self)
        result = result.replace("Pi", "pi")
        if maple_type == 'symbol':  # pi
            pass  # left to symbolic ring
        elif maple_type == 'string':  # "banane"
            return result
        elif maple_type == 'exprseq':  # 2, 2
            n = self.parent()(f"[{self._name}]").nops()._sage_()
            return tuple(self[i] for i in range(1, n + 1))
        elif maple_type == 'set':  # {1, 2}
            n = self.nops()._sage_()
            return set(self.op(i)._sage_() for i in range(1, n + 1))
        elif maple_type == 'list':  # [1, 2]
            n = self.nops()._sage_()
            return [self.op(i)._sage_() for i in range(1, n + 1)]
        elif maple_type == "Matrix":  # Matrix(2, 2, [[1,2],[3,4]])
            mn = self.op(1)
            m = mn[1]._sage_()
            n = mn[2]._sage_()
            coeffs = [
                self[i + 1, j + 1]._sage_() for i in range(m) for j in range(n)
            ]
            return matrix(m, n, coeffs)
        elif maple_type[:6] == "Vector":  # Vector[row](3, [4,5,6])
            n = self.op(1)._sage_()
            return vector([self[i + 1]._sage_() for i in range(n)])
        elif maple_type == 'integer':
            return ZZ(result)
        elif maple_type == 'fraction':
            return self.op(1)._sage_() / self.op(2)._sage_()
        elif maple_type == "function":
            pass  # TODO : here one should translate back function names
        elif maple_type == "float":
            from sage.rings.real_mpfr import RealField
            mantissa = len(repr(self.op(1)))
            prec = max(53, (mantissa * 13301) // 4004)
            R = RealField(prec)
            return R(result)
        elif maple_type == '`=`':  # (1, 1) = 2
            return (self.op(1)._sage_() == self.op(2)._sage())
        try:
            from sage.symbolic.all import SR
            return SR(result)
        except Exception:
            raise NotImplementedError("Unable to parse Maple output: %s" %
                                      result)