Install

Python users Can install oat_python through PyPI using any package manager, for example pip install oat_python, conda_install oat_python, etc.

Developers Everyone is a developer, and everyone is invited to modify and extend the source code for this package! oat_python is a combination of Rust and Python code. We developed oat_python using PyO3 and maturin. To download and modify oat_python, then install and use the modified version, check out the github repository.

API

Homology

Vietoris Rips

The oat_python.core.vietoris_rips module provides tools to work with Vietoris-Rips complexes.

It can be used to

  • compute persistent homology

  • access rows and columns of a boundary matrix

  • obtain the (co)boundary of a linear combination of simplices

and more!

class oat_python.core.vietoris_rips.BoundaryMatrix(dissimilarity_matrix)

Bases: object

A matrix oracle for the boundary matrix of a Vietoris-Rips complex

This object provides methods to compute

  • rows, columns, and entries of the boundary matrix

  • the boundary of a chain

  • the coboundary of a cochain

boundary_for_chain(chain)

Returns the boundary of a chain

# Input

The input, chain, should be formatted as Pandas data frame with columns simplex and coefficient.

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2)

  • Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2)

  • Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

coboundary_for_cochain(cochain)

Returns the coboundary of a cochain

# Input

The input, cochain, should be formatted as Pandas data frame with columns simplex and coefficient.

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2)

  • Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2)

  • Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

column_for_simplex(simplex)

Returns the column of the matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

# Errors

Returns an error if the simplex is not contained in the Vietoris-Rips complex.

entry_for_row_and_column(row_simplex, column_simplex)

Returns the entry coefficient for the given row and column simplices

# Input

The inputs, row_simplex and column_simplex, should be strictly sorted lists or tuples of integers, e.g. (0,1,2).

# Output

The output is a Python Fraction

# Errors

Returns an error if one of the inputs is not a simplex contained in the Vietoris-Rips complex.

row_for_simplex(simplex)

Returns the row of the matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

# Errors

Returns an error if the simplex is not contained in the Vietoris-Rips complex.

write_submatrix_to_csr(submatrix_index_tool)

Writes a submatrix to a Scipy CSR sparse matrix

# Arguments

  • submatrix_index_tool: a SubmatrixIndexTool object containing the row and column indices of the submatrix

# Returns

A scipy.sparse.csr_matrix, or an error if the row or column indices are not valid in the input matrix. The k`th row of the submatrix corresponds to the `k`th row of the `submatrix_index_tool, and similarly for columns.

Note The coefficients of the matrix are stores as floats, because SciPy offers very limited support for rational numbers.

class oat_python.core.vietoris_rips.BoundaryMatrixDecomposition(dissimilarity_matrix, max_homology_dimension=None, support_fast_column_lookup=None)

Bases: object

A differential umatch decomposition of the boundary matrix of a Vietoris-Rips complex (up to dimension d)

This object stores a minimmal number of matrix entries needed to rapidly compute any row, column, or entry of a differential umatch decomposition \((J,M,D,J)\), corresponding to matrix equation \(JM = DJ\), where \(D\) is

  • the submatrix of the boundary matrix of the Vietoris-Rips complex, containing only simplices of dimension <= d

  • rows and columns of \(D\) are ordered first by dimension, then by filtration value, then lexicographically

# Arguments

  • dissimilarity_matrix: a sparse dissimilarity matrix stored as a Scipy sparse CSR - this matrix must be symmetric - missing entries will be treated as edges that never enter the filtration - Diagonal entries will be treated as vertex birth times. That is, dissimilarity_matrix[i,i] is regarded as the filtration parameter of vertex i. If dissimilarity_matrix[i,i] is structurally zero then vertex i is not included in the filtration. If row i contains any structural nonzero entry, then entry (i,i) must be structurally nonzero, and the smallest of all structural nonzero entries in that row

  • max_homology_dimension: the maximum dimension for which homology is desired - Defaults to 1.

  • support_fast_column_lookup: if True, then the decomposition will be optimized for efficient access to the columns of J. This also accelerates computation of cycle representatives and bounding chains in persistent homology.

    • Defaults to True. However, if this argument is set to False, then the user can still obtain a copy optimized for column access later by calling decomposition.column_major(), which is an out-of-place operation.

    • Requires (modest) extra computation. The optimization for fast column lookup is a post-processing step which can be added to the regular computation. Typically this post-processing step requires less time and memory than the initial decomposition. If the user wishes to compute a basis of cycle representatives for persistent homology, it is typically effective to pay this cost up front, because computation of cycle representatives will be much faster.

    • Changes J. Performing this post-processing step will typically change the matrix J. In many applications, it will make J sparser; in experiments with random point clouds, for example, J typically loses around two thirds of its nonzero entries. However, both versions of J are valid.

# Panics

Panics if

  • dissimilarity_matrix is not symmetric

  • there exists an i such that entry [i,i] is not explicitly stored, but some other entry in row i is explicitly stored. this is because we regard missing entries as having infinite value, rather than zero.

  • there exists an i such that entry [i,i] is strictly greater than some other entry in row i

antitranspose_umatch_test()

A helper function used for profiling.

boundary_for_chain(chain)

Returns the boundary of a chain

# Input

The input, chain, should be formatted as Pandas data frame with columns simplex and coefficient.

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2)

  • Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2)

  • Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

boundary_matrix_as_csr()

Returns the boundary matrix of the Vietoris-Rips complex, formatted as a scipy.sparse.csr_matrix sparse matrix

The ith row/column of this matrix corresponds to the ith simplex in self.boundary_matrix_indices(). See the documentation of that function for details.

boundary_matrix_indices_df()

Returns a set of row/column indices of the filtered boundary matrix, in sorted order

The indices include

  • every simplex of dimension <= d, and

  • every death (a.k.a. negative) simplex of dimension d+1

where d is the max homology dimension specified by the user when factoring the boundary matrix.

The result is a dataframe with columns simplex and filtration.

boundary_matrix_oracle()

Returns a matrix oracle for the boundary matrix

This oracle is lazy; it stores only a reference to the underlying weighted graph, and generates entries, rows, and columns on demand.

boundary_space_indices()

Returns the indices of the nonzero columns of the generalized matching matrix in the Umatch decomposition

These are commonly known as the “negative simplices” in persistent homology literature.

Output is a Pandas dataframe with columns simplex and filtration.

change_of_basis_matrix_inverse_oracle()

Returns a matrix oracle for the inverse differential COBM of the decomposition

This oracle represents the matrix J^{-1} in the differential umatch decomposition (J,M,D,J), corresponding to the Umatch equation JM = DJ.

This object stores only two pieces of data: (1) the maximum homology dimension for which the Umatch decomposition is valid, and (2) a reference to the decomposition itself. Therefore is uses almost no memory.

change_of_basis_matrix_oracle()

Returns a matrix oracle for the differential COBM of the decomposition

This oracle represents the matrix J in the differential umatch decomposition (J,M,D,J), corresponding to the Umatch equation JM = DJ.

This object stores only two pieces of data: (1) the maximum homology dimension for which the Umatch decomposition is valid, and (2) a reference to the decomposition itself. Therefore is uses almost no memory.

coboundary_for_cochain(cochain)

Returns the coboundary of a cochain

# Input

The input, cochain, should be formatted as Pandas data frame with columns simplex and coefficient.

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2)

  • Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2)

  • Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

coboundary_space_indices()

Returns the indices of the nonzero rows of the generalized matching matrix

These are commonly known as the “negative simplices” in persistent cohomology

Output is a Pandas dataframe with columns simplex and filtration.

cocycle_indices()

Returns the indices of the zero rows of the generalized matching matrix

These are commonly known as the “positive simplices” in persistent cohomology

Output is a Pandas dataframe with columns simplex and filtration.

column_major()

Returns a column-major version of the differential Umatch decomposition

  • Out of place operation (if self is already column-major, then a copy of self is returned)

  • This version typically has a different differential COMB J.

  • There is a modest computational cost to obtaining the column-major version, but it is typically smaller than the time and memory cost of computing the original version, and

  • The column-major version is often enables substantial performance gains for computing cycle representatives and bounding chains in persistent homology. (Indeed, any lookup operations for the columns of the differential COMB in general).

  • By contrast, the original version is often more efficient for computing rows of the inverse differential COMB, which is used for computing cocycles representatives and bounding chains in persistent cohomology.

cycle_indices()

Returns the indices of the zero-columns of the generalized matching matrix

These are commonly known as the “positive simplices” in persistent homology literature.

Output is a Pandas dataframe with columns simplex and filtration.

differential_comb_as_csr()

Returns the differential COBM J of a [differential Umatch decomposition](oat_rust::algebra::matrices::operations::umatch::differential) JM = DJ.

  • D stands for the differential matrix (aka boundary matrix) returned by self.boundary_matrix_as_csr().

  • The ith row/column of each matrix (J, M, D) corresponds to the ith simplex in self.boundary_matrix_indices().

  • J is returned as a scipy.sparse.csr_matrix sparse matrix

differential_comb_inverse_as_csr()

Returns the inverse of the differential COBM J of a [differential Umatch decomposition](oat_rust::algebra::matrices::operations::umatch::differential) JM = DJ.

  • D stands for the differential matrix (aka boundary matrix) returned by self.boundary_matrix_as_csr().

  • The ith row/column of each matrix (J, M, D) corresponds to the ith simplex in self.boundary_matrix_indices().

  • Jinv is returned as a scipy.sparse.csr_matrix sparse matrix

dissimilarity_matrix()

Returns a copy of the dissimilarity matrix used to construct the Vietoris-Rips complex

escolar_hiraoka_indices_df(birth_simplex)

Returns the Escolar-Hiraoka indices of a persistent cycle.

The result is a dataframe with columns simplex and filtration.

generalized_matching_matrix_as_csr()

Returns the generalized matching matrix M of a [differential Umatch decomposition](oat_rust::algebra::matrices::operations::umatch::differential) JM = DJ.

  • D stands for the differential matrix (aka boundary matrix) returned by self.boundary_matrix_csmat_base().

  • The ith row/column of each matrix (J, M, D) corresponds to the ith simplex in self.boundary_matrix_indices().

  • M is returned as a [CsMatBase] sparse matrix

generalized_matching_matrix_oracle()

Returns a matrix oracle for the generalized matching matrix of the decomposition

This oracle represents the matrix M in the differential umatch decomposition (J,M,D,J), corresponding to the Umatch equation JM = DJ.

This object stores only two pieces of data: (1) the maximum homology dimension for which the Umatch decomposition is valid, and (2) a reference to the decomposition itself. Therefore is uses almost no memory.

is_column_major()

Returns True if this decomposition is column-major, False otherwise.

max_homology_dimension()

Returns the maximum homology dimension for which this decomposition is valid

This value is determined by the user via the keyword argument max_homology_dimension when constructing the decomposition.

optimize_bounding_chain(birth_simplex, verbose=True)

Finds a chain c whose boundary is the cycle representative of birth_simplex, such that the l1 norm of c is as small as possible

optimize_bounding_chain_kernel(birth_simplex, problem_type)

Minimize a bounding chain, subject to the constraint that the new bounding chain has equal boundary, and is obtained by adding simplices born strictly before the last simplex in the input bounding chain in the refined filtration order.

The constraint is formalized as follows, where death_simplex is the death simplex that pairs with the user-provided birth_simplex. We say that death_simplex precedes simplex sigma if death_simplex precedes sigma in the filtration order on simplices (with ties broken by lexicographic order).

minimize the L1 norm of b + x

subject to the condition that

Dx = 0, and x_sigma = 0 for all i such that death_simplex precedes simplex sigma as described above.

We suspect this is less efficient that other formulations.

optimize_cycle(birth_simplex, problem_type=None, verbose=True)

Optimize a cycle representative

This is a method to find tight cycle reprepresentaives in (persistent) homology. The output is typically a cycle with fewer simplices.

Mathematically, it uses the “edge loss” method to find a solution x’ to the problem

minimize Cost(Ax + z)

where

  • x is unconstrained

  • z is a cycle representative for a (persistent) homology class associated to a given birth_simplex

  • A is a matrix composed of a subset of columns of the [differential COBM](oat_rust::algebra::matrices::operations::umatch::differential) J of a [differential Umatch decomposition](oat_rust::algebra::matrices::operations::umatch::differential)

  • Cost(z) is the sum of the absolute values of the products z_s * filtration_value(s).

Parameters:
  • homology. (- The birth_simplex of a cycle represenative z for a bar b in persistent)

  • combination. (- The problem_type type for the problem. The optimization procedure works by adding linear combinations of column vectors from the Jordan basis matrix computed in the factorization. This argument controls which columns are available for the) –

    • (default) “preserve PH basis” adds cycles which appear strictly before birth_simplex in the standard ordering on filtered simplex (first by filtration, then breaking ties by lexicographic order on simplices) and die no later than the persistent homology class represented by birth_simplex. Note this is almost the same as the problem described in [Escolar and Hiraoka, Optimal Cycles for Persistent Homology Via Linear Programming](https://link.springer.com/chapter/10.1007/978-4-431-55420-2_5) except that we can include essential cycles, if birth_simplex represents an essential class.

    • ”preserve homology class” includes every column of J that lies in the image of the boundary operator at or before the filtration value of birth_simplex

Returns:

  • A pandas dataframe containing the following vectors

  • - ``initial_cycle`` (the initial cycle representative returned by the decomposition)

  • - ``optimal_cycle`` (the optimal cycle representative. This cycle has form) –

    \[o = z + e + Dc\]

    where - \(o\) is the optimal cycle, - \(z\) is the initial cycle, - \(c\) is a chain and \(Dc\) is the boundary of \(c\), - \(e\) is a chain in the space spanned by essential cycles (that is, cycles which never become boundaries).

    • Typically \(e\) is zero, so \(o = z + Dc\). In fact this is will always true if \(z\) is non-essential, i.e. if \(z\) represents persistent homology class with a finite death time. If this is true, then \(z\) and o will eventually become homologous, since they differ by a boundary. However, \(c\) may have a birth time strictly later than \(z\), so \(z\) and o may not be homologous at the birth time of \(z\).

    • surface_between_cycles is a chain \(c\). You can think of this chain, informally, – as a surface whose boundary is the difference between the initial and optimal cycles. In particular, if \(e=0\) then \(0 = z + Dc\).

  • - ``difference_in_essential_cycles`` (is the chain \(e\) in the decomposition above.)

Examples

See Persistent Homology: Stanford Dragon for an example.

persistent_homology_dataframe(return_cycle_representatives, return_bounding_chains)

Extract a barcode and a basis of cycle representatives

Computes the persistent homology of the filtered Vietoris Rips complex with dissimilarity matrix dissimilarity_matrix, over the field of rational numbers.

  • Edges of weight >= max_dissimilarity are excluded.

  • Homology is computed in dimensions 0 through max_homology_dimension, inclusive

Returns: a Pandas data frame with one row for each bar in the barcode. The columns are

  • dimension: The dimension of the homology class.

  • interval_length: The length of the bar, equal to death_filtration - birth_filtration.

  • birth_filtration

  • death_filtration

  • birth_simplex

  • death_simplex

  • cycle_representative (optional): A cycle representative for the persistent homology class, formatted as a data frame with columns simplex, filtration, and coefficient

  • num_cycle_simplices (optional): The number of nonzero coefficients in the cycle representative

  • bounding_chain (optional): A bounding chain for the cycle representative. Concretely, if the cycle representative is z, then the bounding chain is a chain x such that Dx = z, where D is the boundary matrix. The bounding chain is formatted as a data frame with columns simplex, filtration, and coefficient.

  • num_bounding_chain_simplices (optional): the number of nonzero coefficients in the bounding chain.

solve_dx_equals_b(b)

Solve Dx = b for x, where D is the boundary matrix of the Vietoris-Rips complex

# Input

The input, b, should be formatted as a Pandas data frame with columns simplex and coefficient.

  • Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2)

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2) - If mulitple entries in b have the same simplex, then they will be summed together.

  • Any other columns will be ignored.

# Output

  • If a solution exists, then the output is a Pandas data frame with columns simplex, filtration, and coefficient.

  • If no solution exists, then the output is None.

# Errors

Returns an error if any simplex in b is not contained in the Vietoris-Rips complex. Also returns an error if b contains a simplex of dimension greater > max_homology_dimension + 1, where max_homology_dimension is the maximum homology dimension for which this decomposition is valid (this parameter is set by the user when constructing the decomposition).

solve_xd_equals_b(b)

Solve xD = b for x, where D is the boundary matrix of the Vietoris-Rips complex

# Input

The input, b, should be formatted as a Pandas data frame with columns simplex and coefficient.

  • Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2)

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2) - If mulitple entries in b have the same simplex, then they will be summed together.

  • Any other columns will be ignored.

# Output

  • If a solution exists, then the output is a Pandas data frame with columns simplex, filtration, and coefficient.

  • If no solution exists, then the output is None.

# Errors

Returns an error if any simplex in b is not contained in the Vietoris-Rips complex. Also returns an error if b contains a simplex of dimension greater > max_homology_dimension + 1, where max_homology_dimension is the maximum homology dimension for which this decomposition is valid (this parameter is set by the user when constructing the decomposition).

submatrix_index_tool(row_dimensions=None, column_dimensions=None)

Returns a SubmatrixIndexTool object containing ordered sequences of row and column indices

# Arguments

  • row_dimensions (optional, defaults to None)

    • A list of dimensions for the row indices

    • If this list has form [d1, d2, …], then the row indices will include every simplex of dimension d1, d2.

    • If None is provided, then the index tool will contain row indices for every simplex of dimension <= d, where d is the maximum homology dimension specified by the user when creating the decomposition. It will also contain every death (a.k.a. negative) simplex of dimension d+1.

  • column_dimensions (optional, defaults to None)

    • A list of dimensions for the column indices

    • If this list has form [d1, d2, …], then the column indices will include every simplex of dimension d1, d2.

    • If None is provided, then the index tool will contain column indices for every simplex of dimension <= d, where d is the maximum homology dimension specified by the user when creating the decomposition. It will also contain every death (a.k.a. negative) simplex of dimension d+1.

