GCC Code Coverage Report


Directory: ./
File: bindings/python/crocoddyl/core/residual-base.cpp
Date: 2025-03-26 19:23:43
Exec Total Coverage
Lines: 35 35 100.0%
Branches: 74 148 50.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2021-2025, University of Edinburgh, Heriot-Watt University
5 // Copyright note valid unless otherwise stated in individual files.
6 // All rights reserved.
7 ///////////////////////////////////////////////////////////////////////////////
8
9 #include "python/crocoddyl/core/residual-base.hpp"
10
11 namespace crocoddyl {
12 namespace python {
13
14 template <typename Model>
15 struct ResidualModelAbstractVisitor
16 : public bp::def_visitor<ResidualModelAbstractVisitor<Model>> {
17 typedef typename Model::ResidualModel ResidualModel;
18 typedef typename Model::ResidualData ResidualData;
19 typedef typename Model::State State;
20 typedef typename Model::VectorXs VectorXs;
21 template <class PyClass>
22 40 void visit(PyClass& cl) const {
23
2/4
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
40 cl.def(bp::init<std::shared_ptr<State>, std::size_t,
24 bp::optional<bool, bool, bool>>(
25 bp::args("self", "state", "nr", "q_dependent", "v_dependent",
26 "u_dependent"),
27 "Initialize the cost model.\n\n"
28 ":param state: state description\n"
29 ":param nr: dimension of the residual vector\n"
30 ":param q_dependent: define if the residual function depends on "
31 "q (default true)\n"
32 ":param v_dependent: define if the residual function depends on "
33 "v (default true)\n"
34 ":param u_dependent: define if the residual function depends on "
35 "u (default true)"))
36
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .def("calc", pure_virtual(&Model::calc),
37 bp::args("self", "data", "x", "u"),
38 "Compute the residual vector.\n\n"
39 ":param data: residual data\n"
40 ":param x: state point (dim. state.nx)\n"
41 ":param u: control input (dim. nu)")
42
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("calc",
43 static_cast<void (ResidualModel::*)(
44 const std::shared_ptr<ResidualData>&,
45 const Eigen::Ref<const VectorXs>&)>(&ResidualModel::calc),
46 bp::args("self", "data", "x"),
47 "Compute the residual vector for nodes that depends only on the "
48 "state.\n\n"
49 "This function is used in the terminal nodes of an optimal "
50 "control problem. This is the reason why it updates the residual "
51 "vector based on the state only.\n"
52 ":param data: residual data\n"
53 ":param x: state point (dim. state.nx)")
54
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .def("calcDiff", pure_virtual(&Model::calcDiff),
55 bp::args("self", "data", "x", "u"),
56 "Compute the Jacobians of the residual function.\n\n"
57 ":param data: residual data\n"
58 ":param x: state point (dim. state.nx)\n"
59 ":param u: control input (dim. nu)")
60
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("calcDiff",
61 static_cast<void (ResidualModel::*)(
62 const std::shared_ptr<ResidualData>&,
63 const Eigen::Ref<const VectorXs>&)>(&ResidualModel::calcDiff),
64 bp::args("self", "data", "x"),
65 "Compute the Jacobian of the residual functions with respect to "
66 "the state only.\n\n"
67 "This function is used in the terminal nodes of an optimal "
68 "control problem. This is the reason why it updates the residual "
69 "vector based on the state only.\n"
70 ":param data: residual data\n"
71 ":param x: state point (dim. state.nx)")
72
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
80 .def("createData", &Model::createData, &Model::default_createData,
73 bp::args("self"),
74 "Create the residual data.\n\n"
75 "Each residual model might has its own data that needs to be "
76 "allocated.")
77
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("calcCostDiff", &Model::calcCostDiff, &Model::default_calcCostDiff,
78 bp::args("self", "cdata", "rdata", "adata", "update_u"),
79 "Compute the derivative of the cost function.\n\n"
80 "This function assumes that the derivatives of the activation and "
81 "residual are computed via calcDiff functions.\n"
82 ":param cdata: cost data\n"
83 ":param rdata: residual data\n"
84 ":param adata: activation data\n"
85 ":param update_u: update the derivative of the cost function "
86 "w.r.t. to the control if True.")
87
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 .def("calcCostDiff", &Model::default_calcCostDiff_noupdate_u)
88
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
40 .add_property(
89 "state",
90 bp::make_function(&Model::get_state,
91 40 bp::return_value_policy<bp::return_by_value>()),
92 "state")
93
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .add_property("nr", bp::make_function(&Model::get_nr),
94 "dimension of residual vector")
95
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .add_property("nu", bp::make_function(&Model::get_nu),
96 "dimension of control vector")
97
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .add_property(
98 "q_dependent", bp::make_function(&Model::get_q_dependent),
99 "flag that indicates if the residual function depends on q")
100
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .add_property(
101 "v_dependent", bp::make_function(&Model::get_v_dependent),
102 "flag that indicates if the residual function depends on v")
103
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
104 "u_dependent", bp::make_function(&Model::get_u_dependent),
105 "flag that indicates if the residual function depends on u");
106 40 }
107 };
108
109 template <typename Data>
110 struct ResidualDataAbstractVisitor
111 : public bp::def_visitor<ResidualDataAbstractVisitor<Data>> {
112 template <class PyClass>
113 40 void visit(PyClass& cl) const {
114
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 cl.add_property(
115 "shared",
116 40 bp::make_getter(&Data::shared, bp::return_internal_reference<>()),
117 "shared data")
118
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .add_property(
119 40 "r", bp::make_getter(&Data::r, bp::return_internal_reference<>()),
120 bp::make_setter(&Data::r), "residual vector")
121
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .add_property(
122 40 "Rx", bp::make_getter(&Data::Rx, bp::return_internal_reference<>()),
123 bp::make_setter(&Data::Rx), "Jacobian of the residual")
124
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .add_property(
125 40 "Ru", bp::make_getter(&Data::Ru, bp::return_internal_reference<>()),
126 bp::make_setter(&Data::Ru), "Jacobian of the residual")
127
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
128 "Arr_Rx",
129 40 bp::make_getter(&Data::Arr_Rx, bp::return_internal_reference<>()),
130 "Intermediate product of Arr (2nd deriv of Activation) with Rx "
131 "(deriv of residue)")
132
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
133 "Arr_Ru",
134 40 bp::make_getter(&Data::Arr_Ru, bp::return_internal_reference<>()),
135 "Intermediate product of Arr (2nd deriv of Activation) with Ru "
136 "(deriv of residue)");
137 40 }
138 };
139
140 #define CROCODDYL_RESIDUAL_MODEL_ABSTRACT_PYTHON_BINDINGS(Scalar) \
141 typedef ResidualModelAbstractTpl<Scalar> Model; \
142 typedef ResidualModelAbstractTpl_wrap<Scalar> Model_wrap; \
143 typedef StateAbstractTpl<Scalar> State; \
144 bp::register_ptr_to_python<std::shared_ptr<Model>>(); \
145 bp::class_<Model_wrap, boost::noncopyable>( \
146 "ResidualModelAbstract", \
147 "Abstract class for residual models.\n\n" \
148 "A residual model defines a vector function r(x,u) in R^nr, where nr " \
149 "describes its dimension in the the Euclidean space. For each residual " \
150 "model, we need to provide ways of computing the residual vector and " \
151 "its Jacobians. These computations are mainly carried out inside " \
152 "calc() and calcDiff(), respectively.", \
153 bp::init<std::shared_ptr<State>, std::size_t, std::size_t, \
154 bp::optional<bool, bool, bool>>( \
155 bp::args("self", "state", "nr", "nu", "q_dependent", "v_dependent", \
156 "u_dependent"), \
157 "Initialize the residual model.\n\n" \
158 ":param state: state description,\n" \
159 ":param nr: dimension of the residual vector\n" \
160 ":param nu: dimension of control vector (default state.nv)\n" \
161 ":param q_dependent: define if the residual function depends on q " \
162 "(default true)\n" \
163 ":param v_dependent: define if the residual function depends on v " \
164 "(default true)\n" \
165 ":param u_dependent: define if the residual function depends on u " \
166 "(default true)")) \
167 .def(ResidualModelAbstractVisitor<Model_wrap>()) \
168 .def(PrintableVisitor<Model_wrap>()) \
169 .def(CopyableVisitor<Model_wrap>());
170
171 #define CROCODDYL_RESIDUAL_DATA_ABSTRACT_PYTHON_BINDINGS(Scalar) \
172 typedef ResidualDataAbstractTpl<Scalar> Data; \
173 typedef ResidualModelAbstractTpl<Scalar> Model; \
174 typedef Model::DataCollectorAbstract DataCollector; \
175 bp::register_ptr_to_python<std::shared_ptr<Data>>(); \
176 bp::class_<Data>( \
177 "ResidualDataAbstract", \
178 "Abstract class for residual data.\n\n" \
179 "In Crocoddyl, a residual data contains all the required information " \
180 "for processing an user-defined residual models. The residual data " \
181 "typically is allocated once and containts the residual vector and its " \
182 "Jacobians.", \
183 bp::init<Model*, DataCollector*>( \
184 bp::args("self", "model", "data"), \
185 "Create common data shared between residual models.\n\n" \
186 ":param model: residual model\n" \
187 ":param data: shared data")[bp::with_custodian_and_ward< \
188 1, 2, bp::with_custodian_and_ward<1, 3>>()]) \
189 .def(ResidualDataAbstractVisitor<Data>()) \
190 .def(CopyableVisitor<Data>());
191
192 10 void exposeResidualAbstract() {
193
15/30
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 10 times.
✗ Branch 16 not taken.
✓ Branch 21 taken 10 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 10 times.
✗ Branch 28 not taken.
✓ Branch 32 taken 10 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 10 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 10 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 10 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 10 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 10 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 10 times.
✗ Branch 51 not taken.
20 CROCODDYL_PYTHON_SCALARS(CROCODDYL_RESIDUAL_MODEL_ABSTRACT_PYTHON_BINDINGS)
194
15/30
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 10 times.
✗ Branch 16 not taken.
✓ Branch 21 taken 10 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 10 times.
✗ Branch 28 not taken.
✓ Branch 32 taken 10 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 10 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 10 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 10 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 10 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 10 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 10 times.
✗ Branch 51 not taken.
20 CROCODDYL_PYTHON_SCALARS(CROCODDYL_RESIDUAL_DATA_ABSTRACT_PYTHON_BINDINGS)
195 10 }
196
197 } // namespace python
198 } // namespace crocoddyl
199