diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 8539fb82..dc5d393a 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -42,7 +42,7 @@ concurrency: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 - UV_VERSION: "0.11.27" + UV_VERSION: "0.11.28" BENCHMARK_TIMEOUT: 1800 # 30 min; pre-computed seeds + reduced 5D counts keep runtime well under this DELAUNAY_BENCH_DISCOVER_SEEDS_LIMIT: 256 # fallback only; ci_performance_suite uses pre-computed seeds diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f109cd2c..daa7a0e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ env: RUMDL_VERSION: "0.2.28" TAPLO_VERSION: "0.10.0" TYPOS_VERSION: "1.48.0" - UV_VERSION: "0.11.27" + UV_VERSION: "0.11.28" ZIZMOR_VERSION: "1.26.1" jobs: diff --git a/.github/workflows/generate-baseline.yml b/.github/workflows/generate-baseline.yml index d564eefb..9eb0c003 100644 --- a/.github/workflows/generate-baseline.yml +++ b/.github/workflows/generate-baseline.yml @@ -26,7 +26,7 @@ permissions: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 - UV_VERSION: "0.11.27" + UV_VERSION: "0.11.28" # Seed search limit for both old (pre-v0.8) and current env var names. # Old tags read DELAUNAY_BENCH_SEED_SEARCH_LIMIT; current code reads # DELAUNAY_BENCH_DISCOVER_SEEDS_LIMIT. Setting both ensures backward diff --git a/.github/workflows/papers.yml b/.github/workflows/papers.yml index d5cfec18..2a34e940 100644 --- a/.github/workflows/papers.yml +++ b/.github/workflows/papers.yml @@ -52,7 +52,7 @@ env: JUST_VERSION: "1.55.1" TECTONIC_VERSION: "0.16.9" TEX_FMT_VERSION: "0.5.7" - UV_VERSION: "0.11.27" + UV_VERSION: "0.11.28" jobs: papers: diff --git a/.github/workflows/release-benchmarks.yml b/.github/workflows/release-benchmarks.yml index 6f49b77f..fb90a71c 100644 --- a/.github/workflows/release-benchmarks.yml +++ b/.github/workflows/release-benchmarks.yml @@ -19,7 +19,7 @@ concurrency: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 - UV_VERSION: "0.11.27" + UV_VERSION: "0.11.28" jobs: release-baseline: diff --git a/.github/workflows/semgrep-sarif.yml b/.github/workflows/semgrep-sarif.yml index 724e47aa..7d0e0ea5 100644 --- a/.github/workflows/semgrep-sarif.yml +++ b/.github/workflows/semgrep-sarif.yml @@ -24,7 +24,7 @@ permissions: actions: read env: - UV_VERSION: "0.11.27" + UV_VERSION: "0.11.28" jobs: semgrep-sarif: diff --git a/AGENTS.md b/AGENTS.md index d1f3f5f3..0413381d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -112,7 +112,7 @@ When in doubt, favor the invariant over the convenient edit. - Every mutating operation preserves the invariants checked by `Tds::is_valid` / `validate` (Levels 1-2), `Triangulation::is_valid_topology` / `validate` (Level 3), - `Triangulation::is_valid_embedding` / `validate_embedding` (Level 4), and + `Triangulation::is_valid_realization` / `validate_realization` (Level 4), and `DelaunayTriangulation::is_valid_delaunay` / `validate` (Level 5). An operation that cannot preserve them must fail explicitly rather than leave inconsistent state behind. @@ -135,17 +135,20 @@ The library exposes five validation levels, each a superset of the last: 3. **Level 3 - Intrinsic PL Topology**: the abstract simplicial complex has the requested PL topology, including manifold/pseudomanifold conditions, links, Euler characteristic, orientability, and connected components. -4. **Level 4 - Embedding Validity**: the complex is faithfully realized in the - chosen ambient model, including Euclidean affine charts, toroidal periodic - charts, spherical `S^d` embeddings, and embedding-specific constraints. -5. **Level 5 - Geometric Predicates**: the embedding satisfies the selected +4. **Level 4 - Valid Realization**: the complex is realized without geometric + degeneracy or unintended intersections in the chosen model, including + Euclidean/toroidal affine-chart realization, spherical `S^d` realization, + and model-specific realization constraints. +5. **Level 5 - Geometric Predicates**: the realization satisfies the selected geometric predicate family, currently Euclidean/toroidal/spherical Delaunay checks and eventually regular, weighted, constrained, Gabriel, alpha, or related predicates. -Level 4 uses orientation and exact barycentric geometry for affine-chart -embedding, with backend-specific realization checks for non-Euclidean models. -Level 5 uses geometry-specific predicates. Levels 1-3 are embedding-independent +Level 4 uses orientation and exact barycentric geometry for Euclidean/toroidal +affine-chart realization, where toroidal checks run in lifted periodic +covering-space charts, and backend-specific realization checks for curved +models. Level 5 uses geometry-specific predicates. Levels 1-3 are +realization-independent graph/topology checks. Validation code belongs at the lowest layer that owns the invariant. Each layer should expose the standard validation surface. Use plain @@ -155,7 +158,7 @@ multiple validation layers. Use `*_diagnostic` for the first actionable repair/retry diagnostic, `*_report` for layer-local aggregate diagnostics, and `validate()` / `validation_report()` for cumulative roll-up through the owning layer. Report names should identify the layer being checked, e.g. -`structure_report`, `topology_report`, `embedding_report`, and +`structure_report`, `topology_report`, `realization_report`, and `delaunay_report`. Higher layers should roll lower diagnostics up without stringifying them. diff --git a/CITATION.cff b/CITATION.cff index 2bc265c1..c934896c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -26,7 +26,7 @@ abstract: >- robustness and degeneracy handling, and Hilbert curves for deterministic insertion ordering and efficient spatial indexing. Provides an explicit 5-level validation hierarchy on individual elements, combinatorial - consistency, intrinsic PL topology, embedding validity in the active model, + consistency, intrinsic PL topology, valid realization in the active model, and geometric predicates such as Delaunay. Allows for the complete set of Pachner moves up to D=5 using bistellar flips, vertex insertion and deletion, and the conversion of non-Delaunay diff --git a/README.md b/README.md index 38ed3f96..228ed6a4 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Rust crate providing D-dimensional [Delaunay triangulations] and [convex hulls][ topologies. Uses [exact predicates] and [Simulation of Simplicity] for robustness and degeneracy handling, and [Hilbert curve]s for deterministic insertion ordering and efficient spatial indexing. Provides an explicit [5-level validation hierarchy][Validation Guide] on individual elements, -combinatorial consistency, intrinsic PL topology, embedding validity in the active +combinatorial consistency, intrinsic PL topology, valid realization in the active model, and geometric predicates such as Delaunay. Allows for the complete set of [Pachner moves] up to D=5 using bistellar flips, vertex insertion and deletion, and the conversion of non-Delaunay triangulations into Delaunay triangulations via bounded flip/rebuilds. Auxiliary data may be stored @@ -54,11 +54,11 @@ Use this crate when you want: - Delaunay triangulations or convex hulls in 2D through 5D. - Exact predicates and deterministic SoS handling for degenerate inputs. -- Embedding Validity validation for Euclidean and toroidal models independent of Delaunay predicates. +- Valid-realization checks for Euclidean, toroidal, and spherical models independent of Delaunay predicates. - PL-manifold checks and explicit topology guarantees. - PL-manifold-aware editing via bistellar flips and bounded Delaunay repair. - Typed construction, insertion, validation, topology, and repair diagnostics. -- Validation reports that separate element, combinatorial, intrinsic topology, embedding, and +- Validation reports that separate element, combinatorial, intrinsic topology, realization, and geometric-predicate failures. This is not a replacement for full meshing packages such as [CGAL], TetGen, or Gmsh when you need @@ -93,7 +93,7 @@ meshing, or production-scale dynamic remeshing. correctness tests. - [x] PL-manifold validation by default, with pseudomanifold checks available as an explicit opt-out. - [x] Prototype spherical `S^2`/`S^3` construction through `SphericalDelaunayBuilder`, with - Level 3 Intrinsic PL Topology, spherical Level 4 Embedding Validity, and spherical Level 5 + Level 3 Intrinsic PL Topology, spherical Level 4 realization checks, and spherical Level 5 empty-cap predicate checks. - [x] Safe Rust: `#![forbid(unsafe_code)]`. - [x] Serialization/deserialization through [JSON]. @@ -190,18 +190,29 @@ just notebook-clear-outputs-all ## πŸ§ͺ Scientific Basis -The crate models triangulations as oriented simplicial complexes with separate combinatorial and -geometric checks. Robustness comes from the same layered predicate strategy used throughout the code: -fast f64 filters when the sign is provable, exact arithmetic fallback when it is not, and deterministic -SoS resolution for degenerate configurations. - -The validation contract is computational and finite-dimensional. The crate checks that constructed or -edited triangulations satisfy implemented element, combinatorial, intrinsic topology, embedding, and -geometric-predicate invariants; it does not claim to solve meshing constraints or certify unsupported -geometric models. - -For the detailed contract, see [REFERENCES.md](REFERENCES.md), [`docs/invariants.md`](docs/invariants.md), -and [`docs/numerical_robustness_guide.md`](docs/numerical_robustness_guide.md). +The crate treats a finite point-set triangulation as an oriented abstract simplicial complex plus a +coordinate realization in a supported geometric model. Levels 1-3 certify element validity, +combinatorial consistency, and intrinsic PL topology without depending on coordinates. Level 4 +certifies geometric validity: every maximal simplex must be nondegenerate and realized simplices may +intersect only in their shared abstract faces. Level 5 +certifies geometric optimality or predicate satisfaction, currently the Delaunay empty-circumsphere +property. + +Correctness evidence comes from the invariant model, exact predicate fallbacks, deterministic +Simulation of Simplicity, validation reports, property tests, regression tests, and public examples. +Performance evidence is separate: Hilbert ordering, allocation-conscious data structures, +validation-level benchmarks, math-kernel benchmarks, and release-to-release Criterion reports +characterize cost and observability, but they do not replace correctness checks. + +The crate guarantees the implemented finite-dimensional Delaunay, topology, and validation contracts +for the documented coordinate models and dimensions. It does not replace constrained meshing +packages, prove arbitrary abstract PL-manifolds realizable from coordinates, or certify unsupported +spherical/hyperbolic workflows. + +For the detailed contract, see [`docs/validation.md`](docs/validation.md), +[`docs/invariants.md`](docs/invariants.md), [`docs/topology.md`](docs/topology.md), +[`docs/numerical_robustness_guide.md`](docs/numerical_robustness_guide.md), +[`docs/limitations.md`](docs/limitations.md), and [`benches/README.md`](benches/README.md). ## βœ… Validation Model @@ -210,18 +221,19 @@ and [`docs/numerical_robustness_guide.md`](docs/numerical_robustness_guide.md). | 1 | Element Validity: vertex, simplex, facet, coordinate, and local-object invariants | `is_valid()` / element reports | | 2 | Combinatorial Consistency: TDS incidences, neighbors, and simplex/ridge connectivity | `validate_structure()` / `structure_report()` | | 3 | Intrinsic PL Topology: manifold/pseudomanifold links, components, and Euler consistency | `is_valid_topology()` / `topology_report()` | -| 4 | Embedding Validity: faithful realization in the active Euclidean, toroidal, or spherical model | `is_valid_embedding()` / `embedding_report()` | -| 5 | Geometric Predicates: Delaunay and future geometry-specific predicate families | `is_valid_delaunay()` / `delaunay_report()` | +| 4 | Valid Realization: nondegenerate realized simplices with only shared-face intersections | `is_valid_realization()` / `realization_report()` | +| 5 | Geometric Predicates: Delaunay and future geometry-specific optimality predicates | `is_valid_delaunay()` / `delaunay_report()` | | 1-5 | Cumulative diagnostics | `dt.validate()` / `dt.validation_report()` | `TopologyGuarantee` controls which Level 3 Intrinsic PL Topology invariants are enforced. `ValidationPolicy` -controls when Level 3 checks run during incremental insertion. Level 4 Embedding Validity is -backend-specific: Euclidean and toroidal paths validate affine charts, while the spherical prototype -validates simplices on `S^D \subset R^(D+1)`. Level 5 geometric predicates are likewise +controls when Level 3 checks run during incremental insertion. Level 4 realization validation is +backend-specific: Euclidean and toroidal paths validate affine-chart realizations, with toroidal +checks lifted to periodic covering-space charts, while the spherical prototype validates simplices on +`S^D \subset R^(D+1)`. Level 5 geometric predicates are likewise backend-specific: Euclidean/toroidal Delaunay paths use empty-circumsphere predicates, while the spherical prototype uses the empty-cap / ambient-hull-facet predicate. Use -`dt.as_triangulation().validate_embedding()` when you want -cumulative Levels 1-4 validation for ordinary triangulations. `dt.as_triangulation().embedding_report()` +`dt.as_triangulation().validate_realization()` when you want +cumulative Levels 1-4 validation for ordinary triangulations. `dt.as_triangulation().realization_report()` returns simplex keys, simplex UUIDs, and offending vertex keys/UUIDs for Level 4 repair planning. The default is PL-manifold topology with explicit full-validation checkpoints. Layer-local APIs use `is_valid()` for unambiguous element/TDS owners, `is_valid_*` diff --git a/REFERENCES.md b/REFERENCES.md index 7b7f75c3..a610f962 100644 --- a/REFERENCES.md +++ b/REFERENCES.md @@ -347,12 +347,14 @@ set-based structures (e.g., edge sets) under different construction orders. IBM Technical Report, 1958. Often cited for the Tanimoto coefficient (equivalent to the Jaccard index for binary vectors). -## Topological Manifolds and PL Topology (Level 3 Validation) +## Topological Manifolds, Realizations, and PL Topology (Levels 3-4 Validation) -These references support the topology-only manifold / PL-manifold validation logic in this -library (facet degree, closed-boundary checks, and links of simplices). +These references support abstract and geometric simplicial complexes, affine/geometric +realizations, and the topology-only manifold / PL-manifold validation logic in this library +(facet degree, closed-boundary checks, and links of simplices). -- Edelsbrunner, H., and Harer, J. *Computational Topology*. AMS, 2010. +- Dey, T. K., and Wang, Y. *Computational Topology for Data Analysis*. Cambridge University Press, 2022. +- Edelsbrunner, H., and Harer, J. *Computational Topology: An Introduction*. AMS, 2010. - Hatcher, A. *Algebraic Topology*. Cambridge University Press, 2002. (Appendix A: PL Manifolds and Links.) - Munkres, J. R. *Elements of Algebraic Topology*. Addison–Wesley, 1984. @@ -361,15 +363,16 @@ library (facet degree, closed-boundary checks, and links of simplices). - Stillwell, J. *Euler's Gem: The Polyhedron Formula and the Birth of Topology*. Princeton University Press, 2010. - Zomorodian, A. *Topology for Computing*. Cambridge University Press, 2005. -## Embedded-Geometry Overlap Detection (Level 4 Validation) +## Realized-Simplex Overlap Detection (Level 4 Validation) -These references support the embedded-geometry (Level 4) validator, which certifies that maximal -simplices are nondegenerate and intersect only in their shared faces. Candidate overlapping pairs -are found with a sweep-and-prune broad phase over axis-aligned bounding boxes before exact rational -barycentric intersection tests are applied. Two axis-aligned boxes intersect if and only if their -projections overlap on every coordinate axis (the separating-axis test), and sorting boxes by their -lower endpoint on one axis while retiring boxes whose upper endpoint precedes the current lower -endpoint examines a superset of all axis-overlapping pairs, so no intersecting pair is skipped. +These references support the realized-simplex overlap validator used by Level 4 affine-chart +realization checks, which certify that maximal simplices are nondegenerate and intersect only in +their shared faces. Candidate overlapping pairs are found with a sweep-and-prune broad phase over +axis-aligned bounding boxes before exact rational barycentric intersection tests are applied. Two +axis-aligned boxes intersect if and only if their projections overlap on every coordinate axis (the +separating-axis test), and sorting boxes by their lower endpoint on one axis while retiring boxes +whose upper endpoint precedes the current lower endpoint examines a superset of all axis-overlapping +pairs, so no intersecting pair is skipped. - Baraff, D. "Dynamic Simulation of Non-Penetrating Rigid Bodies." PhD thesis, Cornell University, 1992. Introduces coordinate sorting ("sort and sweep") for axis-aligned bounding-box overlap detection. diff --git a/benches/README.md b/benches/README.md index 494bdc18..8631641a 100644 --- a/benches/README.md +++ b/benches/README.md @@ -288,7 +288,7 @@ cargo bench --profile perf --bench ci_performance_suite - convex hull extraction - boundary facet traversal - cumulative validation Levels 1-5, including Level 1-2 TDS structure, Level 3 - topology, Level 4 embedding, and Level 5 Delaunay predicate checks + topology, Level 4 realization, and Level 5 Delaunay predicate checks - incremental vertex insertion into prepared triangulations - explicit 2D-5D bistellar flip roundtrips @@ -357,7 +357,7 @@ Use `just bench-pachner-stress*` for Criterion timing evidence. Criterion requires at least 10 samples. The benchmark recipe measures stable accepted move fixtures and corresponding forward/inverse round trips. -The stress cases validate topology plus the Level 4 embedding invariant that +The stress cases validate topology plus the Level 4 realization invariant that arbitrary Pachner moves are expected to preserve; Level 5 Delaunay validity is not a postcondition of arbitrary topology edits. Invalid local candidates are counted as candidate misses or proposal rejections, while successfully planned diff --git a/benches/common/flip_fixtures.rs b/benches/common/flip_fixtures.rs index dec005fe..d65deb73 100644 --- a/benches/common/flip_fixtures.rs +++ b/benches/common/flip_fixtures.rs @@ -191,7 +191,7 @@ pub const ADVERSARIAL_POINTS_5D: &[[f64; 5]] = &[ /// Intentionally invalid 3D fixture used to prove benchmark setup rejects /// degenerate inputs instead of silently sanitizing them. /// -/// All points are coplanar (`z = 0`), so no faithful 3D simplex embedding can +/// All points are coplanar (`z = 0`), so no faithful 3D simplex realization can /// be formed. #[allow( dead_code, diff --git a/benches/profiling_suite.rs b/benches/profiling_suite.rs index 31f5466e..17b309ba 100644 --- a/benches/profiling_suite.rs +++ b/benches/profiling_suite.rs @@ -1072,11 +1072,11 @@ macro_rules! benchmark_validation_components_dimension { }); }); - group.bench_function("validate_embedding", |b| { + group.bench_function("validate_realization", |b| { b.iter(|| { - if let Err(error) = black_box(dt.as_triangulation().validate_embedding()) { + if let Err(error) = black_box(dt.as_triangulation().validate_realization()) { abort_benchmark(format_args!( - "embedding validation should pass for benchmark triangulation: {error}" + "realization validation should pass for benchmark triangulation: {error}" )); } }); diff --git a/docs/ORIENTATION_SPEC.md b/docs/ORIENTATION_SPEC.md index 9572459d..85ed29f0 100644 --- a/docs/ORIENTATION_SPEC.md +++ b/docs/ORIENTATION_SPEC.md @@ -202,7 +202,7 @@ drive repair, but replacement-simplex orientation itself uses `robust_orientatio and then enforces the Delaunay property. - `.try_toroidal([..])` builds an image-point triangulation and then runs orientation normalization, lifted geometric orientation validation, final - Levels 1-3 topology validation, Level 4 Embedding Validity in periodic + Levels 1-3 topology validation, Level 4 realization validation in periodic covering-space charts, and final Level 5 Delaunay-predicate validation before returning the quotient triangulation. diff --git a/docs/api_design.md b/docs/api_design.md index c109a2a1..ca381778 100644 --- a/docs/api_design.md +++ b/docs/api_design.md @@ -164,7 +164,7 @@ for topology guarantee and validation policy details. `RepairOperationFailed { operation, source }`. - **Validation**: The active `ValidationPolicy` (set with `dt.try_set_validation_policy(...)` or `dt.set_validation_policy(...)`) governs automatic topology and - changed-scope embedding guards for subsequent construction/modification operations + changed-scope realization guards for subsequent construction/modification operations ### Simplex Barycenters For Local Editing @@ -342,7 +342,7 @@ After applying flips, you should: 1. Manually verify the Delaunay property if needed: ```rust - assert!(dt.as_triangulation().validate_embedding().is_ok()); // Check Level 4 (Embedding Validity) + assert!(dt.as_triangulation().validate_realization().is_ok()); // Check Level 4 (Valid Realization) assert!(dt.is_valid_delaunay().is_ok()); // Check Level 5 (Geometric Predicates: Delaunay) ``` @@ -395,7 +395,7 @@ Both APIs work with the same validation framework but have different guarantees: - βœ… Maintains **Element Validity** and **Combinatorial Consistency** (Levels 1-2) - βœ… Maintains **Intrinsic PL Topology** (Level 3, controlled by `TopologyGuarantee`) -- βœ… Designed to maintain **Embedding Validity** (Level 4) and the implemented +- βœ… Designed to maintain **Valid Realization** (Level 4) and the implemented **Geometric Predicates** for Delaunay (Level 5) - βœ… Fails gracefully if invariants cannot be maintained @@ -417,8 +417,8 @@ assert!(dt.is_valid_structure().is_ok()); // Level 3: + Intrinsic PL Topology assert!(dt.as_triangulation().is_valid_topology().is_ok()); -// Level 4: + Embedding Validity -assert!(dt.as_triangulation().validate_embedding().is_ok()); +// Level 4: + Valid Realization +assert!(dt.as_triangulation().validate_realization().is_ok()); // Level 5: + Geometric Predicates (Delaunay today) assert!(dt.is_valid_delaunay().is_ok()); diff --git a/docs/architecture/module_map.md b/docs/architecture/module_map.md index c7a2469d..01ab9754 100644 --- a/docs/architecture/module_map.md +++ b/docs/architecture/module_map.md @@ -63,7 +63,7 @@ PL-manifold validation. Ridge ownership therefore belongs in `src/topology/`. - `coordinate_range.rs` - validated coordinate-range value type for random point and triangulation generator APIs. -- `embedding.rs` - pure labeled-simplex embedding predicates and witnesses +- `realization.rs` - pure labeled-simplex realization predicates and witnesses used by generic Level 4 validation. - `kernel.rs` - kernel abstraction (`AdaptiveKernel`, `RobustKernel`, `FastKernel`) and `ExactPredicates` marker trait. @@ -112,7 +112,7 @@ coordinate model/API rather than loosening ordinary `f64` APIs. - `serialization.rs` - conversion to/from `Tds` with topology metadata reset rules. - `spherical.rs` - bounded `S^2`/`S^3` spherical construction, - embedding-validation, and empty-cap Delaunay backend using the topology + realization-validation, and empty-cap Delaunay backend using the topology space coordinate/metric backend. - `validation.rs` - implemented Level 5 Geometric Predicate APIs for Delaunay validation errors and construction validation cadence helpers. @@ -151,7 +151,7 @@ slotmap handles. - `spaces/euclidean.rs` and `spaces/toroidal.rs` - concrete `TopologicalSpace` helper implementations. - `spaces/spherical.rs` - spherical coordinate and metric backend for points on - `S^D` embedded in `R^(D+1)`. + `S^D` realized in `R^(D+1)`. - `traits/topological_space.rs` - public `GlobalTopology` metadata enum and `TopologyKind`. - `traits/global_topology_model.rs` - internal scalar-generic diff --git a/docs/architecture/prelude_reference.md b/docs/architecture/prelude_reference.md index 7a5777dd..f644a76c 100644 --- a/docs/architecture/prelude_reference.md +++ b/docs/architecture/prelude_reference.md @@ -18,7 +18,7 @@ they exercise. | Incremental insertion diagnostics and result types | `use delaunay::prelude::insertion::*` | | Post-construction vertex deletion errors and keys | `use delaunay::prelude::deletion::*` | | Low-level TDS simplices, facets, keys, and validation reports | `use delaunay::prelude::tds::*` | -| Points, simplex embeddings, coordinate ranges, kernels, predicates, and geometric measures | `use delaunay::prelude::geometry::*` | +| Points, simplex realizations, coordinate ranges, kernels, predicates, and geometric measures | `use delaunay::prelude::geometry::*` | | Random points or triangulations for examples, tests, and benchmarks | `use delaunay::prelude::generators::*` | | Read-only traversal, adjacency, ridge views, simplex barycenters, convex hulls, and comparison helpers | `use delaunay::prelude::query::*` | | Topological space helpers, topology traits, spherical point/metric backends, and lifted toroidal IDs | `use delaunay::prelude::topology::spaces::*` | diff --git a/docs/code_organization.md b/docs/code_organization.md index 055ed4da..4103c24a 100644 --- a/docs/code_organization.md +++ b/docs/code_organization.md @@ -49,7 +49,7 @@ into architecture docs; link to the command guide instead. - `edge.rs` and `facet.rs` stay in `src/core/` because they are direct TDS traversal primitives. Ridge query/view types belong in `src/topology/` because ridge shape and link semantics depend on dimension and topology. -- Generic Level 4 Embedding Validity belongs in `src/core/embedding.rs`; +- Generic Level 4 realization validation belongs in `src/core/realization.rs`; implemented Level 5 Geometric Predicate APIs for Delaunay belong in `src/delaunay/validation.rs`, with TDS-level Delaunay-property scan helpers under `src/delaunay/`; generic Level 1-3 validation belongs in the diff --git a/docs/dev/commands.md b/docs/dev/commands.md index 00b50219..fd7a190c 100644 --- a/docs/dev/commands.md +++ b/docs/dev/commands.md @@ -309,8 +309,8 @@ default to 100 attempted moves with progress every 10 attempts, write progress CSV plus summary JSON under `target/pachner_stress/`, and keep parseable stdout stage/report/progress lines so long workloads can be diagnosed without making the workflow part of routine CI. These direct stress recipes currently validate -topology scope only (Levels 1-3); the large Level 4 embedding overlap scan is -deferred to the dedicated embedding-validation work. The CLI supports +topology scope only (Levels 1-3); the large Level 4 realization overlap scan is +deferred to the dedicated realization-validation work. The CLI supports `round-trip` and `random-walk` modes; `round-trip` is the default. Pass explicit `attempts`, `vertices`, and `validate_every` arguments for soak runs. Use `just bench-pachner-stress*` when Criterion timing statistics for stable 4D move diff --git a/docs/dev/perf-tuning.md b/docs/dev/perf-tuning.md index 5aad8ead..0120c1bb 100644 --- a/docs/dev/perf-tuning.md +++ b/docs/dev/perf-tuning.md @@ -176,7 +176,7 @@ unless validation itself is the behavior being measured. For final handoff after Rust code changes, run: ```bash -PATH=/opt/homebrew/bin:$PATH just ci +just ci ``` For documentation-only, configuration-only, or Python-only changes, follow the diff --git a/docs/dev/tooling-alignment.md b/docs/dev/tooling-alignment.md index 5ff9520b..f651244b 100644 --- a/docs/dev/tooling-alignment.md +++ b/docs/dev/tooling-alignment.md @@ -61,7 +61,7 @@ The useful updates ported in this pass are: Delaunay on the sibling repository's current Markdown linter release after local `just check` exposed the older 0.2.10 pin as stale. - uv-managed Python support-tool pins now use exact reviewed versions for the - shared dev tools: `ruff` 0.15.20, `semgrep` 1.168.0, and `ty` 0.0.55. + shared dev tools: `ruff` 0.15.20, `semgrep` 1.168.0, and `ty` 0.0.56. Semgrep is intentionally ahead of the older sibling baseline so its transitive dependency graph stays on the current reviewed toolchain baseline. Delaunay previously used lower-bound specifiers for those tools, which allowed local @@ -228,7 +228,7 @@ The useful updates ported in this pass are: runs on macOS, installs `chktex` from the TeX distribution when the runner does not already provide it, and installs the native bridge-library packages required when compiling Tectonic from Cargo. All uv-backed workflows use uv - 0.11.27 to match the local Python tooling bootstrap. + 0.11.28 to match the local Python tooling bootstrap. - `.codecov.yml` now ratchets Delaunay's coverage policy above the older causal-triangulations baseline without copying la-stack's near-total threshold. Project coverage targets the current 90% line with only 1% diff --git a/docs/diagnostics.md b/docs/diagnostics.md index 2ce1eec9..f425d07a 100644 --- a/docs/diagnostics.md +++ b/docs/diagnostics.md @@ -98,10 +98,10 @@ Layer-local diagnostics follow a standard naming pattern: - `*_diagnostic`: first actionable repair/retry diagnostic for that layer. - `*_report`: all checkable layer-local failures. -For Level 4 embedding failures specifically, use -`dt.as_triangulation().embedding_diagnostic()` for the first repair-oriented -failure and `dt.as_triangulation().embedding_report()` for all checkable -embedding failures. These report invalid simplices or simplex pairs with +For Level 4 realization failures specifically, use +`dt.as_triangulation().realization_diagnostic()` for the first repair-oriented +failure and `dt.as_triangulation().realization_report()` for all checkable +realization failures. These report invalid simplices or simplex pairs with simplex keys, simplex UUIDs, offending vertex keys, and offending vertex UUIDs. That key-oriented payload is the intended starting point for explicit rollback, vertex deletion, or future repair workflows; the report itself is pure and does diff --git a/docs/invariants.md b/docs/invariants.md index cb991305..08fb953e 100644 --- a/docs/invariants.md +++ b/docs/invariants.md @@ -27,7 +27,7 @@ the guarantees stated in the public API documentation. - [Validation layering](#validation-layering) - [Coherent orientation](#coherent-orientation) - [Geometric invariants](#geometric-invariants) - - [Embedding validity in affine charts](#embedding-validity-in-affine-charts) + - [Valid realization](#valid-realization) - [Geometric predicates and the Delaunay condition](#geometric-predicates-and-the-delaunay-condition) - [Robust predicate envelope](#robust-predicate-envelope) - [PL-manifold conditions](#pl-manifold-conditions) @@ -116,25 +116,26 @@ operation has certified which part of the structure: 3. **Level 3 β€” Intrinsic PL Topology**: the abstract simplicial complex satisfies the requested `TopologyGuarantee` (pseudomanifold, PL manifold, or strict PL manifold) through incidence, connected components, Euler-characteristic, and link checks. -4. **Level 4 β€” Embedding Validity**: the complex is faithfully realized in the chosen ambient model. - Euclidean topology validates in the ambient affine chart; toroidal topology validates in periodic - covering-space charts; the bounded spherical prototype validates simplices on +4. **Level 4 β€” Valid Realization**: the complex is geometrically valid in the chosen coordinate + model. Euclidean/toroidal topology validates affine-chart realizations, with toroidal checks + lifted to periodic covering-space charts; the bounded spherical prototype validates simplices on `S^D \subset R^(D+1)`. -5. **Level 5 β€” Geometric Predicates**: the embedding satisfies the selected geometry-specific - predicate family. The implemented family today is Delaunay, with Euclidean/toroidal - empty-circumsphere predicates and spherical empty-cap / ambient-hull-facet predicates. +5. **Level 5 β€” Geometric Predicates**: the valid realization satisfies the selected + geometry-specific predicate family. The implemented family today is Delaunay, with + Euclidean/toroidal empty-circumsphere predicates and spherical empty-cap / ambient-hull-facet + predicates. `Triangulation::is_valid_topology()` is a Level 3 intrinsic PL-topology check. `DelaunayTriangulation::is_valid_delaunay()` is the implemented Level 5 geometric-predicate check -for an already-formed Delaunay triangulation. `Triangulation` also exposes Level 4 embedding -validation through `is_valid_embedding` / -`validate_embedding`. +for an already-formed Delaunay triangulation. `Triangulation` also exposes Level 4 realization +validation through `is_valid_realization` / +`validate_realization`. Cumulative validation is exposed through the `validate` / `validation_report` APIs described in [`docs/validation.md`](validation.md). Automatic validation during construction is intentionally topology-oriented: `ValidationPolicy` -controls Level 3 checks during insertion and can enable local insertion-time embedding checks. -Full/global Level 4 embedding certification and Level 5 geometric-predicate validation remain +controls Level 3 checks during insertion and can enable local insertion-time realization checks. +Full/global Level 4 realization certification and Level 5 geometric-predicate validation remain explicit certification steps for workflows that need them. --- @@ -157,6 +158,15 @@ are a deliberate exception at the TDS layer: their neighbor reciprocity is still plain Euclidean facet-parity test is not a meaningful combinatorial-orientation certificate once periodic offsets are part of the simplex identity. +Pachner and bistellar-editing transactions must keep coherent combinatorial orientation and positive +geometric simplex orientation separate. A move can leave the TDS coherently oriented while affected +simplices have negative signed volume, or can make individual simplices positive while breaking +shared-facet coherence. The ordinary realized-geometry-preserving edit path repairs negative +orientation by reordering simplex vertex slots where possible, then relies on topology and Level 4 +realization validation before the edited state is accepted. If the repaired state still violates the +contract, the transaction rolls back with a typed error instead of leaving a partially repaired +triangulation behind. + See [`ORIENTATION_SPEC.md`](ORIENTATION_SPEC.md) for the exact parity convention, implementation map, and test expectations. @@ -164,20 +174,22 @@ map, and test expectations. ## Geometric invariants -### Embedding validity in affine charts +### Valid realization Levels 1-3 validate the abstract oriented simplicial complex: elements, incidence, neighbor reciprocity, coherent orientation, manifoldness, links, connectedness, and Euler consistency. These -checks do not by themselves prove that the complex is faithfully embedded in its coordinates. A +checks do not by themselves prove that the complex is faithfully realized in its coordinates. A topologically valid complex can still fold over itself, contain a zero-volume maximal simplex, or identify simplices in a way that overlaps in the chosen geometric chart. -Level 4 is the embedding-validity check. It is independent of Level 5 geometric predicates and +Level 4 is the valid-realization check. It is independent of Level 5 geometric predicates and enforces: - every maximal simplex has nonzero `D`-volume under the robust orientation predicate; -- every pair of maximal simplices intersects only in the face spanned by their shared vertices; -- toroidal triangulations are checked in periodic covering-space charts, including translated +- every pair of maximal simplices intersects only in the realization of the face spanned by their + shared vertices; +- Euclidean and toroidal triangulations use valid affine-chart realization checks, with toroidal + triangulations checked in periodic covering-space charts, including translated images that can overlap across the fundamental-domain boundary. - the bounded spherical prototype validates `S^2`/`S^3` maximal simplices as nondegenerate spherical simplices in `S^D \subset R^(D+1)`. @@ -185,15 +197,20 @@ enforces: This is intentionally separate from topology. Non-orientable spaces are valid objects in topology in general, but this crate's TDS contract maintains coherent orientation for the oriented complexes its construction, flip, and predicate machinery operate on. Level 4 then asks whether that oriented -complex is a valid realization in the active embedding model. General spherical integration with -the ordinary mutable triangulation surface and hyperbolic topology need model-specific chart -validators before they can offer the same Level 4 guarantee. +complex is a valid realization in the active realization model. For Euclidean/toroidal affine-chart models, this means +the vertex map is injective, every abstract simplex is realized as a nondegenerate affine simplex, +and realized simplex intersections satisfy `|sigma| ∩ |tau| = |sigma ∩ tau|`. General spherical +integration with the ordinary mutable triangulation surface and hyperbolic topology need +model-specific chart validators before they can offer the same Level 4 guarantee. The crate +validates finite coordinate realizations; it does not construct a realization for an arbitrary +abstract PL-manifold. ### Geometric predicates and the Delaunay condition -Level 5 is the geometric-predicate layer. Its implemented predicate family is Delaunay: -Euclidean and toroidal triangulations use empty-circumsphere predicates, while the bounded -spherical prototype uses the equivalent empty-cap / ambient convex-hull-facet predicate. +Level 5 is the geometric-predicate layer: geometric optimality or predicate satisfaction on top of +a valid realization. Its implemented predicate family is Delaunay: Euclidean and toroidal +triangulations use empty-circumsphere predicates, while the bounded spherical prototype uses the +equivalent empty-cap / ambient convex-hull-facet predicate. A Euclidean Delaunay triangulation is characterized by the **empty circumsphere** condition:[^deberg2008][^edelsbrunner2001] @@ -201,7 +218,7 @@ condition:[^deberg2008][^edelsbrunner2001] - for each `D`-simplex (simplex), no non-simplex vertex lies *strictly inside* that simplex’s circumsphere. -This is a **geometric** invariant: it depends on the embedding coordinates and on robust evaluation +This is a **geometric** invariant: it depends on the realization coordinates and on robust evaluation of orientation / in-sphere predicates.[^shewchuk1997] The key assumption behind local repair is that *regular triangulations* (including Delaunay triangulations) @@ -297,7 +314,7 @@ and intuition. A **vertex link** is the simplicial complex formed by taking all simplices incident to a given vertex and removing that vertex from each simplex. Intuitively, the vertex link represents the local neighborhood around the vertex, abstracted -away from the embedding space. +away from the realization space. For a PL-manifold, the link of every interior vertex must be homeomorphic to a (dβˆ’1)-sphere, where d is the dimension of the triangulation. Boundary vertices @@ -488,8 +505,9 @@ The crate therefore treats flip/repair as a best-effort procedure with explicit - Prefer to validate Level 3 intrinsic PL topology (`Triangulation::validate` / `TopologyGuarantee`) when running flip-heavy workflows. -- Validate the relevant Level 5 geometric predicate explicitly when inputs are near-degenerate - (`DelaunayTriangulation::is_valid_delaunay` for the Delaunay predicate family). +- Validate Level 4 realization and the relevant Level 5 geometric predicate explicitly when inputs + are near-degenerate (`Triangulation::validate_realization` and + `DelaunayTriangulation::is_valid_delaunay` for the Delaunay predicate family). See the public API docs () and [`docs/workflows.md`](workflows.md) for practical guidance. diff --git a/docs/limitations.md b/docs/limitations.md index 758f68ad..1f3bcb71 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -82,8 +82,8 @@ projecting finite nonzero coordinates onto the unit sphere. The bounded `SphericalDelaunayBuilder` prototype additionally supports `S^2` and `S^3` construction from points in `R^3`/`R^4` by ambient convex-hull duality. Its validation surface keeps Level 3 Intrinsic PL Topology separate from spherical -Level 4 Embedding Validity and spherical Level 5 empty-cap / hull-facet predicates. Full -2D-5D spherical integration, richer spherical embedding diagnostics, and +Level 4 realization validation and spherical Level 5 empty-cap / hull-facet predicates. Full +2D-5D spherical integration, richer spherical realization diagnostics, and integration with the ordinary mutable triangulation/editing surface remain tracked by issue #414. Hyperbolic topologies remain public metadata and behavior-model scaffolds. diff --git a/docs/topology.md b/docs/topology.md index 619a2d36..fdc4d2c0 100644 --- a/docs/topology.md +++ b/docs/topology.md @@ -56,10 +56,10 @@ Notes: ## Level 3 Intrinsic PL Topology validation (`Triangulation::is_valid_topology()`) -`Triangulation::is_valid_topology()` validates embedding-independent PL-topology +`Triangulation::is_valid_topology()` validates realization-independent PL-topology invariants (Level 3). It intentionally does **not** validate lower layers (elements or combinatorial TDS consistency), nor does it certify Level 4 -embedding validity or Level 5 geometric predicates. +realization validity or Level 5 geometric predicates. For cumulative validation, use `Triangulation::validate()` (Levels 1–3) or `DelaunayTriangulation::validate()` (Levels 1–5). diff --git a/docs/validation.md b/docs/validation.md index 5630570a..237c7222 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -25,10 +25,10 @@ correctness question while building on the previous level: 1. **Element Validity** - Are individual geometric and combinatorial objects internally valid? 2. **Combinatorial Consistency** - Does the simplicial complex satisfy the required incidence invariants? 3. **Intrinsic PL Topology** - Does the abstract complex represent the intended PL topology? -4. **Embedding Validity** - Is the complex faithfully realized in the chosen ambient space? -5. **Geometric Predicates** - Does the embedding satisfy the selected geometry-specific predicate family? +4. **Valid Realization** - Is the complex realized by nondegenerate simplices whose intersections are shared faces? +5. **Geometric Predicates** - Does a valid realization satisfy the selected geometry-specific predicate family? -| Level | Concern | Depends on embedding? | +| Level | Concern | Depends on realization? | |---|---|---| | 1 | Local object correctness | No | | 2 | Combinatorial structure | No | @@ -49,7 +49,7 @@ Level 2: Combinatorial Consistency ↓ (called by) Level 3: Intrinsic PL Topology ↓ (independent) -Level 4: Embedding Validity +Level 4: Valid Realization ↓ (independent) Level 5: Geometric Predicates ``` @@ -72,7 +72,7 @@ support it without hiding useful failures: layers up through the owning abstraction. Report names identify the layer being checked: `structure_report`, -`topology_report`, `embedding_report`, and `delaunay_report`. +`topology_report`, `realization_report`, and `delaunay_report`. Higher-level reports roll up lower-level diagnostics as structured enum values, not strings. This keeps `DelaunayTriangulation::validation_report()` useful both @@ -85,17 +85,17 @@ as a full audit and as input to future repair workflows. The library always provides **explicit** validation APIs (Levels 1–5) that you can call when you need them. Separately, incremental construction (`new()` / `insert*()`) can run an **automatic** -global Level 3 intrinsic-topology pass plus changed-scope Level 4 embedding guards after an insertion attempt, +global Level 3 intrinsic-topology pass plus changed-scope Level 4 realization guards after an insertion attempt, controlled by a `ValidationPolicy` on the triangulation. This is a performance vs certainty knob: Level 3 (`Triangulation::is_valid_topology()`) and full -pairwise Level 4 (`Triangulation::is_valid_embedding()`) are relatively expensive. The default depends +pairwise Level 4 (`Triangulation::is_valid_realization()`) are relatively expensive. The default depends on the topology guarantee chosen for the incremental construction path: - `TopologyGuarantee::PLManifold` starts with `ValidationPolicy::ExplicitOnly`, so normal insertions preserve local invariants and callers request global Level 3 / Level 4 checks explicitly. - `TopologyGuarantee::Pseudomanifold` starts with `ValidationPolicy::OnSuspicion`, so automatic - global topology and changed-scope embedding checks run only when an insertion reports a suspicious + global topology and changed-scope realization checks run only when an insertion reports a suspicious local condition. ### What is validated automatically? @@ -115,11 +115,11 @@ When the policy triggers automatic validation, it runs **Level 3** Note: neighbor-pointer consistency is a **Level 2 Combinatorial Consistency** invariant checked by `Tds::is_valid()` / `Tds::validate()`, and is intentionally not part of Level 3. -The same automatic validation pass then runs **Level 4 Embedding Validity** guards for the changed simplex +The same automatic validation pass then runs **Level 4 realization** guards for the changed simplex scope. It always checks changed simplices for degeneracy and checks changed-vs-current pairwise intersections. It does **not** rescan old-vs-old simplex pairs. It also does **not** run Level 5 -Delaunay empty-circumsphere validation. If you need complete Embedding Validity or a Level 5 -geometric-predicate check, call `dt.as_triangulation().validate_embedding()`, `dt.is_valid_delaunay()`, +Delaunay empty-circumsphere validation. If you need complete Level 4 realization validation or a Level 5 +geometric-predicate check, call `dt.as_triangulation().validate_realization()`, `dt.is_valid_delaunay()`, `dt.delaunay_report()`, or `dt.validate()` explicitly. ### Default: derived from `TopologyGuarantee` @@ -263,10 +263,15 @@ The library separates **construction-time** failures from **validation-time** in - `TriangulationValidationError` (Level 3): wraps `TdsError` and adds codimension-1 manifoldness + codimension-2 boundary manifoldness (closed boundary) + (optional) vertex-link PL-manifold checks + connectedness + isolated-vertex + Euler characteristic checks. -- `TriangulationEmbeddingValidationError` (Level 4): wraps `TriangulationValidationError` and adds - nondegenerate-simplex and overlap checks in the active affine chart. -- `DelaunayTriangulationValidationError` (Level 5): wraps `TriangulationEmbeddingValidationError` - and adds the implemented geometric predicate checks, currently Delaunay. +- `TriangulationRealizationValidationError` (Level 4): wraps + `TriangulationValidationError` and adds Euclidean/toroidal affine-chart + nondegeneracy and overlap checks. +- `SphericalDelaunayValidationError` (spherical prototype Levels 3-5): reports + intrinsic PL-topology failures, spherical realization failures, and spherical + Delaunay predicate failures for the bounded `S^2`/`S^3` backend. +- `DelaunayTriangulationValidationError` (Level 5): wraps + `TriangulationRealizationValidationError` and adds the implemented geometric + predicate checks, currently Delaunay. ### Reporting (full diagnostics) @@ -274,7 +279,7 @@ The library separates **construction-time** failures from **validation-time** in On failure, the `Err(TriangulationValidationReport)` contains a `Vec`; each `InvariantViolation` stores an `InvariantKind` plus an `InvariantError` **enum** that wraps the structured error from the failing layer (`TdsError`, `TriangulationValidationError`, -`TriangulationEmbeddingValidationError`, or `DelaunayTriangulationValidationError`). +`TriangulationRealizationValidationError`, or `DelaunayTriangulationValidationError`). --- @@ -425,7 +430,9 @@ For most users, start with `dt.is_valid_structure()` (fast-fail) or `dt.validati ### Purpose -Validates that the triangulation forms a valid topological manifold. +Validates that the triangulation satisfies the requested intrinsic PL-topology +contract, ranging from relaxed pseudomanifold checks to strict PL-manifold +certification. ### Methods @@ -515,33 +522,54 @@ fn main() -> DelaunayResult<()> { --- -## Level 4: Embedding Validity +## Level 4: Valid Realization ### Purpose -Validates that the abstract triangulation has a faithful geometric realization -in the active embedding model. +Validates that the coordinate realization of the abstract triangulation is geometrically valid in +the active model. + +The terminology separates the generic Level 4 contract from its model-specific implementations: + +```text +Level 4: Valid Realization + Euclidean/toroidal: valid affine-chart realization + Spherical: valid spherical realization +Level 5: Geometric Predicate Satisfaction / Delaunay Optimality +``` + +For Euclidean and toroidal affine-chart models, the Level 4 contract is: the vertex map is +injective, every abstract simplex is realized as a nondegenerate simplex in the active chart, and any +two realized simplices intersect exactly in the realization of their shared abstract face: + +```text +|sigma| ∩ |tau| = |sigma ∩ tau| +``` + +This is a validation contract over the finite coordinate realization the crate constructs or accepts. +It is not a general realization algorithm for an arbitrary abstract PL-manifold into +coordinates. ### Methods -- `Triangulation::is_valid_embedding()` - Level 4 embedding fast-fail validation only. -- `Triangulation::embedding_diagnostic()` - First actionable Level 4 diagnostic. -- `Triangulation::embedding_report()` - Level 4 diagnostic report with offending +- `Triangulation::is_valid_realization()` - Level 4 realization fast-fail validation only. +- `Triangulation::realization_diagnostic()` - First actionable Level 4 diagnostic. +- `Triangulation::realization_report()` - Level 4 diagnostic report with offending simplex and vertex keys/UUIDs. -- `Triangulation::validate_embedding()` - Levels 1–4 (elements + combinatorics + intrinsic topology + embedding). +- `Triangulation::validate_realization()` - Levels 1–4 (elements + combinatorics + intrinsic topology + realization). ### What It Checks - **Nondegenerate maximal simplices**: every maximal simplex has nonzero `D`-volume by the robust orientation predicate. -- **No overlap outside shared faces**: any two maximal simplices may intersect only in the face - spanned by their shared vertices. +- **No overlap outside shared faces**: any two maximal simplices may intersect only in the + realization of the face spanned by their shared vertices. - **Toroidal periodic images**: toroidal topology is checked in covering-space charts, including periodic translates that can overlap across the fundamental-domain boundary. - **Spherical prototype simplices**: `SphericalDelaunayTriangulation` validates `S^2`/`S^3` - maximal simplices as nondegenerate spherical simplices embedded in `S^D \subset R^(D+1)`. -- **Independent of geometric predicates**: Level 4 does not evaluate empty-circumsphere, - empty-cap, regular, weighted, or constrained predicates. It catches invalid embeddings before + maximal simplices as nondegenerate spherical simplices realized in `S^D \subset R^(D+1)`. +- **Geometric validity, not optimality**: Level 4 does not evaluate empty-circumsphere, + empty-cap, regular, weighted, or constrained predicates. It catches invalid realizations before Level 5 asks whether the realized triangulation satisfies the selected predicate family. General spherical integration with the ordinary mutable triangulation surface, dimensions beyond @@ -555,19 +583,34 @@ until model-specific chart validators are implemented. - **Space**: O(DΒ²) to O(simplices) temporary space depending on the number of candidate overlaps. For the broad-phase overlap-detection references, see the -[Embedded-Geometry Overlap Detection](../REFERENCES.md#embedded-geometry-overlap-detection-level-4-validation) +[Realized-Simplex Overlap Detection](../REFERENCES.md#realized-simplex-overlap-detection-level-4-validation) section of `REFERENCES.md`. ### When to Use -- **Tests**: After construction or manual edits when embedded correctness matters. +- **Tests**: After construction or manual edits when realized correctness matters. - **Debug**: Investigating folded, self-overlapping, or zero-volume triangulations. - **Before geometric-predicate certification**: Level 5 validation runs Level 4 first so Delaunay - or future predicates are evaluated only on a valid embedding. -- **Repair planning**: `Triangulation::embedding_report()` reports simplex keys, UUIDs, shared + or future predicates are evaluated only on a valid realization. +- **Repair planning**: `Triangulation::realization_report()` reports simplex keys, UUIDs, shared vertices, and witness vertices that can guide explicit rollback or deletion-based repair. The validator itself is pure and does not delete vertices. +### Pachner and Orientation Failure Modes + +Pachner and raw bistellar transactions keep two orientation contracts distinct. Level 2 coherent +orientation is combinatorial: adjacent simplices must induce opposite orientations on their shared +facets. Level 4 geometric orientation is coordinate-based: affected maximal simplices must have +positive signed volume after any allowed vertex-slot reordering, and the realized simplices must not +fold or overlap outside shared faces. + +A local move can satisfy one contract while violating the other. The ordinary `PachnerProposal::attempt_on` +path canonicalizes replacement simplex orientation, preserves realized-geometry validity, and rolls +back with typed `FlipError` or validation errors if the repaired state still violates the contract. +The hidden `attempt_topology_on` path is narrower: it is reserved for diagnostics and benchmarks that +intentionally validate topology-scope invariants without paying the Level 4 overlap scan after every +move. + ### Example ```rust @@ -584,10 +627,10 @@ fn main() -> DelaunayResult<()> { ]; let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; - // Embedding validity validation (Levels 1-4) - match dt.as_triangulation().validate_embedding() { - Ok(()) => println!("valid embedded triangulation"), - Err(e) => eprintln!("embedding violation: {}", e), + // Realization validation (Levels 1-4) + match dt.as_triangulation().validate_realization() { + Ok(()) => println!("valid realized triangulation"), + Err(e) => eprintln!("realization violation: {}", e), } Ok(()) } @@ -599,19 +642,19 @@ fn main() -> DelaunayResult<()> { ### Purpose -Validates geometry-specific predicates on a valid embedding. The implemented -predicate family today is Delaunay; the layer is intentionally broad enough for -future regular, weighted, Gabriel, alpha, constrained, or related predicates. +Validates geometry-specific predicates on a valid realization. This is the geometric optimality +layer: the implemented predicate family today is Delaunay, and the layer is intentionally broad +enough for future regular, weighted, Gabriel, alpha, constrained, or related predicates. ### Methods -- `DelaunayTriangulation::is_valid_delaunay()` - implemented Level 5 Delaunay predicate only after Level 4 Embedding Validity +- `DelaunayTriangulation::is_valid_delaunay()` - implemented Level 5 Delaunay predicate only after Level 4 realization validation. - `DelaunayTriangulation::delaunay_diagnostic()` - First actionable Level 5 diagnostic, including the violating simplex, its vertices, neighbor slots, and an offending vertex when available. - `DelaunayTriangulation::delaunay_report()` - All checkable Level 5 Delaunay failures with the same repair-oriented detail where it can be reconstructed. - `DelaunayTriangulation::validate()` - Levels 1–5 (elements + combinatorics + intrinsic topology + - embedding + geometric predicates). + realization + geometric predicates). ### What It Checks @@ -626,7 +669,7 @@ future regular, weighted, Gabriel, alpha, constrained, or related predicates. or on the facet hyperplane. Euclidean and toroidal triangulations keep using their existing empty-circumsphere validators. - **Layered after Levels 1-4**: `validate()` checks elements, combinatorics, intrinsic topology, - and embedding before the geometric-predicate layer. + and realization before the geometric-predicate layer. - **Flip-based repair**: Insertions run k=2/k=3 flip repairs with inverse edge/triangle queues in higher dimensions by default. Delaunay validation can still fail if repair is disabled, if repair fails to converge, or if inputs are highly degenerate/duplicate-heavy. See @@ -688,18 +731,18 @@ Start: Do you need to validate? β”‚ β”œβ”€ Just built triangulation? β”‚ β”œβ”€ Production hot path? β†’ Usually skip (but validate during integration testing / when debugging) - β”‚ └─ Need certainty? β†’ Validate (Level 2 or 3; add Level 4 if embedding matters, Level 5 if predicates matter) + β”‚ └─ Need certainty? β†’ Validate (Level 2 or 3; add Level 4 if realization matters, Level 5 if predicates matter) β”‚ β”œβ”€ After manual topology mutation? β†’ Level 2 (`dt.is_valid_structure()`) β”‚ - β”œβ”€ Debugging embedded-geometry issues? β†’ Level 4 (`dt.as_triangulation().validate_embedding()`) + β”œβ”€ Debugging realized-geometry issues? β†’ Level 4 (`dt.as_triangulation().validate_realization()`) β”‚ β”œβ”€ Debugging Delaunay or other geometric-predicate issues? β†’ Level 5 (`dt.is_valid_delaunay()`) β”‚ β”œβ”€ Production validation? β”‚ β”œβ”€ Performance critical? β†’ Level 2 (`dt.is_valid_structure()`) β”‚ β”œβ”€ Topological correctness critical? β†’ Level 3 (`dt.as_triangulation().is_valid_topology()`) - β”‚ β”œβ”€ Realization correctness critical? β†’ Level 4 (`dt.as_triangulation().validate_embedding()`) + β”‚ β”œβ”€ Realization correctness critical? β†’ Level 4 (`dt.as_triangulation().validate_realization()`) β”‚ └─ Delaunay or geometric-predicate correctness critical? β†’ Level 5 (`dt.is_valid_delaunay()`) β”‚ └─ Paranoid mode? β†’ All levels (`dt.validate()`) @@ -711,10 +754,10 @@ Start: Do you need to validate? - Level 2 Combinatorial Consistency and Level 3 Intrinsic PL Topology validation are dominated by combinatorial bookkeeping (roughly O(simplices Γ— DΒ²)). -- Level 4 Embedding Validity checks simplex degeneracy and pairwise realized-simplex +- Level 4 Valid Realization checks simplex degeneracy and pairwise realized-simplex intersections, using bounding boxes before exact rational witness construction. - Level 5 `DelaunayTriangulation::is_valid_delaunay()` verifies the implemented Delaunay predicate - family via local flip predicates after Level 4 Embedding Validity. + family via local flip predicates after Level 4 realization validation. - A brute-force empty-circumsphere check would be O(simplices Γ— vertices) and is not used by `is_valid_delaunay()`. In practice, `DelaunayTriangulation::validate()` is usually dominated by Level 3 Intrinsic PL Topology work or @@ -735,7 +778,7 @@ helper. used for validation failures across Levels 1–4. Its variants preserve the failing layer's typed error: `TdsError` for Levels 1–2, `TriangulationValidationError` for Level 3 Intrinsic PL Topology failures, and -`TriangulationEmbeddingValidationError` for Level 4 embedding failures. In normal +`TriangulationRealizationValidationError` for Level 4 realization failures. In normal Level 3 code, handle the wrapper as shown in Patterns 2 and 3 rather than expecting `TriangulationValidationError` directly. @@ -752,7 +795,7 @@ fn test_my_triangulation_operation() { // Validate at appropriate level assert!(dt.is_valid_structure().is_ok()); // Level 2: Combinatorial Consistency assert!(dt.as_triangulation().is_valid_topology().is_ok()); // Level 3: Intrinsic PL Topology - assert!(dt.as_triangulation().validate_embedding().is_ok()); // Level 4: Embedding Validity + assert!(dt.as_triangulation().validate_realization().is_ok()); // Level 4: Valid Realization assert!(dt.is_valid_delaunay().is_ok()); // Level 5: Geometric Predicates (Delaunay) assert!(dt.validate().is_ok()); // Levels 1–5: Full validation } @@ -793,7 +836,7 @@ pub fn my_algorithm( use delaunay::prelude::query::*; use delaunay::prelude::tds::{InvariantError, TdsError}; use delaunay::prelude::validation::{ - DelaunayTriangulationValidationError, TriangulationEmbeddingValidationError, + DelaunayTriangulationValidationError, TriangulationRealizationValidationError, }; #[derive(Debug, thiserror::Error)] @@ -803,7 +846,7 @@ pub enum ValidationLevelError { #[error(transparent)] Topology(#[from] InvariantError), #[error(transparent)] - Embedding(#[from] TriangulationEmbeddingValidationError), + Realization(#[from] TriangulationRealizationValidationError), #[error(transparent)] Delaunay(#[from] DelaunayTriangulationValidationError), #[error("unsupported validation level {level}; expected 2, 3, 4, or 5")] @@ -822,7 +865,7 @@ pub fn validate_with_level( .map_err(ValidationLevelError::from), 4 => dt .as_triangulation() - .validate_embedding() + .validate_realization() .map_err(ValidationLevelError::from), 5 => dt.is_valid_delaunay().map_err(ValidationLevelError::from), _ => Err(ValidationLevelError::UnsupportedLevel { level }), @@ -851,10 +894,10 @@ ensure no isolated vertices, and verify the simplex neighbor graph is connected ### Validation Passes Level 3, Fails at Level 4 -**Problem**: Embedded simplex degeneracy or overlap outside shared faces +**Problem**: Realized simplex degeneracy or overlap outside shared faces **Likely Cause**: Folded realization, duplicate/collinear/coplanar coordinates, or a toroidal periodic image that overlaps across the fundamental-domain boundary -**Fix**: Inspect the embedding error's simplex keys, UUIDs, shared vertices, and witness vertices. +**Fix**: Inspect the realization error's simplex keys, UUIDs, shared vertices, and witness vertices. If this happened during insertion, rollback or explicit deletion-based repair can use those witnesses, but the validator itself does not mutate the triangulation. @@ -881,8 +924,8 @@ converge, consider the opt-in heuristic rebuild fallback via | 2 | `Tds::validate()` | `tds` | O(NΓ—DΒ²) | | 3 | `Triangulation::is_valid_topology()` | `triangulation` | O(NΓ—DΒ²) | | 3 | `Triangulation::validate()` | `triangulation` | O(NΓ—DΒ²) | -| 4 | `Triangulation::is_valid_embedding()` | `triangulation` | O(simplicesΒ² Γ— f(D)) | -| 4 | `Triangulation::validate_embedding()` | `triangulation` | O(simplices Γ— DΒ²) + O(simplicesΒ² Γ— f(D)) | +| 4 | `Triangulation::is_valid_realization()` | `triangulation` | O(simplicesΒ² Γ— f(D)) | +| 4 | `Triangulation::validate_realization()` | `triangulation` | O(simplices Γ— DΒ²) + O(simplicesΒ² Γ— f(D)) | | 5 | `DelaunayTriangulation::is_valid_delaunay()` | `delaunay` | O(simplices) | | 5 | `DelaunayTriangulation::validate()` | `delaunay` | Levels 1-4 + O(simplices) | | β€” | `DelaunayTriangulation::validation_report()` | `delaunay` | Levels 1-4 + O(simplices) | diff --git a/docs/workflows.md b/docs/workflows.md index dd9771cf..cb19ce9f 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -31,7 +31,7 @@ fn main() -> DelaunayResult<()> { let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; // Optional verification (see docs/validation.md for when to use each): - assert!(dt.as_triangulation().validate_embedding().is_ok()); // Levels 1-4 (Embedding Validity) + assert!(dt.as_triangulation().validate_realization().is_ok()); // Levels 1-4 (Valid Realization) assert!(dt.is_valid_delaunay().is_ok()); // Level 5 only (Geometric Predicates: Delaunay) Ok(()) } @@ -438,7 +438,7 @@ For guidance on retry/skip behavior and choosing `RobustKernel`, see Vertex deletion is supported and preserves Levels 1–3. It uses an inverse k=1 fast path when possible and fan retriangulation otherwise, then runs flip-based Delaunay repair when the active `DelaunayRepairPolicy` allows it. If automatic repair is disabled, deletion still runs Level 4 -Embedding Validity and the Level 5 Delaunay predicate, rolling back on any violation. If post-deletion repair, validation, or +Level 4 realization validation and the Level 5 Delaunay predicate, rolling back on any violation. If post-deletion repair, validation, or orientation canonicalization fails, the operation rolls back to the pre-deletion triangulation. ```rust diff --git a/notebooks/01_validation.ipynb b/notebooks/01_validation.ipynb index ef1e6cc8..b63a2223 100644 --- a/notebooks/01_validation.ipynb +++ b/notebooks/01_validation.ipynb @@ -36,7 +36,6 @@ "import os\n", "import shutil\n", "import subprocess\n", - "import textwrap\n", "import time\n", "from dataclasses import dataclass\n", "from pathlib import Path\n", @@ -134,8 +133,7 @@ "NOTEBOOK_STEM = \"01_validation\"\n", "OUTPUT_DIR = ROOT / \"target\" / \"notebooks\" / NOTEBOOK_STEM\n", "DEMO_PATH = OUTPUT_DIR / \"validation_demo.json\"\n", - "HIERARCHY_FIGURE_PATH = OUTPUT_DIR / \"validation_hierarchy.png\"\n", - "TABLE_FIGURE_PATH = OUTPUT_DIR / \"validation_model_failures.png\"\n", + "VALIDATION_FIGURE_DIR = OUTPUT_DIR / \"validation_levels\"\n", "PAPER_FIGURE_DIR = paper_figure_dir_from_env(ROOT)\n", "TIMEOUT_SECONDS = positive_int_env(\"DELAUNAY_VALIDATION_DEMO_TIMEOUT_SECONDS\", 120)\n", "\n", @@ -451,9 +449,9 @@ "id": "render-hierarchy-heading", "metadata": {}, "source": [ - "## 3. Render the validation hierarchy\n", + "## 3. Prepare validation figures\n", "\n", - "This paper figure summarizes the five validation levels and the point where embedding-dependent checks begin." + "The notebook writes both the validation hierarchy overview and one generated PNG per validation level. The paper owns captions and explanatory text." ] }, { @@ -463,74 +461,55 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"Render the five-level validation hierarchy as a paper figure.\"\"\"\n", - "\n", - "validation_layers = [\n", - " (\"1\", \"Element Validity\", \"local objects\", \"No\"),\n", - " (\"2\", \"Combinatorial Consistency\", \"incidence and TDS\", \"No\"),\n", - " (\"3\", \"Intrinsic PL Topology\", \"links and manifolds\", \"No\"),\n", - " (\"4\", \"Embedding Validity\", \"ambient realization\", \"Yes\"),\n", - " (\"5\", \"Geometric Predicates\", \"Delaunay today\", \"Yes\"),\n", - "]\n", + "\"\"\"Prepare output paths for overview and per-level validation figures.\"\"\"\n", "\n", - "hierarchy_fig, hierarchy_ax = plt.subplots(figsize=(11.0, 6.0), facecolor=\"white\", layout=\"constrained\")\n", - "hierarchy_ax.set_axis_off()\n", - "hierarchy_ax.set_xlim(0.0, 1.0)\n", - "hierarchy_ax.set_ylim(0.0, 1.0)\n", - "\n", - "box_width = 0.82\n", - "box_height = 0.115\n", - "box_left = 0.09\n", - "box_y0 = 0.78\n", - "box_gap = 0.145\n", - "colors = [\"#dbeafe\", \"#e0f2fe\", \"#dcfce7\", \"#fef3c7\", \"#fee2e2\"]\n", - "\n", - "for index, (level, name, concern, embedding) in enumerate(validation_layers):\n", - " y = box_y0 - index * box_gap\n", - " rectangle = plt.Rectangle(\n", - " (box_left, y),\n", - " box_width,\n", - " box_height,\n", - " facecolor=colors[index],\n", - " edgecolor=\"#334155\",\n", - " linewidth=1.2,\n", - " )\n", - " hierarchy_ax.add_patch(rectangle)\n", - " hierarchy_ax.text(box_left + 0.035, y + 0.073, f\"Level {level}\", fontsize=11, weight=\"bold\", color=\"#0f172a\")\n", - " hierarchy_ax.text(box_left + 0.18, y + 0.073, name, fontsize=12, weight=\"bold\", color=\"#0f172a\")\n", - " hierarchy_ax.text(box_left + 0.18, y + 0.032, concern, fontsize=10, color=\"#475569\")\n", - " hierarchy_ax.text(\n", - " box_left + 0.72,\n", - " y + 0.052,\n", - " f\"embedding: {embedding}\",\n", - " fontsize=10,\n", - " ha=\"right\",\n", - " color=\"#475569\",\n", - " )\n", - " if index < len(validation_layers) - 1:\n", - " arrow_x = box_left + box_width / 2.0\n", - " hierarchy_ax.annotate(\n", - " \"\",\n", - " xy=(arrow_x, y - 0.025),\n", - " xytext=(arrow_x, y - 0.002),\n", - " arrowprops={\"arrowstyle\": \"->\", \"linewidth\": 1.1, \"color\": \"#64748b\"},\n", - " )\n", "\n", - "hierarchy_ax.text(0.09, 0.95, \"delaunay validation architecture\", fontsize=16, weight=\"bold\", color=\"#0f172a\")\n", - "hierarchy_ax.text(\n", - " 0.09,\n", - " 0.91,\n", - " \"Levels 1-3 are intrinsic; Levels 4-5 depend on the chosen embedding and predicate family.\",\n", - " fontsize=11,\n", - " color=\"#475569\",\n", + "HIERARCHY_FIGURE_PATH = OUTPUT_DIR / \"validation_hierarchy.png\"\n", + "\n", + "VALIDATION_FIGURE_SLUGS = {\n", + " 1: \"element_validity\",\n", + " 2: \"combinatorial_consistency\",\n", + " 3: \"intrinsic_pl_topology\",\n", + " 4: \"valid_realization\",\n", + " 5: \"geometric_predicates\",\n", + "}\n", + "OBSOLETE_VALIDATION_FIGURE_NAMES = (\n", + " \"validation_model_failures.png\",\n", + " \"validation_level_4_valid_affine_realization.png\",\n", ")\n", "\n", - "save_figure_png(hierarchy_fig, HIERARCHY_FIGURE_PATH, dpi=180)\n", - "plt.show()\n", "\n", - "print(f\"validation hierarchy figure: {HIERARCHY_FIGURE_PATH}\")\n", - "if PAPER_FIGURE_DIR is not None:\n", - " print(f\"paper hierarchy figure: {paper_figure_path(HIERARCHY_FIGURE_PATH.name)}\")" + "def validation_level_figure_path(case: ValidationCase) -> Path:\n", + " \"\"\"Return the generated PNG path for one validation level.\"\"\"\n", + " try:\n", + " slug = VALIDATION_FIGURE_SLUGS[case.level]\n", + " except KeyError as error:\n", + " raise ValueError(f\"unsupported validation level for paper figure: {case.level}\") from error\n", + " return VALIDATION_FIGURE_DIR / f\"validation_level_{case.level}_{slug}.png\"\n", + "\n", + "\n", + "def clear_stale_validation_figures() -> None:\n", + " \"\"\"Remove obsolete notebook-owned validation images before rendering fresh ones.\"\"\"\n", + " figure_dirs = [OUTPUT_DIR, VALIDATION_FIGURE_DIR]\n", + " if PAPER_FIGURE_DIR is not None:\n", + " figure_dirs.append(PAPER_FIGURE_DIR)\n", + "\n", + " for figure_dir in figure_dirs:\n", + " for path in figure_dir.glob(\"validation_level_*.png\"):\n", + " path.unlink()\n", + " for filename in OBSOLETE_VALIDATION_FIGURE_NAMES:\n", + " path = figure_dir / filename\n", + " if path.exists():\n", + " path.unlink()\n", + "\n", + "\n", + "VALIDATION_FIGURE_PATHS = tuple(validation_level_figure_path(case) for case in validation_cases)\n", + "ALL_VALIDATION_FIGURE_PATHS = (HIERARCHY_FIGURE_PATH, *VALIDATION_FIGURE_PATHS)\n", + "\n", + "print(\"validation figures:\")\n", + "print(f\"- {HIERARCHY_FIGURE_PATH}\")\n", + "for figure_path in VALIDATION_FIGURE_PATHS:\n", + " print(f\"- {figure_path}\")" ] }, { @@ -538,9 +517,9 @@ "id": "render-table-heading", "metadata": {}, "source": [ - "## 4. Render the validation table\n", + "## 4. Render validation figures\n", "\n", - "Each picture is generated from the CLI artifact. The middle column points at the public API check and test anchor; the right column gives the failure interpretation and exact binary diagnostic." + "The overview diagram summarizes the layer stack; the per-level images intentionally contain only the geometric witness. Paper captions and surrounding prose explain the validation layer." ] }, { @@ -550,7 +529,7 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"Render generated validation cases as a three-column visual table.\"\"\"\n", + "\"\"\"Render generated validation cases as overview and separate visual figures.\"\"\"\n", "\n", "\n", "def visual_points(visual: ValidationVisual) -> list[tuple[str, Point2]]:\n", @@ -601,6 +580,17 @@ " duplicate_simplices: list[tuple[int, ...]]\n", "\n", "\n", + "@dataclass(frozen=True, slots=True)\n", + "class ValidationHierarchyLayer:\n", + " \"\"\"One row in the validation hierarchy overview diagram.\"\"\"\n", + "\n", + " level: int\n", + " name: str\n", + " scope: tuple[str, ...]\n", + " questions: tuple[str, ...]\n", + " color: str\n", + "\n", + "\n", "def canonical_simplex(simplex: tuple[int, ...]) -> tuple[int, ...]:\n", " \"\"\"Return the orientation-independent simplex vertex set.\"\"\"\n", " return tuple(sorted(simplex))\n", @@ -739,7 +729,7 @@ " return (center_x - half_span, center_x + half_span, center_y - half_span, center_y + half_span)\n", "\n", "\n", - "def draw_visual(ax: Any, case: ValidationCase) -> None:\n", + "def draw_visual(ax: Any, case: ValidationCase, *, show_point_labels: bool = False) -> None:\n", " \"\"\"Draw one validation case from generated visual metadata.\"\"\"\n", " visual = case.visual\n", " labeled_points = visual_points(visual)\n", @@ -779,10 +769,6 @@ " alpha=0.8,\n", " )\n", " ax.add_patch(polygon)\n", - " centroid_x = sum(point[0] for point in duplicate_points) / len(duplicate_points)\n", - " centroid_y = sum(point[1] for point in duplicate_points) / len(duplicate_points)\n", - " ax.text(centroid_x, centroid_y, \"x2\", ha=\"center\", va=\"center\", fontsize=9, weight=\"bold\", color=\"#7f1d1d\")\n", - "\n", " for edge_index, (left, right) in enumerate(highlighted_edges):\n", " left_point = point_by_index(points, left, f\"visual.highlighted_edges[{edge_index}][0]\")\n", " right_point = point_by_index(points, right, f\"visual.highlighted_edges[{edge_index}][1]\")\n", @@ -800,7 +786,8 @@ " ax.scatter([point[0]], [point[1]], marker=marker, s=size, color=color, zorder=6)\n", " if index in isolated_points:\n", " ax.scatter([point[0]], [point[1]], marker=\"o\", s=180, facecolor=\"none\", edgecolor=\"#dc2626\", linewidth=1.8, zorder=5)\n", - " ax.text(point[0] + 0.03, point[1] + 0.03, label, fontsize=9, weight=\"bold\", color=color)\n", + " if show_point_labels:\n", + " ax.text(point[0] + 0.03, point[1] + 0.03, label, fontsize=9, weight=\"bold\", color=color)\n", "\n", " limits = axes_limits(points, circle)\n", " ax.set_xlim(limits[0], limits[1])\n", @@ -813,64 +800,188 @@ " ax.set_facecolor(\"#f8fafc\")\n", "\n", "\n", - "def wrapped_text(value: str, width: int) -> str:\n", - " \"\"\"Wrap long table text for stable figure layout.\"\"\"\n", - " return textwrap.fill(value, width=width, break_long_words=True)\n", - "\n", - "\n", - "def shorten_text(value: str, limit: int) -> str:\n", - " \"\"\"Shorten a diagnostic while preserving its first concrete payload.\"\"\"\n", - " if len(value) <= limit:\n", - " return value\n", - " return f\"{value[: limit - 1].rstrip()}...\"\n", - "\n", - "\n", - "for case_index, case in enumerate(validation_cases):\n", - " validate_case_visual_invariants(case, case_index)\n", + "VALIDATION_HIERARCHY_LAYERS = (\n", + " ValidationHierarchyLayer(\n", + " level=1,\n", + " name=\"Element Validity\",\n", + " scope=(\"Vertex / Simplex\",),\n", + " questions=(\n", + " \"Are vertex coordinates finite and valid?\",\n", + " \"Are element UUIDs present and non-nil?\",\n", + " \"Do simplices have D+1 distinct vertex keys?\",\n", + " \"Are local neighbor slots shaped and assigned?\",\n", + " ),\n", + " color=\"#dbeafe\",\n", + " ),\n", + " ValidationHierarchyLayer(\n", + " level=2,\n", + " name=\"Combinatorial Consistency\",\n", + " scope=(\"Triangulation Data Structure\",),\n", + " questions=(\n", + " \"Are UUID-key maps unique and bidirectional?\",\n", + " \"Does every vertex, simplex, and neighbor reference resolve in the TDS?\",\n", + " \"Are incident-simplex hints internally consistent?\",\n", + " \"Are vertex-to-simplex incidence indexes exact?\",\n", + " \"Do simplex vertices have distinct coordinates?\",\n", + " \"Are duplicate simplices absent?\",\n", + " \"Are facets shared by at most two simplices?\",\n", + " \"Do neighbor links and coherent orientation agree?\",\n", + " ),\n", + " color=\"#e0f2fe\",\n", + " ),\n", + " ValidationHierarchyLayer(\n", + " level=3,\n", + " name=\"Intrinsic PL Topology\",\n", + " scope=(\"Triangulation\", \"Pseudomanifold / PL-Manifold\"),\n", + " questions=(\n", + " \"Is the simplex neighbor graph connected?\",\n", + " \"Is every vertex incident to a simplex?\",\n", + " \"Do facet degrees satisfy the topology guarantee?\",\n", + " \"Is the true boundary closed?\",\n", + " \"Do fast ridge-link checks pass when required?\",\n", + " \"Do complete vertex-link checks pass when required?\",\n", + " \"Does Euler characteristic match the declared topology?\",\n", + " ),\n", + " color=\"#dcfce7\",\n", + " ),\n", + " ValidationHierarchyLayer(\n", + " level=4,\n", + " name=\"Valid Realization\",\n", + " scope=(\"Euclidean affine-chart\", \"Toroidal periodic chart\", \"Spherical realization\"),\n", + " questions=(\n", + " \"Are realized simplices positive and nondegenerate?\",\n", + " \"Do simplices intersect only along shared faces?\",\n", + " \"Do toroidal lifts fit valid periodic charts?\",\n", + " \"Do spherical simplices separate the sphere center?\",\n", + " \"Does the active realization model support the check?\",\n", + " ),\n", + " color=\"#fef3c7\",\n", + " ),\n", + " ValidationHierarchyLayer(\n", + " level=5,\n", + " name=\"Geometric Predicate Satisfaction\",\n", + " scope=(\"Delaunay Optimality\",),\n", + " questions=(\n", + " \"Do selected geometric predicates accept every cell?\",\n", + " \"Do local k=2/k=3 flip predicates and inverses pass?\",\n", + " \"Do Euclidean/toroidal empty-circumsphere checks pass?\",\n", + " \"Do spherical empty-cap / ambient hull-facet checks pass?\",\n", + " \"Is Delaunay optimality certified for the active model?\",\n", + " ),\n", + " color=\"#fee2e2\",\n", + " ),\n", + ")\n", "\n", "\n", - "fig = plt.figure(figsize=(15.0, 12.0), facecolor=\"white\", layout=\"constrained\")\n", - "grid = fig.add_gridspec(len(validation_cases), 3, width_ratios=[1.15, 1.25, 2.25], wspace=0.08, hspace=0.22)\n", - "headers = [\"Generated failure picture\", \"Public check / test\", \"Explanation\"]\n", - "\n", - "for row_index, case in enumerate(validation_cases):\n", - " visual_axis = fig.add_subplot(grid[row_index, 0])\n", - " check_axis = fig.add_subplot(grid[row_index, 1])\n", - " explanation_axis = fig.add_subplot(grid[row_index, 2])\n", - "\n", - " if row_index == 0:\n", - " for axis, header in zip((visual_axis, check_axis, explanation_axis), headers, strict=True):\n", - " axis.set_title(header, fontsize=12, weight=\"bold\", pad=12)\n", - "\n", - " draw_visual(visual_axis, case)\n", - " visual_axis.text(\n", - " 0.03,\n", - " 0.97,\n", - " f\"Level {case.level}: {case.layer}\",\n", - " transform=visual_axis.transAxes,\n", - " ha=\"left\",\n", - " va=\"top\",\n", - " fontsize=10,\n", - " weight=\"bold\",\n", - " color=\"#0f172a\",\n", - " bbox={\"boxstyle\": \"round,pad=0.2\", \"facecolor\": \"#f8fafc\", \"edgecolor\": \"none\", \"alpha\": 0.85},\n", + "def render_validation_hierarchy_figure(output_path: Path) -> None:\n", + " \"\"\"Render the five-level validation hierarchy overview PNG.\"\"\"\n", + " figure, axis = plt.subplots(figsize=(13.2, 8.8), facecolor=\"white\", layout=\"constrained\")\n", + " axis.set_axis_off()\n", + " axis.set_xlim(0.0, 1.0)\n", + " axis.set_ylim(0.0, 1.0)\n", + "\n", + " box_width = 0.86\n", + " box_left = 0.07\n", + " box_top = 0.86\n", + " box_bottom = 0.055\n", + " box_gap = 0.018\n", + " box_inner_gap = 0.042\n", + " level_font_size = 11.8\n", + " name_font_size = 12.8\n", + " scope_font_size = 9.1\n", + " question_font_size = 8.7\n", + " scope_gap = 0.031\n", + " scope_step = 0.024\n", + " question_step_cap = 0.024\n", + " layer_weights = [len(layer.questions) + 2.0 for layer in VALIDATION_HIERARCHY_LAYERS]\n", + " usable_height = box_top - box_bottom - box_gap * (len(VALIDATION_HIERARCHY_LAYERS) - 1)\n", + " box_heights = [usable_height * weight / sum(layer_weights) for weight in layer_weights]\n", + "\n", + " current_top = box_top\n", + " for index, (layer, box_height) in enumerate(zip(VALIDATION_HIERARCHY_LAYERS, box_heights, strict=True)):\n", + " y = current_top - box_height\n", + " row_center = y + box_height / 2.0\n", + " rectangle = plt.Rectangle(\n", + " (box_left, y),\n", + " box_width,\n", + " box_height,\n", + " facecolor=layer.color,\n", + " edgecolor=\"#334155\",\n", + " linewidth=1.2,\n", + " )\n", + " axis.add_patch(rectangle)\n", + " scope_group_height = scope_gap + scope_step * max(len(layer.scope) - 1, 0)\n", + " label_y = row_center + scope_group_height / 2.0\n", + " axis.text(box_left + 0.035, label_y, f\"Level {layer.level}\", fontsize=level_font_size, weight=\"bold\", color=\"#0f172a\", wrap=False)\n", + " axis.text(box_left + 0.18, label_y, layer.name, fontsize=name_font_size, weight=\"bold\", color=\"#0f172a\", wrap=False)\n", + " for scope_index, scope in enumerate(layer.scope):\n", + " axis.text(\n", + " box_left + 0.18,\n", + " label_y - scope_gap - scope_step * scope_index,\n", + " scope,\n", + " fontsize=scope_font_size,\n", + " color=\"#64748b\",\n", + " wrap=False,\n", + " )\n", + " question_step = min(question_step_cap, (box_height - box_inner_gap) / max(len(layer.questions) - 1, 1))\n", + " question_top = row_center + question_step * (len(layer.questions) - 1) / 2.0\n", + " for question_index, question in enumerate(layer.questions):\n", + " axis.text(\n", + " box_left + 0.48,\n", + " question_top - question_step * question_index,\n", + " f\"- {question}\",\n", + " fontsize=question_font_size,\n", + " color=\"#475569\",\n", + " wrap=False,\n", + " )\n", + " if index < len(VALIDATION_HIERARCHY_LAYERS) - 1:\n", + " arrow_x = box_left + box_width / 2.0\n", + " axis.annotate(\n", + " \"\",\n", + " xy=(arrow_x, y - box_gap * 0.86),\n", + " xytext=(arrow_x, y - box_gap * 0.14),\n", + " arrowprops={\"arrowstyle\": \"->\", \"linewidth\": 1.1, \"color\": \"#64748b\"},\n", + " )\n", + " current_top = y - box_gap\n", + "\n", + " axis.text(0.07, 0.965, \"delaunay validation architecture\", fontsize=16.5, weight=\"bold\", color=\"#0f172a\", wrap=False)\n", + " axis.text(\n", + " 0.07,\n", + " 0.928,\n", + " \"Levels 1-3 are intrinsic; Level 4 checks valid realization; Level 5 checks geometric predicate satisfaction.\",\n", + " fontsize=11.5,\n", + " color=\"#475569\",\n", + " wrap=False,\n", " )\n", + " save_figure_png(figure, output_path, dpi=180)\n", + " plt.show()\n", + " plt.close(figure)\n", "\n", - " for axis in (check_axis, explanation_axis):\n", - " axis.set_axis_off()\n", - "\n", - " check_text = f\"{case.public_check}\\n\\n{case.public_reference}\"\n", - " check_axis.text(0.0, 0.82, wrapped_text(check_text, 34), ha=\"left\", va=\"top\", fontsize=9.5, color=\"#0f172a\")\n", "\n", - " explanation = f\"{case.title}\\n\\n{case.explanation}\\n\\nDiagnostic: {shorten_text(case.diagnostic, 360)}\"\n", - " explanation_axis.text(0.0, 0.88, wrapped_text(explanation, 72), ha=\"left\", va=\"top\", fontsize=9.5, color=\"#111827\")\n", + "def render_validation_case_figure(case: ValidationCase, output_path: Path) -> None:\n", + " \"\"\"Render one text-light validation witness PNG.\"\"\"\n", + " figure, axis = plt.subplots(figsize=(4.2, 4.2), facecolor=\"white\", layout=\"constrained\")\n", + " draw_visual(axis, case, show_point_labels=False)\n", + " save_figure_png(figure, output_path, dpi=240)\n", + " plt.show()\n", + " plt.close(figure)\n", "\n", - "save_figure_png(fig, TABLE_FIGURE_PATH, dpi=180)\n", - "plt.show()\n", "\n", - "print(f\"validation table figure: {TABLE_FIGURE_PATH}\")\n", + "clear_stale_validation_figures()\n", + "render_validation_hierarchy_figure(HIERARCHY_FIGURE_PATH)\n", + "print(f\"validation hierarchy figure: {HIERARCHY_FIGURE_PATH}\")\n", "if PAPER_FIGURE_DIR is not None:\n", - " print(f\"paper table figure: {paper_figure_path(TABLE_FIGURE_PATH.name)}\")" + " print(f\"paper hierarchy figure: {paper_figure_path(HIERARCHY_FIGURE_PATH.name)}\")\n", + "\n", + "for case_index, case in enumerate(validation_cases):\n", + " validate_case_visual_invariants(case, case_index)\n", + "\n", + "for case in validation_cases:\n", + " output_path = validation_level_figure_path(case)\n", + " render_validation_case_figure(case, output_path)\n", + " print(f\"Level {case.level} figure: {output_path}\")\n", + " if PAPER_FIGURE_DIR is not None:\n", + " print(f\"paper Level {case.level} figure: {paper_figure_path(output_path.name)}\")" ] }, { @@ -878,9 +989,7 @@ "id": "summary-heading", "metadata": {}, "source": [ - "## 5. Copyable artifact summary\n", - "\n", - "Use these paths when linking generated outputs from documentation or issue comments." + "## 5. Copyable artifact summary" ] }, { @@ -892,20 +1001,26 @@ "source": [ "\"\"\"Print the generated validation-demo artifact paths.\"\"\"\n", "\n", + "\n", "if not DEMO_PATH.is_file():\n", " raise FileNotFoundError(f\"validation demo JSON was not written: {DEMO_PATH}\")\n", - "if not HIERARCHY_FIGURE_PATH.is_file():\n", - " raise FileNotFoundError(f\"validation hierarchy figure was not written: {HIERARCHY_FIGURE_PATH}\")\n", - "if not TABLE_FIGURE_PATH.is_file():\n", - " raise FileNotFoundError(f\"validation table figure was not written: {TABLE_FIGURE_PATH}\")\n", + "\n", + "missing_figures = [figure_path for figure_path in ALL_VALIDATION_FIGURE_PATHS if not figure_path.is_file()]\n", + "if missing_figures:\n", + " raise FileNotFoundError(f\"validation figures were not written: {missing_figures}\")\n", + "\n", "if PAPER_FIGURE_DIR is not None:\n", - " for figure_path in (paper_figure_path(HIERARCHY_FIGURE_PATH.name), paper_figure_path(TABLE_FIGURE_PATH.name)):\n", - " if figure_path is None or not figure_path.is_file():\n", - " raise FileNotFoundError(f\"paper figure was not written: {figure_path}\")\n", + " tracked_figures = [paper_figure_path(figure_path.name) for figure_path in ALL_VALIDATION_FIGURE_PATHS]\n", + " missing_tracked_figures = [figure_path for figure_path in tracked_figures if figure_path is None or not figure_path.is_file()]\n", + " if missing_tracked_figures:\n", + " raise FileNotFoundError(f\"paper figures were not written: {missing_tracked_figures}\")\n", + "\n", "\n", - "print(f\"JSON artifact: {DEMO_PATH}\")\n", - "print(f\"Hierarchy: {HIERARCHY_FIGURE_PATH}\")\n", - "print(f\"Table artifact: {TABLE_FIGURE_PATH}\")" + "print(f\"JSON artifact: {DEMO_PATH}\")\n", + "print(f\"Hierarchy: {HIERARCHY_FIGURE_PATH}\")\n", + "print(\"Validation level figures:\")\n", + "for figure_path in VALIDATION_FIGURE_PATHS:\n", + " print(f\"- {figure_path}\")" ] } ], diff --git a/papers/generated/validation_hierarchy.png b/papers/generated/validation_hierarchy.png index 6c477308..7aef9c52 100644 Binary files a/papers/generated/validation_hierarchy.png and b/papers/generated/validation_hierarchy.png differ diff --git a/papers/generated/validation_level_1_element_validity.png b/papers/generated/validation_level_1_element_validity.png new file mode 100644 index 00000000..8d447f18 Binary files /dev/null and b/papers/generated/validation_level_1_element_validity.png differ diff --git a/papers/generated/validation_level_2_combinatorial_consistency.png b/papers/generated/validation_level_2_combinatorial_consistency.png new file mode 100644 index 00000000..6e5ffe7a Binary files /dev/null and b/papers/generated/validation_level_2_combinatorial_consistency.png differ diff --git a/papers/generated/validation_level_3_intrinsic_pl_topology.png b/papers/generated/validation_level_3_intrinsic_pl_topology.png new file mode 100644 index 00000000..ec1326cc Binary files /dev/null and b/papers/generated/validation_level_3_intrinsic_pl_topology.png differ diff --git a/papers/generated/validation_level_4_valid_realization.png b/papers/generated/validation_level_4_valid_realization.png new file mode 100644 index 00000000..dd8df7fe Binary files /dev/null and b/papers/generated/validation_level_4_valid_realization.png differ diff --git a/papers/generated/validation_level_5_geometric_predicates.png b/papers/generated/validation_level_5_geometric_predicates.png new file mode 100644 index 00000000..955347db Binary files /dev/null and b/papers/generated/validation_level_5_geometric_predicates.png differ diff --git a/papers/generated/validation_model_failures.png b/papers/generated/validation_model_failures.png deleted file mode 100644 index b41e4e73..00000000 Binary files a/papers/generated/validation_model_failures.png and /dev/null differ diff --git a/papers/validation.pdf b/papers/validation.pdf index bc995fdf..b0fe95af 100644 Binary files a/papers/validation.pdf and b/papers/validation.pdf differ diff --git a/papers/validation.tex b/papers/validation.tex index 12c95794..82679639 100644 --- a/papers/validation.tex +++ b/papers/validation.tex @@ -3,6 +3,7 @@ \setcopyright{none} \settopmatter{printacmref=false} +\raggedbottom{} \acmJournal{TOMS} \title{Validation Architecture in delaunay} @@ -25,6 +26,14 @@ % TeX structure, build tooling, citation plumbing, figures, and TODO prompts, % but Adam writes the substantive paper prose. \newcommand{\AuthorTodo}[1]{\textbf{Author TODO.} #1} +\newcommand{\ValidationWitnessPanel}[3]{% + \begin{minipage}[t]{0.30\textwidth} + \centering + \includegraphics[width=\linewidth]{#1} + \par\smallskip + {\footnotesize\textbf{#2}\\#3} + \end{minipage}% +} \begin{abstract} \AuthorTodo{Write the abstract in your own words.} @@ -49,9 +58,9 @@ \section{Background and Definitions} \begin{itemize} \item \AuthorTodo{Define the triangulation, simplex, ridge, facet, and - embedding terms used throughout the paper.} + realization terms used throughout the paper.} \item \AuthorTodo{Introduce PL-manifold terminology and the link condition.} - \item \AuthorTodo{Introduce Euclidean, toroidal, and spherical embedding + \item \AuthorTodo{Introduce Euclidean, toroidal, and spherical realization models.} \item \AuthorTodo{Introduce Delaunay and future geometric-predicate terminology.} @@ -62,10 +71,12 @@ \section{Validation Hierarchy} \begin{figure}[htbp] \centering \includegraphics[width=0.95\linewidth]{generated/validation_hierarchy.png} - \caption{\AuthorTodo{Describe the validation hierarchy - figure.}}\label{fig:validation-hierarchy} - \Description{Author TODO accessible description of the validation - hierarchy figure.} + \caption{Overview of the validation hierarchy in + delaunay}\label{fig:validation-hierarchy} + \Description{The 5-level validation hierarchy in delaunay. Level 1: + Element Validity; Level 2: Combinatorial Consistency; Level 3: Intrinsic + PL Topology; Level 4: Valid Realization; Level 5: Geometric Predicate + Satisfaction.} \end{figure} \subsection{Level 1: Element Validity} @@ -91,17 +102,21 @@ \subsection{Level 3: Intrinsic PL Topology} \item \AuthorTodo{Discuss pseudomanifold and strict PL-manifold policy choices.} \item \AuthorTodo{Explain why this layer is independent of Euclidean, - toroidal, and spherical embeddings.} + toroidal, and spherical realizations.} \end{itemize} -\subsection{Level 4: Embedding Validity} +\subsection{Level 4: Valid Realization} \begin{itemize} - \item \AuthorTodo{Describe faithful realization in the active ambient + \item \AuthorTodo{Use the terminology stack: Level 4 Valid Realization; + Euclidean/toroidal valid affine-chart realization; spherical valid + spherical realization; Level 5 Geometric Predicate Satisfaction / Delaunay + Optimality.} + \item \AuthorTodo{Describe valid realization in the active ambient model.} - \item \AuthorTodo{Compare Euclidean affine charts, toroidal periodic charts, - and spherical embeddings.} - \item \AuthorTodo{Explain why embedding validity is a precondition for + \item \AuthorTodo{Compare Euclidean/toroidal affine-chart realizations and + spherical realizations.} + \item \AuthorTodo{Explain why realization validity is a precondition for geometric predicates.} \end{itemize} @@ -132,11 +147,36 @@ \section{Diagnostics and Reproducible Figures} \begin{figure}[htbp] \centering - \includegraphics[width=\linewidth]{generated/validation_model_failures.png} - \caption{\AuthorTodo{Describe the generated validation-failure - examples.}}\label{fig:validation-failures} - \Description{Author TODO accessible description of the validation-failure - figure.} + \ValidationWitnessPanel% + {generated/validation_level_1_element_validity.png} + {Level 1} + {Element Validity} + \hfill + \ValidationWitnessPanel% + {generated/validation_level_2_combinatorial_consistency.png} + {Level 2} + {Combinatorial Consistency} + \hfill + \ValidationWitnessPanel% + {generated/validation_level_3_intrinsic_pl_topology.png} + {Level 3} + {Intrinsic PL Topology} + + \medskip + + \ValidationWitnessPanel% + {generated/validation_level_4_valid_realization.png} + {Level 4} + {Valid Realization} + \hfill + \ValidationWitnessPanel% + {generated/validation_level_5_geometric_predicates.png} + {Level 5} + {Geometric Predicate Satisfaction} + \caption{\AuthorTodo{Describe the validation witness + figures.}}\label{fig:validation-witnesses} + \Description{Author TODO accessible description of the validation witness + figures.} \end{figure} \begin{itemize} @@ -162,7 +202,7 @@ \section{Related Work} \section{Discussion and Future Work} \begin{itemize} - \item \AuthorTodo{Discuss extensibility to additional embedding models and + \item \AuthorTodo{Discuss extensibility to additional realization models and predicate families.} \item \AuthorTodo{Discuss limitations of the current implementation.} \item \AuthorTodo{Identify open validation and benchmarking questions.} diff --git a/scripts/benchmark_utils.py b/scripts/benchmark_utils.py index 702d5fb3..14ec8f54 100755 --- a/scripts/benchmark_utils.py +++ b/scripts/benchmark_utils.py @@ -5989,8 +5989,7 @@ def _write_optional_report(output_path: Path | None, report_text: str) -> None: if output_path is None: return - output_path.parent.mkdir(parents=True, exist_ok=True) - output_path.write_text(report_text, encoding="utf-8") + _write_text_atomic(output_path, report_text) def _baseline_fetch_options_from_args(args: argparse.Namespace) -> BaselineFetchOptions: diff --git a/semgrep.yaml b/semgrep.yaml index eb029107..88920f4c 100644 --- a/semgrep.yaml +++ b/semgrep.yaml @@ -173,7 +173,7 @@ rules: - "/src/core/simplex.rs" - "/src/core/tds/validation.rs" - "/src/core/validation.rs" - - "/src/core/embedding.rs" + - "/src/core/realization.rs" - "/src/delaunay/validation.rs" - "/tests/semgrep/src/project_rules/**/*.rs" pattern-regex: >- @@ -480,7 +480,7 @@ rules: paths: include: - "/src/core/validation.rs" - - "/src/core/embedding.rs" + - "/src/core/realization.rs" - "/src/delaunay/validation.rs" - "/tests/semgrep/src/project_rules/**/*.rs" pattern-regex: >- diff --git a/src/config.rs b/src/config.rs index 6051a488..b6912ba0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -644,12 +644,12 @@ fn validation_demo_level_3() -> Result { }) } -/// Generate the Level 4 invalid affine realization failure example. +/// Generate the Level 4 invalid Euclidean realization failure example. fn validation_demo_level_4() -> Result { let coordinates = [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]; let simplices = vec![vec![0, 1, 2]]; let diagnostic = explicit_builder_failure( - "Level 4 invalid affine realization", + "Level 4 invalid Euclidean realization", coordinates, &simplices, )?; @@ -659,13 +659,13 @@ fn validation_demo_level_4() -> Result { Ok(ValidationDemoCase { level: 4, - layer: "Valid affine realization", + layer: "Valid realization", title: "Degenerate realized simplex", status: "failed_as_expected", - public_check: "Triangulation::validate_embedding", + public_check: "Triangulation::validate_realization", public_reference: "tests/triangulation_builder.rs::test_explicit_error_variant_geometric_nondegeneracy", input_summary: "One triangle whose three vertices are collinear", - explanation: "The coordinate realization is not a valid affine realization because the abstract 2-simplex collapses to zero area.", + explanation: "The Euclidean coordinate realization is invalid because the abstract 2-simplex collapses to zero area.", diagnostic, visual, }) @@ -2580,7 +2580,7 @@ mod tests { .iter() .all(|case| case.status == "failed_as_expected") ); - assert_eq!(export.cases[3].layer, "Valid affine realization"); + assert_eq!(export.cases[3].layer, "Valid realization"); } #[test] diff --git a/src/core/algorithms/flips.rs b/src/core/algorithms/flips.rs index 1181f458..5e4880ac 100644 --- a/src/core/algorithms/flips.rs +++ b/src/core/algorithms/flips.rs @@ -39,9 +39,9 @@ use crate::core::collections::{ SimplexKeyBuffer, SmallBuffer, }; use crate::core::edge::{EdgeKey, EdgeKeyError}; -use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::facet::{AllFacetsIter, FacetError, FacetHandle, facet_key_from_vertices}; use crate::core::operations::TopologicalOperation; +use crate::core::realization::TriangulationRealizationValidationError; use crate::core::simplex::{NeighborSlot, Simplex, SimplexValidationError}; use crate::core::tds::{ EntityKind, NeighborValidationError, SimplexKey, Tds, TdsMutationError, TdsRollbackTransaction, @@ -3208,9 +3208,9 @@ pub enum FlipFailureKind { /// Flip transaction could not repair post-mutation orientation invariants. #[error("postcondition orientation repair")] PostconditionRepair, - /// Flip transaction failed embedded-geometry validation after mutation. - #[error("embedding validation")] - EmbeddingValidation, + /// Flip transaction failed realized-geometry validation after mutation. + #[error("realization validation")] + RealizationValidation, /// Neighbor wiring failed. #[error("neighbor wiring")] NeighborWiring, @@ -3378,9 +3378,9 @@ pub enum FlipNeighborDelaunayValidationFailureKind { /// Lower-layer topology validation failed. #[error("triangulation")] Triangulation, - /// Embedded-geometry validation failed. - #[error("embedding")] - Embedding, + /// Realized-geometry validation failed. + #[error("realization")] + Realization, /// Delaunay verification failed. #[error("verification failed")] VerificationFailed, @@ -3394,7 +3394,7 @@ impl From<&DelaunayTriangulationValidationError> for FlipNeighborDelaunayValidat match source { DelaunayTriangulationValidationError::Tds(_) => Self::Tds, DelaunayTriangulationValidationError::Triangulation(_) => Self::Triangulation, - DelaunayTriangulationValidationError::Embedding(_) => Self::Embedding, + DelaunayTriangulationValidationError::Realization(_) => Self::Realization, DelaunayTriangulationValidationError::VerificationFailed { .. } => { Self::VerificationFailed } @@ -3411,7 +3411,7 @@ impl From for FlipNeighborDelaunayValidati } } -/// Compact repair diagnostics preserved when embedding repair failures in flip wiring errors. +/// Compact repair diagnostics preserved when realization repair failures in flip wiring errors. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct FlipNeighborRepairDiagnostics { /// Number of queued items checked. @@ -3586,12 +3586,12 @@ pub enum FlipNeighborWiringError { /// Structured validation reason. reason: FlipNeighborDelaunayValidationFailureKind, }, - /// Embedding validation failed while preparing flip neighbor wiring. - #[error("embedding validation error reached flip neighbor wiring: {source}")] - EmbeddingValidation { - /// Underlying embedding validation error, preserving simplex/pair witness context. + /// Realization validation failed while preparing flip neighbor wiring. + #[error("realization validation error reached flip neighbor wiring: {source}")] + RealizationValidation { + /// Underlying realization validation error, preserving simplex/pair witness context. #[source] - source: TriangulationEmbeddingValidationError, + source: TriangulationRealizationValidationError, }, /// Delaunay repair failed while preparing flip neighbor wiring. #[error("Delaunay repair error reached flip neighbor wiring: {reason}")] @@ -3676,8 +3676,8 @@ impl From for FlipNeighborWiringError { InsertionError::DelaunayValidationFailed { source } => Self::DelaunayValidation { reason: source.into(), }, - InsertionError::EmbeddingValidationFailed { source } => { - Self::EmbeddingValidation { source } + InsertionError::RealizationValidationFailed { source } => { + Self::RealizationValidation { source } } InsertionError::DelaunayRepairFailed { source, context: _ } => Self::DelaunayRepair { reason: FlipNeighborRepairFailure::from(*source), @@ -4145,12 +4145,12 @@ pub enum FlipError { #[source] source: Box, }, - /// Flip transaction failed embedded-geometry validation after mutation. - #[error("Flip postcondition embedding validation failed: {source}")] - EmbeddingValidation { - /// Structured Level 4 embedding validation error. + /// Flip transaction failed realized-geometry validation after mutation. + #[error("Flip postcondition realization validation failed: {source}")] + RealizationValidation { + /// Structured Level 4 realization validation error. #[source] - source: Box, + source: Box, }, /// Neighbor wiring failed during flip application. #[error("Neighbor wiring failed: {reason}")] @@ -4271,11 +4271,11 @@ impl From<&FlipError> for FlipFailureKind { FlipError::FacetIteration { .. } => Self::FacetIteration, FlipError::SimplexCreation(_) => Self::SimplexCreation, FlipError::PostconditionRepair { .. } => Self::PostconditionRepair, - FlipError::EmbeddingValidation { .. } => Self::EmbeddingValidation, + FlipError::RealizationValidation { .. } => Self::RealizationValidation, FlipError::NeighborWiring { reason } => match reason.as_ref() { FlipNeighborWiringError::TopologyValidation { .. } | FlipNeighborWiringError::DelaunayValidation { .. } - | FlipNeighborWiringError::EmbeddingValidation { .. } + | FlipNeighborWiringError::RealizationValidation { .. } | FlipNeighborWiringError::TopologyValidationFailed { .. } => { Self::WiringValidation } @@ -5341,8 +5341,8 @@ const fn insertion_error_kind(source: &InsertionError) -> InsertionErrorKind { InsertionError::DelaunayValidationFailed { .. } => { InsertionErrorKind::DelaunayValidationFailed } - InsertionError::EmbeddingValidationFailed { .. } => { - InsertionErrorKind::EmbeddingValidationFailed + InsertionError::RealizationValidationFailed { .. } => { + InsertionErrorKind::RealizationValidationFailed } InsertionError::DelaunayRepairFailed { .. } => InsertionErrorKind::DelaunayRepairFailed, InsertionError::DuplicateCoordinates { .. } => InsertionErrorKind::DuplicateCoordinates, @@ -10683,7 +10683,7 @@ mod tests { }; use crate::core::algorithms::locate::LocateResult; use crate::core::collections::{SimplexVertexKeyBuffer, SimplexVertexUuidBuffer, Uuid}; - use crate::core::embedding::TriangulationEmbeddingSimplexDetail; + use crate::core::realization::TriangulationRealizationSimplexDetail; use crate::core::validation::TopologyGuarantee; use crate::geometry::kernel::{AdaptiveKernel, FastKernel}; use crate::geometry::traits::coordinate::CoordinateConversionValue; @@ -15044,7 +15044,7 @@ mod tests { } #[test] - fn flip_neighbor_wiring_preserves_embedding_validation_source() { + fn flip_neighbor_wiring_preserves_realization_validation_source() { let simplex_key = SimplexKey::from(KeyData::from_ffi(9_101)); let simplex_uuid = Uuid::from_u128(0x9101); let vertices: SimplexVertexKeyBuffer = [ @@ -15062,10 +15062,10 @@ mod tests { .into_iter() .collect(); - let embedding_source = TriangulationEmbeddingValidationError::DegenerateSimplex { + let realization_source = TriangulationRealizationValidationError::DegenerateSimplex { simplex_key, simplex_uuid, - detail: Box::new(TriangulationEmbeddingSimplexDetail { + detail: Box::new(TriangulationRealizationSimplexDetail { key: simplex_key, uuid: simplex_uuid, vertices, @@ -15074,35 +15074,35 @@ mod tests { dimension: 2, }; - let embedding_wiring = - FlipNeighborWiringError::from(InsertionError::EmbeddingValidationFailed { - source: embedding_source.clone(), + let realization_wiring = + FlipNeighborWiringError::from(InsertionError::RealizationValidationFailed { + source: realization_source.clone(), }); - let FlipNeighborWiringError::EmbeddingValidation { source } = &embedding_wiring else { - panic!("expected preserved embedding validation source, got {embedding_wiring:?}"); + let FlipNeighborWiringError::RealizationValidation { source } = &realization_wiring else { + panic!("expected preserved realization validation source, got {realization_wiring:?}"); }; - assert_eq!(source, &embedding_source); - let error_source = embedding_wiring + assert_eq!(source, &realization_source); + let error_source = realization_wiring .source() - .and_then(|source| source.downcast_ref::()) - .expect("embedding validation should remain the typed error source"); - assert_eq!(error_source, &embedding_source); + .and_then(|source| source.downcast_ref::()) + .expect("realization validation should remain the typed error source"); + assert_eq!(error_source, &realization_source); assert_eq!( - FlipFailureKind::from(&FlipError::from(embedding_wiring)), + FlipFailureKind::from(&FlipError::from(realization_wiring)), FlipFailureKind::WiringValidation ); - let transaction_embedding = FlipError::EmbeddingValidation { - source: Box::new(embedding_source.clone()), + let transaction_realization = FlipError::RealizationValidation { + source: Box::new(realization_source.clone()), }; assert_eq!( - FlipFailureKind::from(&transaction_embedding), - FlipFailureKind::EmbeddingValidation + FlipFailureKind::from(&transaction_realization), + FlipFailureKind::RealizationValidation ); let transaction_repair = FlipError::PostconditionRepair { - source: Box::new(InsertionError::EmbeddingValidationFailed { - source: embedding_source, + source: Box::new(InsertionError::RealizationValidationFailed { + source: realization_source, }), }; assert_eq!( diff --git a/src/core/algorithms/incremental_insertion.rs b/src/core/algorithms/incremental_insertion.rs index 8922ef89..fdceb457 100644 --- a/src/core/algorithms/incremental_insertion.rs +++ b/src/core/algorithms/incremental_insertion.rs @@ -38,8 +38,8 @@ use crate::core::collections::{ use crate::core::construction::{ FinalDelaunayValidationContext, FinalTopologyValidationContext, TriangulationConstructionError, }; -use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::facet::{FacetError, FacetHandle}; +use crate::core::realization::TriangulationRealizationValidationError; use crate::core::simplex::{NeighborSlot, Simplex, SimplexValidationError}; use crate::core::tds::{ DelaunayValidationErrorKind, EntityKind, GeometricError, InvariantError, @@ -701,12 +701,12 @@ pub enum InitialSimplexUnexpectedInsertionStage { source: DelaunayTriangulationValidationError, }, - /// Embedding validation escaped initial-simplex construction. - #[error("embedding validation failed during insertion: {source}")] - EmbeddingValidation { - /// Underlying embedding validation error. + /// Realization validation escaped initial-simplex construction. + #[error("realization validation failed during insertion: {source}")] + RealizationValidation { + /// Underlying realization validation error. #[source] - source: TriangulationEmbeddingValidationError, + source: TriangulationRealizationValidationError, }, /// Topology validation escaped initial-simplex construction. @@ -917,10 +917,10 @@ impl From for InitialSimplexConstructionError { ), } } - TriangulationConstructionError::InsertionEmbeddingValidation { source } => { + TriangulationConstructionError::InsertionRealizationValidation { source } => { Self::UnexpectedInsertionStage { reason: Box::new( - InitialSimplexUnexpectedInsertionStage::EmbeddingValidation { source }, + InitialSimplexUnexpectedInsertionStage::RealizationValidation { source }, ), } } @@ -1123,8 +1123,8 @@ pub enum InsertionErrorKind { HullExtension, /// Delaunay validation failed after insertion. DelaunayValidationFailed, - /// Embedded-geometry validation failed after insertion. - EmbeddingValidationFailed, + /// Realized-geometry validation failed after insertion. + RealizationValidationFailed, /// Flip-based Delaunay repair failed. DelaunayRepairFailed, /// Duplicate coordinates were supplied. @@ -1151,8 +1151,8 @@ pub enum InsertionErrorSourceKind { Tds(TdsErrorKind), /// Triangulation-layer topology validation failed. Triangulation(TriangulationValidationErrorKind), - /// Level 4 embedding validation failed. - Embedding, + /// Level 4 realization validation failed. + Realization, /// Level 5 Delaunay validation failed. Delaunay(DelaunayValidationErrorKind), /// Flip repair failed. @@ -1713,15 +1713,15 @@ pub enum InsertionError { source: DelaunayTriangulationValidationError, }, - /// Global embedding validation failed after insertion. + /// Global realization validation failed after insertion. /// /// This indicates the triangulation is structurally and topologically valid - /// but violates the embedded-geometry invariant (Level 4). - #[error("Embedding validation failed: {source}")] - EmbeddingValidationFailed { + /// but violates the realized-geometry invariant (Level 4). + #[error("Realization validation failed: {source}")] + RealizationValidationFailed { /// The structured Level 4 validation error. #[source] - source: TriangulationEmbeddingValidationError, + source: TriangulationRealizationValidationError, }, /// Flip-based Delaunay repair failed. @@ -1961,7 +1961,7 @@ impl InsertionError { // `NonManifoldTopology` variant. Self::NeighborWiring { .. } | Self::Location(_) - | Self::EmbeddingValidationFailed { .. } + | Self::RealizationValidationFailed { .. } | Self::DelaunayValidationFailed { .. } | Self::DelaunayRepairFailed { .. } | Self::DuplicateCoordinates { .. } @@ -2086,7 +2086,7 @@ impl InsertionError { | InitialSimplexUnexpectedInsertionStage::OrientationCanonicalization { .. } | InitialSimplexUnexpectedInsertionStage::Location { .. } | InitialSimplexUnexpectedInsertionStage::DelaunayValidation { .. } - | InitialSimplexUnexpectedInsertionStage::EmbeddingValidation { .. } + | InitialSimplexUnexpectedInsertionStage::RealizationValidation { .. } | InitialSimplexUnexpectedInsertionStage::SpatialIndexConstruction { .. } => false, } } @@ -2109,7 +2109,7 @@ impl InsertionError { | TriangulationValidationErrorKind::OrientationPromotionNonConvergence | TriangulationValidationErrorKind::IsolatedVertex ), - InvariantError::Embedding(_) | InvariantError::Delaunay(_) => false, + InvariantError::Realization(_) | InvariantError::Delaunay(_) => false, } } diff --git a/src/core/construction.rs b/src/core/construction.rs index ebad1c32..6c248c19 100644 --- a/src/core/construction.rs +++ b/src/core/construction.rs @@ -13,7 +13,7 @@ use crate::core::algorithms::incremental_insertion::{ }; use crate::core::algorithms::locate::{ConflictError, LocateError}; use crate::core::collections::{MAX_PRACTICAL_DIMENSION_SIZE, SmallBuffer}; -use crate::core::embedding::TriangulationEmbeddingValidationError; +use crate::core::realization::TriangulationRealizationValidationError; use crate::core::simplex::{Simplex, SimplexValidationError}; use crate::core::tds::{ InvariantError, SimplexKey, Tds, TdsConstructionError, TdsError, VertexKey, @@ -509,12 +509,12 @@ pub enum TriangulationConstructionError { source: DelaunayTriangulationValidationError, }, - /// Level 4 embedding validation failed during incremental construction. - #[error("Embedding validation failed during insertion: {source}")] - InsertionEmbeddingValidation { - /// Underlying embedding validation error. + /// Level 4 realization validation failed during incremental construction. + #[error("Realization validation failed during insertion: {source}")] + InsertionRealizationValidation { + /// Underlying realization validation error. #[source] - source: TriangulationEmbeddingValidationError, + source: TriangulationRealizationValidationError, }, /// Level 3 topology validation failed during incremental construction. diff --git a/src/core/facet.rs b/src/core/facet.rs index 1c22ab25..1031fc4d 100644 --- a/src/core/facet.rs +++ b/src/core/facet.rs @@ -295,7 +295,7 @@ pub enum FacetError { /// /// This provides a more readable and maintainable alternative to raw tuples throughout /// the codebase. Facet handles are used to reference facets without storing full vertex data. -/// They are storage-local runtime handles: the embedded [`SimplexKey`] is regenerated when a +/// They are storage-local runtime handles: the realized [`SimplexKey`] is regenerated when a /// [`Tds`] is hydrated from a snapshot and must not be persisted as durable topology identity. /// /// # Components diff --git a/src/core/insertion.rs b/src/core/insertion.rs index a5a94fbb..b5c63af3 100644 --- a/src/core/insertion.rs +++ b/src/core/insertion.rs @@ -332,8 +332,8 @@ struct TryInsertImplOk { /// out of the final conflict region so higher layers can revisit nearby /// Delaunay violations without rediscovering the inserted vertex star globally. repair_seed_simplices: SimplexKeyBuffer, - /// Live simplices whose embedded geometry was newly created by this insertion. - embedding_validation_simplices: SimplexKeyBuffer, + /// Live simplices whose realized geometry was newly created by this insertion. + realization_validation_simplices: SimplexKeyBuffer, /// Whether the insertion path can leave local Delaunay work for the caller. /// /// Clean interior Bowyer-Watson insertions preserve the Delaunay property. @@ -351,8 +351,8 @@ struct CavityInsertionOutcome { simplices_removed: usize, /// Simplices touched by insertion that should seed follow-up local repair. repair_seed_simplices: SimplexKeyBuffer, - /// Live simplices whose embedded geometry was newly created by this cavity fill. - embedding_validation_simplices: SimplexKeyBuffer, + /// Live simplices whose realized geometry was newly created by this cavity fill. + realization_validation_simplices: SimplexKeyBuffer, /// Whether this cavity path can leave Delaunay work for the caller. delaunay_repair_required: bool, } @@ -1142,7 +1142,7 @@ where .triangulation_mut() .validate_after_insertion_and_record_telemetry( insert_ok.suspicion, - &insert_ok.embedding_validation_simplices, + &insert_ok.realization_validation_simplices, telemetry, telemetry_mode, ); @@ -1235,7 +1235,7 @@ where let mut repair_seed_simplices = SimplexKeyBuffer::new(); append_live_unique_simplex_seeds(&self.tds, &new_simplices, &mut repair_seed_simplices); - let embedding_validation_simplices = new_simplices + let realization_validation_simplices = new_simplices .iter() .copied() .filter(|simplex_key| self.tds.contains_simplex(*simplex_key)) @@ -1246,7 +1246,7 @@ where simplices_removed: 0, suspicion: SuspicionFlags::default(), repair_seed_simplices, - embedding_validation_simplices, + realization_validation_simplices, delaunay_repair_required: true, })) } @@ -1298,7 +1298,7 @@ where let validation_result = self.validate_after_insertion_and_record_telemetry( fallback_ok.suspicion, - &fallback_ok.embedding_validation_simplices, + &fallback_ok.realization_validation_simplices, telemetry, telemetry_mode, ); @@ -1975,7 +1975,7 @@ where hint, simplices_removed: total_removed, repair_seed_simplices, - embedding_validation_simplices: new_simplices + realization_validation_simplices: new_simplices .iter() .copied() .filter(|simplex_key| self.tds.contains_simplex(*simplex_key)) @@ -2167,7 +2167,7 @@ where simplices_removed: 0, suspicion, repair_seed_simplices: SimplexKeyBuffer::new(), - embedding_validation_simplices: SimplexKeyBuffer::new(), + realization_validation_simplices: SimplexKeyBuffer::new(), delaunay_repair_required: false, }); } else if num_vertices == D + 1 { @@ -2191,13 +2191,13 @@ where // Return first simplex key for hint caching let first_simplex = self.tds.simplex_keys().next(); - let embedding_validation_simplices = first_simplex.into_iter().collect(); + let realization_validation_simplices = first_simplex.into_iter().collect(); return Ok(TryInsertImplOk { inserted: (v_key, first_simplex), simplices_removed: 0, suspicion, repair_seed_simplices: SimplexKeyBuffer::new(), - embedding_validation_simplices, + realization_validation_simplices, delaunay_repair_required: false, }); } @@ -2411,7 +2411,7 @@ where simplices_removed: outcome.simplices_removed, suspicion, repair_seed_simplices: outcome.repair_seed_simplices, - embedding_validation_simplices: outcome.embedding_validation_simplices, + realization_validation_simplices: outcome.realization_validation_simplices, delaunay_repair_required: outcome.delaunay_repair_required, }) } @@ -2447,8 +2447,8 @@ where simplices_removed: outcome.simplices_removed, suspicion, repair_seed_simplices: outcome.repair_seed_simplices, - embedding_validation_simplices: outcome - .embedding_validation_simplices, + realization_validation_simplices: outcome + .realization_validation_simplices, delaunay_repair_required: true, }); } @@ -2570,8 +2570,8 @@ where simplices_removed: outcome.simplices_removed, suspicion, repair_seed_simplices: outcome.repair_seed_simplices, - embedding_validation_simplices: outcome - .embedding_validation_simplices, + realization_validation_simplices: outcome + .realization_validation_simplices, delaunay_repair_required: true, }); } @@ -2836,7 +2836,7 @@ where simplices_removed: total_removed, suspicion, repair_seed_simplices, - embedding_validation_simplices: new_simplices + realization_validation_simplices: new_simplices .iter() .copied() .filter(|simplex_key| self.tds.contains_simplex(*simplex_key)) diff --git a/src/core/embedding.rs b/src/core/realization.rs similarity index 75% rename from src/core/embedding.rs rename to src/core/realization.rs index 315f7298..e434cece 100644 --- a/src/core/embedding.rs +++ b/src/core/realization.rs @@ -1,9 +1,9 @@ -//! Embedded-geometry validation for generic triangulations. +//! Realized-geometry validation for generic triangulations. //! //! This module owns Level 4 validation for generic [`Triangulation`](crate::Triangulation): //! after the TDS and topology layers have certified a valid oriented simplicial -//! complex, the embedding layer verifies that maximal simplices are nondegenerate -//! and intersect only in their shared faces in the topology's active affine chart. +//! complex, the realization layer verifies that maximal simplices are nondegenerate +//! and intersect only in their shared faces in the topology's active coordinate chart. #![forbid(unsafe_code)] @@ -18,14 +18,14 @@ use crate::core::tds::{InvariantError, InvariantKind, SimplexKey, Tds, TdsError, use crate::core::traits::data_type::DataType; use crate::core::triangulation::Triangulation; use crate::core::validation::TriangulationValidationError; -use crate::geometry::embedding::{ - LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, PeriodicSimplexSpanError, - SimplexIntersectionFailure, axis_aligned_bounding_boxes_overlap, coordinate_range_for_axis, - try_periodic_simplex_span, validate_simplex_embeddings_intersect_only_in_shared_faces, -}; use crate::geometry::kernel::Kernel; use crate::geometry::point::Point; use crate::geometry::predicates::Orientation; +use crate::geometry::realization::{ + LabeledSimplexRealization, LabeledSimplexRealizationError, PeriodicSimplexSpanError, + SimplexIntersectionFailure, axis_aligned_bounding_boxes_overlap, coordinate_range_for_axis, + try_periodic_simplex_span, validate_simplex_realizations_intersect_only_in_shared_faces, +}; use crate::geometry::robust_predicates::robust_orientation; use crate::geometry::traits::coordinate::{ CoordinateConversionError, CoordinateValidationError, InvalidCoordinateValue, @@ -38,9 +38,9 @@ use num_traits::ToPrimitive; use thiserror::Error; use uuid::Uuid; -/// Key- and UUID-based snapshot of one embedded simplex. +/// Key- and UUID-based snapshot of one realized simplex. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct TriangulationEmbeddingSimplexDetail { +pub struct TriangulationRealizationSimplexDetail { /// Simplex key at validation time. pub key: SimplexKey, /// Simplex UUID at validation time. @@ -51,22 +51,22 @@ pub struct TriangulationEmbeddingSimplexDetail { pub vertex_uuids: SimplexVertexUuidBuffer, } -/// Key- and UUID-based snapshot of one embedded simplex pair. +/// Key- and UUID-based snapshot of one realized simplex pair. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct TriangulationEmbeddingSimplexPairDetail { +pub struct TriangulationRealizationSimplexPairDetail { /// First simplex in the pair. - pub first_simplex: TriangulationEmbeddingSimplexDetail, + pub first_simplex: TriangulationRealizationSimplexDetail, /// Second simplex in the pair. - pub second_simplex: TriangulationEmbeddingSimplexDetail, + pub second_simplex: TriangulationRealizationSimplexDetail, } -/// Detailed witness for an illegal embedded-simplex intersection. +/// Detailed witness for an illegal realized-simplex intersection. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct TriangulationEmbeddingIntersectionDetail { +pub struct TriangulationRealizationIntersectionDetail { /// First simplex in the violating pair. - pub first_simplex: TriangulationEmbeddingSimplexDetail, + pub first_simplex: TriangulationRealizationSimplexDetail, /// Second simplex in the violating pair. - pub second_simplex: TriangulationEmbeddingSimplexDetail, + pub second_simplex: TriangulationRealizationSimplexDetail, /// Vertices shared by both simplices. pub shared_vertices: SimplexVertexKeyBuffer, /// UUIDs of vertices shared by both simplices. @@ -81,7 +81,7 @@ pub struct TriangulationEmbeddingIntersectionDetail { pub second_only_witness_vertex_uuids: SimplexVertexUuidBuffer, } -/// Invalid periodic-domain period observed during Level 4 embedding validation. +/// Invalid periodic-domain period observed during Level 4 realization validation. #[derive(Clone, Debug, Error, PartialEq)] #[non_exhaustive] pub enum PeriodicDomainPeriodError { @@ -116,15 +116,15 @@ impl From for PeriodicDomainPeriodError { } } -/// Errors returned by embedded-geometry validation (Level 4). +/// Errors returned by realized-geometry validation (Level 4). /// /// This error type is independent of the Delaunay empty-circumsphere predicate: -/// it certifies that the generic triangulation has a valid affine realization -/// in the topology's supported affine chart before any Delaunay-specific +/// it certifies that the generic triangulation has a valid realization +/// in the topology's supported coordinate chart before any Delaunay-specific /// predicate is evaluated. #[derive(Clone, Debug, Error, PartialEq)] #[non_exhaustive] -pub enum TriangulationEmbeddingValidationError { +pub enum TriangulationRealizationValidationError { /// Lower-layer element or TDS structural validation failed (Levels 1-2). #[error(transparent)] Tds(Box), @@ -133,9 +133,9 @@ pub enum TriangulationEmbeddingValidationError { #[error(transparent)] Triangulation(Box), - /// Embedded-overlap validation is not yet defined for this topology model. + /// Realized-overlap validation is not yet defined for this topology model. #[error( - "embedded validation is unsupported for {topology:?} topology in dimension {dimension}" + "realization validation is unsupported for {topology:?} topology in dimension {dimension}" )] UnsupportedTopology { /// Topology kind configured on the triangulation. @@ -144,7 +144,7 @@ pub enum TriangulationEmbeddingValidationError { dimension: usize, }, - /// Topology-specific coordinate lifting failed while preparing an embedded simplex. + /// Topology-specific coordinate lifting failed while preparing a realized simplex. #[error( "topology-specific lifting failed for simplex {simplex_uuid} (key {simplex_key:?}), vertex {vertex_key:?}: {source}" )] @@ -162,24 +162,24 @@ pub enum TriangulationEmbeddingValidationError { source: GlobalTopologyModelError, }, - /// A simplex embedding reused a vertex label. + /// A simplex realization reused a vertex label. #[error( - "simplex {simplex_uuid} (key {simplex_key:?}) has duplicate embedding label {vertex_key:?} ({vertex_uuid}) at indices {first_index} and {duplicate_index}" + "simplex {simplex_uuid} (key {simplex_key:?}) has duplicate realization label {vertex_key:?} ({vertex_uuid}) at indices {first_index} and {duplicate_index}" )] - DuplicateSimplexEmbeddingLabel { + DuplicateSimplexRealizationLabel { /// Key of the simplex with duplicate labels. simplex_key: SimplexKey, /// UUID of the simplex with duplicate labels. simplex_uuid: Uuid, /// Vertex-level diagnostic details for the malformed simplex. - detail: Box, + detail: Box, /// Duplicated vertex key. vertex_key: VertexKey, /// UUID of the duplicated vertex. vertex_uuid: Uuid, - /// First embedding slot containing the label. + /// First realization slot containing the label. first_index: usize, - /// Later embedding slot containing the same label. + /// Later realization slot containing the same label. duplicate_index: usize, }, @@ -191,7 +191,7 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the degenerate simplex. simplex_uuid: Uuid, /// Vertex-level diagnostic details for the degenerate simplex. - detail: Box, + detail: Box, /// Const-generic coordinate dimension. dimension: usize, }, @@ -224,7 +224,7 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the simplex whose orientation predicate failed. simplex_uuid: Uuid, /// Vertex-level diagnostic details for the simplex. - detail: Box, + detail: Box, /// Underlying coordinate conversion failure from the predicate boundary. #[source] source: CoordinateConversionError, @@ -240,7 +240,7 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the simplex whose basis was singular. simplex_uuid: Uuid, /// Vertex-level diagnostic details for the singular simplex. - detail: Box, + detail: Box, /// Const-generic coordinate dimension. dimension: usize, }, @@ -259,13 +259,13 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the second offending simplex. second_simplex_uuid: Uuid, /// Vertex-level diagnostic details for the illegal intersection. - detail: Box, + detail: Box, }, /// A lifted periodic simplex spans at least one full period along an axis. /// /// Such a simplex cannot be certified as injective in one affine covering - /// chart, so the quotient embedding is invalid before pairwise overlap + /// chart, so the quotient realization is invalid before pairwise overlap /// checks run. #[error( "simplex {simplex_uuid} (key {simplex_key:?}) spans {span} along periodic axis {axis}, but the period is {period}" @@ -276,7 +276,7 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the offending simplex. simplex_uuid: Uuid, /// Vertex-level diagnostic details for the offending simplex. - detail: Box, + detail: Box, /// Periodic axis whose lifted span is too wide. axis: usize, /// Lifted coordinate span along `axis`. @@ -285,7 +285,7 @@ pub enum TriangulationEmbeddingValidationError { period: f64, }, - /// A periodic domain period was invalid while checking embedded geometry. + /// A periodic domain period was invalid while checking realized geometry. #[error( "invalid periodic domain period while validating simplex {simplex_uuid} (key {simplex_key:?}): {source}" )] @@ -295,7 +295,7 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the simplex being checked. simplex_uuid: Uuid, /// Vertex-level diagnostic details for the simplex being checked. - detail: Box, + detail: Box, /// Underlying invalid-period error. #[source] source: PeriodicDomainPeriodError, @@ -315,7 +315,7 @@ pub enum TriangulationEmbeddingValidationError { /// UUID of the second simplex in the pair. second_simplex_uuid: Uuid, /// Vertex-level diagnostic details for the pair. - detail: Box, + detail: Box, /// Periodic axis whose shift range overflowed. axis: usize, /// Lower floating-point shift bound before integer conversion. @@ -325,9 +325,9 @@ pub enum TriangulationEmbeddingValidationError { }, /// A higher validation layer unexpectedly surfaced while running Level 4 validation. - #[error("unexpected {kind:?} validation error while validating Level 4 embedding: {source}")] + #[error("unexpected {kind:?} validation error while validating Level 4 realization: {source}")] UnexpectedValidationLayer { - /// Validation layer that leaked into the embedding boundary. + /// Validation layer that leaked into the realization boundary. kind: InvariantKind, /// Original typed validation error. #[source] @@ -335,32 +335,32 @@ pub enum TriangulationEmbeddingValidationError { }, } -impl From for TriangulationEmbeddingValidationError { +impl From for TriangulationRealizationValidationError { fn from(source: TdsError) -> Self { Self::Tds(Box::new(source)) } } -impl From for TriangulationEmbeddingValidationError { +impl From for TriangulationRealizationValidationError { fn from(source: TriangulationValidationError) -> Self { Self::Triangulation(Box::new(source)) } } -/// Discriminant for compact Level 4 embedded-geometry validation summaries. +/// Discriminant for compact Level 4 realized-geometry validation summaries. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum TriangulationEmbeddingValidationErrorKind { +pub enum TriangulationRealizationValidationErrorKind { /// Lower-layer TDS validation failed. Tds, /// Lower-layer topology validation failed. Triangulation, - /// The topology is not currently supported by embedded validation. + /// The topology is not currently supported by realization validation. UnsupportedTopology, /// Topology-specific coordinate lifting failed. TopologyLifting, - /// A simplex embedding reused a vertex label. - DuplicateSimplexEmbeddingLabel, + /// A simplex realization reused a vertex label. + DuplicateSimplexRealizationLabel, /// A simplex has zero D-volume. DegenerateSimplex, /// Coordinate validation failed at the predicate boundary. @@ -377,66 +377,72 @@ pub enum TriangulationEmbeddingValidationErrorKind { InvalidPeriodicDomainPeriod, /// Periodic translate enumeration exceeded supported shift bounds. PeriodicTranslateRangeOverflow, - /// A higher validation layer unexpectedly surfaced during embedding validation. + /// A higher validation layer unexpectedly surfaced during realization validation. UnexpectedValidationLayer, } -impl From<&TriangulationEmbeddingValidationError> for TriangulationEmbeddingValidationErrorKind { - fn from(source: &TriangulationEmbeddingValidationError) -> Self { +impl From<&TriangulationRealizationValidationError> + for TriangulationRealizationValidationErrorKind +{ + fn from(source: &TriangulationRealizationValidationError) -> Self { match source { - TriangulationEmbeddingValidationError::Tds(_) => Self::Tds, - TriangulationEmbeddingValidationError::Triangulation(_) => Self::Triangulation, - TriangulationEmbeddingValidationError::UnsupportedTopology { .. } => { + TriangulationRealizationValidationError::Tds(_) => Self::Tds, + TriangulationRealizationValidationError::Triangulation(_) => Self::Triangulation, + TriangulationRealizationValidationError::UnsupportedTopology { .. } => { Self::UnsupportedTopology } - TriangulationEmbeddingValidationError::TopologyLifting { .. } => Self::TopologyLifting, - TriangulationEmbeddingValidationError::DuplicateSimplexEmbeddingLabel { .. } => { - Self::DuplicateSimplexEmbeddingLabel + TriangulationRealizationValidationError::TopologyLifting { .. } => { + Self::TopologyLifting } - TriangulationEmbeddingValidationError::DegenerateSimplex { .. } => { + TriangulationRealizationValidationError::DuplicateSimplexRealizationLabel { + .. + } => Self::DuplicateSimplexRealizationLabel, + TriangulationRealizationValidationError::DegenerateSimplex { .. } => { Self::DegenerateSimplex } - TriangulationEmbeddingValidationError::CoordinateValidation { .. } => { + TriangulationRealizationValidationError::CoordinateValidation { .. } => { Self::CoordinateValidation } - TriangulationEmbeddingValidationError::PredicateFailed { .. } => Self::PredicateFailed, - TriangulationEmbeddingValidationError::SingularBarycentricBasis { .. } => { + TriangulationRealizationValidationError::PredicateFailed { .. } => { + Self::PredicateFailed + } + TriangulationRealizationValidationError::SingularBarycentricBasis { .. } => { Self::SingularBarycentricBasis } - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } => Self::SimplexIntersectionOutsideSharedFace, - TriangulationEmbeddingValidationError::PeriodicSimplexSpansDomain { .. } => { + TriangulationRealizationValidationError::PeriodicSimplexSpansDomain { .. } => { Self::PeriodicSimplexSpansDomain } - TriangulationEmbeddingValidationError::InvalidPeriodicDomainPeriod { .. } => { + TriangulationRealizationValidationError::InvalidPeriodicDomainPeriod { .. } => { Self::InvalidPeriodicDomainPeriod } - TriangulationEmbeddingValidationError::PeriodicTranslateRangeOverflow { .. } => { + TriangulationRealizationValidationError::PeriodicTranslateRangeOverflow { .. } => { Self::PeriodicTranslateRangeOverflow } - TriangulationEmbeddingValidationError::UnexpectedValidationLayer { .. } => { + TriangulationRealizationValidationError::UnexpectedValidationLayer { .. } => { Self::UnexpectedValidationLayer } } } } -/// Structured Level 4 embedding validation report. +/// Structured Level 4 realization validation report. /// /// This report is the diagnostic counterpart to -/// [`Triangulation::is_valid_embedding`]. The fast-fail method returns the -/// first invalid embedding condition, while this report records every +/// [`Triangulation::is_valid_realization`]. The fast-fail method returns the +/// first invalid realization condition, while this report records every /// simplex-level failure and every pairwise overlap failure that can be checked /// after invalid simplices are excluded from pairwise intersection work. #[derive(Clone, Debug, PartialEq)] #[must_use] -pub struct TriangulationEmbeddingValidationReport { +pub struct TriangulationRealizationValidationReport { /// Number of vertices in the triangulation when the report was generated. pub number_of_vertices: usize, /// Number of simplices in the triangulation when the report was generated. pub number_of_simplices: usize, - /// Number of simplex embeddings prepared for Level 4 validation. + /// Number of simplex realizations prepared for Level 4 validation. pub checked_simplices: usize, /// Number of candidate simplex pairs examined by the overlap broad phase. /// @@ -444,12 +450,12 @@ pub struct TriangulationEmbeddingValidationReport { /// after the sweep-and-prune broad phase; for periodic charts it counts all /// non-degenerate pairs (exhaustive enumeration). pub checked_simplex_pairs: usize, - /// Ordered list of Level 4 embedding violations. - pub violations: Vec, + /// Ordered list of Level 4 realization violations. + pub violations: Vec, } -impl TriangulationEmbeddingValidationReport { - /// Returns `true` when no Level 4 embedding violations were found. +impl TriangulationRealizationValidationReport { + /// Returns `true` when no Level 4 realization violations were found. /// /// # Examples /// @@ -467,7 +473,7 @@ impl TriangulationEmbeddingValidationReport { /// let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; /// /// std::assert_matches!( - /// dt.as_triangulation().embedding_report(), + /// dt.as_triangulation().realization_report(), /// Ok(report) if report.is_valid() /// ); /// # Ok(()) @@ -480,25 +486,25 @@ impl TriangulationEmbeddingValidationReport { } #[derive(Debug)] -struct EmbeddedSimplex { +struct RealizedSimplex { key: SimplexKey, uuid: Uuid, vertex_keys: SimplexVertexKeyBuffer, vertex_uuids: SimplexVertexUuidBuffer, - embedding: LabeledSimplexEmbedding, + realization: LabeledSimplexRealization, } type PeriodicShiftRangeBuffer = SmallBuffer<(i32, i32), MAX_PRACTICAL_DIMENSION_SIZE>; -impl EmbeddedSimplex { - /// Builds the lifted, labeled embedding for one TDS simplex while preserving +impl RealizedSimplex { + /// Builds the lifted, labeled realization for one TDS simplex while preserving /// simplex and vertex identities for later diagnostics. fn try_from_simplex( tds: &Tds, topology_model: &impl GlobalTopologyModel, simplex_key: SimplexKey, simplex: &Simplex, - ) -> Result { + ) -> Result { let mut vertices = SimplexVertexKeyBuffer::with_capacity(simplex.number_of_vertices()); let mut vertex_uuids = SimplexVertexUuidBuffer::with_capacity(simplex.number_of_vertices()); let mut coords = SmallBuffer::<[f64; D], MAX_PRACTICAL_DIMENSION_SIZE>::with_capacity( @@ -513,7 +519,7 @@ impl EmbeddedSimplex { expected: simplex.number_of_vertices(), actual: offsets.len(), context: format!( - "simplex {:?} (key {simplex_key:?}) periodic offset count vs vertex count during embedding validation", + "simplex {:?} (key {simplex_key:?}) periodic offset count vs vertex count during realization validation", simplex.uuid(), ), } @@ -526,7 +532,7 @@ impl EmbeddedSimplex { .ok_or_else(|| TdsError::VertexNotFound { vertex_key, context: format!( - "embedded validation for simplex {:?} (key {simplex_key:?})", + "realization validation for simplex {:?} (key {simplex_key:?})", simplex.uuid() ), })?; @@ -536,7 +542,7 @@ impl EmbeddedSimplex { let lifted_coords = topology_model .lift_for_orientation(*vertex.point().coords(), periodic_offset) .map_err( - |source| TriangulationEmbeddingValidationError::TopologyLifting { + |source| TriangulationRealizationValidationError::TopologyLifting { simplex_key, simplex_uuid: simplex.uuid(), vertex_key, @@ -547,10 +553,10 @@ impl EmbeddedSimplex { coords.push(lifted_coords); } - let embedding = - LabeledSimplexEmbedding::try_new(vertices.iter().copied(), coords.iter().copied()) + let realization = + LabeledSimplexRealization::try_new(vertices.iter().copied(), coords.iter().copied()) .map_err(|source| { - labeled_simplex_error_to_embedding_error( + labeled_simplex_error_to_realization_error( source, simplex_key, simplex, @@ -564,21 +570,21 @@ impl EmbeddedSimplex { uuid: simplex.uuid(), vertex_keys: vertices, vertex_uuids, - embedding, + realization, }) } - /// Rehydrates one embedded vertex coordinate as a validated point for exact predicates. + /// Rehydrates one realized vertex coordinate as a validated point for exact predicates. fn point_at( &self, vertex_index: usize, - ) -> Result, TriangulationEmbeddingValidationError> { - self.embedding.point_at(vertex_index).ok_or_else(|| { + ) -> Result, TriangulationRealizationValidationError> { + self.realization.point_at(vertex_index).ok_or_else(|| { TdsError::DimensionMismatch { - expected: self.embedding.labels().len(), + expected: self.realization.labels().len(), actual: vertex_index.saturating_add(1), context: format!( - "embedded simplex {:?} (key {:?}) point index during Level 4 validation", + "realized simplex {:?} (key {:?}) point index during Level 4 validation", self.uuid, self.key, ), } @@ -586,7 +592,7 @@ impl EmbeddedSimplex { }) } - /// Finds a labeled vertex in this embedded simplex and validates its point coordinates. + /// Finds a labeled vertex in this realized simplex and validates its point coordinates. /// /// The full-facet shortcut uses keys rather than coordinate indices so its /// orientation predicates stay tied to the same vertex identities reported @@ -594,16 +600,16 @@ impl EmbeddedSimplex { fn point_for_key( &self, vertex_key: VertexKey, - ) -> Result, TriangulationEmbeddingValidationError> { + ) -> Result, TriangulationRealizationValidationError> { let vertex_index = self - .embedding + .realization .labels() .iter() .position(|candidate| *candidate == vertex_key) .ok_or_else(|| TdsError::VertexNotFound { vertex_key, context: format!( - "embedded simplex {:?} (key {:?}) facet-side validation", + "realized simplex {:?} (key {:?}) facet-side validation", self.uuid, self.key, ), })?; @@ -623,8 +629,8 @@ impl EmbeddedSimplex { } /// Builds the public simplex detail payload reused by Level 4 error variants. - fn detail(&self) -> TriangulationEmbeddingSimplexDetail { - TriangulationEmbeddingSimplexDetail { + fn detail(&self) -> TriangulationRealizationSimplexDetail { + TriangulationRealizationSimplexDetail { key: self.key, uuid: self.uuid, vertices: self.vertex_keys.clone(), @@ -636,34 +642,34 @@ impl EmbeddedSimplex { /// Converts labeled simplex construction failures into Level 4 diagnostics /// that preserve the owning simplex and vertex identities callers need for /// repair planning. -fn labeled_simplex_error_to_embedding_error( - source: LabeledSimplexEmbeddingError, +fn labeled_simplex_error_to_realization_error( + source: LabeledSimplexRealizationError, simplex_key: SimplexKey, simplex: &Simplex, vertex_keys: &SimplexVertexKeyBuffer, vertex_uuids: &SimplexVertexUuidBuffer, -) -> TriangulationEmbeddingValidationError { +) -> TriangulationRealizationValidationError { let (expected, actual) = match source { - LabeledSimplexEmbeddingError::LabelCoordinateLengthMismatch { + LabeledSimplexRealizationError::LabelCoordinateLengthMismatch { label_count, coordinate_count, } => (label_count, coordinate_count), - LabeledSimplexEmbeddingError::InvalidArity { expected, actual } => (expected, actual), - LabeledSimplexEmbeddingError::DuplicateLabel { + LabeledSimplexRealizationError::InvalidArity { expected, actual } => (expected, actual), + LabeledSimplexRealizationError::DuplicateLabel { first_index, duplicate_index, } => { - return duplicate_simplex_embedding_label_error( + return duplicate_simplex_realization_label_error( simplex_key, simplex.uuid(), vertex_keys, vertex_uuids, first_index, duplicate_index, - "duplicate embedding label during embedding validation", + "duplicate realization label during realization validation", ); } - LabeledSimplexEmbeddingError::NonFiniteCoordinate { + LabeledSimplexRealizationError::NonFiniteCoordinate { vertex_index, coordinate_index, coordinate_value, @@ -673,7 +679,7 @@ fn labeled_simplex_error_to_embedding_error( expected: vertex_keys.len(), actual: vertex_index.saturating_add(1), context: format!( - "simplex {:?} (key {simplex_key:?}) finite-coordinate diagnostic vertex index during embedding validation", + "simplex {:?} (key {simplex_key:?}) finite-coordinate diagnostic vertex index during realization validation", simplex.uuid(), ), } @@ -684,13 +690,13 @@ fn labeled_simplex_error_to_embedding_error( expected: vertex_uuids.len(), actual: vertex_index.saturating_add(1), context: format!( - "simplex {:?} (key {simplex_key:?}) finite-coordinate diagnostic vertex UUID index during embedding validation", + "simplex {:?} (key {simplex_key:?}) finite-coordinate diagnostic vertex UUID index during realization validation", simplex.uuid(), ), } .into(); }; - return TriangulationEmbeddingValidationError::CoordinateValidation { + return TriangulationRealizationValidationError::CoordinateValidation { simplex_key, simplex_uuid: simplex.uuid(), vertex_key, @@ -702,11 +708,11 @@ fn labeled_simplex_error_to_embedding_error( }, }; } - LabeledSimplexEmbeddingError::InvalidPeriodicDomainPeriod { source } => { - return TriangulationEmbeddingValidationError::InvalidPeriodicDomainPeriod { + LabeledSimplexRealizationError::InvalidPeriodicDomainPeriod { source } => { + return TriangulationRealizationValidationError::InvalidPeriodicDomainPeriod { simplex_key, simplex_uuid: simplex.uuid(), - detail: Box::new(TriangulationEmbeddingSimplexDetail { + detail: Box::new(TriangulationRealizationSimplexDetail { key: simplex_key, uuid: simplex.uuid(), vertices: vertex_keys.clone(), @@ -721,15 +727,15 @@ fn labeled_simplex_error_to_embedding_error( expected, actual, context: format!( - "simplex {:?} (key {simplex_key:?}) arity during embedding validation", + "simplex {:?} (key {simplex_key:?}) arity during realization validation", simplex.uuid(), ), } .into() } -/// Preserves duplicate embedding labels as structured Level 4 diagnostics. -fn duplicate_simplex_embedding_label_error( +/// Preserves duplicate realization labels as structured Level 4 diagnostics. +fn duplicate_simplex_realization_label_error( simplex_key: SimplexKey, simplex_uuid: Uuid, vertex_keys: &SimplexVertexKeyBuffer, @@ -737,7 +743,7 @@ fn duplicate_simplex_embedding_label_error( first_index: usize, duplicate_index: usize, context: &'static str, -) -> TriangulationEmbeddingValidationError { +) -> TriangulationRealizationValidationError { let Some(&vertex_key) = vertex_keys.get(first_index) else { return TdsError::DimensionMismatch { expected: vertex_keys.len(), @@ -757,10 +763,10 @@ fn duplicate_simplex_embedding_label_error( .into(); }; - TriangulationEmbeddingValidationError::DuplicateSimplexEmbeddingLabel { + TriangulationRealizationValidationError::DuplicateSimplexRealizationLabel { simplex_key, simplex_uuid, - detail: Box::new(TriangulationEmbeddingSimplexDetail { + detail: Box::new(TriangulationRealizationSimplexDetail { key: simplex_key, uuid: simplex_uuid, vertices: vertex_keys.clone(), @@ -773,33 +779,33 @@ fn duplicate_simplex_embedding_label_error( } } -/// Converts translated embedded-simplex construction failures into the same -/// key- and UUID-rich public diagnostics as the primary embedding path. -fn labeled_simplex_error_to_embedded_simplex_error( - source: LabeledSimplexEmbeddingError, - simplex: &EmbeddedSimplex, -) -> TriangulationEmbeddingValidationError { +/// Converts translated realized-simplex construction failures into the same +/// key- and UUID-rich public diagnostics as the primary realization path. +fn labeled_simplex_error_to_realized_simplex_error( + source: LabeledSimplexRealizationError, + simplex: &RealizedSimplex, +) -> TriangulationRealizationValidationError { let (expected, actual) = match source { - LabeledSimplexEmbeddingError::LabelCoordinateLengthMismatch { + LabeledSimplexRealizationError::LabelCoordinateLengthMismatch { label_count, coordinate_count, } => (label_count, coordinate_count), - LabeledSimplexEmbeddingError::InvalidArity { expected, actual } => (expected, actual), - LabeledSimplexEmbeddingError::DuplicateLabel { + LabeledSimplexRealizationError::InvalidArity { expected, actual } => (expected, actual), + LabeledSimplexRealizationError::DuplicateLabel { first_index, duplicate_index, } => { - return duplicate_simplex_embedding_label_error( + return duplicate_simplex_realization_label_error( simplex.key, simplex.uuid, &simplex.vertex_keys, &simplex.vertex_uuids, first_index, duplicate_index, - "duplicate translated embedding label during embedding validation", + "duplicate translated realization label during realization validation", ); } - LabeledSimplexEmbeddingError::NonFiniteCoordinate { + LabeledSimplexRealizationError::NonFiniteCoordinate { vertex_index, coordinate_index, coordinate_value, @@ -809,7 +815,7 @@ fn labeled_simplex_error_to_embedded_simplex_error( expected: simplex.vertex_keys.len(), actual: vertex_index.saturating_add(1), context: format!( - "simplex {:?} (key {:?}) finite-coordinate translated diagnostic vertex index during embedding validation", + "simplex {:?} (key {:?}) finite-coordinate translated diagnostic vertex index during realization validation", simplex.uuid, simplex.key, ), } @@ -820,13 +826,13 @@ fn labeled_simplex_error_to_embedded_simplex_error( expected: simplex.vertex_uuids.len(), actual: vertex_index.saturating_add(1), context: format!( - "simplex {:?} (key {:?}) finite-coordinate translated diagnostic vertex UUID index during embedding validation", + "simplex {:?} (key {:?}) finite-coordinate translated diagnostic vertex UUID index during realization validation", simplex.uuid, simplex.key, ), } .into(); }; - return TriangulationEmbeddingValidationError::CoordinateValidation { + return TriangulationRealizationValidationError::CoordinateValidation { simplex_key: simplex.key, simplex_uuid: simplex.uuid, vertex_key, @@ -838,8 +844,8 @@ fn labeled_simplex_error_to_embedded_simplex_error( }, }; } - LabeledSimplexEmbeddingError::InvalidPeriodicDomainPeriod { source } => { - return TriangulationEmbeddingValidationError::InvalidPeriodicDomainPeriod { + LabeledSimplexRealizationError::InvalidPeriodicDomainPeriod { source } => { + return TriangulationRealizationValidationError::InvalidPeriodicDomainPeriod { simplex_key: simplex.key, simplex_uuid: simplex.uuid, detail: Box::new(simplex.detail()), @@ -852,7 +858,7 @@ fn labeled_simplex_error_to_embedded_simplex_error( expected, actual, context: format!( - "simplex {:?} (key {:?}) arity during translated embedding validation", + "simplex {:?} (key {:?}) arity during translated realization validation", simplex.uuid, simplex.key, ), } @@ -860,21 +866,21 @@ fn labeled_simplex_error_to_embedded_simplex_error( } impl Triangulation { - /// Validates embedded geometry only (Level 4). + /// Validates realized geometry only (Level 4). /// /// This method assumes lower layers have already passed validation. Use - /// [`validate_embedding`](Self::validate_embedding) for cumulative Levels + /// [`validate_realization`](Self::validate_realization) for cumulative Levels /// 1-4 validation. /// /// Euclidean topology is validated in its ordinary affine chart. Toroidal /// topology is validated in the stored periodic covering-space charts and /// across periodic translates. Spherical and hyperbolic topology currently - /// return [`TriangulationEmbeddingValidationError::UnsupportedTopology`] - /// until their model-specific affine/projective chart validators are added. + /// return [`TriangulationRealizationValidationError::UnsupportedTopology`] + /// until their model-specific realization validators are added. /// /// # Errors /// - /// Returns [`TriangulationEmbeddingValidationError`] if the topology model is + /// Returns [`TriangulationRealizationValidationError`] if the topology model is /// unsupported, a simplex is geometrically degenerate, a periodic simplex is /// not contained in a single covering chart, or two maximal simplices /// intersect outside their shared face. @@ -894,27 +900,27 @@ impl Triangulation { /// ]; /// let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; /// - /// assert!(dt.as_triangulation().is_valid_embedding().is_ok()); + /// assert!(dt.as_triangulation().is_valid_realization().is_ok()); /// # Ok(()) /// # } /// ``` - pub fn is_valid_embedding(&self) -> Result<(), TriangulationEmbeddingValidationError> { - if let Some(first_violation) = self.embedding_diagnostic()? { + pub fn is_valid_realization(&self) -> Result<(), TriangulationRealizationValidationError> { + if let Some(first_violation) = self.realization_diagnostic()? { return Err(first_violation); } Ok(()) } - /// Returns the first actionable Level 4 embedding diagnostic, if any. + /// Returns the first actionable Level 4 realization diagnostic, if any. /// /// This is the repair/retry-oriented counterpart to - /// [`is_valid_embedding`](Self::is_valid_embedding). It returns at most one + /// [`is_valid_realization`](Self::is_valid_realization). It returns at most one /// Level 4 violation with simplex keys, simplex UUIDs, and offending vertex /// keys/UUIDs where applicable. /// /// # Errors /// - /// Returns [`TriangulationEmbeddingValidationError`] when simplex embedding + /// Returns [`TriangulationRealizationValidationError`] when simplex realization /// preparation cannot continue because lower-layer TDS data are missing or /// malformed. /// @@ -933,27 +939,29 @@ impl Triangulation { /// ]; /// let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; /// - /// std::assert_matches!(dt.as_triangulation().embedding_diagnostic(), Ok(None)); + /// std::assert_matches!(dt.as_triangulation().realization_diagnostic(), Ok(None)); /// # Ok(()) /// # } /// ``` - pub fn embedding_diagnostic( + pub fn realization_diagnostic( &self, - ) -> Result, TriangulationEmbeddingValidationError> - { - self.first_embedding_violation() + ) -> Result< + Option, + TriangulationRealizationValidationError, + > { + self.first_realization_violation() } - /// Builds a Level 4 embedding report with key- and UUID-based violation details. + /// Builds a Level 4 realization report with key- and UUID-based violation details. /// - /// This method checks embedded geometry only. It does not run lower-layer + /// This method checks realized geometry only. It does not run lower-layer /// TDS/topology validation and does not evaluate the Level 5 Delaunay - /// property. Use [`validate_embedding`](Self::validate_embedding) for + /// property. Use [`validate_realization`](Self::validate_realization) for /// cumulative Levels 1-4 validation when pass/fail behavior is enough. /// /// # Errors /// - /// Returns [`TriangulationEmbeddingValidationError`] when simplex embedding + /// Returns [`TriangulationRealizationValidationError`] when simplex realization /// preparation cannot continue because lower-layer TDS data are missing or /// malformed. Ordinary Level 4 violations are returned inside the report. /// @@ -973,17 +981,18 @@ impl Triangulation { /// let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; /// /// std::assert_matches!( - /// dt.as_triangulation().embedding_report(), + /// dt.as_triangulation().realization_report(), /// Ok(report) if report.is_valid() /// ); /// # Ok(()) /// # } /// ``` - pub fn embedding_report( + pub fn realization_report( &self, - ) -> Result { + ) -> Result + { let topology_model = self.global_topology.model(); - let mut report = TriangulationEmbeddingValidationReport { + let mut report = TriangulationRealizationValidationReport { number_of_vertices: self.tds.number_of_vertices(), number_of_simplices: self.tds.number_of_simplices(), checked_simplices: 0, @@ -991,17 +1000,17 @@ impl Triangulation { violations: Vec::new(), }; - if !topology_model.supports_affine_embedding_validation() { - report - .violations - .push(TriangulationEmbeddingValidationError::UnsupportedTopology { + if !topology_model.supports_affine_chart_realization_validation() { + report.violations.push( + TriangulationRealizationValidationError::UnsupportedTopology { topology: self.global_topology.kind(), dimension: D, - }); + }, + ); return Ok(report); } - let simplices = self.collect_embedded_simplices()?; + let simplices = self.collect_realized_simplices()?; report.checked_simplices = simplices.len(); let periodic_domain = topology_model.periodic_domain(); let periodic_periods = periodic_domain.map(|domain| *domain.periods()); @@ -1042,13 +1051,13 @@ impl Triangulation { /// /// This validates: /// - **Levels 1-3** via [`Triangulation::validate`](Self::validate) - /// - **Level 4** via [`Triangulation::is_valid_embedding`](Self::is_valid_embedding) + /// - **Level 4** via [`Triangulation::is_valid_realization`](Self::is_valid_realization) /// /// # Errors /// - /// Returns [`TriangulationEmbeddingValidationError`] if lower-layer - /// validation fails, the topology cannot currently be embedded-validated, - /// or embedded Euclidean geometry is invalid. + /// Returns [`TriangulationRealizationValidationError`] if lower-layer + /// validation fails, the topology cannot currently be realized-validated, + /// or realized geometry is invalid. /// /// # Examples /// @@ -1065,11 +1074,11 @@ impl Triangulation { /// ]; /// let dt = DelaunayTriangulationBuilder::new(&vertices).build()?; /// - /// assert!(dt.as_triangulation().validate_embedding().is_ok()); + /// assert!(dt.as_triangulation().validate_realization().is_ok()); /// # Ok(()) /// # } /// ``` - pub fn validate_embedding(&self) -> Result<(), TriangulationEmbeddingValidationError> + pub fn validate_realization(&self) -> Result<(), TriangulationRealizationValidationError> where K: Kernel, U: DataType, @@ -1078,29 +1087,29 @@ impl Triangulation { self.validate().map_err(|error| match error { InvariantError::Tds(source) => source.into(), InvariantError::Triangulation(source) => source.into(), - InvariantError::Embedding(source) => source, + InvariantError::Realization(source) => source, source @ InvariantError::Delaunay(_) => { - TriangulationEmbeddingValidationError::UnexpectedValidationLayer { + TriangulationRealizationValidationError::UnexpectedValidationLayer { kind: InvariantKind::DelaunayProperty, source: Box::new(source), } } })?; - self.is_valid_embedding() + self.is_valid_realization() } /// Validates the Level 4 nondegeneracy invariant for a local simplex set. /// /// This intentionally does not perform pairwise overlap checks; insertion /// uses it as a cheap mutation-time guard so zero-volume simplices fail - /// inside the existing rollback transaction. Full embedding validation - /// remains the responsibility of [`is_valid_embedding`](Self::is_valid_embedding). - pub(crate) fn validate_local_embedding_nondegeneracy( + /// inside the existing rollback transaction. Full realization validation + /// remains the responsibility of [`is_valid_realization`](Self::is_valid_realization). + pub(crate) fn validate_local_realization_nondegeneracy( &self, simplices: &[SimplexKey], - ) -> Result<(), TriangulationEmbeddingValidationError> { + ) -> Result<(), TriangulationRealizationValidationError> { let topology_model = self.global_topology.model(); - if !topology_model.supports_affine_embedding_validation() { + if !topology_model.supports_affine_chart_realization_validation() { return Ok(()); } @@ -1111,45 +1120,47 @@ impl Triangulation { .simplex(simplex_key) .ok_or_else(|| TdsError::SimplexNotFound { simplex_key, - context: "local embedding nondegeneracy validation".to_string(), + context: "local realization nondegeneracy validation".to_string(), })?; - let embedded = EmbeddedSimplex::try_from_simplex( + let realized = RealizedSimplex::try_from_simplex( &self.tds, &topology_model, simplex_key, simplex, )?; - validate_simplex_nondegenerate(&embedded)?; + validate_simplex_nondegenerate(&realized)?; if let Some(domain) = periodic_domain { - validate_periodic_simplex_chart(&embedded, domain.periods())?; + validate_periodic_simplex_chart(&realized, domain.periods())?; } } Ok(()) } - /// Validates the Level 4 embedding invariant for a changed simplex scope. + /// Validates the Level 4 realization invariant for a changed simplex scope. /// /// Insertion and repair already assume the pre-existing triangulation was - /// embedding-valid before the local mutation. Under that precondition, only + /// realization-valid before the local mutation. Under that precondition, only /// the changed simplices can introduce a new nondegenerate-simplex or /// pairwise-intersection violation, so this checks each scoped simplex /// against every candidate it can intersect instead of rescanning all old /// simplex pairs. - pub(crate) fn validate_embedding_for_simplices( + pub(crate) fn validate_realization_for_simplices( &self, local_simplices: &[SimplexKey], - ) -> Result<(), TriangulationEmbeddingValidationError> { + ) -> Result<(), TriangulationRealizationValidationError> { if local_simplices.is_empty() { return Ok(()); } let topology_model = self.global_topology.model(); - if !topology_model.supports_affine_embedding_validation() { - return Err(TriangulationEmbeddingValidationError::UnsupportedTopology { - topology: self.global_topology.kind(), - dimension: D, - }); + if !topology_model.supports_affine_chart_realization_validation() { + return Err( + TriangulationRealizationValidationError::UnsupportedTopology { + topology: self.global_topology.kind(), + dimension: D, + }, + ); } let mut local_simplex_keys = FastHashSet::default(); @@ -1158,14 +1169,14 @@ impl Triangulation { if !self.tds.contains_simplex(simplex_key) { return Err(TdsError::SimplexNotFound { simplex_key, - context: "scoped embedding validation".to_string(), + context: "scoped realization validation".to_string(), } .into()); } local_simplex_keys.insert(simplex_key); } - let simplices = self.collect_embedded_simplices()?; + let simplices = self.collect_realized_simplices()?; let periodic_domain = topology_model.periodic_domain(); let periodic_periods = periodic_domain.map(|domain| *domain.periods()); @@ -1181,7 +1192,7 @@ impl Triangulation { let empty_skip = FastHashSet::default(); let (_, violation) = - for_each_scoped_candidate_simplex_pair::( + for_each_scoped_candidate_simplex_pair::( &simplices, &empty_skip, &local_simplex_keys, @@ -1203,27 +1214,29 @@ impl Triangulation { Ok(()) } - /// Collects all simplex embeddings after applying the topology model's active chart. - fn collect_embedded_simplices( + /// Collects all simplex realizations after applying the topology model's active chart. + fn collect_realized_simplices( &self, - ) -> Result>, TriangulationEmbeddingValidationError> { + ) -> Result>, TriangulationRealizationValidationError> { let topology_model = self.global_topology.model(); self.tds .simplices() .map(|(simplex_key, simplex)| { - EmbeddedSimplex::try_from_simplex(&self.tds, &topology_model, simplex_key, simplex) + RealizedSimplex::try_from_simplex(&self.tds, &topology_model, simplex_key, simplex) }) .collect() } - fn first_embedding_violation( + fn first_realization_violation( &self, - ) -> Result, TriangulationEmbeddingValidationError> - { + ) -> Result< + Option, + TriangulationRealizationValidationError, + > { let topology_model = self.global_topology.model(); - if !topology_model.supports_affine_embedding_validation() { + if !topology_model.supports_affine_chart_realization_validation() { return Ok(Some( - TriangulationEmbeddingValidationError::UnsupportedTopology { + TriangulationRealizationValidationError::UnsupportedTopology { topology: self.global_topology.kind(), dimension: D, }, @@ -1234,26 +1247,26 @@ impl Triangulation { let periodic_periods = periodic_domain.map(|domain| *domain.periods()); let mut simplices = Vec::with_capacity(self.tds.number_of_simplices()); for (simplex_key, simplex) in self.tds.simplices() { - let embedded = EmbeddedSimplex::try_from_simplex( + let realized = RealizedSimplex::try_from_simplex( &self.tds, &topology_model, simplex_key, simplex, )?; - if let Err(error) = validate_simplex_nondegenerate(&embedded) { + if let Err(error) = validate_simplex_nondegenerate(&realized) { return Ok(Some(error)); } if let Some(domain) = periodic_domain - && let Err(error) = validate_periodic_simplex_chart(&embedded, domain.periods()) + && let Err(error) = validate_periodic_simplex_chart(&realized, domain.periods()) { return Ok(Some(error)); } - simplices.push(embedded); + simplices.push(realized); } let empty_skip: FastHashSet = FastHashSet::default(); let (_, violation) = - for_each_candidate_simplex_pair::( + for_each_candidate_simplex_pair::( &simplices, &empty_skip, periodic_periods, @@ -1273,10 +1286,10 @@ impl Triangulation { /// Dispatches pairwise overlap validation through Euclidean or periodic chart logic. fn validate_topology_aware_simplex_pair( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, + first: &RealizedSimplex, + second: &RealizedSimplex, periodic_periods: Option<[f64; D]>, -) -> Result<(), TriangulationEmbeddingValidationError> { +) -> Result<(), TriangulationRealizationValidationError> { let Some(periods) = periodic_periods else { if bounding_boxes_overlap(first, second) { if try_validate_full_facet_pair(first, second)? { @@ -1298,11 +1311,11 @@ fn validate_topology_aware_simplex_pair( /// exactly the shared facet iff the two opposite vertices lie on opposite sides /// of the shared facet. This avoids the more expensive barycentric intersection /// solver for the common adjacent-pair case while preserving the same Level 4 -/// error shape for invalid same-side embeddings. +/// error shape for invalid same-side realizations. fn try_validate_full_facet_pair( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, -) -> Result { + first: &RealizedSimplex, + second: &RealizedSimplex, +) -> Result { let mut shared = SimplexVertexKeyBuffer::new(); let mut first_only = SimplexVertexKeyBuffer::new(); let mut second_only = SimplexVertexKeyBuffer::new(); @@ -1340,7 +1353,7 @@ fn try_validate_full_facet_pair( second_only, )), (Orientation::DEGENERATE, _) => { - Err(TriangulationEmbeddingValidationError::DegenerateSimplex { + Err(TriangulationRealizationValidationError::DegenerateSimplex { simplex_key: first.key, simplex_uuid: first.uuid, detail: Box::new(first.detail()), @@ -1348,7 +1361,7 @@ fn try_validate_full_facet_pair( }) } (_, Orientation::DEGENERATE) => { - Err(TriangulationEmbeddingValidationError::DegenerateSimplex { + Err(TriangulationRealizationValidationError::DegenerateSimplex { simplex_key: second.key, simplex_uuid: second.uuid, detail: Box::new(second.detail()), @@ -1364,10 +1377,10 @@ fn try_validate_full_facet_pair( /// vertex, so the sign can be compared between adjacent simplices without /// constructing a barycentric intersection system. fn orientation_against_shared_facet( - simplex: &EmbeddedSimplex, + simplex: &RealizedSimplex, shared: &SimplexVertexKeyBuffer, opposite: VertexKey, -) -> Result { +) -> Result { let mut points = SmallBuffer::, MAX_PRACTICAL_DIMENSION_SIZE>::with_capacity(D + 1); for &vertex_key in shared { points.push(simplex.point_for_key(vertex_key)?); @@ -1375,7 +1388,7 @@ fn orientation_against_shared_facet( points.push(simplex.point_for_key(opposite)?); robust_orientation(&points).map_err(|source| { - TriangulationEmbeddingValidationError::PredicateFailed { + TriangulationRealizationValidationError::PredicateFailed { simplex_key: simplex.key, simplex_uuid: simplex.uuid, detail: Box::new(simplex.detail()), @@ -1386,27 +1399,27 @@ fn orientation_against_shared_facet( /// Builds the standard Level 4 overlap diagnostic for a failed facet-side test. /// -/// Keeping the same [`TriangulationEmbeddingValidationError`] variant as the +/// Keeping the same [`TriangulationRealizationValidationError`] variant as the /// barycentric path lets repair/report callers consume one error contract /// regardless of which validator found the illegal intersection. fn shared_facet_same_side_intersection( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, + first: &RealizedSimplex, + second: &RealizedSimplex, shared_vertices: SimplexVertexKeyBuffer, first_only_witness_vertices: SimplexVertexKeyBuffer, second_only_witness_vertices: SimplexVertexKeyBuffer, -) -> TriangulationEmbeddingValidationError { +) -> TriangulationRealizationValidationError { let shared_vertex_uuids = first.vertex_uuids_for_keys(&shared_vertices); let first_only_witness_vertex_uuids = first.vertex_uuids_for_keys(&first_only_witness_vertices); let second_only_witness_vertex_uuids = second.vertex_uuids_for_keys(&second_only_witness_vertices); - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { first_simplex_key: first.key, first_simplex_uuid: first.uuid, second_simplex_key: second.key, second_simplex_uuid: second.uuid, - detail: Box::new(TriangulationEmbeddingIntersectionDetail { + detail: Box::new(TriangulationRealizationIntersectionDetail { first_simplex: first.detail(), second_simplex: second.detail(), shared_vertices, @@ -1421,13 +1434,13 @@ fn shared_facet_same_side_intersection( /// Recursively checks every periodic translate that can overlap two simplex boxes. fn validate_periodic_translates( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, + first: &RealizedSimplex, + second: &RealizedSimplex, periods: &[f64; D], shift_ranges: &[(i32, i32)], axis: usize, shift: &mut [i32; D], -) -> Result<(), TriangulationEmbeddingValidationError> { +) -> Result<(), TriangulationRealizationValidationError> { if axis == D { let translated = translated_simplex(second, periods, shift)?; if bounding_boxes_overlap(first, &translated) { @@ -1446,15 +1459,15 @@ fn validate_periodic_translates( /// Computes the finite integer shift range needed to test possible periodic overlaps. fn periodic_shift_ranges( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, + first: &RealizedSimplex, + second: &RealizedSimplex, periods: &[f64; D], -) -> Result { +) -> Result { (0..D) .map(|axis| { - let (first_min, first_max) = coordinate_range_for_axis(&first.embedding, axis) + let (first_min, first_max) = coordinate_range_for_axis(&first.realization, axis) .expect("axis generated from 0..D must be valid"); - let (second_min, second_max) = coordinate_range_for_axis(&second.embedding, axis) + let (second_min, second_max) = coordinate_range_for_axis(&second.realization, axis) .expect("axis generated from 0..D must be valid"); let period = periods[axis]; let lower_bound = ((first_min - second_max) / period).floor(); @@ -1484,18 +1497,18 @@ fn periodic_shift_ranges( /// Builds the shared diagnostic for periodic shift bounds that cannot fit in `i32`. fn periodic_translate_range_overflow( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, + first: &RealizedSimplex, + second: &RealizedSimplex, axis: usize, lower_bound: f64, upper_bound: f64, -) -> TriangulationEmbeddingValidationError { - TriangulationEmbeddingValidationError::PeriodicTranslateRangeOverflow { +) -> TriangulationRealizationValidationError { + TriangulationRealizationValidationError::PeriodicTranslateRangeOverflow { first_simplex_key: first.key, first_simplex_uuid: first.uuid, second_simplex_key: second.key, second_simplex_uuid: second.uuid, - detail: Box::new(TriangulationEmbeddingSimplexPairDetail { + detail: Box::new(TriangulationRealizationSimplexPairDetail { first_simplex: first.detail(), second_simplex: second.detail(), }), @@ -1505,32 +1518,32 @@ fn periodic_translate_range_overflow( } } -/// Translates one embedded simplex into a neighboring periodic chart. +/// Translates one realized simplex into a neighboring periodic chart. fn translated_simplex( - simplex: &EmbeddedSimplex, + simplex: &RealizedSimplex, periods: &[f64; D], shift: &[i32; D], -) -> Result, TriangulationEmbeddingValidationError> { - let embedding = simplex - .embedding +) -> Result, TriangulationRealizationValidationError> { + let realization = simplex + .realization .try_translated(periods, shift) - .map_err(|source| labeled_simplex_error_to_embedded_simplex_error(source, simplex))?; - Ok(EmbeddedSimplex { + .map_err(|source| labeled_simplex_error_to_realized_simplex_error(source, simplex))?; + Ok(RealizedSimplex { key: simplex.key, uuid: simplex.uuid, vertex_keys: simplex.vertex_keys.clone(), vertex_uuids: simplex.vertex_uuids.clone(), - embedding, + realization, }) } /// Rejects a periodic simplex whose lifted vertices cannot fit in one chart. fn validate_periodic_simplex_chart( - simplex: &EmbeddedSimplex, + simplex: &RealizedSimplex, periods: &[f64; D], -) -> Result<(), TriangulationEmbeddingValidationError> { - let span = try_periodic_simplex_span(&simplex.embedding, periods).map_err(|source| { - TriangulationEmbeddingValidationError::InvalidPeriodicDomainPeriod { +) -> Result<(), TriangulationRealizationValidationError> { + let span = try_periodic_simplex_span(&simplex.realization, periods).map_err(|source| { + TriangulationRealizationValidationError::InvalidPeriodicDomainPeriod { simplex_key: simplex.key, simplex_uuid: simplex.uuid, detail: Box::new(simplex.detail()), @@ -1539,7 +1552,7 @@ fn validate_periodic_simplex_chart( })?; if let Some(span) = span { return Err( - TriangulationEmbeddingValidationError::PeriodicSimplexSpansDomain { + TriangulationRealizationValidationError::PeriodicSimplexSpansDomain { simplex_key: simplex.key, simplex_uuid: simplex.uuid, detail: Box::new(simplex.detail()), @@ -1554,24 +1567,24 @@ fn validate_periodic_simplex_chart( /// Rejects zero-volume simplices before pairwise overlap validation runs. fn validate_simplex_nondegenerate( - simplex: &EmbeddedSimplex, -) -> Result<(), TriangulationEmbeddingValidationError> { + simplex: &RealizedSimplex, +) -> Result<(), TriangulationRealizationValidationError> { let points: SmallBuffer, MAX_PRACTICAL_DIMENSION_SIZE> = - (0..simplex.embedding.labels().len()) + (0..simplex.realization.labels().len()) .map(|index| simplex.point_at(index)) .collect::>()?; match robust_orientation(&points) { Ok(Orientation::POSITIVE | Orientation::NEGATIVE) => Ok(()), Ok(Orientation::DEGENERATE) => { - Err(TriangulationEmbeddingValidationError::DegenerateSimplex { + Err(TriangulationRealizationValidationError::DegenerateSimplex { simplex_key: simplex.key, simplex_uuid: simplex.uuid, detail: Box::new(simplex.detail()), dimension: D, }) } - Err(source) => Err(TriangulationEmbeddingValidationError::PredicateFailed { + Err(source) => Err(TriangulationRealizationValidationError::PredicateFailed { simplex_key: simplex.key, simplex_uuid: simplex.uuid, detail: Box::new(simplex.detail()), @@ -1582,24 +1595,24 @@ fn validate_simplex_nondegenerate( /// Applies the cheap bounding-box prefilter before exact intersection work. fn bounding_boxes_overlap( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, + first: &RealizedSimplex, + second: &RealizedSimplex, ) -> bool { - axis_aligned_bounding_boxes_overlap(&first.embedding, &second.embedding) + axis_aligned_bounding_boxes_overlap(&first.realization, &second.realization) } /// Converts pure simplex-intersection failures into triangulation-level diagnostics. fn validate_simplex_pair_intersection( - first: &EmbeddedSimplex, - second: &EmbeddedSimplex, -) -> Result<(), TriangulationEmbeddingValidationError> { - match validate_simplex_embeddings_intersect_only_in_shared_faces( - &first.embedding, - &second.embedding, + first: &RealizedSimplex, + second: &RealizedSimplex, +) -> Result<(), TriangulationRealizationValidationError> { + match validate_simplex_realizations_intersect_only_in_shared_faces( + &first.realization, + &second.realization, ) { Ok(()) => Ok(()), Err(SimplexIntersectionFailure::SingularBarycentricBasis) => Err( - TriangulationEmbeddingValidationError::SingularBarycentricBasis { + TriangulationRealizationValidationError::SingularBarycentricBasis { simplex_key: first.key, simplex_uuid: first.uuid, detail: Box::new(first.detail()), @@ -1613,12 +1626,12 @@ fn validate_simplex_pair_intersection( let second_only_witness_vertex_uuids = second.vertex_uuids_for_keys(&witness.second_only_witness); Err( - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { first_simplex_key: first.key, first_simplex_uuid: first.uuid, second_simplex_key: second.key, second_simplex_uuid: second.uuid, - detail: Box::new(TriangulationEmbeddingIntersectionDetail { + detail: Box::new(TriangulationRealizationIntersectionDetail { first_simplex: first.detail(), second_simplex: second.detail(), shared_vertices: witness.shared, @@ -1634,11 +1647,11 @@ fn validate_simplex_pair_intersection( } } -/// Axis-aligned bounding box for one embedded simplex, tagged with its index +/// Axis-aligned bounding box for one realized simplex, tagged with its index /// in the validated simplex list. #[derive(Clone, Copy, Debug)] struct SimplexBoundingBox { - /// Index of the owning simplex in the embedded-simplex slice. + /// Index of the owning simplex in the realized-simplex slice. simplex_index: usize, /// Per-axis lower bounds of the simplex vertices. min: [f64; D], @@ -1647,11 +1660,11 @@ struct SimplexBoundingBox { } impl SimplexBoundingBox { - /// Computes the bounding box of an embedded simplex from its lifted coordinates. - fn from_embedded(simplex_index: usize, simplex: &EmbeddedSimplex) -> Self { + /// Computes the bounding box of a realized simplex from its lifted coordinates. + fn from_realized(simplex_index: usize, simplex: &RealizedSimplex) -> Self { let mut min = [f64::INFINITY; D]; let mut max = [f64::NEG_INFINITY; D]; - for coords in simplex.embedding.coordinates() { + for coords in simplex.realization.coordinates() { for (axis, &value) in coords.iter().enumerate() { min[axis] = min[axis].min(value); max[axis] = max[axis].max(value); @@ -1693,7 +1706,7 @@ fn widest_extent_axis(boxes: &[SimplexBoundingBox]) -> usize .map_or(0, |(axis, _)| axis) } -/// Visits candidate overlapping simplex pairs for Level 4 embedding validation. +/// Visits candidate overlapping simplex pairs for Level 4 realization validation. /// /// The all-pairs intersection test is `O(S^2)` in the number of simplices, /// which dominates validation on large triangulations. For the Euclidean @@ -1737,12 +1750,12 @@ fn widest_extent_axis(boxes: &[SimplexBoundingBox]) -> usize /// - Ericson, *Real-Time Collision Detection* (2005), ch. 7 (sweep-and-prune) /// and ch. 4-5 (AABB separating-axis test). /// -/// See `REFERENCES.md`, "Embedded-Geometry Overlap Detection (Level 4 Validation)". +/// See `REFERENCES.md`, "Realized-Simplex Overlap Detection (Level 4 Validation)". fn for_each_candidate_simplex_pair( - simplices: &[EmbeddedSimplex], + simplices: &[RealizedSimplex], skip: &FastHashSet, periodic_periods: Option<[f64; D]>, - on_pair: impl FnMut(&EmbeddedSimplex, &EmbeddedSimplex) -> ControlFlow, + on_pair: impl FnMut(&RealizedSimplex, &RealizedSimplex) -> ControlFlow, ) -> (usize, Option) { // Lifted-chart AABBs cannot express wrap-around overlaps, and a degenerate // 0-dimensional chart has no sweep axis, so both fall back to exhaustive @@ -1755,11 +1768,11 @@ fn for_each_candidate_simplex_pair( /// Visits candidate pairs where at least one simplex belongs to a changed scope. fn for_each_scoped_candidate_simplex_pair( - simplices: &[EmbeddedSimplex], + simplices: &[RealizedSimplex], skip: &FastHashSet, scope: &FastHashSet, periodic_periods: Option<[f64; D]>, - mut on_pair: impl FnMut(&EmbeddedSimplex, &EmbeddedSimplex) -> ControlFlow, + mut on_pair: impl FnMut(&RealizedSimplex, &RealizedSimplex) -> ControlFlow, ) -> (usize, Option) { if scope.is_empty() { return for_each_candidate_simplex_pair(simplices, skip, periodic_periods, on_pair); @@ -1778,9 +1791,9 @@ fn for_each_scoped_candidate_simplex_pair( /// Exhaustive `O(S^2)` pairwise enumeration over non-skipped simplices. fn exhaustive_candidate_simplex_pairs( - simplices: &[EmbeddedSimplex], + simplices: &[RealizedSimplex], skip: &FastHashSet, - mut on_pair: impl FnMut(&EmbeddedSimplex, &EmbeddedSimplex) -> ControlFlow, + mut on_pair: impl FnMut(&RealizedSimplex, &RealizedSimplex) -> ControlFlow, ) -> (usize, Option) { let mut examined = 0_usize; for (first_index, first_simplex) in simplices.iter().enumerate() { @@ -1808,10 +1821,10 @@ fn exhaustive_candidate_simplex_pairs( /// mutation only needs changed-vs-all pairs. This keeps automatic insertion /// validation proportional to the changed scope instead of all old pairs. fn scoped_exhaustive_candidate_simplex_pairs( - simplices: &[EmbeddedSimplex], + simplices: &[RealizedSimplex], skip: &FastHashSet, scope: &FastHashSet, - mut on_pair: impl FnMut(&EmbeddedSimplex, &EmbeddedSimplex) -> ControlFlow, + mut on_pair: impl FnMut(&RealizedSimplex, &RealizedSimplex) -> ControlFlow, ) -> (usize, Option) { let mut examined = 0_usize; for (local_index, local_simplex) in simplices.iter().enumerate() { @@ -1845,15 +1858,15 @@ fn scoped_exhaustive_candidate_simplex_pairs( /// See [`for_each_candidate_simplex_pair`] for the completeness argument and /// references. fn sweep_and_prune_candidate_simplex_pairs( - simplices: &[EmbeddedSimplex], + simplices: &[RealizedSimplex], skip: &FastHashSet, - mut on_pair: impl FnMut(&EmbeddedSimplex, &EmbeddedSimplex) -> ControlFlow, + mut on_pair: impl FnMut(&RealizedSimplex, &RealizedSimplex) -> ControlFlow, ) -> (usize, Option) { let mut boxes: Vec> = simplices .iter() .enumerate() .filter(|(_, simplex)| !skip.contains(&simplex.key)) - .map(|(index, simplex)| SimplexBoundingBox::from_embedded(index, simplex)) + .map(|(index, simplex)| SimplexBoundingBox::from_realized(index, simplex)) .collect(); if boxes.len() < 2 { return (0, None); @@ -1973,11 +1986,11 @@ mod tests { } let simplex = (0..=D).collect(); let tri = tri_from_tds(tds_from_vertices_and_simplices(&coords, &[simplex])); - assert!(tri.is_valid_embedding().is_ok()); + assert!(tri.is_valid_realization().is_ok()); } #[test] - fn is_valid_embedding_accepts_single_simplex_dimensions_two_through_five() { + fn is_valid_realization_accepts_single_simplex_dimensions_two_through_five() { assert_single_simplex_embeds::<2>(); assert_single_simplex_embeds::<3>(); assert_single_simplex_embeds::<4>(); @@ -1985,7 +1998,7 @@ mod tests { } #[test] - fn validate_embedding_accepts_builder_constructed_triangulation() { + fn validate_realization_accepts_builder_constructed_triangulation() { let vertices = vec![ test_vertex([0.0, 0.0, 0.0]), test_vertex([1.0, 0.0, 0.0]), @@ -1997,11 +2010,11 @@ mod tests { .build() .unwrap(); - assert!(dt.as_triangulation().validate_embedding().is_ok()); + assert!(dt.as_triangulation().validate_realization().is_ok()); } #[test] - fn is_valid_embedding_accepts_two_tetrahedra_sharing_a_facet() { + fn is_valid_realization_accepts_two_tetrahedra_sharing_a_facet() { let coords = [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], @@ -2012,11 +2025,11 @@ mod tests { let tds = tds_from_vertices_and_simplices(&coords, &[vec![0, 1, 2, 3], vec![0, 2, 1, 4]]); let tri = tri_from_tds(tds); - assert!(tri.is_valid_embedding().is_ok()); + assert!(tri.is_valid_realization().is_ok()); } #[test] - fn is_valid_embedding_rejects_full_facet_same_side_overlap() { + fn is_valid_realization_rejects_full_facet_same_side_overlap() { let coords = [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], @@ -2027,11 +2040,11 @@ mod tests { let tds = tds_from_vertices_and_simplices(&coords, &[vec![0, 1, 2, 3], vec![0, 2, 1, 4]]); let tri = tri_from_tds(tds); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_matches!( err, - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { detail, .. } if detail.shared_vertices.len() == 3 @@ -2044,17 +2057,17 @@ mod tests { } #[test] - fn validate_embedding_rejects_degenerate_simplex() { + fn validate_realization_rejects_degenerate_simplex() { let coords = [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]; let tds = tds_from_vertices_and_simplices(&coords, &[vec![0, 1, 2]]); let tri = tri_from_tds(tds); let diagnostic = tri - .embedding_diagnostic() + .realization_diagnostic() .unwrap() .expect("degenerate simplex should produce a diagnostic"); let report_first = tri - .embedding_report() + .realization_report() .unwrap() .violations .into_iter() @@ -2062,16 +2075,16 @@ mod tests { .expect("degenerate simplex should be the first report violation"); assert_eq!(diagnostic, report_first); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_eq!(err, diagnostic); assert_matches!( err, - TriangulationEmbeddingValidationError::DegenerateSimplex { dimension: 2, .. } + TriangulationRealizationValidationError::DegenerateSimplex { dimension: 2, .. } ); } #[test] - fn is_valid_embedding_preserves_duplicate_label_detail() { + fn is_valid_realization_preserves_duplicate_label_detail() { let coords = [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]; let (mut tds, simplex_keys) = tds_from_vertices_and_simplices_with_keys(&coords, &[vec![0, 1, 2]]); @@ -2099,11 +2112,11 @@ mod tests { } let tri = tri_from_tds(tds); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_matches!( err, - TriangulationEmbeddingValidationError::DuplicateSimplexEmbeddingLabel { + TriangulationRealizationValidationError::DuplicateSimplexRealizationLabel { simplex_key: observed_simplex_key, vertex_key, vertex_uuid, @@ -2120,19 +2133,19 @@ mod tests { } #[test] - fn embedding_report_includes_degenerate_simplex_vertices() { + fn realization_report_includes_degenerate_simplex_vertices() { let coords = [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]; let tds = tds_from_vertices_and_simplices(&coords, &[vec![0, 1, 2]]); let tri = tri_from_tds(tds); let report = tri - .embedding_report() - .expect("embedding report should be generated"); + .realization_report() + .expect("realization report should be generated"); assert!(!report.is_valid()); assert_eq!(report.checked_simplices, 1); assert_matches!( &report.violations[..], - [TriangulationEmbeddingValidationError::DegenerateSimplex { + [TriangulationRealizationValidationError::DegenerateSimplex { detail, dimension: 2, .. @@ -2141,7 +2154,7 @@ mod tests { } #[test] - fn is_valid_embedding_rejects_nonadjacent_edge_crossing() { + fn is_valid_realization_rejects_nonadjacent_edge_crossing() { let coords = [[0.0, 0.0], [2.0, 0.0], [0.0, 2.0], [2.0, 2.0], [1.0, -1.0]]; let tds = tds_from_vertices_and_simplices( &coords, @@ -2149,15 +2162,15 @@ mod tests { ); let tri = tri_from_tds(tds); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_matches!( err, - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { .. } + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } ); } #[test] - fn is_valid_embedding_sweep_and_prune_detects_interposed_overlap() { + fn is_valid_realization_sweep_and_prune_detects_interposed_overlap() { // Regression guard for the sweep-and-prune broad phase: triangles A and // B genuinely overlap (no shared vertices), but triangle C sits between // them in the sweep-axis ordering while overlapping neither. A naive @@ -2181,15 +2194,15 @@ mod tests { ); let tri = tri_from_tds(tds); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_matches!( err, - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { .. } + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } ); } #[test] - fn embedding_report_includes_intersection_witness_vertices() { + fn realization_report_includes_intersection_witness_vertices() { let coords = [[0.0, 0.0], [2.0, 0.0], [0.0, 2.0], [2.0, 2.0], [1.0, -1.0]]; let tds = tds_from_vertices_and_simplices( &coords, @@ -2198,8 +2211,8 @@ mod tests { let tri = tri_from_tds(tds); let report = tri - .embedding_report() - .expect("embedding report should be generated"); + .realization_report() + .expect("realization report should be generated"); let intersection = report .violations @@ -2207,7 +2220,7 @@ mod tests { .find(|violation| { matches!( violation, - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } ) @@ -2216,7 +2229,7 @@ mod tests { assert_matches!( intersection, - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { detail, .. } if detail.first_simplex.vertices.len() == 3 @@ -2233,7 +2246,7 @@ mod tests { } #[test] - fn is_valid_embedding_accepts_lifted_toroidal_simplex_chart() { + fn is_valid_realization_accepts_lifted_toroidal_simplex_chart() { let coords = [[0.9, 0.1], [0.1, 0.1], [0.9, 0.3]]; let (mut tds, simplex_keys) = tds_from_vertices_and_simplices_with_keys(&coords, &[vec![0, 1, 2]]); @@ -2247,19 +2260,19 @@ mod tests { .unwrap(), ); - assert!(tri.is_valid_embedding().is_ok()); + assert!(tri.is_valid_realization().is_ok()); } #[test] - fn is_valid_embedding_rejects_unsupported_spherical_topology() { + fn is_valid_realization_rejects_unsupported_spherical_topology() { let coords = [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]; let tds = tds_from_vertices_and_simplices(&coords, &[vec![0, 1, 2]]); let tri = tri_from_tds_with_topology(tds, GlobalTopology::Spherical); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_matches!( err, - TriangulationEmbeddingValidationError::UnsupportedTopology { + TriangulationRealizationValidationError::UnsupportedTopology { topology: TopologyKind::Spherical, dimension: 2, } @@ -2267,7 +2280,7 @@ mod tests { } #[test] - fn is_valid_embedding_rejects_periodic_simplex_spanning_domain() { + fn is_valid_realization_rejects_periodic_simplex_spanning_domain() { let coords = [[0.0, 0.0], [1.0, 0.0], [0.0, 0.25]]; let tds = tds_from_vertices_and_simplices(&coords, &[vec![0, 1, 2]]); let tri = tri_from_tds_with_topology( @@ -2276,9 +2289,9 @@ mod tests { .unwrap(), ); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); let (span, period) = match err { - TriangulationEmbeddingValidationError::PeriodicSimplexSpansDomain { + TriangulationRealizationValidationError::PeriodicSimplexSpansDomain { axis: 0, span, period, @@ -2291,7 +2304,7 @@ mod tests { } #[test] - fn is_valid_embedding_rejects_periodic_translate_overlap() { + fn is_valid_realization_rejects_periodic_translate_overlap() { let coords = [ [0.0, 0.0], [0.2, 0.0], @@ -2312,19 +2325,19 @@ mod tests { .unwrap(), ); - let err = tri.is_valid_embedding().unwrap_err(); + let err = tri.is_valid_realization().unwrap_err(); assert_matches!( err, - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { .. } + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } ); } #[test] - fn embedding_error_kind_covers_variants() { - let source = TriangulationEmbeddingValidationError::DegenerateSimplex { + fn realization_error_kind_covers_variants() { + let source = TriangulationRealizationValidationError::DegenerateSimplex { simplex_key: SimplexKey::default(), simplex_uuid: Uuid::nil(), - detail: Box::new(TriangulationEmbeddingSimplexDetail { + detail: Box::new(TriangulationRealizationSimplexDetail { key: SimplexKey::default(), uuid: Uuid::nil(), vertices: SimplexVertexKeyBuffer::new(), @@ -2334,15 +2347,15 @@ mod tests { }; assert_eq!( - TriangulationEmbeddingValidationErrorKind::from(&source), - TriangulationEmbeddingValidationErrorKind::DegenerateSimplex, + TriangulationRealizationValidationErrorKind::from(&source), + TriangulationRealizationValidationErrorKind::DegenerateSimplex, ); let duplicate_label_source = - TriangulationEmbeddingValidationError::DuplicateSimplexEmbeddingLabel { + TriangulationRealizationValidationError::DuplicateSimplexRealizationLabel { simplex_key: SimplexKey::default(), simplex_uuid: Uuid::nil(), - detail: Box::new(TriangulationEmbeddingSimplexDetail { + detail: Box::new(TriangulationRealizationSimplexDetail { key: SimplexKey::default(), uuid: Uuid::nil(), vertices: SimplexVertexKeyBuffer::new(), @@ -2355,15 +2368,15 @@ mod tests { }; assert_eq!( - TriangulationEmbeddingValidationErrorKind::from(&duplicate_label_source), - TriangulationEmbeddingValidationErrorKind::DuplicateSimplexEmbeddingLabel, + TriangulationRealizationValidationErrorKind::from(&duplicate_label_source), + TriangulationRealizationValidationErrorKind::DuplicateSimplexRealizationLabel, ); let invalid_period_source = - TriangulationEmbeddingValidationError::InvalidPeriodicDomainPeriod { + TriangulationRealizationValidationError::InvalidPeriodicDomainPeriod { simplex_key: SimplexKey::default(), simplex_uuid: Uuid::nil(), - detail: Box::new(TriangulationEmbeddingSimplexDetail { + detail: Box::new(TriangulationRealizationSimplexDetail { key: SimplexKey::default(), uuid: Uuid::nil(), vertices: SimplexVertexKeyBuffer::new(), @@ -2376,28 +2389,29 @@ mod tests { }; assert_eq!( - TriangulationEmbeddingValidationErrorKind::from(&invalid_period_source), - TriangulationEmbeddingValidationErrorKind::InvalidPeriodicDomainPeriod, + TriangulationRealizationValidationErrorKind::from(&invalid_period_source), + TriangulationRealizationValidationErrorKind::InvalidPeriodicDomainPeriod, ); - let unexpected_source = TriangulationEmbeddingValidationError::UnexpectedValidationLayer { - kind: InvariantKind::DelaunayProperty, - source: Box::new(InvariantError::Delaunay( - DelaunayTriangulationValidationError::VerificationFailed { - source: Box::new(DelaunayVerificationError::from( - DelaunayValidationError::TriangulationState { - source: TdsError::InconsistentDataStructure { - message: "synthetic higher-layer failure".to_string(), + let unexpected_source = + TriangulationRealizationValidationError::UnexpectedValidationLayer { + kind: InvariantKind::DelaunayProperty, + source: Box::new(InvariantError::Delaunay( + DelaunayTriangulationValidationError::VerificationFailed { + source: Box::new(DelaunayVerificationError::from( + DelaunayValidationError::TriangulationState { + source: TdsError::InconsistentDataStructure { + message: "synthetic higher-layer failure".to_string(), + }, }, - }, - )), - }, - )), - }; + )), + }, + )), + }; assert_eq!( - TriangulationEmbeddingValidationErrorKind::from(&unexpected_source), - TriangulationEmbeddingValidationErrorKind::UnexpectedValidationLayer, + TriangulationRealizationValidationErrorKind::from(&unexpected_source), + TriangulationRealizationValidationErrorKind::UnexpectedValidationLayer, ); } } diff --git a/src/core/repair.rs b/src/core/repair.rs index 3a382792..ee29fbe4 100644 --- a/src/core/repair.rs +++ b/src/core/repair.rs @@ -858,8 +858,8 @@ where { self.tds.is_valid().map_err(InvariantError::Tds)?; self.is_valid_topology()?; - self.is_valid_embedding() - .map_err(InvariantError::Embedding)?; + self.is_valid_realization() + .map_err(InvariantError::Realization)?; } Ok(()) diff --git a/src/core/tds/errors.rs b/src/core/tds/errors.rs index 79f2d7c8..39d8ee51 100644 --- a/src/core/tds/errors.rs +++ b/src/core/tds/errors.rs @@ -5,8 +5,8 @@ use super::{SimplexKey, VertexKey}; use crate::core::algorithms::flips::{FlipError, FlipNeighborWiringError}; -use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::facet::FacetError; +use crate::core::realization::TriangulationRealizationValidationError; use crate::core::simplex::SimplexValidationError; use crate::core::validation::TriangulationValidationError; use crate::core::vertex::VertexValidationError; @@ -987,8 +987,8 @@ pub enum InvariantKind { Connectedness, /// Triangulation/topology invariants (manifold-with-boundary, Euler characteristic). Topology, - /// Embedded Euclidean geometry (nondegenerate simplices, no illegal overlap). - Embedding, + /// Realized geometry (nondegenerate simplices, no illegal overlap). + Realization, /// Delaunay empty-circumsphere property. DelaunayProperty, } @@ -1020,9 +1020,9 @@ pub enum InvariantError { #[error(transparent)] Triangulation(#[from] TriangulationValidationError), - /// Level 4 (embedded Euclidean geometry). + /// Level 4 (realized geometry). #[error(transparent)] - Embedding(#[from] TriangulationEmbeddingValidationError), + Realization(#[from] TriangulationRealizationValidationError), /// Level 5 (Delaunay property). #[error(transparent)] @@ -1097,8 +1097,8 @@ pub enum DelaunayValidationErrorKind { Tds, /// Lower-layer topology validation failed. Triangulation, - /// Lower-layer embedded-geometry validation failed. - Embedding, + /// Lower-layer realized-geometry validation failed. + Realization, /// Delaunay verification failed. VerificationFailed, /// Typed repair validation failed. @@ -1110,7 +1110,7 @@ impl From<&DelaunayTriangulationValidationError> for DelaunayValidationErrorKind match source { DelaunayTriangulationValidationError::Tds(_) => Self::Tds, DelaunayTriangulationValidationError::Triangulation(_) => Self::Triangulation, - DelaunayTriangulationValidationError::Embedding(_) => Self::Embedding, + DelaunayTriangulationValidationError::Realization(_) => Self::Realization, DelaunayTriangulationValidationError::VerificationFailed { .. } => { Self::VerificationFailed } diff --git a/src/core/tds/mutation.rs b/src/core/tds/mutation.rs index c0f6ee5f..98535f97 100644 --- a/src/core/tds/mutation.rs +++ b/src/core/tds/mutation.rs @@ -1933,7 +1933,7 @@ impl Tds { ), })?; // Periodic-lifted adjacencies do not have a unique canonical orientation at this - // structural layer because the embedding depends on lattice representative choice. + // structural layer because the realization depends on lattice representative choice. // Skip normalization constraints for these pairs. if simplex.periodic_vertex_offsets().is_some() || neighbor_simplex.periodic_vertex_offsets().is_some() diff --git a/src/core/tds/rollback.rs b/src/core/tds/rollback.rs index 4b18efc9..5b11d05d 100644 --- a/src/core/tds/rollback.rs +++ b/src/core/tds/rollback.rs @@ -5,7 +5,7 @@ use crate::core::tds::Tds; use std::ptr; -/// Owner abstraction for rollback guards that snapshot an embedded canonical [`Tds`]. +/// Owner abstraction for rollback guards that snapshot a canonical [`Tds`]. pub(crate) trait TdsRollbackOwner { /// Returns the canonical [`Tds`] that a rollback transaction snapshots. fn rollback_tds(&self) -> &Tds; diff --git a/src/core/tds/storage.rs b/src/core/tds/storage.rs index 6723af9c..e6b57f4a 100644 --- a/src/core/tds/storage.rs +++ b/src/core/tds/storage.rs @@ -30,7 +30,7 @@ //! //! The triangulation data structure represents a finite simplicial complex where: //! -//! - **0-simplices**: Individual vertices embedded in D-dimensional Euclidean space +//! - **0-simplices**: Individual vertices realized in D-dimensional Euclidean space //! - **1-simplices**: Edges connecting two vertices (inferred from maximal simplices) //! - **2-simplices**: Triangular faces with three vertices (inferred from maximal simplices) //! - **...** @@ -80,7 +80,7 @@ //! The incremental insertion algorithm attempts to maintain the Delaunay property during //! construction, but rare violations can remain. Structural invariants are enforced //! **reactively** through validation methods. For a definitive Delaunay check, run -//! Level 4 Embedding Validity via `Triangulation::validate_embedding()` and +//! Level 4 Valid Realization via `Triangulation::validate_realization()` and //! Level 5 Geometric Predicates via `DelaunayTriangulation::is_valid_delaunay()` / //! `DelaunayTriangulation::validate()`. //! @@ -104,8 +104,8 @@ //! 3. **Level 3: Intrinsic PL Topology** - [`Triangulation::is_valid_topology()`] //! - Builds on Level 2, and rejects isolated vertices (every vertex must be incident to β‰₯ 1 simplex) //! - Adds manifold-with-boundary + Euler characteristic -//! 4. **Level 4: Embedding Validity** - [`Triangulation::validate_embedding()`](crate::Triangulation::validate_embedding) -//! - Nondegenerate embedded simplices and no intersections outside shared faces +//! 4. **Level 4: Valid Realization** - [`Triangulation::validate_realization()`](crate::Triangulation::validate_realization) +//! - Nondegenerate realized simplices and no intersections outside shared faces //! 5. **Level 5: Geometric Predicates** - [`DelaunayTriangulation::is_valid_delaunay()`] //! - Implemented Delaunay predicates, including the empty circumsphere property //! diff --git a/src/core/tds/validation.rs b/src/core/tds/validation.rs index 5cd50a11..aa4f5a78 100644 --- a/src/core/tds/validation.rs +++ b/src/core/tds/validation.rs @@ -933,7 +933,7 @@ impl Tds { /// /// This is a **Level 2 (TDS structural)** check in the validation hierarchy. /// It intentionally does **not** validate individual vertices/simplices (Level 1), - /// nor triangulation topology (Level 3), valid affine realization (Level 4), + /// nor triangulation topology (Level 3), valid realization (Level 4), /// or the Delaunay property (Level 5). /// /// # Structural invariants checked @@ -1152,7 +1152,7 @@ impl Tds { /// error. /// /// **Note**: This does NOT check the Delaunay property. Use - /// `Triangulation::validate_embedding()` for Levels 1–4, `DelaunayTriangulation::is_valid_delaunay()` + /// `Triangulation::validate_realization()` for Levels 1–4, `DelaunayTriangulation::is_valid_delaunay()` /// for Level 5 only, or `DelaunayTriangulation::validate()` for cumulative Levels 1–5. /// /// # Errors diff --git a/src/core/validation.rs b/src/core/validation.rs index 7b04c226..a0479760 100644 --- a/src/core/validation.rs +++ b/src/core/validation.rs @@ -12,8 +12,8 @@ //! [`Tds`](crate::prelude::tds::Tds). //! - **Level 3** Intrinsic PL Topology validation is orchestrated here for //! [`Triangulation`](crate::Triangulation). -//! - **Level 4** Embedding Validity validation is implemented by -//! [`Triangulation::validate_embedding`](crate::Triangulation::validate_embedding). +//! - **Level 4** Valid Realization validation is implemented by +//! [`Triangulation::validate_realization`](crate::Triangulation::validate_realization). //! //! Implemented Level 5 Geometric Predicate validation for Delaunay lives in //! [`crate::validation`]. Keeping the module boundary at the generic @@ -61,13 +61,13 @@ //! Use [`Triangulation::validate()`](crate::prelude::triangulation::Triangulation::validate) //! for cumulative Levels 1–3. //! -//! ## Level 4: Embedding Validity +//! ## Level 4: Valid Realization //! -//! - **Method**: [`Triangulation::validate_embedding`](crate::prelude::triangulation::Triangulation::validate_embedding) +//! - **Method**: [`Triangulation::validate_realization`](crate::prelude::triangulation::Triangulation::validate_realization) //! - **Checks**: Nondegenerate maximal simplices and no intersections outside shared faces //! - **Cost**: O(NΒ²) worst case, dominated by pairwise simplex-intersection checks //! -//! Use [`Triangulation::validate_embedding`](crate::prelude::triangulation::Triangulation::validate_embedding) +//! Use [`Triangulation::validate_realization`](crate::prelude::triangulation::Triangulation::validate_realization) //! for cumulative Levels 1–4. //! //! ## Level 5: Geometric Predicates @@ -145,7 +145,7 @@ use uuid::Uuid; /// /// - `TopologyValidation(source)` β†’ `InvariantError::Tds(source)` (Level 1–2 preserved) /// - `TopologyValidationFailed { source }` β†’ `InvariantError::Triangulation(source)` (Level 3 preserved) -/// - `EmbeddingValidationFailed { source }` β†’ `InvariantError::Embedding(source)` (Level 4 preserved) +/// - `RealizationValidationFailed { source }` β†’ `InvariantError::Realization(source)` (Level 4 preserved) /// - `DelaunayValidationFailed { source }` β†’ `InvariantError::Delaunay(source)` (Level 5 preserved) /// - All other variants β†’ `InvariantError::Tds(InconsistentDataStructure { .. })` with `context` pub(crate) fn insertion_error_to_invariant_error( @@ -157,7 +157,9 @@ pub(crate) fn insertion_error_to_invariant_error( InsertionError::TopologyValidationFailed { source, .. } => { InvariantError::Triangulation(source) } - InsertionError::EmbeddingValidationFailed { source } => InvariantError::Embedding(source), + InsertionError::RealizationValidationFailed { source } => { + InvariantError::Realization(source) + } InsertionError::DelaunayValidationFailed { source } => InvariantError::Delaunay(source), other => InvariantError::Tds(TdsError::InconsistentDataStructure { message: format!("{context}: {other}"), @@ -506,7 +508,7 @@ pub enum ValidationPolicy { /// full validation checkpoints are owned by the caller. Never, - /// Do not run policy-triggered global topology/changed-scope embedding validation during insertion. + /// Do not run policy-triggered global topology/changed-scope realization validation during insertion. /// /// Mandatory local topology checks required by the active [`TopologyGuarantee`] still run /// during insertion, but suspicion-triggered global Level 3/changed-scope Level 4 validation is disabled. @@ -1553,7 +1555,7 @@ where /// This report checks topology-layer invariants only. It assumes the TDS /// structure is already valid. Use [`validation_report`](Self::validation_report) /// for cumulative Levels 1-3 diagnostics, and - /// [`embedding_report`](Self::embedding_report) for Level 4 embedded-geometry + /// [`realization_report`](Self::realization_report) for Level 4 realized-geometry /// diagnostics. /// /// # Errors @@ -1860,7 +1862,7 @@ where /// /// - `InvariantError::Tds(e)` β†’ `InsertionError::TopologyValidation(e)` /// - `InvariantError::Triangulation(e)` β†’ `InsertionError::TopologyValidationFailed { source: e }` - /// - `InvariantError::Embedding(e)` β†’ `InsertionError::EmbeddingValidationFailed { source: e }` + /// - `InvariantError::Realization(e)` β†’ `InsertionError::RealizationValidationFailed { source: e }` /// - `InvariantError::Delaunay(e)` β†’ `InsertionError::DelaunayValidationFailed { source: e }` pub(crate) fn invariant_error_to_insertion_error(err: InvariantError) -> InsertionError { match err { @@ -1869,9 +1871,11 @@ where context: InsertionTopologyValidationContext::InvariantConversion, source: tri_err, }, - InvariantError::Embedding(embedding_err) => InsertionError::EmbeddingValidationFailed { - source: embedding_err, - }, + InvariantError::Realization(realization_err) => { + InsertionError::RealizationValidationFailed { + source: realization_err, + } + } InvariantError::Delaunay(dt_err) => { InsertionError::DelaunayValidationFailed { source: dt_err } } @@ -1912,8 +1916,8 @@ where // checks so topology diagnostics still surface first. self.validate_geometric_simplex_orientation()?; let simplex_keys: SimplexKeyBuffer = self.tds.simplex_keys().collect(); - self.validate_local_embedding_nondegeneracy(&simplex_keys) - .map_err(InvariantError::Embedding)?; + self.validate_local_realization_nondegeneracy(&simplex_keys) + .map_err(InvariantError::Realization)?; Ok(()) } @@ -2046,8 +2050,8 @@ where } self.validate_geometric_simplex_orientation_for_simplices(simplices)?; - self.validate_local_embedding_nondegeneracy(simplices) - .map_err(InvariantError::Embedding)?; + self.validate_local_realization_nondegeneracy(simplices) + .map_err(InvariantError::Realization)?; Ok(()) } @@ -2092,10 +2096,10 @@ where InsertionValidationWork::FullValidation => { self.validate()?; match local_simplices { - Some([]) | None => self.is_valid_embedding(), - Some(simplices) => self.validate_embedding_for_simplices(simplices), + Some([]) | None => self.is_valid_realization(), + Some(simplices) => self.validate_realization_for_simplices(simplices), } - .map_err(InvariantError::Embedding) + .map_err(InvariantError::Realization) } InsertionValidationWork::RequiredTopologyLinks => local_simplices.map_or_else( || self.validate_required_topology_links(), @@ -2185,9 +2189,9 @@ mod tests { use crate::core::algorithms::incremental_insertion::CavityFillingError; use crate::core::algorithms::incremental_insertion::repair_neighbor_pointers; use crate::core::collections::{NeighborBuffer, SimplexVertexKeyBuffer}; - use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::facet::FacetError; use crate::core::operations::InsertionOutcome; + use crate::core::realization::TriangulationRealizationValidationError; use crate::core::simplex::Simplex; use crate::core::tds::{ GeometricError, NeighborValidationError, Tds, TriangulationConstructionState, @@ -2218,8 +2222,8 @@ mod tests { } } - const fn synthetic_embedding_error() -> TriangulationEmbeddingValidationError { - TriangulationEmbeddingValidationError::UnsupportedTopology { + const fn synthetic_realization_error() -> TriangulationRealizationValidationError { + TriangulationRealizationValidationError::UnsupportedTopology { topology: TopologyKind::Spherical, dimension: 3, } @@ -3085,13 +3089,13 @@ mod tests { InvariantError::Triangulation(inner) ); - let embedding_source = synthetic_embedding_error(); - let error = InsertionError::EmbeddingValidationFailed { - source: embedding_source.clone(), + let realization_source = synthetic_realization_error(); + let error = InsertionError::RealizationValidationFailed { + source: realization_source.clone(), }; assert_eq!( insertion_error_to_invariant_error(error, "ctx"), - InvariantError::Embedding(embedding_source) + InvariantError::Realization(realization_source) ); let delaunay_source = synthetic_delaunay_verification_error("delaunay"); @@ -3134,10 +3138,10 @@ mod tests { Triangulation::, (), (), 3>::invariant_error_to_insertion_error(inv); assert_matches!(ins, InsertionError::TopologyValidationFailed { .. }); - let inv = InvariantError::Embedding(synthetic_embedding_error()); + let inv = InvariantError::Realization(synthetic_realization_error()); let ins = Triangulation::, (), (), 3>::invariant_error_to_insertion_error(inv); - assert_matches!(ins, InsertionError::EmbeddingValidationFailed { .. }); + assert_matches!(ins, InsertionError::RealizationValidationFailed { .. }); let inv = InvariantError::Delaunay(synthetic_delaunay_verification_error("test")); let ins = @@ -4111,7 +4115,7 @@ mod tests { } #[test] - fn validate_after_insertion_rejects_local_degenerate_simplex_embedding() { + fn validate_after_insertion_rejects_local_degenerate_simplex_realization() { let (tri, ck) = build_degenerate_tet(); let mut scope = SimplexKeyBuffer::new(); scope.push(ck); @@ -4122,8 +4126,8 @@ mod tests { assert_matches!( err, - InvariantError::Embedding( - TriangulationEmbeddingValidationError::DegenerateSimplex { + InvariantError::Realization( + TriangulationRealizationValidationError::DegenerateSimplex { simplex_key, dimension: 3, .. @@ -4133,7 +4137,7 @@ mod tests { } #[test] - fn validate_after_insertion_full_validation_rejects_local_degenerate_simplex_embedding() { + fn validate_after_insertion_full_validation_rejects_local_degenerate_simplex_realization() { let (mut tri, ck) = build_degenerate_tet(); tri.set_validation_policy(ValidationPolicy::Always); let mut scope = SimplexKeyBuffer::new(); @@ -4145,8 +4149,8 @@ mod tests { assert_matches!( err, - InvariantError::Embedding( - TriangulationEmbeddingValidationError::DegenerateSimplex { + InvariantError::Realization( + TriangulationRealizationValidationError::DegenerateSimplex { simplex_key, dimension: 3, .. @@ -4156,14 +4160,14 @@ mod tests { } #[test] - fn validate_after_insertion_full_validation_rejects_global_embedding_intersection() { + fn validate_after_insertion_full_validation_rejects_global_realization_intersection() { let (tds, scope) = build_topologically_valid_self_overlapping_tds_2d(); let mut tri = Triangulation::, (), (), 2>::new_with_tds(FastKernel::new(), tds); tri.set_validation_policy(ValidationPolicy::Always); tri.is_valid_topology() - .expect("fixture should isolate a Level 4 embedding failure"); + .expect("fixture should isolate a Level 4 realization failure"); let err = tri .validate_after_insertion_with_scope(SuspicionFlags::default(), Some(&scope[..1])) @@ -4171,23 +4175,23 @@ mod tests { assert_matches!( err, - InvariantError::Embedding( - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { .. } + InvariantError::Realization( + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } ) ); } #[test] - fn validate_after_insertion_full_validation_checks_empty_local_embedding_scope() { + fn validate_after_insertion_full_validation_checks_empty_local_realization_scope() { let (tds, _) = build_topologically_valid_self_overlapping_tds_2d(); let mut tri = Triangulation::, (), (), 2>::new_with_tds(FastKernel::new(), tds); tri.set_validation_policy(ValidationPolicy::Always); tri.is_valid_topology() - .expect("fixture should isolate a Level 4 embedding failure"); - let expected_embedding_error = tri - .is_valid_embedding() + .expect("fixture should isolate a Level 4 realization failure"); + let expected_realization_error = tri + .is_valid_realization() .expect_err("fixture should fail whole-triangulation Level 4 validation"); let empty_scope = SimplexKeyBuffer::new(); @@ -4195,18 +4199,18 @@ mod tests { .validate_after_insertion_with_scope(SuspicionFlags::default(), Some(&empty_scope)) .unwrap_err(); - assert_eq!(err, InvariantError::Embedding(expected_embedding_error)); + assert_eq!(err, InvariantError::Realization(expected_realization_error)); } #[test] - fn validate_after_insertion_full_validation_checks_large_raw_embedding_scope() { + fn validate_after_insertion_full_validation_checks_large_raw_realization_scope() { let (tds, scope) = build_topologically_valid_self_overlapping_tds_2d(); let mut tri = Triangulation::, (), (), 2>::new_with_tds(FastKernel::new(), tds); tri.set_validation_policy(ValidationPolicy::Always); tri.is_valid_topology() - .expect("fixture should isolate a Level 4 embedding failure"); + .expect("fixture should isolate a Level 4 realization failure"); let mut large_scope = SimplexKeyBuffer::new(); for _ in 0..9 { @@ -4219,8 +4223,8 @@ mod tests { assert_matches!( err, - InvariantError::Embedding( - TriangulationEmbeddingValidationError::SimplexIntersectionOutsideSharedFace { .. } + InvariantError::Realization( + TriangulationRealizationValidationError::SimplexIntersectionOutsideSharedFace { .. } ) ); } diff --git a/src/delaunay/builder.rs b/src/delaunay/builder.rs index d23eff7e..a16f5ec0 100644 --- a/src/delaunay/builder.rs +++ b/src/delaunay/builder.rs @@ -486,10 +486,10 @@ pub enum ExplicitConstructionError { #[source] source: Box, }, - /// Level 4 embedding validation failed before returning the wrapper. - #[error("Embedding validation failed during explicit construction: {source}")] - EmbeddingValidation { - /// Underlying cumulative embedding validation error. + /// Level 4 realization validation failed before returning the wrapper. + #[error("Realization validation failed during explicit construction: {source}")] + RealizationValidation { + /// Underlying cumulative realization validation error. #[source] source: Box, }, @@ -502,7 +502,7 @@ pub enum ExplicitConstructionError { }, /// Explicit quotient connectivity is not supported for the requested topology. #[error( - "Explicit non-Euclidean connectivity is not supported for {topology:?}; quotient embedding validation is required" + "Explicit non-Euclidean connectivity is not supported for {topology:?}; quotient realization validation is required" )] UnsupportedExplicitTopology { /// Requested global topology metadata. @@ -1427,7 +1427,7 @@ where /// geometric degeneracy, etc.). /// - Explicit-simplex construction is requested with unsupported /// [`ConstructionOptions`], non-Euclidean topology, invalid topology or - /// embedding, or a failed Level 5 Delaunay check when final enforcement is + /// realization, or a failed Level 5 Delaunay check when final enforcement is /// enabled. /// /// # Examples @@ -1999,14 +1999,14 @@ where /// [`ConstructionOptions::without_final_delaunay_enforcement`] is used, the /// explicit connectivity is returned after Levels 1–4 validation without /// Delaunay repair or proof. Non-Euclidean explicit connectivity is rejected - /// because it requires quotient embedding validation before the public + /// because it requires quotient realization validation before the public /// `DelaunayTriangulation` wrapper can accept it. /// /// # Algorithm /// /// 1. Receive prevalidated simplex specs: each simplex has D+1 in-bounds, /// unique vertex indices. - /// 2. Reject non-Euclidean explicit connectivity until quotient embedding + /// 2. Reject non-Euclidean explicit connectivity until quotient realization /// validation exists. /// 3. Build a `Tds`: insert all vertices, then insert simplices from the specifications. /// 4. Compute adjacency via `assign_neighbors()`. @@ -2164,12 +2164,12 @@ where } if !enforce_final_delaunay { - let proof = candidate.validate_embedding_only().map_err(|source| { - ExplicitConstructionError::EmbeddingValidation { + let proof = candidate.validate_realization_only().map_err(|source| { + ExplicitConstructionError::RealizationValidation { source: Box::new(source), } })?; - return Ok(candidate.into_embedding_validated_delaunay(proof)); + return Ok(candidate.into_realization_validated_delaunay(proof)); } let proof = Self::enforce_explicit_delaunay_property(&candidate)?; @@ -2181,7 +2181,7 @@ where /// The public return type is `DelaunayTriangulation`, so Euclidean explicit /// connectivity must prove the empty-circumsphere property before it crosses /// this API boundary. Explicit non-Euclidean topology is rejected earlier in - /// `build_explicit` until quotient embedding validation exists for explicit + /// `build_explicit` until quotient realization validation exists for explicit /// connectivity. fn enforce_explicit_delaunay_property( candidate: &DelaunayTriangulationCandidate, @@ -2197,7 +2197,7 @@ where }) } - /// Rejects explicit quotient connectivity until embedding validation supports it. + /// Rejects explicit quotient connectivity until realization validation supports it. fn reject_explicit_non_euclidean_topology( global_topology: GlobalTopology, ) -> Result<(), DelaunayTriangulationConstructionError> { diff --git a/src/delaunay/construction.rs b/src/delaunay/construction.rs index cd9097f5..ffb94887 100644 --- a/src/delaunay/construction.rs +++ b/src/delaunay/construction.rs @@ -65,13 +65,13 @@ use crate::core::construction::{ PeriodicQuotientFacetKeyDerivationFailure, TriangulationConstructionError, }; use crate::core::edge::EdgeKeyError; -use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::facet::FacetError; use crate::core::insertion::record_duplicate_detection_metrics; use crate::core::operations::{ DelaunayInsertionState, InsertionOutcome, InsertionResult, InsertionStatistics, InsertionTelemetryMode, RepairDecision, TopologicalOperation, }; +use crate::core::realization::TriangulationRealizationValidationError; use crate::core::simplex::SimplexValidationError; use crate::core::tds::{InvariantError, SimplexKey, TdsMutationError}; use crate::core::tds::{TdsConstructionError, TdsError, TriangulationConstructionState}; @@ -1190,12 +1190,12 @@ pub enum DelaunayConstructionFailure { source: DelaunayTriangulationValidationError, }, - /// Level 4 embedding validation failed during insertion. - #[error("embedding validation failed during insertion: {source}")] - InsertionEmbeddingValidation { - /// Underlying embedding validation error. + /// Level 4 realization validation failed during insertion. + #[error("realization validation failed during insertion: {source}")] + InsertionRealizationValidation { + /// Underlying realization validation error. #[source] - source: TriangulationEmbeddingValidationError, + source: TriangulationRealizationValidationError, }, /// Level 3 topology validation failed during insertion. @@ -1427,8 +1427,8 @@ impl From for DelaunayConstructionFailure { TriangulationConstructionError::InsertionDelaunayValidation { source } => { Self::InsertionDelaunayValidation { source } } - TriangulationConstructionError::InsertionEmbeddingValidation { source } => { - Self::InsertionEmbeddingValidation { source } + TriangulationConstructionError::InsertionRealizationValidation { source } => { + Self::InsertionRealizationValidation { source } } TriangulationConstructionError::InsertionTopologyValidation { context, source } => { Self::InsertionTopologyValidation { context, source } @@ -1509,7 +1509,7 @@ fn is_geometric_flip_error(error: &FlipError) -> bool { | FlipError::InsertedSimplexAlreadyExists { .. } | FlipError::FacetIteration { .. } | FlipError::PostconditionRepair { .. } - | FlipError::EmbeddingValidation { .. } + | FlipError::RealizationValidation { .. } | FlipError::NeighborWiring { .. } | FlipError::TdsMutation { .. } => false, } @@ -5409,7 +5409,7 @@ where | DelaunayConstructionFailure::CanonicalizedUnsupportedGlobalTopology { .. } | DelaunayConstructionFailure::PeriodicImageConflictingGlobalTopology { .. } | DelaunayConstructionFailure::SpatialIndexConstruction { .. } - | DelaunayConstructionFailure::InsertionEmbeddingValidation { .. } + | DelaunayConstructionFailure::InsertionRealizationValidation { .. } | DelaunayConstructionFailure::InsertionTopologyValidation { .. } | DelaunayConstructionFailure::LocalRepairBudgetExceeded { .. } | DelaunayConstructionFailure::ShuffledRetryExhausted { .. } @@ -5497,7 +5497,7 @@ where | InsertionError::Location(_) | InsertionError::NonManifoldTopology { .. } | InsertionError::HullExtension { .. } - | InsertionError::EmbeddingValidationFailed { .. } + | InsertionError::RealizationValidationFailed { .. } | InsertionError::DelaunayValidationFailed { .. } | InsertionError::DuplicateCoordinates { .. } | InsertionError::PerturbedCoordinateInvalid { .. }) => { @@ -5590,8 +5590,8 @@ where InsertionError::DelaunayValidationFailed { source } => { TriangulationConstructionError::InsertionDelaunayValidation { source } } - InsertionError::EmbeddingValidationFailed { source } => { - TriangulationConstructionError::InsertionEmbeddingValidation { source } + InsertionError::RealizationValidationFailed { source } => { + TriangulationConstructionError::InsertionRealizationValidation { source } } InsertionError::TopologyValidationFailed { context, source } => { TriangulationConstructionError::InsertionTopologyValidation { context, source } diff --git a/src/delaunay/flips.rs b/src/delaunay/flips.rs index cda57be3..8c604459 100644 --- a/src/delaunay/flips.rs +++ b/src/delaunay/flips.rs @@ -40,8 +40,8 @@ use crate::core::vertex::Vertex; use crate::geometry::kernel::Kernel; use crate::triangulation::DelaunayTriangulation; -/// Applies a high-level flip transaction and preserves topology/embedding invariants. -fn apply_embedded_flip( +/// Applies a high-level flip transaction and preserves topology/realization invariants. +fn apply_realized_flip( tri: &mut Triangulation, apply: impl FnOnce(&mut Triangulation) -> Result, FlipError>, ) -> Result, FlipError> @@ -69,9 +69,9 @@ where source: Box::new(error), }); } - if let Err(source) = transaction.triangulation_mut().validate_embedding() { + if let Err(source) = transaction.triangulation_mut().validate_realization() { transaction.rollback(); - return Err(FlipError::EmbeddingValidation { + return Err(FlipError::RealizationValidation { source: Box::new(source), }); } @@ -597,7 +597,7 @@ where simplex_key: SimplexKey, vertex: Vertex, ) -> Result, FlipError> { - apply_embedded_flip(self, |tri| { + apply_realized_flip(self, |tri| { apply_bistellar_flip_k1_raw(&mut tri.tds, simplex_key, vertex) }) } @@ -611,7 +611,7 @@ where } fn flip_k1_remove(&mut self, vertex_key: VertexKey) -> Result, FlipError> { - apply_embedded_flip(self, |tri| { + apply_realized_flip(self, |tri| { apply_bistellar_flip_k1_inverse_raw(&mut tri.tds, vertex_key) }) } @@ -621,7 +621,7 @@ where } fn flip_k2(&mut self, facet: FacetHandle) -> Result, FlipError> { - apply_embedded_flip(self, |tri| { + apply_realized_flip(self, |tri| { let context = build_k2_flip_context(&tri.tds, facet)?; apply_bistellar_flip_raw::(&mut tri.tds, &context) }) @@ -633,7 +633,7 @@ where } fn flip_k3(&mut self, ridge: RidgeHandle) -> Result, FlipError> { - apply_embedded_flip(self, |tri| { + apply_realized_flip(self, |tri| { let context = build_k3_flip_context(&tri.tds, ridge)?; apply_bistellar_flip_raw::(&mut tri.tds, &context) }) @@ -645,7 +645,7 @@ where } fn flip_k2_inverse_from_edge(&mut self, edge: EdgeKey) -> Result, FlipError> { - apply_embedded_flip(self, |tri| { + apply_realized_flip(self, |tri| { let context = build_k2_flip_context_from_edge(&tri.tds, edge)?; apply_bistellar_flip_dynamic_raw(&mut tri.tds, D, &context) }) @@ -667,7 +667,7 @@ where return Err(FlipError::UnsupportedDimension { dimension: D }); } - apply_embedded_flip(self, |tri| { + apply_realized_flip(self, |tri| { let context = build_k3_flip_context_from_triangle(&tri.tds, triangle)?; // Avoid const-eval underflow for invalid instantiations (e.g. D=0), even though @@ -801,8 +801,8 @@ where #[cfg(test)] mod tests { use super::*; - use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::facet::FacetError; + use crate::core::realization::TriangulationRealizationValidationError; use crate::vertex; use std::assert_matches; @@ -865,11 +865,11 @@ mod tests { assert_eq!(tri.tds.number_of_simplices(), before_simplices); assert!(tri.vertex_key_from_uuid(&inserted_uuid).is_none()); assert!(tri.validate().is_ok()); - assert!(tri.is_valid_embedding().is_ok()); + assert!(tri.is_valid_realization().is_ok()); } #[test] - fn embedded_flip_transaction_rolls_back_topology_validation_failure() { + fn realized_flip_transaction_rolls_back_topology_validation_failure() { let vertices = vec![ vertex!([0.0, 0.0]).unwrap(), vertex!([1.0, 0.0]).unwrap(), @@ -883,7 +883,7 @@ mod tests { let before_vertices = tri.tds.number_of_vertices(); let before_simplices = tri.tds.number_of_simplices(); - let err = apply_embedded_flip(&mut tri, |tri| { + let err = apply_realized_flip(&mut tri, |tri| { tri.tds .insert_vertex_with_mapping(vertex!([2.0, 2.0]).unwrap()) .unwrap(); @@ -900,13 +900,13 @@ mod tests { assert_matches!( err, - FlipError::EmbeddingValidation { source } - if matches!(*source, TriangulationEmbeddingValidationError::Triangulation(_)) + FlipError::RealizationValidation { source } + if matches!(*source, TriangulationRealizationValidationError::Triangulation(_)) ); assert_eq!(tri.tds.number_of_vertices(), before_vertices); assert_eq!(tri.tds.number_of_simplices(), before_simplices); assert!(tri.validate().is_ok()); - assert!(tri.validate_embedding().is_ok()); + assert!(tri.validate_realization().is_ok()); } #[test] diff --git a/src/delaunay/pachner.rs b/src/delaunay/pachner.rs index 0eb5c6c8..86fd5fba 100644 --- a/src/delaunay/pachner.rs +++ b/src/delaunay/pachner.rs @@ -437,11 +437,11 @@ impl PachnerProposal { /// Attempts this provenanced proposal while preserving topology-scope invariants only. /// /// This terminal method is intended for diagnostics and benchmarks that - /// deliberately validate Levels 1-3 without paying the Level 4 embedding + /// deliberately validate Levels 1-3 without paying the Level 4 realization /// overlap scan after every move. It still checks proposal provenance, /// revalidates the local bistellar move, and canonicalizes positive simplex /// orientation before committing. Use [`attempt_on`](Self::attempt_on) for - /// ordinary editing workflows that must preserve embedded-geometry validity. + /// ordinary editing workflows that must preserve realized-geometry validity. /// /// # Errors /// @@ -721,18 +721,18 @@ pub trait PachnerMoves: BistellarFlips + TopologyOwner { ) -> Result, FlipError>; } -/// Topology-scope Pachner execution that skips Level 4 embedding validation. +/// Topology-scope Pachner execution that skips Level 4 realization validation. /// /// This trait backs [`PachnerProposal::attempt_topology_on`]. It is intentionally -/// separate from [`BistellarFlips`], whose mutating methods preserve embedded +/// separate from [`BistellarFlips`], whose mutating methods preserve realized /// geometry after every committed move. Use this trait only for diagnostics, -/// stress tests, or benchmark workloads that validate embedding separately. +/// stress tests, or benchmark workloads that validate realization separately. #[doc(hidden)] pub trait TopologyPachnerMoves: TopologyOwner { /// User data type stored on vertices inserted through k=1 moves. type VertexData; - /// Apply a forward k=1 move without Level 4 embedding validation. + /// Apply a forward k=1 move without Level 4 realization validation. /// /// # Errors /// @@ -744,7 +744,7 @@ pub trait TopologyPachnerMoves: TopologyOwner { vertex: Vertex, ) -> Result, FlipError>; - /// Apply an inverse k=1 move without Level 4 embedding validation. + /// Apply an inverse k=1 move without Level 4 realization validation. /// /// # Errors /// @@ -752,7 +752,7 @@ pub trait TopologyPachnerMoves: TopologyOwner { /// applied atomically, or fails topology-scope postcondition repair. fn flip_k1_remove_topology(&mut self, vertex_key: VertexKey) -> Result, FlipError>; - /// Apply a forward k=2 move without Level 4 embedding validation. + /// Apply a forward k=2 move without Level 4 realization validation. /// /// # Errors /// @@ -760,7 +760,7 @@ pub trait TopologyPachnerMoves: TopologyOwner { /// applied atomically, or fails topology-scope postcondition repair. fn flip_k2_topology(&mut self, facet: FacetHandle) -> Result, FlipError>; - /// Apply an inverse k=2 move without Level 4 embedding validation. + /// Apply an inverse k=2 move without Level 4 realization validation. /// /// # Errors /// @@ -771,7 +771,7 @@ pub trait TopologyPachnerMoves: TopologyOwner { edge: EdgeKey, ) -> Result, FlipError>; - /// Apply a forward k=3 move without Level 4 embedding validation. + /// Apply a forward k=3 move without Level 4 realization validation. /// /// # Errors /// @@ -779,7 +779,7 @@ pub trait TopologyPachnerMoves: TopologyOwner { /// applied atomically, or fails topology-scope postcondition repair. fn flip_k3_topology(&mut self, ridge: RidgeHandle) -> Result, FlipError>; - /// Apply an inverse k=3 move without Level 4 embedding validation. + /// Apply an inverse k=3 move without Level 4 realization validation. /// /// # Errors /// diff --git a/src/delaunay/query.rs b/src/delaunay/query.rs index d4aa687f..e08c1b78 100644 --- a/src/delaunay/query.rs +++ b/src/delaunay/query.rs @@ -1683,8 +1683,8 @@ impl DelaunayTriangulation { /// [`DelaunayTriangulationValidationError::Triangulation`] when Level 3 /// topology violates the requested metadata, for example when Euclidean /// boundary facets are relabeled as closed spherical or toroidal topology, - /// [`DelaunayTriangulationValidationError::Embedding`] when Level 4 rejects - /// the requested embedding model, or + /// [`DelaunayTriangulationValidationError::Realization`] when Level 4 rejects + /// the requested realization model, or /// [`DelaunayTriangulationValidationError::VerificationFailed`] when Level 5 /// Delaunay validation fails. The previous topology metadata is restored /// before the error is returned. @@ -1717,7 +1717,7 @@ impl DelaunayTriangulation { Ok(()) => Ok(()), Err(InvariantError::Tds(err)) => Err(err.into()), Err(InvariantError::Triangulation(err)) => Err(err.into()), - Err(InvariantError::Embedding(err)) => Err(err.into()), + Err(InvariantError::Realization(err)) => Err(err.into()), Err(InvariantError::Delaunay(err)) => Err(err), } } diff --git a/src/delaunay/spherical.rs b/src/delaunay/spherical.rs index 26406b88..7058c16d 100644 --- a/src/delaunay/spherical.rs +++ b/src/delaunay/spherical.rs @@ -1,7 +1,7 @@ //! Prototype spherical Delaunay construction via ambient convex-hull duality. //! //! This module treats `D` as the intrinsic manifold dimension. Spherical points -//! live on `S^D`, embedded in `R^(D+1)`, and construction uses an ambient +//! live on `S^D`, realized in `R^(D+1)`, and construction uses an ambient //! Euclidean convex hull only as the duality engine. The returned simplices are //! intrinsic `D`-simplices on the sphere, not ambient `(D + 1)`-simplices. //! @@ -179,7 +179,7 @@ impl SphericalSimplex { /// /// This type stores normalized spherical points and hull-derived intrinsic /// simplices. Its validation surface follows the crate-wide layer model: -/// Level 3 is intrinsic PL topology, Level 4 is spherical embedding in +/// Level 3 is intrinsic PL topology, Level 4 is spherical realization in /// `S^D \subset R^(D+1)`, and Level 5 is the spherical Delaunay predicate via /// ambient convex-hull support. /// @@ -202,7 +202,7 @@ impl SphericalSimplex { /// .simplices() /// .iter() /// .all(|simplex| simplex.vertex_indices().len() == 3)); -/// assert!(triangulation.validate_embedding().is_ok()); +/// assert!(triangulation.validate_realization().is_ok()); /// assert!(triangulation.validate_delaunay().is_ok()); /// # Ok::<(), delaunay::prelude::construction::SphericalDelaunayConstructionError>(()) /// ``` @@ -501,10 +501,10 @@ impl SphericalDelaunayTriangulation { self.validate_topology() } - /// Checks the prototype Level 4 spherical embedding. + /// Checks the prototype Level 4 spherical realization. /// /// This fast-fail wrapper matches the crate-wide validation naming surface - /// and delegates to [`validate_embedding`](Self::validate_embedding). + /// and delegates to [`validate_realization`](Self::validate_realization). /// /// # Errors /// @@ -524,11 +524,11 @@ impl SphericalDelaunayTriangulation { /// [-1.0, -1.0, 1.0], /// ])?.build()?; /// - /// std::assert_matches!(triangulation.is_valid_embedding(), Ok(())); + /// std::assert_matches!(triangulation.is_valid_realization(), Ok(())); /// # Ok::<(), SphericalDelaunayConstructionError>(()) /// ``` - pub fn is_valid_embedding(&self) -> Result<(), SphericalDelaunayValidationError> { - self.validate_embedding() + pub fn is_valid_realization(&self) -> Result<(), SphericalDelaunayValidationError> { + self.validate_realization() } /// Checks the prototype Level 5 spherical Delaunay predicate. @@ -663,7 +663,7 @@ impl SphericalDelaunayTriangulation { /// Validates intrinsic PL topology through the crate's topology validators. /// /// Spherical coordinates live in `R^(D+1)`, but Level 3 is intentionally - /// embedding-independent. This bridge therefore builds a temporary abstract + /// realization-independent. This bridge therefore builds a temporary abstract /// TDS with synthetic finite coordinates, then runs the same combinatorial /// connectedness, closed-boundary, link, and Euler checks used by ordinary /// triangulations without invoking Euclidean orientation validation. @@ -772,10 +772,10 @@ impl SphericalDelaunayTriangulation { Ok(()) } - /// Validates the prototype Level 4 spherical embedding. + /// Validates the prototype Level 4 spherical realization. /// /// The intrinsic PL topology is still checked by - /// [`validate_topology`](Self::validate_topology). The spherical embedding + /// [`validate_topology`](Self::validate_topology). The spherical realization /// layer then checks that each maximal simplex is a nondegenerate geodesic /// simplex on `S^D` by requiring the ambient hyperplane through its /// vertices not to contain the sphere center. @@ -798,16 +798,16 @@ impl SphericalDelaunayTriangulation { /// [-1.0, -1.0, 1.0], /// ])?.build()?; /// - /// std::assert_matches!(triangulation.validate_embedding(), Ok(())); + /// std::assert_matches!(triangulation.validate_realization(), Ok(())); /// # Ok::<(), SphericalDelaunayConstructionError>(()) /// ``` - pub fn validate_embedding(&self) -> Result<(), SphericalDelaunayValidationError> { + pub fn validate_realization(&self) -> Result<(), SphericalDelaunayValidationError> { self.validate_topology()?; match D { - 2 => self.validate_embedding_with_ambient::<3>(), - 3 => self.validate_embedding_with_ambient::<4>(), + 2 => self.validate_realization_with_ambient::<3>(), + 3 => self.validate_realization_with_ambient::<4>(), _ => Err(SphericalDelaunayValidationError::UnsupportedLayer { - layer: SphericalValidationLayer::Embedding, + layer: SphericalValidationLayer::Realization, dimension: D, tracking_issue: SPHERICAL_ROADMAP_ISSUE, }), @@ -844,7 +844,7 @@ impl SphericalDelaunayTriangulation { /// # Ok::<(), SphericalDelaunayConstructionError>(()) /// ``` pub fn validate_delaunay(&self) -> Result<(), SphericalDelaunayValidationError> { - self.validate_embedding()?; + self.validate_realization()?; match D { 2 => self.validate_delaunay_with_ambient::<3>(), 3 => self.validate_delaunay_with_ambient::<4>(), @@ -858,10 +858,10 @@ impl SphericalDelaunayTriangulation { /// Validates each simplex as nondegenerate for Level 4. /// - /// This helper backs the public spherical embedding contract: every simplex + /// This helper backs the public spherical realization contract: every simplex /// must determine an ambient hyperplane that separates the simplex from the /// sphere center. - fn validate_embedding_with_ambient( + fn validate_realization_with_ambient( &self, ) -> Result<(), SphericalDelaunayValidationError> { Self::validate_ambient_dimension::()?; @@ -1355,8 +1355,8 @@ impl SphericalDelaunayBuilder { source: Box::new(source), } })?; - spherical.validate_embedding().map_err(|source| { - SphericalDelaunayConstructionError::EmbeddingValidation { + spherical.validate_realization().map_err(|source| { + SphericalDelaunayConstructionError::RealizationValidation { source: Box::new(source), } })?; @@ -1396,7 +1396,7 @@ impl SphericalDelaunayBuilder { /// Builds finite, distinct coordinates for the temporary abstract topology TDS. /// -/// These coordinates have no embedding meaning. They only let the existing TDS +/// These coordinates have no realization meaning. They only let the existing TDS /// element constructors carry vertex identities through intrinsic PL topology /// validators that operate on the abstract simplicial complex. fn synthetic_topology_coordinates( @@ -1662,9 +1662,9 @@ pub enum SphericalDelaunayConstructionError { source: Box, }, - /// Level 4 spherical embedding validation failed after construction. - #[error("spherical embedding validation failed after construction: {source}")] - EmbeddingValidation { + /// Level 4 spherical realization validation failed after construction. + #[error("spherical realization validation failed after construction: {source}")] + RealizationValidation { /// Underlying validation error. #[source] source: Box, @@ -1683,8 +1683,8 @@ pub enum SphericalDelaunayConstructionError { #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] pub enum SphericalValidationLayer { - /// Level 4 curved embedding validation. - Embedding, + /// Level 4 curved realization validation. + Realization, /// Level 5 spherical Delaunay predicate validation. Delaunay, } @@ -1692,7 +1692,7 @@ pub enum SphericalValidationLayer { impl fmt::Display for SphericalValidationLayer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Embedding => f.write_str("Level 4 Embedding Validity"), + Self::Realization => f.write_str("Level 4 Spherical Realization"), Self::Delaunay => f.write_str("Level 5 Geometric Predicates"), } } @@ -2165,9 +2165,9 @@ mod tests { .validate_topology() .expect("5-simplex boundary is intrinsically S4"); assert_matches!( - triangulation.validate_embedding(), + triangulation.validate_realization(), Err(SphericalDelaunayValidationError::UnsupportedLayer { - layer: SphericalValidationLayer::Embedding, + layer: SphericalValidationLayer::Realization, dimension: 4, tracking_issue: SPHERICAL_ROADMAP_ISSUE, }) @@ -2201,8 +2201,8 @@ mod tests { .validate_topology() .expect("flipped fixture remains a closed PL sphere"); triangulation - .validate_embedding() - .expect("flipped fixture remains a spherical embedding"); + .validate_realization() + .expect("flipped fixture remains a spherical realization"); assert_matches!( triangulation.validate_delaunay(), Err(SphericalDelaunayValidationError::NonSupportingSimplex { .. }) @@ -2233,7 +2233,7 @@ mod tests { .validate_topology() .expect("fixture is combinatorially a closed sphere"); assert_matches!( - triangulation.validate_embedding(), + triangulation.validate_realization(), Err( SphericalDelaunayValidationError::SimplexHyperplaneContainsOrigin { simplex_index: 0, diff --git a/src/delaunay/validation.rs b/src/delaunay/validation.rs index c44aafac..764a22e2 100644 --- a/src/delaunay/validation.rs +++ b/src/delaunay/validation.rs @@ -12,8 +12,8 @@ use crate::core::algorithms::flips::{ DelaunayRepairError, verify_triangulation_via_flip_predicates, }; use crate::core::algorithms::incremental_insertion::InsertionError; -use crate::core::embedding::TriangulationEmbeddingValidationError; use crate::core::operations::DelaunayInsertionState; +use crate::core::realization::TriangulationRealizationValidationError; use crate::core::tds::{ InvariantError, InvariantKind, InvariantViolation, SimplexKey, Tds, TdsError, TriangulationValidationReport, @@ -45,9 +45,9 @@ pub(crate) struct TdsStructureValidationProof(()); #[derive(Clone, Copy, Debug)] pub(crate) struct DelaunayTriangulationValidationProof(()); -/// Proof that a candidate passed Levels 1-4 through embedded-geometry validation. +/// Proof that a candidate passed Levels 1-4 through realized-geometry validation. #[derive(Clone, Copy, Debug)] -pub(crate) struct TriangulationEmbeddingValidationProof(()); +pub(crate) struct TriangulationRealizationValidationProof(()); /// Internal assembly stage for a triangulation that has not crossed its validation boundary yet. /// @@ -117,9 +117,9 @@ impl DelaunayTriangulationCandidate { } /// Converts a candidate after the caller has proved Levels 1-4 validity. - pub(crate) fn into_embedding_validated_delaunay( + pub(crate) fn into_realization_validated_delaunay( self, - _proof: TriangulationEmbeddingValidationProof, + _proof: TriangulationRealizationValidationProof, ) -> DelaunayTriangulation { self.candidate } @@ -170,13 +170,13 @@ where /// This preserves the public reconstruction contract for /// [`DelaunayTriangulation`]: a candidate cannot cross the boundary until /// its underlying [`Triangulation`] passes Levels 1-3 validation. Euclidean - /// candidates additionally pass Level 4 embedded-geometry validation before + /// candidates additionally pass Level 4 realized-geometry validation before /// the Level 5 Delaunay property is checked with the topology-appropriate /// validator. pub(crate) fn validate_delaunay_property( &self, ) -> Result { - self.candidate.tri.validate_embedding()?; + self.candidate.tri.validate_realization()?; if self.candidate.global_topology().is_euclidean() { is_delaunay_property_only(&self.candidate.tri.tds).map_err(|source| { @@ -192,11 +192,11 @@ where } /// Validates Levels 1-4 without enforcing the Level 5 Delaunay property. - pub(crate) fn validate_embedding_only( + pub(crate) fn validate_realization_only( &self, - ) -> Result { - self.candidate.tri.validate_embedding()?; - Ok(TriangulationEmbeddingValidationProof(())) + ) -> Result { + self.candidate.tri.validate_realization()?; + Ok(TriangulationRealizationValidationProof(())) } } @@ -309,7 +309,7 @@ impl From<&DelaunayVerificationError> for DelaunayVerificationErrorKind { /// (validation Levels 1-5): /// - [`Tds`](Self::Tds) β€” element or TDS structural errors (Levels 1–2). /// - [`Triangulation`](Self::Triangulation) β€” topology errors (Level 3). -/// - [`Embedding`](Self::Embedding) β€” embedded-geometry errors (Level 4). +/// - [`Realization`](Self::Realization) β€” realized-geometry errors (Level 4). /// - [`VerificationFailed`](Self::VerificationFailed) β€” Delaunay property violation (Level 5). /// /// [`DelaunayTriangulation::is_valid_delaunay`](crate::DelaunayTriangulation::is_valid_delaunay) returns only the Level 5 @@ -356,9 +356,9 @@ pub enum DelaunayTriangulationValidationError { #[error(transparent)] Triangulation(Box), - /// Lower-layer embedded-geometry validation error (Level 4). + /// Lower-layer realized-geometry validation error (Level 4). #[error(transparent)] - Embedding(Box), + Realization(Box), /// Flip-based Delaunay verification detected a violation. /// @@ -407,14 +407,14 @@ impl From for DelaunayTriangulationValidationError } } -impl From for DelaunayTriangulationValidationError { - fn from(source: TriangulationEmbeddingValidationError) -> Self { +impl From for DelaunayTriangulationValidationError { + fn from(source: TriangulationRealizationValidationError) -> Self { match source { - TriangulationEmbeddingValidationError::Tds(source) => Self::Tds(source), - TriangulationEmbeddingValidationError::Triangulation(source) => { + TriangulationRealizationValidationError::Tds(source) => Self::Tds(source), + TriangulationRealizationValidationError::Triangulation(source) => { Self::Triangulation(source) } - source => Self::Embedding(Box::new(source)), + source => Self::Realization(Box::new(source)), } } } @@ -782,13 +782,13 @@ where /// Performs cumulative validation for Levels 1–5. /// /// This validates: - /// - **Levels 1–4** via [`Triangulation::validate_embedding`](crate::Triangulation::validate_embedding) + /// - **Levels 1–4** via [`Triangulation::validate_realization`](crate::Triangulation::validate_realization) /// - **Level 5** via [`DelaunayTriangulation::is_valid_delaunay`](Self::is_valid_delaunay) /// /// # Errors /// /// Returns a [`DelaunayTriangulationValidationError`] if lower-layer validation fails, if - /// Euclidean embedded-geometry validation fails, or if the Delaunay property check (Level 5) + /// Level 4 realized-geometry validation fails, or if the Delaunay property check (Level 5) /// fails. /// /// # Examples @@ -807,13 +807,13 @@ where /// ]; /// let dt = DelaunayTriangulationBuilder::new(&vertices_4d).build()?; /// - /// // Levels 1–5: elements + structure + topology + embedding + Delaunay property + /// // Levels 1–5: elements + structure + topology + realization + Delaunay property /// assert!(dt.validate().is_ok()); /// # Ok(()) /// # } /// ``` pub fn validate(&self) -> Result<(), DelaunayTriangulationValidationError> { - self.tri.validate_embedding()?; + self.tri.validate_realization()?; self.is_valid_delaunay() } @@ -856,21 +856,20 @@ where // Levels 1–3: reuse the Triangulation layer report. match self.tri.validation_report() { Ok(()) => { - // Level 4 (embedded geometry) - let embedding_report = - self.tri - .embedding_report() - .map_err(|error| TriangulationValidationReport { - violations: vec![InvariantViolation { - kind: InvariantKind::Embedding, - error: error.into(), - }], - })?; + // Level 4 (realized geometry) + let realization_report = self.tri.realization_report().map_err(|error| { + TriangulationValidationReport { + violations: vec![InvariantViolation { + kind: InvariantKind::Realization, + error: error.into(), + }], + } + })?; let mut violations = Vec::new(); - if !embedding_report.is_valid() { - violations.extend(embedding_report.violations.into_iter().map(|error| { + if !realization_report.is_valid() { + violations.extend(realization_report.violations.into_iter().map(|error| { InvariantViolation { - kind: InvariantKind::Embedding, + kind: InvariantKind::Realization, error: error.into(), } })); @@ -898,22 +897,22 @@ where return Err(report); } - // Level 4 (embedded geometry) - match self.tri.embedding_report() { - Ok(embedding_report) => { + // Level 4 (realized geometry) + match self.tri.realization_report() { + Ok(realization_report) => { report .violations - .extend(embedding_report.violations.into_iter().map(|error| { + .extend(realization_report.violations.into_iter().map(|error| { InvariantViolation { - kind: InvariantKind::Embedding, - error: InvariantError::Embedding(error), + kind: InvariantKind::Realization, + error: InvariantError::Realization(error), } })); } Err(source) => { report.violations.push(InvariantViolation { - kind: InvariantKind::Embedding, - error: InvariantError::Embedding(source), + kind: InvariantKind::Realization, + error: InvariantError::Realization(source), }); } } @@ -960,7 +959,7 @@ where /// via `try_from_tds` validates with [`GlobalTopology::Euclidean`]. Use /// [`try_from_tds_with_topology_context`](Self::try_from_tds_with_topology_context) if you /// need to validate toroidal or other non-default topology metadata during reconstruction. - /// - Euclidean reconstruction validates Level 4 embedded geometry, then + /// - Euclidean reconstruction validates Level 4 realized geometry, then /// validates Level 5 with the crate's robust empty-circumsphere validator, /// independent of the supplied runtime kernel. The supplied kernel is /// stored for later queries and insertions. @@ -994,7 +993,7 @@ where /// # Errors /// /// Returns [`DelaunayTriangulationValidationError`] if the TDS violates - /// structural, topological, embedded-geometry, or Delaunay invariants. + /// structural, topological, realized-geometry, or Delaunay invariants. pub fn try_from_tds( tds: Tds, kernel: K, @@ -1046,7 +1045,7 @@ where /// # Errors /// /// Returns [`DelaunayTriangulationValidationError`] if the TDS violates - /// structural, topological, embedded-geometry, or Delaunay invariants. + /// structural, topological, realized-geometry, or Delaunay invariants. pub fn try_from_tds_with_topology_guarantee( tds: Tds, kernel: K, @@ -1102,7 +1101,7 @@ where /// # Errors /// /// Returns [`DelaunayTriangulationValidationError`] if the TDS violates - /// structural, topological, embedded-geometry, or Delaunay invariants under + /// structural, topological, realized-geometry, or Delaunay invariants under /// the supplied topology context. pub fn try_from_tds_with_topology_context( tds: Tds, @@ -1530,7 +1529,7 @@ mod tests { } #[test] - fn validation_report_includes_delaunay_after_embedding_violations() { + fn validation_report_includes_delaunay_after_realization_violations() { init_tracing(); let tds = tds_from_2d_vertices_and_simplices( &[[0.0, 0.0], [2.0, 0.0], [0.0, 2.0], [2.0, 2.0], [1.0, -1.0]], @@ -1544,8 +1543,8 @@ mod tests { report .violations .iter() - .any(|v| v.kind == InvariantKind::Embedding), - "expected embedding violation in report: {report:?}" + .any(|v| v.kind == InvariantKind::Realization), + "expected realization violation in report: {report:?}" ); assert!( report diff --git a/src/geometry/algorithms/convex_hull.rs b/src/geometry/algorithms/convex_hull.rs index 86bfa209..3b436b71 100644 --- a/src/geometry/algorithms/convex_hull.rs +++ b/src/geometry/algorithms/convex_hull.rs @@ -328,7 +328,7 @@ pub enum ConvexHullConstructionError { /// let hull = ConvexHull::try_from_triangulation(dt.as_triangulation())?; /// assert!(hull.is_valid_for_triangulation(dt.as_triangulation())); // Valid initially /// -/// // Hull extension is now implemented - inserting outside points works! +/// // Mutating the triangulation leaves this detached hull snapshot stale. /// dt.insert_vertex(vertex![2.0, 2.0, 2.0]?)?; /// # Ok(()) /// # } @@ -375,10 +375,10 @@ pub enum ConvexHullConstructionError { /// assert_eq!(hull.number_of_facets(), 4); /// assert!(hull.is_valid_for_triangulation(dt.as_triangulation())); /// -/// // Hull extension is now implemented - inserting outside points works! -/// // Note: The hull becomes invalid after modification and needs to be recreated +/// // Inserting a vertex mutates the triangulation; the hull must be recreated +/// // before using it against the new TDS state. /// let new_vertex = vertex![2.0, 2.0, 2.0]?; -/// dt.insert_vertex(new_vertex)?; // Now works with hull extension! +/// dt.insert_vertex(new_vertex)?; /// assert!(!hull.is_valid_for_triangulation(dt.as_triangulation())); // Hull is stale /// # Ok(()) /// # } @@ -830,9 +830,8 @@ impl ConvexHull { /// let hull = ConvexHull::try_from_triangulation(dt.as_triangulation())?; /// assert!(hull.is_valid_for_triangulation(dt.as_triangulation())); /// - /// // After any modification to the triangulation, the hull would become invalid - /// // Note: Currently, hull extension is not yet implemented, so inserting - /// // outside points will cause an error. This demonstrates the validation concept. + /// // After any modification to the triangulation, the hull would become invalid. + /// // Rebuild the hull before using it against the modified TDS state. /// # Ok(()) /// # } /// ``` diff --git a/src/geometry/embedding.rs b/src/geometry/realization.rs similarity index 79% rename from src/geometry/embedding.rs rename to src/geometry/realization.rs index a7d5256a..9c6b773a 100644 --- a/src/geometry/embedding.rs +++ b/src/geometry/realization.rs @@ -1,12 +1,12 @@ -//! Pure predicates for labeled simplex embeddings. +//! Pure predicates for labeled simplex realizations. //! //! This module has no TDS, topology, or triangulation storage dependencies. It //! answers geometric questions about labeled maximal simplices after another //! layer has chosen the appropriate affine chart. Algorithmic provenance for //! the Level 4 overlap broad phase is summarized in `REFERENCES.md`, -//! "Embedded-Geometry Overlap Detection (Level 4 Validation)". +//! "Realized-Simplex Overlap Detection (Level 4 Validation)". //! -//! Use [`Triangulation::embedding_report`](crate::Triangulation::embedding_report) +//! Use [`Triangulation::realization_report`](crate::Triangulation::realization_report) //! when validating a stored triangulation. Use this module directly when a //! caller already has chart-local simplex coordinates and wants the pure //! geometric Level 4 predicate without TDS storage. @@ -15,22 +15,22 @@ //! //! ```rust //! use delaunay::prelude::geometry::{ -//! LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, SimplexIntersectionFailure, -//! validate_simplex_embeddings_intersect_only_in_shared_faces, +//! LabeledSimplexRealization, LabeledSimplexRealizationError, SimplexIntersectionFailure, +//! validate_simplex_realizations_intersect_only_in_shared_faces, //! }; //! -//! # fn main() -> Result<(), LabeledSimplexEmbeddingError> { -//! let first = LabeledSimplexEmbedding::try_new( +//! # fn main() -> Result<(), LabeledSimplexRealizationError> { +//! let first = LabeledSimplexRealization::try_new( //! [0_usize, 1, 2], //! [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], //! )?; -//! let second = LabeledSimplexEmbedding::try_new( +//! let second = LabeledSimplexRealization::try_new( //! [0_usize, 1, 3], //! [[0.0, 0.0], [1.0, 0.0], [0.25, 0.25]], //! )?; //! //! std::assert_matches!( -//! validate_simplex_embeddings_intersect_only_in_shared_faces(&first, &second), +//! validate_simplex_realizations_intersect_only_in_shared_faces(&first, &second), //! Err(SimplexIntersectionFailure::IntersectionOutsideSharedFace { .. }) //! ); //! # Ok(()) @@ -45,49 +45,49 @@ use crate::geometry::traits::coordinate::InvalidCoordinateValue; use la_stack::{BigInt, BigRational, FromPrimitive, Signed}; use thiserror::Error; -/// Stack-backed buffer for per-simplex embedding labels and coordinates. -pub type SimplexEmbeddingBuffer = SmallBuffer; +/// Stack-backed buffer for per-simplex realization labels and coordinates. +pub type SimplexRealizationBuffer = SmallBuffer; /// Validated coordinates for one labeled D-simplex in an affine chart. /// /// Labels implement [`Eq`] and are unique within the simplex so intersection /// witnesses can distinguish shared faces from accidental duplicate vertices. /// Coordinates are finite `f64` values ready to be converted into exact -/// predicate inputs by the triangulation-level embedding validator. +/// predicate inputs by the triangulation-level realization validator. #[derive(Clone, Debug, PartialEq)] -pub struct LabeledSimplexEmbedding { - labels: SimplexEmbeddingBuffer, - coordinates: SimplexEmbeddingBuffer<[f64; D]>, +pub struct LabeledSimplexRealization { + labels: SimplexRealizationBuffer, + coordinates: SimplexRealizationBuffer<[f64; D]>, } -impl LabeledSimplexEmbedding { - /// Builds a labeled D-simplex embedding after checking arity, uniqueness, and finite coordinates. +impl LabeledSimplexRealization { + /// Builds a labeled D-simplex realization after checking arity, uniqueness, and finite coordinates. /// - /// This is the parse boundary for pure simplex-embedding predicates: callers + /// This is the parse boundary for pure simplex-realization predicates: callers /// supply labels and coordinates in matching order, and the constructor - /// stores only embeddings with exactly `D + 1` distinct labels. Labels use + /// stores only realizations with exactly `D + 1` distinct labels. Labels use /// [`Eq`] because they represent vertex identity, not an approximate value. /// /// # Errors /// - /// Returns [`LabeledSimplexEmbeddingError::LabelCoordinateLengthMismatch`] + /// Returns [`LabeledSimplexRealizationError::LabelCoordinateLengthMismatch`] /// when the two iterators produce different lengths, - /// [`LabeledSimplexEmbeddingError::InvalidArity`] when the simplex does not + /// [`LabeledSimplexRealizationError::InvalidArity`] when the simplex does not /// contain exactly `D + 1` vertices, - /// [`LabeledSimplexEmbeddingError::DuplicateLabel`] when a label appears + /// [`LabeledSimplexRealizationError::DuplicateLabel`] when a label appears /// more than once, or - /// [`LabeledSimplexEmbeddingError::NonFiniteCoordinate`] when any coordinate + /// [`LabeledSimplexRealizationError::NonFiniteCoordinate`] when any coordinate /// is NaN or infinite. /// /// # Examples /// /// ```rust /// use delaunay::prelude::geometry::{ - /// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, + /// LabeledSimplexRealization, LabeledSimplexRealizationError, /// }; /// - /// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { - /// let simplex = LabeledSimplexEmbedding::try_new( + /// # fn main() -> Result<(), LabeledSimplexRealizationError> { + /// let simplex = LabeledSimplexRealization::try_new( /// ["a", "b", "c"], /// [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], /// )?; @@ -100,16 +100,16 @@ impl LabeledSimplexEmbedding { pub fn try_new( labels: impl IntoIterator, coordinates: impl IntoIterator, - ) -> Result + ) -> Result where L: Eq, { - let labels: SimplexEmbeddingBuffer = labels.into_iter().collect(); - let coordinates: SimplexEmbeddingBuffer<[f64; D]> = coordinates.into_iter().collect(); + let labels: SimplexRealizationBuffer = labels.into_iter().collect(); + let coordinates: SimplexRealizationBuffer<[f64; D]> = coordinates.into_iter().collect(); if labels.len() != coordinates.len() { return Err( - LabeledSimplexEmbeddingError::LabelCoordinateLengthMismatch { + LabeledSimplexRealizationError::LabelCoordinateLengthMismatch { label_count: labels.len(), coordinate_count: coordinates.len(), }, @@ -118,7 +118,7 @@ impl LabeledSimplexEmbedding { let expected = D + 1; if labels.len() != expected { - return Err(LabeledSimplexEmbeddingError::InvalidArity { + return Err(LabeledSimplexRealizationError::InvalidArity { expected, actual: labels.len(), }); @@ -129,7 +129,7 @@ impl LabeledSimplexEmbedding { .iter() .position(|label| label == first_label) { - return Err(LabeledSimplexEmbeddingError::DuplicateLabel { + return Err(LabeledSimplexRealizationError::DuplicateLabel { first_index, duplicate_index: first_index + duplicate_offset + 1, }); @@ -150,11 +150,11 @@ impl LabeledSimplexEmbedding { /// /// ```rust /// use delaunay::prelude::geometry::{ - /// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, + /// LabeledSimplexRealization, LabeledSimplexRealizationError, /// }; /// - /// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { - /// let simplex = LabeledSimplexEmbedding::try_new( + /// # fn main() -> Result<(), LabeledSimplexRealizationError> { + /// let simplex = LabeledSimplexRealization::try_new( /// ["left", "right", "apex"], /// [[0.0, 0.0], [1.0, 0.0], [0.5, 1.0]], /// )?; @@ -174,11 +174,11 @@ impl LabeledSimplexEmbedding { /// ```rust /// use approx::assert_abs_diff_eq; /// use delaunay::prelude::geometry::{ - /// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, + /// LabeledSimplexRealization, LabeledSimplexRealizationError, /// }; /// - /// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { - /// let simplex = LabeledSimplexEmbedding::try_new( + /// # fn main() -> Result<(), LabeledSimplexRealizationError> { + /// let simplex = LabeledSimplexRealization::try_new( /// [0_usize, 1, 2], /// [[0.0, 0.0], [1.0, 0.0], [0.5, 1.0]], /// )?; @@ -201,29 +201,29 @@ impl LabeledSimplexEmbedding { }) } - /// Returns an embedding translated by integer multiples of the periodic domain. + /// Returns a realization translated by integer multiples of the periodic domain. /// /// The translated coordinates are re-validated so overflow to non-finite - /// values becomes a typed embedding error rather than a hidden predicate + /// values becomes a typed realization error rather than a hidden predicate /// input. /// /// # Errors /// - /// Returns [`LabeledSimplexEmbeddingError::InvalidPeriodicDomainPeriod`] if a + /// Returns [`LabeledSimplexRealizationError::InvalidPeriodicDomainPeriod`] if a /// period is non-finite or non-positive, or - /// [`LabeledSimplexEmbeddingError::NonFiniteCoordinate`] if translating by + /// [`LabeledSimplexRealizationError::NonFiniteCoordinate`] if translating by /// `shift * period` produces a NaN or infinite coordinate. /// /// # Examples /// /// ```rust /// use delaunay::prelude::geometry::{ - /// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, + /// LabeledSimplexRealization, LabeledSimplexRealizationError, /// }; /// use approx::assert_abs_diff_eq; /// - /// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { - /// let simplex = LabeledSimplexEmbedding::try_new( + /// # fn main() -> Result<(), LabeledSimplexRealizationError> { + /// let simplex = LabeledSimplexRealization::try_new( /// [0_usize, 1, 2], /// [[0.0, 0.0], [0.5, 0.0], [0.0, 0.5]], /// )?; @@ -238,7 +238,7 @@ impl LabeledSimplexEmbedding { &self, periods: &[f64; D], shift: &[i32; D], - ) -> Result + ) -> Result where L: Clone, { @@ -260,12 +260,12 @@ impl LabeledSimplexEmbedding { /// Validates translated or newly parsed coordinate rows before predicate use. fn validate_coordinate_rows( - coordinates: &SimplexEmbeddingBuffer<[f64; D]>, -) -> Result<(), LabeledSimplexEmbeddingError> { + coordinates: &SimplexRealizationBuffer<[f64; D]>, +) -> Result<(), LabeledSimplexRealizationError> { for (vertex_index, coords) in coordinates.iter().enumerate() { for (coordinate_index, coordinate) in coords.iter().enumerate() { if !coordinate.is_finite() { - return Err(LabeledSimplexEmbeddingError::NonFiniteCoordinate { + return Err(LabeledSimplexRealizationError::NonFiniteCoordinate { vertex_index, coordinate_index, coordinate_value: InvalidCoordinateValue::from_debug(coordinate), @@ -276,10 +276,10 @@ fn validate_coordinate_rows( Ok(()) } -/// Errors produced while parsing a labeled simplex embedding. +/// Errors produced while parsing a labeled simplex realization. #[derive(Clone, Debug, Error, PartialEq)] #[non_exhaustive] -pub enum LabeledSimplexEmbeddingError { +pub enum LabeledSimplexRealizationError { /// The label and coordinate iterators produced different lengths. #[error("label count {label_count} does not match coordinate count {coordinate_count}")] LabelCoordinateLengthMismatch { @@ -288,8 +288,8 @@ pub enum LabeledSimplexEmbeddingError { /// Number of coordinate rows supplied by the caller. coordinate_count: usize, }, - /// The embedding did not contain exactly D + 1 vertices. - #[error("invalid simplex embedding arity: expected {expected}, got {actual}")] + /// The realization did not contain exactly D + 1 vertices. + #[error("invalid simplex realization arity: expected {expected}, got {actual}")] InvalidArity { /// Required vertex count for one maximal D-simplex. expected: usize, @@ -297,7 +297,7 @@ pub enum LabeledSimplexEmbeddingError { actual: usize, }, /// A simplex label appeared more than once. - #[error("duplicate simplex embedding label at indices {first_index} and {duplicate_index}")] + #[error("duplicate simplex realization label at indices {first_index} and {duplicate_index}")] DuplicateLabel { /// First index containing the duplicated label. first_index: usize, @@ -347,15 +347,15 @@ pub enum PeriodicSimplexSpanError { }, } -/// Barycentric witness showing where two simplex embeddings overlap illegally. +/// Barycentric witness showing where two simplex realizations overlap illegally. #[derive(Clone, Debug, Eq, PartialEq)] pub struct SimplexIntersectionWitness { - /// Labels appearing in both simplex embeddings. - pub shared: SimplexEmbeddingBuffer, + /// Labels appearing in both simplex realizations. + pub shared: SimplexRealizationBuffer, /// Labels from the first simplex with positive witness weight outside the shared face. - pub first_only_witness: SimplexEmbeddingBuffer, + pub first_only_witness: SimplexRealizationBuffer, /// Labels from the second simplex with positive witness weight outside the shared face. - pub second_only_witness: SimplexEmbeddingBuffer, + pub second_only_witness: SimplexRealizationBuffer, } /// Failure modes for exact simplex-intersection validation. @@ -413,12 +413,12 @@ impl PeriodicSimplexSpan { /// /// ```rust /// use delaunay::prelude::geometry::{ -/// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, coordinate_range_for_axis, +/// LabeledSimplexRealization, LabeledSimplexRealizationError, coordinate_range_for_axis, /// }; /// use approx::abs_diff_eq; /// -/// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { -/// let simplex = LabeledSimplexEmbedding::try_new( +/// # fn main() -> Result<(), LabeledSimplexRealizationError> { +/// let simplex = LabeledSimplexRealization::try_new( /// [0_usize, 1, 2], /// [[-1.0, 0.0], [2.0, 0.5], [0.0, 1.0]], /// )?; @@ -434,7 +434,7 @@ impl PeriodicSimplexSpan { /// # } /// ``` pub fn coordinate_range_for_axis( - simplex: &LabeledSimplexEmbedding, + simplex: &LabeledSimplexRealization, axis: usize, ) -> Option<(f64, f64)> { if axis >= D { @@ -457,16 +457,16 @@ pub fn coordinate_range_for_axis( /// /// ```rust /// use delaunay::prelude::geometry::{ -/// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, +/// LabeledSimplexRealization, LabeledSimplexRealizationError, /// axis_aligned_bounding_boxes_overlap, /// }; /// -/// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { -/// let first = LabeledSimplexEmbedding::try_new( +/// # fn main() -> Result<(), LabeledSimplexRealizationError> { +/// let first = LabeledSimplexRealization::try_new( /// [0_usize, 1, 2], /// [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], /// )?; -/// let second = LabeledSimplexEmbedding::try_new( +/// let second = LabeledSimplexRealization::try_new( /// [3_usize, 4, 5], /// [[2.0, 2.0], [3.0, 2.0], [2.0, 3.0]], /// )?; @@ -476,8 +476,8 @@ pub fn coordinate_range_for_axis( /// # } /// ``` pub fn axis_aligned_bounding_boxes_overlap( - first: &LabeledSimplexEmbedding, - second: &LabeledSimplexEmbedding, + first: &LabeledSimplexRealization, + second: &LabeledSimplexRealization, ) -> bool { (0..D).all(|axis| { let Some((first_min, first_max)) = coordinate_range_for_axis(first, axis) else { @@ -501,20 +501,20 @@ pub fn axis_aligned_bounding_boxes_overlap( /// /// ```rust /// use delaunay::prelude::geometry::{ -/// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, +/// LabeledSimplexRealization, LabeledSimplexRealizationError, /// PeriodicSimplexSpanError, try_periodic_simplex_span, /// }; /// /// #[derive(Debug, thiserror::Error)] /// enum ExampleError { /// #[error(transparent)] -/// Embedding(#[from] LabeledSimplexEmbeddingError), +/// Realization(#[from] LabeledSimplexRealizationError), /// #[error(transparent)] /// PeriodicSpan(#[from] PeriodicSimplexSpanError), /// } /// /// # fn main() -> Result<(), ExampleError> { -/// let simplex = LabeledSimplexEmbedding::try_new( +/// let simplex = LabeledSimplexRealization::try_new( /// [0_usize, 1, 2], /// [[0.0, 0.0], [1.0, 0.0], [0.0, 0.25]], /// )?; @@ -525,7 +525,7 @@ pub fn axis_aligned_bounding_boxes_overlap( /// # } /// ``` pub fn try_periodic_simplex_span( - simplex: &LabeledSimplexEmbedding, + simplex: &LabeledSimplexRealization, periods: &[f64; D], ) -> Result, PeriodicSimplexSpanError> { validate_periods(periods)?; @@ -562,7 +562,7 @@ fn validate_periods(periods: &[f64; D]) -> Result<(), PeriodicSi Ok(()) } -/// Validates that two simplex embeddings meet only along labels they share. +/// Validates that two simplex realizations meet only along labels they share. /// /// This is the pure geometric core of Level 4 overlap validation. It uses /// exact rational barycentric arithmetic after coordinates have been parsed as @@ -579,30 +579,30 @@ fn validate_periods(periods: &[f64; D]) -> Result<(), PeriodicSi /// /// ```rust /// use delaunay::prelude::geometry::{ -/// LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, SimplexIntersectionFailure, -/// validate_simplex_embeddings_intersect_only_in_shared_faces, +/// LabeledSimplexRealization, LabeledSimplexRealizationError, SimplexIntersectionFailure, +/// validate_simplex_realizations_intersect_only_in_shared_faces, /// }; /// -/// # fn main() -> Result<(), LabeledSimplexEmbeddingError> { -/// let first = LabeledSimplexEmbedding::try_new( +/// # fn main() -> Result<(), LabeledSimplexRealizationError> { +/// let first = LabeledSimplexRealization::try_new( /// [0_usize, 1, 2], /// [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], /// )?; -/// let second = LabeledSimplexEmbedding::try_new( +/// let second = LabeledSimplexRealization::try_new( /// [0_usize, 1, 3], /// [[0.0, 0.0], [1.0, 0.0], [0.25, 0.25]], /// )?; /// /// std::assert_matches!( -/// validate_simplex_embeddings_intersect_only_in_shared_faces(&first, &second), +/// validate_simplex_realizations_intersect_only_in_shared_faces(&first, &second), /// Err(SimplexIntersectionFailure::IntersectionOutsideSharedFace { .. }) /// ); /// # Ok(()) /// # } /// ``` -pub fn validate_simplex_embeddings_intersect_only_in_shared_faces( - first: &LabeledSimplexEmbedding, - second: &LabeledSimplexEmbedding, +pub fn validate_simplex_realizations_intersect_only_in_shared_faces( + first: &LabeledSimplexRealization, + second: &LabeledSimplexRealization, ) -> Result<(), SimplexIntersectionFailure> where L: Clone + Eq, @@ -632,11 +632,11 @@ where Ok(()) } -/// Collects labels common to two simplex embeddings so witnesses can distinguish shared faces. +/// Collects labels common to two simplex realizations so witnesses can distinguish shared faces. fn shared_labels( - first: &LabeledSimplexEmbedding, - second: &LabeledSimplexEmbedding, -) -> SimplexEmbeddingBuffer + first: &LabeledSimplexRealization, + second: &LabeledSimplexRealization, +) -> SimplexRealizationBuffer where L: Clone + Eq, { @@ -650,8 +650,8 @@ where /// Expresses every vertex of one simplex in the barycentric basis of another. fn barycentric_coordinates_of_vertices( - vertices: &LabeledSimplexEmbedding, - basis: &LabeledSimplexEmbedding, + vertices: &LabeledSimplexRealization, + basis: &LabeledSimplexRealization, ) -> Result>, SimplexIntersectionFailure> { vertices .coordinates() @@ -663,7 +663,7 @@ fn barycentric_coordinates_of_vertices( /// Computes exact barycentric coordinates of one point in one simplex basis. fn barycentric_coordinates( point: &[f64; D], - simplex: &LabeledSimplexEmbedding, + simplex: &LabeledSimplexRealization, ) -> Result, SimplexIntersectionFailure> { if D == 0 { return Ok(vec![rational_one()]); @@ -824,7 +824,7 @@ fn positive_nonshared_labels( barycentric: &[BigRational], labels: &[L], shared_labels: &[L], -) -> SimplexEmbeddingBuffer +) -> SimplexRealizationBuffer where L: Clone + Eq, { @@ -911,14 +911,14 @@ mod tests { struct CloneOnlyLabel; #[test] - fn labeled_simplex_embedding_rejects_label_coordinate_length_mismatch() { + fn labeled_simplex_realization_rejects_label_coordinate_length_mismatch() { let err = - LabeledSimplexEmbedding::<_, 2>::try_new(vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0]]) + LabeledSimplexRealization::<_, 2>::try_new(vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0]]) .unwrap_err(); assert_matches!( err, - LabeledSimplexEmbeddingError::LabelCoordinateLengthMismatch { + LabeledSimplexRealizationError::LabelCoordinateLengthMismatch { label_count: 3, coordinate_count: 2, } @@ -926,8 +926,8 @@ mod tests { } #[test] - fn labeled_simplex_embedding_rejects_invalid_arity() { - let err = LabeledSimplexEmbedding::<_, 2>::try_new( + fn labeled_simplex_realization_rejects_invalid_arity() { + let err = LabeledSimplexRealization::<_, 2>::try_new( vec![0, 1, 2, 3], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], ) @@ -935,7 +935,7 @@ mod tests { assert_matches!( err, - LabeledSimplexEmbeddingError::InvalidArity { + LabeledSimplexRealizationError::InvalidArity { expected: 3, actual: 4, } @@ -943,8 +943,8 @@ mod tests { } #[test] - fn labeled_simplex_embedding_rejects_duplicate_labels() { - let err = LabeledSimplexEmbedding::<_, 2>::try_new( + fn labeled_simplex_realization_rejects_duplicate_labels() { + let err = LabeledSimplexRealization::<_, 2>::try_new( vec![0, 1, 0], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], ) @@ -952,7 +952,7 @@ mod tests { assert_matches!( err, - LabeledSimplexEmbeddingError::DuplicateLabel { + LabeledSimplexRealizationError::DuplicateLabel { first_index: 0, duplicate_index: 2, } @@ -961,7 +961,7 @@ mod tests { #[test] fn coordinate_range_rejects_out_of_bounds_axis() { - let simplex = LabeledSimplexEmbedding::try_new( + let simplex = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], ) @@ -972,25 +972,25 @@ mod tests { #[test] fn disjoint_triangles_do_not_intersect_outside_shared_face() { - let first = LabeledSimplexEmbedding::try_new( + let first = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], ) .unwrap(); - let second = LabeledSimplexEmbedding::try_new( + let second = LabeledSimplexRealization::try_new( vec![3, 4, 5], vec![[2.0, 2.0], [3.0, 2.0], [2.0, 3.0]], ) .unwrap(); assert!( - validate_simplex_embeddings_intersect_only_in_shared_faces(&first, &second).is_ok() + validate_simplex_realizations_intersect_only_in_shared_faces(&first, &second).is_ok() ); } #[test] - fn labeled_simplex_embedding_rejects_non_finite_coordinates() { - let err = LabeledSimplexEmbedding::try_new( + fn labeled_simplex_realization_rejects_non_finite_coordinates() { + let err = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [1.0, f64::NAN], [0.0, 1.0]], ) @@ -998,7 +998,7 @@ mod tests { assert_matches!( err, - LabeledSimplexEmbeddingError::NonFiniteCoordinate { + LabeledSimplexRealizationError::NonFiniteCoordinate { vertex_index: 1, coordinate_index: 1, coordinate_value: InvalidCoordinateValue::Nan, @@ -1007,8 +1007,8 @@ mod tests { } #[test] - fn labeled_simplex_embedding_rehydrates_points_from_validated_rows() { - let simplex = LabeledSimplexEmbedding::try_new( + fn labeled_simplex_realization_rehydrates_points_from_validated_rows() { + let simplex = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[-0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], ) @@ -1022,8 +1022,8 @@ mod tests { } #[test] - fn translated_embedding_rejects_non_finite_coordinates() { - let simplex = LabeledSimplexEmbedding::try_new( + fn translated_realization_rejects_non_finite_coordinates() { + let simplex = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], ) @@ -1035,7 +1035,7 @@ mod tests { assert_matches!( err, - LabeledSimplexEmbeddingError::NonFiniteCoordinate { + LabeledSimplexRealizationError::NonFiniteCoordinate { vertex_index: 0, coordinate_index: 0, coordinate_value: InvalidCoordinateValue::PositiveInfinity, @@ -1044,8 +1044,8 @@ mod tests { } #[test] - fn translated_embedding_rejects_invalid_periods() { - let simplex = LabeledSimplexEmbedding::try_new( + fn translated_realization_rejects_invalid_periods() { + let simplex = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]], ) @@ -1055,7 +1055,7 @@ mod tests { assert_matches!( err, - LabeledSimplexEmbeddingError::InvalidPeriodicDomainPeriod { + LabeledSimplexRealizationError::InvalidPeriodicDomainPeriod { source: PeriodicSimplexSpanError::NonPositivePeriod { axis: 1, period: -1.0, @@ -1065,8 +1065,8 @@ mod tests { } #[test] - fn translated_embedding_requires_only_clone_labels() { - let simplex = LabeledSimplexEmbedding { + fn translated_realization_requires_only_clone_labels() { + let simplex = LabeledSimplexRealization { labels: vec![CloneOnlyLabel, CloneOnlyLabel, CloneOnlyLabel] .into_iter() .collect(), @@ -1085,18 +1085,18 @@ mod tests { #[test] fn crossing_triangles_report_positive_nonshared_witnesses() { - let first = LabeledSimplexEmbedding::try_new( + let first = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [2.0, 0.0], [0.0, 2.0]], ) .unwrap(); - let second = LabeledSimplexEmbedding::try_new( + let second = LabeledSimplexRealization::try_new( vec![3, 4, 5], vec![[2.0, 2.0], [1.0, -1.0], [3.0, 2.0]], ) .unwrap(); - let err = validate_simplex_embeddings_intersect_only_in_shared_faces(&first, &second) + let err = validate_simplex_realizations_intersect_only_in_shared_faces(&first, &second) .unwrap_err(); assert_matches!( err, @@ -1108,7 +1108,7 @@ mod tests { #[test] fn spanning_periodic_simplex_is_detected() { - let simplex = LabeledSimplexEmbedding::try_new( + let simplex = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [1.0, 0.0], [0.0, 0.25]], ) @@ -1124,7 +1124,7 @@ mod tests { #[test] fn periodic_simplex_span_rejects_invalid_periods() { - let simplex = LabeledSimplexEmbedding::try_new( + let simplex = LabeledSimplexRealization::try_new( vec![0, 1, 2], vec![[0.0, 0.0], [0.5, 0.0], [0.0, 0.25]], ) diff --git a/src/geometry/util/measures.rs b/src/geometry/util/measures.rs index b8956068..622f9d3a 100644 --- a/src/geometry/util/measures.rs +++ b/src/geometry/util/measures.rs @@ -676,7 +676,7 @@ pub fn facet_measure(points: &[Point]) -> Result( // Compute Gram determinant with validation. // - // For a (D-1)-simplex embedded in D dimensions, there are (D-1) edge vectors from + // For a (D-1)-simplex realized in D dimensions, there are (D-1) edge vectors from // one vertex to the remaining vertices, so the Gram matrix is (D-1)Γ—(D-1). let gram_dim = D - 1; let det = try_with_la_stack_matrix!(gram_dim, |gram_matrix| { diff --git a/src/geometry/util/point_generation.rs b/src/geometry/util/point_generation.rs index 0a6e9c18..ffbd289c 100644 --- a/src/geometry/util/point_generation.rs +++ b/src/geometry/util/point_generation.rs @@ -412,7 +412,7 @@ struct PositiveScalar(f64); impl PositiveScalar { /// Parses a raw scalar into a finite positive scalar proof. /// - /// The returned [`InvalidPositiveScalar`] is embedded directly in public + /// The returned [`InvalidPositiveScalar`] is realized directly in public /// [`RandomPointGenerationError`] variants by the caller. fn try_new(value: f64) -> Result { if !value.is_finite() { diff --git a/src/lib.rs b/src/lib.rs index d4b56bfd..478ed0ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ //! | Post-construction vertex deletion errors and keys | `use delaunay::prelude::deletion::*` | //! | Read-only queries, traversal, ridge views, simplex barycenters, convex hull | `use delaunay::prelude::query::*` | //! | Point location and conflict-region algorithms | `use delaunay::prelude::algorithms::*` | -//! | Geometry helpers, simplex embeddings, coordinate ranges, predicates, points | `use delaunay::prelude::geometry::*` | +//! | Geometry helpers, simplex realizations, coordinate ranges, predicates, points | `use delaunay::prelude::geometry::*` | //! | Random points / triangulations for examples and tests | `use delaunay::prelude::generators::*` | //! | Hilbert ordering and quantization utilities | `use delaunay::prelude::ordering::*` | //! | Unified Pachner move workflow | `use delaunay::prelude::pachner::*` | @@ -120,8 +120,8 @@ //! // Levels 1–3: + Intrinsic PL Topology //! assert!(dt.as_triangulation().validate().is_ok()); //! -//! // Levels 1–4: elements + combinatorics + topology + embedding validity -//! assert!(dt.as_triangulation().validate_embedding().is_ok()); +//! // Levels 1–4: elements + combinatorics + topology + realization validity +//! assert!(dt.as_triangulation().validate_realization().is_ok()); //! //! // Level 5 only: Geometric Predicates (Delaunay today; assumes Levels 1–4) //! assert!(dt.is_valid_delaunay().is_ok()); @@ -234,10 +234,10 @@ //! boundary; two-sided facets are interior. //! - Checks the **Euler characteristic** of the triangulation (using the topology module). //! -//! - [`Triangulation`] also validates the **embedding validity** of the abstract +//! - [`Triangulation`] also validates the **realization validity** of the abstract //! complex in the active ambient model. Level 4 validation is performed by -//! [`Triangulation::is_valid_embedding`](crate::Triangulation::is_valid_embedding) (Level 4 only) and -//! [`Triangulation::validate_embedding`](crate::Triangulation::validate_embedding) (Levels 1–4). +//! [`Triangulation::is_valid_realization`](crate::Triangulation::is_valid_realization) (Level 4 only) and +//! [`Triangulation::validate_realization`](crate::Triangulation::validate_realization) (Levels 1–4). //! Euclidean topology is checked directly in its ambient chart; toroidal //! topology is checked in periodic covering-space charts. //! @@ -259,7 +259,7 @@ //! //! The crate exposes five validation levels //! (Element Validity β†’ Combinatorial Consistency β†’ Intrinsic PL Topology β†’ -//! Embedding Validity β†’ Geometric Predicates). The +//! Valid Realization β†’ Geometric Predicates). The //! canonical guide (when to use each level, complexity, examples, troubleshooting) lives in //! `docs/validation.md`: //! @@ -273,14 +273,14 @@ //! - Level 3 (Intrinsic PL Topology / `Triangulation`): //! `dt.as_triangulation().is_valid_topology()` for topology-only checks, or //! `dt.as_triangulation().validate()` for Levels 1–3. -//! - Level 4 (Embedding Validity / `Triangulation`): `dt.as_triangulation().validate_embedding()` -//! for cumulative embedded-geometry checks, or `dt.as_triangulation().embedding_report()` for layer-local diagnostics. +//! - Level 4 (Valid Realization / `Triangulation`): `dt.as_triangulation().validate_realization()` +//! for cumulative realized-geometry checks, or `dt.as_triangulation().realization_report()` for layer-local diagnostics. //! - Level 5 (Geometric Predicates / `DelaunayTriangulation`): `dt.is_valid_delaunay()` for the //! implemented Delaunay predicate family, or `dt.delaunay_report()` for layer-local diagnostics. //! - Cumulative Delaunay validation: `dt.validate()` for Levels 1–5, or //! `dt.validation_report()` for full diagnostics. //! -//! ### Automatic topology and changed-scope embedding validation during insertion (`ValidationPolicy`) +//! ### Automatic topology and changed-scope realization validation during insertion (`ValidationPolicy`) //! //! In addition to explicit validation calls, incremental construction (`new()` / `insert*()`) can run an //! automatic **global Level 3 plus changed-scope Level 4** validation pass after insertion, controlled by @@ -289,13 +289,13 @@ //! The initial policy is derived from the active topology guarantee. The default //! [`TopologyGuarantee::PLManifold`](crate::prelude::TopologyGuarantee::PLManifold) //! uses [`ValidationPolicy::ExplicitOnly`](crate::prelude::validation::ValidationPolicy::ExplicitOnly): -//! mandatory local topology and nondegenerate-embedding checks still run during insertion, while automatic -//! global-topology/changed-scope embedding validation is a caller-owned explicit checkpoint. +//! mandatory local topology and nondegenerate-realization checks still run during insertion, while automatic +//! global-topology/changed-scope realization validation is a caller-owned explicit checkpoint. //! //! This automatic pass runs Level 3 (`Triangulation::is_valid_topology()`), changed-simplex //! Level 4 nondegeneracy checks, and changed-vs-current Level 4 pairwise checks. It does //! **not** run Level 5 geometric-predicate validation, and old-vs-old Level 4 rescans remain an explicit -//! `Triangulation::validate_embedding()` checkpoint. +//! `Triangulation::validate_realization()` checkpoint. //! //! ```rust //! use delaunay::prelude::construction::{ @@ -581,8 +581,6 @@ mod core { /// Generic triangulation construction helpers. pub mod construction; pub mod edge; - /// Embedded Euclidean geometry validation for generic triangulations. - pub mod embedding; pub mod facet; /// Incremental insertion for generic triangulations. pub mod insertion; @@ -592,6 +590,8 @@ mod core { pub mod orientation; /// Read-only query and traversal helpers for generic triangulations. pub mod query; + /// Realized Euclidean geometry validation for generic triangulations. + pub mod realization; /// Local topology repair for generic triangulations. pub mod repair; /// Scoped rollback guards for internal topology mutation windows. @@ -681,8 +681,8 @@ pub mod geometry { } /// Validated coordinate-range types. pub mod coordinate_range; - /// Pure labeled-simplex embedding predicates used by Level 4 validation. - pub mod embedding; + /// Pure labeled-simplex realization predicates used by Level 4 validation. + pub mod realization; #[macro_use] pub mod matrix; /// Geometric kernel abstraction (CGAL-style). @@ -724,11 +724,11 @@ pub mod geometry { } pub use algorithms::*; pub use coordinate_range::*; - pub use embedding::*; pub use matrix::*; pub use point::*; pub use predicates::*; pub use quality::*; + pub use realization::*; pub use traits::*; pub use util::*; } @@ -815,17 +815,17 @@ pub use crate::core::algorithms::pl_manifold_repair::{ pub use crate::core::construction::{ FinalDelaunayValidationContext, FinalTopologyValidationContext, TriangulationConstructionError, }; -pub use crate::core::embedding::{ - PeriodicDomainPeriodError, TriangulationEmbeddingIntersectionDetail, - TriangulationEmbeddingSimplexDetail, TriangulationEmbeddingSimplexPairDetail, - TriangulationEmbeddingValidationError, TriangulationEmbeddingValidationErrorKind, - TriangulationEmbeddingValidationReport, -}; pub use crate::core::insertion::DuplicateDetectionMetrics; pub use crate::core::operations::{ InsertionOutcome, InsertionResult, InsertionStatistics, RepairDecision, RepairSkipReason, SuspicionFlags, TopologicalOperation, }; +pub use crate::core::realization::{ + PeriodicDomainPeriodError, TriangulationRealizationIntersectionDetail, + TriangulationRealizationSimplexDetail, TriangulationRealizationSimplexPairDetail, + TriangulationRealizationValidationError, TriangulationRealizationValidationErrorKind, + TriangulationRealizationValidationReport, +}; pub use crate::core::triangulation::Triangulation; pub use crate::core::util::DeduplicationError; pub use crate::core::validation::{ @@ -989,7 +989,7 @@ pub mod topology { /// /// This module contains the Euclidean and toroidal topology-space helpers, /// plus the spherical coordinate/metric backend for points on `S^D` - /// embedded in `R^(D+1)`. + /// realized in `R^(D+1)`. pub mod spaces { /// Euclidean space topology pub mod euclidean; @@ -1224,10 +1224,10 @@ pub mod prelude { SphericalDelaunayTriangulation, SphericalDelaunayValidationError, SphericalMetric, SphericalPoint, SphericalPointError, SphericalSimplex, SphericalSimplexError, SphericalValidationLayer, TopologicalOperation, TopologyGuarantee, Triangulation, - TriangulationConstructionError, TriangulationEmbeddingIntersectionDetail, - TriangulationEmbeddingSimplexDetail, TriangulationEmbeddingSimplexPairDetail, - TriangulationEmbeddingValidationError, TriangulationEmbeddingValidationErrorKind, - TriangulationEmbeddingValidationReport, TriangulationValidationError, + TriangulationConstructionError, TriangulationRealizationIntersectionDetail, + TriangulationRealizationSimplexDetail, TriangulationRealizationSimplexPairDetail, + TriangulationRealizationValidationError, TriangulationRealizationValidationErrorKind, + TriangulationRealizationValidationReport, TriangulationValidationError, TriangulationValidationReport, ValidationConfigurationError, ValidationPolicy, try_vertices_from_points, }; @@ -1443,9 +1443,9 @@ pub mod prelude { pub use crate::{ InsertionError, PeriodicDomainPeriodError, SpatialIndexConstructionFailure, TopologyGuarantee, Triangulation, TriangulationConstructionError, - TriangulationEmbeddingIntersectionDetail, TriangulationEmbeddingSimplexDetail, - TriangulationEmbeddingSimplexPairDetail, TriangulationEmbeddingValidationError, - TriangulationEmbeddingValidationErrorKind, TriangulationEmbeddingValidationReport, + TriangulationRealizationIntersectionDetail, TriangulationRealizationSimplexDetail, + TriangulationRealizationSimplexPairDetail, TriangulationRealizationValidationError, + TriangulationRealizationValidationErrorKind, TriangulationRealizationValidationReport, TriangulationValidationError, TriangulationValidationReport, ValidationConfigurationError, ValidationPolicy, }; @@ -1667,9 +1667,9 @@ pub mod prelude { DelaunayTriangulationValidationError, DelaunayVerificationError, DelaunayVerificationErrorKind, PeriodicDomainPeriodError, SphericalDelaunayValidationError, SphericalValidationLayer, TopologyGuarantee, - TriangulationEmbeddingIntersectionDetail, TriangulationEmbeddingSimplexDetail, - TriangulationEmbeddingSimplexPairDetail, TriangulationEmbeddingValidationError, - TriangulationEmbeddingValidationErrorKind, TriangulationEmbeddingValidationReport, + TriangulationRealizationIntersectionDetail, TriangulationRealizationSimplexDetail, + TriangulationRealizationSimplexPairDetail, TriangulationRealizationValidationError, + TriangulationRealizationValidationErrorKind, TriangulationRealizationValidationReport, TriangulationValidationError, TriangulationValidationReport, ValidationConfigurationError, ValidationPolicy, }; @@ -1741,20 +1741,13 @@ pub mod prelude { pub use crate::tds::*; } - /// Focused exports for geometry types, simplex embeddings, predicates, and helpers. + /// Focused exports for geometry types, simplex realizations, predicates, and helpers. pub mod geometry { pub use crate::geometry::{ coordinate_range::{ CoordinateRange, CoordinateRangeBound, CoordinateRangeError, CoordinateRangeOrdering, InvalidCoordinateValue, }, - embedding::{ - LabeledSimplexEmbedding, LabeledSimplexEmbeddingError, PeriodicSimplexSpan, - PeriodicSimplexSpanError, SimplexEmbeddingBuffer, SimplexIntersectionFailure, - SimplexIntersectionWitness, axis_aligned_bounding_boxes_overlap, - coordinate_range_for_axis, try_periodic_simplex_span, - validate_simplex_embeddings_intersect_only_in_shared_faces, - }, kernel::{AdaptiveKernel, ExactPredicates, FastKernel, Kernel, RobustKernel}, matrix::{LaError, Matrix, MatrixError, determinant}, point::Point, @@ -1766,6 +1759,13 @@ pub mod prelude { QualityDegeneracyMeasure, QualityError, QualityNumericOperation, QualitySimplexVerticesError, normalized_volume, radius_ratio, }, + realization::{ + LabeledSimplexRealization, LabeledSimplexRealizationError, PeriodicSimplexSpan, + PeriodicSimplexSpanError, SimplexIntersectionFailure, SimplexIntersectionWitness, + SimplexRealizationBuffer, axis_aligned_bounding_boxes_overlap, + coordinate_range_for_axis, try_periodic_simplex_span, + validate_simplex_realizations_intersect_only_in_shared_faces, + }, robust_predicates::{ ConsistencyResult, InsphereConsistencyError, robust_insphere, robust_orientation, }, diff --git a/src/topology/spaces/euclidean.rs b/src/topology/spaces/euclidean.rs index 748abde9..f7b7f4d7 100644 --- a/src/topology/spaces/euclidean.rs +++ b/src/topology/spaces/euclidean.rs @@ -1,7 +1,7 @@ //! Euclidean space topology implementation. //! //! This module provides topological analysis for triangulations -//! embedded in flat Euclidean space. +//! realized in flat Euclidean space. #![forbid(unsafe_code)] diff --git a/src/topology/spaces/spherical.rs b/src/topology/spaces/spherical.rs index 49e5f919..6f7abd0a 100644 --- a/src/topology/spaces/spherical.rs +++ b/src/topology/spaces/spherical.rs @@ -1,13 +1,13 @@ //! Spherical coordinate and metric backend. //! //! This module provides fallible coordinate and metric types for points on -//! `S^D` embedded in `R^(D+1)`. +//! `S^D` realized in `R^(D+1)`. #![forbid(unsafe_code)] use thiserror::Error; -/// Typed point on `S^D` embedded in `R^(D+1)`. +/// Typed point on `S^D` realized in `R^(D+1)`. /// /// Rust's stable const generics do not allow a public `[f64; D + 1]` field, so /// this topology backend stores the ambient coordinates in a length-checked diff --git a/src/topology/traits/global_topology_model.rs b/src/topology/traits/global_topology_model.rs index 7a745b95..e7cd5feb 100644 --- a/src/topology/traits/global_topology_model.rs +++ b/src/topology/traits/global_topology_model.rs @@ -156,12 +156,12 @@ pub trait GlobalTopologyModel { } /// Indicates whether this topology has an affine chart suitable for Level 4 - /// embedded-geometry validation. + /// realized-geometry validation. /// /// Euclidean topology validates directly in its ambient chart. Toroidal /// topology validates in its periodic covering-space charts. Curved models /// return `false` until they provide model-specific chart validators. - fn supports_affine_embedding_validation(&self) -> bool { + fn supports_affine_chart_realization_validation(&self) -> bool { false } @@ -219,7 +219,7 @@ impl GlobalTopologyModel for EuclideanModel { Ok(coords) } - fn supports_affine_embedding_validation(&self) -> bool { + fn supports_affine_chart_realization_validation(&self) -> bool { true } } @@ -309,7 +309,7 @@ impl GlobalTopologyModel for ToroidalModel { Some(self.domain) } - fn supports_affine_embedding_validation(&self) -> bool { + fn supports_affine_chart_realization_validation(&self) -> bool { true } @@ -571,19 +571,19 @@ impl GlobalTopologyModel for GlobalTopologyModelAdapter { } } - fn supports_affine_embedding_validation(&self) -> bool { + fn supports_affine_chart_realization_validation(&self) -> bool { match self { Self::Euclidean(model) => { - GlobalTopologyModel::::supports_affine_embedding_validation(model) + GlobalTopologyModel::::supports_affine_chart_realization_validation(model) } Self::Toroidal(model) => { - GlobalTopologyModel::::supports_affine_embedding_validation(model) + GlobalTopologyModel::::supports_affine_chart_realization_validation(model) } Self::Spherical(model) => { - GlobalTopologyModel::::supports_affine_embedding_validation(model) + GlobalTopologyModel::::supports_affine_chart_realization_validation(model) } Self::Hyperbolic(model) => { - GlobalTopologyModel::::supports_affine_embedding_validation(model) + GlobalTopologyModel::::supports_affine_chart_realization_validation(model) } } } diff --git a/src/topology/traits/topological_space.rs b/src/topology/traits/topological_space.rs index 54bf0512..9612cedf 100644 --- a/src/topology/traits/topological_space.rs +++ b/src/topology/traits/topological_space.rs @@ -75,7 +75,7 @@ pub enum TopologyError { /// Classification of topological spaces for triangulations. /// /// This enum categorizes the fundamental geometry of the space in which -/// a triangulation is embedded. Different topologies have different +/// a triangulation is realized. Different topologies have different /// properties regarding boundary conditions and geometric constraints. /// /// # Future Use @@ -105,7 +105,7 @@ pub enum TopologyKind { /// as opposite edges are identified. Toroidal, - /// Spherical space embedded on the surface of a sphere. + /// Spherical space realized on the surface of a sphere. /// /// All points lie on a sphere surface. No boundary facets as the space /// is closed and compact. @@ -135,7 +135,7 @@ pub enum ToroidalConstructionMode { /// /// No coordinate canonicalization or image-point expansion is performed. The /// current Delaunay builder rejects non-Euclidean explicit connectivity - /// because quotient embedding validation is not implemented for that + /// because quotient realization validation is not implemented for that /// construction path. Explicit, } diff --git a/tests/benchmark_flip_fixtures.rs b/tests/benchmark_flip_fixtures.rs index efd20a39..7f11b79c 100644 --- a/tests/benchmark_flip_fixtures.rs +++ b/tests/benchmark_flip_fixtures.rs @@ -29,7 +29,7 @@ use delaunay::prelude::construction::{ }; use delaunay::prelude::tds::{FacetError, SimplexKey}; use delaunay::prelude::validation::{ - DelaunayTriangulationValidationError, TriangulationEmbeddingValidationError, + DelaunayTriangulationValidationError, TriangulationRealizationValidationError, }; use slotmap::KeyData; @@ -601,8 +601,8 @@ fn assert_topology_and_delaunay_valid(dt: &FlipTriangulation, .validate() .unwrap_or_else(|err| panic!("{context} should pass Levels 1-3: {err}")); dt.as_triangulation() - .is_valid_embedding() - .unwrap_or_else(|err| panic!("{context} should pass Level 4 embedding: {err}")); + .is_valid_realization() + .unwrap_or_else(|err| panic!("{context} should pass Level 4 realization: {err}")); dt.is_valid_delaunay() .unwrap_or_else(|err| panic!("{context} should pass Level 5: {err}")); } @@ -616,10 +616,10 @@ fn construction_error_is_degenerate(error: &DelaunayTriangulationConstructionErr DelaunayConstructionFailure::FinalDelaunayValidation { source, .. }, ) => validation_error_is_degenerate(source), DelaunayTriangulationConstructionError::Triangulation( - DelaunayConstructionFailure::InsertionEmbeddingValidation { source }, + DelaunayConstructionFailure::InsertionRealizationValidation { source }, ) => matches!( source, - TriangulationEmbeddingValidationError::DegenerateSimplex { .. } + TriangulationRealizationValidationError::DegenerateSimplex { .. } ), DelaunayTriangulationConstructionError::Triangulation( DelaunayConstructionFailure::ShuffledRetryExhausted { source, .. }, @@ -636,10 +636,10 @@ fn construction_error_is_degenerate(error: &DelaunayTriangulationConstructionErr fn validation_error_is_degenerate(error: &DelaunayTriangulationValidationError) -> bool { matches!( error, - DelaunayTriangulationValidationError::Embedding(source) + DelaunayTriangulationValidationError::Realization(source) if matches!( source.as_ref(), - TriangulationEmbeddingValidationError::DegenerateSimplex { .. } + TriangulationRealizationValidationError::DegenerateSimplex { .. } ) ) } diff --git a/tests/cli.rs b/tests/cli.rs index d82503f8..3c35ea37 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -240,7 +240,7 @@ mod cli_tests { assert_eq!(json["dimension"], 2); assert_eq!(json["valid_baseline"]["status"], "passed"); assert_eq!(cases.len(), 5); - assert_eq!(cases[3]["layer"], "Valid affine realization"); + assert_eq!(cases[3]["layer"], "Valid realization"); } #[test] diff --git a/tests/delaunay_edge_cases.rs b/tests/delaunay_edge_cases.rs index e862070a..76e9e203 100644 --- a/tests/delaunay_edge_cases.rs +++ b/tests/delaunay_edge_cases.rs @@ -19,7 +19,7 @@ use delaunay::prelude::generators::{ }; use delaunay::prelude::geometry::RobustKernel; use delaunay::prelude::validation::{ - DelaunayTriangulationValidationError, TriangulationEmbeddingValidationError, + DelaunayTriangulationValidationError, TriangulationRealizationValidationError, }; use delaunay::vertex; use rand::SeedableRng; @@ -78,10 +78,10 @@ fn is_geometric_degeneracy_or_retry_exhausted( fn validation_error_is_degenerate_simplex(error: &DelaunayTriangulationValidationError) -> bool { matches!( error, - DelaunayTriangulationValidationError::Embedding(source) + DelaunayTriangulationValidationError::Realization(source) if matches!( source.as_ref(), - TriangulationEmbeddingValidationError::DegenerateSimplex { .. } + TriangulationRealizationValidationError::DegenerateSimplex { .. } ) ) } @@ -94,10 +94,10 @@ fn construction_error_is_degenerate_simplex( DelaunayConstructionFailure::FinalDelaunayValidation { source, .. }, ) => validation_error_is_degenerate_simplex(source), DelaunayTriangulationConstructionError::Triangulation( - DelaunayConstructionFailure::InsertionEmbeddingValidation { source }, + DelaunayConstructionFailure::InsertionRealizationValidation { source }, ) => matches!( source, - TriangulationEmbeddingValidationError::DegenerateSimplex { .. } + TriangulationRealizationValidationError::DegenerateSimplex { .. } ), DelaunayTriangulationConstructionError::Triangulation( DelaunayConstructionFailure::ShuffledRetryExhausted { source, .. }, @@ -795,7 +795,7 @@ fn test_cube_vertices_3d() { assert!( construction_error_is_degenerate_simplex(&err), - "cube-corner failure should preserve the embedding degeneracy source: {err:?}" + "cube-corner failure should preserve the realization degeneracy source: {err:?}" ); } diff --git a/tests/euler_characteristic.rs b/tests/euler_characteristic.rs index 3d5d988f..5ac595bf 100644 --- a/tests/euler_characteristic.rs +++ b/tests/euler_characteristic.rs @@ -311,7 +311,7 @@ fn test_2d_toroidal_explicit_construction_rejected() { .global_topology(topology) .topology_guarantee(TopologyGuarantee::Pseudomanifold) .build() - .expect_err("explicit toroidal connectivity requires a quotient embedding validator"); + .expect_err("explicit toroidal connectivity requires a quotient realization validator"); match err { DelaunayTriangulationConstructionError::ExplicitConstruction( @@ -393,7 +393,7 @@ fn test_3d_toroidal_explicit_construction_rejected() { .global_topology(topology) .topology_guarantee(TopologyGuarantee::Pseudomanifold) .build() - .expect_err("explicit toroidal connectivity requires a quotient embedding validator"); + .expect_err("explicit toroidal connectivity requires a quotient realization validator"); match err { DelaunayTriangulationConstructionError::ExplicitConstruction( diff --git a/tests/large_scale_debug.rs b/tests/large_scale_debug.rs index 6081ccb3..8f98cf05 100644 --- a/tests/large_scale_debug.rs +++ b/tests/large_scale_debug.rs @@ -615,10 +615,10 @@ fn debug_mode_from_env() -> DebugMode { #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ValidationScope { - /// Cumulative Levels 1–5, including the Level 4 embedding overlap scan. + /// Cumulative Levels 1–5, including the Level 4 realization overlap scan. Full, /// Construction correctness only: Levels 1–3 (structure + topology) plus - /// Level 5 (Delaunay property), skipping the expensive Level 4 embedding + /// Level 5 (Delaunay property), skipping the expensive Level 4 realization /// overlap scan. Used by the `perf-large-scale-smoke` wall-clock guard. Construction, } @@ -1568,11 +1568,11 @@ where ValidationScope::Construction => { // Levels 1–3 (structure + topology) plus the fast O(simplices) // flip-based Level 5 Delaunay check. This skips the expensive Level 4 - // embedding overlap scan and the full report's all-violations Delaunay + // realization overlap scan and the full report's all-violations Delaunay // scan, keeping the wall-clock guard focused on construction // correctness. Level 4 is exercised at scale by `just test-slow` // (full scope); see issue #482. - println!("Running validation (Levels 1–3 + fast Level 5; embedding skipped)..."); + println!("Running validation (Levels 1–3 + fast Level 5; realization skipped)..."); let t_validate = Instant::now(); let topology_result = dt.as_triangulation().validation_report(); let delaunay_result = if topology_result.is_ok() { diff --git a/tests/pachner_roundtrip.rs b/tests/pachner_roundtrip.rs index aedb4753..5fe1a6b4 100644 --- a/tests/pachner_roundtrip.rs +++ b/tests/pachner_roundtrip.rs @@ -94,7 +94,7 @@ fn topology_and_delaunay_valid( dt: &DelaunayTriangulation, (), (), D>, ) -> bool { dt.as_triangulation().validate().is_ok() - && dt.as_triangulation().is_valid_embedding().is_ok() + && dt.as_triangulation().is_valid_realization().is_ok() && dt.is_valid_delaunay().is_ok() } @@ -106,8 +106,8 @@ fn assert_topology_and_delaunay_valid( .validate() .unwrap_or_else(|err| panic!("{context} should pass Levels 1-3: {err}")); dt.as_triangulation() - .is_valid_embedding() - .unwrap_or_else(|err| panic!("{context} should pass Level 4 embedding: {err}")); + .is_valid_realization() + .unwrap_or_else(|err| panic!("{context} should pass Level 4 realization: {err}")); dt.is_valid_delaunay() .unwrap_or_else(|err| panic!("{context} should pass Level 5: {err}")); } diff --git a/tests/prelude_exports.rs b/tests/prelude_exports.rs index 63d83124..be376421 100644 --- a/tests/prelude_exports.rs +++ b/tests/prelude_exports.rs @@ -32,8 +32,8 @@ use delaunay::flips::{ use delaunay::geometry::{ CoordinateConversionError as GeometryModuleCoordinateConversionError, CoordinateRange as GeometryCoordinateRange, - LabeledSimplexEmbedding as GeometryModuleLabeledSimplexEmbedding, - validate_simplex_embeddings_intersect_only_in_shared_faces as geometry_module_validate_simplex_embeddings_intersect_only_in_shared_faces, + LabeledSimplexRealization as GeometryModuleLabeledSimplexRealization, + validate_simplex_realizations_intersect_only_in_shared_faces as geometry_module_validate_simplex_realizations_intersect_only_in_shared_faces, }; use delaunay::pachner::PachnerMoves as DirectPachnerMoves; use delaunay::prelude::DelaunayValidationError; @@ -106,12 +106,12 @@ use delaunay::prelude::geometry::{ ArrayConversionFailureReason, CircumcenterError, CircumcenterFailureReason, CoordinateConversionError, CoordinateConversionValue, CoordinateValidationError, CoordinateValues, DegenerateGeometry, DegenerateMeasure, DegenerateSimplexReason, - FiniteCoordinateValue, InvalidCoordinateValue, LaError, LabeledSimplexEmbedding, - LabeledSimplexEmbeddingError, MatrixError, PeriodicSimplexSpan, PeriodicSimplexSpanError, - Point, QualitySimplexVerticesError, SimplexEmbeddingBuffer, SimplexIntersectionFailure, - SimplexIntersectionWitness, SurfaceMeasureError, ValueConversionError, + FiniteCoordinateValue, InvalidCoordinateValue, LaError, LabeledSimplexRealization, + LabeledSimplexRealizationError, MatrixError, PeriodicSimplexSpan, PeriodicSimplexSpanError, + Point, QualitySimplexVerticesError, SimplexIntersectionFailure, SimplexIntersectionWitness, + SimplexRealizationBuffer, SurfaceMeasureError, ValueConversionError, ValueConversionFailureReason, axis_aligned_bounding_boxes_overlap, coordinate_range_for_axis, - try_periodic_simplex_span, validate_simplex_embeddings_intersect_only_in_shared_faces, + try_periodic_simplex_span, validate_simplex_realizations_intersect_only_in_shared_faces, }; use delaunay::prelude::insertion::{ InitialSimplexConstructionError, InitialSimplexUnexpectedInsertionStage, InsertionError, @@ -1621,13 +1621,13 @@ fn geometry_prelude_covers_typed_error_variants() { } #[test] -fn geometry_prelude_covers_simplex_embedding_validation() { +fn geometry_prelude_covers_simplex_realization_validation() { let first = - LabeledSimplexEmbedding::try_new([0_usize, 1, 2], [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]) - .expect("valid labeled simplex embedding"); + LabeledSimplexRealization::try_new([0_usize, 1, 2], [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]) + .expect("valid labeled simplex realization"); let second = - LabeledSimplexEmbedding::try_new([0_usize, 1, 3], [[0.0, 0.0], [1.0, 0.0], [0.25, 0.25]]) - .expect("valid labeled simplex embedding"); + LabeledSimplexRealization::try_new([0_usize, 1, 3], [[0.0, 0.0], [1.0, 0.0], [0.25, 0.25]]) + .expect("valid labeled simplex realization"); assert_matches!( coordinate_range_for_axis(&first, 0), @@ -1637,7 +1637,7 @@ fn geometry_prelude_covers_simplex_embedding_validation() { ); assert!(axis_aligned_bounding_boxes_overlap(&first, &second)); assert_matches!( - validate_simplex_embeddings_intersect_only_in_shared_faces(&first, &second), + validate_simplex_realizations_intersect_only_in_shared_faces(&first, &second), Err(SimplexIntersectionFailure::IntersectionOutsideSharedFace { witness: SimplexIntersectionWitness { shared, @@ -1649,20 +1649,20 @@ fn geometry_prelude_covers_simplex_embedding_validation() { && first_only_witness.as_slice() == [2] && second_only_witness.as_slice() == [3] ); - let module_root_simplex = GeometryModuleLabeledSimplexEmbedding::try_new( + let module_root_simplex = GeometryModuleLabeledSimplexRealization::try_new( [10_usize, 11, 12], [[2.0, 2.0], [3.0, 2.0], [2.0, 3.0]], ) - .expect("geometry module root re-exports labeled simplex embedding"); - geometry_module_validate_simplex_embeddings_intersect_only_in_shared_faces( + .expect("geometry module root re-exports labeled simplex realization"); + geometry_module_validate_simplex_realizations_intersect_only_in_shared_faces( &first, &module_root_simplex, ) .expect("geometry module root re-exports simplex-intersection validation"); let spanning_simplex = - LabeledSimplexEmbedding::try_new([4_usize, 5, 6], [[0.0, 0.0], [1.0, 0.0], [0.0, 0.25]]) - .expect("valid labeled simplex embedding"); + LabeledSimplexRealization::try_new([4_usize, 5, 6], [[0.0, 0.0], [1.0, 0.0], [0.0, 0.25]]) + .expect("valid labeled simplex realization"); let span = try_periodic_simplex_span(&spanning_simplex, &[1.0, 2.0]) .expect("prelude re-exports periodic span validation") .expect("spanning simplex crosses the first periodic domain"); @@ -1670,13 +1670,13 @@ fn geometry_prelude_covers_simplex_embedding_validation() { assert!(abs_diff_eq!(span.span(), 1.0, epsilon = f64::EPSILON)); assert!(abs_diff_eq!(span.period(), 1.0, epsilon = f64::EPSILON)); - let duplicate = LabeledSimplexEmbedding::<_, 2>::try_new( + let duplicate = LabeledSimplexRealization::<_, 2>::try_new( [7_usize, 7, 8], [[0.0, 0.0], [0.5, 0.0], [0.0, 0.5]], ); assert_matches!( duplicate, - Err(LabeledSimplexEmbeddingError::DuplicateLabel { + Err(LabeledSimplexRealizationError::DuplicateLabel { first_index: 0, duplicate_index: 1 }) @@ -1689,9 +1689,9 @@ fn geometry_prelude_covers_simplex_embedding_validation() { }) ); - let _labels: SimplexEmbeddingBuffer = [0, 1].into_iter().collect(); + let _labels: SimplexRealizationBuffer = [0, 1].into_iter().collect(); assert_send_sync_unpin::(); - assert_send_sync_unpin::(); + assert_send_sync_unpin::(); assert_send_sync_unpin::(); assert_send_sync_unpin::>(); assert_error::>(); @@ -1875,16 +1875,16 @@ fn construction_prelude_covers_typed_explicit_error_wrappers() { if matches!(source.as_ref(), InvariantError::Tds(TdsError::FacetSharingViolation { .. })) ); - let explicit_embedding = ExplicitConstructionError::EmbeddingValidation { + let explicit_realization = ExplicitConstructionError::RealizationValidation { source: Box::new(ConstructionDelaunayTriangulationValidationError::Tds( Box::new(TdsError::InconsistentDataStructure { - message: "embedding validation failed".to_string(), + message: "realization validation failed".to_string(), }), )), }; assert_matches!( - explicit_embedding, - ExplicitConstructionError::EmbeddingValidation { source } + explicit_realization, + ExplicitConstructionError::RealizationValidation { source } if matches!( source.as_ref(), ConstructionDelaunayTriangulationValidationError::Tds(tds) @@ -1968,8 +1968,8 @@ fn validation_prelude_covers_configuration_error() { ); assert_eq!( - FocusedSphericalValidationLayer::Embedding.to_string(), - "Level 4 Embedding Validity" + FocusedSphericalValidationLayer::Realization.to_string(), + "Level 4 Spherical Realization" ); let _spherical_validation_error_size = size_of::(); } diff --git a/tests/proptest_delaunay_triangulation.rs b/tests/proptest_delaunay_triangulation.rs index ea701c30..c26c0524 100644 --- a/tests/proptest_delaunay_triangulation.rs +++ b/tests/proptest_delaunay_triangulation.rs @@ -350,7 +350,7 @@ fn has_no_cospherical_5_tuples_3d(vertices: &[Vertex<(), 3>]) -> bool { /// Assert the layered validation contract we rely on in these properties: /// - Levels 1–3 only (elements + structure + topology) -/// - Levels 4–5 (embedding + Delaunay empty-circumsphere) are intentionally NOT asserted here +/// - Levels 4–5 (realization + Delaunay empty-circumsphere) are intentionally NOT asserted here macro_rules! prop_assert_levels_1_to_3_valid { ($dim:expr, $dt:expr, $context:expr) => {{ let validation = ($dt).as_triangulation().validate(); diff --git a/tests/proptest_flips.rs b/tests/proptest_flips.rs index 2def993c..4355a67c 100644 --- a/tests/proptest_flips.rs +++ b/tests/proptest_flips.rs @@ -174,8 +174,8 @@ fn assert_valid( triangulation .validate() .map_err(|err| TestCaseError::fail(format!("{context} validation failed: {err:?}")))?; - triangulation.is_valid_embedding().map_err(|err| { - TestCaseError::fail(format!("{context} embedding validation failed: {err:?}")) + triangulation.is_valid_realization().map_err(|err| { + TestCaseError::fail(format!("{context} realization validation failed: {err:?}")) })?; Ok(()) } diff --git a/tests/regressions.rs b/tests/regressions.rs index 6c60bd1a..48600995 100644 --- a/tests/regressions.rs +++ b/tests/regressions.rs @@ -494,7 +494,7 @@ fn regression_empty_circumsphere_2d_minimal_case() { dt.repair_delaunay_with_flips().unwrap(); dt.as_triangulation() - .validate_embedding() + .validate_realization() .expect("2D triangulation should preserve lower-layer invariants after global flip repair"); assert!( dt.is_valid_delaunay().is_ok(), diff --git a/tests/semgrep/src/project_rules/rust_style.rs b/tests/semgrep/src/project_rules/rust_style.rs index 97a42321..60f6e14b 100644 --- a/tests/semgrep/src/project_rules/rust_style.rs +++ b/tests/semgrep/src/project_rules/rust_style.rs @@ -168,22 +168,22 @@ impl ValidationApiNamingFixture { } // ruleid: delaunay.rust.validation-api-naming-standard - pub fn embedding_validation_report(&self) -> Result<(), ()> { + pub fn realization_validation_report(&self) -> Result<(), ()> { Ok(()) } // ok: delaunay.rust.validation-api-naming-standard - pub fn is_valid_embedding(&self) -> Result<(), ()> { + pub fn is_valid_realization(&self) -> Result<(), ()> { Ok(()) } // ok: delaunay.rust.validation-api-naming-standard - pub fn embedding_diagnostic(&self) -> Option<()> { + pub fn realization_diagnostic(&self) -> Option<()> { None } // ok: delaunay.rust.validation-api-naming-standard - pub fn embedding_report(&self) -> Result<(), ()> { + pub fn realization_report(&self) -> Result<(), ()> { Ok(()) } @@ -193,7 +193,7 @@ impl ValidationApiNamingFixture { } // ok: delaunay.rust.validation-api-naming-standard - pub fn validate_embedding(&self) -> Result<(), ()> { + pub fn validate_realization(&self) -> Result<(), ()> { Ok(()) } diff --git a/tests/spherical_delaunay.rs b/tests/spherical_delaunay.rs index 84a98964..cd8c7173 100644 --- a/tests/spherical_delaunay.rs +++ b/tests/spherical_delaunay.rs @@ -110,11 +110,11 @@ fn spherical_s2_tetrahedron_hull_facets_are_triangles() { .is_valid_topology() .expect("Level 3 wrapper should validate spherical topology"); triangulation - .validate_embedding() - .expect("tetrahedron facets should satisfy spherical Level 4 embedding"); + .validate_realization() + .expect("tetrahedron facets should satisfy spherical Level 4 realization"); triangulation - .is_valid_embedding() - .expect("Level 4 wrapper should validate spherical embedding"); + .is_valid_realization() + .expect("Level 4 wrapper should validate spherical realization"); triangulation .validate_delaunay() .expect("tetrahedron facets should satisfy spherical Level 5 Delaunay"); diff --git a/tests/triangulation_builder.rs b/tests/triangulation_builder.rs index 5e1bc3dd..79d66c76 100644 --- a/tests/triangulation_builder.rs +++ b/tests/triangulation_builder.rs @@ -700,10 +700,10 @@ fn test_builder_toroidal_large_dimension_fails_before_expansion_math() { } /// Explicit 7-vertex torus (Heawood triangulation) with `GlobalTopology::Toroidal` -/// is rejected until explicit non-Euclidean construction has quotient embedding validation. +/// is rejected until explicit non-Euclidean construction has quotient realization validation. /// /// The 14-triangle closed mesh has Ο‡ = 0 (torus), but explicit quotient -/// connectivity cannot yet be validated against a faithful quotient embedding. +/// connectivity cannot yet be validated against a faithful quotient realization. #[test] fn test_explicit_toroidal_heawood_torus_rejected() { // Regular heptagon: 7 well-separated points, no 3 collinear. @@ -729,7 +729,7 @@ fn test_explicit_toroidal_heawood_torus_rejected() { .unwrap() .global_topology(topology) .build() - .expect_err("explicit toroidal connectivity requires a quotient embedding validator"); + .expect_err("explicit toroidal connectivity requires a quotient realization validator"); match err { DelaunayTriangulationConstructionError::ExplicitConstruction(