Ejemplo n.º 1
0
    def plot(self, max_points=2500, **args):
        r"""
        Create a visualization of this `p`-adic ring as a fractal
        similar to a generalization of the Sierpi\'nski
        triangle.

        The resulting image attempts to capture the
        algebraic and topological characteristics of `\mathbb{Z}_p`.

        INPUT:

        - ``max_points`` -- the maximum number or points to plot,
          which controls the depth of recursion (default 2500)

        - ``**args`` -- color, size, etc. that are passed to the
          underlying point graphics objects

        REFERENCES:

        - Cuoco, A. ''Visualizing the `p`-adic Integers'', The
          American Mathematical Monthly, Vol. 98, No. 4 (Apr., 1991),
          pp. 355-364

        EXAMPLES::

            sage: Zp(3).plot()
            Graphics object consisting of 1 graphics primitive
            sage: Zp(5).plot(max_points=625)
            Graphics object consisting of 1 graphics primitive
            sage: Zp(23).plot(rgbcolor=(1,0,0))
            Graphics object consisting of 1 graphics primitive
        """
        if 'pointsize' not in args:
            args['pointsize'] = 1
        from sage.misc.mrange import cartesian_product_iterator
        from sage.rings.real_double import RDF
        from sage.plot.all import points, circle, Graphics
        p = self.prime()
        phi = 2*RDF.pi()/p
        V = RDF**2
        vs = [V([(phi*t).sin(), (phi*t).cos()]) for t in range(p)]
        all = []
        depth = max(RDF(max_points).log(p).floor(), 1)
        scale = min(RDF(1.5/p), 1/RDF(3))
        pts = [vs]*depth
        if depth == 1 and 23 < p < max_points:
            extras = int(max_points/p)
            if p/extras > 5:
                pts = [vs]*depth + [vs[::extras]]
        for digits in cartesian_product_iterator(pts):
            p = sum([v * scale**n for n, v in enumerate(digits)])
            all.append(tuple(p))
        g = points(all, **args)
        # Set default plotting options
        g.axes(False)
        g.set_aspect_ratio(1)
        return g
Ejemplo n.º 2
0
def log(x, b=None):
    r"""
    Return the log of ``x`` to the base `b`. The default base is `e`.

    DEPRECATED by :trac:`19444`

    INPUT:

    - ``x`` -- number

    - `b` -- base (default: ``None``, which means natural log)

    OUTPUT: number

    .. NOTE::

        In Magma, the order of arguments is reversed from in Sage,
        i.e., the base is given first. We use the opposite ordering, so
        the base can be viewed as an optional second argument.

    EXAMPLES::

        sage: from sage.misc.functional import log
        sage: log(e^2)
        doctest:warning...
        DeprecationWarning: use .log() or log() from sage.functions.log instead
        See http://trac.sagemath.org/19444 for details.
        2
        sage: log(16,2)
        4
        sage: log(3.)
        1.09861228866811
        sage: log(float(3))  # abs tol 1e-15
        1.0986122886681098
    """
    deprecation(19444, 'use .log() or log() from sage.functions.log instead')
    if b is None:
        if hasattr(x, 'log'):
            return x.log()
        return RDF(x).log()
    else:
        if hasattr(x, 'log'):
            return x.log(b)
        return RDF(x).log(b)
Ejemplo n.º 3
0
 def set_transform(self, s, tx, ty):
     r"""
     Set the parts of the transformation which convert to screen coordinates.
     """
     s = QQ(s)
     tx = QQ(tx)
     ty = QQ(ty)
     ratio = self._s / s
     if (ratio > QQ(999) / 1000) and (ratio < QQ(1001) / 1000):
         # ignore negligible change in scale!
         self._editor.get_canvas().move(ALL, RDF(tx - self._tx),
                                        RDF(ty - self._ty))
         self._tx = self._field(tx)
         self._ty = self._field(ty)
     else:
         self.before_zoom_change()
         scale = 1 / ratio
         offset_x = ((self._s * tx) - (self._tx * s)) / (self._s - s)
         offset_y = ((self._s * ty) - (self._ty * s)) / (self._s - s)
         self._editor.get_canvas().scale(ALL, RDF(offset_x), RDF(offset_y),
                                         RDF(scale), RDF(scale))
         self._s = self._field(s)
         self._tx = self._field(tx)
         self._ty = self._field(ty)
         self.after_zoom_change()
Ejemplo n.º 4
0
def round(x, ndigits=0):
    """
    round(number[, ndigits]) - double-precision real number
    
    Round a number to a given precision in decimal digits (default 0
    digits). This always returns a real double field element.
    
    EXAMPLES::
    
        sage: round(sqrt(2),2)
        1.41
        sage: round(sqrt(2),5)
        1.41421
        sage: round(pi)
        3.0
        sage: b = 5.4999999999999999
        sage: round(b)
        5.0
    
    Since we use floating-point with a limited range, some roundings can't
    be performed::
    
        sage: round(sqrt(Integer('1'*500)))
        Traceback (most recent call last):
        ...
        OverflowError: cannot convert float infinity to long
    
    IMPLEMENTATION: If ndigits is specified, it calls Python's builtin
    round function, and converts the result to a real double field
    element. Otherwise, it tries the argument's .round() method, and if
    that fails, it falls back to the builtin round function.
    
    .. note::

       This is currently slower than the builtin round function, since
       it does more work - i.e., allocating an RDF element and
       initializing it. To access the builtin version do
       ``import __builtin__; __builtin__.round``.
    """
    try:
        if ndigits:
            return RealDoubleElement(__builtin__.round(x, ndigits))
        else:
            try:
                return RealDoubleElement(x.round())
            except AttributeError:
                return RealDoubleElement(__builtin__.round(x, 0))
    except ArithmeticError:
        if not isinstance(x, RealDoubleElement):
            return round(RDF(x), ndigits)
        else:
            raise
Ejemplo n.º 5
0
def power_spectral_density(freq):
    r"""
    Return the effective power spectral density (PSD) of the detector noise
    at a given frequency.

    INPUT:

    - ``freq`` -- frequency `f` (in `\mathrm{Hz}`)

    OUTPUT:

    - effective power spectral density `S(f)` (in `\mathrm{Hz}^{-1}`)

    EXAMPLES::

        sage: from kerrgeodesic_gw import lisa_detector
        sage: Sn = lisa_detector.power_spectral_density
        sage: Sn(1.e-1)  # tol 1.0e-13
        3.3944027493062926e-39
        sage: Sn(1.e-2)  # tol 1.0e-13
        2.738383947022306e-40
        sage: Sn(1.e-3)  # tol 1.0e-13
        3.269807574220045e-38

    """
    global _psd_spline
    if not _psd_spline:
        data = []
        file_name = os.path.join(os.path.dirname(__file__),
                                 "data/Sensitivity_LISA_SciRD1806_Alloc.dat")
        with open(file_name, "r") as data_file:
            for dline in data_file:
                f, s = dline.split('\t')
                data.append((log(RDF(f), 10), log(RDF(s), 10)))
        _psd_spline = spline(data)
    if freq < 1.e-5 or freq > 1.:
        raise ValueError("frequency {} Hz is out of range".format(freq))
    freq = RDF(freq)
    return RDF(10)**(_psd_spline(log(freq, 10)))
Ejemplo n.º 6
0
def log(x,b=None):
    r"""
    Returns the log of x to the base b. The default base is e.

    INPUT:


    -  ``x`` - number

    -  ``b`` - base (default: None, which means natural
       log)


    OUTPUT: number

    .. note::

       In Magma, the order of arguments is reversed from in Sage,
       i.e., the base is given first. We use the opposite ordering, so
       the base can be viewed as an optional second argument.

    EXAMPLES::

        sage: log(e^2)
        2
        sage: log(16,2)
        4
        sage: log(3.)
        1.09861228866811
    """
    if b is None:
        if hasattr(x, 'log'):
            return x.log()
        return RDF(x)._log_base(1)
    else:
        if hasattr(x, 'log'):
            return x.log(b)
        return RDF(x).log(b)
Ejemplo n.º 7
0
def acos(x):
    """
    Returns the arc cosine of x.

    EXAMPLES::

        sage: acos(.5)
        1.04719755119660
        sage: acos(sin(pi/3))
        arccos(1/2*sqrt(3))
        sage: acos(sin(pi/3)).simplify_full()
        1/6*pi
    """
    try: return x.acos()
    except AttributeError: return RDF(x).acos()
Ejemplo n.º 8
0
def asin(x):
    """
    Returns the arc sine of x.

    EXAMPLES::

        sage: asin(.5)
        0.523598775598299
        sage: asin(sin(pi/3))
        arcsin(1/2*sqrt(3))
        sage: asin(sin(pi/3)).simplify_full()
        1/3*pi
    """
    try: return x.asin()
    except AttributeError: return RDF(x).asin()
Ejemplo n.º 9
0
def atan(x):
    """
    Returns the arc tangent of x.

    EXAMPLES::

        sage: z = atan(3);z
        arctan(3)
        sage: n(z)
        1.24904577239825
        sage: atan(tan(pi/4))
        1/4*pi
    """
    try: return x.atan()
    except AttributeError: return RDF(x).atan()
