csaps-js 0.1.0 → 0.1.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/dist/index.cjs +127 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.global.js +127 -80
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +127 -80
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.global.js
CHANGED
|
@@ -87,43 +87,70 @@ var csapsjs = (function (exports) {
|
|
|
87
87
|
}
|
|
88
88
|
return lo;
|
|
89
89
|
}
|
|
90
|
-
/** Evaluate component `n` at scalar `xq` with derivative order `nu`. */
|
|
91
|
-
evalScalar(n, xq, nu, extrapolate) {
|
|
92
|
-
const i = this.findPiece(xq, extrapolate);
|
|
93
|
-
if (i < 0) return NaN;
|
|
94
|
-
const s = xq - this.breaks[i];
|
|
95
|
-
const order = this.order;
|
|
96
|
-
const pieces = this.pieces;
|
|
97
|
-
const ndim = this.ndim;
|
|
98
|
-
let res = 0;
|
|
99
|
-
for (let k = 0; k < order; k++) {
|
|
100
|
-
const e = order - 1 - k;
|
|
101
|
-
if (e < nu) continue;
|
|
102
|
-
let f = 1;
|
|
103
|
-
for (let t = 0; t < nu; t++) f *= e - t;
|
|
104
|
-
const coef = this.c[(k * pieces + i) * ndim + n];
|
|
105
|
-
res += coef * f * Math.pow(s, e - nu);
|
|
106
|
-
}
|
|
107
|
-
return res;
|
|
108
|
-
}
|
|
109
90
|
/**
|
|
110
|
-
* Evaluate all components at every point in `xs
|
|
91
|
+
* Evaluate all components at every point in `xs` (Horner's method).
|
|
92
|
+
*
|
|
93
|
+
* The piece lookup is done once per evaluation point and reused across all
|
|
94
|
+
* components, and the polynomial is evaluated with Horner's scheme rather
|
|
95
|
+
* than `Math.pow` — both matter for multivariate and N-D gridded data where
|
|
96
|
+
* `ndim` is large.
|
|
111
97
|
*
|
|
112
98
|
* @returns Flat row-major array with logical shape `(ndim, xs.length)`:
|
|
113
99
|
* `out[n * xs.length + q]`.
|
|
114
100
|
*/
|
|
115
101
|
evalAll(xs, nu, extrapolate) {
|
|
102
|
+
const { order, pieces, ndim, breaks, c } = this;
|
|
103
|
+
const deg = order - 1;
|
|
116
104
|
const L = xs.length;
|
|
117
|
-
const out = new Float64Array(
|
|
105
|
+
const out = new Float64Array(ndim * L);
|
|
106
|
+
if (nu > deg) return out;
|
|
107
|
+
const effDeg = deg - nu;
|
|
108
|
+
const kstep = pieces * ndim;
|
|
109
|
+
let mult = null;
|
|
110
|
+
if (nu !== 0) {
|
|
111
|
+
mult = new Float64Array(effDeg + 1);
|
|
112
|
+
for (let k = 0; k <= effDeg; k++) mult[k] = fallingFactorial(deg - k, nu);
|
|
113
|
+
}
|
|
118
114
|
for (let q = 0; q < L; q++) {
|
|
119
115
|
const xq = xs[q];
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
const i = this.findPiece(xq, extrapolate);
|
|
117
|
+
if (i < 0) {
|
|
118
|
+
for (let n = 0; n < ndim; n++) out[n * L + q] = NaN;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const s = xq - breaks[i];
|
|
122
|
+
const start = i * ndim;
|
|
123
|
+
if (nu === 0) {
|
|
124
|
+
for (let n = 0; n < ndim; n++) {
|
|
125
|
+
let off = start + n;
|
|
126
|
+
let res = c[off];
|
|
127
|
+
for (let k = 1; k <= deg; k++) {
|
|
128
|
+
off += kstep;
|
|
129
|
+
res = res * s + c[off];
|
|
130
|
+
}
|
|
131
|
+
out[n * L + q] = res;
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
const m = mult;
|
|
135
|
+
for (let n = 0; n < ndim; n++) {
|
|
136
|
+
let off = start + n;
|
|
137
|
+
let res = c[off] * m[0];
|
|
138
|
+
for (let k = 1; k <= effDeg; k++) {
|
|
139
|
+
off += kstep;
|
|
140
|
+
res = res * s + c[off] * m[k];
|
|
141
|
+
}
|
|
142
|
+
out[n * L + q] = res;
|
|
143
|
+
}
|
|
122
144
|
}
|
|
123
145
|
}
|
|
124
146
|
return out;
|
|
125
147
|
}
|
|
126
148
|
};
|
|
149
|
+
function fallingFactorial(base, nu) {
|
|
150
|
+
let f = 1;
|
|
151
|
+
for (let t = 0; t < nu; t++) f *= base - t;
|
|
152
|
+
return f;
|
|
153
|
+
}
|
|
127
154
|
|
|
128
155
|
// src/umv.ts
|
|
129
156
|
function computeSmooth(traceR, traceQtw) {
|
|
@@ -155,9 +182,8 @@ var csapsjs = (function (exports) {
|
|
|
155
182
|
const s = smooth == null ? 0.5 : smooth;
|
|
156
183
|
return s / (s + (1 - s) * k);
|
|
157
184
|
}
|
|
158
|
-
function makeSpline(x,
|
|
185
|
+
function makeSpline(x, y, N, w, smooth, normalizedsmooth) {
|
|
159
186
|
const M = x.length;
|
|
160
|
-
const N = y2d.length;
|
|
161
187
|
const dx = new Float64Array(M - 1);
|
|
162
188
|
for (let i = 0; i < M - 1; i++) {
|
|
163
189
|
dx[i] = x[i + 1] - x[i];
|
|
@@ -165,18 +191,18 @@ var csapsjs = (function (exports) {
|
|
|
165
191
|
throw new Error("Items of 'xdata' must satisfy x1 < x2 < ... < xN.");
|
|
166
192
|
}
|
|
167
193
|
}
|
|
168
|
-
const
|
|
194
|
+
const md = M - 1;
|
|
195
|
+
const dydx = new Float64Array(N * md);
|
|
169
196
|
for (let n = 0; n < N; n++) {
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
for (let i = 0; i <
|
|
173
|
-
dydx[n] = row;
|
|
197
|
+
const yb = n * M;
|
|
198
|
+
const db = n * md;
|
|
199
|
+
for (let i = 0; i < md; i++) dydx[db + i] = (y[yb + i + 1] - y[yb + i]) / dx[i];
|
|
174
200
|
}
|
|
175
201
|
if (M === 2) {
|
|
176
202
|
const c2 = new Float64Array(2 * 1 * N);
|
|
177
203
|
for (let n = 0; n < N; n++) {
|
|
178
|
-
c2[0 * N + n] = dydx[n]
|
|
179
|
-
c2[1 * N + n] =
|
|
204
|
+
c2[0 * N + n] = dydx[n * md];
|
|
205
|
+
c2[1 * N + n] = y[n * M];
|
|
180
206
|
}
|
|
181
207
|
return { pp: new PPoly(c2, Float64Array.from(x), 2, 1, N), smooth: 1 };
|
|
182
208
|
}
|
|
@@ -224,44 +250,63 @@ var csapsjs = (function (exports) {
|
|
|
224
250
|
}
|
|
225
251
|
const B = new Float64Array(m * N);
|
|
226
252
|
for (let i = 0; i < m; i++) {
|
|
227
|
-
for (let n = 0; n < N; n++)
|
|
253
|
+
for (let n = 0; n < N; n++) {
|
|
254
|
+
const db = n * md + i;
|
|
255
|
+
B[i * N + n] = dydx[db + 1] - dydx[db];
|
|
256
|
+
}
|
|
228
257
|
}
|
|
229
258
|
const U = ldltBandSolve(m, 2, lower, B, N);
|
|
230
|
-
const
|
|
259
|
+
const uFull = new Float64Array(M * N);
|
|
260
|
+
for (let i = 1; i < M - 1; i++) {
|
|
261
|
+
const src = (i - 1) * N;
|
|
262
|
+
const dst = i * N;
|
|
263
|
+
for (let n = 0; n < N; n++) uFull[dst + n] = U[src + n];
|
|
264
|
+
}
|
|
231
265
|
const d1 = new Float64Array((M - 1) * N);
|
|
232
266
|
for (let i = 0; i < M - 1; i++) {
|
|
233
267
|
const inv = dr[i];
|
|
234
|
-
|
|
268
|
+
const a = i * N;
|
|
269
|
+
const b = a + N;
|
|
270
|
+
for (let n = 0; n < N; n++) d1[a + n] = (uFull[b + n] - uFull[a + n]) * inv;
|
|
235
271
|
}
|
|
236
|
-
const d1At = (r, n) => r === 0 || r === M ? 0 : d1[(r - 1) * N + n];
|
|
237
272
|
const d2 = new Float64Array(M * N);
|
|
238
|
-
|
|
239
|
-
|
|
273
|
+
const lastD1 = (M - 2) * N;
|
|
274
|
+
const lastD2 = (M - 1) * N;
|
|
275
|
+
for (let n = 0; n < N; n++) {
|
|
276
|
+
d2[n] = d1[n];
|
|
277
|
+
d2[lastD2 + n] = -d1[lastD1 + n];
|
|
278
|
+
}
|
|
279
|
+
for (let i = 1; i < M - 1; i++) {
|
|
280
|
+
const di = i * N;
|
|
281
|
+
const dim1 = di - N;
|
|
282
|
+
for (let n = 0; n < N; n++) d2[di + n] = d1[di + n] - d1[dim1 + n];
|
|
240
283
|
}
|
|
241
284
|
const yi = new Float64Array(M * N);
|
|
242
285
|
for (let i = 0; i < M; i++) {
|
|
243
286
|
const f = pp6 * iw[i];
|
|
244
|
-
|
|
287
|
+
const row = i * N;
|
|
288
|
+
for (let n = 0; n < N; n++) yi[row + n] = y[n * M + i] - f * d2[row + n];
|
|
245
289
|
}
|
|
246
|
-
const puAt = (r, n) => r === 0 || r === M - 1 ? 0 : p * U[(r - 1) * N + n];
|
|
247
290
|
const pieces = M - 1;
|
|
248
291
|
const c = new Float64Array(4 * pieces * N);
|
|
292
|
+
const o1 = pieces * N;
|
|
293
|
+
const o2 = 2 * pieces * N;
|
|
294
|
+
const o3 = 3 * pieces * N;
|
|
249
295
|
for (let i = 0; i < pieces; i++) {
|
|
250
296
|
const h = dx[i];
|
|
251
297
|
const invh = dr[i];
|
|
298
|
+
const ri = i * N;
|
|
299
|
+
const ri1 = ri + N;
|
|
252
300
|
for (let n = 0; n < N; n++) {
|
|
253
|
-
const pu0 =
|
|
254
|
-
const pu1 =
|
|
255
|
-
const yi0 = yi[
|
|
256
|
-
const yi1 = yi[
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
c[
|
|
262
|
-
c[(1 * pieces + i) * N + n] = c2;
|
|
263
|
-
c[(2 * pieces + i) * N + n] = c3;
|
|
264
|
-
c[(3 * pieces + i) * N + n] = c4;
|
|
301
|
+
const pu0 = p * uFull[ri + n];
|
|
302
|
+
const pu1 = p * uFull[ri1 + n];
|
|
303
|
+
const yi0 = yi[ri + n];
|
|
304
|
+
const yi1 = yi[ri1 + n];
|
|
305
|
+
const ci = ri + n;
|
|
306
|
+
c[ci] = (pu1 - pu0) * invh;
|
|
307
|
+
c[o1 + ci] = 3 * pu0;
|
|
308
|
+
c[o2 + ci] = (yi1 - yi0) * invh - h * (2 * pu0 + pu1);
|
|
309
|
+
c[o3 + ci] = yi0;
|
|
265
310
|
}
|
|
266
311
|
}
|
|
267
312
|
return { pp: new PPoly(c, Float64Array.from(x), 4, pieces, N), smooth: p };
|
|
@@ -273,36 +318,44 @@ var csapsjs = (function (exports) {
|
|
|
273
318
|
const x = toFloat64(xdata);
|
|
274
319
|
const M = x.length;
|
|
275
320
|
if (x.length < 2) throw new Error("'xdata' must contain at least 2 data points.");
|
|
276
|
-
let
|
|
321
|
+
let y;
|
|
322
|
+
let N;
|
|
277
323
|
let isVector;
|
|
278
324
|
let transposed = false;
|
|
279
325
|
const first = ydata[0];
|
|
280
326
|
if (Array.isArray(first) || first instanceof Float64Array) {
|
|
281
|
-
const
|
|
282
|
-
const R =
|
|
283
|
-
const C =
|
|
327
|
+
const yin = ydata;
|
|
328
|
+
const R = yin.length;
|
|
329
|
+
const C = yin[0].length;
|
|
284
330
|
const ndimY = 2;
|
|
285
331
|
const ax = axis < 0 ? ndimY + axis : axis;
|
|
286
332
|
if (ax === 1) {
|
|
287
333
|
if (C !== M) throw new Error(`'ydata' shape[${ax}] (${C}) must equal 'xdata' size (${M}).`);
|
|
288
|
-
|
|
334
|
+
N = R;
|
|
335
|
+
y = new Float64Array(N * M);
|
|
336
|
+
for (let n = 0; n < N; n++) {
|
|
337
|
+
const row = yin[n];
|
|
338
|
+
const base = n * M;
|
|
339
|
+
for (let i = 0; i < M; i++) y[base + i] = row[i];
|
|
340
|
+
}
|
|
289
341
|
} else if (ax === 0) {
|
|
290
342
|
if (R !== M) throw new Error(`'ydata' shape[${ax}] (${R}) must equal 'xdata' size (${M}).`);
|
|
291
343
|
transposed = true;
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
344
|
+
N = C;
|
|
345
|
+
y = new Float64Array(N * M);
|
|
346
|
+
for (let i = 0; i < M; i++) {
|
|
347
|
+
const row = yin[i];
|
|
348
|
+
for (let n = 0; n < N; n++) y[n * M + i] = row[n];
|
|
297
349
|
}
|
|
298
350
|
} else {
|
|
299
351
|
throw new Error(`Unsupported axis ${axis} for 2-D ydata.`);
|
|
300
352
|
}
|
|
301
353
|
isVector = false;
|
|
302
354
|
} else {
|
|
303
|
-
const
|
|
304
|
-
if (
|
|
305
|
-
|
|
355
|
+
const yin = ydata;
|
|
356
|
+
if (yin.length !== M) throw new Error(`'ydata' size (${yin.length}) must equal 'xdata' size (${M}).`);
|
|
357
|
+
N = 1;
|
|
358
|
+
y = toFloat64(yin);
|
|
306
359
|
isVector = true;
|
|
307
360
|
}
|
|
308
361
|
let w;
|
|
@@ -312,7 +365,6 @@ var csapsjs = (function (exports) {
|
|
|
312
365
|
w = toFloat64(weights);
|
|
313
366
|
if (w.length !== M) throw new Error("Weights vector size must equal xdata size.");
|
|
314
367
|
}
|
|
315
|
-
const N = y2d.length;
|
|
316
368
|
const restore = (flat, L) => {
|
|
317
369
|
if (isVector) {
|
|
318
370
|
const out2 = new Array(L);
|
|
@@ -336,13 +388,13 @@ var csapsjs = (function (exports) {
|
|
|
336
388
|
}
|
|
337
389
|
return out;
|
|
338
390
|
};
|
|
339
|
-
return { x,
|
|
391
|
+
return { x, y, N, w, restore };
|
|
340
392
|
}
|
|
341
393
|
var CubicSmoothingSpline = class {
|
|
342
394
|
constructor(xdata, ydata, options = {}) {
|
|
343
395
|
const { weights, smooth = null, axis = -1, normalizedsmooth = false } = options;
|
|
344
396
|
const prep = prepareUnivariate(xdata, ydata, weights, axis);
|
|
345
|
-
const res = makeSpline(prep.x, prep.
|
|
397
|
+
const res = makeSpline(prep.x, prep.y, prep.N, prep.w, smooth ?? null, normalizedsmooth);
|
|
346
398
|
this.pp = res.pp;
|
|
347
399
|
this.smooth = res.smooth;
|
|
348
400
|
this.restore = prep.restore;
|
|
@@ -392,17 +444,19 @@ var csapsjs = (function (exports) {
|
|
|
392
444
|
const d = this.shape.length;
|
|
393
445
|
const newShape = perm.map((axis) => this.shape[axis]);
|
|
394
446
|
const oldStrides = cStrides(this.shape);
|
|
395
|
-
const
|
|
447
|
+
const ps = perm.map((axis) => oldStrides[axis]);
|
|
396
448
|
const total = this.data.length;
|
|
449
|
+
const src = this.data;
|
|
397
450
|
const out = new Float64Array(total);
|
|
398
451
|
const idx = new Array(d).fill(0);
|
|
452
|
+
let off = 0;
|
|
399
453
|
for (let pos = 0; pos < total; pos++) {
|
|
400
|
-
|
|
401
|
-
for (let a = 0; a < d; a++) off += idx[a] * permutedStrides[a];
|
|
402
|
-
out[pos] = this.data[off];
|
|
454
|
+
out[pos] = src[off];
|
|
403
455
|
for (let a = d - 1; a >= 0; a--) {
|
|
456
|
+
off += ps[a];
|
|
404
457
|
if (++idx[a] < newShape[a]) break;
|
|
405
458
|
idx[a] = 0;
|
|
459
|
+
off -= ps[a] * newShape[a];
|
|
406
460
|
}
|
|
407
461
|
}
|
|
408
462
|
return new _NdArray(out, newShape);
|
|
@@ -484,15 +538,8 @@ var csapsjs = (function (exports) {
|
|
|
484
538
|
const lastSize = shape[shape.length - 1];
|
|
485
539
|
const total = coeffs.data.length;
|
|
486
540
|
const Nrest = total / lastSize;
|
|
487
|
-
const y2d = new Array(Nrest);
|
|
488
|
-
for (let n = 0; n < Nrest; n++) {
|
|
489
|
-
const row = new Array(lastSize);
|
|
490
|
-
const base = n * lastSize;
|
|
491
|
-
for (let col = 0; col < lastSize; col++) row[col] = coeffs.data[base + col];
|
|
492
|
-
y2d[n] = row;
|
|
493
|
-
}
|
|
494
541
|
const w = weights[i] ?? new Float64Array(lastSize).fill(1);
|
|
495
|
-
const res = makeSpline(xs[i],
|
|
542
|
+
const res = makeSpline(xs[i], coeffs.data, Nrest, w, smooth[i], normalizedsmooth);
|
|
496
543
|
const order = res.pp.order;
|
|
497
544
|
const pcs = res.pp.pieces;
|
|
498
545
|
orders[i] = order;
|