Example #1
0
    def approximate(self, x, parent=None):
        r"""
        Approximate using de Bruijn's formula
        
        .. math::
        
             \rho(x) \sim \frac{exp(-x \xi + Ei(\xi))}{\sqrt{2\pi x}\xi} 
        
        which is asymptotically equal to Dickman's function, and is much
        faster to compute.
        
        REFERENCES:

        - N. De Bruijn, "The Asymptotic behavior of a function
          occurring in the theory of primes." J. Indian Math Soc. v 15.
          (1951)
        
        EXAMPLES::
        
            sage: dickman_rho.approximate(10)
            2.41739196365564e-11
            sage: dickman_rho(10)
            2.77017183772596e-11
            sage: dickman_rho.approximate(1000)
            4.32938809066403e-3464
        """
        log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi
        x = float(x)
        xi = log(x)
        y = (exp(xi) - 1.0) / xi - x
        while abs(y) > 1e-12:
            dydxi = (exp(xi) * (xi - 1.0) + 1.0) / (xi * xi)
            xi -= y / dydxi
            y = (exp(xi) - 1.0) / xi - x
        return (-x * xi + RR(xi).eint()).exp() / (sqrt(2 * pi * x) * xi)
Example #2
0
    def perpendicular_bisector(self): #UHP
        r"""
        Return the perpendicular bisector of the hyperbolic geodesic ``self``
        if that geodesic has finite length.

        EXAMPLES::

            sage: UHP = HyperbolicPlane().UHP()
            sage: g = UHP.random_geodesic()
            sage: h = g.perpendicular_bisector()
            sage: c = lambda x: x.coordinates()
            sage: bool(c(g.intersection(h)[0]) - c(g.midpoint()) < 10**-9)
            True

        Infinite geodesics cannot be bisected::

            sage: UHP.get_geodesic(0, 1).perpendicular_bisector()
            Traceback (most recent call last):
            ...
            ValueError: the length must be finite
        """
        if self.length() == infinity:
            raise ValueError("the length must be finite")
        start = self._start.coordinates()
        d = self._model._dist_points(start, self._end.coordinates()) / 2
        S = self.complete()._to_std_geod(start)
        T1 = matrix([[exp(d/2), 0], [0, exp(-d/2)]])
        s2 = sqrt(2) * 0.5
        T2 = matrix([[s2, -s2], [s2, s2]])
        isom_mtrx = S.inverse() * (T1 * T2) * S # We need to clean this matrix up.
        if (isom_mtrx - isom_mtrx.conjugate()).norm() < 5*EPSILON: # Imaginary part is small.
            isom_mtrx = (isom_mtrx + isom_mtrx.conjugate()) / 2 # Set it to its real part.
        H = self._model.get_isometry(isom_mtrx)
        return self._model.get_geodesic(H(self._start), H(self._end))
