org.appliedtopology.tda4j.cells

Members list

Type members

Experimental classlikes

object Cube

Attributes

Experimental
true
Supertypes
class Object
trait Matchable
class Any
Self type
Cube.type

product/coproduct/quotient/identify/elementsAtDim are scoped here, on FiniteSimplicialSet's companion, rather than as top-level cells package defs: names this generic (especially product) are exactly the kind of top-level-name collision hazard documented elsewhere in this codebase (CLAUDE.md, the extension-companion-object pattern) -- every file that does import cells.{given, *} would otherwise have them ambient. Callers write FiniteSimplicialSet.product(...), or import FiniteSimplicialSet.* locally where the ergonomics matter.

product/coproduct/quotient/identify/elementsAtDim are scoped here, on FiniteSimplicialSet's companion, rather than as top-level cells package defs: names this generic (especially product) are exactly the kind of top-level-name collision hazard documented elsewhere in this codebase (CLAUDE.md, the extension-companion-object pattern) -- every file that does import cells.{given, *} would otherwise have them ambient. Callers write FiniteSimplicialSet.product(...), or import FiniteSimplicialSet.* locally where the ergonomics matter.

Attributes

Companion
class
Experimental
true
Supertypes
class Object
trait Matchable
class Any
Self type
class FiniteSimplicialSet[G](val generatorsByDim: IndexedSeq[Set[G]], val faces: G => IndexedSeq[SSetElement[G]])(using val ord: Ordering[G])

A finite simplicial set presented by generators (non-degenerate simplices) and, for each generator, its primitive face data -- from which everything else (arbitrary d_i/s_j, the OrderedCell instance feeding the homology engines) is inferred via faceOf/insertOuter (SSetElement.scala).

A finite simplicial set presented by generators (non-degenerate simplices) and, for each generator, its primitive face data -- from which everything else (arbitrary d_i/s_j, the OrderedCell instance feeding the homology engines) is inferred via faceOf/insertOuter (SSetElement.scala).

faces(g), for g of dimension n, must supply exactly n+1 already-normalized SSetElements of dimension n-1 each (empty for n = 0) -- validate() checks this contract plus the simplicial identities at runtime, since it's easy to get a hand-written presentation subtly wrong with no crash, just silently wrong homology.

Attributes

Companion
object
Experimental
true
Supertypes
class Object
trait Matchable
class Any
case class ProductGenerator[GX, GY](x: SSetElement[GX], y: SSetElement[GY])

A non-degenerate n-simplex of X x Y, presented as the pair of SSetElements (each possibly itself degenerate over its own non-degenerate generator) whose word-sets are disjoint -- NOT an Eilenberg-Zilber shuffle triple. The shuffle family indexes the classical chain MAP between C_*(X) tensor C_*(Y) and C_*(X x Y), not the product's own non-degenerate simplices: (e_X, e_Y), both non-degenerate of dimension 1, is a non-degenerate 1-simplex of X x Y that no (p,q)-shuffle with p+q=1 could ever produce, since a shuffle needs p+q=n but here p=q=1=n. See .claude/WORKLOG-simplicial-set-constructions.md.

A non-degenerate n-simplex of X x Y, presented as the pair of SSetElements (each possibly itself degenerate over its own non-degenerate generator) whose word-sets are disjoint -- NOT an Eilenberg-Zilber shuffle triple. The shuffle family indexes the classical chain MAP between C_*(X) tensor C_*(Y) and C_*(X x Y), not the product's own non-degenerate simplices: (e_X, e_Y), both non-degenerate of dimension 1, is a non-degenerate 1-simplex of X x Y that no (p,q)-shuffle with p+q=1 could ever produce, since a shuffle needs p+q=n but here p=q=1=n. See .claude/WORKLOG-simplicial-set-constructions.md.

Attributes

Experimental
true
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object Simplex extends SimplexOps