Ejemplo n.º 10
0
def exp(x):
    """
    Returns the value of the exponentiation function at x.

    EXAMPLES::

        sage: exp(3)
        e^3
        sage: exp(0)
        1
        sage: exp(2.5)
        12.1824939607035
        sage: exp(pi*i)
        -1
    """
    try: return x.exp()
    except AttributeError: return RDF(x).exp()
Ejemplo n.º 11
0
def sqrt(x):
    """
    Return a square root of x.
    
    EXAMPLES::
    
        sage: sqrt(10.1)
        3.17804971641414
        sage: sqrt(9)
        3
    """
    try:
        return x.sqrt()
    except (AttributeError, ValueError):
        try:
            return RDF(x).sqrt()
        except TypeError:
            return CDF(x).sqrt()
Ejemplo n.º 12
0
    def plot_zero_flag(self, **options):
        r"""
        Draw a line segment from the zero vertex toward the baricenter.

        A real parameter ``t`` can be provided. If t=1, then the segment will
        go all the way to the baricenter.  The value of ``t`` is linear in the
        length of the segment. Defaults to t=0.5.

        Other options are processed as in sage.plot.line.line2d.
        """
        if "t" in options:
            t = RDF(options.pop("t"))
        else:
            t = 0.5

        return line2d([
            self._v[0], self._v[0] + t *
            (sum(self._v) / len(self._v) - self._v[0])
        ], **options)
Ejemplo n.º 13
0
def sqrt(x):
    """
    Returns a square root of x.

    This function (``numerical_sqrt``) is deprecated.  Use ``sqrt(x,
    prec=n)`` instead.
    
    EXAMPLES::
    
        sage: numerical_sqrt(10.1)
        doctest:1: DeprecationWarning: numerical_sqrt is deprecated, use sqrt(x, prec=n) instead
        3.17804971641414
        sage: numerical_sqrt(9)
        3
    """
    from sage.misc.misc import deprecation
    deprecation("numerical_sqrt is deprecated, use sqrt(x, prec=n) instead")
    try:
        return x.sqrt()
    except (AttributeError, ValueError):
        try:
            return RDF(x).sqrt()
        except TypeError:
            return CDF(x).sqrt()
Ejemplo n.º 14
0
def sqrt(x):
    """
    Returns a square root of x.

    This function (``numerical_sqrt``) is deprecated.  Use ``sqrt(x,
    prec=n)`` instead.

    EXAMPLES::

        sage: numerical_sqrt(10.1)
        doctest:1: DeprecationWarning: numerical_sqrt is deprecated, use sqrt(x, prec=n) instead
        See http://trac.sagemath.org/5404 for details.
        3.17804971641414
        sage: numerical_sqrt(9)
        3
    """
    from sage.misc.superseded import deprecation
    deprecation(5404, "numerical_sqrt is deprecated, use sqrt(x, prec=n) instead")
    try: return x.sqrt()
    except (AttributeError, ValueError):
        try:
            return RDF(x).sqrt()
        except TypeError:
            return CDF(x).sqrt()
def k2(s, l, m, gamma):
    return (gamma**2 * sqrt(
        RDF((1 + l - m) * (2 + l - m) * (1 + l + m) * (2 + l + m) *
            (1 + l - s) * (2 + l - s) * (1 + l + s) * (2 + l + s)) / RDF(
                (1 + 2 * l) * (5 + 2 * l)))) / RDF(
                    (1 + l) * (2 + l) * (3 + 2 * l))
Ejemplo n.º 16
0
def h_toy_model_semi_analytic(u, theta, phi, a, r0, phi0, lam, Dphi, l_max=10):
    r"""
    Return the gravitational wave emitted by a matter blob orbiting a Kerr
    black hole (semi-analytic computation based on a toy model surface density).

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

    The gravitational wave is computed according to the formula

    .. MATH::

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

    INPUT:

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

    OUTPUT:

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

    EXAMPLES:

    Schwarzschild black hole::

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

    Comparison with the exact value::

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

    """
    import numpy
    from sage.rings.real_double import RDF
    from sage.rings.complex_double import CDF
    from sage.symbolic.all import i as I
    from .spin_weighted_spherical_harm import spin_weighted_spherical_harmonic
    from .spin_weighted_spheroidal_harm import spin_weighted_spheroidal_harmonic
    from .zinf import Zinf
    u = RDF(u)
    theta = RDF(theta)
    phi = RDF(phi)
    a = RDF(a)
    omega0 = RDF(1. / (r0**1.5 + a))
    eps = lam/r0
    resu = CDF(0)
    for l in range(2, l_max+1):
        for m in range(-l, l+1):
            if m == 0:    # m=0 is skipped
                continue  #
            m_omega0 = RDF(m*omega0)
            if a == 0:
                Slm = spin_weighted_spherical_harmonic(-2, l, m, theta, phi,
                                                       numerical=RDF)
            else:
                a = RDF(a)
                Slm = spin_weighted_spheroidal_harmonic(-2, l, m, a*m_omega0,
                                                        theta, phi)
            # Division by pi in the Sinc function due to the defintion used by numpy
            resu += Zinf(a, l, m, r0) / m_omega0**2 \
                    * numpy.sinc(m*Dphi/2./numpy.pi) \
                    * numpy.sinc(0.75*eps*m_omega0*(1-a*omega0)*u/numpy.pi) \
                    * CDF(exp(-I*(m_omega0*u + m*phi0))) * Slm
    resu *= 2
    return (resu.real(), -resu.imag())
Ejemplo n.º 17
0
    def _sage_(self):
        """
        Convert self to a Sage object.

        EXAMPLES::

            sage: a = axiom(1/2); a #optional - axiom
              1
              -
              2
            sage: a.sage()          #optional - axiom
            1/2
            sage: _.parent()        #optional - axiom
            Rational Field

            sage: gp(axiom(1/2))    #optional - axiom
            1/2

        DoubleFloat's in Axiom are converted to be in RDF in Sage.

        ::

            sage: axiom(2.0).as_type('DoubleFloat').sage()  #optional - axiom
            2.0
            sage: _.parent() #optional - axiom
            Real Double Field


            sage: axiom(2.1234)._sage_() #optional - axiom
            2.12340000000000
            sage: _.parent()             #optional - axiom
            Real Field with 53 bits of precision
            sage: a = RealField(100)(pi)
            sage: axiom(a)._sage_()      #optional - axiom
            3.1415926535897932384626433833
            sage: _.parent()             #optional - axiom
            Real Field with 100 bits of precision
            sage: axiom(a)._sage_() == a #optional - axiom
            True
            sage: axiom(2.0)._sage_() #optional - axiom
            2.00000000000000
            sage: _.parent() #optional  - axiom
            Real Field with 53 bits of precision


        We can also convert Axiom's polynomials to Sage polynomials.
            sage: a = axiom(x^2 + 1)   #optional - axiom
            sage: a.type()             #optional - axiom
            Polynomial Integer
            sage: a.sage()             #optional - axiom
            x^2 + 1
            sage: _.parent()           #optional - axiom
            Univariate Polynomial Ring in x over Integer Ring
            sage: axiom('x^2 + y^2 + 1/2').sage()    #optional - axiom
            y^2 + x^2 + 1/2
            sage: _.parent()                         #optional - axiom
            Multivariate Polynomial Ring in y, x over Rational Field


        """
        P = self._check_valid()
        type = str(self.type())

        if type in ["Type", "Domain"]:
            return self._sage_domain()

        if type == "Float":
            from sage.rings.all import RealField, ZZ
            prec = max(self.mantissa().length()._sage_(), 53)
            R = RealField(prec)
            x, e, b = self.unparsed_input_form().lstrip('float(').rstrip(
                ')').split(',')
            return R(ZZ(x) * ZZ(b)**ZZ(e))
        elif type == "DoubleFloat":
            from sage.rings.real_double import RDF
            return RDF(repr(self))
        elif type in ["PositiveInteger", "Integer"]:
            from sage.rings.integer_ring import ZZ
            return ZZ(repr(self))
        elif type.startswith('Polynomial'):
            from sage.rings.all import PolynomialRing
            base_ring = P(type.lstrip('Polynomial '))._sage_domain()
            vars = str(self.variables())[1:-1]
            R = PolynomialRing(base_ring, vars)
            return R(self.unparsed_input_form())
        elif type.startswith('Fraction'):
            return self.numer().sage() / self.denom().sage()

        #If all else fails, try using the unparsed input form
        try:
            import sage.misc.sage_eval
            vars = sage.symbolic.ring.var(str(self.variables())[1:-1])
            if isinstance(vars, tuple):
                return sage.misc.sage_eval.sage_eval(
                    self.unparsed_input_form(),
                    locals={str(x): x
                            for x in vars})
            else:
                return sage.misc.sage_eval.sage_eval(
                    self.unparsed_input_form(), locals={str(vars): vars})
        except Exception:
            raise NotImplementedError
Ejemplo n.º 18
0
 def math_to_screen_coordinates(self, v):
     return (RDF(self._s * v[0] + self._tx),
             RDF(-self._s * v[1] + self._ty))
