Example #1
0
def plotkin_upper_bound(n, q, d, algorithm=None):
    r"""
    Returns Plotkin upper bound for number of elements in the largest
    code of minimum distance d in `\GF{q}^n`.

    The algorithm="gap" option wraps Guava's UpperBoundPlotkin.

    EXAMPLES::

        sage: codes.bounds.plotkin_upper_bound(10,2,3)
        192
        sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap")  # optional - gap_packages (Guava package)
        192
    """
    if algorithm == "gap":
        gap.load_package("guava")
        ans = gap.eval("UpperBoundPlotkin(%s,%s,%s)" % (n, d, q))
        return QQ(ans)
    else:
        t = 1 - 1 / q
        if (q == 2) and (n == 2 * d) and (d % 2 == 0):
            return 4 * d
        elif (q == 2) and (n == 2 * d + 1) and (d % 2 == 1):
            return 4 * d + 4
        elif d > t * n:
            return int(d / (d - t * n))
        elif d < t * n + 1:
            fact = (d - 1) / t
            if RR(fact) == RR(int(fact)):
                fact = int(fact) + 1
            return int(d / (d - t * fact)) * q**(n - fact)
Example #2
0
    def random_isometry(self, preserve_orientation=True, **kwargs):
        r"""
        Return a random isometry in the Upper Half Plane model.

        INPUT:

        - ``preserve_orientation`` -- if ``True`` return an
          orientation-preserving isometry

        OUTPUT:

        - a hyperbolic isometry

        EXAMPLES::

            sage: A = HyperbolicPlane().UHP().random_isometry()
            sage: B = HyperbolicPlane().UHP().random_isometry(preserve_orientation=False)
            sage: B.preserves_orientation()
            False
        """
        [a,b,c,d] = [RR.random_element() for k in range(4)]
        while abs(a*d - b*c) < EPSILON:
            [a,b,c,d] = [RR.random_element() for k in range(4)]
        M = matrix(RDF, 2,[a,b,c,d])
        M = M / (M.det()).abs().sqrt()
        if M.det() > 0:
            if not preserve_orientation:
                M = M * matrix(2,[0,1,1,0])
        elif preserve_orientation:
            M = M * matrix(2,[0,1,1,0])
        return self._Isometry(self, M, check=False)
Example #3
0
    def random_isometry(self, preserve_orientation=True, **kwargs):
        r"""
        Return a random isometry in the Upper Half Plane model.

        INPUT:

        - ``preserve_orientation`` -- if ``True`` return an
          orientation-preserving isometry

        OUTPUT:

        - a hyperbolic isometry

        EXAMPLES::

            sage: A = HyperbolicPlane().UHP().random_isometry()
            sage: B = HyperbolicPlane().UHP().random_isometry(preserve_orientation=False)
            sage: B.preserves_orientation()
            False
        """
        [a, b, c, d] = [RR.random_element() for k in range(4)]
        while abs(a * d - b * c) < EPSILON:
            [a, b, c, d] = [RR.random_element() for k in range(4)]
        M = matrix(RDF, 2, [a, b, c, d])
        M = M / (M.det()).abs().sqrt()
        if M.det() > 0:
            if not preserve_orientation:
                M = M * matrix(2, [0, 1, 1, 0])
        elif preserve_orientation:
            M = M * matrix(2, [0, 1, 1, 0])
        return self._Isometry(self, M, check=False)
Example #4
0
def plotkin_upper_bound(n, q, d, algorithm=None):
    r"""
    Return the Plotkin upper bound.

    Return the Plotkin upper bound for the number of elements in a largest
    code of minimum distance `d` in `\GF{q}^n`.
    More precisely this is a generalization of Plotkin's result for `q=2`
    to bigger `q` due to Berlekamp.

    The ``algorithm="gap"`` option wraps Guava's ``UpperBoundPlotkin``.

    EXAMPLES::

        sage: codes.bounds.plotkin_upper_bound(10,2,3)
        192
        sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap")  # optional - gap_packages (Guava package)
        192
    """
    _check_n_q_d(n, q, d, field_based=False)
    if algorithm == "gap":
        libgap.load_package("guava")
        return QQ(libgap.UpperBoundPlotkin(n, d, q))
    else:
        t = 1 - 1 / q
        if (q == 2) and (n == 2 * d) and (d % 2 == 0):
            return 4 * d
        elif (q == 2) and (n == 2 * d + 1) and (d % 2 == 1):
            return 4 * d + 4
        elif d > t * n:
            return int(d / (d - t * n))
        elif d < t * n + 1:
            fact = (d - 1) / t
            if RR(fact) == RR(int(fact)):
                fact = int(fact) + 1
            return int(d / (d - t * fact)) * q**(n - fact)
Example #5
0
    def _eval_(self, x):
        """
        EXAMPLES::

            sage: [dickman_rho(n) for n in [1..10]]
            [1.00000000000000, 0.306852819440055, 0.0486083882911316, 0.00491092564776083, 0.000354724700456040, 0.0000196496963539553, 8.74566995329392e-7, 3.23206930422610e-8, 1.01624828273784e-9, 2.77017183772596e-11]
            sage: dickman_rho(0)
            1.00000000000000
        """
        if not is_RealNumber(x):
            try:
                x = RR(x)
            except (TypeError, ValueError):
                return None  # PrimitiveFunction.__call__(self, SR(x))
        if x < 0:
            return x.parent()(0)
        elif x <= 1:
            return x.parent()(1)
        elif x <= 2:
            return 1 - x.log()
        n = x.floor()
        if self._cur_prec < x.parent().prec() or n not in self._f:
            self._cur_prec = rel_prec = x.parent().prec()
            # Go a bit beyond so we're not constantly re-computing.
            max = x.parent()(1.1) * x + 10
            abs_prec = (-self.approximate(max).log2() + rel_prec + 2 * max.log2()).ceil()
            self._f = {}
            if sys.getrecursionlimit() < max + 10:
                sys.setrecursionlimit(int(max) + 10)
            self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
        return self._f[n](2 * (x - n - x.parent()(0.5)))
