jacobian.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_JACOBIAN_H
00024 #define O2SCL_JACOBIAN_H
00025 
00026 #include <string>
00027 #include <o2scl/collection.h>
00028 #include <o2scl/omatrix_tlate.h>
00029 #include <o2scl/mm_funct.h>
00030 #include <o2scl/gsl_deriv.h>
00031 
00032 #ifndef DOXYGENP
00033 namespace o2scl {
00034 #endif
00035 
00036   /** 
00037       \brief Base for a square Jacobian where J is computed at x given y=f(x)
00038 
00039       Compute
00040       \f[
00041       J_(i,j) = \frac{\partial f_i}{\partial x_j}
00042       \f]
00043 
00044       The \c vec_t objects in operator() could have been written to be
00045       \c const, but they are not \c const so that they can be
00046       used as temporary workspace. They are restored to their 
00047       original values before operator() exits.
00048 
00049   */
00050   template<class param_t, class vec_t=ovector_view, 
00051     class mat_t=omatrix_view> class jac_funct {
00052 
00053     public:  
00054 
00055     jac_funct() {}
00056 
00057     virtual ~jac_funct() {}
00058     
00059     /** \brief The operator()
00060      */
00061     virtual int operator()(size_t nv, vec_t &x, 
00062                            vec_t &y, mat_t &j, param_t &pa) {
00063       set_err_ret("Missing base in mm_funct::operator().",gsl_nobase);
00064     }
00065     
00066 #ifndef DOXYGENP
00067 
00068     private:
00069 
00070     jac_funct(const jac_funct &);
00071     jac_funct& operator=(const jac_funct&);
00072 
00073 #endif
00074 
00075   };
00076 
00077   /** \brief Function pointer to jacobian
00078    */
00079   template<class param_t, class vec_t=ovector_view, 
00080     class mat_t=omatrix_view> class jac_funct_fptr : 
00081   public jac_funct<param_t,vec_t,mat_t> {
00082     
00083     public:
00084     
00085     /** \brief Specify the function pointer
00086      */
00087     jac_funct_fptr(int (*fp)(size_t nv, vec_t &x, vec_t &y, 
00088                              mat_t &j, param_t &pa)) {
00089       fptr=fp;
00090     }
00091     
00092     virtual ~jac_funct_fptr();
00093     
00094     /** \brief The operator()
00095      */
00096     virtual int operator()(size_t nv, vec_t &x, 
00097                            vec_t &y, mat_t &j, param_t &pa) {
00098       return fptr(nv,x,y,j,pa);
00099     }
00100 
00101 #ifndef DOXYGENP
00102 
00103     protected:
00104   
00105     jac_funct_fptr() {};
00106     
00107     /// Function pointer
00108     int (*fptr)(size_t nv, vec_t &x, vec_t &y,
00109                 mat_t &j, param_t &pa);
00110     
00111     private:
00112 
00113     jac_funct_fptr(const jac_funct_fptr &);
00114     jac_funct_fptr& operator=(const jac_funct_fptr&);
00115 
00116 #endif
00117 
00118   };
00119 
00120   /** \brief Member function pointer to a Jacobian
00121    */
00122   template <class tclass, class param_t, class vec_t=ovector_view,
00123     class mat_t=omatrix_view> class jac_funct_mfptr : 
00124   public jac_funct<param_t,vec_t,mat_t> {
00125 
00126     public:
00127   
00128     /** \brief Specify the member function pointer
00129      */
00130     jac_funct_mfptr(tclass *tp, int (tclass::*fp)
00131                     (size_t nv, vec_t &x, vec_t &y,
00132                      mat_t &j, param_t &pa)) {
00133       tptr=tp;
00134       fptr=fp;
00135     }
00136   
00137     virtual ~jac_funct_mfptr() {};
00138   
00139     /** \brief The operator()
00140      */
00141     virtual int operator()(size_t nv, vec_t &x, 
00142                            vec_t &y, mat_t &j, param_t &pa) {
00143       return (*tptr.*fptr)(nv,x,y,j,pa);
00144     }
00145   
00146 #ifndef DOXYGEN_INTERNAL
00147 
00148     protected:
00149   
00150     /// Member function pointer
00151     int (tclass::*fptr)(size_t nv, vec_t &x, vec_t &y,
00152                         mat_t &j, param_t &pa);
00153 
00154     /// Class pointer
00155     tclass *tptr;
00156 
00157 #endif
00158 
00159 #ifndef DOXYGENP
00160   
00161     private:
00162 
00163     jac_funct_mfptr(const jac_funct_mfptr &);
00164     jac_funct_mfptr& operator=(const jac_funct_mfptr&);
00165 
00166 #endif
00167 
00168   };
00169 
00170   /** \brief Base for providing a numerical jacobian
00171    */
00172   template<class param_t, class func_t, class vec_t=ovector_view, 
00173     class mat_t=omatrix_view>
00174     class jacobian : public jac_funct<param_t,vec_t,mat_t> {
00175     public:
00176     
00177     jacobian() {
00178     };
00179     
00180     virtual ~jacobian() {};
00181     
00182     /// Set the function to compute the Jacobian of
00183     virtual int set_function(func_t &f) {
00184       func=&f;
00185       return 0;
00186     }
00187     
00188     /** \brief The operator()
00189      */
00190     virtual int operator()(size_t nv, vec_t &x, vec_t &y,
00191                            mat_t &j, param_t &pa) {
00192       return 0;
00193     }
00194     
00195 #ifndef DOXYGEN_INTERNAL
00196     
00197     protected:
00198     
00199     /// A pointer to the user-specified function
00200     func_t *func;
00201     
00202     private:
00203     
00204     jacobian(const jacobian &);
00205     jacobian& operator=(const jacobian&);
00206     
00207 #endif
00208     
00209   };
00210   
00211   /** 
00212       \brief Simple automatic Jacobian
00213       
00214       This simple routine is nearly equivalent to GSL as given in \c
00215       multiroots/fdjac.c. It has an additional test to ensure that the
00216       finite-differencing stepsize does not vanish, and returns an
00217       error if the Jacobian is singular. To obtain the GSL behavior,
00218       set \ref epsrel to \c GSL_SQRT_DBL_EPSILON and set epsmin to
00219       zero. 
00220 
00221       This class does not separately check the vector and matrix sizes
00222       to ensure they are commensurate. 
00223 
00224       \todo Double check that this class works with arrays
00225   */
00226   template<class param_t, class func_t, class vec_t=ovector_view, 
00227     class mat_t=omatrix_view, class alloc_vec_t=ovector, 
00228     class alloc_t=ovector_alloc> class simple_jacobian : 
00229   public jacobian<param_t,func_t,vec_t,mat_t> {
00230 
00231     public:
00232     
00233     simple_jacobian() {
00234       epsrel=1.0e-4;
00235       epsmin=1.0e-15;
00236     }
00237     
00238     /** \brief The relative stepsize for finite-differencing 
00239         (default \f$ 10^{-4} \f$ )
00240     */
00241     double epsrel;
00242     
00243     /// The minimum stepsize (default \f$ 10^{-15} \f$)
00244     double epsmin;
00245 
00246     /// For memory allocation
00247     alloc_t ao;
00248 
00249     /** \brief The operator()
00250      */
00251     virtual int operator()(size_t nv, vec_t &x, vec_t &y, 
00252                            mat_t &jac, param_t &pa) {
00253       
00254       size_t i,j;
00255       double h,temp;
00256       alloc_vec_t f;
00257       bool success=true;
00258 
00259       ao.allocate(f,nv);
00260       
00261       for (j=0;j<nv;j++) {
00262         
00263         h=epsrel*fabs(x[j]);
00264         if (fabs(h)<=epsmin) h=epsrel;
00265         
00266         x[j]+=h;
00267         (*this->func)(nv,x,f,pa);
00268         x[j]-=h;
00269 
00270         bool nonzero=false;
00271         for (i=0;i<nv;i++) {
00272           temp=(f[i]-y[i])/h;
00273           if (temp!=0.0) nonzero=true;
00274           jac[i][j]=temp;
00275         }
00276         if (nonzero==false) success=false;
00277       }
00278       
00279       ao.free(f);
00280       
00281       if (success==false) {
00282         set_err_ret("At least one row of the Jacobian is zero.",gsl_efailed);
00283       }
00284       return 0;
00285     }
00286   };
00287 
00288   /** 
00289       \brief A direct calculation of the jacobian using a \ref deriv object
00290       
00291       Note that it is sometimes wasteful to use this Jacobian in a
00292       root-finding routine and using more approximate Jacobians is
00293       more efficient. This class is mostly useful for demonstration
00294       purposes.
00295   */
00296   template<class param_t, class func_t, class vec_t=ovector_view, 
00297     class mat_t=omatrix_view> class exact_jacobian : 
00298   public jacobian<param_t,func_t,vec_t,mat_t> {
00299     
00300     public:
00301     
00302     exact_jacobian() {
00303       def_deriv.h=1.0e-4;
00304       dptr=&def_deriv;
00305     }
00306     
00307     /** 
00308         \brief Parameter structure for passing information
00309         
00310         This class is primarily useful for specifying derivatives
00311         for using the jacobian::set_deriv() function.
00312 
00313         \comment
00314         This type needs to be publicly available so that the
00315         user can properly specify a base 1-dimensional derivative
00316         object. 
00317         \endcomment
00318     */
00319     typedef struct {
00320       /// The number of variables
00321       size_t nv;
00322       /// The current x value
00323       size_t xj;
00324       /// The current y value
00325       size_t yi;
00326       /// The x vector
00327       vec_t *x;
00328       /// The y vector
00329       vec_t *y;
00330       /// The parameters
00331       param_t *pa;
00332     } ej_parms;
00333 
00334     /// The default derivative object
00335     gsl_deriv<ej_parms,funct<ej_parms> > def_deriv;
00336 
00337     /// Set the derivative object
00338     int set_deriv(deriv<ej_parms,funct<ej_parms> > &de) {
00339       dptr=&de;
00340       return 0;
00341     }
00342     
00343     /** \brief The operator()
00344      */
00345     virtual int operator()(size_t nv, vec_t &x, vec_t &y, 
00346                            mat_t &jac, param_t &pa) {
00347       size_t i,j;
00348       double h,temp;
00349 
00350       ej_parms ejp;
00351       ejp.nv=nv;
00352       ejp.x=&x;
00353       ejp.y=&y;
00354       ejp.pa=&pa;
00355       
00356       funct_mfptr<exact_jacobian,ej_parms> dfnp(this,&exact_jacobian::dfn);
00357       
00358       for (j=0;j<nv;j++) {
00359         ejp.xj=j;
00360         for (i=0;i<nv;i++) {
00361           ejp.yi=i;
00362           double tmp=(*ejp.x)[j];
00363           jac[i][j]=dptr->calc(tmp,ejp,dfnp);
00364           (*ejp.x)[j]=tmp;
00365         }
00366       }
00367 
00368       return 0;
00369     }
00370     
00371 
00372 #ifndef DOXYGEN_INTERNAL
00373 
00374     protected:
00375 
00376     /// Pointer to the derivative object
00377     deriv<ej_parms,funct<ej_parms> > *dptr;
00378     
00379     /// Function for the derivative object
00380     int dfn(double x, double &y, ej_parms &ejp) {
00381       (*ejp.x)[ejp.xj]=x;
00382       (*this->func)(ejp.nv,*ejp.x,*ejp.y,*ejp.pa);
00383       y=(*ejp.y)[ejp.yi];
00384       return 0;
00385     }
00386 
00387 #endif
00388 
00389   };
00390   
00391 #ifndef DOXYGENP
00392 }
00393 #endif
00394 
00395 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page