.. -*- coding: utf-8 -*- .. linkall .. _polytutorial: A Brief Introduction to Polytopes in Sage ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. MODULEAUTHOR:: sarah-marie belcastro <smbelcas@toroidalsnark.net> If you already know some convex geometry *a la* Grünbaum or Brøndsted, then you may have itched to get your hands dirty with some polytope calculations. Here is a mini\-guide to doing just that. Basics """""" First, let's define a polytope as the convex hull of a set of points, i.e. given `S` we compute `P={\rm conv}(S)`: :: sage: P1 = Polyhedron(vertices = [[-5,2], [4,4], [3,0], [1,0], [2,-4], [-3,-1], [-5,-3]]) sage: P1 A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices .. end of output Notice that Sage tells you the dimension of the polytope as well as the dimension of the ambient space. Of course, you want to know what this object looks like: :: sage: P1.plot() Graphics object consisting of 6 graphics primitives .. end of output Even in only 2 dimensions, it's a pain to figure out what the supporting hyperplanes are. Luckily Sage will take care of that for us. :: sage: for q in P1.Hrepresentation(): ....: print(q) An inequality (-4, 1) x + 12 >= 0 An inequality (1, 7) x + 26 >= 0 An inequality (1, 0) x + 5 >= 0 An inequality (2, -9) x + 28 >= 0 .. end of output That notation is not immediately parseable, because seriously, those do not look like equations of lines (or of halfspaces, which is really what they are). ``(-4, 1) x + 12 >= 0`` really means `(-4, 1)\cdot\vec{x} + 12 \geq 0`. So... if you want to define a polytope via inequalities, you have to translate each inequality into a vector. For example, `(-4, 1)\cdot\vec{x} + 12 \geq 0` becomes (12, \-4, 1). :: sage: altP1 = Polyhedron(ieqs=[(12, -4, 1), (26, 1, 7),(5,1,0), (28, 2, -9)]) sage: altP1.plot() Graphics object consisting of 6 graphics primitives .. end of output Other information you might want to pull out of Sage about a polytope is the vertex list, which can be done in two ways: :: sage: for q in P1.Vrepresentation(): ....: print(q) A vertex at (-5, -3) A vertex at (-5, 2) A vertex at (4, 4) A vertex at (2, -4) .. end of output :: sage: P1.vertices() (A vertex at (-5, -3), A vertex at (-5, 2), A vertex at (4, 4), A vertex at (2, -4)) .. end of output Polar duals """"""""""" Surely you want to compute the polar dual: :: sage: P1dual = P1.polar() sage: P1dual A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices .. end of output Check it out\-\-\-we started with an integer\-lattice polytope and dualized to a rational\-lattice polytope. Let's look at that. :: sage: P1dual.plot() Graphics object consisting of 6 graphics primitives .. end of output :: sage: P1.plot() + P1dual.plot() Graphics object consisting of 12 graphics primitives .. end of output Oh, yeah, unless the polytope is unit\-sphere\-sized, the dual will be a very different size. Let's rescale. :: sage: ((1/4)*P1).plot() + (4*P1dual).plot() Graphics object consisting of 12 graphics primitives .. end of output If you think that looks a little bit shady, you're correct. Here is an example that makes the issue a bit clearer. :: sage: P2 = Polyhedron(vertices = [[-5,0], [-1,1], [-2,0], [1,0], [-2,-1], [-3,-1], [-5,-1]]) sage: P2 A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 5 vertices sage: P2dual = P2.polar(); P2dual A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices sage: P2.plot() + P2dual.plot() Graphics object consisting of 14 graphics primitives .. end of output That is clearly not computing what we think of as the polar dual. But look at this... :: sage: P2.plot() + (-1*P2dual).plot() Graphics object consisting of 14 graphics primitives .. end of output Here is what's going on. If a polytope ``P`` is in `\ZZ`, then... (1) ...the dual is inverted in some way, which is vertically for polygons. (2) ...the dual is taken of P itself. (3) ...if the origin is not in P, then an error is returned. However, if a polytope is *not* in `\ZZ`, for example if it's in `\QQ` or ``RDF``, then... (1') ...the dual is not inverted. (2') ...the dual is taken of P\-translated\-so\-barycenter\-is\-at\-origin. Keep all of this in mind as you take polar duals. Polytope Constructions """""""""""""""""""""" Minkowski sums! Now with two syntaxes! :: sage: P1+P2 A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 8 vertices .. end of output :: sage: P1.minkowski_sum(P2) A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 8 vertices .. end of output Okay, fine. We should have some 3\-dimensional examples, at least. (Note that in order to display polytopes effectively you'll need visualization software such as Javaview and Jmol installed.) :: sage: P3 = Polyhedron(vertices=[(0,0,0), (0,0,1/2), (0,1/2,0), (1/2,0,0), (3/4,1/5,3/2)]); P3 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 5 vertices sage: P4 = Polyhedron(vertices=[(-1,1,0),(1,1,0),(-1,0,1), (1,0,1),(0,-1,1),(0,1,1)]); P4 A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices sage: P3.plot() + P4.plot() Graphics3d Object .. end of output :: sage: (P3+P4).plot() Graphics3d Object .. end of output We can also find the intersection of two polytopes... and this too has two syntaxes! :: sage: int12 = P1.intersection(P2*.5); int12.plot() Graphics object consisting of 7 graphics primitives .. end of output :: sage: int34 = P3 & P4; int34.plot() Graphics3d Object .. end of output Should one wish to translate, one can. :: sage: transP2 = P2.translation([2,1]) sage: P2.plot() + transP2.plot() Graphics object consisting of 14 graphics primitives .. end of output Then of course we can take prisms, pyramids, and bipyramids of polytopes... :: sage: P2.prism().plot() Graphics3d Object .. end of output :: sage: P1.pyramid().plot() Graphics3d Object .. end of output :: sage: P2dual.bipyramid().plot() Graphics3d Object .. end of output Okay, fine. Yes, Sage has some kinds of polytopes built in. If you type ``polytopes.`` and then press ``TAB`` after the period, you'll get a list of pre\-built polytopes. :: sage: P5 = polytopes.hypercube(5) sage: P6 = polytopes.cross_polytope(3) sage: P7 = polytopes.simplex(7) .. end of output Let's look at a 4\-dimensional polytope. :: sage: P8 = polytopes.hypercube(4) sage: P8.plot() Graphics3d Object .. end of output We can see it from a different perspective: :: sage: P8.schlegel_projection([2,5,11,17]).plot() Graphics3d Object .. end of output Queries to polytopes """""""""""""""""""" Once you've constructed some polytope, you can ask Sage questions about it. :: sage: P1.contains([1,0]) True .. end of output :: sage: P1.interior_contains([3,0]) False .. end of output :: sage: P3.contains([1,0,0]) False .. end of output Face information can be useful. :: sage: int34.f_vector() (1, 8, 12, 6, 1) .. end of output Well, geometric information might be *more* helpful... Here we are told which of the vertices form each 2\-face: :: sage: [f.ambient_V_indices() for f in int34.faces(2)] [(1, 3, 4), (0, 1, 3, 5), (0, 1, 2, 4, 6), (2, 3, 4, 5, 7), (2, 6, 7), (0, 5, 6, 7)] .. end of output Yeah, that isn't so useful as it is. Let's figure out the vertex and hyperplane representations of the first face in the list. :: sage: first2faceofint34 = P3.faces(2)[0] sage: first2faceofint34.ambient_Hrepresentation(); first2faceofint34.vertices() (An inequality (1, 0, 0) x + 0 >= 0,) (A vertex at (0, 0, 0), A vertex at (0, 0, 1/2), A vertex at (0, 1/2, 0)) .. end of output If you want more... :ref:`sage.geometry.polyhedron.base` is the first place you want to go.