Submatrix Index Tool

A common pain point in computational homological algebra is passing between matrix and integer indices for boundary and other matrices. OAT offers a oat_python.core.vietoris_rips.SubmatrixIndexTool to help wth this.

See also

See the Sparse Matrices gallery for more examples!

Setup

import oat_python as oat

from fractions import Fraction
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from scipy.sparse import csr_matrix

Generate a point cloud

points               =   oat.point_cloud.sphere_or_slice(n_points=100)

Plot the point cloud

trace               =   go.Scatter3d(x=points[:,0],y=points[:,1],z=points[:,2], mode="markers", marker=dict(opacity=1, size=4, color=points[:,2], colorscale="Aggrnyl"))
fig                 =   go.Figure(data=trace)
fig.update_layout(title=dict(text="Point cloud"), height=800,width=850)
fig


Compute persistent homology

We compute persistent homology by factoring the boundary matrix. The following cell generates a sparse distance matrix and feeds it to the persistent homology solver. The result is a decomposition boundary matrix. We will extract information from this matrix in the following cells.

Prepare a dissimilarity matrix

dissimilarity_matrix    =   oat.dissimilarity.sparse_matrix_for_points(
                                points                   =   points,
                                max_dissimilarity        =   0.5,
                            )

Create and decompose the boundary matrix

decomposition           =   oat.core.vietoris_rips.BoundaryMatrixDecomposition(
                                dissimilarity_matrix    =   dissimilarity_matrix,
                                max_homology_dimension  =   1,
                            )

Access indices

Create a oat_python.core.vietoris_rips.SubmatrixIndexTool whose rows and columns are the vertices and edges of the Vietoris-Rips complex, respectively.

submatrix_index_tool    =   decomposition.submatrix_index_tool(
                                row_dimensions      =   [0,],
                                column_dimensions   =   [1,]
                            )
submatrix_index_tool
<SubmatrixIndexTool: 100 row indices, 292 column indices>

The number of row and column indices can be accessed via lookup functions:

submatrix_index_tool.number_of_rows()
100
submatrix_index_tool.number_of_columns()
292

The (ordered) lists of row and column indices can also be exported to dataframe format, for inspection:

oat.plot.display_dataframes_side_by_side(
    submatrix_index_tool.row_indices()[:5],
    submatrix_index_tool.column_indices()[:5],
    titles=["Row indices (vertices)","Column indices (edges)"]
)

Row indices (vertices)

simplex filtration
0 (0,) 0.0
1 (1,) 0.0
2 (2,) 0.0
3 (3,) 0.0
4 (4,) 0.0

Column indices (edges)

simplex filtration
0 (0, 1) 0.200000
1 (96, 99) 0.220606
2 (98, 99) 0.272721
3 (0, 2) 0.282843
4 (1, 4) 0.319210


Write a submatrix to CSR

A common task in data analysis is to export a submatrix of the boundary matrix into standard Python sparse matrix format, such as SciPy’s CSR. In order to do this, you have to specify which rows and columns you want, and in what order. The oat_python.core.vietoris_rips.SubmatrixIndexTool lets you specify these criteria exactly.

boundary_matrix         =   decomposition.boundary_matrix_oracle()
boundary_submatrix      =   boundary_matrix.write_submatrix_to_csr(
                                submatrix_index_tool
                            )
boundary_submatrix
<100x292 sparse matrix of type '<class 'numpy.float64'>'
    with 584 stored elements in Compressed Sparse Row format>
