Path: blob/master/src/sage/geometry/polyhedron/library.py
8817 views
r"""1Library of commonly used, famous, or interesting polytopes23REFERENCES:45.. [Fetter2012]6Hans L. Fetter,7"A Polyhedron Full of Surprises",8Mathematics Magazine 85 (2012), no. 5, 334-342.9"""1011########################################################################12# Copyright (C) 2008 Marshall Hampton <[email protected]>13# Copyright (C) 2011 Volker Braun <[email protected]>14#15# Distributed under the terms of the GNU General Public License (GPL)16#17# http://www.gnu.org/licenses/18########################################################################192021from sage.rings.all import Integer, QQ, ZZ, RDF22from sage.matrix.constructor import matrix23from sage.modules.free_module_element import vector24from sage.combinat.permutation import Permutations25from sage.groups.perm_gps.permgroup_named import AlternatingGroup26from sage.misc.functional import norm27from sage.functions.other import sqrt, floor, ceil28from sage.functions.trig import sin, cos29from sage.misc.decorators import rename_keyword3031from constructor import Polyhedron32333435#########################################################################36class Polytopes():37"""38A class of constructors for commonly used, famous, or interesting39polytopes.4041TESTS::4243sage: TestSuite(polytopes).run(skip='_test_pickling')44"""4546@staticmethod47def orthonormal_1(dim_n=5):48"""49A matrix of rational approximations to orthonormal vectors to50``(1,...,1)``.5152INPUT:5354- ``dim_n`` - the dimension of the vectors5556OUTPUT:5758A matrix over ``QQ`` whose rows are close to an orthonormal59basis to the subspace normal to ``(1,...,1)``.6061EXAMPLES::6263sage: from sage.geometry.polyhedron.library import Polytopes64sage: m = Polytopes.orthonormal_1(5)65sage: m66[ 70711/100000 -7071/10000 0 0 0]67[ 1633/4000 1633/4000 -81649/100000 0 0]68[ 7217/25000 7217/25000 7217/25000 -43301/50000 0]69[ 22361/100000 22361/100000 22361/100000 22361/100000 -44721/50000]70"""71pb = []72for i in range(0,dim_n-1):73pb.append([1.0/(i+1)]*(i+1) + [-1] + [0]*(dim_n-i-2))74m = matrix(RDF,pb)75new_m = []76for i in range(0,dim_n-1):77new_m.append([RDF(100000*q/norm(m[i])).ceil()/100000 for q in m[i]])78return matrix(QQ,new_m)7980@staticmethod81def project_1(fpoint):82"""83Take a ndim-dimensional point and projects it onto the plane84perpendicular to (1,1,...,1).8586INPUT:8788- ``fpoint`` - a list of ndim numbers8990EXAMPLES::9192sage: from sage.geometry.polyhedron.library import Polytopes93sage: Polytopes.project_1([1,1,1,1,2])94[1/100000, 1/100000, 1/50000, -559/625]95"""96dim_n = len(fpoint)97p_basis = [list(q) for q in Polytopes.orthonormal_1(dim_n)]98out_v = []99for v in p_basis:100out_v.append(sum([fpoint[ind]*v[ind] for ind in range(dim_n)]))101return out_v102103@staticmethod104def _pfunc(i,j,perm):105"""106An internal utility function for constructing the Birkhoff polytopes.107108EXAMPLES::109110sage: from sage.geometry.polyhedron.library import Polytopes111sage: Polytopes._pfunc(1,2,Permutations(3)[0])1120113"""114if perm[i-1] == j:115return 1116else:117return 0118119120@rename_keyword(deprecation=11634, field='base_ring')121def regular_polygon(self, n, base_ring=QQ):122"""123Return a regular polygon with n vertices. Over the rational124field the vertices may not be exact.125126INPUT:127128- ``n`` -- a positive integer, the number of vertices.129130- ``field`` -- either ``QQ`` or ``RDF``.131132EXAMPLES::133134sage: octagon = polytopes.regular_polygon(8)135sage: len(octagon.vertices())1368137"""138npi = 3.14159265359139verts = []140for i in range(n):141t = 2*npi*i/n142verts.append([sin(t),cos(t)])143verts = [[base_ring(RDF(x)) for x in y] for y in verts]144return Polyhedron(vertices=verts, base_ring=base_ring)145146147def Birkhoff_polytope(self, n):148"""149Return the Birkhoff polytope with n! vertices. Each vertex150is a (flattened) n by n permutation matrix.151152INPUT:153154- ``n`` -- a positive integer giving the size of the permutation matrices.155156EXAMPLES::157158sage: b3 = polytopes.Birkhoff_polytope(3)159sage: b3.n_vertices()1606161"""162verts = []163for p in Permutations(range(1,n+1)):164verts += [ [Polytopes._pfunc(i,j,p) for j in range(1,n+1)165for i in range(1,n+1) ] ]166return Polyhedron(vertices=verts)167168169def n_simplex(self, dim_n=3, project = True):170"""171Return a rational approximation to a regular simplex in172dimension ``dim_n``.173174INPUT:175176- ``dim_n`` -- The dimension of the cross-polytope, a positive177integer.178179- ``project`` -- Optional argument, whether to project180orthogonally. Default is True.181182OUTPUT:183184A Polyhedron object of the ``dim_n``-dimensional simplex.185186EXAMPLES::187188sage: s5 = polytopes.n_simplex(5)189sage: s5.dim()1905191"""192verts = Permutations([0 for i in range(dim_n)] + [1]).list()193if project: verts = [Polytopes.project_1(x) for x in verts]194return Polyhedron(vertices=verts)195196197@rename_keyword(deprecation=11634, field='base_ring')198def icosahedron(self, base_ring=QQ):199"""200Return an icosahedron with edge length 1.201202INPUT:203204- ``base_ring`` -- Either ``QQ`` or ``RDF``.205206OUTPUT:207208A Polyhedron object of a floating point or rational209approximation to the regular 3d icosahedron.210211If ``base_ring=QQ``, a rational approximation is used and the212points are not exactly the vertices of the icosahedron. The213icosahedron's coordinates contain the golden ratio, so there214is no exact representation possible.215216EXAMPLES::217218sage: ico = polytopes.icosahedron()219sage: sum(sum( ico.vertex_adjacency_matrix() ))/222030221"""222if base_ring == QQ:223g = QQ(1618033)/1000000 # Golden ratio approximation224r12 = QQ(1)/2225elif base_ring == RDF:226g = RDF( (1 + sqrt(5))/2 )227r12 = RDF( QQ(1)/2 )228else:229raise ValueError, "field must be QQ or RDF."230verts = [i([0,r12,g/2]) for i in AlternatingGroup(3)]231verts = verts + [i([0,r12,-g/2]) for i in AlternatingGroup(3)]232verts = verts + [i([0,-r12,g/2]) for i in AlternatingGroup(3)]233verts = verts + [i([0,-r12,-g/2]) for i in AlternatingGroup(3)]234return Polyhedron(vertices=verts, base_ring=base_ring)235236237@rename_keyword(deprecation=11634, field='base_ring')238def dodecahedron(self, base_ring=QQ):239"""240Return a dodecahedron.241242INPUT:243244- ``base_ring`` -- Either ``QQ`` (in which case a rational245approximation to the golden ratio is used) or ``RDF``.246247EXAMPLES::248249sage: d12 = polytopes.dodecahedron()250sage: d12.n_inequalities()25112252"""253return self.icosahedron(base_ring=base_ring).polar()254255256def small_rhombicuboctahedron(self):257"""258Return an Archimedean solid with 24 vertices and 26 faces.259260EXAMPLES::261262sage: sr = polytopes.small_rhombicuboctahedron()263sage: sr.n_vertices()26424265sage: sr.n_inequalities()26626267"""268verts = [ [-3/2, -1/2, -1/2], [-3/2, -1/2, 1/2], [-3/2, 1/2, -1/2],269[-3/2, 1/2, 1/2], [-1/2, -3/2, -1/2], [-1/2, -3/2, 1/2],270[-1/2, -1/2, -3/2], [-1/2,-1/2, 3/2], [-1/2, 1/2, -3/2],271[-1/2, 1/2, 3/2], [-1/2, 3/2, -1/2], [-1/2, 3/2, 1/2],272[1/2, -3/2, -1/2], [1/2, -3/2, 1/2], [1/2, -1/2,-3/2],273[1/2, -1/2, 3/2], [1/2, 1/2, -3/2], [1/2, 1/2, 3/2],274[1/2, 3/2,-1/2], [1/2, 3/2, 1/2], [3/2, -1/2, -1/2],275[3/2, -1/2, 1/2], [3/2, 1/2,-1/2], [3/2, 1/2, 1/2] ]276return Polyhedron(vertices=verts)277278279@rename_keyword(deprecation=11634, field='base_ring')280def great_rhombicuboctahedron(self, base_ring=QQ):281"""282Return an Archimedean solid with 48 vertices and 26 faces.283284EXAMPLES::285286sage: gr = polytopes.great_rhombicuboctahedron()287sage: gr.n_vertices()28848289sage: gr.n_inequalities()29026291"""292v1 = QQ(131739771357/54568400000)293v2 = QQ(104455571357/27284200000)294verts = [ [1, v1, v2],295[1, v2, v1],296[v1, 1, v2],297[v1, v2, 1],298[v2, 1, v1],299[v2, v1, 1] ]300verts = verts + [[x[0],x[1],-x[2]] for x in verts]301verts = verts + [[x[0],-x[1],x[2]] for x in verts]302verts = verts + [[-x[0],x[1],x[2]] for x in verts]303if base_ring!=QQ:304verts = [base_ring(v) for v in verts]305return Polyhedron(vertices=verts, base_ring=base_ring)306307308def rhombic_dodecahedron(self):309"""310This face-regular, vertex-uniform polytope is dual to the311cuboctahedron. It has 14 vertices and 12 faces.312313EXAMPLES::314315sage: rd = polytopes.rhombic_dodecahedron()316sage: rd.n_vertices()31714318sage: rd.n_inequalities()31912320"""321v = [ [1, 1, 1], [1, 1, -1], [1, -1, 1], [1, -1, -1], [-1, 1, 1],322[-1, 1, -1], [-1, -1, 1], [-1, -1, -1], [0, 0, 2], [0, 2, 0],323[2, 0, 0], [0, 0, -2], [0, -2, 0], [-2, 0, 0] ]324return Polyhedron(vertices=v)325326327def cuboctahedron(self):328"""329An Archimedean solid with 12 vertices and 14 faces. Dual to330the rhombic dodecahedron.331332EXAMPLES::333334sage: co = polytopes.cuboctahedron()335sage: co.n_vertices()33612337sage: co.n_inequalities()33814339"""340one = Integer(1)341v = [ [0, -one/2, -one/2], [0, one/2, -one/2], [one/2, -one/2, 0],342[one/2, one/2, 0], [one/2, 0, one/2], [one/2, 0, -one/2],343[0, one/2, one/2], [0, -one/2, one/2], [-one/2, 0, one/2],344[-one/2, one/2, 0], [-one/2, 0, -one/2], [-one/2, -one/2, 0] ]345return Polyhedron(vertices=v)346347348@rename_keyword(deprecation=11634, field='base_ring')349def buckyball(self, base_ring=QQ):350"""351Also known as the truncated icosahedron, an Archimedean solid.352It has 32 faces and 60 vertices. Rational coordinates are not353exact.354355EXAMPLES::356357sage: bb = polytopes.buckyball()358sage: bb.n_vertices()35960360sage: bb.n_inequalities() # number of facets36132362sage: bb.base_ring()363Rational Field364"""365# Note: QQ would give some incorrecty subdivided facets366p = self.icosahedron(base_ring=RDF).edge_truncation()367if base_ring==RDF:368return p369# Converting with low precision to save time.370new_ieqs = [[int(1000*x)/QQ(1000) for x in y] for y in p.inequalities()]371return Polyhedron(ieqs=new_ieqs)372373374def pentakis_dodecahedron(self):375"""376This face-regular, vertex-uniform polytope is dual to the377truncated icosahedron. It has 60 faces and 32 vertices.378379EXAMPLES::380381sage: pd = polytopes.pentakis_dodecahedron()382sage: pd.n_vertices()38332384sage: pd.n_inequalities() # number of facets38560386"""387return self.buckyball().polar()388389def Kirkman_icosahedron(self):390"""391A non-uniform icosahedron with interesting properties.392393See [Fetter2012]_ for details.394395OUTPUT:396397The Kirkman icosahedron, a 3-dimensional polyhedron398with 20 vertices, 20 faces, and 38 edges.399400EXAMPLES::401402sage: KI = polytopes.Kirkman_icosahedron()403sage: KI.f_vector()404(1, 20, 38, 20, 1)405sage: vertices = KI.vertices()406sage: edges = [[vector(edge[0]),vector(edge[1])] for edge in KI.bounded_edges()]407sage: edge_lengths = [norm(edge[0]-edge[1]) for edge in edges]408sage: union(edge_lengths)409[7, 8, 9, 11, 12, 14, 16]410"""411vertices = [[-12, -4, 0], [-12, 4, 0], [-9, -6, -6],412[-9, -6, 6], [-9, 6, -6], [-9, 6, 6], [-6, 0, -12],413[-6, 0, 12], [0, -12, -8], [0, -12, 8], [0, 12, -8],414[0, 12, 8], [6, 0, -12], [6, 0, 12], [9, -6, -6],415[9, -6, 6], [9, 6, -6], [9, 6, 6], [12, -4, 0],416[12, 4, 0]]417return Polyhedron(vertices=vertices)418419420def twenty_four_cell(self):421"""422Return the standard 24-cell polytope.423424OUTPUT:425426A Polyhedron object of the 4-dimensional 24-cell, a regular427polytope. The coordinates of this polytope are exact.428429EXAMPLES::430431sage: p24 = polytopes.twenty_four_cell()432sage: v = p24.vertex_generator().next()433sage: for adj in v.neighbors(): print adj434A vertex at (-1/2, -1/2, -1/2, 1/2)435A vertex at (-1/2, -1/2, 1/2, -1/2)436A vertex at (-1, 0, 0, 0)437A vertex at (-1/2, 1/2, -1/2, -1/2)438A vertex at (0, -1, 0, 0)439A vertex at (0, 0, -1, 0)440A vertex at (0, 0, 0, -1)441A vertex at (1/2, -1/2, -1/2, -1/2)442"""443verts = []444q12 = QQ(1)/2445base = [q12,q12,q12,q12]446for i in range(2):447for j in range(2):448for k in range(2):449for l in range(2):450verts.append([x for x in base])451base[3] = base[3]*(-1)452base[2] = base[2]*(-1)453base[1] = base[1]*(-1)454base[0] = base[0]*(-1)455verts = verts + Permutations([0,0,0,1]).list()456verts = verts + Permutations([0,0,0,-1]).list()457return Polyhedron(vertices=verts)458459460def six_hundred_cell(self):461"""462Return the standard 600-cell polytope.463464OUTPUT:465466A Polyhedron object of the 4-dimensional 600-cell, a regular467polytope. In many ways this is an analogue of the468icosahedron. The coordinates of this polytope are rational469approximations of the true coordinates of the 600-cell, some470of which involve the (irrational) golden ratio.471472EXAMPLES::473474sage: p600 = polytopes.six_hundred_cell() # not tested - very long time475sage: len(list(p600.bounded_edges())) # not tested - very long time476120477"""478verts = []479q12 = QQ(1)/2480base = [q12,q12,q12,q12]481for i in range(2):482for j in range(2):483for k in range(2):484for l in range(2):485verts.append([x for x in base])486base[3] = base[3]*(-1)487base[2] = base[2]*(-1)488base[1] = base[1]*(-1)489base[0] = base[0]*(-1)490verts += Permutations([0,0,0,1]).list()491verts += Permutations([0,0,0,-1]).list()492g = QQ(1618033)/1000000 # Golden ratio approximation493verts = verts + [i([q12,g/2,1/(g*2),0]) for i in AlternatingGroup(4)]494verts = verts + [i([q12,g/2,-1/(g*2),0]) for i in AlternatingGroup(4)]495verts = verts + [i([q12,-g/2,1/(g*2),0]) for i in AlternatingGroup(4)]496verts = verts + [i([q12,-g/2,-1/(g*2),0]) for i in AlternatingGroup(4)]497verts = verts + [i([-q12,g/2,1/(g*2),0]) for i in AlternatingGroup(4)]498verts = verts + [i([-q12,g/2,-1/(g*2),0]) for i in AlternatingGroup(4)]499verts = verts + [i([-q12,-g/2,1/(g*2),0]) for i in AlternatingGroup(4)]500verts = verts + [i([-q12,-g/2,-1/(g*2),0]) for i in AlternatingGroup(4)]501return Polyhedron(vertices=verts)502503504@rename_keyword(deprecation=11634, field='base_ring')505def cyclic_polytope(self, dim_n, points_n, base_ring=QQ):506"""507Return a cyclic polytope.508509INPUT:510511- ``dim_n`` -- positive integer. the dimension of the polytope.512513- ``points_n`` -- positive integer. the number of vertices.514515- ``base_ring`` -- either ``QQ`` (default) or ``RDF``.516517OUTPUT:518519A cyclic polytope of dim_n with points_n vertices on the520moment curve ``(t,t^2,...,t^n)``, as Polyhedron object.521522EXAMPLES::523524sage: c = polytopes.cyclic_polytope(4,10)525sage: c.n_inequalities()52635527"""528verts = [[t**i for i in range(1,dim_n+1)] for t in range(points_n)]529return Polyhedron(vertices=verts, base_ring=base_ring)530531532def hypersimplex(self, dim_n, k, project = True):533"""534The hypersimplex in dimension dim_n with d choose k vertices,535projected into (dim_n - 1) dimensions.536537INPUT:538539- ``n`` -- the numbers ``(1,...,n)`` are permuted540541- ``project`` -- If ``False``, the polyhedron is left in542dimension ``n``.543544OUTPUT:545546A Polyhedron object representing the hypersimplex.547548EXAMPLES::549550sage: h_4_2 = polytopes.hypersimplex(4,2) # combinatorially equivalent to octahedron551sage: h_4_2.n_vertices()5526553sage: h_4_2.n_inequalities()5548555"""556vert0 = [0]*(dim_n-k) + [1]*k557verts = Permutations(vert0).list()558if project:559verts = [Polytopes.project_1(x) for x in verts]560return Polyhedron(vertices=verts)561562563def permutahedron(self, n, project = True):564"""565The standard permutahedron of (1,...,n) projected into n-1566dimensions.567568INPUT:569570- ``n`` -- the numbers ``(1,...,n)`` are permuted571572- ``project`` -- If ``False`` the polyhedron is left in dimension ``n``.573574OUTPUT:575576A Polyhedron object representing the permutahedron.577578EXAMPLES::579580sage: perm4 = polytopes.permutahedron(4)581sage: perm4582A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices583sage: polytopes.permutahedron(5).show() # long time584"""585verts = range(1,n+1)586verts = Permutations(verts).list()587if project:588verts = [Polytopes.project_1(x) for x in verts]589p = Polyhedron(vertices=verts)590return p591592593def n_cube(self, dim_n):594"""595Return a cube in the given dimension596597INPUT:598599- ``dim_n`` -- integer. The dimension of the cube.600601OUTPUT:602603A Polyhedron object of the ``dim_n``-dimensional cube, with604exact coordinates.605606EXAMPLES::607608sage: four_cube = polytopes.n_cube(4)609sage: four_cube.is_simple()610True611"""612if dim_n == 1:613return Polyhedron(vertices = [[1],[-1]])614615pre_cube = polytopes.n_cube(dim_n-1)616vertices = [];617for pre_v in pre_cube.vertex_generator():618vertices.append( [ 1] + [v for v in pre_v] );619vertices.append( [-1] + [v for v in pre_v] );620return Polyhedron(vertices = vertices)621622623def cross_polytope(self, dim_n):624"""625Return a cross-polytope in dimension ``dim_n``. These are626the generalization of the octahedron.627628INPUT:629630- ``dim_n`` -- integer. The dimension of the cross-polytope.631632OUTPUT:633634A Polyhedron object of the ``dim_n``-dimensional cross-polytope,635with exact coordinates.636637EXAMPLES::638639sage: four_cross = polytopes.cross_polytope(4)640sage: four_cross.is_simple()641False642sage: four_cross.n_vertices()6438644"""645verts = Permutations([0 for i in range(dim_n-1)] + [1]).list()646verts += Permutations([0 for i in range(dim_n-1)] + [-1]).list()647return Polyhedron(vertices=verts)648649650def parallelotope(self, generators):651r"""652Return the parallelotope spanned by the generators.653654INPUT:655656- ``generators`` -- an iterable of anything convertible to vector657(for example, a list of vectors) such that the vectors all658have the same dimension.659660OUTPUT:661662The parallelotope. This is the multi-dimensional663generalization of a parallelogram (2 generators) and a664parallelepiped (3 generators).665666EXAMPLES::667668sage: polytopes.parallelotope([ (1,0), (0,1) ])669A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices670sage: polytopes.parallelotope([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]])671A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 16 vertices672"""673try:674generators = [ vector(QQ,v) for v in generators ]675base_ring = QQ676except TypeError:677generators = [ vector(RDF,v) for v in generators ]678base_ring = RDF679680from sage.combinat.combination import Combinations681par = [ 0*generators[0] ]682par += [ sum(c) for c in Combinations(generators) if c!=[] ]683return Polyhedron(vertices=par, base_ring=base_ring)684685686687polytopes = Polytopes()688689690