Ejemplo n.º 19
0
def polyhedron_from_Hrep(A, b, base_ring=QQ):
    r"""Builds a polytope given the H-representation, in the form `Ax \leq b`

    INPUT:

    * ``A`` - matrix of size m x n, in RDF or QQ ring. Accepts generic Sage matrix, and also a Numpy arrays with a matrix shape.

    * ``b`` - vector of size m, in RDF or QQ ring. Accepts generic Sage matrix, and also a Numpy array.

    * ``base_ring`` - (default: ``QQ``). Specifies the ring (base_ring) for the Polyhedron constructor. Valid choices are:

        * ``QQ`` - rational. Uses ``'ppl'`` (Parma Polyhedra Library) backend

        * ``RDF`` - Real double field. Uses ``'cdd'`` backend.

    OUTPUT:

    * "P" - a Polyhedron object

    TO-DO:

    * accept numpy arrays. notice that we often handle numpy arrays (for instance if we load some data from matlab using the function
    ``scipy.io.loadmat(..)``, then the data will be loaded as a dictionary of numpy arrays)

    EXAMPLES::

        sage: A = matrix(RDF, [[-1.0, 0.0,  0.0,  0.0,  0.0,  0.0],
        ....: [ 1.0,  0.0,  0.0,  0.0,  0.0,  0.0],
        ....: [ 0.0,  1.0,  0.0,  0.0,  0.0,  0.0],
        ....: [ 0.0, -1.0,  0.0,  0.0,  0.0,  0.0],
        ....: [ 0.0,  0.0, -1.0,  0.0,  0.0,  0.0],
        ....: [ 0.0,  0.0,  1.0,  0.0,  0.0,  0.0],
        ....: [ 0.0,  0.0,  0.0, -1.0,  0.0,  0.0],
        ....: [ 0.0,  0.0,  0.0,  1.0,  0.0,  0.0],
        ....: [ 0.0,  0.0,  0.0,  0.0,  1.0,  0.0],
        ....: [ 0.0,  0.0,  0.0,  0.0, -1.0,  0.0],
        ....: [ 0.0,  0.0,  0.0,  0.0,  0.0,  1.0],
        ....: [ 0.0,  0.0,  0.0,  0.0,  0.0, -1.0]])
        sage: b = vector(RDF, [0.0, 10.0, 0.0, 0.0, 0.2, 0.2, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0])
        sage: from polyhedron_tools.misc import polyhedron_from_Hrep
        sage: P = polyhedron_from_Hrep(A, b, base_ring=QQ); P
        A 3-dimensional polyhedron in QQ^6 defined as the convex hull of 8 vertices

    NOTES:

    - This function is useful especially when the input matrices `A`, `b` are ill-defined 
    (constraints that differ by tiny amounts making the input data to be degenerate or almost degenerate), 
    causing problems to Polyhedron(...). 
    
    - In this case it is recommended to use ``base_ring = QQ``. Each element of `A` and `b` will be converted to rational, and this will be sent to Polyhedron.
     Note that Polyhedron automatically removes redundant constraints.
    """

    if (base_ring == RDF):

        if 'numpy.ndarray' in str(type(A)):
            # assuming that b is also a numpy array
            m = A.shape[0]
            n = A.shape[1]

            b_RDF = vector(RDF, m, [RDF(bi) for bi in b])

            A_RDF = matrix(RDF, m, n)
            for i in range(m):
                A_RDF.set_row(i, [RDF(A[i][j]) for j in range(n)])

            A = copy(A_RDF)
            b = copy(b_RDF)

        ambient_dim = A.ncols()

        # transform to real, if needed
        if A.base_ring() != RDF:
            A.change_ring(RDF)

        if b.base_ring() != RDF:
            b.change_ring(RDF)

        ieqs_list = []
        for i in range(A.nrows()):
            ieqs_list.append(
                list(-A.row(i))
            )  #change in sign, necessary since Polyhedron receives Ax+b>=0
            ieqs_list[i].insert(0, b[i])

        P = Polyhedron(ieqs=ieqs_list,
                       base_ring=RDF,
                       ambient_dim=A.ncols(),
                       backend='cdd')

    elif (base_ring == QQ):

        if 'numpy.ndarray' in str(type(A)):
            # assuming that b is also a numpy array
            m = A.shape[0]
            n = A.shape[1]

            b_QQ = vector(QQ, m, [QQ(b[i]) for i in range(m)])
            A_QQ = matrix(QQ, m, n)

            for i in range(m):
                A_QQ.set_row(i, [QQ(A[i][j]) for j in range(n)])

            A = copy(A_QQ)
            b = copy(b_QQ)

        ambient_dim = A.ncols()

        # transform to rational, if needed
        if A.base_ring() != QQ:
            #for i in range(A.nrows()):
            #    A.set_row(i,[QQ(A.row(i)[j]) for j in range(ambient_dim)]);
            A.change_ring(QQ)

        if b.base_ring() != QQ:
            #b = vector(QQ, [QQ(bi) for bi in b]);
            b.change_ring(QQ)

        ieqs_list = []
        for i in range(A.nrows()):
            ieqs_list.append(
                list(-A.row(i))
            )  #change in sign, necessary since Polyhedron receives Ax+b>=0
            ieqs_list[i].insert(0, b[i])

        P = Polyhedron(ieqs=ieqs_list,
                       base_ring=QQ,
                       ambient_dim=A.ncols(),
                       backend='ppl')

    else:
        raise ValueError('Base ring not supported. Try with RDF or QQ.')

    return P
Ejemplo n.º 20
0
def Zinf(a, l, m, r, algorithm='spline'):
    r"""
    Amplitude factor of the mode `(\ell,m)`.

    The factor `Z^\infty_{\ell m}(r)` is obtained by spline interpolation
    of tabulated numerical solutions of the radial component of the
    Teukolsky equation.

    INPUT:

    - ``a`` -- BH angular momentum parameter (in units of `M`, the BH mass)
    - ``l`` -- integer >= 2; the harmonic degree `\ell`
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number `m`
    - ``r`` -- areal radius of the orbit (in units of `M`)
    - ``algorithm`` -- (default: ``'spline'``) string describing the
      computational method; allowed values are

      - ``'spline'``: spline interpolation of tabulated data
      - ``'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`], with a minus one factor
        accounting for a different convention for the metric signature.

    OUTPUT:

    - coefficient `Z^\infty_{\ell m}(r)` (in units of `M^{-2}`)

    EXAMPLES::

        sage: from kerrgeodesic_gw import Zinf
        sage: Zinf(0.98, 2, 2, 1.7)  # tol 1.0e-13
        -0.04302234478778856 + 0.28535368610053824*I
        sage: Zinf(0., 2, 2, 10.)  # tol 1.0e-13
        0.0011206407919254163 - 0.0003057608384581628*I
        sage: Zinf(0., 2, 2, 10., algorithm='1.5PN')  # tol 1.0e-13
        0.0011971529546749354 - 0.0003551610880408921*I

    """
    if m < 0:
        return (-1)**l * Zinf(a, l, -m, r, algorithm=algorithm).conjugate()
    if algorithm == '1.5PN':
        if a == 0:
            # the factor (-1) below accounts for a difference of signature with
            # Poisson (1993):
            return -Zinf_Schwarzchild_PN(l, m, r)
        raise ValueError("a must be zero for algorithm='1.5PN'")
    a = RDF(a)
    param = (a, l, m)
    if param in _cached_splines:
        splines = _cached_splines[param]
    else:
        file_name = "data/Zinf_a{:.1f}.dat".format(float(a)) if a <= 0.9 \
                    else "data/Zinf_a{:.2f}.dat".format(float(a))
        file_name = os.path.join(os.path.dirname(__file__), file_name)
        r_high_l = 20. if a <= 0.9 else 10.
        with open(file_name, "r") as data_file:
            lm_values = []  # l values up to 10 (for r <= r_high_l)
            lm_values_low = []  # l values up to 5 only (for r > r_high_l)
            for ld in range(2, 6):
                for md in range(1, ld + 1):
                    lm_values_low.append((ld, md))
            for ld in range(2, 11):
                for md in range(1, ld + 1):
                    lm_values.append((ld, md))
            Zreal = {}
            Zimag = {}
            for (ld, md) in lm_values:
                Zreal[(ld, md)] = []
                Zimag[(ld, md)] = []
            for line in data_file:
                items = line.split('\t')
                rd = RDF(items.pop(0))
                if rd <= r_high_l:
                    for (ld, md) in lm_values:
                        Zreal[(ld, md)].append((rd, RDF(items.pop(0))))
                        Zimag[(ld, md)].append((rd, RDF(items.pop(0))))
                else:
                    for (ld, md) in lm_values_low:
                        Zreal[(ld, md)].append((rd, RDF(items.pop(0))))
                        Zimag[(ld, md)].append((rd, RDF(items.pop(0))))
        for (ld, md) in lm_values:
            _cached_splines[(a, ) + (ld, md)] = (spline(Zreal[(ld, md)]),
                                                 spline(Zimag[(ld, md)]))
        if param not in _cached_splines:
            raise ValueError(
                "Zinf: case (a, l, m) = {} not implemented".format(param))
        splines = _cached_splines[param]
    # The factor (-1)**(l+m) below accounts for a difference of convention
    # in the C++ code used to produce the data files
    return (-1)**(l + m) * CDF(splines[0](r), splines[1](r))
