diff --git a/Numeric/ConjugateGradients.cpp b/Numeric/ConjugateGradients.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9720f14e3e9eea6ff15aab0395b86c81d88b9324 --- /dev/null +++ b/Numeric/ConjugateGradients.cpp @@ -0,0 +1,131 @@ +#include <math.h> +#include "GmshMessage.h" +#include "ConjugateGradients.h" +/* + min_a f(x+a*d); + f(x+a*d) = f(x) + f'(x) ( +*/ + +static double _norm (std::vector<double> &x){ + double n = 0.0; + for (unsigned int i=0;i<x.size();i++)n += x[i]*x[i]; + return sqrt(n); +} +static void scale (std::vector<double> &x, double s){ + for (unsigned int i=0;i<x.size();i++)x[i]*=s; +} + +static void gmshLineSearch(void (*func)(std::vector<double> &x, + double &Obj, + bool needGrad, + std::vector<double> &gradObj, void *), // the function + void* data, // eventual data + std::vector<double> &x, // variables + std::vector<double> &p, // search direction + std::vector<double> &g, // gradient + double &f, + double stpmax, + int &check) +{ + int i; + double alam, alam2 = 1., alamin, f2 = 0., fold2 = 0., rhs1, rhs2, temp, tmplam = 0.; + + const double ALF = 1.e-4; + const double TOLX = 1.0e-9; + + std::vector<double> xold(x), grad(x); + double fold; + (*func)(xold, fold, false, grad, data); + + check=0; + int n = x.size(); + double norm = _norm(p); + if (norm > stpmax) scale(p,stpmax / norm); + double slope=0.0; + for (i = 0; i < n; i++) slope += g[i]*p[i]; + double test=0.0; + for (i = 0; i < n; i++) { + temp = fabs(p[i]) / std::max(fabs(xold[i]), 1.0); + if (temp > test) test = temp; + } + + alamin = TOLX / test; + alam = 1.; + + while(1) { + for (i = 0; i < n; i++) x[i] = xold[i] + alam*p[i]; + (*func)(x, f, false, grad, data); + if (f > 1.e280) alam*=.5; + else break; + } + + while(1) { + for (i = 0; i < n; i++) x[i] = xold[i] + alam*p[i]; + (*func)(x, f, false, grad, data); + + // printf("alam = %12.5E alamin = %12.5E f = %12.5E fold = %12.5E slope %12.5E stuff %12.5E\n",alam,alamin,f,fold, slope, ALF * alam * slope); + + // f = (*func)(x, data); + if (alam < alamin) { + for (i = 0; i <n; i++) x[i] = xold[i]; + check = 1; + return; + } + else if (f <= fold + ALF * alam * slope) return; + else { + if (alam == 1.0) + tmplam = -slope / (2.0 * (f - fold - slope)); + else { + rhs1 = f - fold - alam * slope; + rhs2 = f2 - fold2 - alam2 * slope; + const double a = (rhs1/(alam*alam)-rhs2/(alam2*alam2))/(alam-alam2); + const double b = (-alam2*rhs1/(alam*alam)+alam*rhs2/(alam2*alam2))/(alam-alam2); + if (a == 0.0) tmplam = -slope / (2.0 * b); + else { + const double disc = b*b-3.0*a*slope; + if (disc < 0.0) Msg::Error("Roundoff problem in gmshLineSearch."); + else tmplam = (-b+sqrt(disc))/(3.0*a); + } + if (tmplam > 0.5 * alam) + tmplam = 0.5 * alam; + } + } + alam2 = alam; + f2 = f; + fold2 = fold; + alam = std::max(tmplam, 0.1 * alam); + } +} + +// Simple Gradient Descent Minimization (use finite differences to compute the gradient) + +double GradientDescent(void (*func)(std::vector<double> &x, + double &Obj, + bool needGrad, + std::vector<double> &gradObj, void *), // its gradient + std::vector<double> &x, // The variables + void *data) // User data +{ + const int MAXIT = 3; + const int N = x.size(); + + std::vector<double> grad(N); + std::vector<double> dir(N); + double f; + + printf("entering gradient descent (%d unknowns)...\n",N); + + for (int iter = 0; iter < MAXIT; iter++){ + // compute gradient of func + double stpmax=100000; + func(x, f, true, grad, data); + // printf("computing f ... %22.15E\n",f); + for (int i=0;i<N;i++)dir[i] = -grad[i]; + int check; + gmshLineSearch(func, data, x, dir, grad, f, stpmax, check); + // printf("line search is done, f reduces to %22.15E\n",f); + // printf("Line search done x = (%g %g) f = %g\n",x(0),x(1),f); + if (check == 1) break; + } + return f; +} diff --git a/Numeric/ConjugateGradients.h b/Numeric/ConjugateGradients.h new file mode 100644 index 0000000000000000000000000000000000000000..65cac55754636bf5d58efccd5eb86b75e0c412e5 --- /dev/null +++ b/Numeric/ConjugateGradients.h @@ -0,0 +1,13 @@ +#ifndef _CONJUGATEGRADIENTS +#define _CONJUGATEGRADIENTS + +#include <vector> + +double GradientDescent(void (*func)(std::vector<double> &x, + double &Obj, + bool needGrad, + std::vector<double> &gradObj, void *), + std::vector<double> &x, + void *data); // User data + +#endif