283 using DenseVector = Eigen::Vector<Scalar, Eigen::Dynamic>;
284 using SparseMatrix = Eigen::SparseMatrix<Scalar>;
285 using SparseVector = Eigen::SparseVector<Scalar>;
288 DenseVector x{m_decision_variables.size()};
289 for (
size_t i = 0; i < m_decision_variables.size(); ++i) {
290 x[i] = m_decision_variables[i].value();
293 if (options.diagnostics) {
294 print_exit_conditions(options);
295 print_problem_analysis();
304 if (f_type <= ExpressionType::CONSTANT &&
305 c_e_type <= ExpressionType::CONSTANT &&
306 c_i_type <= ExpressionType::CONSTANT) {
307#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
308 if (options.diagnostics) {
309 slp::println(
"\nInvoking no-op solver\n");
312 return ExitStatus::SUCCESS;
315 VariableMatrix<Scalar> x_ad{m_decision_variables};
318 Variable f = m_f.value_or(Scalar(0));
320 int num_decision_variables = m_decision_variables.size();
321 int num_equality_constraints = m_equality_constraints.size();
322 int num_inequality_constraints = m_inequality_constraints.size();
324 gch::small_vector<std::function<bool(
const IterationInfo<Scalar>& info)>>
326 for (
const auto& callback : m_iteration_callbacks) {
327 iteration_callbacks.emplace_back(callback);
329 for (
const auto& callback : m_persistent_iteration_callbacks) {
330 iteration_callbacks.emplace_back(callback);
335 if (m_equality_constraints.empty() && m_inequality_constraints.empty()) {
336 if (options.diagnostics) {
337 slp::println(
"\nInvoking Newton solver\n");
340 gch::small_vector<SetupProfiler> ad_setup_profilers;
341 ad_setup_profilers.emplace_back(
"setup");
342 ad_setup_profilers.emplace_back(
"↳ ∇f(x)");
343 ad_setup_profilers.emplace_back(
"↳ ∇²ₓₓL");
345 ad_setup_profilers[0].start();
348 ad_setup_profilers[1].start();
350 ad_setup_profilers[1].stop();
353 ad_setup_profilers[2].start();
354 Hessian<Scalar, Eigen::Lower> H{f, x_ad};
355 ad_setup_profilers[2].stop();
357 ad_setup_profilers[0].stop();
359 if (options.diagnostics) {
360 print_setup_diagnostics(ad_setup_profilers);
363#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
365 std::unique_ptr<Spy<Scalar>> H_spy;
368 H_spy = std::make_unique<Spy<Scalar>>(
369 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
370 num_decision_variables, num_decision_variables);
371 iteration_callbacks.push_back(
372 [&](
const IterationInfo<Scalar>& info) ->
bool {
382 const ProblemScaling<Scalar> scaling{g.value()};
384 NewtonMatrixCallbacks<Scalar> matrix_callbacks{
385 num_decision_variables,
386 [&](
const DenseVector& x) -> Scalar {
388 return scaling.f * f.value();
390 [&](
const DenseVector& x) -> SparseVector {
392 return scaling.f * g.value();
394 [&](
const DenseVector& x) -> SparseMatrix {
396 return scaling.f * H.value();
402 newton<Scalar>(matrix_callbacks, iteration_callbacks, options, x);
403 }
else if (m_inequality_constraints.empty()) {
404 if (options.diagnostics) {
405 slp::println(
"\nInvoking SQP solver\n");
408 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
409 VariableMatrix<Scalar> y_ad(num_equality_constraints);
411 gch::small_vector<SetupProfiler> ad_setup_profilers;
412 ad_setup_profilers.emplace_back(
"setup");
413 ad_setup_profilers.emplace_back(
"↳ ∇f(x)");
414 ad_setup_profilers.emplace_back(
"↳ ∇²ₓₓL");
415 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_f");
416 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_c");
417 ad_setup_profilers.emplace_back(
"↳ ∂cₑ/∂x");
419 ad_setup_profilers[0].start();
422 ad_setup_profilers[1].start();
424 ad_setup_profilers[1].stop();
426 ad_setup_profilers[2].start();
429 ad_setup_profilers[3].start();
430 Hessian<Scalar, Eigen::Lower> H_f{f, x_ad};
431 ad_setup_profilers[3].stop();
434 ad_setup_profilers[4].start();
435 Hessian<Scalar, Eigen::Lower> H_c{-y_ad.T() * c_e_ad, x_ad};
436 ad_setup_profilers[4].stop();
438 ad_setup_profilers[2].stop();
441 ad_setup_profilers[5].start();
442 Jacobian A_e{c_e_ad, x_ad};
443 ad_setup_profilers[5].stop();
445 ad_setup_profilers[0].stop();
447 if (options.diagnostics) {
448 print_setup_diagnostics(ad_setup_profilers);
451#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
453 std::unique_ptr<Spy<Scalar>> H_spy;
454 std::unique_ptr<Spy<Scalar>> A_e_spy;
457 H_spy = std::make_unique<Spy<Scalar>>(
458 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
459 num_decision_variables, num_decision_variables);
460 A_e_spy = std::make_unique<Spy<Scalar>>(
461 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
462 "Decision variables", num_equality_constraints,
463 num_decision_variables);
464 iteration_callbacks.push_back(
465 [&](
const IterationInfo<Scalar>& info) ->
bool {
467 A_e_spy->add(info.A_e);
477 const ProblemScaling<Scalar> scaling{g.value(), A_e.value()};
479 SQPMatrixCallbacks<Scalar> matrix_callbacks{
480 num_decision_variables,
481 num_equality_constraints,
482 [&](
const DenseVector& x) -> Scalar {
484 return scaling.f * f.value();
486 [&](
const DenseVector& x) -> SparseVector {
488 return scaling.f * g.value();
490 [&](
const DenseVector& x,
const DenseVector& y) -> SparseMatrix {
492 y_ad.set_value(scaling.c_e.cwiseProduct(y));
493 return scaling.f * H_f.value() + H_c.value();
495 [&](
const DenseVector& x,
const DenseVector& y) -> SparseMatrix {
497 y_ad.set_value(scaling.c_e.cwiseProduct(y));
500 [&](
const DenseVector& x) -> DenseVector {
502 return scaling.c_e.cwiseProduct(c_e_ad.value());
504 [&](
const DenseVector& x) -> SparseMatrix {
506 return scaling.c_e.asDiagonal() * A_e.value();
511 status = sqp<Scalar>(matrix_callbacks, iteration_callbacks, options, x);
513 if (options.diagnostics) {
514 slp::println(
"\nInvoking IPM solver\n");
517 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
518 VariableMatrix<Scalar> c_i_ad{m_inequality_constraints};
519 VariableMatrix<Scalar> y_ad(num_equality_constraints);
520 VariableMatrix<Scalar> z_ad(num_inequality_constraints);
522 gch::small_vector<SetupProfiler> ad_setup_profilers;
523 ad_setup_profilers.emplace_back(
"setup");
524 ad_setup_profilers.emplace_back(
"↳ ∇f(x)");
525 ad_setup_profilers.emplace_back(
"↳ ∇²ₓₓL");
526 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_f");
527 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL_c");
528 ad_setup_profilers.emplace_back(
"↳ ∂cₑ/∂x");
529 ad_setup_profilers.emplace_back(
"↳ ∂cᵢ/∂x");
531 ad_setup_profilers[0].start();
534 ad_setup_profilers[1].start();
536 ad_setup_profilers[1].stop();
538 ad_setup_profilers[2].start();
541 ad_setup_profilers[3].start();
542 Hessian<Scalar, Eigen::Lower> H_f{f, x_ad};
543 ad_setup_profilers[3].stop();
546 ad_setup_profilers[4].start();
547 Hessian<Scalar, Eigen::Lower> H_c{-y_ad.T() * c_e_ad - z_ad.T() * c_i_ad,
549 ad_setup_profilers[4].stop();
551 ad_setup_profilers[2].stop();
554 ad_setup_profilers[5].start();
555 Jacobian A_e{c_e_ad, x_ad};
556 ad_setup_profilers[5].stop();
559 ad_setup_profilers[6].start();
560 Jacobian A_i{c_i_ad, x_ad};
561 ad_setup_profilers[6].stop();
563 ad_setup_profilers[0].stop();
565 if (options.diagnostics) {
566 print_setup_diagnostics(ad_setup_profilers);
569#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
571 std::unique_ptr<Spy<Scalar>> H_spy;
572 std::unique_ptr<Spy<Scalar>> A_e_spy;
573 std::unique_ptr<Spy<Scalar>> A_i_spy;
576 H_spy = std::make_unique<Spy<Scalar>>(
577 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
578 num_decision_variables, num_decision_variables);
579 A_e_spy = std::make_unique<Spy<Scalar>>(
580 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
581 "Decision variables", num_equality_constraints,
582 num_decision_variables);
583 A_i_spy = std::make_unique<Spy<Scalar>>(
584 "A_i.spy",
"Inequality constraint Jacobian",
"Constraints",
585 "Decision variables", num_inequality_constraints,
586 num_decision_variables);
587 iteration_callbacks.push_back(
588 [&](
const IterationInfo<Scalar>& info) ->
bool {
590 A_e_spy->add(info.A_e);
591 A_i_spy->add(info.A_i);
597 const auto [bound_constraint_mask, bounds, conflicting_bound_indices] =
598 get_bounds<Scalar>(m_decision_variables, m_inequality_constraints,
600 if (!conflicting_bound_indices.empty()) {
601 if (options.diagnostics) {
602 print_bound_constraint_global_infeasibility_error(
603 conflicting_bound_indices);
605 return ExitStatus::GLOBALLY_INFEASIBLE;
608#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
609 project_onto_bounds(x, bounds);
616 const ProblemScaling<Scalar> scaling{g.value(), A_e.value(), A_i.value()};
618 InteriorPointMatrixCallbacks<Scalar> matrix_callbacks{
619 num_decision_variables,
620 num_equality_constraints,
621 num_inequality_constraints,
622 [&](
const DenseVector& x) -> Scalar {
624 return scaling.f * f.value();
626 [&](
const DenseVector& x) -> SparseVector {
628 return scaling.f * g.value();
630 [&](
const DenseVector& x,
const DenseVector& y,
631 const DenseVector& z) -> SparseMatrix {
633 y_ad.set_value(scaling.c_e.cwiseProduct(y));
634 z_ad.set_value(scaling.c_i.cwiseProduct(z));
635 return scaling.f * H_f.value() + H_c.value();
637 [&](
const DenseVector& x,
const DenseVector& y,
638 const DenseVector& z) -> SparseMatrix {
640 y_ad.set_value(scaling.c_e.cwiseProduct(y));
641 z_ad.set_value(scaling.c_i.cwiseProduct(z));
644 [&](
const DenseVector& x) -> DenseVector {
646 return scaling.c_e.cwiseProduct(c_e_ad.value());
648 [&](
const DenseVector& x) -> SparseMatrix {
650 return scaling.c_e.asDiagonal() * A_e.value();
652 [&](
const DenseVector& x) -> DenseVector {
654 return scaling.c_i.cwiseProduct(c_i_ad.value());
656 [&](
const DenseVector& x) -> SparseMatrix {
658 return scaling.c_i.asDiagonal() * A_i.value();
664 interior_point<Scalar>(matrix_callbacks, iteration_callbacks, options,
665#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
666 bound_constraint_mask,
671 if (options.diagnostics) {
672 slp::println(
"\nExit: {}", status);
676 VariableMatrix<Scalar>{m_decision_variables}.set_value(x);