Source code for jax_sbgeom.jax_utils.stationary

"""Sample-then-polish: the shared building block of `minimum_distance` and `Coil.bounding_box`."""
from __future__ import annotations

import jax
import jax.numpy as jnp
import optimistix as optx


[docs] def polish_stationary(f, starts, args=None, *, tol : float = 1e-10, max_steps : int = 12): """ Newton-polish the stationary points of a smooth scalar f(x, args) from each row of `starts` (k, d). Sampling is the caller's job (it chooses the starts). Derivatives use optimistix' implicit adjoint, so nothing is differentiated through the iterations (first order: the envelope theorem). Returns (x, converged): the polished points (k, d) and a boolean (k,). Where Newton did not converge x is the last iterate: still a valid point, but derivatives through it are not. """ solver = optx.Newton(rtol=tol, atol=tol) sol = jax.vmap(lambda x0: optx.root_find(jax.grad(f), solver, x0, args=args, throw=False, max_steps=max_steps))(starts) return sol.value, sol.result == optx.RESULTS.successful