edge_interface.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2020,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * Authors: Christoph Rösmann
23  *********************************************************************/
24 
27 
28 #include <corbo-core/console.h>
29 
30 namespace corbo {
31 
32 constexpr const double HESSIAN_DELTA = 1e-2;
33 
35 {
36  int num_lb = 0;
37  for (int i = 0; i < getNumVertices(); ++i)
38  {
39  assert(getVertex(i));
40  num_lb += getVertex(i)->getNumberFiniteLowerBounds(true);
41  }
42  return num_lb;
43 }
45 {
46  int num_ub = 0;
47  for (int i = 0; i < getNumVertices(); ++i)
48  {
49  assert(getVertex(i));
50  num_ub += getVertex(i)->getNumberFiniteUpperBounds(true);
51  }
52  return num_ub;
53 }
54 
55 void BaseEdge::computeJacobian(int vtx_idx, Eigen::Ref<Eigen::MatrixXd> block_jacobian, const double* multipliers)
56 {
57  if (getNumVertices() == 0) return;
58 
59  assert(vtx_idx >= 0 && vtx_idx < getNumVertices());
60  assert(block_jacobian.rows() == getDimension());
61  // TODO(roesmann) fixed vertices
62  assert(block_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
63 
64  constexpr const double delta = 1e-9;
65  constexpr const double neg2delta = -2 * delta;
66  constexpr const double scalar = 1.0 / (2 * delta);
67 
68  VertexInterface* vertex = getVertexRaw(vtx_idx);
69 
70  Eigen::VectorXd values1(getDimension());
71  Eigen::VectorXd values2(getDimension());
72 
73  int col_idx = 0;
74  for (int i = 0; i < vertex->getDimension(); ++i)
75  {
76  if (vertex->isFixedComponent(i)) continue;
77 
78  vertex->plus(i, delta); // increment current value by delta
79  computeValues(values2);
80 
81  vertex->plus(i, neg2delta); // subtract 2*delta
82  computeValues(values1);
83  block_jacobian.col(col_idx) = scalar * (values2 - values1);
84 
85  vertex->plus(i, delta); // revert offset
86 
87  // increase column index
88  ++col_idx;
89  }
90 
91  if (multipliers)
92  {
93  // Eigen::Map<const Eigen::VectorXd> mult_vec(multipliers, getDimension());
94  for (int i = 0; i < getDimension(); ++i) block_jacobian.row(i) *= multipliers[i];
95  }
96 }
97 
98 void BaseEdge::computeHessianInc(int vtx_idx_i, int vtx_idx_j, Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
99 {
100  if (getNumVertices() == 0) return;
101 
102  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
103  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
104  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
105  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
106 
107  if (isLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
108 
109  // parameter
110  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
111  // but the results are numerically not stable
112  constexpr const double delta = HESSIAN_DELTA;
113 
114  double scalar = 1.0 / delta;
115  if (weight != 1.0) scalar *= weight;
116 
117  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
118  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
119 
120  Eigen::MatrixXd jacobian1(getDimension(), vertex_i->getDimensionUnfixed());
121  Eigen::MatrixXd jacobian2(getDimension(), vertex_i->getDimensionUnfixed());
122 
123  computeJacobian(vtx_idx_i, jacobian1, multipliers);
124 
125  int param_idx_j = 0;
126  for (int j = 0; j < vertex_j->getDimension(); ++j)
127  {
128  if (vertex_j->isFixedComponent(j)) continue;
129 
130  vertex_j->plus(j, delta); // increment current value by delta
131 
132  computeJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
133 
134  if (multipliers)
135  {
136  for (int val_idx = 0; val_idx < getDimension(); ++val_idx)
137  block_hessian_ij.col(param_idx_j) += scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - jacobian1.row(val_idx)).transpose();
138  }
139  else
140  {
141  for (int val_idx = 0; val_idx < getDimension(); ++val_idx)
142  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - jacobian1.row(val_idx)).transpose();
143  }
144  vertex_j->plus(j, -delta); // revert offset
145 
146  // increase vertex value index
147  ++param_idx_j;
148  }
149 }
150 
151 void BaseEdge::computeHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
152  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
153 {
154  if (getNumVertices() == 0) return;
155 
156  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
157  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
158  assert(block_jacobian_i.rows() == getDimension());
159  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
160  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
161  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
162 
163  if (isLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
164 
165  // parameter
166  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
167  // but the results are numerically not stable
168  constexpr const double delta = HESSIAN_DELTA;
169 
170  double scalar = 1.0 / delta;
171  if (weight != 1.0) scalar *= weight;
172 
173  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
174  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
175 
176  Eigen::MatrixXd jacobian2(getDimension(), vertex_i->getDimensionUnfixed());
177 
178  int param_idx_j = 0;
179  for (int j = 0; j < vertex_j->getDimension(); ++j)
180  {
181  if (vertex_j->isFixedComponent(j)) continue;
182 
183  vertex_j->plus(j, delta); // increment current value by delta
184 
185  computeJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
186 
187  if (multipliers)
188  {
189  for (int val_idx = 0; val_idx < getDimension(); ++val_idx)
190  block_hessian_ij.col(param_idx_j) +=
191  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
192  }
193  else
194  {
195  for (int val_idx = 0; val_idx < getDimension(); ++val_idx)
196  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
197  }
198  vertex_j->plus(j, -delta); // revert offset
199 
200  // increase vertex value index
201  ++param_idx_j;
202  }
203 }
204 
205 void BaseEdge::computeHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
206  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
207 {
208  if (getNumVertices() == 0) return;
209 
210  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
211  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
212  assert(block_jacobian_i.rows() == getDimension());
213  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
214  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
215  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
216 
217  if (isLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
218 
219  // parameter
220  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
221  // but the results are numerically not stable
222  constexpr const double delta = HESSIAN_DELTA;
223 
224  double scalar = 1.0 / delta;
225  if (weight != 1.0) scalar *= weight;
226 
227  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
228  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
229 
230  Eigen::MatrixXd jacobian2(getDimension(), vertex_i->getDimensionUnfixed());
231 
232  int param_idx_j = 0;
233  for (int j = 0; j < vertex_j->getDimension(); ++j)
234  {
235  if (vertex_j->isFixedComponent(j)) continue;
236 
237  vertex_j->plus(j, delta); // increment current value by delta
238 
239  computeJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
240 
241  if (multipliers)
242  {
243  block_hessian_ij.col(param_idx_j) = scalar * multipliers[0] * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
244  for (int val_idx = 1; val_idx < getDimension(); ++val_idx)
245  block_hessian_ij.col(param_idx_j) +=
246  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
247  }
248  else
249  {
250  block_hessian_ij.col(param_idx_j) = scalar * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
251  for (int val_idx = 1; val_idx < getDimension(); ++val_idx)
252  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
253  }
254  vertex_j->plus(j, -delta); // revert offset
255 
256  // increase vertex value index
257  ++param_idx_j;
258  }
259 }
260 
261 void BaseMixedEdge::computeObjectiveJacobian(int vtx_idx, Eigen::Ref<Eigen::MatrixXd> block_jacobian, const double* multipliers)
262 {
263  if (getNumVertices() == 0 || getObjectiveDimension() < 1) return;
264 
265  assert(vtx_idx >= 0 && vtx_idx < getNumVertices());
266  assert(block_jacobian.rows() == getObjectiveDimension());
267  // TODO(roesmann) fixed vertices
268  assert(block_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
269 
270  constexpr const double delta = 1e-9;
271  constexpr const double neg2delta = -2 * delta;
272  constexpr const double scalar = 1.0 / (2 * delta);
273 
274  VertexInterface* vertex = getVertexRaw(vtx_idx);
275 
276  Eigen::VectorXd values1(getObjectiveDimension());
277  Eigen::VectorXd values2(getObjectiveDimension());
278 
279  int col_idx = 0;
280  for (int i = 0; i < vertex->getDimension(); ++i)
281  {
282  if (vertex->isFixedComponent(i)) continue;
283 
284  vertex->plus(i, delta); // increment current value by delta
285  precompute();
286  computeObjectiveValues(values2);
287 
288  vertex->plus(i, neg2delta); // subtract 2*delta
289  precompute();
290  computeObjectiveValues(values1);
291  block_jacobian.col(col_idx) = scalar * (values2 - values1);
292 
293  vertex->plus(i, delta); // revert offset
294 
295  // increase column index
296  ++col_idx;
297  }
298 
299  if (multipliers)
300  {
301  // Eigen::Map<const Eigen::VectorXd> mult_vec(multipliers, getObjectiveDimension());
302  for (int i = 0; i < getObjectiveDimension(); ++i) block_jacobian.row(i) *= multipliers[i];
303  }
304 }
305 void BaseMixedEdge::computeEqualityJacobian(int vtx_idx, Eigen::Ref<Eigen::MatrixXd> block_jacobian, const double* multipliers)
306 {
307  if (getNumVertices() == 0 || getEqualityDimension() < 1) return;
308 
309  assert(vtx_idx >= 0 && vtx_idx < getNumVertices());
310  assert(block_jacobian.rows() == getEqualityDimension());
311  // TODO(roesmann) fixed vertices
312  assert(block_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
313 
314  constexpr const double delta = 1e-9;
315  constexpr const double neg2delta = -2 * delta;
316  constexpr const double scalar = 1.0 / (2 * delta);
317 
318  VertexInterface* vertex = getVertexRaw(vtx_idx);
319 
320  Eigen::VectorXd values1(getEqualityDimension());
321  Eigen::VectorXd values2(getEqualityDimension());
322 
323  int col_idx = 0;
324  for (int i = 0; i < vertex->getDimension(); ++i)
325  {
326  if (vertex->isFixedComponent(i)) continue;
327 
328  vertex->plus(i, delta); // increment current value by delta
329  precompute();
330  computeEqualityValues(values2);
331 
332  vertex->plus(i, neg2delta); // subtract 2*delta
333  precompute();
334  computeEqualityValues(values1);
335  block_jacobian.col(col_idx) = scalar * (values2 - values1);
336 
337  vertex->plus(i, delta); // revert offset
338 
339  // increase column index
340  ++col_idx;
341  }
342 
343  if (multipliers)
344  {
345  // Eigen::Map<const Eigen::VectorXd> mult_vec(multipliers, getEqualityDimension());
346  for (int i = 0; i < getEqualityDimension(); ++i) block_jacobian.row(i) *= multipliers[i];
347  }
348 }
349 void BaseMixedEdge::computeInequalityJacobian(int vtx_idx, Eigen::Ref<Eigen::MatrixXd> block_jacobian, const double* multipliers)
350 {
351  if (getNumVertices() == 0 || getInequalityDimension() < 1) return;
352 
353  assert(vtx_idx >= 0 && vtx_idx < getNumVertices());
354  assert(block_jacobian.rows() == getInequalityDimension());
355  // TODO(roesmann) fixed vertices
356  assert(block_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
357 
358  constexpr const double delta = 1e-9;
359  constexpr const double neg2delta = -2 * delta;
360  constexpr const double scalar = 1.0 / (2 * delta);
361 
362  VertexInterface* vertex = getVertexRaw(vtx_idx);
363 
364  Eigen::VectorXd values1(getInequalityDimension());
365  Eigen::VectorXd values2(getInequalityDimension());
366 
367  int col_idx = 0;
368  for (int i = 0; i < vertex->getDimension(); ++i)
369  {
370  if (vertex->isFixedComponent(i)) continue;
371 
372  vertex->plus(i, delta); // increment current value by delta
373  precompute();
374  computeInequalityValues(values2);
375 
376  vertex->plus(i, neg2delta); // subtract 2*delta
377  precompute();
378  computeInequalityValues(values1);
379  block_jacobian.col(col_idx) = scalar * (values2 - values1);
380 
381  vertex->plus(i, delta); // revert offset
382 
383  // increase column index
384  ++col_idx;
385  }
386 
387  if (multipliers)
388  {
389  // Eigen::Map<const Eigen::VectorXd> mult_vec(multipliers, getInequalityDimension());
390  for (int i = 0; i < getInequalityDimension(); ++i) block_jacobian.row(i) *= multipliers[i];
391  }
392 }
393 
395  Eigen::Ref<Eigen::MatrixXd> ineq_jacobian, const double* obj_multipliers, const double* eq_multipliers,
396  const double* ineq_multipliers)
397 {
398  if (getNumVertices() == 0) return;
399 
400  int obj_dim = getObjectiveDimension();
401  int eq_dim = getEqualityDimension();
402  int ineq_dim = getInequalityDimension();
403 
404  assert(vtx_idx >= 0 && vtx_idx < getNumVertices());
405  assert(obj_jacobian.rows() == obj_dim);
406  assert(obj_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
407  assert(eq_jacobian.rows() == eq_dim);
408  assert(eq_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
409  assert(ineq_jacobian.rows() == ineq_dim);
410  assert(ineq_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
411 
412  constexpr const double delta = 1e-9;
413  constexpr const double neg2delta = -2 * delta;
414  constexpr const double scalar = 1.0 / (2 * delta);
415 
416  VertexInterface* vertex = getVertexRaw(vtx_idx);
417 
418  Eigen::VectorXd obj_values1(obj_dim);
419  Eigen::VectorXd obj_values2(obj_dim);
420  Eigen::VectorXd eq_values1(eq_dim);
421  Eigen::VectorXd eq_values2(eq_dim);
422  Eigen::VectorXd ineq_values1(ineq_dim);
423  Eigen::VectorXd ineq_values2(ineq_dim);
424 
425  int col_idx = 0;
426  for (int i = 0; i < vertex->getDimension(); ++i)
427  {
428  if (vertex->isFixedComponent(i)) continue;
429 
430  vertex->plus(i, delta); // increment current value by delta
431  precompute();
432  if (obj_dim > 0) computeObjectiveValues(obj_values2);
433  if (eq_dim > 0) computeEqualityValues(eq_values2);
434  if (ineq_dim > 0) computeInequalityValues(ineq_values2);
435 
436  vertex->plus(i, neg2delta); // subtract 2*delta
437  precompute();
438  if (obj_dim > 0) computeObjectiveValues(obj_values1);
439  if (eq_dim > 0) computeEqualityValues(eq_values1);
440  if (ineq_dim > 0) computeInequalityValues(ineq_values1);
441 
442  if (obj_dim > 0) obj_jacobian.col(col_idx) = scalar * (obj_values2 - obj_values1);
443  if (eq_dim > 0) eq_jacobian.col(col_idx) = scalar * (eq_values2 - eq_values1);
444  if (ineq_dim > 0) ineq_jacobian.col(col_idx) = scalar * (ineq_values2 - ineq_values1);
445 
446  vertex->plus(i, delta); // revert offset
447 
448  // increase column index
449  ++col_idx;
450  }
451 
452  if (obj_multipliers && obj_dim > 0)
453  {
454  for (int i = 0; i < obj_dim; ++i) obj_jacobian.row(i) *= obj_multipliers[i];
455  }
456  if (eq_multipliers && eq_dim > 0)
457  {
458  for (int i = 0; i < eq_dim; ++i) eq_jacobian.row(i) *= eq_multipliers[i];
459  }
460  if (ineq_multipliers && ineq_dim > 0)
461  {
462  for (int i = 0; i < ineq_dim; ++i) ineq_jacobian.row(i) *= ineq_multipliers[i];
463  }
464 }
465 
467  const double* eq_multipliers, const double* ineq_multipliers)
468 {
469  if (getNumVertices() == 0) return;
470 
471  int eq_dim = getEqualityDimension();
472  int ineq_dim = getInequalityDimension();
473 
474  assert(vtx_idx >= 0 && vtx_idx < getNumVertices());
475  assert(eq_jacobian.rows() == eq_dim);
476  assert(eq_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
477  assert(ineq_jacobian.rows() == ineq_dim);
478  assert(ineq_jacobian.cols() == getVertexRaw(vtx_idx)->getDimensionUnfixed());
479 
480  constexpr const double delta = 1e-9;
481  constexpr const double neg2delta = -2 * delta;
482  constexpr const double scalar = 1.0 / (2 * delta);
483 
484  VertexInterface* vertex = getVertexRaw(vtx_idx);
485 
486  Eigen::VectorXd eq_values1(eq_dim);
487  Eigen::VectorXd eq_values2(eq_dim);
488  Eigen::VectorXd ineq_values1(ineq_dim);
489  Eigen::VectorXd ineq_values2(ineq_dim);
490 
491  int col_idx = 0;
492  for (int i = 0; i < vertex->getDimension(); ++i)
493  {
494  if (vertex->isFixedComponent(i)) continue;
495 
496  vertex->plus(i, delta); // increment current value by delta
497  precompute();
498  if (eq_dim > 0) computeEqualityValues(eq_values2);
499  if (ineq_dim > 0) computeInequalityValues(ineq_values2);
500 
501  vertex->plus(i, neg2delta); // subtract 2*delta
502  precompute();
503  if (eq_dim > 0) computeEqualityValues(eq_values1);
504  if (ineq_dim > 0) computeInequalityValues(ineq_values1);
505 
506  if (eq_dim > 0) eq_jacobian.col(col_idx) = scalar * (eq_values2 - eq_values1);
507  if (ineq_dim > 0) ineq_jacobian.col(col_idx) = scalar * (ineq_values2 - ineq_values1);
508 
509  vertex->plus(i, delta); // revert offset
510 
511  // increase column index
512  ++col_idx;
513  }
514 
515  if (eq_multipliers && eq_dim > 0)
516  {
517  for (int i = 0; i < eq_dim; ++i) eq_jacobian.row(i) *= eq_multipliers[i];
518  }
519  if (ineq_multipliers && ineq_dim > 0)
520  {
521  for (int i = 0; i < ineq_dim; ++i) ineq_jacobian.row(i) *= ineq_multipliers[i];
522  }
523 }
524 
525 void BaseMixedEdge::computeObjectiveHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
526  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
527 {
528  if (getNumVertices() == 0) return;
529 
530  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
531  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
532  assert(block_jacobian_i.rows() == getObjectiveDimension());
533  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
534  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
535  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
536 
537  if (isObjectiveLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
538 
539  // parameter
540  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
541  // but the results are numerically not stable
542  constexpr const double delta = HESSIAN_DELTA;
543 
544  double scalar = 1.0 / delta;
545  if (weight != 1.0) scalar *= weight;
546 
547  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
548  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
549 
550  Eigen::MatrixXd jacobian2(getObjectiveDimension(), vertex_i->getDimensionUnfixed());
551 
552  int param_idx_j = 0;
553  for (int j = 0; j < vertex_j->getDimension(); ++j)
554  {
555  if (vertex_j->isFixedComponent(j)) continue;
556 
557  vertex_j->plus(j, delta); // increment current value by delta
558 
559  computeObjectiveJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
560 
561  if (multipliers)
562  {
563  block_hessian_ij.col(param_idx_j) = scalar * multipliers[0] * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
564  for (int val_idx = 1; val_idx < getObjectiveDimension(); ++val_idx)
565  block_hessian_ij.col(param_idx_j) +=
566  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
567  }
568  else
569  {
570  block_hessian_ij.col(param_idx_j) = scalar * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
571  for (int val_idx = 1; val_idx < getObjectiveDimension(); ++val_idx)
572  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
573  }
574  vertex_j->plus(j, -delta); // revert offset
575 
576  // increase vertex value index
577  ++param_idx_j;
578  }
579 }
580 void BaseMixedEdge::computeEqualityHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
581  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
582 {
583  if (getNumVertices() == 0) return;
584 
585  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
586  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
587  assert(block_jacobian_i.rows() == getEqualityDimension());
588  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
589  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
590  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
591 
592  if (isEqualityLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
593 
594  // parameter
595  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
596  // but the results are numerically not stable
597  constexpr const double delta = HESSIAN_DELTA;
598 
599  double scalar = 1.0 / delta;
600  if (weight != 1.0) scalar *= weight;
601 
602  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
603  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
604 
605  Eigen::MatrixXd jacobian2(getEqualityDimension(), vertex_i->getDimensionUnfixed());
606 
607  int param_idx_j = 0;
608  for (int j = 0; j < vertex_j->getDimension(); ++j)
609  {
610  if (vertex_j->isFixedComponent(j)) continue;
611 
612  vertex_j->plus(j, delta); // increment current value by delta
613 
614  computeEqualityJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
615 
616  if (multipliers)
617  {
618  block_hessian_ij.col(param_idx_j) = scalar * multipliers[0] * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
619  for (int val_idx = 1; val_idx < getEqualityDimension(); ++val_idx)
620  block_hessian_ij.col(param_idx_j) +=
621  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
622  }
623  else
624  {
625  block_hessian_ij.col(param_idx_j) = scalar * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
626  for (int val_idx = 1; val_idx < getEqualityDimension(); ++val_idx)
627  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
628  }
629  vertex_j->plus(j, -delta); // revert offset
630 
631  // increase vertex value index
632  ++param_idx_j;
633  }
634 }
635 void BaseMixedEdge::computeInequalityHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
636  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
637 {
638  if (getNumVertices() == 0) return;
639 
640  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
641  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
642  assert(block_jacobian_i.rows() == getInequalityDimension());
643  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
644  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
645  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
646 
647  if (isInequalityLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
648 
649  // parameter
650  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
651  // but the results are numerically not stable
652  constexpr const double delta = HESSIAN_DELTA;
653 
654  double scalar = 1.0 / delta;
655  if (weight != 1.0) scalar *= weight;
656 
657  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
658  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
659 
660  Eigen::MatrixXd jacobian2(getInequalityDimension(), vertex_i->getDimensionUnfixed());
661 
662  int param_idx_j = 0;
663  for (int j = 0; j < vertex_j->getDimension(); ++j)
664  {
665  if (vertex_j->isFixedComponent(j)) continue;
666 
667  vertex_j->plus(j, delta); // increment current value by delta
668 
669  computeInequalityJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
670 
671  if (multipliers)
672  {
673  block_hessian_ij.col(param_idx_j) = scalar * multipliers[0] * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
674  for (int val_idx = 1; val_idx < getInequalityDimension(); ++val_idx)
675  block_hessian_ij.col(param_idx_j) +=
676  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
677  }
678  else
679  {
680  block_hessian_ij.col(param_idx_j) = scalar * (jacobian2.row(0) - block_jacobian_i.row(0)).transpose();
681  for (int val_idx = 1; val_idx < getInequalityDimension(); ++val_idx)
682  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
683  }
684  vertex_j->plus(j, -delta); // revert offset
685 
686  // increase vertex value index
687  ++param_idx_j;
688  }
689 }
690 void BaseMixedEdge::computeHessians(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& obj_jacobian_i,
691  const Eigen::Ref<const Eigen::MatrixXd>& eq_jacobian_i, const Eigen::Ref<const Eigen::MatrixXd>& ineq_jacobian_i,
692  Eigen::Ref<Eigen::MatrixXd> obj_hessian_ij, Eigen::Ref<Eigen::MatrixXd> eq_hessian_ij,
693  Eigen::Ref<Eigen::MatrixXd> ineq_hessian_ij, const double* multipliers_eq, const double* multipliers_ineq,
694  double weight_obj)
695 {
696  if (getNumVertices() == 0) return;
697 
698  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
699  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
700  assert(obj_jacobian_i.rows() == getObjectiveDimension());
701  assert(obj_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
702  assert(eq_jacobian_i.rows() == getEqualityDimension());
703  assert(eq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
704  assert(ineq_jacobian_i.rows() == getInequalityDimension());
705  assert(ineq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
706  assert(obj_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
707  assert(obj_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
708  assert(eq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
709  assert(eq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
710  assert(ineq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
711  assert(ineq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
712 
713  // parameter
714  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
715  // but the results are numerically not stable
716  constexpr const double delta = HESSIAN_DELTA;
717  constexpr const double scalar = 1.0 / delta;
718 
719  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
720  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
721 
722  Eigen::MatrixXd obj_jacobian_j(getObjectiveDimension(), vertex_i->getDimensionUnfixed());
723  Eigen::MatrixXd eq_jacobian_j(getEqualityDimension(), vertex_i->getDimensionUnfixed());
724  Eigen::MatrixXd ineq_jacobian_j(getInequalityDimension(), vertex_i->getDimensionUnfixed());
725 
726  int param_idx_j = 0;
727  for (int j = 0; j < vertex_j->getDimension(); ++j)
728  {
729  if (vertex_j->isFixedComponent(j)) continue;
730 
731  vertex_j->plus(j, delta); // increment current value by delta
732 
733  computeJacobians(vtx_idx_i, obj_jacobian_j, eq_jacobian_j, ineq_jacobian_j);
734 
735  if (!isObjectiveLinear() && getObjectiveDimension() > 0)
736  {
737  obj_hessian_ij.col(param_idx_j) = weight_obj * scalar * (obj_jacobian_j.row(0) - obj_jacobian_i.row(0)).transpose();
738  for (int val_idx = 1; val_idx < getObjectiveDimension(); ++val_idx)
739  obj_hessian_ij.col(param_idx_j) += weight_obj * scalar * (obj_jacobian_j.row(val_idx) - obj_jacobian_i.row(val_idx)).transpose();
740  }
741  if (!isEqualityLinear() && getEqualityDimension() > 0)
742  {
743  if (multipliers_eq)
744  {
745  eq_hessian_ij.col(param_idx_j) = scalar * multipliers_eq[0] * (eq_jacobian_j.row(0) - eq_jacobian_i.row(0)).transpose();
746  for (int val_idx = 1; val_idx < getEqualityDimension(); ++val_idx)
747  eq_hessian_ij.col(param_idx_j) +=
748  scalar * multipliers_eq[val_idx] * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
749  }
750  else
751  {
752  eq_hessian_ij.col(param_idx_j) = scalar * (eq_jacobian_j.row(0) - eq_jacobian_i.row(0)).transpose();
753  for (int val_idx = 1; val_idx < getEqualityDimension(); ++val_idx)
754  eq_hessian_ij.col(param_idx_j) += scalar * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
755  }
756  }
757  if (!isInequalityLinear() && getInequalityDimension() > 0)
758  {
759  if (multipliers_ineq)
760  {
761  ineq_hessian_ij.col(param_idx_j) = scalar * multipliers_ineq[0] * (ineq_jacobian_j.row(0) - ineq_jacobian_i.row(0)).transpose();
762  for (int val_idx = 1; val_idx < getInequalityDimension(); ++val_idx)
763  ineq_hessian_ij.col(param_idx_j) +=
764  scalar * multipliers_ineq[val_idx] * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
765  }
766  else
767  {
768  ineq_hessian_ij.col(param_idx_j) = scalar * (ineq_jacobian_j.row(0) - ineq_jacobian_i.row(0)).transpose();
769  for (int val_idx = 1; val_idx < getInequalityDimension(); ++val_idx)
770  ineq_hessian_ij.col(param_idx_j) += scalar * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
771  }
772  }
773 
774  vertex_j->plus(j, -delta); // revert offset
775 
776  // increase vertex value index
777  ++param_idx_j;
778  }
779 }
780 
781 void BaseMixedEdge::computeConstraintHessians(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& eq_jacobian_i,
782  const Eigen::Ref<const Eigen::MatrixXd>& ineq_jacobian_i, Eigen::Ref<Eigen::MatrixXd> eq_hessian_ij,
783  Eigen::Ref<Eigen::MatrixXd> ineq_hessian_ij, const double* multipliers_eq,
784  const double* multipliers_ineq)
785 {
786  if (getNumVertices() == 0) return;
787 
788  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
789  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
790  assert(eq_jacobian_i.rows() == getEqualityDimension());
791  assert(eq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
792  assert(ineq_jacobian_i.rows() == getInequalityDimension());
793  assert(ineq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
794  assert(eq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
795  assert(eq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
796  assert(ineq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
797  assert(ineq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
798 
799  // parameter
800  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
801  // but the results are numerically not stable
802  constexpr const double delta = HESSIAN_DELTA;
803  constexpr const double scalar = 1.0 / delta;
804 
805  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
806  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
807 
808  Eigen::MatrixXd eq_jacobian_j(getEqualityDimension(), vertex_i->getDimensionUnfixed());
809  Eigen::MatrixXd ineq_jacobian_j(getInequalityDimension(), vertex_i->getDimensionUnfixed());
810 
811  int param_idx_j = 0;
812  for (int j = 0; j < vertex_j->getDimension(); ++j)
813  {
814  if (vertex_j->isFixedComponent(j)) continue;
815 
816  vertex_j->plus(j, delta); // increment current value by delta
817 
818  computeConstraintJacobians(vtx_idx_i, eq_jacobian_j, ineq_jacobian_j);
819 
820  if (!isEqualityLinear() && getEqualityDimension() > 0)
821  {
822  if (multipliers_eq)
823  {
824  eq_hessian_ij.col(param_idx_j) = scalar * multipliers_eq[0] * (eq_jacobian_j.row(0) - eq_jacobian_i.row(0)).transpose();
825  for (int val_idx = 1; val_idx < getEqualityDimension(); ++val_idx)
826  eq_hessian_ij.col(param_idx_j) +=
827  scalar * multipliers_eq[val_idx] * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
828  }
829  else
830  {
831  eq_hessian_ij.col(param_idx_j) = scalar * (eq_jacobian_j.row(0) - eq_jacobian_i.row(0)).transpose();
832  for (int val_idx = 1; val_idx < getEqualityDimension(); ++val_idx)
833  eq_hessian_ij.col(param_idx_j) += scalar * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
834  }
835  }
836  if (!isInequalityLinear() && getInequalityDimension() > 0)
837  {
838  if (multipliers_ineq)
839  {
840  ineq_hessian_ij.col(param_idx_j) = scalar * multipliers_ineq[0] * (ineq_jacobian_j.row(0) - ineq_jacobian_i.row(0)).transpose();
841  for (int val_idx = 1; val_idx < getInequalityDimension(); ++val_idx)
842  ineq_hessian_ij.col(param_idx_j) +=
843  scalar * multipliers_ineq[val_idx] * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
844  }
845  else
846  {
847  ineq_hessian_ij.col(param_idx_j) = scalar * (ineq_jacobian_j.row(0) - ineq_jacobian_i.row(0)).transpose();
848  for (int val_idx = 1; val_idx < getInequalityDimension(); ++val_idx)
849  ineq_hessian_ij.col(param_idx_j) += scalar * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
850  }
851  }
852 
853  vertex_j->plus(j, -delta); // revert offset
854 
855  // increase vertex value index
856  ++param_idx_j;
857  }
858 }
859 
860 void BaseMixedEdge::computeObjectiveHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
861  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
862 {
863  if (getNumVertices() == 0) return;
864 
865  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
866  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
867  assert(block_jacobian_i.rows() == getObjectiveDimension());
868  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
869  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
870  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
871 
872  if (isObjectiveLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
873 
874  // parameter
875  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
876  // but the results are numerically not stable
877  constexpr const double delta = HESSIAN_DELTA;
878 
879  double scalar = 1.0 / delta;
880  if (weight != 1.0) scalar *= weight;
881 
882  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
883  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
884 
885  Eigen::MatrixXd jacobian2(getObjectiveDimension(), vertex_i->getDimensionUnfixed());
886 
887  int param_idx_j = 0;
888  for (int j = 0; j < vertex_j->getDimension(); ++j)
889  {
890  if (vertex_j->isFixedComponent(j)) continue;
891 
892  vertex_j->plus(j, delta); // increment current value by delta
893 
894  computeObjectiveJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
895 
896  if (multipliers)
897  {
898  for (int val_idx = 0; val_idx < getObjectiveDimension(); ++val_idx)
899  block_hessian_ij.col(param_idx_j) +=
900  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
901  }
902  else
903  {
904  for (int val_idx = 0; val_idx < getObjectiveDimension(); ++val_idx)
905  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
906  }
907  vertex_j->plus(j, -delta); // revert offset
908 
909  // increase vertex value index
910  ++param_idx_j;
911  }
912 }
913 void BaseMixedEdge::computeEqualityHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
914  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
915 {
916  if (getNumVertices() == 0) return;
917 
918  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
919  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
920  assert(block_jacobian_i.rows() == getEqualityDimension());
921  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
922  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
923  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
924 
925  if (isEqualityLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
926 
927  // parameter
928  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
929  // but the results are numerically not stable
930  constexpr const double delta = HESSIAN_DELTA;
931 
932  double scalar = 1.0 / delta;
933  if (weight != 1.0) scalar *= weight;
934 
935  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
936  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
937 
938  Eigen::MatrixXd jacobian2(getEqualityDimension(), vertex_i->getDimensionUnfixed());
939 
940  int param_idx_j = 0;
941  for (int j = 0; j < vertex_j->getDimension(); ++j)
942  {
943  if (vertex_j->isFixedComponent(j)) continue;
944 
945  vertex_j->plus(j, delta); // increment current value by delta
946 
947  computeEqualityJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
948 
949  if (multipliers)
950  {
951  for (int val_idx = 0; val_idx < getEqualityDimension(); ++val_idx)
952  block_hessian_ij.col(param_idx_j) +=
953  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
954  }
955  else
956  {
957  for (int val_idx = 0; val_idx < getEqualityDimension(); ++val_idx)
958  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
959  }
960  vertex_j->plus(j, -delta); // revert offset
961 
962  // increase vertex value index
963  ++param_idx_j;
964  }
965 }
966 void BaseMixedEdge::computeInequalityHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& block_jacobian_i,
967  Eigen::Ref<Eigen::MatrixXd> block_hessian_ij, const double* multipliers, double weight)
968 {
969  if (getNumVertices() == 0) return;
970 
971  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
972  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
973  assert(block_jacobian_i.rows() == getInequalityDimension());
974  assert(block_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
975  assert(block_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
976  assert(block_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
977 
978  if (isInequalityLinear()) return; // we do not need to set to zero, since we assume that it is already initialized with zeros!
979 
980  // parameter
981  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
982  // but the results are numerically not stable
983  constexpr const double delta = HESSIAN_DELTA;
984 
985  double scalar = 1.0 / delta;
986  if (weight != 1.0) scalar *= weight;
987 
988  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
989  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
990 
991  Eigen::MatrixXd jacobian2(getInequalityDimension(), vertex_i->getDimensionUnfixed());
992 
993  int param_idx_j = 0;
994  for (int j = 0; j < vertex_j->getDimension(); ++j)
995  {
996  if (vertex_j->isFixedComponent(j)) continue;
997 
998  vertex_j->plus(j, delta); // increment current value by delta
999 
1000  computeInequalityJacobian(vtx_idx_i, jacobian2); // always use jacobian of vertex1
1001 
1002  if (multipliers)
1003  {
1004  for (int val_idx = 0; val_idx < getInequalityDimension(); ++val_idx)
1005  block_hessian_ij.col(param_idx_j) +=
1006  scalar * multipliers[val_idx] * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
1007  }
1008  else
1009  {
1010  for (int val_idx = 0; val_idx < getInequalityDimension(); ++val_idx)
1011  block_hessian_ij.col(param_idx_j) += scalar * (jacobian2.row(val_idx) - block_jacobian_i.row(val_idx)).transpose();
1012  }
1013  vertex_j->plus(j, -delta); // revert offset
1014 
1015  // increase vertex value index
1016  ++param_idx_j;
1017  }
1018 }
1019 void BaseMixedEdge::computeHessiansInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& obj_jacobian_i,
1020  const Eigen::Ref<const Eigen::MatrixXd>& eq_jacobian_i,
1021  const Eigen::Ref<const Eigen::MatrixXd>& ineq_jacobian_i, Eigen::Ref<Eigen::MatrixXd> obj_hessian_ij,
1022  Eigen::Ref<Eigen::MatrixXd> eq_hessian_ij, Eigen::Ref<Eigen::MatrixXd> ineq_hessian_ij,
1023  const double* multipliers_eq, const double* multipliers_ineq, double weight_obj)
1024 {
1025  if (getNumVertices() == 0) return;
1026 
1027  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
1028  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
1029  assert(obj_jacobian_i.rows() == getObjectiveDimension());
1030  assert(obj_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1031  assert(eq_jacobian_i.rows() == getEqualityDimension());
1032  assert(eq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1033  assert(ineq_jacobian_i.rows() == getInequalityDimension());
1034  assert(ineq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1035  assert(obj_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1036  assert(obj_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
1037  assert(eq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1038  assert(eq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
1039  assert(ineq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1040  assert(ineq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
1041 
1042  // parameter
1043  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
1044  // but the results are numerically not stable
1045  constexpr const double delta = HESSIAN_DELTA;
1046  constexpr const double scalar = 1.0 / delta;
1047 
1048  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
1049  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
1050 
1051  Eigen::MatrixXd obj_jacobian_j(getObjectiveDimension(), vertex_i->getDimensionUnfixed());
1052  Eigen::MatrixXd eq_jacobian_j(getEqualityDimension(), vertex_i->getDimensionUnfixed());
1053  Eigen::MatrixXd ineq_jacobian_j(getInequalityDimension(), vertex_i->getDimensionUnfixed());
1054 
1055  int param_idx_j = 0;
1056  for (int j = 0; j < vertex_j->getDimension(); ++j)
1057  {
1058  if (vertex_j->isFixedComponent(j)) continue;
1059 
1060  vertex_j->plus(j, delta); // increment current value by delta
1061 
1062  computeJacobians(vtx_idx_i, obj_jacobian_j, eq_jacobian_j, ineq_jacobian_j);
1063 
1064  if (!isObjectiveLinear())
1065  {
1066  for (int val_idx = 0; val_idx < getObjectiveDimension(); ++val_idx)
1067  obj_hessian_ij.col(param_idx_j) += weight_obj * scalar * (obj_jacobian_j.row(val_idx) - obj_jacobian_i.row(val_idx)).transpose();
1068  }
1069  if (!isEqualityLinear())
1070  {
1071  if (multipliers_eq)
1072  {
1073  for (int val_idx = 0; val_idx < getEqualityDimension(); ++val_idx)
1074  eq_hessian_ij.col(param_idx_j) +=
1075  scalar * multipliers_eq[val_idx] * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
1076  }
1077  else
1078  {
1079  for (int val_idx = 0; val_idx < getEqualityDimension(); ++val_idx)
1080  eq_hessian_ij.col(param_idx_j) += scalar * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
1081  }
1082  }
1083  if (!isInequalityLinear())
1084  {
1085  if (multipliers_ineq)
1086  {
1087  for (int val_idx = 0; val_idx < getInequalityDimension(); ++val_idx)
1088  ineq_hessian_ij.col(param_idx_j) +=
1089  scalar * multipliers_ineq[val_idx] * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
1090  }
1091  else
1092  {
1093  for (int val_idx = 0; val_idx < getInequalityDimension(); ++val_idx)
1094  ineq_hessian_ij.col(param_idx_j) += scalar * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
1095  }
1096  }
1097 
1098  vertex_j->plus(j, -delta); // revert offset
1099 
1100  // increase vertex value index
1101  ++param_idx_j;
1102  }
1103 }
1104 
1105 void BaseMixedEdge::computeConstraintHessiansInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref<const Eigen::MatrixXd>& eq_jacobian_i,
1106  const Eigen::Ref<const Eigen::MatrixXd>& ineq_jacobian_i, Eigen::Ref<Eigen::MatrixXd> eq_hessian_ij,
1107  Eigen::Ref<Eigen::MatrixXd> ineq_hessian_ij, const double* multipliers_eq,
1108  const double* multipliers_ineq)
1109 {
1110  if (getNumVertices() == 0) return;
1111 
1112  assert(vtx_idx_i >= 0 && vtx_idx_i < getNumVertices());
1113  assert(vtx_idx_j >= 0 && vtx_idx_j < getNumVertices());
1114  assert(eq_jacobian_i.rows() == getEqualityDimension());
1115  assert(eq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1116  assert(ineq_jacobian_i.rows() == getInequalityDimension());
1117  assert(ineq_jacobian_i.cols() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1118  assert(eq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1119  assert(eq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
1120  assert(ineq_hessian_ij.rows() == getVertexRaw(vtx_idx_i)->getDimensionUnfixed());
1121  assert(ineq_hessian_ij.cols() == getVertexRaw(vtx_idx_j)->getDimensionUnfixed());
1122 
1123  // parameter
1124  // TODO(roesmann): improve hessian computation: delta=1e-2 is not much,
1125  // but the results are numerically not stable
1126  constexpr const double delta = HESSIAN_DELTA;
1127  constexpr const double scalar = 1.0 / delta;
1128 
1129  VertexInterface* vertex_i = getVertexRaw(vtx_idx_i);
1130  VertexInterface* vertex_j = getVertexRaw(vtx_idx_j);
1131 
1132  Eigen::MatrixXd eq_jacobian_j(getEqualityDimension(), vertex_i->getDimensionUnfixed());
1133  Eigen::MatrixXd ineq_jacobian_j(getInequalityDimension(), vertex_i->getDimensionUnfixed());
1134 
1135  int param_idx_j = 0;
1136  for (int j = 0; j < vertex_j->getDimension(); ++j)
1137  {
1138  if (vertex_j->isFixedComponent(j)) continue;
1139 
1140  vertex_j->plus(j, delta); // increment current value by delta
1141 
1142  computeConstraintJacobians(vtx_idx_i, eq_jacobian_j, ineq_jacobian_j);
1143 
1144  if (!isEqualityLinear())
1145  {
1146  if (multipliers_eq)
1147  {
1148  for (int val_idx = 0; val_idx < getEqualityDimension(); ++val_idx)
1149  eq_hessian_ij.col(param_idx_j) +=
1150  scalar * multipliers_eq[val_idx] * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
1151  }
1152  else
1153  {
1154  for (int val_idx = 0; val_idx < getEqualityDimension(); ++val_idx)
1155  eq_hessian_ij.col(param_idx_j) += scalar * (eq_jacobian_j.row(val_idx) - eq_jacobian_i.row(val_idx)).transpose();
1156  }
1157  }
1158  if (!isInequalityLinear())
1159  {
1160  if (multipliers_ineq)
1161  {
1162  for (int val_idx = 0; val_idx < getInequalityDimension(); ++val_idx)
1163  ineq_hessian_ij.col(param_idx_j) +=
1164  scalar * multipliers_ineq[val_idx] * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
1165  }
1166  else
1167  {
1168  for (int val_idx = 0; val_idx < getInequalityDimension(); ++val_idx)
1169  ineq_hessian_ij.col(param_idx_j) += scalar * (ineq_jacobian_j.row(val_idx) - ineq_jacobian_i.row(val_idx)).transpose();
1170  }
1171  }
1172 
1173  vertex_j->plus(j, -delta); // revert offset
1174 
1175  // increase vertex value index
1176  ++param_idx_j;
1177  }
1178 }
1179 
1180 } // namespace corbo
virtual int getDimension() const =0
Get dimension of the edge (dimension of the cost-function/constraint value vector) ...
virtual void computeHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
virtual void computeConstraintJacobians(int vtx_idx, Eigen::Ref< Eigen::MatrixXd > eq_jacobian, Eigen::Ref< Eigen::MatrixXd > ineq_jacobian, const double *eq_multipliers=nullptr, const double *ineq_multipliers=nullptr)
virtual void computeObjectiveHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
virtual int getNumberFiniteLowerBounds(bool unfixed_only) const =0
Get number of finite lower bounds.
constexpr const double HESSIAN_DELTA
virtual int getNumVertices() const =0
Return number of attached vertices.
virtual void computeInequalityHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
virtual void computeObjectiveJacobian(int vtx_idx, Eigen::Ref< Eigen::MatrixXd > block_jacobian, const double *multipliers=nullptr)
virtual int getDimension() const =0
Return number of elements/values/components stored in this vertex.
Generic interface class for vertices.
virtual void computeEqualityJacobian(int vtx_idx, Eigen::Ref< Eigen::MatrixXd > block_jacobian, const double *multipliers=nullptr)
virtual void computeHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
Compute edge block Hessian for a given vertex pair.
virtual void computeJacobians(int vtx_idx, Eigen::Ref< Eigen::MatrixXd > obj_jacobian, Eigen::Ref< Eigen::MatrixXd > eq_jacobian, Eigen::Ref< Eigen::MatrixXd > ineq_jacobian, const double *obj_multipliers=nullptr, const double *eq_multipliers=nullptr, const double *ineq_multipliers=nullptr)
virtual void computeEqualityHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
virtual int getDimensionUnfixed() const =0
Return number of unfixed elements (unfixed elements are skipped as parameters in the Hessian and Jaco...
virtual void computeInequalityHessianInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
virtual void computeHessiansInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &obj_jacobian_i, const Eigen::Ref< const Eigen::MatrixXd > &eq_jacobian_i, const Eigen::Ref< const Eigen::MatrixXd > &ineq_jacobian_i, Eigen::Ref< Eigen::MatrixXd > obj_hessian_ij, Eigen::Ref< Eigen::MatrixXd > eq_hessian_ij, Eigen::Ref< Eigen::MatrixXd > ineq_hessian_ij, const double *multipliers_eq=nullptr, const double *multipliers_ineq=nullptr, double weight_obj=1.0)
virtual void computeValues(Eigen::Ref< Eigen::VectorXd > values)=0
Compute function values.
virtual void computeObjectiveHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
virtual void computeInequalityJacobian(int vtx_idx, Eigen::Ref< Eigen::MatrixXd > block_jacobian, const double *multipliers=nullptr)
virtual void computeConstraintHessiansInc(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &eq_jacobian_i, const Eigen::Ref< const Eigen::MatrixXd > &ineq_jacobian_i, Eigen::Ref< Eigen::MatrixXd > eq_hessian_ij, Eigen::Ref< Eigen::MatrixXd > ineq_hessian_ij, const double *multipliers_eq=nullptr, const double *multipliers_ineq=nullptr)
virtual VertexInterface * getVertexRaw(int idx)=0
Get access to vertex with index idx (0 <= idx < numVertices)
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:192
virtual void plus(int idx, double inc)=0
Add value to a specific component of the vertex: x[idx] += inc.
virtual void computeEqualityHessian(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &block_jacobian_i, Eigen::Ref< Eigen::MatrixXd > block_hessian_ij, const double *multipliers=nullptr, double weight=1.0)
int getNumFiniteVerticesUpperBounds() const
virtual void computeConstraintHessians(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &eq_jacobian_i, const Eigen::Ref< const Eigen::MatrixXd > &ineq_jacobian_i, Eigen::Ref< Eigen::MatrixXd > eq_hessian_ij, Eigen::Ref< Eigen::MatrixXd > ineq_hessian_ij, const double *multipliers_eq=nullptr, const double *multipliers_ineq=nullptr)
virtual void computeJacobian(int vtx_idx, Eigen::Ref< Eigen::MatrixXd > block_jacobian, const double *multipliers=nullptr)
Compute edge block jacobian for a given vertex.
virtual void computeHessians(int vtx_idx_i, int vtx_idx_j, const Eigen::Ref< const Eigen::MatrixXd > &obj_jacobian_i, const Eigen::Ref< const Eigen::MatrixXd > &eq_jacobian_i, const Eigen::Ref< const Eigen::MatrixXd > &ineq_jacobian_i, Eigen::Ref< Eigen::MatrixXd > obj_hessian_ij, Eigen::Ref< Eigen::MatrixXd > eq_hessian_ij, Eigen::Ref< Eigen::MatrixXd > ineq_hessian_ij, const double *multipliers_eq=nullptr, const double *multipliers_ineq=nullptr, double weight_obj=1.0)
virtual int getNumberFiniteUpperBounds(bool unfixed_only) const =0
Get number of finite upper bounds.
int getNumFiniteVerticesLowerBounds() const
virtual const VertexInterface * getVertex(int idx) const =0
virtual bool isFixedComponent(int idx) const =0
Check if individual components are fixed or unfixed.


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Mon Feb 28 2022 22:06:51