# Returns

A SubmatrixIndexTool object containing the specified row and column indices.

  • Indices are sorted first by dimension, then by filtration value, then lexicographically (the same order used for the boundary matrix itself).

  • Duplicate dimensions are removed.

validate_simplex_dimension(simplex)

Returns an error if the simplex dimension is too high.

This function checks if the dimension of the simplex is strictly greater than the maximum homology dimension for which this decomposition is valid.

vietoris_rips_complex()

Returns a copy of the underlying VietorisRipsComplex

The returned object stores only minimal data (just a pointer to the dissimilarity matrix stored in the decomposition), so it uses very little memory. However, it can be used to generate lists of simplices, compute filtration values, and other operations.

class oat_python.core.vietoris_rips.ChangeOfBasisMatrix

Bases: object

column_for_simplex(simplex)

Returns the column of the matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

# Errors

Returns an error if the simplex is not contained in the Vietoris-Rips complex.

entry_for_row_and_column(row_simplex, column_simplex)

Returns the entry coefficient for the given row and column simplices

# Input

The inputs, row_simplex and column_simplex, should be strictly sorted lists or tuples of integers, e.g. (0,1,2).

# Output

The output is a Python Fraction

# Errors

Returns an error if one of the inputs is not a simplex contained in the Vietoris-Rips complex.

product_with_column_vector(chain)

Returns the product of the matrix with a column vector

# Input

The input, chain, should be formatted as Pandas data frame with columns simplex and coefficient. - Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2) - Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2) - Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

product_with_row_vector(cochain)

Returns the product of the matrix with a row vector

# Input

The input, cochain, should be formatted as Pandas data frame with columns simplex and coefficient. - Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2) - Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2) - Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

row_for_simplex(simplex)

Returns the row of the matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

# Errors

Returns an error if the simplex is not contained in the Vietoris-Rips complex.

validate_simplex_dimension(simplex)

Returns an error if the simplex dimension is too high.

write_submatrix_to_csr(submatrix_index_tool)

Writes a submatrix of this matrix to a Scipy CSR matrix format

# Arguments

  • submatrix_index_tool: a SubmatrixIndexTool object containing the row and column indices of the submatrix

# Returns

A scipy.sparse.csr_matrix, or an error if the row or column indices are not valid in the input matrix. The k`th row of the submatrix corresponds to the `k`th row of the `submatrix_index_tool, and similarly for columns.

Note The coefficients of the matrix are stores as floats, because SciPy offers very limited support for rational numbers.

class oat_python.core.vietoris_rips.ChangeOfBasisMatrixInverse

Bases: object

column_for_simplex(simplex)

Returns the column of the matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

# Errors

Returns an error if the simplex is not contained in the Vietoris-Rips complex.

entry_for_row_and_column(row_simplex, column_simplex)

Returns the entry coefficient for the given row and column simplices

# Input

The inputs, row_simplex and column_simplex, should be strictly sorted lists or tuples of integers, e.g. (0,1,2).

# Output

The output is a Python Fraction

# Errors

Returns an error if one of the inputs is not a simplex contained in the Vietoris-Rips complex.

product_with_column_vector(chain)

Returns the product of the the matrix with a column vector

# Input

The input, chain, should be formatted as Pandas data frame with columns simplex and coefficient. - Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2) - Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2) - Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

product_with_row_vector(cochain)

Returns the product of the matrix with a row vector

# Input

The input, cochain, should be formatted as Pandas data frame with columns simplex and coefficient. - Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2) - Each entry in the coefficient column should be a rational number, e.g. Fraction(1,2) - Any other columns will be ignored.

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

row_for_simplex(simplex)

Returns the row of the matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

# Errors

Returns an error if the simplex is not contained in the Vietoris-Rips complex.

validate_simplex_dimension(simplex)

Returns an error if the simplex dimension is too high.

write_submatrix_to_csr(submatrix_index_tool)

Writes a submatrix of this matrix to a Scipy CSR matrix format

# Arguments

  • submatrix_index_tool: a SubmatrixIndexTool object containing the row and column indices of the submatrix

# Returns

A scipy.sparse.csr_matrix, or an error if the row or column indices are not valid in the input matrix. The k`th row of the submatrix corresponds to the `k`th row of the `submatrix_index_tool, and similarly for columns.

Note The coefficients of the matrix are stores as floats, because SciPy offers very limited support for rational numbers.

class oat_python.core.vietoris_rips.GeneralizedMatchingMatrix

Bases: object

column_index_for_row_index(row_index)

Returns the column index matched to a given row index, or None if no such column exists.

# Input

The input, row_index, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a oat_python.core.vietoris_rips.WeightedSimplex object representing the column index, or None if no such column exists. The column index is the (unique, if it exists) column such that M[row_index, column_index] != 0, where M is the generalized matching matrix.

# Errors

Returns an error if the input is not a valid simplex in the Vietoris-Rips complex.

entry_for_row_and_column(row_simplex, column_simplex)

Returns the entry coefficient for the given row and column simplices

# Input

The inputs, row_simplex and column_simplex, should be strictly sorted lists or tuples of integers, e.g. (0,1,2).

# Output

The output is a Python Fraction

# Errors

Returns an error if one of the inputs is not a simplex contained in the Vietoris-Rips complex.

nonzero_entries()

Returns the nonzero entries of the generalized matching matrix as a dataframe

The dataframe has columns row_simplex, column_simplex, row_filtration, column_filtration, and coefficient.

row_index_for_column_index(column_index)

Returns the row index matched to a given column index, or None if no such row exists.

# Input

The input, column_index, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a oat_python.core.vietoris_rips.WeightedSimplex object representing the row index, or None if no such column exists. The row index is the (unique, if it exists) row such that M[row_index, column_index] != 0, where M is the generalized matching matrix.

# Errors

Returns an error if the input is not a valid simplex in the Vietoris-Rips complex.

validate_simplex_dimension(simplex)

Returns an error if the simplex dimension is too high.

write_submatrix_to_csr(submatrix_index_tool)

Writes a submatrix to a Scipy CSR sparse matrix

# Arguments

  • submatrix_index_tool: a SubmatrixIndexTool object containing the row and column indices of the submatrix

# Returns

A scipy.sparse.csr_matrix, or an error if the row or column indices are not valid in the input matrix. The k`th row of the submatrix corresponds to the `k`th row of the `submatrix_index_tool, and similarly for columns.

Note The coefficients of the matrix are stores as floats, because SciPy offers very limited support for rational numbers.

write_to_dataframe()

Returns a Pandas dataframe encoding the structural nonzero entries of the generalized matching matrix

The dataframe has columns coefficient, row_simplex, row_filtration, column_simplex, column_filtration, and filtration_difference. The filtration_difference value is the difference between the column_filtration and row_filtration values.

class oat_python.core.vietoris_rips.LaplacianMatrix

Bases: object

A matrix oracle for the Laplacian matrix of a Vietoris-Rips complex

product_with_vector(chain)

Multiplies the Laplacian with a vector

# Arguments

chain: a Pandas DataFrame containing columns simplex and coefficient. Other columns are ignored.

  • Each entry in the simplex column should be a strictly sorted list of vertices, e.g. (0,1,2).

  • Each entry in the coefficient column should be a float.

# Returns

A Pandas DataFrame with columns simplex, filtration, and coefficient.

row_for_simplex(simplex)

Returns the row of the Laplacian matrix indexed by a given simplex

# Input

The input, simplex, should be a strictly sorted list or tuple of integers, e.g. (0,1,2).

# Output

The output is a Pandas data frame with columns simplex, filtration, and coefficient.

class oat_python.core.vietoris_rips.SubmatrixIndexTool

Bases: object

Stores the row and column indices of a submatrix of the boundary matrix of a Vietoris-Rips complex

The primary use for this object is to provide an ergonomic / readable way to map between simplices and row/column numbers of a submatrix.

Caution

This object is not an Oracle; it stores the row and column indices in memory. If the number of simplices is large, this may lead to high memory usage.

column_indices()

Returns the collection of column indices as a dataframe

The kth row of the dataframe corresponds to the kth column of the submatrix.

column_vector_dataframe_for_dense_array(dense_array)

Converts a dense numpy array or list (with length equal to the number of rows of the submatrix) into a linear combination of simplices represented by a Pandas DataFrame

# Arguments

  • dense_array: a list of values [v0 .. vn] corresponding to the sequence of row indices [r0 .. rn] contained in the SubmatrixIndexTool.

# Returns

A Pandas DataFrame with columns simplex, filtration, and coefficient, where simplex is a tuple of vertices and coefficient is the corresponding coefficient.

Concretely, if dense_array[ i ] = v, then the output will contain a row with simplex = self.weighted_simplex_for_submatrix_row_number( i ) and coefficient = v.

Zero coefficients are ignored, so the dataframe will typically have fewer rows than len(dense_array).

# Errors

Returns an error if the length of the input array does not match the number of rows in the submatrix.

contains_a_column_for_simplex(simplex)

Returns True if the given simplex is a column index in the submatrix

contains_a_row_for_simplex(simplex)

Returns True if the given simplex is a row index in the submatrix

dense_array_for_column_vector_dataframe(dataframe)

Converts a linear combination of simplices into a dense array whose length equals the number of rows in the submatrix

# Arguments

  • dataframe: a Pandas DataFrame containing columns simplex and coefficient. Other columns are ignored.

    Entries in the coefficient column should have Frac values. If the same simplex appears multiple times, the coefficients are summed.

# Returns

A 1-dimensional numpy.ndarray with Frac values representing the dense array for the column vector, where the index corresponds to the row number in the submatrix.

# Errors

Returns an error if the input DataFrame does not contain the required columns, or if the simplices are not valid in the Vietoris-Rips complex.

dense_array_for_row_vector_dataframe(dataframe)

Converts a linear combination of simplices into a dense array whose length equals the number of columns in the submatrix

# Arguments

  • dataframe: a Pandas DataFrame containing columns simplex and coefficient. Other columns are ignored.

    Entries in the coefficient column should have Frac values. If the same simplex appears multiple times, the coefficients are summed.

# Returns

A 1-dimensional numpy.ndarray with Frac values representing the dense array for the column vector, where the index corresponds to the row number in the submatrix.

# Errors

Returns an error if the input DataFrame does not contain the required columns, or if the simplices are not valid in the Vietoris-Rips complex.

number_of_columns()

Returns the number of columns in the submatrix

number_of_rows()

Returns the number of rows in the submatrix

row_indices()

Returns the collection of row indices as a dataframe

The kth row of the dataframe corresponds to the kth row of the submatrix.

row_vector_dataframe_for_dense_array(dense_array)

Converts a dense numpy array or list (with length equal to the number of columns of the submatrix) into a linear combination of simplices represented by a Pandas DataFrame

# Arguments

  • dense_array: a list of values [v0 .. vn] corresponding to the sequence of column indices [r0 .. rn] contained in the SubmatrixIndexTool.

# Returns

A Pandas DataFrame with columns simplex, filtration, and coefficient, where simplex is a tuple of vertices and coefficient is the corresponding coefficient.

Concretely, if dense_array[ i ] = v, then the output will contain a row with simplex = self.weighted_simplex_for_submatrix_column_number( i ) and coefficient = v.

Zero coefficients are ignored, so the dataframe will typically have fewer columns than len(dense_array).

# Errors

Returns an error if the length of the input array does not match the number of columns in the submatrix.

set_column_indices(column_indices)

Sets the row indices of the index tool

# Arguments

  • row_indices: a list of list/tuples of nonnegative integers, e.g. [[0,1,2], [1,2,3]].

    • Each inner list must be strictly sorted.

    • The outer list can contain no duplicates.

# Errors

Returns an error if

  • any of the inner lists are not strictly sorted, or

  • any of the simplices are not valid simplices in the Vietoris-Rips complex

  • the outer list contains duplicate simplices

set_row_indices(row_indices)

Sets the row indices of the index tool

# Arguments

  • row_indices: a list of list/tuples of nonnegative integers, e.g. [[0,1,2], [1,2,3]].

    • Each inner list must be strictly sorted.

    • The outer list can contain no duplicates.

# Errors

Returns an error if

  • any of the inner lists are not strictly sorted, or

  • any of the simplices are not valid simplices in the Vietoris-Rips complex

  • the outer list contains duplicate simplices

sparse_dataframe_for_csr_matrix(matrix)

Converts a sparse CSR matrix into a sparse Pandas DataFrame indexed by tuples of vertices

# Arguments

  • matrix: a scipy.sparse.csr_matrix

# Returns

A Pandas DataFrame with rows and columns indexed by simplices (represented as tuples of vertices).

# Examples

See Sparse Matrices for an example (scroll to the bottom).

submatrix_column_number_for_simplex(simplex)

Returns the column number of the given simplex

# Arguments

  • simplex: a strictly sorted list of vertices, e.g. [0,1,2]

# Returns

An integer representing the column number of the simplex in the submatrix, or an error if the Vietoris-Rips complex does not contain this simplex.

submatrix_row_number_for_simplex(simplex)

Returns the row number of the given simplex

# Arguments

  • simplex: a strictly sorted list of vertices, e.g. [0,1,2]

# Returns

An integer representing the row number of the simplex in the submatrix, or an error if the Vietoris-Rips complex does not contain this simplex.

weighted_simplex_for_submatrix_column_number(column_number)

Returns the simplex corresponding to the given column number

# Arguments

  • column_number: an integer representing the column number in the submatrix

# Returns

A WeightedSimplexPython representing the simplex at the given column number, or an error if the column number is out of bounds.

weighted_simplex_for_submatrix_row_number(row_number)

Returns the simplex corresponding to the given row number

# Arguments

  • row_number: an integer representing the row number in the submatrix

# Returns

A WeightedSimplexPython representing the simplex at the given row number, or an error if the row number is out of bounds.

class oat_python.core.vietoris_rips.VectorIndexTool

Bases: object

Stores the row and column indices of a submatrix of the boundary matrix of a Vietoris-Rips complex

The primary use for this object is to provide an ergonomic / readable way to map between simplices and row/column numbers of a submatrix.

Caution

This object is not an Oracle; it stores the row and column indices in memory. If the number of simplices is large, this may lead to high memory usage.

contains_simplex(simplex)

Returns True if the simplex tool contains simplex in its list of indices

dataframe_for_dense_array(dense)

Converts a dense numpy array or list (with length equal to the number of rows of the submatrix) into a linear combination of simplices represented by a Pandas DataFrame

# Arguments

  • chain: a list of Frac values representing the dense array for the column vector, where the index corresponds to the row number in the submatrix.

# Returns

A Pandas DataFrame with columns simplex, filtration, and coefficient, where simplex is a tuple of vertices and coefficient is the corresponding coefficient.

Concretely, if dense[ i ] = v, then row i of the dataframe will have simplex = self.weighted_simplex_for_submatrix_row_number( i ) and coefficient = v.

Zero coefficients are ignored.

# Errors

Returns an error if the length of the input array does not match the number of rows in the submatrix.

dense_array_for_dataframe(chain)

Converts a linear combination of simplices into a dense array whose length equals the number of indices in the VectorIndexTool

# Arguments

  • chain: a Pandas DataFrame containing columns simplex and coefficient. Other columns are ignored.

    Entries in the coefficient column should have Frac or float values. If the same simplex appears multiple times, the coefficients are summed.

# Returns

A 1-dimensional numpy.ndarray with values representing the dense array for the column vector, where the index corresponds to the row number in the submatrix.

# Errors

Returns an error if the input DataFrame does not contain the required columns, or if the simplices are not valid in the Vietoris-Rips complex.

index_number_for_simplex(simplex)

Returns the index number of the given simplex

# Arguments

  • simplex: a strictly sorted list of vertices, e.g. [0,1,2]

# Returns

An integer representing the location of the simplex within the list of simplices stored by the tool simplex_0 .. simplex_n.

# Errors

Returns an error if the Vietoris-Rips complex does not contain this simplex.

number_of_simplices()

Returns the number of simplices in the index tool

set_simplices(indices)

Sets the indices of the index tool

# Arguments

  • indices: a list of list/tuples of nonnegative integers, e.g. [[0,1,2], [1,2,3]].

    • Each inner list must be strictly sorted.

    • The outer list can contain no duplicates.

# Errors

Returns an error if

  • any of the inner lists is not strictly sorted, or

  • any of the simplices is not a valid simplex in the Vietoris-Rips complex

  • the outer list contains duplicate simplices

simplex_for_index_number(k)

Returns the k-th simplex in the index tool

# Arguments

  • k: an integer representing the row number in the submatrix

# Returns

A WeightedSimplexPython representing the simplex at the given row number

# Errors

Returns an error if k is greater than or equal to the number of indices in the tool.

simplices()

Returns the collection of indices as a dataframe

The kth row of the dataframe corresponds to the kth simplex in the index tool.

class oat_python.core.vietoris_rips.VietorisRipsComplex(dissimilarity_matrix)

Bases: object

boundary_matrix_oracle()

Returns a matrix oracle for the boundary matrix of the Vietoris-Rips complex

filtration_value(simplex)

Returns the filtration value of a simplex

# Arguments

  • simplex: a strictly sorted list of vertices, e.g. [0,1,2]

# Returns

A f64 representing the filtration value of the simplex, or an error if the Vietoris-Rips complex does not contain this simplex.

laplacian_matrix_oracle()

Returns a matrix oracle for the Laplacian matrix of the Vietoris-Rips complex

simplices_for_dimensions(dimensions)

Returns the simplices of the Vietoris-Rips complex in sorted order

Simplices are sorted first by dimension, then by filtration value, then lexicographic order.

submatrix_index_tool(row_dimensions=None, column_dimensions=None)

Returns a SubmatrixIndexTool object containing ordered sequences of row and column indices