Example #3
0
def circle_image(A, B):
    G = Graphics()
    G += circle((0, 0), 1, color='grey')
    from collections import defaultdict
    tmp = defaultdict(int)
    for a in A:
        for j in range(a):
            if gcd(j, a) == 1:
                rational = Rational(j) / Rational(a)
                tmp[(rational.numerator(), rational.denominator())] += 1

    for b in B:
        for j in range(b):
            if gcd(j, b) == 1:
                rational = Rational(j) / Rational(b)
                tmp[(rational.numerator(), rational.denominator())] -= 1
    C = ComplexField()
    for val in tmp:
        if tmp[val] > 0:
            G += text(str(tmp[val]),
                      exp(C(-.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color="green")
        if tmp[val] < 0:
            G += text(str(abs(tmp[val])),
                      exp(C(.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color="blue")
    return G
Example #4
0
    def approximate(self, x, parent=None):
        r"""
        Approximate using de Bruijn's formula

        .. math::

             \rho(x) \sim \frac{exp(-x \xi + Ei(\xi))}{\sqrt{2\pi x}\xi}

        which is asymptotically equal to Dickman's function, and is much
        faster to compute.

        REFERENCES:

        - N. De Bruijn, "The Asymptotic behavior of a function
          occurring in the theory of primes." J. Indian Math Soc. v 15.
          (1951)

        EXAMPLES::

            sage: dickman_rho.approximate(10)
            2.41739196365564e-11
            sage: dickman_rho(10)
            2.77017183772596e-11
            sage: dickman_rho.approximate(1000)
            4.32938809066403e-3464
        """
        log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi
        x = float(x)
        xi = log(x)
        y = (exp(xi)-1.0)/xi - x
        while abs(y) > 1e-12:
            dydxi = (exp(xi)*(xi-1.0) + 1.0)/(xi*xi)
            xi -= y/dydxi
            y = (exp(xi)-1.0)/xi - x
        return (-x*xi + RR(xi).eint()).exp() / (sqrt(2*pi*x)*xi)
Example #5
0
def error_function(model, N, x0):
    """
    Compute the error function of a truncated ODE.

    INPUT:

    - ``model`` -- Polynomial ODE or string containing the model in text format

    - ``N`` -- integer; truncation order

    - ``x0`` -- list; initial point

    OUTPUT:

    - ``Ts`` -- convergence time computed from the reduced quadratic system

    - ``error`` -- function of `t`, the estimated truncation error in the supremum norm

    EXAMPLES::

        sage: from carlin.transformation import error_function
        sage: from carlin.library import quadratic_scalar as P
        sage: Ts, error = error_function(P(0.5, 2), 2, [0, 0.5])
        sage: Ts
        0.8109...
        sage: error
        0.5*(2.0*e^(0.5*t) - 2.0)^2*e^(0.5*t)/(-2.0*e^(0.5*t) + 3.0)
    """
    from numpy.linalg import norm
    from sage.symbolic.ring import SR

    if isinstance(model, str):
        [F, n, k] = get_Fj_from_model(model)
    elif isinstance(model, PolynomialODE):
        [F, n, k] = get_Fj_from_model(model.funcs(), model.dim(),
                                      model.degree())

    [Fquad, nquad, kquad] = quadratic_reduction(F, n, k)

    ch = characteristics(Fquad, nquad, kquad)

    norm_F1_tilde, norm_F2_tilde = ch['norm_Fi_inf']

    x0_hat = [kron_power(x0, i + 1) for i in range(k - 1)]

    #transform to flat list
    x0_hat = [item for sublist in x0_hat for item in sublist]

    norm_x0_hat = norm(x0_hat, ord=inf)
    beta0 = ch['beta0_const'] * norm_x0_hat
    Ts = 1 / norm_F1_tilde * log(1 + 1 / beta0)

    t = SR.var('t')
    error = norm_x0_hat * exp(
        norm_F1_tilde * t) / (1 + beta0 - beta0 * exp(norm_F1_tilde * t)) * (
            beta0 * (exp(norm_F1_tilde * t) - 1))**N
    return [Ts, error]
Example #6
0
    def _eval_(self, x, y):
        """
        EXAMPLES::

            sage: gamma_inc(2.,0)
            1.00000000000000
            sage: gamma_inc(2,0)
            1
            sage: gamma_inc(1/2,2)
            -(erf(sqrt(2)) - 1)*sqrt(pi)
            sage: gamma_inc(1/2,1)
            -(erf(1) - 1)*sqrt(pi)
            sage: gamma_inc(1/2,0)
            sqrt(pi)
            sage: gamma_inc(x,0)
            gamma(x)
            sage: gamma_inc(1,2)
            e^(-2)
            sage: gamma_inc(0,2)
            -Ei(-2)
        """
        if not isinstance(x, Expression) and not isinstance(y, Expression) and \
               (is_inexact(x) or is_inexact(y)):
            x, y = coercion_model.canonical_coercion(x, y)
            return self._evalf_(x, y, parent(x))

        if y == 0:
            return gamma(x)
        if x == 1:
            return exp(-y)
        if x == 0:
            return -Ei(-y)
        if x == Rational(1) / 2:  #only for x>0
            return sqrt(pi) * (1 - erf(sqrt(y)))
        return None
Example #7
0
    def partition_function(self, beta, epsilon):
        r"""
        Return the partition function of ``self``.

        The partition function of a 6 vertex model is defined by:

        .. MATH::

            Z = \sum_{\nu} e^{-\beta E(\nu)}

        where we sum over all configurations and `E` is the energy function.
        The constant `\beta` is known as the *inverse temperature* and is
        equal to `1 / k_B T` where `k_B` is Boltzmann's constant and `T` is
        the system's temperature.

        INPUT:

        - ``beta`` -- the inverse temperature constant `\beta`
        - ``epsilon`` -- the energy constants, see
          :meth:`~sage.combinat.six_vertex_model.SixVertexConfiguration.energy()`

        EXAMPLES::

            sage: M = SixVertexModel(3, boundary_conditions='ice')
            sage: M.partition_function(2, [1,2,1,2,1,2])
            e^(-24) + 2*e^(-28) + e^(-30) + 2*e^(-32) + e^(-36)

        REFERENCES:

        :wikipedia:`Partition_function_(statistical_mechanics)`
        """
        from sage.functions.log import exp
        return sum(exp(-beta * nu.energy(epsilon)) for nu in self)
Example #8
0
    def partition_function(self, beta, epsilon):
        r"""
        Return the partition function of ``self``.

        The partition function of a 6 vertex model is defined by:

        .. MATH::

            Z = \sum_{\nu} e^{-\beta E(\nu)}

        where we sum over all configurations and `E` is the energy function.
        The constant `\beta` is known as the *inverse temperature* and is
        equal to `1 / k_B T` where `k_B` is Boltzmann's constant and `T` is
        the system's temperature.

        INPUT:

        - ``beta`` -- the inverse temperature constant `\beta`
        - ``epsilon`` -- the energy constants, see
          :meth:`~sage.combinat.six_vertex_model.SixVertexConfiguration.energy()`

        EXAMPLES::

            sage: M = SixVertexModel(3, boundary_conditions='ice')
            sage: M.partition_function(2, [1,2,1,2,1,2])
            e^(-24) + 2*e^(-28) + e^(-30) + 2*e^(-32) + e^(-36)

        REFERENCES:

        :wikipedia:`Partition_function_(statistical_mechanics)`
        """
        from sage.functions.log import exp
        return sum(exp(-beta * nu.energy(epsilon)) for nu in self)
Example #9
0
    def _eval_(self, x, y):
        """
        EXAMPLES::

            sage: gamma_inc(2.,0)
            1.00000000000000
            sage: gamma_inc(2,0)
            1
            sage: gamma_inc(1/2,2)
            -(erf(sqrt(2)) - 1)*sqrt(pi)
            sage: gamma_inc(1/2,1)
            -(erf(1) - 1)*sqrt(pi)
            sage: gamma_inc(1/2,0)
            sqrt(pi)
            sage: gamma_inc(x,0)
            gamma(x)
            sage: gamma_inc(1,2)
            e^(-2)
            sage: gamma_inc(0,2)
            -Ei(-2)
        """
        if not isinstance(x, Expression) and not isinstance(y, Expression) and \
               (is_inexact(x) or is_inexact(y)):
            x, y = coercion_model.canonical_coercion(x, y)
            return self._evalf_(x, y, parent(x))

        if y == 0:
            return gamma(x)
        if x == 1:
            return exp(-y)
        if x == 0:
            return -Ei(-y)
        if x == Rational(1)/2: #only for x>0
            return sqrt(pi)*(1-erf(sqrt(y)))
        return None
Example #10
0
    def xseries(self, all_conjugates=True):
        r"""Returns the corresponding x-series.

        Parameters
        ----------
        all_conjugates : bool
            (default: True) If ``True``, returns all conjugates
            x-representations of this Puiseux t-series. If ``False``,
            only returns one representative.

        Returns
        -------
        list
            List of PuiseuxXSeries representations of this PuiseuxTSeries.

        """
        # obtain relevant rings:
        #   o R = parent ring of curve
        #   o L = parent ring of T-series
        #   o S = temporary polynomial ring over base ring of T-series
        #   o P = Puiseux series ring
        L = self.ypart.parent()
        t = L.gen()
        S = L.base_ring()['z']
        z = S.gen()

        R = self.f.parent()
        x, y = R.gens()
        P = PuiseuxSeriesRing(L.base_ring(), str(x))
        x = P.gen()

        # given x = alpha + lambda*t^e solve for t. this involves finding an
        # e-th root of either (1/lambda) or of lambda, depending on e's sign
        e = self.ramification_index
        lamb = S(self.xcoefficient)
        order = self.order
        if e > 0:
            phi = lamb * z**e - 1
        else:
            phi = z**abs(e) - lamb
        mu = phi.roots(QQbar, multiplicities=False)[0]

        if all_conjugates:
            conjugates = [
                mu * exp(2 * pi * I * k / abs(e)) for k in range(abs(e))
            ]
        else:
            conjugates = [mu]
        map(lambda x: x.exactify(), conjugates)

        # determine the resulting x-series
        xseries = []
        for c in conjugates:
            t = self.ypart.parent().gen()
            fconj = self.ypart(c * t)
            p = P(fconj(x**(QQ(1) / e)))
            p = p.add_bigoh(QQ(order + 1) / abs(e))
            xseries.append(p)
        return xseries
Example #11
0
    def _eval_(self, n, z):
        """
        EXAMPLES::

            sage: exp_integral_e(1.0, x)
            exp_integral_e(1.00000000000000, x)
            sage: exp_integral_e(x, 1.0)
            exp_integral_e(x, 1.00000000000000)
            sage: exp_integral_e(1.0, 1.0)
            0.219383934395520

        """
        if not isinstance(n, Expression) and not isinstance(z, Expression) and \
               (is_inexact(n) or is_inexact(z)):
            coercion_model = sage.structure.element.get_coercion_model()
            n, z = coercion_model.canonical_coercion(n, z)
            return self._evalf_(n, z, parent(n))

        z_zero = False
        # special case: z == 0 and n > 1
        if isinstance(z, Expression):
            if z.is_trivial_zero():
                z_zero = True # for later
                if n > 1:
                    return 1/(n-1)
        else:
            if not z:
                z_zero = True
                if n > 1:
                    return 1/(n-1)

        # special case: n == 0
        if isinstance(n, Expression):
            if n.is_trivial_zero():
                if z_zero:
                    return None
                else:
                    return exp(-z)/z
        else:
            if not n:
                if z_zero:
                    return None
                else:
                    return exp(-z)/z

        return None # leaves the expression unevaluated
Example #12
0
    def _eval_(self, n, z):
        """
        EXAMPLES::

            sage: exp_integral_e(1.0, x)
            exp_integral_e(1.00000000000000, x)
            sage: exp_integral_e(x, 1.0)
            exp_integral_e(x, 1.00000000000000)
            sage: exp_integral_e(3, 0)
            1/2

        TESTS:

        Check that Python ints work (:trac:`14766`)::

            sage: exp_integral_e(int(3), 0)
            1/2
        """
        z_zero = False
        # special case: z == 0 and n > 1
        if isinstance(z, Expression):
            if z.is_trivial_zero():
                z_zero = True  # for later
                if n > 1:
                    return 1 / (n - 1)
        else:
            if not z:
                z_zero = True
                if n > 1:
                    return 1 / (n - 1)

        # special case: n == 0
        if isinstance(n, Expression):
            if n.is_trivial_zero():
                if z_zero:
                    return None
                else:
                    return exp(-z) / z
        else:
            if not n:
                if z_zero:
                    return None
                else:
                    return exp(-z) / z

        return None  # leaves the expression unevaluated
Example #13
0
    def _eval_(self, n, z):
        """
        EXAMPLES::

            sage: exp_integral_e(1.0, x)
            exp_integral_e(1.00000000000000, x)
            sage: exp_integral_e(x, 1.0)
            exp_integral_e(x, 1.00000000000000)
            sage: exp_integral_e(3, 0)
            1/2

        TESTS:

        Check that Python ints work (:trac:`14766`)::

            sage: exp_integral_e(int(3), 0)
            1/2
        """
        z_zero = False
        # special case: z == 0 and n > 1
        if isinstance(z, Expression):
            if z.is_trivial_zero():
                z_zero = True # for later
                if n > 1:
                    return 1/(n-1)
        else:
            if not z:
                z_zero = True
                if n > 1:
                    return 1/(n-1)

        # special case: n == 0
        if isinstance(n, Expression):
            if n.is_trivial_zero():
                if z_zero:
                    return None
                else:
                    return exp(-z)/z
        else:
            if not n:
                if z_zero:
                    return None
                else:
                    return exp(-z)/z

        return None # leaves the expression unevaluated
Example #14
0
    def _eval_(self, n, z):
        """
        EXAMPLES::

            sage: exp_integral_e(1.0, x)
            exp_integral_e(1.00000000000000, x)
            sage: exp_integral_e(x, 1.0)
            exp_integral_e(x, 1.00000000000000)
            sage: exp_integral_e(1.0, 1.0)
            0.219383934395520

        """
        if not isinstance(n, Expression) and not isinstance(z, Expression) and \
               (is_inexact(n) or is_inexact(z)):
            coercion_model = sage.structure.element.get_coercion_model()
            n, z = coercion_model.canonical_coercion(n, z)
            return self._evalf_(n, z, parent(n))

        z_zero = False
        # special case: z == 0 and n > 1
        if isinstance(z, Expression):
            if z.is_trivial_zero():
                z_zero = True  # for later
                if n > 1:
                    return 1 / (n - 1)
        else:
            if not z:
                z_zero = True
                if n > 1:
                    return 1 / (n - 1)

        # special case: n == 0
        if isinstance(n, Expression):
            if n.is_trivial_zero():
                if z_zero:
                    return None
                else:
                    return exp(-z) / z
        else:
            if not n:
                if z_zero:
                    return None
                else:
                    return exp(-z) / z

        return None  # leaves the expression unevaluated
Example #15
0
    def xseries(self, all_conjugates=True):
        r"""Returns the corresponding x-series.

        Parameters
        ----------
        all_conjugates : bool
            (default: True) If ``True``, returns all conjugates
            x-representations of this Puiseux t-series. If ``False``,
            only returns one representative.

        Returns
        -------
        list
            List of PuiseuxXSeries representations of this PuiseuxTSeries.

        """
        # obtain relevant rings:
        #   o R = parent ring of curve
        #   o L = parent ring of T-series
        #   o S = temporary polynomial ring over base ring of T-series
        #   o P = Puiseux series ring
        L = self.ypart.parent()
        t = L.gen()
        S = L.base_ring()['z']
        z = S.gen()

        R = self.f.parent()
        x,y = R.gens()
        P = PuiseuxSeriesRing(L.base_ring(), str(x))
        x = P.gen()

        # given x = alpha + lambda*t^e solve for t. this involves finding an
        # e-th root of either (1/lambda) or of lambda, depending on e's sign
        e = self.ramification_index
        lamb = S(self.xcoefficient)
        order = self.order
        if e > 0:
            phi = lamb*z**e - 1
        else:
            phi = z**abs(e) - lamb
        mu = phi.roots(QQbar, multiplicities=False)[0]

        if all_conjugates:
            conjugates = [mu*exp(2*pi*I*k/abs(e)) for k in range(abs(e))]
        else:
            conjugates = [mu]
        map(lambda x: x.exactify(), conjugates)

        # determine the resulting x-series
        xseries = []
        for c in conjugates:
            t = self.ypart.parent().gen()
            fconj = self.ypart(c*t)
            p = P(fconj(x**(QQ(1)/e)))
            p = p.add_bigoh(QQ(order+1)/abs(e))
            xseries.append(p)
        return xseries
Example #16
0
def get_bound_poly(F, prec=53, norm_type='norm', emb=None):
    """
    The hyperbolic distance from `j` which must contain the smallest poly.

    This defines the maximum possible distance from `j` to the `z_0` covariant
    in the hyperbolic 3-space for which the associated `F` could have smaller
    coefficients.

    INPUT:

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

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

    - ``norm_type`` -- string, either norm or height

    - ``emb`` -- embedding into CC

    OUTPUT: a positive real number

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import get_bound_poly
        sage: R.<x,y> = QQ[]
        sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3
        sage: get_bound_poly(F) # tol 1e-12
        28.0049336543295
        sage: get_bound_poly(F, norm_type='height') # tol 1e-11
        111.890642019092
    """
    def coshdelta(z):
        #The cosh of the hyperbolic distance from z = t+uj to j
        return (z.norm() + 1) / (2 * z.imag())

    if F.base_ring() != ComplexField(prec=prec):
        if emb is None:
            compF = F.change_ring(ComplexField(prec=prec))
        else:
            compF = F.change_ring(emb)
    else:
        compF = F
    n = F.degree()
    assert (n > 2), "degree 2 polynomial"

    z0F, thetaF = covariant_z0(compF, prec=prec, emb=emb)
    if norm_type == 'norm':
        #euclidean norm squared
        normF = (sum([abs(i)**2 for i in compF.coefficients()]))
        target = (2**(n - 1)) * normF / thetaF
    elif norm_type == 'height':
        hF = exp(max([c.global_height(prec=prec)
                      for c in F.coefficients()]))  # height
        target = (2**(n - 1)) * (n + 1) * (hF**2) / thetaF
    else:
        raise ValueError('type must be norm or height')
    return cosh(epsinv(F, target, prec=prec))
Example #17
0
def random_polygon_2d(num_vertices, **kwargs):
    r"""Generate a random polygon (2d) obtained by uniform sampling over the unit circle.

    INPUT:

    * ``num_vertices`` - the number of vertices of the generated polyhedron.

    * ``base_ring`` - (default: ``QQ``). The ring passed to the constructor of Polyhedron. 
    alid options are ``QQ`` and ``RDF``.

    * ``scale`` - (default: 1). The scale factor; each vertex is chosen randomly from the unit circle, 
    and then multiplied by scale.

    OUTPUT:

    A random polygon (object of type Polyhedron), whose vertices belong to a circle
    of radius ``scale``.

    NOTES:

    - If ``RDF`` is chosen as ``base_ring``, sometimes there are exceptions related 
    to numerical errors, and show up as ``'FrozenSet'`` exceptions. This occurs 
    particularly frequently for a large number of vertices (more than 30).
    """
    from sage.functions.log import exp
    from sage.symbolic.constants import pi
    from sage.symbolic.all import I

    base_ring = kwargs['base_ring'] if 'base_ring' in kwargs else QQ

    scale = kwargs['scale'] if 'scale' in kwargs else 1

    angles = [
        random.uniform(0, 2 * pi.n(digits=5)) for i in range(num_vertices)
    ]
    vert = [[
        scale * exp(I * angles[i]).real(), scale * exp(I * angles[i]).imag()
    ] for i in range(num_vertices)]

    return Polyhedron(vertices=vert, base_ring=base_ring)
 def eval(self, tau, prec=10):
     """
     Evaluates the QExpansion with prec many terms at tau. Prec can be set to 'max', to use all available Fourier coefficients.
     """
     if prec == 'max':
         prec = self.prec
     pi = ComplexField(53).pi()
     I = ComplexField(53).gen()
     return sum([
         self[n] *
         ComplexField(53)(exp(2 * pi * I * tau * n / self.param_level))
         for n in range(prec)
     ])
Example #19
0
    def _eval_(self, n, x):
        """
        EXAMPLES::

            sage: bessel_K(1,0)
            bessel_K(1, 0)
            sage: bessel_K(1.0, 0.0)
            +infinity
            sage: bessel_K(-1, 1).n(128)
            0.60190723019723457473754000153561733926
        """
        # special identity
        if n == Integer(1) / Integer(2) and x > 0:
            return sqrt(pi / 2) * exp(-x) * x**(-Integer(1) / Integer(2))
Example #20
0
    def _eval_(self, n, x):
        """
        EXAMPLES::

            sage: bessel_K(1,0)
            bessel_K(1, 0)
            sage: bessel_K(1.0, 0.0)
            +infinity
            sage: bessel_K(-1, 1).n(128)
            0.60190723019723457473754000153561733926
        """
        # special identity
        if n == Integer(1) / Integer(2) and x > 0:
            return sqrt(pi / 2) * exp(-x) * x ** (-Integer(1) / Integer(2))
Example #21
0
def circle_image(A,B):
    G = Graphics()
    G += circle((0,0), 1 , color = 'grey')
    from collections import defaultdict
    tmp = defaultdict(int)
    for a in A:
        for j in range(a):
            if gcd(j,a) == 1:
                rational = Rational(j)/Rational(a)
                tmp[(rational.numerator(),rational.denominator())] += 1
    
    for b in B:
        for j in range(b):
            if gcd(j,b) == 1:
                rational = Rational(j)/Rational(b)
                tmp[(rational.numerator(),rational.denominator())] -= 1
    C = ComplexField()
    for val in tmp:
        if tmp[val] > 0:
            G += text(str(tmp[val]),exp(C(2*3.14159*I*val[0]/val[1])), fontsize = 30, axes = False, color = "green")
        if tmp[val] < 0:
            G += text(str(abs(tmp[val])),exp(C(2*3.14159*I*val[0]/val[1])), fontsize = 30, axes = False, color = "red")
    return G
    def perpendicular_bisector(self):  # UHP
        r"""
        Return the perpendicular bisector of the hyperbolic geodesic ``self``
        if that geodesic has finite length.

        EXAMPLES::

            sage: UHP = HyperbolicPlane().UHP()
            sage: g = UHP.random_geodesic()
            sage: h = g.perpendicular_bisector()
            sage: c = lambda x: x.coordinates()
            sage: bool(c(g.intersection(h)[0]) - c(g.midpoint()) < 10**-9)
            True

        Infinite geodesics cannot be bisected::

            sage: UHP.get_geodesic(0, 1).perpendicular_bisector()
            Traceback (most recent call last):
            ...
            ValueError: the length must be finite
        """
        if self.length() == infinity:
            raise ValueError("the length must be finite")
        start = self._start.coordinates()
        d = self._model._dist_points(start, self._end.coordinates()) / 2
        S = self.complete()._to_std_geod(start)
        T1 = matrix([[exp(d / 2), 0], [0, exp(-d / 2)]])
        s2 = sqrt(2) * 0.5
        T2 = matrix([[s2, -s2], [s2, s2]])
        isom_mtrx = S.inverse() * (T1 * T2) * S
        # We need to clean this matrix up.
        if (isom_mtrx - isom_mtrx.conjugate()).norm() < 5 * EPSILON:
            # Imaginary part is small.
            isom_mtrx = (isom_mtrx + isom_mtrx.conjugate()) / 2
            # Set it to its real part.
        H = self._model.get_isometry(isom_mtrx)
        return self._model.get_geodesic(H(self._start), H(self._end))
Example #23
0
 def _derivative_(self, x, diff_param=None):
     """
     EXAMPLES::
     
         sage: Ei(x).diff(x)
         e^x/x
         sage: Ei(x).diff(x).subs(x=1)
         e
         sage: Ei(x^2).diff(x)
         2*e^(x^2)/x
         sage: f = function('f')
         sage: Ei(f(x)).diff(x)
         e^f(x)*D[0](f)(x)/f(x)
     """
     return exp(x) / x
Example #24
0
    def _derivative_(self, x, diff_param=None):
        """
        EXAMPLES::

            sage: Ei(x).diff(x)
            e^x/x
            sage: Ei(x).diff(x).subs(x=1)
            e
            sage: Ei(x^2).diff(x)
            2*e^(x^2)/x
            sage: f = function('f')
            sage: Ei(f(x)).diff(x)
            e^f(x)*D[0](f)(x)/f(x)
        """
        return exp(x)/x
Example #25
0
def circle_image(A, B):
    G = Graphics()
    G += circle((0, 0), 1, color='black', thickness=3)
    G += circle(
        (0, 0), 1.4, color='black', alpha=0
    )  # This adds an invisible framing circle to the plot, which protects the aspect ratio from being skewed.
    from collections import defaultdict
    tmp = defaultdict(int)
    for a in A:
        for j in range(a):
            if gcd(j, a) == 1:
                rational = Rational(j) / Rational(a)
                tmp[(rational.numerator(), rational.denominator())] += 1

    for b in B:
        for j in range(b):
            if gcd(j, b) == 1:
                rational = Rational(j) / Rational(b)
                tmp[(rational.numerator(), rational.denominator())] -= 1
    C = ComplexField()
    color1 = (41 / 255, 95 / 255, 45 / 255)
    color2 = (0 / 255, 0 / 255, 150 / 255)
    for val in tmp:
        if tmp[val] > 0:
            G += text(str(tmp[val]),
                      exp(C(-.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color=color1)
        if tmp[val] < 0:
            G += text(str(abs(tmp[val])),
                      exp(C(.2 + 2 * 3.14159 * I * val[0] / val[1])),
                      fontsize=30,
                      axes=False,
                      color=color2)
    return G
Example #26
0
    def _derivative_(self, z, diff_param=None):
        """
        The derivative of `E_1(z)` is `-e^{-z}/z`. See [AS], 5.1.26.

        EXAMPLES::

            sage: x = var('x')
            sage: f = exp_integral_e1(x)
            sage: f.diff(x)
            -e^(-x)/x

            sage: f = exp_integral_e1(x^2)
            sage: f.diff(x)
            -2*e^(-x^2)/x

        """
        return -exp(-z)/z
Example #27
0
    def _derivative_(self, z, diff_param=None):
        """
        The derivative of `E_1(z)` is `-e^{-z}/z`. See [AS], 5.1.26.

        EXAMPLES::

            sage: x = var('x')
            sage: f = exp_integral_e1(x)
            sage: f.diff(x)
            -e^(-x)/x

            sage: f = exp_integral_e1(x^2)
            sage: f.diff(x)
            -2*e^(-x^2)/x

        """
        return -exp(-z) / z
Example #28
0
File: lwe.py Project: Etn40ff/sage
    def __getattr__(self, name):
        """
        EXAMPLE::

            sage: from sage.crypto.lwe import DiscreteGaussianSamplerRejection
            sage: DiscreteGaussianSamplerRejection(3.0).foo
            Traceback (most recent call last):
            ...
            AttributeError: 'DiscreteGaussianSamplerRejection' object has no attribute 'foo'
        """
        if name == "rho":
            # we delay the creation of rho until we actually need it
            R = RealField(self.precision)
            self.rho = [round(self.max_precs * exp((-(R(x) / R(self.stddev))**2)/R(2))) for x in range(0,self.upper_bound)]
            self.rho[0] = self.rho[0] / 2
            return self.rho
        else:
            raise AttributeError("'%s' object has no attribute '%s'"%(self.__class__.__name__, name))
Example #29
0
    def _derivative_(self, x, diff_param=None):
        """
        Derivative of erf function

        EXAMPLES::

            sage: erf(x).diff(x)
            2*e^(-x^2)/sqrt(pi)

        TESTS::

        Check if #8568 is fixed::

            sage: var('c,x')
            (c, x)
            sage: derivative(erf(c*x),x)
            2*c*e^(-c^2*x^2)/sqrt(pi)
            sage: erf(c*x).diff(x)._maxima_init_()
            '((%pi)^(-1/2))*(c)*(exp(((c)^(2))*((x)^(2))*(-1)))*(2)'
        """
        return 2*exp(-x**2)/sqrt(pi)
Example #30
0
    def _derivative_(self, x, diff_param=None):
        """
        Derivative of erf function

        EXAMPLES::

            sage: erf(x).diff(x)
            2*e^(-x^2)/sqrt(pi)

        TESTS::

        Check if #8568 is fixed::

            sage: var('c,x')
            (c, x)
            sage: derivative(erf(c*x),x)
            2*c*e^(-c^2*x^2)/sqrt(pi)
            sage: erf(c*x).diff(x)._maxima_init_()
            '((%pi)^(-1/2))*(c)*(exp(((c)^(2))*((x)^(2))*(-1)))*(2)'
        """
        return 2 * exp(-x**2) / sqrt(pi)
Example #31
0
    def __getattr__(self, name):
        """
        EXAMPLE::

            sage: DiscreteGaussianSamplerRejection(3.0).foo
            Traceback (most recent call last):
            ...
            AttributeError: 'DiscreteGaussianSamplerRejection' object has no attribute 'foo'
        """
        if name == "rho":
            # we delay the creation of rho until we actually need it
            R = RealField(self.precision)
            self.rho = [
                round(self.max_precs * exp(
                    (-(R(x) / R(self.stddev))**2) / R(2)))
                for x in range(0, self.upper_bound)
            ]
            self.rho[0] = self.rho[0] / 2
            return self.rho
        else:
            raise AttributeError("'%s' object has no attribute '%s'" %
                                 (self.__class__.__name__, name))
Example #32
0
    def _eval_(self, n, x):
        """
        EXAMPLES::

            sage: bessel_K(1,0)
            bessel_K(1, 0)
            sage: bessel_K(1.0, 0.0)
            +infinity
            sage: bessel_K(-1, 1).n(128)
            0.60190723019723457473754000153561733926
        """
        if (not isinstance(n, Expression) and not isinstance(x, Expression)
                and (is_inexact(n) or is_inexact(x))):
            coercion_model = get_coercion_model()
            n, x = coercion_model.canonical_coercion(n, x)
            return self._evalf_(n, x, parent(n))

        # special identity
        if n == Integer(1) / Integer(2) and x > 0:
            return sqrt(pi / 2) * exp(-x) * x**(-Integer(1) / Integer(2))

        return None  # leaves the expression unevaluated
Example #33
0
    def _eval_(self, n, x):
        """
        EXAMPLES::

            sage: bessel_K(1,0)
            bessel_K(1, 0)
            sage: bessel_K(1.0, 0.0)
            +infinity
            sage: bessel_K(-1, 1).n(128)
            0.60190723019723457473754000153561733926
        """
        if (not isinstance(n, Expression) and not isinstance(x, Expression) and
                (is_inexact(n) or is_inexact(x))):
            coercion_model = get_coercion_model()
            n, x = coercion_model.canonical_coercion(n, x)
            return self._evalf_(n, x, parent(n))

        # special identity
        if n == Integer(1) / Integer(2) and x > 0:
            return sqrt(pi / 2) * exp(-x) * x ** (-Integer(1) / Integer(2))

        return None  # leaves the expression unevaluated
    def midpoint(self):  # UHP
        r"""
        Return the (hyperbolic) midpoint of ``self`` if it exists.

        EXAMPLES::

            sage: UHP = HyperbolicPlane().UHP()
            sage: g = UHP.random_geodesic()
            sage: m = g.midpoint()
            sage: d1 = UHP.dist(m, g.start())
            sage: d2 = UHP.dist(m, g.end())
            sage: bool(abs(d1 - d2) < 10**-9)
            True

        Infinite geodesics have no midpoint::

            sage: UHP.get_geodesic(0, 2).midpoint()
            Traceback (most recent call last):
            ...
            ValueError: the length must be finite
        """
        if self.length() == infinity:
            raise ValueError("the length must be finite")

        start = self._start.coordinates()
        end = self._end.coordinates()
        d = self._model._dist_points(start, end) / 2
        S = self.complete()._to_std_geod(start)
        T = matrix([[exp(d), 0], [0, 1]])
        M = S.inverse() * T * S
        if ((real(start - end) < EPSILON)
                or (abs(real(start - end)) < EPSILON
                    and imag(start - end) < EPSILON)):
            end_p = start
        else:
            end_p = end
        return self._model.get_point(mobius_transform(M, end_p))
    def midpoint(self):  # UHP
        r"""
        Return the (hyperbolic) midpoint of ``self`` if it exists.

        EXAMPLES::

            sage: UHP = HyperbolicPlane().UHP()
            sage: g = UHP.random_geodesic()
            sage: m = g.midpoint()
            sage: d1 = UHP.dist(m, g.start())
            sage: d2 = UHP.dist(m, g.end())
            sage: bool(abs(d1 - d2) < 10**-9)
            True

        Infinite geodesics have no midpoint::

            sage: UHP.get_geodesic(0, 2).midpoint()
            Traceback (most recent call last):
            ...
            ValueError: the length must be finite
        """
        if self.length() == infinity:
            raise ValueError("the length must be finite")

        start = self._start.coordinates()
        end = self._end.coordinates()
        d = self._model._dist_points(start, end) / 2
        S = self.complete()._to_std_geod(start)
        T = matrix([[exp(d), 0], [0, 1]])
        M = S.inverse() * T * S
        if ((real(start - end) < EPSILON)
                or (abs(real(start - end)) < EPSILON
                    and imag(start - end) < EPSILON)):
            end_p = start
        else:
            end_p = end
        return self._model.get_point(mobius_transform(M, end_p))
    def Stirling(var, precision=None, skip_constant_factor=False):
        r"""
        Return Stirling's approximation formula for factorials.

        INPUT:

        - ``var`` -- a string for the variable name.

        - ``precision`` -- (default: ``None``) an integer `\ge 3`. If ``None``, then
          the default precision of the asymptotic ring is used.

        - ``skip_constant_factor`` -- (default: ``False``) a
          boolean. If set, then the constant factor `\sqrt{2\pi}` is left out.
          As a consequence, the coefficient ring of the output changes
          from ``Symbolic Constants Subring`` (if ``False``) to
          ``Rational Field`` (if ``True``).

        OUTPUT:

        An asymptotic expansion.

        EXAMPLES::

            sage: asymptotic_expansions.Stirling('n', precision=5)
            sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(1/2) +
            1/12*sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(-1/2) +
            1/288*sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(-3/2) +
            O(e^(n*log(n))*(e^n)^(-1)*n^(-5/2))
            sage: _.parent()
            Asymptotic Ring <(e^(n*log(n)))^QQ * (e^n)^QQ * n^QQ * log(n)^QQ>
            over Symbolic Constants Subring

        .. SEEALSO::

            :meth:`log_Stirling`,
            :meth:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpansion.factorial`.

        TESTS::

            sage: expansion = asymptotic_expansions.Stirling('n', precision=5)
            sage: n = expansion.parent().gen()
            sage: expansion.compare_with_values(n, lambda x: x.factorial(), [5, 10, 20])  # rel tol 1e-6
            [(5, 0.00675841118?), (10, 0.0067589306?), (20, 0.006744925?)]
            sage: asymptotic_expansions.Stirling('n', precision=5,
            ....:                                skip_constant_factor=True)
            e^(n*log(n))*(e^n)^(-1)*n^(1/2) +
            1/12*e^(n*log(n))*(e^n)^(-1)*n^(-1/2) +
            1/288*e^(n*log(n))*(e^n)^(-1)*n^(-3/2) +
            O(e^(n*log(n))*(e^n)^(-1)*n^(-5/2))
            sage: _.parent()
            Asymptotic Ring <(e^(n*log(n)))^QQ * (e^n)^QQ * n^QQ * log(n)^QQ>
            over Rational Field
            sage: asymptotic_expansions.Stirling('m', precision=4)
            sqrt(2)*sqrt(pi)*e^(m*log(m))*(e^m)^(-1)*m^(1/2) +
            O(e^(m*log(m))*(e^m)^(-1)*m^(-1/2))
            sage: asymptotic_expansions.Stirling('m', precision=3)
            O(e^(m*log(m))*(e^m)^(-1)*m^(1/2))
            sage: asymptotic_expansions.Stirling('m', precision=2)
            Traceback (most recent call last):
            ...
            ValueError: precision must be at least 3
        """
        if precision < 3:
            raise ValueError("precision must be at least 3")
        log_Stirling = AsymptoticExpansionGenerators.log_Stirling(
            var, precision=precision, skip_constant_summand=True)

        P = log_Stirling.parent().change_parameter(
            growth_group=
            '(e^({n}*log({n})))^QQ * (e^{n})^QQ * {n}^QQ * log({n})^QQ'.format(
                n=var))
        from sage.functions.log import exp
        result = exp(P(log_Stirling))

        if not skip_constant_factor:
            from sage.symbolic.ring import SR
            SCR = SR.subring(no_variables=True)
            result *= (2 * SCR('pi')).sqrt()

        return result
Example #37
0
def createLists (f, pars):
	'''
	Creates list1 and list 2 from the right side function f of an ODE:
	input: 
		f -> right side function for ODE system
		pars -> list with the parameters on f
	output:
		list1 and list2


	Example with Lorenz Equation
	sage: var('t, x, y, z')		# variables for lorenz equations
	sage: var('s, r, b')		# parameters for lorenz equations
	sage: f(t,x,y,z) = [s*(y-x), x*(r-z) - y, x*y - b*z]	# Right side function for Lorenz equation

	'''
	vars = f[0].arguments ()				# gets the list of variables from function f
	varpar = list (vars) + list (pars)			# gets the list of vars and pars totegher
	_f = f (*vars).function (varpar)	# _f is f but with vars and pars as arguments


	fastCallList = flatten ([fast_callable (i,vars=varpar).op_list () for i in f], max_level=1)
		# This list is the fast callable version of f using a stack-mode call
	'''
	We create create the lists list1, list2 and stack.
	stack will be expresion stack-list

	'''
	list1 = []; list2 = []; stack = [];
	'''
	Starts parser on fastCallList. 
	'''
	for s in fastCallList:
		if s[0] == 'load_arg':			# Loads a variable in stack. no changes on list1, or list2
			stack.append (varpar[s[1]])	# appends the variable or parameter on symbolic stack

		elif s[0] == 'ipow':			# Integer power. 
			if s[1] in NN:			# If natural, parser as products
				basis = stack[-1]
				for j in range (s[1]-1):
					a=stack.pop (-1)
					stack.append (a*basis)
					list1.append (stack[-1])
					list2.append (('mul', a, basis))
			elif -s[1] in NN:
				basis = stack[-1]
				for j in range (-s[1]-1):
					a=stack.pop (-1)
					stack.append (a*basis)
					list1.append (stack[-1])
					list2.append (('mul', a, basis))
				a = stack.pop (-1);
				stack.append (1/a);
				list1.append (stack[-1])
				list2.append (('div', 1, a))
			else:				# Attach as normal power
				a = stack.pop (-1)	#basis
				stack.append (a ** s[1])
				list1.append (stack[-1])
				list2.append (('pow', a, s[1]))

		elif s[0] == 'load_const':		# Loads a constant value on stack. Not in list1 or list2
			stack.append (s[1])

		elif s == 'neg':			# multiplies by -1.0
			a = stack.pop (-1)		# expresion to be multiplied by -1
			stack.append (-a)
			list1.append (stack[-1])
			list2.append (('mul', -1, a))

		elif s == 'mul':			# Product
			a=stack.pop (-1)
			b=stack.pop (-1)
			list2.append (('mul', a, b))
			stack.append (a*b)
			list1.append (stack[-1])

		elif s == 'div':			# divission Numerator First.
			b=stack.pop (-1)		# denominator (after a in stack)
			a=stack.pop (-1)		# numerator (before b in stack)
			if expresionIsConstant (b, pars):
				list1.append(1/b)
				list2.append(('div', 1, b))
				b = 1/b;
				stack.append (a*b)
				list1.append(stack[-1])
				list2.append (('mul', a, b))
			else:
				list2.append (('div', a, b))
				stack.append (a/b)
				list1.append (stack[-1])

		elif s == 'add':			# addition
			b = stack.pop (-1)		# second operand
			a = stack.pop (-1)		# first operand
			stack.append (a+b)
			list1.append (stack[-1])
			list2.append (('add', a, b))

		elif s == 'pow':			# any other pow
			b = stack.pop (-1)		# exponent
			a = stack.pop (-1)		# basis
			stack.append (a**b)
			list1.append (stack[-1])
			list2.append (('pow', a, b))

		elif s[0] == 'py_call' and 'sqrt' in str (s[1]):	# square root. Compute as power
			a = stack.pop (-1)		# argument of sqrt
			stack.append (sqrt (a))
			list1.append (stack[-1])
			list2.append (('pow', a, 0.5))

		elif s[0] == 'py_call' and str (s[1]) == 'log':	# logarithm
			a = stack.pop (-1);		# argument of log
			stack.append (log (a))
			list1.append (stack[-1])
			list2.append (('log', a))

		elif s[0] == 'py_call' and str (s[1]) == 'exp':
			a = stack.pop (-1);		# argument of exp
			stack.append (exp (a))
			list1.append (stack[-1])
			list2.append (('exp', a))

		elif s[0] == 'py_call' and str (s[1]) == 'sin':		# sine. For AD needs computation of cos
			a = stack.pop (-1)
			stack.append (sin (a))
			list1.append (sin (a))
			list1.append (cos (a))
			list2.append (('sin', a))
			list2.append (('cos', a))

		elif s[0] == 'py_call' and str (s[1]) == 'cos':		# cosine. For AD needs computation of sin
			a = stack.pop (-1)
			stack.append (cos (a))
			list1.append (sin (a))
			list1.append (cos (a))
			list2.append (('sin', a))
			list2.append (('cos', a))
		elif s[0] == 'py_call' and str (s[1]) == 'tan':
			a = stack.pop (-1)
			stack.append (tan (a))
			list1.append (sin (a))
			list1.append (cos (a))
			list1.append (tan (a))
			list2.append (('sin', a))
			list2.append (('cos', a))
			list2.append (('div', sin (a), cos (a)))

	return list1, list2
Example #38
0
def createLists(f, pars):
    '''
	Creates list1 and list 2 from the right side function f of an ODE:
	input: 
		f -> right side function for ODE system
		pars -> list with the parameters on f
	output:
		list1 and list2


	Example with Lorenz Equation
	sage: var('t, x, y, z')		# variables for lorenz equations
	sage: var('s, r, b')		# parameters for lorenz equations
	sage: f(t,x,y,z) = [s*(y-x), x*(r-z) - y, x*y - b*z]	# Right side function for Lorenz equation

	'''
    vars = f[0].arguments()  # gets the list of variables from function f
    varpar = list(vars) + list(pars)  # gets the list of vars and pars totegher
    _f = f(*vars).function(
        varpar)  # _f is f but with vars and pars as arguments

    fastCallList = flatten(
        [fast_callable(i, vars=varpar).op_list() for i in f], max_level=1)
    # This list is the fast callable version of f using a stack-mode call
    '''
	We create create the lists list1, list2 and stack.
	stack will be expresion stack-list

	'''
    list1 = []
    list2 = []
    stack = []
    '''
	Starts parser on fastCallList. 
	'''
    for s in fastCallList:
        if s[0] == 'load_arg':  # Loads a variable in stack. no changes on list1, or list2
            stack.append(varpar[
                s[1]])  # appends the variable or parameter on symbolic stack

        elif s[0] == 'ipow':  # Integer power.
            if s[1] in NN:  # If natural, parser as products
                basis = stack[-1]
                for j in range(s[1] - 1):
                    a = stack.pop(-1)
                    stack.append(a * basis)
                    list1.append(stack[-1])
                    list2.append(('mul', a, basis))
            elif -s[1] in NN:
                basis = stack[-1]
                for j in range(-s[1] - 1):
                    a = stack.pop(-1)
                    stack.append(a * basis)
                    list1.append(stack[-1])
                    list2.append(('mul', a, basis))
                a = stack.pop(-1)
                stack.append(1 / a)
                list1.append(stack[-1])
                list2.append(('div', 1, a))
            else:  # Attach as normal power
                a = stack.pop(-1)  #basis
                stack.append(a**s[1])
                list1.append(stack[-1])
                list2.append(('pow', a, s[1]))

        elif s[0] == 'load_const':  # Loads a constant value on stack. Not in list1 or list2
            stack.append(s[1])

        elif s == 'neg':  # multiplies by -1.0
            a = stack.pop(-1)  # expresion to be multiplied by -1
            stack.append(-a)
            list1.append(stack[-1])
            list2.append(('mul', -1, a))

        elif s == 'mul':  # Product
            a = stack.pop(-1)
            b = stack.pop(-1)
            list2.append(('mul', a, b))
            stack.append(a * b)
            list1.append(stack[-1])

        elif s == 'div':  # divission Numerator First.
            b = stack.pop(-1)  # denominator (after a in stack)
            a = stack.pop(-1)  # numerator (before b in stack)
            if expresionIsConstant(b, pars):
                list1.append(1 / b)
                list2.append(('div', 1, b))
                b = 1 / b
                stack.append(a * b)
                list1.append(stack[-1])
                list2.append(('mul', a, b))
            else:
                list2.append(('div', a, b))
                stack.append(a / b)
                list1.append(stack[-1])

        elif s == 'add':  # addition
            b = stack.pop(-1)  # second operand
            a = stack.pop(-1)  # first operand
            stack.append(a + b)
            list1.append(stack[-1])
            list2.append(('add', a, b))

        elif s == 'pow':  # any other pow
            b = stack.pop(-1)  # exponent
            a = stack.pop(-1)  # basis
            stack.append(a**b)
            list1.append(stack[-1])
            list2.append(('pow', a, b))

        elif s[0] == 'py_call' and 'sqrt' in str(
                s[1]):  # square root. Compute as power
            a = stack.pop(-1)  # argument of sqrt
            stack.append(sqrt(a))
            list1.append(stack[-1])
            list2.append(('pow', a, 0.5))

        elif s[0] == 'py_call' and str(s[1]) == 'log':  # logarithm
            a = stack.pop(-1)
            # argument of log
            stack.append(log(a))
            list1.append(stack[-1])
            list2.append(('log', a))

        elif s[0] == 'py_call' and str(s[1]) == 'exp':
            a = stack.pop(-1)
            # argument of exp
            stack.append(exp(a))
            list1.append(stack[-1])
            list2.append(('exp', a))

        elif s[0] == 'py_call' and str(
                s[1]) == 'sin':  # sine. For AD needs computation of cos
            a = stack.pop(-1)
            stack.append(sin(a))
            list1.append(sin(a))
            list1.append(cos(a))
            list2.append(('sin', a))
            list2.append(('cos', a))

        elif s[0] == 'py_call' and str(
                s[1]) == 'cos':  # cosine. For AD needs computation of sin
            a = stack.pop(-1)
            stack.append(cos(a))
            list1.append(sin(a))
            list1.append(cos(a))
            list2.append(('sin', a))
            list2.append(('cos', a))
        elif s[0] == 'py_call' and str(s[1]) == 'tan':
            a = stack.pop(-1)
            stack.append(tan(a))
            list1.append(sin(a))
            list1.append(cos(a))
            list1.append(tan(a))
            list2.append(('sin', a))
            list2.append(('cos', a))
            list2.append(('div', sin(a), cos(a)))

    return list1, list2
Example #39
0
def surface_density_gaussian(r, phi, param):
    r"""

    Surface density of a matter blob with a Gaussian profile

    INPUT:

    - ``r`` -- Boyer-Lindquist radial coordinate `\bar{r}` in the matter blob
    - ``phi`` -- Boyer-Lindquist azimuthal coordinate `\bar{\phi}` in the
      matter blob
    - ``param`` -- list of parameters defining the position and width of
      matter blob:

      - ``param[0]``: mean radius `r_0` (Boyer-Lindquist coordinate)
      - ``param[1]``: mean azimuthal angle `\phi_0` (Boyer-Lindquist
        coordinate)
      - ``param[2]``: width `\lambda` of the Gaussian profile
      - ``param[3]`` (optional): amplitude `\Sigma_0`; if not provided,
        then `\Sigma_0=1` is used

    OUTPUT:

    - surface density `\Sigma(\bar{r}, \bar{\phi})`

    EXAMPLES::

        sage: from kerrgeodesic_gw import surface_density_gaussian
        sage: param = [6.5, 0., 0.3]
        sage: surface_density_gaussian(6.5, 0, param)
        1.0
        sage: surface_density_gaussian(8., 0, param)  # tol 1.0e-13
        1.3887943864964021e-11
        sage: surface_density_gaussian(6.5, pi/16, param)  # tol 1.0e-13
        1.4901161193847656e-08

    3D representation: `z=\Sigma(\bar{r}, \bar{\phi})` in terms of
    `x:=\bar{r}\cos\bar\phi` and `y:=\bar{r}\sin\bar\phi`::

        sage: s_plot = lambda r, phi: surface_density_gaussian(r, phi, param)
        sage: r, phi, z = var('r phi z')
        sage: plot3d(s_plot, (r, 6, 8), (phi, -0.4, 0.4),
        ....:        transformation=(r*cos(phi), r*sin(phi), z))
        Graphics3d Object

    .. PLOT::

        from kerrgeodesic_gw import surface_density_gaussian
        param = param = [6.5, 0., 0.3]
        s_plot = lambda r, phi: surface_density_gaussian(r, phi, param)
        r, phi, z = var('r phi z')
        g = plot3d(s_plot, (r, 6, 8), (phi, -0.4, 0.4), \
                   transformation=(r*cos(phi), r*sin(phi), z))
        sphinx_plot(g)

    Use with a non-default amplitude (`\Sigma_0=10^{-5}`)::

        sage: sigma0 = 1.e-5
        sage: param = [6.5, 0., 0.3, sigma0]
        sage: surface_density_gaussian(6.5, 0, param)
        1e-05

    """
    r0, phi0, lam = param[0], param[1], param[2]
    Sigma0 = param[3] if len(param) == 4 else float(1)
    return float(Sigma0*exp(-((r - r0*cos(phi-phi0))**2 +
                              (r0*sin(phi-phi0))**2)/lam**2))
Example #40
0
def h_toy_model_semi_analytic(u, theta, phi, a, r0, phi0, lam, Dphi, l_max=10):
    r"""
    Return the gravitational wave emitted by a matter blob orbiting a Kerr
    black hole (semi-analytic computation based on a toy model surface density).

    The surface density of the matter blob is that given by
    :func:`surface_density_toy_model`.

    The gravitational wave is computed according to the formula

    .. MATH::

        h = \frac{2\mu}{r} \, \sum_{\ell=2}^{\infty} \sum_{m=-\ell}^\ell
        \frac{Z^\infty_{\ell m}(r_0)}{(m\omega_0)^2} \;
        \text{sinc}\left( \frac{m}{2} \Delta\varphi \right) \,
        \text{sinc}\left( \frac{3}{4} \varepsilon \, m \omega_0
        (1-a\omega_0)u \right)
        e^{- i m (\omega_0 u + \phi_0)} \,
        _{-2}S_{\ell m}^{a m \omega_0}(\theta,\varphi)

    INPUT:

    - ``u`` -- retarded time coordinate of the observer (in units of `M`, the
      BH mass): `u = t - r_*`, where `t` is the Boyer-Lindquist time coordinate
      and `r_*` is the tortoise coordinate
    - ``theta`` -- Boyer-Lindquist colatitute  `\theta` of the observer
    - ``phi`` -- Boyer-Lindquist azimuthal coordinate `\phi`  of the observer
    - ``a`` -- BH angular momentum parameter (in units of `M`)
    - ``r0`` -- mean radius `r_0` of the matter blob (Boyer-Lindquist
      coordinate)
    - ``phi0`` -- mean azimuthal angle `\phi_0` of the matter blob
      (Boyer-Lindquist coordinate)
    - ``lam`` -- radial extent `\lambda` of the matter blob
    - ``Dphi``-- opening angle `\Delta\phi` of the matter blob
    - ``l_max`` -- (default: 10) upper bound in the summation over the harmonic
      degree `\ell`

    OUTPUT:

    - a pair ``(hp, hc)``, where ``hp`` (resp. ``hc``) is `(r / \mu) h_+`
      (resp. `(r / \mu) h_\times`), `\mu` being the blob's mass and
      `r` is the Boyer-Lindquist radial coordinate of the observer

    EXAMPLES:

    Schwarzschild black hole::

        sage: from kerrgeodesic_gw import h_toy_model_semi_analytic
        sage: a = 0
        sage: r0, phi0, lam, Dphi = 6.5, 0, 0.6, 0.1
        sage: u = 60.
        sage: h_toy_model_semi_analytic(u, pi/4, 0., a, r0, phi0, lam, Dphi)  # tol 1.0e-13
        (0.2999183296797872, 0.36916647790743246)
        sage: hp, hc = _

    Comparison with the exact value::

        sage: from kerrgeodesic_gw import (h_blob, blob_mass,
        ....:                              surface_density_toy_model)
        sage: param_surf_dens = [r0, phi0, lam, Dphi]
        sage: integ_range = [6.2, 6.8, -0.05, 0.05]
        sage: mu = blob_mass(a, surface_density_toy_model, param_surf_dens,
        ....:                integ_range)[0]
        sage: hp0 = h_blob(u, pi/4, 0., a, surface_density_toy_model,
        ....:              param_surf_dens, integ_range)[0] / mu
        sage: hc0 = h_blob(u, pi/4, 0., a, surface_density_toy_model,
        ....:              param_surf_dens, integ_range, mode='x')[0] / mu
        sage: hp0, hc0  # tol 1.0e-13
        (0.2951163078053617, 0.3743683023327848)
        sage: (hp - hp0) / hp0  # tol 1.0e-13
        0.01627162494047128
        sage: (hc - hc0) / hc0  # tol 1.0e-13
        -0.013894938201066784

    """
    import numpy
    from sage.rings.real_double import RDF
    from sage.rings.complex_double import CDF
    from sage.symbolic.all import i as I
    from .spin_weighted_spherical_harm import spin_weighted_spherical_harmonic
    from .spin_weighted_spheroidal_harm import spin_weighted_spheroidal_harmonic
    from .zinf import Zinf
    u = RDF(u)
    theta = RDF(theta)
    phi = RDF(phi)
    a = RDF(a)
    omega0 = RDF(1. / (r0**1.5 + a))
    eps = lam/r0
    resu = CDF(0)
    for l in range(2, l_max+1):
        for m in range(-l, l+1):
            if m == 0:    # m=0 is skipped
                continue  #
            m_omega0 = RDF(m*omega0)
            if a == 0:
                Slm = spin_weighted_spherical_harmonic(-2, l, m, theta, phi,
                                                       numerical=RDF)
            else:
                a = RDF(a)
                Slm = spin_weighted_spheroidal_harmonic(-2, l, m, a*m_omega0,
                                                        theta, phi)
            # Division by pi in the Sinc function due to the defintion used by numpy
            resu += Zinf(a, l, m, r0) / m_omega0**2 \
                    * numpy.sinc(m*Dphi/2./numpy.pi) \
                    * numpy.sinc(0.75*eps*m_omega0*(1-a*omega0)*u/numpy.pi) \
                    * CDF(exp(-I*(m_omega0*u + m*phi0))) * Slm
    resu *= 2
    return (resu.real(), -resu.imag())
def compute_flowpipe(A=None, X0=None, B=None, U=None, **kwargs):
    r"""Implements LGG reachability algorithm for the linear continuous system dx/dx = Ax + Bu.

    INPUTS:

    * ``A`` -- coefficient matrix of the system

    * ``X0`` -- initial set

    * ``B`` -- transformation of the input

    * ``U`` -- input set

    * ``time_step`` -- (default = 1e-2) time step

    * ``initial_time`` -- (default = 0) the initial time

    * ``time_horizon`` -- (default = 1) the final time

    * ``number_of_time_steps`` -- (default = ceil(T/tau)) number of time steps

    * "directions" -- (default: random, and a box) dictionary

    * ``solver`` -- LP solver. Valid options are:
        * 'GLPK' (default).
        * 'Gurobi'

    * ``base_ring`` -- base ring where polyhedral computations are performed
        Valid options are:
        * QQ - (default) rational field
        * RDF - real double field

    OUTPUTS:

    * ``flowpipe``

    """

    # ################
    # Parse input    #
    # ################
    if A is None:
        raise ValueError('System matrix A is missing.')
    else:
        if 'sage.matrix' in str(type(A)):
            n = A.ncols()
        elif type(A) == np.ndarray:
            n = A.shape[0]

    base_ring = kwargs['base_ring'] if 'base_ring' in kwargs else QQ

    if X0 is None:
        raise ValueError('Initial state X0 is missing.')
    elif 'sage.geometry.polyhedron' not in str(type(X0)) and type(X0) == list:
        # If X0 is not some type of polyhedron, set an initial point
        X0 = Polyhedron(vertices = [X0], base_ring = base_ring)
    elif 'sage.geometry.polyhedron' not in str(type(X0)) and X0.is_vector():
        X0 = Polyhedron(vertices = [X0], base_ring = base_ring)
    elif 'sage.geometry.polyhedron' in str(type(X0)):
        # ensure that all input sets are on the same ring
        # not sure about this
        if 1==0:
            if X0.base_ring() != base_ring:
                [F, g] = polyhedron_to_Hrep(X0)
                X0 = polyhedron_from_Hrep(F, g, base_ring=base_ring)
    else:
        raise ValueError('Initial state X0 not understood')

    if B is None:
        # the system is homogeneous: dx/dt = Ax
        got_homogeneous = True
    else:
        got_homogeneous = False
        if U is None:
            raise ValueError('Input range U is missing.')

    tau = kwargs['time_step'] if 'time_step' in kwargs else 1e-2

    t0 = kwargs['initial_time'] if 'initial_time' in kwargs else 0

    T = kwargs['time_horizon'] if 'time_horizon' in kwargs else 1

    global N
    N = kwargs['number_of_time_steps'] if 'number_of_time_steps' in kwargs else ceil(T/tau)

    directions = kwargs['directions'] if 'directions' in kwargs else {'select':'box'}

    global solver
    solver = kwargs['solver'] if 'solver' in kwargs else 'GLPK'

    global verbose
    verbose = kwargs['verbose'] if 'verbose' in kwargs else 0

    # this involves the convex hull of X0 and a Minkowski sum
    #first_element_evaluation = kwargs['first_element_evaluation'] if 'first_element_evaluation' in kwargs else 'approximate'

    # #######################################################
    # Generate template directions                          #
    # #######################################################
    if directions['select'] == 'box':

        if n==2:
            theta = [0,pi/2,pi,3*pi/2] # box
            dList = [vector(RR,[cos(t), sin(t)]) for t in theta]

        else: # directions of hypercube
            dList = []
            dList += [-identity_matrix(n).column(i) for i in range(n)]
            dList += [identity_matrix(n).column(i) for i in range(n)]

    elif directions['select'] == 'oct':

        if n != 2:
            raise NotImplementedError('Directions select octagon not implemented for n other than 2. Try box.')

        theta = [i*pi/4 for i in range(8)] # octagon
        dList = [vector(RR,[cos(t), sin(t)]) for t in theta]

    elif directions['select'] == 'random':

        order = directions['order'] if 'order' in directions else 12

        if n == 2:
            theta = [random.uniform(0, 2*pi.n(digits=5)) for i in range(order)]
            dList = [vector(RR,[cos(theta[i]), sin(theta[i])]) for i in range(order)]
        else:
            raise NotImplementedError('Directions select random not implemented for n greater than 2. Try box.')

    elif directions['select'] == 'custom':

        dList = directions['dList']

    else:

        raise TypeError('Template directions not understood.')


    # transform directions to numpy array, and get number of directions
    dArray = np.array(dList)
    k = len(dArray)

    global Phi_tau, expX0, alpha_tau_B

    if got_homogeneous: # dx/dx = Ax

        # #######################################################
        # Compute first element of the approximating sequence   #
        # #######################################################

        # compute matrix exponential exp(A*tau)
        Phi_tau = expm(np.multiply(A, tau))

        # compute exp(tau*A)X0
        expX0 = Phi_tau * X0

        # compute the bloating factor
        Ainfty = A.norm(Infinity)
        RX0 = radius(X0)

        unitBall = BoxInfty(center = zero_vector(n), radius = 1, base_ring = base_ring)
        alpha_tau = (exp(tau*Ainfty) - 1 - tau*Ainfty)*(RX0)
        alpha_tau_B = (alpha_tau*np.identity(n)) * unitBall

        # now we have that:
        # Omega0 = X0.convex_hull(expX0.Minkowski_sum(alpha_tau_B))

        # compute the first element of the approximating sequence, Omega_0
        #if first_element_evaluation == 'exact':
        #    Omega0 = X0.convex_hull(expX0.Minkowski_sum(alpha_tau_B))

        #elif first_element_evaluation == 'approximate': # NOT TESTED!!!
            #Omega0_A = dArray
        #    Omega0_b = np.zeros(k)

        #    for i, d in enumerate(dArray):
        # rho_X0_d = supp_fun_polyhedron(X0, d, solver=solver, verbose=verbose)
        #        rho_expX0_d = supp_fun_polyhedron(expX0, d, solver=solver, verbose=verbose)
        #        rho_alpha_tau_B_d = supp_fun_polyhedron(alpha_tau_B, d, solver=solver, verbose=verbose)
        #        Omega0_b[i] = max(rho_X0_d, rho_expX0_d + rho_alpha_tau_B_d);

        #    Omega0 = PolyhedronFromHSpaceRep(dArray, Omega0_b);

        #W_tau = Polyhedron(vertices = [], ambient_dim=n)
        # since W_tau = [], supp_fun_polyhedron returns 0

        # ################################################
        # Build the sequence of approximations Omega_i   #
        # ################################################

        Omega_i_Family_SF = [_Omega_i_supports_hom(d, X0) for d in dArray]


    else: # dx/dx = Ax + Bu

        global tau_V, beta_tau_B

        # compute range of the input under B, V = BU
        V = B * U

        # compute matrix exponential exp(A*tau)
        Phi_tau = expm(np.multiply(A, tau))

        # compute exp(tau*A)X0
        expX0 = Phi_tau * X0

        # compute the initial over-approximation
        tau_V = (tau*np.identity(n)) * V

        # compute the bloating factor
        Ainfty = A.norm(Infinity)
        RX0 = radius(X0)
        RV = radius(V)

        unitBall = BoxInfty(center = zero_vector(n), radius = 1, base_ring = base_ring)
        alpha_tau = (exp(tau*Ainfty) - 1 - tau*Ainfty)*(RX0 + RV/Ainfty)
        alpha_tau_B = (alpha_tau*np.identity(n)) * unitBall

        # compute the first element of the approximating sequence, Omega_0
        #aux = expX0.Minkowski_sum(tau_V)
        #Omega0 = X0.convex_hull(aux.Minkowski_sum(alpha_tau_B))

        beta_tau = (exp(tau*Ainfty) - 1 - tau*Ainfty)*(RV/Ainfty)
        beta_tau_B = (beta_tau*np.identity(n)) * unitBall

        #W_tau = tau_V.Minkowski_sum(beta_tau_B)

        # ################################################
        # Build the sequence of approximations Omega_i   #
        # ################################################

        Omega_i_Family_SF = [_Omega_i_supports_inhom(d, X0) for d in dArray]


    # ################################################
    # Build the approximating polyhedra              #
    # ################################################

    # each polytope is built using the support functions over-approximation
    Omega_i_Poly = list()

    # This loop can be vectorized (?)
    for i in range(N):    # we have N polytopes

        # for each one, use all directions
        A = matrix(base_ring, k, n);
        b = vector(base_ring, k)

        for j in range(k): #run over directions
            s_fun = Omega_i_Family_SF[j][i]
            A.set_row(j, dList[j])
            b[j] = s_fun

        Omega_i_Poly.append( polyhedron_from_Hrep(A, b, base_ring = base_ring) )

    return Omega_i_Poly
Example #42
0
    def _closed_form(hyp):
        a, b, z = hyp.operands()
        a, b = a.operands(), b.operands()
        p, q = len(a), len(b)

        if z == 0:
            return Integer(1)
        if p == q == 0:
            return exp(z)
        if p == 1 and q == 0:
            return (1 - z)**(-a[0])

        if p == 0 and q == 1:
            # TODO: make this require only linear time
            def _0f1(b, z):
                F12 = cosh(2 * sqrt(z))
                F32 = sinh(2 * sqrt(z)) / (2 * sqrt(z))
                if 2 * b == 1:
                    return F12
                if 2 * b == 3:
                    return F32
                if 2 * b > 3:
                    return ((b - 2) * (b - 1) / z *
                            (_0f1(b - 2, z) - _0f1(b - 1, z)))
                if 2 * b < 1:
                    return (_0f1(b + 1, z) + z / (b *
                                                  (b + 1)) * _0f1(b + 2, z))
                raise ValueError

            # Can evaluate 0F1 in terms of elementary functions when
            # the parameter is a half-integer
            if 2 * b[0] in ZZ and b[0] not in ZZ:
                return _0f1(b[0], z)

        # Confluent hypergeometric function
        if p == 1 and q == 1:
            aa, bb = a[0], b[0]
            if aa * 2 == 1 and bb * 2 == 3:
                t = sqrt(-z)
                return sqrt(pi) / 2 * erf(t) / t
            if a == 1 and b == 2:
                return (exp(z) - 1) / z
            n, m = aa, bb
            if n in ZZ and m in ZZ and m > 0 and n > 0:
                rf = rising_factorial
                if m <= n:
                    return (exp(z) * sum(
                        rf(m - n, k) * (-z)**k / factorial(k) / rf(m, k)
                        for k in xrange(n - m + 1)))
                else:
                    T = sum(
                        rf(n - m + 1, k) * z**k / (factorial(k) * rf(2 - m, k))
                        for k in xrange(m - n))
                    U = sum(
                        rf(1 - n, k) * (-z)**k / (factorial(k) * rf(2 - m, k))
                        for k in xrange(n))
                    return (factorial(m - 2) * rf(1 - m, n) * z**(1 - m) /
                            factorial(n - 1) * (T - exp(z) * U))

        if p == 2 and q == 1:
            R12 = QQ('1/2')
            R32 = QQ('3/2')

            def _2f1(a, b, c, z):
                """
                Evaluation of 2F1(a, b, c, z), assuming a, b, c positive
                integers or half-integers
                """
                if b == c:
                    return (1 - z)**(-a)
                if a == c:
                    return (1 - z)**(-b)
                if a == 0 or b == 0:
                    return Integer(1)
                if a > b:
                    a, b = b, a
                if b >= 2:
                    F1 = _2f1(a, b - 1, c, z)
                    F2 = _2f1(a, b - 2, c, z)
                    q = (b - 1) * (z - 1)
                    return (((c - 2 * b + 2 + (b - a - 1) * z) * F1 +
                             (b - c - 1) * F2) / q)
                if c > 2:
                    # how to handle this case?
                    if a - c + 1 == 0 or b - c + 1 == 0:
                        raise NotImplementedError
                    F1 = _2f1(a, b, c - 1, z)
                    F2 = _2f1(a, b, c - 2, z)
                    r1 = (c - 1) * (2 - c - (a + b - 2 * c + 3) * z)
                    r2 = (c - 1) * (c - 2) * (1 - z)
                    q = (a - c + 1) * (b - c + 1) * z
                    return (r1 * F1 + r2 * F2) / q

                if (a, b, c) == (R12, 1, 2):
                    return (2 - 2 * sqrt(1 - z)) / z
                if (a, b, c) == (1, 1, 2):
                    return -log(1 - z) / z
                if (a, b, c) == (1, R32, R12):
                    return (1 + z) / (1 - z)**2
                if (a, b, c) == (1, R32, 2):
                    return 2 * (1 / sqrt(1 - z) - 1) / z
                if (a, b, c) == (R32, 2, R12):
                    return (1 + 3 * z) / (1 - z)**3
                if (a, b, c) == (R32, 2, 1):
                    return (2 + z) / (2 * (sqrt(1 - z) * (1 - z)**2))
                if (a, b, c) == (2, 2, 1):
                    return (1 + z) / (1 - z)**3
                raise NotImplementedError

            aa, bb = a
            cc, = b
            if z == 1:
                return (gamma(cc) * gamma(cc - aa - bb) / gamma(cc - aa) /
                        gamma(cc - bb))
            if ((aa * 2) in ZZ and (bb * 2) in ZZ and (cc * 2) in ZZ and aa > 0
                    and bb > 0 and cc > 0):
                try:
                    return _2f1(aa, bb, cc, z)
                except NotImplementedError:
                    pass
        return hyp
Example #43
0
def subexpressions_list(f, pars=None):
    """
    Construct the lists with the intermediate steps on the evaluation of the
    function.

    INPUT:

    - ``f`` -- a symbolic function of several components.

    - ``pars`` -- a list of the parameters that appear in the function
      this should be the symbolic constants that appear in f but are not
      arguments.

    OUTPUT:

    - a list of the intermediate subexpressions that appear in the evaluation
      of f.

    - a list with the operations used to construct each of the subexpressions.
      each element of this list is a tuple, formed by a string describing the
      operation made, and the operands.

    For the trigonometric functions, some extra expressions will be added.
    These extra expressions will be used later to compute their derivatives.


    EXAMPLES::

        sage: from sage.interfaces.tides import subexpressions_list
        sage: var('x,y')
        (x, y)
        sage: f(x,y) = [x^2+y, cos(x)/log(y)]
        sage: subexpressions_list(f)
        ([x^2, x^2 + y, sin(x), cos(x), log(y), cos(x)/log(y)],
        [('mul', x, x),
        ('add', y, x^2),
        ('sin', x),
        ('cos', x),
        ('log', y),
        ('div', log(y), cos(x))])

    ::

        sage: f(a)=[cos(a), arctan(a)]
        sage: from sage.interfaces.tides import subexpressions_list
        sage: subexpressions_list(f)
        ([sin(a), cos(a), a^2, a^2 + 1, arctan(a)],
        [('sin', a), ('cos', a), ('mul', a, a), ('add', 1, a^2), ('atan', a)])

    ::

        sage: from sage.interfaces.tides import subexpressions_list
        sage: var('s,b,r')
        (s, b, r)
        sage: f(t,x,y,z)= [s*(y-x),x*(r-z)-y,x*y-b*z]
        sage: subexpressions_list(f,[s,b,r])
        ([-y,
        x - y,
        s*(x - y),
        -s*(x - y),
        -z,
        r - z,
        (r - z)*x,
        -y,
        (r - z)*x - y,
        x*y,
        b*z,
        -b*z,
        x*y - b*z],
        [('mul', -1, y),
        ('add', -y, x),
        ('mul', x - y, s),
        ('mul', -1, s*(x - y)),
        ('mul', -1, z),
        ('add', -z, r),
        ('mul', x, r - z),
        ('mul', -1, y),
        ('add', -y, (r - z)*x),
        ('mul', y, x),
        ('mul', z, b),
        ('mul', -1, b*z),
        ('add', -b*z, x*y)])

    ::

        sage: var('x, y')
        (x, y)
        sage: f(x,y)=[exp(x^2+sin(y))]
        sage: from sage.interfaces.tides import *
        sage: subexpressions_list(f)
        ([x^2, sin(y), cos(y), x^2 + sin(y), e^(x^2 + sin(y))],
        [('mul', x, x),
        ('sin', y),
        ('cos', y),
        ('add', sin(y), x^2),
        ('exp', x^2 + sin(y))])


    """
    from sage.functions.trig import sin, cos, arcsin, arctan, arccos
    variables = f[0].arguments()
    if not pars:
        parameters = []
    else:
        parameters = pars
    varpar = list(parameters) + list(variables)
    F = symbolic_expression([i(*variables) for i in f]).function(*varpar)
    lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1)
    stack = []
    const =[]
    stackcomp=[]
    detail=[]
    for i in lis:
        if i[0] == 'load_arg':
            stack.append(varpar[i[1]])
        elif i[0] == 'ipow':
            if i[1] in NN:
                basis = stack[-1]
                for j in range(i[1]-1):
                    a=stack.pop(-1)
                    detail.append(('mul', a, basis))
                    stack.append(a*basis)
                    stackcomp.append(stack[-1])
            else:
                detail.append(('pow',stack[-1],i[1]))
                stack[-1]=stack[-1]**i[1]
                stackcomp.append(stack[-1])

        elif i[0] == 'load_const':
            const.append(i[1])
            stack.append(i[1])
        elif i == 'mul':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('mul', a, b))
            stack.append(a*b)
            stackcomp.append(stack[-1])

        elif i == 'div':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('div', a, b))
            stack.append(b/a)
            stackcomp.append(stack[-1])

        elif i == 'add':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('add',a,b))
            stack.append(a+b)
            stackcomp.append(stack[-1])

        elif i == 'pow':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('pow', b, a))
            stack.append(b**a)
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='log':
            a=stack.pop(-1)
            detail.append(('log', a))
            stack.append(log(a))
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='exp':
            a=stack.pop(-1)
            detail.append(('exp', a))
            stack.append(exp(a))
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='sin':
            a=stack.pop(-1)
            detail.append(('sin', a))
            detail.append(('cos', a))
            stackcomp.append(sin(a))
            stackcomp.append(cos(a))
            stack.append(sin(a))

        elif i[0] == 'py_call' and str(i[1])=='cos':
            a=stack.pop(-1)
            detail.append(('sin', a))
            detail.append(('cos', a))
            stackcomp.append(sin(a))
            stackcomp.append(cos(a))
            stack.append(cos(a))

        elif i[0] == 'py_call' and str(i[1])=='tan':
            a=stack.pop(-1)
            b = sin(a)
            c = cos(a)
            detail.append(('sin', a))
            detail.append(('cos', a))
            detail.append(('div', b, c))
            stackcomp.append(b)
            stackcomp.append(c)
            stackcomp.append(b/c)
            stack.append(b/c)

        elif i[0] == 'py_call' and str(i[1])=='arctan':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('add', 1, a*a))
            detail.append(('atan', a))
            stackcomp.append(a*a)
            stackcomp.append(1+a*a)
            stackcomp.append(arctan(a))
            stack.append(arctan(a))

        elif i[0] == 'py_call' and str(i[1])=='arcsin':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('mul', -1, a*a))
            detail.append(('add', 1, -a*a))
            detail.append(('pow', 1- a*a, 0.5))
            detail.append(('asin', a))
            stackcomp.append(a*a)
            stackcomp.append(-a*a)
            stackcomp.append(1-a*a)
            stackcomp.append(sqrt(1-a*a))
            stackcomp.append(arcsin(a))
            stack.append(arcsin(a))

        elif i[0] == 'py_call' and str(i[1])=='arccos':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('mul', -1, a*a))
            detail.append(('add', 1, -a*a))
            detail.append(('pow', 1- a*a, 0.5))
            detail.append(('mul', -1, sqrt(1-a*a)))
            detail.append(('acos', a))
            stackcomp.append(a*a)
            stackcomp.append(-a*a)
            stackcomp.append(1-a*a)
            stackcomp.append(sqrt(1-a*a))
            stackcomp.append(-sqrt(1-a*a))
            stackcomp.append(arccos(a))
            stack.append(arccos(a))

        elif i[0] == 'py_call' and 'sqrt' in str(i[1]):
            a=stack.pop(-1)
            detail.append(('pow', a, 0.5))
            stackcomp.append(sqrt(a))
            stack.append(sqrt(a))


        elif i == 'neg':
            a = stack.pop(-1)
            detail.append(('mul', -1, a))
            stack.append(-a)
            stackcomp.append(-a)

    return stackcomp,detail
    def __init__(self, B, sigma=1, c=None, precision=None):
        r"""
        Construct a discrete Gaussian sampler over the lattice `Λ(B)`
        with parameter ``sigma`` and center `c`.

        INPUT:

        - ``B`` -- a basis for the lattice, one of the following:

          - an integer matrix,
          - an object with a ``matrix()`` method, e.g. ``ZZ^n``, or
          - an object where ``matrix(B)`` succeeds, e.g. a list of vectors.

        - ``sigma`` -- Gaussian parameter `σ>0`.
        - ``c`` -- center `c`, any vector in `\ZZ^n` is supported, but `c ∈ Λ(B)` is faster.
        - ``precision`` -- bit precision `≥ 53`.

        EXAMPLES::

            sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler
            sage: n = 2; sigma = 3.0; m = 5000
            sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma)
            sage: f = D.f
            sage: c = D._normalisation_factor_zz(); c
            56.2162803067524

            sage: l = [D() for _ in range(m)]
            sage: v = vector(ZZ, n, (-3,-3))
            sage: l.count(v), ZZ(round(m*f(v)/c))
            (39, 33)

            sage: target = vector(ZZ, n, (0,0))
            sage: l.count(target), ZZ(round(m*f(target)/c))
            (116, 89)

            sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler
            sage: qf = QuadraticForm(matrix(3, [2, 1, 1,  1, 2, 1,  1, 1, 2]))
            sage: D = DiscreteGaussianDistributionLatticeSampler(qf, 3.0); D
            Discrete Gaussian sampler with σ = 3.000000, c=(0, 0, 0) over lattice with basis
            <BLANKLINE>
            [2 1 1]
            [1 2 1]
            [1 1 2]
            sage: D()
            (0, 1, -1)
        """
        precision = DiscreteGaussianDistributionLatticeSampler.compute_precision(precision, sigma)

        self._RR = RealField(precision)
        self._sigma = self._RR(sigma)

        try:
            B = matrix(B)
        except (TypeError, ValueError):
            pass

        try:
            B = B.matrix()
        except AttributeError:
            pass

        self.B = B
        self._G = B.gram_schmidt()[0]

        try:
            c = vector(ZZ, B.ncols(), c)
        except TypeError:
            try:
                c = vector(QQ, B.ncols(), c)
            except TypeError:
                c = vector(RR, B.ncols(), c)

        self._c = c

        self.f = lambda x: exp(-(vector(ZZ, B.ncols(), x) - c).norm() ** 2 / (2 * self._sigma ** 2))

        # deal with trivial case first, it is common
        if self._G == 1 and self._c == 0:
            self._c_in_lattice = True
            D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma)
            self.D = tuple([D for _ in range(self.B.nrows())])
            self.VS = FreeModule(ZZ, B.nrows())
            return

        w = B.solve_left(c)
        if w in ZZ ** B.nrows():
            self._c_in_lattice = True
            D = []
            for i in range(self.B.nrows()):
                sigma_ = self._sigma / self._G[i].norm()
                D.append(DiscreteGaussianDistributionIntegerSampler(sigma=sigma_))
            self.D = tuple(D)
            self.VS = FreeModule(ZZ, B.nrows())
        else:
            self._c_in_lattice = False
