Skip to content

feat: apply SoS to AdaptiveKernel::orientation() for deterministic degeneracy resolution #263

@acgetchell

Description

@acgetchell

Summary

AdaptiveKernel::in_sphere() already uses Simulation of Simplicity (SoS) to deterministically resolve cospherical ties (never returns 0). However, AdaptiveKernel::orientation() intentionally preserves orientation == 0 for truly degenerate inputs, relying on algorithm-level coordinate perturbation retries to handle degeneracies.

This is inconsistent and less scientifically correct than applying SoS uniformly to both predicates, as CGAL does. For a library supporting quantum gravity research (CDT, Regge calculus), the triangulation is the spacetime — perturbation-based retries introduce a non-physical, non-deterministic source of randomness into the ensemble. SoS eliminates this: same input → same triangulation, always.

Current behavior

  • AdaptiveKernel::orientation(): exact via Bareiss, returns 0 for truly degenerate input (line 493-496 of kernel.rs: "No SoS: orientation must reflect true geometry so that zero-volume (degenerate) cells are detected, not masked.")
  • AdaptiveKernel::in_sphere(): exact + SoS fallback, never returns 0
  • Algorithm-level handling: insert_transactional() retries with coordinate perturbation when is_retryable() returns true (includes DegenerateOrientation)

Proposed change

Apply SoS to AdaptiveKernel::orientation() so it never returns 0, matching the insphere behavior. This requires:

  1. AdaptiveKernel::orientation(): call sos_orientation_sign() when exact determinant is 0
  2. Separate degeneracy detection: add explicit volume/degeneracy checks where the algorithm currently relies on orientation == 0:
    • build_initial_simplex — reject collinear/coplanar input via volume check
    • find_visible_boundary_facets — hull coplanarity detection
    • apply_bistellar_flip_with_k — zero-volume cell prevention (currently FlipError::DegenerateCell)
    • canonicalize_positive_orientation_for_cells — currently skips orientation == 0 cells
  3. Error hierarchy impact: GeometricError::DegenerateOrientation becomes unreachable for AdaptiveKernel users; the retryable error category shrinks

Motivation

  • Determinism: SoS perturbation is symbolic and depends only on vertex ordering (combinatorial structure), not random seeds
  • Reproducibility: same input always produces the same triangulation — critical for Monte Carlo simulations over triangulation ensembles
  • CGAL consistency: matches the battle-tested approach used by CGAL's exact predicate kernels
  • Simplifies error hierarchy: fewer retryable error paths, simpler is_retryable() logic

Relationship to other issues

  • Blocks refactor: orthogonalize the error hierarchy #262 (error hierarchy orthogonalization): the error hierarchy should reflect the actual failure modes after SoS is applied, not the current perturbation-retry design
  • References: Edelsbrunner & Mücke, "Simulation of Simplicity" (1990); Seidel, "The Nature and Meaning of Perturbations in Geometric Computing" (1998)

Files most affected

  • src/geometry/kernel.rsAdaptiveKernel::orientation()
  • src/geometry/sos.rs — already implements sos_orientation_sign()
  • src/core/triangulation.rs — orientation canonicalization, validation
  • src/core/algorithms/flips.rsresolve_zero_orientation, DegenerateCell
  • src/core/algorithms/incremental_insertion.rs — hull extension visibility
  • src/core/delaunay_triangulation.rs — construction paths

Co-Authored-By: Oz oz-agent@warp.dev

Metadata

Metadata

Assignees

No one assigned

    Labels

    apibugSomething isn't workingdocumentationImprovements or additions to documentationgeometryGeometry-related issuesrustPull requests that update rust codetopology

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions