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
,
O2scl Sourceforge Project Page