HelixDelaunay

org.appliedtopology.tda4j.alpha.HelixDelaunay
See theHelixDelaunay companion object
class HelixDelaunay(pts: Array[Array[Double]], seed: Long = ..., requireValidTriangulation: Boolean = ...)(using epsilon: Epsilon) extends AlphaShapes

Based on https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=10917453&tag=1

'''Accepted limitation''': near-cospherical clusters make the frontier walk order-dependent (~1/170 at ambient dimension 4, 20-30 points) -- a real fix needs joint near-tie detection, not attempted here. So Helix is not reliable ground truth for dimension >= 4 fuzzing (AlphaCrossValidationSpec's comparisons stay as unsafeCompare/unsafeFuzzCompare diagnostics, not wired into sbt test). seed makes a given (pts, seed) pair deterministic, but does not remove this order-dependency -- see HelixDelaunayBuilder's own doc.

Value parameters

pts

the input points to triangulate

requireValidTriangulation

OFF by default -- changes nothing above when false. When true, and compute() produces a facet- multiplicity violation (FastAlphaHomologyContext's own precondition), runs HelixDelaunay.repairByJitterRetriangulation (.claude/DESIGN-helix-triangulation-repair.md): a "simulation of simplicity"-style repair that nudges exactly the offending, near-tied points by a tiny random perturbation and re-runs this SAME HelixDelaunayBuilder on the full (mostly unperturbed) point set, then recomputes every resulting simplex's own circumsphere from the ORIGINAL, un-nudged coordinates so the perturbation never leaks into a real filtration value -- only into the combinatorial tie-break, plus a direct check that the repaired result has no interior gap (see that method's own doc for why the facet-count check alone was found insufficient). Two other designs (discarding the conflicting region and re-filling it via coning from an arbitrary apex; discarding the extra claimants outright with no replacement) were tried first and rejected after being checked against the actual failing fixture -- see the design note's own "First"/"Second design attempt (rejected)" sections. Validated by targeted stress sweep at d=2 and d=3 (FastAlphaHomologyContext's own primary use case); d>=4 is untested -- HelixDelaunayBuilder itself is already "not reliable ground truth" there for unrelated reasons (this class's own doc above), so this repair inherits that pre-existing limitation rather than introducing a new one.

seed

seeds the bootstrap frontier-selection shuffle (HelixDelaunayBuilder); same pts and seed always produce the same triangulation.

Attributes

Companion
object
Experimental
true
Graph
Supertypes
class AlphaShapes
trait StratifiedSimplexStream[Int, Double]
trait StratifiedCellStream[Simplex[Int], Double]
trait CellStream[Simplex[Int], Double]
trait IterableOnce[Simplex[Int]]
trait Filtration[Simplex[Int], Double]
trait Filterable[Double]
class Object
trait Matchable
class Any
Show all

Members list

Value members

Concrete methods

def computeFVal(s: Simplex[Int]): Double
def edgeIsDelaunay(s: Simplex[Int]): Option[Double]
override def filtrationOrdering: Ordering[Simplex[Int]]

Attributes

Definition Classes
override def filtrationValue: PartialFunction[Simplex[Int], Double]

Attributes

Definition Classes
override def iterateDimension: PartialFunction[Int, Iterator[Simplex[Int]]]

Contract .iterator below relies on: the domain must be contiguous starting at 0 -- defined for 0, 1, ..., k for some k (or empty, or all of the non-negative integers), never with a gap. .iterator stops at the first dimension this is undefined for, so a non-contiguous domain (defined at d but not at d - 1) would silently truncate iteration instead of skipping the gap. Every implementation in this codebase already satisfies this (a simplicial complex can't have a d-simplex without its (d-1)-dimensional faces, so "no cells at d" implies "no cells at any dimension beyond d" too); a new implementation must preserve it.

Contract .iterator below relies on: the domain must be contiguous starting at 0 -- defined for 0, 1, ..., k for some k (or empty, or all of the non-negative integers), never with a gap. .iterator stops at the first dimension this is undefined for, so a non-contiguous domain (defined at d but not at d - 1) would silently truncate iteration instead of skipping the gap. Every implementation in this codebase already satisfies this (a simplicial complex can't have a d-simplex without its (d-1)-dimensional faces, so "no cells at d" implies "no cells at any dimension beyond d" too); a new implementation must preserve it.

Attributes

Definition Classes
def simplices(): Iterator[Simplex[Int]]
def simplicesInDimension(d: Int): Iterator[Simplex[Int]]

Inherited methods

override def iterator: Iterator[Simplex[Int]]

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[Simplex[Int], 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 ambientDimension: Int
val filtrationValuesMemo: Map[Simplex[Int], Double]
val points: Seq[Point]
val simplicesMap: Map[Int, Seq[Simplex[Int]]]
val simplicesSortedMap: Map[Int, Seq[Simplex[Int]]]

Inherited fields

val largest: Double

Attributes

Inherited from:
DoubleFiltration
val smallest: Double

Attributes

Inherited from:
DoubleFiltration