object Simplex mixes in SimplexOps (SimplexOps.scala) rather than the trait's methods living as a separate top-level extension clause: extension methods declared in the opaque type's own companion object are found via the receiver type's implicit scope, not via blanket top-level visibility across the package -- the fix for the same-named top-level extension collisions documented in .claude/WORKLOG-extension-companion-objects.md. underlying moved in here for the same reason, even though nothing currently collides on that name -- keeping every Simplex[VertexT]-receiver extension routed through one place is what makes "a future opaque type may reuse this name" actually hold.

object Simplex mixes in SimplexOps (SimplexOps.scala) rather than the trait's methods living as a separate top-level extension clause: extension methods declared in the opaque type's own companion object are found via the receiver type's implicit scope, not via blanket top-level visibility across the package -- the fix for the same-named top-level extension collisions documented in .claude/WORKLOG-extension-companion-objects.md. underlying moved in here for the same reason, even though nothing currently collides on that name -- keeping every Simplex[VertexT]-receiver extension routed through one place is what makes "a future opaque type may reuse this name" actually hold.

asSimplex (below, top-level, NOT moved in here) is a real exception, not an oversight: its RECEIVER is SortedSet[VertexT], not Simplex[VertexT] -- companion-object extension lookup is keyed by the receiver type, so an extension on SortedSet[VertexT] placed inside Simplex's companion is never found from a SortedSet[VertexT] receiver. It was also never part of the naming collision in the first place (asSimplex/asCube don't share a name), so there's no reason to move it either.

Attributes

Experimental
true
Supertypes
trait SimplexOps
class Object
trait Matchable
class Any
Self type
Simplex.type
trait SimplexOps

Inherit a selection of the SortedSet methods and add other utility methods

Inherit a selection of the SortedSet methods and add other utility methods

A trait, mixed into object Simplex (Simplex.scala), rather than a top-level extension clause: Scala 3 does not allow same-named top-level extension methods for unrelated receiver types across different files in one package (.claude/WORKLOG-extension-companion-objects.md). Routing through the opaque type's own companion object instead scopes lookup by nominal receiver type, so a future opaque type's extensions can reuse a name like show/underlying without colliding with this one.

Attributes

Experimental
true
Supertypes
class Object
trait Matchable
class Any
Known subtypes
object Simplex

Types

opaque type Cube

Elementary cubes for cubical complexes.

Elementary cubes for cubical complexes.

An elementary cube in ambient dimension n is a product I_1 x I_2 x ... x I_n where each factor I_k is either a degenerate interval [a,a] (a single lattice point) or a unit interval [a,a+1]. The cube's own dimension is the number of non-degenerate (unit-interval) factors, not n -- n (the ambient/embedding dimension) is fixed per complex, the length of every Cube's own coordinate vector.

Represented via the standard "doubled coordinate" encoding used throughout the cubical-homology literature (Kaczynski-Mischaikow-Mrozek, Computational Homology): axis k is encoded as 2*a for the degenerate interval [a,a], or 2*a+1 for the unit interval [a,a+1]. This makes both "is this axis degenerate" (parity) and "what is its lower lattice coordinate" (halve, rounding down) O(1) per axis, and gives a cube a single Vector[Int] as its entire representation -- no separate bitmask needed.

opaque type over Vector[Int], not Array/IArray: Vector has structural equals/hashCode, which Chain's pivot tables (mutable.Map[CellT, Chain[...]], SortedMap[CellT, CoefficientT]) depend on to collide two structurally-identical cubes -- an array-backed opaque type would silently use reference equality instead and corrupt every reduction that touches two independently-constructed copies of the same cube.

Attributes

opaque type Simplex[VertexT]

Simplices really are just sets, outright. We provide an implementation of the [OrderedCell] typeclass for simplicial complex structures, to enable their use.

Simplices really are just sets, outright. We provide an implementation of the [OrderedCell] typeclass for simplicial complex structures, to enable their use.

