17 #if PANOCPY_HAVE_CASADI
21 #include <pybind11/attr.h>
22 #include <pybind11/cast.h>
23 #include <pybind11/chrono.h>
24 #include <pybind11/detail/common.h>
25 #include <pybind11/eigen.h>
26 #include <pybind11/functional.h>
27 #include <pybind11/iostream.h>
28 #include <pybind11/pybind11.h>
29 #include <pybind11/pytypes.h>
30 #include <pybind11/stl.h>
37 #include <type_traits>
45 namespace py = pybind11;
47 template <
class DirectionProv
iderT>
51 static_assert(std::is_base_of_v<Base, DirectionProviderT>);
52 auto full_python_copy = std::make_shared<py::object>(py::cast(dir));
53 auto base_copy = full_python_copy->template cast<Base *>();
54 return std::make_shared<pa::PolymorphicPANOCSolver>(
57 std::shared_ptr<Base>(full_python_copy, base_copy),
62 template <
class DirectionProviderT,
class... DirectionArgumentsT>
64 return [](
const pa::PANOCParams &pp,
const DirectionArgumentsT &...args) {
66 static_assert(std::is_base_of_v<Base, DirectionProviderT>);
67 static_assert(std::is_constructible_v<DirectionProviderT,
68 DirectionArgumentsT...>);
69 DirectionProviderT dir{args...};
70 return PolymorphicPANOCConstructor<DirectionProviderT>()(pp, dir);
74 template <
class InnerSolverT>
76 return [](
const pa::ALMParams &pp,
const InnerSolverT &inner) {
78 static_assert(std::is_base_of_v<Base, InnerSolverT>);
79 auto full_python_copy = std::make_shared<py::object>(py::cast(inner));
80 auto base_copy = full_python_copy->template cast<Base *>();
83 std::shared_ptr<Base>(full_python_copy, base_copy),
88 template <
class InnerSolverT>
90 return [](
const InnerSolverT &inner) {
91 return PolymorphicALMConstructor<InnerSolverT>()(
pa::ALMParams(),
96 template <
class InnerSolverT,
class... InnerSolverArgumentsT>
98 return [](
const pa::ALMParams &pp,
const InnerSolverArgumentsT &...args) {
100 static_assert(std::is_base_of_v<Base, InnerSolverT>);
102 std::is_constructible_v<InnerSolverT, InnerSolverArgumentsT...>);
103 InnerSolverT inner{args...};
104 return PolymorphicALMConstructor<InnerSolverT>()(pp, inner);
108 #define STRINGIFY(x) #x
109 #define MACRO_STRINGIFY(x) STRINGIFY(x)
112 using py::operator
""_a;
115 options.enable_function_signatures();
116 options.enable_user_defined_docstrings();
118 m.doc() =
"PANOC+ALM solvers";
123 m.attr(
"__version__") =
"dev";
126 py::class_<pa::Box>(
m,
"Box",
"C++ documentation: :cpp:class:`pa::Box`")
127 .def(py::init([](
unsigned n) {
132 "Create an :math:`n`-dimensional box at with bounds at "
133 ":math:`\\pm\\infty` (no constraints).")
135 if (ub.size() != lb.size())
136 throw std::invalid_argument(
137 "Upper bound and lower bound dimensions do not "
139 return pa::Box{std::move(ub), std::move(lb)};
141 "ub"_a,
"lb"_a,
"Create a box with the given bounds.")
145 py::class_<pa::Problem>(
m,
"Problem",
146 "C++ documentation: :cpp:class:`pa::Problem`")
148 .def(py::init<unsigned, unsigned>(),
"n"_a,
"m"_a,
149 ":param n: Number of unknowns\n"
150 ":param m: Number of constraints")
152 "Number of unknowns, dimension of :math:`x`")
155 "Number of general constraints, dimension of :math:`g(x)`")
156 .def_readwrite(
"C", &
pa::Problem::C,
"Box constraints on :math:`x`")
157 .def_readwrite(
"D", &
pa::Problem::D,
"Box constraints on :math:`g(x)`")
159 "Objective funcion, :math:`f(x)`")
162 "Gradient of the objective function, :math:`\\nabla f(x)`")
164 "Constraint function, :math:`g(x)`")
167 "Gradient of constraint function times vector, "
168 ":math:`\\nabla g(x)\\, v`")
170 "Gradient vector of the :math:`i`-th component of the "
171 "constriant function, :math:`\\nabla g_i(x)`")
174 "Hessian of the Lagrangian function, :math:`\\nabla^2_{xx} L(x,y)`")
177 "Hessian of the Lagrangian function times vector, "
178 ":math:`\\nabla^2_{xx} L(x,y)\\, v`");
180 py::class_<pa::ProblemWithParam, pa::Problem>(
181 m,
"ProblemWithParam",
182 "C++ documentation: :cpp:class:`pa::ProblemWithParam`\n\n"
183 "See :py:class:`panocpy._panocpy.Problem` for the full documentation.")
184 .def(py::init<unsigned, unsigned>(),
"n"_a,
"m"_a)
201 "Parameter vector :math:`p` of the problem");
203 py::class_<pa::ProblemFull>(
204 m,
"ProblemFull",
"C++ documentation: :cpp:class:`pa::ProblemFull`")
206 .def(py::init<unsigned, unsigned, unsigned>(),
"n"_a,
"m1"_a,
"m2"_a,
207 ":param n: Number of unknowns\n"
208 ":param m1: Number of ALM constraints\n"
209 ":param m2: Number of quadratic penalty constraints")
211 "Number of unknowns, dimension of :math:`x`")
214 "Number of general constraints, dimension of :math:`g1(x)`")
217 "Number of general constraints, dimension of :math:`g2(x)`")
220 "Box constraints on :math:`g1(x)`")
222 "Box constraints on :math:`g2(x)`")
224 "Objective funcion, :math:`f(x)`")
227 "Gradient of the objective function, :math:`\\nabla f(x)`")
229 "Constraint function, :math:`g1(x)`")
232 "Gradient of constraint function times vector, "
233 ":math:`\\nabla g1(x)\\, v`")
236 "Gradient vector of the :math:`i`-th component of the "
237 "constraint function, :math:`\\nabla g1_i(x)`")
239 "Constraint function, :math:`g2(x)`")
242 "Gradient of constraint function times vector, "
243 ":math:`\\nabla g2(x)\\, v`")
246 "Gradient vector of the :math:`i`-th component of the "
247 "constraint function, :math:`\\nabla g2_i(x)`")
250 "Hessian of the Lagrangian function, :math:`\\nabla^2_{xx} L(x,y)`")
253 "Hessian of the Lagrangian function times vector, "
254 ":math:`\\nabla^2_{xx} L(x,y)\\, v`");
256 py::class_<pa::ProblemFullWithParam, pa::ProblemFull>(
257 m,
"ProblemFullWithParam",
258 "C++ documentation: :cpp:class:`pa::ProblemFullWithParam`")
260 .def(py::init<unsigned, unsigned, unsigned>(),
"n"_a,
"m1"_a,
"m2"_a,
261 ":param n: Number of unknowns\n"
262 ":param m1: Number of ALM constraints\n"
263 ":param m2: Number of quadratic penalty constraints")
265 "Number of unknowns, dimension of :math:`x`")
268 "Number of general constraints, dimension of :math:`g1(x)`")
271 "Number of general constraints, dimension of :math:`g2(x)`")
273 "Box constraints on :math:`x`")
275 "Box constraints on :math:`g1(x)`")
277 "Box constraints on :math:`g2(x)`")
279 "Objective funcion, :math:`f(x)`")
282 "Gradient of the objective function, :math:`\\nabla f(x)`")
284 "Constraint function, :math:`g1(x)`")
287 "Gradient of constraint function times vector, "
288 ":math:`\\nabla g1(x)\\, v`")
291 "Gradient vector of the :math:`i`-th component of the "
292 "constraint function, :math:`\\nabla g1_i(x)`")
294 "Constraint function, :math:`g2(x)`")
297 "Gradient of constraint function times vector, "
298 ":math:`\\nabla g2(x)\\, v`")
301 "Gradient vector of the :math:`i`-th component of the "
302 "constraint function, :math:`\\nabla g2_i(x)`")
305 "Hessian of the Lagrangian function, :math:`\\nabla^2_{xx} L(x,y)`")
308 "Hessian of the Lagrangian function times vector, "
309 ":math:`\\nabla^2_{xx} L(x,y)\\, v`")
313 "Parameter vector :math:`p` of the problem");
316 std::shared_ptr<pa::PolymorphicPANOCDirectionBase>,
319 "Class that provides fast directions for the PANOC algorithm (e.g. "
331 std::shared_ptr<pa::PolymorphicLBFGSDirection>,
334 "C++ documentation: :cpp:class:`pa::LBFGSDirection`")
335 .def(py::init<pa::LBFGSParams>(),
"params"_a)
343 .def_property_readonly(
"params",
347 py::class_<paLBFGSParamCBFGS>(
348 m,
"LBFGSParamsCBFGS",
349 "C++ documentation: :cpp:member:`pa::LBFGSParams::cbfgs`")
351 .def(py::init(&kwargs_to_struct<paLBFGSParamCBFGS>))
352 .def(
"to_dict", &struct_to_dict<paLBFGSParamCBFGS>)
354 .def_readwrite(
"ϵ", &paLBFGSParamCBFGS::ϵ);
356 py::class_<pa::LBFGSParams>(
357 m,
"LBFGSParams",
"C++ documentation: :cpp:class:`pa::LBFGSParams`")
359 .def(py::init(&kwargs_to_struct<pa::LBFGSParams>))
360 .def(
"to_dict", &struct_to_dict<pa::LBFGSParams>)
363 .def_readwrite(
"rescale_when_γ_changes",
366 py::enum_<pa::LBFGSStepSize>(
367 m,
"LBFGSStepsize",
"C++ documentation: :cpp:enum:`pa::LBFGSStepSize`")
368 .value(
"BasedOnGradientStepSize",
369 pa::LBFGSStepSize::BasedOnGradientStepSize)
373 py::class_<pa::LipschitzEstimateParams>(
374 m,
"LipschitzEstimateParams",
375 "C++ documentation: :cpp:class:`pa::LipschitzEstimateParams`")
377 .def(py::init(&kwargs_to_struct<pa::LipschitzEstimateParams>))
378 .def(
"to_dict", &struct_to_dict<pa::LipschitzEstimateParams>)
384 py::class_<pa::PANOCParams>(
385 m,
"PANOCParams",
"C++ documentation: :cpp:class:`pa::PANOCParams`")
387 .def(py::init(&kwargs_to_struct<pa::PANOCParams>))
388 .def(
"to_dict", &struct_to_dict<pa::PANOCParams>)
397 .def_readwrite(
"quadratic_upperbound_tolerance_factor",
399 .def_readwrite(
"update_lipschitz_in_linesearch",
401 .def_readwrite(
"alternative_linesearch_cond",
405 py::enum_<pa::SolverStatus>(
406 m,
"SolverStatus", py::arithmetic(),
407 "C++ documentation: :cpp:enum:`pa::SolverStatus`")
408 .value(
"Unknown", pa::SolverStatus::Unknown,
"Initial value")
409 .value(
"Converged", pa::SolverStatus::Converged,
410 "Converged and reached given tolerance")
411 .value(
"MaxTime", pa::SolverStatus::MaxTime,
412 "Maximum allowed execution time exceeded")
413 .value(
"MaxIter", pa::SolverStatus::MaxIter,
414 "Maximum number of iterations exceeded")
415 .value(
"NotFinite", pa::SolverStatus::NotFinite,
416 "Intermediate results were infinite or not-a-number")
417 .value(
"NoProgress", pa::SolverStatus::NoProgress,
418 "No progress was made in the last iteration")
420 "Solver was interrupted by the user")
423 py::class_<pa::PolymorphicInnerSolverBase::Stats>(
m,
"InnerSolverStats")
427 std::shared_ptr<pa::PolymorphicInnerSolverBase>,
430 .def(
"__call__", &pa::PolymorphicInnerSolverBase::operator())
435 py::class_<pa::PGAParams>(
m,
"PGAParams",
436 "C++ documentation: :cpp:class:`pa::PGAParams`")
438 .def(py::init(&kwargs_to_struct<pa::PGAParams>))
439 .def(
"to_dict", &struct_to_dict<pa::PGAParams>)
447 .def_readwrite(
"quadratic_upperbound_tolerance_factor",
450 py::class_<pa::PGAProgressInfo>(
451 m,
"PGAProgressInfo",
452 "C++ documentation: :cpp:class:`pa::PGAProgressInfo`")
468 return std::sqrt(
p.norm_sq_p) /
p.γ;
471 py::class_<pa::GAAPGAParams>(
472 m,
"GAAPGAParams",
"C++ documentation: :cpp:class:`pa::GAAPGAParams`")
474 .def(py::init(&kwargs_to_struct<pa::GAAPGAParams>))
475 .def(
"to_dict", &struct_to_dict<pa::GAAPGAParams>)
484 .def_readwrite(
"quadratic_upperbound_tolerance_factor",
487 .def_readwrite(
"full_flush_on_γ_change",
490 py::class_<pa::GAAPGAProgressInfo>(
491 m,
"GAAPGAProgressInfo",
492 "C++ documentation: :cpp:class:`pa::GAAPGAProgressInfo`")
508 return std::sqrt(
p.norm_sq_p) /
p.γ;
511 py::class_<pa::PANOCProgressInfo>(
512 m,
"PANOCProgressInfo",
513 "Data passed to the PANOC progress callback.\n\n"
514 "C++ documentation: :cpp:class:`pa::PANOCProgressInfo`")
518 "Decision variable :math:`x`")
520 "Projected gradient step :math:`p`")
522 ":math:`\\left\\|p\\right\\|^2`")
525 "Decision variable after projected gradient step :math:`\\hat x`")
527 "Forward-backward envelope :math:`\\varphi_\\gamma(x)`")
529 "Objective value :math:`\\psi(x)`")
531 "Gradient of objective :math:`\\nabla\\psi(x)`")
535 "Estimate of Lipschitz constant of objective :math:`L`")
537 "Step size :math:`\\gamma`")
539 "Line search parameter :math:`\\tau`")
541 "Tolerance reached :math:`\\varepsilon_k`")
543 "Penalty factor :math:`\\Sigma`")
545 "Lagrange multipliers :math:`y`")
546 .def_property_readonly(
549 return std::sqrt(
p.norm_sq_p) /
p.γ;
551 "Fixed-point residual :math:`\\left\\|p\\right\\| / \\gamma`");
553 py::class_<pa::StructuredPANOCLBFGSProgressInfo>(
554 m,
"StructuredPANOCLBFGSProgressInfo",
555 "Data passed to the structured PANOC progress callback.\n\n"
556 "C++ documentation: :cpp:class:`pa::StructuredPANOCLBFGSProgressInfo`")
560 .def_readonly(
"norm_sq_p",
567 .def_readonly(
"grad_ψ_hat",
575 .def_property_readonly(
577 return std::sqrt(
p.norm_sq_p) /
p.γ;
581 std::shared_ptr<pa::PolymorphicPANOCSolver>,
583 m,
"PANOCSolver",
"C++ documentation: :cpp:class:`pa::PANOCSolver`")
585 return std::make_shared<pa::PolymorphicPANOCSolver>(
588 std::static_pointer_cast<pa::PolymorphicPANOCDirectionBase>(
589 std::make_shared<pa::PolymorphicLBFGSDirection>(
594 "panoc_params"_a,
"lbfgs_direction"_a)
597 "panoc_params"_a,
"lbfgs_params"_a)
600 "panoc_params"_a,
"direction"_a)
602 "set_progress_callback",
604 "Attach a callback that is called on each iteration of the solver.")
606 pa::InnerSolverCallWrapper<pa::PolymorphicPANOCSolver>(),
607 py::call_guard<py::scoped_ostream_redirect,
608 py::scoped_estream_redirect>(),
609 "problem"_a,
"Σ"_a,
"ε"_a,
"x"_a,
612 ":param problem: Problem to solve\n"
613 ":param Σ: Penalty factor\n"
614 ":param ε: Desired tolerance\n"
615 ":param x: Initial guess\n"
616 ":param y: Initial Lagrange multipliers\n\n"
617 ":return: * Solution :math:`x`\n"
618 " * Updated Lagrange multipliers :math:`y`\n"
619 " * Slack variable error :math:`g(x) - z`\n"
622 .def_property_readonly(
"params",
624 .def_property_readonly(
630 py::class_<PANOCFullLBFGS>(
631 m,
"PANOCSolverFull",
632 "C++ documentation: :cpp:class:`pa::PANOCSolverFull`")
634 return PANOCFullLBFGS(
p, lp);
637 "set_progress_callback", &PANOCFullLBFGS::set_progress_callback,
639 "Attach a callback that is called on each iteration of the solver.")
640 .def(
"__call__", pa::InnerSolverFullCallWrapper<PANOCFullLBFGS>(),
641 py::call_guard<py::scoped_ostream_redirect,
642 py::scoped_estream_redirect>(),
643 "problem"_a,
"Σ1"_a,
"Σ2"_a,
"ε"_a,
"x"_a,
646 ":param problem: Problem to solve\n"
647 ":param Σ1: Penalty factor\n"
648 ":param Σ2: Penalty factor\n"
649 ":param ε: Desired tolerance\n"
650 ":param x: Initial guess\n"
651 ":param y: Initial Lagrange multipliers\n\n"
652 ":return: * Solution :math:`x`\n"
653 " * Updated Lagrange multipliers :math:`y`\n"
654 " * Slack variable error :math:`g1(x) - z`\n"
655 " * Slack variable error :math:`g2(x) - z`\n"
657 .def(
"__str__", &PANOCFullLBFGS::get_name)
658 .def_property_readonly(
"params", &PANOCFullLBFGS::get_params)
659 .def_property_readonly(
"direction", [](
const PANOCFullLBFGS &s) {
660 return s.direction_provider;
664 std::shared_ptr<pa::PolymorphicPGASolver>,
666 m,
"PGASolver",
"C++ documentation: :cpp:class:`pa::PGASolver`")
667 .def(py::init<pa::PGAParams>())
669 "set_progress_callback",
671 "Attach a callback that is called on each iteration of the solver.")
672 .def(
"__call__", pa::InnerSolverCallWrapper<pa::PolymorphicPGASolver>(),
673 py::call_guard<py::scoped_ostream_redirect,
674 py::scoped_estream_redirect>(),
675 "problem"_a,
"Σ"_a,
"ε"_a,
"x"_a,
678 ":param problem: Problem to solve\n"
679 ":param Σ: Penalty factor\n"
680 ":param ε: Desired tolerance\n"
681 ":param x: Initial guess\n"
682 ":param y: Initial Lagrange multipliers\n\n"
683 ":return: * Solution :math:`x`\n"
684 " * Updated Lagrange multipliers :math:`y`\n"
685 " * Slack variable error :math:`g(x) - z`\n"
691 std::shared_ptr<pa::PolymorphicGAAPGASolver>,
693 m,
"GAAPGASolver",
"C++ documentation: :cpp:class:`pa::GAAPGASolver`")
694 .def(py::init<pa::GAAPGAParams>())
696 "set_progress_callback",
698 "Attach a callback that is called on each iteration of the solver.")
700 pa::InnerSolverCallWrapper<pa::PolymorphicGAAPGASolver>(),
701 py::call_guard<py::scoped_ostream_redirect,
702 py::scoped_estream_redirect>(),
703 "problem"_a,
"Σ"_a,
"ε"_a,
"x"_a,
706 ":param problem: Problem to solve\n"
707 ":param Σ: Penalty factor\n"
708 ":param ε: Desired tolerance\n"
709 ":param x: Initial guess\n"
710 ":param y: Initial Lagrange multipliers\n\n"
711 ":return: * Solution :math:`x`\n"
712 " * Updated Lagrange multipliers :math:`y`\n"
713 " * Slack variable error :math:`g(x) - z`\n"
716 .def_property_readonly(
"params",
719 py::enum_<pa::PANOCStopCrit>(
720 m,
"PANOCStopCrit",
"C++ documentation: :cpp:enum:`pa::PANOCStopCrit`")
721 .value(
"ApproxKKT", pa::PANOCStopCrit::ApproxKKT)
722 .value(
"ProjGradNorm", pa::PANOCStopCrit::ProjGradNorm)
723 .value(
"ProjGradUnitNorm", pa::PANOCStopCrit::ProjGradUnitNorm)
727 py::class_<pa::StructuredPANOCLBFGSParams>(
728 m,
"StructuredPANOCLBFGSParams",
729 "C++ documentation: :cpp:class:`pa::StructuredPANOCLBFGSParams`")
730 .def(py::init(&kwargs_to_struct<pa::StructuredPANOCLBFGSParams>))
731 .def(
"to_dict", &struct_to_dict<pa::StructuredPANOCLBFGSParams>)
739 .def_readwrite(
"nonmonotone_linesearch",
742 .def_readwrite(
"max_no_progress",
744 .def_readwrite(
"print_interval",
746 .def_readwrite(
"quadratic_upperbound_tolerance_factor",
748 quadratic_upperbound_tolerance_factor)
750 "update_lipschitz_in_linesearch",
753 "alternative_linesearch_cond",
756 "hessian_vec_finited_differences",
758 .def_readwrite(
"full_augmented_hessian",
760 .def_readwrite(
"lbfgs_stepsize",
764 std::shared_ptr<pa::PolymorphicStructuredPANOCLBFGSSolver>,
766 m,
"StructuredPANOCLBFGSSolver",
767 "C++ documentation: :cpp:class:`pa::StructuredPANOCLBFGSSolver`")
769 return std::make_shared<pa::PolymorphicStructuredPANOCLBFGSSolver>(
775 .def(py::init<pa::StructuredPANOCLBFGSParams, pa::LBFGSParams>(),
776 "panoc_params"_a,
"lbfgs_params"_a)
778 "set_progress_callback",
781 "Attach a callback that is called on each iteration of the solver.")
785 py::call_guard<py::scoped_ostream_redirect,
786 py::scoped_estream_redirect>(),
787 "problem"_a,
"Σ"_a,
"ε"_a,
"x"_a,
790 ":param problem: Problem to solve\n"
791 ":param Σ: Penalty factor\n"
792 ":param ε: Desired tolerance\n"
793 ":param x: Initial guess\n"
794 ":param y: Initial Lagrange multipliers\n\n"
795 ":return: * Solution :math:`x`\n"
796 " * Updated Lagrange multipliers :math:`y`\n"
797 " * Slack variable error :math:`g(x) - z`\n"
800 .def_property_readonly(
803 py::class_<pa::ALMParams>(
m,
"ALMParams",
804 "C++ documentation: :cpp:class:`pa::ALMParams`")
806 .def(py::init(&kwargs_to_struct<pa::ALMParams>))
807 .def(
"to_dict", &struct_to_dict<pa::ALMParams>)
825 .def_readwrite(
"max_num_initial_retries",
828 .def_readwrite(
"max_total_num_retries",
832 .def_readwrite(
"single_penalty_factor",
835 py::class_<pa::PolymorphicALMSolver>(
837 "Main augmented Lagrangian solver.\n\n"
838 "C++ documentation: :cpp:class:`pa::ALMSolver`")
843 std::static_pointer_cast<pa::PolymorphicInnerSolverBase>(
850 "Build an ALM solver using Structured PANOC as inner solver.")
852 .def(py::init(PolymorphicALMConstructor<pa::PolymorphicPANOCSolver>()),
853 "alm_params"_a,
"panoc_solver"_a,
854 "Build an ALM solver using PANOC as inner solver.")
855 .def(py::init(PolymorphicALMConstructor<pa::PolymorphicPGASolver>()),
856 "alm_params"_a,
"pga_solver"_a,
857 "Build an ALM solver using the projected gradient algorithm as "
861 "alm_params"_a,
"structuredpanoc_solver"_a,
862 "Build an ALM solver using Structured PANOC as inner solver.")
865 "alm_params"_a,
"inner_solver"_a,
866 "Build an ALM solver using a custom inner solver.")
871 "Build an ALM solver using PANOC as inner solver.")
875 "Build an ALM solver using the projected gradient algorithm as "
879 "structuredpanoc_solver"_a,
880 "Build an ALM solver using Structured PANOC as inner solver.")
884 "Build an ALM solver using a custom inner solver.")
889 std::static_pointer_cast<pa::PolymorphicInnerSolverBase>(
897 "Build an ALM solver using Structured PANOC as inner solver.")
899 .def_property_readonly(
"inner_solver",
906 std::optional<pa::vec>
x, std::optional<pa::vec>
y)
907 -> std::tuple<pa::vec, pa::vec, py::dict> {
909 x = pa::vec::Zero(
p.n);
910 else if (
x->size() !=
p.n)
911 throw std::invalid_argument(
912 "Length of x does not match problem size problem.n");
914 y = pa::vec::Zero(
p.m);
915 else if (
y->size() !=
p.m)
916 throw std::invalid_argument(
917 "Length of y does not match problem size problem.m");
920 return std::make_tuple(std::move(*
x), std::move(*
y),
923 "problem"_a,
"x"_a = std::nullopt,
"y"_a = std::nullopt,
924 py::call_guard<py::scoped_ostream_redirect,
925 py::scoped_estream_redirect>(),
927 ":param problem: Problem to solve.\n"
928 ":param y: Initial guess for Lagrange multipliers :math:`y`\n"
929 ":param x: Initial guess for decision variables :math:`x`\n\n"
930 ":return: * Lagrange multipliers :math:`y` at the solution\n"
931 " * Solution :math:`x`\n"
937 py::class_<ALMFull>(
m,
"ALMSolverFull",
938 "Main augmented Lagrangian solver.\n\n"
939 "C++ documentation: :cpp:class:`pa::ALMSolverFull`")
942 return ALMFull(
params, inner_solver);
944 "Build an ALM solver using Structured PANOC as inner solver.")
948 std::optional<pa::vec>
x, std::optional<pa::vec>
y)
949 -> std::tuple<pa::vec, pa::vec, py::dict> {
951 x = pa::vec::Zero(
p.n);
952 else if (
x->size() !=
p.n)
953 throw std::invalid_argument(
954 "Length of x does not match problem size problem.n");
956 y = pa::vec::Zero(
p.m1);
957 else if (
y->size() !=
p.m1)
958 throw std::invalid_argument(
959 "Length of y does not match problem size problem.m");
962 return std::make_tuple(
963 std::move(*
x), std::move(*
y),
964 pa::stats_to_dict<ALMFull::InnerSolver>(
stats));
966 "problem"_a,
"x"_a = std::nullopt,
"y"_a = std::nullopt,
967 py::call_guard<py::scoped_ostream_redirect,
968 py::scoped_estream_redirect>(),
970 ":param problem: Problem to solve.\n"
971 ":param y: Initial guess for Lagrange multipliers :math:`y`\n"
972 ":param x: Initial guess for decision variables :math:`x`\n\n"
973 ":return: * Lagrange multipliers :math:`y` at the solution\n"
974 " * Solution :math:`x`\n"
976 .def(
"__str__", &ALMFull::get_name)
977 .def_property_readonly(
"params", &ALMFull::get_params);
984 auto n =
C.lowerbound.size();
985 if (
C.upperbound.size() !=
n)
986 throw std::invalid_argument(
"Length of C.upperbound does not "
987 "match length of C.lowerbound");
989 x0 = pa::vec::Zero(
n);
990 else if (
x0->size() !=
n)
991 throw std::invalid_argument(
992 "Length of x does not match problem size problem.n");
994 auto &&
t = grad_ψ(
x);
995 if (
t.size() !=
x.size())
996 throw std::runtime_error(
"Invalid grad_ψ dimension");
1000 pa::panoc<pa::LBFGS>(ψ, grad_ψ_,
C, *
x0,
ε,
params, {lbfgs_params});
1004 m.def(
"panoc",
panoc,
"ψ"_a,
"grad_ψ"_a,
"C"_a,
"x0"_a = std::nullopt,
1008 #if !PANOCPY_HAVE_CASADI
1011 throw std::runtime_error(
1012 "This version of panocpy was compiled without CasADi support");
1016 throw std::runtime_error(
1017 "This version of panocpy was compiled without CasADi support");
1021 throw std::runtime_error(
1022 "This version of panocpy was compiled without CasADi support");
1026 throw std::runtime_error(
1027 "This version of panocpy was compiled without CasADi support");
1037 "second_order"_a =
false,
1038 "Load a compiled CasADi problem without parameters.\n\n"
1039 "C++ documentation: :cpp:func:`pa::load_CasADi_problem`");
1041 "so_name"_a,
"n"_a,
"m"_a,
"second_order"_a =
false,
1042 "Load a compiled CasADi problem with parameters.\n\n"
1043 "C++ documentation: :cpp:func:`pa::load_CasADi_problem_with_param`");
1046 "n"_a,
"m1"_a,
"m2"_a,
"second_order"_a =
false,
1047 "Load a compiled CasADi problem without parameters.\n\n"
1048 "C++ documentation: :cpp:func:`pa::load_CasADi_problem`");
1049 m.def(
"load_casadi_problem_full_with_param",
1051 "m2"_a,
"second_order"_a =
false,
1052 "Load a compiled CasADi problem with parameters.\n\n"
1053 "C++ documentation: :cpp:func:`pa::load_CasADi_problem_with_param`");