casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
SparseDiff.h
Go to the documentation of this file.
00001 //# SparseDiff.h: An automatic differentiating class for functions
00002 //# Copyright (C) 2007,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 //#
00027 //# $Id: SparseDiff.h,v 1.3 2008/01/10 12:00:42 wbrouw Exp $
00028 
00029 #ifndef SCIMATH_SPARSEDIFF_H
00030 #define SCIMATH_SPARSEDIFF_H
00031 
00032 //# Includes
00033 #include <casa/aips.h>
00034 #include <scimath/Mathematics/AutoDiff.h>
00035 #include <scimath/Mathematics/SparseDiffRep.h>
00036 #include <casa/vector.h>
00037 #include <utility>
00038 
00039 // Using
00040 using std::pair;
00041 
00042 namespace casa { //# NAMESPACE CASA - BEGIN
00043 
00044   //# Forward declarations
00045   template <class T> class SparseDiff;
00046 
00047   // <summary>
00048   // Class that computes partial derivatives by automatic differentiation.
00049   // </summary>
00050   //
00051   // <use visibility=export>
00052   //
00053   // <reviewed reviewer="UNKNOWN" date="" tests="tSparseDiff.cc" demos="dSparseDiff.cc">
00054   // </reviewed>
00055   //
00056   // <prerequisite>
00057   // <li>  <linkto class=AutoDiff>AutoDiff</linkto> class
00058   // </prerequisite>
00059   //
00060   // <etymology>
00061   // Class that computes partial derivatives for some parameters by automatic
00062   // differentiation, thus SparseDiff.
00063   // </etymology>
00064   //
00065   // <synopsis>
00066   // Class that computes partial derivatives by automatic differentiation.
00067   // It does this by storing the value of a function and the values of its first 
00068   // derivatives with respect to some of its independent parameters. 
00069   // When a mathematical
00070   // operation is applied to a SparseDiff object, the derivative values of the 
00071   // resulting new object are computed according to the chain rules 
00072   // of differentiation. SparseDiff operates like the 
00073   // <linkto class=AutoDiff>AutoDiff</linkto> class, but only determines the
00074   // derivatives with respect to the actual dependent variables. 
00075   //
00076   // Suppose we have a function f(x0,x1,...,xn) and its differential is
00077   // <srcblock> 
00078   // df = (df/dx0)*dx0 + (df/dx1)*dx1 + ... + (df/dxn)*dxn
00079   // </srcblock> 
00080   // We can build a class that has the value of the function, 
00081   // f(x0,x1,...,xn), and the values of the derivatives, (df/dx0), (df/dx1), 
00082   // ..., (df/dxn) at (x0,x1,...,xn), as class members. 
00083   //
00084   // Now if we have another function, g(x0,x1,...,xn) and its differential is
00085   // dg = (dg/dx0)*dx0 + (dg/dx1)*dx1 + ... + (dg/dxn)*dxn,
00086   // since 
00087   // <srcblock> 
00088   // d(f+g) = df + dg, 
00089   // d(f*g) = g*df + f*dg, 
00090   // d(f/g) = df/g - fdg/g^2,
00091   // dsin(f) = cos(f)df, 
00092   // ...,
00093   // </srcblock> 
00094   // we can calculate
00095   // <srcblock>  
00096   // d(f+g), d(f*g), ..., 
00097   // </srcblock>  based on our information on
00098   // <srcblock>  
00099   // df/dx0, df/dx1, ..., dg/dx0, dg/dx1, ..., dg/dxn. 
00100   // </srcblock>  
00101   // All we need to do is to define the operators and derivatives of common 
00102   // mathematical functions.
00103   //
00104   // To be able to use the class as an automatic differentiator of a function
00105   // object, we need a templated function object, i.e. an object with:
00106   // <ul>
00107   // <li> a <src> template <class T> T operator()(const T)</src>
00108   // <li> or multiple variable input like: 
00109   //            <src> template <class T> T operator()(const Vector<T> &)</src>
00110   // <li> all dependent variables  used in the calculation of the function
00111   //    value should have been typed with T.
00112   // </ul>
00113   // A simple example of such a function object could be:
00114   // <srcblock>
00115   //    template <class T> f {
00116   //    public:
00117   //      T operator()(const T &x, const T &a, const T &b) {
00118   //            return a*b*x; }
00119   //    };
00120   //      // Instantiate the following versions:
00121   //    template class f<Double>;
00122   //    template class f<SparseDiff<Double> >;
00123   // </srcblock>
00124   // A call with values will produce the function value:
00125   // <srcblock>
00126   //    cout << f(7.0, 2.0, 3.0) << endl;
00127   //    // will produce the value at x=7 for a=2; b=3:
00128   //    42
00129   //    // But a call indicating that we want derivatives to a and b:
00130   //    cout << f(SparseDiff<Double>(7.0), SparseDiff<Double>(2.0, 0),
00131   //              SparseDiff<Double>(3.0, 1)) << endl;
00132   //    // will produce the value at x=7 for a=2; b=3:
00133   //    // and the partial derivatives wrt a and b at x=7:
00134   //    (42, [21, 14])
00135   //    // The following will calculate the derivate wrt x:
00136   //    cout << f(SparseDiff<Double>(7.0, 0), SparseDiff<Double>(2.0),
00137   //              SparseDiff<Double>(3.0)) << endl;
00138   //    (42,[6])
00139   // </srcblock>
00140   // Note that in practice constants may be given as Double constants.
00141   // In actual practice, there are a few rules to obey for the structure of
00142   // the function object if you want to use the function object and its
00143   // derivatives in least squares fitting procedures in the Fitting
00144   // module. The major one is to view the function object having 'fixed' and
00145   // 'variable' parameters. I.e., rather than viewing the function as
00146   // depending on parameters <em>a, b, x</em> (<src>f(a,b,x)</src>), the 
00147   // function is considered to be <src>f(x; a,b)</src>, where <em>a, b</em> 
00148   // are 'fixed' parameters, and <em>x</em> a variable parameter.
00149   // Fixed parameters should be contained in a 
00150   // <linkto class=FunctionParam>FunctionParam</linkto> container object;
00151   // while the variable parameter(s) are given in the function
00152   // <src>operator()</src>. See <linkto class=Function>Function</linkto> class
00153   // for details.
00154   //
00155   // A Gaussian spectral profile would in general have the center frequency,
00156   // the width and the amplitude as fixed parameters, and the frequency as
00157   // a variable. Given a spectrum, you would solve for the fixed parameters,
00158   // given spectrum values. However, in other cases the role of the
00159   // parameters could be reversed. An example could be a whole stack of
00160   // observed (in the laboratory) spectra at different temperatures at
00161   // one frequency. In that case the width would be the variable parameter,
00162   // and the frequency one of the fixed (and to be solved for)parameters. 
00163   //
00164   // Since the calculation of the derivatives is done with simple overloading, 
00165   // the calculation of second (and higher) derivatives is easy. It should be
00166   // noted that higher deivatives are inefficient in the current incarnation
00167   // (there is no knowledge e.g. about symmetry in the Jacobian). However,
00168   // it is a very good way to get the correct answers of the derivatives. In
00169   // practice actual production code will be better off with specialization
00170   // of the <src>f<SparseDiff<> ></src> implementation.
00171   //
00172   // The <src>SparseDiff</src> class is the class the user communicates with.
00173   // Alias classes (<linkto class=SparseDiffA>SparseDiffA</linkto> and
00174   // <linkto class=SparseDiffA>SparseDiffX</linkto>) exist
00175   // to make it possible to have different incarnations of a templated
00176   // method (e.g. a generic one and a specialized one). See the
00177   // <src>dSparseDiff</src> demo for an example of its use.
00178   //
00179   // All operators and functions are declared in <linkto file=SparseDiffMath.h> 
00180   // SparseDiffMath</linkto>. The output operator in 
00181   // <linkto file=SparseDiffIO.h>SparseDiffIO</linkto>.
00182   // The actual structure of the
00183   // data block used by <src>SparseDiff</src> is described in 
00184   // <linkto class=SparseDiffRep>SparseDiffRep</linkto>.
00185   //
00186   // A SparseDiff can be constructed from an AutoDiff.
00187   // <em>toAutoDiff(n)</em> can convert it to an AutoDiff.
00188   // </synopsis>
00189   //
00190   // <example>
00191   // <srcblock>
00192   // // First a simple example.
00193   // // We have a function of the form f(x,y,z); and want to know the
00194   // // value of the function for x=10; y=20; z=30; and for
00195   // // the derivatives at those points.
00196   // // Specify the values; and indicate the parameter dependence:
00197   //    SparseDiff<Double> x(10.0, 0); 
00198   //    SparseDiff<Double> y(20.0, 1); 
00199   //    SparseDiff<Double> z(30.0, 2);
00200   // // The result will be:
00201   //    SparseDiff<Double> result = x*y + sin(z);
00202   //    cout << result.value() << endl;
00203   // // 199.012
00204   //    cout << result.derivatives() << endl;
00205   // // [20, 10, 0.154251]
00206   // // Note: sin(30) = -0.988; cos(30) =  0.154251;
00207   // </srcblock>
00208   //
00209   // See for an extensive example the demo program dSparseDiff. It is
00210   // based on the example given above, and shows also the use of second
00211   // derivatives (which is just using <src>SparseDiff<SparseDiff<Double> ></src>
00212   // as template argument). 
00213   // <srcblock>
00214   //    // The function, with fixed parameters a,b:
00215   //    template <class T> class f {
00216   //    public:
00217   //      T operator()(const T& x) { return a_p*a_p*a_p*b_p*b_p*x; }
00218   //      void set(const T& a, const T& b) { a_p = a; b_p = b; }
00219   //    private:
00220   //      T a_p;
00221   //      T b_p;
00222   //    };
00223   //    // Call it with different template arguments:
00224   //      Double a0(2), b0(3), x0(7);
00225   //      f<Double> f0; f0.set(a0, b0);
00226   //      cout << "Value:     " << f0(x0) << endl;
00227   //    
00228   //      SparseDiff<Double> a1(2,0), b1(3,1), x1(7);
00229   //      f<SparseDiff<Double> > f1; f1.set(a1, b1);
00230   //      cout << "Diff a,b:   " << f1(x1) << endl;
00231   //    
00232   //      SparseDiff<Double> a2(2), b2(3), x2(7,0);
00233   //      f<SparseDiff<Double> > f2; f2.set(a2, b2);
00234   //      cout << "Diff x:     " << f2(x2) << endl;
00235   //    
00236   //      SparseDiff<SparseDiff<Double> > a3(SparseDiff<Double>(2,0),0),
00237   //        b3(SparseDiff<Double>(3,1),1), x3(SparseDiff<Double>(7));
00238   //      f<SparseDiff<SparseDiff<Double> > > f3; f3.set(a3, b3);
00239   //      cout << "Diff2 a,b:  " << f3(x3) << endl;
00240   //    
00241   //      SparseDiff<SparseDiff<Double> > a4(SparseDiff<Double>(2)),
00242   //        b4(SparseDiff<Double>(3)),
00243   //        x4(SparseDiff<Double>(7,0),0);
00244   //      f<SparseDiff<SparseDiff<Double> > > f4; f4.set(a4, b4);
00245   //      cout << "Diff2 x:    " << f4(x4) << endl;
00246   //
00247   //    // Result will be:
00248   //    // Value:     504
00249   //    // Diff a,b:  (504, [756, 336])
00250   //    // Diff x:    (504, [72])
00251   //    // Diff2 a,b: ((504, [756, 336]), [(756, [756, 504]), (336, [504, 112])])
00252   //    // Diff2 x:   ((504, [72]), [(72, [0])])
00253   //
00254   //    // It needed the template instantiations definitions:
00255   //    template class f<Double>;
00256   //    template class f<SparseDiff<Double> >;
00257   //    template class f<SparseDiff<SparseDiff<Double> > >;
00258   // </srcblock>
00259   // </example>
00260   //
00261   // <motivation>
00262   // The creation of the class was motivated by least-squares non-linear fits
00263   // in cases where each individual condition equation depends only on a
00264   // fraction of the fixed parameters (e.g. self-calibration where only pairs
00265   // of antennas are present per equation), and hence only a few 
00266   // partial derivatives of a fitted function are needed. It would be tedious
00267   // to create functionals for all partial derivatives of a function.
00268   // </motivation>
00269   //
00270   // <templating arg=T>
00271   //  <li> any class that has the standard mathematical and comparison
00272   //    operators and functions defined.
00273   // </templating>
00274   //
00275   // <todo asof="2007/11/27">
00276   // <li> Nothing I know of.
00277   // </todo>
00278 
00279   template <class T> class SparseDiff {
00280   public:
00281     //# Typedefs
00282     typedef T                   value_type;
00283     typedef value_type&         reference;
00284     typedef const value_type&   const_reference;
00285     typedef value_type*         iterator;
00286     typedef const value_type*   const_iterator;
00287 
00288     //# Constructors
00289     // Construct a constant with a value of zero.  Zero derivatives.
00290     SparseDiff();
00291  
00292     // Construct a constant with a value of v.  Zero derivatives.
00293     SparseDiff(const T &v);
00294 
00295     // A function f(x0,x1,...,xn,...) with a value of v.  The 
00296     // nth derivative is one, and all other derivatives are zero. 
00297     SparseDiff(const T &v, const uInt n); 
00298 
00299     // A function f(x0,x1,...,xn,...) with a value of v.  The 
00300     // nth derivative is der, and all other derivatives are zero. 
00301     SparseDiff(const T &v, const uInt n, const T &der); 
00302 
00303     // Construct from an AutoDiff
00304     SparseDiff(const AutoDiff<T> &other);
00305 
00306     // Construct one from another (deep copy)
00307     SparseDiff(const SparseDiff<T> &other);
00308 
00309     // Destructor
00310     ~SparseDiff();
00311 
00312     // Assignment operator.  Assign a constant to variable.
00313     SparseDiff<T> &operator=(const T &v);
00314 
00315     // Assignment operator.  Add a gradient to variable.
00316     SparseDiff<T> &operator=(const pair<uInt, T> &der);
00317 
00318     // Assignment operator.  Assign gradients to variable.
00319     SparseDiff<T> &operator=(const vector<pair<uInt, T> > &der);
00320 
00321     // Assign from an Autodiff
00322     SparseDiff<T> &operator=(const AutoDiff<T> &other);
00323 
00324     // Assign one to another (deep copy)
00325     SparseDiff<T> &operator=(const SparseDiff<T> &other);
00326 
00327     // Assignment operators
00328     // <group>
00329     void operator*=(const SparseDiff<T> &other);
00330     void operator/=(const SparseDiff<T> &other);
00331     void operator+=(const SparseDiff<T> &other);
00332     void operator-=(const SparseDiff<T> &other);
00333     void operator*=(const T other) { rep_p->operator*=(other);
00334     value() *= other; }
00335     void operator/=(const T other) { rep_p->operator/=(other);
00336     value() /= other; }
00337     void operator+=(const T other) { value() += other; }
00338     void operator-=(const T other) { value() -= other; }
00339     // </group>
00340 
00341     // Convert to an AutoDiff of length <em>n</em>
00342     AutoDiff<T> toAutoDiff(uInt n) const;
00343 
00344     // Returns the pointer to the structure of value and derivatives.
00345     // <group>
00346     SparseDiffRep<T> *theRep() { return rep_p; }
00347     const SparseDiffRep<T> *theRep() const { return rep_p; }
00348     // </group>
00349 
00350     // Returns the value of the function
00351     // <group>
00352     T &value() { return rep_p->val_p; }
00353     const T &value() const { return rep_p->val_p; }
00354     // </group>
00355   
00356     // Returns a vector of the derivatives of a SparseDiff
00357     // <group>
00358     vector<pair<uInt, T> > &derivatives() const;
00359     void derivatives(vector<pair<uInt, T> > &res) const;
00360     const vector<pair<uInt, T> > &grad() const { return rep_p->grad_p; }
00361     vector<pair<uInt, T> > &grad() { return rep_p->grad_p; }
00362     // </group>
00363 
00364     // Returns a specific derivative. No check for a valid which.
00365     // <group>
00366     pair<uInt, T> &derivative(uInt which) { return rep_p->grad_p[which]; }
00367     const pair<uInt, T> &derivative(uInt which) const {
00368       return rep_p->grad_p[which]; }
00369     // </group>
00370   
00371     // Return total number of derivatives
00372     uInt nDerivatives() const { return rep_p->grad_p.size(); }
00373   
00374     // Is it a constant, i.e., with zero derivatives?
00375     Bool isConstant() const { return rep_p->grad_p.empty(); }
00376 
00377     // Sort criterium
00378     static Bool ltSort(pair<uInt, T> &lhs, pair<uInt, T> &rhs);
00379 
00380     // Sort derivative list; cater for doubles and zeroes
00381     void sort();
00382  
00383   private:
00384     //# Data
00385     // Value representation
00386     SparseDiffRep<T> *rep_p;
00387 
00388   };
00389 
00390 
00391 } //# NAMESPACE CASA - END
00392 
00393 #ifndef CASACORE_NO_AUTO_TEMPLATES
00394 #include <scimath/Mathematics/SparseDiff.tcc>
00395 #endif //# CASACORE_NO_AUTO_TEMPLATES
00396 #endif