@nirs4all/methods 1.0.17 → 1.1.0
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/README.md +37 -2
- package/dist/estimatorRoles.d.ts +139 -0
- package/dist/estimatorRoles.js +531 -0
- package/dist/estimatorRolesGenerated.d.ts +4711 -0
- package/dist/estimatorRolesGenerated.js +3825 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/methodResult.d.ts +2 -0
- package/dist/methodResult.js +33 -1
- package/dist/model.d.ts +29 -1
- package/dist/model.js +69 -3
- package/dist/n4m.js +1 -1
- package/dist/n4m.wasm +0 -0
- package/dist/nativeAugmentation.d.ts +29 -0
- package/dist/nativeAugmentation.js +49 -0
- package/dist/nativeModel.d.ts +17 -0
- package/dist/nativeModel.js +100 -0
- package/dist/nativePreprocessingPipeline.d.ts +42 -0
- package/dist/nativePreprocessingPipeline.js +246 -0
- package/dist/nativeSplitter.d.ts +23 -0
- package/dist/nativeSplitter.js +116 -0
- package/dist/selection.d.ts +6 -0
- package/dist/selection.js +245 -0
- package/dist/types.d.ts +14 -13
- package/dist/types.js +14 -13
- package/package.json +3 -3
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
// SPDX-License-Identifier: CECILL-2.1
|
|
2
|
+
// Generic native estimator roles (ABI 2.13).
|
|
3
|
+
//
|
|
4
|
+
// Every class in estimatorRolesGenerated.ts extends NativeEstimator and
|
|
5
|
+
// implements exactly the role interfaces its native method declares
|
|
6
|
+
// (Regressor, Transformer, ...). Parameters, defaults, required inputs,
|
|
7
|
+
// fitting and the portable N4ME state are native; this file marshals only.
|
|
8
|
+
import { checkStatus, getModule, makeMatrixView } from "./ffi.js";
|
|
9
|
+
// n4m_fit_inputs_v1_t on wasm32 (pointers 4 bytes, int64 8-aligned); checked
|
|
10
|
+
// against offsetof() of the C header when the layout was written.
|
|
11
|
+
const FIT_INPUTS_SIZE = 120;
|
|
12
|
+
const OFF = {
|
|
13
|
+
X: 4, Y: 8, labels: 12, nLabels: 16, sampleWeight: 24, nSampleWeight: 32, groups: 40, nGroups: 48,
|
|
14
|
+
featureGroups: 56, nFeatureGroups: 64, blocks: 72, nBlocks: 80, axis: 88,
|
|
15
|
+
nAxis: 96, XTarget: 104, foldIds: 108, nFoldIds: 112,
|
|
16
|
+
};
|
|
17
|
+
/** Runs `fn` with a fresh native context, destroyed afterwards. */
|
|
18
|
+
function withContext(fn) {
|
|
19
|
+
const m = getModule();
|
|
20
|
+
const out = m._malloc(4);
|
|
21
|
+
try {
|
|
22
|
+
m.setValue(out, 0, "i32");
|
|
23
|
+
checkStatus(m.ccall("n4m_context_create", "number", ["number"], [out]));
|
|
24
|
+
const ctx = m.getValue(out, "i32");
|
|
25
|
+
try {
|
|
26
|
+
return fn(ctx);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
m.ccall("n4m_context_destroy", null, ["number"], [ctx]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
m._free(out);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function readI64(ptr) {
|
|
37
|
+
const m = getModule();
|
|
38
|
+
return Number(m.getValue(ptr, "i64"));
|
|
39
|
+
}
|
|
40
|
+
function allocF64(values) {
|
|
41
|
+
const m = getModule();
|
|
42
|
+
const ptr = m._malloc(Math.max(1, values.length) * 8);
|
|
43
|
+
m.HEAPF64.set(values instanceof Float64Array ? values : Float64Array.from(values), ptr / 8);
|
|
44
|
+
return { ptr, free: () => m._free(ptr) };
|
|
45
|
+
}
|
|
46
|
+
function allocI64(values) {
|
|
47
|
+
const m = getModule();
|
|
48
|
+
const ptr = m._malloc(Math.max(1, values.length) * 8);
|
|
49
|
+
values.forEach((v, i) => m.setValue(ptr + 8 * i, BigInt(v), "i64"));
|
|
50
|
+
return { ptr, free: () => m._free(ptr) };
|
|
51
|
+
}
|
|
52
|
+
const registry = new Map();
|
|
53
|
+
function cString(s) {
|
|
54
|
+
const m = getModule();
|
|
55
|
+
const n = m.lengthBytesUTF8(s) + 1;
|
|
56
|
+
const ptr = m._malloc(n);
|
|
57
|
+
m.stringToUTF8(s, ptr, n);
|
|
58
|
+
return { ptr, free: () => m._free(ptr) };
|
|
59
|
+
}
|
|
60
|
+
/** Validated native parameters of a method; the caller destroys them. */
|
|
61
|
+
function nativeParams(ctx, method) {
|
|
62
|
+
const m = getModule();
|
|
63
|
+
const indexPtr = m._malloc(4);
|
|
64
|
+
const out = m._malloc(4);
|
|
65
|
+
const allocs = [];
|
|
66
|
+
const id = cString(method.methodId);
|
|
67
|
+
allocs.push(id);
|
|
68
|
+
try {
|
|
69
|
+
checkStatus(m.ccall("n4m_method_find", "number", ["number", "number"], [id.ptr, indexPtr]));
|
|
70
|
+
m.setValue(out, 0, "i32");
|
|
71
|
+
checkStatus(m.ccall("n4m_params_create", "number", ["number", "number", "number"], [ctx, m.getValue(indexPtr, "i32"), out]), ctx);
|
|
72
|
+
const params = m.getValue(out, "i32");
|
|
73
|
+
try {
|
|
74
|
+
for (const [name, value] of Object.entries(method.params)) {
|
|
75
|
+
if (value === undefined)
|
|
76
|
+
continue;
|
|
77
|
+
const type = method.paramTypes[name];
|
|
78
|
+
if (type === undefined)
|
|
79
|
+
throw new Error(`${method.methodId}: unknown parameter '${name}'`);
|
|
80
|
+
const key = cString(name);
|
|
81
|
+
allocs.push(key);
|
|
82
|
+
let status;
|
|
83
|
+
if (type === "int") {
|
|
84
|
+
status = m.ccall("n4m_params_set_int", "number", ["number", "number", "i64"], [params, key.ptr, BigInt(value)]);
|
|
85
|
+
}
|
|
86
|
+
else if (type === "double") {
|
|
87
|
+
status = m.ccall("n4m_params_set_double", "number", ["number", "number", "number"], [params, key.ptr, value]);
|
|
88
|
+
}
|
|
89
|
+
else if (type === "bool") {
|
|
90
|
+
status = m.ccall("n4m_params_set_bool", "number", ["number", "number", "number"], [params, key.ptr, value ? 1 : 0]);
|
|
91
|
+
}
|
|
92
|
+
else if (type === "enum") {
|
|
93
|
+
const choice = cString(String(value));
|
|
94
|
+
allocs.push(choice);
|
|
95
|
+
status = m.ccall("n4m_params_set_enum", "number", ["number", "number", "number"], [params, key.ptr, choice.ptr]);
|
|
96
|
+
}
|
|
97
|
+
else if (type === "int_array") {
|
|
98
|
+
const arr = allocI64(value);
|
|
99
|
+
allocs.push(arr);
|
|
100
|
+
status = m.ccall("n4m_params_set_int_array", "number", ["number", "number", "number", "i64"], [params, key.ptr, arr.ptr, BigInt(value.length)]);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const arr = allocF64(value);
|
|
104
|
+
allocs.push(arr);
|
|
105
|
+
status = m.ccall("n4m_params_set_double_array", "number", ["number", "number", "number", "i64"], [params, key.ptr, arr.ptr, BigInt(value.length)]);
|
|
106
|
+
}
|
|
107
|
+
if (status !== 0)
|
|
108
|
+
throw new Error(`${method.methodId}: invalid value for parameter '${name}'`);
|
|
109
|
+
}
|
|
110
|
+
checkStatus(m.ccall("n4m_params_validate", "number", ["number", "number"], [ctx, params]), ctx);
|
|
111
|
+
return params;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
m.ccall("n4m_params_destroy", null, ["number"], [params]);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
allocs.forEach((a) => a.free());
|
|
120
|
+
m._free(indexPtr);
|
|
121
|
+
m._free(out);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Runs `fn` over an n4m_fit_inputs_v1_t built from the given data. */
|
|
125
|
+
function withFitInputs(X, y, labels, inputs, fn) {
|
|
126
|
+
const m = getModule();
|
|
127
|
+
const allocs = [];
|
|
128
|
+
const hold = (a) => (allocs.push(a), a.ptr);
|
|
129
|
+
const struct = m._malloc(FIT_INPUTS_SIZE);
|
|
130
|
+
try {
|
|
131
|
+
m.HEAPU8.fill(0, struct, struct + FIT_INPUTS_SIZE);
|
|
132
|
+
m.setValue(struct, FIT_INPUTS_SIZE, "i32");
|
|
133
|
+
const xv = makeMatrixView(X.data, X.rows, X.cols);
|
|
134
|
+
allocs.push({ ptr: xv.viewPtr, free: xv.free });
|
|
135
|
+
m.setValue(struct + OFF.X, xv.viewPtr, "i32");
|
|
136
|
+
const setArray = (ptrOff, lenOff, a, n) => {
|
|
137
|
+
m.setValue(struct + ptrOff, hold(a), "i32");
|
|
138
|
+
m.setValue(struct + lenOff, BigInt(n), "i64");
|
|
139
|
+
};
|
|
140
|
+
if (y !== undefined && labels) {
|
|
141
|
+
const ids = Array.from(y);
|
|
142
|
+
setArray(OFF.labels, OFF.nLabels, allocI64(ids), ids.length);
|
|
143
|
+
}
|
|
144
|
+
else if (y !== undefined) {
|
|
145
|
+
const ym = "data" in y ? y
|
|
146
|
+
: { data: Float64Array.from(y), rows: y.length, cols: 1 };
|
|
147
|
+
const yv = makeMatrixView(ym.data, ym.rows, ym.cols);
|
|
148
|
+
allocs.push({ ptr: yv.viewPtr, free: yv.free });
|
|
149
|
+
m.setValue(struct + OFF.Y, yv.viewPtr, "i32");
|
|
150
|
+
}
|
|
151
|
+
if (inputs.sampleWeight)
|
|
152
|
+
setArray(OFF.sampleWeight, OFF.nSampleWeight, allocF64(inputs.sampleWeight), inputs.sampleWeight.length);
|
|
153
|
+
if (inputs.groups)
|
|
154
|
+
setArray(OFF.groups, OFF.nGroups, allocI64(inputs.groups), inputs.groups.length);
|
|
155
|
+
if (inputs.featureGroups)
|
|
156
|
+
setArray(OFF.featureGroups, OFF.nFeatureGroups, allocI64(inputs.featureGroups), inputs.featureGroups.length);
|
|
157
|
+
if (inputs.blocks)
|
|
158
|
+
setArray(OFF.blocks, OFF.nBlocks, allocI64(inputs.blocks), inputs.blocks.length);
|
|
159
|
+
if (inputs.axis)
|
|
160
|
+
setArray(OFF.axis, OFF.nAxis, allocF64(inputs.axis), inputs.axis.length);
|
|
161
|
+
if (inputs.foldIds)
|
|
162
|
+
setArray(OFF.foldIds, OFF.nFoldIds, allocI64(inputs.foldIds), inputs.foldIds.length);
|
|
163
|
+
if (inputs.XTarget) {
|
|
164
|
+
const tv = makeMatrixView(inputs.XTarget.data, inputs.XTarget.rows, inputs.XTarget.cols);
|
|
165
|
+
allocs.push({ ptr: tv.viewPtr, free: tv.free });
|
|
166
|
+
m.setValue(struct + OFF.XTarget, tv.viewPtr, "i32");
|
|
167
|
+
}
|
|
168
|
+
return fn(struct, hold);
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
allocs.forEach((a) => a.free());
|
|
172
|
+
m._free(struct);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** Parameters of one catalog method (estimator or procedure). */
|
|
176
|
+
export class NativeMethod {
|
|
177
|
+
/** Explicit parameter values (unset ones take the native default). */
|
|
178
|
+
params = {};
|
|
179
|
+
/** Registers a generated class so fromN4me() and methodClass() find it. */
|
|
180
|
+
static register(methodId, cls) {
|
|
181
|
+
registry.set(methodId, cls);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** The native manifest: every method's roles, node kinds, fit inputs and typed parameters. */
|
|
185
|
+
export function manifest() {
|
|
186
|
+
const m = getModule();
|
|
187
|
+
const sizePtr = m._malloc(4);
|
|
188
|
+
try {
|
|
189
|
+
checkStatus(m.ccall("n4m_method_manifest_json", "number", ["number", "number", "number"], [0, 0, sizePtr]));
|
|
190
|
+
const size = m.getValue(sizePtr, "i32");
|
|
191
|
+
const buf = m._malloc(Math.max(1, size));
|
|
192
|
+
try {
|
|
193
|
+
checkStatus(m.ccall("n4m_method_manifest_json", "number", ["number", "number", "number"], [buf, size, sizePtr]));
|
|
194
|
+
return JSON.parse(new TextDecoder().decode(m.HEAPU8.subarray(buf, buf + size)));
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
m._free(buf);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
m._free(sizePtr);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/** The generated class of a catalog method id. */
|
|
205
|
+
export function methodClass(methodId) {
|
|
206
|
+
const cls = registry.get(methodId);
|
|
207
|
+
if (cls === undefined)
|
|
208
|
+
throw new Error(`no n4m role class for '${methodId}'`);
|
|
209
|
+
return cls;
|
|
210
|
+
}
|
|
211
|
+
/** Base of every generated estimator: parameters, fit and N4ME state. */
|
|
212
|
+
export class NativeEstimator extends NativeMethod {
|
|
213
|
+
/** True when the fit target is class labels (classifiers). */
|
|
214
|
+
labelTarget = false;
|
|
215
|
+
ptr = 0;
|
|
216
|
+
get fitted() {
|
|
217
|
+
return this.ptr !== 0;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Fit on row-major X and the target: responses for a regressor (a vector
|
|
221
|
+
* or a row-major matrix), integer class ids for a classifier. Returns this.
|
|
222
|
+
*/
|
|
223
|
+
fit(X, y, inputs = {}) {
|
|
224
|
+
const m = getModule();
|
|
225
|
+
const est = withFitInputs(X, y, this.labelTarget, inputs, (struct, hold) => withContext((ctx) => {
|
|
226
|
+
const params = nativeParams(ctx, this);
|
|
227
|
+
const out = m._malloc(4);
|
|
228
|
+
try {
|
|
229
|
+
m.setValue(out, 0, "i32");
|
|
230
|
+
const idPtr = hold(cString(this.methodId));
|
|
231
|
+
checkStatus(m.ccall("n4m_estimator_create", "number", ["number", "number", "number", "number"], [ctx, idPtr, params, out]), ctx);
|
|
232
|
+
const handle = m.getValue(out, "i32");
|
|
233
|
+
const status = m.ccall("n4m_estimator_fit", "number", ["number", "number", "number"], [ctx, handle, struct]);
|
|
234
|
+
if (status !== 0) {
|
|
235
|
+
m.ccall("n4m_estimator_destroy", null, ["number"], [handle]);
|
|
236
|
+
checkStatus(status, ctx);
|
|
237
|
+
}
|
|
238
|
+
return handle;
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
m._free(out);
|
|
242
|
+
m.ccall("n4m_params_destroy", null, ["number"], [params]);
|
|
243
|
+
}
|
|
244
|
+
}));
|
|
245
|
+
this.dispose();
|
|
246
|
+
this.ptr = est;
|
|
247
|
+
return this;
|
|
248
|
+
}
|
|
249
|
+
/** Portable fitted state (N4ME bytes), readable by every n4m binding. */
|
|
250
|
+
toN4me() {
|
|
251
|
+
const m = getModule();
|
|
252
|
+
const handle = this.handle();
|
|
253
|
+
return withContext((ctx) => {
|
|
254
|
+
const sizePtr = m._malloc(4);
|
|
255
|
+
try {
|
|
256
|
+
checkStatus(m.ccall("n4m_estimator_export_size", "number", ["number", "number", "number", "number"], [ctx, handle, 1, sizePtr]), ctx);
|
|
257
|
+
const size = m.getValue(sizePtr, "i32");
|
|
258
|
+
const buf = m._malloc(Math.max(1, size));
|
|
259
|
+
try {
|
|
260
|
+
checkStatus(m.ccall("n4m_estimator_export_to_buffer", "number", ["number", "number", "number", "number", "number", "number"], [ctx, handle, 1, buf, size, sizePtr]), ctx);
|
|
261
|
+
return m.HEAPU8.slice(buf, buf + m.getValue(sizePtr, "i32"));
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
m._free(buf);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
m._free(sizePtr);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/** Rebuilds a fitted estimator of the class registered for its method. */
|
|
273
|
+
static fromN4me(payload) {
|
|
274
|
+
const m = getModule();
|
|
275
|
+
const data = m._malloc(Math.max(1, payload.byteLength));
|
|
276
|
+
const out = m._malloc(4);
|
|
277
|
+
try {
|
|
278
|
+
m.HEAPU8.set(payload, data);
|
|
279
|
+
m.setValue(out, 0, "i32");
|
|
280
|
+
const handle = withContext((ctx) => {
|
|
281
|
+
checkStatus(m.ccall("n4m_estimator_import_from_buffer", "number", ["number", "number", "number", "number"], [ctx, data, payload.byteLength, out]), ctx);
|
|
282
|
+
return m.getValue(out, "i32");
|
|
283
|
+
});
|
|
284
|
+
const cls = registry.get(NativeEstimator.methodIdOf(handle));
|
|
285
|
+
if (cls === undefined || !(cls.prototype instanceof NativeEstimator)) {
|
|
286
|
+
m.ccall("n4m_estimator_destroy", null, ["number"], [handle]);
|
|
287
|
+
throw new Error("no JS class registered for this N4ME method");
|
|
288
|
+
}
|
|
289
|
+
const est = new cls();
|
|
290
|
+
est.ptr = handle;
|
|
291
|
+
return est;
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
m._free(data);
|
|
295
|
+
m._free(out);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/** Releases the native estimator. */
|
|
299
|
+
dispose() {
|
|
300
|
+
if (this.ptr !== 0) {
|
|
301
|
+
getModule().ccall("n4m_estimator_destroy", null, ["number"], [this.ptr]);
|
|
302
|
+
this.ptr = 0;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
predictMatrix(X) {
|
|
306
|
+
return this.matrixOp("n4m_estimator_predict", "n4m_estimator_n_outputs", X);
|
|
307
|
+
}
|
|
308
|
+
transformMatrix(X) {
|
|
309
|
+
return this.matrixOp("n4m_estimator_transform", "n4m_estimator_transform_cols", X);
|
|
310
|
+
}
|
|
311
|
+
decisionMatrix(X) {
|
|
312
|
+
return this.matrixOp("n4m_estimator_decision_function", "n4m_estimator_n_outputs", X);
|
|
313
|
+
}
|
|
314
|
+
probaMatrix(X) {
|
|
315
|
+
return this.matrixOp("n4m_estimator_predict_proba", "n4m_estimator_n_outputs", X);
|
|
316
|
+
}
|
|
317
|
+
labelArray(X) {
|
|
318
|
+
const m = getModule();
|
|
319
|
+
const handle = this.handle();
|
|
320
|
+
const xv = makeMatrixView(X.data, X.rows, X.cols);
|
|
321
|
+
const buf = m._malloc(Math.max(1, X.rows) * 8);
|
|
322
|
+
try {
|
|
323
|
+
withContext((ctx) => checkStatus(m.ccall("n4m_estimator_predict_labels", "number", ["number", "number", "number", "number", "i64"], [ctx, handle, xv.viewPtr, buf, BigInt(X.rows)]), ctx));
|
|
324
|
+
return Array.from({ length: X.rows }, (_, i) => readI64(buf + 8 * i));
|
|
325
|
+
}
|
|
326
|
+
finally {
|
|
327
|
+
xv.free();
|
|
328
|
+
m._free(buf);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
maskArray(X, y) {
|
|
332
|
+
const m = getModule();
|
|
333
|
+
const handle = this.handle();
|
|
334
|
+
const xv = makeMatrixView(X.data, X.rows, X.cols);
|
|
335
|
+
const yv = y === undefined ? undefined
|
|
336
|
+
: makeMatrixView(Float64Array.from(y), X.rows, 1);
|
|
337
|
+
const buf = m._malloc(Math.max(1, X.rows));
|
|
338
|
+
try {
|
|
339
|
+
withContext((ctx) => checkStatus(m.ccall("n4m_estimator_apply_mask", "number", ["number", "number", "number", "number", "number", "i64"], [ctx, handle, xv.viewPtr, yv ? yv.viewPtr : 0, buf, BigInt(X.rows)]), ctx));
|
|
340
|
+
return Array.from(m.HEAPU8.subarray(buf, buf + X.rows), (v) => v !== 0);
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
xv.free();
|
|
344
|
+
yv?.free();
|
|
345
|
+
m._free(buf);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
classArray() {
|
|
349
|
+
return this.indexArray("n4m_estimator_classes");
|
|
350
|
+
}
|
|
351
|
+
selectedIndexArray() {
|
|
352
|
+
return this.indexArray("n4m_estimator_selected_indices");
|
|
353
|
+
}
|
|
354
|
+
/** Reads a (handle, out, capacity, out_count) integer list. */
|
|
355
|
+
indexArray(symbol) {
|
|
356
|
+
const m = getModule();
|
|
357
|
+
const handle = this.handle();
|
|
358
|
+
const countPtr = m._malloc(8);
|
|
359
|
+
try {
|
|
360
|
+
checkStatus(m.ccall(symbol, "number", ["number", "number", "i64", "number"], [handle, 0, BigInt(0), countPtr]));
|
|
361
|
+
const count = readI64(countPtr);
|
|
362
|
+
const buf = m._malloc(Math.max(1, count) * 8);
|
|
363
|
+
try {
|
|
364
|
+
checkStatus(m.ccall(symbol, "number", ["number", "number", "i64", "number"], [handle, buf, BigInt(count), countPtr]));
|
|
365
|
+
return Array.from({ length: count }, (_, i) => readI64(buf + 8 * i));
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
m._free(buf);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
m._free(countPtr);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
matrixOp(symbol, widthSymbol, X) {
|
|
376
|
+
const m = getModule();
|
|
377
|
+
const handle = this.handle();
|
|
378
|
+
const widthPtr = m._malloc(8);
|
|
379
|
+
try {
|
|
380
|
+
checkStatus(m.ccall(widthSymbol, "number", ["number", "number"], [handle, widthPtr]));
|
|
381
|
+
const cols = readI64(widthPtr);
|
|
382
|
+
const xv = makeMatrixView(X.data, X.rows, X.cols);
|
|
383
|
+
const ov = makeMatrixView(new Float64Array(X.rows * cols), X.rows, cols);
|
|
384
|
+
try {
|
|
385
|
+
withContext((ctx) => checkStatus(m.ccall(symbol, "number", ["number", "number", "number", "number"], [ctx, handle, xv.viewPtr, ov.viewPtr]), ctx));
|
|
386
|
+
return { data: m.HEAPF64.slice(ov.dataPtr / 8, ov.dataPtr / 8 + X.rows * cols), rows: X.rows, cols };
|
|
387
|
+
}
|
|
388
|
+
finally {
|
|
389
|
+
xv.free();
|
|
390
|
+
ov.free();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
finally {
|
|
394
|
+
m._free(widthPtr);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
handle() {
|
|
398
|
+
if (this.ptr === 0)
|
|
399
|
+
throw new Error(`${this.methodId} is not fitted`);
|
|
400
|
+
return this.ptr;
|
|
401
|
+
}
|
|
402
|
+
static methodIdOf(handle) {
|
|
403
|
+
const m = getModule();
|
|
404
|
+
const indexPtr = m._malloc(4);
|
|
405
|
+
const capsPtr = m._malloc(8);
|
|
406
|
+
const info = m._malloc(72);
|
|
407
|
+
try {
|
|
408
|
+
checkStatus(m.ccall("n4m_estimator_info", "number", ["number", "number", "number"], [handle, indexPtr, capsPtr]));
|
|
409
|
+
m.HEAPU8.fill(0, info, info + 72);
|
|
410
|
+
m.setValue(info, 72, "i32");
|
|
411
|
+
checkStatus(m.ccall("n4m_method_info_v1", "number", ["number", "number"], [m.getValue(indexPtr, "i32"), info]));
|
|
412
|
+
return m.UTF8ToString(m.getValue(info + 8, "i32"));
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
m._free(indexPtr);
|
|
416
|
+
m._free(capsPtr);
|
|
417
|
+
m._free(info);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/** Base of the generated procedures: one native run, no fitted state. */
|
|
422
|
+
export class NativeProcedure extends NativeMethod {
|
|
423
|
+
runRaw(X, y, inputs, read) {
|
|
424
|
+
const m = getModule();
|
|
425
|
+
const result = withFitInputs(X, y, false, inputs, (struct, hold) => withContext((ctx) => {
|
|
426
|
+
const indexPtr = m._malloc(4);
|
|
427
|
+
const out = m._malloc(4);
|
|
428
|
+
const params = nativeParams(ctx, this);
|
|
429
|
+
try {
|
|
430
|
+
checkStatus(m.ccall("n4m_method_find", "number", ["number", "number"], [hold(cString(this.methodId)), indexPtr]));
|
|
431
|
+
m.setValue(out, 0, "i32");
|
|
432
|
+
checkStatus(m.ccall("n4m_procedure_run", "number", ["number", "number", "number", "number", "number"], [ctx, m.getValue(indexPtr, "i32"), params, struct, out]), ctx);
|
|
433
|
+
return m.getValue(out, "i32");
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
m.ccall("n4m_params_destroy", null, ["number"], [params]);
|
|
437
|
+
m._free(indexPtr);
|
|
438
|
+
m._free(out);
|
|
439
|
+
}
|
|
440
|
+
}));
|
|
441
|
+
try {
|
|
442
|
+
return read(result);
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
m.ccall("n4m_method_result_destroy", null, ["number"], [result]);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
splitFolds(X, y, groups) {
|
|
449
|
+
return this.runRaw(X, y, groups ? { groups } : {}, (result) => {
|
|
450
|
+
const m = getModule();
|
|
451
|
+
const scratch = m._malloc(32);
|
|
452
|
+
try {
|
|
453
|
+
checkStatus(m.ccall("n4m_method_result_get_n_folds", "number", ["number", "number"], [result, scratch]));
|
|
454
|
+
const n = m.getValue(scratch, "i32");
|
|
455
|
+
const folds = [];
|
|
456
|
+
for (let f = 0; f < n; ++f) {
|
|
457
|
+
checkStatus(m.ccall("n4m_method_result_get_fold", "number", ["number", "number", "number", "number", "number", "number"], [result, f, scratch, scratch + 8, scratch + 16, scratch + 24]));
|
|
458
|
+
const take = (ptrAt, lenAt) => {
|
|
459
|
+
const base = m.getValue(ptrAt, "i32");
|
|
460
|
+
return Array.from({ length: readI64(lenAt) }, (_, i) => readI64(base + 8 * i));
|
|
461
|
+
};
|
|
462
|
+
folds.push({ train: take(scratch, scratch + 8), test: take(scratch + 16, scratch + 24) });
|
|
463
|
+
}
|
|
464
|
+
return folds;
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
m._free(scratch);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
augmentMatrix(X, axis) {
|
|
472
|
+
return this.runRaw(X, undefined, axis ? { axis } : {}, (result) => readEntry(result, "X", 0));
|
|
473
|
+
}
|
|
474
|
+
augmentWithTargets(X, y, axis) {
|
|
475
|
+
return this.runRaw(X, y, axis ? { axis } : {}, (result) => ({
|
|
476
|
+
X: readEntry(result, "X", 0),
|
|
477
|
+
Y: readEntry(result, "Y", 0),
|
|
478
|
+
}));
|
|
479
|
+
}
|
|
480
|
+
runOutputs(X, y, inputs = {}) {
|
|
481
|
+
return this.runRaw(X, y, inputs, (result) => {
|
|
482
|
+
const m = getModule();
|
|
483
|
+
const scratch = m._malloc(8);
|
|
484
|
+
try {
|
|
485
|
+
checkStatus(m.ccall("n4m_method_result_entry_count", "number", ["number", "number"], [result, scratch]));
|
|
486
|
+
const count = m.getValue(scratch, "i32");
|
|
487
|
+
const out = {};
|
|
488
|
+
for (let i = 0; i < count; ++i) {
|
|
489
|
+
checkStatus(m.ccall("n4m_method_result_entry", "number", ["number", "number", "number", "number"], [result, i, scratch, scratch + 4]));
|
|
490
|
+
const name = m.UTF8ToString(m.getValue(scratch, "i32"));
|
|
491
|
+
out[name] = readEntry(result, name, m.getValue(scratch + 4, "i32"));
|
|
492
|
+
}
|
|
493
|
+
return out;
|
|
494
|
+
}
|
|
495
|
+
finally {
|
|
496
|
+
m._free(scratch);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
/** One named result entry (kinds of n4m_method_result_entry_kind_t). */
|
|
502
|
+
function readEntry(result, name, kind) {
|
|
503
|
+
const m = getModule();
|
|
504
|
+
const key = cString(name);
|
|
505
|
+
const scratch = m._malloc(24);
|
|
506
|
+
try {
|
|
507
|
+
if (kind === 0) {
|
|
508
|
+
checkStatus(m.ccall("n4m_method_result_get_double_matrix", "number", ["number", "number", "number", "number", "number"], [result, key.ptr, scratch, scratch + 8, scratch + 16]));
|
|
509
|
+
const rows = readI64(scratch + 8);
|
|
510
|
+
const cols = readI64(scratch + 16);
|
|
511
|
+
const data = m.getValue(scratch, "i32") / 8;
|
|
512
|
+
return { data: m.HEAPF64.slice(data, data + rows * cols), rows, cols };
|
|
513
|
+
}
|
|
514
|
+
if (kind === 3) {
|
|
515
|
+
checkStatus(m.ccall("n4m_method_result_get_scalar", "number", ["number", "number", "number"], [result, key.ptr, scratch]));
|
|
516
|
+
return m.getValue(scratch, "double");
|
|
517
|
+
}
|
|
518
|
+
if (kind === 1) {
|
|
519
|
+
checkStatus(m.ccall("n4m_method_result_get_int_vector", "number", ["number", "number", "number", "number"], [result, key.ptr, scratch, scratch + 8]));
|
|
520
|
+
const base = m.getValue(scratch, "i32");
|
|
521
|
+
return Array.from({ length: m.getValue(scratch + 8, "i32") }, (_, i) => m.getValue(base + 4 * i, "i32"));
|
|
522
|
+
}
|
|
523
|
+
checkStatus(m.ccall("n4m_method_result_get_int64_vector", "number", ["number", "number", "number", "number"], [result, key.ptr, scratch, scratch + 8]));
|
|
524
|
+
const base = m.getValue(scratch, "i32");
|
|
525
|
+
return Array.from({ length: readI64(scratch + 8) }, (_, i) => readI64(base + 8 * i));
|
|
526
|
+
}
|
|
527
|
+
finally {
|
|
528
|
+
key.free();
|
|
529
|
+
m._free(scratch);
|
|
530
|
+
}
|
|
531
|
+
}
|