@datagrok-libraries/statistics 0.1.9 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/vendor/lbfgs.js DELETED
@@ -1,310 +0,0 @@
1
- function copyInto(target, source) {
2
- for (var i = 0; i < source.length; i++) {
3
- target[i] = source[i];
4
- }
5
- }
6
-
7
- function limitedMemoryBFGS(optimizable, parameters) {
8
- var lbfgsStart = +new Date();
9
-
10
- var converged = false;
11
- var maxIterations = 1000;
12
- var tolerance = 0.0001;
13
- var gradientTolerance = 0.001;
14
- var epsilon = 0.00001;
15
-
16
- var maxIterations = 100;
17
- var memorySize = 4;
18
-
19
- var numParameters = parameters.length;
20
-
21
- var gradient = numeric.rep([numParameters], 0.0);
22
- optimizable.getGradient(parameters, gradient);
23
- var oldGradient = numeric.clone(gradient);
24
- var oldParameters = numeric.clone(parameters);
25
-
26
- var direction = numeric.clone(gradient);
27
-
28
- // Project direction to the l2 ball
29
- numeric.diveq(direction, numeric.norm2(direction));
30
-
31
- var parameterChangeBuffer = []; // "s"
32
- var gradientChangeBuffer = []; // "y"
33
- var scaleBuffer = []; // "rho"
34
-
35
- // Initial step, do a line search in the direction of the gradient
36
- var scale = backtrackingLineSearch(optimizable, direction, gradient, parameters);
37
-
38
- // "parameters" has now been updated, so get a new value and gradient
39
- var value = optimizable.getValue(parameters);
40
- gradient = optimizable.getGradient(parameters, gradient);
41
-
42
- var oldValue = value;
43
-
44
- if (scale == 0.0) {
45
- console.log("Line search can't step in initial direction.");
46
- }
47
-
48
- for (var iteration = 0; iteration < maxIterations; iteration++) {
49
- var start = +new Date();
50
- var end;
51
-
52
- console.log("Beginning L-BFGS iteration, v=" + value + " ||g||=" + numeric.norm2(gradient));
53
-
54
- // Update the buffers with diffs
55
- if (parameterChangeBuffer.length < memorySize) {
56
- // If the buffer isn't full yet, add new arrays
57
- parameterChangeBuffer.unshift(numeric.sub(parameters, oldParameters));
58
- gradientChangeBuffer.unshift(numeric.sub(gradient, oldGradient));
59
- }
60
- else {
61
- // Otherwise, reuse the memory from the last array
62
- var parameterChange = parameterChangeBuffer.pop();
63
- var gradientChange = gradientChangeBuffer.pop();
64
- for (var i = 0; i < numParameters; i++) {
65
- parameterChange[i] = parameters[i] - oldParameters[i];
66
- gradientChange[i] = gradient[i] - oldGradient[i];
67
- }
68
- parameterChangeBuffer.unshift(parameterChange);
69
- gradientChangeBuffer.unshift(gradientChange);
70
- }
71
-
72
- // Save the old values. Gradient will be overwritten, then parameters.
73
- copyInto(oldParameters, parameters);
74
- copyInto(oldGradient, gradient);
75
-
76
- var sy = 0.0;
77
- var yy = 0.0;
78
- for (var i = 0; i < numParameters; i++) {
79
- sy += parameterChangeBuffer[0][i] * gradientChangeBuffer[0][i];
80
- yy += gradientChangeBuffer[0][i] * gradientChangeBuffer[0][i];
81
- }
82
- var scalingFactor = sy / yy;
83
- scaleBuffer.unshift(1.0 / sy);
84
-
85
- if (scalingFactor > 0.0) { console.log("Scaling factor greater than zero: " + scalingFactor); }
86
-
87
- // Renaming the "gradient" array to "direction" -- but it's the same memory.
88
- copyInto(direction, gradient);
89
-
90
- // Forward pass, from newest to oldest
91
- var alpha = [];
92
- for (var step = 0; step < parameterChangeBuffer.length; step++) {
93
- var currentAlpha = 0.0;
94
- for (var i = 0; i < numParameters; i++) {
95
- currentAlpha += parameterChangeBuffer[step][i] * direction[i];
96
- }
97
- currentAlpha *= scaleBuffer[step];
98
-
99
- //var currentAlpha = scaleBuffer[step] * numeric.dot(parameterChangeBuffer[step], direction)
100
- alpha.push(currentAlpha);
101
- for (var i = 0; i < numParameters; i++) {
102
- direction[i] += gradientChangeBuffer[step][i] * -currentAlpha;
103
- }
104
- }
105
-
106
- for (var i = 0; i < numParameters; i++) {
107
- direction[i] *= scalingFactor;
108
- }
109
-
110
- // Backward pass, from oldest to newest
111
- for (var step = parameterChangeBuffer.length - 1; step >= 0; step--) {
112
- var beta = 0.0;
113
- for (var i = 0; i < numParameters; i++) {
114
- beta += gradientChangeBuffer[step][i] * direction[i];
115
- }
116
- beta *= scaleBuffer[step];
117
-
118
- var currentAlpha = alpha[step];
119
- for (var i = 0; i < numParameters; i++) {
120
- direction[i] += parameterChangeBuffer[step][i] * (currentAlpha - beta);
121
- }
122
- }
123
-
124
- // Negate the direction, to maximize rather than minimize
125
- for (var i = 0; i < numParameters; i++) {
126
- direction[i] = -direction[i];
127
- }
128
-
129
- scale = backtrackingLineSearch(optimizable, direction, gradient, parameters);
130
- if (scale == 0.0) {
131
- console.log("Cannot step in current direction");
132
- }
133
-
134
- value = optimizable.getValue(parameters);
135
- gradient = optimizable.getGradient(parameters, gradient);
136
-
137
- // Test for convergence
138
- if (2.0 * (value - oldValue) <= tolerance * (Math.abs(value) + Math.abs(oldValue) + epsilon)) {
139
- console.log("Value difference below threshold: " + value + " - " + oldValue);
140
- end = +new Date();
141
- console.log("Finished iterations " + (end - lbfgsStart));
142
- return true;
143
- }
144
-
145
- var gradientNorm = numeric.norm2(gradient);
146
- if (gradientNorm < gradientTolerance) {
147
- console.log("Gradient norm below threshold: " + gradientNorm);
148
- end = +new Date();
149
- console.log("Finished iterations " + (end - lbfgsStart));
150
- return true;
151
- }
152
- else if (gradientNorm == 0.0) {
153
- console.log("Gradient norm is zero");
154
- end = +new Date();
155
- console.log("Finished iterations " + (end - lbfgsStart));
156
- return true;
157
- }
158
-
159
- oldValue = value;
160
-
161
- }
162
-
163
- end = +new Date();
164
- console.log("Finished iterations " + (end - lbfgsStart));
165
- return true;
166
- }
167
-
168
- function backtrackingLineSearch(optimizable, direction, gradient, parameters) {
169
- var numParameters = parameters.length;
170
-
171
- var MAXIMUM_STEP = 100.0;
172
- var RELATIVE_TOLERANCE = 0.0001;
173
- var DECREASE_FRACTION = 0.0001;
174
-
175
- var oldScale = 0.0;
176
- var scale = 1.0;
177
- var newScale = 0.0;
178
-
179
- var originalValue = optimizable.getValue(parameters);
180
- var oldValue = originalValue;
181
-
182
- // Make sure the initial step size isn't too big
183
- var twoNorm = numeric.norm2(direction);
184
- if (twoNorm > MAXIMUM_STEP) {
185
- console.log("Initial step " + twoNorm + " is too big, reducing")
186
- numeric.muleq(direction, MAXIMUM_STEP / twoNorm);
187
- }
188
-
189
- // Get the initial slope of the function of the scale.
190
- var slope = 0.0;
191
- for (var i = 0; i < numParameters; i++) {
192
- slope += gradient[i] * direction[i];
193
- }
194
-
195
- // Find the minimum acceptable scale value.
196
- var maxValue = 0.0;
197
- for (var i = 0; i < numParameters; i++) {
198
- var v = Math.abs( direction[i] / Math.max(Math.abs(parameters[i]), 1.0) );
199
- if (v > maxValue) { maxValue = v; }
200
- }
201
- var minimumScale = RELATIVE_TOLERANCE / maxValue;
202
-
203
- for (var iteration = 0; iteration < 25; iteration++) {
204
- for (var i = 0; i < numParameters; i++) {
205
- parameters[i] += (scale - oldScale) * direction[i];
206
- }
207
-
208
- if (scale < minimumScale) {
209
- console.log("Step too small, exiting.");
210
- return 0.0;
211
- }
212
-
213
- var value = optimizable.getValue(parameters);
214
-
215
- if (value >= originalValue + DECREASE_FRACTION * scale * slope) {
216
- //console.log("Exiting line search at value " + value);
217
- return scale;
218
- }
219
- else if (! isFinite(value)) {
220
- newScale = 0.2 * scale;
221
- }
222
- else {
223
- if (scale == 1.0) {
224
- // This is only true if this is the first iteration (?)
225
- newScale = -slope / (2.0 * (value - originalValue - slope));
226
- }
227
- else {
228
- var x1 = value - originalValue - scale * slope;
229
- var x2 = oldValue - originalValue - oldScale * slope;
230
- var oneOverScaleSquared = 1.0 / (scale * scale);
231
- var oneOverOldScaleSquared = 1.0 / (oldScale * oldScale);
232
- var oneOverScaleDiff = 1.0 / (scale - oldScale);
233
-
234
- var a = oneOverScaleDiff * (x1 * oneOverScaleSquared - x2 * oneOverOldScaleSquared);
235
- var b = oneOverScaleDiff * (-x1 * oldScale * oneOverScaleSquared + x2 * scale * oneOverOldScaleSquared);
236
-
237
- if (a == 0.0) {
238
- newScale = -slope / (2.0 * b);
239
- }
240
- else {
241
- var disc = b * b - 3.0 * a * slope;
242
- if (disc < 0.0) { newScale = 0.5 * scale; }
243
- else if (b <= 0.0) { newScale = (-b + Math.sqrt(disc)) / (3.0 * a); }
244
- else { newScale = -slope / (b + Math.sqrt(disc)); }
245
- }
246
-
247
- if (newScale > 0.5 * scale) { newScale = 0.5 * scale; }
248
- }
249
-
250
- }
251
-
252
- oldValue = value;
253
- oldScale = scale;
254
- scale = Math.max(newScale, 0.1 * scale);
255
- }
256
- }
257
-
258
- var quadratic = {
259
- getValue: function(parameters) {
260
- var x = parameters[0];
261
- var y = parameters[1];
262
-
263
- return -3*x*x - 4*y*y + 2*x - 4*y + 18;
264
- },
265
-
266
- getGradient: function (parameters, gradient) {
267
- gradient[0] = -6 * parameters[0] + 2;
268
- gradient[1] = -8 * parameters[1] - 4;
269
- return gradient;
270
- }
271
- };
272
-
273
- function doubleExp (n) {
274
- var x = Array(n);
275
- for (var i = 0; i < n; i++) {
276
- x[i] = Math.log(Math.random()) * ( Math.random() > 0.5 ? 1.0 : -1.0 );
277
- }
278
- return x;
279
- }
280
-
281
- var ridgeRegression = {
282
- covariates: [],
283
- responses: [],
284
- originalParameters: doubleExp(100),
285
-
286
- sample: function (n, noise) {
287
- for (var i = 0; i < n; i++) {
288
- var x = doubleExp(100);
289
- this.responses.push(numeric.dot(x, this.originalParameters) + noise());
290
- this.covariates.push(x);
291
- }
292
- },
293
-
294
- getValue: function(parameters) {
295
- var logLikelihood = 0.0;
296
- for (var i = 0; i < this.covariates.length; i++) {
297
- var residual = this.responses[i] - numeric.dot(this.covariates[i], parameters);
298
- logLikelihood += -0.5 * residual * residual;
299
- }
300
- return logLikelihood;
301
- },
302
-
303
- getGradient: function(parameters, gradient) {
304
- for (var i = 0; i < this.covariates.length; i++) {
305
- var residual = this.responses[i] - numeric.dot(this.covariates[i], parameters);
306
- numeric.addeq(gradient, numeric.mul(this.covariates[i], residual));
307
- }
308
- return gradient;
309
- }
310
- };