{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Steenrod barcode of a filtration of $\\mathbb RP^2$\n",
"\n",
"In this notebook we use ``steenroder`` to computing the Steenrod barcode of a small filtration.\n",
"We will assume familiarity with the content of the notebook *barcode* where it is explained how the barcode of persistent relative cohomology and persistent cocycle representatives are computed by ``steenroder``.\n",
"\n",
"The filtered complex $X$ that we consider is the following model for the real projective plane\n",
"\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:46:36.040092Z",
"iopub.status.busy": "2022-05-29T19:46:36.039776Z",
"iopub.status.idle": "2022-05-29T19:46:36.050224Z",
"shell.execute_reply": "2022-05-29T19:46:36.049597Z"
}
},
"outputs": [],
"source": [
"rp2 = (\n",
" (0,),\n",
" (1,), (0,1),\n",
" (2,), (0,2), (1,2), (0,1,2),\n",
" (3,), (0,3), (1,3), (0,1,3), (2,3),\n",
" (4,), (0,4), (1,4), (2,4), (1,2,4), (3,4), (0,3,4), (2,3,4),\n",
" (5,), (0,5), (1,5), (2,5), (0,2,5), (3,5), (1,3,5), (2,3,5), (4,5), (0,4,5), (1,4,5)\n",
" )\n",
"\n",
"filtration = rp2\n",
"maxdim = max(map(len, filtration)) - 1\n",
"m = len(filtration) - 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## What will be computed\n",
"\n",
"### Relative cohomology\n",
"\n",
"We will consider the persistent relative cohomology of $X$\n",
"\n",
"$$\n",
"H^\\bullet(X) \\leftarrow H^\\bullet(X, X_{0}) \\leftarrow H^\\bullet(X, X_{1}) \\leftarrow \\cdots \\leftarrow H^\\bullet(X, X_{m})\n",
"$$\n",
"as a persistence module.\n",
"\n",
"### Regular barcode\n",
"\n",
"For $i < j \\in \\{-1,\\dots,m\\}$ let $X_{ij}$ be the unique composition $H^\\bullet(X, X_{i}) \\leftarrow H^\\bullet(X, X_{j})$ with the convention $X_{-1} = \\emptyset$.\n",
"The barcode of this persistence module is the multiset\n",
"\n",
"$$\n",
"Bar_X =\n",
"\\big\\{ [p,q] \\mid -1 \\le p < q \\le m \\big\\}\n",
"$$\n",
"\n",
"defined by the property\n",
"\n",
"$$\n",
"\\mathrm{rank} \\, X_{ij} =\n",
"\\mathrm{card} \\big\\{[p,q] \\in Bar_X \\mid p \\le i < j \\le q \\big\\}.\n",
"$$\n",
"\n",
"### Steenrod barcode\n",
"\n",
"Since the cohomology operation $Sq^k$ is natural, we obtain an endomorphism of persistent relative cohomology\n",
"\n",
"\\begin{align*}\n",
"&H^\\bullet(X) \\leftarrow \\cdots \\leftarrow H^\\bullet(X, X_{m}) \\\\\n",
"& {\\tiny Sq^k} \\uparrow \\kern 2.5cm {\\tiny Sq^k} \\uparrow\\\\\n",
"&H^\\bullet(X) \\leftarrow \\cdots \\leftarrow H^\\bullet(X, X_{m}).\n",
"\\end{align*}\n",
"\n",
"The $Sq^k$-barcode of $X$ is the barcode of the image persistent module of this endomorphism.\n",
"\n",
"Let us now compute these invariants using `steenroder`.\n",
"We remark that since there is a compilation step required, the first time this function is run takes a bit long."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:46:36.053295Z",
"iopub.status.busy": "2022-05-29T19:46:36.052929Z",
"iopub.status.idle": "2022-05-29T19:47:12.166750Z",
"shell.execute_reply": "2022-05-29T19:47:12.165368Z"
}
},
"outputs": [],
"source": [
"from steenroder import barcodes\n",
"\n",
"k = 1\n",
"barcode, steenrod_barcode = barcodes(k, filtration)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For each dimension ``d`` each of these is a 2D int array of shape ``(n_bars, 2)`` containing the bars of persistent relative cohomology and of the image of $Sq^k$ in degree ``d``.\n",
"Let us inspect this output."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:12.170251Z",
"iopub.status.busy": "2022-05-29T19:47:12.169735Z",
"iopub.status.idle": "2022-05-29T19:47:12.175182Z",
"shell.execute_reply": "2022-05-29T19:47:12.174636Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Persistent relative cohomology:\n",
"Regular barcode:\n",
"dim 0:[[-1, 0]]\n",
"dim 1:[[20, 21], [12, 13], [-1, 11], [7, 8], [3, 4], [1, 2]]\n",
"dim 2:[[-1, 30], [28, 29], [22, 27], [25, 26], [23, 24], [14, 19], [17, 18], [15, 16], [9, 10], [5, 6]]\n",
"Sq^1-barcode:\n",
"dim 0:[]\n",
"dim 1:[]\n",
"dim 2:[[-1 11]]\n"
]
}
],
"source": [
"print('Persistent relative cohomology:')\n",
"\n",
"print('Regular barcode:')\n",
"for d in range(maxdim + 1):\n",
" print(f'dim {d}:{list(map(list, barcode[d]))}')\n",
" \n",
"print(f'Sq^{k}-barcode:')\n",
"for d in range(maxdim + 1):\n",
" print(f'dim {d}:{steenrod_barcode[d]}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are three infinite bars in the regular barcode\n",
"[-1,0] in deg 0,\n",
"[-1,11] in deg 1,\n",
"[-1,30] in deg 2.\n",
"Additionally, there is one $Sq^1$-bar\n",
"[-1,11] in deg 2.\n",
"This $Sq^1$-bar witnesses in the persistent context the non-trivial relationship $Sq^1 [\\alpha_1] = [\\alpha_2]$ between the degree 1 and 2 generators of the cohomology of $\\mathbb R P^2$."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## How this is computed\n",
"\n",
"We will now describe an effective computation of the $Sq^k$-barcode of persistent relative cohomology bulding on the computation of regular barcodes and persistent cocycle representatives.\n",
"We refer to the notebook *barcode* where more details about this computation are given.\n",
"Recall that the $Sq^k$-barcode is by definition the barcode of the image persistent module of the endomorphism $Sq^k$.\n",
"\n",
"### The $R = D^\\perp V$ decomposition\n",
"\n",
"Let $D$ be the boundary matrix of the filtration with respect to the ordered basis of simplices and $D^\\perp$ its antitransposed:\n",
"\n",
"$$\n",
"D^\\perp_{p,\\, q} = D_{\\overline q,\\ \\overline p}\n",
"$$\n",
"where $\\overline j = m-j$ for $j \\in \\{0,\\dots,m\\}$.\n",
"\n",
"Let us consider the unique decomposition $R = D^\\perp V$ where $V$ is an invertible upper triangular matrix and $R$ is reduced, i.e., no two columns have the same pivot row.\n",
"\n",
"### The regular barcode\n",
"\n",
"Denoting the $i$-th column of $R$ by $R_{i}$ where $i \\in \\{0,\\dots,m\\}$, let\n",
"\n",
"$$\n",
"P = \\{ i \\ |\\ R_i = 0\\}, \\qquad N = \\{ i \\ |\\ R_i \\neq 0\\}, \\qquad E = P \\setminus \\{\\text{pivots of } R\\}.\n",
"$$\n",
"\n",
"There exists a canonical bijection between the union of $N$ and $E$ and the persistence relative cohomology barcode of the filtration given by\n",
"\n",
"\\begin{align*}\n",
"N \\ni j &\\mapsto \\Big[\\, \\overline j, \\overline{\\mathrm{pivot}\\,R_j}\\, \\Big] \\in Bar^{\\dim(j)+1}_X \\\\\n",
"E \\ni j &\\mapsto \\big[\\! -1, \\overline j \\,\\big] \\in Bar^{\\dim(j)}_X\n",
"\\end{align*}\n",
"\n",
"### Representatives\n",
"\n",
"Additionally, a persistent cocycle representative for each bar is given by\n",
"\\begin{equation*}\n",
"[i,j] \\mapsto\n",
"\\begin{cases}\n",
"V_{\\overline j}, & i = -1, \\\\\n",
"R_{\\overline i}, & i \\neq -1.\n",
"\\end{cases}\n",
"\\end{equation*}\n",
"More specifically, a basis for $H^\\bullet(X, X_{\\overline j-1})$ thought of as a subspace in the direct sum\n",
"\n",
"$$\n",
"\\ker \\delta = \\mathrm{img}\\, \\delta \\oplus H^\\bullet(X, X_{\\overline j-1}; \\Bbbk),\n",
"$$\n",
"\n",
"is given by the set of cochains corresponding to the vectors in the union of\n",
"\n",
"$$\n",
"\\big\\{R_k \\mid k \\in N,\\, j < \\mathrm{pivot}(R_k)\\big\\}\n",
"\\quad \\text{and} \\quad\n",
"\\{V_i \\mid i \\in E,\\, i \\leq j\\},\n",
"$$\n",
"\n",
"and a basis for $\\mathrm{img} \\delta$ is given by\n",
"$$\n",
"\\{R_i \\mid i \\in N,\\, i \\leq j\\}.\n",
"$$\n",
"\n",
"and a basis of coboundaries in $C^\\bullet(X, X_{\\overline j})$ corresponds to non-zero vectors in\n",
"\n",
"\\begin{equation*}\n",
"\\{R_i\\ |\\ i \\in N,\\, i \\leq j\\}.\n",
"\\end{equation*}\n",
"\n",
"### Steenrod representatives\n",
"\n",
"Given vector $v$ corresponding to a cocycle $\\alpha$, let $\\mathtt{sq^k}(v)$ be the vector correponding to cocycle representative of $Sq^k \\big( [\\alpha] \\big)$.\n",
"For example, the one obtained using the following pseudo-code, where $A$ is the support of $\\alpha$.\n",
"\n",
"
\n",
"\n",
"### Steenrod matrix\n",
"\n",
"Identifying a vector with the support of its associated cochain, define $Q^k$ to be the matrix whose columns are given by\n",
"\n",
"\\begin{equation*}\n",
"Q^k_i = \\begin{cases}\n",
"\\mathtt{sq^k}(V_i), & i \\in E, \\\\\n",
"\\mathtt{sq^k}(R_j), & i = pivot(R_j), \\\\\n",
"0, & otherwise.\n",
"\\end{cases}\n",
"\\end{equation*}\n",
"\n",
"### Reduction\n",
"\n",
"Given $R$ and $Q^k$, we denote by $R_{\\le j}$ and $Q^k_{\\le j}$ the submatrices containing all columns with indices less than or equal to $j$, and $R_{\\le j} \\mid Q^k_{\\le j}$ the matrix obtained by concatenating their columns.\n",
"With this notation the following pseudo-code computes the $k$-Steenrod barcode of the filtration.\n",
"\n",
"
\n",
"\n",
"Intuitively, the step from $j-1$ to $j$ either adds a new non-zero coboundary $R_j$ (which implies $Q^k_j = 0$) or the image $Q^k_j$ of a persistent cocycle generator (which implies $R_j=0$).\n",
"In either case, we need to reduce with respect to the subspace of coboundaries, generated by $R_{\\leq j}$, the image of $Sq^k$, which is generated by $Q^k_{\\leq j}$.\n",
"This process is done keeping track of when columns in $Q^k$ become zero and extracting from this information the $Sq^k$-barcode of the filtration."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using ``steenroder``\n",
"\n",
"Let us start by using the following functions explained in more detail in the notebook *barcode*."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:12.177843Z",
"iopub.status.busy": "2022-05-29T19:47:12.177396Z",
"iopub.status.idle": "2022-05-29T19:47:13.670342Z",
"shell.execute_reply": "2022-05-29T19:47:13.669521Z"
}
},
"outputs": [],
"source": [
"from steenroder import sort_filtration_by_dim, compute_reduced_triangular, compute_barcode_and_coho_reps\n",
"\n",
"filtration_by_dim = sort_filtration_by_dim(filtration)\n",
"spx2idx, idxs, reduced, triangular = compute_reduced_triangular(filtration_by_dim)\n",
"barcode, coho_reps = compute_barcode_and_coho_reps(idxs, reduced, triangular)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Algorithm 1\n",
"\n",
"Using an implementation of Algorithm 1, ``steenroder`` constructs the Steenrod matrix using the method ``compute_steenrod_matrix``.\n",
"Its output is a list of ``numba.typed.List``, one list per simplex dimension.\n",
"Explicitly, ``steenrod_matrix[d][j]`` entry is the result of computing the Steenrod square of ``coho_reps[d][j]``.\n",
"\n",
"Since we are studying $Sq^k\\big([\\alpha]\\big)$ for $k=1$ we concentarte on classes $[\\alpha]$ of degree $1$ since $Sq^1\\big([\\alpha]\\big) = 0$ otherwise."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.673978Z",
"iopub.status.busy": "2022-05-29T19:47:13.673545Z",
"iopub.status.idle": "2022-05-29T19:47:13.791616Z",
"shell.execute_reply": "2022-05-29T19:47:13.790702Z"
},
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bar : Cocycle --> Sq^1-cocycle:\n",
"[20 21] : {(1, 5), (4, 5), (0, 5), (2, 5), (3, 5)} --> []\n",
"[12 13] : {(2, 4), (0, 4), (3, 4), (1, 4), (4, 5)} --> [(0, 4, 5), (1, 4, 5)]\n",
"[-1 11] : {(2, 4), (1, 5), (1, 4), (2, 3), (3, 5)} --> [(2, 3, 5)]\n",
"[7 8] : {(3, 4), (0, 3), (2, 3), (1, 3), (3, 5)} --> [(0, 3, 4), (2, 3, 4), (1, 3, 5), (2, 3, 5)]\n",
"[3 4] : {(2, 4), (1, 2), (2, 3), (0, 2), (2, 5)} --> [(1, 2, 4), (0, 2, 5)]\n",
"[1 2] : {(0, 1), (1, 2), (1, 5), (1, 4), (1, 3)} --> [(0, 1, 2), (0, 1, 3)]\n"
]
}
],
"source": [
"from steenroder import compute_steenrod_matrix\n",
"\n",
"k = 1\n",
"steenrod_matrix = compute_steenrod_matrix(k, coho_reps, filtration_by_dim, spx2idx)\n",
"\n",
"d = 1\n",
"print(f'Bar : Cocycle --> Sq^{k}-cocycle:')\n",
"for bar, coho_rep, st_coho_rep in zip(barcode[d], coho_reps[d], steenrod_matrix[d+1]):\n",
" cocycle = []\n",
" for p in coho_rep:\n",
" cocycle.append(filtration[idxs[d][p]])\n",
" st_cocycle = []\n",
" for p in st_coho_rep:\n",
" st_cocycle.append(filtration[idxs[d+1][p]])\n",
" print(f'{str(bar): <7} : {set(cocycle)} --> {st_cocycle}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will compare these representatives with those produced by a more explicit implementation of Algorithm 1."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.794969Z",
"iopub.status.busy": "2022-05-29T19:47:13.794524Z",
"iopub.status.idle": "2022-05-29T19:47:13.802934Z",
"shell.execute_reply": "2022-05-29T19:47:13.802191Z"
}
},
"outputs": [],
"source": [
"from itertools import combinations\n",
"\n",
"def sq(k, cocycle, filtration):\n",
" '''Return a cocycle representative of the image of Sq^k applied to the class represented by the given cocycle'''\n",
" st_cocycle = set()\n",
" for pair in combinations(cocycle, 2):\n",
" a, b = set(pair[0]), set(pair[1])\n",
" if (len(a.union(b)) == len(a) + k and\n",
" tuple(sorted(a.union(b))) in filtration):\n",
" a_bar, b_bar = a.difference(b), b.difference(a)\n",
" index = dict()\n",
" for v in a_bar.union(b_bar):\n",
" pos = sorted(a.union(b)).index(v)\n",
" pos_bar = sorted(a_bar.union(b_bar)).index(v)\n",
" index[v] = (pos + pos_bar) % 2\n",
" index_a = {index[v] for v in a_bar}\n",
" index_b = {index[w] for w in b_bar}\n",
" if (index_a == {0} and index_b == {1}\n",
" or index_a == {1} and index_b == {0}):\n",
" u = sorted(a.union(b))\n",
" st_cocycle ^= {tuple(u)}\n",
" return st_cocycle"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us not compute cocycle representatives generating the image of $Sq^k$."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.806073Z",
"iopub.status.busy": "2022-05-29T19:47:13.805388Z",
"iopub.status.idle": "2022-05-29T19:47:13.812346Z",
"shell.execute_reply": "2022-05-29T19:47:13.811514Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cocycle --> Sq^1-cocycle:\n",
"{(1, 5), (4, 5), (0, 5), (2, 5), (3, 5)} --> set()\n",
"{(2, 4), (0, 4), (3, 4), (1, 4), (4, 5)} --> {(1, 4, 5), (0, 4, 5)}\n",
"{(2, 4), (1, 5), (1, 4), (2, 3), (3, 5)} --> {(2, 3, 5)}\n",
"{(3, 4), (0, 3), (2, 3), (1, 3), (3, 5)} --> {(0, 3, 4), (2, 3, 4), (2, 3, 5), (1, 3, 5)}\n",
"{(2, 4), (1, 2), (2, 3), (0, 2), (2, 5)} --> {(1, 2, 4), (0, 2, 5)}\n",
"{(0, 1), (1, 2), (1, 5), (1, 4), (1, 3)} --> {(0, 1, 2), (0, 1, 3)}\n"
]
}
],
"source": [
"d = 1\n",
"print(f'Cocycle --> Sq^{k}-cocycle:')\n",
"for coho_rep in coho_reps[d]:\n",
" cocycle = []\n",
" for p in coho_rep:\n",
" cocycle.append(filtration[idxs[d][p]])\n",
" st_cocycle = sq(k, cocycle, filtration)\n",
" print(f'{set(cocycle)} --> {st_cocycle}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Algorithm 2\n",
"\n",
"It is carried through in `compute_steenrod_barcode`, whose output is the $Sq^k$-barcode of the filtration."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.817376Z",
"iopub.status.busy": "2022-05-29T19:47:13.816980Z",
"iopub.status.idle": "2022-05-29T19:47:13.827410Z",
"shell.execute_reply": "2022-05-29T19:47:13.826860Z"
},
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"array([[-1, 11]])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from steenroder import compute_steenrod_barcode\n",
"\n",
"dd = d + k\n",
"steenrod_barcode = compute_steenrod_barcode(k, steenrod_matrix, idxs, reduced, barcode)\n",
"steenrod_barcode[dd]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will compare this output to an explicit construction obtained by implementing the above algorithms.\n",
"Let us start by representing the matrix $Q$ and $R$ as instances of `np.array`.\n",
"Recall that `steenroder` indexes everything with respect to the order of the original filtration, so we need to apply the transformation $(p,q) \\mapsto (m-p, m-q)$ to the entries of the (sparse) matrices it produces."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.830115Z",
"iopub.status.busy": "2022-05-29T19:47:13.829708Z",
"iopub.status.idle": "2022-05-29T19:47:13.837446Z",
"shell.execute_reply": "2022-05-29T19:47:13.836792Z"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"\n",
"antiQ = np.zeros((m+1,m+1), dtype=int)\n",
"for d in range(maxdim-k+1):\n",
" for bar, col in zip(barcode[d], steenrod_matrix[d+k]):\n",
" for p in col:\n",
" antiQ[idxs[d+k][p], bar[1]] = 1\n",
"Q = np.flip(antiQ, [0,1])\n",
"\n",
"antiR = np.zeros((m+1,m+1), dtype=int)\n",
"for d in range(maxdim+1):\n",
" for i, col in enumerate(reduced[d]):\n",
" for j in col:\n",
" antiR[idxs[d+1][j], idxs[d][i]] = 1\n",
"R = np.flip(antiR, [0,1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Before introducing an implementation of Algorithm 2 we need some auxiliary functions:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.840730Z",
"iopub.status.busy": "2022-05-29T19:47:13.840094Z",
"iopub.status.idle": "2022-05-29T19:47:13.847906Z",
"shell.execute_reply": "2022-05-29T19:47:13.847266Z"
}
},
"outputs": [],
"source": [
"def pivot(column):\n",
" \"\"\"Returns the index of the largest non-zero entry of the column or None if all entries are 0\"\"\"\n",
" try:\n",
" return max(column.nonzero()[0])\n",
" except ValueError:\n",
" return None\n",
"\n",
"def reduce_vector(reduced, column):\n",
" \"\"\"Reduces a column with respect to a reduced matrix with the same number of rows\"\"\"\n",
" num_col = reduced.shape[1]\n",
" i = -1\n",
" while i >= -num_col:\n",
" if not np.any(column):\n",
" break\n",
" else:\n",
" piv_v = pivot(column)\n",
" piv_i = pivot(reduced[:, i])\n",
"\n",
" if piv_i == piv_v:\n",
" column[:, 0] = np.logical_xor(reduced[:, i], column[:, 0])\n",
" i = 0\n",
" i -= 1\n",
"\n",
"def reduce_matrix(reduced, matrix):\n",
" \"\"\"Reduces a matrix with respect to a reduced matrix with the same number of rows\"\"\"\n",
" num_vector = matrix.shape[1]\n",
" reducing = reduced.copy()\n",
"\n",
" for i in range(num_vector):\n",
" reduce_vector(reducing, matrix[:, i:i+1])\n",
" reducing = np.concatenate([reducing, matrix[:, i:i+1]], axis=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We now define a function implementing Algorithm 2.\n",
"Using it we obtain the same Steenrod barcode as the one produced by `steenroder`."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"execution": {
"iopub.execute_input": "2022-05-29T19:47:13.850975Z",
"iopub.status.busy": "2022-05-29T19:47:13.850515Z",
"iopub.status.idle": "2022-05-29T19:47:13.880240Z",
"shell.execute_reply": "2022-05-29T19:47:13.879585Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"[[-1, 11]]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def get_steenrod_barcode(R, Q):\n",
" \"\"\"Returns the Steenrod barcodes implementing Algorithm 2\"\"\"\n",
" m = R.shape[1]-1\n",
" alive = {i: True for i in range(m)}\n",
" steenrod_barcode = []\n",
" for j in range(m):\n",
" reduce_matrix(R[:,:j+1], Q[:,:j+1])\n",
" for i in range(j+1):\n",
" if alive[i] and not np.any(Q[:,i]):\n",
" alive[i] = False\n",
" if j > i:\n",
" steenrod_barcode.append([m-j, m-i])\n",
" steenrod_barcode += [[-1,m-i] for i in alive if alive[i]]\n",
" return steenrod_barcode\n",
"\n",
"get_steenrod_barcode(R, Q)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### To-Do\n",
"\n",
"duality and truncations"
]
}
],
"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.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}