Example #1
0
    def Torus(r=2, R=3, name="Torus"):
        r"""
        Returns a torus obtained by revolving a circle of radius ``r`` around
        a coplanar axis ``R`` units away from the center of the circle. The
        parametrization used is

        .. MATH::

            \begin{aligned}
              x(u, v) & = (R + r \cos(v)) \cos(u); \\
              y(u, v) & = (R + r \cos(v)) \sin(u); \\
              z(u, v) & = r \sin(v).
            \end{aligned}

        INPUT:

        - ``r``, ``R`` -- Minor and major radius of the torus.

        - ``name`` -- string. Name of the surface.

        EXAMPLES::

            sage: torus = surfaces.Torus(); torus
            Parametrized surface ('Torus') with equation ((2*cos(v) + 3)*cos(u), (2*cos(v) + 3)*sin(u), 2*sin(v))
            sage: torus.plot()
            Graphics3d Object

        """

        u, v = var("u, v")
        torus_eq = [(R + r * cos(v)) * cos(u), (R + r * cos(v)) * sin(u), r * sin(v)]
        coords = ((u, 0, 2 * pi), (v, 0, 2 * pi))

        return ParametrizedSurface3D(torus_eq, coords, name)
Example #2
0
    def Klein(r=1, name="Klein bottle"):
        r"""
        Returns the Klein bottle, in the figure-8 parametrization given by

        .. MATH::

            \begin{aligned}
              x(u, v) & = (r + \cos(u/2)\cos(v) - \sin(u/2)\sin(2v)) \cos(u); \\
              y(u, v) & = (r + \cos(u/2)\cos(v) - \sin(u/2)\sin(2v)) \sin(u); \\
              z(u, v) & = \sin(u/2)\cos(v) + \cos(u/2)\sin(2v).
            \end{aligned}

        INPUT:

        - ``r`` -- radius of the "figure-8" circle.

        - ``name`` -- string. Name of the surface.

        EXAMPLES::

            sage: klein = surfaces.Klein(); klein
            Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v))
            sage: klein.plot()
            Graphics3d Object

        """

        u, v = var("u, v")
        x = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * cos(u)
        y = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * sin(u)
        z = sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v)
        klein_eq = [x, y, z]
        coords = ((u, 0, 2 * pi), (v, 0, 2 * pi))

        return ParametrizedSurface3D(klein_eq, coords, name)
Example #3
0
    def Dini(a=1, b=1, name="Dini's surface"):
        r"""
        Returns Dini's surface, with parametrization

        .. MATH::

            \begin{aligned}
              x(u, v) & = a \cos(u)\sin(v); \\
              y(u, v) & = a \sin(u)\sin(v); \\
              z(u, v) & = u + \log(\tan(v/2)) + \cos(v).
            \end{aligned}

        INPUT:

        - ``a, b`` -- surface parameters.

        - ``name`` -- string. Name of the surface.

        EXAMPLES::

            sage: dini = surfaces.Dini(a=3, b=4); dini
            Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v)))
            sage: dini.plot()  # not tested -- known bug (see #10132)

        """

        u, v = var("u, v")
        dini_eq = [a * cos(u) * sin(v), a * sin(u) * sin(v), a * (cos(v) + log(tan(v / 2))) + b * u]
        coords = ((u, 0, 2 * pi), (v, 0, 2 * pi))

        return ParametrizedSurface3D(dini_eq, coords, name)
Example #4
0
    def Crosscap(r=1, name="Crosscap"):
        r"""
        Returns a crosscap surface, with parametrization

        .. MATH::

            \begin{aligned}
              x(u, v) & = r(1 + \cos(v)) \cos(u); \\
              y(u, v) & = r(1 + \cos(v)) \sin(u); \\
              z(u, v) & = - r\tanh(u - \pi) \sin(v).
            \end{aligned}

        INPUT:

        - ``r`` -- surface parameter.

        - ``name`` -- string. Name of the surface.

        EXAMPLES::

            sage: crosscap = surfaces.Crosscap(); crosscap
            Parametrized surface ('Crosscap') with equation ((cos(v) + 1)*cos(u), (cos(v) + 1)*sin(u), -sin(v)*tanh(-pi + u))
            sage: crosscap.plot()
            Graphics3d Object

        """

        u, v = var("u, v")
        crosscap_eq = [r * (1 + cos(v)) * cos(u), r * (1 + cos(v)) * sin(u), -tanh(u - pi) * r * sin(v)]
        coords = ((u, 0, 2 * pi), (v, 0, 2 * pi))

        return ParametrizedSurface3D(crosscap_eq, coords, name)
Example #5
0
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: HyperbolicPlane().PD().get_geodesic(0, 1).show()
            Graphics object consisting of 2 graphics primitives
        """
        opts = dict([('axes', False), ('aspect_ratio', 1)])
        opts.update(self.graphics_options())
        opts.update(options)
        end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()]
        bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()]
        # Check to see if it's a line
        if bool(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1))**2 < EPSILON:
            from sage.plot.line import line
            pic = line([(real(bd_1),imag(bd_1)),(real(bd_2),imag(bd_2))],
                       **opts)
        else:
            # If we are here, we know it's not a line
            # So we compute the center and radius of the circle
            center = (1/(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) *
                ((imag(bd_2)-imag(bd_1)) + (real(bd_1)-real(bd_2))*I))
            radius = RR(abs(bd_1 - center)) # abs is Euclidean distance
            # Now we calculate the angles for the parametric plot
            theta1 = CC(end_1 - center).arg()
            theta2 = CC(end_2 - center).arg()
            if theta2 < theta1:
                theta1, theta2 = theta2, theta1
            from sage.calculus.var import var
            from sage.plot.plot import parametric_plot
            x = var('x')
            mid = (theta1 + theta2)/2.0
            if (radius*cos(mid) + real(center))**2 + \
               (radius*sin(mid) + imag(center))**2 > 1.0:
                # Swap theta1 and theta2
                tmp = theta1 + 2*pi
                theta1 = theta2
                theta2 = tmp
                pic = parametric_plot((radius*cos(x) + real(center),
                                       radius*sin(x) + imag(center)),
                                      (x, theta1, theta2), **opts)

            else:
                pic = parametric_plot((radius*cos(x) + real(center),
                                   radius*sin(x) + imag(center)),
                                  (x, theta1, theta2), **opts)
        if boundary:
            bd_pic = self._model.get_background_graphic()
            pic = bd_pic + pic
        return pic
Example #6
0
    def transform(self, radius=None, azimuth=None, elevation=None):
        """
        A spherical elevation coordinates transform.

        EXAMPLE::

            sage: T = SphericalElevation('radius', ['azimuth', 'elevation'])
            sage: T.transform(radius=var('r'), azimuth=var('theta'), elevation=var('phi'))
            (r*cos(phi)*cos(theta), r*cos(phi)*sin(theta), r*sin(phi))
        """
        return (radius * cos(elevation) * cos(azimuth),
                radius * cos(elevation) * sin(azimuth),
                radius * sin(elevation))
Example #7
0
        def plot_arc(radius, p, q, **opts):
            # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS!
            # plot the arc from p to q differently depending on the type of self
            p = ZZ(p)
            q = ZZ(q)
            t = var('t')
            if p - q in [1, -1]:
                def f(t):
                    return (radius * cos(t), radius * sin(t))
                (p, q) = sorted([p, q])
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                return parametric_plot(f(t), (t, angle_q, angle_p), **opts)
            if self.type() == 'A':
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                if angle_p < angle_q:
                    angle_p += 2 * pi
                internal_angle = angle_p - angle_q
                if internal_angle > pi:
                    (angle_p, angle_q) = (angle_q + 2 * pi, angle_p)
                    internal_angle = angle_p - angle_q
                angle_center = (angle_p+angle_q) / 2
                hypotenuse = radius / cos(internal_angle / 2)
                radius_arc = hypotenuse * sin(internal_angle / 2)
                center = (hypotenuse * cos(angle_center),
                          hypotenuse * sin(angle_center))
                center_angle_p = angle_p + pi / 2
                center_angle_q = angle_q + 3 * pi / 2

                def f(t):
                    return (radius_arc * cos(t) + center[0],
                            radius_arc * sin(t) + center[1])
                return parametric_plot(f(t), (t, center_angle_p,
                                              center_angle_q), **opts)
            elif self.type() == 'D':
                if p >= q:
                    q += self.r()
                px = -2 * pi * p / self.r() + pi / 2
                qx = -2 * pi * q / self.r() + pi / 2
                arc_radius = (px - qx) / 2
                arc_center = qx + arc_radius

                def f(t):
                    return exp(I * ((cos(t) + I * sin(t)) *
                                    arc_radius + arc_center)) * radius
                return parametric_plot((real_part(f(t)), imag_part(f(t))),
                                       (t, 0, pi), **opts)
Example #8
0
    def Catenoid(c=1, name="Catenoid"):
        r"""
        Returns a catenoid surface, with parametric representation

        .. MATH::

            \begin{aligned}
              x(u, v) & = c \cosh(v/c) \cos(u); \\
              y(u, v) & = c \cosh(v/c) \sin(u); \\
              z(u, v) & = v.
            \end{aligned}

        INPUT:

        - ``c`` -- surface parameter.

        - ``name`` -- string. Name of the surface.


        EXAMPLES::

            sage: cat = surfaces.Catenoid(); cat
            Parametrized surface ('Catenoid') with equation (cos(u)*cosh(v), cosh(v)*sin(u), v)
            sage: cat.plot()
            Graphics3d Object

        """
        u, v = var("u, v")
        catenoid_eq = [c * cosh(v / c) * cos(u), c * cosh(v / c) * sin(u), v]
        coords = ((u, 0, 2 * pi), (v, -1, 1))

        return ParametrizedSurface3D(catenoid_eq, coords, name)
Example #9
0
    def Helicoid(h=1, name="Helicoid"):
        r"""
        Returns a helicoid surface, with parametrization

        .. MATH::

            \begin{aligned}
              x(\rho, \theta) & = \rho \cos(\theta); \\
              y(\rho, \theta) & = \rho \sin(\theta); \\
              z(\rho, \theta) & = h\theta/(2\pi).
            \end{aligned}

        INPUT:

        - ``h`` -- distance along the z-axis between two
          successive turns of the helicoid.

        - ``name`` -- string. Name of the surface.

        EXAMPLES::

            sage: helicoid = surfaces.Helicoid(h=2); helicoid
            Parametrized surface ('Helicoid') with equation (rho*cos(theta), rho*sin(theta), theta/pi)
            sage: helicoid.plot()
            Graphics3d Object

        """

        rho, theta = var("rho, theta")
        helicoid_eq = [rho * cos(theta), rho * sin(theta), h * theta / (2 * pi)]
        coords = ((rho, -2, 2), (theta, 0, 2 * pi))

        return ParametrizedSurface3D(helicoid_eq, [rho, theta], name)
Example #10
0
    def _eval_(self, a, z):
        """
        EXAMPLES::

            sage: struve_H(0,0)
            0
            sage: struve_H(pi,0)
            0
            sage: struve_H(-1/2,x)
            sqrt(2)*sqrt(1/(pi*x))*sin(x)
            sage: struve_H(1/2,-1)
            -sqrt(2)*sqrt(-1/pi)*(cos(1) - 1)
            sage: struve_H(1/2,pi)
            2*sqrt(2)/pi
            sage: struve_H(2,x)
            struve_H(2, x)
            sage: struve_H(-3/2,x)
            -bessel_J(3/2, x)
        """
        from sage.symbolic.ring import SR
        if z.is_zero() \
                and (SR(a).is_numeric() or SR(a).is_constant()) \
                and a.real() >= -1:
                return ZZ(0)
        if a == -Integer(1)/2:
            from sage.functions.trig import sin
            return sqrt(2/(pi*z)) * sin(z)
        if a == Integer(1)/2:
            from sage.functions.trig import cos
            return sqrt(2/(pi*z)) * (1-cos(z))
        if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer():
            from sage.rings.rational_field import QQ
            n = (a*(-2) - 1)/2
            return Integer(-1)**n * bessel_J(n+QQ(1)/2, z)
Example #11
0
    def _eval_(self, n, m, theta, phi, **kwargs):
        r"""
        TESTS::

            sage: x, y = var('x y')
            sage: spherical_harmonic(1, 2, x, y)
            0
            sage: spherical_harmonic(1, -2, x, y)
            0
            sage: spherical_harmonic(1/2, 2, x, y)
            spherical_harmonic(1/2, 2, x, y)
            sage: spherical_harmonic(3, 2, x, y)
            1/8*sqrt(30)*sqrt(7)*cos(x)*e^(2*I*y)*sin(x)^2/sqrt(pi)
            sage: spherical_harmonic(3, 2, 1, 2)
            1/8*sqrt(30)*sqrt(7)*cos(1)*e^(4*I)*sin(1)^2/sqrt(pi)
            sage: spherical_harmonic(3 + I, 2., 1, 2)
            -0.351154337307488 - 0.415562233975369*I

        Check that :trac:`20939` is fixed::

            sage: ex = spherical_harmonic(3,2,1,2*pi/3)
            sage: QQbar(ex * sqrt(pi)/cos(1)/sin(1)^2).minpoly()
            x^4 + 105/32*x^2 + 11025/1024
        """
        if n in ZZ and m in ZZ and n > -1:
            if abs(m) > n:
                return ZZ(0)
            if m == 0 and theta.is_zero():
                return sqrt((2*n+1)/4/pi)
            from sage.arith.misc import factorial
            from sage.functions.trig import cos
            from sage.functions.orthogonal_polys import gen_legendre_P
            return (sqrt(factorial(n-m) * (2*n+1) / (4*pi * factorial(n+m))) *
                    exp(I*m*phi) * gen_legendre_P(n, m, cos(theta)) *
                    (-1)**m).simplify_trig()
    def _i_rotation(self, z, alpha):
        r"""
        Return the resulting point after applying a hyperbolic
        rotation centered at `0 + i` and angle ``alpha`` to ``z``.

        INPUT:

        - ``z``-- point in the upper complex halfplane to which
          apply the isometry

        - ``alpha``-- angle of rotation (radians,counterwise)

        OUTPUT:

        - rotated point in the upper complex halfplane

        TESTS::

            sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon
            sage: P = HyperbolicRegularPolygon(4, pi/4, 1+I, {})
            sage: P._i_rotation(2+I, pi/2)
            I - 2
        """
        _a = alpha / 2
        _c = cos(_a)
        _s = sin(_a)
        G = matrix([[_c, _s], [-_s, _c]])
        return (G[0][0] * z + G[0][1]) / (G[1][0] * z + G[1][1])
Example #13
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        MS = MatrixSpace(base_ring, n, sparse=True)
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
        gens = [MS.one() + MS({(i, j): val(coxeter_matrix[i, j])
                               for j in range(n)})
                for i in range(n)]
        FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring,
                                                      gens,
                                                      category=CoxeterGroups())
Example #14
0
def _circ_arc(t0, t1, c, r, num_pts=500):
    r""" Circular arc
    INPUTS:
    - ''t0'' -- starting parameter
    - ''t1'' -- ending parameter
    - ''c''  -- center point of the circle
    - ''r''  -- radius of circle
    - ''num_pts''  -- (default 100) number of points on polygon
    OUTPUT:
    - ''ca'' -- a polygonal approximation of a circular arc centered
    at c and radius r, starting at t0 and ending at t1


    EXAMPLES::

        sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100)

    """
    from sage.plot.plot import parametric_plot
    from sage.functions.trig import cos, sin
    from sage.all import var

    t00 = t0
    t11 = t1
    ## To make sure the line is correct we reduce all arguments to the same branch,
    ## e.g. [0,2pi]
    pi = RR.pi()
    while t00 < 0.0:
        t00 = t00 + RR(2.0 * pi)
    while t11 < 0:
        t11 = t11 + RR(2.0 * pi)
    while t00 > 2 * pi:
        t00 = t00 - RR(2.0 * pi)
    while t11 > 2 * pi:
        t11 = t11 - RR(2.0 * pi)

    xc = CC(c).real()
    yc = CC(c).imag()
    # L0 =
    # [[RR(r*cos(t00+i*(t11-t00)/num_pts))+xc,RR(r*sin(t00+i*(t11-t00)/num_pts))+yc]
    # for i in range(0 ,num_pts)]
    t = var("t")
    if t11 > t00:
        ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t00, t11))
    else:
        ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t11, t00))
    return ca
Example #15
0
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: HyperbolicPlane().UHP().get_geodesic(0, 1).show()
            Graphics object consisting of 2 graphics primitives
        """
        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)
        end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()]
        bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()]
        if (abs(real(end_1) - real(end_2)) < EPSILON) \
                or CC(infinity) in [end_1, end_2]: #on same vertical line
            # If one of the endpoints is infinity, we replace it with a
            # large finite  point
            if end_1 == CC(infinity):
                end_1 = (real(end_2), (imag(end_2) + 10))
                end_2 = (real(end_2), imag(end_2))
            elif end_2 == CC(infinity):
                end_2 = (real(end_1), (imag(end_1) + 10))
                end_1 = (real(end_1), imag(end_1))
            from sage.plot.line import line
            pic = line((end_1, end_2), **opts)
            if boundary:
                cent = min(bd_1, bd_2)
                bd_dict = {'bd_min': cent - 3, 'bd_max': cent + 3}
                bd_pic = self._model.get_background_graphic(**bd_dict)
                pic = bd_pic + pic
                return pic
        else:
            center = (bd_1 + bd_2)/2 # Circle center
            radius = abs(bd_1 - bd_2)/2
            theta1 = CC(end_1 - center).arg()
            theta2 = CC(end_2 - center).arg()
            if abs(theta1 - theta2) < EPSILON:
                theta2 += pi
            [theta1, theta2] = sorted([theta1, theta2])
            from sage.calculus.var import var
            from sage.plot.plot import parametric_plot
            x = var('x')
            pic = parametric_plot((radius*cos(x) + real(center),
                                   radius*sin(x) + imag(center)),
                                  (x, theta1, theta2), **opts)
            if boundary:
                # We want to draw a segment of the real line.  The
                # computations below compute the projection of the
                # geodesic to the real line, and then draw a little
                # to the left and right of the projection.
                shadow_1, shadow_2 = [real(k) for k in [end_1, end_2]]
                midpoint = (shadow_1 + shadow_2)/2
                length = abs(shadow_1 - shadow_2)
                bd_dict = {'bd_min': midpoint - length, 'bd_max': midpoint +
                           length}
                bd_pic = self._model.get_background_graphic(**bd_dict)
                pic = bd_pic + pic
            return pic