Attributes

Value members

Experimental methods

def cubeIsOrderedCell(setOrdering: Ordering[Cube] = ...): is[Cube, OrderedCell]

Cube is OrderedCell instance -- mirrors Simplex.scala's simplexIsOrderedCell parameterized-given pattern exactly, so a stream can inject its own filtration-aware ordering the same way EnumeratingCofaceSimplexStream etc. do for Simplex[Int].

Cube is OrderedCell instance -- mirrors Simplex.scala's simplexIsOrderedCell parameterized-given pattern exactly, so a stream can inject its own filtration-aware ordering the same way EnumeratingCofaceSimplexStream etc. do for Simplex[Int].

Boundary formula (Kaczynski-Mischaikow-Mrozek's standard cubical boundary operator, matching exactly what was asked for: "collapse each unit interval to a degenerate interval both ways, opposite signs, once per unit- interval factor"): for a cube with non-degenerate axes at positions p_1 < p_2 < ... < p_d (0-indexed into the coordinate vector, d = the cube's own dimension), the boundary is

sum_{l=1}^{d} (-1)^(l-1) * (cube with axis p_l collapsed to its UPPER endpoint - cube with axis p_l collapsed to its LOWER endpoint)

i.e. the sign alternates over the RANK of the axis among non-degenerate axes (l, 0-indexed as rank below), not over its raw position in the coordinate vector -- using the raw position instead is a real, easy-to-make sign bug that breaks d(d(x)) = 0 as soon as a cube has a degenerate axis interleaved among its non-degenerate ones. Verified by CubicalSpec's dd=0 property test over a signed field (F3), not just F2 -- F2 cannot distinguish a correct alternating sign from a constant one, since -1 = 1 there.

Attributes

Experimental
true
def cubeOrdering: Ordering[Cube]

cubeOrdering/cubeIsOrderedCell -- split into their own file from Cubical.scala (where the opaque type Cube and its companion live), for the same file-scoped opaque-transparency reason as SimplexOrderedCell.scala's split from Simplex.scala (see that file's doc). One wrinkle specific to Cube: boundary below builds new cube values via Cubical.scala's own top-level .asCube extension on Vector[Int], not a raw Vector[Int] =:= Cube coercion -- that coercion is only available inside Cubical.scala itself and cannot be exported.

cubeOrdering/cubeIsOrderedCell -- split into their own file from Cubical.scala (where the opaque type Cube and its companion live), for the same file-scoped opaque-transparency reason as SimplexOrderedCell.scala's split from Simplex.scala (see that file's doc). One wrinkle specific to Cube: boundary below builds new cube values via Cubical.scala's own top-level .asCube extension on Vector[Int], not a raw Vector[Int] =:= Cube coercion -- that coercion is only available inside Cubical.scala itself and cannot be exported.

Attributes

Experimental
true
def eitherOrdering[GX, GY](using ox: Ordering[GX], oy: Ordering[GY]): Ordering[Either[GX, GY]]

Attributes

Experimental
true
def finiteSimplicialSetIsOrderedCell[G](using ord: Ordering[G])(dimOf: G => Int, faces: G => IndexedSeq[SSetElement[G]]): is[G, OrderedCell]

OrderedCell instance for the generators (non-degenerate simplices) of a finite simplicial set: dim is the generator's own dimension, and boundary is the normalized-chain-complex differential -- only faces that are themselves bare generators (word.isEmpty) contribute, with the usual alternating sign; a degenerate face contributes nothing, since the normalized chain complex is quasi-isomorphic to the full one. This is the only place degeneracy matters for homology -- computing it needs no recursive faceOf, only faces(g) itself.

OrderedCell instance for the generators (non-degenerate simplices) of a finite simplicial set: dim is the generator's own dimension, and boundary is the normalized-chain-complex differential -- only faces that are themselves bare generators (word.isEmpty) contribute, with the usual alternating sign; a degenerate face contributes nothing, since the normalized chain complex is quasi-isomorphic to the full one. This is the only place degeneracy matters for homology -- computing it needs no recursive faceOf, only faces(g) itself.

