{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Face lattices (of Polytopes)\n",
    "\n",
    "By definition the face lattice of a polytope contains all the combinatorial information about a polytope.  Here we want to explore how to work with this in polymake.  Let's start simple.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}\n",
       "{0}\n",
       "{1}\n",
       "{2}\n",
       "{3}\n",
       "{4}\n",
       "{1 2}\n",
       "{2 3}\n",
       "{3 4}\n",
       "{0 4}\n",
       "{0 1}\n",
       "{0 1 2 3 4}\n",
       "\n"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$p = n_gon(5);\n",
    "$HD = $p->HASSE_DIAGRAM;       \n",
    "print $HD->FACES;"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "The obvious question is: How to interpret that output?  Well, the Hasse diagram of a partially ordered set is implemented as a special kind of a directed graph.  Hence all operations on (directed) graphs work.  Each node of the Hasse diagram represents a face.  One way to give a name to such a face is to list all the vertices contained, and this is the output above.  A key feature is that the faces come sorted by dimension.\n",
    "\n",
    "Very often just a part of the face lattice is interesting.  The following command lists just the 1-dimensional faces.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{2 3}{3 4}{0 4}{0 1}{1 2}\n",
       "\n"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print map { $p->HASSE_DIAGRAM->FACES->[$_] } @{$p->HASSE_DIAGRAM->nodes_of_dim(1)};"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Face lattices of polytopes can be huge.  So it may be an advantage to compute only a part.  The following computes the 2-skeleton of an 8-dimensional cube. We need to specify 3 as a limit since this function uses the rank which is one more than the dimension.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(0 (0 0)) (1 (1 256)) (2 (257 1280)) (3 (1281 3072)) (4 (3073 3073))}\n",
       "\n"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$c=cube(8);\n",
    "$HD_partial = lower_hasse_diagram($c->VERTICES_IN_FACETS,3);\n",
    "print $HD_partial->INVERSE_RANK_MAP;"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Instead of listing all those thousands of faces here we give only the pairs indicating the start-node and end-node for each rank.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "256 1024 1792 \n",
       "\n"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print map { $HD_partial->nodes_of_rank($_)->size,\" \" } (1..3);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Dealing with Large Polytopes\n",
    "\n",
    "In order to get the most out of the above it is important to understand that this kind of computation is a two-staged process.  In the first step, polymake determines VERTICES_IN_FACETS, that is, the combinatorial description of the polytope, and then the computation of HASSE_DIAGRAM only takes this incidence matrix as its input; no coordinates involved in the second step.\n",
    "\n",
    "To get at the incidence matrix typically requires a convex hull computation.  This can be triggered like this.  Intentionally, there is no output.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$p=rand_sphere(6,100); \n",
    "$p->VERTICES_IN_FACETS;"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Notice that this takes a couple of seconds with the default convex hull code (via cdd), even on a large machine; and the reason is that the double description method employed is not best possible for this kind of input.  You can speed up *this* computation as follows.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prefer_now \"beneath_beyond\"; $p->VERTICES_IN_FACETS;"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Temporarily (that is, only in this command) we change the default convex hull code to polymake's built-in beneath-and-beyond method.  This is faster on this particular input.\n",
    "\n",
    "In general, there is no way to tell ahead of time which convex hull algorithm works best.  So, for your own experiments you will have to try.  To get an idea you might want to look up:\n",
    "\n",
    "*  Avis, David; Bremner, David; Seidel, Raimund: How good are convex hull algorithms? 11th ACM Symposium on Computational Geometry (Vancouver, BC, 1995). Comput. Geom. 7 (1997), no. 5-6, 265–301.\n",
    "\n",
    "*  Joswig, Michael: Beneath-and-beyond revisited. Algebra, geometry, and software systems, 1–21, Springer, Berlin, 2003.\n",
    "\n",
    "The subsequent second stage looks as above; but the difference is that VERTICES_IN_FACETS is known already.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100 2004 10638 \n",
       "\n"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$HD_partial = lower_hasse_diagram($p->VERTICES_IN_FACETS,3);\n",
    "print map { $HD_partial->nodes_of_rank($_)->size,\" \" } (1..3);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The executive summary: While polymake is designed to do all kinds of things automatically, you might have to guide it a little if you are computing with large or special input.\n",
    "\n",
    "One more caveat:  A *d*-polytope with *n* vertices has at most *O(n^(d/2))* facets.  This is the consequence of the Upper-Bound-Theorem.\n",
    "\n",
    "*  McMullen, Peter:  The maximum numbers of faces of a convex polytope. Mathematika 17 (1970) 179-184.\n",
    "This number is actually attained by neighborly polytopes; for example, by the cyclic polytopes.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "polymake",
   "language": "polymake",
   "name": "polymake"
  },
  "language_info": {
   "codemirror_mode": "perl",
   "file_extension": ".pm",
   "mimetype": "text/x-polymake",
   "name": "polymake"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}