Example #16
0
def _draw_funddom(coset_reps,format="S"):
    r""" Draw a fundamental domain for G.
    
    INPUT:
    
    - ``format``  -- (default 'Disp') How to present the f.d.
    -   ``S`` -- Display directly on the screen
    
    EXAMPLES::        


    sage: G=MySubgroup(Gamma0(3))
    sage: G._draw_funddom()
        
    """
    pi=RR.pi()
    pi_3 = pi / RR(3.0)
    from sage.plot.plot import (Graphics,line)
    from sage.functions.trig import (cos,sin)
    g=Graphics()
    x1=RR(-0.5) ; y1=RR(sqrt(3 )/2 )
    x2=RR(0.5) ; y2=RR(sqrt(3 )/2 )
    xmax=RR(20.0) 
    l1 = line([[x1,y1],[x1,xmax]])
    l2 = line([[x2,y2],[x2,xmax]])
    l3 = line([[x2,xmax],[x1,xmax]]) # This is added to make a closed contour
    c0=_circ_arc(RR(pi/3.0) ,RR(2.0*pi)/RR(3.0) ,0 ,1 ,100 )
    tri=c0+l1+l3+l2
    g=g+tri
    for A in coset_reps:
        [a,b,c,d]=A
        if(a==1  and b==0  and c==0  and d==1 ):
            continue
        if(a<0 ):
            a=RR(-a); b=RR(-b); c=RR(-c); d=RR(-d) 
        else:
            a=RR(a); b=RR(b); c=RR(c); d=RR(d) 
        if(c==0 ): # then this is easier
            L0 = [[cos(pi_3*RR(i/100.0))+b,sin(pi_3*RR(i/100.0))] for i in range(100 ,201 )]
            L1 = [[x1+b,y1],[x1+b,xmax]]
            L2 = [[x2+b,y2],[x2+b,xmax]]
            L3 = [[x2+b,xmax],[x1+b,xmax]]
            c0=line(L0); l1=line(L1); l2=line(L2); l3=line(L3)
            tri=c0+l1+l3+l2
            g=g+tri
        else:
            den=(c*x1+d)**2 +c**2 *y1**2 
            x1_t=(a*c*(x1**2 +y1**2 )+(a*d+b*c)*x1+b*d)/den
            y1_t=y1/den
            den=(c*x2+d)**2 +c**2 *y2**2 
            x2_t=(a*c*(x2**2 +y2**2 )+(a*d+b*c)*x2+b*d)/den
            y2_t=y2/den
            inf_t=a/c
            c0=_geodesic_between_two_points(x1_t,y1_t,x2_t,y2_t)
            c1=_geodesic_between_two_points(x1_t,y1_t,inf_t,0. )
            c2=_geodesic_between_two_points(x2_t,y2_t,inf_t,0.0)
            tri=c0+c1+c2
            g=g+tri
    return g
Example #17
0
 def plot(self):
     from sage.functions.trig import sin, cos
     from sage.plot.circle import circle
     from sage.plot.point import point
     from sage.plot.text import text
     p = circle((0,0),1)
     for i in range(self._dimension):
         a = self._alpha[i]
         p += point([cos(2*pi*a),sin(2*pi*a)], color='blue', size=100)
         p += text(r"$\alpha_%i$"%(self._i_alpha[i]+1),
                   [1.2*cos(2*pi*a),1.2*sin(2*pi*a)],fontsize=40)
     for i in range(self._dimension):
         b = self._beta[i]
         p += point([cos(2*pi*b),sin(2*pi*b)], color='red', size=100)
         p += text(r"$\beta_%i$"%(self._i_beta[i]+1),
                   [1.2*cos(2*pi*b),1.2*sin(2*pi*b)],fontsize=40)
     p.show(axes=False, xmin=-1, xmax=1, ymin=-1, ymax=1)
Example #18
0
    def plot(self, show_box=False, colors=["white","lightgray","darkgray"]):
        r"""
        Return a plot of ``self``.

        INPUT:

        - ``show_box`` -- boolean (default: ``False``); if ``True``,
          also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes

        - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``)
          list ``[A, B, C]`` of 3 strings representing colors

        EXAMPLES::

            sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]])
            sage: PP.plot()
            Graphics object consisting of 27 graphics primitives
        """
        x = self._max_x
        y = self._max_y
        z = self._max_z
        from sage.functions.trig import cos, sin
        from sage.plot.polygon import polygon
        from sage.symbolic.constants import pi
        from sage.plot.plot import plot
        Uside = [[0,0], [cos(-pi/6),sin(-pi/6)], [0,-1], [cos(7*pi/6),sin(7*pi/6)]]
        Lside = [[0,0], [cos(-pi/6),sin(-pi/6)], [cos(pi/6),sin(pi/6)], [0,1]]
        Rside = [[0,0], [0,1], [cos(5*pi/6),sin(5*pi/6)], [cos(7*pi/6),sin(7*pi/6)]]
        Xdir = [cos(7*pi/6), sin(7*pi/6)]
        Ydir = [cos(-pi/6), sin(-pi/6)]
        Zdir = [0, 1]
        def move(side, i, j, k):
            return [[P[0]+i*Xdir[0]+j*Ydir[0]+k*Zdir[0],
                     P[1]+i*Xdir[1]+j*Ydir[1]+k*Zdir[1]]
                    for P in side]
        def add_topside(i, j, k):
            return polygon(move(Uside,i,j,k), edgecolor="black", color=colors[0])
        def add_leftside(i, j, k):
            return polygon(move(Lside,i,j,k), edgecolor="black", color=colors[1])
        def add_rightside(i, j, k):
            return polygon(move(Rside,i,j,k), edgecolor="black", color=colors[2])
        TP = plot([])
        for r in range(len(self.z_tableau())):
            for c in range(len(self.z_tableau()[r])):
                if self.z_tableau()[r][c] > 0 or show_box:
                    TP += add_topside(r, c, self.z_tableau()[r][c])
        for r in range(len(self.y_tableau())):
            for c in range(len(self.y_tableau()[r])):
                if self.y_tableau()[r][c] > 0 or show_box:
                    TP += add_rightside(c, self.y_tableau()[r][c], r)
        for r in range(len(self.x_tableau())):
            for c in range(len(self.x_tableau()[r])):
                if self.x_tableau()[r][c] > 0 or show_box:
                    TP += add_leftside(self.x_tableau()[r][c], r, c)
        TP.axes(show=False)
        return TP
    def __init__(self, sides, i_angle, center, options):
        """
        Initialize HyperbolicRegularPolygon.

        EXAMPLES::

            sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon
            sage: print(HyperbolicRegularPolygon(5,pi/2,I, {}))
            Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I)
        """
        self.center = CC(center)
        if self.center.imag() <= 0 :
            raise ValueError("center: %s is not a valid point in the upper half plane model of the hyperbolic plane"%(self.center))
        if sides < 3 :
            raise ValueError("degenerated polygons (sides<=2) are not supported")
        if i_angle <=0 or i_angle >= pi:
            raise ValueError("interior angle %s must be in (0, pi) interval"%(i_angle))
        if pi*(sides-2) - sides*i_angle <= 0 :
            raise ValueError("there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s"%(sides, pi * (sides-2) / sides))
        self.sides = sides
        self.i_angle = i_angle
        beta = 2 * pi / self.sides # compute the rotation angle to be used ahead
        alpha = self.i_angle / Integer(2)
        I = CC(0, 1)
        # compute using cosine theorem the radius of the circumscribed circle
        # using the triangle formed by the radius and the three known angles
        r = arccosh(cot(alpha) * (1 + cos(beta)) / sin(beta))

        # The first point will be always on the imaginary axis limited
        # to 8 digits for efficiency in the subsequent calculations.
        z_0 = [I*(e**r).n(digits=8)]

        # Compute the dilation isometry used to move the center
        # from I to the imaginary part of the given center.
        scale = self.center.imag()

        # Compute the parabolic isometry to move the center to the
        # real part of the given center.
        h_disp = self.center.real()

        d_z_k = [z_0[0]*scale + h_disp]  #d_k has the points for the polygon in the given center
        z_k = z_0                      #z_k has the Re(z)>0 vertices for the I centered polygon 
        r_z_k = []                     #r_z_k has the Re(z)<0 vertices
        if is_odd(self.sides):
            vert = (self.sides - 1) / 2
        else:
            vert = self.sides / 2 - 1
        for k in range(0, vert):
            # Compute with 8 digits to accelerate calculations
            new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8)
            z_k = z_k + [new_z_k]
            d_z_k = d_z_k + [new_z_k * scale + h_disp]
            r_z_k=[-(new_z_k).conjugate() * scale + h_disp] + r_z_k
        if is_odd(self.sides):
            HyperbolicPolygon.__init__(self, d_z_k + r_z_k, options)
        else:
            z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp]
            HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, options)
