Loading...
Searching...
No Matches
eonc::XtsciOptimizer Class Referencefinal

xtsci-optimize backend. More...

#include <XtsciOptimizer.h>

Inheritance diagram for eonc::XtsciOptimizer:

Public Member Functions

 XtsciOptimizer (std::shared_ptr< ObjectiveFunction > a_objf, const Parameters &a_params)
 ~XtsciOptimizer () override
 XtsciOptimizer (const XtsciOptimizer &)=delete
XtsciOptimizer & operator= (const XtsciOptimizer &)=delete
int step (double a_maxMove) override
int run (size_t a_maxIterations, double a_maxMove) override
Public Member Functions inherited from eonc::Optimizer
 Optimizer (std::shared_ptr< ObjectiveFunction > a_objf, const OptimizerConfig &a_config)
 Optimizer (std::shared_ptr< ObjectiveFunction > a_objf, OptType a_optype, const OptimizerConfig &a_config)
 Optimizer (std::shared_ptr< ObjectiveFunction > a_objf, const Parameters &a_params)
 Optimizer (std::shared_ptr< ObjectiveFunction > a_objf, OptType a_optype, const Parameters &a_params)
virtual ~Optimizer ()=default

Private Member Functions

void ensureSolver (double a_maxMove)

Private Attributes

xts_solver_t * m_solver {nullptr}
xtsci_eindir::State * m_eindir {nullptr}
Eigen::VectorXd m_cached_x
Eigen::VectorXd m_x

Additional Inherited Members

Protected Attributes inherited from eonc::Optimizer
const OptimizerConfig m_optConfig
std::shared_ptr< ObjectiveFunction > m_objf

Detailed Description

xtsci-optimize backend.

Newton / RFO live in Rust; this class is the ObjectiveFunction + pair-Hessian waist.

Definition at line 23 of file XtsciOptimizer.h.

Constructor & Destructor Documentation

◆ XtsciOptimizer() [1/2]

eonc::XtsciOptimizer::XtsciOptimizer ( std::shared_ptr< ObjectiveFunction > a_objf,
const Parameters & a_params )
inline

Definition at line 25 of file XtsciOptimizer.h.

27 : Optimizer(a_objf, OptType::XTSCI,
28 OptimizerConfig::fromParams(a_params)) {}
Optimizer(std::shared_ptr< ObjectiveFunction > a_objf, const OptimizerConfig &a_config)
Definition Optimizer.h:73
static OptimizerConfig fromParams(const Parameters &p)
Definition Optimizer.h:57

◆ ~XtsciOptimizer()

eonc::XtsciOptimizer::~XtsciOptimizer ( )
override

Definition at line 252 of file XtsciOptimizer.cpp.

252 {
253 xts_solver_free(m_solver);
255 m_eindir = nullptr;
256}
xts_solver_t * m_solver
xtsci_eindir::State * m_eindir
void release(State *state)

◆ XtsciOptimizer() [2/2]

eonc::XtsciOptimizer::XtsciOptimizer ( const XtsciOptimizer & )
delete

Member Function Documentation

◆ ensureSolver()

void eonc::XtsciOptimizer::ensureSolver ( double a_maxMove)
private

Definition at line 258 of file XtsciOptimizer.cpp.

