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
2 changes: 1 addition & 1 deletion .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ concurrency:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
UV_VERSION: "0.11.26"
UV_VERSION: "0.11.27"
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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ env:
RUMDL_VERSION: "0.2.28"
TAPLO_VERSION: "0.10.0"
TYPOS_VERSION: "1.48.0"
UV_VERSION: "0.11.26"
UV_VERSION: "0.11.27"
ZIZMOR_VERSION: "1.26.1"

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/generate-baseline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ permissions:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
UV_VERSION: "0.11.26"
UV_VERSION: "0.11.27"
# 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
Expand Down
17 changes: 4 additions & 13 deletions .github/workflows/papers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ env:
JUST_VERSION: "1.55.1"
TECTONIC_VERSION: "0.16.9"
TEX_FMT_VERSION: "0.5.7"
UV_VERSION: "0.11.26"
UV_VERSION: "0.11.27"

jobs:
papers:
runs-on: ubuntu-latest
runs-on: macos-latest
timeout-minutes: 30

steps:
Expand Down Expand Up @@ -86,17 +86,8 @@ jobs:

- name: Install paper system dependencies
run: |
sudo apt-get update
sudo apt-get install --yes \
chktex \
libfontconfig1-dev \
libfreetype6-dev \
libgraphite2-dev \
libharfbuzz-dev \
libicu-dev \
libpng-dev \
pkg-config \
zlib1g-dev
brew update
brew install chktex libpng pkgconf

- name: Install just
uses: taiki-e/cache-cargo-install-action@417450f3c33ee20393705369577571770643d4c7 # v3.0.7
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
UV_VERSION: "0.11.26"
UV_VERSION: "0.11.27"

jobs:
release-baseline:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/semgrep-sarif.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ permissions:
actions: read

env:
UV_VERSION: "0.11.26"
UV_VERSION: "0.11.27"