Mirrors simplexIsOrderedCell's injectable-ordering pattern (SimplexOrderedCell.scala).

Attributes

Experimental
true
def isNonDegeneratePair[GX, GY](a: SSetElement[GX], b: SSetElement[GY]): Boolean

A pair (a, b) in X_n x Y_n is degenerate in the product iff some single j degenerates both sides at once (s_j on X x Y is literally the diagonal (s_j, s_j)) -- and a is s_j-degenerate exactly when j appears in a.word (the normal form's own meaning: word is precisely the set of indices a is degenerate at, not just the outermost one -- e.g. s_1 s_0(v) is degenerate at both s_1 directly and, via s_0 s_0 = s_1 s_0, at s_0 too, matching both entries of its word [1, 0]). So non-degeneracy of the pair is exactly disjointness of the two words. Cross-checked against the definitional sOp(j, dOp(j, a)) == a test in SimplicialSetConstructionsSpec.

A pair (a, b) in X_n x Y_n is degenerate in the product iff some single j degenerates both sides at once (s_j on X x Y is literally the diagonal (s_j, s_j)) -- and a is s_j-degenerate exactly when j appears in a.word (the normal form's own meaning: word is precisely the set of indices a is degenerate at, not just the outermost one -- e.g. s_1 s_0(v) is degenerate at both s_1 directly and, via s_0 s_0 = s_1 s_0, at s_0 too, matching both entries of its word [1, 0]). So non-degeneracy of the pair is exactly disjointness of the two words. Cross-checked against the definitional sOp(j, dOp(j, a)) == a test in SimplicialSetConstructionsSpec.

Attributes

Experimental
true
def productGeneratorOrdering[GX, GY](using ox: Ordering[GX], oy: Ordering[GY]): Ordering[ProductGenerator[GX, GY]]

Attributes

Experimental
true
def simplexIsOrderedCell[VertexT](using vtxOrd: Ordering[VertexT])(setOrdering: Ordering[Simplex[VertexT]] = ...): is[Simplex[VertexT], OrderedCell]

Simplex[VertexT] is OrderedCell, with an injectable ordering so a stream can supply its own filtration order.

Simplex[VertexT] is OrderedCell, with an injectable ordering so a stream can supply its own filtration order.

Must live outside Simplex.scala: an opaque type is transparent throughout its defining file, so there spx.size/spx.iterator/spx - v would resolve to SortedSet's own members (or fail to compile) instead of SimplexOps's. See .claude/WORKLOG-extension-companion-objects.md.

Attributes

Experimental
true
def simplexOrdering[VertexT](using vtxOrd: Ordering[VertexT]): Ordering[Simplex[VertexT]]

Stays in this file (needs Simplex[VertexT]'s own opaque-type transparency for the Ordering[SortedSet[ VertexT]] -> Ordering[Simplex[VertexT]] coercion below), unlike simplexIsOrderedCell (SimplexOrderedCell.scala) -- this function makes no .someExtensionMethod call on any Simplex[VertexT] value, so it isn't exposed to the same-file dealiasing hazard that forced that one out. See SimplexOrderedCell.scala's own doc for the full explanation.

Stays in this file (needs Simplex[VertexT]'s own opaque-type transparency for the Ordering[SortedSet[ VertexT]] -> Ordering[Simplex[VertexT]] coercion below), unlike simplexIsOrderedCell (SimplexOrderedCell.scala) -- this function makes no .someExtensionMethod call on any Simplex[VertexT] value, so it isn't exposed to the same-file dealiasing hazard that forced that one out. See SimplexOrderedCell.scala's own doc for the full explanation.

Attributes

Experimental
true
def ssetElementOrdering[G](using ordG: Ordering[G]): Ordering[SSetElement[G]]

Attributes

Experimental
true
def ∆[VertexT : Ordering](vertices: VertexT*): Simplex[VertexT]

Convenience method for defining simplices

Convenience method for defining simplices

The character ∆ is typed as Alt+J on Mac GB layout, and has unicode code 0x0394.

Attributes

Experimental
true

Givens

Experimental givens

Attributes

Experimental
true
given defaultSimplexIsOrderedCell: [VertexT : Ordering] => is[Simplex[VertexT], OrderedCell]

Attributes

Experimental
true

Extensions

Experimental extensions

extension (coords: Vector[Int])
def asCube: Cube

Attributes

Experimental
true
extension [VertexT](spx: Simplex[VertexT])
def max[B >: VertexT : Ordering]: VertexT

min/max stay a top-level extension, not moved into SimplexOps/object Simplex's companion scope like everything else above: Scala 3 tries phase-1 extension candidates (lexical scope, including any wildcard import math.Ordering.Implicits.* a call site has, which brings in infixOrderingOps's binary min(rhs)/ max(rhs)) before phase-2 (the receiver's own companion). Moving these into the companion drops them to phase 2, so a call site with that import silently rebinds spx.max to the stdlib's binary version instead -- a hard type error (wrong arity), not a silent behavior change, but only caught at those call sites, not here. General lesson: an opaque type's extension name that collides with a wildcard-importable stdlib extension (min/max/</compare from Ordering.Implicits, possibly others) needs to stay top-level.

min/max stay a top-level extension, not moved into SimplexOps/object Simplex's companion scope like everything else above: Scala 3 tries phase-1 extension candidates (lexical scope, including any wildcard import math.Ordering.Implicits.* a call site has, which brings in infixOrderingOps's binary min(rhs)/ max(rhs)) before phase-2 (the receiver's own companion). Moving these into the companion drops them to phase 2, so a call site with that import silently rebinds spx.max to the stdlib's binary version instead -- a hard type error (wrong arity), not a silent behavior change, but only caught at those call sites, not here. General lesson: an opaque type's extension name that collides with a wildcard-importable stdlib extension (min/max/</compare from Ordering.Implicits, possibly others) needs to stay top-level.

Attributes

Experimental
true
def min[B >: VertexT : Ordering]: VertexT

min/max stay a top-level extension, not moved into SimplexOps/object Simplex's companion scope like everything else above: Scala 3 tries phase-1 extension candidates (lexical scope, including any wildcard import math.Ordering.Implicits.* a call site has, which brings in infixOrderingOps's binary min(rhs)/ max(rhs)) before phase-2 (the receiver's own companion). Moving these into the companion drops them to phase 2, so a call site with that import silently rebinds spx.max to the stdlib's binary version instead -- a hard type error (wrong arity), not a silent behavior change, but only caught at those call sites, not here. General lesson: an opaque type's extension name that collides with a wildcard-importable stdlib extension (min/max/</compare from Ordering.Implicits, possibly others) needs to stay top-level.

min/max stay a top-level extension, not moved into SimplexOps/object Simplex's companion scope like everything else above: Scala 3 tries phase-1 extension candidates (lexical scope, including any wildcard import math.Ordering.Implicits.* a call site has, which brings in infixOrderingOps's binary min(rhs)/ max(rhs)) before phase-2 (the receiver's own companion). Moving these into the companion drops them to phase 2, so a call site with that import silently rebinds spx.max to the stdlib's binary version instead -- a hard type error (wrong arity), not a silent behavior change, but only caught at those call sites, not here. General lesson: an opaque type's extension name that collides with a wildcard-importable stdlib extension (min/max/</compare from Ordering.Implicits, possibly others) needs to stay top-level.

Attributes

Experimental
true
extension [VertexT](vertices: SortedSet[VertexT])
def asSimplex: Simplex[VertexT]

Attributes

Experimental
true