casacore
Loading...
Searching...
No Matches
SparseDiff.h
Go to the documentation of this file.
1// # SparseDiff.h: An automatic differentiating class for functions
2// # Copyright (C) 2007,2008
3// # Associated Universities, Inc. Washington DC, USA.
4// #
5// # This library is free software; you can redistribute it and/or modify it
6// # under the terms of the GNU Library General Public License as published by
7// # the Free Software Foundation; either version 2 of the License, or (at your
8// # option) any later version.
9// #
10// # This library is distributed in the hope that it will be useful, but WITHOUT
11// # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12// # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13// # License for more details.
14// #
15// # You should have received a copy of the GNU Library General Public License
16// # along with this library; if not, write to the Free Software Foundation,
17// # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18// #
19// # Correspondence concerning AIPS++ should be addressed as follows:
20// # Internet email: casa-feedback@nrao.edu.
21// # Postal address: AIPS++ Project Office
22// # National Radio Astronomy Observatory
23// # 520 Edgemont Road
24// # Charlottesville, VA 22903-2475 USA
25
26#ifndef SCIMATH_SPARSEDIFF_H
27#define SCIMATH_SPARSEDIFF_H
28
29// # Includes
30#include <casacore/casa/aips.h>
31#include <casacore/scimath/Mathematics/AutoDiff.h>
32#include <casacore/scimath/Mathematics/SparseDiffRep.h>
33#include <casacore/casa/vector.h>
34#include <utility>
35
36// Using
37using std::pair;
38
39namespace casacore { // # NAMESPACE CASACORE - BEGIN
40
41// # Forward declarations
42template <class T>
43class SparseDiff;
44
45// <summary>
46// Class that computes partial derivatives by automatic differentiation.
47// </summary>
48//
49// <use visibility=export>
50//
51// <reviewed reviewer="UNKNOWN" date="" tests="tSparseDiff.cc" demos="dSparseDiff.cc">
52// </reviewed>
53//
54// <prerequisite>
55// <li> <linkto class=AutoDiff>AutoDiff</linkto> class
56// </prerequisite>
57//
58// <etymology>
59// Class that computes partial derivatives for some parameters by automatic
60// differentiation, thus SparseDiff.
61// </etymology>
62//
63// <synopsis>
64// Class that computes partial derivatives by automatic differentiation.
65// It does this by storing the value of a function and the values of its first
66// derivatives with respect to some of its independent parameters.
67// When a mathematical
68// operation is applied to a SparseDiff object, the derivative values of the
69// resulting new object are computed according to the chain rules
70// of differentiation. SparseDiff operates like the
71// <linkto class=AutoDiff>AutoDiff</linkto> class, but only determines the
72// derivatives with respect to the actual dependent variables.
73//
74// Suppose we have a function f(x0,x1,...,xn) and its differential is
75// <srcblock>
76// df = (df/dx0)*dx0 + (df/dx1)*dx1 + ... + (df/dxn)*dxn
77// </srcblock>
78// We can build a class that has the value of the function,
79// f(x0,x1,...,xn), and the values of the derivatives, (df/dx0), (df/dx1),
80// ..., (df/dxn) at (x0,x1,...,xn), as class members.
81//
82// Now if we have another function, g(x0,x1,...,xn) and its differential is
83// dg = (dg/dx0)*dx0 + (dg/dx1)*dx1 + ... + (dg/dxn)*dxn,
84// since
85// <srcblock>
86// d(f+g) = df + dg,
87// d(f*g) = g*df + f*dg,
88// d(f/g) = df/g - fdg/g^2,
89// dsin(f) = cos(f)df,
90// ...,
91// </srcblock>
92// we can calculate
93// <srcblock>
94// d(f+g), d(f*g), ...,
95// </srcblock> based on our information on
96// <srcblock>
97// df/dx0, df/dx1, ..., dg/dx0, dg/dx1, ..., dg/dxn.
98// </srcblock>
99// All we need to do is to define the operators and derivatives of common
100// mathematical functions.
101//
102// To be able to use the class as an automatic differentiator of a function
103// object, we need a templated function object, i.e. an object with:
104// <ul>
105// <li> a <src> template <class T> T operator()(const T)</src>
106// <li> or multiple variable input like:
107// <src> template <class T> T operator()(const Vector<T> &)</src>
108// <li> all dependent variables used in the calculation of the function
109// value should have been typed with T.
110// </ul>
111// A simple example of such a function object could be:
112// <srcblock>
113// template <class T> f {
114// public:
115// T operator()(const T &x, const T &a, const T &b) {
116// return a*b*x; }
117// };
118// // Instantiate the following versions:
119// template class f<Double>;
120// template class f<SparseDiff<Double> >;
121// </srcblock>
122// A call with values will produce the function value:
123// <srcblock>
124// cout << f(7.0, 2.0, 3.0) << endl;
125// // will produce the value at x=7 for a=2; b=3:
126// 42
127// // But a call indicating that we want derivatives to a and b:
128// cout << f(SparseDiff<Double>(7.0), SparseDiff<Double>(2.0, 0),
129// SparseDiff<Double>(3.0, 1)) << endl;
130// // will produce the value at x=7 for a=2; b=3:
131// // and the partial derivatives wrt a and b at x=7:
132// (42, [21, 14])
133// // The following will calculate the derivate wrt x:
134// cout << f(SparseDiff<Double>(7.0, 0), SparseDiff<Double>(2.0),
135// SparseDiff<Double>(3.0)) << endl;
136// (42,[6])
137// </srcblock>
138// Note that in practice constants may be given as Double constants.
139// In actual practice, there are a few rules to obey for the structure of
140// the function object if you want to use the function object and its
141// derivatives in least squares fitting procedures in the Fitting
142// module. The major one is to view the function object having 'fixed' and
143// 'variable' parameters. I.e., rather than viewing the function as
144// depending on parameters <em>a, b, x</em> (<src>f(a,b,x)</src>), the
145// function is considered to be <src>f(x; a,b)</src>, where <em>a, b</em>
146// are 'fixed' parameters, and <em>x</em> a variable parameter.
147// Fixed parameters should be contained in a
148// <linkto class=FunctionParam>FunctionParam</linkto> container object;
149// while the variable parameter(s) are given in the function
150// <src>operator()</src>. See <linkto class=Function>Function</linkto> class
151// for details.
152//
153// A Gaussian spectral profile would in general have the center frequency,
154// the width and the amplitude as fixed parameters, and the frequency as
155// a variable. Given a spectrum, you would solve for the fixed parameters,
156// given spectrum values. However, in other cases the role of the
157// parameters could be reversed. An example could be a whole stack of
158// observed (in the laboratory) spectra at different temperatures at
159// one frequency. In that case the width would be the variable parameter,
160// and the frequency one of the fixed (and to be solved for)parameters.
161//
162// Since the calculation of the derivatives is done with simple overloading,
163// the calculation of second (and higher) derivatives is easy. It should be
164// noted that higher deivatives are inefficient in the current incarnation
165// (there is no knowledge e.g. about symmetry in the Jacobian). However,
166// it is a very good way to get the correct answers of the derivatives. In
167// practice actual production code will be better off with specialization
168// of the <src>f<SparseDiff<> ></src> implementation.
169//
170// The <src>SparseDiff</src> class is the class the user communicates with.
171// Alias classes (<linkto class=SparseDiffA>SparseDiffA</linkto> and
172// <linkto class=SparseDiffA>SparseDiffX</linkto>) exist
173// to make it possible to have different incarnations of a templated
174// method (e.g. a generic one and a specialized one). See the
175// <src>dSparseDiff</src> demo for an example of its use.
176//
177// All operators and functions are declared in <linkto file=SparseDiffMath.h>
178// SparseDiffMath</linkto>. The output operator in
179// <linkto file=SparseDiffIO.h>SparseDiffIO</linkto>.
180// The actual structure of the
181// data block used by <src>SparseDiff</src> is described in
182// <linkto class=SparseDiffRep>SparseDiffRep</linkto>.
183//
184// A SparseDiff can be constructed from an AutoDiff.
185// <em>toAutoDiff(n)</em> can convert it to an AutoDiff.
186// </synopsis>
187//
188// <example>
189// <srcblock>
190// // First a simple example.
191// // We have a function of the form f(x,y,z); and want to know the
192// // value of the function for x=10; y=20; z=30; and for
193// // the derivatives at those points.
194// // Specify the values; and indicate the parameter dependence:
195// SparseDiff<Double> x(10.0, 0);
196// SparseDiff<Double> y(20.0, 1);
197// SparseDiff<Double> z(30.0, 2);
198// // The result will be:
199// SparseDiff<Double> result = x*y + sin(z);
200// cout << result.value() << endl;
201// // 199.012
202// cout << result.derivatives() << endl;
203// // [20, 10, 0.154251]
204// // Note: sin(30) = -0.988; cos(30) = 0.154251;
205// </srcblock>
206//
207// See for an extensive example the demo program dSparseDiff. It is
208// based on the example given above, and shows also the use of second
209// derivatives (which is just using <src>SparseDiff<SparseDiff<Double> ></src>
210// as template argument).
211// <srcblock>
212// // The function, with fixed parameters a,b:
213// template <class T> class f {
214// public:
215// T operator()(const T& x) { return a_p*a_p*a_p*b_p*b_p*x; }
216// void set(const T& a, const T& b) { a_p = a; b_p = b; }
217// private:
218// T a_p;
219// T b_p;
220// };
221// // Call it with different template arguments:
222// Double a0(2), b0(3), x0(7);
223// f<Double> f0; f0.set(a0, b0);
224// cout << "Value: " << f0(x0) << endl;
225//
226// SparseDiff<Double> a1(2,0), b1(3,1), x1(7);
227// f<SparseDiff<Double> > f1; f1.set(a1, b1);
228// cout << "Diff a,b: " << f1(x1) << endl;
229//
230// SparseDiff<Double> a2(2), b2(3), x2(7,0);
231// f<SparseDiff<Double> > f2; f2.set(a2, b2);
232// cout << "Diff x: " << f2(x2) << endl;
233//
234// SparseDiff<SparseDiff<Double> > a3(SparseDiff<Double>(2,0),0),
235// b3(SparseDiff<Double>(3,1),1), x3(SparseDiff<Double>(7));
236// f<SparseDiff<SparseDiff<Double> > > f3; f3.set(a3, b3);
237// cout << "Diff2 a,b: " << f3(x3) << endl;
238//
239// SparseDiff<SparseDiff<Double> > a4(SparseDiff<Double>(2)),
240// b4(SparseDiff<Double>(3)),
241// x4(SparseDiff<Double>(7,0),0);
242// f<SparseDiff<SparseDiff<Double> > > f4; f4.set(a4, b4);
243// cout << "Diff2 x: " << f4(x4) << endl;
244//
245// // Result will be:
246// // Value: 504
247// // Diff a,b: (504, [756, 336])
248// // Diff x: (504, [72])
249// // Diff2 a,b: ((504, [756, 336]), [(756, [756, 504]), (336, [504, 112])])
250// // Diff2 x: ((504, [72]), [(72, [0])])
251//
252// // It needed the template instantiations definitions:
253// template class f<Double>;
254// template class f<SparseDiff<Double> >;
255// template class f<SparseDiff<SparseDiff<Double> > >;
256// </srcblock>
257// </example>
258//
259// <motivation>
260// The creation of the class was motivated by least-squares non-linear fits
261// in cases where each individual condition equation depends only on a
262// fraction of the fixed parameters (e.g. self-calibration where only pairs
263// of antennas are present per equation), and hence only a few
264// partial derivatives of a fitted function are needed. It would be tedious
265// to create functionals for all partial derivatives of a function.
266// </motivation>
267//
268// <templating arg=T>
269// <li> any class that has the standard mathematical and comparison
270// operators and functions defined.
271// </templating>
272//
273// <todo asof="2007/11/27">
274// <li> Nothing I know of.
275// </todo>
276
277template <class T>
279 public:
280 // # Typedefs
281 typedef T value_type;
286
287 // # Constructors
288 // Construct a constant with a value of zero. Zero derivatives.
290
291 // Construct a constant with a value of v. Zero derivatives.
292 SparseDiff(const T &v);
293
294 // A function f(x0,x1,...,xn,...) with a value of v. The
295 // nth derivative is one, and all other derivatives are zero.
296 SparseDiff(const T &v, const uInt n);
297
298 // A function f(x0,x1,...,xn,...) with a value of v. The
299 // nth derivative is der, and all other derivatives are zero.
300 SparseDiff(const T &v, const uInt n, const T &der);
301
302 // Construct from an AutoDiff
303 SparseDiff(const AutoDiff<T> &other);
304
305 // Construct one from another (deep copy)
307
308 // Destructor
310
311 // Assignment operator. Assign a constant to variable.
313
314 // Assignment operator. Add a gradient to variable.
315 SparseDiff<T> &operator=(const pair<uInt, T> &der);
316
317 // Assignment operator. Assign gradients to variable.
318 SparseDiff<T> &operator=(const vector<pair<uInt, T>> &der);
319
320 // Assign from an Autodiff
322
323 // Assign one to another (deep copy)
325
326 // Assignment operators
327 // <group>
328 void operator*=(const SparseDiff<T> &other);
329 void operator/=(const SparseDiff<T> &other);
330 void operator+=(const SparseDiff<T> &other);
331 void operator-=(const SparseDiff<T> &other);
332 void operator*=(const T other) {
333 rep_p->operator*=(other);
334 value() *= other;
335 }
336 void operator/=(const T other) {
337 rep_p->operator/=(other);
338 value() /= other;
339 }
340 void operator+=(const T other) { value() += other; }
341 void operator-=(const T other) { value() -= other; }
342 // </group>
343
344 // Convert to an AutoDiff of length <em>n</em>
346
347 // Returns the pointer to the structure of value and derivatives.
348 // <group>
350 const SparseDiffRep<T> *theRep() const { return rep_p; }
351 // </group>
352
353 // Returns the value of the function
354 // <group>
355 T &value() { return rep_p->val_p; }
356 const T &value() const { return rep_p->val_p; }
357 // </group>
358
359 // Returns a vector of the derivatives of a SparseDiff
360 // <group>
361 vector<pair<uInt, T>> &derivatives() const;
362 void derivatives(vector<pair<uInt, T>> &res) const;
363 const vector<pair<uInt, T>> &grad() const { return rep_p->grad_p; }
364 vector<pair<uInt, T>> &grad() { return rep_p->grad_p; }
365 // </group>
366
367 // Returns a specific derivative. No check for a valid which.
368 // <group>
369 pair<uInt, T> &derivative(uInt which) { return rep_p->grad_p[which]; }
370 const pair<uInt, T> &derivative(uInt which) const { return rep_p->grad_p[which]; }
371 // </group>
372
373 // Return total number of derivatives
374 uInt nDerivatives() const { return rep_p->grad_p.size(); }
375
376 // Is it a constant, i.e., with zero derivatives?
377 Bool isConstant() const { return rep_p->grad_p.empty(); }
378
379 // Sort criterium
380 static Bool ltSort(pair<uInt, T> &lhs, pair<uInt, T> &rhs);
381
382 // Sort derivative list; cater for doubles and zeroes
383 void sort();
384
385 private:
386 // # Data
387 // Value representation
389};
390
391} // namespace casacore
392
393#ifndef CASACORE_NO_AUTO_TEMPLATES
394#include <casacore/scimath/Mathematics/SparseDiff.tcc>
395#endif // # CASACORE_NO_AUTO_TEMPLATES
396#endif
static Bool ltSort(pair< uInt, T > &lhs, pair< uInt, T > &rhs)
Sort criterium.
void sort()
Sort derivative list; cater for doubles and zeroes.
vector< pair< uInt, T > > & derivatives() const
Returns a vector of the derivatives of a SparseDiff.
const T & value() const
Definition SparseDiff.h:356
SparseDiff< T > & operator=(const vector< pair< uInt, T > > &der)
Assignment operator.
void operator*=(const SparseDiff< T > &other)
Assignment operators.
SparseDiff(const T &v, const uInt n)
A function f(x0,x1,...,xn,...) with a value of v.
SparseDiff(const T &v, const uInt n, const T &der)
A function f(x0,x1,...,xn,...) with a value of v.
SparseDiffRep< T > * theRep()
Returns the pointer to the structure of value and derivatives.
Definition SparseDiff.h:349
void operator/=(const SparseDiff< T > &other)
uInt nDerivatives() const
Return total number of derivatives.
Definition SparseDiff.h:374
void operator+=(const SparseDiff< T > &other)
SparseDiff< T > & operator=(const AutoDiff< T > &other)
Assign from an Autodiff.
void operator-=(const SparseDiff< T > &other)
pair< uInt, T > & derivative(uInt which)
Returns a specific derivative.
Definition SparseDiff.h:369
SparseDiff()
Construct a constant with a value of zero.
SparseDiff(const AutoDiff< T > &other)
Construct from an AutoDiff.
value_type & reference
Definition SparseDiff.h:282
const vector< pair< uInt, T > > & grad() const
Definition SparseDiff.h:363
~SparseDiff()
Destructor.
void operator-=(const T other)
Definition SparseDiff.h:341
const value_type & const_reference
Definition SparseDiff.h:283
SparseDiffRep< T > * rep_p
Value representation.
Definition SparseDiff.h:388
AutoDiff< T > toAutoDiff(uInt n) const
Convert to an AutoDiff of length n.
SparseDiff< T > & operator=(const T &v)
Assignment operator.
const SparseDiffRep< T > * theRep() const
Definition SparseDiff.h:350
SparseDiff(const T &v)
Construct a constant with a value of v.
Bool isConstant() const
Is it a constant, i.e., with zero derivatives?
Definition SparseDiff.h:377
value_type * iterator
Definition SparseDiff.h:284
const pair< uInt, T > & derivative(uInt which) const
Definition SparseDiff.h:370
T & value()
Returns the value of the function.
Definition SparseDiff.h:355
SparseDiff(const SparseDiff< T > &other)
Construct one from another (deep copy).
SparseDiff< T > & operator=(const SparseDiff< T > &other)
Assign one to another (deep copy).
SparseDiff< T > & operator=(const pair< uInt, T > &der)
Assignment operator.
vector< pair< uInt, T > > & grad()
Definition SparseDiff.h:364
void operator+=(const T other)
Definition SparseDiff.h:340
void operator/=(const T other)
Definition SparseDiff.h:336
const value_type * const_iterator
Definition SparseDiff.h:285
void operator*=(const T other)
Definition SparseDiff.h:332
void derivatives(vector< pair< uInt, T > > &res) const
For temporary backward namespace compatibility, use casa as alias for casacore.
Definition mainpage.dox:28
unsigned int uInt
Definition aipstype.h:49
bool Bool
Define the standard types used by Casacore.
Definition aipstype.h:40