hyper_graph_optimization_problem_vertex_based.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 
26 
27 namespace corbo {
28 
29 static constexpr const double cd_delta = 1e-9;
30 static constexpr const double cd_neg2delta = -2 * cd_delta;
31 static constexpr const double cd_scalar = 1.0 / (2 * cd_delta);
32 
34 {
35  assert(_graph.hasEdgeSet());
36 
38  if (edges->isModified())
39  {
40  edges->getDimensions(_dim_non_lsq_obj, _dim_lsq_obj, _dim_eq, _dim_ineq);
41  edges->computeEdgeIndices();
42  edges->reserveEdgeCacheMemory(3, 2); // max 3 values (central differences plus current values; max 2 jacobians (for hessian)
43  // we make use of the internal edge cache here; TODO(roesmann) we might not iterate over previously allocated
44  // edges
45  edges->registerEdgesAtVertices(*_graph.getVertexSet()); // we also need to register edges to later iterate vertices
46  edges->setModified(false);
47  }
48 }
49 
50 void HyperGraphOptimizationProblemVertexBased::precomputeConnectedMixedEdges(const VertexInterface* vertex, bool objective, bool equality,
51  bool inequality)
52 {
53  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
54  {
55  if (!equality && !inequality && edge->getObjectiveDimension() == 0) continue;
56  if (!objective && !inequality && edge->getEqualityDimension() == 0) continue;
57  if (!equality && !objective && edge->getInequalityDimension() == 0) continue;
58  // TODO(roesmann): these are not all cases
59 
60  edge->precompute();
61  }
62 }
63 
64 void HyperGraphOptimizationProblemVertexBased::computeObjectiveValuesCached(const VertexInterface* vertex, bool include_lsq_edges,
65  bool include_nonmixed, bool include_mixed)
66 {
67  if (include_nonmixed)
68  {
69  for (BaseEdge* edge : vertex->getConnectedObjectiveEdgesRef())
70  {
71  edge->computeValuesCached();
72  }
73  if (include_lsq_edges)
74  {
75  for (BaseEdge* edge : vertex->getConnectedLsqObjectiveEdgesRef())
76  {
77  edge->computeSquaredNormOfValuesCached();
78  }
79  }
80  }
81  if (include_mixed)
82  {
83  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
84  {
85  if (edge->getObjectiveDimension() == 0) continue;
86  if (!include_lsq_edges && edge->isObjectiveLeastSquaresForm()) continue;
87 
88  edge->precompute();
89 
90  if (edge->isObjectiveLeastSquaresForm())
91  edge->computeSquaredNormOfObjectiveValuesCached();
92  else
93  edge->computeObjectiveValuesCached();
94  }
95  }
96 }
97 
98 void HyperGraphOptimizationProblemVertexBased::finalizeObjectiveGradient(const VertexInterface* vertex, double& gradient_coeff,
99  bool include_lsq_edges, bool include_nonmixed, bool include_mixed,
100  bool precompute_mixed)
101 {
102  if (include_nonmixed)
103  {
104  for (BaseEdge* edge : vertex->getConnectedObjectiveEdgesRef())
105  {
106  Eigen::VectorXd values_minus(edge->getDimension());
107  edge->computeValues(values_minus);
108  gradient_coeff += cd_scalar * (edge->getCache().topValues() - values_minus).sum();
109  edge->getCache().popValues();
110  }
111  if (include_lsq_edges)
112  {
113  for (BaseEdge* edge : vertex->getConnectedLsqObjectiveEdgesRef())
114  {
115  gradient_coeff += cd_scalar * (edge->getCache().topValues()[0] - edge->computeSquaredNormOfValues());
116  edge->getCache().popValues();
117  }
118  }
119  }
120  if (include_mixed)
121  {
122  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
123  {
124  if (edge->getObjectiveDimension() == 0) continue;
125  if (!include_lsq_edges && edge->isObjectiveLeastSquaresForm()) continue;
126 
127  if (precompute_mixed) edge->precompute();
128 
129  if (edge->isObjectiveLeastSquaresForm())
130  {
131  gradient_coeff += cd_scalar * (edge->getObjectiveCache().topValues()[0] - edge->computeSquaredNormOfObjectiveValues());
132  }
133  else
134  {
135  Eigen::VectorXd values_minus(edge->getObjectiveDimension());
136  edge->computeObjectiveValues(values_minus);
137  gradient_coeff += cd_scalar * (edge->getObjectiveCache().topValues() - values_minus).sum();
138  }
139  edge->getObjectiveCache().popValues();
140  }
141  }
142 }
143 
144 void HyperGraphOptimizationProblemVertexBased::computeLsqObjectiveValuesCached(const VertexInterface* vertex, bool include_nonmixed,
145  bool include_mixed, bool precompute_mixed)
146 {
147  if (include_nonmixed)
148  {
149  for (BaseEdge* edge : vertex->getConnectedLsqObjectiveEdgesRef())
150  {
151  edge->computeValuesCached();
152  }
153  }
154  if (include_mixed)
155  {
156  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
157  {
158  if (edge->getObjectiveDimension() == 0) continue;
159  if (!edge->isObjectiveLeastSquaresForm()) continue;
160 
161  if (precompute_mixed) edge->precompute();
162 
163  edge->computeObjectiveValuesCached();
164  }
165  }
166 }
167 
169  Eigen::Ref<Eigen::MatrixXd>& jacobian, const double* multipliers,
170  bool include_nonmixed, bool include_mixed)
171 {
172  if (include_nonmixed)
173  {
174  for (BaseEdge* edge : vertex->getConnectedLsqObjectiveEdgesRef())
175  {
176  Eigen::VectorXd values_minus(edge->getDimension());
177  edge->computeValues(values_minus);
178 
179  if (multipliers)
180  {
181  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeIdx(), edge->getDimension());
182  jacobian.block(edge->getEdgeIdx(), vtx_idx, edge->getDimension(), 1) =
183  cd_scalar * multipliers_map.cwiseProduct(edge->getCache().topValues() - values_minus);
184  }
185  else
186  {
187  jacobian.block(edge->getEdgeIdx(), vtx_idx, edge->getDimension(), 1) = cd_scalar * (edge->getCache().topValues() - values_minus);
188  }
189  edge->getCache().popValues();
190  }
191  }
192 
193  if (include_mixed)
194  {
195  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
196  {
197  if (edge->getObjectiveDimension() == 0) continue;
198  if (!edge->isObjectiveLeastSquaresForm()) continue;
199 
200  edge->precompute();
201 
202  Eigen::VectorXd values_minus(edge->getObjectiveDimension());
203  edge->computeObjectiveValues(values_minus);
204  if (multipliers)
205  {
206  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeObjectiveIdx(), edge->getObjectiveDimension());
207  jacobian.block(edge->getEdgeObjectiveIdx(), vtx_idx, edge->getObjectiveDimension(), 1).noalias() =
208  cd_scalar * multipliers_map.cwiseProduct(edge->getObjectiveCache().topValues() - values_minus);
209  }
210  else
211  {
212  jacobian.block(edge->getEdgeObjectiveIdx(), vtx_idx, edge->getObjectiveDimension(), 1).noalias() =
213  cd_scalar * (edge->getObjectiveCache().topValues() - values_minus);
214  }
215  edge->getObjectiveCache().popValues();
216  }
217  }
218 }
219 
222  Eigen::Ref<Eigen::VectorXi> j_col, int& nnz_idx,
223  int row_offset)
224 {
225  for (BaseEdge* edge : vertex->getConnectedLsqObjectiveEdgesRef())
226  {
227  const int edge_idx = edge->getEdgeIdx() + row_offset;
228 
229  for (int i = 0; i < edge->getDimension(); ++i)
230  {
231  i_row[nnz_idx] = edge_idx + i;
232  j_col[nnz_idx] = vtx_idx;
233  ++nnz_idx;
234  }
235  }
236 
237  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
238  {
239  if (edge->getObjectiveDimension() == 0) continue;
240  if (!edge->isObjectiveLeastSquaresForm()) continue;
241 
242  const int edge_idx = edge->getEdgeObjectiveIdx() + row_offset;
243 
244  for (int i = 0; i < edge->getObjectiveDimension(); ++i)
245  {
246  i_row[nnz_idx] = edge_idx + i;
247  j_col[nnz_idx] = vtx_idx;
248  ++nnz_idx;
249  }
250  }
251 }
252 
253 void HyperGraphOptimizationProblemVertexBased::finalizeLsqObjectiveJacobianSparseValues(const VertexInterface* vertex, int& nnz_idx,
255  const double* multipliers, bool precompute_mixed)
256 {
257  for (BaseEdge* edge : vertex->getConnectedLsqObjectiveEdgesRef())
258  {
259  Eigen::VectorXd values_minus(edge->getDimension());
260  edge->computeValues(values_minus);
261 
262  if (multipliers)
263  {
264  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeIdx(), edge->getDimension());
265  values.segment(nnz_idx, edge->getDimension()) = cd_scalar * multipliers_map.cwiseProduct(edge->getCache().topValues() - values_minus);
266  nnz_idx += edge->getDimension();
267  }
268  else
269  {
270  values.segment(nnz_idx, edge->getDimension()) = cd_scalar * (edge->getCache().topValues() - values_minus);
271  nnz_idx += edge->getDimension();
272  }
273  edge->getCache().popValues();
274  }
275 
276  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
277  {
278  if (edge->getObjectiveDimension() == 0) continue;
279  if (!edge->isObjectiveLeastSquaresForm()) continue;
280 
281  if (precompute_mixed) edge->precompute();
282 
283  Eigen::VectorXd values_minus(edge->getObjectiveDimension());
284  edge->computeObjectiveValues(values_minus);
285  if (multipliers)
286  {
287  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeObjectiveIdx(), edge->getObjectiveDimension());
288  values.segment(nnz_idx, edge->getObjectiveDimension()).noalias() =
289  cd_scalar * multipliers_map.cwiseProduct(edge->getObjectiveCache().topValues() - values_minus);
290  nnz_idx += edge->getObjectiveDimension();
291  }
292  else
293  {
294  values.segment(nnz_idx, edge->getObjectiveDimension()).noalias() = cd_scalar * (edge->getObjectiveCache().topValues() - values_minus);
295  nnz_idx += edge->getObjectiveDimension();
296  }
297  edge->getObjectiveCache().popValues();
298  }
299 }
300 
301 void HyperGraphOptimizationProblemVertexBased::computeEqualitiesValuesCached(const VertexInterface* vertex, bool include_nonmixed, bool include_mixed,
302  bool precompute_mixed)
303 {
304  if (include_nonmixed)
305  {
306  for (BaseEdge* edge : vertex->getConnectedEqualityEdgesRef())
307  {
308  edge->computeValuesCached();
309  }
310  }
311  if (include_mixed)
312  {
313  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
314  {
315  if (edge->getEqualityDimension() == 0) continue;
316 
317  if (precompute_mixed) edge->precompute();
318 
319  edge->computeEqualityValuesCached();
320  }
321  }
322 }
323 
325  Eigen::Ref<Eigen::MatrixXd>& jacobian, const double* multipliers,
326  bool include_nonmixed, bool include_mixed, bool precompute_mixed)
327 {
328  if (include_nonmixed)
329  {
330  for (BaseEdge* edge : vertex->getConnectedEqualityEdgesRef())
331  {
332  Eigen::VectorXd values_minus(edge->getDimension());
333  edge->computeValues(values_minus);
334 
335  if (multipliers)
336  {
337  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeIdx(), edge->getDimension());
338  jacobian.block(edge->getEdgeIdx(), vtx_idx, edge->getDimension(), 1) =
339  cd_scalar * multipliers_map.cwiseProduct(edge->getCache().topValues() - values_minus);
340  }
341  else
342  {
343  jacobian.block(edge->getEdgeIdx(), vtx_idx, edge->getDimension(), 1) = cd_scalar * (edge->getCache().topValues() - values_minus);
344  }
345  edge->getCache().popValues();
346  }
347  }
348 
349  if (include_mixed)
350  {
351  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
352  {
353  if (edge->getEqualityDimension() == 0) continue;
354 
355  if (precompute_mixed) edge->precompute();
356 
357  Eigen::VectorXd values_minus(edge->getEqualityDimension());
358  edge->computeEqualityValues(values_minus);
359  if (multipliers)
360  {
361  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeEqualityIdx(), edge->getEqualityDimension());
362  jacobian.block(edge->getEdgeEqualityIdx(), vtx_idx, edge->getEqualityDimension(), 1).noalias() =
363  cd_scalar * multipliers_map.cwiseProduct(edge->getEqualityCache().topValues() - values_minus);
364  }
365  else
366  {
367  jacobian.block(edge->getEdgeEqualityIdx(), vtx_idx, edge->getEqualityDimension(), 1).noalias() =
368  cd_scalar * (edge->getEqualityCache().topValues() - values_minus);
369  }
370  edge->getEqualityCache().popValues();
371  }
372  }
373 }
374 
377  Eigen::Ref<Eigen::VectorXi> j_col, int& nnz_idx,
378  int row_offset)
379 {
380  for (BaseEdge* edge : vertex->getConnectedEqualityEdgesRef())
381  {
382  const int edge_idx = edge->getEdgeIdx() + row_offset;
383 
384  for (int i = 0; i < edge->getDimension(); ++i)
385  {
386  i_row[nnz_idx] = edge_idx + i;
387  j_col[nnz_idx] = vtx_idx;
388  ++nnz_idx;
389  }
390  }
391 
392  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
393  {
394  if (edge->getEqualityDimension() == 0) continue;
395 
396  const int edge_idx = edge->getEdgeEqualityIdx() + row_offset;
397 
398  for (int i = 0; i < edge->getEqualityDimension(); ++i)
399  {
400  i_row[nnz_idx] = edge_idx + i;
401  j_col[nnz_idx] = vtx_idx;
402  ++nnz_idx;
403  }
404  }
405 }
406 
407 void HyperGraphOptimizationProblemVertexBased::finalizeEqualitiesJacobianSparseValues(const VertexInterface* vertex, int& nnz_idx,
408  Eigen::Ref<Eigen::VectorXd>& values, const double* multipliers,
409  bool precompute_mixed)
410 {
411  for (BaseEdge* edge : vertex->getConnectedEqualityEdgesRef())
412  {
413  Eigen::VectorXd values_minus(edge->getDimension());
414  edge->computeValues(values_minus);
415 
416  if (multipliers)
417  {
418  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeIdx(), edge->getDimension());
419  values.segment(nnz_idx, edge->getDimension()) = cd_scalar * multipliers_map.cwiseProduct(edge->getCache().topValues() - values_minus);
420  nnz_idx += edge->getDimension();
421  }
422  else
423  {
424  values.segment(nnz_idx, edge->getDimension()) = cd_scalar * (edge->getCache().topValues() - values_minus);
425  nnz_idx += edge->getDimension();
426  }
427  edge->getCache().popValues();
428  }
429 
430  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
431  {
432  if (edge->getEqualityDimension() == 0) continue;
433 
434  if (precompute_mixed) edge->precompute();
435 
436  Eigen::VectorXd values_minus(edge->getEqualityDimension());
437  edge->computeEqualityValues(values_minus);
438  if (multipliers)
439  {
440  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeEqualityIdx(), edge->getEqualityDimension());
441  values.segment(nnz_idx, edge->getEqualityDimension()).noalias() =
442  cd_scalar * multipliers_map.cwiseProduct(edge->getEqualityCache().topValues() - values_minus);
443  nnz_idx += edge->getEqualityDimension();
444  }
445  else
446  {
447  values.segment(nnz_idx, edge->getEqualityDimension()).noalias() = cd_scalar * (edge->getEqualityCache().topValues() - values_minus);
448  nnz_idx += edge->getEqualityDimension();
449  }
450  edge->getEqualityCache().popValues();
451  }
452 }
453 
454 void HyperGraphOptimizationProblemVertexBased::computeInequalitiesValuesCached(const VertexInterface* vertex, bool include_nonmixed,
455  bool include_mixed, bool precompute_mixed)
456 {
457  if (include_nonmixed)
458  {
459  for (BaseEdge* edge : vertex->getConnectedInequalityEdgesRef())
460  {
461  edge->computeValuesCached();
462  }
463  }
464  if (include_mixed)
465  {
466  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
467  {
468  if (edge->getInequalityDimension() == 0) continue;
469 
470  if (precompute_mixed) edge->precompute();
471 
472  edge->computeInequalityValuesCached();
473  }
474  }
475 }
476 
478  Eigen::Ref<Eigen::MatrixXd>& jacobian, const double* multipliers,
479  bool include_nonmixed, bool include_mixed, bool precompute_mixed)
480 {
481  if (include_nonmixed)
482  {
483  for (BaseEdge* edge : vertex->getConnectedInequalityEdgesRef())
484  {
485  Eigen::VectorXd values_minus(edge->getDimension());
486  edge->computeValues(values_minus);
487 
488  if (multipliers)
489  {
490  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeIdx(), edge->getDimension());
491  jacobian.block(edge->getEdgeIdx(), vtx_idx, edge->getDimension(), 1) =
492  cd_scalar * multipliers_map.cwiseProduct(edge->getCache().topValues() - values_minus);
493  }
494  else
495  {
496  jacobian.block(edge->getEdgeIdx(), vtx_idx, edge->getDimension(), 1) = cd_scalar * (edge->getCache().topValues() - values_minus);
497  }
498  edge->getCache().popValues();
499  }
500  }
501 
502  if (include_mixed)
503  {
504  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
505  {
506  if (edge->getInequalityDimension() == 0) continue;
507 
508  if (precompute_mixed) edge->precompute();
509 
510  Eigen::VectorXd values_minus(edge->getInequalityDimension());
511  edge->computeInequalityValues(values_minus);
512  if (multipliers)
513  {
514  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeInequalityIdx(), edge->getInequalityDimension());
515  jacobian.block(edge->getEdgeInequalityIdx(), vtx_idx, edge->getInequalityDimension(), 1).noalias() =
516  cd_scalar * multipliers_map.cwiseProduct(edge->getInequalityCache().topValues() - values_minus);
517  }
518  else
519  {
520  jacobian.block(edge->getEdgeInequalityIdx(), vtx_idx, edge->getInequalityDimension(), 1).noalias() =
521  cd_scalar * (edge->getInequalityCache().topValues() - values_minus);
522  }
523  edge->getInequalityCache().popValues();
524  }
525  }
526 }
527 
528 void HyperGraphOptimizationProblemVertexBased::finalizeActiveInequalitiesJacobian(const VertexInterface* vertex, int vtx_idx,
529  Eigen::Ref<Eigen::MatrixXd>& jacobian, double weight,
530  bool include_nonmixed, bool include_mixed)
531 {
532  const double weighted_scalar = weight * cd_scalar;
533 
534  if (include_nonmixed)
535  {
536  for (BaseEdge* edge : vertex->getConnectedInequalityEdgesRef())
537  {
538  assert(edge->getCache().sizeValues() > 1); // we need both the actual values and the intermediate result from finite differences
539 
540  Eigen::Array<bool, -1, 1> active = edge->getCache().recentValues(EdgeCache::Previous).array() > 0.0;
541 
542  if (active.any())
543  {
544  Eigen::VectorXd values_minus(edge->getDimension());
545  edge->computeValues(values_minus);
546 
547  // now set values to zero if inactive or multiply with weight otherwise
548  for (int j = 0; j < edge->getDimension(); ++j)
549  {
550  if (active[j]) jacobian(edge->getEdgeIdx() + j, vtx_idx) = weighted_scalar * (edge->getCache().topValues()(j) - values_minus(j));
551  // else if (!active[j])
552  // jacobian(edge->getEdgeIdx() + j, vtx_idx) = 0.0; // should be zero already
553  }
554  }
555  edge->getCache().popValues(); // intermediate result
556  edge->getCache().popValues(); // values before finite differences
557  }
558  }
559 
560  if (include_mixed)
561  {
562  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
563  {
564  if (edge->getInequalityDimension() == 0) continue;
565 
566  assert(edge->getInequalityCache().sizeValues() >
567  1); // we need both the actual values and the intermediate result from finite differences
568 
569  Eigen::Array<bool, -1, 1> active = edge->getInequalityCache().recentValues(EdgeCache::Previous).array() > 0.0;
570 
571  if (active.any())
572  {
573  edge->precompute();
574 
575  Eigen::VectorXd values_minus(edge->getInequalityDimension());
576  edge->computeInequalityValues(values_minus);
577 
578  // now set values to zero if inactive or multiply with weight otherwise
579  for (int j = 0; j < edge->getInequalityDimension(); ++j)
580  {
581  if (active[j])
582  jacobian(edge->getEdgeInequalityIdx() + j, vtx_idx) =
583  weighted_scalar * (edge->getInequalityCache().topValues()(j) - values_minus(j));
584  // else if (!active[j])
585  // jacobian(edge->getEdgeIdx() + j, vtx_idx) = 0.0; // should be zero already
586  }
587  }
588  edge->getInequalityCache().popValues(); // intermediate result
589  edge->getInequalityCache().popValues(); // values before finite differences
590  }
591  }
592 }
593 
596  Eigen::Ref<Eigen::VectorXi> j_col, int& nnz_idx,
597  int row_offset)
598 {
599  for (BaseEdge* edge : vertex->getConnectedInequalityEdgesRef())
600  {
601  const int edge_idx = edge->getEdgeIdx() + row_offset;
602 
603  for (int i = 0; i < edge->getDimension(); ++i)
604  {
605  i_row[nnz_idx] = edge_idx + i;
606  j_col[nnz_idx] = vtx_idx;
607  ++nnz_idx;
608  }
609  }
610 
611  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
612  {
613  if (edge->getInequalityDimension() == 0) continue;
614 
615  const int edge_idx = edge->getEdgeInequalityIdx() + row_offset;
616 
617  for (int i = 0; i < edge->getInequalityDimension(); ++i)
618  {
619  i_row[nnz_idx] = edge_idx + i;
620  j_col[nnz_idx] = vtx_idx;
621  ++nnz_idx;
622  }
623  }
624 }
625 
626 void HyperGraphOptimizationProblemVertexBased::finalizeInequalitiesJacobianSparseValues(const VertexInterface* vertex, int& nnz_idx,
628  const double* multipliers, bool precompute_mixed)
629 {
630  for (BaseEdge* edge : vertex->getConnectedInequalityEdgesRef())
631  {
632  Eigen::VectorXd values_minus(edge->getDimension());
633  edge->computeValues(values_minus);
634 
635  if (multipliers)
636  {
637  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeIdx(), edge->getDimension());
638  values.segment(nnz_idx, edge->getDimension()) = cd_scalar * multipliers_map.cwiseProduct(edge->getCache().topValues() - values_minus);
639  edge->getCache().popValues();
640  nnz_idx += edge->getDimension();
641  }
642  else
643  {
644  values.segment(nnz_idx, edge->getDimension()) = cd_scalar * (edge->getCache().topValues() - values_minus);
645  edge->getCache().popValues();
646  nnz_idx += edge->getDimension();
647  }
648  }
649 
650  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
651  {
652  if (edge->getInequalityDimension() == 0) continue;
653 
654  if (precompute_mixed) edge->precompute();
655 
656  Eigen::VectorXd values_minus(edge->getInequalityDimension());
657  edge->computeInequalityValues(values_minus);
658  if (multipliers)
659  {
660  Eigen::Map<const Eigen::VectorXd> multipliers_map(multipliers + edge->getEdgeInequalityIdx(), edge->getInequalityDimension());
661  values.segment(nnz_idx, edge->getInequalityDimension()).noalias() =
662  cd_scalar * multipliers_map.cwiseProduct(edge->getInequalityCache().topValues() - values_minus);
663  edge->getInequalityCache().popValues();
664  nnz_idx += edge->getInequalityDimension();
665  }
666  else
667  {
668  values.segment(nnz_idx, edge->getInequalityDimension()).noalias() = cd_scalar * (edge->getInequalityCache().topValues() - values_minus);
669  edge->getInequalityCache().popValues();
670  nnz_idx += edge->getInequalityDimension();
671  }
672  }
673 }
674 
676  Eigen::Ref<Eigen::VectorXd>& values, double weight)
677 {
678  const double weighted_scalar = weight * cd_scalar;
679 
680  for (BaseEdge* edge : vertex->getConnectedInequalityEdgesRef())
681  {
682  assert(edge->getCache().sizeValues() > 1); // we need both the actual values and the intermediate result from finite differences
683 
684  Eigen::Array<bool, -1, 1> active = edge->getCache().recentValues(EdgeCache::Previous).array() > 0.0;
685 
686  if (active.any())
687  {
688  Eigen::VectorXd values_minus(edge->getDimension());
689  edge->computeValues(values_minus);
690 
691  // now set values to zero if inactive or multiply with weight otherwise
692  for (int j = 0; j < edge->getDimension(); ++j)
693  {
694  if (active[j]) values(nnz_idx) = weighted_scalar * (edge->getCache().topValues()(j) - values_minus(j));
695  ++nnz_idx;
696  }
697  }
698  else
699  {
700  nnz_idx += edge->getDimension();
701  }
702  edge->getCache().popValues(); // intermediate result
703  edge->getCache().popValues(); // values before finite differences
704  }
705 
706  for (BaseMixedEdge* edge : vertex->getConnectedMixedEdgesRef())
707  {
708  if (edge->getInequalityDimension() == 0) continue;
709 
710  assert(edge->getInequalityCache().sizeValues() > 1); // we need both the actual values and the intermediate result from finite differences
711 
712  Eigen::Array<bool, -1, 1> active = edge->getInequalityCache().recentValues(EdgeCache::Previous).array() > 0.0;
713 
714  if (active.any())
715  {
716  edge->precompute();
717 
718  Eigen::VectorXd values_minus(edge->getInequalityDimension());
719  edge->computeInequalityValues(values_minus);
720 
721  // now set values to zero if inactive or multiply with weight otherwise
722  for (int j = 0; j < edge->getInequalityDimension(); ++j)
723  {
724  if (active[j]) values(nnz_idx) = weighted_scalar * (edge->getInequalityCache().topValues()(j) - values_minus(j));
725  ++nnz_idx;
726  }
727  }
728  else
729  {
730  nnz_idx += edge->getInequalityDimension();
731  }
732  edge->getInequalityCache().popValues(); // intermediate result
733  edge->getInequalityCache().popValues(); // values before finite differences
734  }
735 }
736 
738 {
739  assert(_graph.hasVertexSet() && _graph.hasEdgeSet());
740  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
742 
743  assert(gradient.size() == getParameterDimension());
744 
745  gradient.setZero();
746 
747  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
748  {
749  if (vertex->isFixed()) continue;
750 
751  int free_idx = 0;
752  for (int i = 0; i < vertex->getDimension(); ++i)
753  {
754  if (vertex->isFixedComponent(i)) continue;
755 
756  vertex->plus(i, cd_delta);
757 
758  computeObjectiveValuesCached(vertex, true);
759 
760  vertex->plus(i, cd_neg2delta);
761 
762  finalizeObjectiveGradient(vertex, gradient(vertex->getVertexIdx() + free_idx), true);
763 
764  vertex->plus(i, cd_delta); // revert offset
765  ++free_idx;
766  }
767  }
768  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
769 }
770 
772 {
773  assert(_graph.hasVertexSet() && _graph.hasEdgeSet());
774  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
776 
777  assert(gradient.size() == getParameterDimension());
778 
779  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
780  {
781  if (vertex->isFixed()) continue;
782 
783  int free_idx = 0;
784  for (int i = 0; i < vertex->getDimension(); ++i)
785  {
786  if (vertex->isFixedComponent(i)) continue;
787 
788  vertex->plus(i, cd_delta);
789 
790  computeObjectiveValuesCached(vertex, false);
791 
792  vertex->plus(i, cd_neg2delta);
793 
794  finalizeObjectiveGradient(vertex, gradient(vertex->getVertexIdx() + free_idx), false);
795 
796  vertex->plus(i, cd_delta); // revert offset
797  ++free_idx;
798  }
799  }
800  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
801 }
802 
804 {
805  assert(_graph.hasVertexSet() && _graph.hasEdgeSet());
806  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
808 
809  assert(jacobian.rows() == getLsqObjectiveDimension());
810  assert(jacobian.cols() == getParameterDimension());
811 
812  // we need to set to zero everything first
813  jacobian.setZero();
814 
815  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
816  {
817  if (vertex->isFixed()) continue;
818 
819  int free_idx = 0;
820  for (int i = 0; i < vertex->getDimension(); ++i)
821  {
822  if (vertex->isFixedComponent(i)) continue;
823 
824  vertex->plus(i, cd_delta);
825 
827 
828  vertex->plus(i, cd_neg2delta);
829 
830  finalizeLsqObjectiveJacobian(vertex, vertex->getVertexIdx() + free_idx, jacobian, multipliers);
831 
832  vertex->plus(i, cd_delta); // revert offset
833  ++free_idx;
834  }
835  }
836  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
837 }
838 
840 {
841  int nnz = 0;
842 
843  assert(_graph.hasEdgeSet());
845 
847 
848  // Iterate lsq objective edges
849  for (BaseEdge::Ptr& edge : edges->getLsqObjectiveEdgesRef())
850  {
851  for (int i = 0; i < edge->getNumVertices(); ++i)
852  {
853  nnz += edge->getDimension() * edge->getVertexRaw(i)->getDimensionUnfixed(); // block size
854  }
855  }
856  // Iterate mixed edges
857  for (BaseMixedEdge::Ptr& edge : edges->getMixedEdgesRef())
858  {
859  if (edge->getObjectiveDimension() == 0 || !edge->isObjectiveLeastSquaresForm()) continue;
860 
861  for (int i = 0; i < edge->getNumVertices(); ++i)
862  {
863  nnz += edge->getObjectiveDimension() * edge->getVertexRaw(i)->getDimensionUnfixed(); // block size
864  }
865  }
866  return nnz;
867 }
868 
871 {
872  assert(i_row.size() == computeSparseJacobianLsqObjectiveNNZ());
873  assert(j_col.size() == i_row.size());
874 
875  int nnz_idx = 0;
876 
877  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
878  {
879  if (vertex->isFixed()) continue;
880 
881  int free_idx = 0;
882  for (int i = 0; i < vertex->getDimension(); ++i)
883  {
884  if (vertex->isFixedComponent(i)) continue;
885 
886  computeLsqObjectiveJacobianStructureForVertex(vertex, vertex->getVertexIdx() + free_idx, i_row, j_col, nnz_idx);
887 
888  ++free_idx;
889  }
890  }
891 }
892 
894 {
895  assert(values.size() == computeSparseJacobianLsqObjectiveNNZ());
896  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
897 
898  // we need to set to zero everything first
899  values.setZero();
900 
901  int nnz_idx = 0;
902 
903  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
904  {
905  if (vertex->isFixed()) continue;
906 
907  int free_idx = 0;
908  for (int i = 0; i < vertex->getDimension(); ++i)
909  {
910  if (vertex->isFixedComponent(i)) continue;
911 
912  vertex->plus(i, cd_delta);
913 
915 
916  vertex->plus(i, cd_neg2delta);
917 
918  finalizeLsqObjectiveJacobianSparseValues(vertex, nnz_idx, values, multipliers);
919 
920  vertex->plus(i, cd_delta); // revert offset
921  ++free_idx;
922  }
923  }
924  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
925 }
926 
928 {
929  assert(_graph.hasVertexSet() && _graph.hasEdgeSet());
930  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
932 
933  assert(jacobian.rows() == getEqualityDimension());
934  assert(jacobian.cols() == getParameterDimension());
935 
936  // we need to set to zero everything first
937  jacobian.setZero();
938 
939  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
940  {
941  if (vertex->isFixed()) continue;
942 
943  int free_idx = 0;
944  for (int i = 0; i < vertex->getDimension(); ++i)
945  {
946  if (vertex->isFixedComponent(i)) continue;
947 
948  vertex->plus(i, cd_delta);
949 
951 
952  vertex->plus(i, cd_neg2delta);
953 
954  finalizeEqualitiesJacobian(vertex, vertex->getVertexIdx() + free_idx, jacobian, multipliers);
955 
956  vertex->plus(i, cd_delta); // revert offset
957  ++free_idx;
958  }
959  }
960  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
961 }
962 
964 {
965  int nnz = 0;
966 
967  assert(_graph.hasEdgeSet());
969 
971 
972  // Iterate equality edges
973  for (BaseEdge::Ptr& edge : edges->getEqualityEdgesRef())
974  {
975  for (int i = 0; i < edge->getNumVertices(); ++i)
976  {
977  nnz += edge->getDimension() * edge->getVertexRaw(i)->getDimensionUnfixed(); // block size
978  }
979  }
980  // Iterate mixed edges
981  for (BaseMixedEdge::Ptr& edge : edges->getMixedEdgesRef())
982  {
983  if (edge->getEqualityDimension() == 0) continue;
984 
985  for (int i = 0; i < edge->getNumVertices(); ++i)
986  {
987  nnz += edge->getEqualityDimension() * edge->getVertexRaw(i)->getDimensionUnfixed(); // block size
988  }
989  }
990  return nnz;
991 }
992 
995 {
996  assert(i_row.size() == computeSparseJacobianEqualitiesNNZ());
997  assert(j_col.size() == i_row.size());
998 
999  int nnz_idx = 0;
1000 
1001  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1002  {
1003  if (vertex->isFixed()) continue;
1004 
1005  int free_idx = 0;
1006  for (int i = 0; i < vertex->getDimension(); ++i)
1007  {
1008  if (vertex->isFixedComponent(i)) continue;
1009 
1010  computeEqualitiesJacobianStructureForVertex(vertex, vertex->getVertexIdx() + free_idx, i_row, j_col, nnz_idx);
1011 
1012  ++free_idx;
1013  }
1014  }
1016 
1018 {
1019  assert(values.size() == computeSparseJacobianEqualitiesNNZ());
1020  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1021 
1022  // we need to set to zero everything first
1023  values.setZero();
1024 
1025  int nnz_idx = 0;
1026 
1027  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1028  {
1029  if (vertex->isFixed()) continue;
1030 
1031  int free_idx = 0;
1032  for (int i = 0; i < vertex->getDimension(); ++i)
1033  {
1034  if (vertex->isFixedComponent(i)) continue;
1035 
1036  vertex->plus(i, cd_delta);
1037 
1040  vertex->plus(i, cd_neg2delta);
1041 
1042  finalizeEqualitiesJacobianSparseValues(vertex, nnz_idx, values, multipliers);
1043 
1044  vertex->plus(i, cd_delta); // revert offset
1045  ++free_idx;
1046  }
1047  }
1048  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1049 }
1050 
1052 {
1053  assert(_graph.hasVertexSet() && _graph.hasEdgeSet());
1054  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1056 
1057  assert(jacobian.rows() == getInequalityDimension());
1058  assert(jacobian.cols() == getParameterDimension());
1059 
1060  // we need to set to zero everything first
1061  jacobian.setZero();
1062 
1063  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1064  {
1065  if (vertex->isFixed()) continue;
1066 
1067  int free_idx = 0;
1068  for (int i = 0; i < vertex->getDimension(); ++i)
1069  {
1070  if (vertex->isFixedComponent(i)) continue;
1071 
1072  vertex->plus(i, cd_delta);
1075 
1076  vertex->plus(i, cd_neg2delta);
1077 
1078  finalizeInequalitiesJacobian(vertex, vertex->getVertexIdx() + free_idx, jacobian, multipliers);
1079 
1080  vertex->plus(i, cd_delta); // revert offset
1081  ++free_idx;
1082  }
1083  }
1084  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1085 }
1086 
1088 {
1089  int nnz = 0;
1090 
1091  assert(_graph.hasEdgeSet());
1093 
1095 
1096  // Iterate inequality edges
1097  for (BaseEdge::Ptr& edge : edges->getInequalityEdgesRef())
1098  {
1099  for (int i = 0; i < edge->getNumVertices(); ++i)
1100  {
1101  nnz += edge->getDimension() * edge->getVertexRaw(i)->getDimensionUnfixed(); // block size
1102  }
1103  }
1104  // Iterate mixed edges
1105  for (BaseMixedEdge::Ptr& edge : edges->getMixedEdgesRef())
1106  {
1107  if (edge->getInequalityDimension() == 0) continue;
1108 
1109  for (int i = 0; i < edge->getNumVertices(); ++i)
1110  {
1111  nnz += edge->getInequalityDimension() * edge->getVertexRaw(i)->getDimensionUnfixed(); // block size
1112  }
1113  }
1114  return nnz;
1115 }
1116 
1119 {
1120  assert(i_row.size() == computeSparseJacobianInequalitiesNNZ());
1121  assert(j_col.size() == i_row.size());
1122 
1123  int nnz_idx = 0;
1124 
1125  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1126  {
1127  if (vertex->isFixed()) continue;
1128 
1129  int free_idx = 0;
1130  for (int i = 0; i < vertex->getDimension(); ++i)
1131  {
1132  if (vertex->isFixedComponent(i)) continue;
1133 
1134  computeInequalitiesJacobianStructureForVertex(vertex, vertex->getVertexIdx() + free_idx, i_row, j_col, nnz_idx);
1135 
1136  ++free_idx;
1137  }
1138  }
1139  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1140 }
1141 
1143 {
1144  assert(values.size() == computeSparseJacobianInequalitiesNNZ());
1145  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1146 
1147  // we need to set to zero everything first
1148  values.setZero();
1149 
1150  int nnz_idx = 0;
1151 
1152  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1153  {
1154  if (vertex->isFixed()) continue;
1155 
1156  int free_idx = 0;
1157  for (int i = 0; i < vertex->getDimension(); ++i)
1158  {
1159  if (vertex->isFixedComponent(i)) continue;
1160 
1161  vertex->plus(i, cd_delta);
1162 
1165  vertex->plus(i, cd_neg2delta);
1166 
1167  finalizeInequalitiesJacobianSparseValues(vertex, nnz_idx, values, multipliers);
1168 
1169  vertex->plus(i, cd_delta); // revert offset
1170  ++free_idx;
1171  }
1172  }
1173  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1174 }
1175 
1177 {
1178  assert(_graph.hasVertexSet() && _graph.hasEdgeSet());
1179  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1181 
1182  assert(jacobian.rows() == getInequalityDimension());
1183  assert(jacobian.cols() == getParameterDimension());
1184 
1185  // we need to set to zero everything first
1186  jacobian.setZero();
1187 
1188  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1189  {
1190  if (vertex->isFixed()) continue;
1191 
1192  int free_idx = 0;
1193  for (int i = 0; i < vertex->getDimension(); ++i)
1194  {
1195  if (vertex->isFixedComponent(i)) continue;
1196 
1197  computeInequalitiesValuesCached(vertex); // we also need the current values
1199  vertex->plus(i, cd_delta);
1200 
1202 
1203  vertex->plus(i, cd_neg2delta);
1204 
1205  finalizeActiveInequalitiesJacobian(vertex, vertex->getVertexIdx() + free_idx, jacobian, weight);
1206 
1207  vertex->plus(i, cd_delta); // revert offset
1208  ++free_idx;
1209  }
1210  }
1211  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1212 }
1214 {
1215  assert(values.size() == computeSparseJacobianInequalitiesNNZ());
1216  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1217 
1218  // we need to set to zero everything first
1219  values.setZero();
1220 
1221  int nnz_idx = 0;
1222 
1223  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1224  {
1225  if (vertex->isFixed()) continue;
1226 
1227  int free_idx = 0;
1228  for (int i = 0; i < vertex->getDimension(); ++i)
1229  {
1230  if (vertex->isFixedComponent(i)) continue;
1231 
1233 
1234  vertex->plus(i, cd_delta);
1237 
1238  vertex->plus(i, cd_neg2delta);
1239 
1240  finalizeActiveInequalitiesJacobianSparseValues(vertex, nnz_idx, values, weight);
1241 
1242  vertex->plus(i, cd_delta); // revert offset
1243  ++free_idx;
1244  }
1245  }
1246 
1247  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1248 }
1249 
1250 int HyperGraphOptimizationProblemVertexBased::computeCombinedSparseJacobiansNNZ(bool objective_lsq, bool equality, bool inequality)
1251 {
1252  int nnz = 0;
1253  if (objective_lsq) nnz += computeSparseJacobianLsqObjectiveNNZ();
1254  if (equality) nnz += computeSparseJacobianEqualitiesNNZ();
1255  if (inequality) nnz += computeSparseJacobianInequalitiesNNZ();
1256  return nnz;
1257 }
1259  Eigen::Ref<Eigen::VectorXi> j_col, bool objective_lsq,
1260  bool equality, bool inequality)
1261 {
1262  assert(i_row.size() == computeCombinedSparseJacobiansNNZ(objective_lsq, equality, inequality));
1263  assert(j_col.size() == i_row.size());
1264 
1265  int nnz_idx = 0;
1266 
1267  int eq_row_offset = objective_lsq ? getLsqObjectiveDimension() : 0;
1268  int ineq_row_offset = equality ? eq_row_offset + getEqualityDimension() : eq_row_offset;
1269 
1270  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1271  {
1272  if (vertex->isFixed()) continue;
1273 
1274  int free_idx = 0;
1275  for (int i = 0; i < vertex->getDimension(); ++i)
1276  {
1277  if (vertex->isFixedComponent(i)) continue;
1278 
1279  if (objective_lsq) computeLsqObjectiveJacobianStructureForVertex(vertex, vertex->getVertexIdx() + free_idx, i_row, j_col, nnz_idx, 0);
1280  if (equality)
1281  computeEqualitiesJacobianStructureForVertex(vertex, vertex->getVertexIdx() + free_idx, i_row, j_col, nnz_idx, eq_row_offset);
1282  if (inequality)
1283  computeInequalitiesJacobianStructureForVertex(vertex, vertex->getVertexIdx() + free_idx, i_row, j_col, nnz_idx, ineq_row_offset);
1284 
1285  ++free_idx;
1286  }
1287  }
1288 }
1290  bool equality, bool inequality, const double* multipliers_obj,
1291  const double* multipliers_eq, const double* multipliers_ineq)
1292 {
1293  assert(values.size() == computeCombinedSparseJacobiansNNZ(objective_lsq, equality, inequality));
1294  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1295 
1296  // we need to set to zero everything first
1297  values.setZero();
1298 
1299  int nnz_idx = 0;
1300 
1301  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1302  {
1303  if (vertex->isFixed()) continue;
1304 
1305  int free_idx = 0;
1306  for (int i = 0; i < vertex->getDimension(); ++i)
1307  {
1308  if (vertex->isFixedComponent(i)) continue;
1309 
1310  vertex->plus(i, cd_delta);
1312  precomputeConnectedMixedEdges(vertex, objective_lsq, equality, inequality);
1313 
1314  if (objective_lsq) computeLsqObjectiveValuesCached(vertex, true, true, false);
1315  if (equality) computeEqualitiesValuesCached(vertex, true, true, false);
1316  if (inequality) computeInequalitiesValuesCached(vertex, true, true, false);
1317 
1318  vertex->plus(i, cd_neg2delta);
1319 
1320  precomputeConnectedMixedEdges(vertex, objective_lsq, equality, inequality);
1321 
1322  if (objective_lsq) finalizeLsqObjectiveJacobianSparseValues(vertex, nnz_idx, values, multipliers_obj, false);
1323  if (equality) finalizeEqualitiesJacobianSparseValues(vertex, nnz_idx, values, multipliers_eq, false);
1324  if (inequality) finalizeInequalitiesJacobianSparseValues(vertex, nnz_idx, values, multipliers_ineq, false);
1325 
1326  vertex->plus(i, cd_delta); // revert offset
1327  ++free_idx;
1328  }
1329  }
1330 
1331  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1332 }
1333 
1335  bool inequality, bool finite_combined_bounds, bool active_ineq,
1336  double weight_eq, double weight_ineq, double weight_bounds,
1337  const Eigen::VectorXd* values, const Eigen::VectorXi* col_nnz)
1338 {
1339  PRINT_ERROR_NAMED("Not yet implemented for the vertex based strategy");
1340  OptimizationProblemInterface::computeCombinedSparseJacobian(jacobian, objective_lsq, equality, inequality, finite_combined_bounds, active_ineq,
1341  weight_eq, weight_ineq, weight_bounds, values, col_nnz);
1342 }
1343 
1345  Eigen::Ref<Eigen::VectorXd> jac_values,
1346  bool equality, bool inequality,
1347  const double* multipliers_eq,
1348  const double* multipliers_ineq)
1349 {
1350  assert(jac_values.size() == computeCombinedSparseJacobiansNNZ(false, equality, inequality));
1351  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1352 
1353  // we need to set to zero everything first
1354  gradient.setZero();
1355  jac_values.setZero();
1357  int nnz_idx = 0;
1358 
1359  for (VertexInterface* vertex : _graph.getVertexSet()->getActiveVertices())
1360  {
1361  if (vertex->isFixed()) continue;
1362 
1363  int free_idx = 0;
1364  for (int i = 0; i < vertex->getDimension(); ++i)
1365  {
1366  if (vertex->isFixedComponent(i)) continue;
1367 
1368  vertex->plus(i, cd_delta);
1369 
1370  precomputeConnectedMixedEdges(vertex, true, equality, inequality);
1371 
1372  computeObjectiveValuesCached(vertex, true);
1373  if (equality) computeEqualitiesValuesCached(vertex, true, true, false);
1374  if (inequality) computeInequalitiesValuesCached(vertex, true, true, false);
1375 
1376  vertex->plus(i, cd_neg2delta);
1377 
1378  precomputeConnectedMixedEdges(vertex, true, equality, inequality);
1379 
1380  finalizeObjectiveGradient(vertex, gradient(vertex->getVertexIdx() + free_idx), true, true, true, false);
1381  if (equality) finalizeEqualitiesJacobianSparseValues(vertex, nnz_idx, jac_values, multipliers_eq, false);
1382  if (inequality) finalizeInequalitiesJacobianSparseValues(vertex, nnz_idx, jac_values, multipliers_ineq, false);
1383 
1384  vertex->plus(i, cd_delta); // revert offset
1385  ++free_idx;
1386  }
1387  }
1388 
1389  assert(getGraph().getEdgeSet()->isEdgeCacheEmpty());
1390 }
1391 
1392 } // namespace corbo
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianInequalitiesValues
void computeSparseJacobianInequalitiesValues(Eigen::Ref< Eigen::VectorXd > values, const double *multipliers=nullptr) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1164
corbo::OptimizationProblemInterface::computeCombinedSparseJacobian
virtual void computeCombinedSparseJacobian(Eigen::SparseMatrix< double > &jacobian, bool objective_lsq, bool equality, bool inequality, bool finite_combined_bounds, bool active_ineq=false, double weight_eq=1.0, double weight_ineq=1.0, double weight_bounds=1.0, const Eigen::VectorXd *values=nullptr, const Eigen::VectorXi *col_nnz=nullptr)
Definition: optimization_problem_interface.cpp:724
corbo::BaseEdge
Definition: edge_interface.h:129
corbo::OptimizationEdgeSet::Ptr
std::shared_ptr< OptimizationEdgeSet > Ptr
Definition: edge_set.h:99
corbo::HyperGraphOptimizationProblemVertexBased::computeGradientNonLsqObjective
void computeGradientNonLsqObjective(Eigen::Ref< Eigen::VectorXd > gradient) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:793
Eigen::SparseMatrix< double >
PRINT_ERROR_NAMED
#define PRINT_ERROR_NAMED(msg)
Definition: console.h:260
corbo::HyperGraphOptimizationProblemVertexBased::finalizeLsqObjectiveJacobian
void finalizeLsqObjectiveJacobian(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::MatrixXd > &jacobian, const double *multipliers=nullptr, bool include_nonmixed=true, bool include_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:190
corbo::BaseHyperGraphOptimizationProblem::getGraph
const HyperGraph & getGraph() const
Definition: hyper_graph_optimization_problem_base.h:133
corbo::HyperGraphOptimizationProblemVertexBased::finalizeInequalitiesJacobian
void finalizeInequalitiesJacobian(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::MatrixXd > &jacobian, const double *multipliers=nullptr, bool include_nonmixed=true, bool include_mixed=true, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:499
corbo::HyperGraphOptimizationProblemVertexBased::finalizeActiveInequalitiesJacobian
void finalizeActiveInequalitiesJacobian(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::MatrixXd > &jacobian, double weight=1.0, bool include_nonmixed=true, bool include_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:550
corbo::cd_delta
static constexpr const double cd_delta
Definition: hyper_graph_optimization_problem_vertex_based.cpp:51
corbo::HyperGraphOptimizationProblemVertexBased::computeInequalitiesJacobianStructureForVertex
void computeInequalitiesJacobianStructureForVertex(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col, int &nnz_idx, int row_offset=0)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:616
corbo::HyperGraph::hasVertexSet
bool hasVertexSet() const
Definition: hyper_graph.h:115
corbo::HyperGraph::getVertexSet
VertexSetInterface::Ptr getVertexSet() const
Definition: hyper_graph.h:118
corbo
Definition: communication/include/corbo-communication/utilities.h:37
corbo::VertexInterface::getConnectedMixedEdgesRef
const std::set< BaseMixedEdge * > & getConnectedMixedEdgesRef() const
Raw access for connected mixed edges.
Definition: vertex_interface.h:181
corbo::HyperGraphOptimizationProblemVertexBased::computeCombinedSparseJacobiansStructure
void computeCombinedSparseJacobiansStructure(Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col, bool objective_lsq=true, bool equality=true, bool inequality=true) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1280
corbo::BaseHyperGraphOptimizationProblem::_graph
HyperGraph _graph
Definition: hyper_graph_optimization_problem_base.h:299
corbo::BaseHyperGraphOptimizationProblem::getEqualityDimension
int getEqualityDimension() override
Total dimension of equality constraints.
Definition: hyper_graph_optimization_problem_base.h:160
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianEqualitiesValues
void computeSparseJacobianEqualitiesValues(Eigen::Ref< Eigen::VectorXd > values, const double *multipliers=nullptr) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1039
corbo::HyperGraph::hasEdgeSet
bool hasEdgeSet() const
Definition: hyper_graph.h:114
Eigen::Array
General-purpose arrays with easy API for coefficient-wise operations.
Definition: Array.h:45
corbo::HyperGraphOptimizationProblemVertexBased::computeLsqObjectiveValuesCached
void computeLsqObjectiveValuesCached(const VertexInterface *vertex, bool include_nonmixed=true, bool include_mixed=true, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:166
corbo::BaseHyperGraphOptimizationProblem::getParameterDimension
int getParameterDimension() override
Effictive dimension of the optimization parameter set (changeable, non-fixed part)
Definition: hyper_graph_optimization_problem_base.h:232
corbo::HyperGraphOptimizationProblemVertexBased::computeEqualitiesValuesCached
void computeEqualitiesValuesCached(const VertexInterface *vertex, bool include_nonmixed=true, bool include_mixed=true, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:323
corbo::HyperGraphOptimizationProblemVertexBased::computeGradientObjectiveAndCombinedSparseJacobiansValues
void computeGradientObjectiveAndCombinedSparseJacobiansValues(Eigen::Ref< Eigen::VectorXd > gradient, Eigen::Ref< Eigen::VectorXd > jac_values, bool equality=true, bool inequality=true, const double *multipliers_eq=nullptr, const double *multipliers_ineq=nullptr) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1366
corbo::BaseHyperGraphOptimizationProblem::precomputeGraphQuantities
virtual void precomputeGraphQuantities()
Definition: hyper_graph_optimization_problem_base.cpp:79
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianInequalitiesStructure
void computeSparseJacobianInequalitiesStructure(Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1139
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianLsqObjectiveNNZ
int computeSparseJacobianLsqObjectiveNNZ() override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:861
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianActiveInequalitiesValues
void computeSparseJacobianActiveInequalitiesValues(Eigen::Ref< Eigen::VectorXd > values, double weight=1.0) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1235
corbo::VertexInterface
Generic interface class for vertices.
Definition: vertex_interface.h:75
corbo::HyperGraphOptimizationProblemVertexBased::computeDenseJacobianActiveInequalities
void computeDenseJacobianActiveInequalities(Eigen::Ref< Eigen::MatrixXd > jacobian, double weight=1.0) override
Compute the Jacobian Jc(x) with non-zeros for active constraints c(x)>= 0 and zeros for inactive ones...
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1198
corbo::HyperGraphOptimizationProblemVertexBased::finalizeActiveInequalitiesJacobianSparseValues
void finalizeActiveInequalitiesJacobianSparseValues(const VertexInterface *vertex, int &nnz_idx, Eigen::Ref< Eigen::VectorXd > &values, double weight=1.0)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:697
corbo::HyperGraphOptimizationProblemVertexBased::computeObjectiveValuesCached
void computeObjectiveValuesCached(const VertexInterface *vertex, bool include_lsq_edges, bool include_nonmixed=true, bool include_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:86
corbo::HyperGraphOptimizationProblemVertexBased::finalizeEqualitiesJacobianSparseValues
void finalizeEqualitiesJacobianSparseValues(const VertexInterface *vertex, int &nnz_idx, Eigen::Ref< Eigen::VectorXd > &values, const double *multipliers=nullptr, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:429
corbo::HyperGraphOptimizationProblemVertexBased::finalizeInequalitiesJacobianSparseValues
void finalizeInequalitiesJacobianSparseValues(const VertexInterface *vertex, int &nnz_idx, Eigen::Ref< Eigen::VectorXd > &values, const double *multipliers=nullptr, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:648
corbo::BaseMixedEdge::Ptr
std::shared_ptr< BaseMixedEdge > Ptr
Definition: edge_interface.h:244
corbo::HyperGraphOptimizationProblemVertexBased::finalizeLsqObjectiveJacobianSparseValues
void finalizeLsqObjectiveJacobianSparseValues(const VertexInterface *vertex, int &nnz_idx, Eigen::Ref< Eigen::VectorXd > &values, const double *multipliers=nullptr, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:275
corbo::BaseMixedEdge
Definition: edge_interface.h:239
corbo::HyperGraph::getEdgeSet
OptimizationEdgeSet::Ptr getEdgeSet() const
Definition: hyper_graph.h:117
corbo::VertexInterface::getConnectedEqualityEdgesRef
const std::set< BaseEdge * > & getConnectedEqualityEdgesRef() const
Raw access for connected equality constraint edges.
Definition: vertex_interface.h:177
corbo::BaseHyperGraphOptimizationProblem::getInequalityDimension
int getInequalityDimension() override
Total dimension of general inequality constraints.
Definition: hyper_graph_optimization_problem_base.h:166
corbo::BaseHyperGraphOptimizationProblem::_dim_eq
int _dim_eq
Definition: hyper_graph_optimization_problem_base.h:305
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianLsqObjectiveStructure
void computeSparseJacobianLsqObjectiveStructure(Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:891
corbo::BaseHyperGraphOptimizationProblem::getLsqObjectiveDimension
int getLsqObjectiveDimension() override
Total dimension of least-squares objective function terms.
Definition: hyper_graph_optimization_problem_base.h:149
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianEqualitiesStructure
void computeSparseJacobianEqualitiesStructure(Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1015
corbo::HyperGraphOptimizationProblemVertexBased::computeGradientObjective
void computeGradientObjective(Eigen::Ref< Eigen::VectorXd > gradient) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:759
corbo::HyperGraphOptimizationProblemVertexBased::computeCombinedSparseJacobian
void computeCombinedSparseJacobian(Eigen::SparseMatrix< double > &jacobian, bool objective_lsq, bool equality, bool inequality, bool finite_combined_bounds, bool active_ineq=false, double weight_eq=1.0, double weight_ineq=1.0, double weight_bounds=1.0, const Eigen::VectorXd *values=nullptr, const Eigen::VectorXi *col_nnz=nullptr) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1356
corbo::BaseEdge::Ptr
std::shared_ptr< BaseEdge > Ptr
Definition: edge_interface.h:134
corbo::HyperGraphOptimizationProblemVertexBased::precomputeConnectedMixedEdges
void precomputeConnectedMixedEdges(const VertexInterface *vertex, bool objective=true, bool equality=true, bool inequality=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:72
corbo::HyperGraphOptimizationProblemVertexBased::computeDenseJacobianInequalities
void computeDenseJacobianInequalities(Eigen::Ref< Eigen::MatrixXd > jacobian, const double *multipliers=nullptr) override
Compute the inequality constraint Jacobian Jc(x) for the current parameter set.
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1073
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianEqualitiesNNZ
int computeSparseJacobianEqualitiesNNZ() override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:985
corbo::HyperGraphOptimizationProblemVertexBased::finalizeEqualitiesJacobian
void finalizeEqualitiesJacobian(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::MatrixXd > &jacobian, const double *multipliers=nullptr, bool include_nonmixed=true, bool include_mixed=true, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:346
corbo::HyperGraphOptimizationProblemVertexBased::finalizeObjectiveGradient
void finalizeObjectiveGradient(const VertexInterface *vertex, double &gradient_coeff, bool include_lsq_edges, bool include_nonmixed=true, bool include_mixed=true, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:120
corbo::HyperGraphOptimizationProblemVertexBased::computeDenseJacobianEqualities
void computeDenseJacobianEqualities(Eigen::Ref< Eigen::MatrixXd > jacobian, const double *multipliers=nullptr) override
Compute the equality constraint Jacobian Jceq(x) for the current parameter set.
Definition: hyper_graph_optimization_problem_vertex_based.cpp:949
corbo::cd_scalar
static constexpr const double cd_scalar
Definition: hyper_graph_optimization_problem_vertex_based.cpp:53
Eigen::Map
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:94
corbo::BaseHyperGraphOptimizationProblem::_dim_lsq_obj
int _dim_lsq_obj
Definition: hyper_graph_optimization_problem_base.h:304
corbo::HyperGraphOptimizationProblemVertexBased::precomputeEdgeQuantities
void precomputeEdgeQuantities() override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:55
corbo::VertexInterface::getConnectedInequalityEdgesRef
const std::set< BaseEdge * > & getConnectedInequalityEdgesRef() const
Raw access for connected inequality constraint edges.
Definition: vertex_interface.h:179
corbo::cd_neg2delta
static constexpr const double cd_neg2delta
Definition: hyper_graph_optimization_problem_vertex_based.cpp:52
Eigen::Ref
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:192
corbo::HyperGraphOptimizationProblemVertexBased::computeDenseJacobianLsqObjective
void computeDenseJacobianLsqObjective(Eigen::Ref< Eigen::MatrixXd > jacobian, const double *multipliers=nullptr) override
Compute the objective Jacobian Jf(x) for the current parameter set.
Definition: hyper_graph_optimization_problem_vertex_based.cpp:825
corbo::BaseHyperGraphOptimizationProblem::_dim_non_lsq_obj
int _dim_non_lsq_obj
Definition: hyper_graph_optimization_problem_base.h:303
corbo::VertexInterface::getConnectedLsqObjectiveEdgesRef
const std::set< BaseEdge * > & getConnectedLsqObjectiveEdgesRef() const
Raw access for connected least-squares objective edges.
Definition: vertex_interface.h:175
corbo::BaseHyperGraphOptimizationProblem::_dim_ineq
int _dim_ineq
Definition: hyper_graph_optimization_problem_base.h:306
corbo::HyperGraphOptimizationProblemVertexBased::computeEqualitiesJacobianStructureForVertex
void computeEqualitiesJacobianStructureForVertex(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col, int &nnz_idx, int row_offset=0)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:397
corbo::HyperGraphOptimizationProblemVertexBased::computeCombinedSparseJacobiansValues
void computeCombinedSparseJacobiansValues(Eigen::Ref< Eigen::VectorXd > values, bool objective_lsq=true, bool equality=true, bool inequality=true, const double *multipliers_obj=nullptr, const double *multipliers_eq=nullptr, const double *multipliers_ineq=nullptr) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1311
corbo::HyperGraphOptimizationProblemVertexBased::computeInequalitiesValuesCached
void computeInequalitiesValuesCached(const VertexInterface *vertex, bool include_nonmixed=true, bool include_mixed=true, bool precompute_mixed=true)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:476
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianInequalitiesNNZ
int computeSparseJacobianInequalitiesNNZ() override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1109
corbo::EdgeCache::Previous
@ Previous
Definition: edge_cache.h:109
corbo::BaseHyperGraphOptimizationProblem::_graph_precomputed
bool _graph_precomputed
Definition: hyper_graph_optimization_problem_base.h:300
hyper_graph_optimization_problem_vertex_based.h
corbo::HyperGraphOptimizationProblemVertexBased::computeLsqObjectiveJacobianStructureForVertex
void computeLsqObjectiveJacobianStructureForVertex(const VertexInterface *vertex, int vtx_idx, Eigen::Ref< Eigen::VectorXi > i_row, Eigen::Ref< Eigen::VectorXi > j_col, int &nnz_idx, int row_offset=0)
Definition: hyper_graph_optimization_problem_vertex_based.cpp:242
corbo::HyperGraphOptimizationProblemVertexBased::computeCombinedSparseJacobiansNNZ
int computeCombinedSparseJacobiansNNZ(bool objective_lsq=true, bool equality=true, bool inequality=true) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:1272
corbo::HyperGraphOptimizationProblemVertexBased::computeSparseJacobianLsqObjectiveValues
void computeSparseJacobianLsqObjectiveValues(Eigen::Ref< Eigen::VectorXd > values, const double *multipliers) override
Definition: hyper_graph_optimization_problem_vertex_based.cpp:915


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Wed Mar 2 2022 00:05:48