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,251 @@
1
+ /*************************************************************************
2
+ Copyright 2008 by 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
+ #ifndef _bdss_h
34
+ #define _bdss_h
35
+
36
+ #include "ap.h"
37
+ #include "ialglib.h"
38
+
39
+ #include "tsort.h"
40
+ #include "descriptivestatistics.h"
41
+
42
+
43
+ struct cvreport
44
+ {
45
+ double relclserror;
46
+ double avgce;
47
+ double rmserror;
48
+ double avgerror;
49
+ double avgrelerror;
50
+ };
51
+
52
+
53
+ /*************************************************************************
54
+ This set of routines (DSErrAllocate, DSErrAccumulate, DSErrFinish)
55
+ calculates different error functions (classification error, cross-entropy,
56
+ rms, avg, avg.rel errors).
57
+
58
+ 1. DSErrAllocate prepares buffer.
59
+ 2. DSErrAccumulate accumulates individual errors:
60
+ * Y contains predicted output (posterior probabilities for classification)
61
+ * DesiredY contains desired output (class number for classification)
62
+ 3. DSErrFinish outputs results:
63
+ * Buf[0] contains relative classification error (zero for regression tasks)
64
+ * Buf[1] contains avg. cross-entropy (zero for regression tasks)
65
+ * Buf[2] contains rms error (regression, classification)
66
+ * Buf[3] contains average error (regression, classification)
67
+ * Buf[4] contains average relative error (regression, classification)
68
+
69
+ NOTES(1):
70
+ "NClasses>0" means that we have classification task.
71
+ "NClasses<0" means regression task with -NClasses real outputs.
72
+
73
+ NOTES(2):
74
+ rms. avg, avg.rel errors for classification tasks are interpreted as
75
+ errors in posterior probabilities with respect to probabilities given
76
+ by training/test set.
77
+
78
+ -- ALGLIB --
79
+ Copyright 11.01.2009 by Bochkanov Sergey
80
+ *************************************************************************/
81
+ void dserrallocate(int nclasses, ap::real_1d_array& buf);
82
+
83
+
84
+ /*************************************************************************
85
+ See DSErrAllocate for comments on this routine.
86
+
87
+ -- ALGLIB --
88
+ Copyright 11.01.2009 by Bochkanov Sergey
89
+ *************************************************************************/
90
+ void dserraccumulate(ap::real_1d_array& buf,
91
+ const ap::real_1d_array& y,
92
+ const ap::real_1d_array& desiredy);
93
+
94
+
95
+ /*************************************************************************
96
+ See DSErrAllocate for comments on this routine.
97
+
98
+ -- ALGLIB --
99
+ Copyright 11.01.2009 by Bochkanov Sergey
100
+ *************************************************************************/
101
+ void dserrfinish(ap::real_1d_array& buf);
102
+
103
+
104
+ /*************************************************************************
105
+
106
+ -- ALGLIB --
107
+ Copyright 19.05.2008 by Bochkanov Sergey
108
+ *************************************************************************/
109
+ void dsnormalize(ap::real_2d_array& xy,
110
+ int npoints,
111
+ int nvars,
112
+ int& info,
113
+ ap::real_1d_array& means,
114
+ ap::real_1d_array& sigmas);
115
+
116
+
117
+ /*************************************************************************
118
+
119
+ -- ALGLIB --
120
+ Copyright 19.05.2008 by Bochkanov Sergey
121
+ *************************************************************************/
122
+ void dsnormalizec(const ap::real_2d_array& xy,
123
+ int npoints,
124
+ int nvars,
125
+ int& info,
126
+ ap::real_1d_array& means,
127
+ ap::real_1d_array& sigmas);
128
+
129
+
130
+ /*************************************************************************
131
+
132
+ -- ALGLIB --
133
+ Copyright 19.05.2008 by Bochkanov Sergey
134
+ *************************************************************************/
135
+ double dsgetmeanmindistance(const ap::real_2d_array& xy,
136
+ int npoints,
137
+ int nvars);
138
+
139
+
140
+ /*************************************************************************
141
+
142
+ -- ALGLIB --
143
+ Copyright 19.05.2008 by Bochkanov Sergey
144
+ *************************************************************************/
145
+ void dstie(ap::real_1d_array& a,
146
+ int n,
147
+ ap::integer_1d_array& ties,
148
+ int& tiecount,
149
+ ap::integer_1d_array& p1,
150
+ ap::integer_1d_array& p2);
151
+
152
+
153
+ /*************************************************************************
154
+
155
+ -- ALGLIB --
156
+ Copyright 11.12.2008 by Bochkanov Sergey
157
+ *************************************************************************/
158
+ void dstiefasti(ap::real_1d_array& a,
159
+ ap::integer_1d_array& b,
160
+ int n,
161
+ ap::integer_1d_array& ties,
162
+ int& tiecount);
163
+
164
+
165
+ /*************************************************************************
166
+ Optimal partition, internal subroutine.
167
+
168
+ -- ALGLIB --
169
+ Copyright 22.05.2008 by Bochkanov Sergey
170
+ *************************************************************************/
171
+ void dsoptimalsplit2(ap::real_1d_array a,
172
+ ap::integer_1d_array c,
173
+ int n,
174
+ int& info,
175
+ double& threshold,
176
+ double& pal,
177
+ double& pbl,
178
+ double& par,
179
+ double& pbr,
180
+ double& cve);
181
+
182
+
183
+ /*************************************************************************
184
+ Optimal partition, internal subroutine. Fast version.
185
+
186
+ Accepts:
187
+ A array[0..N-1] array of attributes array[0..N-1]
188
+ C array[0..N-1] array of class labels
189
+ TiesBuf array[0..N] temporaries (ties)
190
+ CntBuf array[0..2*NC-1] temporaries (counts)
191
+ Alpha centering factor (0<=alpha<=1, recommended value - 0.05)
192
+
193
+ Output:
194
+ Info error code (">0"=OK, "<0"=bad)
195
+ RMS training set RMS error
196
+ CVRMS leave-one-out RMS error
197
+
198
+ Note:
199
+ content of all arrays is changed by subroutine
200
+
201
+ -- ALGLIB --
202
+ Copyright 11.12.2008 by Bochkanov Sergey
203
+ *************************************************************************/
204
+ void dsoptimalsplit2fast(ap::real_1d_array& a,
205
+ ap::integer_1d_array& c,
206
+ ap::integer_1d_array& tiesbuf,
207
+ ap::integer_1d_array& cntbuf,
208
+ int n,
209
+ int nc,
210
+ double alpha,
211
+ int& info,
212
+ double& threshold,
213
+ double& rms,
214
+ double& cvrms);
215
+
216
+
217
+ /*************************************************************************
218
+ Automatic non-optimal discretization, internal subroutine.
219
+
220
+ -- ALGLIB --
221
+ Copyright 22.05.2008 by Bochkanov Sergey
222
+ *************************************************************************/
223
+ void dssplitk(ap::real_1d_array a,
224
+ ap::integer_1d_array c,
225
+ int n,
226
+ int nc,
227
+ int kmax,
228
+ int& info,
229
+ ap::real_1d_array& thresholds,
230
+ int& ni,
231
+ double& cve);
232
+
233
+
234
+ /*************************************************************************
235
+ Automatic optimal discretization, internal subroutine.
236
+
237
+ -- ALGLIB --
238
+ Copyright 22.05.2008 by Bochkanov Sergey
239
+ *************************************************************************/
240
+ void dsoptimalsplitk(ap::real_1d_array a,
241
+ ap::integer_1d_array c,
242
+ int n,
243
+ int nc,
244
+ int kmax,
245
+ int& info,
246
+ ap::real_1d_array& thresholds,
247
+ int& ni,
248
+ double& cve);
249
+
250
+
251
+ #endif
@@ -0,0 +1,1339 @@
1
+ /*************************************************************************
2
+ Copyright (c) 1992-2007 The University of Tennessee. All rights reserved.
3
+
4
+ Contributors:
5
+ * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
6
+ pseudocode.
7
+
8
+ See subroutines comments for additional copyrights.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are
12
+ met:
13
+
14
+ - Redistributions of source code must retain the above copyright
15
+ notice, this list of conditions and the following disclaimer.
16
+
17
+ - Redistributions in binary form must reproduce the above copyright
18
+ notice, this list of conditions and the following disclaimer listed
19
+ in this license in the documentation and/or other materials
20
+ provided with the distribution.
21
+
22
+ - Neither the name of the copyright holders nor the names of its
23
+ contributors may be used to endorse or promote products derived from
24
+ this software without specific prior written permission.
25
+
26
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
+ *************************************************************************/
38
+
39
+ #include <stdafx.h>
40
+ #include "bdsvd.h"
41
+
42
+ static bool bidiagonalsvddecompositioninternal(ap::real_1d_array& d,
43
+ ap::real_1d_array e,
44
+ int n,
45
+ bool isupper,
46
+ bool isfractionalaccuracyrequired,
47
+ ap::real_2d_array& u,
48
+ int ustart,
49
+ int nru,
50
+ ap::real_2d_array& c,
51
+ int cstart,
52
+ int ncc,
53
+ ap::real_2d_array& vt,
54
+ int vstart,
55
+ int ncvt);
56
+ static double extsignbdsqr(double a, double b);
57
+ static void svd2x2(double f, double g, double h, double& ssmin, double& ssmax);
58
+ static void svdv2x2(double f,
59
+ double g,
60
+ double h,
61
+ double& ssmin,
62
+ double& ssmax,
63
+ double& snr,
64
+ double& csr,
65
+ double& snl,
66
+ double& csl);
67
+
68
+ /*************************************************************************
69
+ Singular value decomposition of a bidiagonal matrix (extended algorithm)
70
+
71
+ The algorithm performs the singular value decomposition of a bidiagonal
72
+ matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P -
73
+ orthogonal matrices, S - diagonal matrix with non-negative elements on the
74
+ main diagonal, in descending order.
75
+
76
+ The algorithm finds singular values. In addition, the algorithm can
77
+ calculate matrices Q and P (more precisely, not the matrices, but their
78
+ product with given matrices U and VT - U*Q and (P^T)*VT)). Of course,
79
+ matrices U and VT can be of any type, including identity. Furthermore, the
80
+ algorithm can calculate Q'*C (this product is calculated more effectively
81
+ than U*Q, because this calculation operates with rows instead of matrix
82
+ columns).
83
+
84
+ The feature of the algorithm is its ability to find all singular values
85
+ including those which are arbitrarily close to 0 with relative accuracy
86
+ close to machine precision. If the parameter IsFractionalAccuracyRequired
87
+ is set to True, all singular values will have high relative accuracy close
88
+ to machine precision. If the parameter is set to False, only the biggest
89
+ singular value will have relative accuracy close to machine precision.
90
+ The absolute error of other singular values is equal to the absolute error
91
+ of the biggest singular value.
92
+
93
+ Input parameters:
94
+ D - main diagonal of matrix B.
95
+ Array whose index ranges within [0..N-1].
96
+ E - superdiagonal (or subdiagonal) of matrix B.
97
+ Array whose index ranges within [0..N-2].
98
+ N - size of matrix B.
99
+ IsUpper - True, if the matrix is upper bidiagonal.
100
+ IsFractionalAccuracyRequired -
101
+ accuracy to search singular values with.
102
+ U - matrix to be multiplied by Q.
103
+ Array whose indexes range within [0..NRU-1, 0..N-1].
104
+ The matrix can be bigger, in that case only the submatrix
105
+ [0..NRU-1, 0..N-1] will be multiplied by Q.
106
+ NRU - number of rows in matrix U.
107
+ C - matrix to be multiplied by Q'.
108
+ Array whose indexes range within [0..N-1, 0..NCC-1].
109
+ The matrix can be bigger, in that case only the submatrix
110
+ [0..N-1, 0..NCC-1] will be multiplied by Q'.
111
+ NCC - number of columns in matrix C.
112
+ VT - matrix to be multiplied by P^T.
113
+ Array whose indexes range within [0..N-1, 0..NCVT-1].
114
+ The matrix can be bigger, in that case only the submatrix
115
+ [0..N-1, 0..NCVT-1] will be multiplied by P^T.
116
+ NCVT - number of columns in matrix VT.
117
+
118
+ Output parameters:
119
+ D - singular values of matrix B in descending order.
120
+ U - if NRU>0, contains matrix U*Q.
121
+ VT - if NCVT>0, contains matrix (P^T)*VT.
122
+ C - if NCC>0, contains matrix Q'*C.
123
+
124
+ Result:
125
+ True, if the algorithm has converged.
126
+ False, if the algorithm hasn't converged (rare case).
127
+
128
+ Additional information:
129
+ The type of convergence is controlled by the internal parameter TOL.
130
+ If the parameter is greater than 0, the singular values will have
131
+ relative accuracy TOL. If TOL<0, the singular values will have
132
+ absolute accuracy ABS(TOL)*norm(B).
133
+ By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon,
134
+ where Epsilon is the machine precision. It is not recommended to use
135
+ TOL less than 10*Epsilon since this will considerably slow down the
136
+ algorithm and may not lead to error decreasing.
137
+ History:
138
+ * 31 March, 2007.
139
+ changed MAXITR from 6 to 12.
140
+
141
+ -- LAPACK routine (version 3.0) --
142
+ Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
143
+ Courant Institute, Argonne National Lab, and Rice University
144
+ October 31, 1999.
145
+ *************************************************************************/
146
+ bool rmatrixbdsvd(ap::real_1d_array& d,
147
+ ap::real_1d_array e,
148
+ int n,
149
+ bool isupper,
150
+ bool isfractionalaccuracyrequired,
151
+ ap::real_2d_array& u,
152
+ int nru,
153
+ ap::real_2d_array& c,
154
+ int ncc,
155
+ ap::real_2d_array& vt,
156
+ int ncvt)
157
+ {
158
+ bool result;
159
+ ap::real_1d_array d1;
160
+ ap::real_1d_array e1;
161
+
162
+ d1.setbounds(1, n);
163
+ ap::vmove(&d1(1), &d(0), ap::vlen(1,n));
164
+ if( n>1 )
165
+ {
166
+ e1.setbounds(1, n-1);
167
+ ap::vmove(&e1(1), &e(0), ap::vlen(1,n-1));
168
+ }
169
+ result = bidiagonalsvddecompositioninternal(d1, e1, n, isupper, isfractionalaccuracyrequired, u, 0, nru, c, 0, ncc, vt, 0, ncvt);
170
+ ap::vmove(&d(0), &d1(1), ap::vlen(0,n-1));
171
+ return result;
172
+ }
173
+
174
+
175
+ /*************************************************************************
176
+ Obsolete 1-based subroutine. See RMatrixBDSVD for 0-based replacement.
177
+
178
+ History:
179
+ * 31 March, 2007.
180
+ changed MAXITR from 6 to 12.
181
+
182
+ -- LAPACK routine (version 3.0) --
183
+ Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
184
+ Courant Institute, Argonne National Lab, and Rice University
185
+ October 31, 1999.
186
+ *************************************************************************/
187
+ bool bidiagonalsvddecomposition(ap::real_1d_array& d,
188
+ ap::real_1d_array e,
189
+ int n,
190
+ bool isupper,
191
+ bool isfractionalaccuracyrequired,
192
+ ap::real_2d_array& u,
193
+ int nru,
194
+ ap::real_2d_array& c,
195
+ int ncc,
196
+ ap::real_2d_array& vt,
197
+ int ncvt)
198
+ {
199
+ bool result;
200
+
201
+ result = bidiagonalsvddecompositioninternal(d, e, n, isupper, isfractionalaccuracyrequired, u, 1, nru, c, 1, ncc, vt, 1, ncvt);
202
+ return result;
203
+ }
204
+
205
+
206
+ /*************************************************************************
207
+ Internal working subroutine for bidiagonal decomposition
208
+ *************************************************************************/
209
+ static bool bidiagonalsvddecompositioninternal(ap::real_1d_array& d,
210
+ ap::real_1d_array e,
211
+ int n,
212
+ bool isupper,
213
+ bool isfractionalaccuracyrequired,
214
+ ap::real_2d_array& u,
215
+ int ustart,
216
+ int nru,
217
+ ap::real_2d_array& c,
218
+ int cstart,
219
+ int ncc,
220
+ ap::real_2d_array& vt,
221
+ int vstart,
222
+ int ncvt)
223
+ {
224
+ bool result;
225
+ int i;
226
+ int idir;
227
+ int isub;
228
+ int iter;
229
+ int j;
230
+ int ll;
231
+ int lll;
232
+ int m;
233
+ int maxit;
234
+ int oldll;
235
+ int oldm;
236
+ double abse;
237
+ double abss;
238
+ double cosl;
239
+ double cosr;
240
+ double cs;
241
+ double eps;
242
+ double f;
243
+ double g;
244
+ double h;
245
+ double mu;
246
+ double oldcs;
247
+ double oldsn;
248
+ double r;
249
+ double shift;
250
+ double sigmn;
251
+ double sigmx;
252
+ double sinl;
253
+ double sinr;
254
+ double sll;
255
+ double smax;
256
+ double smin;
257
+ double sminl;
258
+ double sminlo;
259
+ double sminoa;
260
+ double sn;
261
+ double thresh;
262
+ double tol;
263
+ double tolmul;
264
+ double unfl;
265
+ ap::real_1d_array work0;
266
+ ap::real_1d_array work1;
267
+ ap::real_1d_array work2;
268
+ ap::real_1d_array work3;
269
+ int maxitr;
270
+ bool matrixsplitflag;
271
+ bool iterflag;
272
+ ap::real_1d_array utemp;
273
+ ap::real_1d_array vttemp;
274
+ ap::real_1d_array ctemp;
275
+ ap::real_1d_array etemp;
276
+ bool rightside;
277
+ bool fwddir;
278
+ double tmp;
279
+ int mm1;
280
+ int mm0;
281
+ bool bchangedir;
282
+ int uend;
283
+ int cend;
284
+ int vend;
285
+
286
+ result = true;
287
+ if( n==0 )
288
+ {
289
+ return result;
290
+ }
291
+ if( n==1 )
292
+ {
293
+ if( d(1)<0 )
294
+ {
295
+ d(1) = -d(1);
296
+ if( ncvt>0 )
297
+ {
298
+ ap::vmul(&vt(vstart, vstart), ap::vlen(vstart,vstart+ncvt-1), -1);
299
+ }
300
+ }
301
+ return result;
302
+ }
303
+
304
+ //
305
+ // init
306
+ //
307
+ work0.setbounds(1, n-1);
308
+ work1.setbounds(1, n-1);
309
+ work2.setbounds(1, n-1);
310
+ work3.setbounds(1, n-1);
311
+ uend = ustart+ap::maxint(nru-1, 0);
312
+ vend = vstart+ap::maxint(ncvt-1, 0);
313
+ cend = cstart+ap::maxint(ncc-1, 0);
314
+ utemp.setbounds(ustart, uend);
315
+ vttemp.setbounds(vstart, vend);
316
+ ctemp.setbounds(cstart, cend);
317
+ maxitr = 12;
318
+ rightside = true;
319
+ fwddir = true;
320
+
321
+ //
322
+ // resize E from N-1 to N
323
+ //
324
+ etemp.setbounds(1, n);
325
+ for(i = 1; i <= n-1; i++)
326
+ {
327
+ etemp(i) = e(i);
328
+ }
329
+ e.setbounds(1, n);
330
+ for(i = 1; i <= n-1; i++)
331
+ {
332
+ e(i) = etemp(i);
333
+ }
334
+ e(n) = 0;
335
+ idir = 0;
336
+
337
+ //
338
+ // Get machine constants
339
+ //
340
+ eps = ap::machineepsilon;
341
+ unfl = ap::minrealnumber;
342
+
343
+ //
344
+ // If matrix lower bidiagonal, rotate to be upper bidiagonal
345
+ // by applying Givens rotations on the left
346
+ //
347
+ if( !isupper )
348
+ {
349
+ for(i = 1; i <= n-1; i++)
350
+ {
351
+ generaterotation(d(i), e(i), cs, sn, r);
352
+ d(i) = r;
353
+ e(i) = sn*d(i+1);
354
+ d(i+1) = cs*d(i+1);
355
+ work0(i) = cs;
356
+ work1(i) = sn;
357
+ }
358
+
359
+ //
360
+ // Update singular vectors if desired
361
+ //
362
+ if( nru>0 )
363
+ {
364
+ applyrotationsfromtheright(fwddir, ustart, uend, 1+ustart-1, n+ustart-1, work0, work1, u, utemp);
365
+ }
366
+ if( ncc>0 )
367
+ {
368
+ applyrotationsfromtheleft(fwddir, 1+cstart-1, n+cstart-1, cstart, cend, work0, work1, c, ctemp);
369
+ }
370
+ }
371
+
372
+ //
373
+ // Compute singular values to relative accuracy TOL
374
+ // (By setting TOL to be negative, algorithm will compute
375
+ // singular values to absolute accuracy ABS(TOL)*norm(input matrix))
376
+ //
377
+ tolmul = ap::maxreal(double(10), ap::minreal(double(100), pow(eps, -0.125)));
378
+ tol = tolmul*eps;
379
+ if( !isfractionalaccuracyrequired )
380
+ {
381
+ tol = -tol;
382
+ }
383
+
384
+ //
385
+ // Compute approximate maximum, minimum singular values
386
+ //
387
+ smax = 0;
388
+ for(i = 1; i <= n; i++)
389
+ {
390
+ smax = ap::maxreal(smax, fabs(d(i)));
391
+ }
392
+ for(i = 1; i <= n-1; i++)
393
+ {
394
+ smax = ap::maxreal(smax, fabs(e(i)));
395
+ }
396
+ sminl = 0;
397
+ if( tol>=0 )
398
+ {
399
+
400
+ //
401
+ // Relative accuracy desired
402
+ //
403
+ sminoa = fabs(d(1));
404
+ if( sminoa!=0 )
405
+ {
406
+ mu = sminoa;
407
+ for(i = 2; i <= n; i++)
408
+ {
409
+ mu = fabs(d(i))*(mu/(mu+fabs(e(i-1))));
410
+ sminoa = ap::minreal(sminoa, mu);
411
+ if( sminoa==0 )
412
+ {
413
+ break;
414
+ }
415
+ }
416
+ }
417
+ sminoa = sminoa/sqrt(double(n));
418
+ thresh = ap::maxreal(tol*sminoa, maxitr*n*n*unfl);
419
+ }
420
+ else
421
+ {
422
+
423
+ //
424
+ // Absolute accuracy desired
425
+ //
426
+ thresh = ap::maxreal(fabs(tol)*smax, maxitr*n*n*unfl);
427
+ }
428
+
429
+ //
430
+ // Prepare for main iteration loop for the singular values
431
+ // (MAXIT is the maximum number of passes through the inner
432
+ // loop permitted before nonconvergence signalled.)
433
+ //
434
+ maxit = maxitr*n*n;
435
+ iter = 0;
436
+ oldll = -1;
437
+ oldm = -1;
438
+
439
+ //
440
+ // M points to last element of unconverged part of matrix
441
+ //
442
+ m = n;
443
+
444
+ //
445
+ // Begin main iteration loop
446
+ //
447
+ while(true)
448
+ {
449
+
450
+ //
451
+ // Check for convergence or exceeding iteration count
452
+ //
453
+ if( m<=1 )
454
+ {
455
+ break;
456
+ }
457
+ if( iter>maxit )
458
+ {
459
+ result = false;
460
+ return result;
461
+ }
462
+
463
+ //
464
+ // Find diagonal block of matrix to work on
465
+ //
466
+ if( tol<0&&fabs(d(m))<=thresh )
467
+ {
468
+ d(m) = 0;
469
+ }
470
+ smax = fabs(d(m));
471
+ smin = smax;
472
+ matrixsplitflag = false;
473
+ for(lll = 1; lll <= m-1; lll++)
474
+ {
475
+ ll = m-lll;
476
+ abss = fabs(d(ll));
477
+ abse = fabs(e(ll));
478
+ if( tol<0&&abss<=thresh )
479
+ {
480
+ d(ll) = 0;
481
+ }
482
+ if( abse<=thresh )
483
+ {
484
+ matrixsplitflag = true;
485
+ break;
486
+ }
487
+ smin = ap::minreal(smin, abss);
488
+ smax = ap::maxreal(smax, ap::maxreal(abss, abse));
489
+ }
490
+ if( !matrixsplitflag )
491
+ {
492
+ ll = 0;
493
+ }
494
+ else
495
+ {
496
+
497
+ //
498
+ // Matrix splits since E(LL) = 0
499
+ //
500
+ e(ll) = 0;
501
+ if( ll==m-1 )
502
+ {
503
+
504
+ //
505
+ // Convergence of bottom singular value, return to top of loop
506
+ //
507
+ m = m-1;
508
+ continue;
509
+ }
510
+ }
511
+ ll = ll+1;
512
+
513
+ //
514
+ // E(LL) through E(M-1) are nonzero, E(LL-1) is zero
515
+ //
516
+ if( ll==m-1 )
517
+ {
518
+
519
+ //
520
+ // 2 by 2 block, handle separately
521
+ //
522
+ svdv2x2(d(m-1), e(m-1), d(m), sigmn, sigmx, sinr, cosr, sinl, cosl);
523
+ d(m-1) = sigmx;
524
+ e(m-1) = 0;
525
+ d(m) = sigmn;
526
+
527
+ //
528
+ // Compute singular vectors, if desired
529
+ //
530
+ if( ncvt>0 )
531
+ {
532
+ mm0 = m+(vstart-1);
533
+ mm1 = m-1+(vstart-1);
534
+ ap::vmove(&vttemp(vstart), &vt(mm1, vstart), ap::vlen(vstart,vend), cosr);
535
+ ap::vadd(&vttemp(vstart), &vt(mm0, vstart), ap::vlen(vstart,vend), sinr);
536
+ ap::vmul(&vt(mm0, vstart), ap::vlen(vstart,vend), cosr);
537
+ ap::vsub(&vt(mm0, vstart), &vt(mm1, vstart), ap::vlen(vstart,vend), sinr);
538
+ ap::vmove(&vt(mm1, vstart), &vttemp(vstart), ap::vlen(vstart,vend));
539
+ }
540
+ if( nru>0 )
541
+ {
542
+ mm0 = m+ustart-1;
543
+ mm1 = m-1+ustart-1;
544
+ ap::vmove(utemp.getvector(ustart, uend), u.getcolumn(mm1, ustart, uend), cosl);
545
+ ap::vadd(utemp.getvector(ustart, uend), u.getcolumn(mm0, ustart, uend), sinl);
546
+ ap::vmul(u.getcolumn(mm0, ustart, uend), cosl);
547
+ ap::vsub(u.getcolumn(mm0, ustart, uend), u.getcolumn(mm1, ustart, uend), sinl);
548
+ ap::vmove(u.getcolumn(mm1, ustart, uend), utemp.getvector(ustart, uend));
549
+ }
550
+ if( ncc>0 )
551
+ {
552
+ mm0 = m+cstart-1;
553
+ mm1 = m-1+cstart-1;
554
+ ap::vmove(&ctemp(cstart), &c(mm1, cstart), ap::vlen(cstart,cend), cosl);
555
+ ap::vadd(&ctemp(cstart), &c(mm0, cstart), ap::vlen(cstart,cend), sinl);
556
+ ap::vmul(&c(mm0, cstart), ap::vlen(cstart,cend), cosl);
557
+ ap::vsub(&c(mm0, cstart), &c(mm1, cstart), ap::vlen(cstart,cend), sinl);
558
+ ap::vmove(&c(mm1, cstart), &ctemp(cstart), ap::vlen(cstart,cend));
559
+ }
560
+ m = m-2;
561
+ continue;
562
+ }
563
+
564
+ //
565
+ // If working on new submatrix, choose shift direction
566
+ // (from larger end diagonal element towards smaller)
567
+ //
568
+ // Previously was
569
+ // "if (LL>OLDM) or (M<OLDLL) then"
570
+ // fixed thanks to Michael Rolle < m@rolle.name >
571
+ // Very strange that LAPACK still contains it.
572
+ //
573
+ bchangedir = false;
574
+ if( idir==1&&fabs(d(ll))<1.0E-3*fabs(d(m)) )
575
+ {
576
+ bchangedir = true;
577
+ }
578
+ if( idir==2&&fabs(d(m))<1.0E-3*fabs(d(ll)) )
579
+ {
580
+ bchangedir = true;
581
+ }
582
+ if( ll!=oldll||m!=oldm||bchangedir )
583
+ {
584
+ if( fabs(d(ll))>=fabs(d(m)) )
585
+ {
586
+
587
+ //
588
+ // Chase bulge from top (big end) to bottom (small end)
589
+ //
590
+ idir = 1;
591
+ }
592
+ else
593
+ {
594
+
595
+ //
596
+ // Chase bulge from bottom (big end) to top (small end)
597
+ //
598
+ idir = 2;
599
+ }
600
+ }
601
+
602
+ //
603
+ // Apply convergence tests
604
+ //
605
+ if( idir==1 )
606
+ {
607
+
608
+ //
609
+ // Run convergence test in forward direction
610
+ // First apply standard test to bottom of matrix
611
+ //
612
+ if( fabs(e(m-1))<=fabs(tol)*fabs(d(m))||tol<0&&fabs(e(m-1))<=thresh )
613
+ {
614
+ e(m-1) = 0;
615
+ continue;
616
+ }
617
+ if( tol>=0 )
618
+ {
619
+
620
+ //
621
+ // If relative accuracy desired,
622
+ // apply convergence criterion forward
623
+ //
624
+ mu = fabs(d(ll));
625
+ sminl = mu;
626
+ iterflag = false;
627
+ for(lll = ll; lll <= m-1; lll++)
628
+ {
629
+ if( fabs(e(lll))<=tol*mu )
630
+ {
631
+ e(lll) = 0;
632
+ iterflag = true;
633
+ break;
634
+ }
635
+ sminlo = sminl;
636
+ mu = fabs(d(lll+1))*(mu/(mu+fabs(e(lll))));
637
+ sminl = ap::minreal(sminl, mu);
638
+ }
639
+ if( iterflag )
640
+ {
641
+ continue;
642
+ }
643
+ }
644
+ }
645
+ else
646
+ {
647
+
648
+ //
649
+ // Run convergence test in backward direction
650
+ // First apply standard test to top of matrix
651
+ //
652
+ if( fabs(e(ll))<=fabs(tol)*fabs(d(ll))||tol<0&&fabs(e(ll))<=thresh )
653
+ {
654
+ e(ll) = 0;
655
+ continue;
656
+ }
657
+ if( tol>=0 )
658
+ {
659
+
660
+ //
661
+ // If relative accuracy desired,
662
+ // apply convergence criterion backward
663
+ //
664
+ mu = fabs(d(m));
665
+ sminl = mu;
666
+ iterflag = false;
667
+ for(lll = m-1; lll >= ll; lll--)
668
+ {
669
+ if( fabs(e(lll))<=tol*mu )
670
+ {
671
+ e(lll) = 0;
672
+ iterflag = true;
673
+ break;
674
+ }
675
+ sminlo = sminl;
676
+ mu = fabs(d(lll))*(mu/(mu+fabs(e(lll))));
677
+ sminl = ap::minreal(sminl, mu);
678
+ }
679
+ if( iterflag )
680
+ {
681
+ continue;
682
+ }
683
+ }
684
+ }
685
+ oldll = ll;
686
+ oldm = m;
687
+
688
+ //
689
+ // Compute shift. First, test if shifting would ruin relative
690
+ // accuracy, and if so set the shift to zero.
691
+ //
692
+ if( tol>=0&&n*tol*(sminl/smax)<=ap::maxreal(eps, 0.01*tol) )
693
+ {
694
+
695
+ //
696
+ // Use a zero shift to avoid loss of relative accuracy
697
+ //
698
+ shift = 0;
699
+ }
700
+ else
701
+ {
702
+
703
+ //
704
+ // Compute the shift from 2-by-2 block at end of matrix
705
+ //
706
+ if( idir==1 )
707
+ {
708
+ sll = fabs(d(ll));
709
+ svd2x2(d(m-1), e(m-1), d(m), shift, r);
710
+ }
711
+ else
712
+ {
713
+ sll = fabs(d(m));
714
+ svd2x2(d(ll), e(ll), d(ll+1), shift, r);
715
+ }
716
+
717
+ //
718
+ // Test if shift negligible, and if so set to zero
719
+ //
720
+ if( sll>0 )
721
+ {
722
+ if( ap::sqr(shift/sll)<eps )
723
+ {
724
+ shift = 0;
725
+ }
726
+ }
727
+ }
728
+
729
+ //
730
+ // Increment iteration count
731
+ //
732
+ iter = iter+m-ll;
733
+
734
+ //
735
+ // If SHIFT = 0, do simplified QR iteration
736
+ //
737
+ if( shift==0 )
738
+ {
739
+ if( idir==1 )
740
+ {
741
+
742
+ //
743
+ // Chase bulge from top to bottom
744
+ // Save cosines and sines for later singular vector updates
745
+ //
746
+ cs = 1;
747
+ oldcs = 1;
748
+ for(i = ll; i <= m-1; i++)
749
+ {
750
+ generaterotation(d(i)*cs, e(i), cs, sn, r);
751
+ if( i>ll )
752
+ {
753
+ e(i-1) = oldsn*r;
754
+ }
755
+ generaterotation(oldcs*r, d(i+1)*sn, oldcs, oldsn, tmp);
756
+ d(i) = tmp;
757
+ work0(i-ll+1) = cs;
758
+ work1(i-ll+1) = sn;
759
+ work2(i-ll+1) = oldcs;
760
+ work3(i-ll+1) = oldsn;
761
+ }
762
+ h = d(m)*cs;
763
+ d(m) = h*oldcs;
764
+ e(m-1) = h*oldsn;
765
+
766
+ //
767
+ // Update singular vectors
768
+ //
769
+ if( ncvt>0 )
770
+ {
771
+ applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, work0, work1, vt, vttemp);
772
+ }
773
+ if( nru>0 )
774
+ {
775
+ applyrotationsfromtheright(fwddir, ustart, uend, ll+ustart-1, m+ustart-1, work2, work3, u, utemp);
776
+ }
777
+ if( ncc>0 )
778
+ {
779
+ applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, work2, work3, c, ctemp);
780
+ }
781
+
782
+ //
783
+ // Test convergence
784
+ //
785
+ if( fabs(e(m-1))<=thresh )
786
+ {
787
+ e(m-1) = 0;
788
+ }
789
+ }
790
+ else
791
+ {
792
+
793
+ //
794
+ // Chase bulge from bottom to top
795
+ // Save cosines and sines for later singular vector updates
796
+ //
797
+ cs = 1;
798
+ oldcs = 1;
799
+ for(i = m; i >= ll+1; i--)
800
+ {
801
+ generaterotation(d(i)*cs, e(i-1), cs, sn, r);
802
+ if( i<m )
803
+ {
804
+ e(i) = oldsn*r;
805
+ }
806
+ generaterotation(oldcs*r, d(i-1)*sn, oldcs, oldsn, tmp);
807
+ d(i) = tmp;
808
+ work0(i-ll) = cs;
809
+ work1(i-ll) = -sn;
810
+ work2(i-ll) = oldcs;
811
+ work3(i-ll) = -oldsn;
812
+ }
813
+ h = d(ll)*cs;
814
+ d(ll) = h*oldcs;
815
+ e(ll) = h*oldsn;
816
+
817
+ //
818
+ // Update singular vectors
819
+ //
820
+ if( ncvt>0 )
821
+ {
822
+ applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, work2, work3, vt, vttemp);
823
+ }
824
+ if( nru>0 )
825
+ {
826
+ applyrotationsfromtheright(!fwddir, ustart, uend, ll+ustart-1, m+ustart-1, work0, work1, u, utemp);
827
+ }
828
+ if( ncc>0 )
829
+ {
830
+ applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, work0, work1, c, ctemp);
831
+ }
832
+
833
+ //
834
+ // Test convergence
835
+ //
836
+ if( fabs(e(ll))<=thresh )
837
+ {
838
+ e(ll) = 0;
839
+ }
840
+ }
841
+ }
842
+ else
843
+ {
844
+
845
+ //
846
+ // Use nonzero shift
847
+ //
848
+ if( idir==1 )
849
+ {
850
+
851
+ //
852
+ // Chase bulge from top to bottom
853
+ // Save cosines and sines for later singular vector updates
854
+ //
855
+ f = (fabs(d(ll))-shift)*(extsignbdsqr(double(1), d(ll))+shift/d(ll));
856
+ g = e(ll);
857
+ for(i = ll; i <= m-1; i++)
858
+ {
859
+ generaterotation(f, g, cosr, sinr, r);
860
+ if( i>ll )
861
+ {
862
+ e(i-1) = r;
863
+ }
864
+ f = cosr*d(i)+sinr*e(i);
865
+ e(i) = cosr*e(i)-sinr*d(i);
866
+ g = sinr*d(i+1);
867
+ d(i+1) = cosr*d(i+1);
868
+ generaterotation(f, g, cosl, sinl, r);
869
+ d(i) = r;
870
+ f = cosl*e(i)+sinl*d(i+1);
871
+ d(i+1) = cosl*d(i+1)-sinl*e(i);
872
+ if( i<m-1 )
873
+ {
874
+ g = sinl*e(i+1);
875
+ e(i+1) = cosl*e(i+1);
876
+ }
877
+ work0(i-ll+1) = cosr;
878
+ work1(i-ll+1) = sinr;
879
+ work2(i-ll+1) = cosl;
880
+ work3(i-ll+1) = sinl;
881
+ }
882
+ e(m-1) = f;
883
+
884
+ //
885
+ // Update singular vectors
886
+ //
887
+ if( ncvt>0 )
888
+ {
889
+ applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, work0, work1, vt, vttemp);
890
+ }
891
+ if( nru>0 )
892
+ {
893
+ applyrotationsfromtheright(fwddir, ustart, uend, ll+ustart-1, m+ustart-1, work2, work3, u, utemp);
894
+ }
895
+ if( ncc>0 )
896
+ {
897
+ applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, work2, work3, c, ctemp);
898
+ }
899
+
900
+ //
901
+ // Test convergence
902
+ //
903
+ if( fabs(e(m-1))<=thresh )
904
+ {
905
+ e(m-1) = 0;
906
+ }
907
+ }
908
+ else
909
+ {
910
+
911
+ //
912
+ // Chase bulge from bottom to top
913
+ // Save cosines and sines for later singular vector updates
914
+ //
915
+ f = (fabs(d(m))-shift)*(extsignbdsqr(double(1), d(m))+shift/d(m));
916
+ g = e(m-1);
917
+ for(i = m; i >= ll+1; i--)
918
+ {
919
+ generaterotation(f, g, cosr, sinr, r);
920
+ if( i<m )
921
+ {
922
+ e(i) = r;
923
+ }
924
+ f = cosr*d(i)+sinr*e(i-1);
925
+ e(i-1) = cosr*e(i-1)-sinr*d(i);
926
+ g = sinr*d(i-1);
927
+ d(i-1) = cosr*d(i-1);
928
+ generaterotation(f, g, cosl, sinl, r);
929
+ d(i) = r;
930
+ f = cosl*e(i-1)+sinl*d(i-1);
931
+ d(i-1) = cosl*d(i-1)-sinl*e(i-1);
932
+ if( i>ll+1 )
933
+ {
934
+ g = sinl*e(i-2);
935
+ e(i-2) = cosl*e(i-2);
936
+ }
937
+ work0(i-ll) = cosr;
938
+ work1(i-ll) = -sinr;
939
+ work2(i-ll) = cosl;
940
+ work3(i-ll) = -sinl;
941
+ }
942
+ e(ll) = f;
943
+
944
+ //
945
+ // Test convergence
946
+ //
947
+ if( fabs(e(ll))<=thresh )
948
+ {
949
+ e(ll) = 0;
950
+ }
951
+
952
+ //
953
+ // Update singular vectors if desired
954
+ //
955
+ if( ncvt>0 )
956
+ {
957
+ applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, work2, work3, vt, vttemp);
958
+ }
959
+ if( nru>0 )
960
+ {
961
+ applyrotationsfromtheright(!fwddir, ustart, uend, ll+ustart-1, m+ustart-1, work0, work1, u, utemp);
962
+ }
963
+ if( ncc>0 )
964
+ {
965
+ applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, work0, work1, c, ctemp);
966
+ }
967
+ }
968
+ }
969
+
970
+ //
971
+ // QR iteration finished, go back and check convergence
972
+ //
973
+ continue;
974
+ }
975
+
976
+ //
977
+ // All singular values converged, so make them positive
978
+ //
979
+ for(i = 1; i <= n; i++)
980
+ {
981
+ if( d(i)<0 )
982
+ {
983
+ d(i) = -d(i);
984
+
985
+ //
986
+ // Change sign of singular vectors, if desired
987
+ //
988
+ if( ncvt>0 )
989
+ {
990
+ ap::vmul(&vt(i+vstart-1, vstart), ap::vlen(vstart,vend), -1);
991
+ }
992
+ }
993
+ }
994
+
995
+ //
996
+ // Sort the singular values into decreasing order (insertion sort on
997
+ // singular values, but only one transposition per singular vector)
998
+ //
999
+ for(i = 1; i <= n-1; i++)
1000
+ {
1001
+
1002
+ //
1003
+ // Scan for smallest D(I)
1004
+ //
1005
+ isub = 1;
1006
+ smin = d(1);
1007
+ for(j = 2; j <= n+1-i; j++)
1008
+ {
1009
+ if( d(j)<=smin )
1010
+ {
1011
+ isub = j;
1012
+ smin = d(j);
1013
+ }
1014
+ }
1015
+ if( isub!=n+1-i )
1016
+ {
1017
+
1018
+ //
1019
+ // Swap singular values and vectors
1020
+ //
1021
+ d(isub) = d(n+1-i);
1022
+ d(n+1-i) = smin;
1023
+ if( ncvt>0 )
1024
+ {
1025
+ j = n+1-i;
1026
+ ap::vmove(&vttemp(vstart), &vt(isub+vstart-1, vstart), ap::vlen(vstart,vend));
1027
+ ap::vmove(&vt(isub+vstart-1, vstart), &vt(j+vstart-1, vstart), ap::vlen(vstart,vend));
1028
+ ap::vmove(&vt(j+vstart-1, vstart), &vttemp(vstart), ap::vlen(vstart,vend));
1029
+ }
1030
+ if( nru>0 )
1031
+ {
1032
+ j = n+1-i;
1033
+ ap::vmove(utemp.getvector(ustart, uend), u.getcolumn(isub+ustart-1, ustart, uend));
1034
+ ap::vmove(u.getcolumn(isub+ustart-1, ustart, uend), u.getcolumn(j+ustart-1, ustart, uend));
1035
+ ap::vmove(u.getcolumn(j+ustart-1, ustart, uend), utemp.getvector(ustart, uend));
1036
+ }
1037
+ if( ncc>0 )
1038
+ {
1039
+ j = n+1-i;
1040
+ ap::vmove(&ctemp(cstart), &c(isub+cstart-1, cstart), ap::vlen(cstart,cend));
1041
+ ap::vmove(&c(isub+cstart-1, cstart), &c(j+cstart-1, cstart), ap::vlen(cstart,cend));
1042
+ ap::vmove(&c(j+cstart-1, cstart), &ctemp(cstart), ap::vlen(cstart,cend));
1043
+ }
1044
+ }
1045
+ }
1046
+ return result;
1047
+ }
1048
+
1049
+
1050
+ static double extsignbdsqr(double a, double b)
1051
+ {
1052
+ double result;
1053
+
1054
+ if( b>=0 )
1055
+ {
1056
+ result = fabs(a);
1057
+ }
1058
+ else
1059
+ {
1060
+ result = -fabs(a);
1061
+ }
1062
+ return result;
1063
+ }
1064
+
1065
+
1066
+ static void svd2x2(double f,
1067
+ double g,
1068
+ double h,
1069
+ double& ssmin,
1070
+ double& ssmax)
1071
+ {
1072
+ double aas;
1073
+ double at;
1074
+ double au;
1075
+ double c;
1076
+ double fa;
1077
+ double fhmn;
1078
+ double fhmx;
1079
+ double ga;
1080
+ double ha;
1081
+
1082
+ fa = fabs(f);
1083
+ ga = fabs(g);
1084
+ ha = fabs(h);
1085
+ fhmn = ap::minreal(fa, ha);
1086
+ fhmx = ap::maxreal(fa, ha);
1087
+ if( fhmn==0 )
1088
+ {
1089
+ ssmin = 0;
1090
+ if( fhmx==0 )
1091
+ {
1092
+ ssmax = ga;
1093
+ }
1094
+ else
1095
+ {
1096
+ ssmax = ap::maxreal(fhmx, ga)*sqrt(1+ap::sqr(ap::minreal(fhmx, ga)/ap::maxreal(fhmx, ga)));
1097
+ }
1098
+ }
1099
+ else
1100
+ {
1101
+ if( ga<fhmx )
1102
+ {
1103
+ aas = 1+fhmn/fhmx;
1104
+ at = (fhmx-fhmn)/fhmx;
1105
+ au = ap::sqr(ga/fhmx);
1106
+ c = 2/(sqrt(aas*aas+au)+sqrt(at*at+au));
1107
+ ssmin = fhmn*c;
1108
+ ssmax = fhmx/c;
1109
+ }
1110
+ else
1111
+ {
1112
+ au = fhmx/ga;
1113
+ if( au==0 )
1114
+ {
1115
+
1116
+ //
1117
+ // Avoid possible harmful underflow if exponent range
1118
+ // asymmetric (true SSMIN may not underflow even if
1119
+ // AU underflows)
1120
+ //
1121
+ ssmin = fhmn*fhmx/ga;
1122
+ ssmax = ga;
1123
+ }
1124
+ else
1125
+ {
1126
+ aas = 1+fhmn/fhmx;
1127
+ at = (fhmx-fhmn)/fhmx;
1128
+ c = 1/(sqrt(1+ap::sqr(aas*au))+sqrt(1+ap::sqr(at*au)));
1129
+ ssmin = fhmn*c*au;
1130
+ ssmin = ssmin+ssmin;
1131
+ ssmax = ga/(c+c);
1132
+ }
1133
+ }
1134
+ }
1135
+ }
1136
+
1137
+
1138
+ static void svdv2x2(double f,
1139
+ double g,
1140
+ double h,
1141
+ double& ssmin,
1142
+ double& ssmax,
1143
+ double& snr,
1144
+ double& csr,
1145
+ double& snl,
1146
+ double& csl)
1147
+ {
1148
+ bool gasmal;
1149
+ bool swp;
1150
+ int pmax;
1151
+ double a;
1152
+ double clt;
1153
+ double crt;
1154
+ double d;
1155
+ double fa;
1156
+ double ft;
1157
+ double ga;
1158
+ double gt;
1159
+ double ha;
1160
+ double ht;
1161
+ double l;
1162
+ double m;
1163
+ double mm;
1164
+ double r;
1165
+ double s;
1166
+ double slt;
1167
+ double srt;
1168
+ double t;
1169
+ double temp;
1170
+ double tsign;
1171
+ double tt;
1172
+ double v;
1173
+
1174
+ ft = f;
1175
+ fa = fabs(ft);
1176
+ ht = h;
1177
+ ha = fabs(h);
1178
+
1179
+ //
1180
+ // PMAX points to the maximum absolute element of matrix
1181
+ // PMAX = 1 if F largest in absolute values
1182
+ // PMAX = 2 if G largest in absolute values
1183
+ // PMAX = 3 if H largest in absolute values
1184
+ //
1185
+ pmax = 1;
1186
+ swp = ha>fa;
1187
+ if( swp )
1188
+ {
1189
+
1190
+ //
1191
+ // Now FA .ge. HA
1192
+ //
1193
+ pmax = 3;
1194
+ temp = ft;
1195
+ ft = ht;
1196
+ ht = temp;
1197
+ temp = fa;
1198
+ fa = ha;
1199
+ ha = temp;
1200
+ }
1201
+ gt = g;
1202
+ ga = fabs(gt);
1203
+ if( ga==0 )
1204
+ {
1205
+
1206
+ //
1207
+ // Diagonal matrix
1208
+ //
1209
+ ssmin = ha;
1210
+ ssmax = fa;
1211
+ clt = 1;
1212
+ crt = 1;
1213
+ slt = 0;
1214
+ srt = 0;
1215
+ }
1216
+ else
1217
+ {
1218
+ gasmal = true;
1219
+ if( ga>fa )
1220
+ {
1221
+ pmax = 2;
1222
+ if( fa/ga<ap::machineepsilon )
1223
+ {
1224
+
1225
+ //
1226
+ // Case of very large GA
1227
+ //
1228
+ gasmal = false;
1229
+ ssmax = ga;
1230
+ if( ha>1 )
1231
+ {
1232
+ v = ga/ha;
1233
+ ssmin = fa/v;
1234
+ }
1235
+ else
1236
+ {
1237
+ v = fa/ga;
1238
+ ssmin = v*ha;
1239
+ }
1240
+ clt = 1;
1241
+ slt = ht/gt;
1242
+ srt = 1;
1243
+ crt = ft/gt;
1244
+ }
1245
+ }
1246
+ if( gasmal )
1247
+ {
1248
+
1249
+ //
1250
+ // Normal case
1251
+ //
1252
+ d = fa-ha;
1253
+ if( d==fa )
1254
+ {
1255
+ l = 1;
1256
+ }
1257
+ else
1258
+ {
1259
+ l = d/fa;
1260
+ }
1261
+ m = gt/ft;
1262
+ t = 2-l;
1263
+ mm = m*m;
1264
+ tt = t*t;
1265
+ s = sqrt(tt+mm);
1266
+ if( l==0 )
1267
+ {
1268
+ r = fabs(m);
1269
+ }
1270
+ else
1271
+ {
1272
+ r = sqrt(l*l+mm);
1273
+ }
1274
+ a = 0.5*(s+r);
1275
+ ssmin = ha/a;
1276
+ ssmax = fa*a;
1277
+ if( mm==0 )
1278
+ {
1279
+
1280
+ //
1281
+ // Note that M is very tiny
1282
+ //
1283
+ if( l==0 )
1284
+ {
1285
+ t = extsignbdsqr(double(2), ft)*extsignbdsqr(double(1), gt);
1286
+ }
1287
+ else
1288
+ {
1289
+ t = gt/extsignbdsqr(d, ft)+m/t;
1290
+ }
1291
+ }
1292
+ else
1293
+ {
1294
+ t = (m/(s+t)+m/(r+l))*(1+a);
1295
+ }
1296
+ l = sqrt(t*t+4);
1297
+ crt = 2/l;
1298
+ srt = t/l;
1299
+ clt = (crt+srt*m)/a;
1300
+ v = ht/ft;
1301
+ slt = v*srt/a;
1302
+ }
1303
+ }
1304
+ if( swp )
1305
+ {
1306
+ csl = srt;
1307
+ snl = crt;
1308
+ csr = slt;
1309
+ snr = clt;
1310
+ }
1311
+ else
1312
+ {
1313
+ csl = clt;
1314
+ snl = slt;
1315
+ csr = crt;
1316
+ snr = srt;
1317
+ }
1318
+
1319
+ //
1320
+ // Correct signs of SSMAX and SSMIN
1321
+ //
1322
+ if( pmax==1 )
1323
+ {
1324
+ tsign = extsignbdsqr(double(1), csr)*extsignbdsqr(double(1), csl)*extsignbdsqr(double(1), f);
1325
+ }
1326
+ if( pmax==2 )
1327
+ {
1328
+ tsign = extsignbdsqr(double(1), snr)*extsignbdsqr(double(1), csl)*extsignbdsqr(double(1), g);
1329
+ }
1330
+ if( pmax==3 )
1331
+ {
1332
+ tsign = extsignbdsqr(double(1), snr)*extsignbdsqr(double(1), snl)*extsignbdsqr(double(1), h);
1333
+ }
1334
+ ssmax = extsignbdsqr(ssmax, tsign);
1335
+ ssmin = extsignbdsqr(ssmin, tsign*extsignbdsqr(double(1), f)*extsignbdsqr(double(1), h));
1336
+ }
1337
+
1338
+
1339
+