alglib 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. data/History.txt +7 -0
  2. data/Manifest.txt +253 -0
  3. data/README.txt +33 -0
  4. data/Rakefile +27 -0
  5. data/ext/Rakefile +24 -0
  6. data/ext/alglib.i +24 -0
  7. data/ext/alglib/Makefile +157 -0
  8. data/ext/alglib/airyf.cpp +372 -0
  9. data/ext/alglib/airyf.h +81 -0
  10. data/ext/alglib/alglib.cpp +8558 -0
  11. data/ext/alglib/alglib_util.cpp +19 -0
  12. data/ext/alglib/alglib_util.h +14 -0
  13. data/ext/alglib/ap.cpp +877 -0
  14. data/ext/alglib/ap.english.html +364 -0
  15. data/ext/alglib/ap.h +666 -0
  16. data/ext/alglib/ap.russian.html +442 -0
  17. data/ext/alglib/apvt.h +754 -0
  18. data/ext/alglib/bdss.cpp +1500 -0
  19. data/ext/alglib/bdss.h +251 -0
  20. data/ext/alglib/bdsvd.cpp +1339 -0
  21. data/ext/alglib/bdsvd.h +164 -0
  22. data/ext/alglib/bessel.cpp +1226 -0
  23. data/ext/alglib/bessel.h +331 -0
  24. data/ext/alglib/betaf.cpp +105 -0
  25. data/ext/alglib/betaf.h +74 -0
  26. data/ext/alglib/bidiagonal.cpp +1328 -0
  27. data/ext/alglib/bidiagonal.h +350 -0
  28. data/ext/alglib/binomialdistr.cpp +247 -0
  29. data/ext/alglib/binomialdistr.h +153 -0
  30. data/ext/alglib/blas.cpp +576 -0
  31. data/ext/alglib/blas.h +132 -0
  32. data/ext/alglib/cblas.cpp +226 -0
  33. data/ext/alglib/cblas.h +57 -0
  34. data/ext/alglib/cdet.cpp +138 -0
  35. data/ext/alglib/cdet.h +92 -0
  36. data/ext/alglib/chebyshev.cpp +216 -0
  37. data/ext/alglib/chebyshev.h +76 -0
  38. data/ext/alglib/chisquaredistr.cpp +157 -0
  39. data/ext/alglib/chisquaredistr.h +144 -0
  40. data/ext/alglib/cholesky.cpp +285 -0
  41. data/ext/alglib/cholesky.h +86 -0
  42. data/ext/alglib/cinverse.cpp +298 -0
  43. data/ext/alglib/cinverse.h +111 -0
  44. data/ext/alglib/clu.cpp +337 -0
  45. data/ext/alglib/clu.h +120 -0
  46. data/ext/alglib/correlation.cpp +280 -0
  47. data/ext/alglib/correlation.h +77 -0
  48. data/ext/alglib/correlationtests.cpp +726 -0
  49. data/ext/alglib/correlationtests.h +134 -0
  50. data/ext/alglib/crcond.cpp +826 -0
  51. data/ext/alglib/crcond.h +148 -0
  52. data/ext/alglib/creflections.cpp +310 -0
  53. data/ext/alglib/creflections.h +165 -0
  54. data/ext/alglib/csolve.cpp +312 -0
  55. data/ext/alglib/csolve.h +99 -0
  56. data/ext/alglib/ctrinverse.cpp +387 -0
  57. data/ext/alglib/ctrinverse.h +98 -0
  58. data/ext/alglib/ctrlinsolve.cpp +297 -0
  59. data/ext/alglib/ctrlinsolve.h +81 -0
  60. data/ext/alglib/dawson.cpp +234 -0
  61. data/ext/alglib/dawson.h +74 -0
  62. data/ext/alglib/descriptivestatistics.cpp +436 -0
  63. data/ext/alglib/descriptivestatistics.h +112 -0
  64. data/ext/alglib/det.cpp +140 -0
  65. data/ext/alglib/det.h +94 -0
  66. data/ext/alglib/dforest.cpp +1819 -0
  67. data/ext/alglib/dforest.h +316 -0
  68. data/ext/alglib/elliptic.cpp +497 -0
  69. data/ext/alglib/elliptic.h +217 -0
  70. data/ext/alglib/estnorm.cpp +429 -0
  71. data/ext/alglib/estnorm.h +107 -0
  72. data/ext/alglib/expintegrals.cpp +422 -0
  73. data/ext/alglib/expintegrals.h +108 -0
  74. data/ext/alglib/faq.english.html +258 -0
  75. data/ext/alglib/faq.russian.html +272 -0
  76. data/ext/alglib/fdistr.cpp +202 -0
  77. data/ext/alglib/fdistr.h +163 -0
  78. data/ext/alglib/fresnel.cpp +211 -0
  79. data/ext/alglib/fresnel.h +91 -0
  80. data/ext/alglib/gammaf.cpp +338 -0
  81. data/ext/alglib/gammaf.h +104 -0
  82. data/ext/alglib/gqgengauss.cpp +235 -0
  83. data/ext/alglib/gqgengauss.h +92 -0
  84. data/ext/alglib/gqgenhermite.cpp +268 -0
  85. data/ext/alglib/gqgenhermite.h +63 -0
  86. data/ext/alglib/gqgenjacobi.cpp +297 -0
  87. data/ext/alglib/gqgenjacobi.h +72 -0
  88. data/ext/alglib/gqgenlaguerre.cpp +265 -0
  89. data/ext/alglib/gqgenlaguerre.h +69 -0
  90. data/ext/alglib/gqgenlegendre.cpp +300 -0
  91. data/ext/alglib/gqgenlegendre.h +62 -0
  92. data/ext/alglib/gqgenlobatto.cpp +305 -0
  93. data/ext/alglib/gqgenlobatto.h +97 -0
  94. data/ext/alglib/gqgenradau.cpp +232 -0
  95. data/ext/alglib/gqgenradau.h +95 -0
  96. data/ext/alglib/hbisinv.cpp +480 -0
  97. data/ext/alglib/hbisinv.h +183 -0
  98. data/ext/alglib/hblas.cpp +228 -0
  99. data/ext/alglib/hblas.h +64 -0
  100. data/ext/alglib/hcholesky.cpp +339 -0
  101. data/ext/alglib/hcholesky.h +91 -0
  102. data/ext/alglib/hermite.cpp +114 -0
  103. data/ext/alglib/hermite.h +49 -0
  104. data/ext/alglib/hessenberg.cpp +370 -0
  105. data/ext/alglib/hessenberg.h +152 -0
  106. data/ext/alglib/hevd.cpp +247 -0
  107. data/ext/alglib/hevd.h +107 -0
  108. data/ext/alglib/hsschur.cpp +1316 -0
  109. data/ext/alglib/hsschur.h +108 -0
  110. data/ext/alglib/htridiagonal.cpp +734 -0
  111. data/ext/alglib/htridiagonal.h +180 -0
  112. data/ext/alglib/ialglib.cpp +6 -0
  113. data/ext/alglib/ialglib.h +9 -0
  114. data/ext/alglib/ibetaf.cpp +960 -0
  115. data/ext/alglib/ibetaf.h +125 -0
  116. data/ext/alglib/igammaf.cpp +430 -0
  117. data/ext/alglib/igammaf.h +157 -0
  118. data/ext/alglib/inv.cpp +274 -0
  119. data/ext/alglib/inv.h +115 -0
  120. data/ext/alglib/inverseupdate.cpp +480 -0
  121. data/ext/alglib/inverseupdate.h +185 -0
  122. data/ext/alglib/jacobianelliptic.cpp +164 -0
  123. data/ext/alglib/jacobianelliptic.h +94 -0
  124. data/ext/alglib/jarquebera.cpp +2271 -0
  125. data/ext/alglib/jarquebera.h +80 -0
  126. data/ext/alglib/kmeans.cpp +356 -0
  127. data/ext/alglib/kmeans.h +76 -0
  128. data/ext/alglib/laguerre.cpp +94 -0
  129. data/ext/alglib/laguerre.h +48 -0
  130. data/ext/alglib/lbfgs.cpp +1167 -0
  131. data/ext/alglib/lbfgs.h +218 -0
  132. data/ext/alglib/lda.cpp +434 -0
  133. data/ext/alglib/lda.h +133 -0
  134. data/ext/alglib/ldlt.cpp +1130 -0
  135. data/ext/alglib/ldlt.h +124 -0
  136. data/ext/alglib/leastsquares.cpp +1252 -0
  137. data/ext/alglib/leastsquares.h +290 -0
  138. data/ext/alglib/legendre.cpp +107 -0
  139. data/ext/alglib/legendre.h +49 -0
  140. data/ext/alglib/linreg.cpp +1185 -0
  141. data/ext/alglib/linreg.h +380 -0
  142. data/ext/alglib/logit.cpp +1523 -0
  143. data/ext/alglib/logit.h +333 -0
  144. data/ext/alglib/lq.cpp +399 -0
  145. data/ext/alglib/lq.h +160 -0
  146. data/ext/alglib/lu.cpp +462 -0
  147. data/ext/alglib/lu.h +119 -0
  148. data/ext/alglib/mannwhitneyu.cpp +4490 -0
  149. data/ext/alglib/mannwhitneyu.h +115 -0
  150. data/ext/alglib/minlm.cpp +918 -0
  151. data/ext/alglib/minlm.h +312 -0
  152. data/ext/alglib/mlpbase.cpp +3375 -0
  153. data/ext/alglib/mlpbase.h +589 -0
  154. data/ext/alglib/mlpe.cpp +1369 -0
  155. data/ext/alglib/mlpe.h +552 -0
  156. data/ext/alglib/mlptrain.cpp +1056 -0
  157. data/ext/alglib/mlptrain.h +283 -0
  158. data/ext/alglib/nearunityunit.cpp +91 -0
  159. data/ext/alglib/nearunityunit.h +17 -0
  160. data/ext/alglib/normaldistr.cpp +377 -0
  161. data/ext/alglib/normaldistr.h +175 -0
  162. data/ext/alglib/nsevd.cpp +1869 -0
  163. data/ext/alglib/nsevd.h +140 -0
  164. data/ext/alglib/pca.cpp +168 -0
  165. data/ext/alglib/pca.h +87 -0
  166. data/ext/alglib/poissondistr.cpp +143 -0
  167. data/ext/alglib/poissondistr.h +130 -0
  168. data/ext/alglib/polinterpolation.cpp +685 -0
  169. data/ext/alglib/polinterpolation.h +206 -0
  170. data/ext/alglib/psif.cpp +173 -0
  171. data/ext/alglib/psif.h +88 -0
  172. data/ext/alglib/qr.cpp +414 -0
  173. data/ext/alglib/qr.h +168 -0
  174. data/ext/alglib/ratinterpolation.cpp +134 -0
  175. data/ext/alglib/ratinterpolation.h +72 -0
  176. data/ext/alglib/rcond.cpp +705 -0
  177. data/ext/alglib/rcond.h +140 -0
  178. data/ext/alglib/reflections.cpp +504 -0
  179. data/ext/alglib/reflections.h +165 -0
  180. data/ext/alglib/rotations.cpp +473 -0
  181. data/ext/alglib/rotations.h +128 -0
  182. data/ext/alglib/rsolve.cpp +221 -0
  183. data/ext/alglib/rsolve.h +99 -0
  184. data/ext/alglib/sbisinv.cpp +217 -0
  185. data/ext/alglib/sbisinv.h +171 -0
  186. data/ext/alglib/sblas.cpp +185 -0
  187. data/ext/alglib/sblas.h +64 -0
  188. data/ext/alglib/schur.cpp +156 -0
  189. data/ext/alglib/schur.h +102 -0
  190. data/ext/alglib/sdet.cpp +193 -0
  191. data/ext/alglib/sdet.h +101 -0
  192. data/ext/alglib/sevd.cpp +116 -0
  193. data/ext/alglib/sevd.h +99 -0
  194. data/ext/alglib/sinverse.cpp +672 -0
  195. data/ext/alglib/sinverse.h +138 -0
  196. data/ext/alglib/spddet.cpp +138 -0
  197. data/ext/alglib/spddet.h +96 -0
  198. data/ext/alglib/spdgevd.cpp +842 -0
  199. data/ext/alglib/spdgevd.h +200 -0
  200. data/ext/alglib/spdinverse.cpp +509 -0
  201. data/ext/alglib/spdinverse.h +122 -0
  202. data/ext/alglib/spdrcond.cpp +421 -0
  203. data/ext/alglib/spdrcond.h +118 -0
  204. data/ext/alglib/spdsolve.cpp +275 -0
  205. data/ext/alglib/spdsolve.h +105 -0
  206. data/ext/alglib/spline2d.cpp +1192 -0
  207. data/ext/alglib/spline2d.h +301 -0
  208. data/ext/alglib/spline3.cpp +1264 -0
  209. data/ext/alglib/spline3.h +290 -0
  210. data/ext/alglib/srcond.cpp +595 -0
  211. data/ext/alglib/srcond.h +127 -0
  212. data/ext/alglib/ssolve.cpp +895 -0
  213. data/ext/alglib/ssolve.h +139 -0
  214. data/ext/alglib/stdafx.h +0 -0
  215. data/ext/alglib/stest.cpp +131 -0
  216. data/ext/alglib/stest.h +94 -0
  217. data/ext/alglib/studenttdistr.cpp +222 -0
  218. data/ext/alglib/studenttdistr.h +115 -0
  219. data/ext/alglib/studentttests.cpp +377 -0
  220. data/ext/alglib/studentttests.h +178 -0
  221. data/ext/alglib/svd.cpp +620 -0
  222. data/ext/alglib/svd.h +126 -0
  223. data/ext/alglib/tdbisinv.cpp +2608 -0
  224. data/ext/alglib/tdbisinv.h +228 -0
  225. data/ext/alglib/tdevd.cpp +1229 -0
  226. data/ext/alglib/tdevd.h +115 -0
  227. data/ext/alglib/tridiagonal.cpp +594 -0
  228. data/ext/alglib/tridiagonal.h +171 -0
  229. data/ext/alglib/trigintegrals.cpp +490 -0
  230. data/ext/alglib/trigintegrals.h +131 -0
  231. data/ext/alglib/trinverse.cpp +345 -0
  232. data/ext/alglib/trinverse.h +98 -0
  233. data/ext/alglib/trlinsolve.cpp +926 -0
  234. data/ext/alglib/trlinsolve.h +73 -0
  235. data/ext/alglib/tsort.cpp +405 -0
  236. data/ext/alglib/tsort.h +54 -0
  237. data/ext/alglib/variancetests.cpp +245 -0
  238. data/ext/alglib/variancetests.h +134 -0
  239. data/ext/alglib/wsr.cpp +6285 -0
  240. data/ext/alglib/wsr.h +96 -0
  241. data/ext/ap.i +97 -0
  242. data/ext/correlation.i +24 -0
  243. data/ext/extconf.rb +6 -0
  244. data/ext/logit.i +89 -0
  245. data/lib/alglib.rb +71 -0
  246. data/lib/alglib/correlation.rb +26 -0
  247. data/lib/alglib/linearregression.rb +63 -0
  248. data/lib/alglib/logit.rb +42 -0
  249. data/test/test_alglib.rb +52 -0
  250. data/test/test_correlation.rb +44 -0
  251. data/test/test_correlationtest.rb +45 -0
  252. data/test/test_linreg.rb +35 -0
  253. data/test/test_logit.rb +43 -0
  254. data/test/test_pca.rb +27 -0
  255. metadata +326 -0
