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
17 changes: 11 additions & 6 deletions benches/allocation_hot_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ mod allocation_contracts {
use delaunay::prelude::construction::{
ConstructionOptions, DelaunayTriangulation, RetryPolicy, Vertex, vertex,
};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::{
AdaptiveKernel, Coordinate, FastKernel, Point, simplex_volume,
AdaptiveKernel, Coordinate, CoordinateRange, FastKernel, Point, simplex_volume,
};
use delaunay::prelude::query::measure_with_result;
use delaunay::prelude::tds::{SimplexKey, TdsError, VertexKey, facet_key_from_vertices};
Expand Down Expand Up @@ -89,11 +89,16 @@ mod allocation_contracts {
attempts
}

fn benchmark_bounds() -> CoordinateRange<f64> {
bench_result(
CoordinateRange::try_new(-100.0_f64, 100.0),
"allocation benchmark bounds must be valid",
)
}

fn canary_vertices<const D: usize>(count: usize, seed: u64) -> Vec<Vertex<f64, (), D>> {
let points = bench_result(
generate_random_points_seeded::<f64, D>(count, (-100.0, 100.0), seed),
format!("failed to generate {D}D allocation benchmark points"),
);
let points =
generate_random_points_in_range_seeded::<f64, D>(count, benchmark_bounds(), seed);
points.into_iter().map(|point| vertex!(point)).collect()
}

Expand Down
22 changes: 13 additions & 9 deletions benches/boundary_uuid_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use delaunay::prelude::construction::{DelaunayTriangulation, Vertex, vertex};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::CoordinateRange;
use delaunay::prelude::query::BoundaryAnalysis;
use uuid::Uuid;

Expand All @@ -20,19 +21,22 @@ use std::hint::black_box;
pub mod bench_utils;
use bench_utils::{bench_option, bench_result};

const BOUNDS: (f64, f64) = (-100.0, 100.0);
const BOUNDARY_COUNTS_3D: &[usize] = &[20, 40, 60, 80];

fn benchmark_bounds() -> CoordinateRange<f64> {
bench_result(
CoordinateRange::try_new(-100.0_f64, 100.0),
"boundary benchmark bounds must be valid",
)
}

fn boundary_triangulation_3d(
requested_vertices: usize,
) -> DelaunayTriangulation<delaunay::prelude::geometry::AdaptiveKernel<f64>, (), (), 3> {
let points = bench_result(
generate_random_points_seeded::<f64, 3>(
requested_vertices,
BOUNDS,
0xB0DA_FACE_0000_0000 ^ requested_vertices as u64,
),
"failed to generate 3D boundary benchmark points",
let points = generate_random_points_in_range_seeded::<f64, 3>(
requested_vertices,
benchmark_bounds(),
0xB0DA_FACE_0000_0000 ^ requested_vertices as u64,
);
let vertices = Vertex::from_points(&points);
bench_result(
Expand Down
56 changes: 37 additions & 19 deletions benches/ci_performance_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ use delaunay::prelude::construction::{
ConstructionOptions, DelaunayTriangulation, RetryPolicy, Vertex,
};
use delaunay::prelude::flips::{FacetHandle, RidgeHandle, SimplexKey};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::geometry::{AdaptiveKernel, Coordinate, Point};
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::{AdaptiveKernel, Coordinate, CoordinateRange, Point};
use delaunay::prelude::query::ConvexHull;
use delaunay::vertex;
use std::{env, hint::black_box, num::NonZeroUsize, sync::Once};
Expand Down Expand Up @@ -321,7 +321,7 @@ fn print_manifest_once() {
fn prepare_data<const D: usize>(
dim_seed: u64,
count: usize,
bounds: (f64, f64),
bounds: CoordinateRange<f64>,
attempts: NonZeroUsize,
) -> (u64, Vec<Point<f64, D>>, Vec<Vertex<f64, (), D>>) {
// Fast path: use the pre-computed seed (single verification construction)
Expand All @@ -340,7 +340,7 @@ fn prepare_data<const D: usize>(
find_seed_vertices::<D>(base_seed, count, bounds, search_limit, attempts),
format_args!(
"No stable benchmark seed found for {D}D/{count}: \
start_seed={base_seed}; search_limit={search_limit}; bounds={bounds:?}"
start_seed={base_seed}; search_limit={search_limit}; bounds={bounds}"
),
)
}
Expand All @@ -366,7 +366,10 @@ fn warn_known_seed_failed<const D: usize>(seed: u64, count: usize, dataset: Data
}

fn prepare_dt<const D: usize>(dim_seed: u64, count: usize) -> BenchTriangulation<D> {
let bounds = (-100.0, 100.0);
let bounds = bench_result(
CoordinateRange::try_new(-100.0_f64, 100.0),
"well-conditioned benchmark bounds must be valid",
);
let attempts = retry_attempts(6);
let (seed, _, vertices) = prepare_data::<D>(dim_seed, count, bounds, attempts);
let options = ConstructionOptions::default().with_retry_policy(RetryPolicy::Shuffled {
Expand Down Expand Up @@ -404,9 +407,13 @@ fn prepare_inserts<const D: usize>(
seed ^= 0xA5A5_A5A5;
}
let points = match dataset {
Dataset::WellConditioned => bench_result(
generate_random_points_seeded::<f64, D>(count, (-50.0, 50.0), seed),
format!("insert point generation failed for {D}D"),
Dataset::WellConditioned => generate_random_points_in_range_seeded::<f64, D>(
count,
bench_result(
CoordinateRange::try_new(-50.0_f64, 50.0),
"insert benchmark bounds must be valid",
),
seed,
),
Dataset::Adversarial => generate_adv_points::<D>(count, seed),
};
Expand All @@ -416,16 +423,14 @@ fn prepare_inserts<const D: usize>(
fn find_seed_vertices<const D: usize>(
start_seed: u64,
count: usize,
bounds: (f64, f64),
bounds: CoordinateRange<f64>,
limit: usize,
attempts: NonZeroUsize,
) -> SeedSearchResult<D> {
for offset in 0..limit {
let candidate_seed = start_seed.wrapping_add(offset as u64);
let points = bench_result(
generate_random_points_seeded::<f64, D>(count, bounds, candidate_seed),
format!("generate_random_points_seeded failed for {D}D"),
);
let points =
generate_random_points_in_range_seeded::<f64, D>(count, bounds, candidate_seed);
let vertices = points.iter().map(|p| vertex!(*p)).collect::<Vec<_>>();

let options = ConstructionOptions::default().with_retry_policy(RetryPolicy::Shuffled {
Expand Down Expand Up @@ -496,9 +501,13 @@ fn prepare_adv_data<const D: usize>(
}

fn generate_adv_points<const D: usize>(count: usize, seed: u64) -> Vec<Point<f64, D>> {
let base_points = bench_result(
generate_random_points_seeded::<f64, D>(count, (-1.0, 1.0), seed),
format!("generate_random_points_seeded failed for adversarial {D}D"),
let base_points = generate_random_points_in_range_seeded::<f64, D>(
count,
bench_result(
CoordinateRange::try_new(-1.0_f64, 1.0),
"adversarial benchmark bounds must be valid",
),
seed,
);

base_points
Expand Down Expand Up @@ -900,7 +909,10 @@ macro_rules! benchmark_tds_new_dimension {
// We avoid `std::process::exit` here so that destructors run and Criterion
// can clean up state on both success and failure.
if discover_seeds_enabled() {
let bounds = (-100.0, 100.0);
let bounds = bench_result(
CoordinateRange::try_new(-100.0_f64, 100.0),
"well-conditioned benchmark bounds must be valid",
);
let filters = criterion_filters();

let bench_id = format!("tds_new_{}d/tds_new/{count}", stringify!($dim));
Expand Down Expand Up @@ -945,7 +957,10 @@ macro_rules! benchmark_tds_new_dimension {
format!("tds_new_{}d/tds_new_adversarial/{count}", stringify!($dim));

if benchmark_selected(&filters, &bench_id) {
let bounds = (-100.0, 100.0);
let bounds = bench_result(
CoordinateRange::try_new(-100.0_f64, 100.0),
"well-conditioned benchmark bounds must be valid",
);
let attempts = retry_attempts(6);
let (seed, _, vertices) = prepare_data::<$dim>($seed, count, bounds, attempts);
let options = ConstructionOptions::default().with_retry_policy(
Expand Down Expand Up @@ -985,7 +1000,10 @@ macro_rules! benchmark_tds_new_dimension {
group.bench_with_input(BenchmarkId::new("tds_new", count), &count, |b, &count| {
// Reduce variance: pre-generate deterministic inputs outside the measured loop,
// then benchmark only triangulation construction.
let bounds = (-100.0, 100.0);
let bounds = bench_result(
CoordinateRange::try_new(-100.0_f64, 100.0),
"well-conditioned benchmark bounds must be valid",
);
let attempts = retry_attempts(6);
let (seed, points, vertices) =
prepare_data::<$dim>($seed, count, bounds, attempts);
Expand Down
28 changes: 18 additions & 10 deletions benches/circumsphere_containment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
//! - Numerical consistency validation between all three algorithms

use criterion::{Criterion, criterion_group, criterion_main};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::CoordinateRange;
use delaunay::prelude::query::*;
use std::hint::black_box;

Expand All @@ -23,6 +24,10 @@ use std::hint::black_box;
pub mod bench_utils;
use bench_utils::{abort_benchmark, bench_option, bench_result};

fn coordinate_range(min: f64, max: f64, context: &'static str) -> CoordinateRange<f64> {
bench_result(CoordinateRange::try_new(min, max), context)
}

/// Generate a standard D-dimensional simplex (D+1 vertices)
///
/// Creates a simplex with vertices at:
Expand All @@ -46,17 +51,19 @@ fn standard_simplex<const D: usize>() -> Vec<Point<f64, D>> {

/// Generate a random 3D simplex (tetrahedron) for benchmarking using seeded generation
fn generate_random_simplex_3d(seed: u64) -> Vec<Point<f64, 3>> {
bench_result(
generate_random_points_seeded(4, (-10.0, 10.0), seed),
"failed to generate random simplex points",
generate_random_points_in_range_seeded(
4,
coordinate_range(-10.0, 10.0, "random simplex bounds must be valid"),
seed,
)
}

/// Generate a random 3D test point using seeded generation
fn generate_random_test_point_3d(seed: u64) -> Point<f64, 3> {
let points = bench_result(
generate_random_points_seeded(1, (-5.0, 5.0), seed),
"failed to generate random test point",
let points = generate_random_points_in_range_seeded(
1,
coordinate_range(-5.0, 5.0, "random test point bounds must be valid"),
seed,
);
bench_option(points.into_iter().next(), "expected exactly one test point")
}
Expand All @@ -67,9 +74,10 @@ fn benchmark_random_queries(c: &mut Criterion) {
let simplex_points = generate_random_simplex_3d(42);

// Generate many test points using seeded generation for reproducible results
let test_points = bench_result(
generate_random_points_seeded(1000, (-5.0, 5.0), 123),
"failed to generate random test points",
let test_points = generate_random_points_in_range_seeded(
1000,
coordinate_range(-5.0, 5.0, "random query bounds must be valid"),
123,
);

c.bench_function("random/insphere_1000_queries", |b| {
Expand Down
21 changes: 14 additions & 7 deletions benches/cold_path_predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
//! ```

use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::CoordinateRange;
use delaunay::prelude::query::*;
use std::hint::black_box;

Expand All @@ -44,6 +45,10 @@ use std::hint::black_box;
pub mod bench_utils;
use bench_utils::{abort_benchmark, bench_result};

fn coordinate_range(min: f64, max: f64, context: &'static str) -> CoordinateRange<f64> {
bench_result(CoordinateRange::try_new(min, max), context)
}

/// Deterministic seed for query-point generation in the hot path.
const HOT_SEED: u64 = 0xC01D_BEEF_0000_CAFE_u64;
/// Deterministic seed for query-point generation in the near-boundary group.
Expand Down Expand Up @@ -72,9 +77,10 @@ fn standard_simplex<const D: usize>() -> Vec<Point<f64, D>> {
/// Uses the range `[-10, 10]` against a unit simplex so that the Shewchuk
/// errbound comfortably resolves the sign in Stage 1.
fn hot_queries<const D: usize>() -> Vec<Point<f64, D>> {
bench_result(
generate_random_points_seeded(HOT_QUERIES, (-10.0, 10.0), HOT_SEED),
"failed to generate hot-path query points",
generate_random_points_in_range_seeded(
HOT_QUERIES,
coordinate_range(-10.0, 10.0, "hot-path query bounds must be valid"),
HOT_SEED,
)
}

Expand All @@ -86,9 +92,10 @@ fn near_boundary_queries<const D: usize>() -> Vec<Point<f64, D>> {
// Centered near the circumsphere radius of the standard simplex (~0.5 for
// the D = 3 unit case); the exact value is unimportant — we just want a
// high rate of errbound-ambiguous inputs.
bench_result(
generate_random_points_seeded(NEAR_BOUNDARY_QUERIES, (0.40, 0.60), NEAR_BOUNDARY_SEED),
"failed to generate near-boundary query points",
generate_random_points_in_range_seeded(
NEAR_BOUNDARY_QUERIES,
coordinate_range(0.40, 0.60, "near-boundary query bounds must be valid"),
NEAR_BOUNDARY_SEED,
)
}

Expand Down
Loading
Loading