Example #6
0
    def _compute_power_series(self, n, abs_prec, cache_ring=None):
        """
        Compute the power series giving Dickman's function on [n, n+1], by
        recursion in n. For internal use; self.power_series() is a wrapper
        around this intended for the user.

        INPUT:

        -  ``n`` - the lower endpoint of the interval for which
           this power series holds

        -  ``abs_prec`` - the absolute precision of the
           resulting power series

        -  ``cache_ring`` - for internal use, caches the power
           series at this precision.

        EXAMPLES::

            sage: f = dickman_rho.power_series(2, 20); f
            -9.9376e-8*x^11 + 3.7722e-7*x^10 - 1.4684e-6*x^9 + 5.8783e-6*x^8 - 0.000024259*x^7 + 0.00010341*x^6 - 0.00045583*x^5 + 0.0020773*x^4 - 0.0097336*x^3 + 0.045224*x^2 - 0.11891*x + 0.13032
        """
        if n <= 1:
            if n <= -1:
                return PolynomialRealDense(RealField(abs_prec)['x'])
            if n == 0:
                return PolynomialRealDense(RealField(abs_prec)['x'], [1])
            elif n == 1:
                nterms = (RDF(abs_prec) * RDF(2).log() / RDF(3).log()).ceil()
                R = RealField(abs_prec)
                neg_three = ZZ(-3)
                coeffs = [1 - R(1.5).log()
                          ] + [neg_three**-k / k for k in range(1, nterms)]
                f = PolynomialRealDense(R['x'], coeffs)
                if cache_ring is not None:
                    self._f[n] = f.truncate_abs(f[0] >> (
                        cache_ring.prec() + 1)).change_ring(cache_ring)
                return f
        else:
            f = self._compute_power_series(n - 1, abs_prec, cache_ring)
            # integrand = f / (2n+1 + x)
            # We calculate this way because the most significant term is the constant term,
            # and so we want to push the error accumulation and remainder out to the least
            # significant terms.
            integrand = f.reverse().quo_rem(
                PolynomialRealDense(f.parent(), [1, 2 * n + 1]))[0].reverse()
            integrand = integrand.truncate_abs(RR(2)**-abs_prec)
            iintegrand = integrand.integral()
            ff = PolynomialRealDense(f.parent(),
                                     [f(1) + iintegrand(-1)]) - iintegrand
            i = 0
            while abs(f[i]) < abs(f[i + 1]):
                i += 1
            rel_prec = int(abs_prec + abs(RR(f[i])).log2())
            if cache_ring is not None:
                self._f[n] = ff.truncate_abs(
                    ff[0] >> (cache_ring.prec() + 1)).change_ring(cache_ring)
            return ff.change_ring(RealField(rel_prec))
    def newton_sqrt(self,f,x0, prec):
        r"""
        Takes the square root of the power series `f` by Newton's method

        NOTE:

        this function should eventually be moved to `p`-adic power series ring

        INPUT:

        - f power series wtih coefficients in `\QQ_p` or an extension
        - x0 seeds the Newton iteration
        - prec precision

        OUTPUT:

        the square root of `f`

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)
            sage: Q = H(0,0)
            sage: u,v = H.local_coord(Q,prec=100)
            sage: K = Qp(11,5)
            sage: HK = H.change_ring(K)
            sage: L.<a> = K.extension(x^20-11)
            sage: HL = H.change_ring(L)
            sage: S = HL(u(a),v(a))
            sage: f = H.hyperelliptic_polynomials()[0]
            sage: y = HK.newton_sqrt( f(u(a)^11), a^11,5)
            sage: y^2 - f(u(a)^11)
            O(a^122)

        AUTHOR:

        - Jennifer Balakrishnan

        """
        z = x0
        try:
            x = f.parent().variable_name()
            if x!='a' :  #this is to distinguish between extensions of Qp that are finite vs. not
                S = f.base_ring()[[x]]
                x = S.gen()
        except ValueError:
            pass
        z = x0
        loop_prec = (log(RR(prec))/log(RR(2))).ceil()
        for i in range(loop_prec):
            z = (z+f/z)/2
        try:
            return z + O(x**prec)
        except (NameError,ArithmeticError,TypeError):
            return z
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES:

        First some lines::

            sage: PD = HyperbolicPlane().PD()
            sage: PD.get_geodesic(0, 1).show()
            Graphics object consisting of 2 graphics primitives
            sage: PD.get_geodesic(0, 0.3+0.8*I).show()
            Graphics object consisting of 2 graphics primitives

        Then some generic geodesics::

            sage: PD.get_geodesic(-0.5, 0.3+0.4*I).show()
            Graphics object consisting of 2 graphics primitives
            sage: PD.get_geodesic(-1, exp(3*I*pi/7)).show(linestyle="dashed", color="red")
            Graphics object consisting of 2 graphics primitives
            sage: PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)).show(thickness=6, color="orange")
            Graphics object consisting of 2 graphics primitives
        """
        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)
        end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()]
        bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()]
        # Check to see if it's a line
        if abs(bd_1 + bd_2) < EPSILON:
            pic = line([end_1, end_2], **opts)
        else:
            # If we are here, we know it's not a line
            # So we compute the center and radius of the circle
            invdet = RR.one() / (real(bd_1) * imag(bd_2) -
                                 real(bd_2) * imag(bd_1))
            centerx = (imag(bd_2) - imag(bd_1)) * invdet
            centery = (real(bd_1) - real(bd_2)) * invdet
            center = centerx + I * centery
            radius = RR(abs(bd_1 - center))
            # Now we calculate the angles for the arc
            theta1 = CC(end_1 - center).arg()
            theta2 = CC(end_2 - center).arg()
            theta1, theta2 = sorted([theta1, theta2])
            # Make sure the sector is inside the disk
            if theta2 - theta1 > pi:
                theta1 += 2 * pi
            pic = arc((centerx, centery),
                      radius,
                      sector=(theta1, theta2),
                      **opts)
        if boundary:
            pic += self._model.get_background_graphic()
        return pic
Example #9
0
def rotation_matrix_angle(r, check=False):
    r"""
    Return the angle of the rotation matrix ``r`` divided by ``2 pi``.

    EXAMPLES::

        sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle

        sage: def rot_matrix(p, q):
        ....:     z = QQbar.zeta(q) ** p
        ....:     c = z.real()
        ....:     s = z.imag()
        ....:     return matrix(AA, 2, [c,-s,s,c])
        sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)]
        [1/5, 2/5, 3/5, 4/5]
        sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)]
        [1/5, 2/5, 3/5, 4/5]
        sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)]
        [1/7, 2/7, 3/7, 4/7, 5/7, 6/7]

    Some random tests::

        sage: for _ in range(100):
        ....:     r = QQ.random_element(x=0,y=500)
        ....:     r -= r.floor()
        ....:     m = rot_matrix(r.numerator(), r.denominator())
        ....:     assert rotation_matrix_angle(m) == r

    .. NOTE::

        This is using floating point arithmetic and might be wrong.
    """
    e0, e1 = r.change_ring(CDF).eigenvalues()
    m0 = (e0.log() / 2 / CDF.pi()).imag()
    m1 = (e1.log() / 2 / CDF.pi()).imag()
    r0 = RR(m0).nearby_rational(max_denominator=10000)
    r1 = RR(m1).nearby_rational(max_denominator=10000)
    if r0 != -r1:
        raise RuntimeError
    r0 = r0.abs()
    if r[0][1] > 0:
        return QQ.one() - r0
    else:
        return r0

    if check:
        e = r.change_ring(AA).eigenvalues()[0]
        if e.minpoly() != ZZ['x'].cyclotomic_polynomial()(r.denominator()):
            raise RuntimeError
        z = QQbar.zeta(r.denominator())
        if z**r.numerator() != e:
            raise RuntimeError

    return r
Example #10
0
    def good_primes(B):
        r"""
        Given the bound returns the prime whose product is greater than ``B``
        and which would take least amount of time to run main sieve algorithm

        Complexity of finding points modulo primes is assumed to be N^2 * P_max^{N}.
        Complexity of lifting points and LLL() function is assumed to
        be close to N^5 * (alpha^dim_scheme / P_max).
        where alpha is product of all primes, and P_max is largest prime in list.
        """

        M = dict()  # stores optimal list of primes, corresponding to list size
        small_primes = sufficient_primes(B)
        max_length = len(small_primes)
        M[max_length] = small_primes
        current_count = max_length - 1

        while current_count > 1:
            current_list = []  # stores prime which are bigger than least
            updated_list = []
            best_list = []

            least = (RR(B)**(1.00 / current_count)).floor()
            for i in range(current_count):
                current_list.append(next_prime(least))
                least = current_list[-1]
            # improving list of primes by taking prime less than least
            # this part of algorithm is used to centralize primes around `least`
            prod_prime = prod(current_list)
            least = current_list[0]
            while least != 2 and prod_prime > B and len(
                    updated_list) < current_count:
                best_list = updated_list + current_list[:current_count -
                                                        len(updated_list)]
                updated_list.append(previous_prime(least))
                least = updated_list[-1]

                removed_prime = current_list[current_count - len(updated_list)]
                prod_prime = (prod_prime * least) / removed_prime

            M[current_count] = sorted(best_list)
            current_count = current_count - 1

        best_size = 2
        best_time = (N**2) * M[2][-1]**(N) + (
            N**5 * RR(prod(M[2])**dim_scheme / M[2][-1]))
        for i in range(2, max_length + 1):
            current_time = (N**2) * M[i][-1]**(N) + (
                N**5 * RR(prod(M[i])**dim_scheme / M[i][-1]))
            if current_time < best_time:
                best_size = i
                best_time = current_time

        return M[best_size]
Example #11
0
 def rational_in(x, y):
     r"""
     Computes a rational number q, such that x<q<y using Archimedes' axiom
     """
     z = y - x
     n = RR(1 / z).ceil() + 1
     if RR(n * y).ceil() is n * y:
         m = n * y - 1
     else:
         m = RR(n * y).floor()
     return m / n
def bkz_runtime_k_sieve(k, n):
    """
    Runtime estimation given ‘k‘ and assuming sieving is used to realise the SVP oracle.
    For small ‘k‘ we use estimates based on experiments. For ‘k ě 90‘ we use the asymptotics.
    """
    repeat = _sage_const_3 * log(n, _sage_const_2) - _sage_const_2 * log(
        k, _sage_const_2) + log(log(n, _sage_const_2), _sage_const_2)
    if k < _sage_const_90:
        return RR(_sage_const_0p45 * k + _sage_const_12p31) + repeat
    else:
        # we simply pick the same additive constant 12.31 as above
        return RR(_sage_const_0p3366 * k + _sage_const_12p31) + repeat
Example #13
0
def rotation_matrix_angle(r, check=False):
    r"""
    Return the angle of the rotation matrix ``r`` divided by ``2 pi``.

    EXAMPLES::

        sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle

        sage: def rot_matrix(p, q):
        ....:     z = QQbar.zeta(q) ** p
        ....:     c = z.real()
        ....:     s = z.imag()
        ....:     return matrix(AA, 2, [c,-s,s,c])
        sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)]
        [1/5, 2/5, 3/5, 4/5]
        sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)]
        [1/7, 2/7, 3/7, 4/7, 5/7, 6/7]

    Some random tests::

        sage: for _ in range(100):
        ....:     r = QQ.random_element(x=0,y=500)
        ....:     r -= r.floor()
        ....:     m = rot_matrix(r.numerator(), r.denominator())
        ....:     assert rotation_matrix_angle(m) == r

    .. NOTE::

        This is using floating point arithmetic and might be wrong.
    """
    e0,e1 = r.change_ring(CDF).eigenvalues()
    m0 = (e0.log() / 2 / CDF.pi()).imag()
    m1 = (e1.log() / 2 / CDF.pi()).imag()
    r0 = RR(m0).nearby_rational(max_denominator=10000)
    r1 = RR(m1).nearby_rational(max_denominator=10000)
    if r0 != -r1:
        raise RuntimeError
    r0 = r0.abs()
    if r[0][1] > 0:
        return QQ.one() - r0
    else:
        return r0

    if check:
        e = r.change_ring(AA).eigenvalues()[0]
        if e.minpoly() != ZZ['x'].cyclotomic_polynomial()(r.denominator()):
            raise RuntimeError
        z = QQbar.zeta(r.denominator())
        if z**r.numerator() != e:
            raise RuntimeError

    return r
Example #14
0
 def circle_plot(self):
     pts = []
     pi = RR.pi()
     for angle in self.angles:
         angle = RR(angle)*pi
         c = angle.cos()
         s = angle.sin()
         if abs(s) < 0.00000001:
             pts.append((c,s))
         else:
             pts.extend([(c,s),(c,-s)])
     P = points(pts,size=100) + circle((0,0),1,color='black')
     P.axes(False)
     P.set_aspect_ratio(1)
     return encode_plot(P)
Example #15
0
 def circle_plot(self):
     pts = []
     pi = RR.pi()
     for angle in self.angles:
         angle = RR(angle) * pi
         c = angle.cos()
         s = angle.sin()
         if abs(s) < 0.00000001:
             pts.append((c, s))
         else:
             pts.extend([(c, s), (c, -s)])
     P = points(pts, size=100) + circle((0, 0), 1, color='black')
     P.axes(False)
     P.set_aspect_ratio(1)
     return encode_plot(P)
    def __init__(self, P, n, sigma):
        r"""
        Construct a sampler for univariate polynomials of degree ``n-1``
        where coefficients are drawn independently with standard deviation
        ``sigma``.

        INPUT:

        - ``P`` - a univariate polynomial ring over the Integers
        - ``n`` - number of coefficients to be sampled
        - ``sigma`` - coefficients `x` are accepted with probability
          proportional to `\exp(-x²/(2σ²))`. If an object of type
          :class:`sage.stats.distributions.discrete_gaussian_integer.DiscreteGaussianDistributionIntegerSampler`
          is passed, then this sampler is used to sample coefficients.

        EXAMPLES::

            sage: from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler
            sage: DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], 8, 3.0)()
            3*x^7 + 3*x^6 - 3*x^5 - x^4 - 5*x^2 + 3
            sage: gs = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], 8, 3.0)
            sage: [gs() for _ in range(3)]
            [4*x^7 + 4*x^6 - 4*x^5 + 2*x^4 + x^3 - 4*x + 7, -5*x^6 + 4*x^5 - 3*x^3 + 4*x^2 + x, 2*x^7 + 2*x^6 + 2*x^5 - x^4 - 2*x^2 + 3*x + 1]
        """
        if isinstance(sigma, DiscreteGaussianDistributionIntegerSampler):
            self.D = sigma
        else:
            self.D = DiscreteGaussianDistributionIntegerSampler(RR(sigma))
        self.n = ZZ(n)
        self.P = P
Example #17
0
    def __float__(self):
        r"""
        Generate a floating-point infinity.  The printing of
        floating-point infinity varies across platforms.

        EXAMPLES::

            sage: RDF(infinity)
            +infinity
            sage: float(infinity) # random
            +infinity
            sage: CDF(infinity)
            +infinity
            sage: infinity.__float__() # random
            +infinity

            sage: RDF(-infinity)
            -infinity
            sage: float(-infinity) # random
            -inf
            sage: CDF(-infinity)
            -infinity
            sage: (-infinity).__float__() # random
            -inf

        """
        # Evidently there is no standard way to generate an infinity
        # in Python (before Python 2.6).
        from sage.rings.all import RR
        return float(RR(self))
Example #18
0
def take_power(x,n):
    r'''

    TESTS::

        sage: from functions import *
        sage: A = Matrix(Zmod(3,10),5,5,range(10,10+25))
        sage: take_power(A,10) == A ** 10
        True

    '''
    if n == 1:
        return x
    R = x.parent().base_ring()
    y = x.parent()(1)
    if n == 0:
        return y
    while n > 1:
        verbose("log_2(n) = %s"%RR(n).log(2))
        if n % 2 == 0:
            n = n // 2
        else:
            y = multiply_and_reduce(x,y)
            n = (n - 1) // 2
        x = multiply_and_reduce(x,x)
    return multiply_and_reduce(x, y)
def bkz_runtime_k_bkz2(k, n):
    """
    Runtime estimation given ‘k‘ and assuming [CheNgu12]_ estimates are correct.
    The constants in this function were derived as follows based on Table 4 in [CheNgu12]_::
    sage: dim = [100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240,
          250]
    sage: nodes = [39.0, 44.0, 49.0, 54.0, 60.0, 66.0, 72.0, 78.0, 84.0, 96.0, 99.0, 105.0,
          111.0, 120.0, 127.0, 134.0]
    sage: times = [c + log(200,2).n() for c in nodes]
    sage: T = zip(dim, nodes)
    sage: var("a,b,c,k")
    sage: f = a*k*log(k, 2.0) + b*k + c
    sage: f = f.function(k)
    sage: f.subs(find_fit(T, f, solution_dict=True))
    k |--> 0.270188776350190*k*log(k) - 1.0192050451318417*k + 16.10253135200765
    
    .. [CheNgu12] Yuanmi Chen and Phong Q. Nguyen. BKZ 2.0: Better lattice security estimates (
        Full Version).
                  2012. http://www.di.ens.fr/~ychen/research/Full_BKZ.pdf
    """
    repeat = _sage_const_3 * log(n, _sage_const_2) - _sage_const_2 * log(
        k, _sage_const_2) + log(log(n, _sage_const_2), _sage_const_2)
    return RR(_sage_const_0p270188776350190 * k * log(k) -
              _sage_const_1p0192050451318417 * k +
              _sage_const_16p10253135200765 + repeat)
Example #20
0
def error_fcn(t):
    r"""
    The complementary error function
    `\frac{2}{\sqrt{\pi}}\int_t^\infty e^{-x^2} dx` (t belongs
    to RR).  This function is currently always
    evaluated immediately.

    EXAMPLES::

        sage: error_fcn(6)
        2.15197367124989e-17
        sage: error_fcn(RealField(100)(1/2))
        0.47950012218695346231725334611

    Note this is literally equal to `1 - erf(t)`::

        sage: 1 - error_fcn(0.5)
        0.520499877813047
        sage: erf(0.5)
        0.520499877813047
    """
    try:
        return t.erfc()
    except AttributeError:
        try:
            return RR(t).erfc()
        except Exception:
            raise NotImplementedError
Example #21
0
    def approximate(self, x, parent=None):
        r"""
        Approximate using de Bruijn's formula

        .. MATH::

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

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

        REFERENCES:

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

        EXAMPLES::

            sage: dickman_rho.approximate(10)
            2.41739196365564e-11
            sage: dickman_rho(10)
            2.77017183772596e-11
            sage: dickman_rho.approximate(1000)
            4.32938809066403e-3464
        """
        log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi
        x = float(x)
        xi = log(x)
        y = (exp(xi) - 1.0) / xi - x
        while abs(y) > 1e-12:
            dydxi = (exp(xi) * (xi - 1.0) + 1.0) / (xi * xi)
            xi -= y / dydxi
            y = (exp(xi) - 1.0) / xi - x
        return (-x * xi + RR(xi).eint()).exp() / (sqrt(2 * pi * x) * xi)
Example #22
0
def first_prime_in_class(c, norm_bound=1000):
    Cl = c.parent() # the class group
    K = Cl.number_field()
    for P in K.primes_of_bounded_norm_iter(RR(norm_bound)):
        if Cl(P)==c:
            return P
    raise RuntimeError("No prime of norm less than %s found in class %s" % (norm_bound, c))
Example #23
0
    def local_coordinates_at_infinity(self, prec=20, name='t'):
        """
        For the genus `g` hyperelliptic curve `y^2 = f(x)`, return
        `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is
        the local parameter at infinity

        INPUT:

        - ``prec`` -- desired precision of the local coordinates
        - ``name`` -- generator of the power series ring (default: ``t``)

        OUTPUT:

        `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x^g/y`
        is the local parameter at infinity

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-5*x^2+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12)
            sage: y
            t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12)

        ::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^3-x+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12)
            sage: y
            t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12)

        Note: if even degree model, just returns local coordinate above one point

        AUTHOR:
            - Jennifer Balakrishnan (2007-12)
        """
        g = self.genus()
        pol = self.hyperelliptic_polynomials()[0]
        K = LaurentSeriesRing(self.base_ring(), name)
        t = K.gen()
        K.set_default_prec(prec + 2)
        L = PolynomialRing(K, 'x')
        x = L.gen()
        i = 0
        w = (x**g / t)**2 - pol
        wprime = w.derivative(x)
        if pol.degree() == 2 * g + 1:
            x = t**-2
        else:
            x = t**-1
        for i in range((RR(log(prec + 2) / log(2))).ceil()):
            x = x - w(x) / wprime(x)
        y = x**g / t
        return x + O(t**(prec + 2)), y + O(t**(prec + 2))
Example #24
0
 def circle_plot(self):
     pts = []
     pi = RR.pi()
     for angle in self.angles:
         angle = RR(angle) * pi
         c = angle.cos()
         s = angle.sin()
         if abs(s) < 0.00000001:
             pts.append((c, s))
         else:
             pts.extend([(c, s), (c, -s)])
     P = circle((0, 0), 1, color="black", thickness=2.5)
     P[0].set_zorder(-1)
     P += points(pts, size=300, rgbcolor="darkblue")
     P.axes(False)
     P.set_aspect_ratio(1)
     return encode_plot(P, pad=0, pad_inches=None, transparent=True, axes_pad=0.04)
Example #25
0
    def icosidodecahedron(self, exact=True):
        """
        Return the Icosidodecahedron

        The Icosidodecahedron is a polyhedron with twenty triangular faces and
        twelve pentagonal faces. For more information see the
        :wikipedia:`Icosidodecahedron`.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        EXAMPLES::

            sage: gr = polytopes.icosidodecahedron()
            sage: gr.f_vector()
            (1, 30, 60, 32, 1)

        TESTS::

            sage: polytopes.icosidodecahedron(exact=False)
            A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 30 vertices
        """
        from sage.rings.number_field.number_field import QuadraticField
        from itertools import product

        K = QuadraticField(5, 'sqrt5')
        one = K.one()
        phi = (one + K.gen()) / 2

        gens = [((-1)**a * one / 2, (-1)**b * phi / 2,
                 (-1)**c * (one + phi) / 2)
                for a, b, c in product([0, 1], repeat=3)]
        gens.extend([(0, 0, phi), (0, 0, -phi)])

        verts = []
        for p in AlternatingGroup(3):
            verts.extend(p(x) for x in gens)

        if exact:
            return Polyhedron(vertices=verts, base_ring=K)
        else:
            verts = [(RR(x), RR(y), RR(z)) for x, y, z in verts]
            return Polyhedron(vertices=verts)
Example #26
0
    def random_point(self, **kwargs):
        r"""
        Return a random point in the upper half plane. The points are
        uniformly distributed over the rectangle `[-10, 10] \times [0, 10i]`.

        EXAMPLES::

            sage: p = HyperbolicPlane().UHP().random_point().coordinates()
            sage: bool((p.imag()) > 0)
            True
        """
        # TODO: use **kwargs to allow these to be set
        real_min = -10
        real_max = 10
        imag_min = 0
        imag_max = 10
        p = RR.random_element(min=real_min, max=real_max) \
            + I * RR.random_element(min=imag_min, max=imag_max)
        return self.get_point(p)
Example #27
0
    def random_point(self, **kwargs):
        r"""
        Return a random point in the upper half plane. The points are
        uniformly distributed over the rectangle `[-10, 10] \times [0, 10i]`.

        EXAMPLES::

            sage: p = HyperbolicPlane().UHP().random_point().coordinates()
            sage: bool((p.imag()) > 0)
            True
        """
        # TODO: use **kwargs to allow these to be set
        real_min = -10
        real_max = 10
        imag_min = 0
        imag_max = 10
        p = RR.random_element(min=real_min, max=real_max) \
            + I * RR.random_element(min=imag_min, max=imag_max)
        return self.get_point(p)
Example #28
0
    def _evalf_(self, x, **kwargs):
        """
        EXAMPLES::

            sage: airy_bi_prime(0.0)
            0.448288357353826

        We can use several methods for numerical evaluation::

            sage: airy_bi_prime(4).n(algorithm='mpmath')
            161.926683504613
            sage: airy_bi_prime(4).n(algorithm='mpmath', prec=100)
            161.92668350461340184309492429
            sage: airy_bi_prime(4).n(algorithm='scipy')  # rel tol 1e-10
            161.92668350461398
            sage: airy_bi_prime(I).n(algorithm='scipy')  # rel tol 1e-10
            0.135026646710819 - 0.1288373867812549*I

        TESTS::

            sage: parent(airy_bi_prime(3).n(algorithm='scipy'))
            Real Field with 53 bits of precision
            sage: airy_bi_prime(3).n(algorithm='scipy', prec=200)
            Traceback (most recent call last):
            ...
            NotImplementedError: airy_bi_prime not implemented
             for precision > 53
        """
        algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath'
        parent = kwargs.get('parent', None)
        if algorithm == 'scipy':
            if hasattr(parent, 'prec') and parent.prec() > 53:
                raise NotImplementedError(
                    "%s not implemented for precision > 53" % self.name())
            from sage.rings.all import RR, CC
            from sage.functions.other import real, imag
            from scipy.special import airy as airy
            if x in RR:
                y = airy(real(x))[3]
                if parent is None:
                    return RR(y)
            else:
                y = airy(complex(real(x), imag(x)))[3]
                if parent is None:
                    return CC(y)
            return parent(y)
        elif algorithm == 'mpmath':
            import mpmath
            from sage.libs.mpmath import utils as mpmath_utils
            return mpmath_utils.call(mpmath.airybi,
                                     x,
                                     derivative=1,
                                     parent=parent)
        else:
            raise ValueError("unknown algorithm '%s'" % algorithm)
Example #29
0
    def local_coordinates_at_nonweierstrass(self, P, prec=20, name='t'):
        """
        For a non-Weierstrass point `P = (a,b)` on the hyperelliptic
        curve `y^2 = f(x)`, return `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`,
        where `t = x - a` is the local parameter.

        INPUT:

        - ``P = (a, b)`` -- a non-Weierstrass point on self
        - ``prec`` --  desired precision of the local coordinates
        - ``name`` -- gen of the power series ring (default: ``t``)

        OUTPUT:

        `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x - a`
        is the local parameter at `P`

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)
            sage: P = H(1,6)
            sage: x,y = H.local_coordinates_at_nonweierstrass(P,prec=5)
            sage: x
            1 + t + O(t^5)
            sage: y
            6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5)
            sage: Q = H(-2,12)
            sage: x,y = H.local_coordinates_at_nonweierstrass(Q,prec=5)
            sage: x
            -2 + t + O(t^5)
            sage: y
            12 - 19/2*t - 19/32*t^2 + 61/256*t^3 - 5965/24576*t^4 + O(t^5)

        AUTHOR:

            - Jennifer Balakrishnan (2007-12)
        """
        d = P[1]
        if d == 0:
            raise TypeError(
                "P = %s is a Weierstrass point. Use local_coordinates_at_weierstrass instead!"
                % P)
        pol = self.hyperelliptic_polynomials()[0]
        L = PowerSeriesRing(self.base_ring(), name)
        t = L.gen()
        L.set_default_prec(prec)
        K = PowerSeriesRing(L, 'x')
        pol = K(pol)
        x = K.gen()
        b = P[0]
        f = pol(t + b)
        for i in range((RR(log(prec) / log(2))).ceil()):
            d = (d + f / d) / 2
        return t + b + O(t**(prec)), d + O(t**(prec))
Example #30
0
def bessel_Y(nu, z, algorithm="maxima", prec=53):
    r"""
    Implements the "Y-Bessel function", or "Bessel function of the 2nd
    kind", with index (or "order") nu and argument z.
    
    .. note::

       Currently only prec=53 is supported.
    
    Defn::
    
                    cos(pi n)*bessel_J(nu, z) - bessel_J(-nu, z)
                   -------------------------------------------------
                                     sin(nu*pi)
    
    if nu is not an integer and by taking a limit otherwise.
    
    Sometimes bessel_Y(n,z) is denoted Y_n(z) in the literature.
    
    This is computed using Maxima by default.
    
    EXAMPLES::
    
        sage: bessel_Y(2,1.1,"scipy")
        -1.4314714939...
        sage: bessel_Y(2,1.1)   
        -1.4314714939590...
        sage: bessel_Y(3.001,2.1) 
        -1.0299574976424...

    TESTS::

        sage: bessel_Y(2,1.1, algorithm="pari")
        Traceback (most recent call last):
        ...
        NotImplementedError: The Y-Bessel function is only implemented for the maxima and scipy algorithms
    """
    if algorithm == "scipy":
        if prec != 53:
            raise ValueError, "for the scipy algorithm the precision must be 53"
        import scipy.special
        ans = str(scipy.special.yv(float(nu), complex(real(z), imag(z))))
        ans = ans.replace("(", "")
        ans = ans.replace(")", "")
        ans = ans.replace("j", "*I")
        ans = sage_eval(ans)
        return real(ans) if z in RR else ans
    elif algorithm == "maxima":
        if prec != 53:
            raise ValueError, "for the maxima algorithm the precision must be 53"
        return RR(maxima.eval("bessel_y(%s,%s)" % (float(nu), float(z))))
    elif algorithm == "pari":
        raise NotImplementedError, "The Y-Bessel function is only implemented for the maxima and scipy algorithms"
    else:
        raise ValueError, "unknown algorithm '%s'" % algorithm
Example #31
0
    def _evalf_(self, x, **kwargs):
        """
        EXAMPLES::

            sage: airy_ai_prime(0.0)
            -0.258819403792807

        We can use several methods for numerical evaluation::

            sage: airy_ai_prime(4).n(algorithm='mpmath')
            -0.00195864095020418
            sage: airy_ai_prime(4).n(algorithm='mpmath', prec=100)
            -0.0019586409502041789001381409184
            sage: airy_ai_prime(4).n(algorithm='scipy')    # rel tol 1e-10
            -0.00195864095020418
            sage: airy_ai_prime(I).n(algorithm='scipy')    # rel tol 1e-10
            -0.43249265984180707 + 0.09804785622924324*I

        TESTS::

            sage: parent(airy_ai_prime(3).n(algorithm='scipy'))
            Real Field with 53 bits of precision
            sage: airy_ai_prime(3).n(algorithm='scipy', prec=200)
            Traceback (most recent call last):
            ...
            NotImplementedError: airy_ai_prime not implemented
             for precision > 53
        """
        algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath'
        parent = kwargs.get('parent', None)
        if algorithm == 'scipy':
            if hasattr(parent, 'prec') and parent.prec() > 53:
                raise NotImplementedError(
                    "%s not implemented for precision > 53" % self.name())
            from sage.rings.all import RR, CC
            from sage.functions.other import real, imag
            from scipy.special import airy as airy
            if x in RR:
                y = airy(real(x))[1]
                if parent is None:
                    return RR(y)
            else:
                y = airy(complex(real(x), imag(x)))[1]
                if parent is None:
                    return CC(y)
            return parent(y)
        elif algorithm == 'mpmath':
            import mpmath
            from sage.libs.mpmath import utils as mpmath_utils
            return mpmath_utils.call(mpmath.airyai,
                                     x,
                                     derivative=1,
                                     parent=parent)
        else:
            raise ValueError("unknown algorithm '%s'" % algorithm)
Example #32
0
    def _evalf_(self, x, **kwargs):
        """
        EXAMPLES::

            sage: from sage.functions.airy import airy_ai_simple
            sage: airy_ai_simple(0.0)
            0.355028053887817
            sage: airy_ai_simple(1.0 * I)
            0.331493305432141 - 0.317449858968444*I

        We can use several methods for numerical evaluation::

            sage: airy_ai_simple(3).n(algorithm='mpmath')
            0.00659113935746072
            sage: airy_ai_simple(3).n(algorithm='mpmath', prec=100)
            0.0065911393574607191442574484080
            sage: airy_ai_simple(3).n(algorithm='scipy')  # rel tol 1e-10
            0.006591139357460719
            sage: airy_ai_simple(I).n(algorithm='scipy')  # rel tol 1e-10
            0.33149330543214117 - 0.3174498589684438*I
            
        TESTS::

            sage: parent(airy_ai_simple(3).n(algorithm='scipy'))                                          
            Real Field with 53 bits of precision
            sage: airy_ai_simple(3).n(algorithm='scipy', prec=200)
            Traceback (most recent call last):
            ...
            NotImplementedError: airy_ai not implemented for precision > 53
        """
        algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath'
        parent = kwargs.get('parent')
        if algorithm == 'scipy':
            if hasattr(parent, 'prec') and parent.prec() > 53:
                raise NotImplementedError(
                    "%s not implemented for precision > 53" % self.name())
            from sage.rings.all import RR, CC
            from sage.functions.other import real, imag
            from scipy.special import airy as airy
            if x in RR:
                y = airy(real(x))[0]
                if parent is None:
                    return RR(y)
            else:
                y = airy(complex(real(x), imag(x)))[0]
                if parent is None:
                    return CC(y)
            return parent(y)
        elif algorithm == 'mpmath':
            import mpmath
            from sage.libs.mpmath import utils as mpmath_utils
            return mpmath_utils.call(mpmath.airyai, x, parent=parent)
        else:
            raise ValueError("unknown algorithm '%s'" % algorithm)
Example #33
0
 def log_height_for_generators_approx(alpha, beta, Lambda):
     r"""
     Compute the rational approximation of logarithmic height function.
     Return a lambda approximation h_K(alpha/beta)
     """
     delta = Lambda / (r + 2)
     norm_log = delta_approximation(RR(O_K.ideal(alpha, beta).norm()).log(), delta)
     log_ga = vector_delta_approximation(log_map(alpha), delta)
     log_gb = vector_delta_approximation(log_map(beta), delta)
     arch_sum = sum([max(log_ga[k], log_gb[k]) for k in range(r + 1)])
     return (arch_sum - norm_log)
Example #34
0
    def _evalf_(self, x, **kwargs):
        """
        EXAMPLES::

            sage: from sage.functions.airy import airy_bi_simple
            sage: airy_bi_simple(0.0)
            0.614926627446001
            sage: airy_bi_simple(1.0 * I)
            0.648858208330395 + 0.344958634768048*I

        We can use several methods for numerical evaluation::

            sage: airy_bi_simple(3).n(algorithm='mpmath')
            14.0373289637302
            sage: airy_bi_simple(3).n(algorithm='mpmath', prec=100)
            14.037328963730232031740267314
            sage: airy_bi_simple(3).n(algorithm='scipy')  # rel tol 1e-10
            14.037328963730136
            sage: airy_bi_simple(I).n(algorithm='scipy')  # rel tol 1e-10
            0.648858208330395 + 0.34495863476804844*I
            
        TESTS::

            sage: parent(airy_bi_simple(3).n(algorithm='scipy'))                                          
            Real Field with 53 bits of precision
            sage: airy_bi_simple(3).n(algorithm='scipy', prec=200)
            Traceback (most recent call last):
            ...
            NotImplementedError: airy_bi not implemented for precision > 53
        """
        algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath'
        parent = kwargs.get('parent', None)
        if algorithm == 'scipy':
            if hasattr(parent, 'prec') and parent.prec() > 53:
                raise NotImplementedError(
                    "%s not implemented for precision > 53" % self.name())
            from sage.rings.all import RR, CC
            from sage.functions.other import real, imag
            from scipy.special import airy as airy
            if x in RR:
                y = airy(real(x))[2]
                if parent is None:
                    return RR(y)
            else:
                y = airy(complex(real(x), imag(x)))[2]
                if parent is None:
                    return CC(y)
            return parent(y)
        elif algorithm == 'mpmath':
            import mpmath
            from sage.libs.mpmath import utils as mpmath_utils
            return mpmath_utils.call(mpmath.airybi, x, parent=parent)
        else:
            raise ValueError("unknown algorithm '%s'" % algorithm)
    def newton_sqrt(self, f, x0, prec):
        r"""
        Takes the square root of the power series `f` by Newton's method

        NOTE:

        this function should eventually be moved to `p`-adic power series ring

        INPUT:

        - ``f`` -- power series with coefficients in `\QQ_p` or an extension
        - ``x0`` -- seeds the Newton iteration
        - ``prec`` -- precision

        OUTPUT: the square root of `f`

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)
            sage: Q = H(0,0)
            sage: u,v = H.local_coord(Q,prec=100)
            sage: K = Qp(11,5)
            sage: HK = H.change_ring(K)
            sage: L.<a> = K.extension(x^20-11)
            sage: HL = H.change_ring(L)
            sage: S = HL(u(a),v(a))
            sage: f = H.hyperelliptic_polynomials()[0]
            sage: y = HK.newton_sqrt( f(u(a)^11), a^11,5)
            sage: y^2 - f(u(a)^11)
            O(a^122)

        AUTHOR:

        - Jennifer Balakrishnan
        """
        z = x0
        loop_prec = (log(RR(prec)) / log(RR(2))).ceil()
        for i in range(loop_prec):
            z = (z + f / z) / 2
        return z
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES:

        First some lines::

            sage: PD = HyperbolicPlane().PD()
            sage: PD.get_geodesic(0, 1).show()
            Graphics object consisting of 2 graphics primitives
            sage: PD.get_geodesic(0, 0.3+0.8*I).show()
            Graphics object consisting of 2 graphics primitives

        Then some generic geodesics::

            sage: PD.get_geodesic(-0.5, 0.3+0.4*I).show()
            Graphics object consisting of 2 graphics primitives
            sage: PD.get_geodesic(-1, exp(3*I*pi/7)).show(linestyle="dashed", color="red")
            Graphics object consisting of 2 graphics primitives
            sage: PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)).show(thickness=6, color="orange")
            Graphics object consisting of 2 graphics primitives
        """
        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)
        end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()]
        bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()]
        # Check to see if it's a line
        if abs(bd_1 + bd_2) < EPSILON:
            pic = line([end_1, end_2], **opts)
        else:
            # If we are here, we know it's not a line
            # So we compute the center and radius of the circle
            invdet = RR.one() / (real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1))
            centerx = (imag(bd_2) - imag(bd_1)) * invdet
            centery = (real(bd_1) - real(bd_2)) * invdet
            center = centerx + I * centery
            radius = RR(abs(bd_1 - center))
            # Now we calculate the angles for the arc
            theta1 = CC(end_1 - center).arg()
            theta2 = CC(end_2 - center).arg()
            theta1, theta2 = sorted([theta1, theta2])
            # Make sure the sector is inside the disk
            if theta2 - theta1 > pi:
                theta1 += 2 * pi
            pic = arc((centerx, centery), radius,
                      sector=(theta1, theta2), **opts)
        if boundary:
            pic += self._model.get_background_graphic()
        return pic
Example #37
0
    def regular_polygon(self, n, base_ring=QQ):
        """
        Return a regular polygon with `n` vertices.  Over the rational
        field the vertices may not be exact.

        INPUT:

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

        - ``base_ring`` -- a ring in which the coordinates will lie.

        EXAMPLES::

            sage: octagon = polytopes.regular_polygon(8)
            sage: len(octagon.vertices())
            8
            sage: polytopes.regular_polygon(3).vertices()
            (A vertex at (-125283617/144665060, -500399958596723/1000799917193445),
             A vertex at (0, 1),
             A vertex at (94875313/109552575, -1000799917193444/2001599834386889))
            sage: polytopes.regular_polygon(3, base_ring=RealField(100)).vertices()
            (A vertex at (0.00000000000000000000000000000, 1.0000000000000000000000000000),
             A vertex at (0.86602540378443864676372317075, -0.50000000000000000000000000000),
             A vertex at (-0.86602540378443864676372317076, -0.50000000000000000000000000000))
            sage: polytopes.regular_polygon(3, base_ring=RealField(10)).vertices()
            (A vertex at (0.00, 1.0),
             A vertex at (0.87, -0.50),
             A vertex at (-0.86, -0.50))
        """
        try:
            omega = 2*base_ring.pi()/n
        except AttributeError:
            omega = 2*RR.pi()/n
        verts = []
        for i in range(n):
            t = omega*i
            verts.append([base_ring(t.sin()), base_ring(t.cos())])
        return Polyhedron(vertices=verts, base_ring=base_ring)
Example #38
0
def angle(u, v, assume_rational=False):
    r"""
    Return the angle between the vectors ``u`` and ``v`` divided by `2 \pi`.

    INPUT:

    - ``u``, ``v`` - vectors

    - ``assume_rational`` - whether we assume that the angle is a multiple
      rational of ``pi``. By default it is ``False`` but if it is known in
      advance that the result is rational then setting it to ``True`` might be
      much faster.

    EXAMPLES::

        sage: from flatsurf.geometry.matrix_2x2 import angle

    As the implementation is dirty, we at least check that it works for all
    denominator up to 20::

        sage: u = vector((AA(1),AA(0)))
        sage: for n in xsrange(1,20):       # long time  (10 sec)
        ....:     for k in xsrange(1,n):
        ....:         v = vector((AA(cos(2*k*pi/n)), AA(sin(2*k*pi/n))))
        ....:         assert angle(u,v) == k/n

    And we test up to 50 when setting ``assume_rational`` to ``True``::

        sage: for n in xsrange(1,20):       # long time
        ....:     for k in xsrange(1,n):
        ....:         v = vector((AA(cos(2*k*pi/n)), AA(sin(2*k*pi/n))))
        ....:         assert angle(u,v,assume_rational=True) == k/n

    If the angle is not rational, then the method returns an element in the real
    lazy field::

        sage: v = vector((AA(sqrt(2)), AA(sqrt(3))))
        sage: a = angle(u,v)
        sage: a
        0.1410235542122437?
        sage: exp(2*pi.n()*CC(0,1)*a.n())
        0.632455532033676 + 0.774596669241483*I
        sage: v / v.norm()
        (0.6324555320336758?, 0.774596669241484?)
    """
    if not assume_rational:
        sqnorm_u = u[0] * u[0] + u[1] * u[1]
        sqnorm_v = v[0] * v[0] + v[1] * v[1]

        if sqnorm_u != sqnorm_v:
            uu = u.change_ring(AA)
            vv = (AA(sqnorm_u) / AA(sqnorm_v)).sqrt() * v.change_ring(AA)
        else:
            uu = u
            vv= v

        cos_uv = (uu[0]*vv[0] + uu[1]*vv[1]) / sqnorm_u
        sin_uv = (uu[0]*vv[1] - uu[1]*vv[0]) / sqnorm_u

        is_rational = is_cosine_sine_of_rational(cos_uv, sin_uv)

    else:
        is_rational = True

    if is_rational:
        # fast and dirty way using floating point approximation
        # (see below for a slow but exact method)
        from math import acos,asin,sqrt

        u0 = float(u[0]); u1 = float(u[1])
        v0 = float(v[0]); v1 = float(v[1])

        cos_uv = (u0*v0 + u1*v1) / sqrt((u0*u0 + u1*u1)*(v0*v0 + v1*v1))
        angle = acos(float(cos_uv)) / (2*pi_float)   # rat number between 0 and 1/2
        angle_rat = RR(angle).nearby_rational(0.00000001)
        if angle_rat.denominator() > 100:
            raise NotImplementedError("the numerical method used is not smart enough!")
        if u0*v1 - u1*v0 < 0:
            return 1 - angle_rat
        return angle_rat

    else:
        from sage.functions.trig import acos
        from sage.rings.real_lazy import RLF
        from sage.symbolic.constants import pi

        if sin_uv > 0:
            return acos(RLF(cos_uv)) / RLF(2*pi)
        else:
            return -acos(RLF(cos_uv)) / RLF(2*pi)