def _compute_sw_spherical_harm(s,
                               l,
                               m,
                               theta,
                               phi,
                               condon_shortley=True,
                               numerical=None):
    r"""
    Compute the spin-weighted spherical harmonic of spin weight ``s`` and
    indices ``(l,m)`` as a callable symbolic expression in (theta,phi)

    INPUT:

    - ``s`` -- integer; the spin weight
    - ``l`` -- non-negative integer; the harmonic degree
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number
    - ``theta`` -- colatitude angle
    - ``phi`` -- azimuthal angle
    - ``condon_shortley`` -- (default: ``True``) determines whether the
      Condon-Shortley phase of `(-1)^m` is taken into account (see below)
    - ``numerical`` -- (default: ``None``) determines whether a symbolic or
      a numerical computation of a given type is performed; allowed values are

      - ``None``: a symbolic computation is performed
      - ``RDF``: Sage's machine double precision floating-point numbers
        (``RealDoubleField``)
      - ``RealField(n)``, where ``n`` is a number of bits: Sage's
        floating-point numbers with an arbitrary precision; note that ``RR`` is
        a shortcut for ``RealField(53)``.
      - ``float``: Python's floating-point numbers


    OUTPUT:

    - `{}_s Y_l^m(\theta,\phi)` either

      - as a symbolic expression if ``numerical`` is ``None``
      - or a pair of floating-point numbers, each of them being of the type
        corresponding to ``numerical`` and representing respectively the
        real and imaginary parts of `{}_s Y_l^m(\theta,\phi)`

    ALGORITHM:

    The spin-weighted spherical harmonic is evaluated according to Eq. (3.1)
    of J. N. Golberg et al., J. Math. Phys. **8**, 2155 (1967)
    [:doi:`10.1063/1.1705135`], with an extra `(-1)^m` factor (the so-called
    *Condon-Shortley phase*) if ``condon_shortley`` is ``True``, the actual
    formula being then the one given in
    :wikipedia:`Spin-weighted_spherical_harmonics#Calculating`

    TESTS::

        sage: from kerrgeodesic_gw.spin_weighted_spherical_harm import _compute_sw_spherical_harm
        sage: theta, phi = var("theta phi")
        sage: _compute_sw_spherical_harm(-2, 2, 1, theta, phi)
        1/4*(sqrt(5)*cos(theta) + sqrt(5))*e^(I*phi)*sin(theta)/sqrt(pi)

    """
    if abs(s) > l:
        return ZZ(0)
    if abs(theta) < 1.e-6:  # TODO: fix the treatment of small theta values
        if theta < 0:  #       possibly with exact formula for theta=0
            theta = -1.e-6  #
        else:  #
            theta = 1.e-6  #
    cott2 = cos(theta / 2) / sin(theta / 2)
    res = 0
    for r in range(l - s + 1):
        res += (-1)**(l - r - s) * (binomial(l - s, r) * binomial(
            l + s, r + s - m) * cott2**(2 * r + s - m))
    res *= sin(theta / 2)**(2 * l)
    ff = factorial(l + m) * factorial(l - m) * (2 * l + 1) / (
        factorial(l + s) * factorial(l - s))
    if numerical:
        pre = sqrt(numerical(ff) / numerical(pi)) / 2
    else:
        pre = sqrt(ff) / (2 * sqrt(pi))
    res *= pre
    if condon_shortley:
        res *= (-1)**m
    if numerical:
        return (numerical(res * cos(m * phi)), numerical(res * sin(m * phi)))
    # Symbolic case:
    res = res.simplify_full()
    res = res.reduce_trig()  # get rid of cos(theta/2) and sin(theta/2)
    res = res.simplify_trig()  # further trigonometric simplifications
    res *= exp(I * m * phi)
    return res