Ejemplo n.º 21
0
    def __init__(self, points):
        r"""
        See ``VoronoiDiagram`` for full documentation.

        EXAMPLES::

            sage: V = VoronoiDiagram([[1, 3, 3], [2, -2, 1], [-1 ,2, -1]]); V
            The Voronoi diagram of 3 points of dimension 3 in the Rational Field
        """
        self._P = {}
        self._points = PointConfiguration(points)
        self._n = self._points.n_points()
        if not self._n or self._points.base_ring().is_subring(QQ):
            self._base_ring = QQ
        elif isinstance(self._points.base_ring(), sage.rings.abc.RealDoubleField) or self._points.base_ring() == AA:
            self._base_ring = self._points.base_ring()
        elif isinstance(self._points.base_ring(), sage.rings.abc.RealField):
            from sage.rings.real_double import RDF
            self._base_ring = RDF
            self._points = PointConfiguration([[RDF(cor) for cor in poi]
                                               for poi in self._points])
        else:
            raise NotImplementedError('Base ring of the Voronoi diagram must '
                                      'be one of QQ, RDF, AA.')

        if self._n > 0:
            self._d = self._points.ambient_dim()
            e = [([sum(vector(i)[k] ** 2
                       for k in range(self._d))] +
                  [(-2) * vector(i)[l] for l in range(self._d)] + [1])
                 for i in self._points]
            # we attach hyperplane to the paraboloid

            e = [[self._base_ring(i) for i in k] for k in e]
            p = Polyhedron(ieqs=e, base_ring=self._base_ring)
            # To understand the reordering that takes place when
            # defining a rational polyhedron, we generate two sorted
            # lists, that are used a few lines below
            if self.base_ring() == QQ:
                enormalized = []
                for ineq in e:
                    if ineq[0] == 0:
                        enormalized.append(ineq)
                    else:
                        enormalized.append([i / ineq[0] for i in ineq[1:]])
                # print enormalized
                hlist = [list(ineq) for ineq in p.Hrepresentation()]
                hlistnormalized = []
                for ineq in hlist:
                    if ineq[0] == 0:
                        hlistnormalized.append(ineq)
                    else:
                        hlistnormalized.append([i / ineq[0] for i in ineq[1:]])
                # print hlistnormalized

        for i in range(self._n):
            # for base ring RDF and AA, Polyhedron keeps the order of the
            # points in the input, for QQ we resort
            if self.base_ring() == QQ:
                equ = p.Hrepresentation(hlistnormalized.index(enormalized[i]))
            else:
                equ = p.Hrepresentation(i)
            pvert = [[u[k] for k in range(self._d)] for u in equ.incident()
                     if u.is_vertex()]
            prays = [[u[k] for k in range(self._d)] for u in equ.incident()
                     if u.is_ray()]
            pline = [[u[k] for k in range(self._d)] for u in equ.incident()
                     if u.is_line()]
            (self._P)[self._points[i]] = Polyhedron(vertices=pvert,
                                                    lines=pline, rays=prays,
                                                    base_ring=self._base_ring)
Ejemplo n.º 22
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
Ejemplo n.º 23
0
def round(x, ndigits=0):
    """
    round(number[, ndigits]) - double-precision real number

    Round a number to a given precision in decimal digits (default 0
    digits). If no precision is specified this just calls the element's
    .round() method.

    EXAMPLES::

        sage: round(sqrt(2),2)
        1.41
        sage: q = round(sqrt(2),5); q
        1.41421
        sage: type(q)
        <type 'sage.rings.real_double.RealDoubleElement'>
        sage: q = round(sqrt(2)); q
        1
        sage: type(q)
        <type 'sage.rings.integer.Integer'>
        sage: round(pi)
        3
        sage: b = 5.4999999999999999
        sage: round(b)
        5

    This example addresses :trac:`23502`::

        sage: n = round(6); type(n)
        <type 'sage.rings.integer.Integer'>

    Since we use floating-point with a limited range, some roundings can't
    be performed::

        sage: round(sqrt(Integer('1'*1000)),2)
        +infinity

    IMPLEMENTATION: If ndigits is specified, it calls Python's builtin
    round function, and converts the result to a real double field
    element. Otherwise, it tries the argument's .round() method; if
    that fails, it reverts to the builtin round function, converted to
    a real double field element.

    .. NOTE::

        This is currently slower than the builtin round function, since
        it does more work - i.e., allocating an RDF element and
        initializing it. To access the builtin version do
        ``from six.moves import builtins; builtins.round``.
    """
    try:
        if ndigits:
            x = float(x)
            return RealDoubleElement(builtins.round(x, ndigits))
        else:
            try:
                return x.round()
            except AttributeError:
                return RealDoubleElement(builtins.round(x, 0))
    except ArithmeticError:
        if not isinstance(x, RealDoubleElement):
            return round(RDF(x), ndigits)
        else:
            raise
Ejemplo n.º 24
0
def density_plot(f, xrange, yrange, **options):
    r"""
    ``density_plot`` takes a function of two variables, `f(x,y)`
    and plots the height of the function over the specified
    ``xrange`` and ``yrange`` as demonstrated below.

    ``density_plot(f, (xmin,xmax), (ymin,ymax), ...)``

    INPUT:

    - ``f`` -- a function of two variables

    - ``(xmin,xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
      ``(x,xmin,xmax)``

    - ``(ymin,ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
      ``(y,ymin,ymax)``

    The following inputs must all be passed in as named parameters:

    - ``plot_points`` -- integer (default: 25); number of points to plot
      in each direction of the grid

    - ``cmap`` -- a colormap (default: ``'gray'``), the name of
      a predefined colormap, a list of colors or an instance of a matplotlib
      Colormap. Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``interpolation`` -- string (default: ``'catrom'``), the interpolation
      method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``,
      ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``,
      ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``,
      ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'``


    EXAMPLES:

    Here we plot a simple function of two variables.  Note that
    since the input function is an expression, we need to explicitly
    declare the variables in 3-tuples for the range::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x) * sin(y), (x,-2,2), (y,-2,2))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(sin(x) * sin(y), (x,-2,2), (y,-2,2))
        sphinx_plot(g)

    Here we change the ranges and add some options; note that here
    ``f`` is callable (has variables declared), so we can use 2-tuple ranges::

        sage: x,y = var('x,y')
        sage: f(x,y) = x^2 * cos(x*y)
        sage: density_plot(f, (x,-10,5), (y,-5,5), interpolation='sinc', plot_points=100)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        def f(x,y): return x**2 * cos(x*y)
        g = density_plot(f, (x,-10,5), (y,-5,5), interpolation='sinc', plot_points=100)
        sphinx_plot(g)

    An even more complicated plot::

        sage: x,y = var('x,y')
        sage: density_plot(sin(x^2+y^2) * cos(x) * sin(y), (x,-4,4), (y,-4,4), cmap='jet', plot_points=100)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(sin(x**2 + y**2)*cos(x)*sin(y), (x,-4,4), (y,-4,4), cmap='jet', plot_points=100)
        sphinx_plot(g)

    This should show a "spotlight" right on the origin::

        sage: x,y = var('x,y')
        sage: density_plot(1/(x^10 + y^10), (x,-10,10), (y,-10,10))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(1/(x**10 + y**10), (x,-10,10), (y,-10,10))
        sphinx_plot(g)

    Some elliptic curves, but with symbolic endpoints.  In the first
    example, the plot is rotated 90 degrees because we switch the
    variables `x`, `y`::

        sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(y**2 + 1 - x**3 - x, (y,-pi,pi), (x,-pi,pi))
        sphinx_plot(g)

    ::

        sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi))
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi))
        sphinx_plot(g)

    Extra options will get passed on to show(), as long as they are valid::

        sage: density_plot(log(x) + log(y), (x,1,10), (y,1,10), dpi=20)
        Graphics object consisting of 1 graphics primitive

    .. PLOT::

        x,y = var('x,y')
        g = density_plot(log(x) + log(y), (x,1,10), (y,1,10), dpi=20)
        sphinx_plot(g)

    ::

        sage: density_plot(log(x) + log(y), (x,1,10), (y,1,10)).show(dpi=20) # These are equivalent

    TESTS:

    Check that :trac:`15315` is fixed, i.e., density_plot respects the
    ``aspect_ratio`` parameter. Without the fix, it looks like a thin line
    of width a few mm. With the fix it should look like a nice fat layered
    image::

        sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500), aspect_ratio=.01)
        Graphics object consisting of 1 graphics primitive

    Default ``aspect_ratio`` is ``"automatic"``, and that should work too::

        sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500))
        Graphics object consisting of 1 graphics primitive

    Check that :trac:`17684` is fixed, i.e., symbolic values can be plotted::

        sage: def f(x,y):
        ....:     return SR(x)
        sage: density_plot(f, (0,1), (0,1))
        Graphics object consisting of 1 graphics primitive
    """
    from sage.plot.all import Graphics
    from sage.plot.misc import setup_for_eval_on_grid
    from sage.rings.real_double import RDF
    g, ranges = setup_for_eval_on_grid([f], [xrange, yrange],
                                       options['plot_points'])
    g = g[0]
    xrange, yrange = [r[:2] for r in ranges]

    xy_data_array = [[
        RDF(g(x, y)) for x in xsrange(*ranges[0], include_endpoint=True)
    ] for y in xsrange(*ranges[1], include_endpoint=True)]

    g = Graphics()
    g._set_extra_kwds(
        Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax']))
    g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options))
    return g