# Arguments

  • row_dimensions (optional, defaults to the empty list)

    • A list of dimensions for the row indices

    • If this list has form [d1, d2, …], then the row indices will include every simplex of dimension d1, d2.

  • column_dimensions (optional, defaults to the empty list [])

    • A list of dimensions for the column indices

    • If this list has form [d1, d2, …], then the column indices will include every simplex of dimension d1, d2.

# Returns

A SubmatrixIndexTool object containing the specified row and column indices.

  • Indices are sorted first by dimension, then by filtration value, then lexicographically (the same order used for the boundary matrix itself).

  • Duplicate dimensions are removed.

vector_index_tool(dimensions=None)

Returns a VectorIndexTool, which provides an ergonomic way to translate between simplex-based and number-based indexing

# Arguments

  • dimensions: a list of simplex dimensions (defaults to an empty list)

# Returns

A VectorIndexTool object containing simplices of the specified dimensions. These simplex indices are sorted in the standard order: by dimension, then filtration value, then lexicographically. This is the same order used for the boundary matrix itself.

class oat_python.core.vietoris_rips.WeightedSimplex(simplex, weight)

Bases: object

dimension()

Returns the dimension of the simplex

simplex()

Returns the vertices of the simplex

weight()

Returns the weight of the simplex

Point clouds

This module contains functions to generate a variety of point clouds, including random points on disks, circles, spheres, and tori.

Persistent homology and cohomology

For the persistent (co)homology of point clouds, see the Vietoris Rips section.

oat_python.point_cloud.annulus(n_points=1, inner_radius=1, outer_radius=2, random_seed=None)[source]

Samples points uniformly from an annulus (ring-shaped region) in the plane.

The annulus is defined as the region between two concentric circles centered at the origin, with inner radius inner_radius and outer radius outer_radius. Points are sampled uniformly with respect to area.

Parameters:
  • n_points (int, optional) – Number of points to sample. Default is 1.

  • inner_radius (float, optional) – Inner radius of the annulus. Default is 1.

  • outer_radius (float, optional) – Outer radius of the annulus. Default is 2.

  • random_seed (int or None, optional) – If provided, sets the random seed for reproducibility.

Returns:

points – Array of sampled points in the annulus, each row is a 2D point [x, y].

Return type:

numpy.ndarray, shape (n_points, 2)

Notes

  • The sampling is uniform with respect to area, not radius.

  • If inner_radius equals outer_radius, all points will lie on the circle of that radius.

  • If random_seed is provided, the randomization is reproducible.

oat_python.point_cloud.circle(n_points=10, radius=1, mode='uniform', random_seed=None)[source]

Generate points on a circle of given radius.

Parameters:
  • n_points (int (optional, default=10)) – Number of points to sample.

  • radius (float (optional, default=1)) – Radius of the circle.

  • mode ({'random', 'uniform'} (optional, default='uniform')) –

    • ‘random’: Points are sampled by drawing angles uniformly at random from [0, 2π).

    • ’uniform’: Points are placed at equally spaced angles from 0 to 2π (not including endpoint).

    Default is ‘uniform’.

  • random_seed (int or None (optional, default=None)) – If provided and mode is ‘random’, sets the random seed for reproducibility.

Returns:

points – Array of sampled points on the circle, each row is a 2D point [x, y].

Return type:

numpy.ndarray, shape (n_points, 2)

Notes

  • In ‘random’ mode, the sampling is uniform with respect to angle, not arc length.

  • In ‘uniform’ mode, the points are spaced uniformly in angle, so the first and last points may coincide if n_points divides 2π evenly.

  • If random_seed is provided, the randomization is reproducible (only for ‘random’ mode).

oat_python.point_cloud.disk(n_points, radius, random_seed=None)[source]

Randomly samples points from the disk of given radius centered at the origin in the Euclidean plane.

Parameters:
  • n_points (int) – The number of points to sample from the disk.

  • radius (float) – The radius of the disk.

  • random_seed (int or None (optional, default=None)) – If provided, sets the random seed for reproducibility.

Returns:

An N x 2 array of points sampled from the disk.

Return type:

np.ndarray

oat_python.point_cloud.half_dome(n_points=50, noise_scale=1)[source]

Samples points evenly from the half of the Euclidean 2-sphere that lies between x = -1 and x = 0.

This function is just a wrapper for sphere_or_slice(n_points=n_points, xmin=-1, xmax=0) + noise.

Parameters:
  • n_points (int, optional) – Number of points to sample. Default is 50.

  • noise_scale (float, optional) – Standard deviation of the random noise added to each coordinate. Default is 1.

Returns:

points – Array of sampled points on the half-sphere, each row is a 3D point [x, y, z].

Return type:

numpy.ndarray, shape (n_points, 3)

oat_python.point_cloud.sphere_or_slice(n_points=1, xmin=-1.0, xmax=1.0, randomize=False, random_seed=None)[source]

Samples (approximately) evenly distributed points from the portion of the unit sphere in Euclidean 3-space that lies between the planes x = xmin and x = xmax, using the Fibonacci spiral method.

Parameters:
  • n_points (int, optional) – Number of points to sample. Default is 1.

  • xmin (float, optional) – Lower threshold for x coordinates (inclusive). Default is -1.0.

  • xmax (float, optional) – Upper threshold for x coordinates (inclusive). Default is 1.0.

  • randomize (bool, (optional, default=False)) – If True, adds randomization to the initial condition for the spiral. Default is True.

  • random_seed (int or None (default None)) – A random seed for the generation of noise, for reproducibility. If None, the random number generator is not seeded.

Returns:

points – Array of sampled points on the sphere slice, each row is a 3D point [x, y, z].

Return type:

numpy.ndarray, shape (n_points, 3)

Notes

  • The method uses a Fibonacci Lattice to distribute points approximately evenly on the sphere.

  • The slice is defined by the region where xmin <= x <= xmax.

  • If randomize is True, the spiral is randomly rotated for more uniformity.

  • If random_seed is provided, the randomization is reproducible.

oat_python.point_cloud.sphere_or_slice_spiral(n_points=50, embedding_dim=3, noise_scale=1, xmax=1, random_seed=None)[source]

A sample of points for a sphere intersected with a halfspace of form x ≤ xmax, formatted as an N x 3 array.

Points are sampled using a “spiral” method; see the source code for details.

Parameters:
  • n_points (int) – Number of points in the points.

  • embedding_dim (int) – Embedding dimension of the points, defaults to 3.

  • noise_scale (float) – Points are generated in a deterministic fashion, then modified by adding a small amount of noise drawn iid from the unit cube of size [0,noise_scale]^n.

  • xmax (float) – Determines how far on the x axis you go; xmax=0 returns a hemisphere.

  • random_seed (int or None (default 0)) – A random seed for the generation of noise, for reproducibility. If None, the random number generator is not seeded.

oat_python.point_cloud.stanford_dragon()[source]

Load a point cloud of 1000 points, sampled from the Stanford Dragon.

The points are returned as a numpy array of shape (1000, 3).

Notes

The data file is saved to oat_python/data/stanford_dragon.txt.

oat_python.point_cloud.torus(radius_outer=4, radius_inner=1, n_points_outer=60, n_points_inner=20, repeat_last=True)[source]

Returns an N x 3 array of points sampled from a torus in 3D Euclidean space.

Parameters:
  • radius_outer – the larger radius (default = 4)

  • radius_inner – the smaller radius (default = 1)

  • n_points_outer – number of points to sample from the larger circle (default = 60)

  • n_points_inner – number of points to sample from the smaller circle (default = 20)

  • repeat_last – determines whether the first and last rows (respectively, columns) of each x, y, z matrix are equal; defualt = True

oat_python.point_cloud.torus_curve(n_points=100, inner_radius=0.3, outer_radius=1, angle_initial=0, nturns=1)[source]

Return a sequence of points that curves around a torus nturns times.

oat_python.point_cloud.two_circles()[source]

Points evenly spaced along two tangent circles in the Euclidean plane.

Hypergraphs

class oat_python.core.dowker.BoundaryMatrixDecompositionDowker(dowker_simplices, max_homology_dimension)

Bases: object

A differential umatch decomposition for the boundary matrix of a Dowker complex, with rational coefficients. This can be used to compute

  • (co)homology groups

  • (co)cycle representatives

  • bounding chains

and more!

betti_numbers()

The Betti numbers of the Dowker complex.

Returns a list [b_0, b_1, …, b_max_homology_dimension], where b_i is the dimension of the i-th homology group.

boundary(index)

Returns a column of the boundary matrix

coboundary(index)

Returns a row of the boundary matrix

diagnostic(maxdim)

Runs a diagnostic to check that major and minor views of the dowker complex agree.

fundamental_subspace_dimensions()

Dimensions of homology and the spaces of chains, cycles, boundaries

Each entry is the dimension of a vector space.

get_matched_column(index)

Returns the index of the matched column of the boundary matrix (if it exists)

get_matched_row(index)

Returns the index of the matched row of the boundary matrix (if it exists)

homology()

Returns a data frame representing a basis for homology.

Each row of the data frame represents a homology class; together these homology classes form a basis for homology. The data frame has the following columns:

  • dimension: The dimension of the homology class

  • cycle_representative: A cycle representative for the homology class. This is represented as a dataframe with columns simplex and coefficient.

  • cycle_representative_nonzero_coefficient_count: The number of nonzero coefficients in the cycle representative.

  • unique_simplex_id: A simplex which can be used as a unique identifier for the homology class (each homology class gets a different unique_simplex_id).

    Note: The `unique_simplex_id` corresponds to the birth simplex in persistent homology. The homology computation for Dowker complexes is implemented in essentially the same way as a persistent homology computation – with simplices ordered lexicographically. The unique_simplex_id is simply the birth simplex from that computation.

homology_indices()

Returns the column indices of the differential COBM that collectively represent a basis for homology.

matching_basis_vector_for_simplex(simplex)

Returns a column of the differential COBM

max_homology_dimension()

The maximum dimension for which we can recover information about homology, cycle spaces, boundaries, etc.

optimize_cycle(unique_simplex_id, problem_type, verbose=True)

Optimize a cycle representative

Specifically, we employ the “edge loss” method to find a solution x’ to the problem

minimize Cost(Ax + z)

where

  • x is unconstrained

  • z is a cycle representative for a (persistent) homology class associated to birth_simplex

  • A is a matrix composed of a subset of columns of the Jordna basis

  • Cost(z) is the sum of the absolute values of the products z_s * filtration_value(s).

