tranfi 0.1.2 → 0.2.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/LICENSE +177 -0
- package/NOTICE +8 -0
- package/README.md +443 -51
- package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
- package/app/index.html +1 -1
- package/binding.gyp +55 -3
- package/csrc/arena.c +7 -5
- package/csrc/batch.c +818 -71
- package/csrc/buffer.c +84 -8
- package/csrc/cJSON.c +262 -19
- package/csrc/cJSON.h +17 -1
- package/csrc/codec_csv.c +1074 -181
- package/csrc/codec_jsonl.c +830 -118
- package/csrc/codec_table.c +108 -78
- package/csrc/codec_text.c +286 -68
- package/csrc/compiler.c +31 -3
- package/csrc/config.h +21 -0
- package/csrc/dsl.c +4722 -485
- package/csrc/expr.c +363 -55
- package/csrc/expr.h +2 -0
- package/csrc/internal.h +316 -27
- package/csrc/ir.c +65 -18
- package/csrc/ir.h +41 -0
- package/csrc/ir_schema.c +20 -5
- package/csrc/ir_serialize.c +68 -6
- package/csrc/ir_sql.c +796 -185
- package/csrc/ir_validate.c +462 -6
- package/csrc/json_path.c +210 -0
- package/csrc/main.c +879 -30
- package/csrc/memory_estimate.c +477 -0
- package/csrc/op_acf.c +171 -21
- package/csrc/op_across.c +477 -0
- package/csrc/op_anomaly.c +167 -32
- package/csrc/op_assert.c +761 -0
- package/csrc/op_bin.c +168 -29
- package/csrc/op_cast.c +383 -55
- package/csrc/op_clip.c +30 -19
- package/csrc/op_date_trunc.c +208 -34
- package/csrc/op_datetime.c +259 -77
- package/csrc/op_derive.c +65 -97
- package/csrc/op_diff.c +146 -30
- package/csrc/op_ewma.c +149 -30
- package/csrc/op_explode.c +124 -26
- package/csrc/op_fill_down.c +125 -53
- package/csrc/op_fill_null.c +176 -31
- package/csrc/op_filter.c +89 -40
- package/csrc/op_frequency.c +571 -43
- package/csrc/op_grep.c +36 -18
- package/csrc/op_group_agg.c +1790 -119
- package/csrc/op_hash.c +48 -15
- package/csrc/op_head.c +21 -86
- package/csrc/op_interpolate.c +268 -62
- package/csrc/op_join.c +2700 -182
- package/csrc/op_json_extract.c +227 -0
- package/csrc/op_json_filter.c +384 -0
- package/csrc/op_json_flatten.c +293 -0
- package/csrc/op_json_schema.c +503 -0
- package/csrc/op_label_encode.c +328 -53
- package/csrc/op_lag.c +181 -0
- package/csrc/op_lead.c +141 -89
- package/csrc/op_normalize.c +363 -79
- package/csrc/op_onehot.c +345 -73
- package/csrc/op_pivot.c +1546 -162
- package/csrc/op_quarantine.c +189 -0
- package/csrc/op_registry.c +2062 -166
- package/csrc/op_rename.c +41 -50
- package/csrc/op_replace.c +270 -118
- package/csrc/op_rleid.c +297 -0
- package/csrc/op_rowid.c +559 -0
- package/csrc/op_sample.c +80 -23
- package/csrc/op_schema.c +1341 -0
- package/csrc/op_schema_infer.c +252 -0
- package/csrc/op_select.c +265 -65
- package/csrc/op_set.c +3449 -0
- package/csrc/op_skip.c +30 -87
- package/csrc/op_sort.c +670 -124
- package/csrc/op_source_name.c +120 -0
- package/csrc/op_split.c +65 -28
- package/csrc/op_split_data.c +41 -9
- package/csrc/op_stack.c +178 -222
- package/csrc/op_stats.c +206 -110
- package/csrc/op_step.c +217 -55
- package/csrc/op_tail.c +21 -12
- package/csrc/op_tee.c +338 -0
- package/csrc/op_top.c +260 -53
- package/csrc/op_trim.c +48 -19
- package/csrc/op_unique.c +1193 -150
- package/csrc/op_unpivot.c +100 -66
- package/csrc/op_validate.c +601 -24
- package/csrc/op_window.c +492 -51
- package/csrc/path_policy.c +85 -0
- package/csrc/pipeline.c +872 -99
- package/csrc/recipes.c +3 -1
- package/csrc/report.c +73 -30
- package/csrc/selector.c +1097 -0
- package/csrc/size_utils.c +352 -0
- package/csrc/spill.c +317 -0
- package/csrc/spill.h +21 -0
- package/csrc/tranfi.h +169 -1
- package/csrc/transform.h +209 -0
- package/csrc/transform_api.c +2237 -0
- package/csrc/transform_categorical.c +923 -0
- package/csrc/transform_internal.h +472 -0
- package/csrc/transform_json.c +3812 -0
- package/csrc/transform_numeric.c +1966 -0
- package/csrc/transform_sha256.c +154 -0
- package/csrc/transform_wasm.h +162 -0
- package/csrc/transform_wasm_api.c +1373 -0
- package/csrc/wasm_api.c +70 -9
- package/napi_api.c +219 -11
- package/napi_transform.c +1648 -0
- package/napi_transform.h +8 -0
- package/package.json +27 -11
- package/scripts/install-native.js +76 -0
- package/scripts/prepack.js +64 -0
- package/scripts/sync-csrc.js +23 -0
- package/src/cli.js +81 -41
- package/src/engines/duckdb.js +45 -12
- package/src/index.js +661 -42
- package/src/memory_policy.js +411 -0
- package/src/native.js +1 -5
- package/src/pipeline.js +454 -31
- package/src/recipe_json.js +80 -0
- package/src/server.js +10 -8
- package/src/transform.js +403 -0
- package/src/transform_error.js +10 -0
- package/src/wasm.js +6 -4
- package/wasm/index.js +498 -10
- package/wasm/tranfi_core.js +0 -0
- package/wasm/transform.js +1156 -0
- package/wasm/worker.js +786 -0
- package/csrc/plan.c +0 -206
package/csrc/op_acf.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* op_acf.c — Autocorrelation function.
|
|
3
|
-
* Aggregate op: buffers
|
|
3
|
+
* Aggregate op: buffers numeric values, computes ACF for lags 0..N.
|
|
4
4
|
* Output: 2-column table (lag, acf).
|
|
5
5
|
*
|
|
6
6
|
* Config: {"column": "price", "lags": 20}
|
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
#include <string.h>
|
|
13
13
|
#include <stdio.h>
|
|
14
14
|
#include <math.h>
|
|
15
|
+
#include <limits.h>
|
|
16
|
+
|
|
17
|
+
typedef enum {
|
|
18
|
+
ACF_MISSING_ERROR,
|
|
19
|
+
ACF_MISSING_NULL,
|
|
20
|
+
ACF_MISSING_IGNORE
|
|
21
|
+
} acf_missing_policy;
|
|
22
|
+
|
|
23
|
+
typedef enum {
|
|
24
|
+
ACF_TYPE_FAIL,
|
|
25
|
+
ACF_TYPE_NULL
|
|
26
|
+
} acf_type_policy;
|
|
15
27
|
|
|
16
28
|
typedef struct {
|
|
17
29
|
char *column;
|
|
@@ -19,30 +31,112 @@ typedef struct {
|
|
|
19
31
|
double *values;
|
|
20
32
|
size_t n_values;
|
|
21
33
|
size_t cap_values;
|
|
34
|
+
int checked_schema;
|
|
35
|
+
int col_idx;
|
|
36
|
+
int ignore;
|
|
37
|
+
int force_null;
|
|
38
|
+
acf_missing_policy missing;
|
|
39
|
+
acf_type_policy on_type_error;
|
|
22
40
|
} acf_state;
|
|
23
41
|
|
|
42
|
+
static int acf_is_numeric(tf_type type) {
|
|
43
|
+
return type == TF_TYPE_INT64 || type == TF_TYPE_FLOAT64;
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
static double get_numeric(const tf_batch *b, size_t r, int ci) {
|
|
25
47
|
if (b->col_types[ci] == TF_TYPE_INT64) return (double)tf_batch_get_int64(b, r, ci);
|
|
26
48
|
if (b->col_types[ci] == TF_TYPE_FLOAT64) return tf_batch_get_float64(b, r, ci);
|
|
27
49
|
return 0;
|
|
28
50
|
}
|
|
29
51
|
|
|
52
|
+
static int acf_parse_missing_policy(const cJSON *args, acf_missing_policy *out) {
|
|
53
|
+
*out = ACF_MISSING_ERROR;
|
|
54
|
+
const cJSON *j = cJSON_GetObjectItemCaseSensitive(args, "missing");
|
|
55
|
+
if (!j) return TF_OK;
|
|
56
|
+
if (!cJSON_IsString(j)) {
|
|
57
|
+
tf_set_last_error("acf: missing must be error, null, or ignore");
|
|
58
|
+
return TF_ERROR;
|
|
59
|
+
}
|
|
60
|
+
if (strcmp(j->valuestring, "error") == 0) *out = ACF_MISSING_ERROR;
|
|
61
|
+
else if (strcmp(j->valuestring, "null") == 0) *out = ACF_MISSING_NULL;
|
|
62
|
+
else if (strcmp(j->valuestring, "ignore") == 0) *out = ACF_MISSING_IGNORE;
|
|
63
|
+
else {
|
|
64
|
+
tf_set_last_error("acf: missing must be error, null, or ignore");
|
|
65
|
+
return TF_ERROR;
|
|
66
|
+
}
|
|
67
|
+
return TF_OK;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static int acf_parse_type_policy(const cJSON *args, acf_type_policy *out) {
|
|
71
|
+
*out = ACF_TYPE_FAIL;
|
|
72
|
+
const cJSON *j = cJSON_GetObjectItemCaseSensitive(args, "on_type_error");
|
|
73
|
+
if (!j) return TF_OK;
|
|
74
|
+
if (!cJSON_IsString(j)) {
|
|
75
|
+
tf_set_last_error("acf: on_type_error must be fail or null");
|
|
76
|
+
return TF_ERROR;
|
|
77
|
+
}
|
|
78
|
+
if (strcmp(j->valuestring, "fail") == 0) *out = ACF_TYPE_FAIL;
|
|
79
|
+
else if (strcmp(j->valuestring, "null") == 0) *out = ACF_TYPE_NULL;
|
|
80
|
+
else {
|
|
81
|
+
tf_set_last_error("acf: on_type_error must be fail or null");
|
|
82
|
+
return TF_ERROR;
|
|
83
|
+
}
|
|
84
|
+
return TF_OK;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static int acf_set_col_error(acf_state *st, const tf_batch *in) {
|
|
88
|
+
if (st->col_idx < 0) {
|
|
89
|
+
char msg[256];
|
|
90
|
+
snprintf(msg, sizeof(msg), "acf: column '%s' not found", st->column);
|
|
91
|
+
tf_set_last_error(msg);
|
|
92
|
+
return TF_ERROR;
|
|
93
|
+
}
|
|
94
|
+
if (!acf_is_numeric(in->col_types[st->col_idx])) {
|
|
95
|
+
char msg[256];
|
|
96
|
+
snprintf(msg, sizeof(msg), "acf: column '%s' must be numeric", st->column);
|
|
97
|
+
tf_set_last_error(msg);
|
|
98
|
+
return TF_ERROR;
|
|
99
|
+
}
|
|
100
|
+
return TF_OK;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static int acf_check_schema(acf_state *st, const tf_batch *in) {
|
|
104
|
+
if (st->checked_schema) return TF_OK;
|
|
105
|
+
st->checked_schema = 1;
|
|
106
|
+
st->col_idx = tf_batch_col_index(in, st->column);
|
|
107
|
+
if (st->col_idx < 0) {
|
|
108
|
+
if (st->missing == ACF_MISSING_ERROR) return acf_set_col_error(st, in);
|
|
109
|
+
if (st->missing == ACF_MISSING_IGNORE) st->ignore = 1;
|
|
110
|
+
else st->force_null = 1;
|
|
111
|
+
return TF_OK;
|
|
112
|
+
}
|
|
113
|
+
if (!acf_is_numeric(in->col_types[st->col_idx])) {
|
|
114
|
+
if (st->on_type_error == ACF_TYPE_FAIL) return acf_set_col_error(st, in);
|
|
115
|
+
st->force_null = 1;
|
|
116
|
+
}
|
|
117
|
+
return TF_OK;
|
|
118
|
+
}
|
|
119
|
+
|
|
30
120
|
static int acf_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
31
121
|
tf_side_channels *side) {
|
|
32
122
|
(void)side;
|
|
33
123
|
acf_state *st = self->state;
|
|
34
124
|
*out = NULL;
|
|
35
125
|
|
|
36
|
-
|
|
37
|
-
if (
|
|
126
|
+
if (acf_check_schema(st, in) != TF_OK) return TF_ERROR;
|
|
127
|
+
if (st->ignore || st->force_null || st->col_idx < 0) return TF_OK;
|
|
38
128
|
|
|
39
129
|
for (size_t r = 0; r < in->n_rows; r++) {
|
|
40
|
-
if (tf_batch_is_null(in, r,
|
|
41
|
-
double val = get_numeric(in, r,
|
|
130
|
+
if (tf_batch_is_null(in, r, (size_t)st->col_idx)) continue;
|
|
131
|
+
double val = get_numeric(in, r, st->col_idx);
|
|
42
132
|
|
|
43
133
|
if (st->n_values >= st->cap_values) {
|
|
44
|
-
size_t
|
|
45
|
-
|
|
134
|
+
size_t min_cap = 0, newcap = 0;
|
|
135
|
+
if (tf_size_add(st->n_values, 1, &min_cap) != TF_OK ||
|
|
136
|
+
tf_size_grow_pow2(st->cap_values, min_cap, 256, &newcap) != TF_OK) {
|
|
137
|
+
return TF_ERROR;
|
|
138
|
+
}
|
|
139
|
+
double *tmp = tf_reallocarray_checked(st->values, newcap, sizeof(double));
|
|
46
140
|
if (!tmp) return TF_ERROR;
|
|
47
141
|
st->values = tmp;
|
|
48
142
|
st->cap_values = newcap;
|
|
@@ -53,23 +147,48 @@ static int acf_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
|
53
147
|
return TF_OK;
|
|
54
148
|
}
|
|
55
149
|
|
|
150
|
+
static int acf_emit_nulls(acf_state *st, tf_batch **out) {
|
|
151
|
+
size_t out_rows = 0;
|
|
152
|
+
if (tf_size_add((size_t)st->lags, 1, &out_rows) != TF_OK) return TF_ERROR;
|
|
153
|
+
tf_batch *ob = tf_batch_create(2, out_rows);
|
|
154
|
+
if (!ob) return TF_ERROR;
|
|
155
|
+
if (tf_batch_set_schema(ob, 0, "lag", TF_TYPE_INT64) != TF_OK ||
|
|
156
|
+
tf_batch_set_schema(ob, 1, "acf", TF_TYPE_FLOAT64) != TF_OK) {
|
|
157
|
+
tf_batch_free(ob);
|
|
158
|
+
return TF_ERROR;
|
|
159
|
+
}
|
|
160
|
+
for (int k = 0; k <= st->lags; k++) {
|
|
161
|
+
if (tf_batch_set_int64(ob, (size_t)k, 0, k) != TF_OK) {
|
|
162
|
+
tf_batch_free(ob);
|
|
163
|
+
return TF_ERROR;
|
|
164
|
+
}
|
|
165
|
+
if (tf_batch_expose_row(ob, (size_t)k) != TF_OK) {
|
|
166
|
+
tf_batch_free(ob);
|
|
167
|
+
return TF_ERROR;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
*out = ob;
|
|
171
|
+
return TF_OK;
|
|
172
|
+
}
|
|
173
|
+
|
|
56
174
|
static int acf_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
57
175
|
(void)side;
|
|
58
176
|
acf_state *st = self->state;
|
|
59
177
|
*out = NULL;
|
|
60
178
|
|
|
179
|
+
if (st->ignore) return TF_OK;
|
|
180
|
+
if (st->force_null) return acf_emit_nulls(st, out);
|
|
181
|
+
|
|
61
182
|
size_t n = st->n_values;
|
|
62
183
|
if (n < 2) return TF_OK;
|
|
63
184
|
|
|
64
185
|
int max_lag = st->lags;
|
|
65
186
|
if ((size_t)max_lag >= n) max_lag = (int)(n - 1);
|
|
66
187
|
|
|
67
|
-
/* Compute mean */
|
|
68
188
|
double mean = 0;
|
|
69
189
|
for (size_t i = 0; i < n; i++) mean += st->values[i];
|
|
70
190
|
mean /= (double)n;
|
|
71
191
|
|
|
72
|
-
/* Compute variance (denominator for ACF) */
|
|
73
192
|
double var = 0;
|
|
74
193
|
for (size_t i = 0; i < n; i++) {
|
|
75
194
|
double d = st->values[i] - mean;
|
|
@@ -77,12 +196,15 @@ static int acf_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
77
196
|
}
|
|
78
197
|
if (var == 0) return TF_OK;
|
|
79
198
|
|
|
80
|
-
|
|
81
|
-
size_t out_rows
|
|
199
|
+
size_t out_rows = 0;
|
|
200
|
+
if (tf_size_add((size_t)max_lag, 1, &out_rows) != TF_OK) return TF_ERROR;
|
|
82
201
|
tf_batch *ob = tf_batch_create(2, out_rows);
|
|
83
202
|
if (!ob) return TF_ERROR;
|
|
84
|
-
tf_batch_set_schema(ob, 0, "lag", TF_TYPE_INT64)
|
|
85
|
-
|
|
203
|
+
if (tf_batch_set_schema(ob, 0, "lag", TF_TYPE_INT64) != TF_OK ||
|
|
204
|
+
tf_batch_set_schema(ob, 1, "acf", TF_TYPE_FLOAT64) != TF_OK) {
|
|
205
|
+
tf_batch_free(ob);
|
|
206
|
+
return TF_ERROR;
|
|
207
|
+
}
|
|
86
208
|
|
|
87
209
|
for (int k = 0; k <= max_lag; k++) {
|
|
88
210
|
double cov = 0;
|
|
@@ -91,9 +213,15 @@ static int acf_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
91
213
|
}
|
|
92
214
|
double acf_val = cov / var;
|
|
93
215
|
|
|
94
|
-
tf_batch_set_int64(ob, k, 0, k)
|
|
95
|
-
|
|
96
|
-
|
|
216
|
+
if (tf_batch_set_int64(ob, (size_t)k, 0, k) != TF_OK ||
|
|
217
|
+
tf_batch_set_float64(ob, (size_t)k, 1, acf_val) != TF_OK) {
|
|
218
|
+
tf_batch_free(ob);
|
|
219
|
+
return TF_ERROR;
|
|
220
|
+
}
|
|
221
|
+
if (tf_batch_expose_row(ob, (size_t)k) != TF_OK) {
|
|
222
|
+
tf_batch_free(ob);
|
|
223
|
+
return TF_ERROR;
|
|
224
|
+
}
|
|
97
225
|
}
|
|
98
226
|
|
|
99
227
|
*out = ob;
|
|
@@ -101,7 +229,7 @@ static int acf_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
101
229
|
}
|
|
102
230
|
|
|
103
231
|
static void acf_destroy(tf_step *self) {
|
|
104
|
-
acf_state *st = self->state;
|
|
232
|
+
acf_state *st = self ? self->state : NULL;
|
|
105
233
|
if (st) {
|
|
106
234
|
free(st->column);
|
|
107
235
|
free(st->values);
|
|
@@ -110,20 +238,42 @@ static void acf_destroy(tf_step *self) {
|
|
|
110
238
|
free(self);
|
|
111
239
|
}
|
|
112
240
|
|
|
241
|
+
static int parse_lags(const cJSON *lags_j, int *out) {
|
|
242
|
+
*out = 20;
|
|
243
|
+
if (!lags_j) return TF_OK;
|
|
244
|
+
size_t parsed_lags = 0;
|
|
245
|
+
if (tf_json_size_value(lags_j, "lags", 1, (size_t)INT_MAX,
|
|
246
|
+
&parsed_lags, "acf") < 0) {
|
|
247
|
+
return TF_ERROR;
|
|
248
|
+
}
|
|
249
|
+
*out = (int)parsed_lags;
|
|
250
|
+
return TF_OK;
|
|
251
|
+
}
|
|
252
|
+
|
|
113
253
|
tf_step *tf_acf_create(const cJSON *args) {
|
|
114
254
|
if (!args) return NULL;
|
|
115
255
|
cJSON *col_j = cJSON_GetObjectItemCaseSensitive(args, "column");
|
|
116
|
-
if (!cJSON_IsString(col_j))
|
|
256
|
+
if (!cJSON_IsString(col_j) || !col_j->valuestring[0]) {
|
|
257
|
+
tf_set_last_error("acf: column is required");
|
|
258
|
+
return NULL;
|
|
259
|
+
}
|
|
117
260
|
|
|
118
261
|
acf_state *st = calloc(1, sizeof(acf_state));
|
|
119
262
|
if (!st) return NULL;
|
|
263
|
+
st->col_idx = -1;
|
|
120
264
|
st->column = strdup(col_j->valuestring);
|
|
265
|
+
if (!st->column) { free(st); return NULL; }
|
|
121
266
|
|
|
122
267
|
cJSON *lags_j = cJSON_GetObjectItemCaseSensitive(args, "lags");
|
|
123
|
-
st->lags
|
|
124
|
-
|
|
268
|
+
if (parse_lags(lags_j, &st->lags) != TF_OK ||
|
|
269
|
+
acf_parse_missing_policy(args, &st->missing) != TF_OK ||
|
|
270
|
+
acf_parse_type_policy(args, &st->on_type_error) != TF_OK) {
|
|
271
|
+
free(st->column);
|
|
272
|
+
free(st);
|
|
273
|
+
return NULL;
|
|
274
|
+
}
|
|
125
275
|
|
|
126
|
-
tf_step *step =
|
|
276
|
+
tf_step *step = calloc(1, sizeof(tf_step));
|
|
127
277
|
if (!step) { free(st->column); free(st); return NULL; }
|
|
128
278
|
step->process = acf_process;
|
|
129
279
|
step->flush = acf_flush;
|