Ejemplo n.º 25
0
def Polyhedra(ambient_space_or_base_ring=None,
              ambient_dim=None,
              backend=None,
              *,
              ambient_space=None,
              base_ring=None):
    r"""
    Construct a suitable parent class for polyhedra

    INPUT:

    - ``base_ring`` -- A ring. Currently there are backends for `\ZZ`,
      `\QQ`, and `\RDF`.

    - ``ambient_dim`` -- integer. The ambient space dimension.

    - ``ambient_space`` -- A free module.

    - ``backend`` -- string. The name of the backend for computations. There are
       several backends implemented:

         * ``backend="ppl"`` uses the Parma Polyhedra Library

         * ``backend="cdd"`` uses CDD

         * ``backend="normaliz"`` uses normaliz

         * ``backend="polymake"`` uses polymake

         * ``backend="field"`` a generic Sage implementation

    OUTPUT:

    A parent class for polyhedra over the given base ring if the
    backend supports it. If not, the parent base ring can be larger
    (for example, `\QQ` instead of `\ZZ`). If there is no
    implementation at all, a ``ValueError`` is raised.

    EXAMPLES::

        sage: from sage.geometry.polyhedron.parent import Polyhedra
        sage: Polyhedra(AA, 3)
        Polyhedra in AA^3
        sage: Polyhedra(ZZ, 3)
        Polyhedra in ZZ^3
        sage: type(_)
        <class 'sage.geometry.polyhedron.parent.Polyhedra_ZZ_ppl_with_category'>
        sage: Polyhedra(QQ, 3, backend='cdd')
        Polyhedra in QQ^3
        sage: type(_)
        <class 'sage.geometry.polyhedron.parent.Polyhedra_QQ_cdd_with_category'>

    CDD does not support integer polytopes directly::

        sage: Polyhedra(ZZ, 3, backend='cdd')
        Polyhedra in QQ^3

    Using a more general form of the constructor::

        sage: V = VectorSpace(QQ, 3)
        sage: Polyhedra(V) is Polyhedra(QQ, 3)
        True
        sage: Polyhedra(V, backend='field') is Polyhedra(QQ, 3, 'field')
        True
        sage: Polyhedra(backend='field', ambient_space=V) is Polyhedra(QQ, 3, 'field')
        True

        sage: M = FreeModule(ZZ, 2)
        sage: Polyhedra(M, backend='ppl') is Polyhedra(ZZ, 2, 'ppl')
        True

    TESTS::

        sage: Polyhedra(RR, 3, backend='field')
        Traceback (most recent call last):
        ...
        ValueError: the 'field' backend for polyhedron cannot be used with non-exact fields
        sage: Polyhedra(RR, 3)
        Traceback (most recent call last):
        ...
        ValueError: no default backend for computations with Real Field with 53 bits of precision
        sage: Polyhedra(QQ[I], 2)
        Traceback (most recent call last):
        ...
        ValueError: invalid base ring: Number Field in I with defining polynomial x^2 + 1 with I = 1*I cannot be coerced to a real field
        sage: Polyhedra(AA, 3, backend='polymake')  # optional - polymake
        Traceback (most recent call last):
        ...
        ValueError: the 'polymake' backend for polyhedron cannot be used with Algebraic Real Field

        sage: Polyhedra(QQ, 2, backend='normaliz')   # optional - pynormaliz
        Polyhedra in QQ^2
        sage: Polyhedra(SR, 2, backend='normaliz')   # optional - pynormaliz  # optional - sage.symbolic
        Polyhedra in (Symbolic Ring)^2
        sage: SCR = SR.subring(no_variables=True)                             # optional - sage.symbolic
        sage: Polyhedra(SCR, 2, backend='normaliz')  # optional - pynormaliz  # optional - sage.symbolic
        Polyhedra in (Symbolic Constants Subring)^2
    """
    if ambient_space_or_base_ring is not None:
        if ambient_space_or_base_ring in Rings():
            base_ring = ambient_space_or_base_ring
        else:
            ambient_space = ambient_space_or_base_ring
    if ambient_space is not None:
        if ambient_space not in Modules:
            # There is no category of free modules, unfortunately
            # (see https://trac.sagemath.org/ticket/30164)...
            raise ValueError('ambient_space must be a free module')
        if base_ring is None:
            base_ring = ambient_space.base_ring()
        if ambient_dim is None:
            try:
                ambient_dim = ambient_space.rank()
            except AttributeError:
                # ... so we test whether it is free using the existence of
                # a rank method
                raise ValueError('ambient_space must be a free module')
        if ambient_space is not FreeModule(base_ring, ambient_dim):
            raise NotImplementedError(
                'ambient_space must be a standard free module')
    if backend is None:
        if base_ring is ZZ or base_ring is QQ:
            backend = 'ppl'
        elif base_ring is RDF:
            backend = 'cdd'
        elif base_ring.is_exact():
            # TODO: find a more robust way of checking that the coefficients are indeed
            # real numbers
            if not RDF.has_coerce_map_from(base_ring):
                raise ValueError(
                    "invalid base ring: {} cannot be coerced to a real field".
                    format(base_ring))
            backend = 'field'
        else:
            raise ValueError(
                "no default backend for computations with {}".format(
                    base_ring))

    try:
        from sage.symbolic.ring import SR
    except ImportError:
        SR = None
    if backend == 'ppl' and base_ring is QQ:
        return Polyhedra_QQ_ppl(base_ring, ambient_dim, backend)
    elif backend == 'ppl' and base_ring is ZZ:
        return Polyhedra_ZZ_ppl(base_ring, ambient_dim, backend)
    elif backend == 'normaliz' and base_ring is QQ:
        return Polyhedra_QQ_normaliz(base_ring, ambient_dim, backend)
    elif backend == 'normaliz' and base_ring is ZZ:
        return Polyhedra_ZZ_normaliz(base_ring, ambient_dim, backend)
    elif backend == 'normaliz' and (isinstance(
            base_ring, sage.rings.abc.SymbolicRing) or base_ring.is_exact()):
        return Polyhedra_normaliz(base_ring, ambient_dim, backend)
    elif backend == 'cdd' and base_ring in (ZZ, QQ):
        return Polyhedra_QQ_cdd(QQ, ambient_dim, backend)
    elif backend == 'cdd' and base_ring is RDF:
        return Polyhedra_RDF_cdd(RDF, ambient_dim, backend)
    elif backend == 'polymake':
        base_field = base_ring.fraction_field()
        try:
            from sage.interfaces.polymake import polymake
            polymake_base_field = polymake(base_field)
        except TypeError:
            raise ValueError(
                f"the 'polymake' backend for polyhedron cannot be used with {base_field}"
            )
        return Polyhedra_polymake(base_field, ambient_dim, backend)
    elif backend == 'field':
        if not base_ring.is_exact():
            raise ValueError(
                "the 'field' backend for polyhedron cannot be used with non-exact fields"
            )
        return Polyhedra_field(base_ring.fraction_field(), ambient_dim,
                               backend)
    else:
        raise ValueError('No such backend (=' + str(backend) +
                         ') implemented for given basering (=' +
                         str(base_ring) + ').')