# Arguments

  • The birth_simplex of a cycle represenative z for a bar b in persistent homology.

  • The problem_type type for the problem. The optimization procedure works by adding linear combinations of column vectors from the Jordan basis matrix computed in the factorization. This argument controls which columns are available for the combination.

    • (default) “preserve PH basis” adds cycles which appear strictly before birth_simplex in the lexicographic ordering on filtered simplex (by filtration, then breaking ties by lexicographic order on simplices) and die no later than birth_simplex. Note this is almost the same as the problem described in [Escolar and Hiraoka, Optimal Cycles for Persistent Homology Via Linear Programming](https://link.springer.com/chapter/10.1007/978-4-431-55420-2_5) except that we can include essential cycles, if birth_simplex represents an essential class.

    • “preserve PH basis (once)” adds cycles which (i) are distince from the one we want to optimize, and (ii) appear (respectively, disappear) no later than the cycle of birth_simplex. This is a looser requirement than “preserve PH basis”, and may therefore produce a tighter cycle. Note, however, that if we perform this optimization on two or more persistent homology classes in a basis of cycle representatives for persistent homology, then the result may not be a persistent homology basis.

    • “preserve homology class” adds every boundary vector

    • “preserve homology calss (once)” adds every cycle except the one represented by birth_simplex

# Returns

A pandas dataframe containing

  • z, labeled “initial_cycle”

  • y, labeled “optimal_cycle”

  • x, which we separate into two components:

    • “surface_between_cycles”, which is made up of codimension-1 simplices

    • “difference_in_essential cycles”, which is made up of codimension-0 simplices

  • The number of nonzero entries in each of these chains

  • The objective values of the initial and optimized cycles

# Related

See

row_indices()

The sequence of row indices in the order visited when factoring the boundary matrix.

Returns the sequence of row indices of the boundary matrix sorted (first) in ascending order of dimension, and (second) in descending lexicographic order (excluding simplices whose dimension strictly exceeds self.max_homology_dimension())

oat_python.core.dowker.transpose_listlist(vecvec)

Return the transpose of a list of lists

We regard the input as a sparse 0-1 matrix in vector-of-rowvectors format

oat_python.core.dowker.unique_row_indices(vecvec)

Returns indices for unique elements in a list of lists of integers

Concretely, if \(L = [L_1, \ldots, L_n]\) is a list of lists of integers, then this function returns a list of indices \(I = [i_1, \ldots, i_k]\) such that \(L_{i_1}, \ldots, L_{i_k}\) are the unique elements of \(L\).

oat_python.core.dowker.unique_rows(vecvec)

Returns a list of unique elements in a list of lists of integers

Concretely, if \(L = [L_1, \ldots, L_n]\) is a list of lists of integers, then this function returns a list of lists \(U = [U_1, \ldots, U_k]\) such that \(U_{i_1}, \ldots, U_{i_k}\) are the unique elements of \(L\).

oat_python.core.dowker.zigzag_homology(hypergraphs, max_homology_dimension, return_cycle_representatives)

Converts a sequence of hypergraphs into the corresponding zigzag homology barcodes, with cycle representatives.

Homology is computed with coefficients in the two-element field.

The simplicial complexes in the construction are the downward-closures of the hypergraphs.

# Arguments

  • hypergraphs: a list of hypergraphs. Each hypergraph is formatted as a list hyperedges, where each hyperedge is represented by a sorted list of integers.

  • max_homology_dimension: the maximum dimension in which to compute homology. Homology in dimensions 2 and above is often substantially more expensive in time and memory than homology in dimension 1.

  • return_cycle_representatives: if true, the method will provide cycle representatives

# Output

Given a sequence of hypergraphs A, B, C, .., this method decomposes the zigzag homology module for

A –> A u B <– B –> B u C <– ..

as a direct sum of interval modules. It then returns a Pandas DataFrame frame with columns for

  • submodule uuid: a unique integer assigned to each subdule, used as its “name”

  • dimension: the homological dimension of the submodule

  • birth (inclusive): the first index at which the submodule is nonzero. For example, if the feature first appears in hypergraph A this index will be zero, and if it first appears in hypergraph A u B then the index will be 0.5.

  • death (exclusive): the first index i such that the submodule remains zero at index i and all indices greater than i. For example, if the feature is present in hypergraph A but not in hypergraph A u B, then the value of death (exlusive) will be 0.5

  • cycle representatives: a Pandas DataFrame containing a list of cycle representatives for an interval submodule. We think of the module as a representation of a quiver (aka directed graph) whose vertices are labeled 0, 0.5, 1, 1.5, .. as follows:

    0 –> 0.5 <– 1 –> 1.5 <– ..

    For each vertex in the quiver, the submodule contains a vector space of dimension 1 or zero. The cycle representatives DataFrame contains a basis vector (cycle representative) for each vertex where the subspace is nonzero. The basis vector is formatted as a list of simplices. This formatting represents a linear combination of simplices with coefficients in the two element field.

Additional tools

Tools for working with hypergraphs.

oat_python.hypergraph.containment_map(list_of_collections)[source]

Given a list of colections with pairwise-empty intersections, denoted list_of_collections, return the dictionary D such that \(k \in list_of_collections[ D[k] ]\) for all k.

oat_python.hypergraph.edge_containment_graph(L)[source]

Given a length-m list of lists L, returns a networkx directed graph G with vertex set 0, .., m-1, where there exists a directed edge i->j iff L[i] is a subset of L[j]

oat_python.hypergraph.edge_containment_graph_symmetrized(L)[source]

Given a length-m list of lists L, returns a networkx undirected graph G with vertex set 0, .., m-1, where i and j are adjacent iff L[i] contains L[j] or vice-versa

oat_python.hypergraph.edge_containment_relation(L)[source]

Given a length-m list of lists L, returns an m x m matrix adjacency matrix adj of type scipy.sparse.csr_matrix such that - adj[i][j] = 1 if L[j] contains L[i] - adj[i][j] = 0, otherwise

oat_python.hypergraph.edge_containment_relation_symmetrized(L)[source]

Given a length-m list of lists L, returns an m x m adjacency matrix adj of type scipy.sparse.csr_matrix, such that - adj[i][j] = 1 if L[i] contains L[j] or vice versa - adj[i][j] = 0, otherwise

oat_python.hypergraph.networkx_nerve_for_hypergraph(L)[source]

Given a length-m list of lists L, returns a networkx graph G with - m edges - an undirected edge {i,j} iff L[i] is a subset of L[j], or vice versa

oat_python.hypergraph.reduce_hypergraph(hg)[source]

Given a list of lists (regarded as the sparsity pattern of a sparse 0-1 matrix), returns a list of lists representing the sparse matrix obtained by deleting duplicate rows and columns

oat_python.hypergraph.reduce_hypergraph_with_labels(hgdict)[source]

Given a hypergraph H represented by a dictionary of lists D, - regard D as a binary relation B, and let B’ be the relation obtained by deleting duplicate rows and columns - relabel the rows and columns of B’ with integers - let H be the corresponding hypergraph, represented as a list of lists of integers Every node (respectively, edge) of B maps to a unique row (respectively, edge) of B’. Let T be a dictionary with keys new_edge_for_old_edge new_node_for_old_node old_edges_for_new_edge old_nodes_for_new_node and require T[“new_edge_for_old_edge”][old_edge] is the integer label of the edge in H corresponding to old_edge. The other entries of T are defined similarly.

Return H, T

oat_python.hypergraph.relabel(hgdict)[source]

Relabel the nodes and edges of a hypergraph with consecutive integers.

Given a hypergraph represented as a dictionary of lists, where each list is sorted in strictly ascending order, this function returns a copy of the hypergraph with nodes and edges relabeled with integers, and a dictionary containing the relabeling information.

Parameters:

hgdict (dict of list) – A hypergraph H represented by a dictionary of lists. Each list must be sorted in strictly ascending order.

Returns:

  • H (list of list of int) – A copy of hgdict with nodes and edges relabeled with integers; formatted as a list of sorted lists.

  • T (dict) –

    A dictionary containing relabeling information with the following keys:

    • ’new_edge_for_old_edge’: maps original edge labels to new integer labels

    • ’new_node_for_old_node’: maps original node labels to new integer labels

    • ’old_edge_for_new_edge’: maps new integer edge labels to original edge labels

    • ’old_node_for_new_node’: maps new integer node labels to original node labels

Notes

  • T[“new_edge_for_old_edge”][old_edge] gives the integer label of the edge in H corresponding to old_edge.

  • The other entries of T are defined similarly.

oat_python.hypergraph.transpose(L)[source]

Transpose a list of lists of integers, L, producing a list of lists P such that L[i][j] = P[j][i]

oat_python.hypergraph.unique_elements(L)[source]

Returns a list of the unique elements of a list L.

oat_python.hypergraph.unique_values(key_val_iter)[source]

Returns a pair of lists U and P such that P[i] equals the set of all keys with value U[i], and U has no repeated entries.

Plotting

Plotting tools.

This module contains plotting tools for simplicial complexes, surfaces, barcodes, persistence diagrams, etc.

oat_python.plot.ball_2d(x, y, radius, n_points)[source]

Returns a trace for a ball of radius radius centered at (x,y). The perimiter of the ball is a closed piecewise linear curve with n_points vertices.

oat_python.plot.barcode(persistent_homology_dataframe, guideline_limit=None)[source]

Create a Plotly figure for the barcode of a filtered chain complex.

Parameters:
  • persistent_homology_dataframe (pandas.DataFrame) – DataFrame with numeric columns labeled birth, death, and dimension. Optionally, may include birth simplex, death simplex, num_cycle_simplices, and num_bounding_simplices columns for richer hovertext.

  • guideline_limit (float, optional) – If provided, sets the upper limit for the vertical guideline (drawn at 1.1 × guideline_limit). If not provided, the function determines a suitable limit from the data.

Returns:

fig – A Plotly figure displaying the barcode diagram.

Return type:

plotly.graph_objs.Figure

Notes

  • Each horizontal bar represents a persistent feature, colored by its homology dimension.

  • Hovering over a bar shows detailed information, including birth/death filtration, birth/death simplex, cycle and bounding chain sparsity, and the row index in the DataFrame.

  • Infinite death values are replaced by a finite proxy for plotting.

  • The function adds a vertical guideline for visual reference.

Example

import pandas as pd
from oat_python.plot import barcode

persistent_homology_dataframe = pd.DataFrame({
    "birth_filtration": [0.1, 0.2, 0.3],
    "death_filtration": [0.5, float("inf"), 0.8],
    "dimension": [0, 1, 2],
    "birth_simplex": [(0,), (1,2), (6,7,8)],
    "death_simplex": [(1,), (3,4,5), (9,10,11)],
    "num_cycle_simplices": [3, 4, 7],
    "num_bounding_simplices": [5, 6, 8],
})
fig     =   barcode(
                persistent_homology_dataframe
            )
fig
oat_python.plot.blank_background(fig)[source]

Remove grid lines, zero lines, tick labels, and axis titles from a 3D Plotly figure.

Parameters:

fig (plotly.graph_objs.Figure) – A Plotly Figure object containing a 3D scatter or surface plot.

Returns:

The function modifies the input figure in place.

Return type:

None

Example

See the Styling in 3D gallery for examples and styling.

oat_python.plot.contains_3d_trace(fig)[source]

Returns True if the Plotly figure contains one or more 3D traces.

Parameters:

fig (plotly.graph_objs.Figure) – A Plotly Figure object.

Returns:

True if the figure contains at least one 3D trace, False otherwise.

Return type:

bool

Notes

This function works by checking whether any of the traces in the figure is an instance of one of the following types:

  • plotly.graph_objects.Scatter3d

  • plotly.graph_objects.Surface

  • plotly.graph_objects.Mesh3d

  • plotly.graph_objects.Volume

  • plotly.graph_objects.Isosurface

  • plotly.graph_objects.Cone

  • plotly.graph_objects.Streamtube

  • plotly.graph_objects.Volume

Example

import plotly.graph_objects as go
from oat_python.plot import contains_3d_trace

fig = go.Figure()
fig.add_trace(go.Scatter3d(x=[1,2], y=[3,4], z=[5,6]))
print(contains_3d_trace(fig))  # Output: True

fig2 = go.Figure()
fig2.add_trace(go.Scatter(x=[1,2], y=[3,4]))

print(contains_3d_trace(fig2))  # Output: False
oat_python.plot.contrast_initial_and_optimal_cycles_in_3d(boundary_matrix_decomposition, birth_simplex, points, kwargs_initial={'line': {'color': 'white', 'width': 10}, 'name': 'Initial cycle'}, kwargs_optimal={'line': {'color': 'crimson', 'width': 10}, 'name': 'Optimal cycle'}, kwargs_surface={'color': 'white', 'name': 'Surface between cycles', 'opacity': 0.5, 'showlegend': True}, kwargs_points={'marker': {'color': [-0.045437, 0.0079908, 0.020266, -0.042987, 0.01155, 0.0070625, -4.1097e-05, -0.023396, 0.019312, -0.00052554, -0.031788, -0.021288, 0.0066776, 0.0098625, -0.032059, -0.0093875, -0.023841, 0.019662, -0.018385, 0.013713, -0.021743, 0.015463, -0.025837, 0.0063612, -0.038088, -0.0012922, -0.0044875, -0.014637, -0.024438, 0.0085448, -0.028987, -0.0083375, -0.041729, -0.026187, -0.0090101, 0.012034, -0.029337, 0.0046125, 0.0014625, -0.037387, -0.0084488, 0.025962, -0.031759, 0.0053125, -0.0016471, -0.0034375, -0.0080997, -0.0044875, -0.012124, -0.034039, -0.019887, -0.0048375, -0.0016875, 0.020761, 0.028063, -0.032831, 6.2503e-05, -0.0027965, -0.0093872, -0.016037, -0.0090375, 0.00041251, 0.024213, -0.032837, 0.0095125, -0.0034375, 0.018613, -0.032137, -0.019887, -0.035287, -0.0076375, 0.0068811, -0.020237, -0.023619, -0.017732, -0.010438, 0.0049625, -0.0072875, -0.014287, 0.017913, 0.024913, -0.0016875, -0.030347, -0.0024262, -0.014287, 0.035412, -0.020237, 0.0021841, -0.0063548, -0.025487, 0.0014512, -0.035903, -0.026187, -0.03605, 0.016162, 0.012663, -0.031288, -0.012538, -0.030738, -0.0041375, 0.022812, -0.022097, 0.034362, -0.01664, -0.024438, 6.2503e-05, 0.026497, -0.0023037, -0.034542, -0.014988, -0.027907, -0.023037, -0.035287, 0.017563, 0.0091625, -0.014988, 0.011962, 0.0059858, -0.0022034, -0.013754, -0.015688, -0.032837, -0.017191, -0.0055375, -0.010382, -0.0011114, -0.0072875, 0.010391, -0.032488, -0.0099916, -0.0034375, -0.026533, -0.0023875, -0.035287, -0.0044219, 0.012569, -0.0080605, -0.011137, -0.028637, -0.038763, 0.0062842, 0.0090152, -0.019887, -0.031088, -0.014988, 0.011972, 0.012663, 6.2503e-05, 0.023863, 0.021724, -0.031491, -0.00066844, -0.0090976, -0.034237, 0.017212, -0.0082394, 0.0074125, -0.034867, -0.021638, -0.0006375, -0.029687, -0.0015123, -0.014287, 0.0073859, -0.00085987, -0.01439, -0.019713, -0.017296, 0.019312, -0.010087, -0.010974, -0.010087, 0.022113, -0.023741, 0.015813, -0.039837, -0.017087, 0.0070625, -0.017049, -0.0027114, -0.010751, -0.042287, -0.0033466, -0.0031859, -0.0006375, -0.016992, -0.0088622, 0.0022192, 0.01602, -0.035287, -0.032433, -0.0006375, 0.0065121, 0.033313, -0.030388, -0.015688, 0.0007625, -0.014637, 0.014093, -0.019887, -0.029795, 0.00041251, -0.025477, 0.014762, 0.0056625, -0.012188, -0.050006, -0.028637, -0.020938, 0.015112, -0.0032648, -0.018138, -0.02058, -0.011137, 0.017503, 0.020012, -0.0076375, -0.0020148, 0.0035533, -0.039254, -0.0041375, -0.036188, -0.011867, -0.0099752, -0.039488, -0.03426, 0.020012, -0.0065268, -0.015319, -0.0163, -0.028978, -0.028861, -0.016387, -0.01696, 0.0083637, -0.0086875, -0.0097375, -0.030038, 0.01635, 0.0007625, 0.012313, -0.0011579, 0.030863, 0.028762, -0.022467, -0.0020375, 0.0042625, -0.0079913, 0.013362, -0.025837, -0.030388, -0.046837, -0.028723, -0.0062375, -0.0076369, -0.014566, -0.018952, -0.046488, 0.010563, -0.001524, -0.010438, -0.022337, 0.0098625, 0.011055, 0.013317, -0.0097375, 0.025714, 0.0127, -0.033729, -0.022687, 0.010622, -0.012887, -0.0097375, 0.022782, 0.024711, 0.0070625, -0.0043667, 0.018963, -0.0079875, -0.027663, -0.017788, -0.019617, -0.0048375, -0.03448, -0.034466, -0.0278, 0.022203, 0.010563, 0.0028625, 0.025612, 0.0081125, 0.03289, -0.028637, 0.023579, -0.0062375, -0.034066, -0.018838, 0.016799, 0.011772, -0.047188, -0.0015388, 0.0098095, -0.022337, -0.034826, -0.021768, -0.032137, -0.0086875, -0.012188, -0.014637, 0.015939, -0.012188, -0.020584, -0.035638, -0.023738, -0.022964, -0.038437, 0.002004, -0.043338, -0.0027375, -0.012887, -0.022578, -0.0006375, -0.018138, -0.031788, -0.0062375, -0.027588, 0.015495, 1.9699e-05, 0.013319, 0.0067125, 0.010212, -0.0017599, 0.0028625, 0.0012151, -0.018225, -0.0062375, 0.015004, -0.035321, -0.0079875, -0.011773, 0.017316, -0.0019206, 0.030162, -0.0040543, 0.01256, -0.009329, -0.0055375, -0.026537, -0.0018482, 0.024563, -0.0065624, -0.0090375, 0.0090298, -0.032837, 0.015813, -0.046137, -0.0072875, 0.0007625, -0.0046981, -0.0090544, -0.018158, -0.0028245, 0.01828, 0.0008074, 0.022462, -0.032468, -0.0072875, -0.031438, -0.0055375, 0.0014625, -0.028987, 0.0077625, -0.013237, 0.017212, -0.019134, -0.034613, -0.024085, -0.033188, 0.022812, -0.040537, -0.031088, -0.041587, -0.024395, -0.041938, -0.00095612, -0.0069375, -0.022363, -0.025487, -0.032848, -0.015507, -0.043452, -0.0030875, -0.0090375, -0.019181, 0.0053125, 0.011913, -0.021768, -0.0074199, -0.01074, -0.017087, 0.012254, 0.029812, -0.0020375, -0.026537, -0.030738, -0.0037875, -0.017946, -0.021535, -0.0055375, -0.026537, 0.00052175, -0.034989, -0.03798, -0.020237, -0.033537, 0.017212, 0.012885, -0.013588, -0.027238, -0.011802, -0.012218, 0.0042625, -0.012957, 0.022812, 0.018613, 0.022812, -0.017003, -0.019887, 0.015928, -0.024779, -0.030055, -0.0069375, 0.017949, -0.013489, -0.024237, -0.033537, 0.020712, -0.0030875, -0.014642, 6.2503e-05, 0.0086141, -0.01769, 0.001802, -0.025028, 0.023862, 0.0028625, -0.027588, 0.016699, -0.0016875, 0.020105, -0.0065875, -0.0020375, 0.0011125, 0.019662, -0.028654, -0.012887, -0.018838, 0.0018125, 0.016848, -0.0084763, 0.0097947, -0.018131, -0.005593, -0.013938, 0.016685, 0.0007625, 0.011634, -0.031438, -0.020588, 0.0070625, -0.024088, -0.037738, -0.011167, 0.020781, -0.021639, -0.0044875, -0.015688, -0.038788, -0.0079875, 0.011466, -0.021837, -0.035927, -0.022337, -0.00056881, -0.01793, -0.00060092, -0.041331, 0.0032931, -0.014059, -0.037765, -0.013219, 0.0032125, 0.019662, 0.030399, 0.030162, 0.016661, 0.014136, 0.0095125, -0.0054421, -0.012188, -0.030388, -0.00078056, 0.014412, -0.020938, 0.012163, -0.033888, -0.014637, -0.021288, -0.028736, -0.0017855, -0.018488, 0.023862, -0.0079875, 0.0051438, -0.041719, -0.0027876, -0.0042611, 0.0098823, -0.00063824, 0.015463, 0.017507, -0.028637, -0.025837, 0.0086287, -0.035129, -0.013952, -0.019537, 0.0042696, -0.031788, 0.0087325, 0.0078307, -0.0062375, -0.021988, -0.033987, -0.0022117, -0.039137, -0.034588, -0.030167, -0.010438, 0.00011163, 0.013713, -0.0079875, -0.035931, -0.018488, -0.0013375, 0.0083605, -0.019887, -0.0080482, 0.010904, -0.0034375, -0.0062375, -0.017788, -0.012538, 0.009028, -0.016737, -0.0097375, -0.015564, 0.00042066, -0.0044875, -0.0006375, -0.0083375, -0.013237, -0.009216, -0.034446, -0.012717, 0.025574, 0.0081125, 0.0042163, 0.0067125, 0.0063625, 0.012663, 0.0070625, 0.027851, -0.031514, -0.013588, -0.0083654, -0.021638, -0.03704, 0.026375, 0.0039125, -0.028987, -0.028987, 0.0025125, -0.014637, -0.033888, -0.012538, -0.029337, 0.0095125, 0.020362, -0.045788, -0.0006375, 0.00056301, -0.02208, 0.012528, -0.019887, -0.038788, -0.032538, 0.0088391, 0.0025559, 0.0079514, -0.0020692, 0.011262, -0.037434, -0.012887, -0.022479, -0.0093037, 0.015463, -0.020588, -0.0034339, -0.038877, -0.02831, 0.011722, -0.025487, 0.011444, -0.017087, 6.5126e-05, -0.035287, 0.0046125, -0.0080199, 0.021589, -0.019887, -0.014637, -0.031088, 0.024913, -0.011487, -0.033437, 0.0032125, -0.0076375, -0.017809, 0.0058023, 0.012313, -0.021988, -0.0062375, -0.011476, -0.028288, -0.003132, 0.021063, -0.031788, 0.017212, -0.0055375, -0.011892, -0.028637, -0.022388, -0.010788, -0.0062375, -0.016037, 0.0075019, 0.015813, 0.0045626, -0.013204, -0.002676, -0.0014086, -0.030729, -0.0080494, -0.018838, -0.0039569, 0.021763, -0.011911, -0.037738, 0.020202, 0.019804, -0.016272, -0.021828, 0.0084625, -0.0072875, -0.0048375, 0.0011125, -0.032896, 0.014516, 0.021492, -0.032767, 0.013012, 0.018231, -0.042029, -0.0062426, -0.0010448, -0.014287, -0.00067499, 0.0067125, -0.0041375, -0.0017752, -0.020588, 0.0123, -0.011838, -0.0017305, 0.011948, -0.020938, -0.013507, -0.0052985, -0.011063, -0.032837, 0.0053125, -0.037842, -0.011487, -0.037038, 0.026927, -0.0072326, 0.018263, -0.014287, 0.015919, -0.022003, 0.018183, 0.016862, -0.013588, -0.0020375, -0.0044875, 0.016862, -0.024411, -0.046137, 0.015412, -0.023172, -0.022337, -0.0014364, -0.0193, 0.011387, 0.015813, 0.022113, -0.013938, 0.0091894, -0.028609, -0.0020375, 0.0022099, -0.033287, -0.0062375, 0.016162, -0.021288, -0.023074, 0.012313, -0.0084406, -0.028637, -0.023037, -0.0002875, -0.0048375, -0.019887, -0.0020375, 0.0032125, -0.020588, -0.012561, -0.015688, 0.0081125, -0.030022, 0.017563, -0.019912, -0.0080582, 0.0081125, 0.00059219, -0.028637, 0.0016563, -0.030038, 0.022113, 0.016162, -0.0072875, 0.0007625, 0.027012, -0.030388, 0.0056625, 0.011612, 0.0081125, -0.025839, -0.011487, -0.041151, -0.017788, -0.029687, -0.010717, -0.0045016, 0.0086643, -0.012296, -0.0062375, 0.020012, 0.017212, -0.0056939, 0.01723, -0.035539, 0.010212, -0.017767, -0.023721, 0.011262, -0.016737, -0.027588, -0.038475, 0.023162, 0.00054105, 0.014063, 0.021413, 0.0006073, 0.018709, -0.022133, 0.015813, 0.019189, -0.019537, -0.033888, 0.0070625, -0.033188, 0.0039125, -0.010788, -0.0006375, -0.027501, -0.0064255, -0.001695, -0.04124, -0.0093875, 0.016138, -0.031088, -0.010788, -0.0002875, -0.019537, 0.022812, 0.0018125, -0.025079, -0.0051875, 0.015266, -0.005366, 0.0056625, 0.016794, 0.012663, -0.030038, -0.025837, -0.028288, -0.038535, -0.043134, -0.0031427, -0.0027375, 0.019312, 0.0046125, -0.019241, -0.0083375, -0.021638, 0.0041658, -0.031088, 0.0053125, 0.010212, 0.0053125, -0.017438, -0.00405, -0.0097375, -0.033188, 0.011612, 0.0011125, -0.02119, 0.02531, -0.026187, -0.019537, -0.012538, -0.023157, -0.025487, 0.0025125, -0.026537, -0.0071299, -0.019775, -0.0097432, 0.019992, -0.024425, -0.048946, 0.017913, 0.0007625, -0.0073491, -0.0069375, -0.031831, 0.040062, -0.016113, 0.011292, -0.013588, -0.043338, -0.0056789, -0.0076375, -0.022472, -0.035995, 0.012567, -0.035638, -0.018615, 0.0081677, 0.025863, -0.0037875, 0.0074798, 0.0037479, -0.0006375, 6.2503e-05, 0.021392, -0.0062375, -0.013588, 0.00040339, -0.011137, -0.030038, -0.011137, -0.0055375, -0.013588, -0.013588, 0.0054517, -0.0069456, -0.0083929, -0.032869, -0.021988, -0.010788, -0.0015674, 0.0022601, 0.035063, 0.020712, -0.032837, 0.023162, -0.0282, 0.025382, -0.0030875, -0.022692, -0.034237, -0.019865, 0.01053, -0.034228, -0.016037, -0.030109, -0.028288, -0.034833, 0.0021625, -0.033361, -0.0025627, -0.026888, -0.0006375, -0.0079875, -0.020237, 0.011612, 0.010913, 0.021063, -0.049638, -0.0013375, -0.043903, -0.03204, -0.031788, -0.015338, -0.022687, -0.017104, -0.022337, -0.014287, -0.012188, -0.0014223, 0.0084522, -0.020938, 0.012641, 0.0049625, 0.011262, -0.026537, -0.034295, -0.0030378, 0.0021625, -0.031438, -0.032739, -0.0031165, 0.010339, 0.010507, -0.032837, 0.0042625, 0.017446, -0.010521, -0.034237, -0.022687, 0.0046279, -0.036844, -0.011838, -0.0058875, 0.022817, -0.024461, -0.031088, -0.0012544, -0.031788, 0.029761, -0.022337, -0.0027375, 0.010563, 0.011612, -0.008983, 0.0063213, 0.018424, 0.017084, -0.024088, -0.0055887, 0.0081125, -0.025487, 0.0053125, -0.0093875, -0.0037875, -0.02153, -0.033396, -0.019537, 0.018883, -0.0095068, -0.021288, 0.0067125, 0.0074125, -0.039837, 0.015158, 0.0091625, -0.018138, 6.2503e-05, -0.019537, 0.020362, -0.020588, -0.027238, 0.0052395, -0.0090504, -0.00081956, 0.024658, -0.018488], 'colorscale': 'Peach', 'opacity': 0.8, 'size': 3}, 'mode': 'markers', 'name': 'Point cloud', 'opacity': 0.8}, kwargs_layout={'height': 1000, 'template': 'plotly_dark', 'title': {'text': 'A cycle before and after optimization'}, 'width': 1200})[source]

Generates a Plotly figure comparing an initial cycle representative with an optimal cycle representative.

Parameters:
  • boundary_matrix_decomposition (oat_python.core.vietoris_rips.BoundaryMatrixDecomposition)

  • birth_simplex (list or tuple of int) – The birth simplex of the persistent homology class whose cycle representative is to be compared.

  • points (indexable) – An object that maps integer vertex labels to 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 3).

  • kwargs_initial (dict, optional) –

    Additional keyword arguments to pass to the Plot for the initial cycle. These arguments are passed to the plotly.graph_objects.Scatter3d constructor. The only keywords which are set by default are

    • line="white"

    • name="Initial cycle"

  • kwargs_optimal (dict, optional) –

    Additional keyword arguments to pass to the Plot for the optimal cycle. These arguments are passed to the plotly.graph_objects.Scatter3d constructor. The only keywords which are set by default are

    • line="crimson"

    • name="Optimal cycle"

  • kwargs_surface (dict, optional) –

    Additional keyword arguments to pass to the Plot for the surface between the cycles. These arguments are passed to the plotly.graph_objects.Mesh3d constructor. The only keywords which are set by default are

    • opacity=0.5

    • color="white"

    • name="Surface between cycles".

  • kwargs_points (dict, optional) –

    Additional keyword arguments to pass to the Plot for the point cloud. These arguments are passed to the plotly.graph_objects.Scatter3d constructor. The keywords which are set by default are as follows (points are slightly transparent and colored by their y-coordinate):

    • mode="markers"

    • marker=dict(opacity=0.8, size=3, color=[point[1] for point in points], colorscale="Peach")

    • opacity=0.8

    • name="Point cloud".

  • kwargs_layout (dict, optional) –

    Additional keyword arguments to pass to the Plot layout. If None is provided, then background color is set to black, and gridlines, tick labels, and axis titles are removed. If an empty dictionary is provided, then the default Plotly layout is used. The keywords which are set by default are

    • title=dict(text="A cycle before and after optimization")

    • template="plotly_dark"

    • height=1000

    • width=1200.

