Solvers

Solvers#

Base#

class mink_warp.Solver[source]#

Bases: ABC

Batched IK solver operating on a shared Configuration.

Contract: solve_and_integrate() advances the configuration toward the task targets and returns a representative tangent velocity (nworld, nv).

For multi-iteration backends (LM / L-BFGS) the returned v is the sum of the per-iteration tangent steps divided by dt. Re-integrating v over dt reproduces the optimized configuration exactly for Euclidean joints (hinge / slide); for free / ball joints it agrees to second order (the true update is a composition of manifold exponentials, v their tangent sum). The configuration itself is always left at the exact optimized state. A solver is bound to its configuration’s nworld / nv and cannot be reused with a differently sized one.

name: str = 'solver'#

Registry key / human label.

supports_limits: bool = False#

Whether this backend enforces hard limits. Only ConstrainedSolver sets this True; the cost-only backends (DLS / LM / L-BFGS) cannot honour a limits= argument and callers must not silently assume they do.

abstractmethod solve_and_integrate(tasks: Sequence[Task], dt: float, *, iterations: int = 1, use_graph: bool = False, **kwargs) array[source]#

Advance configuration and return the tangent velocity.

step(tasks: Sequence[Task], dt: float, *, iterations: int = 1, **kwargs) array[source]#

Alias for solve_and_integrate() (no graph capture).

invalidate_graph() None[source]#

Drop any captured CUDA graph. Backends without a graph no-op.

Backends#

class mink_warp.DLSSolver[source]#

Bases: Solver

Reusable batched damped-least-squares IK solver.

Solves \((W^T W + \lambda I)\Delta q = -W^T e\) on device and returns \(v = \Delta q / dt\). Optional CUDA graph capture for fixed task sets.

Note: CUDA graphs cannot include host->device copies. dt is written to a device buffer before capture; integrate is out-of-place (in-place qpos aliasing is not graph-safe).

name: str = 'dls'#

Registry key / human label.

solve(tasks: Sequence[Task], dt: float, damping: float | None = None) array[source]#

Compute the velocity for one differential step (no integration).

solve_and_integrate(tasks: Sequence[Task], dt: float, *, iterations: int = 1, use_graph: bool = False, damping: float | None = None) array[source]#

Solve and integrate iterations times; returns last velocity.

invalidate_graph() None[source]#

Drop a captured CUDA graph (e.g. after changing the task list).

class mink_warp.LMSolver[source]#

Bases: Solver

Batched Levenberg-Marquardt IK solver.

Parameters:
  • lambda0 – initial damping (reset at the start of every call).

  • lambda_max (lambda_min /) – clamp range for the adaptive damping.

  • eps – gain-ratio regularizer added to the predicted reduction, so a near-zero prediction at convergence does not amplify float32 noise.

name: str = 'lm'#

Registry key / human label.

solve_and_integrate(tasks: Sequence[Task], dt: float, *, iterations: int = 2, use_graph: bool = False, **_ignored) array[source]#

Advance configuration and return the tangent velocity.

invalidate_graph() None[source]#

Drop any captured CUDA graph. Backends without a graph no-op.

class mink_warp.LBFGSSolver[source]#

Bases: Solver

Batched limited-memory BFGS IK solver.

Parameters:
  • history – number m of (s, y) pairs retained.

  • line_search – candidate step sizes evaluated in parallel each iteration.

  • eps – sufficient-decrease floor for the line search.

  • curvature_eps – relative curvature floor s.y > curvature_eps * ||y||^2 below which a pair is skipped (kept out of the history).

name: str = 'lbfgs'#

Registry key / human label.

solve_and_integrate(tasks: Sequence[Task], dt: float, *, iterations: int = 5, use_graph: bool = False, **_ignored) array[source]#

Advance configuration and return the tangent velocity.

class mink_warp.ConstrainedSolver[source]#

Bases: Solver

Batched constrained IK via ADMM on the task normal equations.

Per world, solves:

\[\min_{\Delta q}\ \tfrac{1}{2} \Delta q^\top H \Delta q + c^\top \Delta q \quad \text{s.t.}\ \ell \leq \Delta q \leq u,\ G \Delta q \leq h\]

where \(H, c\) match DLSSolver. Box limits are enforced exactly each ADMM iteration; general rows converge with admm_iters.

Parameters:
  • configuration – Batched configuration to advance.

  • limits – Hard limits. None → default ConfigurationLimit; [] → unconstrained regularized DLS inside the solver.

  • admm_iters – Inner ADMM iterations per solve.

  • rho_scale – ADMM penalty \(\rho = \mathrm{clamp}(\rho_{\mathrm{scale}} \sqrt{h_{\min} h_{\max}}, \ldots)\).

  • rho_min – ADMM penalty \(\rho = \mathrm{clamp}(\rho_{\mathrm{scale}} \sqrt{h_{\min} h_{\max}}, \ldots)\).

  • rho_max – ADMM penalty \(\rho = \mathrm{clamp}(\rho_{\mathrm{scale}} \sqrt{h_{\min} h_{\max}}, \ldots)\).

  • alpha – Over-relaxation in \([1, 2)\).

  • damping – Tikhonov \(\lambda\) on \(H\) (matches solve_ik).

  • sigma – SPD floor for the general-inequality path.

  • use_inequalities – Force dense \(G \Delta q \leq h\) even for box limits. Auto-enabled for inequality-only limits such as CollisionAvoidanceLimit.

name: str = 'constrained'#

Registry key / human label.

supports_limits: bool = True#

Whether this backend enforces hard limits. Only ConstrainedSolver sets this True; the cost-only backends (DLS / LM / L-BFGS) cannot honour a limits= argument and callers must not silently assume they do.

solve(tasks: Sequence[Task], dt: float, damping: float | None = None) array[source]#

Compute the box-feasible velocity for one differential step.

solve_and_integrate(tasks: Sequence[Task], dt: float, *, iterations: int = 1, use_graph: bool = False, damping: float | None = None) array[source]#

Solve and integrate iterations times; returns last velocity.

Each outer iteration re-linearizes H and recomputes the box at the current configuration, so the returned step stays feasible throughout.

invalidate_graph() None[source]#

Drop any captured CUDA graph. Backends without a graph no-op.

Factory#

mink_warp.make_solver(configuration: Configuration, kind: str = 'dls', **kwargs) Solver[source]#

Construct a solver backend by name.

"dls" / "lm" / "lbfgs" / "constrained" (the last enforces hard joint limits; pass limits= to override the default ConfigurationLimit).

Registry#

mink_warp.solvers.SOLVERS maps solver name strings to backend classes ("dls", "lm", "lbfgs", "constrained").