casa
$Rev:20696$
|
00001 //# Function.h: Numerical functional interface class 00002 //# Copyright (C) 2001,2002,2003,2004,2005 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: Function.h 21024 2011-03-01 11:46:18Z gervandiepen $ 00027 00028 #ifndef SCIMATH_FUNCTION_H 00029 #define SCIMATH_FUNCTION_H 00030 00031 //# Includes 00032 #include <casa/aips.h> 00033 #include <casa/Arrays/Vector.h> 00034 #include <casa/BasicMath/Functional.h> 00035 #include <casa/Utilities/Assert.h> 00036 #include <scimath/Functionals/FunctionParam.h> 00037 #include <scimath/Functionals/FunctionTraits.h> 00038 00039 //# Forward declarations 00040 #include <casa/iosfwd.h> 00041 00042 namespace casa { //# NAMESPACE CASA - BEGIN 00043 00044 //# Forward declarations 00045 class String; 00046 class RecordInterface; 00047 00048 // <summary> Numerical functional interface class 00049 // </summary> 00050 00051 // <use visibility=export> 00052 00053 // <reviewed reviewer="tcornwel" date="1996/02/22" tests="tGaussian2D" 00054 // demos=""> 00055 // </reviewed> 00056 00057 // <prerequisite> 00058 // <li> <linkto class="Functional">Functional</linkto> 00059 // <li> <linkto class="FunctionParam">FunctionParam</linkto> 00060 // </prerequisite> 00061 // 00062 // <synopsis> 00063 // A <src>Function</src> is used for classes which map a 00064 // scalar or n-dimensional Vector of type <src>T</src> into a <src>T</src>. 00065 // The object also has zero or more parameters which can be masked 00066 // if necessary, and be used in the <src>Fitting</src> module, and, implicitly, 00067 // in the <linkto class=AutoDiff>AutoDiff</linkto> differentiation module. 00068 // 00069 // The parameter interface is provided by the 00070 // <linkto class="FunctionParam"><src>FunctionParam</src></linkto> class. 00071 // 00072 // A Function can have a <src>name()</src> which can be used in generic 00073 // interfaces. 00074 // 00075 // The function calls implemented are: 00076 // <ul> 00077 // <li> <src>operator()()</src> 00078 // <li> <src>operator()(const T &x)</src> 00079 // <li> <src>operator()(const Vector<T> &x)</src> 00080 // <li> <src>operator()(Function::FunctionArg x)</src> 00081 // <li> <src>operator()(const T &x, const T &y)</src> (for 2D) 00082 // <li> <src>operator()(const T &x, const T &y, const T &z)</src> (for 3D) 00083 // </ul> 00084 // The <src>T</src> in the above is the <src>Function::ArgType</src> 00085 // as derived from the <linkto class="FunctionTraits">FunctionTraits</linkto> 00086 // class. 00087 // These calls are (in debug mode) tested for the correct number of arguments, 00088 // after which they call a <src>T eval(FunctionArg x) const = 0</src> to 00089 // be implemented in derived classes. The derived class should also implement 00090 // an <src>uInt ndim() const = 0</src>. The derived class can access the 00091 // nth parameter with the <src>[n]</src> operator, and the corresponding 00092 // mask with <src>mask(n)</src> method. 00093 // The variables are referenced with <src>x[i]</src>. 00094 // 00095 // </synopsis> 00096 00097 // <example> 00098 // A complete implementation of say an <src>A.sin(2pi.f.x)</src> with 00099 // parameters amplitude(<em>A</em>) and frequency(<em>f</em>) and variable 00100 // time(<em>x</em>) could be: 00101 // <srcblock> 00102 // //# Sinusoid.h 00103 // #include <casa/aips.h> 00104 // #include <scimath/Functionals/Function.h> 00105 // #include <casa/BasicSL/Constants.h> 00106 // #include <casa/BasicMath/Math.h> 00107 // // The sinusoid class 00108 // template<class T> class Sinusoid : public Function<T> { 00109 // public: 00110 // // For easy reference of the parameters 00111 // enum { AMPL=0, FREQ }; 00112 // // Constructors. Defaults are A=1, f=1 00113 // Sinusoid() : Function<T>(2) { 00114 // param_p[AMPL] = T(1.0); param_p[FREQ] = T(1.0); } 00115 // explicit Sinusoid(const T &l) : Function<T>(2) { 00116 // param_p[AMPL] = ampl; param_p[FREQ] = T(1.0); } 00117 // Sinusoid(const T &l, const T &freq) : Function<T>(2) { 00118 // param_p[AMPL] = ampl; param_p[FREQ] = freq; } 00119 // Sinusoid(const Sinusoid &other) : Function<T>(2) { 00120 // param_p[AMPL] = other.param_p[AMPL]; 00121 // param_p[FREQ] = other.parameter[FREQ]; } 00122 // Sinusoid<T> &operator=(const Sinusoid<T> &other) { 00123 // if (this != &other) param_p = other.param_p; 00124 // return *this; } 00125 // virtual ~Sinusoid() {} 00126 // // Dimensionality 00127 // virtual uInt ndim() const { return 2; } 00128 // // Evaluate 00129 // virtual T eval(Function<T>::FunctionArg x) const { 00130 // return param_p[AMPL]*sin(T(C::_2pi)*param_p[FREQ]*x[0]); } 00131 // // Copy it 00132 // virtual Function<T> *clone() const { return new Sinusoid<T>(param_p); } 00133 // }; 00134 // </srcblock> 00135 // The following will calculate the value and the derivative for 00136 // <src>A=2; f=3; x=0.1;</src> 00137 // <srcblock> 00138 // // The function objects for value, and for value + derivative 00139 // Sinusoid<Double> soid1(2.0, 3.0); 00140 // typedef AutoDiff<Double> Adif; 00141 // Sinusoid<Adif> soid2(Adif(2,2,0), Adif(3,2,1)); 00142 // cout << "Value: " << soid1(0.1) << endl; 00143 // cout << "(val, deriv): " << soid2(Adif(0.1)) << endl; 00144 // </srcblock> 00145 // 00146 // A shorter version, where all parameter handling is done at user level 00147 // could be: 00148 // <srcblock> 00149 // //# Sinusoid.h 00150 // #include <casa/aips.h> 00151 // #include <scimath/Functionals/Function.h> 00152 // #include <casa/BasicSL/Constants.h> 00153 // #include <casa/BasicMath/Math.h> 00154 // template<class T> class Sinusoid : public Function<T> { 00155 // public: 00156 // enum { AMPL=0, FREQ }; 00157 // Sinusoid() : Function<T>(2){param_p[AMPL] T(1);param_p[FREQ]=T(1);} 00158 // virtual ~Sinusoid() {} 00159 // virtual uInt ndim() const { return 2; } 00160 // virtual T eval(Function<T>::FunctionArg x) const { 00161 // return param_p[AMPL]*sin(T(C::_2pi)*param_p[FREQ]*x[0]); } 00162 // virtual Function<T> *clone() const { return new Sinusoid<T>param_p; } 00163 // }; 00164 // </srcblock> 00165 // The following will calculate the value and the derivative for 00166 // <src>A=2; f=3; x=0.1;</src> 00167 // <srcblock> 00168 // // The function objects for value, and for value + derivative 00169 // typedef AutoDiff<Double> Adif; 00170 // typedef Function<Double> FD; 00171 // typedef Function<AutoDiff<Double> > FAdif 00172 // Sinusoid<Double> soid1; 00173 // Sinusoid<Adif> soid2; 00174 // soid1[FD::AMPL] = 2; soid1[FD::FREQ] = 3; 00175 // soid2[FAdif::AMPL] = Adif(2,2,0); 00176 // soid2[FAdif::FREQ] = Adif(3,2,1); 00177 // cout << "Value: " << soid1(0.1) << endl; 00178 // cout << "(val, deriv): " << soid2(Adif(0.1)) << endl; 00179 // </srcblock> 00180 // </example> 00181 00182 // <motivation> 00183 // A function of more than one variable was required for a function which 00184 // represents the sky brightness. Adjustable parameters were required for 00185 // non-linear least squares fitting. 00186 // </motivation> 00187 // 00188 // <templating arg=T> 00189 // <li> Besides the requirements set by the 00190 // <linkto class="Functional">Functional</linkto> base class, it must be 00191 // possible to form a <src>Vector<T></src>. 00192 // </templating> 00193 // 00194 // <todo asof="2005/01/20"> 00195 // <li> At some point, we may want to implement a letter-envelope class, 00196 // implement function arithmetic, etc. 00197 // <li> use maybe Poolstack for static Vector 00198 // </todo> 00199 00200 template<class T, class U=T> class Function : 00201 public Functional<typename FunctionTraits<T>::ArgType, U>, 00202 public Functional<Vector<typename FunctionTraits<T>::ArgType>, U> { 00203 00204 public: 00205 //# Typedefs 00206 typedef typename FunctionTraits<T>::ArgType ArgType; 00207 typedef const ArgType* FunctionArg; 00208 00209 //# Constructors 00210 // Constructors 00211 // <group> 00212 Function() : param_p(), arg_p(0), parset_p(False), locked_p(False) {} 00213 explicit Function(const uInt n) : param_p(n), arg_p(0), parset_p(False), 00214 locked_p(False) {} 00215 explicit Function(const Vector<T> &in) : param_p(in), arg_p(0), 00216 parset_p(False), locked_p(False) {} 00217 Function(const FunctionParam<T> &other) : param_p(other), arg_p(0), 00218 parset_p(False), locked_p(False) {} 00219 template <class W, class X> 00220 Function(const Function<W,X> &other) : param_p(other.parameters()), 00221 arg_p(0), parset_p(other.parsetp()), locked_p(False) {} 00222 Function(const Function<T,U> &other) : 00223 Functional<typename FunctionTraits<T>::ArgType, U> (other), 00224 Functional<Vector<typename FunctionTraits<T>::ArgType>, U>(other), 00225 param_p(other.param_p), 00226 arg_p(other.arg_p), 00227 parset_p(other.parset_p), 00228 locked_p(False) 00229 {} 00230 // </group> 00231 00232 // Destructor 00233 virtual ~Function() {} 00234 00235 // Returns the number of dimensions of function 00236 virtual uInt ndim() const = 0; 00237 // Returns the number of parameters 00238 uInt nparameters() const { return param_p.nelements(); } 00239 00240 // Evaluate the function object 00241 virtual U eval(FunctionArg x) const = 0; 00242 00243 //# Operators 00244 // Manipulate the nth parameter (0-based) with no index check 00245 // <group> 00246 T &operator[](const uInt n) { parset_p |= !locked_p; 00247 return param_p[n]; } 00248 const T &operator[](const uInt n) const { return param_p[n]; } 00249 // </group> 00250 // Evaluate this function object at <src>x</src>or at <src>x, y</src>. 00251 // The length of <src>x</src> must be greater than or equal to 00252 // <src>ndim()</src>. 00253 // <group> 00254 virtual U operator()() const { 00255 DebugAssert(ndim()==0, AipsError); return eval(FunctionArg(0)); } 00256 virtual U operator()(const ArgType &x) const { 00257 DebugAssert(ndim()<=1, AipsError); return eval(&x); } 00258 virtual U operator()(const Vector<ArgType> &x) const; 00259 virtual U operator()(FunctionArg x) const { return eval(x); } 00260 virtual U operator()(const ArgType &x, const ArgType &y) const; 00261 virtual U operator()(const ArgType &x, const ArgType &y, 00262 const ArgType &z) const; 00263 // </group> 00264 00265 //# Member functions 00266 // Specify the name associated with the function (default will be 00267 // <src>unknown</src>) 00268 virtual const String &name() const; 00269 // Manipulate the mask associated with the nth parameter 00270 // (e.g. to indicate whether the parameter is adjustable or 00271 // nonadjustable). 00272 // Note: no index check. 00273 // <group> 00274 Bool &mask(const uInt n) { parset_p |= !locked_p; 00275 return param_p.mask(n); } 00276 const Bool &mask(const uInt n) const { return param_p.mask(n); } 00277 // </group> 00278 // Return the parameter interface 00279 // <group> 00280 const FunctionParam<T> ¶meters() const { return param_p; } 00281 FunctionParam<T> ¶meters() { parset_p = True; return param_p; } 00282 // </group> 00283 // Get <src>arg_p</src> and <src>parset_p</src>. Necessary for reasons 00284 // of protection in the copying of non-conforming Functions. 00285 // <group> 00286 const Vector<ArgType> &argp() const { return arg_p; } 00287 Bool parsetp() const { return parset_p; } 00288 // </group> 00289 // Compiler cannot always find the correct 'const' version of parameter 00290 // access. In cases where this would lead to excessive overheads in 00291 // moving parameters around (like in <src>CompoundFunction</src>) the 00292 // parameter changing can be set to be locked, and no changes are 00293 // assumed. 00294 // <group> 00295 void lockParam() { locked_p = True; } 00296 void unlockParam() { locked_p = False; } 00297 // </group> 00298 00299 // get/set the function mode. These provide an interface to 00300 // function-specific configuration or state that controls how the 00301 // function calculates its values but otherwise does not qualify as 00302 // a parameter. Some part of the state, for example, might have a 00303 // type different from that of T. The state is passed as fields of a 00304 // record, mode--the names, types and values of which are specific to 00305 // the implementing function and should be documented in the implementing 00306 // class. It is recommended that all possible inputs passed to this 00307 // function via setMode() be considered optional such that if the 00308 // record omits a legal field, that part of the state is left unchanged. 00309 // Fields not recognized by the implementing class should be ignored. 00310 // An exception should be thrown if a recognized field contains illegal 00311 // data. The default implementations for both getMode() and setMode() 00312 // ignore the input record. 00313 // <group> 00314 virtual void setMode(const RecordInterface& mode); 00315 virtual void getMode(RecordInterface& mode) const; 00316 // </group> 00317 00318 // return True if the implementing function supports a mode. The default 00319 // implementation returns False. 00320 virtual Bool hasMode() const; 00321 00322 // Print the function (i.e. the parameters) 00323 ostream &print(ostream &os) const { return param_p.print(os); } 00324 // Return a copy of this object from the heap. The caller is responsible 00325 // for deleting this pointer. The <src>cloneAD</src> will return a clone 00326 // with an <src>AutoDef<T></src>; the <src>cloneNonAD</src> a clone 00327 // with <src><T></src>. An <src>AipsError</src> will be thrown if the 00328 // <src>cloneAD()</src> or <src>cloneNonAD()</src> is not implemented 00329 // for a specific function. 00330 // <group> 00331 virtual Function<T,U> *clone() const = 0; 00332 virtual Function<typename FunctionTraits<T>::DiffType> *cloneAD() const; 00333 virtual Function<typename FunctionTraits<T>::BaseType> 00334 *cloneNonAD() const; 00335 // </group> 00336 00337 protected: 00338 //# Data 00339 // The parameters and masks 00340 FunctionParam<T> param_p; 00341 // Aid for non-contiguous argument storage 00342 mutable Vector<ArgType> arg_p; 00343 // Indicate parameter written 00344 mutable Bool parset_p; 00345 // Indicate that parameters are expected to be locked from changing 00346 mutable Bool locked_p; 00347 }; 00348 00349 //# Global functions 00350 // <summary> Global functions </summary> 00351 // <group name=Output> 00352 // Output declaration 00353 template<class T, class U> 00354 ostream &operator<<(ostream &os, const Function<T,U> &fun); 00355 // </group> 00356 00357 //# Inlines 00358 template<class T, class U> 00359 inline ostream &operator<<(ostream &os, const Function<T,U> &fun) { 00360 return fun.print(os); } 00361 00362 } //# NAMESPACE CASA - END 00363 00364 #ifndef CASACORE_NO_AUTO_TEMPLATES 00365 #include <scimath/Functionals/Function.tcc> 00366 #endif //# CASACORE_NO_AUTO_TEMPLATES 00367 #endif