258 {
259 if (m_solver != nullptr) {
260 return;
261 }
262 const auto dim = static_cast<size_t>(m_objf->degreesOfFreedom());
263 if (dim == 0) {
264 return;
265 }
266 const auto stamp = xts_abi_stamp();
267 if (xts_abi_compatible(&stamp) == 0) {
268 throw std::runtime_error("incompatible xtsci-optimize ABI");
269 }
270 const auto &lbfgs = m_optConfig.opts.lbfgs;
271 const xts_method_t method = method_from_name(m_optConfig.opts.xtsci.method);
272 double istep = std::max(a_maxMove, 1.0e-12);
273 if (method == XTS_FIRE || method == XTS_FIRE2) {
274 istep = m_optConfig.opts.time_step;
275 if (istep <= 0.0) {
276 istep = m_optConfig.opts.time_step_input;
277 }
278 if (istep <= 0.0) {
279 istep = 0.1;
280 }
281 }
282 xts_control_t control{
283 static_cast<size_t>(std::max<long>(1, m_optConfig.opts.max_iterations)),
284 m_optConfig.opts.converged_force,
285 istep,
286 static_cast<size_t>(std::max<long>(0, lbfgs.memory)),
287 0.0,
288 };
289 m_solver = xts_solver_create(method, &control, dim);
290 if (m_solver == nullptr) {
291 throw std::runtime_error(xts_last_error());
292 }
293 const auto step = resolved_qn_step(m_optConfig.opts);
294 if (step == "newton") {
295 xts_solver_set_qn_step(m_solver, XTS_QN_NEWTON);
296 } else if (step == "rfo") {
297 xts_solver_set_qn_step(m_solver, XTS_QN_RFO);
298 } else {
299 xts_solver_set_qn_step(m_solver, XTS_QN_LBFGS);
300 }
301 const auto accept = resolved_accept(m_optConfig.opts);
302 if (accept == "energy") {
303 xts_solver_set_accept(m_solver, XTS_ACCEPT_ENERGY);
304 } else if (accept == "nonmonotone") {
305 xts_solver_set_accept(m_solver, XTS_ACCEPT_NONMONOTONE);
306 } else {
307 xts_solver_set_accept(m_solver, XTS_ACCEPT_NONE);
308 }
309 xts_solver_set_project_rigid(m_solver, lbfgs.project_rigid ? 1 : 0);
310 xts_solver_set_extra_updates(
311 m_solver, static_cast<size_t>(std::max<long>(0, lbfgs.extra_updates)));
312 if (lbfgs.curvature == "cautious") {
313 xts_solver_set_cautious(m_solver, lbfgs.cautious_eps, lbfgs.cautious_alpha);
314 } else {
315 xts_solver_set_cautious(m_solver, 0.0, lbfgs.cautious_alpha);
316 }
317 if (m_optConfig.opts.xtsci.highs) {
318 if (xts_solver_set_highs(m_solver, 1) != 0) {
319 throw std::runtime_error(
320 "Xtsci.highs needs xtsci-optimize built with --features highs");
321 }
322 }
323 const auto &mani = m_optConfig.opts.xtsci.manifold;
324 if (mani == "so3" && dim != 9) {
325 throw std::runtime_error(
326 "Xtsci.manifold=so3 needs length 9; a 3N cluster is "
327 "rigid_quotient (Sella R^{3N}/SE(3)), not a packed rotation");
328 }
329 if (mani == "se3" && dim != 12) {
330 throw std::runtime_error(
331 "Xtsci.manifold=se3 needs length 12; a 3N cluster is "
332 "rigid_quotient (Sella R^{3N}/SE(3)), not an SE(3) prefix");
333 }
334 if ((mani == "rigid_quotient" || mani == "mw_rigid" || mani == "sella" ||
335 mani == "eckart" || mani == "irc") &&
336 (dim < 6 || dim % 3 != 0)) {
337 throw std::runtime_error("Xtsci.manifold=" + mani +
338 " needs 3N Cartesians with N >= 2");
339 }
340 if (mani == "sphere") {
341 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_SPHERE);
342 } else if (mani == "so3") {
343 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_SO3);
344 } else if (mani == "stiefel") {
345 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_STIEFEL);
346 } else if (mani == "se3") {
347 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_SE3);
348 } else if (mani == "rigid_quotient" || mani == "sella") {
349 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_RIGID_QUOTIENT);
350 } else if (mani == "mw_rigid" || mani == "eckart" || mani == "irc") {
351 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_MW_RIGID);
352 const auto masses = m_objf->getMasses();
353 if (masses.size() > 0) {
354 xts_solver_set_masses(m_solver, masses.data(),
355 static_cast<size_t>(masses.size()));
356 }
357 } else {
358 xts_solver_set_manifold(m_solver, XTS_MANIFOLD_EUCLIDEAN);
359 }
360 if (mani == "rigid_quotient" || mani == "mw_rigid" || mani == "sella" ||
361 mani == "eckart" || mani == "irc") {
362 xts_solver_set_periodic(m_solver, m_objf->getPeriodic() ? 1 : 0);
363 }
364 if (m_eindir == nullptr) {
366 }
367}
const OptimizerConfig m_optConfig
Definition Optimizer.h:69
std::shared_ptr< ObjectiveFunction > m_objf
Definition Optimizer.h:70
Eigen::VectorXd m_cached_x
int step(double a_maxMove) override
State * bind(ObjectiveFunction *objective, Eigen::VectorXd *cached)
Borrow an ObjectiveFunction as an eindir objective.

◆ operator=()

XtsciOptimizer & eonc::XtsciOptimizer::operator= ( const XtsciOptimizer & )
delete

◆ run()

int eonc::XtsciOptimizer::run ( size_t a_maxIterations,
double a_maxMove )
overridevirtual

Implements eonc::Optimizer.

Definition at line 420 of file XtsciOptimizer.cpp.

