{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# flatsurf and surface_dynamics Demo\n",
    "## Sage days 96 (Fields Institute, Toronto)\n",
    "By Vincent Delecroix <vincent.delecroix@u-bordeaux.fr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will present two Sage modules which work with \"flat surfaces\"\n",
    "\n",
    "- `flatsurf` (https://github.com/videlec/sage-flatsurf): deals with \"concrete\" flat surfaces and their properties (linear flow, saddle connections, SL(2,R)-action). Written by Vincent Delecroix and Pat Hooper.\n",
    "- `surface_dynamics` (https://gitlab.com/videlec/surface_dynamics): combinatorics of interval exchanges, origamis, Lyapunov exponents of covering loci, etc. Maintained by Vincent Delecroix.\n",
    "\n",
    "Both modules are developing in random directions depending on our interests, but we would like it to be as helpful as possible for everyone... We welcome other contributors! As of now, the two modules do not interact but we aim to merge them in a near future (including the features from `flipper`).\n",
    "\n",
    "For the installation, see the wiki https://wiki.sagemath.org/days96.\n",
    "\n",
    "As we did with flipper, the first step in order to be able to use a module they need to be imported"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import flatsurf\n",
    "import surface_dynamics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As with other objects in Sage, you can use tab completion to have a look at what is available."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flatsurf."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "surface_dynamics."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `flatsurf` Affine symmetries"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Veech's double n-gon surfaces:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = flatsurf.translation_surfaces.veech_double_n_gon(5)\n",
    "s.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s.plot(edge_labels='number')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = s.polygon(0)\n",
    "modulus = (p.vertex(3)[1] - p.vertex(2)[1]) / (p.vertex(2)[0] - p.vertex(4)[0])\n",
    "modulus"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "modulus.numerical_approx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "K = s.base_ring()\n",
    "a = K.gen()\n",
    "m = matrix(s.base_ring(),[[1,1/modulus],[0,1]])\n",
    "print m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ss = m*s\n",
    "ss.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Make a better picture"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ss.delaunay_decomposition().plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Looks like the same as the initial surface..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ss.canonicalize() == s.canonicalize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TODO: convert back and forth mapping classes between `flatsurf` and `flipper`. Namely:\n",
    "- given a mapping class from `flipper` and a flat structure, check whether this mapping class preserves the flat structure\n",
    "- obtain the flip sequence of Delaunay decomposition in `flatsurf` in order to give it to `flipper`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `surface_dynamics` origamis\n",
    "\n",
    "Origamis (or square tiled surfaces) are translation surfaces that are obtained by gluing squares. Equivalently, they are the coverings of the square torus ramified at most over the origin."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o = surface_dynamics.Origami('(1,2)', '(1,3)')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "G = o.veech_group()\n",
    "G"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "G.index()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "G.farey_symbol().fundamental_domain()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.sum_of_lyapunov_exponents()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.lyapunov_exponents_approx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o = surface_dynamics.origamis.EierlegendeWollmilchsau()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.sum_of_lyapunov_exponents()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.lyapunov_exponents_approx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o = surface_dynamics.Origami('(1,2)(3,4)(5,6)','(2,3)(4,5)')\n",
    "o.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.sum_of_lyapunov_exponents()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o.lyapunov_exponents_approx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TODO:\n",
    "- make origamis available in `flatsurf` so that we can also explore properties of linear flows.\n",
    "- compute mapping classes / action on homology"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `flatsurf` geodesics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = flatsurf.translation_surfaces.veech_double_n_gon(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The tangent bundle of the surface:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "TB = s.tangent_bundle()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define a tangent vector in polygon $0$ starting at $(\\frac{1}{2},0)$ and pointed in some direction:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "direction = s.polygon(0).vertex(2)+3*s.polygon(0).vertex(3)\n",
    "v = TB(0, (1/2,0), direction)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Convert the vector to a straight-line trajectory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "traj = v.straight_line_trajectory()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s.plot() + traj.plot(color='black')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "traj.flow(1000)\n",
    "s.plot() + traj.plot(color='black')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is actually a periodic direction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "traj.is_closed()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `flatsurf` cone surfaces from polyhedra"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Polyhedra are built into Sage and you can use them to build a translation surface. In this Demo we only use a built in function for a Platonic Solid."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import flatsurf.geometry.polyhedra as flatsurf_poly"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "polyhedron,s,mapping = flatsurf_poly.platonic_dodecahedron()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "polyhedron.plot(frame=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s.plot(polygon_labels=False,edge_labels=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "TB = s.tangent_bundle()\n",
    "direction = s.polygon(0).vertex(2)+2*s.polygon(0).vertex(3)\n",
    "v = TB(0, (1/2,0), direction)\n",
    "traj = v.straight_line_trajectory()\n",
    "traj.flow(100)\n",
    "print(traj.is_closed())\n",
    "print(traj.combinatorial_length())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s.plot() + traj.plot(color='black')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "polyhedron.plot?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "G = polyhedron.plot(frame=False, point=False,\n",
    "                    line={'color':'red', 'alpha':0.5},\n",
    "                    polygon={'alpha': 0.5}, wireframe=None)\n",
    "G += line3d(mapping(traj), radius=0.02, frame=False)\n",
    "G.show(viewer='tachyon')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "TB = s.tangent_bundle()\n",
    "direction = s.polygon(0).vertex(2)+3*s.polygon(0).vertex(3)\n",
    "v = TB(0, (1/2,0), direction)\n",
    "traj = v.straight_line_trajectory()\n",
    "traj.flow(1000)\n",
    "print(traj.is_closed())\n",
    "print(traj.combinatorial_length())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show(s.plot() + traj.plot(color='black'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "G = polyhedron.plot(frame=False, point=False,\n",
    "                    line={'color':'red', 'alpha':0.5},\n",
    "                    polygon={'alpha': 0.5}, wireframe=None)\n",
    "G += line3d(mapping(traj), radius=0.02, frame=False)\n",
    "G.show(viewer='tachyon')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `surface_dynamics` Lyapunov exponents (for strata and strata covering)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "H1 = surface_dynamics.QuadraticStratum(1,1,1,1)\n",
    "H2 = surface_dynamics.QuadraticStratum(9,-1)\n",
    "print H1\n",
    "print H2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print H1.components()\n",
    "print H2.components()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1, = H1.components()\n",
    "c2,c3 = H2.components()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print c1.lyapunov_exponents_H_minus()\n",
    "print c1.lyapunov_exponents_H_plus()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = c2.permutation_representative()\n",
    "print p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p2 = p.cover(['(1,2,3)','','','','','','(3,2,1)'])\n",
    "print p2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print p2.stratum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p2.lyapunov_exponents_H_plus()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TODO:\n",
    "- make it possible to compute Lyapunov exponents of Abelian strata (bug in the currrent code)\n",
    "- area Siegel-Veech constants (for the sum of Lyapunov exponents)\n",
    "- volumes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TODO\n",
    "- unify SL(2,R)-orbit closure properties (origamis and strata)\n",
    "- More Teichmüller curves\n",
    "- decomposition of foliation\n",
    "- SL(2,R)-orbit closure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "SageMath 8.2",
   "language": "",
   "name": "sagemath"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
