ARTS  2.3.1285(git:92a29ea9-dirty)
oem.cc
Go to the documentation of this file.
1 
9 #include "arts.h"
10 #include <iostream>
11 #include "lin_alg.h"
12 #include "logic.h"
13 #include "math.h"
14 //#include "oem.h"
15 #include "stdlib.h"
16 #include "arts_omp.h"
17 
18 using std::ostream;
19 using std::endl;
20 using std::setw;
21 using std::scientific;
22 using std::fixed;
23 
24 
25 //------------------------------------------------------------------------------------
26 //
27 // Functions for displaying progress of inversions
28 //
29 //------------------------------------------------------------------------------------
30 
31 void separator( ostream& stream,
32  Index length )
33 {
34  for (Index i = 0; i < length; i++)
35  stream << "-";
36  stream << endl;
37 }
38 
40 
44 void log_init_li( ostream& stream )
45 {
46  stream << endl;
47  stream << "Starting linear OEM inversion:" << endl << endl;
48  separator( stream, 52 );
49  stream << setw(6) << "Step";
50  stream << setw(15) << " Chi^2 ";
51  stream << setw(15) << " Chi^2_x ";
52  stream << setw(15) << " Chi^2_y ";
53  stream << endl;
54  separator( stream, 52 );
55 }
56 
58 
66 void log_step_li( ostream& stream,
67  Index step_number,
68  Numeric cost,
69  Numeric cost_x,
70  Numeric cost_y )
71 {
72  stream << setw(5) << step_number << " ";
73  stream << scientific;
74  stream << setw(15) << cost;
75  stream << setw(15) << cost_x;
76  stream << setw(15) << cost_y;
77  stream << endl;
78 }
79 
81 
91 void log_finalize_li( ostream& stream )
92 {
93  separator( stream, 52 );
94  stream << endl;
95 }
96 
98 
104 void log_init_gn( ostream& stream,
105  Numeric tol,
106  Index max_iter )
107 {
108  stream << endl;
109  stream << "Starting OEM inversion: " << endl << endl;
110  stream << "\tMethod: Gauss-Newton" << endl;
111  stream << "\tStop criterion: " << tol << endl;
112  stream << "\tMax. iterations: " << max_iter << endl << endl;
113  separator( stream, 67 );
114  stream << setw(6) << "Step";
115  stream << setw(15) << " Chi^2 ";
116  stream << setw(15) << " Chi^2_x ";
117  stream << setw(15) << " Chi^2_y ";
118  stream << setw(15) << " d_i^2 ";
119  stream << endl;
120  separator( stream, 67 );
121 }
122 
124 
133 void log_step_gn( ostream& stream,
134  Index step_number,
135  Numeric cost,
136  Numeric cost_x,
137  Numeric cost_y,
138  Numeric di2 )
139 {
140  stream << setw(5) << step_number << " ";
141  stream << scientific;
142  stream << setw(15) << cost;
143  stream << setw(15) << cost_x;
144  stream << setw(15) << cost_y;
145  if (di2 < 0)
146  stream << setw(15) << "";
147  else
148  stream << setw(15) << di2;
149  stream << endl;
150 }
151 
153 
163 void log_finalize_gn( ostream& stream,
164  bool converged,
165  Index iter,
166  Index max_iter )
167 {
168  separator( stream, 67 );
169  stream << endl;
170  if ( converged )
171  stream << "\tConverged: YES";
172  else if ( iter == max_iter )
173  {
174  stream << "\tConverged: NO" << endl;
175  stream << "\tMaximum no. of iterations was reached.";
176  }
177  stream << endl << endl;
178 }
179 
181 
187 void log_init_lm( ostream& stream,
188  Numeric tol,
189  Index max_iter )
190 {
191  stream << endl;
192  stream << "Starting OEM inversion: " << endl << endl;
193  stream << " Method: Levenberg-Marquardt " << endl;
194  stream << " Stop criterion: " << tol << endl;
195  stream << " Max. iterations: " << max_iter << endl << endl;
196  separator( stream, 75 );
197  stream << setw(6) << "Step";
198  stream << setw(15) << " Chi^2 ";
199  stream << setw(15) << " Chi^2_x ";
200  stream << setw(15) << " Chi^2_y ";
201  stream << setw(9) << " gamma ";
202  stream << setw(15) << " d_i^2 ";
203  stream << endl;
204  separator( stream, 75 );
205 }
206 
207 void log_gamma_step_lm( ostream& stream,
208  Numeric cost,
209  Numeric cost_x,
210  Numeric cost_y,
211  Numeric gamma )
212 {
213  stream << setw(6) << "";
214  stream << scientific;
215  stream << setw(15) << cost;
216  stream << setw(15) << cost_x;
217  stream << setw(15) << cost_y;
218  stream.unsetf(ios_base::floatfield);
219  stream << setw(9) << gamma;
220  stream << endl;
221 }
222 
224 
234 void log_step_lm( ostream& stream,
235  Index step_number,
236  Numeric cost,
237  Numeric cost_x,
238  Numeric cost_y,
239  Numeric gamma,
240  Numeric di2 )
241 {
242  stream << setw(6) << step_number;
243  stream << scientific;
244  stream << setw(15) << cost;
245  stream << setw(15) << cost_x;
246  stream << setw(15) << cost_y;
247  stream.unsetf(ios_base::floatfield);
248  stream << setw(9) << gamma;
249  stream << scientific;
250  stream << setw(15) << di2;
251  stream << endl;
252 }
253 
255 
267 void log_finalize_lm( ostream& stream,
268  bool converged,
269  Numeric cost,
270  Numeric cost_x,
271  Numeric cost_y,
272  Numeric gamma,
273  Numeric gamma_max,
274  Index iter,
275  Index max_iter )
276 {
277  separator( stream, 75 );
278  stream << endl << "Finished Levenberg-Marquardt iterations:" << endl;
279  if ( converged )
280  stream << "\t Converged: YES" << endl;
281  else if ( gamma == gamma_max )
282  {
283  stream << "\t Converged: NO" << endl;
284  stream << "\t Iteration aborted because gamma > gamma_max.";
285  }
286  else if ( iter == max_iter )
287  {
288  stream << "\t Converged: NO" << endl;
289  stream << "\t Iteration aborted because maximum no. of iterations was reached.";
290  }
291  stream << endl;
292 
293  stream << "\t Chi^2: " << cost << endl;
294  stream << "\t Chi^2_x: " << cost_x << endl;
295  stream << "\t Chi^2_y: " << cost_y << endl;
296  stream << endl << endl << endl;
297 }
298 
299 //------------------------------------------------------------------------------------
300 //
301 // Calculation of the cost function
302 //
303 //------------------------------------------------------------------------------------
304 
306 
318 template <typename Se_t>
319 void oem_cost_y( Numeric& cost_y,
320  ConstVectorView y,
321  ConstVectorView yf,
322  Se_t SeInv,
323  const Numeric& normfac )
324 {
325  Vector dy = y; dy -= yf;
326  Vector tmp( y.nelem() );
327  mult( tmp, SeInv, dy );
328  cost_y = dy * tmp;
329  cost_y /= normfac;
330 }
331 
333 
345 void oem_cost_x( Numeric& cost_x,
346  ConstVectorView x,
347  ConstVectorView xa,
348  ConstMatrixView SxInv,
349  const Numeric& normfac )
350 {
351 
352  Vector dx = x; dx -= xa;
353 
354  Vector tmp( x.nelem() );
355  mult( tmp, SxInv, dx );
356  cost_x = dx * tmp;
357  cost_x /= normfac;
358 }
359 
360 //------------------------------------------------------------------------------------
361 //
362 // Algebra Helper Functions
363 //
364 //------------------------------------------------------------------------------------
365 
367 
378  ConstMatrixView B,
379  ConstVectorView b )
380 {
381  Index n;
382 
383  n = b.nelem();
384 
385  // A,B must be n x n.
386  assert( is_size( A, n, n ) );
387  assert( is_size( B, n, n ) );
388 
389  for ( Index i = 0; i < n; i++)
390  {
391  for ( Index j = 0; j < n; j++)
392  {
393  A(i,j) = B(i,j) * b[i] * b[j];
394  }
395  }
396 }
397 
399 
407  ConstMatrixView B,
408  ConstVectorView b )
409 {
410  Index m,n;
411 
412  m = A.nrows();
413  n = A.ncols();
414 
415  // A,B must be n x n.
416  assert( is_size( B, m, n ) );
417  assert( is_size( b, n ) );
418 
419  for ( Index i = 0; i < n; i++)
420  {
421  for ( Index j = 0; j < n; j++)
422  {
423  A(i,j) = B(i,j) * b[j];
424  }
425  }
426 }
427 
429 
437  ConstMatrixView B,
438  ConstVectorView b )
439 {
440  Index m,n;
441 
442  m = A.nrows();
443  n = A.ncols();
444 
445  // A,B must be n x n.
446  assert( is_size( B, m, n ) );
447  assert( is_size( b, n ) );
448 
449  for ( Index i = 0; i < n; i++)
450  {
451  for ( Index j = 0; j < n; j++)
452  {
453  A(i,j) = B(i,j) * b[i];
454  }
455  }
456 }
457 
458 //------------------------------------------------------------------------------------
459 //
460 // Linear OEM Class
461 //
462 //------------------------------------------------------------------------------------
463 
465 
481 LinearOEM::LinearOEM( ConstMatrixView J_,
482  ConstMatrixView SeInv_,
483  ConstVectorView xa_,
484  ConstMatrixView SxInv_ )
485  : J(J_), SeInv(SeInv_), SxInv(SxInv_), x_norm()
486 {
487  n = J.ncols();
488  m = J.nrows();
489 
490  assert( is_size( SeInv_, m, m ) );
491  assert( is_size( SxInv_, n, n ) );
492  assert( is_size( xa_, n ) );
493 
494  xa = xa_;
495 
496  matrices_set = false;
497  gain_set = false;
498  x_norm_set = false;
499  form = NFORM;
500 
501  // Allocate memory for matrices.
502  LU = Matrix( n, n );
503  indx = ArrayOfIndex( n );
504  tmp_nn_1 = Matrix( n, n );
505  tmp_nm_1 = Matrix( n, m );
506  tmp_n_1 = Vector( n );
507 
508 }
509 
511 
518 void LinearOEM::set_x_norm( ConstVectorView x_norm_ )
519 {
520  x_norm = x_norm_;
521  x_norm_set = true;
522  matrices_set = false;
523  gain_set = false;
524 
525 }
526 
528 
533 ConstVectorView LinearOEM::get_x_norm()
534 {
535  return x_norm;
536 }
537 
539 
559  ConstVectorView y,
560  ConstVectorView y0 )
561 {
562 
563  // Set up timers.
564  Index t1, t2, t3;
565  t1 = timer.add_timer( "State vector computation" );
566  timer.mark( t1 );
567  t2 = timer.add_timer( "Matrix multiplication");
568  t3 = timer.add_timer( "Linear system solving");
569 
570  if (!(matrices_set || gain_set))
571  {
572 
573  timer.mark( t2 );
574  mult( tmp_nm_1, transpose(J), SeInv );
575  mult( tmp_nn_1, tmp_nm_1, J);
576  timer.mark( t2 );
577 
578  tmp_nn_1 += SxInv;
579 
580  if ( x_norm_set )
581  {
582  mult_outer( tmp_nn_1, tmp_nn_1, x_norm );
583  scale_rows( tmp_nm_1, tmp_nm_1, x_norm );
584  }
585 
586  timer.mark( t3 );
587  ludcmp( LU, indx, tmp_nn_1 );
588  timer.mark( t3 );
589 
590  matrices_set = true;
591  }
592 
593  tmp_m_1 = y;
594  tmp_m_1 -= y0;
595 
596  if (!gain_set)
597  {
598  mult( tmp_n_1, tmp_nm_1, tmp_m_1 );
599 
600  timer.mark( t3 );
601  lubacksub( x, LU, tmp_n_1, indx);
602  timer.mark( t3 );
603 
604  if (x_norm_set)
605  x *= x_norm;
606  }
607  else
608  {
609  mult( x, G, tmp_m_1 );
610  }
611 
612  x += xa;
613 
614  timer.mark( t1 );
615 
616  return 0;
617 }
618 
620 
639  MatrixView G_,
640  ConstVectorView y,
641  ConstVectorView y0 )
642 {
643 
644  if (!gain_set)
645  compute_gain_matrix();
646 
647  compute( x, y, y0 );
648  G_ = G;
649 
650  return 0;
651 }
652 
653 void LinearOEM::compute_gain_matrix()
654 {
655 
656  // Setup timers.
657  Index t1, t2, t3;
658  t1 = timer.add_timer( "Gain Matrix Computation" );
659  t2 = timer.add_timer( "Matrix Matrix Mult.");
660  t3 = timer.add_timer( "Linear System" );
661  timer.mark( t1 );
662 
663  // Assure that G has the right size.
664  G.resize( n, m );
665  tmp_nn_2.resize( n, n );
666 
667  if (!(matrices_set))
668  {
669  timer.mark( t2 );
670  mult( tmp_nm_1, transpose(J), SeInv );
671  mult( tmp_nn_1, tmp_nm_1, J);
672  timer.mark( t2 );
673 
674  tmp_nn_1 += SxInv;
675 
676  if ( x_norm_set )
677  {
678  mult_outer( tmp_nn_1, tmp_nn_1, x_norm );
679  scale_rows( tmp_nm_1, tmp_nm_1, x_norm );
680  }
681 
682  timer.mark( t3 );
683  ludcmp( LU, indx, tmp_nn_1 );
684  timer.mark( t3 );
685 
686  matrices_set = true;
687  }
688 
689  // Invert J^T S_e^{-1} J using the already computed LU decomposition.
690  tmp_n_1 = 0.0;
691 
692  timer.mark( t3 );
693  for ( Index i = 0; i < n; i++ )
694  {
695  tmp_n_1[i] = 1.0;
696  lubacksub( tmp_nn_2(joker,i), LU, tmp_n_1, indx);
697  tmp_n_1[i] = 0.0;
698  }
699  timer.mark( t3 );
700 
701  timer.mark( t2 );
702  mult( G, tmp_nn_2, tmp_nm_1 );
703  timer.mark( t2 );
704 
705  if ( x_norm_set )
706  {
707  scale_rows( G, G, x_norm );
708  matrices_set = false;
709  }
710  gain_set = true;
711 
712  timer.mark( t1 );
713 }
714 
716 
720 void LinearOEM::compute_averaging_kernel( MatrixView A )
721 {
722 
723  assert( n == A.ncols() );
724  assert( n == A.nrows() );
725 
726  // If not already computed, compute Gain matrix, which is
727  // required for the computation of the averaging kernel.
728  if (!gain_set)
729  compute_gain_matrix( );
730 
731  // If the Gain matrix has already been computed, G
732  // is set and can be reused for the computation of A.
733 
734  mult( A, G, J );
735 }
736 
738 
748 Index LinearOEM::compute_fit( Vector &yf,
749  const Vector &x,
750  ForwardModel &F )
751 {
752  try
753  {
754  F.evaluate( yf, x );
755  }
756  catch (int e)
757  {
758  err = 9;
759  return err;
760  }
761 
762  return 0;
763 }
764 
766 
778 Index LinearOEM::compute_fit( Vector &yf,
779  Numeric &cost_x,
780  Numeric &cost_y,
781  Vector &x,
782  ConstVectorView y,
783  ForwardModel &F )
784 {
785 
786  try
787  {
788  F.evaluate( yf, x );
789  }
790  catch (int e)
791  {
792  return 9;
793  }
794 
795  oem_cost_y( cost_y, y, yf, SeInv, (Numeric) m);
796  oem_cost_x( cost_x, x, xa, SxInv, (Numeric) m);
797 
798  return 0;
799 }
800 
801 //------------------------------------------------------------------------------------
802 //
803 // Linear OEM
804 //
805 //------------------------------------------------------------------------------------
806 
808 
837  Matrix& G,
838  Matrix& J,
839  Vector& yf,
840  Numeric& cost_y,
841  Numeric& cost_x,
842  ForwardModel &F,
843  ConstVectorView xa,
844  ConstVectorView x_norm,
845  ConstVectorView y,
846  ConstMatrixView SeInv,
847  ConstMatrixView SxInv,
848  const Numeric& cost_start,
849  const bool& verbose )
850 {
851  const Index m = J.nrows();
852  const Index n = J.ncols();
853 
854  // Check dimensions for consistency.
855  assert( xa.nelem() == n );
856  assert( x_norm.nelem() == 0 || x_norm.nelem() == n );
857  assert( y.nelem() == m );
858  assert( (SeInv.ncols() == m) && (SeInv.nrows() == m) );
859  assert( (SxInv.ncols() == n) && (SxInv.nrows() == n) );
860 
861  LinearOEM oem( J, SeInv, xa, SxInv );
862 
863  if ( x_norm.nelem() == n )
864  oem.set_x_norm( x_norm );
865 
866  // Initialize log output.
867  if (verbose)
868  {
869  log_init_li( cout );
870  log_step_li( cout, 0, cost_start, 0, cost_start );
871  }
872 
873  oem.compute( x, G, y, yf );
874  oem.compute_fit( yf, cost_x, cost_y, x, y, F );
875 
876  // Finalize log output.
877  if (verbose)
878  {
879  log_step_li( cout, 1, cost_y+cost_x, cost_x, cost_y );
880  log_finalize_li( cout );
881  }
882 
883  // Return convergence status
884  return oem.get_error();
885 }
886 
887 //------------------------------------------------------------------------------------
888 //
889 // Non-linear OEM Class
890 //
891 //------------------------------------------------------------------------------------
892 
894 
928 template<typename Se_t, typename Sx_t>
929 NonLinearOEM<Se_t, Sx_t>::NonLinearOEM( const Se_t &SeInv_,
930  ConstVectorView xa_,
931  const Sx_t &SxInv_,
932  ForwardModel &F_,
933  OEMMethod method_ )
934  : SeInv(SeInv_), SxInv(SxInv_), xa(xa_), F(F_), method(method_)
935 {
936 
937  m = SeInv_.nrows();
938  n = SxInv_.nrows();
939 
940  assert( xa_.nelem() == n );
941  assert( (SeInv_.ncols() == m) && (SeInv_.nrows() == m) );
942  assert( (SxInv_.ncols() == n) && (SxInv_.nrows() == n) );
943 
944  xa = xa_;
945 
946  // Allocate memory for internal matrices and vectors.
947  J = Matrix(m,n);
948  G = Matrix(n,m);
949  tmp_nm_1 = Matrix(n,m);
950  tmp_nn_1 = Matrix(n,n);
951  tmp_nn_2 = Matrix(n,n);
952 
953  tmp_m_1 = Vector(m);
954  tmp_n_1 = Vector(n);
955  tmp_n_2 = Vector(n);
956  dx = Vector(n);
957  yi = Vector(m);
958 
959  // Initialize internal state variables.
960  matrices_set = false;
961  gain_set = false;
962  x_norm_set = false;
963  conv = false;
964 
965  // Default iteration parameters.
966  tol = 1e-5;
967  max_iter = 100;
968 
969  ga_start = 4.0;
970  ga_max = 100.0;
971  ga_decrease = 2.0;
972  ga_increase = 3.0;
973  ga_threshold = 1.0;
974 
975 }
976 
978 
984 template<typename Se_t, typename Sx_t>
985 void NonLinearOEM<Se_t, Sx_t>::set_x_norm( ConstVectorView x_norm_ )
986 {
987  x_norm = x_norm_;
988  x_norm_set = true;
989 }
990 
992 
995 template<typename Se_t, typename Sx_t>
996 ConstVectorView NonLinearOEM<Se_t, Sx_t>::get_x_norm()
997 {
998  return x_norm;
999 }
1000 
1002 
1016 template<typename Se_t, typename Sx_t>
1018  ConstVectorView y,
1019  bool verbose )
1020 {
1021 
1022  if (method == GAUSS_NEWTON)
1023  {
1024  gauss_newton( x, y, verbose );
1025  }
1026  else if (method == LEVENBERG_MARQUARDT)
1027  {
1028  levenberg_marquardt( x, y, verbose );
1029  }
1030 
1031  if (verbose)
1032  cout << timer << endl;
1033 
1034  return err;
1035 }
1036 
1038 
1047 template<typename Se_t, typename Sx_t>
1049  MatrixView G_,
1050  ConstVectorView y,
1051  bool verbose )
1052 {
1053 
1054  if (method == GAUSS_NEWTON)
1055  {
1056  gauss_newton( x, y, verbose );
1057  }
1058  else if (method == LEVENBERG_MARQUARDT)
1059  {
1060  levenberg_marquardt( x, y, verbose );
1061  }
1062 
1063  compute_gain_matrix( x );
1064  G_ = G;
1065 
1066  if (verbose)
1067  cout << timer << endl;
1068 
1069  return err;
1070 }
1071 
1073 
1084 template<typename Se_t, typename Sx_t>
1085 void NonLinearOEM<Se_t, Sx_t>::gauss_newton( Vector &x,
1086  ConstVectorView y,
1087  bool verbose )
1088 {
1089 
1090  Index t1, t2, t3, t4;
1091  t1 = timer.add_timer( "Gauss-Newton Iteration" );
1092  t2 = timer.add_timer( "Matrix Matrix Mult." );
1093  t3 = timer.add_timer( "Linear System" );
1094  t4 = timer.add_timer( "Jacobian Evaluation" );
1095  timer.mark( t1 );
1096 
1097  Numeric di2 = -1.0;
1098 
1099  cost_x = 0.0; cost_y = 0.0;
1100  iter = 0;
1101  conv = false;
1102  err = 1;
1103 
1104  // Initialize log output.
1105  if (verbose)
1106  {
1107  log_init_gn( cout, tol, max_iter );
1108  }
1109 
1110  // Start stop watch.
1111 
1112  // Set the starting vector.
1113  x = xa;
1114 
1115  while ( (!conv) && (iter < max_iter) )
1116  {
1117  // Compute Jacobian and y_i.
1118 
1119  timer.mark( t1 );
1120  timer.mark( t4 );
1121  try
1122  {
1123  F.evaluate_jacobian( yi, J, x);
1124  }
1125  catch (int e)
1126  {
1127  err = 9;
1128  return void();
1129  }
1130  timer.mark( t1 );
1131  timer.mark( t4 );
1132 
1133 
1134  timer.mark( t2 );
1135  mult( tmp_nm_1, transpose(J), SeInv );
1136  mult( tmp_nn_1, tmp_nm_1, J );
1137  timer.mark( t2 );
1138 
1139  tmp_nn_1 += SxInv;
1140 
1141  if (x_norm_set)
1142  {
1143  mult_outer( tmp_nn_1, tmp_nn_1, x_norm );
1144  scale_rows( tmp_nm_1, tmp_nm_1, x_norm );
1145  }
1146 
1147  // tm1 = K_i(x_i - x_a)
1148 
1149  tmp_n_1 = x;
1150  tmp_n_1 -= xa;
1151  mult( tmp_n_2, SxInv, tmp_n_1 );
1152 
1153  if (x_norm_set)
1154  tmp_n_2 *= x_norm;
1155 
1156  tmp_m_1 = y;
1157  tmp_m_1 -= yi;
1158  // tmp_n_1 = K_i^T * S_e^{-1} * (y - F(x_i))
1159  mult( tmp_n_1, tmp_nm_1, tmp_m_1 );
1160 
1161  // This vector is used to test for convergence later.
1162  // See eqn. (5.31).
1163  tmp_n_1 -= tmp_n_2;
1164 
1165  // Compute cost function and convergence criterion.
1166  oem_cost_x( cost_x, x, xa, SxInv, (Numeric) m);
1167  oem_cost_y( cost_y, y, yi, SeInv, (Numeric) m);
1168 
1169  // Print log.
1170  if ( verbose )
1171  log_step_gn( cout, iter, cost_x + cost_y, cost_x, cost_y, di2 );
1172 
1173  timer.mark( t3 );
1174  solve( dx, tmp_nn_1, tmp_n_1 );
1175  timer.mark( t3 );
1176 
1177  if (x_norm_set)
1178  dx *= x_norm;
1179  x += dx;
1180  iter++;
1181 
1182  // Compute convergence criterion.
1183  di2 = dx * tmp_n_1;
1184 
1185  // If converged, stop iteration.
1186  if ( di2 <= tol * (Numeric) n )
1187  {
1188  conv = true;
1189  err = 0;
1190  }
1191  }
1192 
1193  if ( iter == max_iter )
1194  err = 1;
1195 
1196  // Stop stop watch.
1197 
1198  // Finalize log output.
1199  if ( verbose )
1200  log_finalize_gn( cout, conv, iter, max_iter );
1201 
1202 }
1203 
1205 
1233 template<typename Se_t, typename Sx_t>
1234 void NonLinearOEM<Se_t, Sx_t>::levenberg_marquardt( Vector &x,
1235  ConstVectorView y,
1236  bool verbose )
1237 {
1238  // Setup timers.
1239  Index t1, t2, t3, t4;
1240  t1 = timer.add_timer( "Levenberg-Marquardt Iteration" );
1241  t2 = timer.add_timer( "Matrix Matrix Mult." );
1242  t3 = timer.add_timer( "Linear System" );
1243  t4 = timer.add_timer( "Jacobian Evaluation" );
1244  timer.mark( t1 );
1245 
1246  Numeric cost_old, cost, di2;
1247  di2 = -1.0;
1248 
1249  if ( verbose )
1250  log_init_lm( cout, tol, max_iter );
1251 
1252  // Set starting vector.
1253  x = xa;
1254 
1255  conv = false;
1256  iter = 0;
1257  cost_x = 0.0;
1258  cost_y = 0.0;
1259  Numeric gamma = ga_start;
1260 
1261  while ( (!conv) && (iter < max_iter) && (gamma <= ga_max) )
1262  {
1263  // Compute Jacobian and y_i.
1264  timer.mark( t1 );
1265  timer.mark( t4 );
1266  try
1267  {
1268  F.evaluate_jacobian( yi, J, x);
1269  }
1270  catch (int e)
1271  {
1272  err = 9;
1273  return void();
1274  }
1275  timer.mark( t1 );
1276  timer.mark( t4 );
1277 
1278  timer.mark(t2);
1279  mult( tmp_nm_1, transpose(J), SeInv );
1280  mult( tmp_nn_1, tmp_nm_1, J );
1281  timer.mark(t2);
1282 
1283  tmp_n_1 = x;
1284  tmp_n_1 -= xa;
1285  mult( tmp_n_2, SxInv, tmp_n_1 );
1286 
1287  tmp_m_1 = y;
1288  tmp_m_1 -= yi;
1289  mult( tmp_n_1, tmp_nm_1, tmp_m_1 );
1290 
1291  tmp_n_1 -= tmp_n_2;
1292  tmp_n_2 = tmp_n_1;
1293  if (x_norm_set)
1294  tmp_n_1 *= x_norm;
1295 
1296  // Compute costs and print log message.
1297  oem_cost_x( cost_x, x, xa, SxInv, (Numeric) m);
1298  oem_cost_y( cost_y, y, yi, SeInv, (Numeric) m);
1299  cost_old = cost_y + cost_x;
1300 
1301  if ( verbose )
1302  log_step_gn( cout, iter, cost_x + cost_y, cost_x, cost_y, di2 );
1303 
1304  bool found_x = false;
1305  while ( !found_x )
1306  {
1307  tmp_nn_2 = SxInv;
1308  tmp_nn_2 *= ( 1.0 + gamma );
1309  tmp_nn_2 += tmp_nn_1;
1310 
1311  if ( x_norm_set )
1312  {
1313  mult_outer( tmp_nn_2, tmp_nn_2, x_norm );
1314  }
1315 
1316  // This vector is used to test for convergence later.
1317  // See eqn. (5.31).
1318 
1319  timer.mark( t3 );
1320  solve( dx, tmp_nn_2, tmp_n_1 );
1321  timer.mark( t3 );
1322 
1323  if (x_norm_set)
1324  dx *= x_norm;
1325  xnew = x;
1326  xnew += dx;
1327 
1328  // Evaluate cost function.
1329 
1330 
1331  timer.mark(t1);
1332  timer.mark(t4);
1333  try
1334  {
1335  F.evaluate( yi, xnew );
1336  }
1337  catch ( int e )
1338  {
1339  err = 9;
1340  return void();
1341  }
1342  timer.mark(t1);
1343  timer.mark(t4);
1344 
1345 
1346  oem_cost_x( cost_x, xnew, xa, SxInv, (Numeric) m);
1347  oem_cost_y( cost_y, y, yi, SeInv, (Numeric) m);
1348  cost = cost_x + cost_y;
1349 
1350  // If cost has decreased, keep new x and
1351  // scale gamma.
1352  if (cost < cost_old)
1353  {
1354 
1355  if ( gamma >= (ga_threshold * ga_decrease))
1356  gamma /= ga_decrease;
1357  else
1358  gamma = 0;
1359 
1360  x = xnew;
1361  cost_old = cost;
1362  found_x = true;
1363 
1364  }
1365  // Else try to increase gamma and look for a
1366  // new x.
1367  else
1368  {
1369  if ( gamma < ga_threshold )
1370  gamma = ga_threshold;
1371  else
1372  {
1373  if ( gamma < ga_max )
1374  {
1375  gamma *= ga_increase;
1376  if (gamma > ga_max)
1377  gamma = ga_max;
1378  }
1379  // Gamma exceeds maximum. Abort.
1380  else
1381  {
1382  gamma = ga_max + 1.0;
1383  break;
1384  }
1385  }
1386  }
1387  }
1388 
1389  // Increase iteration counter and check for convergence.
1390  iter++;
1391 
1392  di2 = dx * tmp_n_2;
1393  di2 /= (Numeric) n;
1394 
1395  if ( di2 <= tol )
1396  {
1397  conv = true;
1398  err = 0;
1399  }
1400 
1401  }
1402 
1403  if ( iter == max_iter )
1404  err = 1;
1405  if ( gamma >= ga_max )
1406  err = 2;
1407 
1408  timer.mark( t1 );
1409 
1410  // Final log output.
1411  if ( verbose )
1412  {
1413  cost = cost_x + cost_y;
1414  log_finalize_lm( cout, conv, cost, cost_x, cost_y,
1415  gamma, ga_max, iter, max_iter );
1416  }
1417 }
1418 
1420 
1429 template<typename Se_t, typename Sx_t>
1430 Index NonLinearOEM<Se_t, Sx_t>::compute_fit( Vector &yf,
1431  const Vector &x )
1432 {
1433  try
1434  {
1435  F.evaluate( yf, x );
1436  }
1437  catch (int e)
1438  {
1439  err = 9;
1440  return err;
1441  }
1442  return 0;
1443 
1444 }
1445 
1447 
1460 template<typename Se_t, typename Sx_t>
1461 Index NonLinearOEM<Se_t, Sx_t>::compute_fit( Vector &yf,
1462  Numeric &cost_x_,
1463  Numeric &cost_y_,
1464  const Vector &x,
1465  ConstVectorView y )
1466 {
1467 
1468  try
1469  {
1470  F.evaluate( yf, x );
1471  }
1472  catch (int e)
1473  {
1474  err = 9;
1475  return err;
1476  }
1477 
1478  oem_cost_y( cost_y_, y, yf, SeInv, (Numeric) m);
1479  oem_cost_x( cost_x_, x, xa, SxInv, (Numeric) m);
1480 
1481  return 0;
1482 
1483 }
1484 
1486 
1491 template<typename Se_t, typename Sx_t>
1492 void NonLinearOEM<Se_t, Sx_t>::compute_gain_matrix( ConstVectorView x )
1493 {
1494  Index t1, t2, t3, t4;
1495  t1 = timer.add_timer( "Gain Matrix Computation" );
1496  t2 = timer.add_timer( "Matrix Matrix Mult." );
1497  t3 = timer.add_timer( "Linear System" );
1498  t4 = timer.add_timer( "Jacobian Evaluation" );
1499  timer.mark( t1 );
1500 
1501  timer.mark( t4 );
1502  try
1503  {
1504  F.evaluate_jacobian( tmp_m_1, J, x);
1505  }
1506  catch (int e)
1507  {
1508  err = 9;
1509  return void();
1510  }
1511  timer.mark( t4 );
1512 
1513  timer.mark( t2 );
1514  mult( tmp_nm_1, transpose(J), SeInv );
1515  mult( tmp_nn_1, tmp_nm_1, J );
1516  timer.mark( t2 );
1517 
1518  tmp_nn_1 += SxInv;
1519 
1520  if (x_norm_set)
1521  {
1522  mult_outer( tmp_nn_1, tmp_nn_1, x_norm );
1523  scale_columns( tmp_nm_1, tmp_nm_1, x_norm );
1524  }
1525 
1526  timer.mark( t3 );
1527  inv( tmp_nn_2, tmp_nn_1 );
1528  timer.mark( t3 );
1529 
1530  timer.mark( t2 );
1531  mult( G, tmp_nn_2, tmp_nm_1 );
1532  timer.mark( t2 );
1533 
1534  timer.mark( t1 );
1535 }
1536 
1538 
1544 template <typename Se_t, typename Sx_t>
1545 void NonLinearOEM<Se_t,Sx_t>::compute_averaging_kernel( MatrixView A,
1546  ConstVectorView x )
1547 {
1548  assert( A.ncols() == n );
1549  assert( A.nrows() == n );
1550 
1551  // If not already computed, compute Gain matrix, which is
1552  // required for the computation of the averaging kernel.
1553  if (!gain_set)
1554  compute_gain_matrix( x );
1555 
1556  // If the Gain matrix has already been computed both G and J
1557  // are set and can be reused for the computation of A.
1558 
1559  mult( A, G, J );
1560 }
1561 
1563 
1602 template <typename Se_t, typename Sx_t>
1604  Matrix& G,
1605  Matrix& J,
1606  Vector& yf,
1607  Numeric& cost_y,
1608  Numeric& cost_x,
1609  Index& iter,
1610  ForwardModel &F,
1611  ConstVectorView xa,
1612  ConstVectorView x_norm,
1613  ConstVectorView y,
1614  const Se_t &SeInv,
1615  const Sx_t &SxInv,
1616  const Index max_iter,
1617  const Numeric tol,
1618  bool verbose )
1619 {
1620  const Index m = J.nrows();
1621  const Index n = J.ncols();
1622 
1623  // Check dimensions for consistency.
1624  assert( xa.nelem() == n );
1625  assert( x_norm.nelem() == 0 || x_norm.nelem() == n );
1626  assert( y.nelem() == m );
1627  assert( (SeInv.ncols() == m) && (SeInv.nrows() == m) );
1628  assert( (SxInv.ncols() == n) && (SxInv.nrows() == n) );
1629 
1630  NonLinearOEM<Se_t, Sx_t>
1631  oem( SeInv, xa, SxInv, F, GAUSS_NEWTON);
1632  oem.tolerance( tol );
1633  oem.maximum_iterations( max_iter );
1634 
1635  if ( x_norm.nelem() == n )
1636  oem.set_x_norm( x_norm );
1637 
1638  oem.compute( x, G, y, verbose );
1639  oem.compute_fit( yf, cost_x, cost_y, x, y );
1640 
1641  J = oem.get_jacobian();
1642 
1643 
1644  iter = oem.iterations();
1645 
1646  return oem.get_error();
1647 }
1648 
1649 
1650 
1652 
1702 template <typename Se_t, typename Sx_t>
1704  Matrix& G,
1705  Matrix& J,
1706  Vector& yf,
1707  Numeric& cost_y,
1708  Numeric& cost_x,
1709  Index& iter,
1710  ForwardModel &F,
1711  ConstVectorView xa,
1712  ConstVectorView x_norm,
1713  ConstVectorView y,
1714  const Se_t &SeInv,
1715  const Sx_t &SxInv,
1716  Index max_iter,
1717  Numeric tol,
1718  Numeric gamma_start,
1719  Numeric gamma_decrease,
1720  Numeric gamma_increase,
1721  Numeric gamma_max,
1722  Numeric gamma_threshold,
1723  bool verbose )
1724 {
1725 
1726  const Index m = J.nrows();
1727  const Index n = J.ncols();
1728 
1729  // Check dimensions for consistency.
1730  assert( xa.nelem() == n );
1731  assert( x_norm.nelem() == 0 || x_norm.nelem() == n );
1732  assert( y.nelem() == m );
1733  assert( (SeInv.ncols() == m) && (SeInv.nrows() == m) );
1734  assert( (SxInv.ncols() == n) && (SxInv.nrows() == n) );
1735 
1736  NonLinearOEM<Se_t, Sx_t>
1737  oem( SeInv, xa, SxInv, F, LEVENBERG_MARQUARDT);
1738  oem.tolerance( tol );
1739  oem.maximum_iterations( max_iter );
1740  oem.gamma_start( gamma_start );
1741  oem.gamma_decrease( gamma_decrease );
1742  oem.gamma_increase( gamma_increase );
1743  oem.gamma_max( gamma_max );
1744  oem.gamma_threshold( gamma_threshold );
1745 
1746  if ( x_norm.nelem() == n )
1747  oem.set_x_norm( x_norm );
1748 
1749  oem.compute( x, G, y, verbose );
1750  oem.compute_fit( yf, cost_x, cost_y, x, y );
1751 
1752  J = oem.get_jacobian();
1753 
1754  iter = oem.iterations();
1755 
1756  return oem.get_error();
1757 
1758 }
1759 
1760 //------------------------------------------------------------------------------------
1761 //
1762 // OEM versions so far not used
1763 //
1764 //------------------------------------------------------------------------------------
1765 
1766 
1768 
1790  MatrixView G,
1791  ConstVectorView xa,
1792  ConstVectorView yf,
1793  ConstVectorView y,
1794  ConstMatrixView K,
1795  ConstMatrixView Se,
1796  ConstMatrixView Sx )
1797 {
1798  Index m = K.nrows();
1799  Index n = K.ncols();
1800 
1801  // Check dimensions for consistency.
1802  assert( x.nelem() == n );
1803  assert( xa.nelem() == n );
1804  assert( y.nelem() == m );
1805 
1806  assert( (Se.ncols() == m) && (Se.nrows() == m) );
1807  assert( (Sx.ncols() == n) && (Sx.nrows() == n) );
1808 
1809  // m-form (eq. (4.6)).
1810  Matrix tmp_nm(n,m);
1811  Matrix tmp_mm(m,m), tmp_mm2(m,m);
1812  Vector tmp_m(m);
1813 
1814  mult( tmp_nm, Sx, transpose(K) ); // tmp_nm = S_a * K^T
1815  mult( tmp_mm, K, tmp_nm);
1816  tmp_mm += Se;
1817 
1818  // Compute gain matrix.
1819  inv( tmp_mm2, tmp_mm );
1820  mult( G, tmp_nm, tmp_mm2 );
1821 
1822  tmp_m = y;
1823  tmp_m -= yf;
1824  mult( x, G, tmp_m );
1825 
1826  x += xa;
1827 }
1828 
1829 
1830 
1832 
1853  ConstVectorView y,
1854  ConstVectorView xa,
1855  ForwardModel &K,
1856  ConstMatrixView Se,
1857  ConstMatrixView Sx,
1858  Numeric tol,
1859  Index max_iter )
1860 {
1861  Index n( x.nelem() ), m( y.nelem() );
1862  Numeric di2;
1863  Matrix Ki(m,n), SxKiT(m, n), KiSxKiT(m, m);
1864  Vector xi(n), yi(m), tm(m), tm2(m), tn(n), yi_old(m);
1865 
1866  Index iter = 0;
1867  bool converged = false;
1868 
1869  // Set the starting vector.
1870  x = xa;
1871 
1872  while ((!converged) && (iter < max_iter))
1873  {
1874 
1875  // Compute Jacobian and y_i.
1876  K.evaluate_jacobian( yi, Ki, x );
1877  // If not in the first iteration, check for
1878  // convergence here.
1879  if (iter > 0)
1880  {
1881  yi_old -= yi;
1882 
1883  solve( tm, Se, yi_old );
1884  mult( tm2, KiSxKiT, tm );
1885  // TODO: Optimize using LU decomp.
1886  solve( tm, Se, tm2);
1887  di2 = yi_old * tm;
1888  if ( fabs( di2 ) < tol * (Numeric) n )
1889  {
1890  converged = true;
1891  break;
1892  }
1893  }
1894 
1895  mult( SxKiT, Sx, transpose(Ki) );
1896  mult( KiSxKiT, Ki, SxKiT );
1897  KiSxKiT += Se;
1898 
1899  // tm = K_i(x_i - x_a)
1900  tn = x;
1901  tn -= xa;
1902  mult( tm, Ki, tn );
1903 
1904  tm -= yi;
1905  tm += y;
1906 
1907  solve( tm2, KiSxKiT, tm );
1908  mult( x, SxKiT, tm2 );
1909  x += xa;
1910 
1911  // Increase iteration counter and store yi.
1912  iter++;
1913  yi_old = yi;
1914  }
1915  return converged;
1916 }
1917 
1919 
1942  ConstVectorView y,
1943  ConstVectorView xa,
1944  ForwardModel &K,
1945  ConstMatrixView Se,
1946  ConstMatrixView Sx,
1947  Numeric tol,
1948  Index max_iter )
1949 {
1950  Index n( x.nelem() ), m( y.nelem() );
1951  Numeric di2;
1952  Matrix Ki(m,n), KiTSeInvKi(n, n), KiTSeInv(m,n), SeInv(m,m), SxInv(n,n);
1953  Vector xi(n), dx(n), dx_old(n), yi(m), tm(m), tn(n), sInvDx(n);
1954 
1955  Index iter = 0;
1956  bool converged = false;
1957 
1958  // Required matrix inverses.
1959  inv(SeInv, Se);
1960  inv(SxInv, Sx);
1961 
1962  // Set the starting vector.
1963  x = xa;
1964  dx_old = 0;
1965 
1966  while ((!converged) && (iter < max_iter))
1967  {
1968 
1969  // Compute Jacobian and y_i.
1970  K.evaluate_jacobian( yi, Ki, x );
1971  mult( KiTSeInv, transpose( Ki ), SeInv );
1972  mult( KiTSeInvKi, KiTSeInv, Ki );
1973  KiTSeInvKi += SxInv;
1974 
1975  // tm = K_i(x_i - x_a)
1976  tn = x;
1977  tn -= xa;
1978  mult( tm, Ki, tn );
1979 
1980  tm -= yi;
1981  tm += y;
1982 
1983  mult( tn, KiTSeInv, tm );
1984  solve( dx, KiTSeInvKi, tn );
1985 
1986  x = xa;
1987  x += dx;
1988 
1989  // Check for convergence.
1990  tm = y;
1991  tm -= yi;
1992  mult( sInvDx, KiTSeInv, tm );
1993  mult( tn, SxInv, dx_old );
1994  sInvDx -= tn;
1995 
1996  dx -= dx_old;
1997  di2 = dx * sInvDx;
1998 
1999  if ( di2 <= tol * (Numeric) m )
2000  {
2001  converged = true;
2002  }
2003 
2004  // Increase iteration counter and store yi.
2005  iter++;
2006  dx_old = dx;
2007  }
2008  return converged;
2009 }
2010 
2011 
void separator(ostream &stream, Index length)
Definition: oem.cc:31
bool oem_gauss_newton_m_form(VectorView x, ConstVectorView y, ConstVectorView xa, ForwardModel &K, ConstMatrixView Se, ConstMatrixView Sx, Numeric tol, Index max_iter)
Non-linear OEM using Gauss-Newton method.
Definition: oem.cc:1852
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
void log_init_gn(ostream &stream, Numeric tol, Index max_iter)
Initial log message, Gauss-Newton.
Definition: oem.cc:104
The VectorView class.
Definition: matpackI.h:610
Index oem_levenberg_marquardt(Vector &x, Matrix &G, Matrix &J, Vector &yf, Numeric &cost_y, Numeric &cost_x, Index &iter, ForwardModel &F, ConstVectorView xa, ConstVectorView x_norm, ConstVectorView y, const Se_t &SeInv, const Sx_t &SxInv, Index max_iter, Numeric tol, Numeric gamma_start, Numeric gamma_decrease, Numeric gamma_increase, Numeric gamma_max, Numeric gamma_threshold, bool verbose)
Non-linear OEM using Levenberg-Marquardt method.
Definition: oem.cc:1703
void oem_linear_mform(VectorView x, MatrixView G, ConstVectorView xa, ConstVectorView yf, ConstVectorView y, ConstMatrixView K, ConstMatrixView Se, ConstMatrixView Sx)
Linear OEM, m-form.
Definition: oem.cc:1789
Index oem_linear_nform(Vector &x, Matrix &G, Matrix &J, Vector &yf, Numeric &cost_y, Numeric &cost_x, ForwardModel &F, ConstVectorView xa, ConstVectorView x_norm, ConstVectorView y, ConstMatrixView SeInv, ConstMatrixView SxInv, const Numeric &cost_start, const bool &verbose)
Linear OEM, n-form.
Definition: oem.cc:836
void scale_rows(MatrixView A, ConstMatrixView B, ConstVectorView b)
Scale rows.
Definition: oem.cc:436
void lubacksub(VectorView x, ConstMatrixView LU, ConstVectorView b, const ArrayOfIndex &indx)
LU backsubstitution.
Definition: lin_alg.cc:91
void log_finalize_gn(ostream &stream, bool converged, Index iter, Index max_iter)
Final log message, Gauss-Newton.
Definition: oem.cc:163
void oem_cost_x(Numeric &cost_x, ConstVectorView x, ConstVectorView xa, ConstMatrixView SxInv, const Numeric &normfac)
Calculation of x-part of cost function.
Definition: oem.cc:345
The Vector class.
Definition: matpackI.h:860
void mult_outer(MatrixView A, ConstMatrixView B, ConstVectorView b)
Multiply matrix element-wise by outer product of vector.
Definition: oem.cc:377
The MatrixView class.
Definition: matpackI.h:1093
void log_step_gn(ostream &stream, Index step_number, Numeric cost, Numeric cost_x, Numeric cost_y, Numeric di2)
Step log message, Gauss-Newton.
Definition: oem.cc:133
void log_gamma_step_lm(ostream &stream, Numeric cost, Numeric cost_x, Numeric cost_y, Numeric gamma)
Definition: oem.cc:207
Linear algebra functions.
invlib::Vector< ArtsVector > Vector
invlib wrapper type for ARTS vectors.
Definition: oem.h:32
void oem_cost_y(Numeric &cost_y, ConstVectorView y, ConstVectorView yf, Se_t SeInv, const Numeric &normfac)
Calculation of y-part of cost function.
Definition: oem.cc:319
void scale_columns(MatrixView A, ConstMatrixView B, ConstVectorView b)
Scale columns.
Definition: oem.cc:406
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:51
void log_init_li(ostream &stream)
Initial log message, linear.
Definition: oem.cc:44
Array< Index > ArrayOfIndex
An array of Index.
Definition: array.h:40
Definition: oem.h:29
Index ncols() const
Returns the number of columns.
Definition: matpackI.cc:432
The global header file for ARTS.
const Joker joker
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
The Matrix class.
Definition: matpackI.h:1193
void log_finalize_lm(ostream &stream, bool converged, Numeric cost, Numeric cost_x, Numeric cost_y, Numeric gamma, Numeric gamma_max, Index iter, Index max_iter)
Final log message, Levenberg-Marquardt.
Definition: oem.cc:267
void log_init_lm(ostream &stream, Numeric tol, Index max_iter)
Initial log message, Levenberg-Marquardt.
Definition: oem.cc:187
void log_finalize_li(ostream &stream)
Final log message, linear.
Definition: oem.cc:91
#define dx
void mult(ComplexVectorView y, const ConstComplexMatrixView &M, const ConstComplexVectorView &x)
Matrix-Vector Multiplication.
Definition: complex.cc:1579
Header file for logic.cc.
Vector compute(const Numeric p, const Numeric t, const Numeric xco2, const Numeric xh2o, const ConstVectorView invcm_grid, const Numeric stotmax, const calctype type)
ConstComplexMatrixView transpose(ConstComplexMatrixView m)
Const version of transpose.
Definition: complex.cc:1509
void log_step_lm(ostream &stream, Index step_number, Numeric cost, Numeric cost_x, Numeric cost_y, Numeric gamma, Numeric di2)
Step log message, Levenberg-Marquardt.
Definition: oem.cc:234
void inv(MatrixView Ainv, ConstMatrixView A)
Matrix Inverse.
Definition: lin_alg.cc:167
A constant view of a Vector.
Definition: matpackI.h:476
A constant view of a Matrix.
Definition: matpackI.h:982
bool is_size(ConstVectorView x, const Index &n)
Verifies that the size of x is l.
Definition: logic.cc:79
Header file for helper functions for OpenMP.
bool oem_gauss_newton_n_form(VectorView x, ConstVectorView y, ConstVectorView xa, ForwardModel &K, ConstMatrixView Se, ConstMatrixView Sx, Numeric tol, Index max_iter)
Non-linear OEM using Gauss-Newton method.
Definition: oem.cc:1941
Index oem_gauss_newton(Vector &x, Matrix &G, Matrix &J, Vector &yf, Numeric &cost_y, Numeric &cost_x, Index &iter, ForwardModel &F, ConstVectorView xa, ConstVectorView x_norm, ConstVectorView y, const Se_t &SeInv, const Sx_t &SxInv, const Index max_iter, const Numeric tol, bool verbose)
Gauss-Newton non-linear OEM using precomputed inverses, n-form.
Definition: oem.cc:1603
void solve(VectorView w, const CovarianceMatrix &A, ConstVectorView v)
void log_step_li(ostream &stream, Index step_number, Numeric cost, Numeric cost_x, Numeric cost_y)
Step log message, linear.
Definition: oem.cc:66
void ludcmp(Matrix &LU, ArrayOfIndex &indx, ConstMatrixView A)
LU decomposition.
Definition: lin_alg.cc:56
invlib::Matrix< ArtsMatrix > Matrix
invlib wrapper type for ARTS matrices.
Definition: oem.h:34
Index nrows() const
Returns the number of rows.
Definition: matpackI.cc:429