Example #20
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix
        base_ring = mat.base_ring()

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField

        UCF = UniversalCyclotomicField()
        if UCF.has_coerce_map_from(base_ring):
            R = UCF
        else:
            R = base_ring
        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        if R is UCF:
            val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R(-2) if x > -1 else R.one() * x
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x

        MS = MatrixSpace(R, n, sparse=True)
        MC = MS._get_matrix_class()

        bilinear = MC(
            MS,
            entries={(i, j): val(mat[i, j]) for i in range(n) for j in range(n) if mat[i, j] != 2},
            coerce=True,
            copy=True,
        )
        bilinear.set_immutable()
        return bilinear
    def plot(self, **kwargs):
        """
        Return a graphics object representing the Kontsevich graph.

        INPUT:

        - ``edge_labels`` (boolean, default True) -- if True, show edge labels.
        - ``indices`` (boolean, default False) -- if True, show indices as
          edge labels instead of L and R; see :meth:`._latex_`.
        - ``upright`` (boolean, default False) -- if True, try to plot the
          graph with the ground vertices on the bottom and the rest on top.
        """
        if not 'edge_labels' in kwargs:
            kwargs['edge_labels'] = True        # show edge labels by default
        if 'indices' in kwargs:
            del kwargs['indices']
            KG = DiGraph(self)
            for (k,e) in enumerate(self.edges()):
                KG.delete_edge(e)
                KG.add_edge((e[0], e[1], chr(97 + k)))
            return KG.plot(**kwargs)
        if len(self.ground_vertices()) == 2 and 'upright' in kwargs:
            del kwargs['upright']
            kwargs['save_pos'] = True
            DiGraph.plot(self, **kwargs)
            positions = self.get_pos()
            # translate F to origin:
            F_pos = vector(positions[self.ground_vertices()[0]])
            for p in positions:
                positions[p] = list(vector(positions[p]) - F_pos)
            # scale F - G distance to 1:
            G_len = abs(vector(positions[self.ground_vertices()[1]]))
            for p in positions:
                positions[p] = list(vector(positions[p])/G_len)
            # rotate the vector F - G to (1,0)
            from math import atan2
            theta = -atan2(positions[self.ground_vertices()[1]][1], positions[self.ground_vertices()[1]][0])
            for p in positions:
                positions[p] = list(matrix([[cos(theta),-(sin(theta))],[sin(theta),cos(theta)]]) * vector(positions[p]))
            # flip if most things are below the x-axis:
            if len([(x,y) for (x,y) in positions.values() if y < 0])/len(self.internal_vertices()) > 0.5:
                for p in positions:
                    positions[p] = [positions[p][0], -positions[p][1]]
        return DiGraph.plot(self, **kwargs)
Example #22
0
    def _derivative_(self, x, diff_param=None):
        """
        EXAMPLES::

            sage: x = var('x')
            sage: fresnel_cos(x).diff(x)
            cos(1/2*pi*x^2)
        """
        from sage.functions.trig import cos
        return cos(pi*x**2/2)
Example #23
0
    def Ellipsoid(center=(0,0,0), axes=(1,1,1), name="Ellipsoid"):
        r"""
        Returns an ellipsoid centered at ``center`` whose semi-principal axes
        have lengths given by the components of ``axes``. The
        parametrization of the ellipsoid is given by

        .. MATH::

            \begin{aligned}
              x(u, v) & = x_0 + a \cos(u) \cos(v); \\
              y(u, v) & = y_0 + b \sin(u) \cos(v); \\
              z(u, v) & = z_0 + c \sin(v).
            \end{aligned}

        INPUT:

        - ``center`` -- 3-tuple. Coordinates of the center of the ellipsoid.

        - ``axes`` -- 3-tuple. Lengths of the semi-principal axes.

        - ``name`` -- string. Name of the ellipsoid.

        EXAMPLES::

            sage: ell = surfaces.Ellipsoid(axes=(1, 2, 3)); ell
            Parametrized surface ('Ellipsoid') with equation (cos(u)*cos(v), 2*cos(v)*sin(u), 3*sin(v))
            sage: ell.plot()

        """

        u, v = var ('u, v')
        x, y, z = center
        a, b, c = axes
        ellipsoid_parametric_eq = [x + a*cos(u)*cos(v),
                                   y + b*sin(u)*cos(v),
                                   z + c*sin(v)]
        coords = ((u, 0, 2*pi), (v, -pi/2, pi/2))

        return ParametrizedSurface3D(ellipsoid_parametric_eq, coords, name)
Example #24
0
    def transform(self, radius=None, azimuth=None, height=None):
        """
        A cylindrical coordinates transform.

        EXAMPLE::

            sage: T = Cylindrical('height', ['azimuth', 'radius'])
            sage: T.transform(radius=var('r'), azimuth=var('theta'), height=var('z'))
            (r*cos(theta), r*sin(theta), z)
        """
        return (radius * cos(azimuth),
                radius * sin(azimuth),
                height)
Example #25
0
    def _derivative_(self, z, diff_param=None):
        r"""
        The derivative of `\operatorname{Ci}(z)` is `\cos(z)/z` if `z` is not zero.

        EXAMPLES::

            sage: x = var('x')
            sage: f = cos_integral(x)
            sage: f.diff(x)
            cos(x)/x

            sage: f = cos_integral(x^2)
            sage: f.diff(x)
            2*cos(x^2)/x

        """
        return cos(z)/z
Example #26
0
    def photon_orbit_radius(self, retrograde=False):
        r"""
        Return the Boyer-Lindquist radial coordinate of the circular orbit
        of photons in the equatorial plane.

        INPUT:

        - ``retrograde`` -- (default: ``False``) boolean determining whether
          retrograde or prograde (direct) orbits are considered

        OUTPUT:

        - Boyer-Lindquist radial coordinate `r` of the circular orbit of
          photons in the equatorial plane

        EXAMPLES::

            sage: from kerrgeodesic_gw import KerrBH
            sage: a, m = var('a m')
            sage: BH = KerrBH(a, m)
            sage: BH.photon_orbit_radius()
            2*m*(cos(2/3*arccos(-a/m)) + 1)
            sage: BH.photon_orbit_radius(retrograde=True)
            2*m*(cos(2/3*arccos(a/m)) + 1)

        Photon orbit in Schwarzschild spacetime::

            sage: KerrBH(0, m).photon_orbit_radius()
            3*m

        Photon orbits in extreme Kerr spacetime (`a=m`)::

            sage: KerrBH(m, m).photon_orbit_radius()
            m
            sage: KerrBH(m, m).photon_orbit_radius(retrograde=True)
            4*m

        """
        m = self._m
        a = self._a
        eps = -1 if not retrograde else 1
        # Eq. (2.18) in Bardeen, Press & Teukolsky, ApJ 178, 347 (1972)
        return 2 * m * (1 + cos(2 * acos(eps * a / m) / 3))
Example #27
0
def _circ_arc(t0, t1, c, r, num_pts=5000):
    r""" Circular arc
    INPUTS:
    - ''t0'' -- starting parameter
    - ''t1'' -- ending parameter
    - ''c''  -- center point of the circle
    - ''r''  -- radius of circle
    - ''num_pts''  -- (default 100) number of points on polygon
    OUTPUT:
    - ''ca'' -- a polygonal approximation of a circular arc centered
    at c and radius r, starting at t0 and ending at t1

    
    EXAMPLES::

        sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100)
    
    """
    from sage.plot.plot import line
    from sage.functions.trig import (cos, sin)
    t00 = t0
    t11 = t1
    ## To make sure the line is correct we reduce all arguments to the same branch,
    ## e.g. [0,2pi]
    pi = RR.pi()
    while (t00 < 0.0):
        t00 = t00 + RR(2.0 * pi)
    while (t11 < 0):
        t11 = t11 + RR(2.0 * pi)
    while (t00 > 2 * pi):
        t00 = t00 - RR(2.0 * pi)
    while (t11 > 2 * pi):
        t11 = t11 - RR(2.0 * pi)

    xc = CC(c).real()
    yc = CC(c).imag()
    L0 = [[
        RR(r * cos(t00 + i * (t11 - t00) / num_pts)) + xc,
        RR(r * sin(t00 + i * (t11 - t00) / num_pts)) + yc
    ] for i in range(0, num_pts)]
    ca = line(L0)
    return ca
Example #28
0
def draw_transformed_triangle_H(A,xmax=20):
    r"""
    Draw the modular triangle translated by A=[a,b,c,d]
    """
    #print "A=",A,type(A)
    pi=RR.pi()
    pi_3 = pi / RR(3.0)
    from sage.plot.plot import (Graphics,line)
    from sage.functions.trig import (cos,sin)
    x1=RR(-0.5) ; y1=RR(sqrt(3 )/2 )
    x2=RR(0.5) ; y2=RR(sqrt(3 )/2 )
    a,b,c,d = A #[0,0]; b=A[0,1]; c=A[1,0]; d=A[1,1]
    if a<0:
        a=RR(-a); b=RR(-b); c=RR(-c); d=RR(-d) 
    else:
        a=RR(a); b=RR(b); c=RR(c); d=RR(d) 
    if c==0: # then this is easier
        if a*d<>0:
            a=a/d; b=b/d; 
        L0 = [[a*cos(pi_3*RR(i/100.0))+b,a*sin(pi_3*RR(i/100.0))] for i in range(100 ,201 )]
        L1 = [[a*x1+b,a*y1],[a*x1+b,xmax]]
        L2 = [[a*x2+b,a*y2],[a*x2+b,xmax]]
        L3 = [[a*x2+b,xmax],[a*x1+b,xmax]]
        c0=line(L0); l1=line(L1); l2=line(L2); l3=line(L3)
        tri=c0+l1+l3+l2
    else:
        den=(c*x1+d)**2 +c**2 *y1**2 
        x1_t=(a*c*(x1**2 +y1**2 )+(a*d+b*c)*x1+b*d)/den
        y1_t=y1/den
        den=(c*x2+d)**2 +c**2 *y2**2 
        x2_t=(a*c*(x2**2 +y2**2 )+(a*d+b*c)*x2+b*d)/den
        y2_t=y2/den
        inf_t=a/c
        #print "A=",A
        #print "arg1=",x1_t,y1_t,x2_t,y2_t
        c0=_geodesic_between_two_points(x1_t,y1_t,x2_t,y2_t)
        #print "arg1=",x1_t,y1_t,inf_t
        c1=_geodesic_between_two_points(x1_t,y1_t,inf_t,0. )
        #print "arg1=",x2_t,y2_t,inf_t
        c2=_geodesic_between_two_points(x2_t,y2_t,inf_t,0.0)
        tri=c0+c1+c2
    return tri
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        MS = MatrixSpace(base_ring, n, sparse=True)
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2 * x) + ~base_ring.gen(
                2 * x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2 * cos(pi / x)
                                      ) if x != -1 else base_ring(2)
        gens = [
            MS.one() + MS({(i, j): val(coxeter_matrix[i, j])
                           for j in range(n)}) for i in range(n)
        ]
        FinitelyGeneratedMatrixGroup_generic.__init__(self,
                                                      n,
                                                      base_ring,
                                                      gens,
                                                      category=CoxeterGroups())
Example #30
0
    def regular_polygon(self, n, base_ring=QQ):
        """
        Return a regular polygon with n vertices.  Over the rational
        field the vertices may not be exact.

        INPUT:

        - ``n`` -- a positive integer, the number of vertices.

        - ``field`` -- either ``QQ`` or ``RDF``.

        EXAMPLES::

            sage: octagon = polytopes.regular_polygon(8)
            sage: len(octagon.vertices())
            8
        """
        npi = 3.14159265359
        verts = []
        for i in range(n):
            t = 2*npi*i/n
            verts.append([sin(t),cos(t)])
        verts = [[base_ring(RDF(x)) for x in y] for y in verts]
        return Polyhedron(vertices=verts, base_ring=base_ring)
Example #31
0
    def _eval_(self, n, m, theta, phi, **kwargs):
        r"""
        TESTS::

            sage: x, y = var('x y')
            sage: spherical_harmonic(1, 2, x, y)
            0
            sage: spherical_harmonic(1, -2, x, y)
            0
            sage: spherical_harmonic(1/2, 2, x, y)
            spherical_harmonic(1/2, 2, x, y)
            sage: spherical_harmonic(3, 2, x, y)
            1/8*sqrt(30)*sqrt(7)*cos(x)*e^(2*I*y)*sin(x)^2/sqrt(pi)
            sage: spherical_harmonic(3, 2, 1, 2)
            1/8*sqrt(30)*sqrt(7)*cos(1)*e^(4*I)*sin(1)^2/sqrt(pi)
            sage: spherical_harmonic(3 + I, 2., 1, 2)
            -0.351154337307488 - 0.415562233975369*I

        Check that :trac:`20939` is fixed::

            sage: ex = spherical_harmonic(3,2,1,2*pi/3)
            sage: QQbar(ex * sqrt(pi)/cos(1)/sin(1)^2).minpoly()
            x^4 + 105/32*x^2 + 11025/1024
        """
        if n in ZZ and m in ZZ and n > -1:
            if abs(m) > n:
                return ZZ(0)
            if m == 0 and theta.is_zero():
                return sqrt((2 * n + 1) / 4 / pi)
            from sage.arith.misc import factorial
            from sage.functions.trig import cos
            from sage.functions.orthogonal_polys import gen_legendre_P
            return (sqrt(
                factorial(n - m) * (2 * n + 1) / (4 * pi * factorial(n + m))) *
                    exp(I * m * phi) * gen_legendre_P(n, m, cos(theta)) *
                    (-1)**m).simplify_trig()
Example #32
0
    def regular_polygon(self, n, base_ring=QQ):
        """
        Return a regular polygon with n vertices.  Over the rational
        field the vertices may not be exact.

        INPUT:

        - ``n`` -- a positive integer, the number of vertices.

        - ``field`` -- either ``QQ`` or ``RDF``.

        EXAMPLES::

            sage: octagon = polytopes.regular_polygon(8)
            sage: len(octagon.vertices())
            8
        """
        npi = 3.14159265359
        verts = []
        for i in range(n):
            t = 2 * npi * i / n
            verts.append([sin(t), cos(t)])
        verts = [[base_ring(RDF(x)) for x in y] for y in verts]
        return Polyhedron(vertices=verts, base_ring=base_ring)
Example #33
0
 def f(t):
     return exp(I * ((cos(t) + I * sin(t)) *
                     arc_radius + arc_center)) * radius
        raise ValueError("Ellipse not implemented")
    first_unit_vector = first_vector / radius
    second_unit_vector = second_vector / radius
    normal_vector = second_vector - (second_vector *
                                     first_unit_vector) * first_unit_vector
    if norm(normal_vector) == 0:
        print(first_point, second_point)
        return
    normal_unit_vector = normal_vector / norm(normal_vector)
    scalar_product = first_unit_vector * second_unit_vector
    if abs(scalar_product) == 1:
        raise ValueError("The points are alligned")
    angle = arccos(scalar_product)
    var('t')
    return parametric_plot3d(
        center + first_vector * cos(t) + radius * normal_unit_vector * sin(t),
        (0, angle), **kwds)