Returns:

fig – A Plotly figure comparing the initial and optimal cycle representatives, along with the surface between them and the underlying point cloud.

Return type:

plotly.graph_objs.Figure

Example

See Persistent Homology: Stanford Dragon for an example.

Notes

  • To view the source code for this funciton, click the “[source]” link to the right of the function signature at the top of this docstring.

oat_python.plot.display_dataframes_side_by_side(*dfs, titles=())[source]

Display multiple pandas DataFrames side by side in a Jupyter notebook.

Parameters:
  • *dfs (pandas.DataFrame) – One or more DataFrames to display side by side.

  • titles (iterable of str, optional) – Titles for each DataFrame. If provided, must match the number of DataFrames.

Returns:

Displays the DataFrames side by side in the notebook.

Return type:

None

Example

import pandas as pd
from oat_python.plot import display_side_by_side

df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4, 5]})
df2 = pd.DataFrame({'C': [5, 6], 'D': [7, 8, 9]})
display_side_by_side(df1, df2, titles=['First DataFrame', 'Second DataFrame'])
oat_python.plot.fig_3d_for_simplices(simplices, points, kwargs_points={'marker': {'color': 'white', 'size': 5}, 'mode': 'markers', 'name': 'Vertices', 'text': ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', '117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', '137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', '157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', '177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', '197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', '217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', '237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', '257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', '277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', '297', '298', '299', '300', '301', '302', '303', '304', '305', '306', '307', '308', '309', '310', '311', '312', '313', '314', '315', '316', '317', '318', '319', '320', '321', '322', '323', '324', '325', '326', '327', '328', '329', '330', '331', '332', '333', '334', '335', '336', '337', '338', '339', '340', '341', '342', '343', '344', '345', '346', '347', '348', '349', '350', '351', '352', '353', '354', '355', '356', '357', '358', '359', '360', '361', '362', '363', '364', '365', '366', '367', '368', '369', '370', '371', '372', '373', '374', '375', '376', '377', '378', '379', '380', '381', '382', '383', '384', '385', '386', '387', '388', '389', '390', '391', '392', '393', '394', '395', '396', '397', '398', '399', '400', '401', '402', '403', '404', '405', '406', '407', '408', '409', '410', '411', '412', '413', '414', '415', '416', '417', '418', '419', '420', '421', '422', '423', '424', '425', '426', '427', '428', '429', '430', '431', '432', '433', '434', '435', '436', '437', '438', '439', '440', '441', '442', '443', '444', '445', '446', '447', '448', '449', '450', '451', '452', '453', '454', '455', '456', '457', '458', '459', '460', '461', '462', '463', '464', '465', '466', '467', '468', '469', '470', '471', '472', '473', '474', '475', '476', '477', '478', '479', '480', '481', '482', '483', '484', '485', '486', '487', '488', '489', '490', '491', '492', '493', '494', '495', '496', '497', '498', '499', '500', '501', '502', '503', '504', '505', '506', '507', '508', '509', '510', '511', '512', '513', '514', '515', '516', '517', '518', '519', '520', '521', '522', '523', '524', '525', '526', '527', '528', '529', '530', '531', '532', '533', '534', '535', '536', '537', '538', '539', '540', '541', '542', '543', '544', '545', '546', '547', '548', '549', '550', '551', '552', '553', '554', '555', '556', '557', '558', '559', '560', '561', '562', '563', '564', '565', '566', '567', '568', '569', '570', '571', '572', '573', '574', '575', '576', '577', '578', '579', '580', '581', '582', '583', '584', '585', '586', '587', '588', '589', '590', '591', '592', '593', '594', '595', '596', '597', '598', '599', '600', '601', '602', '603', '604', '605', '606', '607', '608', '609', '610', '611', '612', '613', '614', '615', '616', '617', '618', '619', '620', '621', '622', '623', '624', '625', '626', '627', '628', '629', '630', '631', '632', '633', '634', '635', '636', '637', '638', '639', '640', '641', '642', '643', '644', '645', '646', '647', '648', '649', '650', '651', '652', '653', '654', '655', '656', '657', '658', '659', '660', '661', '662', '663', '664', '665', '666', '667', '668', '669', '670', '671', '672', '673', '674', '675', '676', '677', '678', '679', '680', '681', '682', '683', '684', '685', '686', '687', '688', '689', '690', '691', '692', '693', '694', '695', '696', '697', '698', '699', '700', '701', '702', '703', '704', '705', '706', '707', '708', '709', '710', '711', '712', '713', '714', '715', '716', '717', '718', '719', '720', '721', '722', '723', '724', '725', '726', '727', '728', '729', '730', '731', '732', '733', '734', '735', '736', '737', '738', '739', '740', '741', '742', '743', '744', '745', '746', '747', '748', '749', '750', '751', '752', '753', '754', '755', '756', '757', '758', '759', '760', '761', '762', '763', '764', '765', '766', '767', '768', '769', '770', '771', '772', '773', '774', '775', '776', '777', '778', '779', '780', '781', '782', '783', '784', '785', '786', '787', '788', '789', '790', '791', '792', '793', '794', '795', '796', '797', '798', '799', '800', '801', '802', '803', '804', '805', '806', '807', '808', '809', '810', '811', '812', '813', '814', '815', '816', '817', '818', '819', '820', '821', '822', '823', '824', '825', '826', '827', '828', '829', '830', '831', '832', '833', '834', '835', '836', '837', '838', '839', '840', '841', '842', '843', '844', '845', '846', '847', '848', '849', '850', '851', '852', '853', '854', '855', '856', '857', '858', '859', '860', '861', '862', '863', '864', '865', '866', '867', '868', '869', '870', '871', '872', '873', '874', '875', '876', '877', '878', '879', '880', '881', '882', '883', '884', '885', '886', '887', '888', '889', '890', '891', '892', '893', '894', '895', '896', '897', '898', '899', '900', '901', '902', '903', '904', '905', '906', '907', '908', '909', '910', '911', '912', '913', '914', '915', '916', '917', '918', '919', '920', '921', '922', '923', '924', '925', '926', '927', '928', '929', '930', '931', '932', '933', '934', '935', '936', '937', '938', '939', '940', '941', '942', '943', '944', '945', '946', '947', '948', '949', '950', '951', '952', '953', '954', '955', '956', '957', '958', '959', '960', '961', '962', '963', '964', '965', '966', '967', '968', '969', '970', '971', '972', '973', '974', '975', '976', '977', '978', '979', '980', '981', '982', '983', '984', '985', '986', '987', '988', '989', '990', '991', '992', '993', '994', '995', '996', '997', '998', '999']}, kwargs_edges={'line': {'color': 'white', 'width': 4}, 'mode': 'lines', 'name': 'Edges'}, kwargs_triangles={'color': 'orange', 'name': 'Triangles', 'opacity': 0.3, 'showlegend': True}, kwargs_layout={})[source]

Plots a collection of simplices in 3D.

Parameters:
  • simplices (iterable of sequence of int, shape (n_simplices, k)) – An iterable (e.g., list or array) where each element is a sequence of integers, representing the vertices of a simplex.

  • points (indexable) – An object that maps integer vertex labels to 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 3).

  • kwargs_points (dict, optional) –

    Additional keyword arguments to pass to the Plot for vertices. These arguments are passed to the plotly.graph_objects.Scatter3d constructor. The only keywords which are set by default are

    • mode = 'markers'

    • marker = dict(size=6, color="crimson")

    • text = [ str(point_index) for point_index in points.keys() ] if points is a dictionary and text = [ str(p) for p in range(len(points)) ] if points is a list or array

    • name = "Vertices"

  • kwargs_edges (dict, optional) –

    Additional keyword arguments to pass to the Plot for edges. These arguments are passed to the plotly.graph_objects.Scatter3d constructor. The only keywords which are set by default are

    • mode="lines"

    • line = dict(color="crimson", width=4)

    • name = "Edges"

  • kwargs_triangles (dict, optional) –

    Additional keyword arguments to pass to the Plot for triangles. These arguments are passed to the plotly.graph_objects.Mesh3d constructor. The only keywords which are set by default are

    • opacity = 0.2

    • showlegend = True

    • name = "Triangles"

  • kwargs_layout (dict (default: None)) –

    Additional keyword arguments to pass to the Plot layout. - If None is provided, then background color is set to white, and gridlines, tick labels, and axis titles are removed. - If an empty dictionary is provided, then the default Plotly layout is used. - NOTE The layout can be modified post-hoc for customization. Some examples include:

    • fig.update_layout(template="plotly_dark") for a dark theme with light-colored legend text and grid lines

    • oat_python.set_background_color(fig, background_color="navy") for a navy background with light-colored legend text and grid lines

    NOTE If you’d like a white or black background without gridlines, use oat_python.plot.set_background_color(fig, color="white") or oat_python.plot.set_background_color(fig, color="black").

Returns:

fig – A Plotly figure for the the simplices

Return type:

plotly.graph_objs.Figure

Example

See the Styling in 3D gallery for examples and styling.

oat_python.plot.is_dark_color(color, threshold=128)[source]

Determines if a color is “dark” based on its perceived brightness. Supports hex, color names, and ‘rgb(r,g,b)’ strings.

Calculates brightness using the formula: brightness = 0.2126*R + 0.7152*G + 0.0722*B where R, G, and B are the red, green, and blue components (0-255).

Parameters:
  • color (str) – The color to evaluate. Can be a hex string (e.g., ‘#RRGGBB’), a color name (e.g., ‘red’), or an ‘rgb(r,g,b)’ string.

  • threshold (int, optional) – Brightness threshold (0-255) below which a color is considered dark. Default is 128.

Return type:

bool

Examples

>>> is_dark_color('#000000')
True
>>> is_dark_color('#FFFFFF')
False
>>> is_dark_color('#0000FF')
True
>>> is_dark_color('#FFFF00')
False
>>> is_dark_color('white')
False
>>> is_dark_color('rgb(50,50,50)')
True
>>> is_dark_color('rgb(200,200,200)')
False
oat_python.plot.mesh_rectangle(x0, x1, y0, y1, z0, z1)[source]

Generate a Plotly Mesh3d trace for a rectangle of form [x0, x1] x [y0, y1] x [z0, z1].

Parameters:
  • x0 (float) – x coordinate of the left edge.

  • x1 (float) – x coordinate of the right edge.

  • y0 (float) – y coordinate of the bottom edge.

  • y1 (float) – y coordinate of the top edge.

  • z0 (float) – z coordinate of the near edge.

  • z1 (float) – z coordinate of the far edge.

Returns:

trace – A Plotly Mesh3d trace for the rectangle.

Return type:

plotly.graph_objs.Mesh3d

Notes

This method is under review for deprecation, as it tends to produce poor results (e.g., poor shadowing and seams at non-right angles). Consider using surface_rectangle as an alternative.

oat_python.plot.persistence_diagram(persistent_homology_dataframe, guideline_limit=None)[source]

Create a Plotly figure for a persistence diagram.

Parameters:
  • persistent_homology_dataframe (pandas.DataFrame) – DataFrame with numeric columns labeled birth, death, and dimension. Optionally, may include birth simplex, num_cycle_simplices, and num_bounding_simplices columns for richer hovertext.

  • guideline_limit (float, optional) – If provided, sets the upper limit for the diagram guidelines. The diagonal guideline is drawn at 1.2 × guideline_limit, and the horizontal guideline at 1.1 × guideline_limit. If not provided, the function determines suitable limits from the data.

Returns:

fig – A Plotly figure displaying the persistence diagram.

Return type:

plotly.graph_objs.Figure

Notes

  • Each point represents a persistent feature, colored by its homology dimension.

  • Hovering over a point shows detailed information, including birth/death filtration, interval length, birth simplex, and (if present) cycle and bounding chain sparsity.

  • Infinite death values are replaced by a finite proxy for plotting.

  • The function adds diagonal and horizontal guideline lines for visual reference.

Example

import pandas as pd
from oat_python.plot import persistence_diagram

persistent_homology_dataframe = pd.DataFrame({
    "birth_filtration": [0.1, 0.2],
    "death_filtration": [0.5, float("inf")],
    "dimension": [0, 1],
    "birth_simplex": [(0,), (1,)],
})
fig     =   persistence_diagram(
                persistent_homology_dataframe
            )
fig
oat_python.plot.persistence_diagram_guidelines(upper_limit)[source]

Generate Plotly guideline traces for a persistence diagram.

Given a scalar value upper_limit, this function returns two Plotly Scatter traces: - A solid diagonal line segment from (0, 0) to (upper_limit, upper_limit). - A dashed horizontal guideline from (0, upper_limit) to (upper_limit, upper_limit).

Parameters:

upper_limit (float) – The upper bound for the guideline lines in the persistence diagram.

Returns:

  • traced (plotly.graph_objs.Scatter) – Scatter trace for the diagonal line segment (0, 0) – (upper_limit, upper_limit), solid.

  • traceh (plotly.graph_objs.Scatter) – Scatter trace for the horizontal line segment (0, upper_limit) – (upper_limit, upper_limit), dashed.

Example

import plotly.graph_objects as go
from oat_python.plot import persistence_diagram_guidelines

traced, traceh = persistence_diagram_guidelines(1.0)
fig = go.Figure([traced, traceh])
fig
oat_python.plot.set_background_color(fig, background_color='white', font_color=None, blank_background=True)[source]

Set the background color of a Plotly figure.

Parameters:
  • fig (plotly.graph_objs.Figure) – A Plotly Figure object containing a 3D scatter or surface plot.

  • background_color (str (default="white")) – The desired background color.

  • font_color (str (default=None)) –

    • The desired font color for the text (legend, axes, titles, etc.).

    • If None, then the function will check if the provided background color is dark or light and set the font color accordingly (white for dark backgrounds, black for light backgrounds). The test for darkness is oat_python.plot.is_dark_color(background_color).

  • blank_background (bool (default=True)) – If True, the function will call blank_background() to remove grid lines, tick labels, and axis titles from the figure.

Returns:

The function modifies the input figure in place.

Return type:

None

Notes

  • Colors can be specified using any format accepted by Plotly (e.g., “crimson”, “#FF0000”, “rgb(255,0,0)”).

  • For dark plots the user may wish to combine this method with fig.update_layout(template="plotly_dark") to ensure that axis lines and text are also rendered in light colors.

Example

See the Styling in 3D gallery for examples and styling.

oat_python.plot.surface_cube(x0, y0, z0, width=1, anchor='center')[source]

Generate a Plotly Surface trace for a 3-dimensional cube.

The cube has side length equal to width and is positioned according to the anchor point.

Parameters:
  • x0 (float) – x coordinate of the anchor point.

  • y0 (float) – y coordinate of the anchor point.

  • z0 (float) – z coordinate of the anchor point.

  • width (float, optional) – Side length of the cube. Default is 1.

  • anchor ({'left', 'center'}, optional) – If anchor='left', the anchor point is the vertex with minimal x, y, and z coordinates. If anchor='center', the anchor point is the center of the cube. Default is ‘center’.

Returns:

  • trace (plotly.graph_objs.Surface) – A Plotly Surface trace for the cube.

  • x (numpy.ndarray) – The x coordinates of the cube mesh.

  • y (numpy.ndarray) – The y coordinates of the cube mesh.

  • z (numpy.ndarray) – The z coordinates of the cube mesh.

Notes

This is a convenience wrapper around the surface_rectangle function. The cube is defined as [x0, x0+width] x [y0, y0+width] x [z0, z0+width] if anchor='left', or centered at (x0, y0, z0) if anchor='center'.

Example

trace, x, y, z = surface_cube(0, 0, 0, width=2, anchor="center")
oat_python.plot.surface_octahedron()[source]

A Plotly Surface trace for an octahedron. The octahedron is a polyhedron with eight triangular faces, twelve edges, and six vertices.

The octahedron is defined by the following vertices: - (1, 0, 0) - (-1, 0, 0) - (0, 1, 0) - (0, -1, 0) - (0, 0, 1) - (0, 0, -1)

oat_python.plot.surface_rectangle(x0, x1, y0, y1, z0, z1)[source]

A Plotly Surface trace for a 3-dimensional rectangle of form [x0,x1] x [y0,y1] x [z0,z1].

Returns one trace and three coordinate matrices: go.Surface(z=z, x=x, y=y), x, y, z. The coordinates tend to be useful for adjusting surface color.

Remark This tends to produce cleaner results than a Plotly mesh plot.

How it works

The visual intuition is to image a cloth 3 units wide and 4 units long being folded over the surface of a cube. The lefthand 3x3 units of cloth cover the top 5 faces of the cube, and the righthand 1x3 units tuck under to cover the base. Some squares collapse down to lines. For reference, calling

_, x, y, z = rectangle_trace(0,1,2,3,4,5)
print(x,"\n\n",y,"\n\n",z)

will return

[[0 0 1 1 0]
[0 0 1 1 0]
[0 0 1 1 0]
[0 0 1 1 0]]

[[2 2 2 2 2]
[2 2 2 2 2]
[3 3 3 3 3]
[3 3 3 3 3]]

[[4 4 4 4 4]
[4 5 5 4 4]
[4 5 5 4 4]
[4 4 4 4 4]]
oat_python.plot.surface_sphere(x, y, z, radius, resolution=20)[source]

Generate a Plotly Surface trace for a sphere.

Parameters:
  • x (float) – x coordinate of the center of the sphere.

  • y (float) – y coordinate of the center of the sphere.

  • z (float) – z coordinate of the center of the sphere.

  • radius (float) – Radius of the sphere.

  • resolution (int, optional) – Number of points in the discretization of the sphere; the higher the resolution, the smoother the sphere will look. Default is 20.

Returns:

  • trace (plotly.graph_objs.Surface) – A Plotly Surface trace for the sphere.

  • x (numpy.ndarray) – The x coordinates of the sphere mesh.

  • y (numpy.ndarray) – The y coordinates of the sphere mesh.

  • z (numpy.ndarray) – The z coordinates of the sphere mesh.

Notes

The sphere is discretized using spherical coordinates. The u parameter represents the azimuthal angle (longitude) and the v parameter represents the polar angle (latitude). The x, y, and z coordinates are then computed using the formulas:

x = radius * np.cos(u) * np.sin(v) + x
y = radius * np.sin(u) * np.sin(v) + y
z = radius * np.cos(v) + z

The resulting coordinates are then used to create a Plotly Surface trace.

oat_python.plot.trace_2d_for_edge(edge, points, **kwargs)[source]

Generate a 2D Plotly Scatter (plotly.graph_objects.Scatter) trace for a single edge.

Parameters:
  • edge (sequence of int, length 2) – A sequence (e.g., list, tuple, array) of two integers, representing the vertices of the edge.

  • points (indexable) – An object that maps integer vertex labels to 2D or 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 2) or (n_vertices, 3).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter constructor. See Plotly documentation for details. The only keyword which is set by default is mode="lines".

Returns:

trace – A Plotly Scatter trace for the edge, with an “extra” vertex in the center (which is invisible but allows the user to view data when the cursor passes over the center point; see below for an example).

Return type:

plotly.graph_objs.Scatter

Notes

  • For fine-grained control, edges are returned one-by-one rather than as a single trace.

  • You can simulate grouped toggling in Plotly by setting the legendgroup property on each trace.

  • To change the color of the plot, use trace.update(line_color="black") or another color.

  • To add custom hover information, set the text field of the returned trace and set hoverinfo="text" or hovertemplate as desired.

Examples

See Edges in 2D.

oat_python.plot.trace_2d_for_edges(edges, points, **kwargs)[source]

Generate a 2D scatter trace (plotly.graph_objects.Scatter) for a collection of edges.

Parameters:
  • edges (iterable of sequence of int, shape (n_edges, 2)) – An iterable (e.g., list or array) where each element is a sequence of two integers, representing the vertices of an edge.

  • points (indexable) – An object that maps integer vertex labels to 2D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 2).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter constructor. See Plotly documentation for details. The only keyword which is set by default is mode="lines".

Returns:

trace – A Plotly Scatter trace containing all edges.

Return type:

plotly.graph_objs.Scatter

Notes

  • Values passed in **kwargs can be updated later using trace.update(...).

  • This method is slightly less flexible than repeated calls to trace_2d_for_edge, which allows for greater customization, but is kept for convenience and as an example of plotting multiple disjoint edges in a single trace.

Examples

See Edges in 2D.

Notes

The trace returned by this function can be updated later using trace.update(...). In order to perform this update it is helpful to know how the trace is constructed. In fact, trace_2d_for_edges() performs only minimal processing:

  • Clicke the “[source]” link to the right of the function name, above, to view the source code.

  • A copy is also provided below for convenience, but this copy may become outdated if the function is updated in the future, so refer to the source link as the authoritative resource.

  • Note that multiple disjoint line segments are created by separating pairs of endpoint coordinates (x0,y0),(x1,y1) values with None.

def trace_2d_for_edges( edges, points, **kwargs ):
    x       =   []
    y       =   []
    for edge in edges:
        x = x + [ points[edge[0]][0], points[edge[1]][0], None ]
        y = y + [ points[edge[0]][1], points[edge[1]][1], None ]
    if not 'mode' in kwargs.keys():
        kwargs['mode'] = "lines"
    return go.Scatter(x=x,y=y, **kwargs)
oat_python.plot.trace_2d_for_triangle(triangle=[], points=[], **kwargs)[source]

Generates a filled Plotly trace for a triangle in 2D.

Parameters:
  • triangle (iterable of int, length 3) – Indices of the triangle’s vertices.

  • points (indexable) – An object that maps integer vertex labels to 2D or 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 2) or (n_vertices, 3).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter constructor. See Plotly documentation for details. The only keywords which are set by default are fill="toself" and mode="none".