def vectors_by_length(self, bound):
    """
    Returns a list of short vectors together with their values.

    This is a naive algorithm which uses the Cholesky decomposition,
    but does not use the LLL-reduction algorithm.

    INPUT:
       bound -- an integer >= 0

    OUTPUT:
        A list L of length (bound + 1) whose entry L `[i]` is a list of
        all vectors of length `i`.

    Reference: This is a slightly modified version of Cohn's Algorithm
    2.7.5 in "A Course in Computational Number Theory", with the
    increment step moved around and slightly re-indexed to allow clean
    looping.

    Note: We could speed this up for very skew matrices by using LLL
    first, and then changing coordinates back, but for our purposes
    the simpler method is efficient enough. =)

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1])
        sage: Q.vectors_by_length(5)
        [[[0, 0]],
         [[0, -1], [-1, 0]],
         [[-1, -1], [1, -1]],
         [],
         [[0, -2], [-2, 0]],
         [[-1, -2], [1, -2], [-2, -1], [2, -1]]]

    ::

        sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q1.vectors_by_length(5)
        [[[0, 0, 0, 0]],
         [[-1, 0, 0, 0]],
         [],
         [[0, -1, 0, 0]],
         [[-1, -1, 0, 0], [1, -1, 0, 0], [-2, 0, 0, 0]],
         [[0, 0, -1, 0]]]

    ::

        sage: Q = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1])
        sage: map(len, Q.vectors_by_length(2))
        [1, 12, 12]

    ::

        sage: Q = QuadraticForm(ZZ, 4, [1,-1,-1,-1, 1,0,0, 4,-3, 4])
        sage: map(len, Q.vectors_by_length(3))
        [1, 3, 0, 3]
    """
    # pari uses eps = 1e-6 ; nothing bad should happen if eps is too big
    # but if eps is too small, roundoff errors may knock off some
    # vectors of norm = bound (see #7100)
    eps = RDF(1e-6)
    bound = ZZ(floor(max(bound, 0)))
    Theta_Precision = bound + eps
    n = self.dim()

    ## Make the vector of vectors which have a given value
    ## (So theta_vec[i] will have all vectors v with Q(v) = i.)
    theta_vec = [[] for i in range(bound + 1)]

    ## Initialize Q with zeros and Copy the Cholesky array into Q
    Q = self.cholesky_decomposition()


    ## 1. Initialize
    T = n * [RDF(0)]    ## Note: We index the entries as 0 --> n-1
    U = n * [RDF(0)]
    i = n-1
    T[i] = RDF(Theta_Precision)
    U[i] = RDF(0)

    L = n * [0]
    x = n * [0]
    Z = RDF(0)

    ## 2. Compute bounds
    Z = (T[i] / Q[i][i]).sqrt(extend=False)
    L[i] = ( Z - U[i]).floor()
    x[i] = (-Z - U[i]).ceil()

    done_flag = False
    Q_val_double = RDF(0)
    Q_val = 0 ## WARNING: Still need a good way of checking overflow for this value...

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

        ## 3b. Main loop -- try to generate a complete vector x (when i=0)
        while (i > 0):
            #print " i = ", i
            #print " T[i] = ", T[i]
            #print " Q[i][i] = ", Q[i][i]
            #print " x[i] = ", x[i]
            #print " U[i] = ", U[i]
            #print " x[i] + U[i] = ", (x[i] + U[i])
            #print " T[i-1] = ", T[i-1]

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

            #print " T[i-1] = ",  T[i-1]
            #print " x = ", x
            #print

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

            ## Now go back and compute the bounds...
            ## 2. Compute bounds
            Z = (T[i] / Q[i][i]).sqrt(extend=False)
            L[i] = ( Z - U[i]).floor()
            x[i] = (-Z - U[i]).ceil()

            # carry if we go out of bounds -- when Z is so small that
            # there aren't any integral vectors between the bounds
            # Note: this ensures T[i-1] >= 0 in the next iteration
            while (x[i] > L[i]):
                i += 1
                x[i] += 1

        ## 4. Solution found (This happens when i = 0)
        #print "-- Solution found! --"
        #print " x = ", x
        #print " Q_val = Q(x) = ", Q_val
        Q_val_double = Theta_Precision - T[0] + Q[0][0] * (x[0] + U[0]) * (x[0] + U[0])
        Q_val = Q_val_double.round()

        ## SANITY CHECK: Roundoff Error is < 0.001
        if abs(Q_val_double -  Q_val) > 0.001:
            print " x = ", x
            print " Float = ", Q_val_double, "   Long = ", Q_val
            raise RuntimeError("The roundoff error is bigger than 0.001, so we should use more precision somewhere...")

        #print " Float = ", Q_val_double, "   Long = ", Q_val, "  XX "
        #print " The float value is ", Q_val_double
        #print " The associated long value is ", Q_val

        if (Q_val <= bound):
            #print " Have vector ",  x, " with value ", Q_val
            theta_vec[Q_val].append(deepcopy(x))


        ## 5. Check if x = 0, for exit condition. =)
        j = 0
        done_flag = True
        while (j < n):
            if (x[j] != 0):
                done_flag = False
            j += 1


        ## 3a. Increment (and carry if we go out of bounds)
        x[i] += 1
        while (x[i] > L[i]) and (i < n-1):
            i += 1
            x[i] += 1


    #print " Leaving ThetaVectors()"
    return theta_vec
Ejemplo n.º 27
0
Archivo: shapes2.py Proyecto: yarv/sage
def point3d(v, size=5, **kwds):
    """
    Plot a point or list of points in 3d space.

    INPUT:

    -  ``v`` -- a point or list of points

    -  ``size`` -- (default: 5) size of the point (or
       points)

    - ``color`` -- a string (``"red"``, ``"green"`` etc)
      or a tuple (r, g, b) with r, g, b numbers between 0 and 1

    -  ``opacity`` -- (default: 1) if less than 1 then is
       transparent

    EXAMPLES::

        sage: sum([point3d((i,i^2,i^3), size=5) for i in range(10)])
        Graphics3d Object

    We check to make sure this works with vectors and other iterables::

        sage: pl = point3d([vector(ZZ,(1, 0, 0)), vector(ZZ,(0, 1, 0)), (-1, -1, 0)])
        sage: print(point(vector((2,3,4))))
        Graphics3d Object

        sage: c = polytopes.hypercube(3)
        sage: v = c.vertices()[0];  v
        A vertex at (-1, -1, -1)
        sage: print(point(v))
        Graphics3d Object

    We check to make sure the options work::

        sage: point3d((4,3,2),size=20,color='red',opacity=.5)
        Graphics3d Object

    numpy arrays can be provided as input::

        sage: import numpy
        sage: point3d(numpy.array([1,2,3]))
        Graphics3d Object

        sage: point3d(numpy.array([[1,2,3], [4,5,6], [7,8,9]]))
        Graphics3d Object

    We check that iterators of points are accepted (:trac:`13890`)::

        sage: point3d(iter([(1,1,2),(2,3,4),(3,5,8)]),size=20,color='red')
        Graphics3d Object

    TESTS::

        sage: point3d([])
        Graphics3d Object
    """
    try:
        l = len(v)
    except TypeError:
        # argument is an iterator
        v = list(v)
        l = len(v)

    if l == 0:
        from sage.plot.plot3d.base import Graphics3d
        return Graphics3d()

    if l == 3:
        try:
            # check if the first element can be changed to a float
            tmp = RDF(v[0])
            return Point(v, size, **kwds)
        except TypeError:
            pass

    A = sum([Point(z, size, **kwds) for z in v])
    A._set_extra_kwds(kwds)
    return A
def spin_weighted_spheroidal_harmonic(s,
                                      l,
                                      m,
                                      gamma,
                                      theta,
                                      phi,
                                      verbose=False,
                                      cached=True,
                                      min_nmax=8):
    r"""
    Return the spin-weighted oblate spheroidal harmonic of spin weight ``s``,
    degree ``l``, azimuthal order ``m`` and spheroidicity ``gamma``.

    INPUT:

    - ``s`` -- integer; the spin weight
    - ``l`` -- non-negative integer; the harmonic degree
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number
    - ``gamma`` -- spheroidicity parameter
    - ``theta`` -- colatitude angle
    - ``phi`` -- azimuthal angle
    - ``verbose`` -- (default: ``False``) determines whether some details of
      the computation are printed out
    - ``cached`` -- (default: ``True``) determines whether the eigenvectors
      shall be cached; setting ``cached`` to ``False`` forces a new
      computation, without caching the result
    - ``min_nmax`` -- (default: 8) integer; floor for the evaluation of the
      parameter ``nmax``, which sets the highest degree of the spherical
      harmonic expansion as ``l+nmax``.

    OUTPUT:

    - value of `{}_s S_{lm}^\gamma(\theta,\phi)`

    ALGORITHM:

    The spin-weighted oblate spheroidal harmonics are computed by an expansion
    over spin-weighted *spherical* harmonics, the coefficients of the expansion
    being obtained by solving an eigenvalue problem, as exposed in Appendix A
    of S.A. Hughes, Phys. Rev. D **61**, 084004 (2000)
    [:doi:`10.1103/PhysRevD.61.084004`].

    EXAMPLES::

        sage: from kerrgeodesic_gw import spin_weighted_spheroidal_harmonic
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/2, 0)  # tol 1.0e-13
        0.08702532727529422
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/3, pi/3)  # tol 1.0e-13
        -0.14707166027821453 + 0.25473558795537715*I
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/3, pi/3, cached=False)   # tol 1.0e-13
        -0.14707166027821453 + 0.25473558795537715*I
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/3, pi/4)  # tol 1.0e-13
        1.801108380050024e-17 + 0.2941433205564291*I
        sage: spin_weighted_spheroidal_harmonic(-2, 2, -1, 1.1, pi/3, pi/3, cached=False)  # tol 1.0e-13
        0.11612826056899399 - 0.20114004750009495*I

    Test that the relation
    `{}_s S_{lm}^\gamma(\theta,\phi) = (-1)^{l+s}\, {}_s S_{l,-m}^{-\gamma}(\pi-\theta,-\phi)`
    [cf. Eq. (2.3) of :arxiv:`1810.00432`], which is used to evaluate
    `{}_s S_{lm}^\gamma(\theta,\phi)` when `m<0` and ``cached`` is ``True``,
    is correctly implemented::

        sage: spin_weighted_spheroidal_harmonic(-2, 2, -2, 1.1, pi/3, pi/3)  # tol 1.0e-13
        -0.04097260436590737 - 0.07096663248016997*I
        sage: abs(_ - spin_weighted_spheroidal_harmonic(-2, 2, -2, 1.1, pi/3, pi/3,
        ....:                                           cached=False)) < 1.e-13
        True
        sage: spin_weighted_spheroidal_harmonic(-2, 3, -1, 1.1, pi/3, pi/3)  # tol 1.0e-13
        0.1781880511506843 - 0.3086307578946672*I
        sage: abs(_ - spin_weighted_spheroidal_harmonic(-2, 3, -1, 1.1, pi/3, pi/3,
        ....:                                           cached=False)) < 1.e-13
        True

    """
    global _eigenvectors
    if m < 0 and cached:
        # We use the symmetry formula
        #  {}_s S_{lm}^\gamma(\theta,\phi) =
        #                  (-1)^{l+s} {}_s S_{l,-m}^{-\gamma}(\pi-\theta,-\phi)
        # cf. Eq. (2.3) of  https://arxiv.org/abs/1810.00432
        return (-1)**(l + s) * spin_weighted_spheroidal_harmonic(
            s,
            l,
            -m,
            -gamma,
            pi - theta,
            -phi,
            verbose=verbose,
            cached=cached,
            min_nmax=min_nmax)
    s = ZZ(s)  # ensure that we are dealing with Sage integers
    l = ZZ(l)
    m = ZZ(m)
    gamma = RDF(gamma)  # all computations are performed with RDF
    param = (s, l, m, gamma)
    if cached:
        if param not in _eigenvectors:
            _eigenvectors[param] = _compute_eigenvector(*param,
                                                        verbose=verbose,
                                                        min_nmax=min_nmax)
        data = _eigenvectors[param]
    else:
        data = _compute_eigenvector(*param, verbose=verbose, min_nmax=min_nmax)
    egvec = data[1]
    nmin = data[2]
    nmax = data[3]
    lmin = data[4]
    # If neither theta nor phi is symbolic, we convert both of them to RDF:
    if not ((isinstance(theta, Expression) and theta.variables()) or
            (isinstance(phi, Expression) and phi.variables())):
        theta = RDF(theta)
        phi = RDF(phi)
    resu = RDF(0)
    for k in range(-nmin, nmax + 1):
        resu += egvec[k + nmin] \
                 * spin_weighted_spherical_harmonic(s, l+k, m, theta, phi,
                                                    condon_shortley=True)
    resu *= sgn(egvec[min(l - lmin + 1, (nmax + nmin) / 2 + 1) - 1])
    return resu
