301 Eigen::Vector<Scalar, Eigen::Dynamic> x{m_decision_variables.size()};
302 for (
size_t i = 0; i < m_decision_variables.size(); ++i) {
303 x[i] = m_decision_variables[i].value();
306 if (options.diagnostics) {
307 print_exit_conditions(options);
308 print_problem_analysis();
317 if (f_type <= ExpressionType::CONSTANT &&
318 c_e_type <= ExpressionType::CONSTANT &&
319 c_i_type <= ExpressionType::CONSTANT) {
320#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
321 if (options.diagnostics) {
322 slp::println(
"\nInvoking no-op solver...\n");
325 return ExitStatus::SUCCESS;
328 gch::small_vector<SetupProfiler> ad_setup_profilers;
329 ad_setup_profilers.emplace_back(
"setup").start();
331 VariableMatrix<Scalar> x_ad{m_decision_variables};
334 Variable f = m_f.value_or(Scalar(0));
337 ad_setup_profilers.emplace_back(
" ↳ ∇f(x)").start();
339 ad_setup_profilers.back().stop();
342 int num_decision_variables = m_decision_variables.size();
344 int num_equality_constraints = m_equality_constraints.size();
346 int num_inequality_constraints = m_inequality_constraints.size();
348 gch::small_vector<std::function<bool(
const IterationInfo<Scalar>& info)>>
350 for (
const auto& callback : m_iteration_callbacks) {
351 callbacks.emplace_back(callback);
353 for (
const auto& callback : m_persistent_iteration_callbacks) {
354 callbacks.emplace_back(callback);
359 if (m_equality_constraints.empty() && m_inequality_constraints.empty()) {
360 if (options.diagnostics) {
361 slp::println(
"\nInvoking Newton solver...\n");
365 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
366 Hessian<Scalar, Eigen::Lower> H{f, x_ad};
367 ad_setup_profilers.back().stop();
369 ad_setup_profilers[0].stop();
371#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
373 std::unique_ptr<Spy<Scalar>> H_spy;
376 H_spy = std::make_unique<Spy<Scalar>>(
377 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
378 num_decision_variables, num_decision_variables);
379 callbacks.push_back([&](
const IterationInfo<Scalar>& info) ->
bool {
387 status = newton<Scalar>(
388 NewtonMatrixCallbacks<Scalar>{
389 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x) -> Scalar {
393 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
394 -> Eigen::SparseVector<Scalar> {
398 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
399 -> Eigen::SparseMatrix<Scalar> {
403 callbacks, options, x);
404 }
else if (m_inequality_constraints.empty()) {
405 if (options.diagnostics) {
406 slp::println(
"\nInvoking SQP solver\n");
409 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
412 ad_setup_profilers.emplace_back(
" ↳ ∂cₑ/∂x").start();
413 Jacobian A_e{c_e_ad, x_ad};
414 ad_setup_profilers.back().stop();
417 VariableMatrix<Scalar> y_ad(num_equality_constraints);
418 Variable L = f - y_ad.T() * c_e_ad;
421 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
422 Hessian<Scalar, Eigen::Lower> H{L, x_ad};
423 ad_setup_profilers.back().stop();
425 ad_setup_profilers[0].stop();
427#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
429 std::unique_ptr<Spy<Scalar>> H_spy;
430 std::unique_ptr<Spy<Scalar>> A_e_spy;
433 H_spy = std::make_unique<Spy<Scalar>>(
434 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
435 num_decision_variables, num_decision_variables);
436 A_e_spy = std::make_unique<Spy<Scalar>>(
437 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
438 "Decision variables", num_equality_constraints,
439 num_decision_variables);
440 callbacks.push_back([&](
const IterationInfo<Scalar>& info) ->
bool {
442 A_e_spy->add(info.A_e);
449 status = sqp<Scalar>(
450 SQPMatrixCallbacks<Scalar>{
451 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x) -> Scalar {
455 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
456 -> Eigen::SparseVector<Scalar> {
460 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x,
461 const Eigen::Vector<Scalar, Eigen::Dynamic>& y)
462 -> Eigen::SparseMatrix<Scalar> {
467 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
468 -> Eigen::Vector<Scalar, Eigen::Dynamic> {
470 return c_e_ad.value();
472 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
473 -> Eigen::SparseMatrix<Scalar> {
477 callbacks, options, x);
479 if (options.diagnostics) {
480 slp::println(
"\nInvoking IPM solver...\n");
483 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
484 VariableMatrix<Scalar> c_i_ad{m_inequality_constraints};
487 ad_setup_profilers.emplace_back(
" ↳ ∂cₑ/∂x").start();
488 Jacobian A_e{c_e_ad, x_ad};
489 ad_setup_profilers.back().stop();
492 ad_setup_profilers.emplace_back(
" ↳ ∂cᵢ/∂x").start();
493 Jacobian A_i{c_i_ad, x_ad};
494 ad_setup_profilers.back().stop();
497 VariableMatrix<Scalar> y_ad(num_equality_constraints);
498 VariableMatrix<Scalar> z_ad(num_inequality_constraints);
499 Variable L = f - y_ad.T() * c_e_ad - z_ad.T() * c_i_ad;
502 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
503 Hessian<Scalar, Eigen::Lower> H{L, x_ad};
504 ad_setup_profilers.back().stop();
506 ad_setup_profilers[0].stop();
508#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
510 std::unique_ptr<Spy<Scalar>> H_spy;
511 std::unique_ptr<Spy<Scalar>> A_e_spy;
512 std::unique_ptr<Spy<Scalar>> A_i_spy;
515 H_spy = std::make_unique<Spy<Scalar>>(
516 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
517 num_decision_variables, num_decision_variables);
518 A_e_spy = std::make_unique<Spy<Scalar>>(
519 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
520 "Decision variables", num_equality_constraints,
521 num_decision_variables);
522 A_i_spy = std::make_unique<Spy<Scalar>>(
523 "A_i.spy",
"Inequality constraint Jacobian",
"Constraints",
524 "Decision variables", num_inequality_constraints,
525 num_decision_variables);
526 callbacks.push_back([&](
const IterationInfo<Scalar>& info) ->
bool {
528 A_e_spy->add(info.A_e);
529 A_i_spy->add(info.A_i);
535 const auto [bound_constraint_mask, bounds, conflicting_bound_indices] =
536 get_bounds<Scalar>(m_decision_variables, m_inequality_constraints,
538 if (!conflicting_bound_indices.empty()) {
539 if (options.diagnostics) {
540 print_bound_constraint_global_infeasibility_error(
541 conflicting_bound_indices);
543 return ExitStatus::GLOBALLY_INFEASIBLE;
546#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
547 project_onto_bounds(x, bounds);
550 status = interior_point<Scalar>(
551 InteriorPointMatrixCallbacks<Scalar>{
552 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x) -> Scalar {
556 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
557 -> Eigen::SparseVector<Scalar> {
561 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x,
562 const Eigen::Vector<Scalar, Eigen::Dynamic>& y,
563 const Eigen::Vector<Scalar, Eigen::Dynamic>& z)
564 -> Eigen::SparseMatrix<Scalar> {
570 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
571 -> Eigen::Vector<Scalar, Eigen::Dynamic> {
573 return c_e_ad.value();
575 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
576 -> Eigen::SparseMatrix<Scalar> {
580 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
581 -> Eigen::Vector<Scalar, Eigen::Dynamic> {
583 return c_i_ad.value();
585 [&](
const Eigen::Vector<Scalar, Eigen::Dynamic>& x)
586 -> Eigen::SparseMatrix<Scalar> {
591#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
592 bound_constraint_mask,
597 if (options.diagnostics) {
598 print_autodiff_diagnostics(ad_setup_profilers);
599 slp::println(
"\nExit: {}", to_message(status));
603 VariableMatrix<Scalar>{m_decision_variables}.set_value(x);