CubicalGridStream

org.appliedtopology.tda4j.streams.CubicalGridStream
class CubicalGridStream(val shape: IndexedSeq[Int], val topCellValue: IndexedSeq[Int] => Double, val parallelFiltrationValue: Boolean = ...) extends StratifiedCellStream[Cube, Double], DoubleFiltration[Cube]

Dense cubical complex over a full rectangular grid, filtration values assigned via the T-construction: a caller-supplied topCellValue gives every top-dimensional cube (pixel/voxel) its own value directly, and every lower-dimensional cube's value is the min over all top cells that contain it as a face -- exactly the "sublevel set of a piecewise-constant function on pixels" convention GUDHI/DIPHA/Perseus all use for image persistence (see .claude/WORKLOG-cubical.md for the monotonicity proof: since every top cell containing an immediate coface of c also contains c, fv(coface) >= fv(c) always holds by construction, which is exactly what CellularHomologyContext.processingOrder's ascending sort requires).

For a SUPERLEVEL-set convention instead, negate topCellValue before constructing (the standard trick -- see CubicalImage.scala's sublevel parameter, which does exactly this): sublevel persistence of -f is superlevel persistence of f, reparametrized, so this type deliberately does not carry its own sign-direction flag -- one code path, always "min over cofaces," is easier to get right and to verify than baking a direction switch into the core stream.

shape(i) is the number of PIXELS along axis i (not lattice points -- there are shape(i) + 1 of those). The full grid complex has prod_i (2*shape(i)+1) cells total (totalCellCount) -- e.g. a 256x256 image has 513*513 = 263169 cells, not 65536.

Attributes

Experimental
true
Graph
Supertypes
trait StratifiedCellStream[Cube, Double]
trait CellStream[Cube, Double]
trait IterableOnce[Cube]
trait Filtration[Cube, Double]
trait Filterable[Double]
class Object
trait Matchable
class Any
Show all

Members list

Value members

Concrete methods

override def iterateDimension: PartialFunction[Int, Iterator[Cube]]

Bounded at 0 to ambientDim, contiguous from 0 -- the contract StratifiedCellStream.iterator's default implementation (and this class's own callers) rely on. Each dimension's bucket is fully materialized and sorted by filtrationOrdering.reverse (oldest-first, what CellularHomologyContext -- via its own processingOrder re-sort -- and iterateDimension's own established convention both expect); on a large grid this is the memory-heavy step, not containingTopCells. Recomputed and re-sorted from scratch on EVERY call, unlike ExplicitCubicalStream.byDimension below (a lazy val) -- fine for CellularHomologyContext, which calls .iterator (hence this) exactly once per persistentHomology run, but a caller that repeatedly calls iterateDimension(d) directly (as some alpha-complex specs do for their own streams) would pay the full re-sort every time; not measured as an actual problem, just flagged rather than silently left unmentioned.

Bounded at 0 to ambientDim, contiguous from 0 -- the contract StratifiedCellStream.iterator's default implementation (and this class's own callers) rely on. Each dimension's bucket is fully materialized and sorted by filtrationOrdering.reverse (oldest-first, what CellularHomologyContext -- via its own processingOrder re-sort -- and iterateDimension's own established convention both expect); on a large grid this is the memory-heavy step, not containingTopCells. Recomputed and re-sorted from scratch on EVERY call, unlike ExplicitCubicalStream.byDimension below (a lazy val) -- fine for CellularHomologyContext, which calls .iterator (hence this) exactly once per persistentHomology run, but a caller that repeatedly calls iterateDimension(d) directly (as some alpha-complex specs do for their own streams) would pay the full re-sort every time; not measured as an actual problem, just flagged rather than silently left unmentioned.

Attributes

Definition Classes
def totalCellCount: Long

Total cell count of the full grid complex, by the "sum over subsets of a product = product of (in-choice + out-choice)" identity: for a fixed set of non-degenerate axes there are shape(i) choices along a non-degenerate axis and shape(i)+1 along a degenerate one, and summing that product over every subset of non-degenerate axes collapses to prod_i (shape(i) + (shape(i)+1)). O(ambientDim), no enumeration needed.

