Source code for permaviss.persistence_algebra.module_persistence_homology

"""
    module_persistence_homology.py

    This module implements the persistence module homology
"""
import numpy as np

from .barcode_bases import barcode_basis

from .image_kernel import image_kernel


###############################################################################
# Quotient of barcode bases


[docs]def quotient(M, N, p): """Assuming that N generates a submodule of M, we compute a barcode basis for the quotient M / N. Parameters ---------- M : :obj:`barcode_basis` Basis for module N : :obj:`barcode_basis` Basis for submodule of N p : int(prime) Returns ------- Q : :obj:`barcode_basis` Barcode basis for the quotient M / N """ if N.dim == 0: return M # Check that the barcode bases coincide if M.prev_basis != N.prev_basis: raise ValueError # We create N_M, which is not a basis, but will be used as the domain # basis in image_kernel so that the quotient mod N can be performed N_M_barcode = np.concatenate((N.barcode, M.barcode), axis=0) N_M = barcode_basis(N_M_barcode) # create a matrix (N|M) in M.prev_basis matrix_N_M = np.concatenate((N.coordinates, M.coordinates), axis=1) # Compute quotient barcodes for M mod N Q, Ker, PreIm = image_kernel(N_M, M.prev_basis, matrix_N_M, p, start_index=N.dim, prev_basis=M) return Q
############################################################################### # Persistence module homology mod p
[docs]def module_persistence_homology(D, Base, p): """Given the differentials of a chain of tame persistence modules, we compute barcode bases for the homology of the chain. Parameters ---------- D : :obj:`list(Numpy Array)` List of differentials of the chain complex. Base : :obj:`Numpy Array` List containing barcode bases for each dimension p : int(prime) Prime number to perform arithmetic mod p Returns ------- Hom : :obj:`list(barcode_basis)` Cycles mod boundaries of differentials, starting with: birth rad, death rad. If a cycle does not die we put max_rad as death radius. Im : :obj:`list(barcode_basis)` List storing bases for the images of differentials PreIm : :obj:`list(Numpy Array)` List storing bases for the preimages of the differentials. That is, which generators produce each image generator. This leads to how to `go back` from boundaries to preimages. """ dim = len(Base) # lists of homology, boundaries and preboundaries Hom = [] Im = [] PreIm = [] for d in range(dim): Hom.append([]) Im.append([]) PreIm.append([]) Im[dim - 1] = barcode_basis([], Base[d]) # Find bases for Kernel and Image, starting from D[dim-1], ending on D[1]. for d in range(dim - 1, 0, -1): # Handle trivial cases if Base[d].dim == 0: Im[d-1] = barcode_basis([], Base[d-1]) Hom[d] = barcode_basis([], Base[d]) elif Base[d-1].dim == 0: Im[d-1] = Base[d-1] Hom[d] = Base[d] else: # compute barcode bases for image and kernel Im[d - 1], Ker, PreIm[d] = image_kernel( Base[d], Base[d-1], D[d], p) # Perform quotient of Ker by Im[d] Hom[d] = quotient(Ker, Im[d], p) # Trivial case dim 0 if Base[0].dim == 0: Hom[0] = Base[0] else: # All the generators from Base[0] lie in the kernel, since D[0]=0 Ker = barcode_basis(Base[0].barcode, Base[0], np.identity(Base[0].dim)) Ker.sort() if Ker.prev_basis != Im[0].prev_basis: print(Ker.prev_basis) print(Im[0].prev_basis) assert False Hom[0] = quotient(Ker, Im[0], p) # Return lists of barcode bases for Hom, Im and PreIm return Hom, Im, PreIm