420 {
421 if (m_objf->degreesOfFreedom() <= 0 || a_maxIterations == 0) {
422 return m_objf->isConverged() ? 1 : 0;
423 }
424 ensureSolver(a_maxMove);
425 const auto &lbfgs = m_optConfig.opts.lbfgs;
426 std::string precon = resolved_precon(m_optConfig.opts);
427 const xts_method_t method = method_from_name(m_optConfig.opts.xtsci.method);
428 if (method == XTS_DOGLEG && !is_host_precon(precon)) {
429 precon = "pair";
430 }
431 const bool want_hess = method == XTS_NEWTON || method == XTS_RFO ||
432 method == XTS_DOGLEG || is_host_precon(precon);
433 // A full minimize without a host Hessian goes through the eindir entry.
434 // step() stays one session iteration so the host loop keeps its memory.
435 if (m_eindir != nullptr && !want_hess) {
436 if (m_x.size() == 0) {
437 m_x = m_objf->getPositions();
438 }
439 double value = 0.0;
440 const int status = xtsci_eindir::minimize(
441 m_eindir, m_x.data(), static_cast<size_t>(m_x.size()), a_maxIterations,
442 m_optConfig.opts.converged_force, std::max(a_maxMove, 1.0e-12),
443 static_cast<size_t>(std::max<long>(0, lbfgs.memory)),
444 static_cast<int>(method), &value);
445 if (status != XTS_SUCCESS) {
446 throw std::runtime_error(xts_last_error());
447 }
448 m_objf->setPositions(m_x);
449 m_cached_x = m_x;
450 (void)value;
451 return m_objf->isConverged() ? 1 : 0;
452 }
453 for (size_t i = 0; i < a_maxIterations; ++i) {
454 if (step(a_maxMove) != 0) {
455 return 1;
456 }
457 }
458 return m_objf->isConverged() ? 1 : 0;
459}
void ensureSolver(double a_maxMove)
Eigen::VectorXd m_x
int minimize(State *state, double *x, std::size_t n, std::size_t maxiter, double gtol, double istep, std::size_t memory, int method, double *value_out)
xts_minimize_eindir on a caller-owned buffer. The caller keeps State.

◆ step()

int eonc::XtsciOptimizer::step ( double a_maxMove)
overridevirtual

Implements eonc::Optimizer.

Definition at line 369 of file XtsciOptimizer.cpp.

369 {
370 if (m_objf->degreesOfFreedom() <= 0) {
371 return m_objf->isConverged() ? 1 : 0;
372 }
373 ensureSolver(a_maxMove);
374 if (m_solver == nullptr) {
375 return m_objf->isConverged() ? 1 : 0;
376 }
377 // Native LBFGS clips by the largest per-atom move, not ||d||_2.
378 xts_solver_set_maxmove(m_solver, 0.0);
379 xts_solver_set_atom_maxmove(m_solver, std::max(a_maxMove, 0.0));
380
381 if (m_x.size() == 0) {
382 m_x = m_objf->getPositions();
383 }
384 if (m_x.size() != m_objf->degreesOfFreedom()) {
385 throw std::runtime_error("xtsci objective position dimension mismatch");
386 }
387 auto *tensor =
388 xts_tensor_borrow_cpu_f64(m_x.data(), static_cast<size_t>(m_x.size()));
389 if (tensor == nullptr) {
390 throw std::runtime_error("could not allocate xtsci objective tensor");
391 }
392 const auto &lbfgs = m_optConfig.opts.lbfgs;
393 std::string precon = resolved_precon(m_optConfig.opts);
394 const xts_method_t method = method_from_name(m_optConfig.opts.xtsci.method);
395 if (method == XTS_DOGLEG && !is_host_precon(precon)) {
396 precon = "pair";
397 }
398 XtsObjectiveContext context{
399 m_objf.get(), m_optConfig.potential, precon, lbfgs.precon_A,
400 lbfgs.precon_mu, lbfgs.precon_rcut, &m_cached_x, m_eindir,
401 };
402 xts_report_t report{};
403 const bool want_hess = method == XTS_NEWTON || method == XTS_RFO ||
404 method == XTS_DOGLEG || is_host_precon(precon);
405 xts_status_t status;
406 if (want_hess) {
407 status = xts_solver_step_hess_fg(m_solver, evaluate_gradient, hessian,
408 &context, tensor, &report);
409 } else {
410 status = xts_solver_step_fg(m_solver, evaluate_gradient, &context, tensor,
411 &report);
412 }
413 xts_tensor_free(tensor);
414 if (status != XTS_SUCCESS) {
415 throw std::runtime_error(xts_last_error());
416 }
417 return m_objf->isConverged() ? 1 : 0;
418}

Member Data Documentation

◆ m_cached_x

Eigen::VectorXd eonc::XtsciOptimizer::m_cached_x
private

Definition at line 44 of file XtsciOptimizer.h.

◆ m_eindir

xtsci_eindir::State* eonc::XtsciOptimizer::m_eindir {nullptr}
private

Definition at line 41 of file XtsciOptimizer.h.

41{nullptr};

◆ m_solver

xts_solver_t* eonc::XtsciOptimizer::m_solver {nullptr}
private

Definition at line 39 of file XtsciOptimizer.h.

39{nullptr};

◆ m_x

Eigen::VectorXd eonc::XtsciOptimizer::m_x
private

Definition at line 47 of file XtsciOptimizer.h.


The documentation for this class was generated from the following files: