@digitaldefiance/node-accelerate 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/accelerate.cc ADDED
@@ -0,0 +1,657 @@
1
+ // Apple Accelerate Framework Native Addon for Node.js
2
+ // Provides high-performance BLAS/vDSP operations for M4 Max
3
+ //
4
+ // This addon exposes Apple's Accelerate framework to JavaScript,
5
+ // giving you hardware-optimized:
6
+ // - Matrix multiplication (BLAS)
7
+ // - Vector operations (vDSP)
8
+ // - FFT (vDSP)
9
+ // - Convolution (vDSP)
10
+
11
+ #include <node_api.h>
12
+ #include <Accelerate/Accelerate.h>
13
+ #include <cstring>
14
+ #include <vector>
15
+
16
+ // Helper to throw JS errors
17
+ #define NAPI_THROW(env, msg) \
18
+ napi_throw_error(env, nullptr, msg); \
19
+ return nullptr;
20
+
21
+ #define NAPI_CHECK(call) \
22
+ if ((call) != napi_ok) { \
23
+ napi_throw_error(env, nullptr, "NAPI call failed"); \
24
+ return nullptr; \
25
+ }
26
+
27
+ // Get Float64Array data
28
+ static double* GetFloat64ArrayData(napi_env env, napi_value value, size_t* length) {
29
+ bool is_typedarray;
30
+ napi_is_typedarray(env, value, &is_typedarray);
31
+ if (!is_typedarray) return nullptr;
32
+
33
+ napi_typedarray_type type;
34
+ size_t byte_length;
35
+ void* data;
36
+ napi_value arraybuffer;
37
+ size_t byte_offset;
38
+
39
+ napi_get_typedarray_info(env, value, &type, length, &data, &arraybuffer, &byte_offset);
40
+
41
+ if (type != napi_float64_array) return nullptr;
42
+ return static_cast<double*>(data);
43
+ }
44
+
45
+ // Get Float32Array data
46
+ static float* GetFloat32ArrayData(napi_env env, napi_value value, size_t* length) {
47
+ bool is_typedarray;
48
+ napi_is_typedarray(env, value, &is_typedarray);
49
+ if (!is_typedarray) return nullptr;
50
+
51
+ napi_typedarray_type type;
52
+ size_t byte_length;
53
+ void* data;
54
+ napi_value arraybuffer;
55
+ size_t byte_offset;
56
+
57
+ napi_get_typedarray_info(env, value, &type, length, &data, &arraybuffer, &byte_offset);
58
+
59
+ if (type != napi_float32_array) return nullptr;
60
+ return static_cast<float*>(data);
61
+ }
62
+
63
+ // Matrix multiplication using BLAS dgemm (double precision)
64
+ // C = alpha * A * B + beta * C
65
+ // A is MxK, B is KxN, C is MxN
66
+ static napi_value MatMulDouble(napi_env env, napi_callback_info info) {
67
+ size_t argc = 6;
68
+ napi_value args[6];
69
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
70
+
71
+ if (argc < 6) {
72
+ NAPI_THROW(env, "matmul requires 6 arguments: A, B, C, M, K, N");
73
+ }
74
+
75
+ size_t len_a, len_b, len_c;
76
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
77
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
78
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
79
+
80
+ if (!A || !B || !C) {
81
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
82
+ }
83
+
84
+ int32_t M, K, N;
85
+ napi_get_value_int32(env, args[3], &M);
86
+ napi_get_value_int32(env, args[4], &K);
87
+ napi_get_value_int32(env, args[5], &N);
88
+
89
+ // BLAS dgemm: C = 1.0 * A * B + 0.0 * C
90
+ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
91
+ M, N, K,
92
+ 1.0, A, K,
93
+ B, N,
94
+ 0.0, C, N);
95
+
96
+ return args[2]; // Return C
97
+ }
98
+
99
+ // Matrix multiplication using BLAS sgemm (single precision)
100
+ static napi_value MatMulFloat(napi_env env, napi_callback_info info) {
101
+ size_t argc = 6;
102
+ napi_value args[6];
103
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
104
+
105
+ if (argc < 6) {
106
+ NAPI_THROW(env, "matmulFloat requires 6 arguments: A, B, C, M, K, N");
107
+ }
108
+
109
+ size_t len_a, len_b, len_c;
110
+ float* A = GetFloat32ArrayData(env, args[0], &len_a);
111
+ float* B = GetFloat32ArrayData(env, args[1], &len_b);
112
+ float* C = GetFloat32ArrayData(env, args[2], &len_c);
113
+
114
+ if (!A || !B || !C) {
115
+ NAPI_THROW(env, "Arguments must be Float32Arrays");
116
+ }
117
+
118
+ int32_t M, K, N;
119
+ napi_get_value_int32(env, args[3], &M);
120
+ napi_get_value_int32(env, args[4], &K);
121
+ napi_get_value_int32(env, args[5], &N);
122
+
123
+ cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
124
+ M, N, K,
125
+ 1.0f, A, K,
126
+ B, N,
127
+ 0.0f, C, N);
128
+
129
+ return args[2];
130
+ }
131
+
132
+ // Vector dot product using vDSP
133
+ static napi_value DotProduct(napi_env env, napi_callback_info info) {
134
+ size_t argc = 2;
135
+ napi_value args[2];
136
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
137
+
138
+ size_t len_a, len_b;
139
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
140
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
141
+
142
+ if (!A || !B) {
143
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
144
+ }
145
+
146
+ size_t len = len_a < len_b ? len_a : len_b;
147
+ double result;
148
+ vDSP_dotprD(A, 1, B, 1, &result, len);
149
+
150
+ napi_value js_result;
151
+ napi_create_double(env, result, &js_result);
152
+ return js_result;
153
+ }
154
+
155
+ // Vector add: C = A + B
156
+ static napi_value VectorAdd(napi_env env, napi_callback_info info) {
157
+ size_t argc = 3;
158
+ napi_value args[3];
159
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
160
+
161
+ size_t len_a, len_b, len_c;
162
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
163
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
164
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
165
+
166
+ if (!A || !B || !C) {
167
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
168
+ }
169
+
170
+ size_t len = len_a < len_b ? len_a : len_b;
171
+ len = len < len_c ? len : len_c;
172
+
173
+ vDSP_vaddD(A, 1, B, 1, C, 1, len);
174
+
175
+ return args[2];
176
+ }
177
+
178
+ // Vector subtract: C = A - B
179
+ static napi_value VectorSub(napi_env env, napi_callback_info info) {
180
+ size_t argc = 3;
181
+ napi_value args[3];
182
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
183
+
184
+ size_t len_a, len_b, len_c;
185
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
186
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
187
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
188
+
189
+ if (!A || !B || !C) {
190
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
191
+ }
192
+
193
+ size_t len = len_a < len_b ? len_a : len_b;
194
+ len = len < len_c ? len : len_c;
195
+
196
+ vDSP_vsubD(B, 1, A, 1, C, 1, len); // Note: vDSP_vsubD computes C = A - B as C[i] = B[i] - A[i]
197
+
198
+ return args[2];
199
+ }
200
+
201
+ // Vector multiply: C = A * B (element-wise)
202
+ static napi_value VectorMul(napi_env env, napi_callback_info info) {
203
+ size_t argc = 3;
204
+ napi_value args[3];
205
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
206
+
207
+ size_t len_a, len_b, len_c;
208
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
209
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
210
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
211
+
212
+ if (!A || !B || !C) {
213
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
214
+ }
215
+
216
+ size_t len = len_a < len_b ? len_a : len_b;
217
+ len = len < len_c ? len : len_c;
218
+
219
+ vDSP_vmulD(A, 1, B, 1, C, 1, len);
220
+
221
+ return args[2];
222
+ }
223
+
224
+ // Vector divide: C = A / B (element-wise)
225
+ static napi_value VectorDiv(napi_env env, napi_callback_info info) {
226
+ size_t argc = 3;
227
+ napi_value args[3];
228
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
229
+
230
+ size_t len_a, len_b, len_c;
231
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
232
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
233
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
234
+
235
+ if (!A || !B || !C) {
236
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
237
+ }
238
+
239
+ size_t len = len_a < len_b ? len_a : len_b;
240
+ len = len < len_c ? len : len_c;
241
+
242
+ vDSP_vdivD(B, 1, A, 1, C, 1, len); // Note: vDSP_vdivD computes C = A / B as C[i] = B[i] / A[i]
243
+
244
+ return args[2];
245
+ }
246
+
247
+ // Vector scale: B = A * scalar
248
+ static napi_value VectorScale(napi_env env, napi_callback_info info) {
249
+ size_t argc = 3;
250
+ napi_value args[3];
251
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
252
+
253
+ size_t len_a, len_b;
254
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
255
+ double scalar;
256
+ napi_get_value_double(env, args[1], &scalar);
257
+ double* B = GetFloat64ArrayData(env, args[2], &len_b);
258
+
259
+ if (!A || !B) {
260
+ NAPI_THROW(env, "First and third arguments must be Float64Arrays");
261
+ }
262
+
263
+ size_t len = len_a < len_b ? len_a : len_b;
264
+ vDSP_vsmulD(A, 1, &scalar, B, 1, len);
265
+
266
+ return args[2];
267
+ }
268
+
269
+ // Sum of vector elements
270
+ static napi_value VectorSum(napi_env env, napi_callback_info info) {
271
+ size_t argc = 1;
272
+ napi_value args[1];
273
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
274
+
275
+ size_t len;
276
+ double* A = GetFloat64ArrayData(env, args[0], &len);
277
+
278
+ if (!A) {
279
+ NAPI_THROW(env, "Argument must be Float64Array");
280
+ }
281
+
282
+ double result;
283
+ vDSP_sveD(A, 1, &result, len);
284
+
285
+ napi_value js_result;
286
+ napi_create_double(env, result, &js_result);
287
+ return js_result;
288
+ }
289
+
290
+ // Mean of vector elements
291
+ static napi_value VectorMean(napi_env env, napi_callback_info info) {
292
+ size_t argc = 1;
293
+ napi_value args[1];
294
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
295
+
296
+ size_t len;
297
+ double* A = GetFloat64ArrayData(env, args[0], &len);
298
+
299
+ if (!A) {
300
+ NAPI_THROW(env, "Argument must be Float64Array");
301
+ }
302
+
303
+ double result;
304
+ vDSP_meanvD(A, 1, &result, len);
305
+
306
+ napi_value js_result;
307
+ napi_create_double(env, result, &js_result);
308
+ return js_result;
309
+ }
310
+
311
+ // Max of vector elements
312
+ static napi_value VectorMax(napi_env env, napi_callback_info info) {
313
+ size_t argc = 1;
314
+ napi_value args[1];
315
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
316
+
317
+ size_t len;
318
+ double* A = GetFloat64ArrayData(env, args[0], &len);
319
+
320
+ if (!A) {
321
+ NAPI_THROW(env, "Argument must be Float64Array");
322
+ }
323
+
324
+ double result;
325
+ vDSP_maxvD(A, 1, &result, len);
326
+
327
+ napi_value js_result;
328
+ napi_create_double(env, result, &js_result);
329
+ return js_result;
330
+ }
331
+
332
+ // Min of vector elements
333
+ static napi_value VectorMin(napi_env env, napi_callback_info info) {
334
+ size_t argc = 1;
335
+ napi_value args[1];
336
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
337
+
338
+ size_t len;
339
+ double* A = GetFloat64ArrayData(env, args[0], &len);
340
+
341
+ if (!A) {
342
+ NAPI_THROW(env, "Argument must be Float64Array");
343
+ }
344
+
345
+ double result;
346
+ vDSP_minvD(A, 1, &result, len);
347
+
348
+ napi_value js_result;
349
+ napi_create_double(env, result, &js_result);
350
+ return js_result;
351
+ }
352
+
353
+ // FFT (real to complex)
354
+ static napi_value FFT(napi_env env, napi_callback_info info) {
355
+ size_t argc = 2;
356
+ napi_value args[2];
357
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
358
+
359
+ size_t len;
360
+ double* input = GetFloat64ArrayData(env, args[0], &len);
361
+
362
+ if (!input) {
363
+ NAPI_THROW(env, "First argument must be Float64Array");
364
+ }
365
+
366
+ // Find log2 of length
367
+ vDSP_Length log2n = 0;
368
+ vDSP_Length n = len;
369
+ while (n > 1) {
370
+ n >>= 1;
371
+ log2n++;
372
+ }
373
+
374
+ if ((1UL << log2n) != len) {
375
+ NAPI_THROW(env, "Input length must be a power of 2");
376
+ }
377
+
378
+ // Setup FFT
379
+ FFTSetupD setup = vDSP_create_fftsetupD(log2n, FFT_RADIX2);
380
+ if (!setup) {
381
+ NAPI_THROW(env, "Failed to create FFT setup");
382
+ }
383
+
384
+ // Allocate split complex arrays
385
+ size_t half = len / 2;
386
+ std::vector<double> real(half);
387
+ std::vector<double> imag(half);
388
+
389
+ DSPDoubleSplitComplex split;
390
+ split.realp = real.data();
391
+ split.imagp = imag.data();
392
+
393
+ // Convert to split complex
394
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &split, 1, half);
395
+
396
+ // Perform FFT
397
+ vDSP_fft_zripD(setup, &split, 1, log2n, FFT_FORWARD);
398
+
399
+ // Scale
400
+ double scale = 0.5;
401
+ vDSP_vsmulD(split.realp, 1, &scale, split.realp, 1, half);
402
+ vDSP_vsmulD(split.imagp, 1, &scale, split.imagp, 1, half);
403
+
404
+ // Create output array (interleaved real/imag)
405
+ napi_value arraybuffer;
406
+ void* data;
407
+ napi_create_arraybuffer(env, len * sizeof(double), &data, &arraybuffer);
408
+
409
+ double* output = static_cast<double*>(data);
410
+ for (size_t i = 0; i < half; i++) {
411
+ output[i * 2] = real[i];
412
+ output[i * 2 + 1] = imag[i];
413
+ }
414
+
415
+ napi_value result;
416
+ napi_create_typedarray(env, napi_float64_array, len, arraybuffer, 0, &result);
417
+
418
+ vDSP_destroy_fftsetupD(setup);
419
+
420
+ return result;
421
+ }
422
+
423
+ // Matrix-vector multiply: y = A * x
424
+ static napi_value MatVecMul(napi_env env, napi_callback_info info) {
425
+ size_t argc = 5;
426
+ napi_value args[5];
427
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
428
+
429
+ size_t len_a, len_x, len_y;
430
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
431
+ double* x = GetFloat64ArrayData(env, args[1], &len_x);
432
+ double* y = GetFloat64ArrayData(env, args[2], &len_y);
433
+
434
+ if (!A || !x || !y) {
435
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
436
+ }
437
+
438
+ int32_t M, N;
439
+ NAPI_CHECK(napi_get_value_int32(env, args[3], &M));
440
+ NAPI_CHECK(napi_get_value_int32(env, args[4], &N));
441
+
442
+ // y = A * x using GEMV
443
+ cblas_dgemv(CblasRowMajor, CblasNoTrans, M, N, 1.0, A, N, x, 1, 0.0, y, 1);
444
+
445
+ return args[2];
446
+ }
447
+
448
+ // AXPY: y = a*x + y
449
+ static napi_value AXPY(napi_env env, napi_callback_info info) {
450
+ size_t argc = 3;
451
+ napi_value args[3];
452
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
453
+
454
+ double alpha;
455
+ NAPI_CHECK(napi_get_value_double(env, args[0], &alpha));
456
+
457
+ size_t len_x, len_y;
458
+ double* x = GetFloat64ArrayData(env, args[1], &len_x);
459
+ double* y = GetFloat64ArrayData(env, args[2], &len_y);
460
+
461
+ if (!x || !y) {
462
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
463
+ }
464
+
465
+ size_t len = len_x < len_y ? len_x : len_y;
466
+ cblas_daxpy(len, alpha, x, 1, y, 1);
467
+
468
+ return args[2];
469
+ }
470
+
471
+ // Vector absolute value
472
+ static napi_value VectorAbs(napi_env env, napi_callback_info info) {
473
+ size_t argc = 2;
474
+ napi_value args[2];
475
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
476
+
477
+ size_t len_a, len_b;
478
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
479
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
480
+
481
+ if (!A || !B) {
482
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
483
+ }
484
+
485
+ size_t len = len_a < len_b ? len_a : len_b;
486
+ vDSP_vabsD(A, 1, B, 1, len);
487
+
488
+ return args[1];
489
+ }
490
+
491
+ // Vector square: b = a^2
492
+ static napi_value VectorSquare(napi_env env, napi_callback_info info) {
493
+ size_t argc = 2;
494
+ napi_value args[2];
495
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
496
+
497
+ size_t len_a, len_b;
498
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
499
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
500
+
501
+ if (!A || !B) {
502
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
503
+ }
504
+
505
+ size_t len = len_a < len_b ? len_a : len_b;
506
+ vDSP_vsqD(A, 1, B, 1, len);
507
+
508
+ return args[1];
509
+ }
510
+
511
+ // Vector square root
512
+ static napi_value VectorSqrt(napi_env env, napi_callback_info info) {
513
+ size_t argc = 2;
514
+ napi_value args[2];
515
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
516
+
517
+ size_t len_a, len_b;
518
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
519
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
520
+
521
+ if (!A || !B) {
522
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
523
+ }
524
+
525
+ size_t len = len_a < len_b ? len_a : len_b;
526
+
527
+ // vDSP doesn't have sqrt, use vForce
528
+ int n = (int)len;
529
+ vvsqrt(B, A, &n);
530
+
531
+ return args[1];
532
+ }
533
+
534
+ // Vector normalize (unit vector)
535
+ static napi_value VectorNormalize(napi_env env, napi_callback_info info) {
536
+ size_t argc = 2;
537
+ napi_value args[2];
538
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
539
+
540
+ size_t len_a, len_b;
541
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
542
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
543
+
544
+ if (!A || !B) {
545
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
546
+ }
547
+
548
+ size_t len = len_a < len_b ? len_a : len_b;
549
+
550
+ // Compute magnitude
551
+ double magnitude;
552
+ vDSP_dotprD(A, 1, A, 1, &magnitude, len);
553
+ magnitude = sqrt(magnitude);
554
+
555
+ if (magnitude > 0) {
556
+ double inv_mag = 1.0 / magnitude;
557
+ vDSP_vsmulD(A, 1, &inv_mag, B, 1, len);
558
+ } else {
559
+ // Zero vector, just copy
560
+ memcpy(B, A, len * sizeof(double));
561
+ }
562
+
563
+ return args[1];
564
+ }
565
+
566
+ // Euclidean distance between two vectors
567
+ static napi_value EuclideanDistance(napi_env env, napi_callback_info info) {
568
+ size_t argc = 2;
569
+ napi_value args[2];
570
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
571
+
572
+ size_t len_a, len_b;
573
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
574
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
575
+
576
+ if (!A || !B) {
577
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
578
+ }
579
+
580
+ size_t len = len_a < len_b ? len_a : len_b;
581
+
582
+ // Compute distance using vDSP
583
+ double result;
584
+ vDSP_distancesqD(A, 1, B, 1, &result, len);
585
+ result = sqrt(result);
586
+
587
+ napi_value js_result;
588
+ napi_create_double(env, result, &js_result);
589
+ return js_result;
590
+ }
591
+
592
+ // RMS (Root Mean Square)
593
+ static napi_value VectorRMS(napi_env env, napi_callback_info info) {
594
+ size_t argc = 1;
595
+ napi_value args[1];
596
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
597
+
598
+ size_t len;
599
+ double* A = GetFloat64ArrayData(env, args[0], &len);
600
+
601
+ if (!A) {
602
+ NAPI_THROW(env, "Argument must be Float64Array");
603
+ }
604
+
605
+ double result;
606
+ vDSP_rmsqvD(A, 1, &result, len);
607
+
608
+ napi_value js_result;
609
+ napi_create_double(env, result, &js_result);
610
+ return js_result;
611
+ }
612
+
613
+ // Module initialization
614
+ static napi_value Init(napi_env env, napi_value exports) {
615
+ napi_property_descriptor props[] = {
616
+ // Matrix operations
617
+ {"matmul", nullptr, MatMulDouble, nullptr, nullptr, nullptr, napi_default, nullptr},
618
+ {"matmulFloat", nullptr, MatMulFloat, nullptr, nullptr, nullptr, napi_default, nullptr},
619
+ {"matvec", nullptr, MatVecMul, nullptr, nullptr, nullptr, napi_default, nullptr},
620
+
621
+ // BLAS operations
622
+ {"axpy", nullptr, AXPY, nullptr, nullptr, nullptr, napi_default, nullptr},
623
+
624
+ // Vector arithmetic
625
+ {"dot", nullptr, DotProduct, nullptr, nullptr, nullptr, napi_default, nullptr},
626
+ {"vadd", nullptr, VectorAdd, nullptr, nullptr, nullptr, napi_default, nullptr},
627
+ {"vsub", nullptr, VectorSub, nullptr, nullptr, nullptr, napi_default, nullptr},
628
+ {"vmul", nullptr, VectorMul, nullptr, nullptr, nullptr, napi_default, nullptr},
629
+ {"vdiv", nullptr, VectorDiv, nullptr, nullptr, nullptr, napi_default, nullptr},
630
+ {"vscale", nullptr, VectorScale, nullptr, nullptr, nullptr, napi_default, nullptr},
631
+
632
+ // Vector functions
633
+ {"vabs", nullptr, VectorAbs, nullptr, nullptr, nullptr, napi_default, nullptr},
634
+ {"vsquare", nullptr, VectorSquare, nullptr, nullptr, nullptr, napi_default, nullptr},
635
+ {"vsqrt", nullptr, VectorSqrt, nullptr, nullptr, nullptr, napi_default, nullptr},
636
+ {"normalize", nullptr, VectorNormalize, nullptr, nullptr, nullptr, napi_default, nullptr},
637
+
638
+ // Reductions
639
+ {"sum", nullptr, VectorSum, nullptr, nullptr, nullptr, napi_default, nullptr},
640
+ {"mean", nullptr, VectorMean, nullptr, nullptr, nullptr, napi_default, nullptr},
641
+ {"max", nullptr, VectorMax, nullptr, nullptr, nullptr, napi_default, nullptr},
642
+ {"min", nullptr, VectorMin, nullptr, nullptr, nullptr, napi_default, nullptr},
643
+ {"rms", nullptr, VectorRMS, nullptr, nullptr, nullptr, napi_default, nullptr},
644
+
645
+ // Distance metrics
646
+ {"euclidean", nullptr, EuclideanDistance, nullptr, nullptr, nullptr, napi_default, nullptr},
647
+
648
+ // Signal processing
649
+ {"fft", nullptr, FFT, nullptr, nullptr, nullptr, napi_default, nullptr},
650
+ };
651
+
652
+ napi_define_properties(env, exports, sizeof(props) / sizeof(props[0]), props);
653
+
654
+ return exports;
655
+ }
656
+
657
+ NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
package/binding.gyp ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "accelerate",
5
+ "sources": ["accelerate.cc"],
6
+ "conditions": [
7
+ ["OS=='mac'", {
8
+ "link_settings": {
9
+ "libraries": [
10
+ "-framework Accelerate"
11
+ ]
12
+ },
13
+ "xcode_settings": {
14
+ "OTHER_CFLAGS": [
15
+ "-mcpu=apple-m4",
16
+ "-mtune=apple-m4",
17
+ "-O3"
18
+ ]
19
+ }
20
+ }]
21
+ ]
22
+ }
23
+ ]
24
+ }