Returns:

trace – A Plotly Scatter trace representing the filled triangle.

Return type:

plotly.graph_objs.Scatter

Notes

  • Values passed in **kwargs can be updated later using trace.update(...).

Examples

See Triangles in 2D.

oat_python.plot.trace_2d_for_triangles(triangles=[], points=[], single_trace=True, **kwargs)[source]

Generates Plotly traces for a collection of triangles in 2D.

Parameters:
  • triangles (iterable of iterable of int, shape (n_triangles, 3)) – An iterable (e.g., list or array) where each element is a sequence of three integers, representing the indices of the triangle’s vertices.

  • points (indexable) – An object that maps integer vertex labels to 2D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 2).

  • single_trace (bool, optional) – If True, returns a single Plotly Scatter trace containing all triangles (separated by None values). If False, returns a list of individual Scatter traces, one per triangle. Default is True.

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter constructor. See Plotly documentation for details. The only keyword which is set by default is fill="toself".

Returns:

If single_trace is True, returns a single trace. If False, returns a list of such traces, one for each triangle. Each trace has type Plotly Scatter with fill="toself".

Return type:

trace or list of traces

Notes

  • Values passed in **kwargs can be updated later using trace.update(...).

Warning

Plotly may yield unexpected behavior when triangles overlap. In particular, in overlapping regions the color fill may disappear. This can be observed in the code example below.

Examples

See Triangles in 2D.

oat_python.plot.trace_2d_for_vertices(points, **kwargs)[source]

Generate a 2D Plotly Scatter (plotly.graph_objects.Scatter) trace for a collection of vertices.

Parameters:
  • points (indexable) – An object that maps integer vertex labels to 2D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 2).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter constructor. See Plotly documentation for details. The only keyword which is set by default is mode="markers".

Returns:

trace – A Plotly Scatter trace for the vertices.

Return type:

plotly.graph_objs.Scatter

Notes

This function provides minimal processing, and is provided simply for convenience. Check out the source code by clicking the “[source]” link to the right of the function signature at the top of this docstring.

oat_python.plot.trace_3d_for_edge(edge, points, **kwargs)[source]

Generate a 3D Plotly Scatter3d trace (plotly.graph_objects.Scatter3D) for a single edge.

Parameters:
  • edge (sequence of int, length 2) – A sequence (e.g., list, tuple, array) of two integers, representing the vertices of the edge.

  • points (indexable) – An object that maps integer vertex labels to 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 3).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter3d constructor. See Plotly documentation for details. The only keyword which is set by default is mode="lines".

Returns:

trace – A Plotly Scatter3d trace for the edge, with an “extra” vertex in the center (which is invisible but allows the user to view data when the cursor passes over the center point; see below for an example).

Return type:

plotly.graph_objs.Scatter3d

Examples

See Edges in 3D.

Notes

The trace returned by this function can be updated later using trace.update(...). In order to perform this update it is helpful to know how the trace is constructed. In fact, trace_3d_for_edge() performs only minimal processing:

  • Check out the full source code by clicking the “[source]” link to the right of the function name, above

  • A copy is also provided below for convenience, but this copy may become outdated if the function is updated in the future, so refer to the source link as the authoritative resource.

  • Notice that an extra vertex is added at the midpoint of the edge, which allows the user to hover over the center of the edge and see hover text (if provided).

def trace_3d_for_edge( edge, points, **kwargs ):
    x0, x1  =   points[edge[0]][0], points[edge[1]][0]
    y0, y1  =   points[edge[0]][1], points[edge[1]][1]
    z0, z1  =   points[edge[0]][2], points[edge[1]][2]
    x       =   [ x0, (x0+x1)/2, x1 ]
    y       =   [ y0, (y0+y1)/2, y1 ]
    z       =   [ z0, (z0+z1)/2, z1 ]
    if not 'mode' in kwargs.keys():
        kwargs['mode'] = "lines"
    return go.Scatter3d(x=x,y=y,z=z, **kwargs)
oat_python.plot.trace_3d_for_edges(edges, points, **kwargs)[source]

Generate a 3D scatter trace (plotly.graph_objects.Scatter3D) for a collection of edges.

Parameters:
  • edges (iterable of sequence of int, shape (n_edges, 2)) – An iterable (e.g., list or array) where each element is a sequence of two integers, representing the vertices of an edge.

  • points (indexable) – An object that maps integer vertex labels to 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 3).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter3d constructor. See Plotly documentation for details. The only keyword which is set by default is mode="lines".

Returns:

trace – A Plotly Scatter3d trace containing all edges.

Return type:

plotly.graph_objs.Scatter3d

Notes

Individual edges cannot be assigned separate colors in a single trace. If different colors are desired, create separate traces for each edge. See Edges in 2D for an example.

The trace returned by this function can be updated later using trace.update(...). In order to perform this update it is helpful to know how the trace is constructed. In fact, trace_2d_for_edges() performs only minimal processing.

  • Check out the full source code by clicking the “[source]” link to the right of the function name, above.

  • A copy is also provided below for convenience, but this copy may become outdated if the function is updated in the future, so refer to the source link as the authoritative resource.

  • Note that multiple disjoint line segments are created by separating pairs of endpoint coordinates (x0,y0,z0),(x1,y1,z1) values with None.

def trace_3d_for_edges( edges, points, **kwargs ):
    x       =   []
    y       =   []
    z       =   []
    for edge in edges:
        x = x + [ points[edge[0]][0], points[edge[1]][0], None ]
        y = y + [ points[edge[0]][1], points[edge[1]][1], None ]
        z = z + [ points[edge[0]][2], points[edge[1]][2], None ]
    if not 'mode' in kwargs.keys():
        kwargs['mode'] = "lines"
    return go.Scatter3d(x=x,y=y,z=z, **kwargs)

Examples

See Edges in 3D.

oat_python.plot.trace_3d_for_triangles(triangles=[], points=[], **kwargs)[source]

Generate a 3D mesh trace (plotly.graph_objects.Mesh3D) for a collection of triangles in 3D.

Parameters:
  • triangles (array-like of shape (n_triangles, 3)) – An array or list of lists of integers, where each inner list contains three indices referring to the vertices of a triangle.

  • points (indexable object) – An indexable object (such as a dictionary or array) that maps vertex indices to x-y-z coordinates, e.g., a dictionary of tuples or a NumPy array of shape (n_vertices, 3).

  • **kwargs

    Additional keyword arguments to pass to the Plotly Mesh3d constructor.

    • See Plotly documentation for details.

    • Caution: The keyword arguments vertexcolor, intensity, text, and hovertext are handled specially, see below for details.

Returns:

trace – A single Plotly Mesh3d trace containing all triangles.

Return type:

plotly.graph_objs.Mesh3d

Examples

See Triangles in 3D.

Assigning values to vertices

TL;DR

If you want to set values for the vertexcolor, intensity, text, or hovertext keyword arguments in a plot created by this function, there are two different options:

  1. Pass these arguments directly to the function, via the **kwargs argument. In this case there are no special requirements, simply pass an indexable object (e.g., list, array, or dictionary) with values for all vertices that appear in the triangles argument. Aside: this functionality is actually a bit more flexible than the normal Plotly Mesh3d constructor, because you can pass values for only the vertices that appear in the triangles, rather than for all vertices from 0 to N.

  2. Update the returned trace, e.g., trace.update(vertexcolor=...). In this case you can only pass

    lists or arrays, e.g. [color0, color1, ..., colorN] where colori is the color assigned to the i`th largest vertex value. For example, if ``triangles = [(3,5,11), (5,7,8)]`, then

    • color0 is the color assigned to vertex 3

    • color1 is the color assigned to vertex 5

    • color2 is the color assigned to vertex 7

    • color3 is the color assigned to vertex 8

    • color4 is the color assigned to vertex 11

    To obtain the list of vertex labels in sorted order, you can use one of the following methods:

    • vertex_labels = sorted(list(set().union(*triangles)))

    • vertex_labels = oat_python.simplex.vertices_incident_to_simplices(triangles)

    • (after creating the trace) vertex_labels = trace.meta['vertex_labels']

Technical background

Plotly allows you to assign values to vertices for color and hover text by passing lists, e.g. [color0, color1, ...]. In order to use these arguments, you must know which vertex corresponds to each color or size value in the list. That is, you need a list of vertex labels [v0, v1, ..., vN].

In the normal usage of Plotly Mesh3d plots this is not a problem. The Mesh3d constructor takes x, y, and z arguments, which are lists of the x, y, and z coordinates of each vertex, respectively, together with i, j, and k arguments, which are lists of the vertex indices for each triangle. For example, if i = [0, 1, 2], j = [1, 2, 0], and k = [2, 0, 1], then the triangles are (v0, v1, v2), (v1, v2, v0), and (v2, v0, v1). The coordinates of vertex vi are (x[i], y[i], z[i]). So the list of vertex labels is simply 0, 1, 2, …, N.

