{
"cells": [
{
"cell_type": "markdown",
"id": "ada6ec81",
"metadata": {},
"source": [
"# Stratified spaces\n",
"\n",
"$\\textbf{Lead Author: Anna Calissano}$"
]
},
{
"cell_type": "markdown",
"id": "3af12b42",
"metadata": {},
"source": [
"Dear learner, \n",
"the aim of the current notebook is to introduce stratified spaces and its implementation within geomstats. "
]
},
{
"cell_type": "markdown",
"id": "4c0d7eda",
"metadata": {},
"source": [
"## Spider"
]
},
{
"cell_type": "markdown",
"id": "5c26e954",
"metadata": {},
"source": [
"The $k$-Spider consists of $k$ copies of the positive real line $\\mathbb{R}_{\\geq 0}$ glued together at the origin. Within geomstats, we defined the following:\n",
"1. Spider Point: a point object defining the ray and the value\n",
"2. Spider: the space defined by the number of rays\n",
"3. Spider Geometry: by chosing a metric on the rays, we can define a metric on the whole space"
]
},
{
"cell_type": "markdown",
"id": "eb5abd16",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "72158cdb",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Using numpy backend\n"
]
}
],
"source": [
"import geomstats.backend as gs\n",
"\n",
"from geomstats.geometry.stratified.spider import Spider\n",
"\n",
"gs.random.seed(2020)"
]
},
{
"cell_type": "markdown",
"id": "6dc7f1cd",
"metadata": {},
"source": [
"We can define a spider with $k=3$ rays (strata) and sample two points from it."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "85659a76",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spider = Spider(n_rays=3, equip=True)\n",
"\n",
"spider.n_rays"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "475990f8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[r0: 0.0, r0: 0.0]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spider_points = spider.random_point(n_samples=2)\n",
"\n",
"spider_points"
]
},
{
"cell_type": "markdown",
"id": "ac7750b6",
"metadata": {},
"source": [
"The points are represented into the SpiderPoint format, where the first input is the stratum and the second input is the value along the stratum."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f59ca8e4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"0.0\n"
]
}
],
"source": [
"print(spider_points[0].stratum)\n",
"print(spider_points[0].stratum_coord)"
]
},
{
"cell_type": "markdown",
"id": "b62044c5",
"metadata": {},
"source": [
"Given a metric $d_{rays}$ on the strata (the rays), we can extend it to the whole space by $$d_{Spider}(s_1,s_2)=d_{rays}(s_1,0) + d_{rays}(0,s_2)$$"
]
},
{
"cell_type": "markdown",
"id": "aeb317b1",
"metadata": {},
"source": [
"Given two points on the Spider, we can compute the distance between the two points as well as the geodesic between the two."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "a6126dd3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.0"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spider.metric.dist(spider_points[0], spider_points[1])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "7881d1da",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[r0: 0.0] [r0: 0.0] [r0: 0.0]\n"
]
}
],
"source": [
"spider_geodesic_func = spider.metric.geodesic(spider_points[0], spider_points[1])\n",
"\n",
"print(spider_geodesic_func(0), spider_geodesic_func(0.5), spider_geodesic_func(1))"
]
},
{
"cell_type": "markdown",
"id": "76023d66",
"metadata": {},
"source": [
"## Graph Space"
]
},
{
"cell_type": "markdown",
"id": "3358a89e",
"metadata": {},
"source": [
"Graph Space is a space defined to describe set of graphs with a finite number of nodes which can be both node labelled or node unlabelled. \n",
"\n",
"Inspired by: A. Calissano, A. Feragen, S. Vantini, Populations of unlabeled networks: Graph space geometry and geodesic principal components, MOX Report (2020)\n",
"\n",
"\n",
"We consider graphs as triples $G=(V,E,a)$, where the node set $V$ has at most $n$ elements, and the edge set $E \\subset V^2$ has maximal size \n",
"$n^2$. The nodes and edges are attributed with elements of an attribute space $A$, which is considered to be Euclidean, via an attribute \n",
"map $a \\colon E \\rightarrow A$. Here, the map $a$ allows us to describe attributes on both edges and nodes, as we use self loop edges (diagonal \n",
"elements in the graphs adjacency matrix) to assign attributes to nodes. \n",
"A graph with scalar attributes is completely specified by a weighted adjacency matrix of dimension $n\\times n$, residing in a space \n",
"$X=\\mathbb{R}^{n^2}$ of flattened adjacency matrices. If the attributes are vectors of dimension $d$, the graph is represented by a tensor of \n",
"dimension $n\\times n\\times d$, residing in a space $X=\\mathbb{R}^{n\\times n\\times d}$."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "8452b3d8",
"metadata": {},
"outputs": [],
"source": [
"import networkx as nx\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from geomstats.geometry.stratified.graph_space import GraphPoint, GraphSpace"
]
},
{
"cell_type": "markdown",
"id": "fa02c396",
"metadata": {},
"source": [
"### Graph\n",
"Consider a graph with $n=3$ nodes and $A=\\mathbb{R}$ scalar attributes on nodes and edges. The class Graph describe a single graph via its adjacency matrix."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "fd8f3042",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"array([[10, 3, 1],\n",
" [ 3, 2, 4],\n",
" [ 1, 4, 5]])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"adj = gs.array([[10,3,1],[3,2,4],[1,4,5]])\n",
"graph_point = GraphPoint(adj=adj)\n",
"\n",
"graph_point.adj"
]
},
{
"cell_type": "markdown",
"id": "0f89275b",
"metadata": {},
"source": [
"To simplify the visualization and the access to different methods, the Graph object can be turned into a networkx graph."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "edee3873",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"