casa
$Rev:20696$
|
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