Vectorization

org.appliedtopology.tda4j.barcode.Vectorization
object Vectorization

Diagram vectorizations: persistence landscapes (Bubenik 2013) and persistence images (Adams et al. 2017), turning a barcode into a fixed-size numeric array for downstream (e.g. ML) use. Per .claude/WORKLOG-mainstream-feature-gap-analysis.md item 8 -- pure array/geometry code on PersistenceBar, no relation to BarcodeDistance's matching machinery beyond sharing DiagramPoint's extraction helper.

'''Essential (never-dying) bars''' are handled differently by the two vectorizations below, and deliberately so rather than by one blanket policy -- each is documented at its own def:

  • landscape includes them: a tent function max(0, min(t - birth, death - t)) degrades to the unbounded ramp t - birth exactly at death = Infinity, which is already finite and meaningful at every t the caller's own finite grid ever evaluates, so no special-casing is needed.
  • persistenceImage drops them: a Gaussian centered at (birth, Infinity) in birth-persistence coordinates has no overlap with any finite pixel grid, so silently keeping it would either underflow to an all-zero contribution (an implicit policy, not a decided one) or need an arbitrary finite substitute death value (which landscape's case doesn't need and this one has no principled way to choose either).

Attributes

Experimental
true
Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Value members

Concrete methods

def landscape[A](diagram: Seq[PersistenceBar[Double, A]], numLevels: Int, tMin: Double, tMax: Double, resolution: Int): Array[Array[Double]]

Samples the first numLevels persistence landscape functions of diagram (Bubenik 2013) on resolution evenly-spaced points across [tMin, tMax] (inclusive of both ends). Returns levels(k)(j), k from 0 (the outer envelope, i.e. the pointwise max over all bars' tent functions) to numLevels - 1, j from 0 to resolution - 1 at t_j = tMin + j * (tMax - tMin) / (resolution - 1). A t with fewer than numLevels bars alive gets 0 for the missing levels, the standard "k-th order statistic of a smaller set is 0" convention.

Samples the first numLevels persistence landscape functions of diagram (Bubenik 2013) on resolution evenly-spaced points across [tMin, tMax] (inclusive of both ends). Returns levels(k)(j), k from 0 (the outer envelope, i.e. the pointwise max over all bars' tent functions) to numLevels - 1, j from 0 to resolution - 1 at t_j = tMin + j * (tMax - tMin) / (resolution - 1). A t with fewer than numLevels bars alive gets 0 for the missing levels, the standard "k-th order statistic of a smaller set is 0" convention.

'''Closed-form check''' (used by the test suite as an exact oracle, not just eyeballing plots): integrating every level and summing gives sum_i (death_i - birth_i)^2 / 4 exactly, for a [tMin, tMax] containing every finite bar's support -- each bar's tent function has triangular area persistence * (persistence/2) / 2, and sum_k integral(level_k) = sum_i integral(tent_i) because integration is linear and, at each fixed t, the multiset of order statistics {level_k(t)} is exactly the multiset {tent_i(t)} reordered.

Attributes

def persistenceImage[A](diagram: Seq[PersistenceBar[Double, A]], sigma: Double, birthRange: (Double, Double), persistenceRange: (Double, Double), birthResolution: Int, persistenceResolution: Int, weightCap: Option[Double] = ...): Array[Array[Double]]

The persistence image (Adams et al. 2017) of diagram: diagram points are first transformed to birth-persistence coordinates (birth, death - birth) (the paper's own T), then each becomes an isotropic Gaussian bump of standard deviation sigma, weighted by piecewiseLinearWeight evaluated at that point's own persistence value (weightCap defaults to the diagram's own maximum finite persistence, the paper's suggested default). Each pixel's value is the exact integral of the weighted surface over that pixel's box -- via the product of 1D normal-CDF differences along each axis, since an isotropic Gaussian's mass over a rectangle factors along the two axes -- not a point sample of the surface at the pixel center, cross-checked against scikit-tda/persim's own CDF-difference implementation.

The persistence image (Adams et al. 2017) of diagram: diagram points are first transformed to birth-persistence coordinates (birth, death - birth) (the paper's own T), then each becomes an isotropic Gaussian bump of standard deviation sigma, weighted by piecewiseLinearWeight evaluated at that point's own persistence value (weightCap defaults to the diagram's own maximum finite persistence, the paper's suggested default). Each pixel's value is the exact integral of the weighted surface over that pixel's box -- via the product of 1D normal-CDF differences along each axis, since an isotropic Gaussian's mass over a rectangle factors along the two axes -- not a point sample of the surface at the pixel center, cross-checked against scikit-tda/persim's own CDF-difference implementation.

Returns image(r)(c): r indexes birthResolution pixels evenly spanning birthRange, c indexes persistenceResolution pixels evenly spanning persistenceRange.

'''Essential (never-dying) bars are dropped''' -- see the class doc for why, unlike landscape.

Attributes