Example #46
0
 def f(t):
     return exp(I * ((cos(t) + I * sin(t)) *
                     arc_radius + arc_center)) * radius
Example #47
0
 def f(t):
     return exp(I * ((cos(t) + I * sin(t)) *
                     arc_radius + arc_center)) * radius
Example #48
0
    def __init__(self, B, sigma=1, c=None, precision=None):
        r"""
        Construct a discrete Gaussian sampler over the lattice `Λ(B)`
        with parameter ``sigma`` and center `c`.

        INPUT:

        - ``B`` -- a basis for the lattice, one of the following:

          - an integer matrix,
          - an object with a ``matrix()`` method, e.g. ``ZZ^n``, or
          - an object where ``matrix(B)`` succeeds, e.g. a list of vectors.

        - ``sigma`` -- Gaussian parameter `σ>0`.
        - ``c`` -- center `c`, any vector in `\ZZ^n` is supported, but `c ∈ Λ(B)` is faster.
        - ``precision`` -- bit precision `≥ 53`.

        EXAMPLE::

            sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler
            sage: n = 2; sigma = 3.0; m = 5000
            sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma)
            sage: f = D.f
            sage: c = D._normalisation_factor_zz(); c
            56.2162803067524

            sage: l = [D() for _ in xrange(m)]
            sage: v = vector(ZZ, n, (-3,-3))
            sage: l.count(v), ZZ(round(m*f(v)/c))
            (39, 33)

            sage: target = vector(ZZ, n, (0,0))
            sage: l.count(target), ZZ(round(m*f(target)/c))
            (116, 89)

            sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler
            sage: qf = QuadraticForm(matrix(3, [2, 1, 1,  1, 2, 1,  1, 1, 2]))
            sage: D = DiscreteGaussianDistributionLatticeSampler(qf, 3.0); D
            Discrete Gaussian sampler with σ = 3.000000, c=(0, 0, 0) over lattice with basis
            <BLANKLINE>
            [2 1 1]
            [1 2 1]
            [1 1 2]
            sage: D()
            (0, 1, -1)
        """
        precision = DiscreteGaussianDistributionLatticeSampler.compute_precision(precision, sigma)

        self._RR = RealField(precision)
        self._sigma = self._RR(sigma)

        try:
            B = matrix(B)
        except ValueError:
            pass

        try:
            B = B.matrix()
        except AttributeError:
            pass

        self.B = B
        self._G = B.gram_schmidt()[0]

        try:
            c = vector(ZZ, B.ncols(), c)
        except TypeError:
            try:
                c = vector(QQ, B.ncols(), c)
            except TypeError:
                c = vector(RR, B.ncols(), c)

        self._c = c

        self.f = lambda x: exp(-(vector(ZZ, B.ncols(), x)-c).norm()**2/(2*self._sigma**2))

        # deal with trivial case first, it is common
        if self._G == 1 and self._c == 0:
            self._c_in_lattice = True
            D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma)
            self.D = tuple([D for _ in range(self.B.nrows())])
            self.VS = FreeModule(ZZ, B.nrows())
            return

        w = B.solve_left(c)
        if w in ZZ**B.nrows():
            self._c_in_lattice = True
            D = []
            for i in range(self.B.nrows()):
                sigma_ = self._sigma/self._G[i].norm()
                D.append( DiscreteGaussianDistributionIntegerSampler(sigma=sigma_) )
            self.D = tuple(D)
            self.VS = FreeModule(ZZ, B.nrows())
        else:
            self._c_in_lattice = False
