LSQ.h

Classes

LSQ -- Basic routines for complex least squares solutions (full description)

class LSQ : public LSQBase

Types

enum normType

REAL = 0
Real solution (default)
COMPLEX = 1
Normal complex variables and condition equations
SEPARABLE = 3
Separable complex. Solve for n complex variables, but have condition equations with 2n terms. Alternating for the real and imaginary part of the unknowns
ASREAL = 7
Separable as if complex are just two reals. Will give the same result as having 2n real variables to solve for, with independent condition equations for the two sets of n unknowns.
CONJUGATE = 11
Separable with consecutive unknowns are each other's conjugate. Solve for n complex unknowns, with 2n condition equation arguments, alternatively valid for x0, conj(x0), x1, conj(x1)...

Interface

Public Members
typedef WHATEVER_SUN_TYPEDEF(LSQ) normType normType
LSQ(uInt nUnknowns, uInt nKnowns=1, uInt nConstraints=0)
LSQ(uInt nUnknowns, LSQ::normType type, uInt nKnowns=1, uInt nConstraints=0)
LSQ()
LSQ(const LSQ &other)
LSQ &operator=(const LSQ &other)
~LSQ()
void solve(Double sol[], Double sd[], Double mu[])
void solve(Float sol[], Double sd[], Double mu[])
void solve(Complex sol[], Double sd[], Double mu[])
void solve(DComplex sol[], Double sd[], Double mu[])
Bool solveLoop(Double &fit, uInt &nRank, Double sol[], Double sd[], Double mu[], Bool doSVD=False)
Bool solveLoop(Double &fit, uInt &nRank, Float sol[], Double sd[], Double mu[], Bool doSVD=False)
Bool solveLoop(Double &fit, uInt &nRank, Complex sol[], Double sd[], Double mu[], Bool doSVD=False)
Bool solveLoop(Double &fit, uInt &nRank, DComplex sol[], Double sd[], Double mu[], Bool doSVD=False)
void makeNorm(const Double cEq[], Double weight, const Double obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Double cEq[], Double weight, Double obs, Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Float cEq[], Float weight, const Float obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Float cEq[], Float weight, Float obs, Bool doNorm=True, Bool doKnown=True)
void makeNorm(const DComplex cEq[], Double weight, const DComplex obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const DComplex cEq[], Double weight, const DComplex &obs, Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Complex cEq[], Float weight, const Complex obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Complex cEq[], Float weight, const Complex &obs, Bool doNorm=True, Bool doKnown=True)
void makeConstraint(const Double cEq[])
void makeConstraint(const Float cEq[])
void makeConstraint(const DComplex cEq[])
void makeConstraint(const Complex cEq[])
Bool getCovariance(Double *covar)
Bool getCovariance(Float *covar)
Bool getCovariance(DComplex *covar)
Bool getCovariance(Complex *covar)
Bool getErrors(Double *errors)
Bool getErrors(Float *errors)
Bool getErrors(Complex *errors)
Bool getErrors(DComplex *errors)

Description

Review Status

Reviewed By:
Neil Killeen
Date Reviewed:
2000/06/01
Programs:
Demos:
Tests:

Prerequisite

Etymology

From Least SQuares

Synopsis

This class contains the complex values routines for the Least Squares fitting. It will be combined with the LSQBase class to form the one LSQ class, as soon as aips++ contains the standard complex data type, and this class can be exported.

The only difference with the LSQBase class is the set of methods makeNorm(), solve(), solveLoop(), which can accept complex values.

The constructors can accept a complex code, indicating the type of complex solution wanted (see Note 224).

Example

