casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Function.h
Go to the documentation of this file.
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 &ampl) : Function<T>(2) {
00116 //         param_p[AMPL] = ampl; param_p[FREQ] = T(1.0); }
00117 //     Sinusoid(const T &ampl, 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> &parameters() const { return param_p; }
00281      FunctionParam<T> &parameters() { 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