Example #49
0
def smallest_poly(F, prec=53, norm_type='norm', emb=None):
    r"""
    Determine the poly with smallest coefficients in `SL(2,\Z)` orbit of ``F``

    Smallest can be in the sense of `L_2` norm or height.
    The method is the algorithm in Hutz-Stoll [HS2018]_.

    ``F`` needs to be a binary form with no multiple roots of degree
    at least 3. It should already be reduced in the sense of
    Cremona-Stoll [CS2003]_.

    INPUT:

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

    - ``norm_type`` -- string - ``norm`` or ``height`` controlling what ``smallest``
      means for the coefficients.

    OUTPUT: pair [poly, matrix]

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import smallest_poly
        sage: R.<x,y> = QQ[]
        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: smallest_poly(F, prec=100) #long time
        [
        -x^8 - 2*x^7*y + 7*x^6*y^2 + 16*x^5*y^3 + 2*x^4*y^4 - 2*x^3*y^5 + 4*x^2*y^6 - 5*y^8,
        <BLANKLINE>
        [1 1]
        [0 1]
        ]

    ::

        sage: from sage.rings.polynomial.binary_form_reduce import smallest_poly, get_bound_poly
        sage: R.<x,y> = QQ[]
        sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3
        sage: smallest_poly(F)
        [
                                               [1 4]
        -2*x^3 - 22*x^2*y - 77*x*y^2 + 43*y^3, [0 1]
        ]
        sage: F0, M = smallest_poly(F, norm_type='height')
        sage: F0, M  # random
        (
                                                [5 4]
        -58*x^3 - 47*x^2*y + 52*x*y^2 + 43*y^3, [1 1]
        )
        sage: M in SL2Z, F0 == R.hom(M * vector([x, y]))(F)
        (True, True)
        sage: get_bound_poly(F0, norm_type='height')  # tol 1e-12
        23.3402702199809

    An example with a multiple root::

        sage: R.<x,y> = QQ[]
        sage: F = -16*x^7 - 114*x^6*y - 345*x^5*y^2 - 599*x^4*y^3 - 666*x^3*y^4\
        ....: - 481*x^2*y^5 - 207*x*y^6 - 40*y^7
        sage: F.reduced_form()
        (
                                                              [-1 -1]
        -x^5*y^2 - 24*x^3*y^4 - 3*x^2*y^5 - 2*x*y^6 + 16*y^7, [ 1  0]
        )
    """
    def insert_item(pts, item, index):
        #binary insertion to maintain list of points left to consider
        N = len(pts)
        if N == 0:
            return [item]
        elif N == 1:
            if item[index] > pts[0][index]:
                pts.insert(0, item)
            else:
                pts.append(item)
            return pts
        else:  # binary insertion
            left = 1
            right = N
            mid = (left + right) // 2  # these are ints so this is .floor()
            if item[index] > pts[mid][index]:  # item goes into first half
                return insert_item(pts[:mid], item, index) + pts[mid:N]
            else:  # item goes into second half
                return pts[:mid] + insert_item(pts[mid:N], item, index)

    def coshdelta(z):
        #The cosh of the hyperbolic distance from z = t+uj to j
        return (z.norm() + 1) / (2 * z.imag()
                                 )  #reduce in the sense of Cremona-Stoll

    G = F
    MG = matrix(ZZ, 2, 2, [1, 0, 0, 1])
    x, y = G.parent().gens()
    if norm_type == 'norm':
        current_size = sum([abs(i)**2 for i in G.coefficients()
                            ])  #euclidean norm squared
    elif norm_type == 'height':  #height
        current_size = exp(
            max([c.global_height(prec=prec) for c in G.coefficients()]))
    else:
        raise ValueError('type must be norm or height')
    v0, th = covariant_z0(G, prec=prec, emb=emb)
    rep = 2 * CC.gen(0)  #representative point in fundamental domain
    from math import isnan
    if isnan(v0.abs()):
        raise ValueError("invalid covariant: %s" % v0)
    R = get_bound_poly(G, prec=prec, norm_type=norm_type)

    #check orbit
    S = matrix(ZZ, 2, 2, [0, -1, 1, 0])
    T = matrix(ZZ, 2, 2, [1, 1, 0, 1])
    TI = matrix(ZZ, 2, 2, [1, -1, 0, 1])

    count = 0
    pts = [[G, v0, rep, MG, coshdelta(v0),
            0]]  #label - 0:None, 1:S, 2:T, 3:T^(-1)
    current_min = [G, v0, rep, MG, coshdelta(v0)]
    while pts != []:
        G, v, rep, M, D, label = pts.pop()
        #apply ST and keep z, Sz
        if D > R:
            break  #all remaining pts are too far away
        #check if it is smaller. If so, we can improve the bound
        count += 1
        if norm_type == 'norm':
            new_size = sum([abs(i)**2 for i in G.coefficients()
                            ])  #euclidean norm squared
        else:  #height
            new_size = exp(
                max([c.global_height(prec=prec) for c in G.coefficients()]))
        if new_size < current_size:
            current_min = [G, v, rep, M, coshdelta(v)]
            current_size = new_size
            R = get_bound_poly(G, norm_type=norm_type, prec=prec, emb=emb)

        #add new points to check
        if label != 1 and min((rep + 1).norm(),
                              (rep - 1).norm()) >= 1:  #don't undo S
            # the 2nd condition is equivalent to |\Re(-1/rep)| <= 1/2
            # this means that rep can have resulted from an inversion step in
            # the shift-and-invert procedure, so don't invert

            # do inversion
            z = -1 / v
            new_pt = [
                G.subs({
                    x: -y,
                    y: x
                }), z, -1 / rep, M * S,
                coshdelta(z), 1
            ]
            pts = insert_item(pts, new_pt, 4)
        if label != 3:  #don't undo TI
            #do right shift
            z = v - 1
            new_pt = [G.subs({x: x + y}), z, rep - 1, M * T, coshdelta(z), 2]
            pts = insert_item(pts, new_pt, 4)
        if label != 2:  #don't undo T
            #do left shift
            z = v + 1
            new_pt = [G.subs({x: x - y}), z, rep + 1, M * TI, coshdelta(z), 3]
            pts = insert_item(pts, new_pt, 4)

    return [current_min[0], current_min[3]]