plt.figure(figsize=(6, 6))
plt.spy(boundary_submatrix, markersize=2, color="orange")
plt.title(r'Boundary Matrix ($\partial_1$)', y=-0.18)  # Move title to the bottom
plt.tight_layout()
Boundary Matrix ($\partial_1$)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_fontconfig_pattern.py:85: PyparsingDeprecationWarning: 'parseString' deprecated - use 'parse_string'
  parse = parser.parseString(pattern)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_fontconfig_pattern.py:89: PyparsingDeprecationWarning: 'resetCache' deprecated - use 'reset_cache'
  parser.resetCache()
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2010: PyparsingDeprecationWarning: 'oneOf' deprecated - use 'one_of'
  p.space          = oneOf(self._space_widths)("space")
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2012: PyparsingDeprecationWarning: 'oneOf' deprecated - use 'one_of'
  p.style_literal  = oneOf(
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2015: PyparsingDeprecationWarning: 'leaveWhitespace' deprecated - use 'leave_whitespace'
  p.symbol         = Regex(
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2024: PyparsingDeprecationWarning: 'oneOf' deprecated - use 'one_of'
  p.start_group    = Optional(r"\math" + oneOf(self._fontnames)("font")) + "{"
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2027: PyparsingDeprecationWarning: 'oneOf' deprecated - use 'one_of'
  p.delim          = oneOf(self._delims)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:1984: PyparsingDeprecationWarning: 'setName' deprecated - use 'set_name'
  val.setName(key)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:1987: PyparsingDeprecationWarning: 'setParseAction' deprecated - use 'set_parse_action'
  val.setParseAction(getattr(self, key))
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:1748: PyparsingDeprecationWarning: 'setParseAction' deprecated - use 'set_parse_action'
  return Empty().setParseAction(raise_error)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2088: PyparsingDeprecationWarning: 'endQuoteChar' argument is deprecated, use 'end_quote_char'
  p.text = cmd(r"\text", QuotedString('{', '\\', endQuoteChar="}"))
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2097: PyparsingDeprecationWarning: 'oneOf' deprecated - use 'one_of'
  + OneOrMore(oneOf(["_", "^"]) - p.placeable)("subsuper")
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2146: PyparsingDeprecationWarning: 'unquoteResults' argument is deprecated, use 'unquote_results'
  p.math_string   = QuotedString('$', '\\', unquoteResults=False)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2147: PyparsingDeprecationWarning: 'leaveWhitespace' deprecated - use 'leave_whitespace'
  p.non_math      = Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace()
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2170: PyparsingDeprecationWarning: 'parseString' deprecated - use 'parse_string'
  result = self._expression.parseString(s)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2197: PyparsingDeprecationWarning: 'parseString' deprecated - use 'parse_string'
  return self._math_expression.parseString(toks[0][1:-1], parseAll=True)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/pyparsing/util.py:466: PyparsingDeprecationWarning: 'parseAll' argument is deprecated, use 'parse_all'
  return fn(self, *args, **kwargs)
/home/docs/checkouts/readthedocs.org/user_builds/oat-python/envs/latest/lib/python3.9/site-packages/matplotlib/_mathtext.py:2178: PyparsingDeprecationWarning: 'resetCache' deprecated - use 'reset_cache'
  ParserElement.resetCache()

Change index types

Get a row vector from the CSR matrix

# Right now we have to convert row coefficients to fractions, but in the future this will be taken care of automatically
row_vector             =   boundary_submatrix[0].toarray().flatten()
row_vector             =   np.vectorize(Fraction.from_float)(row_vector)
row_vector[:10]
array([Fraction(-1, 1), Fraction(0, 1), Fraction(0, 1), Fraction(-1, 1),
       Fraction(0, 1), Fraction(0, 1), Fraction(0, 1), Fraction(0, 1),
       Fraction(0, 1), Fraction(0, 1)], dtype=object)

Convert integer indices to simplex indices:

chain                   =   submatrix_index_tool.row_vector_dataframe_for_dense_array(
                                row_vector
                            )
chain
simplex filtration coefficient
0 (0, 1) 0.200000 -1
1 (0, 2) 0.282843 -1
2 (0, 3) 0.346410 -1
3 (0, 4) 0.400000 -1
4 (0, 5) 0.447214 -1
5 (0, 6) 0.489898 -1


Total running time of the script: (0 minutes 0.228 seconds)

Gallery generated by Sphinx-Gallery