This is the only format in which Plotly Mesh3d plots can be created, so there’s no functionality to pass a single triangle (3,5,7) together with x-y-z coordinates for just the vertices 3, 5, and 7. In order to work around this limitation, the oat_python.plot.trace_3d_for_triangles() function reassigns vertex labels as needed, so that the set of all vertex labels forms a contiguous sequence 0, 1, 2, ... N. It then permutes the x, y, z values appropriately, and discards any x-y-z coordinates that are not needed. (Discarding unused coordinates is one of the main motivations for using this function.)

So, if you ever want to modify a trace produced by oat_python.plot.trace_3d_for_triangles(), you need to know the original vertex label for each of the vertices labeled 0, 1, 2, ... N in the trace. There are several ways to obtain this list:

  • place the set of all vertex labels into a list and sort it, e.g., vertex_labels = sorted(list(set().union(*triangles))).

  • call oat_python.simplex.vertices_incident_to_simplices(triangles)

  • (after creating the trace) look up trace.meta['vertex_labels']

Any one of these methods will give you a list [v0, v1, ..., vN], where vi is the original label of the vertex that was relabeled as i.

If you pass values for vertexcolor, intensity, text, or hovertext to oat_python.plot.trace_3d_for_triangles() via the **kwargs argument, then the function will take care of relabeling the values appropriately, so you can simply pass an indexable object (e.g., list, array, or dictionary) with values for all vertices that appear in the triangles argument. Otherwise use the list [v0, v1, ..., vN] to assign values to vertices in the trace after it has been created.

oat_python.plot.trace_3d_for_vertices(points, **kwargs)[source]

Generate a 3D Plotly Scatter3d trace (plotly.graph_objects.Scatter3D) for a collection of vertices.

Parameters:
  • points (indexable) – An object that maps integer vertex labels to 3D coordinates, e.g., a dictionary of tuples, a list of coordinate tuples, or a NumPy array of shape (n_vertices, 3).

  • **kwargs – Additional keyword arguments to pass to the Plotly Scatter3d constructor. See Plotly documentation for details. The only keyword which is set by default is mode="markers".

Returns:

trace – A Plotly Scatter3d trace for the vertices.

Return type:

plotly.graph_objs.Scatter3d

Notes

This function provides minimal processing, and is provided simply for convenience. Check out the source code by clicking the “[source]” link to the right of the function signature at the top of this docstring.

oat_python.plot.vertex_embedding_for_networkx_graph(G, dimension=2, method='spring', **kwargs)[source]

Computes an embedding of the nodes of a NetworkX graph.

Parameters:
  • G (networkx.Graph) – A NetworkX graph whose nodes will be embedded.

  • dimension (int, optional) – The dimension of the embedding space (e.g., 2 for planar, 3 for 3D). Default is 2.

  • method (str, (optional, default: "spring")) –

    The method used to generate the embedding. The options are:

    • ”spring”: Use a spring layout to position nodes before computing hop distances.

    • ”hop_mds”: Uses multidimensional scaling (MDS) applied to the hop distance matrix. The hop distance between nodes is the shortest path length in the graph.

  • **kwargs

    Additional keyword argumentsto

Returns:

coords – A dictionary mapping each vertex label to its coordinates in the embedding (as a NumPy array of length dimension).

Return type:

dict

Example

import networkx as nx
from oat_python.plot import vertex_embedding_for_networkx_graph
import plotly.graph_objects as go

G = nx.path_graph([0, 1, 2, 3])
coords = vertex_embedding_for_networkx_graph(G, dimension=2)
print(coords)

# 2D Plotly scatter plot of the embedding
x = [coords[v][0] for v in G.nodes]
y = [coords[v][1] for v in G.nodes]
fig = go.Figure(go.Scatter(x=x, y=y, mode="markers+text", text=list(G.nodes)))
fig.update_layout(title="2D MDS Embedding of Graph Nodes")
fig
oat_python.plot.vertex_embedding_for_simplices(simplices, dimension=2, method='hop_mds', **kwargs)[source]

Computes an embedding of the vertices of a collection of simplices.