Example #50
0
    def _closed_form(hyp):
        a, b, z = hyp.operands()
        a, b = a.operands(), b.operands()
        p, q = len(a), len(b)

        if z == 0:
            return Integer(1)
        if p == q == 0:
            return exp(z)
        if p == 1 and q == 0:
            return (1 - z) ** (-a[0])

        if p == 0 and q == 1:
            # TODO: make this require only linear time
            def _0f1(b, z):
                F12 = cosh(2 * sqrt(z))
                F32 = sinh(2 * sqrt(z)) / (2 * sqrt(z))
                if 2 * b == 1:
                    return F12
                if 2 * b == 3:
                    return F32
                if 2 * b > 3:
                    return ((b - 2) * (b - 1) / z * (_0f1(b - 2, z) -
                            _0f1(b - 1, z)))
                if 2 * b < 1:
                    return (_0f1(b + 1, z) + z / (b * (b + 1)) *
                            _0f1(b + 2, z))
                raise ValueError
            # Can evaluate 0F1 in terms of elementary functions when
            # the parameter is a half-integer
            if 2 * b[0] in ZZ and b[0] not in ZZ:
                return _0f1(b[0], z)

        # Confluent hypergeometric function
        if p == 1 and q == 1:
            aa, bb = a[0], b[0]
            if aa * 2 == 1 and bb * 2 == 3:
                t = sqrt(-z)
                return sqrt(pi) / 2 * erf(t) / t
            if a == 1 and b == 2:
                return (exp(z) - 1) / z
            n, m = aa, bb
            if n in ZZ and m in ZZ and m > 0 and n > 0:
                rf = rising_factorial
                if m <= n:
                    return (exp(z) * sum(rf(m - n, k) * (-z) ** k /
                            factorial(k) / rf(m, k) for k in
                            xrange(n - m + 1)))
                else:
                    T = sum(rf(n - m + 1, k) * z ** k /
                            (factorial(k) * rf(2 - m, k)) for k in
                            xrange(m - n))
                    U = sum(rf(1 - n, k) * (-z) ** k /
                            (factorial(k) * rf(2 - m, k)) for k in
                            xrange(n))
                    return (factorial(m - 2) * rf(1 - m, n) *
                            z ** (1 - m) / factorial(n - 1) *
                            (T - exp(z) * U))

        if p == 2 and q == 1:
            R12 = QQ('1/2')
            R32 = QQ('3/2')

            def _2f1(a, b, c, z):
                """
                Evaluation of 2F1(a, b; c; z), assuming a, b, c positive
                integers or half-integers
                """
                if b == c:
                    return (1 - z) ** (-a)
                if a == c:
                    return (1 - z) ** (-b)
                if a == 0 or b == 0:
                    return Integer(1)
                if a > b:
                    a, b = b, a
                if b >= 2:
                    F1 = _2f1(a, b - 1, c, z)
                    F2 = _2f1(a, b - 2, c, z)
                    q = (b - 1) * (z - 1)
                    return (((c - 2 * b + 2 + (b - a - 1) * z) * F1 +
                            (b - c - 1) * F2) / q)
                if c > 2:
                    # how to handle this case?
                    if a - c + 1 == 0 or b - c + 1 == 0:
                        raise NotImplementedError
                    F1 = _2f1(a, b, c - 1, z)
                    F2 = _2f1(a, b, c - 2, z)
                    r1 = (c - 1) * (2 - c - (a + b - 2 * c + 3) * z)
                    r2 = (c - 1) * (c - 2) * (1 - z)
                    q = (a - c + 1) * (b - c + 1) * z
                    return (r1 * F1 + r2 * F2) / q

                if (a, b, c) == (R12, 1, 2):
                    return (2 - 2 * sqrt(1 - z)) / z
                if (a, b, c) == (1, 1, 2):
                    return -log(1 - z) / z
                if (a, b, c) == (1, R32, R12):
                    return (1 + z) / (1 - z) ** 2
                if (a, b, c) == (1, R32, 2):
                    return 2 * (1 / sqrt(1 - z) - 1) / z
                if (a, b, c) == (R32, 2, R12):
                    return (1 + 3 * z) / (1 - z) ** 3
                if (a, b, c) == (R32, 2, 1):
                    return (2 + z) / (2 * (sqrt(1 - z) * (1 - z) ** 2))
                if (a, b, c) == (2, 2, 1):
                    return (1 + z) / (1 - z) ** 3
                raise NotImplementedError
            aa, bb = a
            cc, = b
            if z == 1:
                return (gamma(cc) * gamma(cc - aa - bb) / gamma(cc - aa) /
                        gamma(cc - bb))
            if ((aa * 2) in ZZ and (bb * 2) in ZZ and (cc * 2) in ZZ and
                aa > 0 and bb > 0 and cc > 0):
                try:
                    return _2f1(aa, bb, cc, z)
                except NotImplementedError:
                    pass
        return hyp
    def Stirling(var, precision=None, skip_constant_factor=False):
        r"""
        Return Stirling's approximation formula for factorials.

        INPUT:

        - ``var`` -- a string for the variable name.

        - ``precision`` -- (default: ``None``) an integer `\ge 3`. If ``None``, then
          the default precision of the asymptotic ring is used.

        - ``skip_constant_factor`` -- (default: ``False``) a
          boolean. If set, then the constant factor `\sqrt{2\pi}` is left out.
          As a consequence, the coefficient ring of the output changes
          from ``Symbolic Constants Subring`` (if ``False``) to
          ``Rational Field`` (if ``True``).

        OUTPUT:

        An asymptotic expansion.

        EXAMPLES::

            sage: asymptotic_expansions.Stirling('n', precision=5)
            sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(1/2) +
            1/12*sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(-1/2) +
            1/288*sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(-3/2) +
            O(e^(n*log(n))*(e^n)^(-1)*n^(-5/2))
            sage: _.parent()
            Asymptotic Ring <(e^(n*log(n)))^QQ * (e^n)^QQ * n^QQ * log(n)^QQ>
            over Symbolic Constants Subring

        .. SEEALSO::

            :meth:`log_Stirling`,
            :meth:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpansion.factorial`.

        TESTS::

            sage: expansion = asymptotic_expansions.Stirling('n', precision=5)
            sage: n = expansion.parent().gen()
            sage: expansion.compare_with_values(n, lambda x: x.factorial(), [5, 10, 20])  # rel tol 1e-6
            [(5, 0.00675841118?), (10, 0.0067589306?), (20, 0.006744925?)]
            sage: asymptotic_expansions.Stirling('n', precision=5,
            ....:                                skip_constant_factor=True)
            e^(n*log(n))*(e^n)^(-1)*n^(1/2) +
            1/12*e^(n*log(n))*(e^n)^(-1)*n^(-1/2) +
            1/288*e^(n*log(n))*(e^n)^(-1)*n^(-3/2) +
            O(e^(n*log(n))*(e^n)^(-1)*n^(-5/2))
            sage: _.parent()
            Asymptotic Ring <(e^(n*log(n)))^QQ * (e^n)^QQ * n^QQ * log(n)^QQ>
            over Rational Field
            sage: asymptotic_expansions.Stirling('m', precision=4)
            sqrt(2)*sqrt(pi)*e^(m*log(m))*(e^m)^(-1)*m^(1/2) +
            O(e^(m*log(m))*(e^m)^(-1)*m^(-1/2))
            sage: asymptotic_expansions.Stirling('m', precision=3)
            O(e^(m*log(m))*(e^m)^(-1)*m^(1/2))
            sage: asymptotic_expansions.Stirling('m', precision=2)
            Traceback (most recent call last):
            ...
            ValueError: precision must be at least 3
        """
        if precision < 3:
            raise ValueError("precision must be at least 3")
        log_Stirling = AsymptoticExpansionGenerators.log_Stirling(
            var, precision=precision, skip_constant_summand=True)

        P = log_Stirling.parent().change_parameter(
            growth_group='(e^({n}*log({n})))^QQ * (e^{n})^QQ * {n}^QQ * log({n})^QQ'.format(n=var))
        from sage.functions.log import exp
        result = exp(P(log_Stirling))

        if not skip_constant_factor:
            from sage.symbolic.ring import SR
            SCR = SR.subring(no_variables=True)
            result *= (2*SCR('pi')).sqrt()

        return result