Ocean
NonLinearUniversalOptimizationSparse.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_GEOMETRY_NON_LINEAR_UNIVERSAL_OPTIMIZATION_SPARSE_H
9 #define META_OCEAN_GEOMETRY_NON_LINEAR_UNIVERSAL_OPTIMIZATION_SPARSE_H
10 
13 
14 namespace Ocean
15 {
16 
17 namespace Geometry
18 {
19 
20 /**
21  * This class implements optimizations for universal sparse problems.
22  * @ingroup geometry
23  */
25 {
26  public:
27 
28  /**
29  * This class implements an optimization for universal sparse problems with one shared model (optimization problem) and concurrently several individual models (optimization problems).
30  * The implementation allows to optimize arbitrary (universal) problems with arbitrary dimensions.
31  * @tparam tSharedModelSize Size of the shared model, the number of model parameters
32  * @tparam tIndividualModelSize Size of the individual model, the number of model parameters
33  * @tparam tResultDimension Number of dimensions that result for each element (measurement) after the model has been applied
34  * @tparam tExternalSharedModelSize Size of the external shared model, the number of model parameters
35  * @tparam tExternalIndividualModelSize Size of the external individual model, the number of model parameters
36  */
37  template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize = tSharedModelSize, unsigned int tExternalIndividualModelSize = tIndividualModelSize>
39  {
40  public:
41 
42  /**
43  * Definition of a shared model.
44  */
46 
47  /**
48  * Definition of an external shared model.
49  */
51 
52  /**
53  * Definition of an individual model.
54  */
56 
57  /**
58  * Definition of an external individual model.
59  */
61 
62  /**
63  * Definition of a model result.
64  */
66 
67  /**
68  * Definition of a vector holding individual models.
69  */
70  typedef std::vector<IndividualModel> IndividualModels;
71 
72  /**
73  * Definition of a callback function for sparse value calculation.
74  * The first parameter provides the shared model that is applied to determine the value.<br>
75  * The second parameter provides the individual model that is applied to determine the value.<br>
76  * The third parameter provides the index of the individual models that is used to determine the value.<br>
77  * The fourth parameter provides the element index for the individual model.<br>
78  * The fifth parameter receives the determined value.
79  */
81 
82  /**
83  * Definition of a callback function for sparse error calculation.
84  * The first parameter provides the shared model that is applied to determine the value.<br>
85  * The second parameter provides the individual model that is applied to determine the value.<br>
86  * The third parameter provides the index of the individual models that is used to determine the error.<br>
87  * The fourth parameter provides the element index for the individual model.<br>
88  * The fifth parameter receives the determined error.<br>
89  * The return value provides True if both models provide valid information for the measurement element.<br>
90  */
92 
93  /**
94  * Definition of a callback function determining whether a shared model is valid.
95  * The first parameter provides the external shared model for which the decision has to be done
96  * True, if the shared model is valid.<br>
97  */
99 
100  /**
101  * Definition of a shared model transformation function.
102  * The transformation function allows to use an external model function for value and error determination while the internal model is used for the internal optimization.<br>
103  * The first parameter provides the internal shared model.<br>
104  * The second parameter receives the external shared model.<br>
105  */
107 
108  /**
109  * Definition of an individual model transformation function.
110  * The transformation function allows to use an external model function for value and error determination while the internal model is used for the internal optimization.<br>
111  * The first parameter provides the internal shared model.<br>
112  * The second parameter receives the external shared model.<br>
113  */
115 
116  /**
117  * Definition of a model accepted function.
118  * The first parameter provides the internal shared model that has been accepted as improved model.
119  * The second parameter provides the internal individual models that have been accepted as improved model.
120  */
122 
123  protected:
124 
125  /**
126  * Definition of a vector holding individual models.
127  */
128  typedef std::vector<ExternalIndividualModel> ExternalIndividualModels;
129 
130  /**
131  * This class implements a sparse universal optimization provider for universal models and measurement/data values.
132  */
134  {
135  public:
136 
137  /**
138  * Creates a new universal optimization object.
139  * @param sharedModel Shared model to be optimized
140  * @param individualModels Individual models to be optimized
141  * @param numberElementsPerIndividualModel Number of elements (measurements) that are used to determine the optimized model
142  * @param valueCallback Callback function that is used to determine the value for an individual element (measurement) by application of the model
143  * @param errorCallback Callback function that is used to determine the error for an individual element (measurement)
144  * @param sharedModelIsValidCallback Optional callback function that allows to decide whether a shared model is valid
145  * @param sharedModelTransformationCallback Callback function allowing to transform the internal shared model into an extern shared model
146  * @param individualModelTransformationCallback Callback function allowing to transform the internal individual model into an external individual model
147  * @param modelAcceptedCallback Optional callback function that allows to be informed whenever the internal models has been improved
148  */
149  inline UniversalOptimizationProvider(SharedModel& sharedModel, IndividualModels& individualModels, const size_t* numberElementsPerIndividualModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const IndividualModelTransformationCallback& individualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback = ModelAcceptedCallback());
150 
151  /**
152  * Determines the jacobian matrix for the current model.
153  * @param jacobian Jacobian matrix
154  */
155  void determineJacobian(SparseMatrix& jacobian) const;
156 
157  /**
158  * Applies the model correction and stores the new model(s) as candidate.
159  * @param deltas Optimization deltas that define the correction
160  */
161  inline void applyCorrection(const Matrix& deltas);
162 
163  /**
164  * Determines the robust error of the current candidate model(s).
165  * @param weightedErrorVector Resulting (weighted - if using a robust estimator) error vector
166  * @param weightVector Vector holding the weights that have already been applied to the error vector
167  * @param invertedCovariances Optional 2x2 inverted covariance matrices
168  * @return The resulting robust error
169  * @tparam tEstimator The type of the estimator that is applied for error determination
170  */
171  template <Estimator::EstimatorType tEstimator>
172  Scalar determineRobustError(Matrix& weightedErrorVector, Matrix& weightVector, const Matrix* invertedCovariances) const;
173 
174  /**
175  * Accepts the current model candidate as better model.
176  */
177  inline void acceptCorrection();
178 
179  protected:
180 
181  /// Universal shared model that will be optimized.
183 
184  /// Universal individual model that will be optimized.
186 
187  /// Universal shared model that stores the most recent optimization result as candidate.
189 
190  /// Universal individual model that stores the most recent optimization result as candidate.
192 
193  /// The number of measurement elements that are used to optimize each individual model.
194  const size_t* numberElementsPerIndividualModel_ = nullptr;
195 
196  /// The overall number of measurement elements that are used to optimize the models.
198 
199  /// The value calculation callback function.
201 
202  /// The error calculation callback function.
204 
205  /// The callback function determining whether a shared model is valid.
207 
208  /// The callback function allowing to transform the shared model into an external model before the value and error callback functions are invoked.
210 
211  /// The callback function allowing to transform the individual model into an external model before the value and error callback functions are invoked.
213 
214  /// Optional callback function allowing to be informed whenever the model has been improved.
216  };
217 
218  public:
219 
220  /**
221  * Optimizes a universal model by minimizing the error the model produces.
222  * @param sharedModel Shared model that will be optimized
223  * @param individualModels Individual models that will be optimized
224  * @param numberElementsPerIndividualModel The numbers of measurement elements individually for each individual model
225  * @param valueCallback Callback function that is used to determine the value for an individual element (measurement) by application of the model
226  * @param errorCallback Callback function that is used to determine the error for an individual element (measurement)
227  * @param sharedModelIsValidCallback Optional callback function that allows to decide whether a shared model is valid
228  * @param sharedModelTransformationCallback Callback function allowing to transform the internal shared model into an extern model if intended
229  * @param individualModelTransformationCallback Callback function allowing to transform the internal individual model into an extern model if intended
230  * @param modelAcceptedCallback Optional callback function that allows to be informed whenever the internal models has been improved
231  * @param optimizedSharedModel Resulting optimized shared model
232  * @param optimizedIndividualModels Resulting optimized individual models
233  * @param iterations Number of iterations to be applied at most, if no convergence can be reached
234  * @param estimator Robust error estimator to be used
235  * @param lambda Initial Levenberg-Marquardt damping value which may be changed after each iteration using the damping factor, with range [0, infinity)
236  * @param lambdaFactor Levenberg-Marquardt damping factor to be applied to the damping value, with range [1, infinity)
237  * @param initialError Optional resulting averaged pixel error for the given initial parameters, in relation to the defined estimator
238  * @param finalError Optional resulting averaged error for the final optimized parameters, in relation to the defined estimator
239  * @param intermediateErrors Optional resulting intermediate (improving) errors
240  * @return True, if the model could be optimized
241  */
242  static bool optimizeUniversalModel(const SharedModel& sharedModel, const IndividualModels& individualModels, const size_t* numberElementsPerIndividualModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const IndividualModelTransformationCallback& individualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback, SharedModel& optimizedSharedModel, IndividualModels& optimizedIndividualModels, const unsigned int iterations = 5u, const Estimator::EstimatorType estimator = Estimator::ET_SQUARE, Scalar lambda = Scalar(0.001), const Scalar lambdaFactor = Scalar(5), Scalar* initialError = nullptr, Scalar* finalError = nullptr, Scalars* intermediateErrors = nullptr);
243  };
244 
245  /**
246  * This class implements an optimization for universal sparse problems with two types of individual models (optimization problems).
247  * The implementation allows to optimize arbitrary (universal) problems with arbitrary dimensions.<br>
248  * @tparam tFirstModelSize Size of the first model, the number of model parameters
249  * @tparam tSecondModelSize Size of the second model, the number of model parameters
250  * @tparam tResultDimension Number of dimensions that result for each element (measurement) after the model has been applied
251  * @tparam tExternalFirstModelSize Size of the external first model, the number of model parameters
252  * @tparam tExternalSecondModelSize Size of the external second model, the number of model parameters
253  */
254  template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize = tFirstModelSize, unsigned int tExternalSecondModelSize = tSecondModelSize>
256  {
257  public:
258 
259  /**
260  * Definition of the first model.
261  */
263 
264  /**
265  * Definition of the external first model.
266  */
268 
269  /**
270  * Definition of the second model.
271  */
273 
274  /**
275  * Definition of the external second model.
276  */
278 
279  /**
280  * Definition of a model result.
281  */
283 
284  /**
285  * Definition of a vector holding the first models.
286  */
287  typedef std::vector<FirstModel> FirstModels;
288 
289  /**
290  * Definition of a vector holding the external first models.
291  */
292  typedef std::vector<ExternalFirstModel> ExternalFirstModels;
293 
294  /**
295  * Definition of a vector holding the first models.
296  */
297  typedef std::vector<SecondModel> SecondModels;
298 
299  /**
300  * Definition of a vector holding the external second models.
301  */
302  typedef std::vector<ExternalSecondModel> ExternalSecondModels;
303 
304  /**
305  * Definition of a callback function for sparse value calculation.
306  * The first parameter provides the external first models that can be used to determine the value.<br>
307  * The second parameter provides the external second models that can be used to determined the value.<br>
308  * The third parameter provides the index of the second model for which the value needs to be determined.<br>
309  * The fourth parameter provides the element index for the second model for which the value needs to be determined.<br>
310  * The fifth parameter receives the determined value.<br>
311  * The return value provides the index of the corresponding first model.<br>
312  */
314 
315  /**
316  * Definition of a callback function for sparse error calculation.
317  * The first parameter provides the external first models that can be used to determine the error.<br>
318  * The second parameter provides the external second models that can be used to determined the error.<br>
319  * The third parameter provides the index of the second model for which the error needs to be determined.<br>
320  * The fourth parameter provides the element index for the second model for which the error needs to be determined.<br>
321  * The fifth parameter receives the determined error.<br>
322  */
324 
325  /**
326  * Definition of a first model transformation function.
327  * The transformation function allows to use an external model for value and error determination while the internal model is used for the internal optimization.<br>
328  * The first parameter provides the internal first model.<br>
329  * The second parameter receives the external first model.<br>
330  */
332 
333  /**
334  * Definition of a second model transformation function.
335  * The transformation function allows to use an external model for value and error determination while the internal model is used for the internal optimization.<br>
336  * The first parameter provides the internal second model.<br>
337  * The second parameter receives the external second model.<br>
338  */
340 
341  /**
342  * Definition of a model accepted function.
343  * The first parameter provides the internal first models that have been accepted as improved models.
344  * The second parameter provides the internal second models that have been accepted as improved model.
345  */
347 
348  protected:
349 
350  /**
351  * This class implements a sparse universal optimization provider for universal models and measurement/data values.
352  */
354  {
355  public:
356 
357  /**
358  * Creates a new universal optimization object.
359  * @param firstModels The first models to be optimized
360  * @param secondModels The second models to be optimized
361  * @param numberElementsPerSecondModel Number of elements (measurements) per second model that are used to determine the optimized models, one number for each second model, with range [1, infinity)
362  * @param valueCallback Callback function that is used to determine the value for an individual element (measurement) by application of the models
363  * @param errorCallback Callback function that is used to determine the error for an individual element (measurement)
364  * @param firstModelTransformationCallback Callback function allowing to transform the internal first model into an extern first model
365  * @param secondModelTransformationCallback Callback function allowing to transform the internal second model into an external second model
366  * @param modelAcceptedCallback Optional callback function that allows to be informed whenever the internal models has been improved
367  */
368  inline UniversalOptimizationProvider(FirstModels& firstModels, SecondModels& secondModels, const size_t* numberElementsPerSecondModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const FirstModelTransformationCallback& firstModelTransformationCallback, const SecondModelTransformationCallback& secondModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback = ModelAcceptedCallback());
369 
370  /**
371  * Returns that this provider comes with an own equation solver.
372  * @return True, as this provider has an own solver
373  */
374  inline bool hasSolver() const;
375 
376  /**
377  * Solves the equation JTJ * deltas = jErrors
378  * @param JTJ The JTJ matrix
379  * @param jErrors The jErrors vector
380  * @param deltas The deltas vector
381  * @return True, if succeeded
382  */
383  inline bool solve(const SparseMatrix& JTJ, const Matrix& jErrors, Matrix& deltas) const;
384 
385  /**
386  * Determines the jacobian matrix for the current model.
387  * @param jacobian Jacobian matrix
388  */
389  void determineJacobian(SparseMatrix& jacobian) const;
390 
391  /**
392  * Applies the model correction and stores the new model(s) as candidate.
393  * @param deltas Optimization deltas that define the correction
394  */
395  inline void applyCorrection(const Matrix& deltas);
396 
397  /**
398  * Determines the robust error of the current candidate model(s).
399  * @param weightedErrorVector Resulting (weighted - if using a robust estimator) error vector
400  * @param weightVector Vector holding the weights that have already been applied to the error vector
401  * @param invertedCovariances Optional 2x2 inverted covariance matrices
402  * @return The resulting robust error
403  * @tparam tEstimator The type of the estimator that is applied for error determination
404  */
405  template <Estimator::EstimatorType tEstimator>
406  Scalar determineRobustError(Matrix& weightedErrorVector, Matrix& weightVector, const Matrix* invertedCovariances) const;
407 
408  /**
409  * Accepts the current model candidate as better model.
410  */
411  inline void acceptCorrection();
412 
413  protected:
414 
415  /// The universal first models that will be optimized.
417 
418  /// The universal second models that will be optimized.
420 
421  /// The universal first models storing the most recent optimization results as candidates.
423 
424  /// The universal second models storing the most recent optimization results as candidates.
426 
427  /// The number of measurement elements for each second model.
428  const size_t* numberElementsPerSecondModel_ = nullptr;
429 
430  /// The overall number of measurement elements that are used to optimize the models.
432 
433  /// The value calculation callback function.
435 
436  /// The error calculation callback function.
438 
439  /// The callback function allowing to transform the first model into an external model before the value and error callback functions are invoked.
441 
442  /// The callback function allowing to transform the second model into an external model before the value and error callback functions are invoked.
444 
445  /// Optional callback function allowing to be informed whenever the model has been improved.
447  };
448 
449  public:
450 
451  /**
452  * Optimizes a universal model by minimizing the error the model produces.
453  * @param firstModels The first models that will be optimized
454  * @param secondModels The second models that will be optimized
455  * @param numberElementsPerSecondModel Number of elements (measurements) per second model that are used to determine the optimized models, one number for each second model, with range [1, infinity)
456  * @param valueCallback Callback function that is used to determine the value for an individual element (measurement) by application of the model(s)
457  * @param errorCallback Callback function that is used to determine the error for an individual element (measurement)
458  * @param firstModelTransformationCallback Callback function allowing to transform the internal first model into an extern model if intended
459  * @param secondModelTransformationCallback Callback function allowing to transform the internal second model into an extern model if intended
460  * @param modelAcceptedCallback Optional callback function that allows to be informed whenever the internal models has been improved
461  * @param optimizedFirstModels Resulting optimized first models
462  * @param optimizedSecondModels Resulting optimized second models
463  * @param iterations Number of iterations to be applied at most, if no convergence can be reached
464  * @param estimator Robust error estimator to be used
465  * @param lambda Initial Levenberg-Marquardt damping value which may be changed after each iteration using the damping factor, with range [0, infinity)
466  * @param lambdaFactor Levenberg-Marquardt damping factor to be applied to the damping value, with range [1, infinity)
467  * @param initialError Optional resulting averaged pixel error for the given initial parameters, in relation to the defined estimator
468  * @param finalError Optional resulting averaged error for the final optimized parameters, in relation to the defined estimator
469  * @param intermediateErrors Optional resulting intermediate (improving) errors
470  * @return True, if the model could be optimized
471  */
472  static bool optimizeUniversalModel(const FirstModels& firstModels, const SecondModels& secondModels, const size_t* numberElementsPerSecondModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const FirstModelTransformationCallback& firstModelTransformationCallback, const SecondModelTransformationCallback& secondModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback, FirstModels& optimizedFirstModels, SecondModels& optimizedSecondModels, const unsigned int iterations = 5u, const Estimator::EstimatorType estimator = Estimator::ET_SQUARE, Scalar lambda = Scalar(0.001), const Scalar lambdaFactor = Scalar(5), Scalar* initialError = nullptr, Scalar* finalError = nullptr, Scalars* intermediateErrors = nullptr);
473  };
474 
475  /**
476  * This class implements an optimization for universal sparse problems with one common shared model (optimization problem) and two types of individual models (optimization problems).
477  * The implementation allows to optimize arbitrary (universal) problems with arbitrary dimensions.<br>
478  * @tparam tSharedModelSize Size of the shared model, the number of model parameters
479  * @tparam tFirstIndividualModelSize Size of the first individual model, the number of model parameters
480  * @tparam tSecondIndividualModelSize Size of the second individual model, the number of model parameters
481  * @tparam tResultDimension Number of dimensions that result for each element (measurement) after the model has been applied
482  * @tparam tExternalSharedModelSize Size of the external shared model, the number of model parameters
483  * @tparam tExternalFirstIndividualModelSize Size of the external first individual model, the number of model parameters
484  * @tparam tExternalSecondIndividualModelSize Size of the external second individual model, the number of model parameters
485  */
486  template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize = tSharedModelSize, unsigned int tExternalFirstIndividualModelSize = tFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize = tSecondIndividualModelSize>
488  {
489  public:
490 
491  /**
492  * Definition of the shared model.
493  */
495 
496  /**
497  * Definition of the external shared model.
498  */
500 
501  /**
502  * Definition of the first individual model.
503  */
505 
506  /**
507  * Definition of the external first individual model.
508  */
510 
511  /**
512  * Definition of the second individual model.
513  */
515 
516  /**
517  * Definition of the external second individual model.
518  */
520 
521  /**
522  * Definition of a model result.
523  */
525 
526  /**
527  * Definition of a vector holding the first individual models.
528  */
529  typedef std::vector<FirstIndividualModel> FirstIndividualModels;
530 
531  /**
532  * Definition of a vector holding the external first individual models.
533  */
534  typedef std::vector<ExternalFirstIndividualModel> ExternalFirstIndividualModels;
535 
536  /**
537  * Definition of a vector holding the first individual models.
538  */
539  typedef std::vector<SecondIndividualModel> SecondIndividualModels;
540 
541  /**
542  * Definition of a vector holding the external second individual models.
543  */
544  typedef std::vector<ExternalSecondIndividualModel> ExternalSecondIndividualModels;
545 
546  /**
547  * Definition of a callback function for sparse value calculation.
548  * The first parameter provides the external shared model that will be used to determined the value.<br>
549  * The second parameter provides the external first individual models that can be used to determine the value.<br>
550  * The third parameter provides the external second individual models that can be used to determined the value.<br>
551  * The fourth parameter provides the index of the second model for which the value needs to be determined.<br>
552  * The fifth parameter provides the element index for the second model for which the value needs to be determined.<br>
553  * The sixth parameter receives the determined value.<br>
554  * The return value provides the index of the corresponding first model.<br>
555  */
557 
558  /**
559  * Definition of a callback function for sparse error calculation.
560  * The first parameter provides the external shared model that will be used to determined the error.<br>
561  * The second parameter provides the external first individual models that can be used to determine the error.<br>
562  * The third parameter provides the external second individual models that can be used to determined the error.<br>
563  * The fourth parameter provides the index of the second model for which the error needs to be determined.<br>
564  * The fifth parameter provides the element index for the second model for which the error needs to be determined.<br>
565  * The sixth parameter receives the determined error.<br>
566  */
568 
569  /**
570  * Definition of a callback function determining whether a shared model is valid.
571  * The first parameter provides the external shared model for which the decision has to be done
572  * True, if the shared model is valid.<br>
573  */
575 
576  /**
577  * Definition of a transformation function for the shared model.
578  * The transformation function allows to use an external model for value and error determination while the internal model is used for the internal optimization.<br>
579  * The first parameter provides the internal shared model.<br>
580  * The second parameter receives the external shared model.<br>
581  */
583 
584  /**
585  * Definition of a transformation function for the first individual models.
586  * The transformation function allows to use an external model for value and error determination while the internal model is used for the internal optimization.<br>
587  * The first parameter provides the internal first individual model.<br>
588  * The second parameter receives the external first individual model.<br>
589  */
591 
592  /**
593  * Definition of a transformation function for the second individual models.
594  * The transformation function allows to use an external model for value and error determination while the internal model is used for the internal optimization.<br>
595  * The first parameter provides the internal second individual model.<br>
596  * The second parameter receives the external second individual model.<br>
597  */
599 
600  /**
601  * Definition of a model accepted function.
602  * The first parameter provides the internal shared model that have been accepted as improved model.
603  * The second parameter provides the internal first individual models that have been accepted as improved models.
604  * The third parameter provides the internal second individual models that have been accepted as improved model.
605  */
607 
608  protected:
609 
610  /**
611  * This class implements a sparse universal optimization provider for universal models and measurement/data values.
612  */
614  {
615  public:
616 
617  /**
618  * Creates a new universal optimization object.
619  * @param sharedModel The shared model to be optimized
620  * @param firstIndividualModels The first individual models to be optimized
621  * @param secondIndividualModels The second individual models to be optimized
622  * @param numberElementsPerSecondModel Number of elements (measurements) per second model that are used to determine the optimized models, one number for each second model, with range [1, infinity)
623  * @param valueCallback Callback function that is used to determine the value for an individual element (measurement) by application of the models
624  * @param errorCallback Callback function that is used to determine the error for an individual element (measurement)
625  * @param sharedModelIsValidCallback Optional callback function that allows to decide whether a shared model is valid
626  * @param sharedModelTransformationCallback Callback function allowing to transform the internal shared model into an external shared model
627  * @param firstIndividualModelTransformationCallback Callback function allowing to transform the internal first model into an extern first model
628  * @param secondIndividualModelTransformationCallback Callback function allowing to transform the internal second model into an external second model
629  * @param modelAcceptedCallback Optional callback function that allows to be informed whenever the internal models has been improved
630  */
631  inline UniversalOptimizationProvider(SharedModel& sharedModel, FirstIndividualModels& firstIndividualModels, SecondIndividualModels& secondIndividualModels, const size_t* numberElementsPerSecondModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const FirstIndividualModelTransformationCallback& firstIndividualModelTransformationCallback, const SecondIndividualModelTransformationCallback& secondIndividualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback = ModelAcceptedCallback());
632 
633  /**
634  * Determines the jacobian matrix for the current model.
635  * @param jacobian Jacobian matrix
636  */
637  void determineJacobian(SparseMatrix& jacobian) const;
638 
639  /**
640  * Applies the model correction and stores the new model(s) as candidate.
641  * @param deltas Optimization deltas that define the correction
642  */
643  inline void applyCorrection(const Matrix& deltas);
644 
645  /**
646  * Determines the robust error of the current candidate model(s).
647  * @param weightedErrorVector Resulting (weighted - if using a robust estimator) error vector
648  * @param weightVector Vector holding the weights that have already been applied to the error vector
649  * @param invertedCovariances Optional 2x2 inverted covariance matrices
650  * @return The resulting robust error
651  * @tparam tEstimator The type of the estimator that is applied for error determination
652  */
653  template <Estimator::EstimatorType tEstimator>
654  Scalar determineRobustError(Matrix& weightedErrorVector, Matrix& weightVector, const Matrix* invertedCovariances) const;
655 
656  /**
657  * Accepts the current model candidate as better model.
658  */
659  inline void acceptCorrection();
660 
661  protected:
662 
663  /// The universal shared model that will be optimized.
665 
666  /// The universal first individual models that will be optimized.
668 
669  /// The universal second individual models that will be optimized.
671 
672  /// The universal shared model storing the most recent optimization result as candidate.
674 
675  /// The universal first individual models storing the most recent optimization results as candidates.
677 
678  /// The universal second individual models storing the most recent optimization results as candidates.
680 
681  /// The number of measurement elements for each second model.
682  const size_t* numberElementsPerSecondModel_ = nullptr;
683 
684  /// The overall number of measurement elements that are used to optimize the models.
686 
687  /// The value calculation callback function.
689 
690  /// The error calculation callback function.
692 
693  /// The callback function determining whether a shared model is valid.
695 
696  /// The callback function allowing to transform the shared model into an external model before the value and error callback functions are invoked.
698 
699  /// The callback function allowing to transform the first individual model into an external model before the value and error callback functions are invoked.
701 
702  /// The callback function allowing to transform the second model into an external model before the value and error callback functions are invoked.
704 
705  /// Optional callback function allowing to be informed whenever the model has been improved.
707  };
708 
709  public:
710 
711  /**
712  * Optimizes a universal model by minimizing the error the model produces.
713  * @param sharedModel The shared model that will be optimized
714  * @param firstIndividualModels The first individual models that will be optimized
715  * @param secondIndividualModels The second individual models that will be optimized
716  * @param numberElementsPerSecondModel Number of elements (measurements) per second model that are used to determine the optimized models, one number for each second model, with range [1, infinity)
717  * @param valueCallback Callback function that is used to determine the value for an individual element (measurement) by application of the model(s)
718  * @param errorCallback Callback function that is used to determine the error for an individual element (measurement)
719  * @param sharedModelIsValidCallback Optional callback function that allows to decide whether a shared model is valid
720  * @param sharedModelTransformationCallback Callback function allowing to transform the internal shared model into an external model if intended
721  * @param firstIndividualModelTransformationCallback Callback function allowing to transform the internal first individual model into an external model if intended
722  * @param secondIndividualModelTransformationCallback Callback function allowing to transform the internal second individual model into an external model if intended
723  * @param modelAcceptedCallback Optional callback function that allows to be informed whenever the internal models has been improved
724  * @param optimizedSharedModel Resulting optimized shared model
725  * @param optimizedFirstIndividualModels Resulting optimized first individual models
726  * @param optimizedSecondIndividualModels Resulting optimized second individual models
727  * @param iterations Number of iterations to be applied at most, if no convergence can be reached
728  * @param estimator Robust error estimator to be used
729  * @param lambda Initial Levenberg-Marquardt damping value which may be changed after each iteration using the damping factor, with range [0, infinity)
730  * @param lambdaFactor Levenberg-Marquardt damping factor to be applied to the damping value, with range [1, infinity)
731  * @param initialError Optional resulting averaged pixel error for the given initial parameters, in relation to the defined estimator
732  * @param finalError Optional resulting averaged error for the final optimized parameters, in relation to the defined estimator
733  * @param intermediateErrors Optional resulting intermediate (improving) errors
734  * @return True, if the model could be optimized
735  */
736  static bool optimizeUniversalModel(const SharedModel& sharedModel, const FirstIndividualModels& firstIndividualModels, const SecondIndividualModels& secondIndividualModels, const size_t* numberElementsPerSecondModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const FirstIndividualModelTransformationCallback& firstIndividualModelTransformationCallback, const SecondIndividualModelTransformationCallback& secondIndividualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback, SharedModel& optimizedSharedModel, FirstIndividualModels& optimizedFirstIndividualModels, SecondIndividualModels& optimizedSecondIndividualModels, const unsigned int iterations = 5u, const Estimator::EstimatorType estimator = Estimator::ET_SQUARE, Scalar lambda = Scalar(0.001), const Scalar lambdaFactor = Scalar(5), Scalar* initialError = nullptr, Scalar* finalError = nullptr, Scalars* intermediateErrors = nullptr);
737  };
738 };
739 
740 template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalIndividualModelSize>
741 inline NonLinearUniversalOptimizationSparse::SharedModelIndividualModels<tSharedModelSize, tIndividualModelSize, tResultDimension, tExternalSharedModelSize, tExternalIndividualModelSize>::UniversalOptimizationProvider::UniversalOptimizationProvider(SharedModel& sharedModel, IndividualModels& individualModels, const size_t* numberElementsPerIndividualModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const IndividualModelTransformationCallback& individualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback) :
742  sharedModel_(sharedModel),
743  individualModels_(individualModels),
744  numberElementsPerIndividualModel_(numberElementsPerIndividualModel),
745  overallNumberElements_(0),
746  valueCallback_(valueCallback),
747  errorCallback_(errorCallback),
748  sharedModelIsValidCallback_(sharedModelIsValidCallback),
749  sharedModelTransformationCallback_(sharedModelTransformationCallback),
750  individualModelTransformationCallback_(individualModelTransformationCallback),
751  modelAcceptedCallback_(modelAcceptedCallback)
752 {
753  ocean_assert(valueCallback_);
754  ocean_assert(errorCallback_);
757 
758  candidateSharedModel_ = sharedModel;
759  candidateIndividualModels_ = individualModels;
760 
761  for (size_t n = 0; n < individualModels.size(); ++n)
762  {
764  }
765 };
766 
767 template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalIndividualModelSize>
769 {
770  ocean_assert(valueCallback_);
771  ocean_assert(sharedModelTransformationCallback_);
772  ocean_assert(individualModelTransformationCallback_);
773 
774  ocean_assert(overallNumberElements_ != 0);
775 
776  SparseMatrix::Entries jacobianEntries;
777  jacobianEntries.reserve(tResultDimension * overallNumberElements_ * (tSharedModelSize + tIndividualModelSize));
778 
779  const Scalar eps = Numeric::weakEps();
780  const Scalar invEps = Scalar(1) / eps;
781 
782  // transform the internal shared to the external shared model
783  ExternalSharedModel externalSharedModel;
784  sharedModelTransformationCallback_(sharedModel_, externalSharedModel);
785 
786  // stores individual models, each model with one individual epsilon offset
788  for (size_t a = 0; a < tSharedModelSize; ++a)
789  {
790  SharedModel internalModel = sharedModel_;
791  internalModel[a] += eps;
792 
793  sharedModelTransformationCallback_(internalModel, externalEpsSharedModels[a]);
794  }
795 
796  // transform the internal individual to the external individual models
797  std::vector<ExternalIndividualModel> externalIndividualModels(individualModels_.size());
798  std::vector< StaticBuffer<ExternalIndividualModel, tIndividualModelSize> > externalEpsIndividualModels(individualModels_.size());
799 
800  for (size_t i = 0; i < individualModels_.size(); ++i)
801  {
802  individualModelTransformationCallback_(individualModels_[i], externalIndividualModels[i]);
803 
804  for (size_t a = 0; a < tIndividualModelSize; ++a)
805  {
806  IndividualModel internalModel = individualModels_[i];
807  internalModel[a] += eps;
808 
809  individualModelTransformationCallback_(internalModel, externalEpsIndividualModels[i][a]);
810  }
811  }
812 
813  Result result, epsResult;
814  size_t row = 0;
815 
818 
819  for (size_t i = 0; i < individualModels_.size(); ++i)
820  {
821  const size_t numberElements = numberElementsPerIndividualModel_[i];
822  const size_t columnIndividual = tSharedModelSize + i * tIndividualModelSize;
823 
824  for (size_t n = 0; n < numberElements; ++n)
825  {
826  // calculate the value for the current model
827  valueCallback_(externalSharedModel, externalIndividualModels[i], i, n, result);
828 
829  // shared model
830  for (size_t m = 0; m < tSharedModelSize; ++m)
831  {
832  // calculate the value for the epsilon model
833  valueCallback_(externalEpsSharedModels[m], externalIndividualModels[i], i, n, epsResult);
834 
835  // store the individual results
836  for (size_t d = 0; d < tResultDimension; ++d)
837  {
838  sharedModelResults[d * tSharedModelSize + m] = (epsResult[d] - result[d]) * invEps;
839  }
840  }
841 
842  // individual model
843  for (size_t m = 0; m < tIndividualModelSize; ++m)
844  {
845  // calculate the value for the epsilon model
846  valueCallback_(externalSharedModel, externalEpsIndividualModels[i][m], i, n, epsResult);
847 
848  // store the individual results
849  for (size_t d = 0; d < tResultDimension; ++d)
850  {
851  individualModelResults[d * tIndividualModelSize + m] = (epsResult[d] - result[d]) * invEps;
852  }
853  }
854 
855  for (size_t d = 0; d < tResultDimension; ++d)
856  {
857  // .insert(row, 0u, sharedModelResults.data() + d * tSharedModelSize, tSharedModelSize);
858  for (size_t e = 0; e < tSharedModelSize; ++e)
859  {
860  jacobianEntries.emplace_back(row, e, sharedModelResults.data()[d * tSharedModelSize + e]);
861  }
862 
863  // .insertBack(row, columnIndividual, individualModelResults.data() + d * tIndividualModelSize, tIndividualModelSize);
864  for (size_t e = 0; e < tIndividualModelSize; ++e)
865  {
866  jacobianEntries.emplace_back(row, columnIndividual + e, individualModelResults.data()[d * tIndividualModelSize + e]);
867  }
868 
869  row++;
870  }
871  }
872  }
873 
874  jacobian = SparseMatrix(tResultDimension * overallNumberElements_, tSharedModelSize + tIndividualModelSize * individualModels_.size(), jacobianEntries);
875  ocean_assert(SparseMatrix::Entry::hasOneEntry(jacobian.rows(), jacobian.columns(), jacobianEntries));
876  ocean_assert(row == jacobian.rows());
877 }
878 
879 template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalIndividualModelSize>
881 {
882  ocean_assert(deltas.rows() == tSharedModelSize + tIndividualModelSize * individualModels_.size());
883 
884  // shared model
885  for (size_t m = 0; m < tSharedModelSize; ++m)
886  {
887  const Scalar& delta = deltas(m);
888  candidateSharedModel_[m] = sharedModel_[m] - delta;
889  }
890 
891  // individual models
892  for (size_t i = 0; i < individualModels_.size(); ++i)
893  {
894  for (size_t m = 0; m < tIndividualModelSize; ++m)
895  {
896  const Scalar& delta = deltas(tSharedModelSize + i * tIndividualModelSize + m);
897  candidateIndividualModels_[i][m] = individualModels_[i][m] - delta;
898  }
899  }
900 }
901 
902 template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalIndividualModelSize>
903 template <Estimator::EstimatorType tEstimator>
905 {
906  ocean_assert(valueCallback_);
907  ocean_assert(sharedModelTransformationCallback_);
908  ocean_assert(individualModelTransformationCallback_);
909 
910  OCEAN_SUPPRESS_UNUSED_WARNING(invertedCovariances);
911  ocean_assert(invertedCovariances == nullptr);
912  ocean_assert(overallNumberElements_ != 0);
913 
914  ExternalSharedModel externalSharedModel;
915  sharedModelTransformationCallback_(candidateSharedModel_, externalSharedModel);
916 
917  // check whether we can stop here as we do not have a valid shared model (and the provider supports to decide that)
918  if (sharedModelIsValidCallback_ && !sharedModelIsValidCallback_(externalSharedModel))
919  {
920  return Numeric::maxValue();
921  }
922 
923  // set the correct size of the resulting error vector
924  weightedErrorVector.resize(overallNumberElements_ * tResultDimension, 1u);
925  Result* const weightedErrors = (Result*)weightedErrorVector.data();
926 
927  ExternalIndividualModels externalIndividualModels(individualModels_.size());
928  for (size_t i = 0; i < individualModels_.size(); ++i)
929  {
930  individualModelTransformationCallback_(candidateIndividualModels_[i], externalIndividualModels[i]);
931  }
932 
933  size_t index = 0;
934  Scalar sqrError = 0;
935  Scalars sqrErrors;
936  if constexpr (!Estimator::isStandardEstimator<tEstimator>())
937  {
938  sqrErrors.reserve(overallNumberElements_);
939  }
940 
941  for (size_t i = 0; i < individualModels_.size(); ++i)
942  {
943  const size_t numberElements = numberElementsPerIndividualModel_[i];
944 
945  for (size_t n = 0; n < numberElements; ++n)
946  {
947  Result& weightedErrorPointer = *((Result*)weightedErrorVector.data() + index);
948 
949  if (!errorCallback_(externalSharedModel, externalIndividualModels[i], i, n, weightedErrorPointer))
950  {
951  return Numeric::maxValue();
952  }
953 
954  if constexpr (Estimator::isStandardEstimator<tEstimator>())
955  {
956  sqrError += Numeric::summedSqr(weightedErrorPointer.data(), tResultDimension);
957  }
958  else
959  {
960  ocean_assert(!Estimator::isStandardEstimator<tEstimator>());
961  sqrErrors.emplace_back(Numeric::summedSqr(weightedErrorPointer.data(), tResultDimension));
962  }
963 
964  index++;
965  }
966  }
967 
968  ocean_assert(index == overallNumberElements_);
969  ocean_assert(index * tResultDimension == weightedErrorVector.rows());
970 
971  // check whether the standard estimator is used
972  if constexpr (Estimator::isStandardEstimator<tEstimator>())
973  {
974  // the weight vector should be and should stay invalid
975  ocean_assert(!weightVector);
976 
977  ocean_assert((overallNumberElements_) > 0);
978  return sqrError /= Scalar(overallNumberElements_);
979  }
980  else
981  {
982  // now we need the weight vector
983  weightVector.resize(tResultDimension * overallNumberElements_, 1u);
984 
985  return sqrErrors2robustErrors<tEstimator, tResultDimension>(sqrErrors, tSharedModelSize + tIndividualModelSize * individualModels_.size(), weightedErrors, (StaticBuffer<Scalar, tResultDimension>*)weightVector.data(), nullptr);
986  }
987 }
988 
989 template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalIndividualModelSize>
991 {
992  sharedModel_ = candidateSharedModel_;
993  individualModels_ = candidateIndividualModels_;
994 
995  if (modelAcceptedCallback_)
996  {
997  modelAcceptedCallback_(sharedModel_, individualModels_);
998  }
999 }
1000 
1001 template <unsigned int tSharedModelSize, unsigned int tIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalIndividualModelSize>
1002 bool NonLinearUniversalOptimizationSparse::SharedModelIndividualModels<tSharedModelSize, tIndividualModelSize, tResultDimension, tExternalSharedModelSize, tExternalIndividualModelSize>::optimizeUniversalModel(const SharedModel& sharedModel, const IndividualModels& individualModels, const size_t* numberElementsPerIndividualModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const IndividualModelTransformationCallback& individualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback, SharedModel& optimizedSharedModel, IndividualModels& optimizedIndividualModels, const unsigned int iterations, const Estimator::EstimatorType estimator, Scalar lambda, const Scalar lambdaFactor, Scalar* initialError, Scalar* finalError, Scalars* intermediateErrors)
1003 {
1004  ocean_assert(&sharedModel != &optimizedSharedModel);
1005  ocean_assert(&individualModels != &optimizedIndividualModels);
1006 
1007  optimizedSharedModel = sharedModel;
1008  optimizedIndividualModels = individualModels;
1009 
1010  if (modelAcceptedCallback)
1011  {
1012  modelAcceptedCallback(sharedModel, individualModels);
1013  }
1014 
1015  UniversalOptimizationProvider provider(optimizedSharedModel, optimizedIndividualModels, numberElementsPerIndividualModel, valueCallback, errorCallback, sharedModelIsValidCallback, sharedModelTransformationCallback, individualModelTransformationCallback, modelAcceptedCallback);
1016  return NonLinearOptimization::sparseOptimization<UniversalOptimizationProvider>(provider, iterations, estimator, lambda, lambdaFactor, initialError, finalError, nullptr, intermediateErrors);
1017 }
1018 
1019 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1021  firstModels_(firstModels),
1022  secondModels_(secondModels),
1023  numberElementsPerSecondModel_(numberElementsPerSecondModel),
1024  overallNumberElements_(0),
1025  valueCallback_(valueCallback),
1026  errorCallback_(errorCallback),
1027  firstModelTransformationCallback_(firstModelTransformationCallback),
1028  secondModelTransformationCallback_(secondModelTransformationCallback),
1029  modelAcceptedCallback_(modelAcceptedCallback)
1030 {
1031  ocean_assert(valueCallback_);
1032  ocean_assert(errorCallback_);
1033  ocean_assert(firstModelTransformationCallback_);
1034  ocean_assert(secondModelTransformationCallback_);
1035 
1036  candidateFirstModels_ = firstModels;
1037  candidateSecondModels_ = secondModels;
1038 
1039  // we need to know how many measurement values are provides as this number determines e.g., the size of the jacobian matrix etc.
1040  for (size_t n = 0; n < secondModels.size(); ++n)
1041  {
1043  }
1044 };
1045 
1046 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1048 {
1049  return true;
1050 }
1051 
1052 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1054 {
1055  static_assert(tFirstModelSize >= 1u, "Invalid model size!");
1056  static_assert(tSecondModelSize >= 1u, "Invalid model size!");
1057 
1058  ocean_assert(JTJ.rows() == JTJ.columns());
1059  ocean_assert(JTJ.rows() == jErrors.rows());
1060 
1061  ocean_assert(jErrors.columns() == 1);
1062 
1063  /**
1064  * here we apply the Schur complement to improve the solve performance:
1065  *
1066  * JTJ * deltas = jErrors
1067  * | A B | | da | | ea |
1068  * | C D | * | db | = | eb |
1069  *
1070  * (A - B D^-1 C ) * da = ea - B D^-1 * eb -> (solve da)
1071  * db = D^-1 (eb - C * da)
1072  *
1073  * or:
1074  * (D - C A^-1 B) * db = eb - C A^-1 * ea -> (solve db)
1075  * da = A^-1 (ea - B * db)
1076  */
1077 
1078  // solving da:
1079 
1080  const size_t sizeA = firstModels_.size() * tFirstModelSize;
1081  const size_t sizeB = JTJ.rows() - sizeA;
1082  ocean_assert(sizeB % tSecondModelSize == 0);
1083 
1084  if (sizeA < sizeB)
1085  {
1086  SparseMatrix D(JTJ.submatrix(sizeA, sizeA, sizeB, sizeB));
1087 
1088  switch (tSecondModelSize)
1089  {
1090  case 1u:
1091  if (!D.invertDiagonal())
1092  return false;
1093  break;
1094 
1095  case 3u:
1096  if (!D.invertBlockDiagonal3())
1097  return false;
1098  break;
1099 
1100  default:
1101  if (!D.invertBlockDiagonal(tSecondModelSize))
1102  return false;
1103  break;
1104  }
1105 
1106  const SparseMatrix A(JTJ.submatrix(0, 0, sizeA, sizeA));
1107  const SparseMatrix B(JTJ.submatrix(0, sizeA, sizeA, sizeB));
1108  const SparseMatrix C(JTJ.submatrix(sizeA, 0, sizeB, sizeA));
1109 
1110  const Matrix ea(sizeA, 1, jErrors.data());
1111  const Matrix eb(sizeB, 1, jErrors.data() + sizeA);
1112 
1113  Matrix da;
1114  if (!(A - B * (D * C)).solve(ea - B * (D * eb), da))
1115  {
1116  return false;
1117  }
1118 
1119  const Matrix db = D * (eb - C * da);
1120 
1121  deltas.resize(jErrors.rows(), 1);
1122 
1123  memcpy(deltas.data(), da.data(), sizeA * sizeof(Scalar));
1124  memcpy(deltas.data() + sizeA, db.data(), sizeB * sizeof(Scalar));
1125  }
1126  else
1127  {
1128  SparseMatrix A(JTJ.submatrix(0, 0, sizeA, sizeA));
1129 
1130  switch (tFirstModelSize)
1131  {
1132  case 1u:
1133  if (!A.invertDiagonal())
1134  return false;
1135  break;
1136 
1137  case 3u:
1138  if (!A.invertBlockDiagonal3())
1139  return false;
1140  break;
1141 
1142  default:
1143  if (!A.invertBlockDiagonal(tFirstModelSize))
1144  return false;
1145  break;
1146  }
1147 
1148  const SparseMatrix D(JTJ.submatrix(sizeA, sizeA, sizeB, sizeB));
1149  const SparseMatrix B(JTJ.submatrix(0, sizeA, sizeA, sizeB));
1150  const SparseMatrix C(JTJ.submatrix(sizeA, 0, sizeB, sizeA));
1151 
1152  const Matrix ea(sizeA, 1, jErrors.data());
1153  const Matrix eb(sizeB, 1, jErrors.data() + sizeA);
1154 
1155  Matrix db;
1156  if (!(D - C * (A * B)).solve(eb - C * (A * ea), db))
1157  {
1158  return false;
1159  }
1160 
1161  const Matrix da = A * (ea - B * db);
1162 
1163  deltas.resize(jErrors.rows(), 1);
1164 
1165  memcpy(deltas.data(), da.data(), sizeA * sizeof(Scalar));
1166  memcpy(deltas.data() + sizeA, db.data(), sizeB * sizeof(Scalar));
1167  }
1168 
1169 #ifdef OCEAN_INTENSIVE_DEBUG
1170  const Matrix debugJErrors(JTJ * deltas);
1171  Scalars difference(jErrors.rows());
1172 
1173  bool allWeakEps = true;
1174  Scalar averageDifference = 0;
1175  for (unsigned int n = 0u; n < jErrors.rows(); ++n)
1176  {
1177  difference[n] = debugJErrors(n, 0) - jErrors(n, 0);
1178 
1179  averageDifference += Numeric::abs(difference[n]);
1180  }
1181 
1182  ocean_assert(jErrors.rows() != 0);
1183  averageDifference /= Scalar(jErrors.rows());
1184 
1185  // sometime event the average difference may not be weak-zero so that we do not check the value by default
1186  // ocean_assert(Numeric::isWeakEqualEps(averageDifference));
1187 #endif
1188 
1189  return true;
1190 }
1191 
1192 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1194 {
1195  ocean_assert(valueCallback_);
1196  ocean_assert(firstModelTransformationCallback_);
1197  ocean_assert(secondModelTransformationCallback_);
1198 
1199  ocean_assert(overallNumberElements_ != 0);
1200 
1201  SparseMatrix::Entries jacobianEntries;
1202  jacobianEntries.reserve(tResultDimension * overallNumberElements_ * (tFirstModelSize + tSecondModelSize));
1203 
1204  const Scalar eps = Numeric::weakEps();
1205  const Scalar invEps = Scalar(1) / eps;
1206 
1207  // for each model (we need to determine a slightly modified epsilon model) so that we can determine the jacobian matrix later
1208  // for each internal model:
1209  // - we determine the corresponding external model (without modifying the individual parameters)
1210  // - we modify each parameter and store the corresponding external sub-models (one external sub-model for each modified internal model parameter)
1211 
1212  // the external (first) models (without modified parameters)
1213  ExternalFirstModels externalFirstModels(firstModels_.size());
1214  // the external (first) models (with modified (internal) parameters)
1215  StaticBuffer<ExternalFirstModels, tFirstModelSize> externalEpsFirstModels(tFirstModelSize, ExternalFirstModels(firstModels_.size()));
1216 
1217  for (size_t i = 0; i < firstModels_.size(); ++i)
1218  {
1219  firstModelTransformationCallback_(firstModels_[i], externalFirstModels[i]);
1220 
1221  for (size_t a = 0; a < tFirstModelSize; ++a)
1222  {
1223  FirstModel firstModel = firstModels_[i];
1224  firstModel[a] += eps;
1225 
1226  firstModelTransformationCallback_(firstModel, externalEpsFirstModels[a][i]);
1227  }
1228  }
1229 
1230  // the external (second) models (without modified parameters)
1231  ExternalSecondModels externalSecondModels(secondModels_.size());
1232  // the external (second models (with modified (internal) parameters)
1233  StaticBuffer<ExternalSecondModels, tSecondModelSize> externalEpsSecondModels(tSecondModelSize, ExternalSecondModels(secondModels_.size()));
1234 
1235  for (size_t i = 0; i < secondModels_.size(); ++i)
1236  {
1237  secondModelTransformationCallback_(secondModels_[i], externalSecondModels[i]);
1238 
1239  for (size_t a = 0; a < tSecondModelSize; ++a)
1240  {
1241  SecondModel secondModel = secondModels_[i];
1242  secondModel[a] += eps;
1243 
1244  secondModelTransformationCallback_(secondModel, externalEpsSecondModels[a][i]);
1245  }
1246  }
1247 
1248  // now we apply the individual external models and their corresponding modified external models to determine the jacobian matrix
1249 
1250  Result result, epsResult;
1251  size_t row = 0;
1252 
1255 
1256  for (size_t i = 0; i < secondModels_.size(); ++i)
1257  {
1258  const size_t numberElements = numberElementsPerSecondModel_[i];
1259  const size_t columnSecond = tFirstModelSize * firstModels_.size() + i * tSecondModelSize;
1260 
1261  for (size_t n = 0; n < numberElements; ++n)
1262  {
1263  // calculate the value for the current model
1264  const size_t firstModelIndex = valueCallback_(externalFirstModels, externalSecondModels, i, n, result);
1265  ocean_assert(firstModelIndex <= firstModels_.size());
1266 
1267  // first model
1268  for (size_t m = 0; m < tFirstModelSize; ++m)
1269  {
1270  // calculate the value for the epsilon model
1271  const size_t checkModelIndex = valueCallback_(externalEpsFirstModels[m], externalSecondModels, i, n, epsResult);
1272  ocean_assert(checkModelIndex == firstModelIndex);
1273  OCEAN_SUPPRESS_UNUSED_WARNING(checkModelIndex);
1274 
1275  // store the individual results
1276  for (size_t d = 0; d < tResultDimension; ++d)
1277  {
1278  firstModelResults[d * tFirstModelSize + m] = (epsResult[d] - result[d]) * invEps;
1279  }
1280  }
1281 
1282  // second model
1283  for (size_t m = 0; m < tSecondModelSize; ++m)
1284  {
1285  // calculate the value for the epsilon model
1286  const size_t checkModelIndex = valueCallback_(externalFirstModels, externalEpsSecondModels[m], i, n, epsResult);
1287  ocean_assert(checkModelIndex == firstModelIndex);
1288  OCEAN_SUPPRESS_UNUSED_WARNING(checkModelIndex);
1289 
1290  // store the individual results
1291  for (size_t d = 0; d < tResultDimension; ++d)
1292  {
1293  secondModelResults[d * tSecondModelSize + m] = (epsResult[d] - result[d]) * invEps;
1294  }
1295  }
1296 
1297  const size_t columnFirst = firstModelIndex * tFirstModelSize;
1298 
1299  for (size_t d = 0; d < tResultDimension; ++d)
1300  {
1301  for (size_t e = 0; e < tFirstModelSize; ++e)
1302  {
1303  jacobianEntries.emplace_back(row, columnFirst + e, firstModelResults.data()[d * tFirstModelSize + e]);
1304  }
1305 
1306  for (size_t e = 0; e < tSecondModelSize; ++e)
1307  {
1308  jacobianEntries.emplace_back(row, columnSecond + e, secondModelResults.data()[d * tSecondModelSize + e]);
1309  }
1310 
1311  row++;
1312  }
1313  }
1314  }
1315 
1316  jacobian = SparseMatrix(tResultDimension * overallNumberElements_, tFirstModelSize * firstModels_.size() + tSecondModelSize * secondModels_.size(), jacobianEntries);
1317  ocean_assert(SparseMatrix::Entry::hasOneEntry(jacobian.rows(), jacobian.columns(), jacobianEntries));
1318  ocean_assert(row == jacobian.rows());
1319 }
1320 
1321 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1323 {
1324  ocean_assert(deltas.rows() == tFirstModelSize * firstModels_.size() + tSecondModelSize * secondModels_.size());
1325 
1326  size_t index = 0;
1327 
1328  // first models
1329  for (size_t i = 0; i < firstModels_.size(); ++i)
1330  {
1331  for (size_t m = 0; m < tFirstModelSize; ++m)
1332  {
1333  const Scalar& delta = deltas(index++);
1334  candidateFirstModels_[i][m] = firstModels_[i][m] - delta;
1335  }
1336  }
1337 
1338  // second models
1339  for (size_t i = 0; i < secondModels_.size(); ++i)
1340  {
1341  for (size_t m = 0; m < tSecondModelSize; ++m)
1342  {
1343  const Scalar& delta = deltas(index++);
1344  candidateSecondModels_[i][m] = secondModels_[i][m] - delta;
1345  }
1346  }
1347 }
1348 
1349 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1350 template <Estimator::EstimatorType tEstimator>
1352 {
1353  ocean_assert(valueCallback_);
1354  ocean_assert(firstModelTransformationCallback_);
1355  ocean_assert(secondModelTransformationCallback_);
1356 
1357  OCEAN_SUPPRESS_UNUSED_WARNING(invertedCovariances);
1358  ocean_assert(invertedCovariances == nullptr);
1359  ocean_assert(overallNumberElements_ != 0);
1360 
1361  // set the correct size of the resulting error vector
1362  weightedErrorVector.resize(overallNumberElements_ * tResultDimension, 1u);
1363  Result* const weightedErrors = (Result*)weightedErrorVector.data();
1364 
1365  ExternalFirstModels externalFirstModels(firstModels_.size());
1366  for (size_t i = 0; i < firstModels_.size(); ++i)
1367  {
1368  firstModelTransformationCallback_(candidateFirstModels_[i], externalFirstModels[i]);
1369  }
1370 
1371  ExternalSecondModels externalSecondModels(secondModels_.size());
1372  for (size_t i = 0; i < secondModels_.size(); ++i)
1373  {
1374  secondModelTransformationCallback_(candidateSecondModels_[i], externalSecondModels[i]);
1375  }
1376 
1377  size_t index = 0;
1378  Scalar sqrError = 0;
1379  Scalars sqrErrors;
1380  if constexpr (!Estimator::isStandardEstimator<tEstimator>())
1381  {
1382  sqrErrors.reserve(overallNumberElements_);
1383  }
1384 
1385  for (size_t i = 0; i < secondModels_.size(); ++i)
1386  {
1387  const size_t numberElements = numberElementsPerSecondModel_[i];
1388 
1389  for (size_t n = 0; n < numberElements; ++n)
1390  {
1391  Result& weightedErrorPointer = *((Result*)weightedErrorVector.data() + index);
1392 
1393  if (!errorCallback_(externalFirstModels, externalSecondModels, i, n, weightedErrorPointer))
1394  {
1395  return Numeric::maxValue();
1396  }
1397 
1398  if constexpr (Estimator::isStandardEstimator<tEstimator>())
1399  {
1400  sqrError += Numeric::summedSqr(weightedErrorPointer.data(), tResultDimension);
1401  }
1402  else
1403  {
1404  ocean_assert(!Estimator::isStandardEstimator<tEstimator>());
1405  sqrErrors.emplace_back(Numeric::summedSqr(weightedErrorPointer.data(), tResultDimension));
1406  }
1407 
1408  index++;
1409  }
1410  }
1411 
1412  ocean_assert(index == overallNumberElements_);
1413  ocean_assert(index * 2 == weightedErrorVector.rows());
1414 
1415  // check whether the standard estimator is used
1416  if constexpr (Estimator::isStandardEstimator<tEstimator>())
1417  {
1418  // the weight vector should be and should stay invalid
1419  ocean_assert(!weightVector);
1420 
1421  ocean_assert((overallNumberElements_) > 0);
1422  return sqrError /= Scalar(overallNumberElements_);
1423  }
1424  else
1425  {
1426  // now we need the weight vector
1427  weightVector.resize(tResultDimension * overallNumberElements_, 1u);
1428 
1429  return sqrErrors2robustErrors<tEstimator, tResultDimension>(sqrErrors, tFirstModelSize * firstModels_.size() + tSecondModelSize * secondModels_.size(), weightedErrors, (StaticBuffer<Scalar, tResultDimension>*)weightVector.data(), nullptr);
1430  }
1431 }
1432 
1433 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1435 {
1436  firstModels_ = candidateFirstModels_;
1437  secondModels_ = candidateSecondModels_;
1438 
1439  if (modelAcceptedCallback_)
1440  {
1441  modelAcceptedCallback_(firstModels_, secondModels_);
1442  }
1443 }
1444 
1445 template <unsigned int tFirstModelSize, unsigned int tSecondModelSize, unsigned int tResultDimension, unsigned int tExternalFirstModelSize, unsigned int tExternalSecondModelSize>
1446 bool NonLinearUniversalOptimizationSparse::IndividualModelsIndividualModels<tFirstModelSize, tSecondModelSize, tResultDimension, tExternalFirstModelSize, tExternalSecondModelSize>::optimizeUniversalModel(const FirstModels& firstModels, const SecondModels& secondModels, const size_t* numberElementsPerSecondModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const FirstModelTransformationCallback& firstModelTransformationCallback, const SecondModelTransformationCallback& secondModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback, FirstModels& optimizedFirstModels, SecondModels& optimizedSecondModels, const unsigned int iterations, const Estimator::EstimatorType estimator, Scalar lambda, const Scalar lambdaFactor, Scalar* initialError, Scalar* finalError, Scalars* intermediateErrors)
1447 {
1448  ocean_assert(&firstModels != &optimizedFirstModels);
1449  ocean_assert(&secondModels != &optimizedSecondModels);
1450 
1451  optimizedFirstModels = firstModels;
1452  optimizedSecondModels = secondModels;
1453 
1454  if (modelAcceptedCallback)
1455  {
1456  modelAcceptedCallback(firstModels, secondModels);
1457  }
1458 
1459  UniversalOptimizationProvider provider(optimizedFirstModels, optimizedSecondModels, numberElementsPerSecondModel, valueCallback, errorCallback, firstModelTransformationCallback, secondModelTransformationCallback, modelAcceptedCallback);
1460  return NonLinearOptimization::sparseOptimization<UniversalOptimizationProvider>(provider, iterations, estimator, lambda, lambdaFactor, initialError, finalError, nullptr, intermediateErrors);
1461 }
1462 
1463 template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize>
1465  sharedModel_(sharedModel),
1466  firstIndividualModels_(firstIndividualModels),
1467  secondIndividualModels_(secondIndividualModels),
1468  numberElementsPerSecondModel_(numberElementsPerSecondModel),
1469  overallNumberElements_(0),
1470  valueCallback_(valueCallback),
1471  errorCallback_(errorCallback),
1472  sharedModelIsValidCallback_(sharedModelIsValidCallback),
1473  sharedModelTransformationCallback_(sharedModelTransformationCallback),
1474  firstIndividualModelTransformationCallback_(firstIndividualModelTransformationCallback),
1475  secondIndividualModelTransformationCallback_(secondIndividualModelTransformationCallback),
1476  modelAcceptedCallback_(modelAcceptedCallback)
1477 {
1478  ocean_assert(valueCallback_);
1479  ocean_assert(errorCallback_);
1480  ocean_assert(sharedModelTransformationCallback_);
1483 
1484  candidateSharedModel_ = sharedModel;
1485  candidateFirstIndividualModels_ = firstIndividualModels;
1486  candidateSecondIndividualModels_ = secondIndividualModels;
1487 
1488  // we need to know how many measurement values are provides as this number determines e.g., the size of the jacobian matrix etc.
1489  for (size_t n = 0; n < secondIndividualModels.size(); ++n)
1490  {
1492  }
1493 };
1494 
1495 template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize>
1497 {
1498  ocean_assert(valueCallback_);
1499  ocean_assert(sharedModelTransformationCallback_);
1500  ocean_assert(firstIndividualModelTransformationCallback_);
1501  ocean_assert(secondIndividualModelTransformationCallback_);
1502 
1503  ocean_assert(overallNumberElements_ != 0);
1504 
1505  SparseMatrix::Entries jacobianEntries;
1506  jacobianEntries.reserve(tResultDimension * overallNumberElements_ * (tSharedModelSize + tFirstIndividualModelSize + tSecondIndividualModelSize));
1507 
1508  const Scalar eps = Numeric::weakEps();
1509  const Scalar invEps = Scalar(1) / eps;
1510 
1511  // for each model (we need to determine a slightly modified epsilon model) so that we can determine the jacobian matrix later
1512  // for each internal model:
1513  // - we determine the corresponding external model (without modifying the individual parameters)
1514  // - we modify each parameter and store the corresponding external sub-models (one external sub-model for each modified internal model parameter)
1515 
1516  // the external shared model (without modified parameter)
1517  ExternalSharedModel externalSharedModel;
1518  // the external shared model (with modified (internal) parameters)
1520 
1521  sharedModelTransformationCallback_(sharedModel_, externalSharedModel);
1522  for (size_t a = 0; a < tSharedModelSize; ++a)
1523  {
1524  SharedModel internalModel = sharedModel_;
1525  internalModel[a] += eps;
1526 
1527  sharedModelTransformationCallback_(internalModel, externalEpsSharedModels[a]);
1528  }
1529 
1530  // the external (first) individual models (without modified parameters)
1531  ExternalFirstIndividualModels externalFirstIndividualModels(firstIndividualModels_.size());
1532  // the external (first) individual models (with modified (internal) parameters)
1533  StaticBuffer<ExternalFirstIndividualModels, tFirstIndividualModelSize> externalEpsFirstIndividualModels(tFirstIndividualModelSize, ExternalFirstIndividualModels(firstIndividualModels_.size()));
1534 
1535  for (size_t i = 0; i < firstIndividualModels_.size(); ++i)
1536  {
1537  firstIndividualModelTransformationCallback_(firstIndividualModels_[i], externalFirstIndividualModels[i]);
1538 
1539  for (size_t a = 0; a < tFirstIndividualModelSize; ++a)
1540  {
1541  FirstIndividualModel firstIndividualModel = firstIndividualModels_[i];
1542  firstIndividualModel[a] += eps;
1543 
1544  firstIndividualModelTransformationCallback_(firstIndividualModel, externalEpsFirstIndividualModels[a][i]);
1545  }
1546  }
1547 
1548  // the external (second) individual models (without modified parameters)
1549  ExternalSecondIndividualModels externalSecondIndividualModels(secondIndividualModels_.size());
1550  // the external (second) individual models (with modified (internal) parameters)
1551  StaticBuffer<ExternalSecondIndividualModels, tSecondIndividualModelSize> externalEpsSecondIndividualModels(tSecondIndividualModelSize, ExternalSecondIndividualModels(secondIndividualModels_.size()));
1552 
1553  for (size_t i = 0; i < secondIndividualModels_.size(); ++i)
1554  {
1555  secondIndividualModelTransformationCallback_(secondIndividualModels_[i], externalSecondIndividualModels[i]);
1556 
1557  for (size_t a = 0; a < tSecondIndividualModelSize; ++a)
1558  {
1559  SecondIndividualModel secondIndividualModel = secondIndividualModels_[i];
1560  secondIndividualModel[a] += eps;
1561 
1562  secondIndividualModelTransformationCallback_(secondIndividualModel, externalEpsSecondIndividualModels[a][i]);
1563  }
1564  }
1565 
1566  // now we apply the shared external model and the individual external models and their corresponding modified external models to determine the jacobian matrix
1567 
1568  Result result, epsResult;
1569  size_t row = 0;
1570 
1574 
1575  for (size_t i = 0; i < secondIndividualModels_.size(); ++i)
1576  {
1577  const size_t numberElements = numberElementsPerSecondModel_[i];
1578  const size_t columnSecond = tSharedModelSize + tFirstIndividualModelSize * firstIndividualModels_.size() + i * tSecondIndividualModelSize;
1579 
1580  for (size_t n = 0; n < numberElements; ++n)
1581  {
1582  // calculate the value for the current model
1583  const size_t firstIndividualModelIndex = valueCallback_(externalSharedModel, externalFirstIndividualModels, externalSecondIndividualModels, i, n, result);
1584  ocean_assert(firstIndividualModelIndex <= firstIndividualModels_.size());
1585 
1586  // shared model
1587  for (size_t m = 0; m < tSharedModelSize; ++m)
1588  {
1589  // calculate the value for the epsilon model
1590  const size_t checkModelIndex = valueCallback_(externalEpsSharedModels[m], externalFirstIndividualModels, externalSecondIndividualModels, i, n, epsResult);
1591  ocean_assert(checkModelIndex == firstIndividualModelIndex);
1592  OCEAN_SUPPRESS_UNUSED_WARNING(checkModelIndex);
1593 
1594  // store the individual results
1595  for (size_t d = 0; d < tResultDimension; ++d)
1596  {
1597  sharedModelResults[d * tSharedModelSize + m] = (epsResult[d] - result[d]) * invEps;
1598  }
1599  }
1600 
1601  // first individual model
1602  for (size_t m = 0; m < tFirstIndividualModelSize; ++m)
1603  {
1604  // calculate the value for the epsilon model
1605  const size_t checkModelIndex = valueCallback_(externalSharedModel, externalEpsFirstIndividualModels[m], externalSecondIndividualModels, i, n, epsResult);
1606  ocean_assert(checkModelIndex == firstIndividualModelIndex);
1607  OCEAN_SUPPRESS_UNUSED_WARNING(checkModelIndex);
1608 
1609  // store the individual results
1610  for (size_t d = 0; d < tResultDimension; ++d)
1611  {
1612  firstIndividualModelResults[d * tFirstIndividualModelSize + m] = (epsResult[d] - result[d]) * invEps;
1613  }
1614  }
1615 
1616  // second individual model
1617  for (size_t m = 0; m < tSecondIndividualModelSize; ++m)
1618  {
1619  // calculate the value for the epsilon model
1620  const size_t checkModelIndex = valueCallback_(externalSharedModel, externalFirstIndividualModels, externalEpsSecondIndividualModels[m], i, n, epsResult);
1621  ocean_assert(checkModelIndex == firstIndividualModelIndex);
1622  OCEAN_SUPPRESS_UNUSED_WARNING(checkModelIndex);
1623 
1624  // store the individual results
1625  for (size_t d = 0; d < tResultDimension; ++d)
1626  {
1627  secondIndividualModelResults[d * tSecondIndividualModelSize + m] = (epsResult[d] - result[d]) * invEps;
1628  }
1629  }
1630 
1631  const size_t columnFirst = tSharedModelSize + firstIndividualModelIndex * tFirstIndividualModelSize;
1632 
1633  for (size_t d = 0; d < tResultDimension; ++d)
1634  {
1635  for (size_t e = 0; e < tSharedModelSize; ++e)
1636  {
1637  jacobianEntries.emplace_back(row, e, sharedModelResults.data()[d * tSharedModelSize + e]);
1638  }
1639 
1640  for (size_t e = 0; e < tFirstIndividualModelSize; ++e)
1641  {
1642  jacobianEntries.emplace_back(row, columnFirst + e, firstIndividualModelResults.data()[d * tFirstIndividualModelSize + e]);
1643  }
1644 
1645  for (size_t e = 0; e < tSecondIndividualModelSize; ++e)
1646  {
1647  jacobianEntries.emplace_back(row, columnSecond + e, secondIndividualModelResults.data()[d * tSecondIndividualModelSize + e]);
1648  }
1649 
1650  row++;
1651  }
1652  }
1653  }
1654 
1655  jacobian = SparseMatrix(tResultDimension * overallNumberElements_, tSharedModelSize + tFirstIndividualModelSize * firstIndividualModels_.size() + tSecondIndividualModelSize * secondIndividualModels_.size(), jacobianEntries);
1656  ocean_assert(SparseMatrix::Entry::hasOneEntry(jacobian.rows(), jacobian.columns(), jacobianEntries));
1657  ocean_assert(row == jacobian.rows());
1658 }
1659 
1660 template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize>
1662 {
1663  ocean_assert(deltas.rows() == tSharedModelSize + tFirstIndividualModelSize * firstIndividualModels_.size() + tSecondIndividualModelSize * secondIndividualModels_.size());
1664 
1665  size_t index = 0;
1666 
1667  // shared model
1668  for (size_t m = 0; m < tSharedModelSize; ++m)
1669  {
1670  const Scalar& delta = deltas(index++);
1671  candidateSharedModel_[m] = sharedModel_[m] - delta;
1672  }
1673 
1674  // first individual models
1675  for (size_t i = 0; i < firstIndividualModels_.size(); ++i)
1676  {
1677  for (size_t m = 0; m < tFirstIndividualModelSize; ++m)
1678  {
1679  const Scalar& delta = deltas(index++);
1680  candidateFirstIndividualModels_[i][m] = firstIndividualModels_[i][m] - delta;
1681  }
1682  }
1683 
1684  // second individual models
1685  for (size_t i = 0; i < secondIndividualModels_.size(); ++i)
1686  {
1687  for (size_t m = 0; m < tSecondIndividualModelSize; ++m)
1688  {
1689  const Scalar& delta = deltas(index++);
1690  candidateSecondIndividualModels_[i][m] = secondIndividualModels_[i][m] - delta;
1691  }
1692  }
1693 }
1694 
1695 template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize>
1696 template <Estimator::EstimatorType tEstimator>
1698 {
1699  ocean_assert(valueCallback_);
1700  ocean_assert(sharedModelTransformationCallback_);
1701  ocean_assert(firstIndividualModelTransformationCallback_);
1702  ocean_assert(secondIndividualModelTransformationCallback_);
1703 
1704  OCEAN_SUPPRESS_UNUSED_WARNING(invertedCovariances);
1705  ocean_assert(invertedCovariances == nullptr);
1706  ocean_assert(overallNumberElements_ != 0);
1707 
1708  ExternalSharedModel externalSharedModel;
1709  sharedModelTransformationCallback_(candidateSharedModel_, externalSharedModel);
1710 
1711  // check whether we can stop here as we do not have a valid shared model (and the provider supports to decide that)
1712  if (sharedModelIsValidCallback_ && !sharedModelIsValidCallback_(externalSharedModel))
1713  {
1714  return Numeric::maxValue();
1715  }
1716 
1717  // set the correct size of the resulting error vector
1718  weightedErrorVector.resize(overallNumberElements_ * tResultDimension, 1u);
1719  Result* const weightedErrors = (Result*)weightedErrorVector.data();
1720 
1721  ExternalFirstIndividualModels externalFirstIndividualModels(firstIndividualModels_.size());
1722  for (size_t i = 0; i < firstIndividualModels_.size(); ++i)
1723  {
1724  firstIndividualModelTransformationCallback_(candidateFirstIndividualModels_[i], externalFirstIndividualModels[i]);
1725  }
1726 
1727  ExternalSecondIndividualModels externalSecondIndividualModels(secondIndividualModels_.size());
1728  for (size_t i = 0; i < secondIndividualModels_.size(); ++i)
1729  {
1730  secondIndividualModelTransformationCallback_(candidateSecondIndividualModels_[i], externalSecondIndividualModels[i]);
1731  }
1732 
1733  size_t index = 0;
1734  Scalar sqrError = 0;
1735  Scalars sqrErrors;
1736  if constexpr (!Estimator::isStandardEstimator<tEstimator>())
1737  {
1738  sqrErrors.reserve(overallNumberElements_);
1739  }
1740 
1741  for (size_t i = 0; i < secondIndividualModels_.size(); ++i)
1742  {
1743  const size_t numberElements = numberElementsPerSecondModel_[i];
1744 
1745  for (size_t n = 0; n < numberElements; ++n)
1746  {
1747  Result& weightedErrorPointer = *((Result*)weightedErrorVector.data() + index);
1748 
1749  if (!errorCallback_(externalSharedModel, externalFirstIndividualModels, externalSecondIndividualModels, i, n, weightedErrorPointer))
1750  {
1751  return Numeric::maxValue();
1752  }
1753 
1754  if constexpr (Estimator::isStandardEstimator<tEstimator>())
1755  {
1756  sqrError += Numeric::summedSqr(weightedErrorPointer.data(), tResultDimension);
1757  }
1758  else
1759  {
1760  ocean_assert(!Estimator::isStandardEstimator<tEstimator>());
1761  sqrErrors.emplace_back(Numeric::summedSqr(weightedErrorPointer.data(), tResultDimension));
1762  }
1763 
1764  index++;
1765  }
1766  }
1767 
1768  ocean_assert(index == overallNumberElements_);
1769  ocean_assert(index * 2 == weightedErrorVector.rows());
1770 
1771  // check whether the standard estimator is used
1772  if constexpr (Estimator::isStandardEstimator<tEstimator>())
1773  {
1774  // the weight vector should be and should stay invalid
1775  ocean_assert(!weightVector);
1776 
1777  ocean_assert((overallNumberElements_) > 0);
1778  return sqrError /= Scalar(overallNumberElements_);
1779  }
1780  else
1781  {
1782  // now we need the weight vector
1783  weightVector.resize(tResultDimension * overallNumberElements_, 1u);
1784 
1785  return sqrErrors2robustErrors<tEstimator, tResultDimension>(sqrErrors, tSharedModelSize + tFirstIndividualModelSize * firstIndividualModels_.size() + tSecondIndividualModelSize * secondIndividualModels_.size(), weightedErrors, (StaticBuffer<Scalar, tResultDimension>*)weightVector.data(), nullptr);
1786  }
1787 }
1788 
1789 template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize>
1791 {
1792  sharedModel_ = candidateSharedModel_;
1793  firstIndividualModels_ = candidateFirstIndividualModels_;
1794  secondIndividualModels_ = candidateSecondIndividualModels_;
1795 
1796  if (modelAcceptedCallback_)
1797  {
1798  modelAcceptedCallback_(sharedModel_, firstIndividualModels_, secondIndividualModels_);
1799  }
1800 }
1801 
1802 template <unsigned int tSharedModelSize, unsigned int tFirstIndividualModelSize, unsigned int tSecondIndividualModelSize, unsigned int tResultDimension, unsigned int tExternalSharedModelSize, unsigned int tExternalFirstIndividualModelSize, unsigned int tExternalSecondIndividualModelSize>
1803 bool NonLinearUniversalOptimizationSparse::SharedModelIndividualModelsIndividualModels<tSharedModelSize, tFirstIndividualModelSize, tSecondIndividualModelSize, tResultDimension, tExternalSharedModelSize, tExternalFirstIndividualModelSize, tExternalSecondIndividualModelSize>::optimizeUniversalModel(const SharedModel& sharedModel, const FirstIndividualModels& firstIndividualModels, const SecondIndividualModels& secondIndividualModels, const size_t* numberElementsPerSecondModel, const ValueCallback& valueCallback, const ErrorCallback& errorCallback, const SharedModelIsValidCallback& sharedModelIsValidCallback, const SharedModelTransformationCallback& sharedModelTransformationCallback, const FirstIndividualModelTransformationCallback& firstIndividualModelTransformationCallback, const SecondIndividualModelTransformationCallback& secondIndividualModelTransformationCallback, const ModelAcceptedCallback& modelAcceptedCallback, SharedModel& optimizedSharedModel, FirstIndividualModels& optimizedFirstIndividualModels, SecondIndividualModels& optimizedSecondIndividualModels, const unsigned int iterations, const Estimator::EstimatorType estimator, Scalar lambda, const Scalar lambdaFactor, Scalar* initialError, Scalar* finalError, Scalars* intermediateErrors)
1804 {
1805  ocean_assert(&sharedModel != &optimizedSharedModel);
1806  ocean_assert(&firstIndividualModels != &optimizedFirstIndividualModels);
1807  ocean_assert(&secondIndividualModels != &optimizedSecondIndividualModels);
1808 
1809  optimizedSharedModel = sharedModel;
1810  optimizedFirstIndividualModels = firstIndividualModels;
1811  optimizedSecondIndividualModels = secondIndividualModels;
1812 
1813  if (modelAcceptedCallback)
1814  {
1815  modelAcceptedCallback(sharedModel, firstIndividualModels, secondIndividualModels);
1816  }
1817 
1818  UniversalOptimizationProvider provider(optimizedSharedModel, optimizedFirstIndividualModels, optimizedSecondIndividualModels, numberElementsPerSecondModel, valueCallback, errorCallback, sharedModelIsValidCallback, sharedModelTransformationCallback, firstIndividualModelTransformationCallback, secondIndividualModelTransformationCallback, modelAcceptedCallback);
1819  return NonLinearOptimization::sparseOptimization<UniversalOptimizationProvider>(provider, iterations, estimator, lambda, lambdaFactor, initialError, finalError, nullptr, intermediateErrors);
1820 }
1821 
1822 }
1823 
1824 }
1825 
1826 #endif // META_OCEAN_GEOMETRY_NON_LINEAR_UNIVERSAL_OPTIMIZATION_SPARSE_H
This class implements a container for callback functions.
Definition: Callback.h:3456
EstimatorType
Definition of individual robust estimator types.
Definition: Estimator.h:34
@ ET_SQUARE
The standard square error estimator (L2).
Definition: Estimator.h:52
This class implements the base optimization provider.
Definition: NonLinearOptimization.h:293
This class implements the basic functions for least square or robust optimization algorithms for non ...
Definition: NonLinearOptimization.h:34
This class implements a sparse universal optimization provider for universal models and measurement/d...
Definition: NonLinearUniversalOptimizationSparse.h:354
void determineJacobian(SparseMatrix &jacobian) const
Determines the jacobian matrix for the current model.
Definition: NonLinearUniversalOptimizationSparse.h:1193
FirstModels candidateFirstModels_
The universal first models storing the most recent optimization results as candidates.
Definition: NonLinearUniversalOptimizationSparse.h:422
const ModelAcceptedCallback modelAcceptedCallback_
Optional callback function allowing to be informed whenever the model has been improved.
Definition: NonLinearUniversalOptimizationSparse.h:446
size_t overallNumberElements_
The overall number of measurement elements that are used to optimize the models.
Definition: NonLinearUniversalOptimizationSparse.h:431
SecondModels & secondModels_
The universal second models that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:419
const size_t * numberElementsPerSecondModel_
The number of measurement elements for each second model.
Definition: NonLinearUniversalOptimizationSparse.h:428
const FirstModelTransformationCallback firstModelTransformationCallback_
The callback function allowing to transform the first model into an external model before the value a...
Definition: NonLinearUniversalOptimizationSparse.h:440
void applyCorrection(const Matrix &deltas)
Applies the model correction and stores the new model(s) as candidate.
Definition: NonLinearUniversalOptimizationSparse.h:1322
Scalar determineRobustError(Matrix &weightedErrorVector, Matrix &weightVector, const Matrix *invertedCovariances) const
Determines the robust error of the current candidate model(s).
Definition: NonLinearUniversalOptimizationSparse.h:1351
FirstModels & firstModels_
The universal first models that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:416
bool solve(const SparseMatrix &JTJ, const Matrix &jErrors, Matrix &deltas) const
Solves the equation JTJ * deltas = jErrors.
Definition: NonLinearUniversalOptimizationSparse.h:1053
void acceptCorrection()
Accepts the current model candidate as better model.
Definition: NonLinearUniversalOptimizationSparse.h:1434
UniversalOptimizationProvider(FirstModels &firstModels, SecondModels &secondModels, const size_t *numberElementsPerSecondModel, const ValueCallback &valueCallback, const ErrorCallback &errorCallback, const FirstModelTransformationCallback &firstModelTransformationCallback, const SecondModelTransformationCallback &secondModelTransformationCallback, const ModelAcceptedCallback &modelAcceptedCallback=ModelAcceptedCallback())
Creates a new universal optimization object.
Definition: NonLinearUniversalOptimizationSparse.h:1020
bool hasSolver() const
Returns that this provider comes with an own equation solver.
Definition: NonLinearUniversalOptimizationSparse.h:1047
const ErrorCallback errorCallback_
The error calculation callback function.
Definition: NonLinearUniversalOptimizationSparse.h:437
const ValueCallback valueCallback_
The value calculation callback function.
Definition: NonLinearUniversalOptimizationSparse.h:434
const SecondModelTransformationCallback secondModelTransformationCallback_
The callback function allowing to transform the second model into an external model before the value ...
Definition: NonLinearUniversalOptimizationSparse.h:443
SecondModels candidateSecondModels_
The universal second models storing the most recent optimization results as candidates.
Definition: NonLinearUniversalOptimizationSparse.h:425
This class implements an optimization for universal sparse problems with two types of individual mode...
Definition: NonLinearUniversalOptimizationSparse.h:256
StaticBuffer< Scalar, tExternalFirstModelSize > ExternalFirstModel
Definition of the external first model.
Definition: NonLinearUniversalOptimizationSparse.h:267
std::vector< FirstModel > FirstModels
Definition of a vector holding the first models.
Definition: NonLinearUniversalOptimizationSparse.h:287
Callback< void, SecondModel &, ExternalSecondModel & > SecondModelTransformationCallback
Definition of a second model transformation function.
Definition: NonLinearUniversalOptimizationSparse.h:339
StaticBuffer< Scalar, tExternalSecondModelSize > ExternalSecondModel
Definition of the external second model.
Definition: NonLinearUniversalOptimizationSparse.h:277
static bool optimizeUniversalModel(const FirstModels &firstModels, const SecondModels &secondModels, const size_t *numberElementsPerSecondModel, const ValueCallback &valueCallback, const ErrorCallback &errorCallback, const FirstModelTransformationCallback &firstModelTransformationCallback, const SecondModelTransformationCallback &secondModelTransformationCallback, const ModelAcceptedCallback &modelAcceptedCallback, FirstModels &optimizedFirstModels, SecondModels &optimizedSecondModels, const unsigned int iterations=5u, const Estimator::EstimatorType estimator=Estimator::ET_SQUARE, Scalar lambda=Scalar(0.001), const Scalar lambdaFactor=Scalar(5), Scalar *initialError=nullptr, Scalar *finalError=nullptr, Scalars *intermediateErrors=nullptr)
Optimizes a universal model by minimizing the error the model produces.
Definition: NonLinearUniversalOptimizationSparse.h:1446
StaticBuffer< Scalar, tFirstModelSize > FirstModel
Definition of the first model.
Definition: NonLinearUniversalOptimizationSparse.h:262
std::vector< ExternalSecondModel > ExternalSecondModels
Definition of a vector holding the external second models.
Definition: NonLinearUniversalOptimizationSparse.h:302
std::vector< ExternalFirstModel > ExternalFirstModels
Definition of a vector holding the external first models.
Definition: NonLinearUniversalOptimizationSparse.h:292
Callback< bool, const ExternalFirstModels &, const ExternalSecondModels &, const size_t, const size_t, Result & > ErrorCallback
Definition of a callback function for sparse error calculation.
Definition: NonLinearUniversalOptimizationSparse.h:323
Callback< void, const FirstModels &, const SecondModels & > ModelAcceptedCallback
Definition of a model accepted function.
Definition: NonLinearUniversalOptimizationSparse.h:346
Callback< void, FirstModel &, ExternalFirstModel & > FirstModelTransformationCallback
Definition of a first model transformation function.
Definition: NonLinearUniversalOptimizationSparse.h:331
StaticBuffer< Scalar, tSecondModelSize > SecondModel
Definition of the second model.
Definition: NonLinearUniversalOptimizationSparse.h:272
StaticBuffer< Scalar, tResultDimension > Result
Definition of a model result.
Definition: NonLinearUniversalOptimizationSparse.h:282
Callback< size_t, const ExternalFirstModels &, const ExternalSecondModels &, const size_t, const size_t, Result & > ValueCallback
Definition of a callback function for sparse value calculation.
Definition: NonLinearUniversalOptimizationSparse.h:313
std::vector< SecondModel > SecondModels
Definition of a vector holding the first models.
Definition: NonLinearUniversalOptimizationSparse.h:297
This class implements a sparse universal optimization provider for universal models and measurement/d...
Definition: NonLinearUniversalOptimizationSparse.h:614
const SharedModelIsValidCallback sharedModelIsValidCallback_
The callback function determining whether a shared model is valid.
Definition: NonLinearUniversalOptimizationSparse.h:694
SharedModel & sharedModel_
The universal shared model that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:664
const ValueCallback valueCallback_
The value calculation callback function.
Definition: NonLinearUniversalOptimizationSparse.h:688
SecondIndividualModels & secondIndividualModels_
The universal second individual models that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:670
const ModelAcceptedCallback modelAcceptedCallback_
Optional callback function allowing to be informed whenever the model has been improved.
Definition: NonLinearUniversalOptimizationSparse.h:706
Scalar determineRobustError(Matrix &weightedErrorVector, Matrix &weightVector, const Matrix *invertedCovariances) const
Determines the robust error of the current candidate model(s).
Definition: NonLinearUniversalOptimizationSparse.h:1697
void acceptCorrection()
Accepts the current model candidate as better model.
Definition: NonLinearUniversalOptimizationSparse.h:1790
const SharedModelTransformationCallback sharedModelTransformationCallback_
The callback function allowing to transform the shared model into an external model before the value ...
Definition: NonLinearUniversalOptimizationSparse.h:697
SecondIndividualModels candidateSecondIndividualModels_
The universal second individual models storing the most recent optimization results as candidates.
Definition: NonLinearUniversalOptimizationSparse.h:679
void applyCorrection(const Matrix &deltas)
Applies the model correction and stores the new model(s) as candidate.
Definition: NonLinearUniversalOptimizationSparse.h:1661
FirstIndividualModels & firstIndividualModels_
The universal first individual models that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:667
const SecondIndividualModelTransformationCallback secondIndividualModelTransformationCallback_
The callback function allowing to transform the second model into an external model before the value ...
Definition: NonLinearUniversalOptimizationSparse.h:703
const ErrorCallback errorCallback_
The error calculation callback function.
Definition: NonLinearUniversalOptimizationSparse.h:691
UniversalOptimizationProvider(SharedModel &sharedModel, FirstIndividualModels &firstIndividualModels, SecondIndividualModels &secondIndividualModels, const size_t *numberElementsPerSecondModel, const ValueCallback &valueCallback, const ErrorCallback &errorCallback, const SharedModelIsValidCallback &sharedModelIsValidCallback, const SharedModelTransformationCallback &sharedModelTransformationCallback, const FirstIndividualModelTransformationCallback &firstIndividualModelTransformationCallback, const SecondIndividualModelTransformationCallback &secondIndividualModelTransformationCallback, const ModelAcceptedCallback &modelAcceptedCallback=ModelAcceptedCallback())
Creates a new universal optimization object.
Definition: NonLinearUniversalOptimizationSparse.h:1464
const size_t * numberElementsPerSecondModel_
The number of measurement elements for each second model.
Definition: NonLinearUniversalOptimizationSparse.h:682
SharedModel candidateSharedModel_
The universal shared model storing the most recent optimization result as candidate.
Definition: NonLinearUniversalOptimizationSparse.h:673
void determineJacobian(SparseMatrix &jacobian) const
Determines the jacobian matrix for the current model.
Definition: NonLinearUniversalOptimizationSparse.h:1496
const FirstIndividualModelTransformationCallback firstIndividualModelTransformationCallback_
The callback function allowing to transform the first individual model into an external model before ...
Definition: NonLinearUniversalOptimizationSparse.h:700
FirstIndividualModels candidateFirstIndividualModels_
The universal first individual models storing the most recent optimization results as candidates.
Definition: NonLinearUniversalOptimizationSparse.h:676
size_t overallNumberElements_
The overall number of measurement elements that are used to optimize the models.
Definition: NonLinearUniversalOptimizationSparse.h:685
This class implements a sparse universal optimization provider for universal models and measurement/d...
Definition: NonLinearUniversalOptimizationSparse.h:134
SharedModel candidateSharedModel_
Universal shared model that stores the most recent optimization result as candidate.
Definition: NonLinearUniversalOptimizationSparse.h:188
IndividualModels candidateIndividualModels_
Universal individual model that stores the most recent optimization result as candidate.
Definition: NonLinearUniversalOptimizationSparse.h:191
size_t overallNumberElements_
The overall number of measurement elements that are used to optimize the models.
Definition: NonLinearUniversalOptimizationSparse.h:197
const ModelAcceptedCallback modelAcceptedCallback_
Optional callback function allowing to be informed whenever the model has been improved.
Definition: NonLinearUniversalOptimizationSparse.h:215
IndividualModels & individualModels_
Universal individual model that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:185
Scalar determineRobustError(Matrix &weightedErrorVector, Matrix &weightVector, const Matrix *invertedCovariances) const
Determines the robust error of the current candidate model(s).
Definition: NonLinearUniversalOptimizationSparse.h:904
void determineJacobian(SparseMatrix &jacobian) const
Determines the jacobian matrix for the current model.
Definition: NonLinearUniversalOptimizationSparse.h:768
void applyCorrection(const Matrix &deltas)
Applies the model correction and stores the new model(s) as candidate.
Definition: NonLinearUniversalOptimizationSparse.h:880
const IndividualModelTransformationCallback individualModelTransformationCallback_
The callback function allowing to transform the individual model into an external model before the va...
Definition: NonLinearUniversalOptimizationSparse.h:212
const size_t * numberElementsPerIndividualModel_
The number of measurement elements that are used to optimize each individual model.
Definition: NonLinearUniversalOptimizationSparse.h:194
const SharedModelTransformationCallback sharedModelTransformationCallback_
The callback function allowing to transform the shared model into an external model before the value ...
Definition: NonLinearUniversalOptimizationSparse.h:209
SharedModel & sharedModel_
Universal shared model that will be optimized.
Definition: NonLinearUniversalOptimizationSparse.h:182
const ValueCallback valueCallback_
The value calculation callback function.
Definition: NonLinearUniversalOptimizationSparse.h:200
const ErrorCallback errorCallback_
The error calculation callback function.
Definition: NonLinearUniversalOptimizationSparse.h:203
void acceptCorrection()
Accepts the current model candidate as better model.
Definition: NonLinearUniversalOptimizationSparse.h:990
const SharedModelIsValidCallback sharedModelIsValidCallback_
The callback function determining whether a shared model is valid.
Definition: NonLinearUniversalOptimizationSparse.h:206
UniversalOptimizationProvider(SharedModel &sharedModel, IndividualModels &individualModels, const size_t *numberElementsPerIndividualModel, const ValueCallback &valueCallback, const ErrorCallback &errorCallback, const SharedModelIsValidCallback &sharedModelIsValidCallback, const SharedModelTransformationCallback &sharedModelTransformationCallback, const IndividualModelTransformationCallback &individualModelTransformationCallback, const ModelAcceptedCallback &modelAcceptedCallback=ModelAcceptedCallback())
Creates a new universal optimization object.
Definition: NonLinearUniversalOptimizationSparse.h:741
This class implements an optimization for universal sparse problems with one shared model (optimizati...
Definition: NonLinearUniversalOptimizationSparse.h:39
Callback< bool, const ExternalSharedModel &, const ExternalIndividualModel &, const size_t, const size_t, Result & > ErrorCallback
Definition of a callback function for sparse error calculation.
Definition: NonLinearUniversalOptimizationSparse.h:91
StaticBuffer< Scalar, tExternalIndividualModelSize > ExternalIndividualModel
Definition of an external individual model.
Definition: NonLinearUniversalOptimizationSparse.h:60
StaticBuffer< Scalar, tIndividualModelSize > IndividualModel
Definition of an individual model.
Definition: NonLinearUniversalOptimizationSparse.h:55
StaticBuffer< Scalar, tExternalSharedModelSize > ExternalSharedModel
Definition of an external shared model.
Definition: NonLinearUniversalOptimizationSparse.h:50
std::vector< IndividualModel > IndividualModels
Definition of a vector holding individual models.
Definition: NonLinearUniversalOptimizationSparse.h:70
std::vector< ExternalIndividualModel > ExternalIndividualModels
Definition of a vector holding individual models.
Definition: NonLinearUniversalOptimizationSparse.h:128
Callback< void, const SharedModel &, const IndividualModels & > ModelAcceptedCallback
Definition of a model accepted function.
Definition: NonLinearUniversalOptimizationSparse.h:121
Callback< bool, const ExternalSharedModel & > SharedModelIsValidCallback
Definition of a callback function determining whether a shared model is valid.
Definition: NonLinearUniversalOptimizationSparse.h:98
Callback< void, const ExternalSharedModel &, const ExternalIndividualModel &, const size_t, const size_t, Result & > ValueCallback
Definition of a callback function for sparse value calculation.
Definition: NonLinearUniversalOptimizationSparse.h:80
Callback< void, IndividualModel &, ExternalIndividualModel & > IndividualModelTransformationCallback
Definition of an individual model transformation function.
Definition: NonLinearUniversalOptimizationSparse.h:114
StaticBuffer< Scalar, tResultDimension > Result
Definition of a model result.
Definition: NonLinearUniversalOptimizationSparse.h:65
static bool optimizeUniversalModel(const SharedModel &sharedModel, const IndividualModels &individualModels, const size_t *numberElementsPerIndividualModel, const ValueCallback &valueCallback, const ErrorCallback &errorCallback, const SharedModelIsValidCallback &sharedModelIsValidCallback, const SharedModelTransformationCallback &sharedModelTransformationCallback, const IndividualModelTransformationCallback &individualModelTransformationCallback, const ModelAcceptedCallback &modelAcceptedCallback, SharedModel &optimizedSharedModel, IndividualModels &optimizedIndividualModels, const unsigned int iterations=5u, const Estimator::EstimatorType estimator=Estimator::ET_SQUARE, Scalar lambda=Scalar(0.001), const Scalar lambdaFactor=Scalar(5), Scalar *initialError=nullptr, Scalar *finalError=nullptr, Scalars *intermediateErrors=nullptr)
Optimizes a universal model by minimizing the error the model produces.
Definition: NonLinearUniversalOptimizationSparse.h:1002
Callback< void, SharedModel &, ExternalSharedModel & > SharedModelTransformationCallback
Definition of a shared model transformation function.
Definition: NonLinearUniversalOptimizationSparse.h:106
StaticBuffer< Scalar, tSharedModelSize > SharedModel
Definition of a shared model.
Definition: NonLinearUniversalOptimizationSparse.h:45
This class implements an optimization for universal sparse problems with one common shared model (opt...
Definition: NonLinearUniversalOptimizationSparse.h:488
StaticBuffer< Scalar, tFirstIndividualModelSize > FirstIndividualModel
Definition of the first individual model.
Definition: NonLinearUniversalOptimizationSparse.h:504
Callback< void, FirstIndividualModel &, ExternalFirstIndividualModel & > FirstIndividualModelTransformationCallback
Definition of a transformation function for the first individual models.
Definition: NonLinearUniversalOptimizationSparse.h:590
StaticBuffer< Scalar, tSecondIndividualModelSize > SecondIndividualModel
Definition of the second individual model.
Definition: NonLinearUniversalOptimizationSparse.h:514
Callback< bool, const ExternalSharedModel & > SharedModelIsValidCallback
Definition of a callback function determining whether a shared model is valid.
Definition: NonLinearUniversalOptimizationSparse.h:574
StaticBuffer< Scalar, tSharedModelSize > SharedModel
Definition of the shared model.
Definition: NonLinearUniversalOptimizationSparse.h:494
Callback< size_t, const ExternalSharedModel &, const ExternalFirstIndividualModels &, const ExternalSecondIndividualModels &, const size_t, const size_t, Result & > ValueCallback
Definition of a callback function for sparse value calculation.
Definition: NonLinearUniversalOptimizationSparse.h:556
StaticBuffer< Scalar, tExternalFirstIndividualModelSize > ExternalFirstIndividualModel
Definition of the external first individual model.
Definition: NonLinearUniversalOptimizationSparse.h:509
StaticBuffer< Scalar, tExternalSharedModelSize > ExternalSharedModel
Definition of the external shared model.
Definition: NonLinearUniversalOptimizationSparse.h:499
static bool optimizeUniversalModel(const SharedModel &sharedModel, const FirstIndividualModels &firstIndividualModels, const SecondIndividualModels &secondIndividualModels, const size_t *numberElementsPerSecondModel, const ValueCallback &valueCallback, const ErrorCallback &errorCallback, const SharedModelIsValidCallback &sharedModelIsValidCallback, const SharedModelTransformationCallback &sharedModelTransformationCallback, const FirstIndividualModelTransformationCallback &firstIndividualModelTransformationCallback, const SecondIndividualModelTransformationCallback &secondIndividualModelTransformationCallback, const ModelAcceptedCallback &modelAcceptedCallback, SharedModel &optimizedSharedModel, FirstIndividualModels &optimizedFirstIndividualModels, SecondIndividualModels &optimizedSecondIndividualModels, const unsigned int iterations=5u, const Estimator::EstimatorType estimator=Estimator::ET_SQUARE, Scalar lambda=Scalar(0.001), const Scalar lambdaFactor=Scalar(5), Scalar *initialError=nullptr, Scalar *finalError=nullptr, Scalars *intermediateErrors=nullptr)
Optimizes a universal model by minimizing the error the model produces.
Definition: NonLinearUniversalOptimizationSparse.h:1803
std::vector< ExternalFirstIndividualModel > ExternalFirstIndividualModels
Definition of a vector holding the external first individual models.
Definition: NonLinearUniversalOptimizationSparse.h:534
StaticBuffer< Scalar, tResultDimension > Result
Definition of a model result.
Definition: NonLinearUniversalOptimizationSparse.h:524
std::vector< FirstIndividualModel > FirstIndividualModels
Definition of a vector holding the first individual models.
Definition: NonLinearUniversalOptimizationSparse.h:529
std::vector< ExternalSecondIndividualModel > ExternalSecondIndividualModels
Definition of a vector holding the external second individual models.
Definition: NonLinearUniversalOptimizationSparse.h:544
StaticBuffer< Scalar, tExternalSecondIndividualModelSize > ExternalSecondIndividualModel
Definition of the external second individual model.
Definition: NonLinearUniversalOptimizationSparse.h:519
Callback< void, SecondIndividualModel &, ExternalSecondIndividualModel & > SecondIndividualModelTransformationCallback
Definition of a transformation function for the second individual models.
Definition: NonLinearUniversalOptimizationSparse.h:598
std::vector< SecondIndividualModel > SecondIndividualModels
Definition of a vector holding the first individual models.
Definition: NonLinearUniversalOptimizationSparse.h:539
Callback< void, SharedModel &, ExternalSharedModel & > SharedModelTransformationCallback
Definition of a transformation function for the shared model.
Definition: NonLinearUniversalOptimizationSparse.h:582
Callback< void, const SharedModel &, const FirstIndividualModels &, const SecondIndividualModels & > ModelAcceptedCallback
Definition of a model accepted function.
Definition: NonLinearUniversalOptimizationSparse.h:606
Callback< bool, const ExternalSharedModel &, const ExternalFirstIndividualModels &, const ExternalSecondIndividualModels &, const size_t, const size_t, Result & > ErrorCallback
Definition of a callback function for sparse error calculation.
Definition: NonLinearUniversalOptimizationSparse.h:567
This class implements optimizations for universal sparse problems.
Definition: NonLinearUniversalOptimizationSparse.h:25
size_t columns() const
Returns the count of columns.
Definition: Matrix.h:698
const T * data() const
Returns a pointer to the internal values.
Definition: Matrix.h:798
size_t rows() const
Returns the count of rows.
Definition: Matrix.h:692
void resize(const size_t rows, const size_t columns)
Resizes this matrix.
static constexpr T weakEps()
Returns a weak epsilon.
static T abs(const T value)
Returns the absolute value of a given value.
Definition: Numeric.h:1220
static T summedSqr(const T *values, const size_t number)
Returns the summed squares of a given values.
Definition: Numeric.h:1514
static constexpr T maxValue()
Returns the max scalar value.
Definition: Numeric.h:3244
static bool hasOneEntry(const size_t rows, const size_t columns, const Entries &entries)
Checks whether a set of given entries have at least one entry in each row and in each column of a mat...
This class implements a sparse matrix using a float type for its elements that is specified by T.
Definition: SparseMatrix.h:61
bool invertBlockDiagonal3()
Inverts this square block diagonal matrix with 3x3 block size.
SparseMatrixT< T > submatrix(const size_t row, const size_t column, const size_t rows, const size_t columns) const
Returns a submatrix of this matrix.
size_t rows() const
Returns the number of rows this matrix has.
std::vector< Entry > Entries
Definition of a vector holding entries.
Definition: SparseMatrix.h:65
size_t columns() const
Returns the number of columns this matrix has.
bool invertDiagonal()
Inverts this square diagonal matrix.
bool invertBlockDiagonal(const size_t size)
Inverts this square block diagonal matrix with size x size block size.
const T * data() const
Returns the buffer data pointer.
Definition: StaticBuffer.h:240
SparseMatrixT< Scalar > SparseMatrix
Definition of the SparseMatrix object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with s...
Definition: SparseMatrix.h:23
float Scalar
Definition of a scalar type.
Definition: Math.h:128
std::vector< Scalar > Scalars
Definition of a vector holding Scalar objects.
Definition: Math.h:144
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15