casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
LSQFit.h
Go to the documentation of this file.
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