AlphaComplexDQPBuilder
Algorithm 1: compute the d-skeleton of Alpha(S, p, a1).
Outer loop over dimension, inner loop over base vertex. B and U are built once per (dimension, vertex) rather than once per simplex, which is the only place ambient dimension enters the cost at all.
Attributes
- Experimental
- true
- Graph
-
- Supertypes
-
class Objecttrait Matchableclass Any
Members list
Type members
Classlikes
One record produced by a single successful QP solve.
One record produced by a single successful QP solve.
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Value members
Concrete methods
Candidate k-simplices, bucketed by their minimal vertex.
Candidate k-simplices, bucketed by their minimal vertex.
k = 0: the vertices of G (line 6). k = 1: the edges of G (line 6). k >= 2: the k-simplices of Lazy_{k-1}(X) (line 8), i.e. every (k+1)-set all of whose facets are already known to be in the complex.
Each candidate is stored as its vertices other than the minimal one, because the base vertex is the bucket key. Considering only simplices whose minimum is x is the "x <= x_j1 <= ... <= x_jk" reduction of step 2(b): every simplex is then tested exactly once.
Attributes
Line 1-2: the one-skeleton of the Cech complex of the weighted ball cover, Cech(S, p, a1).
Line 1-2: the one-skeleton of the Cech complex of the weighted ball cover, Cech(S, p, a1).
Only Cech neighbours can constrain the part of V_x that lies inside U_x: if U_x and U_z are disjoint then any y with pi_x(y) <= a1 already satisfies pi_x(y) <= pi_z(y). So restricting the QP's inequality constraints to N_G(x) is exact, not an approximation -- provided the optimum really is <= a1, which is precisely when we keep the simplex.
Uses the VP-tree spatial index already in FiniteMetricSpace.scala (JVPTree, via PowerDistance.toMetricSpace) rather than the naive O(N^2) all-pairs scan, when maxPower is finite -- see WORKLOG.md for why this only helps a genuinely-truncated complex: AlphaShapeDQP's default (maxRadius = Infinity, to match HelixDelaunay) makes every alive point trivially everyone's neighbour, where a spatial index buys nothing, so that case is still handled directly rather than via a VP-tree query with an infinite radius.
The per-point query radius radius(i) + maxRadiusOverAll is a conservative superset bound, not the exact pairwise one (weights make each point's true radius(i)+radius(j) threshold vary per pair) -- so every candidate the tree returns still goes through the same exact check as before. Correctness therefore doesn't depend on the spatial index at all, only its performance does; see AlphaComplexDQPSpatialIndexSpec for a brute-force cross-check across many random weighted and unweighted configurations.
Attributes
w is monotone along faces by construction -- the QP for a face has strictly fewer equality constraints, hence a larger feasible set and a smaller optimum -- but floating point can violate it by an ulp or two, which some persistence algorithms will not forgive.
w is monotone along faces by construction -- the QP for a face has strictly fewer equality constraints, hence a larger feasible set and a smaller optimum -- but floating point can violate it by an ulp or two, which some persistence algorithms will not forgive.
Attributes
Steps 2(a)-(b): assemble the dual data for the cell V_x once, then run one QP per candidate simplex based at x.
Steps 2(a)-(b): assemble the dual data for the cell V_x once, then run one QP per candidate simplex based at x.
Attributes
KKT conditions (12): Phi(sigma) = y* = x - sum_i lambda_i (x_i - x). None when the input carried no coordinates, matching witness's own contract -- must stay None, not null: storing null under an otherwise-present map key makes .get return Some(null), not None.
KKT conditions (12): Phi(sigma) = y* = x - sum_i lambda_i (x_i - x). None when the input carried no coordinates, matching witness's own contract -- must stay None, not null: storing null under an otherwise-present map key makes .get return Some(null), not None.