Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ just check
just ci
```

Codex sandbox shells may not include Homebrew on `PATH`. When a validation
recipe or direct tooling command needs `uv`, prefer:

```bash
PATH=/opt/homebrew/bin:$PATH just check
/opt/homebrew/bin/uv run pytest scripts/tests
```

Refer to `docs/dev/commands.md` for full details.

For tooling-alignment work, update `docs/dev/tooling-alignment.md` with the
Expand Down
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,15 @@ PRs are evaluated on:
- **Style**: Does the code follow project conventions?
- **Mathematical Accuracy**: Are geometric algorithms correct?

### Non-Substantive Changes

PRs that only introduce whitespace churn, blank-line changes, formatting noise, or other
non-substantive edits may be declined unless they are part of a clearly justified cleanup or
required by project tooling.

Accepted contributions should materially improve correctness, numerical robustness, topology
invariants, performance, documentation clarity, tests, maintainability, or user-facing behavior.

### Handling Feedback

- **Respond to all comments**: Address each piece of feedback
Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,16 @@ Choose the smallest prelude that matches the task:

| Task | Import |
|---|---|
| Build, configure, insert, or remove vertices | `use delaunay::prelude::triangulation::*` |
| Construct/configure a Delaunay triangulation | `use delaunay::prelude::triangulation::construction::*` |
| Read-only traversal, adjacency, convex hulls, and comparison helpers | `use delaunay::prelude::query::*` |
| Points, kernels, predicates, and geometric measures | `use delaunay::prelude::geometry::*` |
| Random points or triangulations for examples, tests, and benchmarks | `use delaunay::prelude::generators::*` |
| Low-level incremental insertion building blocks | `use delaunay::prelude::triangulation::insertion::*` |
| Bistellar flips / Edit API | `use delaunay::prelude::triangulation::flips::*` |
| Delaunay repair diagnostics and policies | `use delaunay::prelude::triangulation::repair::*` |
| Delaunayize workflow | `use delaunay::prelude::triangulation::delaunayize::*` |
| Construction telemetry diagnostics | `use delaunay::prelude::triangulation::diagnostics::*` |
| Construction validation cadence/policy | `use delaunay::prelude::triangulation::validation::*` |
| Hilbert ordering and quantization utilities | `use delaunay::prelude::ordering::*` |
| Low-level TDS cells, facets, keys, and validation reports | `use delaunay::prelude::tds::*` |
| Collection aliases and small buffers | `use delaunay::prelude::collections::*` |
Expand All @@ -107,9 +110,11 @@ Choose the smallest prelude that matches the task:

`use delaunay::prelude::*` remains available for quick experiments, but examples
and benchmarks in this repository prefer focused preludes so imports document intent.
The broad `delaunay::prelude::triangulation::*` import is retained for compatibility,
but new docs and tests should prefer the narrow workflow preludes above.

```rust
use delaunay::prelude::triangulation::*;
use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, vertex};