See the tLSQ.cc program for extensive examples. The following example will first generate 2 condition equations in 3 unknowns (the third degenerate). The first solution will generate normal equations from then and solve. After that they are repeated with ASREAL and CONJUGATE types. The last one is a non-linear solution example.
      #include <aips/aips.h>
      #include <aips/Fitting/LSQ.h>
      #include <aips/Mathematics/Complex.h>
    #include <iostream>
      
      int main() {
        // Condition equations for x+y=2,3i; x-y=4,1i;
        DComplex ce[2][3] = {{DComplex(1,0), DComplex(1,0), DComplex(0,0)},
      		       {DComplex(1,0), DComplex(-1,0), DComplex(0,0)}};
        DComplex m[2] = {DComplex(2,3), DComplex(4,1)};
        // Solution and error area
        DComplex sol[3];
        Double sd, mu;
        uInt rank;
        Bool ok;
      
        // LSQ area
        LSQ fit(2, LSQ::COMPLEX);
      
        // Make normal equation
        for (uInt i=0; i<2; i++) fit.makeNorm(ce[i], 1.0, m[i]);
        // Invert and show
        ok = fit.invert(rank);
        cout << "ok? " << ok << "; rank: " << rank << endl;
        // Solve and show
        if (ok) {
          fit.solve(sol, &sd, &mu);
          for (uInt i=0; i<2; i++) cout << "Sol" << i << ": " << sol[i] << endl;
          cout << "sd: "<< sd << "; mu: " << mu << endl;
        };
        cout << "----------" << endl; 
      
        // Retry with ASREAL type
        fit.set(LSQ::ASREAL);
        for (uInt i=0; i<2; i++) fit.makeNorm(ce[i], 1.0, m[i]);
        ok = fit.invert(rank);
        cout << "ok? " << ok << "; rank: " << rank << endl;
        if (ok) {
          fit.solve(sol, &sd, &mu);
          for (uInt i=0; i<2; i++) cout << "Sol" << i << ": " << sol[i] << endl;
          cout << "sd: "<< sd << "; mu: " << mu << endl; 
        };
        cout << "----------" << endl; 
      
        // Retry with CONJUGATE type: note # of unknowns!
        fit.set(LSQ::CONJUGATE);
        fit.set(1);
        m[0] = DComplex(2,0); m[1] = DComplex(0,1);
        for (uInt i=0; i<2; i++) fit.makeNorm(ce[i], 1.0, m[i]);
        ok = fit.invert(rank, True);
        cout << "ok? " << ok << "; rank: " << rank << endl;
        if (ok) {
          fit.solve(sol, &sd, &mu);
          for (uInt i=0; i<1; i++) cout << "Sol" << i << ": " << sol[i] << endl;
          cout << "sd: "<< sd << "; mu: " << mu << endl; 
        };
        cout << "----------" << endl; 
    
        // Do a real non-linear one for solving x^2 and y^2
        {
          // Condition equations
          Double ce[4][2] = {{1, 1}, {1, -1}, {1, 2}, {3,2}};
          Double m[4] = {13, -5, 22.5, 29.5};
          Double wce[2], wm;
          // Solution and error area (and guess)
          Double sol[2] = {1.6, 3.3};
          Double sd, mu;
          Double covar[2][2];
          // How is fit?
          Double howfit(1);
          uInt rank;
          Bool ok;
          // Number of iterations allowed
          uInt nIter(20);
      
          cout << "Iter " << nIter << ": sol: (" << sol[0] << ", " <<
                   sol[1] << ")";
          cout << endl;
      
          // LSQ area
          LSQ fit(2, LSQ::REAL);
      
          // Iterate till fitting param ok or iterations used up
          while (nIter > 0 && (howfit > 0 || howfit < -0.001)) {
            // Make normal equation
            for (uInt i=0; i<4; i++) {
      	// Adjust
      	wm = m[i];
      	for (uInt j=0; j<2; j++) {
      	  wce[j] = 2*ce[i][j]*sol[j];
      	  wm -= ce[i][j]*sol[j]*sol[j];
      	};
      	fit.makeNorm(wce, 1.0, &wm);
            };
            ok = fit.solveLoop(howfit, rank, sol, &sd, &mu);
            cout << "Iter " << --nIter << ": sol: (" <<
                    sol[0] << ", " << sol[1] << ")";
            cout << "; how: " << howfit << ", rank: " << rank << endl;
          };
          // Show covariance -- but first to solve last time:
          // Make normal equation
          for (uInt i=0; i<4; i++) {
            // Adjust
            wm = m[i];
            for (uInt j=0; j<2; j++) {
      	wce[j] = 2*ce[i][j]*sol[j];
      	wm -= ce[i][j]*sol[j]*sol[j];
            };
            fit.makeNorm(wce, 1.0, &wm);
          };
          ok = fit.invert(rank);
          fit.solve(sol, &sd, &mu);
          cout << "Iter " << --nIter << ": sol: (" <<
                   sol[0] << ", " << sol[1] << ")";
          cout << endl;
          fit.getCovariance(covar[0]);
          for (uInt i=0; i<2; i++) {
            for (uInt j=0; j<2; j++) {
      	     cout << "Covar(" << i << ", " << j << ") = " <<
                        covar[i][j] << endl;
            };
          };
        }
      
        exit(0);
      }
    