jobs:
semgrep-sarif:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ This project is licensed under the [BSD 3-Clause License](https://github.com/acg
[Pachner moves]: https://en.wikipedia.org/wiki/Pachner_move
[PL-manifold]: https://en.wikipedia.org/wiki/Piecewise_linear_manifold
[Pseudomanifold]: https://en.wikipedia.org/wiki/Pseudomanifold
[readme-hero]: docs/images/delaunay_3d_readme.png
[readme-hero]: https://raw.githubusercontent.com/acgetchell/delaunay/main/docs/images/delaunay_3d_readme.png
[Secondary maps]: docs/workflows.md#builder-api-auxiliary-vertex-and-simplex-data
[Simulation of Simplicity]: docs/numerical_robustness_guide.md#simulation-of-simplicity-sos
[Validation Guide]: docs/validation.md
144 changes: 143 additions & 1 deletion benches/ci_performance_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ use criterion::{
BatchSize, BenchmarkGroup, BenchmarkId, Criterion, Throughput, criterion_group, criterion_main,
};
use delaunay::flips::{FacetHandle, RidgeHandle, SimplexKey};
use delaunay::prelude::collections::FastHashMap;
use delaunay::prelude::construction::{
ConstructionOptions, DelaunayTriangulation, RetryPolicy, Vertex,
ConstructionOptions, DelaunayTriangulation, DelaunayTriangulationBuilder, RetryPolicy, Vertex,
};
use delaunay::prelude::generators::generate_random_points_in_range_seeded;
use delaunay::prelude::geometry::{AdaptiveKernel, CoordinateRange, Point};
Expand Down Expand Up @@ -89,9 +90,18 @@ const CANARY_COUNT_5D: usize = 25;
const INSERT_BATCH_COUNT_2D_3D: usize = 10;
const INSERT_BATCH_COUNT_4D: usize = 6;
const INSERT_BATCH_COUNT_5D: usize = 4;
const EXPLICIT_IMPORT_COUNT_2D: usize = 120;
const EXPLICIT_IMPORT_COUNT_3D: usize = 30;
const EXPLICIT_IMPORT_COUNT_4D: usize = 16;
const EXPLICIT_IMPORT_COUNT_5D: usize = 10;
type SeedSearchResult<const D: usize> = Option<(u64, Vec<Point<D>>, Vec<Vertex<(), D>>)>;
type BenchTriangulation<const D: usize> = DelaunayTriangulation<AdaptiveKernel<f64>, (), (), D>;

struct ExplicitImportFixture<const D: usize> {
vertices: Vec<Vertex<(), D>>,
simplices: Vec<Vec<usize>>,
}

fn finite_point<const D: usize>(coords: [f64; D]) -> Point<D> {
Point::try_new(coords).unwrap_or_else(|_| std::process::abort())
}
Expand Down Expand Up @@ -186,6 +196,16 @@ fn insert_benchmark_ids() -> String {
.join(";")
}

fn explicit_import_benchmark_ids() -> String {
[
format!("explicit_import/import_2d/{EXPLICIT_IMPORT_COUNT_2D}"),
format!("explicit_import/import_3d/{EXPLICIT_IMPORT_COUNT_3D}"),
format!("explicit_import/import_4d/{EXPLICIT_IMPORT_COUNT_4D}"),
format!("explicit_import/import_5d/{EXPLICIT_IMPORT_COUNT_5D}"),
]
.join(";")
}

fn api_benchmark_entries() -> Vec<ApiBenchmarkEntry> {
vec![
ApiBenchmarkEntry {
Expand Down Expand Up @@ -230,6 +250,13 @@ fn api_benchmark_entries() -> Vec<ApiBenchmarkEntry> {
benchmark_ids: insert_benchmark_ids(),
note: "insert_batches_into_calibrated_well_conditioned_and_adversarial_triangulations",
},
ApiBenchmarkEntry {
group: "explicit_import",
public_api: "DelaunayTriangulationBuilder::try_from_vertices_and_simplices(...).construction_options(without_final_delaunay_enforcement).build",
dimensions: "2,3,4,5",
benchmark_ids: explicit_import_benchmark_ids(),
note: "reimport_valid_levels_1_through_4_connectivity_from_public_vertex_and_simplex_iterators",
},
ApiBenchmarkEntry {
group: "bistellar_flips",
public_api: "BistellarFlips::{flip_k1_insert,flip_k1_remove,flip_k2,flip_k2_inverse_from_edge,flip_k3,flip_k3_inverse_from_triangle}",
Expand Down Expand Up @@ -397,6 +424,56 @@ fn prepare_adv_dt<const D: usize>(dim_seed: u64, count: usize) -> BenchTriangula
.or_abort()
}

/// Export a valid Delaunay triangulation through public iterators for explicit reimport.
fn prepare_explicit_import_fixture<const D: usize>(
dim_seed: u64,
count: usize,
) -> ExplicitImportFixture<D> {
let seed = dim_seed.wrapping_add(count as u64);
let points = generate_random_points_in_range_seeded::<D>(
count,
CoordinateRange::try_new(-100.0_f64, 100.0).or_abort(),
seed,
)
.or_abort();
let source_vertices = try_vertices_from_points(&points).or_abort();
let attempts = retry_attempts(8);
let options = ConstructionOptions::default().with_retry_policy(RetryPolicy::Shuffled {
attempts,
base_seed: Some(seed),
});
let dt: BenchTriangulation<D> = DelaunayTriangulation::builder(&source_vertices)
.construction_options(options)
.build()
.or_abort();
let mut key_to_index = FastHashMap::default();
let mut vertices = Vec::with_capacity(dt.number_of_vertices());

for (index, (vertex_key, vertex)) in dt.vertices().enumerate() {
key_to_index.insert(vertex_key, index);
vertices.push(*vertex);
}

let mut simplices = Vec::with_capacity(dt.number_of_simplices());
for (_, simplex) in dt.simplices() {
let mut spec = Vec::with_capacity(D + 1);
for vertex_key in simplex.vertices() {
let Some(&vertex_index) = key_to_index.get(vertex_key) else {
abort_benchmark(format_args!(
"{D}D explicit import fixture simplex references an unknown vertex key"
));
};
spec.push(vertex_index);
}
simplices.push(spec);
}

ExplicitImportFixture {
vertices,
simplices,
}
}

fn prepare_inserts<const D: usize>(
dim_seed: u64,
count: usize,
Expand Down Expand Up @@ -1262,6 +1339,38 @@ fn bench_insert_case<const D: usize>(
);
}

fn bench_explicit_import_case<const D: usize>(
group: &mut BenchmarkGroup<'_, WallTime>,
fixture: &ExplicitImportFixture<D>,
) {
group.throughput(Throughput::Elements(fixture.simplices.len() as u64));
group.bench_function(
BenchmarkId::new(
format!("import_{D}d"),
format!(
"vertices_{}_simplices_{}",
fixture.vertices.len(),
fixture.simplices.len()
),
),
|b| {
b.iter(|| {
let dt = DelaunayTriangulationBuilder::try_from_vertices_and_simplices(
&fixture.vertices,
&fixture.simplices,
)
.or_abort()
.construction_options(
ConstructionOptions::default().without_final_delaunay_enforcement(),
)
.build()
.or_abort();
black_box(dt);
});
},
);
}

fn benchmark_boundary_facets(c: &mut Criterion) {
print_manifest_once();
if discover_seeds_enabled() {
Expand Down Expand Up @@ -1609,6 +1718,38 @@ fn benchmark_insert(c: &mut Criterion) {
group.finish();
}

fn benchmark_explicit_import(c: &mut Criterion) {
print_manifest_once();
if discover_seeds_enabled() {
return;
}
let filters = criterion_filters();
let mut group = c.benchmark_group("explicit_import");
group.sample_size(10);

if benchmark_selected(&filters, "explicit_import/import_2d") {
let fixture_2d = prepare_explicit_import_fixture::<2>(42, EXPLICIT_IMPORT_COUNT_2D);
bench_explicit_import_case(&mut group, &fixture_2d);
}

if benchmark_selected(&filters, "explicit_import/import_3d") {
let fixture_3d = prepare_explicit_import_fixture::<3>(123, EXPLICIT_IMPORT_COUNT_3D);
bench_explicit_import_case(&mut group, &fixture_3d);
}

if benchmark_selected(&filters, "explicit_import/import_4d") {
let fixture_4d = prepare_explicit_import_fixture::<4>(456, EXPLICIT_IMPORT_COUNT_4D);
bench_explicit_import_case(&mut group, &fixture_4d);
}

if benchmark_selected(&filters, "explicit_import/import_5d") {
let fixture_5d = prepare_explicit_import_fixture::<5>(789, EXPLICIT_IMPORT_COUNT_5D);
bench_explicit_import_case(&mut group, &fixture_5d);
}

group.finish();
}

/// Registers the complete 2D-5D public bistellar flip benchmark matrix.
fn benchmark_bistellar_flips(c: &mut Criterion) {
print_manifest_once();
Expand Down Expand Up @@ -1778,6 +1919,7 @@ criterion_group!(
benchmark_convex_hull_queries,
benchmark_validation,
benchmark_insert,
benchmark_explicit_import,
benchmark_bistellar_flips
);
criterion_main!(benches);
3 changes: 2 additions & 1 deletion docs/api_design.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,8 @@ fn main() -> Result<(), ExampleError> {
2. **Delaunay flip repair** — k=2/k=3 bistellar flips to restore the
empty-circumsphere property.
3. **Optional fallback rebuild** — rebuilds from the vertex set when both
repair passes fail (`DelaunayizeConfig { fallback_rebuild: true, .. }`).
repair passes fail
(`DelaunayizeConfig::default().with_fallback_rebuild(true)`).
If a failed topology repair is recovered by fallback rebuild,
`outcome.topology_repair.succeeded` remains `false`; use
`outcome.used_fallback_rebuild` to distinguish successful rebuild recovery
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/tooling-alignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ The useful updates ported in this pass are:
separately installs `chktex` from the system package manager because it is TeX
distribution tooling rather than a Rust CLI, and installs the Linux native
bridge-library headers required when compiling Tectonic from Cargo. All
uv-backed workflows use uv 0.11.26 to match the local Python tooling
uv-backed workflows use uv 0.11.27 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
Expand Down
10 changes: 4 additions & 6 deletions examples/delaunayize_repair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,10 @@ fn custom_config_2d() -> Result<(), DelaunayizeRepairExampleError> {
let mut dt: DelaunayTriangulation<_, (), (), 2> =
DelaunayTriangulationBuilder::new(&vertices).build()?;

let config = DelaunayizeConfig {
topology_max_iterations: 10,
topology_max_simplices_removed: 100,
fallback_rebuild: true,
delaunay_max_flips: None,
};
let config = DelaunayizeConfig::default()
.with_topology_max_iterations(10)
.with_topology_max_simplices_removed(100)
.with_fallback_rebuild(true);

println!(
" Config: max_iterations={}, max_simplices_removed={}, fallback={}",
Expand Down
Loading
Loading