// Create a 4D Delaunay triangulation from a set of vertices (uses AdaptiveKernel by default).
let vertices = vec![
Expand Down Expand Up @@ -138,7 +143,9 @@ assert!(dt.is_valid().is_ok());
For periodic boundary conditions, use `DelaunayTriangulationBuilder`:

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

// Phase 1: Canonicalization (wraps coordinates into [0, 1)²)
let vertices = vec![
Expand Down Expand Up @@ -196,7 +203,11 @@ The construction pipeline exposes deterministic controls for experiments and reg
- Explicit topology/validation configuration via `TopologyGuarantee` and `ValidationPolicy`

```rust
use delaunay::prelude::triangulation::*;
use delaunay::prelude::triangulation::construction::{
ConstructionOptions, DedupPolicy, DelaunayTriangulationBuilder, InsertionOrderStrategy,
RetryPolicy, TopologyGuarantee, vertex,
};
use delaunay::prelude::triangulation::validation::ValidationPolicy;

let vertices = vec![
vertex!([0.0, 0.0]),
Expand Down
8 changes: 5 additions & 3 deletions benches/ci_performance_suite.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![forbid(unsafe_code)]

//! CI Performance Suite - optimized performance regression testing for CI/CD
//!
//! This benchmark is the small, durable performance contract for the delaunay
Expand Down Expand Up @@ -36,12 +38,12 @@ use delaunay::prelude::geometry::{
AdaptiveKernel, Coordinate, Point, RobustKernel, simplex_volume,
};
use delaunay::prelude::query::ConvexHull;
use delaunay::prelude::triangulation::construction::{
ConstructionOptions, DelaunayTriangulation, InsertionOrderStrategy, RetryPolicy, Vertex,
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.
use delaunay::prelude::triangulation::flips::{
BistellarFlips, CellKey, EdgeKey, FacetHandle, RidgeHandle, TopologyGuarantee, TriangleHandle,
};
use delaunay::prelude::triangulation::{
ConstructionOptions, DelaunayTriangulation, InsertionOrderStrategy, RetryPolicy, Vertex,
};
use delaunay::vertex;
use std::{env, hint::black_box, num::NonZeroUsize, sync::Once};
#[cfg(feature = "bench-logging")]
Expand Down
2 changes: 1 addition & 1 deletion benches/large_scale_performance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
use criterion::{BatchSize, Criterion, Throughput, criterion_group, criterion_main};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::geometry::AdaptiveKernel;
use delaunay::prelude::triangulation::{
use delaunay::prelude::triangulation::construction::{
ConstructionOptions, DelaunayTriangulation, RetryPolicy, Vertex,
};
use delaunay::vertex;
Expand Down
2 changes: 1 addition & 1 deletion benches/profiling_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ use delaunay::prelude::generators::{
};
use delaunay::prelude::geometry::{Coordinate, safe_usize_to_scalar};
use delaunay::prelude::query::*;
use delaunay::prelude::triangulation::{
use delaunay::prelude::triangulation::construction::{
ConstructionOptions, DelaunayTriangulationBuilder, RetryPolicy,
};
use delaunay::vertex;
Expand Down
8 changes: 5 additions & 3 deletions benches/topology_guarantee_construction.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![forbid(unsafe_code)]

//! Benchmark: construction cost vs topology guarantee (2D–5D)
//!
//! This benchmark compares `TopologyGuarantee::Pseudomanifold`, `TopologyGuarantee::PLManifold`
Expand All @@ -14,9 +16,9 @@

use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use delaunay::prelude::generators::generate_random_points_seeded;
use delaunay::prelude::triangulation::{
DelaunayRepairPolicy, DelaunayTriangulation, TopologyGuarantee, ValidationPolicy,
};
use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, TopologyGuarantee};
use delaunay::prelude::triangulation::repair::DelaunayRepairPolicy;
use delaunay::prelude::triangulation::validation::ValidationPolicy;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
use delaunay::vertex;
use std::hint::black_box;
use std::time::Duration;
Expand Down
8 changes: 4 additions & 4 deletions docs/api_design.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ The library provides two distinct APIs for different use cases:
For most use cases, the simple constructor is sufficient:

```rust
use delaunay::prelude::triangulation::*;
use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, vertex};

// Simple construction from vertices (Euclidean space, default options)
let vertices = vec![
Expand All @@ -87,7 +87,7 @@ For advanced configuration (toroidal topology, custom validation policies, etc.)
use `DelaunayTriangulationBuilder`:

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

// Toroidal (periodic) triangulation in 2D
let vertices = vec![
Expand Down Expand Up @@ -148,7 +148,7 @@ for topology guarantee and validation policy details.
The Edit API is exposed through the `BistellarFlips` trait in `prelude::triangulation::flips`:

```rust
use delaunay::prelude::triangulation::*;
use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, vertex};
use delaunay::prelude::triangulation::flips::*;

// Start with a valid triangulation
Expand Down Expand Up @@ -257,7 +257,7 @@ After applying flips, you should:
You can mix both APIs in the same workflow:

```rust
use delaunay::prelude::triangulation::*;
use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, vertex};
use delaunay::prelude::triangulation::flips::*;

// 1. Build initial triangulation (Builder API)
Expand Down
120 changes: 120 additions & 0 deletions docs/archive/issue_341_n1_repair_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Issue #341: N=1 Repair Performance Plan

This note captures the current plan for resolving #341 after defaulting batch
construction repair to every insertion (`N=1`). The goal is reasonable
performance on 10K vertices in 3D without compromising correctness,
orthogonality, or valid Delaunay output.

## Priority Order

1. Numerical correctness
2. Topological correctness
3. Orthogonality and maintainability
4. Performance within scope

## Current Direction

The branch now treats `EveryInsertion` / `N=1` as the default batch repair
cadence. Because of that, the next performance work should not optimize around
the `N=2` slowdown directly unless it exposes the same hotspot that affects the
default path.

The local flip-repair path has already been improved enough that it is no
longer the dominant 10K cost. The post-insertion topology validation path has
also been scoped to the cells touched by each ordinary insertion. The hot
insertion path now avoids full-TDS orientation normalization when the local
mutation scope is known. The remaining dominant costs are local repair, hull
extension, and ordinary insertion overhead.

## Latest Measurements

### 3K 3D, `N=1`

#### Before Scoped Post-Insertion Topology Validation

- Result: valid Delaunay triangulation, no skipped vertices.
- Total wall time: 54.571s.
- Insertion wall time: 52.908s.
- Local repairs: 485 calls, 5.499s total, 74.848ms max.
- Final repair: 1.082s, 0 flips.
- Final validation report: 580.243ms, OK.

#### After Scoped Post-Insertion Topology Validation

- Result: valid Delaunay triangulation, no skipped vertices.
- Total wall time: 27.991s.
- Insertion wall time: 26.356s.
- Local repairs: 485 calls, 5.561s total, 74.713ms max.
- Final repair: 1.068s, 0 flips.
- Final validation report: 565.459ms, OK.

#### After Local Insertion Orientation Validation

- Result: valid Delaunay triangulation, no skipped vertices.
- Total wall time: 14.599s.
- Insertion wall time: 12.950s.
- Cavity insertions: 2511 calls, 143.671ms total, 0.238ms max.
- Local repairs: 485 calls, 5.653s total, 76.645ms max.
- Final repair: 1.072s, 0 flips.
- Final validation report: 576.049ms, OK.

### 10K 3D, `N=1`

#### Before Scoped Post-Insertion Topology Validation

- Result: valid Delaunay triangulation, no skipped vertices.
- Total wall time: 630.582s.
- Insertion loop: 622.605s.
- Local repairs: 1037 calls, 35.162s total, 384.335ms max.
- Final repair: 3.784s, 0 flips.
- Final validation report: 2.004s, OK.
- Sampling showed the current hotspot in `validate_after_insertion`, especially
`validate_ridge_links`, ridge-link graph construction, and temporary
facet/ridge key work.

#### After Scoped Post-Insertion Topology Validation

- Result: valid Delaunay triangulation, no skipped vertices.
- Total wall time: 261.368s.
- Insertion loop: 253.540s.
- Transactional insertion wall: 190.238s.
- Cavity insertions: 8959 calls, 145.820s total, 36.662ms max.
- Hull extensions: 1037 calls, 14.403s total, 43.503ms max.
- Local repairs: 1037 calls, 46.638s total, 383.214ms max.
- Final repair: 3.689s, 0 flips.
- Final validation report: 2.008s, OK.

#### After Local Insertion Orientation Validation

- Result: valid Delaunay triangulation, no skipped vertices.
- Total wall time: 99.466s.
- Insertion loop: 91.593s.
- Transactional insertion wall: 29.593s.
- Cavity insertions: 8959 calls, 743.262ms total, 0.496ms max.
- Hull extensions: 1037 calls, 14.276s total, 40.226ms max.
- Local repairs: 1037 calls, 45.478s total, 370.416ms max.
- Final repair: 3.713s, 0 flips.
- Final validation report: 2.015s, OK.

## Plan

1. Preserve the correctness model: every mutation must remain locally
topology-safe, and final seeded repair, final global fallback, orientation
canonicalization, and final validation must remain enabled.
2. Keep the scoped post-insertion topology validation path and compare it
against full validation in focused tests whenever its scope changes.
3. Keep full validation available for final validation, explicit public
validation, and any path where the mutation scope cannot be represented
precisely.
4. Profile and optimize local repair without changing correctness: prioritize
repeated facet/ridge checks, queue deduplication, and frontier narrowing.
5. Re-run the 3K and 10K large-scale debug cases with `N=1`, then compare
local repair time, hull-extension time, final repair, and final validation.
6. Reconsider #364 only if profiling shows snapshot/rollback or postcondition
replay dominates after topology validation is scoped.

## Immediate Next Step

Decide whether the ~99s 10K result is sufficient for #341. If not, profile the
local repair facet/ridge queues at 10K scale and reduce repeated checks without
weakening the final repair or final validation safety nets.
11 changes: 10 additions & 1 deletion docs/code_organization.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,10 @@ delaunay/
│ │ ├── builder.rs
│ │ ├── delaunay.rs
│ │ ├── delaunayize.rs
│ │ └── flips.rs
│ │ ├── flips.rs
│ │ ├── locality.rs
│ │ └── validation.rs
│ ├── triangulation.rs
│ └── lib.rs
├── tests/
│ ├── semgrep/
Expand Down Expand Up @@ -431,6 +434,12 @@ The `benchmark-utils` CLI provides integrated benchmark workflow functionality,
- `delaunayize.rs` - End-to-end "repair then delaunayize" workflow (`delaunayize_by_flips`);
bounded topology repair + flip-based Delaunay repair + optional fallback rebuild
- `flips.rs` - High-level bistellar flip (Pachner move) trait and supporting public types; delegates to `core::algorithms::flips`
- `locality.rs` - Local seed/frontier helpers for Hilbert-local construction and repair
- `validation.rs` - Construction validation cadence and scheduling helpers

**`src/triangulation.rs`** - Public facade for triangulation-facing workflows.
It keeps the module namespace stable while the implementation is split across
orthogonal files under `src/triangulation/`.

**`src/topology/`** - Topology analysis and validation:

Expand Down
9 changes: 6 additions & 3 deletions docs/dev/debug_env_vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,18 @@ and release builds.
| `DELAUNAY_LARGE_DEBUG_BALL_RADIUS` | **value** | Radius for ball distribution |
| `DELAUNAY_LARGE_DEBUG_BOX_HALF_WIDTH` | **value** | Half-width for box distribution |
| `DELAUNAY_LARGE_DEBUG_CONSTRUCTION_MODE` | **value** | `new` (batch) or `incremental` |
| `DELAUNAY_LARGE_DEBUG_DEBUG_MODE` | **value** | `cadenced` or `strict` |
| `DELAUNAY_LARGE_DEBUG_INITIAL_SIMPLEX` | **value** | Batch initial simplex strategy: `max-volume` (default), `balanced`, or `first` |
| `DELAUNAY_LARGE_DEBUG_DEBUG_MODE` | **value** | `cadenced` (ridge-link) or `strict` (per-insertion vertex-link) |
| `DELAUNAY_LARGE_DEBUG_SHUFFLE_SEED` | **value** | Vertex shuffle seed |
| `DELAUNAY_LARGE_DEBUG_PROGRESS_EVERY` | **value** | Progress logging interval |
| `DELAUNAY_LARGE_DEBUG_VALIDATE_EVERY` | **value** | Validation interval |
| `DELAUNAY_LARGE_DEBUG_REPAIR_EVERY` | **value** | Repair interval |
| `DELAUNAY_LARGE_DEBUG_REPAIR_EVERY` | **value** | Batch/incremental repair interval (default: 1) |
| `DELAUNAY_LARGE_DEBUG_REPAIR_MAX_FLIPS` | **value** | Flip budget override |
| `DELAUNAY_LARGE_DEBUG_MAX_RUNTIME_SECS` | **value** | Timeout (0 = no cap) |
| `DELAUNAY_LARGE_DEBUG_ALLOW_SKIPS` | presence | Allow vertex insertion skips |
| `DELAUNAY_LARGE_DEBUG_MAX_SKIP_PCT` | **value** | Maximum skipped-vertex percentage before failing (default: 5.0) |
| `DELAUNAY_LARGE_DEBUG_ALLOW_SKIPS` | presence | Allow any number of vertex insertion skips |
| `DELAUNAY_LARGE_DEBUG_SKIP_FINAL_REPAIR` | presence | Skip final global repair pass |
| `DELAUNAY_BATCH_REPAIR_TRACE` | presence | Trace cadenced batch-repair seed counts, flips, queues, and elapsed time |
| `DELAUNAY_LARGE_DEBUG_PREFIX_TOTAL` | **value** | Total prefix probes for bisect mode |
| `DELAUNAY_LARGE_DEBUG_PREFIX_MAX_PROBES` | **value** | Max probes per bisect run |
| `DELAUNAY_LARGE_DEBUG_PREFIX_MAX_RUNTIME_SECS` | **value** | Bisect probe timeout |
Expand Down
5 changes: 4 additions & 1 deletion docs/dev/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -563,9 +563,12 @@ Examples:

```text
delaunay::prelude::triangulation
delaunay::prelude::triangulation::construction
delaunay::prelude::triangulation::flips
delaunay::prelude::triangulation::insertion
delaunay::prelude::triangulation::repair
delaunay::prelude::triangulation::delaunayize
delaunay::prelude::triangulation::validation
delaunay::prelude::query
delaunay::prelude::algorithms
delaunay::prelude::geometry
Expand Down Expand Up @@ -600,7 +603,7 @@ Example:
/// # Examples
///
/// ```rust
/// # use delaunay::prelude::triangulation::*;
/// # use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, vertex};
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut triangulation = DelaunayTriangulation::<_, _, _, 2>::default();
/// let key = triangulation.insert_vertex([0.0, 0.0])?;
Expand Down
2 changes: 1 addition & 1 deletion docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Use `delaunay_violation_report` when you want data instead of only log output:

```rust
use delaunay::prelude::diagnostics::delaunay_violation_report;
use delaunay::prelude::triangulation::*;
use delaunay::prelude::triangulation::construction::{DelaunayTriangulation, vertex};

let vertices = vec![
vertex!([0.0, 0.0, 0.0]),
Expand Down
8 changes: 5 additions & 3 deletions docs/invariants.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,11 @@ identifying *visible* boundary facets and retriangulating the visible region.

### Degenerate input and initial simplex construction

Construction begins by creating an initial simplex from the first `D+1` affinely independent
vertices. If no non-degenerate simplex can be formed (e.g., collinear points in 2D, coplanar in 3D),
construction fails with a geometric degeneracy error.
Construction begins by creating an initial simplex from `D+1` affinely independent real input
vertices. The default batch constructor searches a bounded pool of extreme vertices for a
large-volume simplex before falling back to the selected insertion order. If no non-degenerate
simplex can be formed (e.g., collinear points in 2D, coplanar in 3D), construction fails with a
geometric degeneracy error.

This early degeneracy detection is intentional: it prevents building a combinatorial structure whose
geometric interpretation is undefined.
Expand Down
Loading
Loading