@@ -133,8 +133,9 @@ def _jax_delaunay_tables(points):
133133 NOT an approximation: the callback returns only int32 connectivity
134134 tables, which are piecewise-constant in the vertex positions — their
135135 true derivative is exactly zero everywhere except the measure-zero
136- re-wiring (triangle-flip) events, where the likelihood itself is
137- discontinuous and no gradient exists for any method. Every quantity
136+ re-wiring (triangle-flip) events. The barycentric interpolant is
137+ discontinuous there; the Sibson interpolant in ``DelaunayNN`` instead has
138+ matching limits across an ordinary flip. Every quantity
138139 with a non-zero derivative (point location via the visibility walk,
139140 barycentric weights, dual areas, split points) is computed in-graph
140141 from the traced ``points``, so the frozen-tables gradient is the exact
@@ -164,6 +165,7 @@ def pix_indexes_delaunay_walk_from(
164165 simplex_neighbors ,
165166 vertex_simplex ,
166167 xp = np ,
168+ return_simplex_indexes = False ,
167169):
168170 """JAX/NumPy point location replacing ``scipy.spatial.Delaunay.find_simplex``
169171 on the JAX likelihood path, via the same visibility-walk algorithm
@@ -185,6 +187,11 @@ def pix_indexes_delaunay_walk_from(
185187 vmap (JAX path; the NumPy path — used by the unit tests — processes the
186188 whole array with early exit). Returns a (Q, 3) int32 mapping array with
187189 the same semantics as ``pix_indexes_for_sub_slim_index_delaunay_from``.
190+
191+ When ``return_simplex_indexes`` is true, also return the containing
192+ simplex index for every query (or -1 outside the convex hull). Sibson
193+ interpolation uses this as the seed of its circumcircle-cavity walk, so
194+ point location is not repeated.
188195 """
189196
190197 def cross (u , v ):
@@ -251,10 +258,15 @@ def locate_chunk(q_chunk):
251258
252259 verts = simplices_padded [cur ]
253260 fallback = xp .stack ([seed , - xp .ones_like (seed ), - xp .ones_like (seed )], axis = 1 )
254- return xp .where (done [:, None ], verts , fallback ).astype (xp .int32 )
261+ mappings = xp .where (done [:, None ], verts , fallback ).astype (xp .int32 )
262+ simplex_indexes = xp .where (done , cur , - 1 ).astype (xp .int32 )
263+ return mappings , simplex_indexes
255264
256265 if xp is np :
257- return locate_chunk (query_points )
266+ mappings , simplex_indexes = locate_chunk (query_points )
267+ if return_simplex_indexes :
268+ return mappings , simplex_indexes
269+ return mappings
258270
259271 import jax
260272
@@ -265,8 +277,14 @@ def locate_chunk(q_chunk):
265277 q_padded = xp .concatenate (
266278 [query_points , xp .full ((pad , 2 ), 1.0e9 , dtype = query_points .dtype )]
267279 )
268- mappings = jax .lax .map (locate_chunk , q_padded .reshape (- 1 , chunk , 2 )).reshape (- 1 , 3 )
269- return mappings [:Q ]
280+ mappings , simplex_indexes = jax .lax .map (
281+ locate_chunk , q_padded .reshape (- 1 , chunk , 2 )
282+ )
283+ mappings = mappings .reshape (- 1 , 3 )[:Q ]
284+ simplex_indexes = simplex_indexes .reshape (- 1 )[:Q ]
285+ if return_simplex_indexes :
286+ return mappings , simplex_indexes
287+ return mappings
270288
271289
272290def jax_delaunay (points , query_points , areas_factor = 0.5 ):
0 commit comments