libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo is the group of objects and functions that executes the basic operations of Moldeo 1.0 Platform.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
moMathNumericalAnalysis.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 
3  moMathNumericalAnalysis.h
4 
5  ****************************************************************************
6  * *
7  * This source is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This code is distributed in the hope that it will be useful, but *
13  * WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15  * General Public License for more details. *
16  * *
17  * A copy of the GNU General Public License is available on the World *
18  * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
19  * obtain it by writing to the Free Software Foundation, *
20  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  * *
22  ****************************************************************************
23 
24  Copyright(C) 2006 Fabricio Costa
25 
26  Authors:
27  Fabricio Costa
28  Andrés Colubri
29 
30  Portions taken from
31  Wild Magic Source Code
32  David Eberly
33  http://www.geometrictools.com
34  Copyright (c) 1998-2007
35 
36 *******************************************************************************/
37 
39 
40 // moIntegrate1 class -----------------------------------------------------------
41 /*
42 template <class Real>
43 Real moIntegrate1<Real>::RombergIntegral (int iOrder, Real fA, Real fB,
44  Function oF, void* pvUserData)
45 {
46  //assert(iOrder > 0);
47  Real** aafRom;
48 
49  aafRom = new Real*[2];
50  for (int i = 0; i < 2; i++) aafRom[i] = new Real[iOrder];
51 
52  Real fH = fB - fA;
53 
54  aafRom[0][0] = ((Real)0.5)*fH*(oF(fA,pvUserData)+oF(fB,pvUserData));
55  for (int i0=2, iP0=1; i0 <= iOrder; i0++, iP0 *= 2, fH *= (Real)0.5)
56  {
57  // approximations via the trapezoid rule
58  Real fSum = (Real)0.0;
59  int i1;
60  for (i1 = 1; i1 <= iP0; i1++)
61  {
62  fSum += oF(fA + fH*(i1-((Real)0.5)),pvUserData);
63  }
64 
65  // Richardson extrapolation
66  aafRom[1][0] = ((Real)0.5)*(aafRom[0][0] + fH*fSum);
67  for (int i2 = 1, iP2 = 4; i2 < i0; i2++, iP2 *= 4)
68  {
69  aafRom[1][i2] = (iP2*aafRom[1][i2-1] - aafRom[0][i2-1])/(iP2-1);
70  }
71 
72  for (i1 = 0; i1 < i0; i1++)
73  {
74  aafRom[0][i1] = aafRom[1][i1];
75  }
76  }
77 
78  Real fResult = aafRom[0][iOrder-1];
79 
80  for (int i = 0; i < 2; i++) delete[] aafRom[i];
81  delete[] aafRom;
82 
83  return fResult;
84 }
85 */
86 template <class Real>
87 Real moIntegrate1<Real>::GaussianQuadrature (Real fA, Real fB, Function oF,
88  void* pvUserData)
89 {
90  // Legendre polynomials
91  // P_0(x) = 1
92  // P_1(x) = x
93  // P_2(x) = (3x^2-1)/2
94  // P_3(x) = x(5x^2-3)/2
95  // P_4(x) = (35x^4-30x^2+3)/8
96  // P_5(x) = x(63x^4-70x^2+15)/8
97 
98  // generation of polynomials
99  // d/dx[ (1-x^2) dP_n(x)/dx ] + n(n+1) P_n(x) = 0
100  // P_n(x) = sum_{k=0}^{floor(n/2)} c_k x^{n-2k}
101  // c_k = (-1)^k (2n-2k)! / [ 2^n k! (n-k)! (n-2k)! ]
102  // P_n(x) = ((-1)^n/(2^n n!)) d^n/dx^n[ (1-x^2)^n ]
103  // (n+1)P_{n+1}(x) = (2n+1) x P_n(x) - n P_{n-1}(x)
104  // (1-x^2) dP_n(x)/dx = -n x P_n(x) + n P_{n-1}(x)
105 
106  // roots of the Legendre polynomial of specified degree
107  const int iDegree = 5;
108  const Real afRoot[iDegree] =
109  {
110  (Real)-0.9061798459,
111  (Real)-0.5384693101,
112  (Real) 0.0,
113  (Real)+0.5384693101,
114  (Real)+0.9061798459
115  };
116  const Real afCoeff[iDegree] =
117  {
118  (Real)0.2369268850,
119  (Real)0.4786286705,
120  (Real)0.5688888889,
121  (Real)0.4786286705,
122  (Real)0.2369268850
123  };
124 
125  // Need to transform domain [a,b] to [-1,1]. If a <= x <= b and
126  // -1 <= t <= 1, then x = ((b-a)*t+(b+a))/2.
127  Real fRadius = ((Real)0.5)*(fB - fA);
128  Real fCenter = ((Real)0.5)*(fB + fA);
129 
130  Real fResult = (Real)0.0;
131  for (int i = 0; i < iDegree; i++)
132  {
133  fResult += afCoeff[i]*oF(fRadius*afRoot[i]+fCenter,pvUserData);
134  }
135  fResult *= fRadius;
136 
137  return fResult;
138 }
139 
140 template <class Real>
141 Real moIntegrate1<Real>::TrapezoidRule (int iNumSamples, Real fA, Real fB,
142  Function oF, void* pvUserData)
143 {
144  //assert(iNumSamples >= 2);
145  Real fH = (fB - fA)/(Real)(iNumSamples - 1);
146  Real fResult = ((Real)0.5)*(oF(fA,pvUserData) + oF(fB,pvUserData));
147  for (int i = 1; i <= iNumSamples - 2; i++)
148  {
149  fResult += oF(fA+i*fH,pvUserData);
150  }
151  fResult *= fH;
152  return fResult;
153 }
154 
155 // moMinimize1 class -----------------------------------------------------------
156 
157 template <class Real>
158 moMinimize1<Real>::moMinimize1 (Function oFunction, int iMaxLevel,
159  int iMaxBracket, void* pvData)
160 {
161  //assert(oFunction);
162  m_oFunction = oFunction;
163  m_iMaxLevel = iMaxLevel;
164  m_iMaxBracket = iMaxBracket;
165  m_pvData = pvData;
166 }
167 
168 template <class Real>
170 {
171  return m_iMaxLevel;
172 }
173 
174 template <class Real>
176 {
177  return m_iMaxBracket;
178 }
179 
180 template <class Real>
182 {
183  return m_pvData;
184 }
185 
186 template <class Real>
187 void moMinimize1<Real>::GetMinimum (Real fT0, Real fT1, Real fTInitial,
188  Real& rfTMin, Real& rfFMin)
189 {
190  //assert(fT0 <= fTInitial && fTInitial <= fT1);
191 
192  m_fTMin = moMath<Real>::MAX_REAL;
193  m_fFMin = moMath<Real>::MAX_REAL;
194 
195  Real fF0 = m_oFunction(fT0,m_pvData);
196  Real fFInitial = m_oFunction(fTInitial,m_pvData);
197  Real fF1 = m_oFunction(fT1,m_pvData);
198 
199  GetMinimum(fT0,fF0,fTInitial,fFInitial,fT1,fF1,m_iMaxLevel);
200 
201  rfTMin = m_fTMin;
202  rfFMin = m_fFMin;
203 }
204 
205 template <class Real>
206 void moMinimize1<Real>::GetMinimum (Real fT0, Real fF0, Real fTm, Real fFm,
207  Real fT1, Real fF1, int iLevel)
208 {
209  if (fF0 < m_fFMin)
210  {
211  m_fTMin = fT0;
212  m_fFMin = fF0;
213  }
214 
215  if (fFm < m_fFMin)
216  {
217  m_fTMin = fTm;
218  m_fFMin = fFm;
219  }
220 
221  if (fF1 < m_fFMin)
222  {
223  m_fTMin = fT1;
224  m_fFMin = fF1;
225  }
226 
227  if (iLevel-- == 0)
228  {
229  return;
230  }
231 
232  if ((fT1 - fTm)*(fF0 - fFm) > (fTm - fT0)*(fFm - fF1))
233  {
234  // quadratic fit has positive second derivative at midpoint
235 
236  if (fF1 > fF0)
237  {
238  if (fFm >= fF0)
239  {
240  // increasing, repeat on [t0,tm]
241  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
242  }
243  else
244  {
245  // not monotonic, have a bracket
246  GetBracketedMinimum(fT0,fF0,fTm,fFm,fT1,fF1,iLevel);
247  }
248  }
249  else if (fF1 < fF0)
250  {
251  if (fFm >= fF1)
252  {
253  // decreasing, repeat on [tm,t1]
254  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
255  }
256  else
257  {
258  // not monotonic, have a bracket
259  GetBracketedMinimum(fT0,fF0,fTm,fFm,fT1,fF1,iLevel);
260  }
261  }
262  else
263  {
264  // constant, repeat on [t0,tm] and [tm,t1]
265  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
266  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
267  }
268  }
269  else
270  {
271  // quadratic fit has nonpositive second derivative at midpoint
272 
273  if (fF1 > fF0)
274  {
275  // repeat on [t0,tm]
276  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
277  }
278  else if ( fF1 < fF0 )
279  {
280  // repeat on [tm,t1]
281  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
282  }
283  else
284  {
285  // repeat on [t0,tm] and [tm,t1]
286  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
287  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
288  }
289  }
290 }
291 
292 template <class Real>
293 void moMinimize1<Real>::GetMinimum (Real fT0, Real fF0, Real fT1, Real fF1,
294  int iLevel)
295 {
296  if (fF0 < m_fFMin)
297  {
298  m_fTMin = fT0;
299  m_fFMin = fF0;
300  }
301 
302  if (fF1 < m_fFMin)
303  {
304  m_fTMin = fT1;
305  m_fFMin = fF1;
306  }
307 
308  if (iLevel-- == 0)
309  {
310  return;
311  }
312 
313  Real fTm = ((Real)0.5)*(fT0+fT1);
314  Real fFm = m_oFunction(fTm,m_pvData);
315 
316  if (fF0 - ((Real)2.0)*fFm + fF1 > (Real)0.0)
317  {
318  // quadratic fit has positive second derivative at midpoint
319 
320  if (fF1 > fF0)
321  {
322  if (fFm >= fF0)
323  {
324  // increasing, repeat on [t0,tm]
325  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
326  }
327  else
328  {
329  // not monotonic, have a bracket
330  GetBracketedMinimum(fT0,fF0,fTm,fFm,fT1,fF1,iLevel);
331  }
332  }
333  else if (fF1 < fF0)
334  {
335  if (fFm >= fF1)
336  {
337  // decreasing, repeat on [tm,t1]
338  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
339  }
340  else
341  {
342  // not monotonic, have a bracket
343  GetBracketedMinimum(fT0,fF0,fTm,fFm,fT1,fF1,iLevel);
344  }
345  }
346  else
347  {
348  // constant, repeat on [t0,tm] and [tm,t1]
349  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
350  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
351  }
352  }
353  else
354  {
355  // quadratic fit has nonpositive second derivative at midpoint
356 
357  if (fF1 > fF0)
358  {
359  // repeat on [t0,tm]
360  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
361  }
362  else if (fF1 < fF0)
363  {
364  // repeat on [tm,t1]
365  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
366  }
367  else
368  {
369  // repeat on [t0,tm] and [tm,t1]
370  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
371  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
372  }
373  }
374 }
375 
376 template <class Real>
377 void moMinimize1<Real>::GetBracketedMinimum (Real fT0, Real fF0, Real fTm,
378  Real fFm, Real fT1, Real fF1, int iLevel)
379 {
380  for (int i = 0; i < m_iMaxBracket; i++)
381  {
382  // update minimum value
383  if (fFm < m_fFMin)
384  {
385  m_fTMin = fTm;
386  m_fFMin = fFm;
387  }
388 
389  // test for convergence
390  const Real fEps = (Real)1e-08, fTol = (Real)1e-04;
391  if (moMath<Real>::FAbs(fT1-fT0) <= ((Real)2.0)*fTol*
392  moMath<Real>::FAbs(fTm) + fEps )
393  {
394  break;
395  }
396 
397  // compute vertex of interpolating parabola
398  Real fDT0 = fT0 - fTm, fDT1 = fT1 - fTm;
399  Real fDF0 = fF0 - fFm, fDF1 = fF1 - fFm;
400  Real fTmp0 = fDT0*fDF1, fTmp1 = fDT1*fDF0;
401  Real fDenom = fTmp1 - fTmp0;
402  if (moMath<Real>::FAbs(fDenom) < fEps)
403  {
404  return;
405  }
406 
407  Real fTv = fTm + ((Real)0.5)*(fDT1*fTmp1-fDT0*fTmp0)/fDenom;
408  //assert(fT0 <= fTv && fTv <= fT1);
409  Real fFv = m_oFunction(fTv,m_pvData);
410 
411  if (fTv < fTm)
412  {
413  if (fFv < fFm)
414  {
415  fT1 = fTm;
416  fF1 = fFm;
417  fTm = fTv;
418  fFm = fFv;
419  }
420  else
421  {
422  fT0 = fTv;
423  fF0 = fFv;
424  }
425  }
426  else if (fTv > fTm)
427  {
428  if (fFv < fFm)
429  {
430  fT0 = fTm;
431  fF0 = fFm;
432  fTm = fTv;
433  fFm = fFv;
434  }
435  else
436  {
437  fT1 = fTv;
438  fF1 = fFv;
439  }
440  }
441  else
442  {
443  // vertex of parabola is already at middle sample point
444  GetMinimum(fT0,fF0,fTm,fFm,iLevel);
445  GetMinimum(fTm,fFm,fT1,fF1,iLevel);
446  }
447  }
448 }
449 
void GetMinimum(Real fT0, Real fT1, Real fTInitial, Real &rfTMin, Real &rfFMin)
static Real TrapezoidRule(int iNumSamples, Real fA, Real fB, Function oF, void *pvUserData=0)
moMinimize1(Function oFunction, int iMaxLevel, int iMaxBracket, void *pvData=0)
static Real GaussianQuadrature(Real fA, Real fB, Function oF, void *pvUserData=0)
Definition: moMath.h:64
static Real FAbs(Real fValue)
Definition: moMath.h:180