Skip to content

Releases: python-adaptive/adaptive-triangulation

v0.3.1

10 Jun 22:30
0203515

Choose a tag to compare

Patch release: degenerate input to simplex_volume_in_embedding (collinear, coplanar, or coincident vertices) now yields volume 0.0 like the reference implementation, instead of raising ValueError (#15).

adaptive's curvature losses feed degenerate vertex sets whenever the sampled function is locally flat, so with adaptive ≥ 1.5 auto-selecting this backend, LearnerND runs with curvature_loss_function() crashed where the pure-Python backend returned a zero loss. The fix mirrors the reference's tolerance contract: a Cayley-Menger squared volume within rounding noise of zero (> -1e-15) is a zero-volume simplex; only below that band is it an error. For three vertices in a >2D embedding the squared-distance Cayley-Menger form replaces root-based Heron so rounding near zero behaves like the reference's determinant.

With this release the full adaptive 1.5.0 test suite passes with the Rust backend active (283 passed; previously 7 curvature-loss failures), clearing the way for adaptive to bump _MIN_RUST_VERSION and run the Rust backend in CI.

Full changelog: v0.3.0...v0.3.1

v0.3.0

10 Jun 22:01
a8a02a4

Choose a tag to compare

Minor release: two batched APIs that move LearnerND's remaining Python hot loops into Rust (#13).

Profiling LearnerND with the Rust backend (adaptive ≥ 1.5) showed only 14-25% of runtime left inside this extension; these APIs target the two largest remaining Python-side costs:

  • Triangulation.simplices_containing(point, simplex=None, candidates=None, eps=1e-8) — all simplices containing a point, in one call instead of a point_in_simplex loop. Solves once for a simplex known to contain the point (the simplex hint, or locate_point), reduces it to the face the point lies on, and looks the containing simplices up in the facet index. A stale hint falls back to locating; candidates filters explicitly instead.
  • default_loss(simplex, values, value_scale=None) — LearnerND's default loss (embedded simplex volume) taking the scaled vertex/value arrays directly, signature-compatible with adaptive's loss_per_simplex functions.

Wired into LearnerND the way a future adaptive release would use them (examples/learnernd_batched_apis.py), they add 1.17× (2D) to 1.40× (3D) on top of the Rust backend, while sampling identical points.

Also refreshes the README benchmarks against adaptive 1.5.0, which now selects this backend automatically (pip install "adaptive[rust]").

Full changelog: v0.2.1...v0.3.0

v0.2.1

10 Jun 19:33
c6d6de4

Choose a tag to compare

Patch release: Triangulation now supports pickle, copy.copy, and copy.deepcopy (#11).

The Python reference is a plain class and pickles for free; the Rust class did not, which broke LearnerND.save(), copy.deepcopy(learner), and pickling learners for distributed runners (LearnerND._get_data deepcopies the learner's __dict__, triangulation included).

  • the constructor gained an optional simplices argument that restores an exact prior state without re-triangulating (hand-modified simplex sets and unconnected vertices survive)
  • __reduce__ serializes (vertices, simplices) and reconstructs through it; simplices are sorted, so equal triangulations pickle to identical bytes
  • the class now resolves as adaptive_triangulation._rust.Triangulation instead of advertising itself as builtins.Triangulation

Full changelog: v0.2.0...v0.2.1

v0.2.0

10 Jun 19:11
4ee0bf2

Choose a tag to compare

Performance, robustness, and drop-in completeness release. All changes keep the Python API drop-in compatible with adaptive.learner.triangulation; the 64 cross-validation tests against the reference pass unchanged throughout.

Performance (#5, #7)

  • Core data-structure overhaul: simplices are interned in a slab and referenced by integer ids; a facet-adjacency index makes point-location walks, the Bowyer-Watson cascade, and containing() single hash lookups; the convex hull is maintained incrementally (the old per-insertion full-face recount was O(n²) for hull-heavy workloads).
  • Incremental insertion is 40-291× faster than the pure-Python reference (2D-3D, 500-5000 points) and 2-8× faster than v0.1.0.
  • End-to-end LearnerND runs ~3.7× faster than with the Python triangulation (~7× vs Learner2D at 5K points).
  • numpy fast paths in the bindings; np.asarray(tri.vertices) snapshots are ~50× faster.

Robustness (#6) — behavior change on degenerate input

Insertions are now validated before any mutation: volume conservation is checked with adaptive-precision determinants, and the point must end up connected. Failing cavities are repaired — in 2D/3D by rebuilding them with Shewchuk's exact insphere predicates (via the robust crate) — and if even the repaired cavity fails, the insertion raises (AssertionError, or ValueError when the point cannot be connected) with the triangulation untouched, so callers can skip the point and continue.

Previously (like the Python reference still does) such insertions could corrupt the mesh: on mixed-coordinate-scale stress sweeps, corrupted end states drop from 99/400 runs to 0/400. Well-conditioned inputs never enter the repair path and behave identically to before. The full numerical policy is documented in src/tolerances.rs.

Drop-in API completeness (#7)

LearnerND with neighbor-aware losses (curvature_loss_function(), triangle_loss) now works; previously it crashed on missing methods. Added: get_vertex, get_neighbors_from_vertices, get_simplices_attached_to_points, get_opposing_vertices, get_face_sharing_neighbors, None pass-through in get_vertices, and set operators on the simplices proxy.

Internals & docs (#8, #9)

  • Readability refactor of the core and bindings (net −108 lines, provably behavior-identical).
  • README benchmarks re-measured and a Robustness section added.

Full changelog: v0.1.0...v0.2.0

v0.1.0

10 Jun 19:09

Choose a tag to compare

What's Changed

  • fix: align CI Python versions with PyO3 support by @basnijholt in #1

Full Changelog: https://github.com/python-adaptive/adaptive-triangulation/commits/v0.1.0