@@ -0,0 +1,94 @@
1
+
2
+ #include <stdafx.h>
3
+ #include "laguerre.h"
4
+
5
+ /*************************************************************************
6
+ Calculation of the value of the Laguerre polynomial.
7
+
8
+ Parameters:
9
+ n - degree, n>=0
10
+ x - argument
11
+
12
+ Result:
13
+ the value of the Laguerre polynomial Ln at x
14
+ *************************************************************************/
15
+ double laguerrecalculate(const int& n, const double& x)
16
+ {
17
+ double result;
18
+ double a;
19
+ double b;
20
+ double i;
21
+
22
+ result = 1;
23
+ a = 1;
24
+ b = 1-x;
25
+ if( n==1 )
26
+ {
27
+ result = b;
28
+ }
29
+ i = 2;
30
+ while(i<=n)
31
+ {
32
+ result = ((2*i-1-x)*b-(i-1)*a)/i;
33
+ a = b;
34
+ b = result;
35
+ i = i+1;
36
+ }
37
+ return result;
38
+ }
39
+
40
+
41
+ /*************************************************************************
42
+ Summation of Laguerre polynomials using Clenshaw�s recurrence formula.
43
+
44
+ This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x)
45
+
46
+ Parameters:
47
+ n - degree, n>=0
48
+ x - argument
49
+
50
+ Result:
51
+ the value of the Laguerre polynomial at x
52
+ *************************************************************************/
53
+ double laguerresum(const ap::real_1d_array& c, const int& n, const double& x)
54
+ {
55
+ double result;
56
+ double b1;
57
+ double b2;
58
+ int i;
59
+
60
+ b1 = 0;
61
+ b2 = 0;
62
+ for(i = n; i >= 0; i--)
63
+ {
64
+ result = (2*i+1-x)*b1/(i+1)-(i+1)*b2/(i+2)+c(i);
65
+ b2 = b1;
66
+ b1 = result;
67
+ }
68
+ return result;
69
+ }
70
+
71
+
72
+ /*************************************************************************
73
+ Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N
74
+
75
+ Input parameters:
76
+ N - polynomial degree, n>=0
77
+
78
+ Output parameters:
79
+ C - coefficients
80
+ *************************************************************************/
81
+ void laguerrecoefficients(const int& n, ap::real_1d_array& c)
82
+ {
83
+ int i;
84
+
85
+ c.setbounds(0, n);
86
+ c(0) = 1;
87
+ for(i = 0; i <= n-1; i++)
88
+ {
89
+ c(i+1) = -c(i)*(n-i)/(i+1)/(i+1);
90
+ }
91
+ }
92
+
93
+
94
+
@@ -0,0 +1,48 @@
1
+
2
+ #ifndef _laguerre_h
3
+ #define _laguerre_h
4
+
5
+ #include "ap.h"
6
+ #include "ialglib.h"
7
+
8
+ /*************************************************************************
9
+ Calculation of the value of the Laguerre polynomial.
10
+
11
+ Parameters:
12
+ n - degree, n>=0
13
+ x - argument
14
+
15
+ Result:
16
+ the value of the Laguerre polynomial Ln at x
17
+ *************************************************************************/
18
+ double laguerrecalculate(const int& n, const double& x);
19
+
20
+
21
+ /*************************************************************************
22
+ Summation of Laguerre polynomials using Clenshaw�s recurrence formula.
23
+
24
+ This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x)
25
+
26
+ Parameters:
27
+ n - degree, n>=0
28
+ x - argument
29
+
30
+ Result:
31
+ the value of the Laguerre polynomial at x
32
+ *************************************************************************/
33
+ double laguerresum(const ap::real_1d_array& c, const int& n, const double& x);
34
+
35
+
36
+ /*************************************************************************
37
+ Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N
38
+
39
+ Input parameters:
40
+ N - polynomial degree, n>=0
41
+
42
+ Output parameters:
43
+ C - coefficients
44
+ *************************************************************************/
45
+ void laguerrecoefficients(const int& n, ap::real_1d_array& c);
46
+
47
+
48
+ #endif
@@ -0,0 +1,1167 @@
1
+ /*************************************************************************
2
+ Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are
6
+ met:
7
+
8
+ - Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ - Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer listed
13
+ in this license in the documentation and/or other materials
14
+ provided with the distribution.
15
+
16
+ - Neither the name of the copyright holders nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *************************************************************************/
32
+
33
+ #include <stdafx.h>
34
+ #include "lbfgs.h"
35
+
36
+ static const double ftol = 0.0001;
37
+ static const double xtol = 100*ap::machineepsilon;
38
+ static const double gtol = 0.9;
39
+ static const int maxfev = 20;
40
+ static const double stpmin = 1.0E-20;
41
+ static const double stpmax = 1.0E20;
42
+
43
+ static void mcsrch(const int& n,
44
+ ap::real_1d_array& x,
45
+ double& f,
46
+ ap::real_1d_array& g,
47
+ const ap::real_1d_array& s,
48
+ double& stp,
49
+ int& info,
50
+ int& nfev,
51
+ ap::real_1d_array& wa,
52
+ lbfgsstate& state,
53
+ int& stage);
54
+ static void mcstep(double& stx,
55
+ double& fx,
56
+ double& dx,
57
+ double& sty,
58
+ double& fy,
59
+ double& dy,
60
+ double& stp,
61
+ const double& fp,
62
+ const double& dp,
63
+ bool& brackt,
64
+ const double& stmin,
65
+ const double& stmax,
66
+ int& info);
67
+
68
+ /*************************************************************************
69
+ LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
70
+
71
+ The subroutine minimizes function F(x) of N arguments by using a quasi-
72
+ Newton method (LBFGS scheme) which is optimized to use a minimum amount
73
+ of memory.
74
+
75
+ The subroutine generates the approximation of an inverse Hessian matrix by
76
+ using information about the last M steps of the algorithm (instead of N).
77
+ It lessens a required amount of memory from a value of order N^2 to a
78
+ value of order 2*N*M.
79
+
80
+ Input parameters:
81
+ N - problem dimension. N>0
82
+ M - number of corrections in the BFGS scheme of Hessian
83
+ approximation update. Recommended value: 3<=M<=7. The smaller
84
+ value causes worse convergence, the bigger will not cause a
85
+ considerably better convergence, but will cause a fall in the
86
+ performance. M<=N.
87
+ X - initial solution approximation, array[0..N-1].
88
+ EpsG - positive number which defines a precision of search. The
89
+ subroutine finishes its work if the condition ||G|| < EpsG is
90
+ satisfied, where ||.|| means Euclidian norm, G - gradient, X -
91
+ current approximation.
92
+ EpsF - positive number which defines a precision of search. The
93
+ subroutine finishes its work if on iteration number k+1 the
94
+ condition |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} is
95
+ satisfied.
96
+ EpsX - positive number which defines a precision of search. The
97
+ subroutine finishes its work if on iteration number k+1 the
98
+ condition |X(k+1)-X(k)| <= EpsX is fulfilled.
99
+ MaxIts- maximum number of iterations. If MaxIts=0, the number of
100
+ iterations is unlimited.
101
+ Flags - additional settings:
102
+ * Flags = 0 means no additional settings
103
+ * Flags = 1 "do not allocate memory". used when solving
104
+ a many subsequent tasks with same N/M values.
105
+ First call MUST be without this flag bit set,
106
+ subsequent calls of MinLBFGS with same LBFGSState
107
+ structure can set Flags to 1.
108
+
109
+ Output parameters:
110
+ State - structure used for reverse communication.
111
+
112
+ See also MinLBFGSIteration, MinLBFGSResults
113
+
114
+ -- ALGLIB --
115
+ Copyright 14.11.2007 by Bochkanov Sergey
116
+ *************************************************************************/
117
+ void minlbfgs(const int& n,
118
+ const int& m,
119
+ ap::real_1d_array& x,
120
+ const double& epsg,
121
+ const double& epsf,
122
+ const double& epsx,
123
+ const int& maxits,
124
+ int flags,
125
+ lbfgsstate& state)
126
+ {
127
+ bool allocatemem;
128
+
129
+ ap::ap_error::make_assertion(n>=1, "MinLBFGS: N too small!");
130
+ ap::ap_error::make_assertion(m>=1, "MinLBFGS: M too small!");
131
+ ap::ap_error::make_assertion(m<=n, "MinLBFGS: M too large!");
132
+ ap::ap_error::make_assertion(epsg>=0, "MinLBFGS: negative EpsG!");
133
+ ap::ap_error::make_assertion(epsf>=0, "MinLBFGS: negative EpsF!");
134
+ ap::ap_error::make_assertion(epsx>=0, "MinLBFGS: negative EpsX!");
135
+ ap::ap_error::make_assertion(maxits>=0, "MinLBFGS: negative MaxIts!");
136
+
137
+ //
138
+ // Initialize
139
+ //
140
+ state.n = n;
141
+ state.m = m;
142
+ state.epsg = epsg;
143
+ state.epsf = epsf;
144
+ state.epsx = epsx;
145
+ state.maxits = maxits;
146
+ state.flags = flags;
147
+ allocatemem = flags%2==0;
148
+ flags = flags/2;
149
+ if( allocatemem )
150
+ {
151
+ state.rho.setbounds(0, m-1);
152
+ state.theta.setbounds(0, m-1);
153
+ state.y.setbounds(0, m-1, 0, n-1);
154
+ state.s.setbounds(0, m-1, 0, n-1);
155
+ state.d.setbounds(0, n-1);
156
+ state.x.setbounds(0, n-1);
157
+ state.g.setbounds(0, n-1);
158
+ state.work.setbounds(0, n-1);
159
+ }
160
+
161
+ //
162
+ // Initialize Rep structure
163
+ //
164
+ state.xupdated = false;
165
+
166
+ //
167
+ // Prepare first run
168
+ //
169
+ state.k = 0;
170
+ ap::vmove(&state.x(0), &x(0), ap::vlen(0,n-1));
171
+ state.rstate.ia.setbounds(0, 6);
172
+ state.rstate.ra.setbounds(0, 4);
173
+ state.rstate.stage = -1;
174
+ }
175
+
176
+
177
+ /*************************************************************************
178
+ One L-BFGS iteration
179
+
180
+ Called after initialization with MinLBFGS.
181
+ See HTML documentation for examples.
182
+
183
+ Input parameters:
184
+ State - structure which stores algorithm state between calls and
185
+ which is used for reverse communication. Must be initialized
186
+ with MinLBFGS.
187
+
188
+ If suborutine returned False, iterative proces has converged.
189
+
190
+ If subroutine returned True, caller should calculate function value
191
+ State.F an gradient State.G[0..N-1] at State.X[0..N-1] and call
192
+ MinLBFGSIteration again.
193
+
194
+ -- ALGLIB --
195
+ Copyright 20.04.2009 by Bochkanov Sergey
196
+ *************************************************************************/
197
+ bool minlbfgsiteration(lbfgsstate& state)
198
+ {
199
+ bool result;
200
+ int n;
201
+ int m;
202
+ int maxits;
203
+ double epsf;
204
+ double epsg;
205
+ double epsx;
206
+ int i;
207
+ int j;
208
+ int ic;
209
+ int mcinfo;
210
+ double v;
211
+ double vv;
212
+
213
+
214
+ //
215
+ // Reverse communication preparations
216
+ // I know it looks ugly, but it works the same way
217
+ // anywhere from C++ to Python.
218
+ //
219
+ // This code initializes locals by:
220
+ // * random values determined during code
221
+ // generation - on first subroutine call
222
+ // * values from previous call - on subsequent calls
223
+ //
224
+ if( state.rstate.stage>=0 )
225
+ {
226
+ n = state.rstate.ia(0);
227
+ m = state.rstate.ia(1);
228
+ maxits = state.rstate.ia(2);
229
+ i = state.rstate.ia(3);
230
+ j = state.rstate.ia(4);
231
+ ic = state.rstate.ia(5);
232
+ mcinfo = state.rstate.ia(6);
233
+ epsf = state.rstate.ra(0);
234
+ epsg = state.rstate.ra(1);
235
+ epsx = state.rstate.ra(2);
236
+ v = state.rstate.ra(3);
237
+ vv = state.rstate.ra(4);
238
+ }
239
+ else
240
+ {
241
+ n = -983;
242
+ m = -989;
243
+ maxits = -834;
244
+ i = 900;
245
+ j = -287;
246
+ ic = 364;
247
+ mcinfo = 214;
248
+ epsf = -338;
249
+ epsg = -686;
250
+ epsx = 912;
251
+ v = 585;
252
+ vv = 497;
253
+ }
254
+ if( state.rstate.stage==0 )
255
+ {
256
+ goto lbl_0;
257
+ }
258
+ if( state.rstate.stage==1 )
259
+ {
260
+ goto lbl_1;
261
+ }
262
+
263
+ //
264
+ // Routine body
265
+ //
266
+
267
+ //
268
+ // Unload frequently used variables from State structure
269
+ // (just for typing convinience)
270
+ //
271
+ n = state.n;
272
+ m = state.m;
273
+ epsg = state.epsg;
274
+ epsf = state.epsf;
275
+ epsx = state.epsx;
276
+ maxits = state.maxits;
277
+ state.repterminationtype = 0;
278
+ state.repiterationscount = 0;
279
+ state.repnfev = 0;
280
+
281
+ //
282
+ // Update info
283
+ //
284
+ state.xupdated = false;
285
+
286
+ //
287
+ // Calculate F/G
288
+ //
289
+ state.rstate.stage = 0;
290
+ goto lbl_rcomm;
291
+ lbl_0:
292
+ state.repnfev = 1;
293
+
294
+ //
295
+ // Preparations
296
+ //
297
+ state.fold = state.f;
298
+ v = ap::vdotproduct(&state.g(0), &state.g(0), ap::vlen(0,n-1));
299
+ v = sqrt(v);
300
+ if( v==0 )
301
+ {
302
+ state.repterminationtype = 4;
303
+ result = false;
304
+ return result;
305
+ }
306
+ state.stp = 1.0/v;
307
+ ap::vmoveneg(&state.d(0), &state.g(0), ap::vlen(0,n-1));
308
+
309
+ //
310
+ // Main cycle
311
+ //
312
+ lbl_2:
313
+ if( false )
314
+ {
315
+ goto lbl_3;
316
+ }
317
+
318
+ //
319
+ // Main cycle: prepare to 1-D line search
320
+ //
321
+ state.p = state.k%m;
322
+ state.q = ap::minint(state.k, m-1);
323
+
324
+ //
325
+ // Store X[k], G[k]
326
+ //
327
+ ap::vmoveneg(&state.s(state.p, 0), &state.x(0), ap::vlen(0,n-1));
328
+ ap::vmoveneg(&state.y(state.p, 0), &state.g(0), ap::vlen(0,n-1));
329
+
330
+ //
331
+ // Minimize F(x+alpha*d)
332
+ //
333
+ state.mcstage = 0;
334
+ if( state.k!=0 )
335
+ {
336
+ state.stp = 1.0;
337
+ }
338
+ mcsrch(n, state.x, state.f, state.g, state.d, state.stp, mcinfo, state.nfev, state.work, state, state.mcstage);
339
+ lbl_4:
340
+ if( state.mcstage==0 )
341
+ {
342
+ goto lbl_5;
343
+ }
344
+ state.rstate.stage = 1;
345
+ goto lbl_rcomm;
346
+ lbl_1:
347
+ mcsrch(n, state.x, state.f, state.g, state.d, state.stp, mcinfo, state.nfev, state.work, state, state.mcstage);
348
+ goto lbl_4;
349
+ lbl_5:
350
+
351
+ //
352
+ // Main cycle: update information and Hessian.
353
+ // Check stopping conditions.
354
+ //
355
+ state.repnfev = state.repnfev+state.nfev;
356
+ state.repiterationscount = state.repiterationscount+1;
357
+
358
+ //
359
+ // Calculate S[k], Y[k], Rho[k], GammaK
360
+ //
361
+ ap::vadd(&state.s(state.p, 0), &state.x(0), ap::vlen(0,n-1));
362
+ ap::vadd(&state.y(state.p, 0), &state.g(0), ap::vlen(0,n-1));
363
+
364
+ //
365
+ // Stopping conditions
366
+ //
367
+ if( state.repiterationscount>=maxits&&maxits>0 )
368
+ {
369
+
370
+ //
371
+ // Too many iterations
372
+ //
373
+ state.repterminationtype = 5;
374
+ result = false;
375
+ return result;
376
+ }
377
+ v = ap::vdotproduct(&state.g(0), &state.g(0), ap::vlen(0,n-1));
378
+ if( sqrt(v)<=epsg )
379
+ {
380
+
381
+ //
382
+ // Gradient is small enough
383
+ //
384
+ state.repterminationtype = 4;
385
+ result = false;
386
+ return result;
387
+ }
388
+ if( state.fold-state.f<=epsf*ap::maxreal(fabs(state.fold), ap::maxreal(fabs(state.f), 1.0)) )
389
+ {
390
+
391
+ //
392
+ // F(k+1)-F(k) is small enough
393
+ //
394
+ state.repterminationtype = 1;
395
+ result = false;
396
+ return result;
397
+ }
398
+ v = ap::vdotproduct(&state.s(state.p, 0), &state.s(state.p, 0), ap::vlen(0,n-1));
399
+ if( sqrt(v)<=epsx )
400
+ {
401
+
402
+ //
403
+ // X(k+1)-X(k) is small enough
404
+ //
405
+ state.repterminationtype = 2;
406
+ result = false;
407
+ return result;
408
+ }
409
+
410
+ //
411
+ // Calculate Rho[k], GammaK
412
+ //
413
+ v = ap::vdotproduct(&state.y(state.p, 0), &state.s(state.p, 0), ap::vlen(0,n-1));
414
+ vv = ap::vdotproduct(&state.y(state.p, 0), &state.y(state.p, 0), ap::vlen(0,n-1));
415
+ if( v==0||vv==0 )
416
+ {
417
+
418
+ //
419
+ // Rounding errors make further iterations impossible.
420
+ //
421
+ state.repterminationtype = -2;
422
+ result = false;
423
+ return result;
424
+ }
425
+ state.rho(state.p) = 1/v;
426
+ state.gammak = v/vv;
427
+
428
+ //
429
+ // Calculate d(k+1) = H(k+1)*g(k+1)
430
+ //
431
+ // for I:=K downto K-Q do
432
+ // V = s(i)^T * work(iteration:I)
433
+ // theta(i) = V
434
+ // work(iteration:I+1) = work(iteration:I) - V*Rho(i)*y(i)
435
+ // work(last iteration) = H0*work(last iteration)
436
+ // for I:=K-Q to K do
437
+ // V = y(i)^T*work(iteration:I)
438
+ // work(iteration:I+1) = work(iteration:I) +(-V+theta(i))*Rho(i)*s(i)
439
+ //
440
+ // NOW WORK CONTAINS d(k+1)
441
+ //
442
+ ap::vmove(&state.work(0), &state.g(0), ap::vlen(0,n-1));
443
+ for(i = state.k; i >= state.k-state.q; i--)
444
+ {
445
+ ic = i%m;
446
+ v = ap::vdotproduct(&state.s(ic, 0), &state.work(0), ap::vlen(0,n-1));
447
+ state.theta(ic) = v;
448
+ vv = v*state.rho(ic);
449
+ ap::vsub(&state.work(0), &state.y(ic, 0), ap::vlen(0,n-1), vv);
450
+ }
451
+ v = state.gammak;
452
+ ap::vmul(&state.work(0), ap::vlen(0,n-1), v);
453
+ for(i = state.k-state.q; i <= state.k; i++)
454
+ {
455
+ ic = i%m;
456
+ v = ap::vdotproduct(&state.y(ic, 0), &state.work(0), ap::vlen(0,n-1));
457
+ vv = state.rho(ic)*(-v+state.theta(ic));
458
+ ap::vadd(&state.work(0), &state.s(ic, 0), ap::vlen(0,n-1), vv);
459
+ }
460
+ ap::vmoveneg(&state.d(0), &state.work(0), ap::vlen(0,n-1));
461
+
462
+ //
463
+ // Next step
464
+ //
465
+ state.fold = state.f;
466
+ state.k = state.k+1;
467
+ state.xupdated = true;
468
+ goto lbl_2;
469
+ lbl_3:
470
+ result = false;
471
+ return result;
472
+
473
+ //
474
+ // Saving state
475
+ //
476
+ lbl_rcomm:
477
+ result = true;
478
+ state.rstate.ia(0) = n;
479
+ state.rstate.ia(1) = m;
480
+ state.rstate.ia(2) = maxits;
481
+ state.rstate.ia(3) = i;
482
+ state.rstate.ia(4) = j;
483
+ state.rstate.ia(5) = ic;
484
+ state.rstate.ia(6) = mcinfo;
485
+ state.rstate.ra(0) = epsf;
486
+ state.rstate.ra(1) = epsg;
487
+ state.rstate.ra(2) = epsx;
488
+ state.rstate.ra(3) = v;
489
+ state.rstate.ra(4) = vv;
490
+ return result;
491
+ }
492
+
493
+
494
+ /*************************************************************************
495
+ L-BFGS algorithm results
496
+
497
+ Called after MinLBFGSIteration returned False.
498
+
499
+ Input parameters:
500
+ State - algorithm state (used by MinLBFGSIteration).
501
+
502
+ Output parameters:
503
+ X - array[0..N-1], solution
504
+ Rep - optimization report:
505
+ * Rep.TerminationType completetion code:
506
+ * -2 rounding errors prevent further improvement.
507
+ X contains best point found.
508
+ * -1 incorrect parameters were specified
509
+ * 1 relative function improvement is no more than
510
+ EpsF.
511
+ * 2 relative step is no more than EpsX.
512
+ * 4 gradient norm is no more than EpsG
513
+ * 5 MaxIts steps was taken
514
+ * Rep.IterationsCount contains iterations count
515
+ * NFEV countains number of function calculations
516
+
517
+ -- ALGLIB --
518
+ Copyright 14.11.2007 by Bochkanov Sergey
519
+ *************************************************************************/
520
+ void minlbfgsresults(const lbfgsstate& state,
521
+ ap::real_1d_array& x,
522
+ lbfgsreport& rep)
523
+ {
524
+
525
+ x.setbounds(0, state.n-1);
526
+ ap::vmove(&x(0), &state.x(0), ap::vlen(0,state.n-1));
527
+ rep.iterationscount = state.repiterationscount;
528
+ rep.nfev = state.repnfev;
529
+ rep.terminationtype = state.repterminationtype;
530
+ }
531
+
532
+
533
+ /*************************************************************************
534
+ THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT
535
+ DECREASE CONDITION AND A CURVATURE CONDITION.
536
+
537
+ AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH
538
+ ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN
539
+ SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION
540
+
541
+ F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S).
542
+
543
+ IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE
544
+ FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF
545
+ UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S).
546
+
547
+ THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT
548
+ DECREASE CONDITION
549
+
550
+ F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S),
551
+
552
+ AND THE CURVATURE CONDITION
553
+
554
+ ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S).
555
+
556
+ IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED
557
+ BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS.
558
+ IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE
559
+ ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS.
560
+ IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION.
561
+
562
+ PARAMETERS DESCRIPRION
563
+
564
+ N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER OF VARIABLES.
565
+
566
+ X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE BASE POINT FOR
567
+ THE LINE SEARCH. ON OUTPUT IT CONTAINS X+STP*S.
568
+
569
+ F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F AT X. ON OUTPUT
570
+ IT CONTAINS THE VALUE OF F AT X + STP*S.
571
+
572
+ G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE GRADIENT OF F AT X.
573
+ ON OUTPUT IT CONTAINS THE GRADIENT OF F AT X + STP*S.
574
+
575
+ S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE SEARCH DIRECTION.
576
+
577
+ STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN INITIAL ESTIMATE
578
+ OF A SATISFACTORY STEP. ON OUTPUT STP CONTAINS THE FINAL ESTIMATE.
579
+
580
+ FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION OCCURS WHEN THE
581
+ SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION ARE
582
+ SATISFIED.
583
+
584
+ XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS WHEN THE RELATIVE
585
+ WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL.
586
+
587
+ STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH SPECIFY LOWER AND
588
+ UPPER BOUNDS FOR THE STEP.
589
+
590
+ MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION OCCURS WHEN THE
591
+ NUMBER OF CALLS TO FCN IS AT LEAST MAXFEV BY THE END OF AN ITERATION.
592
+
593
+ INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS:
594
+ INFO = 0 IMPROPER INPUT PARAMETERS.
595
+
596
+ INFO = 1 THE SUFFICIENT DECREASE CONDITION AND THE
597
+ DIRECTIONAL DERIVATIVE CONDITION HOLD.
598
+
599
+ INFO = 2 RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY
600
+ IS AT MOST XTOL.
601
+
602
+ INFO = 3 NUMBER OF CALLS TO FCN HAS REACHED MAXFEV.
603
+
604
+ INFO = 4 THE STEP IS AT THE LOWER BOUND STPMIN.
605
+
606
+ INFO = 5 THE STEP IS AT THE UPPER BOUND STPMAX.
607
+
608
+ INFO = 6 ROUNDING ERRORS PREVENT FURTHER PROGRESS.
609
+ THERE MAY NOT BE A STEP WHICH SATISFIES THE
610
+ SUFFICIENT DECREASE AND CURVATURE CONDITIONS.
611
+ TOLERANCES MAY BE TOO SMALL.
612
+
613
+ NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF CALLS TO FCN.
614
+
615
+ WA IS A WORK ARRAY OF LENGTH N.
616
+
617
+ ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983
618
+ JORGE J. MORE', DAVID J. THUENTE
619
+ *************************************************************************/
620
+ static void mcsrch(const int& n,
621
+ ap::real_1d_array& x,
622
+ double& f,
623
+ ap::real_1d_array& g,
624
+ const ap::real_1d_array& s,
625
+ double& stp,
626
+ int& info,
627
+ int& nfev,
628
+ ap::real_1d_array& wa,
629
+ lbfgsstate& state,
630
+ int& stage)
631
+ {
632
+ double v;
633
+ double p5;
634
+ double p66;
635
+ double zero;
636
+
637
+
638
+ //
639
+ // init
640
+ //
641
+ p5 = 0.5;
642
+ p66 = 0.66;
643
+ state.xtrapf = 4.0;
644
+ zero = 0;
645
+
646
+ //
647
+ // Main cycle
648
+ //
649
+ while(true)
650
+ {
651
+ if( stage==0 )
652
+ {
653
+
654
+ //
655
+ // NEXT
656
+ //
657
+ stage = 2;
658
+ continue;
659
+ }
660
+ if( stage==2 )
661
+ {
662
+ state.infoc = 1;
663
+ info = 0;
664
+
665
+ //
666
+ // CHECK THE INPUT PARAMETERS FOR ERRORS.
667
+ //
668
+ if( n<=0||stp<=0||ftol<0||gtol<zero||xtol<zero||stpmin<zero||stpmax<stpmin||maxfev<=0 )
669
+ {
670
+ stage = 0;
671
+ return;
672
+ }
673
+
674
+ //
675
+ // COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION
676
+ // AND CHECK THAT S IS A DESCENT DIRECTION.
677
+ //
678
+ v = ap::vdotproduct(&g(0), &s(0), ap::vlen(0,n-1));
679
+ state.dginit = v;
680
+ if( state.dginit>=0 )
681
+ {
682
+ stage = 0;
683
+ return;
684
+ }
685
+
686
+ //
687
+ // INITIALIZE LOCAL VARIABLES.
688
+ //
689
+ state.brackt = false;
690
+ state.stage1 = true;
691
+ nfev = 0;
692
+ state.finit = f;
693
+ state.dgtest = ftol*state.dginit;
694
+ state.width = stpmax-stpmin;
695
+ state.width1 = state.width/p5;
696
+ ap::vmove(&wa(0), &x(0), ap::vlen(0,n-1));
697
+
698
+ //
699
+ // THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP,
700
+ // FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP.
701
+ // THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP,
702
+ // FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF
703
+ // THE INTERVAL OF UNCERTAINTY.
704
+ // THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP,
705
+ // FUNCTION, AND DERIVATIVE AT THE CURRENT STEP.
706
+ //
707
+ state.stx = 0;
708
+ state.fx = state.finit;
709
+ state.dgx = state.dginit;
710
+ state.sty = 0;
711
+ state.fy = state.finit;
712
+ state.dgy = state.dginit;
713
+
714
+ //
715
+ // NEXT
716
+ //
717
+ stage = 3;
718
+ continue;
719
+ }
720
+ if( stage==3 )
721
+ {
722
+
723
+ //
724
+ // START OF ITERATION.
725
+ //
726
+ // SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND
727
+ // TO THE PRESENT INTERVAL OF UNCERTAINTY.
728
+ //
729
+ if( state.brackt )
730
+ {
731
+ if( state.stx<state.sty )
732
+ {
733
+ state.stmin = state.stx;
734
+ state.stmax = state.sty;
735
+ }
736
+ else
737
+ {
738
+ state.stmin = state.sty;
739
+ state.stmax = state.stx;
740
+ }
741
+ }
742
+ else
743
+ {
744
+ state.stmin = state.stx;
745
+ state.stmax = stp+state.xtrapf*(stp-state.stx);
746
+ }
747
+
748
+ //
749
+ // FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN.
750
+ //
751
+ if( stp>stpmax )
752
+ {
753
+ stp = stpmax;
754
+ }
755
+ if( stp<stpmin )
756
+ {
757
+ stp = stpmin;
758
+ }
759
+
760
+ //
761
+ // IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET
762
+ // STP BE THE LOWEST POINT OBTAINED SO FAR.
763
+ //
764
+ if( state.brackt&&(stp<=state.stmin||stp>=state.stmax)||nfev>=maxfev-1||state.infoc==0||state.brackt&&state.stmax-state.stmin<=xtol*state.stmax )
765
+ {
766
+ stp = state.stx;
767
+ }
768
+
769
+ //
770
+ // EVALUATE THE FUNCTION AND GRADIENT AT STP
771
+ // AND COMPUTE THE DIRECTIONAL DERIVATIVE.
772
+ //
773
+ ap::vmove(&x(0), &wa(0), ap::vlen(0,n-1));
774
+ ap::vadd(&x(0), &s(0), ap::vlen(0,n-1), stp);
775
+
776
+ //
777
+ // NEXT
778
+ //
779
+ stage = 4;
780
+ return;
781
+ }
782
+ if( stage==4 )
783
+ {
784
+ info = 0;
785
+ nfev = nfev+1;
786
+ v = ap::vdotproduct(&g(0), &s(0), ap::vlen(0,n-1));
787
+ state.dg = v;
788
+ state.ftest1 = state.finit+stp*state.dgtest;
789
+
790
+ //
791
+ // TEST FOR CONVERGENCE.
792
+ //
793
+ if( state.brackt&&(stp<=state.stmin||stp>=state.stmax)||state.infoc==0 )
794
+ {
795
+ info = 6;
796
+ }
797
+ if( stp==stpmax&&f<=state.ftest1&&state.dg<=state.dgtest )
798
+ {
799
+ info = 5;
800
+ }
801
+ if( stp==stpmin&&(f>state.ftest1||state.dg>=state.dgtest) )
802
+ {
803
+ info = 4;
804
+ }
805
+ if( nfev>=maxfev )
806
+ {
807
+ info = 3;
808
+ }
809
+ if( state.brackt&&state.stmax-state.stmin<=xtol*state.stmax )
810
+ {
811
+ info = 2;
812
+ }
813
+ if( f<=state.ftest1&&fabs(state.dg)<=-gtol*state.dginit )
814
+ {
815
+ info = 1;
816
+ }
817
+
818
+ //
819
+ // CHECK FOR TERMINATION.
820
+ //
821
+ if( info!=0 )
822
+ {
823
+ stage = 0;
824
+ return;
825
+ }
826
+
827
+ //
828
+ // IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED
829
+ // FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE.
830
+ //
831
+ if( state.stage1&&f<=state.ftest1&&state.dg>=ap::minreal(ftol, gtol)*state.dginit )
832
+ {
833
+ state.stage1 = false;
834
+ }
835
+
836
+ //
837
+ // A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF
838
+ // WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED
839
+ // FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE
840
+ // DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN
841
+ // OBTAINED BUT THE DECREASE IS NOT SUFFICIENT.
842
+ //
843
+ if( state.stage1&&f<=state.fx&&f>state.ftest1 )
844
+ {
845
+
846
+ //
847
+ // DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES.
848
+ //
849
+ state.fm = f-stp*state.dgtest;
850
+ state.fxm = state.fx-state.stx*state.dgtest;
851
+ state.fym = state.fy-state.sty*state.dgtest;
852
+ state.dgm = state.dg-state.dgtest;
853
+ state.dgxm = state.dgx-state.dgtest;
854
+ state.dgym = state.dgy-state.dgtest;
855
+
856
+ //
857
+ // CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
858
+ // AND TO COMPUTE THE NEW STEP.
859
+ //
860
+ mcstep(state.stx, state.fxm, state.dgxm, state.sty, state.fym, state.dgym, stp, state.fm, state.dgm, state.brackt, state.stmin, state.stmax, state.infoc);
861
+
862
+ //
863
+ // RESET THE FUNCTION AND GRADIENT VALUES FOR F.
864
+ //
865
+ state.fx = state.fxm+state.stx*state.dgtest;
866
+ state.fy = state.fym+state.sty*state.dgtest;
867
+ state.dgx = state.dgxm+state.dgtest;
868
+ state.dgy = state.dgym+state.dgtest;
869
+ }
870
+ else
871
+ {
872
+
873
+ //
874
+ // CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
875
+ // AND TO COMPUTE THE NEW STEP.
876
+ //
877
+ mcstep(state.stx, state.fx, state.dgx, state.sty, state.fy, state.dgy, stp, f, state.dg, state.brackt, state.stmin, state.stmax, state.infoc);
878
+ }
879
+
880
+ //
881
+ // FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE
882
+ // INTERVAL OF UNCERTAINTY.
883
+ //
884
+ if( state.brackt )
885
+ {
886
+ if( fabs(state.sty-state.stx)>=p66*state.width1 )
887
+ {
888
+ stp = state.stx+p5*(state.sty-state.stx);
889
+ }
890
+ state.width1 = state.width;
891
+ state.width = fabs(state.sty-state.stx);
892
+ }
893
+
894
+ //
895
+ // NEXT.
896
+ //
897
+ stage = 3;
898
+ continue;
899
+ }
900
+ }
901
+ }
902
+
903
+
904
+ static void mcstep(double& stx,
905
+ double& fx,
906
+ double& dx,
907
+ double& sty,
908
+ double& fy,
909
+ double& dy,
910
+ double& stp,
911
+ const double& fp,
912
+ const double& dp,
913
+ bool& brackt,
914
+ const double& stmin,
915
+ const double& stmax,
916
+ int& info)
917
+ {
918
+ bool bound;
919
+ double gamma;
920
+ double p;
921
+ double q;
922
+ double r;
923
+ double s;
924
+ double sgnd;
925
+ double stpc;
926
+ double stpf;
927
+ double stpq;
928
+ double theta;
929
+
930
+ info = 0;
931
+
932
+ //
933
+ // CHECK THE INPUT PARAMETERS FOR ERRORS.
934
+ //
935
+ if( brackt&&(stp<=ap::minreal(stx, sty)||stp>=ap::maxreal(stx, sty))||dx*(stp-stx)>=0||stmax<stmin )
936
+ {
937
+ return;
938
+ }
939
+
940
+ //
941
+ // DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN.
942
+ //
943
+ sgnd = dp*(dx/fabs(dx));
944
+
945
+ //
946
+ // FIRST CASE. A HIGHER FUNCTION VALUE.
947
+ // THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER
948
+ // TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN,
949
+ // ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN.
950
+ //
951
+ if( fp>fx )
952
+ {
953
+ info = 1;
954
+ bound = true;
955
+ theta = 3*(fx-fp)/(stp-stx)+dx+dp;
956
+ s = ap::maxreal(fabs(theta), ap::maxreal(fabs(dx), fabs(dp)));
957
+ gamma = s*sqrt(ap::sqr(theta/s)-dx/s*(dp/s));
958
+ if( stp<stx )
959
+ {
960
+ gamma = -gamma;
961
+ }
962
+ p = gamma-dx+theta;
963
+ q = gamma-dx+gamma+dp;
964
+ r = p/q;
965
+ stpc = stx+r*(stp-stx);
966
+ stpq = stx+dx/((fx-fp)/(stp-stx)+dx)/2*(stp-stx);
967
+ if( fabs(stpc-stx)<fabs(stpq-stx) )
968
+ {
969
+ stpf = stpc;
970
+ }
971
+ else
972
+ {
973
+ stpf = stpc+(stpq-stpc)/2;
974
+ }
975
+ brackt = true;
976
+ }
977
+ else
978
+ {
979
+ if( sgnd<0 )
980
+ {
981
+
982
+ //
983
+ // SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF
984
+ // OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC
985
+ // STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP,
986
+ // THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN.
987
+ //
988
+ info = 2;
989
+ bound = false;
990
+ theta = 3*(fx-fp)/(stp-stx)+dx+dp;
991
+ s = ap::maxreal(fabs(theta), ap::maxreal(fabs(dx), fabs(dp)));
992
+ gamma = s*sqrt(ap::sqr(theta/s)-dx/s*(dp/s));
993
+ if( stp>stx )
994
+ {
995
+ gamma = -gamma;
996
+ }
997
+ p = gamma-dp+theta;
998
+ q = gamma-dp+gamma+dx;
999
+ r = p/q;
1000
+ stpc = stp+r*(stx-stp);
1001
+ stpq = stp+dp/(dp-dx)*(stx-stp);
1002
+ if( fabs(stpc-stp)>fabs(stpq-stp) )
1003
+ {
1004
+ stpf = stpc;
1005
+ }
1006
+ else
1007
+ {
1008
+ stpf = stpq;
1009
+ }
1010
+ brackt = true;
1011
+ }
1012
+ else
1013
+ {
1014
+ if( fabs(dp)<fabs(dx) )
1015
+ {
1016
+
1017
+ //
1018
+ // THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
1019
+ // SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES.
1020
+ // THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY
1021
+ // IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC
1022
+ // IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE
1023
+ // EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO
1024
+ // COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP
1025
+ // CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN.
1026
+ //
1027
+ info = 3;
1028
+ bound = true;
1029
+ theta = 3*(fx-fp)/(stp-stx)+dx+dp;
1030
+ s = ap::maxreal(fabs(theta), ap::maxreal(fabs(dx), fabs(dp)));
1031
+
1032
+ //
1033
+ // THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND
1034
+ // TO INFINITY IN THE DIRECTION OF THE STEP.
1035
+ //
1036
+ gamma = s*sqrt(ap::maxreal(double(0), ap::sqr(theta/s)-dx/s*(dp/s)));
1037
+ if( stp>stx )
1038
+ {
1039
+ gamma = -gamma;
1040
+ }
1041
+ p = gamma-dp+theta;
1042
+ q = gamma+(dx-dp)+gamma;
1043
+ r = p/q;
1044
+ if( r<0&&gamma!=0 )
1045
+ {
1046
+ stpc = stp+r*(stx-stp);
1047
+ }
1048
+ else
1049
+ {
1050
+ if( stp>stx )
1051
+ {
1052
+ stpc = stmax;
1053
+ }
1054
+ else
1055
+ {
1056
+ stpc = stmin;
1057
+ }
1058
+ }
1059
+ stpq = stp+dp/(dp-dx)*(stx-stp);
1060
+ if( brackt )
1061
+ {
1062
+ if( fabs(stp-stpc)<fabs(stp-stpq) )
1063
+ {
1064
+ stpf = stpc;
1065
+ }
1066
+ else
1067
+ {
1068
+ stpf = stpq;
1069
+ }
1070
+ }
1071
+ else
1072
+ {
1073
+ if( fabs(stp-stpc)>fabs(stp-stpq) )
1074
+ {
1075
+ stpf = stpc;
1076
+ }
1077
+ else
1078
+ {
1079
+ stpf = stpq;
1080
+ }
1081
+ }
1082
+ }
1083
+ else
1084
+ {
1085
+
1086
+ //
1087
+ // FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
1088
+ // SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES
1089
+ // NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP
1090
+ // IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN.
1091
+ //
1092
+ info = 4;
1093
+ bound = false;
1094
+ if( brackt )
1095
+ {
1096
+ theta = 3*(fp-fy)/(sty-stp)+dy+dp;
1097
+ s = ap::maxreal(fabs(theta), ap::maxreal(fabs(dy), fabs(dp)));
1098
+ gamma = s*sqrt(ap::sqr(theta/s)-dy/s*(dp/s));
1099
+ if( stp>sty )
1100
+ {
1101
+ gamma = -gamma;
1102
+ }
1103
+ p = gamma-dp+theta;
1104
+ q = gamma-dp+gamma+dy;
1105
+ r = p/q;
1106
+ stpc = stp+r*(sty-stp);
1107
+ stpf = stpc;
1108
+ }
1109
+ else
1110
+ {
1111
+ if( stp>stx )
1112
+ {
1113
+ stpf = stmax;
1114
+ }
1115
+ else
1116
+ {
1117
+ stpf = stmin;
1118
+ }
1119
+ }
1120
+ }
1121
+ }
1122
+ }
1123
+
1124
+ //
1125
+ // UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT
1126
+ // DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE.
1127
+ //
1128
+ if( fp>fx )
1129
+ {
1130
+ sty = stp;
1131
+ fy = fp;
1132
+ dy = dp;
1133
+ }
1134
+ else
1135
+ {
1136
+ if( sgnd<0.0 )
1137
+ {
1138
+ sty = stx;
1139
+ fy = fx;
1140
+ dy = dx;
1141
+ }
1142
+ stx = stp;
1143
+ fx = fp;
1144
+ dx = dp;
1145
+ }
1146
+
1147
+ //
1148
+ // COMPUTE THE NEW STEP AND SAFEGUARD IT.
1149
+ //
1150
+ stpf = ap::minreal(stmax, stpf);
1151
+ stpf = ap::maxreal(stmin, stpf);
1152
+ stp = stpf;
1153
+ if( brackt&&bound )
1154
+ {
1155
+ if( sty>stx )
1156
+ {
1157
+ stp = ap::minreal(stx+0.66*(sty-stx), stp);
1158
+ }
1159
+ else
1160
+ {
1161
+ stp = ap::maxreal(stx+0.66*(sty-stx), stp);
1162
+ }
1163
+ }
1164
+ }
1165
+
1166
+
1167
+