Parameters:
  • simplices (list of list of int) – A list of simplices, where each simplex is represented as a list of vertex indices.

  • dimension (int, optional) – The dimension of the embedding space (e.g., 2 for planar, 3 for 3D). Default is 2.

  • method (str (optional, default: "spring")) –

    The method used to generate the embedding. The options are:

    • ”spring”: Use a spring layout to position nodes before computing hop distances.

    • ”hop_mds”: Uses multidimensional scaling (MDS) applied to the hop distance matrix. The hop distance between nodes is the shortest path length in the graph.

  • **kwargs

    Additional keyword argumentsto

    • if method = "spring" these arguments pass to the networkx.spring_layout function. Examples include

      • iterations the maximum number of iterations to perform (default: 50).

      • seed for reproducibility.

      • complete list: `networkx.spring_layout documentation <https://networkx.org/documentation/stable/reference/generated/networkx.drawing.layout.spring_layout.html>_

    • if method = "hop_mds" these arguments pass to the sklearn.manifold.MDS constructor. Examples include

      • max_iter the maximum number of iterations to perform (default: 300).

      • random_state for reproducibility.

      • complete list: sklearn.manifold.MDS documentation <https://scikit-learn.org/stable/modules/generated/sklearn.manifold.MDS.html>_

Returns:

coords – A dictionary mapping each vertex label to its coordinates in the embedding (as a NumPy array of length dimension).

Return type:

dict

oat_python.plot.wire_rectangle(x0, x1, y0, y1, z0, z1)[source]

The edges (1-cells) of a 3d rectangle of form [x0,x1] x [y0,y1] x [z0,z1]

Return data:

a list of Plotly Scatter3d traces, in lines mode

oat_python.plot.wire_sphere_3d(x, y, z, radius, nlattitude, nlongitude)[source]

Plot a wire mesh sphere.

Parameters:
  • x (float) – x coordinate of the center of the sphere.

  • y (float) – y coordinate of the center of the sphere.

  • z (float) – z coordinate of the center of the sphere.

  • radius (float) – Radius of the sphere.

  • nlattitude (int) – Number of latitude lines (horizontal rings) to draw on the sphere.

  • nlongitude (int) – Number of longitude lines (vertical segments) to draw on the sphere.

Returns:

data – A list of Plotly Scatter3d traces. Each trace represents a latitude or longitude line, and together they form a wireframe mesh of the sphere. Pass this list to go.Figure(data) to visualize the wireframe sphere in 3D.

Return type:

list of plotly.graph_objs.Scatter3d

Notes

  • You can cause all these traces to toggle on/off together by calling trace.update(legendgroup="your_legend_group_name") on each trace; see the [Plotly legend documentation](https://plotly.com/python/legend/) for details and examples.

  • You can remove all but one of the traces from the legend by calling trace.update(showlegend=False) on the traces you wish to hide.

Example

import plotly.graph_objects as go
from oat_python.plot import wire_sphere_3d

traces = wire_sphere_3d(x=0, y=0, z=0, radius=1, nlattitude=10, nlongitude=20)
for trace in traces:
    trace.update(legendgroup="sphere", showlegend=False)
traces[0].update(showlegend=True, name="Wire Sphere")
fig = go.Figure(traces)
fig

Simplices

Functions for simplices and their faces.

oat_python.simplex.dimension_m_faces_as_rows_for_dimension_n_simplices_as_rows(dimension_n_simplices_as_rows, m=0, removeduplicatefaces=True)[source]
Parameters:
  • dimension_n_simplices_as_rows (ndarray) – a numpy array where each row represents a simplex

  • m – dimension of desired faces

  • removeduplicatefaces – if True, remove duplicate faces from the output (default True)

Return faces:

a numpy array whose rows represent the dimension-m faces of the simplices. These rows are NOT sorted in lexicographic order.

oat_python.simplex.dimension_m_faces_for_simplices(simplices=[], m=0)[source]

Return all dimension-m faces of the simplices provided

Parameters:
  • simplices – an iterable of iterables; each sub-iterable represents a simplex

  • m – dimension of desired faces

Return faces:

a list of tuples representing the collection of dimension-m faces. This list is sorted in lexicographic order.

oat_python.simplex.networkx_graph_for_simplices(simplices)[source]

Generate a NetworkX graph representing the 1-skeleton of a simplicial complex.

Parameters:

simplices (list of list of int) – A list where each inner list represents a simplex (a collection of vertices). Each vertex should be hashable (typically an int).

Returns:

G – A NetworkX graph where nodes are vertices, and edges connect any pair of vertices that appear together in a simplex (i.e., the 1-skeleton).

Return type:

networkx.Graph

Example

import networkx as nx
from oat_python.plot import networkx_graph_for_simplices

simplices = [[0, 1, 2], [2, 3]]
G = networkx_graph_for_simplices(simplices)
print(G.edges())
oat_python.simplex.vertices_incident_to_simplices(simplices)[source]

Given a list of simplices, return a sorted list of the vertices incident to these simplices.

Parameters:

simplices – an iterable of iterables; each sub-iterable represents a simplex

Return vertices:

a sorted list of the vertices incident to the simplices

Matrices

Functions for dense and sparse matrices.

oat_python.matrix.assert_almost_equal_csr(a, b, decimal, err_msg='')[source]

Assert that two CSR (Compressed Sparse Row) matrices are almost equal.

This function checks that the input matrices a and b have the same sparsity pattern (i.e., identical indptr and indices arrays) and that their explicitly stored data entries are equal up to a specified decimal precision.

Parameters:
  • a (scipy.sparse.csr_matrix) – The first CSR matrix to compare.

  • b (scipy.sparse.csr_matrix) – The second CSR matrix to compare.

  • decimal (int) – The number of decimal places to which the data entries are compared.

  • err_msg (str, optional) – The error message to display in case of failure.

Raises:

AssertionError – If the matrices do not have the same sparsity pattern or their data entries differ beyond the specified precision.

oat_python.matrix.assert_symmetric_triplets_csr(csr_matrix, err_msg='')[source]

Assert that the triplets of a CSR matrix are symmetric.

This function checks that for every triplet (i, j, value) in the CSR matrix, there exists a corresponding triplet (j, i, value) in the same matrix. If the matrix is not symmetric, an AssertionError is raised.

Parameters:
  • csr_matrix (scipy.sparse.csr_matrix) – The CSR matrix to check for symmetry.

  • err_msg (str, optional) – The error message to display in case of failure.

Raises:

AssertionError – If the CSR matrix is not symmetric.

oat_python.matrix.is_structurally_zero(matrix, i, j)[source]

Returns True if entry (i, j) is structurally zero in a scipy CSR matrix.

oat_python.matrix.minmax(matrix, return_row_and_column_indices=False)[source]

Returns the minimum of the maxima of the rows of an \(m \times n\) matrix \(A\). In symbols:

\[\min_{i} ( \max_{j} A_{ij} )\]
  • If \(m = 0\), then the minimum of the maxima is \(\infty\).

  • If \(m > 0\) and \(n = 0\), then the minimum of the maxima is \(-\infty\).

Parameters:
  • matrix (scipy.sparse.csr_matrix or numpy.ndarray) –

    A 2-dimensional matrix, either dense or sparse. If the matrix is scipy.sparse.csr_matrix, then

    • structural zero entries will be treated as positive infinity.

    • the matrix does not have to have sorted indices, as flagged by matrix.has_sorted_indices.

  • return_row_and_column_indices (bool, optional) – If True, returns a dictionary with the row and column indices of the minimum of the maxima, along with the minimum value. If False (default), returns only the minimum value.

Returns:

  • minmax_value (float) – If return_row_and_column_indices is False, returns the minimum of the maxima.

  • result (dict) –

    If return_row_and_column_indices is True, returns a dictionary with keys:

    • row: index \(i\) of the row where the minimum of the maxima occurs,

    • col: index \(j\) of the column where the maximum occurs,

    • minmax_value: the minmax value, equal to \(A_{ij}\).

Raises:
  • TypeError – If the input is not a scipy.sparse.csr_matrix or a numpy.ndarray.

  • Exception – If the input is not a 2-dimensional matrix.

oat_python.matrix.test_minmax()[source]

Unit tests for the minmax function.

This test suite covers the following cases: - Dense (NumPy ndarray) and sparse (scipy.sparse.csr_matrix) matrices. - Matrices with zero rows or zero columns. - Matrices where all entries are different. - Matrices where all entries are the same. - Sparse matrices with positive shape but no structural nonzero entries. - Sparse matrices with some rows or columns that have no structural nonzero entries.

The tests check both the value returned by minmax and the correctness of the returned row and column indices when return_row_and_column_indices=True.

oat_python.matrix.test_validate_square_and_symmetric_matrix()[source]

Unit test to check that a matrix is a numpy ndarray or scipy.sparse.csr_matrix, and that it is square and symmetric.

oat_python.matrix.triplets_for_csr(matrix, sorted=False)[source]

Returns all structural nonzero triplets (i, j, value) for a given sciyp CSR matrix.

This function is a wrapper around a simple block of code:

points = matrix.tocoo()
triplets = list(zip(points.row, points.col, points.data))
Parameters:
  • matrix (scipy.sparse.csr_matrix) – The input CSR matrix.

  • sorted (bool, optional) – If True, the triplets are sorted by (i, j) before returning. Default is False.

Returns:

triplets – A list of tuples (i, j, value) representing the structural non-zero entries of the matrix.

  • If sorted is True, the triplets are sorted lexicographically.

  • If matrix has sorted column indices (within each row), then triplets will be in sorted order even if sorted is False. See the cautionary note on sorting in glossary for more details.

Return type:

list of tuples

Example

import numpy as np
import scipy.sparse
from oat_python.matrix import triplets_for_csr

# Start with a dense matrix
dense = np.array([
    [1, 0, 0],
    [0, 2, 0],
    [0, 0, 3]
])
print("Dense matrix:")
print(dense)

# Convert to CSR
matrix = scipy.sparse.csr_matrix(dense)

# Get triplets
triplets = triplets_for_csr(matrix)
print("Triplets:", triplets)
# Output: [(0, 0, 1), (1, 1, 2), (2, 2, 3)]
oat_python.matrix.validate_square_and_symmetric_matrix(matrix)[source]

Validates that the input matrix is a square and symmetric matrix.

This function checks that the input is either a NumPy ndarray or a SciPy CSR sparse matrix, that it is two-dimensional and square (number of rows equals number of columns), and that it is exactly symmetric (i.e., matrix[i, j] == matrix[j, i] for all i, j).

Parameters:

matrix (numpy.ndarray or scipy.sparse.csr_matrix) – The matrix to validate.

Raises:
  • TypeError – If the input is not a NumPy ndarray or a SciPy CSR sparse matrix.

  • Exception – If the input is not two-dimensional, not square, or not exactly symmetric.

Dissimilarity

Dissimilarity tools, including distance matrices.

Dissimilarity metrics (including distance, inverse correlation, etc) play a major role in persistent homology calculations, and in particular in the construction of Vietoris Rips complexes. However, working with dissimilarity matrices can be onerous, especially when the matrices are large. This module provides a variety of tools to address some of the most common issues.

oat_python.dissimilarity.distance_iterator(points, reference_point)[source]

Iterates over the Euclidean distances from a reference point to every point in a point cloud.

Parameters:
  • points (array-like) – The point cloud, as a list of points or a numpy array of shape (num_points, dimension).

  • reference_point (array-like) – The reference point from which distances are measured.

Yields:

float – The Euclidean distance from the reference point to each point in the points.

oat_python.dissimilarity.enclosing_radius_for_cloud_slow(points, argminmax=False)[source]

Calculates the enclosing radius of a point cloud in a memory efficient manner (without generating and storing a copy of the distance matrix).

See also

oat_python.dissimilarity.enclosing_radius_for_points

This performs the same calculation but can be much faster (at the cost of small numerical error).

Exact compatibility with sparse_matrix_for_cloud_slow()

Most enclosing radius calculations need a small buffer to account for numerical error. However, this function is specifically designed to work together with the function sparse_matrix_for_cloud_slow(). In particular, the dissimilarity matrix sparse_matrix_for_cloud_slow( points, max_dissimilarity = enclosing_radius_for_cloud_slow(points) ) is gauranteed to have Vietoris Rips persistent homology isomorphic to the dissimilarity matrix sparse_matrix_for_cloud_slow( points, dissimilarity_masx = inf ).

Parameters:
  • points (array-like) – A point cloud represented as a list of points, e.g., a list of tuples or a numpy array of shape (num_points, dimension). Each slice points[i] will be treated as a point.

  • argminmax (bool, optional) – If True, returns a dictionary with the enclosing radius and the indices of the two points where it occurs. If False (default), returns only the enclosing radius.

Returns:

  • enclosing_radius (float) – If argminmax is False, returns the enclosing radius.

  • result (dict) –

    If argminmax is True, returns a dictionary with keys:
    • pointa: index of one point,

    • pointb: index of another point, which lies at distance enclosing_radius from point_a

    • enclosing_radius: the enclosing radius value.

oat_python.dissimilarity.enclosing_radius_for_matrix(matrix, validate_input=True, return_row_and_column_indices=False)[source]

Calculates the enclosing radius of a sparse dissimilarity matrix or dense dissimilarity matrix.

This function is a wrapper for the following code:

if validate_input:
    oat_python.matrix.validate_square_and_symmetric_matrix( matrix )

return oat_python.matrix.minmax(
    matrix,
    return_row_and_column_indices=return_row_and_column_indices,
)

Caution

If validate_input is False and the input is not a valid sparse dissimilarity matrix or a dense dissimilarity matrix (e.g. not square, not symmetric, or not a valid filter on the underlying simple graph), then this function will still return a value for the enclosing radius, but that value may not be meaningful in the context of persistent homology. Check the documentation for enclosing radius if you want to work in this setting.

Parameters:
  • matrix (numpy.ndarray or scipy.sparse.csr_matrix) – A square symmetric sparse dissimilarity matrix or dense dissimilarity matrix in numpy array or scipy sparse CSR format.

  • return_row_and_column_indices (bool, optional) – If True, returns a dictionary with the enclosing radius and a row/column where it occurs. If False (default), returns only the enclosing radius.

  • validate_input (bool, optional) – If True (default), checks that the input is a valid sparse dissimilarity matrix or a dense dissimilarity matrix. If False, skips this check and assumes the input is valid.

Returns:

  • enclosing_radius (float) – If argminmax is False, returns the enclosing radius.

  • result (dict) –

    If argminmax is True, returns a dictionary with keys:

    • row: index of the row,

    • col: index of the column,

    • enclosing_radius: the enclosing radius value, equal to matrix[row][col].

Raises:
  • TypeError – If the input is not a numpy array or a scipy sparse CSR matrix.

  • Exception – If the input matrix (A) is not 2d, (B) is not square, and validate_input is True, (C) is not symmetric, and validate_input is True, or (D) is not a valid filter on the underlying simple graph, and validate_input is True. This condition is described in the glossary entries for dissimilarity matrix and dissimilarity matrix.

oat_python.dissimilarity.enclosing_radius_for_points(points, argminmax=False)[source]

Calculates the enclosing radius of a point cloud without calculating a dense distance matrix.

Caution

This calculation is subject to numerical error. See the glossary entry on enclosing radius for details.

Parameters:
  • points (array-like) – Any format for a point cloud compatible with sklearn.neighbors.KDTree.

  • argminmax (bool, optional) – If True, returns a dictionary with the enclosing radius and the indices of the two points where it occurs. If False (default), returns only the enclosing radius.

Returns:

  • enclosing_radius (float) – If argminmax is False, returns the enclosing radius.

  • result (dict) –

    If argminmax is True, returns a dictionary with keys:
    • pointa: index of one point,

    • pointb: index of another point, which lies at distance enclosing_radius from pointa,

    • enclosing_radius: the enclosing radius value.

oat_python.dissimilarity.euclidean_distance(pointa, pointb)[source]

Returns the Euclidean distance between two points.

To avoid some inconveniences that arise from numerical error, this function calculates euclidean_distance_one_sided( pointa, pointb ) and euclidean_distance_one_sided( pointb, pointa ), and returns the maximum of the two values.

Parameters:
  • pointa (array-like) – The first point.

  • pointb (array-like) – The second point.

Returns:

The Euclidean distance from pointa to pointb.

Return type:

float

oat_python.dissimilarity.euclidean_distance_one_sided(pointa, pointb)[source]

Returns the Euclidean distance between two points, but reversing point order may yield different results due to numerical error.

Parameters:
  • pointa (array-like) – The first point.

  • pointb (array-like) – The second point.

Returns:

The Euclidean distance from pointa to pointb.

Return type:

float

oat_python.dissimilarity.farthest_point_sampling(metric_space, stopping_condition={'epsilon': 0})[source]

Applies farthest point sampling to a point cloud or a dissimilarity matrix.

Input types

The input can be one of the following:

  • A point cloud with \(n\) points.

  • A metric space \(M = \{m_0, \ldots, m_{n-1}\}\) represented by an \(n \times n\) square symmetric matrix \(D\), where \(D_{i,j}\) is the distance between points \(m_i\) and \(m_j\).

  • More generally, any square symmetric n times n matrix \(D\).

No matter the input type, it’s standard to regard the input informally as a metric space with points labled \(0, \ldots, n-1\), and regard each entry \(D_{i,j}\) as the distance between points \(i\) and \(j\).

Performance

If your data is a point cloud, then this function will typically perform much better if the points is passed as a list of points, e.g., a list of tuples or a numpy array of shape (num_points, dimension), rather than a distance matrix. This is because there is a significant memory cost to storing a large distance matrix in memory. The implementation of this function is carefully designed to avoid constructing a distance matrix at any time, so it can handle large point clouds efficiently.

Goal

The overall goal of this algorithm is select a collection of points \(X = \{i_0, \ldots, i_N\}\) that samples evenly from the space as a whole. Specifically, we want to ensure that every point in the space is close to some point in \(X\), and no two points in X are too close together.

Algorithm

Farthest point sampling is an iterative procedure that builds a sequence of points as follows:

  1. Start by selecting an initial index \(i_0 = 0\) (the first row/column). Let \(e_0 = \max \{ D_{i_0,i_k} : 0 < k < n \}\) be the maximum distance from \(i_0\) to any other point.

  2. At each step, choose \(i_m\) as far as possible from \(i_0, .., i_{m-1}\). That is, we choose \(i_m ∉ \{i_0, \ldots, i_{m-1}\}\) such that the scalar value \(e_m: = \min \{ D_{i_k,i_m} : k < m \}\) is as large as possible.

  3. Repeat until some stopping condition is met (e.g. the sample has a desired size, or \(e_m\) is sufficiently small).

This produces:
  • a sequence of indices \(i_0, \ldots, i_N\) (the selected points, in order)

  • a sequence of values \(e_0, \ldots, e_N\) (the covering radii at each step)

If \(D\) is distance matrix of a true metric space, then the selected set forms an epsilon net for epsilon = \(e_N\). Moreover, for each \(m\), the set \(\{i_0, ..., i_m\}\) forms an epsilon net for epsilon = \(e_m\).

If \(D\) is not the distance matrix of a metric space then the output may not be an epsilon net, but it may still be a reasonable approximation of an “even” sample; for example, the output is still a set of points such that every point is within distance \(e_N\) of the selected set (i.e., a covering of radius \(e_N\)), but the set may not satisfy all properties of an epsilon net in a metric space.

Parameters:
  • metric_space (dict( str: array-like or scipy.sparse matrix )) –

    A dict containing a point cloud or a square symmetric matrix.

    The key should be either “point_cloud” or “dissimilarity_matrix”, and the value should be one of the following:

    • If the key is “point_cloud”, the value should be a point cloud represented as a list of points, e.g., a list of tuples or a numpy array of shape (num_points, dimension). Each slice points[i] will be treated as a point.

    • If the key is “dissimilarity_matrix”, the value should be a square symmetric matrix represented as a numpy array or scipy sparse CSR format. This matrix does not have to satisfy the properties of a metric space (i.e. triangle inequality), but it should be square and symmetric.

  • stopping_condition (dict, optional) –

    A dictionary specifying the stopping condition for the sampling process. This must be one of the following:

    • dict(epsilon=*): The sampling stops when \(e_m\) is less than or equal to the given epsilon.

    • dict(max_points=*): The sampling stops when the number of sampled points reaches the given maximum.

Returns:

  • sampled_indices (list of int) – The list of indices \([i_0, i_1, \ldots, i_N]\) representing the sampled points.

  • covering_radii (list of float) – The list of covering radii \([e_0, e_1, \ldots, e_N]\) corresponding to the sampled points.

Notes

  • If the input is an empty point cloud or \(0 \times 0\) matrix, then ([], []) is returned.

  • If the input is a point cloud with only one point, then ([0], [0]) is returned.

  • If the input is a square symmetric matrix with only one row/column, then ([0], [matrix[0,0]]) is returned.

  • If the input is a sparse matrix, then the function will treat all structural zero entries as infinity, not as zero.

Raises:
  • TypeError – If the input is not a numpy array or a scipy sparse CSR matrix, or if the input type is not recognized.

  • Exception – If the input matrix is not square or not symmetric, or if the stopping condition is not recognized.

oat_python.dissimilarity.hop_distance_for_networkx_graph(G)[source]

Compute the hop (shortest path) distance matrix for a NetworkX graph.

Parameters:

G (networkx.Graph)

Returns:

  • D (numpy.ndarray) – A 2D NumPy array of shape (n_vertices, n_vertices), where D[i, j] is the hop distance (minimum number of edges) between vertex i and vertex j, using the order of vertex_labels.

  • vertex_labels (list) – A list of vertex labels corresponding to the order of rows and columns in D.

Notes

  • The hop distance between two vertices is the length of the shortest path connecting them.

  • The order of vertices in vertex_labels matches the row and column order in D.

Example

import networkx as nx
from oat_python.plot import hop_distance_for_networkx_graph

G = nx.path_graph([0, 1, 2, 3])
D, labels = hop_distance_for_networkx_graph(G)
print("Labels:", labels)
print("Distance matrix:\n", D)
oat_python.dissimilarity.hop_distance_for_simpices(simplices)[source]

Compute the hop (shortest path) distance matrix for a collection of simplices.

Parameters:

simplices (iterable of iterables of integers) – A list of simplices, where each inner iterable contains vertex labels (hashable types).

Returns:

  • D (numpy.ndarray) – A 2D NumPy array of shape (n_vertices, n_vertices), where D[i, j] is the hop distance (minimum number of edges) between vertex i and vertex j, using the order of vertex_labels.

  • vertex_labels (list) – A list of vertex labels corresponding to the order of rows and columns in D.

Notes

  • The hop distance between two vertices is the length of the shortest path connecting them. Two vertices are considered adjacent if they are both contained in one or more of the same simplices.

  • The order of vertices in vertex_labels matches the row and column order in D.

Example

import networkx as nx
from oat_python.plot import hop_distance_for_networkx_graph

G = nx.path_graph([0, 1, 2, 3])
D, labels = hop_distance_for_networkx_graph(G)
print("Labels:", labels)
print("Distance matrix:\n", D)
oat_python.dissimilarity.sparse_matrix_for_cloud_slow(points, max_dissimilarity)[source]

Returns a sparse symmetric Euclidean distance matrix, where entries strictly above max_dissimilarity are not explicitly stored.

See also

oat_python.dissimilarity.sparse_matrix_for_points()

Returns a sparse Euclidean distance matrix for a point cloud using a fast nearest-neighbors approach. The output specifically to be compatible with the OAT persistent homology solver, and this function typically executes much faster than :func:`sparse_matrix_for_cloud_slow`. However the output of this function is typically slightly different from sparse_matrix_for_cloud_slow(), due to numerical error. Therefore calling oat_python.dissimilarity.sparse_matrix_for_points() with max_dissimilarity equal to the enclosing radius of the point cloud may yield a dissimilarity matrix whose persistent homology is not equal to that of the point cloud. This can be remedied by adding a tiny margin of error to the enclosing radius, e.g. max_dissimilarity = enclosing_radius + 0.00000001.

Parameters:
  • points (array-like) – A point cloud represented as a list of points, e.g., a list of tuples or a numpy array of shape (num_points, dimension).

  • max_dissimilarity (float) – A non-negative real number; all distances with value above this threshold are dropped from the (sparse) distance matrix. If max_dissimilarity is negative, then an empty sparse matrix of appropriate size is returned.

Returns:

A sparse matrix of shape (num_points, num_points) representing the pairwise distances between points in the points. The matrix is strictly symmetric (it exactly equals its transpose), and all entries with value strictly greater than max_dissimilarity are not explicitly stored. If max_dissimilarity is negative, an empty sparse matrix of appropriate size is returned.

Return type:

scipy.sparse.csr_matrix

oat_python.dissimilarity.sparse_matrix_for_csr(dissimilarity_matrix, max_dissimilarity=inf, clamp_diagonal_entries=True)[source]

Validates and formats a scipy sparse CSR dissimilarity matrix for use with the OAT persistent homology solver.

Validation

This constructor checks that

  • the input is a square, symmetric scipy.sparse.csr_matrix \(D\)

  • for each i, if row i of \(D\) contains at least one structural nonzero entry then the diagonal entry \(D_{i,i}\) is structurally nonzero, and \(D_{i,i}\) is the minimum of all structural nonzeros stored in row i.

Formatting

In an out-of-place fashion, this constructor:

  • deletes all entries with value strictly greater than max_dissimilarity

  • sorts the internal data structures that store the column indices and values of the structural nonzero entries

Parameters:
  • dissimilarity_matrix (scipy.sparse.csr_matrix) – A square symmetric sparse dissimilarity matrix in scipy CSR format.

  • max_dissimilarity (float, optional) – A real number; all entries with value above this threshold will be dropped.

  • clamp_diagonal_entries (bool, optional) – If True (default), ensures that each diagonal entry is the smallest structural nonzero in its row. Diagonal entries in rows with no structural nonzero entries are left unchanged (as structural zeros). If False, does not modify diagonal entries, but throws an error if any diagonal entry violates the formatting requirements.

Returns:

dissimilarity_matrix – A square symmetric sparse dissimilarity matrix in scipy CSR format, with all entries greater than max_dissimilarity removed. This matrix is guaranteed to meet the formatting requirements of the OAT persistent homology solver.

Return type:

scipy.sparse.csr_matrix

Raises:
  • TypeError – If the input is not a scipy.sparse.csr_matrix.

  • Exception

    • If the input matrix is not square - If the input matrix is not symmetric - There exists an \(i\) such that row i of the input matrix contains a structural nonzero entry, but the diagonal entry (i,i) is structurally zero

oat_python.dissimilarity.sparse_matrix_for_dense(dissimilarity_matrix, max_dissimilarity=inf)[source]

Converts a dense dissimilarity matrix to a scipy sparse CSR matrix that meets the formatting requirements of the OAT persistent homology solver.

In particular, this constructor checks that

  • the input is a square, symmetric numpy array

  • for each i, the entry (i,i) takes the smallest value of any entry in row i

It then stores the input in a scipy sparse CSR matrix, where

  • all entries with value strictly greater than max_dissimilarity are removed

  • all entries with value less than or equal to max_dissimilarity are stored explicitly – including entries with value 0

Parameters:
  • dissimilarity_matrix (numpy.ndarray) – A square symmetric dissimilarity matrix in numpy array format.

  • max_dissimilarity (float, optional) – A real number; all entries with value above this threshold will be dropped.

Returns:

dissimilarity_matrix – A square symmetric sparse dissimilarity matrix in scipy CSR format, with all entries greater than max_dissimilarity removed. This matrix is guaranteed to meet the formatting requirements of the OAT persistent homology solver.

Return type:

scipy.sparse.csr_matrix

Raises:
  • TypeError – If the input is not a numpy array.

  • Exception

    • If the input matrix is not square - If the input matrix is not symmetric - There exists an \(i\) such that row i of the input matrix contains a structural nonzero entry, but the diagonal entry (i,i) is structurally zero

oat_python.dissimilarity.sparse_matrix_for_points(points, max_dissimilarity)[source]

Returns a sparse (Scipy CSR) Euclidean distance matrix, where all entries with value strictly greater than max_dissimilarity are dropped.

Assymetry

This function uses sklearn.neighbors.radius_neighbors_graph to construct a dissimilarity matrix, however the output of this function is not symmetric in general. Therefore the construction process takes two steps:

  • construct a matrix A with sklearn.neighbors.radius_neighbors_graph

  • replace A with the entrywise-maximum of A and the transpose of A

  • store explicit zero values for all diagonal entries

  • if max_dissimilarity is nonnegative, then store explicit zero values for all diagonal entries; otherwise return an empty sparse matrix of appropriate size

Parameters:
  • points (array-like) – Any format for a point cloud compatible with sklearn.neighbors.radius_neighbors_graph.

  • max_dissimilarity (float) – A non-negative real number; all distances with value above this threshold are dropped.

Examples

import numpy as np
import oat_python as oat

points           =   np.random.rand(10,2)
dissimilarity   =   oat.dissimilarity.sparse_matrix_for_cloud_slow(
                        points               =   points,
                        max_dissimilarity   =   oat.dissimilarity.enclosing_radius(points)
                    )
oat_python.dissimilarity.test_dissimilarity_matrix(max_grid_size)[source]

Tests the correctness and consistency of various dissimilarity matrix formatting and radius calculation functions for grids of increasing size.

For each grid size from 0 to max_grid_size (inclusive), this test:
  • Generates a 2D grid of points (“points”).

  • Computes the pairwise distance matrix (dense and sparse formats).

  • Formats the data into cleaned CSR matrices using multiple methods:
    • From the points (slow and fast/NN implementations).

    • From the CSR matrix.

    • From the dense matrix.

  • Asserts that all formatted matrices are approximately equal.

  • Computes the enclosing radius using multiple methods and asserts their equivalence.

  • Tests sparsified versions of the matrices for a variety of thresholds, ensuring consistency across methods.

Parameters:

max_grid_size (int) – The maximum size of the grid (number of points along one axis) to test.

Raises:

AssertionError – If any of the formatted matrices or computed radii are not approximately equal across methods.

oat_python.dissimilarity.test_validate_dissimilarity_matrix()[source]

Unit tests for the validate_dissimilarity_matrix function.

This test suite covers: - Dense and sparse matrices that are valid (square, symmetric, correct diagonal). - Matrices that are not square. - Matrices that are not symmetric. - Sparse matrices with a row that has structural nonzero entries but no diagonal entry. - Sparse matrices where the diagonal is not the minimum in its row.

The test asserts that valid matrices pass and invalid matrices raise an Exception.

oat_python.dissimilarity.validate_dissimilarity_matrix(matrix)[source]

Validates that the input matrix is a valid sparse or dense dissimilarity matrix.

Parameters:

matrix (numpy.ndarray or scipy.sparse.csr_matrix) – The matrix to validate.

Raises:

Exception

  • If the matrix is not 2-dimensional, not square, or not symmetric. - If the matrix contains a row with one or more structural nonzero entries, but the diagonal entry for that row is structurally zero.

Barcodes

oat_python.barcode.max_finite_value(values)[source]

Find the maximum finite value less than +infinity, in a list. Returns None if the list does not contain a a value < infinity.

Parameters:

values – an iterable of floats

Core

This module contains the objects and functions in oat_python that have been exported from Rust. It is called core because Rust provides many of the most basic building blocks of this library. Rust does not need to be installed to use this module.

This module contains the following submodules:

  • vietoris_rips: Contains the Vietoris-Rips complex and related objects. For details see the Vietoris-Rips.

  • dowker: Contains the Dowker complex and related objects. For details see the Hypergraph.