C and C++ ABI#
Solvers live in Rust. Geometry hosts that call one outer iteration at
a time hold an opaque rgmin_solver_t; scripts that want a one-shot
solve still call rgmin_minimize. Every vector is a dlpk
DLManagedTensorVersioned tensor.
Session (eOn / ASE step)#
#include "xts.h"
rgmin_control_t ctrl = { .maxiter = 200, .gtol = 1e-8, .istep = 1.0, .memory = 8 };
rgmin_solver_t *s = rgmin_solver_create(RGMIN_LBFGS, &ctrl, n);
rgmin_report_t report;
while (!done) {
rgmin_solver_set_maxmove(s, max_move);
rgmin_solver_set_qn_step(s, RGMIN_QN_NEWTON); /* or RGMIN_QN_LBFGS + P as H0 */
rgmin_solver_set_accept(s, RGMIN_ACCEPT_NONE);
rgmin_solver_step_hess_fg(s, evalgrad, hess, user, x, &report);
}
rgmin_solver_free(s);
rgmin_precon_init and rgmin_solver_set_precon install Exp, Lindh,
the bonded metric, or the automatic choice. NaN mu estimates the
energy scale on the next step. L-BFGS uses the matrix as H0. FIRE and
nonlinear CG use it as a metric. rgmin_solver_clear_precon removes
it. Morse bonds and FF torsions are Rust-only.
rgmin_solver_forget drops pairs / conjugacy / moments. Newton and RFO
use rgmin_solver_step_hess_fg (fused energy and gradient, one host
potential call). Split eval / grad callbacks remain. accept
is none (take the clipped step), energy, or nonmonotone.
Callbacks are arguments of each step, not stored on the handle.
A Cartesian session starts with a per-atom cap of 0.2.
rgmin_solver_set_atom_maxmove replaces it. A non-positive argument
clears it. A positive maxmove on rgmin_control_t, with no call to
that setter, is the Euclidean step limit and leaves the per-atom
default off. The cap is the largest per-atom displacement. The C++
OptimizeControl.maxmove is 0, so optimize keeps the per-atom
default. ASE Optimizer.defaults maxstep is 0.2 at tag 3.29.0
(https://gitlab.com/ase/ase/-/blob/3.29.0/ase/optimize/optimize.py).
eOn max_move is 0.2 Å
(https://henkelmanlab.org/eon/optimizer.html); the schema field
OptimizerOptions.maxMove is 0.2 at 4be157d4
(https://github.com/TheochemUI/eOn/blob/4be157d43265af6b1140aaac0e52e42add62693f/schema/eon_params.capnp).
One-shot#
#include "xts.h"
rgmin_control_t ctrl = { .maxiter = 200, .gtol = 1e-8, .istep = 1.0, .memory = 8 };
rgmin_report_t report;
rgmin_status_t st = rgmin_minimize(eval, grad, user, x, &ctrl, RGMIN_LBFGS, &report);
A non-CPU tensor returns RGMIN_UNSUPPORTED_DEVICE. The ABI does not
change when a CUDA path lands.
C++#
#include <xts/optimize.hpp>
xts::optimize::Control ctrl;
auto report = xts::optimize::minimize(eval, grad, user, x, ctrl,
xts::optimize::Method::Lbfgs);
xtensor callers include xts/xtensor.hpp, which adapts xt::xarray to
the same rgmin_minimize entry. There is no solver in the header.
Manifold#
rgmin_solver_set_manifold(s, RGMIN_MANIFOLD_SPHERE);
Tokens: RGMIN_MANIFOLD_EUCLIDEAN (default), RIGID_QUOTIENT
(R^{3N}/SE(3), Sella Cartesian), MW_RIGID (Page–McIver /
Sella IRC Eckart), SPHERE, SO3 (length 9), STIEFEL
(St(n,1)), SE3 (length 12). See
retract onto an embedded manifold.
rgmin_solver_set_masses supplies N atomic masses for MW_RIGID.