def six_hundred_cell(self): """ Return the standard 600-cell polytope. OUTPUT: A Polyhedron object of the 4-dimensional 600-cell, a regular polytope. In many ways this is an analogue of the icosahedron. The coordinates of this polytope are rational approximations of the true coordinates of the 600-cell, some of which involve the (irrational) golden ratio. EXAMPLES:: sage: p600 = polytopes.six_hundred_cell() # not tested - very long time sage: len(list(p600.bounded_edges())) # not tested - very long time 120 """ verts = [] q12 = QQ(1) / 2 base = [q12, q12, q12, q12] for i in range(2): for j in range(2): for k in range(2): for l in range(2): verts.append([x for x in base]) base[3] = base[3] * (-1) base[2] = base[2] * (-1) base[1] = base[1] * (-1) base[0] = base[0] * (-1) for x in permutations([0, 0, 0, 1]): verts.append(x) for x in permutations([0, 0, 0, -1]): verts.append(x) g = QQ(1618033) / 1000000 # Golden ratio approximation verts = verts + [ i([q12, g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([q12, g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([q12, -g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([q12, -g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([-q12, g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([-q12, g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([-q12, -g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4) ] verts = verts + [ i([-q12, -g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4) ] return Polyhedron(vertices=verts)
def AlternatingPresentation(n): r""" Build the Alternating group of order `n!/2` as a finitely presented group. INPUT: - ``n`` -- The size of the underlying set of arbitrary symbols being acted on by the Alternating group of order `n!/2`. OUTPUT: Alternating group as a finite presentation, implementation uses GAP to find an isomorphism from a permutation representation to a finitely presented group representation. Due to this fact, the exact output presentation may not be the same for every method call on a constant ``n``. EXAMPLES:: sage: A6 = groups.presentation.Alternating(6) sage: A6.as_permutation_group().is_isomorphic(AlternatingGroup(6)), A6.order() (True, 360) TESTS:: sage: #even permutation test.. sage: A1 = groups.presentation.Alternating(1); A2 = groups.presentation.Alternating(2) sage: A1.is_isomorphic(A2), A1.order() (True, 1) sage: A3 = groups.presentation.Alternating(3); A3.order(), A3.as_permutation_group().is_cyclic() (3, True) sage: A8 = groups.presentation.Alternating(8); A8.order() 20160 """ from sage.groups.perm_gps.permgroup_named import AlternatingGroup from sage.groups.free_group import _lexi_gen n = Integer(n) perm_rep = AlternatingGroup(n) GAP_fp_rep = libgap.Image( libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens())) image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) ret_rls = tuple([ F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup() ]) return FinitelyPresentedGroup(F, ret_rls)
def AlternatingPresentation(n): r""" Build the Alternating group of order `n!/2` as a finitely presented group. INPUT: - ``n`` -- The size of the underlying set of arbitrary symbols being acted on by the Alternating group of order `n!/2`. OUTPUT: Alternating group as a finite presentation, implementation uses GAP to find an isomorphism from a permutation representation to a finitely presented group representation. Due to this fact, the exact output presentation may not be the same for every method call on a constant ``n``. EXAMPLES:: sage: A6 = groups.presentation.Alternating(6) sage: A6.as_permutation_group().is_isomorphic(AlternatingGroup(6)), A6.order() (True, 360) TESTS:: sage: #even permutation test.. sage: A1 = groups.presentation.Alternating(1); A2 = groups.presentation.Alternating(2) sage: A1.is_isomorphic(A2), A1.order() (True, 1) sage: A3 = groups.presentation.Alternating(3); A3.order(), A3.as_permutation_group().is_cyclic() (3, True) sage: A8 = groups.presentation.Alternating(8); A8.order() 20160 """ from sage.groups.perm_gps.permgroup_named import AlternatingGroup from sage.groups.free_group import _lexi_gen n = Integer(n) perm_rep = AlternatingGroup(n) GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens())) image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) ret_rls = tuple( [F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()] ) return FinitelyPresentedGroup(F, ret_rls)
def six_hundred_cell(self, exact=False): """ Return the standard 600-cell polytope. The 600-cell is a 4-dimensional regular polytope. In many ways this is an analogue of the icosahedron. .. WARNING:: The coordinates are not exact by default. The computation with exact coordinates takes a huge amount of time. INPUT: - ``exact`` - (boolean, default ``False``) if ``True`` use exact coordinates instead of floating point approximations EXAMPLES:: sage: p600 = polytopes.six_hundred_cell() sage: p600 A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 120 vertices sage: p600.f_vector() (1, 120, 720, 1200, 600, 1) Computation with exact coordinates is currently too long to be useful:: sage: p600 = polytopes.six_hundred_cell(exact=True) # not tested - very long time sage: len(list(p600.bounded_edges())) # not tested - very long time 120 """ if exact: from sage.rings.number_field.number_field import QuadraticField K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 base_ring = K else: g = (1 + RDF(5).sqrt()) / 2 base_ring = RDF q12 = base_ring(1) / base_ring(2) z = base_ring.zero() verts = [[s1 * q12, s2 * q12, s3 * q12, s4 * q12] for s1, s2, s3, s4 in itertools.product([1, -1], repeat=4)] V = (base_ring)**4 verts.extend(V.basis()) verts.extend(-v for v in V.basis()) pts = [[s1 * q12, s2 * g / 2, s3 / (2 * g), z] for (s1, s2, s3) in itertools.product([1, -1], repeat=3)] for p in AlternatingGroup(4): verts.extend(p(x) for x in pts) return Polyhedron(vertices=verts, base_ring=base_ring)
def icosahedron(self, base_ring=QQ): """ Return an icosahedron with edge length 1. INPUT: - ``base_ring`` -- Either ``QQ`` or ``RDF``. OUTPUT: A Polyhedron object of a floating point or rational approximation to the regular 3d icosahedron. If ``base_ring=QQ``, a rational approximation is used and the points are not exactly the vertices of the icosahedron. The icosahedron's coordinates contain the golden ratio, so there is no exact representation possible. EXAMPLES:: sage: ico = polytopes.icosahedron() sage: sum(sum( ico.vertex_adjacency_matrix() ))/2 30 """ if base_ring == QQ: g = QQ(1618033) / 1000000 # Golden ratio approximation r12 = QQ(1) / 2 elif base_ring == RDF: g = RDF((1 + sqrt(5)) / 2) r12 = RDF(QQ(1) / 2) else: raise ValueError("field must be QQ or RDF.") verts = [i([0, r12, g / 2]) for i in AlternatingGroup(3)] verts = verts + [i([0, r12, -g / 2]) for i in AlternatingGroup(3)] verts = verts + [i([0, -r12, g / 2]) for i in AlternatingGroup(3)] verts = verts + [i([0, -r12, -g / 2]) for i in AlternatingGroup(3)] return Polyhedron(vertices=verts, base_ring=base_ring)
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)
def icosahedron(self, exact=True, base_ring=None): """ Return an icosahedron with edge length 1. The icosahedron is one of the Platonic sold. It has 20 faces and is dual to the :meth:`dodecahedron`. INPUT: - ``exact`` -- (boolean, default ``True``) If ``False`` use an approximate ring for the coordinates. - ``base_ring`` -- (optional) the ring in which the coordinates will belong to. Note that this ring must contain `\sqrt(5)`. If it is not provided and ``exact=True`` it will be the number field `\QQ[\sqrt(5)]` and if ``exact=False`` it will be the real double field. EXAMPLES:: sage: ico = polytopes.icosahedron() sage: ico.f_vector() (1, 12, 30, 20, 1) sage: ico.volume() 5/12*sqrt5 + 5/4 Its non exact version:: sage: ico = polytopes.icosahedron(exact=False) sage: ico.base_ring() Real Double Field sage: ico.volume() 2.1816949907715726 A version using `AA <sage.rings.qqbar.AlgebraicRealField>`:: sage: ico = polytopes.icosahedron(base_ring=AA) # long time sage: ico.base_ring() # long time Algebraic Real Field sage: ico.volume() # long time 2.181694990624913? Note that if base ring is provided it must contain the square root of `5`. Otherwise you will get an error:: sage: polytopes.icosahedron(base_ring=QQ) Traceback (most recent call last): ... TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 base_ring = K else: if base_ring is None: base_ring = RDF g = (1 + base_ring(5).sqrt()) / 2 r12 = base_ring.one() / 2 z = base_ring.zero() pts = [[z, s1 * r12, s2 * g / 2] for s1, s2 in itertools.product([1, -1], repeat=2)] verts = [p(v) for p in AlternatingGroup(3) for v in pts] return Polyhedron(vertices=verts, base_ring=base_ring)
print('') # Use `g` as shorthand for the multiplication operation. g = b.operations['*'] print('Perform multiplication on the pair (0,1) and give the result.') print(g(0, 1)) print('') print('Check the canonical ordering on `b`.') print(b.canonical_order) print('') print('This ordering is used to create the action matrix for addition by 2.') # Write "add 2" as a lambda function. f = lambda x: b.operations['+'](x, b.canonical_order[1]) print(b.action_matrix(f)) print('') print( 'An example using the ``GroupStructure`` device with the alternating group on 5 letters follows.' ) c = GroupStructure(AlternatingGroup(5)) print(c) print('') # Use `h` as shorthand for the group operation. h = c.operations['*'] x = list(c.elements)[5] y = list(c.elements)[26] print('We multiply {} and {}.'.format(x, y)) print(h(x, y))