@digitaldefiance/node-accelerate 1.0.7 → 2.0.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/accelerate.cc CHANGED
@@ -610,6 +610,1284 @@ static napi_value VectorRMS(napi_env env, napi_callback_info info) {
610
610
  return js_result;
611
611
  }
612
612
 
613
+ // ============================================================================
614
+ // ADDITIONAL ACCELERATE FUNCTIONS
615
+ // ============================================================================
616
+
617
+ // Variance
618
+ static napi_value VectorVariance(napi_env env, napi_callback_info info) {
619
+ size_t argc = 1;
620
+ napi_value args[1];
621
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
622
+
623
+ size_t len;
624
+ double* A = GetFloat64ArrayData(env, args[0], &len);
625
+
626
+ if (!A) {
627
+ NAPI_THROW(env, "Argument must be Float64Array");
628
+ }
629
+
630
+ double mean_val, variance;
631
+ vDSP_meanvD(A, 1, &mean_val, len);
632
+
633
+ // Compute variance manually
634
+ std::vector<double> diff(len);
635
+ double neg_mean = -mean_val;
636
+ vDSP_vsaddD(A, 1, &neg_mean, diff.data(), 1, len);
637
+ vDSP_vsqD(diff.data(), 1, diff.data(), 1, len);
638
+ vDSP_sveD(diff.data(), 1, &variance, len);
639
+ variance /= len;
640
+
641
+ napi_value js_result;
642
+ napi_create_double(env, variance, &js_result);
643
+ return js_result;
644
+ }
645
+
646
+ // Standard Deviation
647
+ static napi_value VectorStdDev(napi_env env, napi_callback_info info) {
648
+ size_t argc = 1;
649
+ napi_value args[1];
650
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
651
+
652
+ size_t len;
653
+ double* A = GetFloat64ArrayData(env, args[0], &len);
654
+
655
+ if (!A) {
656
+ NAPI_THROW(env, "Argument must be Float64Array");
657
+ }
658
+
659
+ double mean_val, variance;
660
+ vDSP_meanvD(A, 1, &mean_val, len);
661
+
662
+ std::vector<double> diff(len);
663
+ double neg_mean = -mean_val;
664
+ vDSP_vsaddD(A, 1, &neg_mean, diff.data(), 1, len);
665
+ vDSP_vsqD(diff.data(), 1, diff.data(), 1, len);
666
+ vDSP_sveD(diff.data(), 1, &variance, len);
667
+ variance /= len;
668
+
669
+ double stddev = sqrt(variance);
670
+
671
+ napi_value js_result;
672
+ napi_create_double(env, stddev, &js_result);
673
+ return js_result;
674
+ }
675
+
676
+ // Min and Max together
677
+ static napi_value VectorMinMax(napi_env env, napi_callback_info info) {
678
+ size_t argc = 1;
679
+ napi_value args[1];
680
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
681
+
682
+ size_t len;
683
+ double* A = GetFloat64ArrayData(env, args[0], &len);
684
+
685
+ if (!A) {
686
+ NAPI_THROW(env, "Argument must be Float64Array");
687
+ }
688
+
689
+ double min_val, max_val;
690
+ vDSP_minvD(A, 1, &min_val, len);
691
+ vDSP_maxvD(A, 1, &max_val, len);
692
+
693
+ napi_value result, min_js, max_js;
694
+ napi_create_object(env, &result);
695
+ napi_create_double(env, min_val, &min_js);
696
+ napi_create_double(env, max_val, &max_js);
697
+ napi_set_named_property(env, result, "min", min_js);
698
+ napi_set_named_property(env, result, "max", max_js);
699
+
700
+ return result;
701
+ }
702
+
703
+ // Trigonometric functions
704
+ static napi_value VectorSin(napi_env env, napi_callback_info info) {
705
+ size_t argc = 2;
706
+ napi_value args[2];
707
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
708
+
709
+ size_t len_a, len_b;
710
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
711
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
712
+
713
+ if (!A || !B) {
714
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
715
+ }
716
+
717
+ size_t len = len_a < len_b ? len_a : len_b;
718
+ int n = (int)len;
719
+ vvsin(B, A, &n);
720
+
721
+ return args[1];
722
+ }
723
+
724
+ static napi_value VectorCos(napi_env env, napi_callback_info info) {
725
+ size_t argc = 2;
726
+ napi_value args[2];
727
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
728
+
729
+ size_t len_a, len_b;
730
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
731
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
732
+
733
+ if (!A || !B) {
734
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
735
+ }
736
+
737
+ size_t len = len_a < len_b ? len_a : len_b;
738
+ int n = (int)len;
739
+ vvcos(B, A, &n);
740
+
741
+ return args[1];
742
+ }
743
+
744
+ static napi_value VectorTan(napi_env env, napi_callback_info info) {
745
+ size_t argc = 2;
746
+ napi_value args[2];
747
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
748
+
749
+ size_t len_a, len_b;
750
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
751
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
752
+
753
+ if (!A || !B) {
754
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
755
+ }
756
+
757
+ size_t len = len_a < len_b ? len_a : len_b;
758
+ int n = (int)len;
759
+ vvtan(B, A, &n);
760
+
761
+ return args[1];
762
+ }
763
+
764
+ // Exponential and logarithm
765
+ static napi_value VectorExp(napi_env env, napi_callback_info info) {
766
+ size_t argc = 2;
767
+ napi_value args[2];
768
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
769
+
770
+ size_t len_a, len_b;
771
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
772
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
773
+
774
+ if (!A || !B) {
775
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
776
+ }
777
+
778
+ size_t len = len_a < len_b ? len_a : len_b;
779
+ int n = (int)len;
780
+ vvexp(B, A, &n);
781
+
782
+ return args[1];
783
+ }
784
+
785
+ static napi_value VectorLog(napi_env env, napi_callback_info info) {
786
+ size_t argc = 2;
787
+ napi_value args[2];
788
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
789
+
790
+ size_t len_a, len_b;
791
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
792
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
793
+
794
+ if (!A || !B) {
795
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
796
+ }
797
+
798
+ size_t len = len_a < len_b ? len_a : len_b;
799
+ int n = (int)len;
800
+ vvlog(B, A, &n);
801
+
802
+ return args[1];
803
+ }
804
+
805
+ static napi_value VectorLog10(napi_env env, napi_callback_info info) {
806
+ size_t argc = 2;
807
+ napi_value args[2];
808
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
809
+
810
+ size_t len_a, len_b;
811
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
812
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
813
+
814
+ if (!A || !B) {
815
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
816
+ }
817
+
818
+ size_t len = len_a < len_b ? len_a : len_b;
819
+ int n = (int)len;
820
+ vvlog10(B, A, &n);
821
+
822
+ return args[1];
823
+ }
824
+
825
+ // Power functions
826
+ static napi_value VectorPow(napi_env env, napi_callback_info info) {
827
+ size_t argc = 3;
828
+ napi_value args[3];
829
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
830
+
831
+ size_t len_a, len_b, len_c;
832
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
833
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
834
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
835
+
836
+ if (!A || !B || !C) {
837
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
838
+ }
839
+
840
+ size_t len = len_a < len_b ? len_a : len_b;
841
+ len = len < len_c ? len : len_c;
842
+ int n = (int)len;
843
+ vvpow(C, B, A, &n);
844
+
845
+ return args[2];
846
+ }
847
+
848
+ // Clipping
849
+ static napi_value VectorClip(napi_env env, napi_callback_info info) {
850
+ size_t argc = 4;
851
+ napi_value args[4];
852
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
853
+
854
+ size_t len_a, len_b;
855
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
856
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
857
+
858
+ if (!A || !B) {
859
+ NAPI_THROW(env, "First two arguments must be Float64Arrays");
860
+ }
861
+
862
+ double min_val, max_val;
863
+ NAPI_CHECK(napi_get_value_double(env, args[2], &min_val));
864
+ NAPI_CHECK(napi_get_value_double(env, args[3], &max_val));
865
+
866
+ size_t len = len_a < len_b ? len_a : len_b;
867
+ vDSP_vclipD(A, 1, &min_val, &max_val, B, 1, len);
868
+
869
+ return args[1];
870
+ }
871
+
872
+ // Threshold
873
+ static napi_value VectorThreshold(napi_env env, napi_callback_info info) {
874
+ size_t argc = 3;
875
+ napi_value args[3];
876
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
877
+
878
+ size_t len_a, len_b;
879
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
880
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
881
+
882
+ if (!A || !B) {
883
+ NAPI_THROW(env, "First two arguments must be Float64Arrays");
884
+ }
885
+
886
+ double threshold;
887
+ NAPI_CHECK(napi_get_value_double(env, args[2], &threshold));
888
+
889
+ size_t len = len_a < len_b ? len_a : len_b;
890
+ vDSP_vthrD(A, 1, &threshold, B, 1, len);
891
+
892
+ return args[1];
893
+ }
894
+
895
+ // Convolution
896
+ static napi_value Convolve(napi_env env, napi_callback_info info) {
897
+ size_t argc = 3;
898
+ napi_value args[3];
899
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
900
+
901
+ size_t signal_len, kernel_len, result_len;
902
+ double* signal = GetFloat64ArrayData(env, args[0], &signal_len);
903
+ double* kernel = GetFloat64ArrayData(env, args[1], &kernel_len);
904
+ double* result = GetFloat64ArrayData(env, args[2], &result_len);
905
+
906
+ if (!signal || !kernel || !result) {
907
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
908
+ }
909
+
910
+ vDSP_convD(signal, 1, kernel, 1, result, 1, result_len, kernel_len);
911
+
912
+ return args[2];
913
+ }
914
+
915
+ // Cross-correlation
916
+ static napi_value CrossCorrelation(napi_env env, napi_callback_info info) {
917
+ size_t argc = 3;
918
+ napi_value args[3];
919
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
920
+
921
+ size_t len_a, len_b, len_c;
922
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
923
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
924
+ double* C = GetFloat64ArrayData(env, args[2], &len_c);
925
+
926
+ if (!A || !B || !C) {
927
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
928
+ }
929
+
930
+ size_t result_len = len_a + len_b - 1;
931
+ if (len_c < result_len) {
932
+ NAPI_THROW(env, "Result array too small");
933
+ }
934
+
935
+ // Use convolution with reversed kernel for correlation
936
+ std::vector<double> b_reversed(len_b);
937
+ for (size_t i = 0; i < len_b; i++) {
938
+ b_reversed[i] = B[len_b - 1 - i];
939
+ }
940
+
941
+ vDSP_convD(A, 1, b_reversed.data(), 1, C, 1, len_a, len_b);
942
+
943
+ return args[2];
944
+ }
945
+
946
+ // Window functions
947
+ static napi_value HammingWindow(napi_env env, napi_callback_info info) {
948
+ size_t argc = 1;
949
+ napi_value args[1];
950
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
951
+
952
+ int32_t length;
953
+ NAPI_CHECK(napi_get_value_int32(env, args[0], &length));
954
+
955
+ napi_value arraybuffer;
956
+ void* data;
957
+ napi_create_arraybuffer(env, length * sizeof(double), &data, &arraybuffer);
958
+ double* window = static_cast<double*>(data);
959
+
960
+ vDSP_hamm_windowD(window, length, 0);
961
+
962
+ napi_value result;
963
+ napi_create_typedarray(env, napi_float64_array, length, arraybuffer, 0, &result);
964
+
965
+ return result;
966
+ }
967
+
968
+ static napi_value HanningWindow(napi_env env, napi_callback_info info) {
969
+ size_t argc = 1;
970
+ napi_value args[1];
971
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
972
+
973
+ int32_t length;
974
+ NAPI_CHECK(napi_get_value_int32(env, args[0], &length));
975
+
976
+ napi_value arraybuffer;
977
+ void* data;
978
+ napi_create_arraybuffer(env, length * sizeof(double), &data, &arraybuffer);
979
+ double* window = static_cast<double*>(data);
980
+
981
+ vDSP_hann_windowD(window, length, 0);
982
+
983
+ napi_value result;
984
+ napi_create_typedarray(env, napi_float64_array, length, arraybuffer, 0, &result);
985
+
986
+ return result;
987
+ }
988
+
989
+ static napi_value BlackmanWindow(napi_env env, napi_callback_info info) {
990
+ size_t argc = 1;
991
+ napi_value args[1];
992
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
993
+
994
+ int32_t length;
995
+ NAPI_CHECK(napi_get_value_int32(env, args[0], &length));
996
+
997
+ napi_value arraybuffer;
998
+ void* data;
999
+ napi_create_arraybuffer(env, length * sizeof(double), &data, &arraybuffer);
1000
+ double* window = static_cast<double*>(data);
1001
+
1002
+ vDSP_blkman_windowD(window, length, 0);
1003
+
1004
+ napi_value result;
1005
+ napi_create_typedarray(env, napi_float64_array, length, arraybuffer, 0, &result);
1006
+
1007
+ return result;
1008
+ }
1009
+
1010
+ // Matrix transpose
1011
+ static napi_value MatrixTranspose(napi_env env, napi_callback_info info) {
1012
+ size_t argc = 4;
1013
+ napi_value args[4];
1014
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1015
+
1016
+ size_t len_a, len_b;
1017
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
1018
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
1019
+
1020
+ if (!A || !B) {
1021
+ NAPI_THROW(env, "First two arguments must be Float64Arrays");
1022
+ }
1023
+
1024
+ int32_t rows, cols;
1025
+ NAPI_CHECK(napi_get_value_int32(env, args[2], &rows));
1026
+ NAPI_CHECK(napi_get_value_int32(env, args[3], &cols));
1027
+
1028
+ vDSP_mtransD(A, 1, B, 1, cols, rows);
1029
+
1030
+ return args[1];
1031
+ }
1032
+
1033
+ // Inverse FFT
1034
+ static napi_value IFFT(napi_env env, napi_callback_info info) {
1035
+ size_t argc = 2;
1036
+ napi_value args[2];
1037
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1038
+
1039
+ size_t real_len, imag_len;
1040
+ double* real_in = GetFloat64ArrayData(env, args[0], &real_len);
1041
+ double* imag_in = GetFloat64ArrayData(env, args[1], &imag_len);
1042
+
1043
+ if (!real_in || !imag_in) {
1044
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1045
+ }
1046
+
1047
+ if (real_len != imag_len) {
1048
+ NAPI_THROW(env, "Real and imaginary arrays must have same length");
1049
+ }
1050
+
1051
+ size_t half = real_len;
1052
+ size_t len = half * 2;
1053
+
1054
+ vDSP_Length log2n = 0;
1055
+ vDSP_Length n = len;
1056
+ while (n > 1) {
1057
+ n >>= 1;
1058
+ log2n++;
1059
+ }
1060
+
1061
+ if ((1UL << log2n) != len) {
1062
+ NAPI_THROW(env, "Length must be power of 2");
1063
+ }
1064
+
1065
+ FFTSetupD setup = vDSP_create_fftsetupD(log2n, FFT_RADIX2);
1066
+ if (!setup) {
1067
+ NAPI_THROW(env, "Failed to create FFT setup");
1068
+ }
1069
+
1070
+ std::vector<double> real(half);
1071
+ std::vector<double> imag(half);
1072
+ memcpy(real.data(), real_in, half * sizeof(double));
1073
+ memcpy(imag.data(), imag_in, half * sizeof(double));
1074
+
1075
+ DSPDoubleSplitComplex split;
1076
+ split.realp = real.data();
1077
+ split.imagp = imag.data();
1078
+
1079
+ vDSP_fft_zripD(setup, &split, 1, log2n, FFT_INVERSE);
1080
+
1081
+ double scale = 1.0 / len;
1082
+ vDSP_vsmulD(split.realp, 1, &scale, split.realp, 1, half);
1083
+ vDSP_vsmulD(split.imagp, 1, &scale, split.imagp, 1, half);
1084
+
1085
+ napi_value arraybuffer;
1086
+ void* data;
1087
+ napi_create_arraybuffer(env, len * sizeof(double), &data, &arraybuffer);
1088
+ double* output = static_cast<double*>(data);
1089
+
1090
+ vDSP_ztocD(&split, 1, (DSPDoubleComplex*)output, 2, half);
1091
+
1092
+ napi_value result;
1093
+ napi_create_typedarray(env, napi_float64_array, len, arraybuffer, 0, &result);
1094
+
1095
+ vDSP_destroy_fftsetupD(setup);
1096
+
1097
+ return result;
1098
+ }
1099
+
1100
+ // Linear interpolation
1101
+ static napi_value Interp1D(napi_env env, napi_callback_info info) {
1102
+ size_t argc = 4;
1103
+ napi_value args[4];
1104
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1105
+
1106
+ size_t x_len, y_len, xi_len, yi_len;
1107
+ double* x = GetFloat64ArrayData(env, args[0], &x_len);
1108
+ double* y = GetFloat64ArrayData(env, args[1], &y_len);
1109
+ double* xi = GetFloat64ArrayData(env, args[2], &xi_len);
1110
+ double* yi = GetFloat64ArrayData(env, args[3], &yi_len);
1111
+
1112
+ if (!x || !y || !xi || !yi) {
1113
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1114
+ }
1115
+
1116
+ // Simple linear interpolation implementation
1117
+ for (size_t i = 0; i < xi_len; i++) {
1118
+ double xi_val = xi[i];
1119
+
1120
+ // Find the interval
1121
+ size_t j = 0;
1122
+ while (j < x_len - 1 && x[j + 1] < xi_val) {
1123
+ j++;
1124
+ }
1125
+
1126
+ if (j >= x_len - 1) {
1127
+ yi[i] = y[x_len - 1];
1128
+ } else {
1129
+ // Linear interpolation
1130
+ double t = (xi_val - x[j]) / (x[j + 1] - x[j]);
1131
+ yi[i] = y[j] + t * (y[j + 1] - y[j]);
1132
+ }
1133
+ }
1134
+
1135
+ return args[3];
1136
+ }
1137
+
1138
+ // Reverse vector
1139
+ static napi_value VectorReverse(napi_env env, napi_callback_info info) {
1140
+ size_t argc = 2;
1141
+ napi_value args[2];
1142
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1143
+
1144
+ size_t len_a, len_b;
1145
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
1146
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
1147
+
1148
+ if (!A || !B) {
1149
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1150
+ }
1151
+
1152
+ size_t len = len_a < len_b ? len_a : len_b;
1153
+
1154
+ // vDSP_vrvrsD reverses in-place, so copy first then reverse
1155
+ memcpy(B, A, len * sizeof(double));
1156
+ vDSP_vrvrsD(B, 1, len);
1157
+
1158
+ return args[1];
1159
+ }
1160
+
1161
+ // Vector negate
1162
+ static napi_value VectorNegate(napi_env env, napi_callback_info info) {
1163
+ size_t argc = 2;
1164
+ napi_value args[2];
1165
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1166
+
1167
+ size_t len_a, len_b;
1168
+ double* A = GetFloat64ArrayData(env, args[0], &len_a);
1169
+ double* B = GetFloat64ArrayData(env, args[1], &len_b);
1170
+
1171
+ if (!A || !B) {
1172
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1173
+ }
1174
+
1175
+ size_t len = len_a < len_b ? len_a : len_b;
1176
+ vDSP_vnegD(A, 1, B, 1, len);
1177
+
1178
+ return args[1];
1179
+ }
1180
+
1181
+ // Sum of squares
1182
+ static napi_value SumOfSquares(napi_env env, napi_callback_info info) {
1183
+ size_t argc = 1;
1184
+ napi_value args[1];
1185
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1186
+
1187
+ size_t len;
1188
+ double* A = GetFloat64ArrayData(env, args[0], &len);
1189
+
1190
+ if (!A) {
1191
+ NAPI_THROW(env, "Argument must be Float64Array");
1192
+ }
1193
+
1194
+ double result;
1195
+ vDSP_svesqD(A, 1, &result, len);
1196
+
1197
+ napi_value js_result;
1198
+ napi_create_double(env, result, &js_result);
1199
+ return js_result;
1200
+ }
1201
+
1202
+ // Mean magnitude
1203
+ static napi_value MeanMagnitude(napi_env env, napi_callback_info info) {
1204
+ size_t argc = 1;
1205
+ napi_value args[1];
1206
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1207
+
1208
+ size_t len;
1209
+ double* A = GetFloat64ArrayData(env, args[0], &len);
1210
+
1211
+ if (!A) {
1212
+ NAPI_THROW(env, "Argument must be Float64Array");
1213
+ }
1214
+
1215
+ double result;
1216
+ vDSP_meamgvD(A, 1, &result, len);
1217
+
1218
+ napi_value js_result;
1219
+ napi_create_double(env, result, &js_result);
1220
+ return js_result;
1221
+ }
1222
+
1223
+ // Mean square
1224
+ static napi_value MeanSquare(napi_env env, napi_callback_info info) {
1225
+ size_t argc = 1;
1226
+ napi_value args[1];
1227
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1228
+
1229
+ size_t len;
1230
+ double* A = GetFloat64ArrayData(env, args[0], &len);
1231
+
1232
+ if (!A) {
1233
+ NAPI_THROW(env, "Argument must be Float64Array");
1234
+ }
1235
+
1236
+ double result;
1237
+ vDSP_measqvD(A, 1, &result, len);
1238
+
1239
+ napi_value js_result;
1240
+ napi_create_double(env, result, &js_result);
1241
+ return js_result;
1242
+ }
1243
+
1244
+ // ============================================================================
1245
+ // ADDITIONAL BLAS OPERATIONS
1246
+ // ============================================================================
1247
+
1248
+ // Vector copy: y = x
1249
+ static napi_value VectorCopy(napi_env env, napi_callback_info info) {
1250
+ size_t argc = 2;
1251
+ napi_value args[2];
1252
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1253
+
1254
+ size_t len_x, len_y;
1255
+ double* x = GetFloat64ArrayData(env, args[0], &len_x);
1256
+ double* y = GetFloat64ArrayData(env, args[1], &len_y);
1257
+
1258
+ if (!x || !y) {
1259
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1260
+ }
1261
+
1262
+ size_t len = len_x < len_y ? len_x : len_y;
1263
+ cblas_dcopy(len, x, 1, y, 1);
1264
+
1265
+ return args[1];
1266
+ }
1267
+
1268
+ // Vector swap: swap x and y
1269
+ static napi_value VectorSwap(napi_env env, napi_callback_info info) {
1270
+ size_t argc = 2;
1271
+ napi_value args[2];
1272
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1273
+
1274
+ size_t len_x, len_y;
1275
+ double* x = GetFloat64ArrayData(env, args[0], &len_x);
1276
+ double* y = GetFloat64ArrayData(env, args[1], &len_y);
1277
+
1278
+ if (!x || !y) {
1279
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1280
+ }
1281
+
1282
+ size_t len = len_x < len_y ? len_x : len_y;
1283
+ cblas_dswap(len, x, 1, y, 1);
1284
+
1285
+ return args[0];
1286
+ }
1287
+
1288
+ // Vector norm (L2 norm / Euclidean length)
1289
+ static napi_value VectorNorm(napi_env env, napi_callback_info info) {
1290
+ size_t argc = 1;
1291
+ napi_value args[1];
1292
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1293
+
1294
+ size_t len;
1295
+ double* x = GetFloat64ArrayData(env, args[0], &len);
1296
+
1297
+ if (!x) {
1298
+ NAPI_THROW(env, "Argument must be Float64Array");
1299
+ }
1300
+
1301
+ double result = cblas_dnrm2(len, x, 1);
1302
+
1303
+ napi_value js_result;
1304
+ napi_create_double(env, result, &js_result);
1305
+ return js_result;
1306
+ }
1307
+
1308
+ // Vector sum of absolute values
1309
+ static napi_value VectorAbsSum(napi_env env, napi_callback_info info) {
1310
+ size_t argc = 1;
1311
+ napi_value args[1];
1312
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1313
+
1314
+ size_t len;
1315
+ double* x = GetFloat64ArrayData(env, args[0], &len);
1316
+
1317
+ if (!x) {
1318
+ NAPI_THROW(env, "Argument must be Float64Array");
1319
+ }
1320
+
1321
+ double result = cblas_dasum(len, x, 1);
1322
+
1323
+ napi_value js_result;
1324
+ napi_create_double(env, result, &js_result);
1325
+ return js_result;
1326
+ }
1327
+
1328
+ // Index of maximum absolute value
1329
+ static napi_value VectorMaxAbsIndex(napi_env env, napi_callback_info info) {
1330
+ size_t argc = 1;
1331
+ napi_value args[1];
1332
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1333
+
1334
+ size_t len;
1335
+ double* x = GetFloat64ArrayData(env, args[0], &len);
1336
+
1337
+ if (!x) {
1338
+ NAPI_THROW(env, "Argument must be Float64Array");
1339
+ }
1340
+
1341
+ size_t result = cblas_idamax(len, x, 1);
1342
+
1343
+ napi_value js_result;
1344
+ napi_create_uint32(env, result, &js_result);
1345
+ return js_result;
1346
+ }
1347
+
1348
+ // Rotation: apply Givens rotation
1349
+ static napi_value VectorRotation(napi_env env, napi_callback_info info) {
1350
+ size_t argc = 4;
1351
+ napi_value args[4];
1352
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1353
+
1354
+ size_t len_x, len_y;
1355
+ double* x = GetFloat64ArrayData(env, args[0], &len_x);
1356
+ double* y = GetFloat64ArrayData(env, args[1], &len_y);
1357
+
1358
+ if (!x || !y) {
1359
+ NAPI_THROW(env, "First two arguments must be Float64Arrays");
1360
+ }
1361
+
1362
+ double c, s;
1363
+ NAPI_CHECK(napi_get_value_double(env, args[2], &c));
1364
+ NAPI_CHECK(napi_get_value_double(env, args[3], &s));
1365
+
1366
+ size_t len = len_x < len_y ? len_x : len_y;
1367
+ cblas_drot(len, x, 1, y, 1, c, s);
1368
+
1369
+ return args[0];
1370
+ }
1371
+
1372
+ // ============================================================================
1373
+ // ADDITIONAL vDSP OPERATIONS
1374
+ // ============================================================================
1375
+
1376
+ // Vector fill with scalar
1377
+ static napi_value VectorFill(napi_env env, napi_callback_info info) {
1378
+ size_t argc = 2;
1379
+ napi_value args[2];
1380
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1381
+
1382
+ double scalar;
1383
+ NAPI_CHECK(napi_get_value_double(env, args[0], &scalar));
1384
+
1385
+ size_t len;
1386
+ double* vec = GetFloat64ArrayData(env, args[1], &len);
1387
+
1388
+ if (!vec) {
1389
+ NAPI_THROW(env, "Second argument must be Float64Array");
1390
+ }
1391
+
1392
+ vDSP_vfillD(&scalar, vec, 1, len);
1393
+
1394
+ return args[1];
1395
+ }
1396
+
1397
+ // Vector ramp: generate linear sequence
1398
+ static napi_value VectorRamp(napi_env env, napi_callback_info info) {
1399
+ size_t argc = 3;
1400
+ napi_value args[3];
1401
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1402
+
1403
+ double start, step;
1404
+ NAPI_CHECK(napi_get_value_double(env, args[0], &start));
1405
+ NAPI_CHECK(napi_get_value_double(env, args[1], &step));
1406
+
1407
+ size_t len;
1408
+ double* vec = GetFloat64ArrayData(env, args[2], &len);
1409
+
1410
+ if (!vec) {
1411
+ NAPI_THROW(env, "Third argument must be Float64Array");
1412
+ }
1413
+
1414
+ vDSP_vrampD(&start, &step, vec, 1, len);
1415
+
1416
+ return args[2];
1417
+ }
1418
+
1419
+ // Vector add with scalar: c = a + b (scalar)
1420
+ static napi_value VectorAddScalar(napi_env env, napi_callback_info info) {
1421
+ size_t argc = 3;
1422
+ napi_value args[3];
1423
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1424
+
1425
+ size_t len_a, len_c;
1426
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1427
+
1428
+ double scalar;
1429
+ NAPI_CHECK(napi_get_value_double(env, args[1], &scalar));
1430
+
1431
+ double* c = GetFloat64ArrayData(env, args[2], &len_c);
1432
+
1433
+ if (!a || !c) {
1434
+ NAPI_THROW(env, "First and third arguments must be Float64Arrays");
1435
+ }
1436
+
1437
+ size_t len = len_a < len_c ? len_a : len_c;
1438
+ vDSP_vsaddD(a, 1, &scalar, c, 1, len);
1439
+
1440
+ return args[2];
1441
+ }
1442
+
1443
+ // Vector multiply and add: d = (a * b) + c
1444
+ static napi_value VectorMultiplyAdd(napi_env env, napi_callback_info info) {
1445
+ size_t argc = 4;
1446
+ napi_value args[4];
1447
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1448
+
1449
+ size_t len_a, len_b, len_c, len_d;
1450
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1451
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1452
+ double* c = GetFloat64ArrayData(env, args[2], &len_c);
1453
+ double* d = GetFloat64ArrayData(env, args[3], &len_d);
1454
+
1455
+ if (!a || !b || !c || !d) {
1456
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1457
+ }
1458
+
1459
+ size_t len = len_a;
1460
+ if (len_b < len) len = len_b;
1461
+ if (len_c < len) len = len_c;
1462
+ if (len_d < len) len = len_d;
1463
+
1464
+ vDSP_vmaD(a, 1, b, 1, c, 1, d, 1, len);
1465
+
1466
+ return args[3];
1467
+ }
1468
+
1469
+ // Vector multiply and scalar add: d = (a * b) + c (scalar)
1470
+ static napi_value VectorMultiplyScalarAdd(napi_env env, napi_callback_info info) {
1471
+ size_t argc = 4;
1472
+ napi_value args[4];
1473
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1474
+
1475
+ size_t len_a, len_b, len_d;
1476
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1477
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1478
+
1479
+ double c;
1480
+ NAPI_CHECK(napi_get_value_double(env, args[2], &c));
1481
+
1482
+ double* d = GetFloat64ArrayData(env, args[3], &len_d);
1483
+
1484
+ if (!a || !b || !d) {
1485
+ NAPI_THROW(env, "First, second, and fourth arguments must be Float64Arrays");
1486
+ }
1487
+
1488
+ size_t len = len_a;
1489
+ if (len_b < len) len = len_b;
1490
+ if (len_d < len) len = len_d;
1491
+
1492
+ vDSP_vmsaD(a, 1, b, 1, &c, d, 1, len);
1493
+
1494
+ return args[3];
1495
+ }
1496
+
1497
+ // Linear interpolation between two vectors
1498
+ static napi_value VectorLinearInterpolate(napi_env env, napi_callback_info info) {
1499
+ size_t argc = 4;
1500
+ napi_value args[4];
1501
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1502
+
1503
+ size_t len_a, len_b, len_c;
1504
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1505
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1506
+
1507
+ double t;
1508
+ NAPI_CHECK(napi_get_value_double(env, args[2], &t));
1509
+
1510
+ double* c = GetFloat64ArrayData(env, args[3], &len_c);
1511
+
1512
+ if (!a || !b || !c) {
1513
+ NAPI_THROW(env, "First, second, and fourth arguments must be Float64Arrays");
1514
+ }
1515
+
1516
+ size_t len = len_a;
1517
+ if (len_b < len) len = len_b;
1518
+ if (len_c < len) len = len_c;
1519
+
1520
+ vDSP_vintbD(a, 1, b, 1, &t, c, 1, len);
1521
+
1522
+ return args[3];
1523
+ }
1524
+
1525
+ // Vector clear (set to zero)
1526
+ static napi_value VectorClear(napi_env env, napi_callback_info info) {
1527
+ size_t argc = 1;
1528
+ napi_value args[1];
1529
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1530
+
1531
+ size_t len;
1532
+ double* vec = GetFloat64ArrayData(env, args[0], &len);
1533
+
1534
+ if (!vec) {
1535
+ NAPI_THROW(env, "Argument must be Float64Array");
1536
+ }
1537
+
1538
+ vDSP_vclrD(vec, 1, len);
1539
+
1540
+ return args[0];
1541
+ }
1542
+
1543
+ // Vector limit (saturate)
1544
+ static napi_value VectorLimit(napi_env env, napi_callback_info info) {
1545
+ size_t argc = 4;
1546
+ napi_value args[4];
1547
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1548
+
1549
+ size_t len_a, len_c;
1550
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1551
+
1552
+ double low, high;
1553
+ NAPI_CHECK(napi_get_value_double(env, args[1], &low));
1554
+ NAPI_CHECK(napi_get_value_double(env, args[2], &high));
1555
+
1556
+ double* c = GetFloat64ArrayData(env, args[3], &len_c);
1557
+
1558
+ if (!a || !c) {
1559
+ NAPI_THROW(env, "First and fourth arguments must be Float64Arrays");
1560
+ }
1561
+
1562
+ size_t len = len_a < len_c ? len_a : len_c;
1563
+ vDSP_vlimD(a, 1, &low, &high, c, 1, len);
1564
+
1565
+ return args[3];
1566
+ }
1567
+
1568
+ // Vector maximum magnitude
1569
+ static napi_value VectorMaxMagnitude(napi_env env, napi_callback_info info) {
1570
+ size_t argc = 1;
1571
+ napi_value args[1];
1572
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1573
+
1574
+ size_t len;
1575
+ double* a = GetFloat64ArrayData(env, args[0], &len);
1576
+
1577
+ if (!a) {
1578
+ NAPI_THROW(env, "Argument must be Float64Array");
1579
+ }
1580
+
1581
+ double result;
1582
+ vDSP_maxmgvD(a, 1, &result, len);
1583
+
1584
+ napi_value js_result;
1585
+ napi_create_double(env, result, &js_result);
1586
+ return js_result;
1587
+ }
1588
+
1589
+ // Vector minimum magnitude
1590
+ static napi_value VectorMinMagnitude(napi_env env, napi_callback_info info) {
1591
+ size_t argc = 1;
1592
+ napi_value args[1];
1593
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1594
+
1595
+ size_t len;
1596
+ double* a = GetFloat64ArrayData(env, args[0], &len);
1597
+
1598
+ if (!a) {
1599
+ NAPI_THROW(env, "Argument must be Float64Array");
1600
+ }
1601
+
1602
+ double result;
1603
+ vDSP_minmgvD(a, 1, &result, len);
1604
+
1605
+ napi_value js_result;
1606
+ napi_create_double(env, result, &js_result);
1607
+ return js_result;
1608
+ }
1609
+
1610
+ // ============================================================================
1611
+ // MORE MATH FUNCTIONS (vForce)
1612
+ // ============================================================================
1613
+
1614
+ // Inverse (reciprocal): b = 1/a
1615
+ static napi_value VectorReciprocal(napi_env env, napi_callback_info info) {
1616
+ size_t argc = 2;
1617
+ napi_value args[2];
1618
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1619
+
1620
+ size_t len_a, len_b;
1621
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1622
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1623
+
1624
+ if (!a || !b) {
1625
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1626
+ }
1627
+
1628
+ size_t len = len_a < len_b ? len_a : len_b;
1629
+ int n = (int)len;
1630
+ vvrec(b, a, &n);
1631
+
1632
+ return args[1];
1633
+ }
1634
+
1635
+ // Inverse square root: b = 1/sqrt(a)
1636
+ static napi_value VectorInverseSqrt(napi_env env, napi_callback_info info) {
1637
+ size_t argc = 2;
1638
+ napi_value args[2];
1639
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1640
+
1641
+ size_t len_a, len_b;
1642
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1643
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1644
+
1645
+ if (!a || !b) {
1646
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1647
+ }
1648
+
1649
+ size_t len = len_a < len_b ? len_a : len_b;
1650
+ int n = (int)len;
1651
+ vvrsqrt(b, a, &n);
1652
+
1653
+ return args[1];
1654
+ }
1655
+
1656
+ // Hyperbolic sine
1657
+ static napi_value VectorSinh(napi_env env, napi_callback_info info) {
1658
+ size_t argc = 2;
1659
+ napi_value args[2];
1660
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1661
+
1662
+ size_t len_a, len_b;
1663
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1664
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1665
+
1666
+ if (!a || !b) {
1667
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1668
+ }
1669
+
1670
+ size_t len = len_a < len_b ? len_a : len_b;
1671
+ int n = (int)len;
1672
+ vvsinh(b, a, &n);
1673
+
1674
+ return args[1];
1675
+ }
1676
+
1677
+ // Hyperbolic cosine
1678
+ static napi_value VectorCosh(napi_env env, napi_callback_info info) {
1679
+ size_t argc = 2;
1680
+ napi_value args[2];
1681
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1682
+
1683
+ size_t len_a, len_b;
1684
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1685
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1686
+
1687
+ if (!a || !b) {
1688
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1689
+ }
1690
+
1691
+ size_t len = len_a < len_b ? len_a : len_b;
1692
+ int n = (int)len;
1693
+ vvcosh(b, a, &n);
1694
+
1695
+ return args[1];
1696
+ }
1697
+
1698
+ // Hyperbolic tangent
1699
+ static napi_value VectorTanh(napi_env env, napi_callback_info info) {
1700
+ size_t argc = 2;
1701
+ napi_value args[2];
1702
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1703
+
1704
+ size_t len_a, len_b;
1705
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1706
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1707
+
1708
+ if (!a || !b) {
1709
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1710
+ }
1711
+
1712
+ size_t len = len_a < len_b ? len_a : len_b;
1713
+ int n = (int)len;
1714
+ vvtanh(b, a, &n);
1715
+
1716
+ return args[1];
1717
+ }
1718
+
1719
+ // Inverse trig functions
1720
+ static napi_value VectorAsin(napi_env env, napi_callback_info info) {
1721
+ size_t argc = 2;
1722
+ napi_value args[2];
1723
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1724
+
1725
+ size_t len_a, len_b;
1726
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1727
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1728
+
1729
+ if (!a || !b) {
1730
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1731
+ }
1732
+
1733
+ size_t len = len_a < len_b ? len_a : len_b;
1734
+ int n = (int)len;
1735
+ vvasin(b, a, &n);
1736
+
1737
+ return args[1];
1738
+ }
1739
+
1740
+ static napi_value VectorAcos(napi_env env, napi_callback_info info) {
1741
+ size_t argc = 2;
1742
+ napi_value args[2];
1743
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1744
+
1745
+ size_t len_a, len_b;
1746
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1747
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1748
+
1749
+ if (!a || !b) {
1750
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1751
+ }
1752
+
1753
+ size_t len = len_a < len_b ? len_a : len_b;
1754
+ int n = (int)len;
1755
+ vvacos(b, a, &n);
1756
+
1757
+ return args[1];
1758
+ }
1759
+
1760
+ static napi_value VectorAtan(napi_env env, napi_callback_info info) {
1761
+ size_t argc = 2;
1762
+ napi_value args[2];
1763
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1764
+
1765
+ size_t len_a, len_b;
1766
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1767
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1768
+
1769
+ if (!a || !b) {
1770
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1771
+ }
1772
+
1773
+ size_t len = len_a < len_b ? len_a : len_b;
1774
+ int n = (int)len;
1775
+ vvatan(b, a, &n);
1776
+
1777
+ return args[1];
1778
+ }
1779
+
1780
+ // Atan2: c = atan2(a, b)
1781
+ static napi_value VectorAtan2(napi_env env, napi_callback_info info) {
1782
+ size_t argc = 3;
1783
+ napi_value args[3];
1784
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1785
+
1786
+ size_t len_a, len_b, len_c;
1787
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1788
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1789
+ double* c = GetFloat64ArrayData(env, args[2], &len_c);
1790
+
1791
+ if (!a || !b || !c) {
1792
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1793
+ }
1794
+
1795
+ size_t len = len_a;
1796
+ if (len_b < len) len = len_b;
1797
+ if (len_c < len) len = len_c;
1798
+ int n = (int)len;
1799
+ vvatan2(c, a, b, &n);
1800
+
1801
+ return args[2];
1802
+ }
1803
+
1804
+ // Ceiling
1805
+ static napi_value VectorCeil(napi_env env, napi_callback_info info) {
1806
+ size_t argc = 2;
1807
+ napi_value args[2];
1808
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1809
+
1810
+ size_t len_a, len_b;
1811
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1812
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1813
+
1814
+ if (!a || !b) {
1815
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1816
+ }
1817
+
1818
+ size_t len = len_a < len_b ? len_a : len_b;
1819
+ int n = (int)len;
1820
+ vvceil(b, a, &n);
1821
+
1822
+ return args[1];
1823
+ }
1824
+
1825
+ // Floor
1826
+ static napi_value VectorFloor(napi_env env, napi_callback_info info) {
1827
+ size_t argc = 2;
1828
+ napi_value args[2];
1829
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1830
+
1831
+ size_t len_a, len_b;
1832
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1833
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1834
+
1835
+ if (!a || !b) {
1836
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1837
+ }
1838
+
1839
+ size_t len = len_a < len_b ? len_a : len_b;
1840
+ int n = (int)len;
1841
+ vvfloor(b, a, &n);
1842
+
1843
+ return args[1];
1844
+ }
1845
+
1846
+ // Truncate (round toward zero)
1847
+ static napi_value VectorTrunc(napi_env env, napi_callback_info info) {
1848
+ size_t argc = 2;
1849
+ napi_value args[2];
1850
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1851
+
1852
+ size_t len_a, len_b;
1853
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1854
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1855
+
1856
+ if (!a || !b) {
1857
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1858
+ }
1859
+
1860
+ size_t len = len_a < len_b ? len_a : len_b;
1861
+ int n = (int)len;
1862
+ vvint(b, a, &n);
1863
+
1864
+ return args[1];
1865
+ }
1866
+
1867
+ // Copysign: c = copysign(a, b) - magnitude of a with sign of b
1868
+ static napi_value VectorCopysign(napi_env env, napi_callback_info info) {
1869
+ size_t argc = 3;
1870
+ napi_value args[3];
1871
+ NAPI_CHECK(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1872
+
1873
+ size_t len_a, len_b, len_c;
1874
+ double* a = GetFloat64ArrayData(env, args[0], &len_a);
1875
+ double* b = GetFloat64ArrayData(env, args[1], &len_b);
1876
+ double* c = GetFloat64ArrayData(env, args[2], &len_c);
1877
+
1878
+ if (!a || !b || !c) {
1879
+ NAPI_THROW(env, "Arguments must be Float64Arrays");
1880
+ }
1881
+
1882
+ size_t len = len_a;
1883
+ if (len_b < len) len = len_b;
1884
+ if (len_c < len) len = len_c;
1885
+ int n = (int)len;
1886
+ vvcopysign(c, b, a, &n);
1887
+
1888
+ return args[2];
1889
+ }
1890
+
613
1891
  // Module initialization
614
1892
  static napi_value Init(napi_env env, napi_value exports) {
615
1893
  napi_property_descriptor props[] = {
@@ -617,9 +1895,16 @@ static napi_value Init(napi_env env, napi_value exports) {
617
1895
  {"matmul", nullptr, MatMulDouble, nullptr, nullptr, nullptr, napi_default, nullptr},
618
1896
  {"matmulFloat", nullptr, MatMulFloat, nullptr, nullptr, nullptr, napi_default, nullptr},
619
1897
  {"matvec", nullptr, MatVecMul, nullptr, nullptr, nullptr, napi_default, nullptr},
1898
+ {"transpose", nullptr, MatrixTranspose, nullptr, nullptr, nullptr, napi_default, nullptr},
620
1899
 
621
1900
  // BLAS operations
622
1901
  {"axpy", nullptr, AXPY, nullptr, nullptr, nullptr, napi_default, nullptr},
1902
+ {"copy", nullptr, VectorCopy, nullptr, nullptr, nullptr, napi_default, nullptr},
1903
+ {"swap", nullptr, VectorSwap, nullptr, nullptr, nullptr, napi_default, nullptr},
1904
+ {"norm", nullptr, VectorNorm, nullptr, nullptr, nullptr, napi_default, nullptr},
1905
+ {"abssum", nullptr, VectorAbsSum, nullptr, nullptr, nullptr, napi_default, nullptr},
1906
+ {"maxAbsIndex", nullptr, VectorMaxAbsIndex, nullptr, nullptr, nullptr, napi_default, nullptr},
1907
+ {"rot", nullptr, VectorRotation, nullptr, nullptr, nullptr, napi_default, nullptr},
623
1908
 
624
1909
  // Vector arithmetic
625
1910
  {"dot", nullptr, DotProduct, nullptr, nullptr, nullptr, napi_default, nullptr},
@@ -628,25 +1913,86 @@ static napi_value Init(napi_env env, napi_value exports) {
628
1913
  {"vmul", nullptr, VectorMul, nullptr, nullptr, nullptr, napi_default, nullptr},
629
1914
  {"vdiv", nullptr, VectorDiv, nullptr, nullptr, nullptr, napi_default, nullptr},
630
1915
  {"vscale", nullptr, VectorScale, nullptr, nullptr, nullptr, napi_default, nullptr},
1916
+ {"vneg", nullptr, VectorNegate, nullptr, nullptr, nullptr, napi_default, nullptr},
1917
+ {"vaddScalar", nullptr, VectorAddScalar, nullptr, nullptr, nullptr, napi_default, nullptr},
1918
+ {"vma", nullptr, VectorMultiplyAdd, nullptr, nullptr, nullptr, napi_default, nullptr},
1919
+ {"vmsa", nullptr, VectorMultiplyScalarAdd, nullptr, nullptr, nullptr, napi_default, nullptr},
631
1920
 
632
1921
  // Vector functions
633
1922
  {"vabs", nullptr, VectorAbs, nullptr, nullptr, nullptr, napi_default, nullptr},
634
1923
  {"vsquare", nullptr, VectorSquare, nullptr, nullptr, nullptr, napi_default, nullptr},
635
1924
  {"vsqrt", nullptr, VectorSqrt, nullptr, nullptr, nullptr, napi_default, nullptr},
636
1925
  {"normalize", nullptr, VectorNormalize, nullptr, nullptr, nullptr, napi_default, nullptr},
1926
+ {"vreverse", nullptr, VectorReverse, nullptr, nullptr, nullptr, napi_default, nullptr},
1927
+ {"vfill", nullptr, VectorFill, nullptr, nullptr, nullptr, napi_default, nullptr},
1928
+ {"vramp", nullptr, VectorRamp, nullptr, nullptr, nullptr, napi_default, nullptr},
1929
+ {"vlerp", nullptr, VectorLinearInterpolate, nullptr, nullptr, nullptr, napi_default, nullptr},
1930
+ {"vclear", nullptr, VectorClear, nullptr, nullptr, nullptr, napi_default, nullptr},
1931
+ {"vlimit", nullptr, VectorLimit, nullptr, nullptr, nullptr, napi_default, nullptr},
1932
+
1933
+ // Trigonometric
1934
+ {"vsin", nullptr, VectorSin, nullptr, nullptr, nullptr, napi_default, nullptr},
1935
+ {"vcos", nullptr, VectorCos, nullptr, nullptr, nullptr, napi_default, nullptr},
1936
+ {"vtan", nullptr, VectorTan, nullptr, nullptr, nullptr, napi_default, nullptr},
1937
+ {"vasin", nullptr, VectorAsin, nullptr, nullptr, nullptr, napi_default, nullptr},
1938
+ {"vacos", nullptr, VectorAcos, nullptr, nullptr, nullptr, napi_default, nullptr},
1939
+ {"vatan", nullptr, VectorAtan, nullptr, nullptr, nullptr, napi_default, nullptr},
1940
+ {"vatan2", nullptr, VectorAtan2, nullptr, nullptr, nullptr, napi_default, nullptr},
1941
+
1942
+ // Hyperbolic
1943
+ {"vsinh", nullptr, VectorSinh, nullptr, nullptr, nullptr, napi_default, nullptr},
1944
+ {"vcosh", nullptr, VectorCosh, nullptr, nullptr, nullptr, napi_default, nullptr},
1945
+ {"vtanh", nullptr, VectorTanh, nullptr, nullptr, nullptr, napi_default, nullptr},
1946
+
1947
+ // Exponential/Logarithmic
1948
+ {"vexp", nullptr, VectorExp, nullptr, nullptr, nullptr, napi_default, nullptr},
1949
+ {"vlog", nullptr, VectorLog, nullptr, nullptr, nullptr, napi_default, nullptr},
1950
+ {"vlog10", nullptr, VectorLog10, nullptr, nullptr, nullptr, napi_default, nullptr},
1951
+ {"vpow", nullptr, VectorPow, nullptr, nullptr, nullptr, napi_default, nullptr},
1952
+ {"vreciprocal", nullptr, VectorReciprocal, nullptr, nullptr, nullptr, napi_default, nullptr},
1953
+ {"vrsqrt", nullptr, VectorInverseSqrt, nullptr, nullptr, nullptr, napi_default, nullptr},
1954
+
1955
+ // Rounding
1956
+ {"vceil", nullptr, VectorCeil, nullptr, nullptr, nullptr, napi_default, nullptr},
1957
+ {"vfloor", nullptr, VectorFloor, nullptr, nullptr, nullptr, napi_default, nullptr},
1958
+ {"vtrunc", nullptr, VectorTrunc, nullptr, nullptr, nullptr, napi_default, nullptr},
1959
+ {"vcopysign", nullptr, VectorCopysign, nullptr, nullptr, nullptr, napi_default, nullptr},
1960
+
1961
+ // Clipping/Thresholding
1962
+ {"vclip", nullptr, VectorClip, nullptr, nullptr, nullptr, napi_default, nullptr},
1963
+ {"vthreshold", nullptr, VectorThreshold, nullptr, nullptr, nullptr, napi_default, nullptr},
637
1964
 
638
1965
  // Reductions
639
1966
  {"sum", nullptr, VectorSum, nullptr, nullptr, nullptr, napi_default, nullptr},
640
1967
  {"mean", nullptr, VectorMean, nullptr, nullptr, nullptr, napi_default, nullptr},
641
1968
  {"max", nullptr, VectorMax, nullptr, nullptr, nullptr, napi_default, nullptr},
642
1969
  {"min", nullptr, VectorMin, nullptr, nullptr, nullptr, napi_default, nullptr},
1970
+ {"minmax", nullptr, VectorMinMax, nullptr, nullptr, nullptr, napi_default, nullptr},
643
1971
  {"rms", nullptr, VectorRMS, nullptr, nullptr, nullptr, napi_default, nullptr},
1972
+ {"variance", nullptr, VectorVariance, nullptr, nullptr, nullptr, napi_default, nullptr},
1973
+ {"stddev", nullptr, VectorStdDev, nullptr, nullptr, nullptr, napi_default, nullptr},
1974
+ {"sumOfSquares", nullptr, SumOfSquares, nullptr, nullptr, nullptr, napi_default, nullptr},
1975
+ {"meanMagnitude", nullptr, MeanMagnitude, nullptr, nullptr, nullptr, napi_default, nullptr},
1976
+ {"meanSquare", nullptr, MeanSquare, nullptr, nullptr, nullptr, napi_default, nullptr},
1977
+ {"maxMagnitude", nullptr, VectorMaxMagnitude, nullptr, nullptr, nullptr, napi_default, nullptr},
1978
+ {"minMagnitude", nullptr, VectorMinMagnitude, nullptr, nullptr, nullptr, napi_default, nullptr},
644
1979
 
645
1980
  // Distance metrics
646
1981
  {"euclidean", nullptr, EuclideanDistance, nullptr, nullptr, nullptr, napi_default, nullptr},
647
1982
 
648
1983
  // Signal processing
649
1984
  {"fft", nullptr, FFT, nullptr, nullptr, nullptr, napi_default, nullptr},
1985
+ {"ifft", nullptr, IFFT, nullptr, nullptr, nullptr, napi_default, nullptr},
1986
+ {"conv", nullptr, Convolve, nullptr, nullptr, nullptr, napi_default, nullptr},
1987
+ {"xcorr", nullptr, CrossCorrelation, nullptr, nullptr, nullptr, napi_default, nullptr},
1988
+
1989
+ // Window functions
1990
+ {"hamming", nullptr, HammingWindow, nullptr, nullptr, nullptr, napi_default, nullptr},
1991
+ {"hanning", nullptr, HanningWindow, nullptr, nullptr, nullptr, napi_default, nullptr},
1992
+ {"blackman", nullptr, BlackmanWindow, nullptr, nullptr, nullptr, napi_default, nullptr},
1993
+
1994
+ // Interpolation
1995
+ {"interp1d", nullptr, Interp1D, nullptr, nullptr, nullptr, napi_default, nullptr},
650
1996
  };
651
1997
 
652
1998
  napi_define_properties(env, exports, sizeof(props) / sizeof(props[0]), props);