Ejemplo n.º 1
0
    def plot(self, max_points=2500, **args):
        r"""
        Creates a visualization of this `p`-adic ring as a fractal
        similar as a generalization of the 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 adjust_options(self):
        r"""
        Adjust plotting options.

        This function determines appropriate default values for those options,
        that were not specified by the user, based on the other options. See
        :class:`ToricPlotter` for a detailed example.

        OUTPUT:

        - none.

        TESTS::

            sage: from sage.geometry.toric_plotter import ToricPlotter
            sage: tp = ToricPlotter(dict(), 2)
            sage: print(tp.show_lattice)
            None
            sage: tp.adjust_options()
            sage: print(tp.show_lattice)
            True
        """
        # Unfortunately, some of the defaults are dimension specific for no
        # good reason but to remedy 2-d/3-d plotting inconsistencies in Sage.
        d = self.dimension
        if d <= 2:
            if self.point_size is None:
                self.point_size = 50
        elif d == 3:
            if self.point_size is None:
                self.point_size = 10
        if self.generator_thickness is None:
            self.generator_thickness = self.ray_thickness
        sd = self.__dict__
        bounds = ["radius", "xmin", "xmax", "ymin", "ymax", "zmin", "zmax"]
        bounds = [abs(sd[bound]) for bound in bounds if sd[bound] is not None]
        r = RDF(max(bounds + [0.5]) if bounds else 2.5)
        self.radius = r
        round = self.mode == "round"
        for key in ["xmin", "ymin", "zmin"]:
            if round or sd[key] is None:
                sd[key] = -r
            if sd[key] > -0.5:
                sd[key] = -0.5
            sd[key] = RDF(sd[key])
        for key in ["xmax", "ymax", "zmax"]:
            if round or sd[key] is None:
                sd[key] = r
            if sd[key] < 0.5:
                sd[key] = 0.5
            sd[key] = RDF(sd[key])
        if self.show_lattice is None:
            self.show_lattice = (r <= 5) if d <= 2 else r <= 3
Ejemplo n.º 3
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()
Ejemplo n.º 4
0
def real(x):
    """
    Return the real part of x.
    
    EXAMPLES::
    
        sage: z = 1+2*I
        sage: real(z)
        1
        sage: real(5/3)
        5/3
        sage: a = 2.5
        sage: real(a)
        2.50000000000000
        sage: type(real(a))
        <type 'sage.rings.real_mpfr.RealLiteral'>
    """

    #Try to all the .real() method
    try:
        return x.real()
    except AttributeError:
        pass

    #Try to coerce x into RDF.  If that
    #succeeds, then we can just return x
    try:
        rdf_x = RDF(x)
        return x
    except TypeError:
        pass

    #Finall try to coerce x into CDF and call
    #the .real() method.
    return CDF(x).real()
Ejemplo n.º 5
0
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.n_cube(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

    """
    if len(v) == 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
Ejemplo n.º 6
0
def power_spectral_density_RCLfit(freq):
    r"""
    Return the effective power spectral density (PSD) of the detector noise
    at a given frequency, according to the analytical fit by Robson, Cornish
    and Liu, :arxiv:`1803.01944`

    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_RCLfit
        sage: Sn(1.e-1)  # tol 1.0e-13
        2.12858262120861e-39
        sage: Sn(1.e-2)  # tol 1.0e-13
        1.44307343517977e-40
        sage: Sn(1.e-3)  # tol 1.0e-13
        1.63410027259543e-38

    """
    p_oms = 2.25e-22 * (1 + (2.e-3 / freq)**4)
    p_acc = 9.e-30 * (1 + (4.e-4 / freq)**2) * (1 + (freq / 8.e-3)**4)
    L = 2.5e9
    f_star = 1.909e-2
    p_n = (p_oms + 2 * (1 + cos(freq / f_star)**2) * p_acc /
           (2 * RDF(pi) * freq)**4) / L**2
    return 10. / 3. * p_n * (1 + 0.6 * (freq / f_star)**2)
Ejemplo n.º 7
0
    def _normal_pivot(self):
        """
        Return the index of the largest entry of the normal vector.

        OUTPUT:

        An integer. The index of the largest entry.

        EXAMPLES::

            sage: H.<x,y,z> = HyperplaneArrangements(QQ)
            sage: V = H.ambient_space()
            sage: (x + 3/2*y - 2*z)._normal_pivot()
            2

            sage: H.<x,y,z> = HyperplaneArrangements(GF(5))
            sage: V = H.ambient_space()
            sage: (x + 3*y - 4*z)._normal_pivot()
            1
        """
        try:
            values = [abs(x) for x in self.A()]
        except ArithmeticError:
            from sage.rings.real_double import RDF
            values = [abs(RDF(x)) for x in self.A()]
        max_pos = 0
        max_value = values[max_pos]
        for i in range(1, len(values)):
            if values[i] > max_value:
                max_pos = i
                max_value = values[i]
        return max_pos
Ejemplo n.º 8
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


    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
       ``import __builtin__; __builtin__.round``.
    """
    try:
        if ndigits:
            return RealDoubleElement(__builtin__.round(x, ndigits))
        else:
            try:
                return 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.º 9
0
def asin(x):
    """
    Return the arc sine of x.
    """
    try:
        return x.asin()
    except AttributeError:
        return RDF(x).asin()
Ejemplo n.º 10
0
def atan(x):
    """
    Return the arc tangent of x.
    """
    try:
        return x.atan()
    except AttributeError:
        return RDF(x).atan()
Ejemplo n.º 11
0
def exp(x):
    """
    Return the value of the exponentation function at x.
    """
    try:
        return x.exp()
    except AttributeError:
        return RDF(x).exp()
Ejemplo n.º 12
0
def acos(x):
    """
    Return the arc cosine of x.
    """
    try:
        return x.acos()
    except AttributeError:
        return RDF(x).acos()
Ejemplo n.º 13
0
def read_signal(filename, dirname=None):
    r"""
    Read a signal from a data file.

    INPUT:

    - ``filename`` -- string; name of the file
    - ``dirname`` -- (default: None) string; name of directory where the file
      is located

    OUTPUT:

    - signal as a list of pairs `(t, h(t))`

    EXAMPLES::

        sage: from kerrgeodesic_gw import save_signal, read_signal
        sage: sig0 = [(RDF(i/10), RDF(sin(i/5))) for i in range(5)]
        sage: from sage.misc.temporary_file import tmp_filename
        sage: filename = tmp_filename(ext='.dat')
        sage: save_signal(sig0, filename)
        sage: sig = read_signal(filename)
        sage: sig   # tol 1.0e-13
        [(0.0, 0.0),
         (0.1, 0.19866933079506122),
         (0.2, 0.3894183423086505),
         (0.3, 0.5646424733950354),
         (0.4, 0.7173560908995228)]

    A test::

        sage: sig == sig0
        True

    """
    sig = []
    if dirname:
        file_name = os.path.join(dirname, filename)
    else:
        file_name = filename
    with open(file_name, "r") as data_file:
        for dline in data_file:
            t, h = dline.split('\t')
            sig.append((RDF(t), RDF(h)))
    return sig
Ejemplo n.º 14
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.º 15
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.º 16
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.º 17
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.º 18
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.º 19
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.º 20
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.º 21
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.º 22
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.º 23
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.º 24
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.º 25
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.º 26
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.º 27
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
Ejemplo n.º 28
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.º 29
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.º 30
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())