cost_functions.h
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Fabian Reister ( fabian dot reister at kit dot edu )
17 * @date 2021
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
22#pragma once
23
25
26#include <ceres/ceres.h>
27
29{
30
31 struct SmoothOrientationFixedPreCostFunctor : ceres::CostFunction
32 {
33
34 SmoothOrientationFixedPreCostFunctor(const double yawPre, const double weight) :
35 yawPre(yawPre), weight(weight)
36 {
37 set_num_residuals(2);
38
39 mutable_parameter_block_sizes()->push_back(1);
40 mutable_parameter_block_sizes()->push_back(1);
41 }
42
43 bool
44 Evaluate(double const* const* parameters,
45 double* residuals,
46 double** jacobians) const override
47 {
48 // One value per parameter block: the block sizes declared above are all 1, so
49 // `parameters[k][0]` is block k. Reading `parameters[0][k]` instead runs off the end
50 // of the first block into whatever Ceres happens to have put next to it -- which is
51 // adjacent stack storage in a hand-written call and unrelated heap in a real solve,
52 // so it can look correct in a test and be wrong in the solver.
53 const double yaw = parameters[0][0];
54 const double yawNext = parameters[1][0];
55
56 residuals[0] = weight * periodicDiff(yawPre, yaw);
57 residuals[1] = weight * periodicDiff(yaw, yawNext);
58
59 const auto periodicDiffJ0 = periodicDiffJacobian(yawPre, yaw);
60 const auto periodicDiffJ1 = periodicDiffJacobian(yaw, yawNext);
61
62 if (jacobians == nullptr)
63 {
64 return true;
65 }
66 // Each block's jacobian is requested independently: Ceres passes a null for any
67 // block it is holding constant, and the callee must still fill the others. Bailing
68 // out on the first null left the later ones as whatever the buffer held, which is
69 // what Ceres reports as `Jacobian ... indicated by 'Uninitialized'`.
70 if (double* jacobian0 = jacobians[0]; jacobian0 != nullptr)
71 {
72 // d r_i / d p_0
73 jacobian0[0] = weight * periodicDiffJ0.at(1);
74 jacobian0[1] = weight * periodicDiffJ1.at(0);
75 }
76
77 if (double* jacobian1 = jacobians[1]; jacobian1 != nullptr)
78 {
79 // d r_i / d p_1
80 jacobian1[0] = 0.;
81 jacobian1[1] = weight * periodicDiffJ1.at(1);
82 }
83
84 return true;
85 }
86
87 private:
88 const double yawPre;
89 const double weight;
90 };
91
92 struct SmoothOrientationFixedNextCostFunctor : ceres::CostFunction
93 {
94
95 SmoothOrientationFixedNextCostFunctor(const double yawNext, const double weight) :
96 yawNext(yawNext), weight(weight)
97 {
98 set_num_residuals(2);
99
100 mutable_parameter_block_sizes()->push_back(1);
101 mutable_parameter_block_sizes()->push_back(1);
102 }
103
104 bool
105 Evaluate(double const* const* parameters,
106 double* residuals,
107 double** jacobians) const override
108 {
109 // One value per parameter block: the block sizes declared above are all 1, so
110 // `parameters[k][0]` is block k. Reading `parameters[0][k]` instead runs off the end
111 // of the first block into whatever Ceres happens to have put next to it -- which is
112 // adjacent stack storage in a hand-written call and unrelated heap in a real solve,
113 // so it can look correct in a test and be wrong in the solver.
114 const double yawPre = parameters[0][0];
115 const double yaw = parameters[1][0];
116
117 residuals[0] = weight * periodicDiff(yawPre, yaw);
118 residuals[1] = weight * periodicDiff(yaw, yawNext);
119
120 const auto periodicDiffJ0 = periodicDiffJacobian(yawPre, yaw);
121 const auto periodicDiffJ1 = periodicDiffJacobian(yaw, yawNext);
122
123 if (jacobians == nullptr)
124 {
125 return true;
126 }
127 // Each block's jacobian is requested independently: Ceres passes a null for any
128 // block it is holding constant, and the callee must still fill the others. Bailing
129 // out on the first null left the later ones as whatever the buffer held, which is
130 // what Ceres reports as `Jacobian ... indicated by 'Uninitialized'`.
131 if (double* jacobian0 = jacobians[0]; jacobian0 != nullptr)
132 {
133 // d r_i / d yawPre
134 jacobian0[0] = weight * periodicDiffJ0.at(0);
135 jacobian0[1] = 0;
136 }
137
138 if (double* jacobian1 = jacobians[1]; jacobian1 != nullptr)
139 {
140 // d r_i / d yaw
141 jacobian1[0] = weight * periodicDiffJ0.at(1);
142 jacobian1[1] = weight * periodicDiffJ1.at(0);
143 }
144
145 return true;
146 }
147
148 private:
149 const double yawNext;
150 const double weight;
151 };
152
153 struct OrientationPriorCostFunctor : ceres::SizedCostFunction<1, 1>
154 {
155
156 OrientationPriorCostFunctor(const double prior, const double weight) :
157 prior(prior), weight(weight)
158 {
159 }
160
161 bool
162 Evaluate(double const* const* parameters,
163 double* residuals,
164 double** jacobians) const override
165 {
166 const double yaw = parameters[0][0];
167
168 residuals[0] = weight * periodicDiff(prior, yaw);
169
170 const auto periodicDiffJ = periodicDiffJacobian(prior, yaw);
171
172 if (jacobians == nullptr)
173 {
174 return true;
175 }
176 double* jacobian = jacobians[0];
177 if (jacobian == nullptr)
178 {
179 return true;
180 }
181
182
183 jacobian[0] = weight * periodicDiffJ.at(1);
184 return true;
185 }
186
187 private:
188 const double prior;
189 const double weight;
190 };
191
192 struct SmoothOrientationCostFunctor : ceres::CostFunction
193 {
194
195 SmoothOrientationCostFunctor(const double weight) : weight(weight)
196 {
197 set_num_residuals(2);
198
199 mutable_parameter_block_sizes()->push_back(1);
200 mutable_parameter_block_sizes()->push_back(1);
201 mutable_parameter_block_sizes()->push_back(1);
202 }
203
204 bool
205 Evaluate(double const* const* parameters,
206 double* residuals,
207 double** jacobians) const override
208 {
209 // One value per parameter block: the block sizes declared above are all 1, so
210 // `parameters[k][0]` is block k. Reading `parameters[0][k]` instead runs off the end
211 // of the first block into whatever Ceres happens to have put next to it -- which is
212 // adjacent stack storage in a hand-written call and unrelated heap in a real solve,
213 // so it can look correct in a test and be wrong in the solver.
214 const double yawPrev = parameters[0][0];
215 const double yaw = parameters[1][0];
216 const double yawNext = parameters[2][0];
217
218 residuals[0] = weight * periodicDiff(yawPrev, yaw);
219 residuals[1] = weight * periodicDiff(yaw, yawNext);
220
221 const auto periodicDiffJ0 = periodicDiffJacobian(yawPrev, yaw);
222 const auto periodicDiffJ1 = periodicDiffJacobian(yaw, yawNext);
223
224 if (jacobians == nullptr)
225 {
226 return true;
227 }
228
229 // Each block's jacobian is requested independently: Ceres passes a null for any
230 // block it is holding constant, and the callee must still fill the others. Bailing
231 // out on the first null left the later ones as whatever the buffer held, which is
232 // what Ceres reports as `Jacobian ... indicated by 'Uninitialized'`.
233 if (double* jacobian0 = jacobians[0]; jacobian0 != nullptr)
234 {
235 // d r_i / d yawPrev
236 jacobian0[0] = weight * periodicDiffJ0.at(0);
237 jacobian0[1] = 0.;
238 }
239
240 if (double* jacobian1 = jacobians[1]; jacobian1 != nullptr)
241 {
242 // d r_i / d yaw
243 jacobian1[0] = weight * periodicDiffJ0.at(1);
244 jacobian1[1] = weight * periodicDiffJ1.at(0);
245 }
246
247 if (double* jacobian2 = jacobians[2]; jacobian2 != nullptr)
248 {
249 // d r_i / d yawNext
250 jacobian2[0] = 0.;
251 jacobian2[1] = weight * periodicDiffJ1.at(1);
252 }
253
254 return true;
255 }
256
257 private:
258 const double weight;
259 };
260
261} // namespace armarx::navigation::global_planning::optimization
std::array< double, 2 > periodicDiffJacobian(const auto, const auto)
Partial derivatives of periodicDiff(a, b) with respect to a and b.
Definition math.h:67
auto periodicDiff(const auto a, const auto b)
Signed, wrapped difference b - a, in (-pi, pi].
Definition math.h:53
bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override
bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override
bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override
bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override