258 {
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 }
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) {
275 if (istep <= 0.0) {
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)),
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);
291 throw std::runtime_error(xts_last_error());
292 }
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 }
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") {
363 }
366 }
367}
const OptimizerConfig m_optConfig
std::shared_ptr< ObjectiveFunction > m_objf
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.