def _arc(p, q, s, **kwds):
    #rewrite this to use polar_plot and get points to do filled triangles
    from sage.misc.functional import det
    from sage.plot.line import line
    from sage.misc.functional import norm
    from sage.symbolic.all import pi
    from sage.plot.arc import arc

    p, q, s = map(lambda x: vector(x), [p, q, s])

    # to avoid running into division by 0 we set to be colinear vectors that are
    # almost colinear
Example #35
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 #36
0
def _geodesic_between_two_points_d(x1,y1,x2,y2,z0=I):
    r""" Geodesic path between two points represented in the unit disc
         by the map w = (z-I)/(z+I)
    INPUTS:
    - ''(x1,y1)'' -- starting point (0<y1<=infinity)
    - ''(x2,y2)'' -- ending point   (0<y2<=infinity)
    - ''z0''  -- (default I) the point in the upper corresponding
                 to the point 0 in the disc. I.e. the transform is
                 w -> (z-I)/(z+I)
    OUTPUT:
    - ''ca'' -- a polygonal approximation of a circular arc centered
    at c and radius r, starting at t0 and ending at t1

    
    EXAMPLES::

        sage: l=_geodesic_between_two_points_d(0.1,0.2,0.0,0.5)
    
    """
    pi=RR.pi()
    from sage.plot.plot import line
    from sage.functions.trig import (cos,sin)    
    # First compute the points
    if(y1<0  or y2<0 ):
        raise ValueError,"Need points in the upper half-plane! Got y1=%s, y2=%s" %(y1,y2)
    if(y1==infinity):
        P1=CC(1 )
    else:
        P1=CC((x1+I*y1-z0)/(x1+I*y1-z0.conjugate()))
    if(y2==infinity):
        P2=CC(1 )
    else:
        P2=CC((x2+I*y2-z0)/(x2+I*y2-z0.conjugate()))
        # First find the endpoints of the completed geodesic in D
    if(x1==x2):
        a=CC((x1-z0)/(x1-z0.conjugate()))
        b=CC(1 )
    else:
        c=RR(y1**2 -y2**2 +x1**2 -x2**2 )/RR(2 *(x1-x2))
        r=RR(sqrt(y1**2 +(x1-c)**2 ))
        a=c-r
        b=c+r
        a=CC((a-z0)/(a-z0.conjugate()))
        b=CC((b-z0)/(b-z0.conjugate()))
    if( abs(a+b) < 1E-10 ): # On a diagonal
        return line([[P1.real(),P1.imag()],[P2.real(),P2.imag()]])
    th_a=a.argument()
    th_b=b.argument()
    # Compute the center of the circle in the disc model
    if( min(abs(b-1 ),abs(b+1 ))< 1E-10  and  min(abs(a-1 ),abs(a+1 ))>1E-10 ):
        c=b+I*(1 -b*cos(th_a))/sin(th_a)
    elif( min(abs(b-1 ),abs(b+1 ))> 1E-10  and  min(abs(a-1 ),abs(a+1 ))<1E-10 ):
        c=a+I*(1 -a*cos(th_b))/RR(sin(th_b))
    else:
        cx=(sin(th_b)-sin(th_a))/sin(th_b-th_a)
        c=cx+I*(1 -cx*cos(th_b))/RR(sin(th_b))
    # First find the endpoints of the completed geodesic
    r=abs(c-a)
    t1=CC(P1-c).argument()
    t2=CC(P2-c).argument()
    #print "t1,t2=",t1,t2
    return _circ_arc(t1,t2,c,r)
Example #37
0
def revolution_plot3d(curve,
                      trange,
                      phirange=None,
                      parallel_axis='z',
                      axis=(0, 0),
                      print_vector=False,
                      show_curve=False,
                      **kwds):
    r"""
    Return a plot of a revolved curve.

    There are three ways to call this function:

    - ``revolution_plot3d(f,trange)`` where `f` is a function located in the `x z` plane.

    - ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric curve on the `x z` plane.

    - ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be any parametric curve.

    INPUT:

    - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple.

    - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve.

    - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved.

    - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis.

    - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is:

        - 'z' - then axis is the point in which the revolution axis intersects the  `x y` plane.

        - 'x' - then axis is the point in which the revolution axis intersects the  `y z` plane.

        - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane.

    - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed.

    - ``show_curve`` - If True, the curve will be displayed.


    EXAMPLES:

    Let's revolve a simple function around different axes::

        sage: u = var('u')
        sage: f = u^2
        sage: revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        f = u**2
        P = revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).plot()
        sphinx_plot(P)

    If we move slightly the axis, we get a goblet-like surface::

        sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        f = u**2
        P = revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).plot()
        sphinx_plot(P)

    A common problem in calculus books, find the volume within the following revolution solid::

        sage: line = u
        sage: parabola = u^2
        sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x')
        sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x')
        sage: (sur1+sur2).show()

    .. PLOT::

        u = var('u')
        line = u
        parabola = u**2
        sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x')
        sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x')
        P = sur1 + sur2
        sphinx_plot(P)

    Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis,
    an axis in `(0,0)` (as the previous one) will produce a sphere-like surface::

        sage: u = var('u')
        sage: circle = (cos(u), sin(u))
        sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        circle = (cos(u), sin(u))
        P = revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5)
        sphinx_plot(P)

    An axis on `(0,y)` will produce a cylinder-like surface::

        sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        circle = (cos(u), sin(u))
        P = revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5)
        sphinx_plot(P)

    And any other axis will produce a torus-like surface::

        sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        circle = (cos(u), sin(u))
        P = revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5)
        sphinx_plot(P)

    Now, we can get another goblet-like surface by revolving a curve in 3d::

        sage: u = var('u')
        sage: curve = (u, cos(4*u), u^2)
        sage: P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z',axis=(1,.2), opacity=0.5)
        sage: P.show(aspect_ratio=(1,1,1))

    .. PLOT::

        u = var('u')
        curve = (u, cos(4*u), u**2)
        P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z', axis=(1,.2), opacity=0.5)
        sphinx_plot(P)

    A curvy curve with only a quarter turn::

        sage: u = var('u')
        sage: curve = (sin(3*u), .8*cos(4*u), cos(u))
        sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5).show(aspect_ratio=(1,1,1),frame=False)

    .. PLOT::

        u = var('u')
        curve = (sin(3*u), .8*cos(4*u), cos(u))
        P = revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5)
        sphinx_plot(P)

    One can also color the surface using a coloring function of two
    parameters and a colormap as follows. Note that the coloring
    function must take values in the interval [0,1]. ::

        sage: u, phi = var('u,phi')
        sage: def cf(u,phi): return sin(phi+u) ^ 2
        sage: curve = (1+u^2/4, 0, u)
        sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1))

    .. PLOT::

        u, phi = var('u,phi')
        def cf(u, phi): return sin(phi+u) ** 2
        curve = (1+u**2/4, 0, u)
        P = revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG))
        sphinx_plot(P)

    The first parameter of the coloring function will be identified with the
    parameter of the curve, and the second with the angle parameter.

    .. WARNING::

        This kind of coloring using a colormap can be visualized using
        Jmol, Tachyon (option ``viewer='tachyon'``) and Canvas3D
        (option ``viewer='canvas3d'`` in the notebook).

    Another colored example, illustrating that one can use (colormap, color function) instead of (color function, colormap)::

        sage: u, phi = var('u,phi')
        sage: def cf(u, phi): return float(2 * u / pi) % 1
        sage: curve = (sin(u), 0, u)
        sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis
        ....: ='z', color=(colormaps.brg, cf)).show(aspect_ratio=1)

    .. PLOT::

        u, phi = var('u,phi')
        def cf(u, phi): return float(2 * u / pi) % 1
        curve = (sin(u), 0, u)
        P = revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis='z', color=(colormaps.brg, cf))
        sphinx_plot(P)
    """
    from sage.symbolic.ring import SR
    from sage.symbolic.constants import pi
    from sage.misc.functional import sqrt
    from sage.functions.trig import sin
    from sage.functions.trig import cos
    from sage.functions.trig import atan2

    if parallel_axis not in ['x', 'y', 'z']:
        raise ValueError("parallel_axis must be either 'x', 'y', or 'z'.")

    vart = trange[0]

    if str(vart) == 'phi':
        phi = SR.var('fi')
    else:
        phi = SR.var('phi')

    if phirange is None:  # this if-else provides a phirange
        phirange = (phi, 0, 2 * pi)
    elif len(phirange) == 3:
        phi = phirange[0]
    else:
        phirange = (phi, phirange[0], phirange[1])

    if isinstance(curve, (tuple, list)):
        #this if-else provides a vector v to be plotted
        #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve
        #in the x-z plane.
        #if it is of length 3 it is interpreted as a parametric curve in 3d space

        if len(curve) == 2:
            x = curve[0]
            y = 0
            z = curve[1]
        elif len(curve) == 3:
            x = curve[0]
            y = curve[1]
            z = curve[2]
    else:
        x = vart
        y = 0
        z = curve

    phase = 0
    if parallel_axis == 'z':
        x0 = axis[0]
        y0 = axis[1]
        # (0,0) must be handled separately for the phase value
        if x0 != 0 or y0 != 0:
            phase = atan2(y - y0, x - x0)
        R = sqrt((x - x0)**2 + (y - y0)**2)
        v = (R * cos(phi + phase) + x0, R * sin(phi + phase) + y0, z)
    elif parallel_axis == 'x':
        y0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        if z0 != 0 or y0 != 0:
            phase = atan2(z - z0, y - y0)
        R = sqrt((y - y0)**2 + (z - z0)**2)
        v = (x, R * cos(phi + phase) + y0, R * sin(phi + phase) + z0)
    elif parallel_axis == 'y':
        x0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        if z0 != 0 or x0 != 0:
            phase = atan2(z - z0, x - x0)
        R = sqrt((x - x0)**2 + (z - z0)**2)
        v = (R * cos(phi + phase) + x0, y, R * sin(phi + phase) + z0)

    if print_vector:
        print(v)

    if show_curve:
        curveplot = parametric_plot3d((x, y, z),
                                      trange,
                                      thickness=2,
                                      rgbcolor=(1, 0, 0))
        return parametric_plot3d(v, trange, phirange, **kwds) + curveplot

    return parametric_plot3d(v, trange, phirange, **kwds)
Example #38
0
def Sphere(dim=None, radius=1, names=None, stereo2d=False, stereo_lim=None):
    """
    Generate a sphere embedded in Euclidean space.

    The shortcut operator ``.<,>`` can be used to specify the coordinates.

    INPUT:

    - ``dim`` -- (optional) the dimension of the sphere; if not specified,
      equals to the number of coordinate names
    - ``radius`` -- (default: ``1``) radius of the sphere
    - ``names`` -- (default: ``None``) name of the coordinates,
      automatically set by the shortcut operator
    - ``stereo2d`` -- (default: ``False``) if ``True``, defines only the
      stereographic charts, only implemented in 2d
    - ``stereo_lim`` -- (default: ``None``) parameter used to restrict the
      span of the stereographic charts, so that they don't cover the whole
      sphere; valid domain will be ``x**2 + y**2 < stereo_lim**2``

    OUTPUT:

    - Riemannian manifold

    EXAMPLES::

        sage: S.<th, ph> = manifolds.Sphere()
        sage: S
        2-dimensional Riemannian submanifold S embedded in the Euclidean
         space E^3
        sage: S.atlas()
        [Chart (S, (th, ph))]
        sage: S.metric().display()
        gamma = dth*dth + sin(th)^2 dph*dph

        sage: S = manifolds.Sphere(2, stereo2d=True)  # long time
        sage: S  # long time
        2-dimensional Riemannian submanifold S embedded in the Euclidean
         space E^3
        sage: S.metric().display()  # long time
        gamma = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx*dx
         + 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dy*dy
    """
    from sage.functions.trig import cos, sin, atan, atan2
    from sage.functions.other import sqrt
    from sage.symbolic.constants import pi
    from sage.misc.misc_c import prod
    from sage.manifolds.manifold import Manifold
    from sage.manifolds.differentiable.euclidean import EuclideanSpace

    if dim is None:
        if names is None:
            raise ValueError("either the names or the dimension must be specified")
        dim = len(names)
    else:
        if names is not None and dim != len(names):
            raise ValueError("the number of coordinates does not match the dimension")

    if stereo2d:
        if dim != 2:
            raise NotImplementedError("stereographic charts only "
                                      "implemented for 2d spheres")
        E = EuclideanSpace(3, names=("X", "Y", "Z"))
        S2 = Manifold(dim, 'S', ambient=E, structure='Riemannian')
        U = S2.open_subset('U')
        V = S2.open_subset('V')
        stereoN = U.chart(names=("x", "y"))
        x, y = stereoN[:]
        stereoS = V.chart(names=("xp", "yp"))
        xp, yp = stereoS[:]
        if stereo_lim is not None:
            stereoN.add_restrictions(x**2+y**2 < stereo_lim**2)
            stereoS.add_restrictions(xp**2+yp**2 < stereo_lim**2)

        stereoN_to_S = stereoN.transition_map(stereoS,
          (x / (x**2 + y**2), y / (x**2 + y**2)), intersection_name='W',
          restrictions1=x**2 + y**2 != 0, restrictions2=xp**2+yp**2!=0)
        stereoN_to_S.set_inverse(xp / (xp**2 + yp**2), yp / (xp**2 + yp**2),
                                 check=False)
        W = U.intersection(V)
        stereoN_W = stereoN.restrict(W)
        stereoS_W = stereoS.restrict(W)
        A = W.open_subset('A', coord_def={stereoN_W: (y != 0, x < 0),
                                          stereoS_W: (yp != 0, xp < 0)})
        stereoN_A = stereoN_W.restrict(A)
        if names is None:
            names = tuple(["phi_{}:(0,pi)".format(i) for i in range(dim - 1)] +
                          ["phi_{}:(-pi,pi):periodic".format(dim - 1)])
        else:
            names = tuple([names[i] + ":(0,pi)" for i in range(dim - 1)] +
                          [names[dim - 1] + ":(-pi,pi):periodic"])
        spher = A.chart(names=names)
        th, ph = spher[:]
        spher_to_stereoN = spher.transition_map(stereoN_A, (sin(th)*cos(ph) / (1-cos(th)),
                                                            sin(th)*sin(ph) / (1-cos(th))))
        spher_to_stereoN.set_inverse(2*atan(1/sqrt(x**2+y**2)), atan2(-y, -x)+pi,
                                     check=False)
        stereoN_to_S_A = stereoN_to_S.restrict(A)
        stereoN_to_S_A * spher_to_stereoN # generates spher_to_stereoS
        stereoS_to_N_A = stereoN_to_S.inverse().restrict(A)
        spher_to_stereoN.inverse() * stereoS_to_N_A  # generates stereoS_to_spher

        coordfunc1 = [sin(th)*cos(ph), sin(th)*sin(ph), cos(th)]
        coordfunc2 = [2*x/(1+x**2+y**2), 2*y/(1+x**2+y**2), (x**2+y**2-1)/(1+x**2+y**2)]
        coordfunc3 = [2*xp/(1+xp**2+yp**2), 2*yp/(1+xp**2+yp**2),(1-xp**2-yp**2)/(1+xp**2+yp**2)]
        imm = S2.diff_map(E, {(spher, E.default_chart()): coordfunc1,
                              (stereoN, E.default_chart()): coordfunc2,
                              (stereoS, E.default_chart()): coordfunc3})
        S2.set_embedding(imm)
        S2.induced_metric()

        return S2

    if dim != 2:
        raise NotImplementedError("only implemented for 2 dimensional spheres")

    E = EuclideanSpace(3, symbols='X Y Z')
    M = Manifold(dim, 'S', ambient=E, structure='Riemannian')
    if names is None:
        names = tuple(["phi_{}:(0,pi)".format(i) for i in range(dim-1)] +
                      ["phi_{}:(-pi,pi):periodic".format(dim-1)])
    else:
        names = tuple([names[i]+":(0,pi)"for i in range(dim - 1)] +
                      [names[dim-1]+":(-pi,pi):periodic"])
    C = M.chart(names=names)
    M._first_ngens = C._first_ngens
    phi = M._first_ngens(dim)[:]
    coordfunc = ([radius * prod(sin(phi[j]) for j in range(dim))] +
                 [radius * cos(phi[i]) * prod(sin(phi[j]) for j in range(i))
                  for i in range(dim)])
    imm = M.diff_map(E, coordfunc)
    M.set_embedding(imm)
    M.induced_metric()
    return M
