{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  Persistent Homology Tutorial \n",
    "\n",
    "Persistent homology is a construct from algebraic topology that formalizes the effect that changing a topological space in a certain way has on its homology. It attempts to overcome the lack of robustness homology shows: changing the space of interest just a little can result in a drastic change in homology. The approach to this is to consider the homology of the space at different \"resolutions\", so to say -- for example by approximating it by a sequence of chain complexes that grow more and more complicated and accurate. One can then try to distinguish prominent topological features in arbitrary dimensions from the irrelevant ones by discarding the features that are only present at a few resolutions.\n",
    "\n",
    "[This paper](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.10.5064) introduces the concept and presents the algorithms. See e.g. [this article](http://www.ams.org/journals/bull/2009-46-02/S0273-0979-09-01249-X/) for a deeper survey of the topic.\n",
    "\n",
    "To use the function, one has to switch to the `topaz` application. See this [tutorial](topaz_tutorial) for a general introduction to `topaz`.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "application 'topaz';"
   ]
  },
  {
   "attachments": {
    "small_filtration.png": {
     "image/png": [
      "[encoded data, 9332 characters]"
     ]
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "## Filtrations\n",
    "\n",
    "The objects of study are filtrations of chain complexes with finitely many frames. The data structure is templated by the type of matrix used for the description of the boundary maps.\n",
    "\n",
    "### From Hasse diagrams\n",
    "\n",
    "A filtration can be initialized by passing the Hasse diagram of the last frame of the filtration and an array containing the degree of each cell, indexed in the same order as the node indexing in the Hasse diagram (without the empty set and the dummy node with index 0, thus shifted by one). Consider this small three-frame example filtration:\n",
    "\n",
    "![{{ :tutorial:small_filtration.png?800 |}}](attachment:small_filtration.png)\n",
    "\n",
    "You can construct it in `polymake` like this:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$S = new SimplicialComplex(FACETS=>[[0,1],[0,2],[1,2],[3]]);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0:-1\n",
       "1:0 1\n",
       "2:0 2\n",
       "3:1 2\n",
       "4:3\n",
       "5:0\n",
       "6:1\n",
       "7:2\n",
       "8:\n"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$HD = $S->HASSE_DIAGRAM;              # Hasse diagram of the last frame\n",
    "print rows_numbered($HD->FACES);      # check indexing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$a = new Array<Int>(1,2,1,2,0,0,1);   # assign degrees to the simplices ([0,1] gets degree 1, [0,2] degree 2 etc)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$F = new Filtration<SparseMatrix<Rational>>($HD,$a);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "You can print the boundary matrix for each frame and dimension:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1 -1 0\n",
       "0 1 -1\n",
       "\n"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print $F->boundary_matrix(1,1);     # print dimension 1 matrix of frame 1"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To find out which rows correspond to which cells, you can print the cells of the filtration. They will be output as an array of 3-tuples, each representing one cell with degree, dimension and boundary matrix index.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0,0,1) (0,0,2) (1,0,3) (1,1,0) (1,1,2) (2,0,0) (2,1,1)\n",
       "\n"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print $F->cells;"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### From boundary matrices\n",
    "\n",
    "It is also possible to construct a filtration by passing such an array of cells, together with an array of matrices to be used as boundary matrices. To construct the same filtration as above:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "        $C->[1] = new Cell(0,0,2);\n",
       "        $C->[2] = new Cell(1,0,3);\n",
       "        $C->[3] = new Cell(1,1,0);\n",
       "        $C->[4] = new Cell(1,1,2);\n",
       "        $C->[5] = new Cell(2,0,0);\n",
       "        $C->[6] = new Cell(2,1,1);\n",
       "        \n"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$C = new Array<Cell>(7);\n",
    "$C->[0] = new Cell(0,0,1);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "        $bd->[1] = new SparseMatrix<Rational>([0,1,-1,0],[0,1,0,-1],[0,0,1,-1]);\n",
       "        $bd->[2] = new SparseMatrix<Rational>();\n",
       "    \n"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$bd = new Array<SparseMatrix<Rational>>(3);\n",
    "$bd->[0] = new SparseMatrix<Rational>([1],[1],[1],[1]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$F = new Filtration<SparseMatrix<Rational>>($C,$bd);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "\n",
    "\n",
    "### Vietoris-Rips filtration\n",
    "\n",
    "It is also possible to compute the Vietoris-Rips-filtration of a point set given a metric. The input consists of the distance matrix of the point set (that is, the matrix whose i,j-entry is the distance between points i and j), an array containing the filtration degrees of the points, the increase in ball size per frame, and an upper bound to the dimension (so one can compute lower-dimensional skeletons and save space). The following computes the four-skeleton of the VR-filtration of six random points in 5-space using the euclidean metric:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$S = polytope::rand_sphere(5,6)->VERTICES;\n",
    "$P = $S->minor(All,sequence(1,5));     # dehomogenize"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sub dist($){                          # define euclidean metric\n",
    "my $v = $_[0] - $_[1];\n",
    "return sqrt(new Float($v*$v));};"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$D = distance_matrix($P,\\&dist);       # conmpute distance matrix of the point set"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$a = new Array<Int>(6);               #zero array -- all points get degree 0"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$F = vietoris_rips_filtration<Rational>($D,$a,0.1,4);"
   ]
  },
  {
   "attachments": {
    "barcode.png": {
     "image/png": [
      "[encoded data, 11468 characters]"
     ]
    },
    "rp2_filtration.png": {
     "image/png": [
      "[encoded data, 64716 characters]"
     ]
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "![{{ :tutorial:rp2_filtration.png?600|}}](attachment:rp2_filtration.png)\n",
    "## Computing Persistence\n",
    "\n",
    "There are two different functions, one to compute persistent homology for coefficients from arbitrary euclidean domains, and another for computing persistence barcodes for field coefficients. Both are templated by the boundary matrix type. The following examples compute both for this filtration of the 5-simplex, whose 3rd frame is the real projective plane:\n",
    "\n",
    "### Coefficients from arbitrary euclidean domains\n",
    "\n",
    "The function for coefficients from arbitrary euclidean domains takes as parameters a filtration object matching the matrix type and indices `i,p,k`. It outputs a sparse matrix containing (as rows) the generators of the torsion-free part of the `p`-persistent `k`-th homology group of the `i`-th frame, and a list of paired torsion coefficients and corresponding generator matrices.\n",
    "\n",
    "The following code loads a filtration object with Integer coefficients containing the example that was previously saved to disk, which you can download {{ :tutorial:filtrationexample.top |here}}. It then computes the 3-persistent first homology group of frame 0, with the result that the torsion-free part is empty, and the part with torsion coefficient 2 has one generator, namely `-v_0+v_1-v_5`:\n",
    "\n",
    "    \n",
    "     topaz > $F = load_data(\"FiltrationExample.top\");\n",
    "     topaz > print persistent_homology<SparseMatrix<Integer>>($F,0,3,1);\n",
    "    <>\n",
    "    <(2, <(15) (0 -1) (1 1) (5 -1)>)>\n",
    "\n",
    "\n",
    "### Field coefficients and barcodes\n",
    "\n",
    "![{{ :tutorial:barcode.png?200|}}](attachment:barcode.png)The function for field coefficients requires only a filtration object of matching type as parameter. The output is an array with an entry for each dimension, containing a list of persistence intervals encoded as tuples of integers (where -1 encodes infinite lifetime). The following computes the intervals of the same filtration as above but with rational coefficients, downloadable {{ :tutorial:filtrationexamplerational.top |here}}.\n",
    "\n",
    "    \n",
    "     topaz > $F2 = load_data(\"FiltrationExampleRational.top\");\n",
    "     topaz > print persistent_homology<SparseMatrix<Rational>>($F2);\n",
    "    {(0 2) (0 -1)}\n",
    "    {(2 3) (2 3) (2 3) (1 3) (2 3) (0 3)}\n",
    "    {}\n",
    "    {}\n",
    "    {}\n",
    "    {}\n",
    "    {}\n",
    "\n",
    "\n",
    "The output corresponds to the barcode on the right.\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
}