casa
$Rev:20696$
|
00001 //# LSQFit.h: Basic class for least squares fitting 00002 //# Copyright (C) 1999-2001,2004-2008 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: LSQFit.h 21049 2011-04-13 07:52:48Z gervandiepen $ 00027 00028 #ifndef SCIMATH_LSQFIT_H 00029 #define SCIMATH_LSQFIT_H 00030 00031 //# Includes 00032 #include <casa/aips.h> 00033 #include <casa/Utilities/RecordTransformable.h> 00034 #include <scimath/Fitting/LSQMatrix.h> 00035 #include <scimath/Fitting/LSQTraits.h> 00036 #include <complex> 00037 #include <string> 00038 #include <utility> 00039 #include <vector> 00040 00041 namespace casa { //# NAMESPACE CASA - BEGIN 00042 00043 //# Forward Declarations 00044 00045 // <summary> Basic class for the least squares fitting </summary> 00046 // <reviewed reviewer="Neil Killeen" date="2000/06/01" tests="tLSQFit" 00047 // demos=""> 00048 // </reviewed> 00049 00050 // <prerequisite> 00051 // <li> Some knowledge of Matrix operations 00052 // <li> The background information provided in 00053 // <a href="../notes/224.html">Note 224</a>. 00054 // <li> <linkto module="Fitting">Fitting module</linkto> 00055 // </prerequisite> 00056 // 00057 // <etymology> 00058 // From Least SQuares and Fitting 00059 // </etymology> 00060 // 00061 // <synopsis> 00062 // The LSQFit class contains the basic functions to do all the fitting 00063 // described in the 00064 // <a href="../notes/224.html">Note</a> 00065 // about fitting. 00066 // It handles real, and complex equations;<br> 00067 // linear and non-linear (Levenberg-Marquardt) solutions;<br> 00068 // regular (with optional constraints) or Singular Value Decomposition 00069 // (<src>SVD</src>).<br> 00070 // In essence they are a set of routines to generate normal equations 00071 // (<src>makeNorm()</src>) in triangular form from a set of condition 00072 // equations;<br> 00073 // to do a Cholesky-type decomposition of the normal 00074 // equations (either regular or <src>SVD</src>) and test its rank 00075 // (<src>invert()</src>);<br> 00076 // to do a quasi inversion of the decomposed equations (<src>solve()</src>) to 00077 // obtain the solution and/or the errors. 00078 // 00079 // All calculations are done in place. 00080 // Methods to obtain additional information about the fitting process are 00081 // available. 00082 // 00083 // This class can be used as a stand-alone class outside of the aips++ 00084 // environment. In that case the aips.h include file 00085 // can be replaced if necessary by appropriate typedefs for Double, Float and 00086 // uInt.<br> 00087 // The interface to the methods have standard data or standard STL iterator 00088 // arguments only. They can be used with any container having an STL 00089 // random-access iterator interface. Especially they can be used with 00090 // <src>carrays</src> (necessary templates provided), 00091 // aips++ Vectors (necessary templates 00092 // provided in <src>LSQaips</src>), 00093 // standard random access STL containers (like <src>std::vector</src>). 00094 // 00095 // The normal operation of the class consists of the following steps: 00096 // <ul> 00097 // <li> Create an LSQFit object. 00098 // The information that can be provided in the constructor of the object, 00099 // either directly, or indirectly using the <src>set()</src> commands, is 00100 // (see <a href="../notes/224.html">Note 224</a>): 00101 // <ul> 00102 // <li> The number of unknowns that have to be solved for (mandatory) 00103 // <li> The number of constraint equations you want to use explicitly 00104 // (defaults to 0, but can be changed on-the-fly) 00105 // </ul> 00106 // Separately settable are: 00107 // <ul> 00108 // <li> A collinearity test factor (defaults to 1e-8) 00109 // <note role=warning> 00110 // The collinearity factor is the square of the sine of the angle between 00111 // a column in the normal equations, and the hyper-plane through 00112 // all the other columns. In special cases (e.g. fitting a polynomial 00113 // in a very narrow bandwidth window, it could be advisable to set this 00114 // factor to zero if you want a solution (whatever the truth of it maybe). 00115 // </note> 00116 // <li> A Levenberg-Marquardt adjustment factor (if appropriate, 00117 // defaults to 1e-3) 00118 // </ul> 00119 // 00120 // <li>Create the normal equations used in solving the set of condition 00121 // equations of the user, by using the <src>makeNorm()</src> methods. 00122 // Separate <src>makenorm()</src> methods are provided for sparse condition 00123 // equations (e.g. if data for 3 antennas are provided, rather than for all 64) 00124 // 00125 // <li>If there are user provided constraints, either limiting constraints like 00126 // the sum of the angles in a triangle is 180 degrees, or constraints to add 00127 // missing information if e.g. only differences between parameters have been 00128 // measured, they can be added to the normal 00129 // equations with the <src>setConstraint()</src> or 00130 // the <src>addConstraint()</src> methods. Lagrange multipliers will be used to 00131 // solve the extended normal equations. 00132 // 00133 // <li>The normal equations are triangu;arised (using the collinearity factor 00134 // as a check for solvability) with the <src>invert()</src> method. If the 00135 // normal equations are non-solvable an error is returned, or a switch to 00136 // an SVD solution is made if indicated in the <src>invert</src> call. 00137 // 00138 // <li>The solutions and adjustment errors are obtained with the 00139 // <src>solve()</src> method. 00140 // A non-linear loop in a Levenberg-Marquardt adjustment can be obtained 00141 // (together with convergence information), with the <src>solveLoop()</src> 00142 // method (see below) replacing the combination of 00143 // <src>invert</src> and <src>solve</src>. 00144 // 00145 // <li>Non-linear loops are done by looping through the data using 00146 // <src>makeNorm()</src> calls, and upgrade the solution with the 00147 // <src>solveLoop()</src> method. 00148 // The normal equations are upgraded by changing LM factors. Upgrade depends 00149 // on the 'balanced' factor. The LM factor is either added in some way to all 00150 // diagonal elements (if balanced) or all diagonal elements are multiplied by 00151 // <src>(1+factor)</src> After each loop convergence can be tested 00152 // by the <src>isReady()</src> call; which will return <src>False</src> or 00153 // a non-zero code indicating the ready reason. Reasons for stopping can be: 00154 // <ul> 00155 // <li> SOLINCREMENT: the relative change in the norm of the parameter 00156 // solutions is less than 00157 // (a settable, <src>setEpsValue()</src>, default 1e-8) value. 00158 // <li> DERIVLEVEL: the inf-norm of the known vector of the equations to be 00159 // solved is less than the settable, <src>setEpsDerivative()</src>, default 00160 // 1e-8, value. 00161 // <li> MAXITER: maximum number of iterations reached (only possible if a 00162 // number is explicitly set) 00163 // <li> NOREDUCTION: if the Levenberg-Marquardt correction factor goes towards 00164 // infinity. I.e. if no Chi2 improvement seems possible. Have to redo the 00165 // solution with a different start condition for the unknowns. 00166 // <li> SINGULAR: can only happen due to numeric rounding, since the LM 00167 // equations are always positive-definite. Best solution is to indicate SVD 00168 // needed in the <src>solveLoop</src> call, which is cost-free 00169 // </ul> 00170 // 00171 // <li>Covariance information in various forms can be obtained with the 00172 // <src>getCovariance(), getErrors()</src>, <src>getChi()</src> 00173 // (or <src>getChi2</src>), <src>getSD</src> and <src>getWeightedSD</src> 00174 // methods after a <src>solve()</src> or after the final loop in a non-linear 00175 // solution (of course, when necessary only). 00176 // </ul> 00177 // 00178 // An LSQFit object can be re-used by issuing the <src>reset()</src> command, 00179 // or <src>set()</src> of new 00180 // values. If an unknown has not been used in the condition equations at all, 00181 // the <src>doDiagonal()</src> will make sure a proper solution is obtained, 00182 // with missing unknowns zeroed. 00183 // 00184 // Most of the calculations are done in place; however, enough data is saved 00185 // that it is possible to continue 00186 // with the same (partial) normal equations after e.g. an interim solution. 00187 // 00188 // If the normal equations are produced in separate partial sets (e.g. 00189 // in a multi-processor environment) a <src>merge()</src> method can combine 00190 // them. 00191 // <note role=tip> 00192 // It is suggested to add any possible constraint equations after the merge. 00193 // </note> 00194 // 00195 // A <src>debugIt()</src> method provides read access to all internal 00196 // information. 00197 // 00198 // The member definitions are split over three files. The second 00199 // one contains the templated member function definitions, to bypass the 00200 // problem of duplicate definitions of non-templated members when 00201 // pre-compiling them. The third contains methods for saving objects as 00202 // Records or through AipsIO. 00203 // 00204 // <note role=warning> No boundary checks on input and output containers 00205 // is done for faster execution. In general these tests should be done at 00206 // the higher level routines, like the 00207 // <linkto class=LinearFit>LinearFit</linkto> and 00208 // <linkto class=NonLinearFitLM>NonLinearFit</linkto> classes which should be 00209 // checked for usage of LSQFit. 00210 // </note> 00211 // 00212 // The contents can be saved in a record (<src>toRecord</src>), 00213 // and an object can be created from a record (<src>fromRecord</src>). 00214 // The record identifier is 'lfit'. 00215 // <br>The object can also be saved or restored using AipsIO. 00216 // </synopsis> 00217 // 00218 // <example> 00219 // See the tLSQFit.cc and tLSQaips.cc program for extensive examples. 00220 // 00221 // The following example will first create 2 condition equations for 00222 // 3 unknowns (the third is degenerate). It will first create normal equations 00223 // for a 2 unknown solution and solve; then it will create normal equations 00224 // for a 3 unknown solution, and solve (note that the degenerate will be 00225 // set to 0. The last one will use SVD and one condition equation.r 00226 // <srcblock> 00227 // #include <casa/aips.h> 00228 // #include <scimath/Fitting/LSQFit.h> 00229 // #include <iostream> 00230 // 00231 // int main() { 00232 // // Condition equations for x+y=2; x-y=4; 00233 // Double ce[2][3] = {{1, 1, 0}, {1, -1, 0}}; 00234 // Double m[2] = {2, 4}; 00235 // // Solution and error area 00236 // Double sol[3]; 00237 // Double sd, mu; 00238 // uInt rank; 00239 // Bool ok; 00240 // 00241 // // LSQ object 00242 // LSQFit fit(2); 00243 // 00244 // // Make normal equation 00245 // for (uInt i=0; i<2; i++) fit.makeNorm(ce[i], 1.0, m[i]); 00246 // // Invert(decompose) and show 00247 // ok = fit.invert(rank); 00248 // cout << "ok? " << ok << "; rank: " << rank << endl; 00249 // // Solve and show 00250 // if (ok) { 00251 // fit.solve(sol, &sd, &mu); 00252 // for (uInt i=0; i<2; i++) cout << "Sol" << i << ": " << sol[i] << endl; 00253 // cout << "sd: "<< sd << "; mu: " << mu << endl; 00254 // }; 00255 // cout << "----------" << endl; 00256 // 00257 // // Retry with 3 unknowns: note auto fill of unmentioned one 00258 // fit.set(uInt(3)); 00259 // for (uInt i=0; i<2; i++) fit.makeNorm(ce[i], 1.0, m[i]); 00260 // ok = fit.invert(rank); 00261 // cout << "ok? " << ok << "; rank: " << rank << endl; 00262 // if (ok) { 00263 // fit.solve(sol, &sd, &mu); 00264 // for (uInt i=0; i<3; i++) cout << "Sol" << i << ": " << sol[i] << endl; 00265 // cout << "sd: "<< sd << "; mu: " << mu << endl; 00266 // }; 00267 // cout << "----------" << endl; 00268 // 00269 // // Retry with 3 unknowns; but 1 condition equation and use SVD 00270 // fit.reset(); 00271 // for (uInt i=0; i<1; i++) fit.makeNorm(ce[i], 1.0, m[i]); 00272 // ok = fit.invert(rank, True); 00273 // cout << "ok? " << ok << "; rank: " << rank << endl; 00274 // if (ok) { 00275 // fit.solve(sol, &sd, &mu); 00276 // for (uInt i=0; i<3; i++) cout << "Sol" << i << ": " << sol[i] << endl; 00277 // cout << "sd: "<< sd << "; mu: " << mu << endl; 00278 // }; 00279 // cout << "----------" << endl; 00280 // 00281 // // Without SVD it would be: 00282 // fit.reset(); 00283 // for (uInt i=0; i<1; i++) fit.makeNorm(ce[i], 1.0, m[i]); 00284 // ok = fit.invert(rank); 00285 // cout << "ok? " << ok << "; rank: " << rank << endl; 00286 // if (ok) { 00287 // fit.solve(sol, &sd, &mu); 00288 // for (uInt i=0; i<3; i++) cout << "Sol" << i << ": " << sol[i] << endl; 00289 // cout << "sd: "<< sd << "; mu: " << mu << endl; 00290 // }; 00291 // cout << "----------" << endl; 00292 // 00293 // exit(0); 00294 // } 00295 // </srcblock> 00296 // Which will produce the output: 00297 // <srcblock> 00298 // ok? 1; rank: 2 00299 // Sol0: 3 00300 // Sol1: -1 00301 // sd: 0; mu: 0 00302 // ---------- 00303 // ok? 1; rank: 3 00304 // Sol0: 3 00305 // Sol1: -1 00306 // Sol2: 0 00307 // sd: 0; mu: 0 00308 // ---------- 00309 // ok? 1; rank: 2 00310 // Sol0: 1 00311 // Sol1: 1 00312 // Sol2: 0 00313 // sd: 0; mu: 0 00314 // ---------- 00315 // ok? 0; rank: 2 00316 // ---------- 00317 // </srcblock> 00318 // </example> 00319 // 00320 // <motivation> 00321 // The class was written to be able to do complex, real standard and SVD 00322 // solutions in a simple and fast way. 00323 // </motivation> 00324 // 00325 // <todo asof="2006/04/02"> 00326 // <li> a thorough check if all loops are optimal in the makeNorm() methods 00327 // <li> input of condition equations with cross covariance 00328 // </todo> 00329 00330 class LSQFit { 00331 public: 00332 // Simple classes to overload templated memberfunctions 00333 struct Real { enum normType { REAL }; }; 00334 struct Complex { enum normType { COMPLEX }; }; 00335 struct Separable { enum normType { SEPARABLE }; }; 00336 struct AsReal { enum normType { ASREAL }; }; 00337 struct Conjugate { enum normType { CONJUGATE }; }; 00338 // And values to use 00339 static Real REAL; 00340 static Complex COMPLEX; 00341 static Separable SEPARABLE; 00342 static AsReal ASREAL; 00343 static Conjugate CONJUGATE; 00344 00345 //# Public enums 00346 // State of the non-linear solution 00347 enum ReadyCode { 00348 NONREADY=0, 00349 SOLINCREMENT, 00350 DERIVLEVEL, 00351 MAXITER, 00352 NOREDUCTION, 00353 SINGULAR, 00354 N_ReadyCode 00355 }; 00356 // Offset of fields in error_p data area. 00357 enum ErrorField { 00358 // Number of condition equations 00359 NC, 00360 // Sum weights of condition equations 00361 SUMWEIGHT, 00362 // Sum known terms squared 00363 SUMLL, 00364 // Calculated chi^2 00365 CHI2, 00366 // Number of error fields 00367 N_ErrorField 00368 }; 00369 //# Constructors 00370 // Construct an object with the number of unknowns and 00371 // constraints, using the default collinearity factor and the 00372 // default Levenberg-Marquardt adjustment factor. 00373 // <group> 00374 // Assume real 00375 explicit LSQFit(uInt nUnknowns, uInt nConstraints=0); 00376 // Allow explicit Real specification 00377 LSQFit(uInt nUnknowns, const LSQReal &, uInt nConstraints=0); 00378 // Allow explicit Complex specification 00379 LSQFit(uInt nUnknowns, const LSQComplex &, uInt nConstraints=0); 00380 // </group> 00381 // Default constructor (empty, only usable after a <src>set(nUnknowns)</src>) 00382 LSQFit(); 00383 // Copy constructor (deep copy) 00384 LSQFit(const LSQFit &other); 00385 // Assignment (deep copy) 00386 LSQFit &operator=(const LSQFit &other); 00387 00388 //# Destructor 00389 ~LSQFit(); 00390 00391 //# Operators 00392 00393 //# General Member Functions 00394 // Triangularize the normal equations and determine 00395 // the rank <src>nRank</src> of the normal equations and, in the case of 00396 // an <src>SVD</src> solution, the constraint 00397 // equations. The collinearity factor is used 00398 // to determine if the system can be solved (in essence it is the square 00399 // of the sine of the angle between a column in the normal equations and 00400 // the plane suspended by the other columns: if too 00401 // parallel, the equations are degenerate). 00402 // If <src>doSVD</src> is given as False, False is returned if rank not 00403 // maximal, else an <src>SVD</src> solution is done. 00404 Bool invert(uInt &nRank, Bool doSVD=False); 00405 // Copy date from beg to end; converting if necessary to complex data 00406 // <group> 00407 template <class U> 00408 void copy(const Double *beg, const Double *end, U &sol, LSQReal); 00409 template <class U> 00410 void copy(const Double *beg, const Double *end, U &sol, LSQComplex); 00411 template <class U> 00412 void copy(const Double *beg, const Double *end, U *sol, LSQReal); 00413 template <class U> 00414 void copy(const Double *beg, const Double *end, U *sol, LSQComplex); 00415 template <class U> 00416 void uncopy(Double *beg, const Double *end, U &sol, LSQReal); 00417 template <class U> 00418 void uncopy(Double *beg, const Double *end, U &sol, LSQComplex); 00419 template <class U> 00420 void uncopy(Double *beg, const Double *end, U *sol, LSQReal); 00421 template <class U> 00422 void uncopy(Double *beg, const Double *end, U *sol, LSQComplex); 00423 template <class U> 00424 void copyDiagonal(U &errors, LSQReal); 00425 template <class U> 00426 void copyDiagonal(U &errors, LSQComplex); 00427 // </group> 00428 // Solve normal equations. 00429 // The solution will be given in <src>sol</src>. 00430 // <group> 00431 template <class U> 00432 void solve(U *sol); 00433 template <class U> 00434 void solve(std::complex<U> *sol); 00435 template <class U> 00436 void solve(U &sol); 00437 // </group> 00438 // Solve a loop in a non-linear set. 00439 // The methods with the <src>fit</src> argument are deprecated. Use 00440 // the combination without the 'fit' parameter, and the <src>isReady()</src> 00441 // call. The 'fit' parameter returns 00442 // for each loop a goodness 00443 // of fit indicator. If it is >0; more loops are necessary. 00444 // If it is negative, 00445 // and has an absolute value of say less than .001, it is probably ok, and 00446 // the iterations can be stopped. 00447 // Other arguments are as for <src>solve()</src> and <src>invert()</src>. 00448 // The <src>sol</src> is used for both input (parameter guess) and output. 00449 // <group> 00450 template <class U> 00451 Bool solveLoop(uInt &nRank, 00452 U *sol, 00453 Bool doSVD=False); 00454 template <class U> 00455 Bool solveLoop(uInt &nRank, 00456 std::complex<U> *sol, 00457 Bool doSVD=False); 00458 template <class U> 00459 Bool solveLoop(uInt &nRank, 00460 U &sol, 00461 Bool doSVD=False); 00462 template <class U> 00463 Bool solveLoop(Double &fit, uInt &nRank, 00464 U *sol, 00465 Bool doSVD=False); 00466 template <class U> 00467 Bool solveLoop(Double &fit, uInt &nRank, 00468 std::complex<U> *sol, 00469 Bool doSVD=False); 00470 template <class U> 00471 Bool solveLoop(Double &fit, uInt &nRank, 00472 U &sol, 00473 Bool doSVD=False); 00474 // </group> 00475 // Make normal equations using the <src>cEq</src> condition equation (cArray) 00476 // (with <src>nUnknowns</src> elements) and a weight <src>weight</src>, 00477 // given the known observed value <src>obs</src>. 00478 // 00479 // <src>doNorm</src> and <src>doKnown</src> can be used 00480 // to e.g. re-use existing normal equations, i.e. the condition equations, 00481 // but make a new known side (i.e. new observations). 00482 // 00483 // The versions with <src>cEqIndex[]</src> indicate which of the 00484 // <src>nUnknowns</src> are actually present in the condition equation 00485 // (starting indexing at 0); the other terms are supposed to be zero. E.g. 00486 // if a 12-telescope array has an equation only using telescopes 2 and 4, 00487 // the lengths of <src>cEqIndex</src> and <src>cEq</src> will be both 2, 00488 // and the index will contain 1 and 3 (when telescope numbering starts at 1) 00489 // or 2 and 4 (when telescope numbering starts at 0. The index is given 00490 // as an iterator (and hence can be a raw pointer) 00491 // 00492 // The complex versions can have different interpretation of the inputs, 00493 // where the complex number can be seen either as a complex number; as two 00494 // real numbers, or as coefficients of equations with complex conjugates. 00495 // See <a href="../notes/224.html">Note 224</a>) 00496 // for the details. 00497 // 00498 // Versions with <em>pair</em> assume that the pairs are created by the 00499 // <em>SparseDiff</em> automatic differentiation class. The pair is an index 00500 // and a value. The indices are assumed to be sorted. 00501 // 00502 // Special (<em>makeNormSorted</em>) indexed versions exist which assume 00503 // that the given indices are sorted (which is the case for the 00504 // LOFAR BBS environment). 00505 // 00506 // Some versions exist with two sets of equations (<em>cEq2, obs2</em>). 00507 // If two simultaneous equations are created they will be faster. 00508 // 00509 // Note that the 00510 // use of <src>const U &</src> is due to a Float->Double conversion problem 00511 // on Solaris. Linux was ok. 00512 // <group> 00513 template <class U, class V> 00514 void makeNorm(const V &cEq, const U &weight, const U &obs, 00515 Bool doNorm=True, Bool doKnown=True); 00516 template <class U, class V> 00517 void makeNorm(const V &cEq, const U &weight, const U &obs, 00518 LSQFit::Real, 00519 Bool doNorm=True, Bool doKnown=True); 00520 template <class U, class V> 00521 void makeNorm(const V &cEq, const U &weight, 00522 const std::complex<U> &obs, 00523 Bool doNorm=True, Bool doKnown=True); 00524 template <class U, class V> 00525 void makeNorm(const V &cEq, const U &weight, 00526 const std::complex<U> &obs, 00527 LSQFit::Complex, 00528 Bool doNorm=True, Bool doKnown=True); 00529 template <class U, class V> 00530 void makeNorm(const V &cEq, const U &weight, 00531 const std::complex<U> &obs, 00532 LSQFit::Separable, 00533 Bool doNorm=True, Bool doKnown=True); 00534 template <class U, class V> 00535 void makeNorm(const V &cEq, const U &weight, 00536 const std::complex<U> &obs, 00537 LSQFit::AsReal, 00538 Bool doNorm=True, Bool doKnown=True); 00539 template <class U, class V> 00540 void makeNorm(const V &cEq, const U &weight, 00541 const std::complex<U> &obs, 00542 LSQFit::Conjugate, 00543 Bool doNorm=True, Bool doKnown=True); 00544 // 00545 template <class U, class V, class W> 00546 void makeNorm(uInt nIndex, const W &cEqIndex, 00547 const V &cEq, const U &weight, const U &obs, 00548 Bool doNorm=True, Bool doKnown=True); 00549 template <class U, class V, class W> 00550 void makeNorm(uInt nIndex, const W &cEqIndex, 00551 const V &cEq, const V &cEq2, 00552 const U &weight, const U &obs, const U &obs2, 00553 Bool doNorm=True, Bool doKnown=True); 00554 template <class U, class V, class W> 00555 void makeNorm(uInt nIndex, const W &cEqIndex, 00556 const V &cEq, const U &weight, const U &obs, 00557 LSQFit::Real, 00558 Bool doNorm=True, Bool doKnown=True); 00559 template <class U, class V, class W> 00560 void makeNorm(uInt nIndex, const W &cEqIndex, 00561 const V &cEq, const U &weight, 00562 const std::complex<U> &obs, 00563 Bool doNorm=True, Bool doKnown=True); 00564 template <class U, class V, class W> 00565 void makeNorm(uInt nIndex, const W &cEqIndex, 00566 const V &cEq, const U &weight, 00567 const std::complex<U> &obs, 00568 LSQFit::Complex, 00569 Bool doNorm=True, Bool doKnown=True); 00570 template <class U, class V, class W> 00571 void makeNorm(uInt nIndex, const W &cEqIndex, 00572 const V &cEq, const U &weight, 00573 const std::complex<U> &obs, 00574 LSQFit::Separable, 00575 Bool doNorm=True, Bool doKnown=True); 00576 template <class U, class V, class W> 00577 void makeNorm(uInt nIndex, const W &cEqIndex, 00578 const V &cEq, const U &weight, 00579 const std::complex<U> &obs, 00580 LSQFit::AsReal, 00581 Bool doNorm=True, Bool doKnown=True); 00582 template <class U, class V, class W> 00583 void makeNorm(uInt nIndex, const W &cEqIndex, 00584 const V &cEq, const U &weight, 00585 const std::complex<U> &obs, 00586 LSQFit::Conjugate, 00587 Bool doNorm=True, Bool doKnown=True); 00588 // 00589 template <class U, class V> 00590 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00591 const U &weight, const U &obs, 00592 Bool doNorm=True, Bool doKnown=True); 00593 template <class U, class V> 00594 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00595 const U &weight, const U &obs, 00596 LSQFit::Real, 00597 Bool doNorm=True, Bool doKnown=True); 00598 template <class U, class V> 00599 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00600 const U &weight, 00601 const std::complex<U> &obs, 00602 Bool doNorm=True, Bool doKnown=True); 00603 template <class U, class V> 00604 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00605 const U &weight, 00606 const std::complex<U> &obs, 00607 LSQFit::Complex, 00608 Bool doNorm=True, Bool doKnown=True); 00609 template <class U, class V> 00610 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00611 const U &weight, 00612 const std::complex<U> &obs, 00613 LSQFit::Separable, 00614 Bool doNorm=True, Bool doKnown=True); 00615 template <class U, class V> 00616 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00617 const U &weight, 00618 const std::complex<U> &obs, 00619 LSQFit::AsReal, 00620 Bool doNorm=True, Bool doKnown=True); 00621 template <class U, class V> 00622 void makeNorm(const std::vector<std::pair<uInt, V> > &cEq, 00623 const U &weight, 00624 const std::complex<U> &obs, 00625 LSQFit::Conjugate, 00626 Bool doNorm=True, Bool doKnown=True); 00627 // 00628 template <class U, class V, class W> 00629 void makeNormSorted(uInt nIndex, const W &cEqIndex, 00630 const V &cEq, const U &weight, 00631 const U &obs, 00632 Bool doNorm=True, Bool doKnown=True); 00633 template <class U, class V, class W> 00634 void makeNormSorted(uInt nIndex, const W &cEqIndex, 00635 const V &cEq, const V &cEq2, const U &weight, 00636 const U &obs, const U &obs2, 00637 Bool doNorm=True, Bool doKnown=True); 00638 // </group> 00639 // Get the <src>n-th</src> (from 0 to the rank deficiency, or missing rank, 00640 // see e.g. <src>getDeficiency()</src>) 00641 // constraint equation as determined by <src>invert()</src> in SVD-mode in 00642 // <src> cEq[nUnknown]</src>. False returned for illegal n. Note 00643 // that nMissing will be equal to the number of unknowns 00644 // (<src>nUnknowns</src>, or double that for the complex case) minus the 00645 // rank as returned from the <src>invert()</src> method. 00646 // <group> 00647 template <class U> 00648 Bool getConstraint(uInt n, U *cEq) const; 00649 template <class U> 00650 Bool getConstraint(uInt n, std::complex<U> *cEq) const; 00651 template <class U> 00652 Bool getConstraint(uInt n, U &cEq) const; 00653 // </group> 00654 // Add a new constraint equation (updating nConstraints); or set a 00655 // numbered constraint equation (0..nConstraints-1). False if illegal 00656 // number n. The constraints are equations with <src>nUnknowns</src> terms, 00657 // and a constant value. E.g. measuring three angles of a triangle 00658 // could lead to equation <src>[1,1,1]</src> with obs as 00659 // <src>3.1415</src>. Note that each complex constraint will be 00660 // converted into two real constraints (see 00661 // <a href="../notes/224.html">Note 224</a>). 00662 // <group> 00663 template <class U, class V> 00664 Bool setConstraint(uInt n, const V &cEq, const U &obs); 00665 template <class U, class V> 00666 Bool setConstraint(uInt n, const V &cEq, 00667 const std::complex<U> &obs); 00668 template <class U, class V, class W> 00669 Bool setConstraint(uInt n, uInt nIndex, const W &cEqIndex, 00670 const V &cEq, const U &obs); 00671 template <class U, class V, class W> 00672 Bool setConstraint(uInt n, uInt nIndex, const W &cEqIndex, 00673 const V &cEq, 00674 const std::complex<U> &obs); 00675 template <class U, class V> 00676 Bool addConstraint(const V &cEq, const U &obs); 00677 template <class U, class V> 00678 Bool addConstraint(const V &cEq, 00679 const std::complex<U> &obs); 00680 template <class U, class V, class W> 00681 Bool addConstraint(uInt nIndex, const W &cEqIndex, 00682 const V &cEq, const U &obs); 00683 template <class U, class V, class W> 00684 Bool addConstraint(uInt nIndex, const W &cEqIndex, 00685 const V &cEq, 00686 const std::complex<U> &obs); 00687 // </group> 00688 // Merge other <src>LSQFit</src> object (i.e. the normal equation and 00689 // related information) into <src>this</src>. Both objects must have the 00690 // same number of unknowns, and be pure normal equations (i.e. no 00691 // <src>invert(), solve(), solveLoop()</src> or statistics calls 00692 // should have been made). If merging cannot be done, <src>False</src> 00693 // is returned. The index case (the index is an iterator) assumes that 00694 // the normal equations to be merged are a sparse subset of the complete 00695 // matrix. The index 'vector' specifies which unknowns are present. An index 00696 // outside the scope of the final equations will be skipped. 00697 // <note role=tip> For highest numerical precision in the case of a larger 00698 // number of partial normal equations to be merged, it is best to merge 00699 // them in pairs (and repeat). 00700 // </note> 00701 // <group> 00702 Bool merge(const LSQFit &other); 00703 Bool merge(const LSQFit &other, uInt nIndex, const uInt *nEqIndex) { 00704 return mergeIt(other, nIndex, nEqIndex); } 00705 Bool merge(const LSQFit &other, uInt nIndex, 00706 const std::vector<uInt> &nEqIndex) { 00707 return mergeIt(other, nIndex, &nEqIndex[0]); } 00708 template <class W> 00709 Bool merge(const LSQFit &other, uInt nIndex, const W &nEqIndex) { 00710 std::vector<uInt> ix(nIndex); 00711 for (uInt i=0; i<nIndex; ++i) ix[i] = nEqIndex[i]; 00712 return mergeIt(other, nIndex, &ix[0]); } 00713 // </group> 00714 // Reset status to empty 00715 void reset(); 00716 // Set new sizes (default is for Real) 00717 // <group> 00718 void set(uInt nUnknowns, uInt nConstraints=0); 00719 void set(Int nUnknowns, Int nConstraints=0) { 00720 set (static_cast<uInt>(nUnknowns), static_cast<uInt>(nConstraints)); 00721 }; 00722 void set(uInt nUnknowns, const LSQReal &, uInt nConstraints=0) { 00723 set (nUnknowns, nConstraints); 00724 }; 00725 void set(Int nUnknowns, const LSQReal &, Int nConstraints=0) { 00726 set (nUnknowns, nConstraints); 00727 }; 00728 void set(uInt nUnknowns, const LSQComplex &, uInt nConstraints=0); 00729 void set(Int nUnknowns, const LSQComplex &, Int nConstraints=0) { 00730 set (static_cast<uInt>(nUnknowns), LSQComplex(), 00731 static_cast<uInt>(nConstraints)); 00732 }; 00733 // </group> 00734 // Set new factors (collinearity <src>factor</src>, and Levenberg-Marquardt 00735 // <src>LMFactor</src>) 00736 void set(Double factor=1e-6, Double LMFactor=1e-3); 00737 // Set new value solution test 00738 void setEpsValue(Double epsval=1e-8) {epsval_p = epsval; }; 00739 // Set new derivative test 00740 void setEpsDerivative(Double epsder=1e-8) {epsder_p = epsder; }; 00741 // Set maximum number of iterations 00742 void setMaxIter(uInt maxiter=0) { maxiter_p = maxiter; }; 00743 // Get number of iterations done 00744 uInt nIterations() const { return (maxiter_p>0 ? maxiter_p-niter_p : 0); }; 00745 // Set the expected form of the normal equations 00746 void setBalanced(Bool balanced=False) { balanced_p = balanced; }; 00747 // Ask the state of the non-linear solutions 00748 // <group> 00749 LSQFit::ReadyCode isReady() const { return ready_p; }; 00750 const std::string &readyText() const; 00751 // </group> 00752 // Get the covariance matrix (of size <src>nUnknowns * nUnknowns</src>) 00753 // <group> 00754 template <class U> 00755 Bool getCovariance(U *covar); 00756 template <class U> 00757 Bool getCovariance(std::complex<U> *covar); 00758 // </group> 00759 // Get main diagonal of covariance function (of size <src>nUnknowns</src>) 00760 // <group> 00761 template <class U> 00762 Bool getErrors(U *errors); 00763 template <class U> 00764 Bool getErrors(std::complex<U> *errors); 00765 template <class U> 00766 Bool getErrors(U &errors); 00767 // </group> 00768 // Get the number of unknowns 00769 uInt nUnknowns() const { return nun_p; }; 00770 // Get the number of constraints 00771 uInt nConstraints() const { return ncon_p; }; 00772 // Get the rank deficiency <note role=warning>Note that the number is 00773 // returned assuming real values. For complex values it has to be halved 00774 // </note> 00775 uInt getDeficiency() const { return n_p-r_p; }; 00776 // Get chi^2 (both are identical); the standard deviation (per observation) 00777 // and the standard deviation per weight unit. 00778 // <group> 00779 Double getChi() const; 00780 Double getChi2() const { return getChi(); }; 00781 Double getSD() const; 00782 Double getWeightedSD() const; 00783 // </group> 00784 // Debug: 00785 // <ul> 00786 // <li> <src>nun = </src> number of unknowns 00787 // <li> <src>np = </src> total number of solved unknowns (nun+ncon) 00788 // <li> <src>ncon = </src> number of constraint equations 00789 // <li> <src>ner = </src> number of elements in chi<sup>2</sup> vector 00790 // <li> <src>rank = </src> rank) 00791 // <li> <src>nEq = </src> normal equation (nun*nun as triangular matrix) 00792 // <li> <src>known = </src> known vector (np) 00793 // <li> <src>constr = </src> constraint matrix (ncon*nun) 00794 // <li> <src>er = </src> error info vector (ner) 00795 // <li> <src>piv = </src> pivot vector (np) 00796 // <li> <src>sEq = </src> normal solution equation (np*np triangular) 00797 // <li> <src>sol = </src> internal solution vector (np) 00798 // <li> <src>prec = </src> collinearity precision 00799 // <li> <src>nonlin = </src> current Levenberg factor-1 00800 // </ul> 00801 // Note that all pointers may be 0. 00802 void debugIt(uInt &nun, uInt &np, uInt &ncon, uInt &ner, uInt &rank, 00803 Double *&nEq, Double *&known, Double *&constr, Double *&er, 00804 uInt *&piv, Double *&sEq, Double *&sol, 00805 Double &prec, Double &nonlin) const; 00806 // 00807 // Create an LSQFit object from a record. 00808 // An error message is generated, and False 00809 // returned if an invalid record is given. A valid record will return True. 00810 // Error messages are postfixed to error. 00811 // <group> 00812 Bool fromRecord(String &error, const RecordInterface &in); 00813 // </group> 00814 // Create a record from an LSQFit object. 00815 // The return will be False and an error 00816 // message generated only if the object does not contain a valid object. 00817 // Error messages are postfixed to error. 00818 Bool toRecord(String &error, RecordInterface &out) const; 00819 // Get identification of record 00820 const String &ident() const; 00821 // 00822 // Save or restore using AipsIO. 00823 // <group> 00824 void toAipsIO (AipsIO&) const; 00825 void fromAipsIO (AipsIO&); 00826 // </group> 00827 // 00828 protected: 00829 //# enum 00830 // Bits that can be set/referenced 00831 enum StateBit { 00832 // Inverted matrix present 00833 INVERTED = 1, 00834 // Triangularised 00835 TRIANGLE = 2*INVERTED, 00836 // Non-linear solution 00837 NONLIN = 2*TRIANGLE, 00838 // Filler for cxx2html 00839 N_StateBit 00840 }; 00841 00842 // Record field names 00843 // <group> 00844 static const String recid; 00845 static const String state; 00846 static const String nun; 00847 static const String ncon; 00848 static const String prec; 00849 static const String startnon; 00850 static const String nonlin; 00851 static const String rank; 00852 static const String nnc; 00853 static const String piv; 00854 static const String constr; 00855 static const String known; 00856 static const String errors; 00857 static const String sol; 00858 static const String lar; 00859 static const String wsol; 00860 static const String wcov; 00861 static const String nceq; 00862 static const String nar; 00863 // </group> 00864 00865 //# Data 00866 // Bits set to indicate state 00867 uInt state_p; 00868 // Number of unknowns 00869 uInt nun_p; 00870 // Number of constraints 00871 uInt ncon_p; 00872 // Matrix size (will be n_p = nun_p + ncon_p) 00873 uInt n_p; 00874 // Rank of normal equations (normally n_p) 00875 uInt r_p; 00876 // Collinearity precision 00877 Double prec_p; 00878 // Levenberg start factor 00879 Double startnon_p; 00880 // Levenberg current factor 00881 Double nonlin_p; 00882 // Levenberg step factor 00883 Double stepfactor_p; 00884 // Test value for [incremental] solution in non-linear loop. 00885 // The <src>||sol increment||/||sol||</src> is tested 00886 Double epsval_p; 00887 // Test value for known vector in non-linear loop. 00888 // ||known||<sub>inf</sub> is tested 00889 Double epsder_p; 00890 // Indicator for a well balanced normal equation. A balanced equation is 00891 // one with similar values in the main diagonal. 00892 Bool balanced_p; 00893 // Maximum number of iterations for non-linear solution. If a non-zero 00894 // maximum number of iterations is set, the value is tested in non-linear 00895 // loops 00896 uInt maxiter_p; 00897 // Iteration count for non-linear solution 00898 uInt niter_p; 00899 // Indicate the non-linear state. A non-zero code indicates that non-linear 00900 // looping is ready. 00901 ReadyCode ready_p; 00902 00903 // Pivot table (n_p) 00904 uInt *piv_p; 00905 // Normal equations (triangular nun_p * nun_p) 00906 LSQMatrix *norm_p; 00907 // Current length nceq_p 00908 uInt nnc_p; 00909 // Normal combined with constraint equations for solutions 00910 // (triangular nnc_p*nnc_p) 00911 LSQMatrix *nceq_p; 00912 // Known part equations (n_p) 00913 Double *known_p; 00914 // Counts for errors (N_ErrorField) 00915 Double *error_p; 00916 // Constraint equation area (nun_p*ncon_p)) 00917 Double *constr_p; 00918 // Solution area (n_p) 00919 Double *sol_p; 00920 // Save area for non-linear case (size determined internally) 00921 LSQFit *nar_p; 00922 // Save area for non-symmetric (i.e. with constraints) (n_p * n_p) 00923 Double *lar_p; 00924 // Work areas for interim solutions and covariance 00925 // <group> 00926 Double *wsol_p; 00927 Double *wcov_p; 00928 // </group> 00929 00930 //# Member functions 00931 // Get pointer in rectangular array 00932 // <group> 00933 Double *rowrt(uInt i) const { return &lar_p[n_p*i]; }; 00934 Double *rowru(uInt i) const { return &lar_p[nun_p*i]; }; 00935 // </group> 00936 // Calculate the real or imag part of <src>x*conj(y)</src> 00937 // <group> 00938 static Double realMC(const std::complex<Double> &x, 00939 const std::complex<Double> &y) { 00940 return (x.real()*y.real() + x.imag()*y.imag()); }; 00941 static Double imagMC(const std::complex<Double> &x, 00942 const std::complex<Double> &y) { 00943 return (x.imag()*y.real() - x.real()*y.imag()); }; 00944 static Float realMC(const std::complex<Float> &x, 00945 const std::complex<Float> &y) { 00946 return (x.real()*y.real() + x.imag()*y.imag()); }; 00947 static Float imagMC(const std::complex<Float> &x, 00948 const std::complex<Float> &y) { 00949 return (x.imag()*y.real() - x.real()*y.imag()); }; 00950 // </group> 00951 // Initialise areas 00952 void init(); 00953 // Clear areas 00954 void clear(); 00955 // De-initialise area 00956 void deinit(); 00957 // Solve normal equations 00958 void solveIt(); 00959 // One non-linear LM loop 00960 Bool solveItLoop(Double &fit, uInt &nRank, Bool doSVD=False); 00961 // Solve missing rank part 00962 void solveMR(uInt nin); 00963 // Invert rectangular matrix (i.e. when constraints present) 00964 Bool invertRect(); 00965 // Get the norm of the current solution vector 00966 Double normSolution(const Double *sol) const; 00967 // Get the infinite norm of the known vector 00968 Double normInfKnown(const Double *known) const; 00969 // Merge sparse normal equations 00970 Bool mergeIt(const LSQFit &other, uInt nIndex, const uInt *nEqIndex); 00971 // Save current status (or part) 00972 void save(Bool all=True); 00973 // Restore current status 00974 void restore(Bool all=True); 00975 // Copy data. If all False, only the relevant data for non-linear 00976 // solution are copied (normal equations, knows and errors). 00977 void copy(const LSQFit &other, Bool all=True); 00978 // Extend the constraint equation area to the specify number of 00979 // equations. 00980 void extendConstraints(uInt n); 00981 // Create the solution equation area nceq_p and fill it. 00982 void createNCEQ(); 00983 // Get work areas for solutions, covariance 00984 // <group> 00985 void getWorkSOL(); 00986 void getWorkCOV(); 00987 // </group> 00988 // 00989 }; 00990 00991 00992 } //# NAMESPACE CASA - END 00993 00994 #ifndef CASACORE_NO_AUTO_TEMPLATES 00995 #include <scimath/Fitting/LSQFit2.tcc> 00996 #endif //# CASACORE_NO_AUTO_TEMPLATES 00997 #endif