v2DM-DOCI  1.0
scan_function.cpp
Go to the documentation of this file.
1 /*
2  * @BEGIN LICENSE
3  *
4  * Copyright (C) 2014-2015 Ward Poelmans
5  *
6  * This file is part of v2DM-DOCI.
7  *
8  * v2DM-DOCI is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * Foobar is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * @END LICENSE
22  */
23 
24 #include <iostream>
25 #include <cmath>
26 #include <random>
27 #include <algorithm>
28 #include <iomanip>
29 
30 // criteria for convergence of NR and comparision of minimums
31 #define CONV_CRIT 1e-12
32 
33 class func
34 {
35  public:
36  virtual double operator()(double t) const = 0;
37 
38  virtual double gradient(double t) const = 0;
39 
40  virtual double hessian(double t) const = 0;
41 
42  virtual double graddivhessian(double t) const = 0;
43 };
44 
45 class Efunc: public func
46 {
47  public:
48  Efunc(double A, double B, double C, double D, double E, double F, double G, double H, double I=0)
49  {
50  this->A = A;
51  this->B = B;
52  this->C = C;
53  this->D = D;
54  this->E = E;
55  this->F = F;
56  this->G = G;
57  this->H = H;
58  this->I = I;
59  }
60 
61  double operator()(double t) const
62  {
63  const double cos = std::cos(t);
64  const double sin = std::sin(t);
65  const double cos2 = cos*cos;
66  const double sin2 = sin*sin;
67  const double cos4 = cos2*cos2;
68  const double sin4 = sin2*sin2;
69  const double cossin = cos*sin;
70  const double cos2sin2 = cos2*sin2;
71  const double cos3sin = cos2*cossin;
72  const double cossin3 = cossin*sin2;
73 
74  return A*cos4+B*sin4+C*cos2+D*sin2+2*(E*cossin+F*cos2sin2+2*(G*cos3sin+H*cossin3))+I;
75  }
76 
77  double gradient(double t) const
78  {
79  const double cos = std::cos(t);
80  const double sin = std::sin(t);
81  const double cos2 = cos*cos;
82  const double cos4 = cos2*cos2;
83  const double cossin = cos*sin;
84  const double cos3sin = cos2*cossin;
85 
86  return 16*(G-H)*cos4-4*(A+B-2*F)*cos3sin+4*(E-3*G+5*H)*cos2+2*(2*B-C+D-2*F)*cossin-2*E-4*H;
87  }
88 
89  double hessian(double t) const
90  {
91  const double cos = std::cos(t);
92  const double sin = std::sin(t);
93  const double cos2 = cos*cos;
94  const double cos4 = cos2*cos2;
95  const double cossin = cos*sin;
96  const double cos3sin = cos2*cossin;
97 
98  return 16*(2*F-A-B)*cos4+64*(H-G)*cos3sin+4*(3*A+5*B-C+D-8*F)*cos2-8*(E-3*G+5*H)*cossin-4*B+2*C-2*D+4*F;
99  }
100 
101  double graddivhessian(double t) const
102  {
103  const double cos = std::cos(t);
104  const double sin = std::sin(t);
105  const double cos2 = cos*cos;
106  const double cos4 = cos2*cos2;
107  const double cossin = cos*sin;
108  const double cos3sin = cos2*cossin;
109 
110  return (16*(G-H)*cos4-4*(A+B-2*F)*cos3sin+4*(E-3*G+5*H)*cos2+2*(2*B-C+D-2*F)*cossin-2*E-4*H) /
111  (16*(2*F-A-B)*cos4+64*(H-G)*cos3sin+4*(3*A+5*B-C+D-8*F)*cos2-8*(E-3*G+5*H)*cossin-4*B+2*C-2*D+4*F);
112  }
113 
114  double A,B,C,D,E,F,G,H,I;
115 };
116 
117 
118 class Efunc2: public func
119 {
120  public:
121  Efunc2(double A, double B, double C, double D, double E=0)
122  {
123  this->A = A;
124  this->B = B;
125  this->C = C;
126  this->D = D;
127  this->E = E;
128  }
129 
130  Efunc2(const Efunc &efunc)
131  {
132  A = 0.125*(efunc.A+efunc.B)-0.25*efunc.F;
133  B = 0.5*(efunc.A-efunc.B+efunc.C-efunc.D);
134  C = 0.5*(efunc.G-efunc.H);
135  D = efunc.G+efunc.H+efunc.E;
136  E = efunc.I + 0.375*(efunc.A+efunc.B)+0.25*efunc.F+0.5*(efunc.C+efunc.D);
137  }
138 
139  double operator()(double t) const
140  {
141  return A*std::cos(4*t)+B*std::cos(2*t)+C*std::sin(4*t)+D*std::sin(2*t)+E;
142  }
143 
144  double gradient(double t) const
145  {
146  return -4*A*std::sin(4*t)-2*B*std::sin(2*t)+4*C*std::cos(4*t)+2*D*std::cos(2*t);
147  }
148 
149  double hessian(double t) const
150  {
151  return -16*A*std::cos(4*t)-4*B*std::cos(2*t)-16*C*std::sin(4*t)-4*D*std::sin(2*t);
152  }
153 
154  double graddivhessian(double t) const
155  {
156  const double cos4t = std::cos(4*t);
157  const double cos2t = std::cos(2*t);
158  const double sin4t = std::sin(4*t);
159  const double sin2t = std::sin(2*t);
160 
161  return (-2*A*sin4t-B*sin2t+2*C*cos4t+D*cos2t)/
162  (-8*A*cos4t-2*B*cos2t-8*C*sin4t-2*D*sin2t);
163  }
164 
165  double A,B,C,D,E;
166 };
167 
168 std::pair<double,bool> find_min_angle(double start_angle, const func& cur)
169 {
170  double theta = start_angle;
171  bool status = true;
172 
173  int iters = 0;
174  double dx = cur.graddivhessian(theta);
175 
176  while(fabs(dx) > CONV_CRIT)
177  {
178  dx = cur.graddivhessian(theta);
179 
180  theta -= dx;
181 
182  iters++;
183 
184  if(iters>100)
185  {
186  status = false;
187  break;
188  }
189  }
190 
191  // out of range or maximum
192  if(theta < 0 || theta > 2*M_PI || cur.hessian(theta)<0 )
193  status = false;
194 
195  return std::make_pair(theta, status);
196 }
197 
198 std::vector<double> scan_mins(const func& cur)
199 {
200  std::vector<double> minimums;
201  minimums.reserve(3);
202  const int steps = 360;
203  const double stepsize = M_PI/180.0;
204  std::vector<double> points;
205  points.reserve(steps);
206 
207  for(int i=0;i<=steps;i++)
208  {
209  const double theta = stepsize*i;
210 
211  const auto cur_min = find_min_angle(theta, cur);
212  if(cur_min.second)
213  points.push_back(cur_min.first);
214  }
215 
216  std::sort(points.begin(), points.end());
217 
218  minimums.push_back(points.front());
219 
220  for(auto i=1;i<points.size();i++)
221  if(fabs(points[i-1]-points[i]) > CONV_CRIT)
222  minimums.push_back(points[i]);
223 
224  return minimums;
225 }
226 
227 int main(void)
228 {
229  std::cout.precision(15);
230 
231  // something truly random
232  std::random_device rd;
233 
234  // each variable has it own pseudo random generator
235  // because we want to sample a lot
236  std::mt19937_64 mt_A(rd());
237  std::mt19937_64 mt_B(rd());
238  std::mt19937_64 mt_C(rd());
239  std::mt19937_64 mt_D(rd());
240  std::mt19937_64 mt_E(rd());
241  std::mt19937_64 mt_F(rd());
242  std::mt19937_64 mt_G(rd());
243  std::mt19937_64 mt_H(rd());
244 
245  std::uniform_real_distribution<double> distr(-1, 1);
246 
247  std::cout << std::fixed;
248  std::cout << std::setw(20);
249 
250 // for(unsigned long long i=0;i<std::numeric_limits<unsigned long long>::max();i++)
251 // {
252 // const double A = distr(mt_A);
253 // const double B = distr(mt_B);
254 // const double C = distr(mt_C);
255 // const double D = distr(mt_D);
256 // const double E = distr(mt_E);
257 // const double F = distr(mt_F);
258 // const double G = distr(mt_G);
259 // const double H = distr(mt_H);
260 //
261 // Efunc cur_sample(A,B,C,D,E,F,G,H);
262 //
263 // auto mins = scan_mins(cur_sample);
264 //
265 // std::cout << i << "\t" << A << "\t" << B << "\t" << C << "\t" << D << "\t" << E << "\t" << F << "\t" << G << "\t" << H << "\t" << mins.size() << std::endl;
266 // }
267 
268 // for(unsigned long long i=0;i<std::numeric_limits<unsigned long long>::max();i++)
269  for(unsigned long long i=0;i<10000;i++)
270  {
271  const double A = distr(mt_A);
272  const double B = distr(mt_B);
273  const double C = distr(mt_C);
274  const double D = distr(mt_D);
275 
276  Efunc2 cur_sample(A,B,C,D);
277 
278  auto mins = scan_mins(cur_sample);
279 
280  std::cout << mins.size() << "\t" << i << "\t" << A << "\t" << B << "\t" << C << "\t" << D << std::endl;
281  }
282 
283  return 0;
284 }
285 
286 
287 /* vim: set ts=3 sw=3 expandtab :*/
double gradient(double t) const
double hessian(double t) const
double D
Efunc(double A, double B, double C, double D, double E, double F, double G, double H, double I=0)
double A
double operator()(double t) const
double B
double graddivhessian(double t) const
double E
double gradient(double t) const
int main(void)
virtual double graddivhessian(double t) const =0
double F
double I
double operator()(double t) const
virtual double hessian(double t) const =0
double E
virtual double gradient(double t) const =0
std::pair< double, bool > find_min_angle(double start_angle, const func &cur)
virtual double operator()(double t) const =0
Efunc2(const Efunc &efunc)
double G
std::vector< double > scan_mins(const func &cur)
#define CONV_CRIT
double A
double C
double B
double C
double H
double hessian(double t) const
Efunc2(double A, double B, double C, double D, double E=0)
double graddivhessian(double t) const
double D