Ejemplo n.º 29
0
def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False):
    """
    A mutable list of elements with a common guaranteed universe,
    which can be set immutable.

    A universe is either an object that supports coercion (e.g., a
    parent), or a category.

    INPUT:

    - ``x`` - a list or tuple instance

    - ``universe`` - (default: None) the universe of elements; if None
      determined using canonical coercions and the entire list of
      elements.  If list is empty, is category Objects() of all
      objects.

    - ``check`` -- (default: True) whether to coerce the elements of x
      into the universe

    - ``immutable`` - (default: True) whether or not this sequence is
      immutable

    - ``cr`` - (default: False) if True, then print a carriage return
      after each comma when printing this sequence.

    - ``cr_str`` - (default: False) if True, then print a carriage return
      after each comma when calling ``str()`` on this sequence.

    - ``use_sage_types`` -- (default: False) if True, coerce the
       built-in Python numerical types int, long, float, complex to the
       corresponding Sage types (this makes functions like vector()
       more flexible)
    
    OUTPUT:

    - a sequence

    EXAMPLES::
    
        sage: v = Sequence(range(10))
        sage: v.universe()
        <type 'int'>
        sage: v
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    We can request that the built-in Python numerical types be coerced
    to Sage objects::
    
        sage: v = Sequence(range(10), use_sage_types=True)
        sage: v.universe()
        Integer Ring
        sage: v
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    You can also use seq for "Sequence", which is identical to using
    Sequence::
    
        sage: v = seq([1,2,1/1]); v
        [1, 2, 1]
        sage: v.universe()
        Rational Field
        sage: v.parent()
        Category of sequences in Rational Field
        sage: v.parent()([3,4/3])
        [3, 4/3]
        

    Note that assignment coerces if possible,::
    
        sage: v = Sequence(range(10), ZZ)
        sage: a = QQ(5)
        sage: v[3] = a
        sage: parent(v[3])
        Integer Ring
        sage: parent(a)
        Rational Field
        sage: v[3] = 2/3
        Traceback (most recent call last):
        ...
        TypeError: no conversion of this rational to integer

    Sequences can be used absolutely anywhere lists or tuples can be used::
    
        sage: isinstance(v, list)
        True

    Sequence can be immutable, so entries can't be changed::
    
        sage: v = Sequence([1,2,3], immutable=True)
        sage: v.is_immutable()
        True
        sage: v[0] = 5
        Traceback (most recent call last):
        ...
        ValueError: object is immutable; please change a copy instead.

    Only immutable sequences are hashable (unlike Python lists),
    though the hashing is potentially slow, since it first involves
    conversion of the sequence to a tuple, and returning the hash of
    that.::

        sage: v = Sequence(range(10), ZZ, immutable=True)
        sage: hash(v)
        1591723448             # 32-bit
        -4181190870548101704   # 64-bit


    If you really know what you are doing, you can circumvent the type
    checking (for an efficiency gain)::
    
        sage: list.__setitem__(v, int(1), 2/3)        # bad circumvention
        sage: v
        [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9]
        sage: list.__setitem__(v, int(1), int(2))     # not so bad circumvention

    You can make a sequence with a new universe from an old sequence.::
    
        sage: w = Sequence(v, QQ)
        sage: w
        [0, 2, 2, 3, 4, 5, 6, 7, 8, 9]
        sage: w.universe()
        Rational Field
        sage: w[1] = 2/3
        sage: w
        [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9]

    Sequences themselves live in a category, the category of all sequences
    in the given universe.::
    
        sage: w.category()
        Category of sequences in Rational Field
        
    This is also the parent of any sequence::
    
        sage: w.parent()
        Category of sequences in Rational Field

    The default universe for any sequence, if no compatible parent structure
    can be found, is the universe of all Sage objects.

    This example illustrates how every element of a list is taken into account
    when constructing a sequence.::
    
        sage: v = Sequence([1,7,6,GF(5)(3)]); v
        [1, 2, 1, 3]
        sage: v.universe()
        Finite Field of size 5
        sage: v.parent()
        Category of sequences in Finite Field of size 5
        sage: v.parent()([7,8,9])
        [2, 3, 4]
    """
    from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal


    if isinstance(x, Sequence_generic) and universe is None:
        universe = x.universe()
        x = list(x)

    if isinstance(x, MPolynomialIdeal) and universe is None:
        universe = x.ring()
        x = x.gens()

    if universe is None:
        if not isinstance(x, (list, tuple)):
            x = list(x)
            #raise TypeError("x must be a list or tuple")

        if len(x) == 0:
            import sage.categories.all
            universe = sage.categories.all.Objects()
        else:
            import sage.structure.element as coerce
            y = x
            x = list(x)   # make a copy, or we'd change the type of the elements of x, which would be bad.
            if use_sage_types:
                # convert any Python built-in numerical types to Sage objects
                from sage.rings.integer_ring import ZZ
                from sage.rings.real_double import RDF
                from sage.rings.complex_double import CDF
                for i in range(len(x)):
                    if isinstance(x[i], int) or isinstance(x[i], long):
                        x[i] = ZZ(x[i])
                    elif isinstance(x[i], float):
                        x[i] = RDF(x[i])
                    elif isinstance(x[i], complex):
                        x[i] = CDF(x[i])
            # start the pairwise coercion
            for i in range(len(x)-1):
                try:
                    x[i], x[i+1] = coerce.canonical_coercion(x[i],x[i+1])
                except TypeError:
                    import sage.categories.all
                    universe = sage.categories.all.Objects()
                    x = list(y)
                    check = False  # no point
                    break
            if universe is None:   # no type errors raised.
                universe = coerce.parent(x[len(x)-1])

    from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
    from sage.rings.quotient_ring import is_QuotientRing
    from sage.rings.polynomial.pbori import BooleanMonomialMonoid

    if is_MPolynomialRing(universe) or \
            (is_QuotientRing(universe) and is_MPolynomialRing(universe.cover_ring())) or \
            isinstance(universe, BooleanMonomialMonoid):
        from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence
        try:
            return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str)
        except (TypeError,AttributeError):
            return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types)
    else:
        return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types)
