GCOP
1.0
|
00001 // -*- coding: utf-8 00002 // vim: set fileencoding=utf-8 00003 00004 // This file is part of Eigen, a lightweight C++ template library 00005 // for linear algebra. 00006 // 00007 // Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org> 00008 // 00009 // This Source Code Form is subject to the terms of the Mozilla 00010 // Public License v. 2.0. If a copy of the MPL was not distributed 00011 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 00012 00013 // Modified to find numerical difference using samples 00014 00015 // Author2: Gowtham 00016 00017 #ifndef EIGEN_SAMPLE_NUMERICAL_DIFF_H 00018 #define EIGEN_SAMPLE_NUMERICAL_DIFF_H 00019 00020 #include <random> 00021 00022 namespace Eigen { 00023 00033 template<typename _Functor> 00034 class SampleNumericalDiff : public _Functor 00035 { 00036 public: 00037 typedef _Functor Functor; 00038 typedef typename Functor::Scalar Scalar; 00039 typedef typename Functor::InputType InputType; 00040 typedef typename Functor::ValueType ValueType; 00041 typedef typename Functor::JacobianType JacobianType; 00042 00043 SampleNumericalDiff(Scalar _epsfcn=0.) : Functor(), epsfcn(_epsfcn), normal_dist(0,1) { 00044 randgenerator.seed(370212); 00045 } 00046 SampleNumericalDiff(const Functor& f, Scalar _epsfcn=0.) : Functor(f), epsfcn(_epsfcn), normal_dist(0,1) { 00047 randgenerator.seed(370212); 00048 } 00049 00050 // forward constructors 00051 template<typename T0> 00052 SampleNumericalDiff(const T0& a0) : Functor(a0), epsfcn(0) {} 00053 template<typename T0, typename T1> 00054 SampleNumericalDiff(const T0& a0, const T1& a1) : Functor(a0, a1), epsfcn(0) {} 00055 template<typename T0, typename T1, typename T2> 00056 SampleNumericalDiff(const T0& a0, const T1& a1, const T2& a2) : Functor(a0, a1, a2), epsfcn(0) {} 00057 00058 enum { 00059 InputsAtCompileTime = Functor::InputsAtCompileTime, 00060 ValuesAtCompileTime = Functor::ValuesAtCompileTime 00061 }; 00062 00066 int df(const InputType& _x, JacobianType &jac) 00067 { 00068 using std::sqrt; 00069 using std::abs; 00070 using std::cout; 00071 using std::endl; 00072 /* Local variables */ 00073 Scalar h; 00074 const typename InputType::Index n = _x.size(); 00075 int nfev= round(n*1.5); 00076 const Scalar eps = sqrt(((std::max)(epsfcn,NumTraits<Scalar>::epsilon() ))); 00077 ValueType val1, val2; 00078 InputType x = _x; 00079 // TODO : we should do this only if the size is not already known 00080 val1.resize(Functor::values()); 00081 val2.resize(Functor::values()); 00082 MatrixXd dymatrix(Functor::values(), nfev); 00083 MatrixXd dumatrix(n, nfev); 00084 00085 // initialization 00086 Functor::operator()(x, val1);//Mean input and value 00087 00088 // Function Body 00089 for(int ns = 0; ns < nfev; ++ns) 00090 { 00091 for (int j = 0; j < n; ++j) { 00092 00093 /*h = eps * abs(x[j]); 00094 if (h == 0.) { 00095 h = eps; 00096 } 00097 h = eps; 00098 if(bernoulli_dist(randgenerator)) 00099 { 00100 dumatrix(j, ns) = h; 00101 } 00102 else 00103 { 00104 dumatrix(j, ns) = -h; 00105 } 00106 */ 00107 dumatrix(j, ns) = eps*normal_dist(randgenerator); 00108 }//Do perturbations to the whole vector 00109 x = _x + dumatrix.col(ns); 00110 Functor::operator()(x, val2);//Evaluate at new perturbed vector 00111 dymatrix.col(ns) = val2 - val1;//dY 00112 //cout<<"dumatrix["<<ns<<"]: "<<dumatrix.col(ns).transpose()<<endl; 00113 //getchar(); 00114 //cout<<"dymatrix["<<ns<<"]: "<<dymatrix.col(ns).transpose()<<endl; 00115 //getchar(); 00116 } 00117 jac = (dumatrix*dumatrix.transpose()).ldlt().solve(dumatrix*dymatrix.transpose()).transpose(); 00118 //cout<<"jac: "<<endl<<jac<<endl; 00119 cout<<endl<<"Error_predicted: "<<sqrt((dymatrix - jac*dumatrix).squaredNorm())<<endl; 00120 getchar(); 00121 return nfev; 00122 } 00123 private: 00124 Scalar epsfcn; 00125 00126 SampleNumericalDiff& operator=(const SampleNumericalDiff&); 00127 00128 std::default_random_engine randgenerator; 00129 00130 //default constructor gives p = 0.5 benoulli 00131 //std::bernoulli_distribution bernoulli_dist; ///< Bernoulli generator for getting perturbations 00132 std::normal_distribution<double> normal_dist; 00133 }; 00134 00135 } // end namespace Eigen 00136 00137 //vim: ai ts=4 sts=4 et sw=4 00138 #endif // EIGEN_NUMERICAL_DIFF_H 00139