Example #39
0
 def val(x):
     if x == -1:
         return 2
     else:
         return base_ring(2 * cos(pi / x))
Example #40
0
File: plot.py Project: biasse/sage
def barycentric_projection_matrix(n, angle=0):
    r"""
    Returns a family of `n+1` vectors evenly spaced in a real vector space of dimension `n`

    Those vectors are of norm `1`, the scalar product between any two
    vector is `1/n`, thus the distance between two tips is constant.

    The family is built recursively and uniquely determined by the
    following property: the last vector is `(0,\dots,0,-1)`, and the
    projection of the first `n` vectors in dimension `n-1`, after
    appropriate rescaling to norm `1`, retrieves the family for `n-1`.

    OUTPUT:

    A matrix with `n+1` columns of height `n` with rational or
    symbolic coefficients.

    EXAMPLES:

    One vector in dimension `0`::

        sage: from sage.combinat.root_system.root_lattice_realizations import barycentric_projection_matrix
        sage: m = barycentric_projection_matrix(0); m
        []
        sage: matrix(QQ,0,1).nrows()
        0
        sage: matrix(QQ,0,1).ncols()
        1

    Two vectors in dimension 1::

        sage: barycentric_projection_matrix(1)
        [ 1 -1]

    Three vectors in dimension 2::

        sage: barycentric_projection_matrix(2)
        [ 1/2*sqrt(3) -1/2*sqrt(3)            0]
        [         1/2          1/2           -1]

    Four vectors in dimension 3::

        sage: m = barycentric_projection_matrix(3); m
        [ 1/3*sqrt(3)*sqrt(2) -1/3*sqrt(3)*sqrt(2)                    0                    0]
        [         1/3*sqrt(2)          1/3*sqrt(2)         -2/3*sqrt(2)                    0]
        [                 1/3                  1/3                  1/3                   -1]

    The columns give four vectors that sum up to zero::

        sage: sum(m.columns())
        (0, 0, 0)

    and have regular mutual angles::

        sage: m.transpose()*m
        [   1 -1/3 -1/3 -1/3]
        [-1/3    1 -1/3 -1/3]
        [-1/3 -1/3    1 -1/3]
        [-1/3 -1/3 -1/3    1]

    Here is a plot of them::

        sage: sum(arrow((0,0,0),x) for x in m.columns())

    For 2D drawings of root systems, it is desirable to rotate the
    result to match with the usual conventions::

        sage: barycentric_projection_matrix(2, angle=2*pi/3)
        [         1/2           -1          1/2]
        [ 1/2*sqrt(3)            0 -1/2*sqrt(3)]

    TESTS::

        sage: for n in range(1, 7):
        ...       m = barycentric_projection_matrix(n)
        ...       assert sum(m.columns()).is_zero()
        ...       assert matrix(QQ, n+1,n+1, lambda i,j: 1 if i==j else -1/n) == m.transpose()*m

    """
    from sage.matrix.constructor import matrix
    from sage.functions.other import sqrt
    n = ZZ(n)
    if n == 0:
        return matrix(QQ, 0, 1)
    a = 1 / n
    b = sqrt(1 - a**2)
    result = b * barycentric_projection_matrix(n - 1)
    result = result.augment(vector([0] * (n - 1)))
    result = result.stack(matrix([[a] * n + [-1]]))
    assert sum(result.columns()).is_zero()
    if angle and n == 2:
        from sage.functions.trig import sin
        from sage.functions.trig import cos
        rotation = matrix([[sin(angle), cos(angle)], [-cos(angle),
                                                      sin(angle)]])
        result = rotation * result
    result.set_immutable()
    return result
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 #42
0
    def plot(self, **kwds):
        r"""
        Plot the initial triangulation associated to ``self``.

        INPUT:

        - ``radius`` - the radius of the disk; by default the length of
          the circle is the number of vertices
        - ``points_color`` - the color of the vertices; default 'black'
        - ``points_size`` - the size of the vertices; default 7
        - ``triangulation_color`` - the color of the arcs; default 'black'
        - ``triangulation_thickness`` - the thickness of the arcs; default 0.5
        - ``shading_color`` - the color of the shading used on neuter
          intervals; default 'lightgray'
        - ``reflections_color`` - the color of the reflection axes; default
          'blue'
        - ``reflections_thickness`` - the thickness of the reflection axes;
          default 1

        EXAMPLES::

            sage: Y = SineGordonYsystem('A',(6,4,3));
            sage: Y.plot()      # not tested
        """
        # Set up plotting options
        if 'radius' in kwds:
            radius = kwds['radius']
        else:
            radius = ceil(self.r() / (2 * pi))
        points_opts = {}
        if 'points_color' in kwds:
            points_opts['color'] = kwds['points_color']
        else:
            points_opts['color'] = 'black'
        if 'points_size' in kwds:
            points_opts['size'] = kwds['points_size']
        else:
            points_opts['size'] = 7
        triangulation_opts = {}
        if 'triangulation_color' in kwds:
            triangulation_opts['color'] = kwds['triangulation_color']
        else:
            triangulation_opts['color'] = 'black'
        if 'triangulation_thickness' in kwds:
            triangulation_opts['thickness'] = kwds['triangulation_thickness']
        else:
            triangulation_opts['thickness'] = 0.5
        shading_opts = {}
        if 'shading_color' in kwds:
            shading_opts['color'] = kwds['shading_color']
        else:
            shading_opts['color'] = 'lightgray'
        reflections_opts = {}
        if 'reflections_color' in kwds:
            reflections_opts['color'] = kwds['reflections_color']
        else:
            reflections_opts['color'] = 'blue'
        if 'reflections_thickness' in kwds:
            reflections_opts['thickness'] = kwds['reflections_thickness']
        else:
            reflections_opts['thickness'] = 1
        # Helper functions

        def triangle(x):
            (a, b) = sorted(x[:2])
            for p in self.vertices():
                if (p, a) in self.triangulation() or (a, p) in self.triangulation():
                    if (p, b) in self.triangulation() or (b, p) in self.triangulation():
                        if p < a or p > b:
                            return sorted((a, b, p))

        def plot_arc(radius, p, q, **opts):
            # plot the arc from p to q differently depending on the type of self
            p = ZZ(p)
            q = ZZ(q)
            t = var('t')
            if p - q in [1, -1]:
                def f(t):
                    return (radius * cos(t), radius * sin(t))
                (p, q) = sorted([p, q])
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                return parametric_plot(f(t), (t, angle_q, angle_p), **opts)
            if self.type() == 'A':
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                if angle_p < angle_q:
                    angle_p += 2 * pi
                internal_angle = angle_p - angle_q
                if internal_angle > pi:
                    (angle_p, angle_q) = (angle_q + 2 * pi, angle_p)
                    internal_angle = angle_p - angle_q
                angle_center = (angle_p+angle_q) / 2
                hypotenuse = radius / cos(internal_angle / 2)
                radius_arc = hypotenuse * sin(internal_angle / 2)
                center = (hypotenuse * cos(angle_center),
                          hypotenuse * sin(angle_center))
                center_angle_p = angle_p + pi / 2
                center_angle_q = angle_q + 3 * pi / 2

                def f(t):
                    return (radius_arc * cos(t) + center[0],
                            radius_arc * sin(t) + center[1])
                return parametric_plot(f(t), (t, center_angle_p,
                                              center_angle_q), **opts)
            elif self.type() == 'D':
                if p >= q:
                    q += self.r()
                px = -2 * pi * p / self.r() + pi / 2
                qx = -2 * pi * q / self.r() + pi / 2
                arc_radius = (px - qx) / 2
                arc_center = qx + arc_radius

                def f(t):
                    return exp(I * ((cos(t) + I * sin(t)) *
                                    arc_radius + arc_center)) * radius
                return parametric_plot((real_part(f(t)), imag_part(f(t))),
                                       (t, 0, pi), **opts)

        def vertex_to_angle(v):
            # v==0 corresponds to pi/2
            return -2 * pi * RR(v) / self.r() + 5 * pi / 2

        # Begin plotting
        P = Graphics()
        # Shade neuter intervals
        neuter_intervals = [x for x in flatten(self.intervals()[:-1],
                                               max_level=1)
                            if x[2] in ["NR", "NL"]]
        shaded_triangles = map(triangle, neuter_intervals)
        for (p, q, r) in shaded_triangles:
            points = list(plot_arc(radius, p, q)[0])
            points += list(plot_arc(radius, q, r)[0])
            points += list(reversed(plot_arc(radius, p, r)[0]))
            P += polygon2d(points, **shading_opts)
        # Disk boundary
        P += circle((0, 0), radius, **triangulation_opts)
        # Triangulation
        for (p, q) in self.triangulation():
            P += plot_arc(radius, p, q, **triangulation_opts)
        if self.type() == 'D':
            s = radius / 50.0
            P += polygon2d([(s, 5 * s), (s, 7 * s),
                            (3 * s, 5 * s), (3 * s, 7 * s)],
                           color=triangulation_opts['color'])
            P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)],
                              [(2 * s, 10 * s), (s, 20 * s)],
                              [(0, 30 * s), (0, radius)]],
                             **triangulation_opts)
            P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)],
                              [(-2 * s, 10 * s), (-s, 20 * s)],
                              [(0, 30 * s), (0, radius)]],
                             **triangulation_opts)
            P += point((0, 0), zorder=len(P), **points_opts)
        # Vertices
        v_points = {x: (radius * cos(vertex_to_angle(x)),
                        radius * sin(vertex_to_angle(x)))
                    for x in self.vertices()}
        for v in v_points:
            P += point(v_points[v], zorder=len(P), **points_opts)
        # Reflection axes
        P += line([(0, 1.1 * radius), (0, -1.1 * radius)],
                  zorder=len(P), **reflections_opts)
        axis_angle = vertex_to_angle(-0.5 * (self.rk() + (1, 1))[1])
        (a, b) = (1.1 * radius * cos(axis_angle),
                  1.1 * radius * sin(axis_angle))
        P += line([(a, b), (-a, -b)], zorder=len(P), **reflections_opts)
        # Wrap up
        P.set_aspect_ratio(1)
        P.axes(False)
        return P
Example #43
0
 def f(t):
     return (radius * cos(t), radius * sin(t))
Example #44
0
 def f(t):
     return (radius_arc * cos(t) + center[0],
             radius_arc * sin(t) + center[1])
Example #45
0
 def val(x):
     if x > -1:
         return -R(cos(pi / SR(x)))
     else:
         return R(x)
Example #46
0
def _geodesic_between_two_points_d(x1, y1, x2, y2, z0=I):
    r""" Geodesic path between two points represented in the unit disc
         by the map w = (z-I)/(z+I)
    INPUTS:
    - ''(x1,y1)'' -- starting point (0<y1<=infinity)
    - ''(x2,y2)'' -- ending point   (0<y2<=infinity)
    - ''z0''  -- (default I) the point in the upper corresponding
                 to the point 0 in the disc. I.e. the transform is
                 w -> (z-I)/(z+I)
    OUTPUT:
    - ''ca'' -- a polygonal approximation of a circular arc centered
    at c and radius r, starting at t0 and ending at t1

    
    EXAMPLES::

        sage: l=_geodesic_between_two_points_d(0.1,0.2,0.0,0.5)
    
    """
    pi = RR.pi()
    from sage.plot.plot import line
    from sage.functions.trig import (cos, sin)
    # First compute the points
    if (y1 < 0 or y2 < 0):
        raise ValueError, "Need points in the upper half-plane! Got y1=%s, y2=%s" % (
            y1, y2)
    if (y1 == infinity):
        P1 = CC(1)
    else:
        P1 = CC((x1 + I * y1 - z0) / (x1 + I * y1 - z0.conjugate()))
    if (y2 == infinity):
        P2 = CC(1)
    else:
        P2 = CC((x2 + I * y2 - z0) / (x2 + I * y2 - z0.conjugate()))
        # First find the endpoints of the completed geodesic in D
    if (x1 == x2):
        a = CC((x1 - z0) / (x1 - z0.conjugate()))
        b = CC(1)
    else:
        c = RR(y1**2 - y2**2 + x1**2 - x2**2) / RR(2 * (x1 - x2))
        r = RR(sqrt(y1**2 + (x1 - c)**2))
        a = c - r
        b = c + r
        a = CC((a - z0) / (a - z0.conjugate()))
        b = CC((b - z0) / (b - z0.conjugate()))
    if (abs(a + b) < 1E-10):  # On a diagonal
        return line([[P1.real(), P1.imag()], [P2.real(), P2.imag()]])
    th_a = a.argument()
    th_b = b.argument()
    # Compute the center of the circle in the disc model
    if (min(abs(b - 1), abs(b + 1)) < 1E-10
            and min(abs(a - 1), abs(a + 1)) > 1E-10):
        c = b + I * (1 - b * cos(th_a)) / sin(th_a)
    elif (min(abs(b - 1), abs(b + 1)) > 1E-10
          and min(abs(a - 1), abs(a + 1)) < 1E-10):
        c = a + I * (1 - a * cos(th_b)) / RR(sin(th_b))
    else:
        cx = (sin(th_b) - sin(th_a)) / sin(th_b - th_a)
        c = cx + I * (1 - cx * cos(th_b)) / RR(sin(th_b))
    # First find the endpoints of the completed geodesic
    r = abs(c - a)
    t1 = CC(P1 - c).argument()
    t2 = CC(P2 - c).argument()
    #print "t1,t2=",t1,t2
    return _circ_arc(t1, t2, c, r)
Example #47
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        n = coxeter_matrix.rank()
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
        gens = [MS.one() + MC(MS, entries={(i, j): val(coxeter_matrix[index_set[i], index_set[j]])
                                           for j in range(n)},
                              coerce=True, copy=True)
                for i in range(n)]
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        if self._matrix.is_finite():
            category = category.Finite()
        else:
            category = category.Infinite()
        FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(n), base_ring,
                                                      gens, category=category)
Example #48
0
def signal_to_noise_particle(a,
                             r0,
                             theta,
                             psd,
                             t_obs,
                             BH_time_scale,
                             m_min=1,
                             m_max=None,
                             scale=1,
                             approximation=None):
    r"""
    Evaluate the signal-to-noise ratio of gravitational radiation emitted
    by a single orbiting particle observed in a detector of a given power
    spectral density.

    INPUT:

    - ``a`` -- BH angular momentum parameter (in units of `M`, the BH mass)
    - ``r0`` -- Boyer-Lindquist radius of the orbit (in units of `M`)
    - ``theta`` -- Boyer-Lindquist colatitute `\theta` of the observer
    - ``psd`` -- function with a single argument (`f`) representing the
      detector's one-sided noise power spectral density `S_n(f)` (see e.g. :func:`.lisa_detector.power_spectral_density`)
    - ``t_obs`` -- observation period, in the same time unit as `S_n(f)`
    - ``BH_time_scale`` -- value of `M` in the same time unit as `S_n(f)`; if
      `S_n(f)` is provided in `\mathrm{Hz}^{-1}`, then ``BH_time_scale`` must
      be `M` expressed in seconds.
    - ``m_min`` -- (default: 1) lower bound in the summation over the Fourier
      mode `m`
    - ``m_max`` -- (default: ``None``) upper bound in the summation over the
      Fourier mode `m`; if ``None``, ``m_max`` is set to 10 for `r_0 \leq 20 M`
      and to 5 for `r_0 > 20 M`
    - ``scale`` -- (default: ``1``) scale factor by which `h(t)` must be
      multiplied to get the actual signal; this should by `\mu/r`, where `\mu`
      is the particle mass and `r` the radial coordinate of the detector
    - ``approximation`` -- (default: ``None``) string describing the
      computational method for the signal; allowed values are

      - ``None``: exact computation
      - ``'quadrupole'``: quadrupole approximation; see
        :func:`.gw_particle.h_particle_quadrupole`
      - ``'1.5PN'`` (only for ``a=0``): 1.5-post-Newtonian expansion following
        E. Poisson, Phys. Rev. D **47**, 1497 (1993)
        [:doi:`10.1103/PhysRevD.47.1497`]

    OUTPUT:

    - the signal-to-noise ratio `\rho`

    EXAMPLES:

    Let us evaluate the SNR of the gravitational signal generated by a 1-solar
    mass object orbiting at the ISCO of Sgr A* observed by LISA during 1 day::

        sage: from kerrgeodesic_gw import (signal_to_noise_particle,
        ....:                              lisa_detector, astro_data)
        sage: a, r0 = 0., 6.
        sage: theta = pi/2
        sage: t_obs = 24*3600  # 1 day in seconds
        sage: BH_time_scale = astro_data.SgrA_mass_s  # Sgr A* mass in seconds
        sage: psd = lisa_detector.power_spectral_density_RCLfit
        sage: mu_ov_r = astro_data.Msol_m / astro_data.dSgrA  # mu/r
        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r)
        7565.6612762972445

    Using the quadrupole approximation::

        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r,
        ....:                          approximation='quadrupole')
        5230.403692883996

    Using the 1.5-PN approximation (``m_max`` has to be at most 5)::

        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r,
        ....:                          approximation='1.5PN', m_max=5)
        7601.344521598601

    For large values of `r_0`, the 1.5-PN approximation and the quadrupole one
    converge::

        sage: r0 = 100
        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r,
        ....:                          approximation='quadrupole')
        0.0030532227165507805
        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r,
        ....:                          approximation='1.5PN')
        0.0031442135473417616

    ::

        sage: r0 = 1000
        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r,
        ....:                          approximation='quadrupole')
        9.663790254603111e-09
        sage: signal_to_noise_particle(a, r0, theta, psd, t_obs,  # tol 1.0e-13
        ....:                          BH_time_scale, scale=mu_ov_r,
        ....:                          approximation='1.5PN')
        9.687469292984858e-09

    """
    from .gw_particle import h_amplitude_particle_fourier
    from .zinf import _lmax
    if approximation == 'quadrupole':
        fm2 = RDF(1. / (pi * r0**1.5) / BH_time_scale)
        return RDF(2. * scale / r0 *
                   sqrt(t_obs / psd(fm2) *
                        (1 + 6 * cos(theta)**2 + cos(theta)**4)))
    if m_max is None:
        m_max = _lmax(a, r0)
    # Orbital frequency in the same time units as S_n(f) (generally seconds):
    f0 = RDF(1. / (2 * pi * (r0**1.5 + a)) / BH_time_scale)
    rho2 = 0
    for m in range(m_min, m_max + 1):
        hmp, hmc = h_amplitude_particle_fourier(m,
                                                a,
                                                r0,
                                                theta,
                                                l_max=m_max,
                                                algorithm_Zinf=approximation)
        rho2 += (hmp**2 + hmc**2) / psd(m * f0)
    return sqrt(rho2 * t_obs) * scale
Example #49
0
    def plot(self, show_box=False, colors=["white", "lightgray", "darkgray"]):
        r"""
        Return a plot of ``self``.

        INPUT:

        - ``show_box`` -- boolean (default: ``False``); if ``True``,
          also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes

        - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``)
          list ``[A, B, C]`` of 3 strings representing colors

        EXAMPLES::

            sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]])
            sage: PP.plot()
            Graphics object consisting of 27 graphics primitives
        """
        from sage.functions.trig import cos, sin
        from sage.plot.polygon import polygon
        from sage.symbolic.constants import pi
        from sage.plot.plot import plot
        Uside = [[0, 0], [cos(-pi / 6), sin(-pi / 6)], [0, -1],
                 [cos(7 * pi / 6), sin(7 * pi / 6)]]
        Lside = [[0, 0], [cos(-pi / 6), sin(-pi / 6)],
                 [cos(pi / 6), sin(pi / 6)], [0, 1]]
        Rside = [[0, 0], [0, 1], [cos(5 * pi / 6),
                                  sin(5 * pi / 6)],
                 [cos(7 * pi / 6), sin(7 * pi / 6)]]
        Xdir = [cos(7 * pi / 6), sin(7 * pi / 6)]
        Ydir = [cos(-pi / 6), sin(-pi / 6)]
        Zdir = [0, 1]

        def move(side, i, j, k):
            return [[
                P[0] + i * Xdir[0] + j * Ydir[0] + k * Zdir[0],
                P[1] + i * Xdir[1] + j * Ydir[1] + k * Zdir[1]
            ] for P in side]

        def add_topside(i, j, k):
            return polygon(move(Uside, i, j, k),
                           edgecolor="black",
                           color=colors[0])

        def add_leftside(i, j, k):
            return polygon(move(Lside, i, j, k),
                           edgecolor="black",
                           color=colors[1])

        def add_rightside(i, j, k):
            return polygon(move(Rside, i, j, k),
                           edgecolor="black",
                           color=colors[2])

        TP = plot([])
        for r in range(len(self.z_tableau())):
            for c in range(len(self.z_tableau()[r])):
                if self.z_tableau()[r][c] > 0 or show_box:
                    TP += add_topside(r, c, self.z_tableau()[r][c])
        for r in range(len(self.y_tableau())):
            for c in range(len(self.y_tableau()[r])):
                if self.y_tableau()[r][c] > 0 or show_box:
                    TP += add_rightside(c, self.y_tableau()[r][c], r)
        for r in range(len(self.x_tableau())):
            for c in range(len(self.x_tableau()[r])):
                if self.x_tableau()[r][c] > 0 or show_box:
                    TP += add_leftside(self.x_tableau()[r][c], r, c)
        TP.axes(show=False)
        return TP
    def __init__(self, sides, i_angle, center, options):
        """
        Initialize HyperbolicRegularPolygon.

        EXAMPLES::

            sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon
            sage: print(HyperbolicRegularPolygon(5,pi/2,I, {}))
            Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I)
        """
        self.center = CC(center)
        if self.center.imag() <= 0:
            raise ValueError(
                "center: %s is not a valid point in the upper half plane model of the hyperbolic plane"
                % (self.center))
        if sides < 3:
            raise ValueError(
                "degenerated polygons (sides<=2) are not supported")
        if i_angle <= 0 or i_angle >= pi:
            raise ValueError("interior angle %s must be in (0, pi) interval" %
                             (i_angle))
        if pi * (sides - 2) - sides * i_angle <= 0:
            raise ValueError(
                "there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s"
                % (sides, pi * (sides - 2) / sides))
        self.sides = sides
        self.i_angle = i_angle
        beta = 2 * pi / self.sides  # compute the rotation angle to be used ahead
        alpha = self.i_angle / Integer(2)
        I = CC(0, 1)
        # compute using cosine theorem the radius of the circumscribed circle
        # using the triangle formed by the radius and the three known angles
        r = arccosh(cot(alpha) * (1 + cos(beta)) / sin(beta))

        # The first point will be always on the imaginary axis limited
        # to 8 digits for efficiency in the subsequent calculations.
        z_0 = [I * (e**r).n(digits=8)]

        # Compute the dilation isometry used to move the center
        # from I to the imaginary part of the given center.
        scale = self.center.imag()

        # Compute the parabolic isometry to move the center to the
        # real part of the given center.
        h_disp = self.center.real()

        d_z_k = [z_0[0] * scale + h_disp
                 ]  #d_k has the points for the polygon in the given center
        z_k = z_0  #z_k has the Re(z)>0 vertices for the I centered polygon
        r_z_k = []  #r_z_k has the Re(z)<0 vertices
        if is_odd(self.sides):
            vert = (self.sides - 1) // 2
        else:
            vert = self.sides // 2 - 1
        for k in range(vert):
            # Compute with 8 digits to accelerate calculations
            new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8)
            z_k = z_k + [new_z_k]
            d_z_k = d_z_k + [new_z_k * scale + h_disp]
            r_z_k = [-(new_z_k).conjugate() * scale + h_disp] + r_z_k
        if is_odd(self.sides):
            HyperbolicPolygon.__init__(self, d_z_k + r_z_k, options)
        else:
            z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp]
            HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, options)
Example #51
0
File: plot.py Project: biasse/sage
def barycentric_projection_matrix(n, angle=0):
    r"""
    Returns a family of `n+1` vectors evenly spaced in a real vector space of dimension `n`

    Those vectors are of norm `1`, the scalar product between any two
    vector is `1/n`, thus the distance between two tips is constant.

    The family is built recursively and uniquely determined by the
    following property: the last vector is `(0,\dots,0,-1)`, and the
    projection of the first `n` vectors in dimension `n-1`, after
    appropriate rescaling to norm `1`, retrieves the family for `n-1`.

    OUTPUT:

    A matrix with `n+1` columns of height `n` with rational or
    symbolic coefficients.

    EXAMPLES:

    One vector in dimension `0`::

        sage: from sage.combinat.root_system.root_lattice_realizations import barycentric_projection_matrix
        sage: m = barycentric_projection_matrix(0); m
        []
        sage: matrix(QQ,0,1).nrows()
        0
        sage: matrix(QQ,0,1).ncols()
        1

    Two vectors in dimension 1::

        sage: barycentric_projection_matrix(1)
        [ 1 -1]

    Three vectors in dimension 2::

        sage: barycentric_projection_matrix(2)
        [ 1/2*sqrt(3) -1/2*sqrt(3)            0]
        [         1/2          1/2           -1]

    Four vectors in dimension 3::

        sage: m = barycentric_projection_matrix(3); m
        [ 1/3*sqrt(3)*sqrt(2) -1/3*sqrt(3)*sqrt(2)                    0                    0]
        [         1/3*sqrt(2)          1/3*sqrt(2)         -2/3*sqrt(2)                    0]
        [                 1/3                  1/3                  1/3                   -1]

    The columns give four vectors that sum up to zero::

        sage: sum(m.columns())
        (0, 0, 0)

    and have regular mutual angles::

        sage: m.transpose()*m
        [   1 -1/3 -1/3 -1/3]
        [-1/3    1 -1/3 -1/3]
        [-1/3 -1/3    1 -1/3]
        [-1/3 -1/3 -1/3    1]

    Here is a plot of them::

        sage: sum(arrow((0,0,0),x) for x in m.columns())

    For 2D drawings of root systems, it is desirable to rotate the
    result to match with the usual conventions::

        sage: barycentric_projection_matrix(2, angle=2*pi/3)
        [         1/2           -1          1/2]
        [ 1/2*sqrt(3)            0 -1/2*sqrt(3)]

    TESTS::

        sage: for n in range(1, 7):
        ...       m = barycentric_projection_matrix(n)
        ...       assert sum(m.columns()).is_zero()
        ...       assert matrix(QQ, n+1,n+1, lambda i,j: 1 if i==j else -1/n) == m.transpose()*m

    """
    from sage.matrix.constructor import matrix
    from sage.functions.other import sqrt
    n = ZZ(n)
    if n == 0:
        return matrix(QQ, 0, 1)
    a = 1/n
    b = sqrt(1-a**2)
    result = b * barycentric_projection_matrix(n-1)
    result = result.augment(vector([0]*(n-1)))
    result = result.stack(matrix([[a]*n+[-1]]))
    assert sum(result.columns()).is_zero()
    if angle and n == 2:
        from sage.functions.trig import sin
        from sage.functions.trig import cos
        rotation = matrix([[sin(angle), cos(angle)],[-cos(angle), sin(angle)]])
        result = rotation * result
    result.set_immutable()
    return result
