gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
ConjugateGradients.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <algorithm>
7 #include <math.h>
8 #include "GmshMessage.h"
9 #include "ConjugateGradients.h"
10 /*
11  min_a f(x+a*d);
12  f(x+a*d) = f(x) + f'(x) (
13 */
14 
15 static double _norm(std::vector<double> &x)
16 {
17  double n = 0.0;
18  for(std::size_t i = 0; i < x.size(); i++) n += x[i] * x[i];
19  return sqrt(n);
20 }
21 static void scale(std::vector<double> &x, double s)
22 {
23  for(std::size_t i = 0; i < x.size(); i++) x[i] *= s;
24 }
25 
26 static void gmshLineSearch(void (*func)(std::vector<double> &x, double &Obj,
27  bool needGrad,
28  std::vector<double> &gradObj,
29  void *), // the function
30  void *data, // eventual data
31  std::vector<double> &x, // variables
32  std::vector<double> &p, // search direction
33  std::vector<double> &g, // gradient
34  double &f, double stpmax, int &check)
35 {
36  int i;
37  double alam, alam2 = 1., alamin, f2 = 0., fold2 = 0., rhs1, rhs2, temp,
38  tmplam = 0.;
39 
40  const double ALF = 1.e-4;
41  const double TOLX = 1.0e-9;
42 
43  std::vector<double> xold(x), grad(x);
44  double fold;
45  (*func)(xold, fold, false, grad, data);
46 
47  check = 0;
48  int n = x.size();
49  double norm = _norm(p);
50  if(norm > stpmax) scale(p, stpmax / norm);
51  double slope = 0.0;
52  for(i = 0; i < n; i++) slope += g[i] * p[i];
53  double test = 0.0;
54  for(i = 0; i < n; i++) {
55  temp = fabs(p[i]) / std::max(fabs(xold[i]), 1.0);
56  if(temp > test) test = temp;
57  }
58 
59  alamin = TOLX / test;
60  alam = 1.;
61 
62  while(1) {
63  for(i = 0; i < n; i++) x[i] = xold[i] + alam * p[i];
64  (*func)(x, f, false, grad, data);
65  if(f > 1.e280)
66  alam *= .5;
67  else
68  break;
69  }
70 
71  while(1) {
72  for(i = 0; i < n; i++) x[i] = xold[i] + alam * p[i];
73  (*func)(x, f, false, grad, data);
74 
75  // printf("alam = %12.5E alamin = %12.5E f = %12.5E fold = %12.5E slope
76  // %12.5E stuff %12.5E\n",alam,alamin,f,fold, slope, ALF * alam *
77  // slope);
78 
79  // f = (*func)(x, data);
80  if(alam < alamin) {
81  for(i = 0; i < n; i++) x[i] = xold[i];
82  check = 1;
83  return;
84  }
85  else if(f <= fold + ALF * alam * slope)
86  return;
87  else {
88  if(alam == 1.0)
89  tmplam = -slope / (2.0 * (f - fold - slope));
90  else {
91  rhs1 = f - fold - alam * slope;
92  rhs2 = f2 - fold2 - alam2 * slope;
93  const double a =
94  (rhs1 / (alam * alam) - rhs2 / (alam2 * alam2)) / (alam - alam2);
95  const double b =
96  (-alam2 * rhs1 / (alam * alam) + alam * rhs2 / (alam2 * alam2)) /
97  (alam - alam2);
98  if(a == 0.0)
99  tmplam = -slope / (2.0 * b);
100  else {
101  const double disc = b * b - 3.0 * a * slope;
102  if(disc < 0.0)
103  Msg::Error("Roundoff problem in gmshLineSearch.");
104  else
105  tmplam = (-b + sqrt(disc)) / (3.0 * a);
106  }
107  if(tmplam > 0.5 * alam) tmplam = 0.5 * alam;
108  }
109  }
110  alam2 = alam;
111  f2 = f;
112  fold2 = fold;
113  alam = std::max(tmplam, 0.1 * alam);
114  }
115 }
116 
117 // Simple Gradient Descent Minimization (use finite differences to compute the
118 // gradient)
119 
120 double GradientDescent(void (*func)(std::vector<double> &x, double &Obj,
121  bool needGrad, std::vector<double> &gradObj,
122  void *), // its gradient
123  std::vector<double> &x, // The variables
124  void *data) // User data
125 {
126  const int MAXIT = 3;
127  const int N = x.size();
128 
129  std::vector<double> grad(N);
130  std::vector<double> dir(N);
131  double f;
132 
133  // printf("entering gradient descent (%d unknowns)...\n",N);
134 
135  for(int iter = 0; iter < MAXIT; iter++) {
136  // compute gradient of func
137  double stpmax = 100000;
138  func(x, f, true, grad, data);
139  // printf("computing f ... %22.15E\n",f);
140  for(int i = 0; i < N; i++) dir[i] = -grad[i];
141  int check;
142  gmshLineSearch(func, data, x, dir, grad, f, stpmax, check);
143  // printf("line search is done, f reduces to %22.15E\n",f);
144  // printf("Line search done x = (%g %g) f = %g\n",x(0),x(1),f);
145  if(check == 1) break;
146  }
147  return f;
148 }
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
GmshMessage.h
norm
void norm(const double *vec, double *norm)
Definition: gmshLevelset.cpp:202
gmshLineSearch
static void gmshLineSearch(void(*func)(std::vector< double > &x, double &Obj, bool needGrad, std::vector< double > &gradObj, void *), void *data, std::vector< double > &x, std::vector< double > &p, std::vector< double > &g, double &f, double stpmax, int &check)
Definition: ConjugateGradients.cpp:26
_norm
static double _norm(std::vector< double > &x)
Definition: ConjugateGradients.cpp:15
ConjugateGradients.h
GradientDescent
double GradientDescent(void(*func)(std::vector< double > &x, double &Obj, bool needGrad, std::vector< double > &gradObj, void *), std::vector< double > &x, void *data)
Definition: ConjugateGradients.cpp:120
scale
static void scale(std::vector< double > &x, double s)
Definition: ConjugateGradients.cpp:21