Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 32 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ efficient spatial indexing. Provides an explicit
[4-level validation hierarchy][Validation Guide] on individual elements,
triangulation data structure validity, manifold topology, and Delaunay property
adherence. Allows for the complete set of [Pachner moves] up to D=5 using
bistellar flips, vertex insertion and deletion, and the conversion of
bistellar flips insertion and deletion, and the conversion of
non-Delaunay triangulations into Delaunay triangulations via bounded
flip/rebuilds. Auxiliary data may be stored directly in vertices and simplices
with external [secondary maps][Secondary maps] provided for vertex- and
Expand Down Expand Up @@ -74,9 +74,9 @@ complete technical background.
for well-conditioned exploratory work.
- [x] D-dimensional [Convex hulls] and [Delaunay triangulations].
- [x] Euclidean and toroidal construction through
[`DelaunayTriangulationBuilder`]: `.toroidal(...)` builds the periodic
[`DelaunayTriangulationBuilder`]: `.try_toroidal(...)` builds the periodic
image-point quotient in validated dimensions, while
`.canonicalized_toroidal(...)` wraps coordinates without quotient rewiring.
`.try_canonicalized_toroidal(...)` wraps coordinates without quotient rewiring.
- [x] Exact predicates, stack-allocated linear algebra through [la-stack], and
deterministic SoS degeneracy handling.
- [x] Focused public preludes for common construction, query, geometry, repair,
Expand Down Expand Up @@ -119,17 +119,23 @@ prelude map and namespace policy, see the

```rust
use delaunay::prelude::construction::{
DelaunayTriangulationBuilder, DelaunayTriangulationConstructionError, vertex,
DelaunayTriangulationBuilder, DelaunayTriangulationConstructionError,
};

fn main() -> Result<(), DelaunayTriangulationConstructionError> {
let vertices = vec![
vertex!([0.0, 0.0, 0.0, 0.0]),
vertex!([1.0, 0.0, 0.0, 0.0]),
vertex!([0.0, 1.0, 0.0, 0.0]),
vertex!([0.0, 0.0, 1.0, 0.0]),
vertex!([0.0, 0.0, 0.0, 1.0]),
vertex!([0.2, 0.2, 0.2, 0.2]),
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 0.0, 0.0, 0.0])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([1.0, 0.0, 0.0, 0.0])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 1.0, 0.0, 0.0])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 0.0, 1.0, 0.0])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 0.0, 0.0, 1.0])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([0.2, 0.2, 0.2, 0.2])
.expect("finite vertex coordinates"),
];

let dt = DelaunayTriangulationBuilder::new(&vertices).build::<()>()?;
Expand All @@ -148,23 +154,29 @@ fn main() -> Result<(), DelaunayTriangulationConstructionError> {
### Toroidal Triangulations

For coordinate wrapping on a toroidal domain, use
`DelaunayTriangulationBuilder::canonicalized_toroidal`:
`DelaunayTriangulationBuilder::try_canonicalized_toroidal`:

```rust
use delaunay::prelude::construction::{
DelaunayTriangulationBuilder, DelaunayTriangulationConstructionError, TopologyKind, vertex,
DelaunayTriangulationBuilder, DelaunayTriangulationConstructionError, TopologyKind,
};