Example #52
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
Example #53
0
def Kerr(m=1, a=0, coordinates="BL", names=None):
    """
    Generate a Kerr spacetime.

    A Kerr spacetime is a 4 dimensional manifold describing a rotating black
    hole. Two coordinate systems are implemented: Boyer-Lindquist and Kerr
    (3+1 version).

    The shortcut operator ``.<,>`` can be used to specify the coordinates.

    INPUT:

    - ``m`` -- (default: ``1``) mass of the black hole in natural units
      (`c=1`, `G=1`)
    - ``a`` -- (default: ``0``) angular momentum in natural units; if set to
      ``0``, the resulting spacetime corresponds to a Schwarzschild black hole
    - ``coordinates`` -- (default: ``"BL"``) either ``"BL"`` for
      Boyer-Lindquist coordinates or ``"Kerr"`` for Kerr coordinates (3+1
      version)
    - ``names`` -- (default: ``None``) name of the coordinates,
      automatically set by the shortcut operator

    OUTPUT:

    - Lorentzian manifold

    EXAMPLES::

        sage: m, a = var('m, a')
        sage: K = manifolds.Kerr(m, a)
        sage: K
        4-dimensional Lorentzian manifold M
        sage: K.atlas()
        [Chart (M, (t, r, th, ph))]
        sage: K.metric().display()
        g = (2*m*r/(a^2*cos(th)^2 + r^2) - 1) dt⊗dt
         + 2*a*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) dt⊗dph
         + (a^2*cos(th)^2 + r^2)/(a^2 - 2*m*r + r^2) dr⊗dr
         + (a^2*cos(th)^2 + r^2) dth⊗dth
         + 2*a*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) dph⊗dt
         + (2*a^2*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) + a^2 + r^2)*sin(th)^2 dph⊗dph

        sage: K.<t, r, th, ph> = manifolds.Kerr()
        sage: K
        4-dimensional Lorentzian manifold M
        sage: K.metric().display()
        g = (2/r - 1) dt⊗dt + r^2/(r^2 - 2*r) dr⊗dr
         + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
        sage: K.default_chart().coord_range()
        t: (-oo, +oo); r: (0, +oo); th: (0, pi); ph: [-pi, pi] (periodic)

        sage: m, a = var('m, a')
        sage: K.<t, r, th, ph> = manifolds.Kerr(m, a, coordinates="Kerr")
        sage: K
        4-dimensional Lorentzian manifold M
        sage: K.atlas()
        [Chart (M, (t, r, th, ph))]
        sage: K.metric().display()
        g = (2*m*r/(a^2*cos(th)^2 + r^2) - 1) dt⊗dt
         + 2*m*r/(a^2*cos(th)^2 + r^2) dt⊗dr
         - 2*a*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) dt⊗dph
         + 2*m*r/(a^2*cos(th)^2 + r^2) dr⊗dt
         + (2*m*r/(a^2*cos(th)^2 + r^2) + 1) dr⊗dr
         - a*(2*m*r/(a^2*cos(th)^2 + r^2) + 1)*sin(th)^2 dr⊗dph
         + (a^2*cos(th)^2 + r^2) dth⊗dth
         - 2*a*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) dph⊗dt
         - a*(2*m*r/(a^2*cos(th)^2 + r^2) + 1)*sin(th)^2 dph⊗dr
         + (2*a^2*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2)
         + a^2 + r^2)*sin(th)^2 dph⊗dph
        sage: K.default_chart().coord_range()
        t: (-oo, +oo); r: (0, +oo); th: (0, pi); ph: [-pi, pi] (periodic)
    """
    from sage.misc.functional import sqrt
    from sage.functions.trig import cos, sin
    from sage.manifolds.manifold import Manifold
    M = Manifold(4, 'M', structure="Lorentzian")
    if coordinates == "Kerr":
        if names is None:
            names = (r't:(-oo,+oo)', r'r:(0,+oo)', r'th:(0,pi):\theta',
                     r'ph:(-pi,pi):periodic:\phi')
        else:
            names = (names[0] + r':(-oo,+oo)', names[1] + r':(0,+oo)',
                     names[2] + r':(0,pi):\theta',
                     names[3] + r':(-pi,pi):periodic:\phi')
        C = M.chart(names=names)
        M._first_ngens = C._first_ngens
        g = M.metric('g')
        t, r, th, ph = C[:]
        rho = sqrt(r**2 + a**2 * cos(th)**2)
        g[0, 0], g[1, 1], g[2, 2], g[3, 3] = -(1-2*m*r/rho**2), 1+2*m*r/rho**2,\
                rho**2, (r**2+a**2+2*a**2*m*r*sin(th)**2/rho**2)*sin(th)**2
        g[0, 1] = 2 * m * r / rho**2
        g[0, 3] = -2 * a * m * r / rho**2 * sin(th)**2
        g[1, 3] = -a * sin(th)**2 * (1 + 2 * m * r / rho**2)
        return M

    if coordinates == "BL":
        if names is None:
            names = (r't:(-oo,+oo)', r'r:(0,+oo)', r'th:(0,pi):\theta',
                     r'ph:(-pi,pi):periodic:\phi')
        else:
            names = (names[0] + r':(-oo,+oo)', names[1] + r':(0,+oo)',
                     names[2] + r':(0,pi):\theta',
                     names[3] + r':(-pi,pi):periodic:\phi')
        C = M.chart(names=names)
        M._first_ngens = C._first_ngens
        g = M.metric('g')
        t, r, th, ph = C[:]
        rho = sqrt(r**2 + a**2 * cos(th)**2)
        g[0, 0], g[1, 1], g[2, 2], g[3, 3] = -(1-2*m*r/rho**2), \
            rho**2/(r**2-2*m*r+a**2), rho**2, \
            (r**2+a**2+2*m*r*a**2/rho**2*sin(th)**2)*sin(th)**2
        g[0, 3] = 2 * m * r * a * sin(th)**2 / rho**2
        return M

    raise NotImplementedError("coordinates system not implemented, see help"
                              " for details")
Example #54
0
 def _compute_init_vector(self, point, pt0, pr0, pth0, pph0, r_increase,
                          th_increase, verbose):
     r"""
     Computes the initial 4-momentum vector `p` from the constants of motion
     """
     BLchart = self._spacetime.boyer_lindquist_coordinates()
     basis = BLchart.frame().at(point)
     r, th = BLchart(point)[1:3]
     a, m = self._a, self._m
     r2 = r**2
     a2 = a**2
     rho2 = r2 + (a * cos(th))**2
     Delta = r2 - 2 * m * r + a2
     if pt0 is None:
         if (self._mu is not None and pr0 is not None and pth0 is not None
                 and pph0 is not None):
             xxx = SR.var('xxx')
             v = self._spacetime.tangent_space(point)(
                 (xxx, pr0, pth0, pph0), basis=basis)
             muv2 = -self._spacetime.metric().at(point)(v, v)
             muv2 = muv2.substitute(self._numerical_substitutions())
             solutions = solve(muv2 == self._mu**2, xxx, solution_dict=True)
             if verbose:
                 print("Solutions for p^t:")
                 pretty_print(solutions)
             for sol in solutions:
                 if sol[xxx] > 0:
                     pt0 = sol[xxx]
                     break
             else:  # pt0 <= 0 might occur in the ergoregion
                 pt0 = solutions[0][xxx]
             try:
                 pt0 = RR(pt0)
             except TypeError:  # pt0 contains some symbolic expression
                 pass
         else:
             if self._E is None:
                 raise ValueError("the constant E must be provided")
             if self._L is None:
                 raise ValueError("the constant L must be provided")
             E, L = self._E, self._L
             pt0 = ((r2 + a2) / Delta * ((r2 + a2) * E - a * L) + a *
                    (L - a * E * sin(th)**2)) / rho2
     if pph0 is None:
         if self._E is None:
             raise ValueError("the constant E must be provided")
         if self._L is None:
             raise ValueError("the constant L must be provided")
         E, L = self._E, self._L
         pph0 = (L / sin(th)**2 - a * E + a / Delta *
                 ((r2 + a2) * E - a * L)) / rho2
     if pr0 is None:
         if self._E is None:
             raise ValueError("the constant E must be provided")
         if self._L is None:
             raise ValueError("the constant L must be provided")
         if self._mu is None:
             raise ValueError("the constant mu must be provided")
         if self._Q is None:
             raise ValueError("the constant Q must be provided")
         E, L, Q = self._E, self._L, self._Q
         mu2 = self._mu**2
         E2_mu2 = E**2 - mu2
         pr0 = sqrt((E2_mu2) * r**4 + 2 * m * mu2 * r**3 +
                    (a2 * E2_mu2 - L**2 - Q) * r**2 + 2 * m *
                    (Q + (L - a * E)**2) * r - a2 * Q) / rho2
         if not r_increase:
             pr0 = -pr0
     if pth0 is None:
         if self._E is None:
             raise ValueError("the constant E must be provided")
         if self._L is None:
             raise ValueError("the constant L must be provided")
         if self._mu is None:
             raise ValueError("the constant mu must be provided")
         if self._Q is None:
             raise ValueError("the constant Q must be provided")
         E2 = self._E**2
         L2 = self._L**2
         mu2 = self._mu**2
         Q = self._Q
         pth0 = sqrt(Q + cos(th)**2 * (a2 *
                                       (E2 - mu2) - L2 / sin(th)**2)) / rho2
         if not th_increase:
             pth0 = -pth0
     return self._spacetime.tangent_space(point)((pt0, pr0, pth0, pph0),
                                                 basis=basis,
                                                 name='p')
Example #55
0
    def _init_spherical(self, names=None):
        r"""
        Construct the chart of spherical coordinates.

        TESTS:

        Spherical coordinates on a 2-sphere::

            sage: S2 = manifolds.Sphere(2)
            sage: S2.spherical_coordinates()
            Chart (A, (theta, phi))

        Spherical coordinates on a 1-sphere::

            sage: S1 = manifolds.Sphere(1, coordinates='stereographic')
            sage: spher = S1.spherical_coordinates(); spher  # create coords
            Chart (A, (phi,))
            sage: S1.atlas()
            [Chart (S^1-{NP}, (y1,)),
             Chart (S^1-{SP}, (yp1,)),
             Chart (S^1-{NP,SP}, (y1,)),
             Chart (S^1-{NP,SP}, (yp1,)),
             Chart (A, (phi,)),
             Chart (A, (y1,)),
             Chart (A, (yp1,))]

        """
        # speed-up via simplification method...
        self.set_simplify_function(lambda expr: expr.simplify_trig())

        # get domain...
        A = self._spher_dom

        # initialize coordinates...
        n = self._dim
        if names:
            # add interval:
            names = tuple([x + ':(0,pi)' for x in names[:-1]] +
                          [names[-1] + ':(-pi,pi):periodic'])
        else:
            if n == 1:
                names = ('phi:(-pi,pi):periodic', )
            elif n == 2:
                names = ('theta:(0,pi)', 'phi:(-pi,pi):periodic')
            elif n == 3:
                names = ('chi:(0,pi)', 'theta:(0,pi)', 'phi:(-pi,pi):periodic')
            else:
                names = tuple(["phi_{}:(0,pi)".format(i)
                               for i in range(1, n)] +
                              ["phi_{}:(-pi,pi):periodic".format(n)])
        spher = A.chart(names=names)
        coord = spher[:]

        # manage embedding...
        from sage.misc.misc_c import prod
        from sage.functions.trig import cos, sin

        R = self._radius

        coordfunc = [
            R * cos(coord[n - 1]) * prod(sin(coord[i]) for i in range(n - 1))
        ]
        coordfunc += [R * prod(sin(coord[i]) for i in range(n))]
        for k in reversed(range(n - 1)):
            c = R * cos(coord[k]) * prod(sin(coord[i]) for i in range(k))
            coordfunc.append(c)
        cart = self._ambient.cartesian_coordinates()
        # shift coordinates to barycenter:
        coordfunc = self._shift_coords(coordfunc, s='+')
        # add expression to embedding:
        self._immersion.add_expr(spher, cart, coordfunc)
        self.clear_cache()  # clear cache of extrinsic information

        # finish process...
        self._coordinates['spherical'] = [spher]

        # adapt other coordinates...
        if 'stereographic' in self._coordinates:
            self._transition_spher_stereo()

        # reset simplification method...
        self.set_simplify_function('default')
Example #56
0
def revolution_plot3d(curve,
                      trange,
                      phirange=None,
                      parallel_axis='z',
                      axis=(0, 0),
                      print_vector=False,
                      show_curve=False,
                      **kwds):
    """
    Return a plot of a revolved curve.

    There are three ways to call this function:

    - ``revolution_plot3d(f,trange)`` where `f` is a function located in the `x z` plane.

    - ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric curve on the `x z` plane.

    - ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be any parametric curve.

    INPUT:

    - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple.

    - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve.

    - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved.

    - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis.

    - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is:

        - 'z' - then axis is the point in which the revolution axis intersects the  `x y` plane.

        - 'x' - then axis is the point in which the revolution axis intersects the  `y z` plane.

        - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane.

    - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed.

    - ``show_curve`` - If True, the curve will be displayed.


    EXAMPLES:

    Let's revolve a simple function around different axes::

        sage: u = var('u')
        sage: f=u^2
        sage: revolution_plot3d(f,(u,0,2),show_curve=True,opacity=0.7).show(aspect_ratio=(1,1,1))

    If we move slightly the axis, we get a goblet-like surface::

        sage: revolution_plot3d(f,(u,0,2),axis=(1,0.2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    A common problem in calculus books, find the volume within the following revolution solid::

        sage: line=u
        sage: parabola=u^2
        sage: sur1=revolution_plot3d(line,(u,0,1),opacity=0.5,rgbcolor=(1,0.5,0),show_curve=True,parallel_axis='x')
        sage: sur2=revolution_plot3d(parabola,(u,0,1),opacity=0.5,rgbcolor=(0,1,0),show_curve=True,parallel_axis='x')
        sage: (sur1+sur2).show()


    Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis, an axis in `(0,0)` (as the previous one) will produce a sphere-like surface::

        sage: u = var('u')
        sage: circle=(cos(u),sin(u))
        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    An axis on `(0,y)` will produce a cylinder-like surface::

        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    And any other axis will produce a torus-like surface::

        sage: revolution_plot3d(circle,(u,0,2*pi),axis=(2,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1))

    Now, we can get another goblet-like surface by revolving a curve in 3d::

        sage: u = var('u')
        sage: curve=(u,cos(4*u),u^2)
        sage: revolution_plot3d(curve,(u,0,2),show_curve=True,parallel_axis='z',axis=(1,.2),opacity=0.5).show(aspect_ratio=(1,1,1))

    A curvy curve with only a quarter turn::

        sage: u = var('u')
        sage: curve=(sin(3*u),.8*cos(4*u),cos(u))
        sage: revolution_plot3d(curve,(u,0,pi),(0,pi/2),show_curve=True,parallel_axis='z',opacity=0.5).show(aspect_ratio=(1,1,1),frame=False)
    """
    from sage.symbolic.ring import SR
    from sage.symbolic.constants import pi
    from sage.functions.other import sqrt
    from sage.functions.trig import sin
    from sage.functions.trig import cos
    from sage.functions.trig import atan2

    if parallel_axis not in ['x', 'y', 'z']:
        raise ValueError("parallel_axis must be either 'x', 'y', or 'z'.")

    vart = trange[0]

    if str(vart) == 'phi':
        phi = SR.var('fi')
    else:
        phi = SR.var('phi')

    if phirange is None:  #this if-else provides a phirange
        phirange = (phi, 0, 2 * pi)
    elif len(phirange) == 3:
        phi = phirange[0]
        pass
    else:
        phirange = (phi, phirange[0], phirange[1])

    if isinstance(curve, tuple) or isinstance(curve, list):
        #this if-else provides a vector v to be plotted
        #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve
        #in the x-z plane.
        #if it is of length 3 it is interpreted as a parametric curve in 3d space

        if len(curve) == 2:
            x = curve[0]
            y = 0
            z = curve[1]
        elif len(curve) == 3:
            x = curve[0]
            y = curve[1]
            z = curve[2]
    else:
        x = vart
        y = 0
        z = curve

    if parallel_axis == 'z':
        x0 = axis[0]
        y0 = axis[1]
        # (0,0) must be handled separately for the phase value
        phase = 0
        if x0 != 0 or y0 != 0:
            phase = atan2((y - y0), (x - x0))
        R = sqrt((x - x0)**2 + (y - y0)**2)
        v = (R * cos(phi + phase) + x0, R * sin(phi + phase) + y0, z)
    elif parallel_axis == 'x':
        y0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        phase = 0
        if z0 != 0 or y0 != 0:
            phase = atan2((z - z0), (y - y0))
        R = sqrt((y - y0)**2 + (z - z0)**2)
        v = (x, R * cos(phi + phase) + y0, R * sin(phi + phase) + z0)
    elif parallel_axis == 'y':
        x0 = axis[0]
        z0 = axis[1]
        # (0,0) must be handled separately for the phase value
        phase = 0
        if z0 != 0 or x0 != 0:
            phase = atan2((z - z0), (x - x0))
        R = sqrt((x - x0)**2 + (z - z0)**2)
        v = (R * cos(phi + phase) + x0, y, R * sin(phi + phase) + z0)

    if print_vector:
        print(v)
    if show_curve:
        curveplot = parametric_plot3d((x, y, z),
                                      trange,
                                      thickness=2,
                                      rgbcolor=(1, 0, 0))
        return parametric_plot3d(v, trange, phirange, **kwds) + curveplot
    return parametric_plot3d(v, trange, phirange, **kwds)
Example #57
0
def _draw_funddom(coset_reps, format="S"):
    r""" Draw a fundamental domain for G.

    INPUT:

    - ``format``  -- (default 'Disp') How to present the f.d.
    -   ``S`` -- Display directly on the screen

    EXAMPLES::


    sage: G=MySubgroup(Gamma0(3))
    sage: G._draw_funddom()

    """
    pi = RR.pi()
    pi_3 = pi / RR(3.0)
    from sage.plot.plot import (Graphics, line)
    from sage.functions.trig import (cos, sin)
    g = Graphics()
    x1 = RR(-0.5)
    y1 = RR(sqrt(3) / 2)
    x2 = RR(0.5)
    y2 = RR(sqrt(3) / 2)
    xmax = RR(20.0)
    l1 = line([[x1, y1], [x1, xmax]])
    l2 = line([[x2, y2], [x2, xmax]])
    l3 = line([[x2, xmax], [x1,
                            xmax]])  # This is added to make a closed contour
    c0 = _circ_arc(RR(pi / 3.0), RR(2.0 * pi) / RR(3.0), 0, 1, 100)
    tri = c0 + l1 + l3 + l2
    g = g + tri
    for A in coset_reps:
        [a, b, c, d] = A
        if (a == 1 and b == 0 and c == 0 and d == 1):
            continue
        if (a < 0):
            a = RR(-a)
            b = RR(-b)
            c = RR(-c)
            d = RR(-d)
        else:
            a = RR(a)
            b = RR(b)
            c = RR(c)
            d = RR(d)
        if (c == 0):  # then this is easier
            L0 = [[cos(pi_3 * RR(i / 100.0)) + b,
                   sin(pi_3 * RR(i / 100.0))] for i in range(100, 201)]
            L1 = [[x1 + b, y1], [x1 + b, xmax]]
            L2 = [[x2 + b, y2], [x2 + b, xmax]]
            L3 = [[x2 + b, xmax], [x1 + b, xmax]]
            c0 = line(L0)
            l1 = line(L1)
            l2 = line(L2)
            l3 = line(L3)
            tri = c0 + l1 + l3 + l2
            g = g + tri
        else:
            den = (c * x1 + d)**2 + c**2 * y1**2
            x1_t = (a * c * (x1**2 + y1**2) +
                    (a * d + b * c) * x1 + b * d) / den
            y1_t = y1 / den
            den = (c * x2 + d)**2 + c**2 * y2**2
            x2_t = (a * c * (x2**2 + y2**2) +
                    (a * d + b * c) * x2 + b * d) / den
            y2_t = y2 / den
            inf_t = a / c
            c0 = _geodesic_between_two_points(x1_t, y1_t, x2_t, y2_t)
            c1 = _geodesic_between_two_points(x1_t, y1_t, inf_t, 0.)
            c2 = _geodesic_between_two_points(x2_t, y2_t, inf_t, 0.0)
            tri = c0 + c1 + c2
            g = g + tri
    return g
Example #58
0
def simplify_abs_trig(expr):
    r"""
    Simplify ``abs(sin(...))`` and ``abs(cos(...))`` in symbolic expressions.

    EXAMPLES::

        sage: M = Manifold(3, 'M', structure='topological')
        sage: X.<x,y,z> = M.chart(r'x y:(0,pi) z:(-pi/3,0)')
        sage: X.coord_range()
        x: (-oo, +oo); y: (0, pi); z: (-1/3*pi, 0)

    Since `x` spans all `\RR`, no simplification of ``abs(sin(x))``
    occurs, while ``abs(sin(y))`` and ``abs(sin(3*z))`` are correctly
    simplified, given that `y \in (0,\pi)` and `z \in (-\pi/3,0)`::

        sage: from sage.manifolds.utilities import simplify_abs_trig
        sage: simplify_abs_trig( abs(sin(x)) + abs(sin(y)) + abs(sin(3*z)) )
        abs(sin(x)) + sin(y) + sin(-3*z)

    Note that neither
    :meth:`~sage.symbolic.expression.Expression.simplify_trig` nor
    :meth:`~sage.symbolic.expression.Expression.simplify_full`
    works in this case::

        sage: s = abs(sin(x)) + abs(sin(y)) + abs(sin(3*z))
        sage: s.simplify_trig()
        abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
        sage: s.simplify_full()
        abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))

    despite the following assumptions hold::

        sage: assumptions()
        [x is real, y is real, y > 0, y < pi, z is real, z > -1/3*pi, z < 0]

    Additional checks are::

        sage: simplify_abs_trig( abs(sin(y/2)) )  # shall simplify
        sin(1/2*y)
        sage: simplify_abs_trig( abs(sin(2*y)) )  # must not simplify
        abs(sin(2*y))
        sage: simplify_abs_trig( abs(sin(z/2)) )  # shall simplify
        sin(-1/2*z)
        sage: simplify_abs_trig( abs(sin(4*z)) )  # must not simplify
        abs(sin(-4*z))

    Simplification of ``abs(cos(...))``::

        sage: forget()
        sage: M = Manifold(3, 'M', structure='topological')
        sage: X.<x,y,z> = M.chart(r'x y:(0,pi/2) z:(pi/4,3*pi/4)')
        sage: X.coord_range()
        x: (-oo, +oo); y: (0, 1/2*pi); z: (1/4*pi, 3/4*pi)
        sage: simplify_abs_trig( abs(cos(x)) + abs(cos(y)) + abs(cos(2*z)) )
        abs(cos(x)) + cos(y) - cos(2*z)

    Additional tests::

        sage: simplify_abs_trig(abs(cos(y-pi/2)))  # shall simplify
        cos(-1/2*pi + y)
        sage: simplify_abs_trig(abs(cos(y+pi/2)))  # shall simplify
        -cos(1/2*pi + y)
        sage: simplify_abs_trig(abs(cos(y-pi)))  # shall simplify
        -cos(-pi + y)
        sage: simplify_abs_trig(abs(cos(2*y)))  # must not simplify
        abs(cos(2*y))
        sage: simplify_abs_trig(abs(cos(y/2)) * abs(sin(z)))  # shall simplify
        cos(1/2*y)*sin(z)

    TESTS:

    Simplification of expressions involving some symbolic derivatives::

        sage: f = function('f')
        sage: s = abs(cos(x)) + abs(cos(y))*diff(f(x),x) + abs(cos(2*z))
        sage: simplify_abs_trig(s)
        cos(y)*diff(f(x), x) + abs(cos(x)) - cos(2*z)
        sage: s = abs(sin(x))*diff(f(x),x).subs(x=y^2) + abs(cos(y))
        sage: simplify_abs_trig(s)
        abs(sin(x))*D[0](f)(y^2) + cos(y)
        sage: forget()  # for doctests below

    """
    w0 = SR.wild()
    if expr.has(abs_symbolic(sin(w0))) or expr.has(abs_symbolic(cos(w0))):
        return SimplifyAbsTrig(expr)()
    return expr
Example #59
0
    def composition(self, ex, operator):
        r"""
        This is the only method of the base class
        :class:`~sage.symbolic.expression_conversions.ExpressionTreeWalker`
        that is reimplemented, since it manages the composition of
        ``abs`` with ``cos`` or ``sin``.

        INPUT:

        - ``ex`` -- a symbolic expression
        - ``operator`` -- an operator

        OUTPUT:

        - a symbolic expression, equivalent to ``ex`` with ``abs(cos(...))``
          and ``abs(sin(...))`` simplified, according to the range of their
          argument.

        EXAMPLES::

            sage: from sage.manifolds.utilities import SimplifyAbsTrig
            sage: assume(-pi/2 < x, x<0)
            sage: a = abs(sin(x))
            sage: s = SimplifyAbsTrig(a)
            sage: a.operator()
            abs
            sage: s.composition(a, a.operator())
            sin(-x)

        ::

            sage: a = exp(function('f')(x))  # no abs(sin_or_cos(...))
            sage: a.operator()
            exp
            sage: s.composition(a, a.operator())
            e^f(x)

        ::

            sage: forget()  # no longer any assumption on x
            sage: a = abs(cos(sin(x)))  # simplifiable since -1 <= sin(x) <= 1
            sage: s.composition(a, a.operator())
            cos(sin(x))
            sage: a = abs(sin(cos(x)))  # not simplifiable
            sage: s.composition(a, a.operator())
            abs(sin(cos(x)))

        """
        if operator is abs_symbolic:
            argum = ex.operands()[0]  # argument of abs
            if argum.operator() is sin:
                # Case of abs(sin(...))
                x = argum.operands()[0]  # argument of sin
                w0 = SR.wild()
                if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(
                        cos(w0))):
                    x = self(x)  # treatment of nested abs(sin_or_cos(...))
                # Simplifications for values of x in the range [-pi, 2*pi]:
                if x >= 0 and x <= pi:
                    ex = sin(x)
                elif (x > pi and x <= 2 * pi) or (x >= -pi and x < 0):
                    ex = -sin(x)
                return ex
            if argum.operator() is cos:
                # Case of abs(cos(...))
                x = argum.operands()[0]  # argument of cos
                w0 = SR.wild()
                if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(
                        cos(w0))):
                    x = self(x)  # treatment of nested abs(sin_or_cos(...))
                # Simplifications for values of x in the range [-pi, 2*pi]:
                if (x >= -pi / 2 and x <= pi / 2) or (x >= 3 * pi / 2
                                                      and x <= 2 * pi):
                    ex = cos(x)
                elif (x > pi / 2 and x <= 3 * pi / 2) or (x >= -pi
                                                          and x < -pi / 2):
                    ex = -cos(x)
                return ex
        # If no pattern is found, we default to ExpressionTreeWalker:
        return super(SimplifyAbsTrig, self).composition(ex, operator)