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