276 using DenseVector = Eigen::Vector<Scalar, Eigen::Dynamic>;
277 using SparseMatrix = Eigen::SparseMatrix<Scalar>;
278 using SparseVector = Eigen::SparseVector<Scalar>;
281 DenseVector x{m_decision_variables.size()};
282 for (
size_t i = 0; i < m_decision_variables.size(); ++i) {
283 x[i] = m_decision_variables[i].value();
286 if (options.diagnostics) {
287 print_exit_conditions(options);
288 print_problem_analysis();
297 if (f_type <= ExpressionType::CONSTANT &&
298 c_e_type <= ExpressionType::CONSTANT &&
299 c_i_type <= ExpressionType::CONSTANT) {
300#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
301 if (options.diagnostics) {
302 slp::println(
"\nInvoking no-op solver...\n");
305 return ExitStatus::SUCCESS;
308 gch::small_vector<SetupProfiler> ad_setup_profilers;
309 ad_setup_profilers.emplace_back(
"setup").start();
311 VariableMatrix<Scalar> x_ad{m_decision_variables};
314 Variable f = m_f.value_or(Scalar(0));
317 ad_setup_profilers.emplace_back(
" ↳ ∇f(x)").start();
319 ad_setup_profilers.back().stop();
322 int num_decision_variables = m_decision_variables.size();
324 int num_equality_constraints = m_equality_constraints.size();
326 int num_inequality_constraints = m_inequality_constraints.size();
328 gch::small_vector<std::function<bool(
const IterationInfo<Scalar>& info)>>
330 for (
const auto& callback : m_iteration_callbacks) {
331 callbacks.emplace_back(callback);
333 for (
const auto& callback : m_persistent_iteration_callbacks) {
334 callbacks.emplace_back(callback);
339 if (m_equality_constraints.empty() && m_inequality_constraints.empty()) {
340 if (options.diagnostics) {
341 slp::println(
"\nInvoking Newton solver...\n");
345 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
346 Hessian<Scalar, Eigen::Lower> H{f, x_ad};
347 ad_setup_profilers.back().stop();
349 ad_setup_profilers[0].stop();
351#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
353 std::unique_ptr<Spy<Scalar>> H_spy;
356 H_spy = std::make_unique<Spy<Scalar>>(
357 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
358 num_decision_variables, num_decision_variables);
359 callbacks.push_back([&](
const IterationInfo<Scalar>& info) ->
bool {
367 status = newton<Scalar>(NewtonMatrixCallbacks<Scalar>{
368 [&](
const DenseVector& x) -> Scalar {
372 [&](
const DenseVector& x) -> SparseVector {
376 [&](
const DenseVector& x) -> SparseMatrix {
380 callbacks, options, x);
381 }
else if (m_inequality_constraints.empty()) {
382 if (options.diagnostics) {
383 slp::println(
"\nInvoking SQP solver\n");
386 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
389 ad_setup_profilers.emplace_back(
" ↳ ∂cₑ/∂x").start();
390 Jacobian A_e{c_e_ad, x_ad};
391 ad_setup_profilers.back().stop();
394 VariableMatrix<Scalar> y_ad(num_equality_constraints);
395 Variable L = f - y_ad.T() * c_e_ad;
398 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
399 Hessian<Scalar, Eigen::Lower> H{L, x_ad};
400 ad_setup_profilers.back().stop();
402 ad_setup_profilers[0].stop();
404#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
406 std::unique_ptr<Spy<Scalar>> H_spy;
407 std::unique_ptr<Spy<Scalar>> A_e_spy;
410 H_spy = std::make_unique<Spy<Scalar>>(
411 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
412 num_decision_variables, num_decision_variables);
413 A_e_spy = std::make_unique<Spy<Scalar>>(
414 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
415 "Decision variables", num_equality_constraints,
416 num_decision_variables);
417 callbacks.push_back([&](
const IterationInfo<Scalar>& info) ->
bool {
419 A_e_spy->add(info.A_e);
426 status = sqp<Scalar>(
427 SQPMatrixCallbacks<Scalar>{
428 [&](
const DenseVector& x) -> Scalar {
432 [&](
const DenseVector& x) -> SparseVector {
436 [&](
const DenseVector& x,
const DenseVector& y) -> SparseMatrix {
441 [&](
const DenseVector& x) -> DenseVector {
443 return c_e_ad.value();
445 [&](
const DenseVector& x) -> SparseMatrix {
449 callbacks, options, x);
451 if (options.diagnostics) {
452 slp::println(
"\nInvoking IPM solver...\n");
455 VariableMatrix<Scalar> c_e_ad{m_equality_constraints};
456 VariableMatrix<Scalar> c_i_ad{m_inequality_constraints};
459 ad_setup_profilers.emplace_back(
" ↳ ∂cₑ/∂x").start();
460 Jacobian A_e{c_e_ad, x_ad};
461 ad_setup_profilers.back().stop();
464 ad_setup_profilers.emplace_back(
" ↳ ∂cᵢ/∂x").start();
465 Jacobian A_i{c_i_ad, x_ad};
466 ad_setup_profilers.back().stop();
469 VariableMatrix<Scalar> y_ad(num_equality_constraints);
470 VariableMatrix<Scalar> z_ad(num_inequality_constraints);
471 Variable L = f - y_ad.T() * c_e_ad - z_ad.T() * c_i_ad;
474 ad_setup_profilers.emplace_back(
" ↳ ∇²ₓₓL").start();
475 Hessian<Scalar, Eigen::Lower> H{L, x_ad};
476 ad_setup_profilers.back().stop();
478 ad_setup_profilers[0].stop();
480#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
482 std::unique_ptr<Spy<Scalar>> H_spy;
483 std::unique_ptr<Spy<Scalar>> A_e_spy;
484 std::unique_ptr<Spy<Scalar>> A_i_spy;
487 H_spy = std::make_unique<Spy<Scalar>>(
488 "H.spy",
"Hessian",
"Decision variables",
"Decision variables",
489 num_decision_variables, num_decision_variables);
490 A_e_spy = std::make_unique<Spy<Scalar>>(
491 "A_e.spy",
"Equality constraint Jacobian",
"Constraints",
492 "Decision variables", num_equality_constraints,
493 num_decision_variables);
494 A_i_spy = std::make_unique<Spy<Scalar>>(
495 "A_i.spy",
"Inequality constraint Jacobian",
"Constraints",
496 "Decision variables", num_inequality_constraints,
497 num_decision_variables);
498 callbacks.push_back([&](
const IterationInfo<Scalar>& info) ->
bool {
500 A_e_spy->add(info.A_e);
501 A_i_spy->add(info.A_i);
507 const auto [bound_constraint_mask, bounds, conflicting_bound_indices] =
508 get_bounds<Scalar>(m_decision_variables, m_inequality_constraints,
510 if (!conflicting_bound_indices.empty()) {
511 if (options.diagnostics) {
512 print_bound_constraint_global_infeasibility_error(
513 conflicting_bound_indices);
515 return ExitStatus::GLOBALLY_INFEASIBLE;
518#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
519 project_onto_bounds(x, bounds);
522 status = interior_point<Scalar>(
523 InteriorPointMatrixCallbacks<Scalar>{
524 [&](
const DenseVector& x) -> Scalar {
528 [&](
const DenseVector& x) -> SparseVector {
532 [&](
const DenseVector& x,
const DenseVector& y,
533 const DenseVector& z) -> SparseMatrix {
539 [&](
const DenseVector& x) -> DenseVector {
541 return c_e_ad.value();
543 [&](
const DenseVector& x) -> SparseMatrix {
547 [&](
const DenseVector& x) -> DenseVector {
549 return c_i_ad.value();
551 [&](
const DenseVector& x) -> SparseMatrix {
556#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
557 bound_constraint_mask,
562 if (options.diagnostics) {
563 print_autodiff_diagnostics(ad_setup_profilers);
564 slp::println(
"\nExit: {}", status);
568 VariableMatrix<Scalar>{m_decision_variables}.set_value(x);