Source code for oineus.diff.freudenthal

import numpy as np
import eagerpy as epy

from .. import _oineus
from .diff_filtration import DiffFiltration
from ._tensor_utils import tensor_to_real_numpy, gather_values


_FR_GRID_CLASS_BY_NDIM = {1: _oineus.Grid_1D, 2: _oineus.Grid_2D, 3: _oineus.Grid_3D}


[docs] def freudenthal_filtration(data, negate=False, wrap=False, max_dim=3, slim=False, n_threads=1): tensor = epy.astensor(data) np_data = tensor_to_real_numpy(tensor) max_dim = min(max_dim, np_data.ndim) # slim=True builds the compact (anchor,type) FreudenthalFiltration_ND for D=1,2,3 on non-wrap # grids: it reduces, produces diagrams and optimizes (sorted_id + value based) identically to # the fat path but with a far smaller boundary-build footprint, and oineus.diff.TopologyOptimizer # dispatches on its per-dim type. It is opt-in for the differentiable factory (the non-diff # oineus.freudenthal_filtration defaults to slim) because some low-level diff entry points # (compute_partial_u_rows, the raw per-cell optimizer ctor) are still fat-only; the high-level # diff pipeline (persistence_diagram, TopologyOptimizer, mapping_cylinder) handles slim. wrap # grids and D>=4 always use the fat universal Filtration (FrGeometry rejects wrap; the slim # builder is bound only for D=1,2,3). The critical-vertex array cv is a flat index array into # the data, identical between the slim and fat paths, so the gathered values are unchanged. if slim and (not wrap) and (1 <= np_data.ndim <= 3): grid = _FR_GRID_CLASS_BY_NDIM[np_data.ndim](np_data, wrap=wrap, values_on="vertices") fil, cv = grid.freudenthal_filtration_and_critical_vertices_slim( max_dim=max_dim, negate=negate, n_threads=n_threads ) else: fil, cv = _oineus.get_freudenthal_filtration_and_crit_vertices( np_data, negate, wrap, max_dim, n_threads ) values = gather_values(tensor, cv) return DiffFiltration(fil, values)