Ejemplo n.º 30
0
def Zinf_Schwarzchild_PN(l, m, r):
    r"""
    Amplitude factor of the mode `(\ell,m)` for a Schwarzschild BH at the 1.5PN
    level.

    The 1.5PN formulas are taken from E. Poisson, Phys. Rev. D **47**, 1497
    (1993), :doi:`10.1103/PhysRevD.47.1497`.

    INPUT:

    - ``l`` -- integer >= 2; the harmonic degree `\ell`
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number `m`
    - ``r`` -- areal radius of the orbit (in units of `M`, the BH mass)

    OUTPUT:

    - coefficient `Z^\infty_{\ell m}(r)` (in units of `M^{-2}`)

    EXAMPLES::

        sage: from kerrgeodesic_gw import Zinf_Schwarzchild_PN
        sage: Zinf_Schwarzchild_PN(2, 2, 6.)  # tol 1.0e-13
        -0.00981450418730346 + 0.003855681972781947*I
        sage: Zinf_Schwarzchild_PN(5, 3, 6.)  # tol 1.0e-13
        -6.958527913913504e-05*I

    """
    if m < 0:
        return (-1)**l * Zinf_Schwarzchild_PN(l, -m, r).conjugate()
    v = 1. / sqrt(r)
    if l == 2:
        b = RDF(sqrt(pi / 5.) / r**4)
        if m == 1:
            return CDF(4. / 3. * I * b * v * (1 - 17. / 28. * v**2))
        if m == 2:
            return CDF(-16 * b *
                       (1 - 107. / 42. * v**2 +
                        (2 * pi + 4 * I *
                         (3 * ln(2 * v) - 0.839451001765134)) * v**3))
    if l == 3:
        b = RDF(sqrt(pi / 7.) / r**(4.5))
        if m == 1:
            return CDF(I / 3. * b / sqrt(10.) * (1 - 8. / 3. * v**2))
        if m == 2:
            return CDF(-16. / 3. * b * v)
        if m == 3:
            return CDF(-81 * I * b / sqrt(8.) * (1 - 4 * v**2))
    if l == 4:
        b = RDF(sqrt(pi) / r**5)
        if m == 1:
            return CDF(I / 105. * b / sqrt(2) * v)
        if m == 2:
            return CDF(-16. / 63. * b)
        if m == 3:
            return CDF(-81. / 5. * I * b / sqrt(14.) * v)
        if m == 4:
            return CDF(512. / 9. * b / sqrt(7.))
    if l == 5:
        b = RDF(sqrt(pi) / r**(5.5))
        if m == 1:
            return CDF(I / 360. * b / sqrt(77.))
        if m == 2:
            return CDF(0)
        if m == 3:
            return CDF(-81. / 40. * I * b * sqrt(3. / 22.))
        if m == 4:
            return CDF(0)
        if m == 5:
            return CDF(3125. / 24. * I * b * sqrt(5. / 66.))
    raise NotImplementedError("{} not implemented".format((l, m)))
Ejemplo n.º 31
0
def vectors_by_length(self, bound):
    """
    Returns a list of short vectors together with their values.

    This is a naive algorithm which uses the Cholesky decomposition,
    but does not use the LLL-reduction algorithm.

    INPUT:

       bound -- an integer >= 0

    OUTPUT:

        A list L of length (bound + 1) whose entry L `[i]` is a list of
        all vectors of length `i`.

    Reference: This is a slightly modified version of Cohn's Algorithm
    2.7.5 in "A Course in Computational Number Theory", with the
    increment step moved around and slightly re-indexed to allow clean
    looping.

    Note: We could speed this up for very skew matrices by using LLL
    first, and then changing coordinates back, but for our purposes
    the simpler method is efficient enough. =)

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1])
        sage: Q.vectors_by_length(5)
        [[[0, 0]],
         [[0, -1], [-1, 0]],
         [[-1, -1], [1, -1]],
         [],
         [[0, -2], [-2, 0]],
         [[-1, -2], [1, -2], [-2, -1], [2, -1]]]

    ::

        sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q1.vectors_by_length(5)
        [[[0, 0, 0, 0]],
         [[-1, 0, 0, 0]],
         [],
         [[0, -1, 0, 0]],
         [[-1, -1, 0, 0], [1, -1, 0, 0], [-2, 0, 0, 0]],
         [[0, 0, -1, 0]]]

    ::

        sage: Q = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1])
        sage: list(map(len, Q.vectors_by_length(2)))
        [1, 12, 12]

    ::

        sage: Q = QuadraticForm(ZZ, 4, [1,-1,-1,-1, 1,0,0, 4,-3, 4])
        sage: list(map(len, Q.vectors_by_length(3)))
        [1, 3, 0, 3]
    """
    # pari uses eps = 1e-6 ; nothing bad should happen if eps is too big
    # but if eps is too small, roundoff errors may knock off some
    # vectors of norm = bound (see #7100)
    eps = RDF(1e-6)
    bound = ZZ(floor(max(bound, 0)))
    Theta_Precision = bound + eps
    n = self.dim()

    ## Make the vector of vectors which have a given value
    ## (So theta_vec[i] will have all vectors v with Q(v) = i.)
    theta_vec = [[] for i in range(bound + 1)]

    ## Initialize Q with zeros and Copy the Cholesky array into Q
    Q = self.cholesky_decomposition()

    ## 1. Initialize
    T = n * [RDF(0)]  ## Note: We index the entries as 0 --> n-1
    U = n * [RDF(0)]
    i = n - 1
    T[i] = RDF(Theta_Precision)
    U[i] = RDF(0)

    L = n * [0]
    x = n * [0]
    Z = RDF(0)

    ## 2. Compute bounds
    Z = (T[i] / Q[i][i]).sqrt(extend=False)
    L[i] = (Z - U[i]).floor()
    x[i] = (-Z - U[i]).ceil()

    done_flag = False
    Q_val_double = RDF(0)
    Q_val = 0  ## WARNING: Still need a good way of checking overflow for this value...

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

        ## 3b. Main loop -- try to generate a complete vector x (when i=0)
        while (i > 0):
            #print " i = ", i
            #print " T[i] = ", T[i]
            #print " Q[i][i] = ", Q[i][i]
            #print " x[i] = ", x[i]
            #print " U[i] = ", U[i]
            #print " x[i] + U[i] = ", (x[i] + U[i])
            #print " T[i-1] = ", T[i-1]

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

            #print " T[i-1] = ",  T[i-1]
            #print " x = ", x
            #print

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

            ## Now go back and compute the bounds...
            ## 2. Compute bounds
            Z = (T[i] / Q[i][i]).sqrt(extend=False)
            L[i] = (Z - U[i]).floor()
            x[i] = (-Z - U[i]).ceil()

            # carry if we go out of bounds -- when Z is so small that
            # there aren't any integral vectors between the bounds
            # Note: this ensures T[i-1] >= 0 in the next iteration
            while (x[i] > L[i]):
                i += 1
                x[i] += 1

        ## 4. Solution found (This happens when i = 0)
        #print "-- Solution found! --"
        #print " x = ", x
        #print " Q_val = Q(x) = ", Q_val
        Q_val_double = Theta_Precision - T[0] + Q[0][0] * (x[0] + U[0]) * (
            x[0] + U[0])
        Q_val = Q_val_double.round()

        ## SANITY CHECK: Roundoff Error is < 0.001
        if abs(Q_val_double - Q_val) > 0.001:
            print(" x = ", x)
            print(" Float = ", Q_val_double, "   Long = ", Q_val)
            raise RuntimeError(
                "The roundoff error is bigger than 0.001, so we should use more precision somewhere..."
            )

        #print " Float = ", Q_val_double, "   Long = ", Q_val, "  XX "
        #print " The float value is ", Q_val_double
        #print " The associated long value is ", Q_val

        if (Q_val <= bound):
            #print " Have vector ",  x, " with value ", Q_val
            theta_vec[Q_val].append(deepcopy(x))

        ## 5. Check if x = 0, for exit condition. =)
        j = 0
        done_flag = True
        while (j < n):
            if (x[j] != 0):
                done_flag = False
            j += 1

        ## 3a. Increment (and carry if we go out of bounds)
        x[i] += 1
        while (x[i] > L[i]) and (i < n - 1):
            i += 1
            x[i] += 1

    #print " Leaving ThetaVectors()"
    return theta_vec
Ejemplo n.º 32
0
def edges_intersection(P, i, cmatrix=None):
    r"""Return the point in the plane where the edges adjacent to the input edge intersect.

    INPUT: 

    ``P`` - a polygon (Polyhedron in 2d).

    ``i`` - integer, index of edge in ``P.inequalities_list()``.

    ``cmatrix`` - (optional) if None, the constraints matrix corresponding to P is computed inside the function.

    OUTPUT: 

    ``p`` - coordinates of the intersection of the edges that are adjacent to i.

    ``neighbor_constraints`` - indices of the edges that are adjacent to it. The edges are indexed according to P.inequalities_list(). 

    NOTES: 

    - This has been tested for P in QQ and RDF.
    """
    from sage.symbolic.ring import SR
    from sage.symbolic.relation import solve

    if cmatrix is None:
        cmatrix = vertex_connections(P)

    got_QQ = True if P.base_ring() == QQ else False

    #constraint_i = P.inequalities_list()[i]

    neighbor_constraints = []

    # vertices associated to the given edge i
    vert_i = cmatrix[i]

    for j, cj in enumerate(cmatrix):
        if (vert_i[0] in cj or vert_i[1] in cj) and (j != i):
            neighbor_constraints.append(j)

    # first one
    constr_1 = P.inequalities_list()[neighbor_constraints[0]]

    # second one
    constr_2 = P.inequalities_list()[neighbor_constraints[1]]

    # write and solve the intersection of the two lines
    x1 = SR.var('x1')
    x2 = SR.var('x2')

    eq1 = constr_1[1] * x1 + constr_1[2] * x2 == -constr_1[0]
    eq2 = constr_2[1] * x1 + constr_2[2] * x2 == -constr_2[0]

    p = solve([eq1, eq2], x1, x2)
    p = [p[0][0].right_hand_side(), p[0][1].right_hand_side()]

    if not got_QQ:  # assuming RDF
        # transform to RDF (because solve produces in general rational answers)
        p = [RDF(pi) for pi in p]

    return p, neighbor_constraints