Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Minpack.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "Minpack.hh"
27 //#include <Base/Math/tnt/fortran.h>
28 #include <Base/Common/CompareFloatingPoint.hh>
29 #include <MathAlgo/minpack/cminpack.h>
30 
31 using namespace std;
32 
33 namespace BIAS
34 {
35  long int Powell(minpack_func_nn fun, void *p,
36  Vector<double>& InitialGuess, Vector<double>& Result,
37  double Tolerance)
38  {
39  // Call function HYBRD1 from minpack
40 
41  long int n = InitialGuess.Size();
42  long int lwa = (n*(3*n+13))/2;
43  double *wa = new double[lwa];
44  Result = InitialGuess;
45  Vector<double> FuncVec(n);
46  long int ret = (long int)hybrd1(fun, p,n, Result.GetData(), FuncVec.GetData(),
47  Tolerance, wa, lwa);
48 
49  // Release memory
50  delete[] wa;
51 
52  // Return 0 in case of convergence, <0 otherwise
53  return (ret > 0 && ret < 5) ? 0 : (ret == 0 ? -1 : ret);
54  }
55 
56  long int PowellExtended(minpack_func_nn fun, void *p,
57  Vector<double>& InitialGuess, Vector<double>& Result,
58  double EpsilonFun, double Tolerance)
59  {
60  // Call function HYBRD from minpack
61 
62  long int n = InitialGuess.Size();
63  double *wa = new double[4*n];
64  Result = InitialGuess;
65  Vector<double> FuncVec(n);
66  long int maxfev = 200*(n + 1);
67  long int ml = n - 1;
68  long int mu = n - 1;
69  long int mode = 2;
70  long int lr = (n*(n + 1))/2;
71  double factor = 1.0;
72  long int nprint = 0;
73  double *diag = new double[n];
74  for (long int i = 0; i < n; i++) diag[i] = 1.0;
75  //long int nfev;
76  int nfev;
77  double *fjac = new double[n*n];
78  long int ldfjac = n;
79  double *r = new double[lr];
80  double *qtf = new double[n];
81  long int ret = (long int)hybrd(fun, p, n, Result.GetData(), FuncVec.GetData(), Tolerance,
82  maxfev, ml, mu, EpsilonFun, diag, mode, factor, nprint,
83  &nfev, fjac, ldfjac, r, lr, qtf,
84  &wa[0], &wa[n], &wa[2*n], &wa[3*n]);
85 
86  // Release memory
87  delete[] wa;
88  delete[] fjac;
89  delete[] r;
90  delete[] qtf;
91  delete[] diag;
92 
93  // Return 0 in case of convergence, <0 otherwise
94  return (ret > 0 && ret < 5) ? 0 : (ret == 0 ? -1 : ret);
95  }
96 
97  long int LevenbergMarquardt(minpack_funcder_mn fun, void *p,
98  long int m, long int n, Vector<double>& InitialGuess,
99  Vector<double>& Result, double Tolerance)
100  {
101 #ifdef BIAS_DEBUG
102  if (m < n) {
103  BIASERR("Target function is underdetermined (" << m << " residuals < "
104  << n << " parameters!");
105  }
106 #endif
107 
108  // Call function LMDER1 from minpack
109 
110  Result = InitialGuess;
111  Vector<double> FuncVec(m);
112  double *fjac = new double[m*n];
113  long int ldfjac = n;
114  //long int *ipvt = new long int[n];
115  int *ipvt = new int[n];
116  long int lwa = 5*n+m;
117  double *wa=new double[lwa];
118  long int ret = (long int)lmder1(fun, p, m, n, Result.GetData(), FuncVec.GetData(), fjac,
119  ldfjac, Tolerance, ipvt, wa, lwa);
120 
121  // Release memory
122  delete[] fjac;
123  delete[] ipvt;
124  delete[] wa;
125 
126  // Return 0 in case of convergence, <0 otherwise
127  return (ret > 0 && ret < 5) ? 0 : (ret == 0 ? -1 : ret);
128  }
129 
130 
131  long int LevenbergMarquardtExtended(minpack_funcder_mn fun,
132  void *p,
133  long int m, long int n,
134  Vector<double>& InitialGuess,
135  Vector<double>& Result,
136  double Tolerance,
137  long int MaxIter)
138  {
139 #ifdef BIAS_DEBUG
140  if (m < n) {
141  BIASERR("Target function is underdetermined (" << m << " residuals < "
142  << n << " parameters!");
143  }
144 #endif
145 
146  // Call function LMDER from minpack
147 
148  Result = InitialGuess;
149  Vector<double> FuncVec(m);
150  long int maxfev = (MaxIter == LM_DEF_MAX_ITER) ? 200*(n + 1) : MaxIter;
151  // Algorithm terminates when change in residuum is less than ftol
152  // or change in solution vector is less than xtol
153  double ftol = Tolerance;
154  double xtol = Tolerance;
155  double gtol = 0.0; // = Tolerance;
156  long int mode = 1;
157  long int nprint = 0;
158  double *diag = new double[n];
159  double factor = 1.0;
160  int *iptv = new int[n];
161  double *qtf = new double[n];
162  double *wa = new double[m+3*n];
163  //long int nfev, njfev;
164  int nfev, njfev;
165  double *fjac = new double[m*n];
166  long int ldfjac = m;
167  long int ret = (long int)lmder(fun, p, m, n, Result.GetData(),
168  FuncVec.GetData(), fjac, ldfjac,
169  ftol, xtol, gtol, maxfev, diag,
170  mode, factor, nprint, &nfev, &njfev, iptv, qtf,
171  &wa[0], &wa[n], &wa[2*n], &wa[3*n]);
172 
173  // Release memory
174  delete[] diag;
175  delete[] iptv;
176  delete[] qtf;
177  delete[] wa;
178  delete[] fjac;
179 
180  // Return 0 in case of convergence, <0 otherwise
181  return (ret > 0 && ret < 5) ? 0 : (ret == 0 ? -1 : ret);
182  }
183 
184  long int LevenbergMarquardt(minpack_func_mn fun,void *p,
185  long int m, long int n, Vector<double>& InitialGuess,
186  Vector<double>& Result, double Tolerance, long int MaxIter)
187  {
188 #ifdef BIAS_DEBUG
189  if (m < n) {
190  BIASERR("Target function is underdetermined (" << m << " residuals < "
191  << n << " parameters!");
192  }
193  if (MaxIter != LM_DEF_MAX_ITER) {
194  BIASWARN("Parameter MaxIter is not used and should be removed here!");
195  }
196 #endif
197 
198  // Call function LMDIF1 from minpack
199 
200  Result = InitialGuess;
201  Vector<double> FuncVec(m);
202  //long int *iwa = new long int[n];
203  int *iwa = new int[n];
204  long int lwa = m*n+5*n+m;
205  double *wa = new double[lwa];
206  long int ret = (long int)lmdif1(fun, p, m, n, Result.GetData(), FuncVec.GetData(),
207  Tolerance, iwa, wa, lwa);
208 
209  // Release memory
210  delete[] iwa;
211  delete[] wa;
212 
213  // Return 0 in case of convergence, <0 otherwise
214  return (ret > 0 && ret < 5) ? 0 : (ret == 0 ? -1 : ret);
215  }
216 
217 
218  long int LevenbergMarquardtExtended(minpack_func_mn fun,
219  void *p,
220  long int num_errors,
221  long int num_vars,
222  Vector<double>& InitialGuess,
223  Vector<double>& Result,
224  double EpsilonFun,
225  double Tolerance,
226  long int MaxIter,
227  double* fjac,
228  int* ipvt,
229  double *SumOfSquaredErrors)
230  {
231 #ifdef BIAS_DEBUG
232  if (num_errors < num_vars) {
233  BIASERR("Target function is underdetermined (" << num_errors
234  << " residuals < " << num_vars << " parameters!");
235  }
236 #endif
237 
238  // Call function LMDIF from minpack
239 
240  long int ret;
241  Result = InitialGuess;
242  Vector<double> FuncVec(num_errors);
243  long int maxfev = (MaxIter == LM_DEF_MAX_ITER) ? 200*(num_vars + 1) : MaxIter;
244  // Algorithm terminates when change in residuum is less than ftol
245  // or change in solution vector is less than xtol
246  double ftol = Tolerance;
247  double xtol = Tolerance;
248  double gtol = Tolerance; // = 0.0;
249  long int mode = 1;
250  long int nprint = 0;
251  double *diag = new double[num_vars];
252  double factor = 1.0;
253  const bool ExhaustiveData =
254  (fjac != NULL) && (ipvt != NULL) && (SumOfSquaredErrors != NULL);
255  if (!ExhaustiveData) {
256  fjac = new double[num_vars*num_errors];
257  ipvt = new int[num_vars];
258  }
259  const long int ldfjac = num_errors;
260  double *qtf = new double[num_vars];
261  double *wa = new double[num_errors+3*num_vars];
262  //long int nfev;
263  int nfev;
264  ret = (long int)lmdif(fun, p, num_errors, num_vars, Result.GetData(),
265  FuncVec.GetData(), ftol, xtol,
266  gtol, maxfev, EpsilonFun, diag, mode, factor, nprint,
267  &nfev, fjac, ldfjac, ipvt, qtf, &wa[0], &wa[num_vars],
268  &wa[2*num_vars], &wa[3*num_vars]);
269 
270  // Release memory
271  delete[] diag;
272  if (!ExhaustiveData) {
273  delete[] fjac;
274  delete[] ipvt;
275  } else {
276  // Computes sum of squared errors in output parameter
277  *SumOfSquaredErrors = 0;
278  for (long int i = 0; i < num_vars; i++)
279  *SumOfSquaredErrors += qtf[i]*qtf[i];
280  }
281  delete[] qtf;
282  delete[] wa;
283 
284  // Return 0 in case of convergence, <0 otherwise
285  return (ret > 0 && ret < 5) ? 0 : (ret == 0 ? -1 : ret);
286  }
287 
288 
289  long int ComputeCovariance(long int NumErrors, long int NumParams, double *Jac,
290  int *Permutation, double &SumOfSquaredErrors,
291  Matrix<double>& Cov)
292  {
293  // Compute covariance from Levenberg-Marquardt results
294 
295  Matrix<double>mJac(NumParams, NumErrors);
296  Vector<int> mperm(NumParams);
297  memcpy(mJac.GetData(), Jac, NumErrors*NumParams*sizeof(double));
298  memcpy(mperm.GetData(), Permutation, NumParams*sizeof(int));
299  return ComputeCovariance(NumErrors, NumParams, mJac, mperm,
300  SumOfSquaredErrors, Cov);
301  }
302 
303 
304  long int ComputeCovariance(const long int NumErrors, const long int NumParams,
305  const Matrix<double> &Jac,
306  const Vector<int>& Permutation,
307  const double &SumOfSquaredErrors,
308  Matrix<double>& Cov)
309  {
310  // Compute covariance from Levenberg-Marquardt results
311 
312  // Enforce correct size for covariance matrix
313  Cov.newsize(NumParams, NumParams);
314 
315  // Buffer for intermediate results
316  Matrix<double> TMP(NumParams, NumParams), P(NumParams, NumParams);
317 
318  // Compute matrix R out of Levenberg-Marquardt Jacobian J(x),
319  // citing minpack documentation (where ipvt is Permutation in our code):
320  //
321  // "fjac is an output m by n array. The upper n by n submatrix
322  // of fjac contains an upper triangular matrix R with
323  // diagonal elements of nonincreasing magnitude such that
324  //
325  // T T T
326  // P *(Jac *Jac)*P = R *R,
327  //
328  // where P is a permutation matrix and Jac is the final
329  // calculated Jacobian. Column j of P is column ipvt(j)
330  // (see below) of the identity matrix. The lower trapezoidal
331  // part of fjac contains information generated during
332  // the computation of R."
333 
334  int row, column, k;
335  for (row = 0; row < NumParams; row++)
336  for (column = 0; column < NumParams; column++)
337  Cov[row][column] = (column<row) ? 0.0 : Jac[column][row];
338 
339  // Invert upper triangular matrix R
340  double s;
341  for (row = 0; row < NumParams; row++) {
342  // invert main diagonal
343  Cov[row][row] = (Equal(Cov[row][row], 0.0)) ? 0.0 : 1.0 / Cov[row][row];
344  // upper right triangle part
345  for (column = row + 1; column < NumParams; column++) {
346  s = 0;
347  for (k = row; k < column; k++) {
348  s -= Cov[row][k] * Cov[k][column];
349  }
350  Cov[row][column] =
351  (Equal(Cov[row][column], 0.0)) ? 0.0 : s / Cov[column][column];
352  }
353  }
354 
355  // Calculation of R^-1 * R^-T
356  for (row = 0; row < NumParams; row++) {
357  for (column = 0; column < NumParams; column++) {
358  TMP[row][column] = 0;
359  for (k = 0; k < NumParams; k++) {
360  TMP[row][column] += Cov[row][k] * Cov[column][k];
361  }
362  }
363  }
364 
365  // Copy temporary buffer into covariance matrix
366  memcpy(Cov.GetData(), TMP.GetData(),
367  NumParams * NumParams * sizeof(double) );
368 
369  // Construct permutation matrix P
370  P.SetZero();
371  for (row = 0; row < NumParams; row++) {
372  P[Permutation[row]-1][row] = 1;
373  }
374 
375 
376  // Compute (R^-1 * R^-T) * P^T
377  for (row = 0; row < NumParams; row++) {
378  for (column = 0; column < NumParams; column++) {
379  TMP[row][column] = 0;
380  for (k = 0; k < NumParams; k++) {
381  TMP[row][column] += Cov[row][k] * P[column][k];
382  }
383  }
384  }
385 
386  // Compute normalization scale sigma0^2 for covariance matrix
387  double sigma0squared;
388  if (NumErrors > NumParams) {
389  sigma0squared = SumOfSquaredErrors / (double)(NumErrors - NumParams);
390  } else {
391  BIASERR("Covariance approximation is not valid, NumErrors = NumParams!");
392  sigma0squared = SumOfSquaredErrors;
393  BIASABORT;
394  return -1;
395  }
396 
397  // Set Cov = P * (R^-1 R^-T * P^T)
398  P.Mult(TMP, Cov);
399 
400  // Normalize scale of covariance matrix
401  Cov.MultiplyIP(sigma0squared);
402 
403  return 0;
404  }
405 
406  void CheckJacobian(minpack_funcder_mn fun, void *p,
407  const long int NumErrors, const Vector<double> &x,
408  Vector<double> &error)
409  {
410  // Check Jacobian matrix J(x) with minpack functions CHKDER
411 
412  long int m = NumErrors;
413  long int n = (long int)x.size();
414  long int ldfjac = n;
415  Vector<double> mx = x, xp(n);
416  Matrix<double> fjac(NumErrors, n);
417  Vector<double> fvec(NumErrors), fvecp(NumErrors);
418  error.newsize(NumErrors);
419 
420  long int mode = 1;
421  long int iflag = 1;
422 
423  // Compute xp and Jacobian numerically
424  chkder(m, n, mx.GetData(), fvec.GetData(), fjac.GetData(),
425  ldfjac, xp.GetData(), fvecp.GetData(), mode, error.GetData());
426 
427  // Evaluate the function at x and put into fvec
428  fun(p, m, n, mx.GetData(), fvec.GetData(), fjac.GetData(), ldfjac, iflag);
429 
430  // Evaluate the function at xp and put into fvecp
431  fun(p, m, n, xp.GetData(), fvecp.GetData(), fjac.GetData(), ldfjac,iflag);
432 
433  // Compute the Jacobian at x and put into fjac
434  iflag = 2;
435  fun(p, m, n, mx.GetData(), fvec.GetData(), fjac.GetData(), ldfjac, iflag);
436 
437  // Now compare Jacobian and numerically computed Jacobian
438  mode = 2;
439  chkder(m, n, mx.GetData(), fvec.GetData(), fjac.GetData(), ldfjac,
440  xp.GetData(), fvecp.GetData(), mode, error.GetData());
441  }
442 
443  long int ComputeJacobian(minpack_func_mn fun,void *p,
444  const int NumErrors,
445  const Vector<double> &x, Matrix<double>& fjac,
446  const double gradientEpsilon)
447  {
448  // Call function FDJAC2 from minpack to compute Jacobian
449 
450  long int m = NumErrors;
451  long int n = (long int)x.size();
452  // The leading dimension in BIAS matrix data is the number of columns
453  long int ldfjac = m;
454  Vector<double> mx = x;
455  Matrix<double> mfjac(n, m);
456  Vector<double> fvec(NumErrors);
457  long int iflag = 0;
458  double eps = gradientEpsilon;
459  double *wa = new double[m];
460  BIASASSERT(wa);
461 
462  // Fill function residual vector fvec
463  fun(p, m, n, mx.GetData(), fvec.GetData(), iflag);
464  long int ret = fdjac2(fun, p, m, n, mx.GetData(), fvec.GetData(),
465  mfjac.GetData(), ldfjac, eps, wa);
466  fjac = mfjac.Transpose();
467 
468  // Release memory
469  delete[] wa;
470  return (ret == 0 ? 0 : -1);
471  }
472 
474  {
475  // Call method QRFAC from minpack
476 
477  const unsigned int m = A.GetRows();
478  const unsigned int n = A.GetCols();
479  if((Q.GetCols()!=m)||(Q.GetRows()!=m)){
480  Q.newsize(m,m);
481  }
482  if((R.GetCols()!=n)||(R.GetRows()!=m)){
483  R.newsize(m,n);
484  }
485  Q.SetIdentity();
486  R.SetZero();
487  double *A_Data = new double[m*n];
488 
489  // Note that the matrix is stored in row major in BIAS matrix, but it is stored in
490  // in column major in LAPACK. So the return from A.GetData() cannot be directly
491  // used as the input of qrfac function. If you do so, you will get the QR
492  // decomposition of matrix AT's, but not of A!
493  for(unsigned int j=0; j<n; j++){
494  for(unsigned int i=0; i<m; i++){
495  A_Data[j*m + i] = A[i][j];
496  }
497  }
498  const int lda = m; // the leading dimension of array A_Data is the number of rows
499  const int pivot = 0; // pivot is set false, so no column pivoting is done
500  int *ipvt = NULL; // pivot is false, so ipvt is not referenced
501  const int lipvt = 1; // pivot is false, so lipvt may be as small as 1
502  double *rdiag = new double[n]; // an output array of length n which contains the
503  // diagonal elements of R
504  double *acnorm = new double[n]; // acnorm is coincide with rdiag which contains the
505  // norms of the corresponding columns of input matrix A
506  double *wa = new double[n]; // pivot is false, so wa can coincide with rdiag.
507  qrfac(m, n, A_Data, lda, pivot, ipvt, lipvt, rdiag, acnorm, wa);
508 
509  // On output, the strict upper trapezoidal part of A_Data contains the strict
510  // upper trapezoidal part of R, and the lower trapezoidal part of A_Data contains
511  // a factored form of Q. C.f. "minpack\qrfac.c" for details.
512 
513  // First save the result of R
514  for(unsigned int j = 0; j < n; j++){
515  for(unsigned int i = 0; i <= j && i < m; i++){
516  if (i == j) {
517  R[i][j] = rdiag[j];
518  } else {
519  R[i][j] = A_Data[j*m+i];
520  }
521  }
522  }
523 
524  // Then save the result of Q
525  Vector<double> vec(m);
526  Matrix<double> Qk(m,m);
527  Matrix<double> I(m,m);
528  I.SetIdentity();
529  for (unsigned int j = 0; j < n && j < m; j++) {
530  vec.SetZero();
531  for (unsigned int i = j; i < m; i++) {
532  vec[i] = A_Data[j*m+i];
533  }
534  Qk = I - (1/vec[j]) * vec.OuterProduct(vec);
535  Q = Q * Qk.Transpose();
536  }
537 
538  // Release memory
539  delete[] A_Data;
540  delete[] rdiag;
541  delete[] acnorm;
542  delete[] wa;
543  }
544 
545 }
long int LevenbergMarquardtExtended(minpack_funcder_mn fun, void *p, long int m, long int n, Vector< double > &InitialGuess, Vector< double > &Result, double Tolerance, long int MaxIter)
Solves an overdetermined system f(x) = 0 of m non-linear equations with n parameters using the extend...
Definition: Minpack.cpp:131
Matrix< T > Transpose() const
transpose function, storing data destination matrix
Definition: Matrix.hh:823
Matrix< T > & newsize(Subscript M, Subscript N)
Definition: cmat.h:269
unsigned int Size() const
length of the vector
Definition: Vector.hh:143
long int ComputeCovariance(long int NumErrors, long int NumParams, double *Jac, int *Permutation, double &SumOfSquaredErrors, Matrix< double > &Cov)
Compute covariance matrix from Levenberg-Marquardt resulting Jacobian matrix J(x) and permutation mat...
Definition: Minpack.cpp:289
void QRFrac(const Matrix< double > &A, Matrix< double > &Q, Matrix< double > &R)
Compute the QR decomposition of input matrix A using Householder transformations without column pivot...
Definition: Minpack.cpp:473
void SetZero()
equivalent to matrix call
Definition: Vector.hh:156
#define TMP
Test Matrix I/O precision issues. Deprecated!
Vector< T > & newsize(Subscript N)
Definition: vec.h:220
Matrix< T > OuterProduct(const Vector< T > &v) const
outer product, constructs a matrix.
Definition: Vector.cpp:99
void SetZero()
Sets all values to zero.
Definition: Matrix.hh:856
unsigned int GetRows() const
Definition: Matrix.hh:202
void CheckJacobian(minpack_funcder_mn fun, void *p, const long int NumErrors, const Vector< double > &x, Vector< double > &error)
Convenience function to check correctness of user supplied Jacobians J(x) needed by the analytical ve...
Definition: Minpack.cpp:406
long int ComputeJacobian(minpack_func_mn fun, void *p, const int NumErrors, const Vector< double > &x, Matrix< double > &fjac, const double gradientEpsilon)
Compute the Jacobian J(x) of function f at x.
Definition: Minpack.cpp:443
long int LevenbergMarquardt(minpack_funcder_mn fun, void *p, long int m, long int n, Vector< double > &InitialGuess, Vector< double > &Result, double Tolerance)
Solves an overdetermined system f(x) = 0 of m non-linear equations with n parameters using the Levenb...
Definition: Minpack.cpp:97
T * GetData()
get the pointer to the data array of the matrix (for faster direct memeory access) ...
Definition: Matrix.hh:185
void SetIdentity()
Converts matrix to identity matrix.
Definition: Matrix.cpp:383
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
unsigned int GetCols() const
Definition: Matrix.hh:204
T * GetData() const
get the pointer to the data array of the vector (for faster direct memory access) ...
Definition: Vector.hh:219
void Mult(const Matrix< T > &arg, Matrix< T > &result) const
matrix multiplication, result is not allocated
Definition: Matrix.hh:913
void MultiplyIP(const T &scalar)
in place multiplication function
Definition: Matrix.hh:448
long int Powell(minpack_func_nn fun, void *p, Vector< double > &InitialGuess, Vector< double > &Result, double Tolerance)
Solve a system f(x) = 0 of n non-linear equations with n unknowns using the Powell hybrid method...
Definition: Minpack.cpp:35
long int PowellExtended(minpack_func_nn fun, void *p, Vector< double > &InitialGuess, Vector< double > &Result, double EpsilonFun, double Tolerance)
Solve a system f(n) = 0 of n non-linear equations with n unknowns using the Powell hybrid method...
Definition: Minpack.cpp:56
Subscript size() const
Definition: vec.h:262