Which will produce:
   ok? 1; rank: 4
   Sol0: (3, 2)
   Sol1: (-1, 1)
   sd: 0; mu: 0
   ----------
   ok? 1; rank: 4
   Sol0: (3, 0)
   Sol1: (-1, 0)
   sd: 3.16228; mu: 3.16228
   ----------
   ok? 1; rank: 2
   Sol0: (1, 0.5)
   sd: 0; mu: 0
   ----------
   Iter 20: sol: (1.6, 3.3)
   Iter 19: sol: (1.99258, 3.03617); how: 1, rank: 2
   Iter 18: sol: (1.95521, 3.02374); how: -1.78727, rank: 2
   Iter 17: sol: (1.95485, 3.02372); how: -0.877943, rank: 2
   Iter 16: sol: (1.95485, 3.02372); how: -8.59124e-05, rank: 2
   Iter 15: sol: (-9.54194e-14, 5.1996e-14)
   Covar(0, 0) = 0.0116822
   Covar(0, 1) = -0.0060421
   Covar(1, 0) = -0.0060421
   Covar(1, 1) = 0.00585938

Motivation

The class was written to be able to properly do complex valued least squares

To Do

Member Description

enum normType

Types of complex variables to be solved for

typedef WHATEVER_SUN_TYPEDEF(LSQ) normType normType

Reference enum Types (included originally for gcc 2.95)

LSQ(uInt nUnknowns, uInt nKnowns=1, uInt nConstraints=0)

Construct an object with the number of unknowns, knowns and constraints, and optionally the type, specified, using the default collinearity factor and the default Levenberg-Marquardt adjustment factor

Assume real

LSQ(uInt nUnknowns, LSQ::normType type, uInt nKnowns=1, uInt nConstraints=0)

Construct an object with the number of unknowns, knowns and constraints, and optionally the type, specified, using the default collinearity factor and the default Levenberg-Marquardt adjustment factor

Allow complex/real specification

LSQ()

Default constructor (empty, Complex, only usable after a set(nUnknowns))

LSQ(const LSQ &other)

Copy constructor (deep copy)

LSQ &operator=(const LSQ &other)

Assignment (deep copy)

~LSQ()

void solve(Double sol[], Double sd[], Double mu[])
void solve(Float sol[], Double sd[], Double mu[])
void solve(Complex sol[], Double sd[], Double mu[])
void solve(DComplex sol[], Double sd[], Double mu[])

Solve normal equations. The solution will be given in sol, with the adjustment error mu, and the standard deviation sd. I.e. mu is per unit weight, sd per observation.

Bool solveLoop(Double &fit, uInt &nRank, Double sol[], Double sd[], Double mu[], Bool doSVD=False)
Bool solveLoop(Double &fit, uInt &nRank, Float sol[], Double sd[], Double mu[], Bool doSVD=False)
Bool solveLoop(Double &fit, uInt &nRank, Complex sol[], Double sd[], Double mu[], Bool doSVD=False)
Bool solveLoop(Double &fit, uInt &nRank, DComplex sol[], Double sd[], Double mu[], Bool doSVD=False)

Solve a loop in a non-linear set. The fit argument returns for each loop a goodness of fit indicator. If it is >0; more loops are necessary. If it is negative, and has an absolute value of say less than .001, it is probably ok, and the iterations can be stopped. Other arguments are as for solve() and invert(). This non-linear solution wil only work for 1 known.

void makeNorm(const Double cEq[], Double weight, const Double obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Double cEq[], Double weight, Double obs, Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Float cEq[], Float weight, const Float obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Float cEq[], Float weight, Float obs, Bool doNorm=True, Bool doKnown=True)
void makeNorm(const DComplex cEq[], Double weight, const DComplex obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const DComplex cEq[], Double weight, const DComplex &obs, Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Complex cEq[], Float weight, const Complex obs[], Bool doNorm=True, Bool doKnown=True)
void makeNorm(const Complex cEq[], Float weight, const Complex &obs, Bool doNorm=True, Bool doKnown=True)

Make normal equations using the cEq condition equations (with nUnknowns elements) and a weight weight, given the known observed values obs (with nKnowns elements). doNorm and doKnown can be used to e.g. re-use existing normal equations, but make a new known side.

void makeConstraint(const Double cEq[])
void makeConstraint(const Float cEq[])
void makeConstraint(const DComplex cEq[])
void makeConstraint(const Complex cEq[])

Set constraint equations cEq (with [nUnknowns][nConstraints] elements).

Bool getCovariance(Double *covar)
Bool getCovariance(Float *covar)
Bool getCovariance(DComplex *covar)
Bool getCovariance(Complex *covar)

Get the covariance matrix (of size nUnknowns * nUnknowns)

Bool getErrors(Double *errors)
Bool getErrors(Float *errors)
Bool getErrors(Complex *errors)
Bool getErrors(DComplex *errors)

Get main diagonal of covariance function (of size nUnknowns)