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 gch::small_vector<SetupProfiler> ad_setup_profilers;
315 ad_setup_profilers.emplace_back(
"setup").start();
317 VariableMatrix<Scalar> x_ad{m_decision_variables};
320 Variable f = m_f.value_or(Scalar(0));
323 ad_setup_profilers.emplace_back(
" ↳ ∇f(x)").start();
325 ad_setup_profilers.back().stop();
327 int num_decision_variables = m_decision_variables.size();
328 int num_equality_constraints = m_equality_constraints.size();
329 int num_inequality_constraints = m_inequality_constraints.size();
331 gch::small_vector<std::function<bool(
const IterationInfo<Scalar>& info)>>
333 for (
const auto& callback : m_iteration_callbacks) {
334 iteration_callbacks.emplace_back(callback);
336 for (
const auto& callback : m_persistent_iteration_callbacks) {
337 iteration_callbacks.emplace_back(callback);
342 if (m_equality_constraints.empty() && m_inequality_constraints.empty()) {
343 if (options.diagnostics) {
344 slp::println(
"\nInvoking Newton solver...\n");
348 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
349 Hessian<Scalar, Eigen::Lower> H{f, x_ad};
350 ad_setup_profilers.back().stop();
352 ad_setup_profilers[0].stop();
354#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
356 std::unique_ptr<Spy<Scalar>> H_spy;
359 H_spy = std::make_unique<Spy<Scalar>>(
360 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
361 num_decision_variables, num_decision_variables);
362 iteration_callbacks.push_back(
363 [&](
const IterationInfo<Scalar>& info) ->
bool {
370 NewtonMatrixCallbacks<Scalar> matrix_callbacks{
371 num_decision_variables,
372 [&](
const DenseVector& x) -> Scalar {
376 [&](
const DenseVector& x) -> SparseVector {
380 [&](
const DenseVector& x) -> SparseMatrix {
387 newton<Scalar>(matrix_callbacks, iteration_callbacks, options, x);
388 }
else if (m_inequality_constraints.empty()) {
389 if (options.diagnostics) {
390 slp::println(
"\nInvoking SQP solver\n");
393 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
396 ad_setup_profilers.emplace_back(
" ↳ ∂cₑ/∂x").start();
397 Jacobian A_e{c_e_ad, x_ad};
398 ad_setup_profilers.back().stop();
401 VariableMatrix<Scalar> y_ad(num_equality_constraints);
402 Variable L = f - y_ad.T() * c_e_ad;
405 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
406 Hessian<Scalar, Eigen::Lower> H{L, x_ad};
407 ad_setup_profilers.back().stop();
409 ad_setup_profilers[0].stop();
411#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
413 std::unique_ptr<Spy<Scalar>> H_spy;
414 std::unique_ptr<Spy<Scalar>> A_e_spy;
417 H_spy = std::make_unique<Spy<Scalar>>(
418 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
419 num_decision_variables, num_decision_variables);
420 A_e_spy = std::make_unique<Spy<Scalar>>(
421 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
422 "Decision variables", num_equality_constraints,
423 num_decision_variables);
424 iteration_callbacks.push_back(
425 [&](
const IterationInfo<Scalar>& info) ->
bool {
427 A_e_spy->add(info.A_e);
433 SQPMatrixCallbacks<Scalar> matrix_callbacks{
434 num_decision_variables,
435 num_equality_constraints,
436 [&](
const DenseVector& x) -> Scalar {
440 [&](
const DenseVector& x) -> SparseVector {
444 [&](
const DenseVector& x,
const DenseVector& y) -> SparseMatrix {
449 [&](
const DenseVector& x) -> DenseVector {
451 return c_e_ad.value();
453 [&](
const DenseVector& x) -> SparseMatrix {
459 status = sqp<Scalar>(matrix_callbacks, iteration_callbacks, options, x);
461 if (options.diagnostics) {
462 slp::println(
"\nInvoking IPM solver...\n");
465 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
466 VariableMatrix<Scalar> c_i_ad{m_inequality_constraints};
469 ad_setup_profilers.emplace_back(
" ↳ ∂cₑ/∂x").start();
470 Jacobian A_e{c_e_ad, x_ad};
471 ad_setup_profilers.back().stop();
474 ad_setup_profilers.emplace_back(
" ↳ ∂cᵢ/∂x").start();
475 Jacobian A_i{c_i_ad, x_ad};
476 ad_setup_profilers.back().stop();
479 VariableMatrix<Scalar> y_ad(num_equality_constraints);
480 VariableMatrix<Scalar> z_ad(num_inequality_constraints);
481 Variable L = f - y_ad.T() * c_e_ad - z_ad.T() * c_i_ad;
484 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
485 Hessian<Scalar, Eigen::Lower> H{L, x_ad};
486 ad_setup_profilers.back().stop();
488 ad_setup_profilers[0].stop();
490#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
492 std::unique_ptr<Spy<Scalar>> H_spy;
493 std::unique_ptr<Spy<Scalar>> A_e_spy;
494 std::unique_ptr<Spy<Scalar>> A_i_spy;
497 H_spy = std::make_unique<Spy<Scalar>>(
498 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
499 num_decision_variables, num_decision_variables);
500 A_e_spy = std::make_unique<Spy<Scalar>>(
501 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
502 "Decision variables", num_equality_constraints,
503 num_decision_variables);
504 A_i_spy = std::make_unique<Spy<Scalar>>(
505 "A_i.spy",
"Inequality constraint Jacobian",
"Constraints",
506 "Decision variables", num_inequality_constraints,
507 num_decision_variables);
508 iteration_callbacks.push_back(
509 [&](
const IterationInfo<Scalar>& info) ->
bool {
511 A_e_spy->add(info.A_e);
512 A_i_spy->add(info.A_i);
518 const auto [bound_constraint_mask, bounds, conflicting_bound_indices] =
519 get_bounds<Scalar>(m_decision_variables, m_inequality_constraints,
521 if (!conflicting_bound_indices.empty()) {
522 if (options.diagnostics) {
523 print_bound_constraint_global_infeasibility_error(
524 conflicting_bound_indices);
526 return ExitStatus::GLOBALLY_INFEASIBLE;
529#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
530 project_onto_bounds(x, bounds);
533 InteriorPointMatrixCallbacks<Scalar> matrix_callbacks{
534 num_decision_variables,
535 num_equality_constraints,
536 num_inequality_constraints,
537 [&](
const DenseVector& x) -> Scalar {
541 [&](
const DenseVector& x) -> SparseVector {
545 [&](
const DenseVector& x,
const DenseVector& y,
546 const DenseVector& z) -> SparseMatrix {
552 [&](
const DenseVector& x) -> DenseVector {
554 return c_e_ad.value();
556 [&](
const DenseVector& x) -> SparseMatrix {
560 [&](
const DenseVector& x) -> DenseVector {
562 return c_i_ad.value();
564 [&](
const DenseVector& x) -> SparseMatrix {
571 interior_point<Scalar>(matrix_callbacks, iteration_callbacks, options,
572#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
573 bound_constraint_mask,
578 if (options.diagnostics) {
579 print_autodiff_diagnostics(ad_setup_profilers);
580 slp::println(
"\nExit: {}", status);
584 VariableMatrix<Scalar>{m_decision_variables}.set_value(x);