GCC Code Coverage Report


Directory: ./
File: bindings/python/crocoddyl/core/solver-base.cpp
Date: 2025-01-16 08:47:40
Exec Total Coverage
Lines: 94 95 98.9%
Branches: 97 194 50.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2023, LAAS-CNRS, University of Edinburgh,
5 // Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "python/crocoddyl/core/solver-base.hpp"
11
12 #include "python/crocoddyl/utils/copyable.hpp"
13 #include "python/crocoddyl/utils/deprecate.hpp"
14 #include "python/crocoddyl/utils/vector-converter.hpp"
15
16 namespace crocoddyl {
17 namespace python {
18
19 10 void exposeSolverAbstract() {
20 // Register custom converters between std::vector and Python list
21 typedef boost::shared_ptr<CallbackAbstract> CallbackAbstractPtr;
22
3/6
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
10 StdVectorPythonVisitor<std::vector<CallbackAbstractPtr>, true>::expose(
23 "StdVec_Callback");
24
25 20 bp::enum_<FeasibilityNorm>("FeasibilityNorm")
26
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .value("LInf", LInf)
27
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .value("L1", L1)
28
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .export_values();
29
30
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::class_<SolverAbstract_wrap, boost::noncopyable>(
31 "SolverAbstract",
32 "Abstract class for optimal control solvers.\n\n"
33 "A solver resolves an optimal control solver which is formulated in a "
34 "shooting problem\n"
35 "abstraction. The main routines are computeDirection and tryStep. The "
36 "former finds\n"
37 "a search direction and typically computes the derivatives of each "
38 "action model. The latter\n"
39 "rollout the dynamics and cost (i.e. the action) to try the search "
40 "direction found by\n"
41 "computeDirection. Both functions used the current guess defined by "
42 "setCandidate. Finally\n"
43 "solve function is used to define when the search direction and length "
44 "are computed in each\n"
45 "iterate. It also describes the globalization strategy (i.e. "
46 "regularization) of the\n"
47 "numerical optimization.",
48
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::init<boost::shared_ptr<ShootingProblem> >(
49 20 bp::args("self", "problem"),
50 "Initialize the solver model.\n\n"
51 ":param problem: shooting problem"))
52
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .def("solve", pure_virtual(&SolverAbstract_wrap::solve),
53
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self", "init_xs", "init_us", "maxiter", "isFeasible",
54 "regInit"),
55 "Compute the optimal trajectory xopt,uopt as lists of T+1 and T "
56 "terms.\n\n"
57 "From an initial guess init_xs,init_us (feasible or not), iterate\n"
58 "over computeDirection and tryStep until stoppingCriteria is below\n"
59 "threshold. It also describes the globalization strategy used\n"
60 "during the numerical optimization.\n"
61 ":param init_xs: initial guess for state trajectory with T+1 "
62 "elements (default [])\n"
63 ":param init_us: initial guess for control trajectory with T "
64 "elements (default []).\n"
65 ":param maxiter: maximum allowed number of iterations (default "
66 "100).\n"
67 ":param isFeasible: true if the init_xs are obtained from "
68 "integrating the init_us (rollout) (default "
69 "False).\n"
70 ":param regInit: initial guess for the regularization value. Very "
71 "low\n"
72 " values are typical used with very good guess "
73 "points (init_xs, init_us).\n"
74 ":returns A boolean that describes if convergence was reached.")
75
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .def("computeDirection",
76 pure_virtual(&SolverAbstract_wrap::computeDirection),
77
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self", "recalc"),
78 "Compute the search direction (dx, du) for the current guess (xs, "
79 "us).\n\n"
80 "You must call setCandidate first in order to define the current\n"
81 "guess. A current guess defines a state and control trajectory\n"
82 "(xs, us) of T+1 and T elements, respectively.\n"
83 ":params recalc: true for recalculating the derivatives at current "
84 "state and control.\n"
85 ":returns the search direction dx, du and the dual lambdas as lists "
86 "of T+1, T and T+1 lengths.")
87
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .def(
88 "tryStep", pure_virtual(&SolverAbstract_wrap::tryStep),
89
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self", "stepLength"),
90 "Try a predefined step length and compute its cost improvement.\n\n"
91 "It uses the search direction found by computeDirection to try a\n"
92 "determined step length; so you need to first run computeDirection.\n"
93 "Additionally it returns the cost improvement along the predefined\n"
94 "step length.\n"
95 ":param stepLength: step length\n"
96 ":returns the cost improvement.")
97
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .def(
98 "stoppingCriteria",
99 pure_virtual(&SolverAbstract_wrap::stoppingCriteria),
100
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self"),
101 "Return a positive value that quantifies the algorithm "
102 "termination.\n\n"
103 "These values typically represents the gradient norm which tell us\n"
104 "that it's been reached the local minima. This function is used to\n"
105 "evaluate the algorithm convergence. The stopping criteria strictly\n"
106 "speaking depends on the search direction (calculated by\n"
107 "computeDirection) but it could also depend on the chosen step\n"
108 "length, tested by tryStep.")
109
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .def("expectedImprovement",
110 pure_virtual(&SolverAbstract_wrap::expectedImprovement_wrap),
111
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self"),
112 "Return the expected improvement from a given current search "
113 "direction.\n\n"
114 "For computing the expected improvement, you need to compute first\n"
115 "the search direction by running computeDirection.")
116
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def("setCandidate", &SolverAbstract_wrap::setCandidate,
117
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 setCandidate_overloads(
118
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self", "xs", "us", "isFeasible"),
119 "Set the solver candidate warm-point values (xs, us).\n\n"
120 "The solver candidates are defined as a state and control "
121 "trajectory\n"
122 "(xs, us) of T+1 and T elements, respectively. Additionally, we "
123 "need\n"
124 "to define is (xs,us) pair is feasible, this means that the "
125 "dynamics\n"
126 "rollout give us produces xs.\n"
127 ":param xs: state trajectory of T+1 elements (default []).\n"
128 ":param us: control trajectory of T elements (default []).\n"
129 ":param isFeasible: true if the xs are obtained from "
130 "integrating the\n"
131 "us (rollout)."))
132
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def("computeDynamicFeasibility",
133
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 &SolverAbstract_wrap::computeDynamicFeasibility, bp::args("self"),
134 "Compute the dynamic feasibility for the current guess.\n\n"
135 "The feasibility can be computed using the computed using the l-1 "
136 "and l-inf norms.\n"
137 "By default we use the l-inf norm, however, we can use the l-1 norm "
138 "by defining inffeas as False.")
139
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def("computeInequalityFeasibility",
140
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 &SolverAbstract_wrap::computeInequalityFeasibility, bp::args("self"),
141 "Compute the feasibility of the inequality constraint for the "
142 "current guess.\n\n"
143 "The feasibility can be computed using the computed using the l-1 "
144 "and l-inf norms.\n"
145 "By default we use the l-inf norm, however, we can use the l-1 norm "
146 "by defining inffeas as False.")
147
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def("computeEqualityFeasibility",
148
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 &SolverAbstract_wrap::computeEqualityFeasibility, bp::args("self"),
149 "Compute the feasibility of the equality constraint for the current "
150 "guess.\n\n"
151 "The feasibility can be computed using the computed using the l-1 "
152 "and l-inf norms.\n"
153 "By default we use the l-inf norm, however, we can use the l-1 norm "
154 "by defining inffeas as False.")
155
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def("setCallbacks", &SolverAbstract_wrap::setCallbacks,
156
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self", "callbacks"),
157 "Set a list of callback functions using for diagnostic.\n\n"
158 "Each iteration, the solver calls these set of functions in order "
159 "to\n"
160 "allowed user the diagnostic of the its performance.\n"
161 ":param callbacks: set of callback functions.")
162
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def("getCallbacks", &SolverAbstract_wrap::getCallbacks,
163 bp::return_value_policy<bp::copy_const_reference>(),
164
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self"),
165 "Return the list of callback functions using for diagnostic.\n\n"
166 ":return set of callback functions.")
167
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property("problem",
168
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::make_function(
169 &SolverAbstract_wrap::get_problem,
170 10 bp::return_value_policy<bp::copy_const_reference>()),
171 "shooting problem")
172
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("xs", &SolverAbstract_wrap::xs_, "state trajectory")
173
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("us", &SolverAbstract_wrap::us_, "control sequence")
174
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("fs", &SolverAbstract_wrap::fs_, "dynamics gaps")
175
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("isFeasible", &SolverAbstract_wrap::is_feasible_,
176 "feasible (xs,us)")
177
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("cost", &SolverAbstract_wrap::cost_,
178 "cost for the current guess")
179
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("merit", &SolverAbstract_wrap::merit_,
180 "merit for the current guess")
181
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("stop", &SolverAbstract_wrap::stop_,
182 "stopping criteria value")
183
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("d", &SolverAbstract_wrap::d_,
184 "linear and quadratic terms of the expected improvement")
185
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("dV", &SolverAbstract_wrap::dV_,
186 "reduction in the cost function computed by `tryStep()`")
187
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("dPhi", &SolverAbstract_wrap::dPhi_,
188 "reduction in the merit function computed by `tryStep()`")
189
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("dVexp", &SolverAbstract_wrap::dVexp_,
190 "expected reduction in the cost function")
191
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("dPhiexp", &SolverAbstract_wrap::dPhiexp_,
192 "expected reduction in the merit function")
193
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("dfeas", &SolverAbstract_wrap::dfeas_,
194 "reduction in the feasibility")
195
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("feas", &SolverAbstract_wrap::feas_,
196 "total feasibility for the current guess")
197 20 .def_readwrite(
198
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 "ffeas", &SolverAbstract_wrap::ffeas_,
199 "feasibility of the dynamic constraint for the current guess")
200 20 .def_readwrite(
201
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 "gfeas", &SolverAbstract_wrap::gfeas_,
202 "feasibility of the inequality constraint for the current guess")
203 20 .def_readwrite(
204
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 "hfeas", &SolverAbstract_wrap::hfeas_,
205 "feasibility of the equality constraint for the current guess")
206 20 .def_readwrite(
207
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 "ffeas_try", &SolverAbstract_wrap::ffeas_try_,
208 "feasibility of the dynamic constraint for the current step length")
209
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("gfeas_try", &SolverAbstract_wrap::gfeas_try_,
210 "feasibility of the inequality constraint for the current "
211 "step length")
212 20 .def_readwrite(
213
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 "hfeas_try", &SolverAbstract_wrap::hfeas_try_,
214 "feasibility of the equality constraint for the current step length")
215
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .add_property("preg", bp::make_function(&SolverAbstract_wrap::get_preg),
216
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_preg),
217 "primal-variable regularization")
218
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .add_property("dreg", bp::make_function(&SolverAbstract_wrap::get_dreg),
219
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_dreg),
220 "dual-variable regularization")
221
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property(
222 "x_reg",
223
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::make_function(
224 &SolverAbstract_wrap::get_xreg,
225
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
20 deprecated<bp::return_value_policy<bp::return_by_value> >(
226 "Deprecated. Use preg")),
227
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_xreg,
228
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
20 deprecated<>("Deprecated. Use preg.")),
229 "state regularization")
230
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property(
231 "u_reg",
232
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::make_function(
233 &SolverAbstract_wrap::get_ureg,
234
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
20 deprecated<bp::return_value_policy<bp::return_by_value> >(
235 "Deprecated. Use preg")),
236
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_ureg,
237
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
20 deprecated<>("Deprecated. Use preg.")),
238 "control regularization")
239
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("stepLength", &SolverAbstract_wrap::steplength_,
240 "applied step length")
241
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property("th_acceptStep",
242
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::make_function(&SolverAbstract_wrap::get_th_acceptstep),
243
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_th_acceptstep),
244 "threshold for step acceptance")
245
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property("th_stop",
246
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::make_function(&SolverAbstract_wrap::get_th_stop),
247
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_th_stop),
248 "threshold for stopping criteria")
249
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property("th_gapTol",
250
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 bp::make_function(&SolverAbstract_wrap::get_th_gaptol),
251
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_th_gaptol),
252 "threshold for accepting a gap as non-zero")
253
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .add_property(
254
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 "feasNorm", bp::make_function(&SolverAbstract_wrap::get_feasnorm),
255
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::make_function(&SolverAbstract_wrap::set_feasnorm),
256 "norm used to compute the dynamic and constraints feasibility")
257
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def_readwrite("iter", &SolverAbstract_wrap::iter_,
258 "number of iterations runned in solve()")
259
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def(CopyableVisitor<SolverAbstract_wrap>());
260
261 10 bp::class_<CallbackAbstract_wrap, boost::noncopyable>(
262 "CallbackAbstract",
263 "Abstract class for solver callbacks.\n\n"
264 "A callback is used to diagnostic the behaviour of our solver in each "
265 "iteration of it.\n"
266 "For instance, it can be used to print values, record data or display "
267 "motions")
268
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .def("__call__", pure_virtual(&CallbackAbstract_wrap::operator()),
269
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 bp::args("self", "solver"),
270 "Run the callback function given a solver.\n\n"
271 ":param solver: solver to be diagnostic")
272
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 .def(CopyableVisitor<CallbackAbstract_wrap>());
273 10 }
274
275 } // namespace python
276 } // namespace crocoddyl
277