def regular_polygon(self, n, exact=True, base_ring=None): """ Return a regular polygon with `n` vertices. INPUT: - ``n`` -- a positive integer, the number of vertices. - ``exact`` -- (boolean, default ``True``) if ``False`` floating point numbers are used for coordinates. - ``base_ring`` -- a ring in which the coordinates will lie. It is ``None`` by default. If it is not provided and ``exact`` is ``True`` then it will be the field of real algebraic number, if ``exact`` is ``False`` it will be the real double field. EXAMPLES:: sage: octagon = polytopes.regular_polygon(8) sage: octagon A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices sage: octagon.n_vertices() 8 sage: v = octagon.volume() sage: v 2.828427124746190? sage: v == 2*QQbar(2).sqrt() True Its non exact version:: sage: polytopes.regular_polygon(3, exact=False).vertices() (A vertex at (0.0, 1.0), A vertex at (0.8660254038, -0.5), A vertex at (-0.8660254038, -0.5)) sage: polytopes.regular_polygon(25, exact=False).n_vertices() 25 """ n = ZZ(n) if n <= 2: raise ValueError( "n (={}) must be an integer greater than 2".format(n)) if base_ring is None: if exact: base_ring = AA else: base_ring = RDF try: omega = 2 * base_ring.pi() / n verts = [((i * omega).sin(), (i * omega).cos()) for i in range(n)] except AttributeError: z = QQbar.zeta(n) verts = [(base_ring((z**k).imag()), base_ring((z**k).real())) for k in range(n)] return Polyhedron(vertices=verts, base_ring=base_ring)
def _formal_monodromy_from_critical_monomials(critical_monomials, ring): r""" Compute the formal monodromy matrix of the canonical system of fundamental solutions at the origin. INPUT: - ``critical_monomials``: list of ``FundamentalSolution`` objects ``sol`` such that, if ``sol = z^(λ+n)·(1 + Õ(z)`` where ``λ`` is the leftmost valuation of a group of solutions and ``s`` is another shift of ``λ`` appearing in the basis, then ``sol.value[s]`` contains the list of coefficients of ``z^(λ+s)·log(z)^k/k!``, ``k = 0, 1, ...`` in ``sol`` - ``ring`` OUTPUT: - the formal monodromy matrix, with coefficients in ``ring`` - a boolean flag indicating whether the local monodromy is scalar (useful when ``ring`` is an inexact ring!) """ mat = matrix.matrix(ring, len(critical_monomials)) twopii = 2 * pi * QQbar(QQi.gen()) expo0 = critical_monomials[0].leftmost scalar = True for j, jsol in enumerate(critical_monomials): for i, isol in enumerate(critical_monomials): if isol.leftmost != jsol.leftmost: continue for k, c in enumerate(jsol.value[isol.shift]): delta = k - isol.log_power if c.is_zero(): continue if delta >= 0: # explicit conversion sometimes necessary (Sage bug #31551) mat[i, j] += ring(c) * twopii**delta / delta.factorial() if delta >= 1: scalar = False expo = jsol.leftmost if expo != expo0: scalar = False if expo.parent() is QQ: eigv = ring(QQbar.zeta(expo.denominator())**expo.numerator()) else: # conversion via QQbar seems necessary with some number fields eigv = twopii.mul(QQbar(expo), hold=True).exp(hold=True) eigv = ring(eigv) if ring is SR: _rescale_col_hold_nontrivial(mat, j, eigv) else: mat.rescale_col(j, eigv) return mat, scalar
def regular_polygon(self, n, exact=True, base_ring=None): """ Return a regular polygon with `n` vertices. INPUT: - ``n`` -- a positive integer, the number of vertices. - ``exact`` -- (boolean, default ``True``) if ``False`` floating point numbers are used for coordinates. - ``base_ring`` -- a ring in which the coordinates will lie. It is ``None`` by default. If it is not provided and ``exact`` is ``True`` then it will be the field of real algebraic number, if ``exact`` is ``False`` it will be the real double field. EXAMPLES:: sage: octagon = polytopes.regular_polygon(8) sage: octagon A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices sage: octagon.n_vertices() 8 sage: v = octagon.volume() sage: v 2.828427124746190? sage: v == 2*QQbar(2).sqrt() True Its non exact version:: sage: polytopes.regular_polygon(3, exact=False).vertices() (A vertex at (0.0, 1.0), A vertex at (0.8660254038, -0.5), A vertex at (-0.8660254038, -0.5)) sage: polytopes.regular_polygon(25, exact=False).n_vertices() 25 """ n = ZZ(n) if n <= 2: raise ValueError("n (={}) must be an integer greater than 2".format(n)) if base_ring is None: if exact: base_ring = AA else: base_ring = RDF try: omega = 2*base_ring.pi() / n verts = [((i*omega).sin(), (i*omega).cos()) for i in range(n)] except AttributeError: z = QQbar.zeta(n) verts = [(base_ring((z**k).imag()), base_ring((z**k).real())) for k in range(n)] return Polyhedron(vertices=verts, base_ring=base_ring)
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
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