282 using DenseVector = Eigen::Vector<Scalar, Eigen::Dynamic>;
283 using SparseMatrix = Eigen::SparseMatrix<Scalar>;
284 using SparseVector = Eigen::SparseVector<Scalar>;
287 DenseVector x{m_decision_variables.size()};
288 for (
size_t i = 0; i < m_decision_variables.size(); ++i) {
289 x[i] = m_decision_variables[i].value();
292 if (options.diagnostics) {
293 print_exit_conditions(options);
294 print_problem_analysis();
303 if (f_type <= ExpressionType::CONSTANT &&
304 c_e_type <= ExpressionType::CONSTANT &&
305 c_i_type <= ExpressionType::CONSTANT) {
306#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
307 if (options.diagnostics) {
308 slp::println(
"\nInvoking no-op solver\n");
311 return ExitStatus::SUCCESS;
314 VariableMatrix<Scalar> x_ad{m_decision_variables};
317 Variable f = m_f.value_or(Scalar(0));
319 int num_decision_variables = m_decision_variables.size();
320 int num_equality_constraints = m_equality_constraints.size();
321 int num_inequality_constraints = m_inequality_constraints.size();
323 gch::small_vector<std::function<bool(
const IterationInfo<Scalar>& info)>>
325 for (
const auto& callback : m_iteration_callbacks) {
326 iteration_callbacks.emplace_back(callback);
328 for (
const auto& callback : m_persistent_iteration_callbacks) {
329 iteration_callbacks.emplace_back(callback);
334 if (m_equality_constraints.empty() && m_inequality_constraints.empty()) {
335 if (options.diagnostics) {
336 slp::println(
"\nInvoking Newton solver\n");
339 gch::small_vector<SetupProfiler> ad_setup_profilers;
340 ad_setup_profilers.emplace_back(
"setup");
341 ad_setup_profilers.emplace_back(
"↳ ∇f(x)");
342 ad_setup_profilers.emplace_back(
"↳ ∇²ₓₓL");
344 ad_setup_profilers[0].start();
347 ad_setup_profilers[1].start();
349 ad_setup_profilers[1].stop();
352 ad_setup_profilers[2].start();
353 Hessian<Scalar, Eigen::Lower> H{f, x_ad};
354 ad_setup_profilers[2].stop();
356 ad_setup_profilers[0].stop();
358 if (options.diagnostics) {
359 print_setup_diagnostics(ad_setup_profilers);
362#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
364 std::unique_ptr<Spy<Scalar>> H_spy;
367 H_spy = std::make_unique<Spy<Scalar>>(
368 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
369 num_decision_variables, num_decision_variables);
370 iteration_callbacks.push_back(
371 [&](
const IterationInfo<Scalar>& info) ->
bool {
378 NewtonMatrixCallbacks<Scalar> matrix_callbacks{
379 num_decision_variables,
380 [&](
const DenseVector& x) -> Scalar {
384 [&](
const DenseVector& x) -> SparseVector {
388 [&](
const DenseVector& x) -> SparseMatrix {
395 newton<Scalar>(matrix_callbacks, iteration_callbacks, options, x);
396 }
else if (m_inequality_constraints.empty()) {
397 if (options.diagnostics) {
398 slp::println(
"\nInvoking SQP solver\n");
401 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
402 VariableMatrix<Scalar> y_ad(num_equality_constraints);
404 gch::small_vector<SetupProfiler> ad_setup_profilers;
405 ad_setup_profilers.emplace_back(
"setup");
406 ad_setup_profilers.emplace_back(
"↳ ∇f(x)");
407 ad_setup_profilers.emplace_back(
"↳ ∇²ₓₓL");
408 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_f");
409 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_c");
410 ad_setup_profilers.emplace_back(
"↳ ∂cₑ/∂x");
412 ad_setup_profilers[0].start();
415 ad_setup_profilers[1].start();
417 ad_setup_profilers[1].stop();
419 ad_setup_profilers[2].start();
422 ad_setup_profilers[3].start();
423 Hessian<Scalar, Eigen::Lower> H_f{f, x_ad};
424 ad_setup_profilers[3].stop();
427 ad_setup_profilers[4].start();
428 Hessian<Scalar, Eigen::Lower> H_c{-y_ad.T() * c_e_ad, x_ad};
429 ad_setup_profilers[4].stop();
431 ad_setup_profilers[2].stop();
434 ad_setup_profilers[5].start();
435 Jacobian A_e{c_e_ad, x_ad};
436 ad_setup_profilers[5].stop();
438 ad_setup_profilers[0].stop();
440 if (options.diagnostics) {
441 print_setup_diagnostics(ad_setup_profilers);
444#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
446 std::unique_ptr<Spy<Scalar>> H_spy;
447 std::unique_ptr<Spy<Scalar>> A_e_spy;
450 H_spy = std::make_unique<Spy<Scalar>>(
451 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
452 num_decision_variables, num_decision_variables);
453 A_e_spy = std::make_unique<Spy<Scalar>>(
454 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
455 "Decision variables", num_equality_constraints,
456 num_decision_variables);
457 iteration_callbacks.push_back(
458 [&](
const IterationInfo<Scalar>& info) ->
bool {
460 A_e_spy->add(info.A_e);
466 SQPMatrixCallbacks<Scalar> matrix_callbacks{
467 num_decision_variables,
468 num_equality_constraints,
469 [&](
const DenseVector& x) -> Scalar {
473 [&](
const DenseVector& x) -> SparseVector {
477 [&](
const DenseVector& x,
const DenseVector& y) -> SparseMatrix {
480 return H_f.value() + H_c.value();
482 [&](
const DenseVector& x,
const DenseVector& y) -> SparseMatrix {
487 [&](
const DenseVector& x) -> DenseVector {
489 return c_e_ad.value();
491 [&](
const DenseVector& x) -> SparseMatrix {
497 status = sqp<Scalar>(matrix_callbacks, iteration_callbacks, options, x);
499 if (options.diagnostics) {
500 slp::println(
"\nInvoking IPM solver\n");
503 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
504 VariableMatrix<Scalar> c_i_ad{m_inequality_constraints};
505 VariableMatrix<Scalar> y_ad(num_equality_constraints);
506 VariableMatrix<Scalar> z_ad(num_inequality_constraints);
508 gch::small_vector<SetupProfiler> ad_setup_profilers;
509 ad_setup_profilers.emplace_back(
"setup");
510 ad_setup_profilers.emplace_back(
"↳ ∇f(x)");
511 ad_setup_profilers.emplace_back(
"↳ ∇²ₓₓL");
512 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_f");
513 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_c");
514 ad_setup_profilers.emplace_back(
"↳ ∂cₑ/∂x");
515 ad_setup_profilers.emplace_back(
"↳ ∂cᵢ/∂x");
517 ad_setup_profilers[0].start();
520 ad_setup_profilers[1].start();
522 ad_setup_profilers[1].stop();
524 ad_setup_profilers[2].start();
527 ad_setup_profilers[3].start();
528 Hessian<Scalar, Eigen::Lower> H_f{f, x_ad};
529 ad_setup_profilers[3].stop();
532 ad_setup_profilers[4].start();
533 Hessian<Scalar, Eigen::Lower> H_c{-y_ad.T() * c_e_ad - z_ad.T() * c_i_ad,
535 ad_setup_profilers[4].stop();
537 ad_setup_profilers[2].stop();
540 ad_setup_profilers[5].start();
541 Jacobian A_e{c_e_ad, x_ad};
542 ad_setup_profilers[5].stop();
545 ad_setup_profilers[6].start();
546 Jacobian A_i{c_i_ad, x_ad};
547 ad_setup_profilers[6].stop();
549 ad_setup_profilers[0].stop();
551 if (options.diagnostics) {
552 print_setup_diagnostics(ad_setup_profilers);
555#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
557 std::unique_ptr<Spy<Scalar>> H_spy;
558 std::unique_ptr<Spy<Scalar>> A_e_spy;
559 std::unique_ptr<Spy<Scalar>> A_i_spy;
562 H_spy = std::make_unique<Spy<Scalar>>(
563 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
564 num_decision_variables, num_decision_variables);
565 A_e_spy = std::make_unique<Spy<Scalar>>(
566 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
567 "Decision variables", num_equality_constraints,
568 num_decision_variables);
569 A_i_spy = std::make_unique<Spy<Scalar>>(
570 "A_i.spy",
"Inequality constraint Jacobian",
"Constraints",
571 "Decision variables", num_inequality_constraints,
572 num_decision_variables);
573 iteration_callbacks.push_back(
574 [&](
const IterationInfo<Scalar>& info) ->
bool {
576 A_e_spy->add(info.A_e);
577 A_i_spy->add(info.A_i);
583 const auto [bound_constraint_mask, bounds, conflicting_bound_indices] =
584 get_bounds<Scalar>(m_decision_variables, m_inequality_constraints,
586 if (!conflicting_bound_indices.empty()) {
587 if (options.diagnostics) {
588 print_bound_constraint_global_infeasibility_error(
589 conflicting_bound_indices);
591 return ExitStatus::GLOBALLY_INFEASIBLE;
594#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
595 project_onto_bounds(x, bounds);
598 InteriorPointMatrixCallbacks<Scalar> matrix_callbacks{
599 num_decision_variables,
600 num_equality_constraints,
601 num_inequality_constraints,
602 [&](
const DenseVector& x) -> Scalar {
606 [&](
const DenseVector& x) -> SparseVector {
610 [&](
const DenseVector& x,
const DenseVector& y,
611 const DenseVector& z) -> SparseMatrix {
615 return H_f.value() + H_c.value();
617 [&](
const DenseVector& x,
const DenseVector& y,
618 const DenseVector& z) -> SparseMatrix {
624 [&](
const DenseVector& x) -> DenseVector {
626 return c_e_ad.value();
628 [&](
const DenseVector& x) -> SparseMatrix {
632 [&](
const DenseVector& x) -> DenseVector {
634 return c_i_ad.value();
636 [&](
const DenseVector& x) -> SparseMatrix {
643 interior_point<Scalar>(matrix_callbacks, iteration_callbacks, options,
644#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
645 bound_constraint_mask,
650 if (options.diagnostics) {
651 slp::println(
"\nExit: {}", status);
655 VariableMatrix<Scalar>{m_decision_variables}.set_value(x);