fn main() -> Result<(), DelaunayTriangulationConstructionError> {
let vertices = vec![
vertex!([0.1, 0.2]),
vertex!([0.8, 0.3]),
vertex!([0.5, 0.7]),
vertex!([1.2, 0.4]), // Wraps to [0.2, 0.4]
delaunay::prelude::Vertex::<(), _>::try_new([0.1, 0.2])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([0.8, 0.3])
.expect("finite vertex coordinates"),
delaunay::prelude::Vertex::<(), _>::try_new([0.5, 0.7])
.expect("finite vertex coordinates"),
// Wraps to [0.2, 0.4].
delaunay::prelude::Vertex::<(), _>::try_new([1.2, 0.4])
.expect("finite vertex coordinates"),
];

let dt = DelaunayTriangulationBuilder::new(&vertices)
.canonicalized_toroidal([1.0, 1.0])
.try_canonicalized_toroidal([1.0, 1.0])
.expect("unit toroidal domain is valid")
.build::<()>()?;

assert_eq!(dt.topology_kind(), TopologyKind::Toroidal);
Expand All @@ -173,7 +185,7 @@ fn main() -> Result<(), DelaunayTriangulationConstructionError> {
```

For boundary-facet identification and periodic neighbor pointers, use
`.toroidal([..])` in 2D or compact 3D; see the
`.try_toroidal([..])` in 2D or compact 3D; see the
[toroidal construction workflow] for the full recipe and current 4D/5D
guardrails.

Expand Down Expand Up @@ -257,8 +269,8 @@ For reproducible checks in CI/local runs, use `just check`, `just test`,
skipped none, ran final repair, and passed `validation_report` in about
52 seconds. The 3,000-point 4D harness remains a manual characterization probe
for issue #340 rather than routine CI.
- **Periodic domains:** `.toroidal()` uses the periodic image-point method and
is release-validated in 2D and compact 3D. `.canonicalized_toroidal()`
- **Periodic domains:** `.try_toroidal()` uses the periodic image-point method and
is release-validated in 2D and compact 3D. `.try_canonicalized_toroidal()`
canonicalizes coordinates into the fundamental domain without quotient
rewiring. 4D/5D periodic quotients fail fast pending scalable construction
work in issue #416.
Expand Down
31 changes: 21 additions & 10 deletions benches/allocation_hot_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ mod allocation_contracts {
use criterion::{BenchmarkGroup, BenchmarkId, Criterion, measurement::WallTime};
use delaunay::prelude::algorithms::{LocateResult, locate_with_stats};
use delaunay::prelude::construction::{
ConstructionOptions, DelaunayTriangulation, RetryPolicy, Vertex, vertex,
ConstructionOptions, DelaunayTriangulation, RetryPolicy, Vertex,
};
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::{
AdaptiveKernel, Coordinate, CoordinateRange, FastKernel, Point, simplex_volume,
AdaptiveKernel, CoordinateRange, FastKernel, Point, simplex_volume,
};
use delaunay::prelude::query::measure_with_result;
use delaunay::prelude::tds::{SimplexKey, TdsError, VertexKey, facet_key_from_vertices};
Expand All @@ -48,6 +48,10 @@ mod allocation_contracts {

type BenchTriangulation<const D: usize> = DelaunayTriangulation<AdaptiveKernel<f64>, (), (), D>;

fn finite_point<const D: usize>(coords: [f64; D]) -> Point<D> {
Point::try_new(coords).unwrap_or_else(|_| std::process::abort())
}

#[derive(Debug, Error)]
enum AllocationBenchError {
#[error("{dimension}D fixture did not contain a simplex")]
Expand Down Expand Up @@ -77,7 +81,7 @@ mod allocation_contracts {
dt: BenchTriangulation<D>,
simplex_key: SimplexKey,
facet_vertices: [VertexKey; D],
query: Point<f64, D>,
query: Point<D>,
simplex_count: usize,
vertex_count: usize,
}
Expand All @@ -96,10 +100,17 @@ mod allocation_contracts {
)
}

fn canary_vertices<const D: usize>(count: usize, seed: u64) -> Vec<Vertex<f64, (), D>> {
let points =
generate_random_points_in_range_seeded::<f64, D>(count, benchmark_bounds(), seed);
points.into_iter().map(|point| vertex!(point)).collect()
fn canary_vertices<const D: usize>(count: usize, seed: u64) -> Vec<Vertex<(), D>> {
let points = generate_random_points_in_range_seeded::<D>(count, benchmark_bounds(), seed);
points
.into_iter()
.map(|point| {
bench_result(
delaunay::prelude::Vertex::<(), _>::try_new(point.into()),
"finite benchmark vertex coordinates",
)
})
.collect()
}

fn first_simplex_key<const D: usize>(
Expand All @@ -114,7 +125,7 @@ mod allocation_contracts {
fn simplex_points<const D: usize>(
dt: &BenchTriangulation<D>,
simplex_key: SimplexKey,
) -> Result<Vec<Point<f64, D>>, AllocationBenchError> {
) -> Result<Vec<Point<D>>, AllocationBenchError> {
let tds = dt.tds();

tds.simplex_vertices(simplex_key)?
Expand Down Expand Up @@ -176,7 +187,7 @@ mod allocation_contracts {
fn simplex_barycenter<const D: usize>(
dt: &BenchTriangulation<D>,
simplex_key: SimplexKey,
) -> Result<Point<f64, D>, AllocationBenchError> {
) -> Result<Point<D>, AllocationBenchError> {
let points = simplex_points(dt, simplex_key)?;
let mut coords = [0.0_f64; D];
for point in &points {
Expand All @@ -194,7 +205,7 @@ mod allocation_contracts {
*coord *= inv_vertex_count;
}

Ok(Point::new(coords))
Ok(finite_point(coords))
}

fn prepare_fixture<const D: usize>(count: usize, seed: u64) -> DimensionFixture<D> {
Expand Down
24 changes: 18 additions & 6 deletions benches/boundary_uuid_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! preserving the quick performance probes.

use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use delaunay::prelude::construction::{DelaunayTriangulation, Vertex, vertex};
use delaunay::prelude::construction::{DelaunayTriangulation, Vertex};
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::CoordinateRange;
use delaunay::prelude::query::BoundaryAnalysis;
Expand All @@ -33,7 +33,7 @@ fn benchmark_bounds() -> CoordinateRange<f64> {
fn boundary_triangulation_3d(
requested_vertices: usize,
) -> DelaunayTriangulation<delaunay::prelude::geometry::AdaptiveKernel<f64>, (), (), 3> {
let points = generate_random_points_in_range_seeded::<f64, 3>(
let points = generate_random_points_in_range_seeded::<3>(
requested_vertices,
benchmark_bounds(),
0xB0DA_FACE_0000_0000 ^ requested_vertices as u64,
Expand Down Expand Up @@ -99,10 +99,22 @@ fn bench_boundary_facets_micro(c: &mut Criterion) {
fn uuid_iter_source()
-> DelaunayTriangulation<delaunay::prelude::geometry::AdaptiveKernel<f64>, (), (), 3> {
let vertices = vec![
vertex!([0.0, 0.0, 0.0]),
vertex!([1.0, 0.0, 0.0]),
vertex!([0.0, 1.0, 0.0]),
vertex!([0.0, 0.0, 1.0]),
bench_result(
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 0.0, 0.0]),
"finite benchmark vertex coordinates",
),
bench_result(
delaunay::prelude::Vertex::<(), _>::try_new([1.0, 0.0, 0.0]),
"finite benchmark vertex coordinates",
),
bench_result(
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 1.0, 0.0]),
"finite benchmark vertex coordinates",
),
bench_result(
delaunay::prelude::Vertex::<(), _>::try_new([0.0, 0.0, 1.0]),
"finite benchmark vertex coordinates",
),
];
bench_result(
DelaunayTriangulation::new(&vertices),
Expand Down
Loading
Loading