{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Can two-dimensional topological voids exist in two dimensions?\n", "\n", "The classic example of a two-dimensional homology class is the \"void\" surrounded by a sphere in three-dimensional space.\n", "Challenge question: **Can two-dimensional topological voids arise from point clouds in two-dimensional space?**\n", "We will answer this question programmatically by computing Vietoris–Rips persistent homology of random point clouds in the square $[0, 1] \\times [0, 1] \\subset \\mathbb{R}^2$.\n", "\n", "If you are looking at a static version of this notebook and would like to run its contents, head over to [GitHub](https://github.com/giotto-ai/giotto-tda/blob/master/examples/voids_on_the_plane.ipynb) and download the source.\n", "\n", "**License: AGPLv3**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import libraries" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from gtda.homology import VietorisRipsPersistence\n", "import itertools\n", "\n", "import matplotlib.pyplot as plt # Not a requirement of giotto-tda, but is needed here\n", "\n", "np.random.seed(1) # Set numpy's random seed" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Initialize the Vietoris–Rips transformer\n", "VR = VietorisRipsPersistence(homology_dimensions=(2,), max_edge_length=np.inf)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create n_samples point clouds of n_points points\n", "n_samples = 15000\n", "n_points = 6\n", "point_clouds = np.random.random((n_samples, n_points, 2))\n", "\n", "# Compute persistence diagrams of all point clouds\n", "diags = VR.fit_transform(point_clouds) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "diffs = np.nan_to_num(diags[:, :, 1] - diags[:, :, 0]) # Compute lifetimes\n", "indices = np.argwhere(diffs != 0) # Indices with non-zero lifetime\n", "print(f'There are {len(indices[:, 0])} persistent homology classes in dimension 2 across all samples.')\n", "print(f'There are {len(np.unique(indices[:, 0]))} different point clouds with at least one persistent homology class in dimension 2.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now plot the edges which exist when these persistent homology classes are born.\n", "What do the clique complexes of the resulting graphs remind you of?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in indices[:, 0]:\n", " for e in itertools.combinations(point_clouds[i], 2):\n", " if np.linalg.norm(e[0] - e[1]) < diags[i, 0, 1] - 0.00001:\n", " edge = np.stack([e[0], e[1]])\n", " plt.plot(edge[:, 0], edge[:, 1])\n", " plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.1" } }, "nbformat": 4, "nbformat_minor": 4 }