Total cell count of the full grid complex, by the "sum over subsets of a product = product of (in-choice + out-choice)" identity: for a fixed set of non-degenerate axes there are shape(i) choices along a non-degenerate axis and shape(i)+1 along a degenerate one, and summing that product over every subset of non-degenerate axes collapses to prod_i (shape(i) + (shape(i)+1)). O(ambientDim), no enumeration needed.

Attributes

Inherited methods

override def iterator: Iterator[Cube]

Dimension-major: all of dimension d before any of dimension d + 1.

Dimension-major: all of dimension d before any of dimension d + 1.

MUST NOT be implemented as Iterator.from(0).filter(iterateDimension.isDefinedAt)....fold(...) (a real, confirmed bug this replaced -- see .claude/WORKLOG-cohomology.md): Iterator.filter on an infinite source can never prove "no more matches ahead", so once past the last dimension iterateDimension is defined for, it spins forever searching for a d that will never come -- and Int silently wrapping from Int.MaxValue to Int.MinValue after ~2^31 iterations can eventually feed a huge negative d straight to iterateDimension instead, surfacing as a BinomialCoefficient range exception rather than a hang. .takeWhile instead stops at the first d this is undefined for and never asks about any d beyond it, relying on exactly the contiguous-domain contract documented on iterateDimension above.

Attributes

Definition Classes
StratifiedCellStream -> IterableOnce
Inherited from:
StratifiedCellStream
def knownSize: Int

The number of elements in this collection, if it can be cheaply computed, -1 otherwise. Cheaply usually means: Not requiring a collection traversal.

The number of elements in this collection, if it can be cheaply computed, -1 otherwise. Cheaply usually means: Not requiring a collection traversal.

Attributes

Inherited from:
IterableOnce
def stepper[S <: Stepper[_]](implicit shape: StepperShape[Cube, S]): S

Returns a scala.collection.Stepper for the elements of this collection.

Returns a scala.collection.Stepper for the elements of this collection.

The Stepper enables creating a Java stream to operate on the collection, see scala.jdk.StreamConverters. For collections holding primitive values, the Stepper can be used as an iterator which doesn't box the elements.

The implicit scala.collection.StepperShape parameter defines the resulting Stepper type according to the element type of this collection.

  • For collections of Int, Short, Byte or Char, an scala.collection.IntStepper is returned
  • For collections of Double or Float, a scala.collection.DoubleStepper is returned
  • For collections of Long a scala.collection.LongStepper is returned
  • For any other element type, an scala.collection.AnyStepper is returned

Note that this method is overridden in subclasses and the return type is refined to S with EfficientSplit, for example scala.collection.IndexedSeqOps.stepper. For Steppers marked with scala.collection.Stepper.EfficientSplit, the converters in scala.jdk.StreamConverters allow creating parallel streams, whereas bare Steppers can be converted only to sequential streams.

Type parameters

S

the type of the returned Stepper, determined by the implicit StepperShape

Attributes

Inherited from:
IterableOnce

Concrete fields

val ambientDim: Int
override val filtrationOrdering: Ordering[Cube]

The shared FiltrationOrdering.canonical shape (fv reversed, then dimension, then the canonical cubeOrdering tie-break). Ties on filtration value are the COMMON case here, not an edge case: every non-top face shares its value with at least one of its cofaces by construction (min-over-cofaces), so a broken tie-break would corrupt essentially every reduction, not just rare coincidences.

The shared FiltrationOrdering.canonical shape (fv reversed, then dimension, then the canonical cubeOrdering tie-break). Ties on filtration value are the COMMON case here, not an edge case: every non-top face shares its value with at least one of its cofaces by construction (min-over-cofaces), so a broken tie-break would corrupt essentially every reduction, not just rare coincidences.

Attributes

override val filtrationValue: PartialFunction[Cube, Double]
val shape: IndexedSeq[Int]
val topCellValue: IndexedSeq[Int] => Double

Inherited fields

val largest: Double

Attributes

Inherited from:
DoubleFiltration
val smallest: Double

Attributes

Inherited from:
DoubleFiltration