catniff 0.2.10 → 0.2.12

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 CHANGED
@@ -87,6 +87,9 @@ I'm mostly just learning and playing with this currently, so there are no concre
87
87
  * Proper documentation.
88
88
  * GPU acceleration.
89
89
  * Some general neural net APIs.
90
+ * Refactor code.
91
+ * Proper tests.
92
+ * Option to load more backends.
90
93
 
91
94
  ## Copyrights and License
92
95
 
package/dist/core.d.ts CHANGED
@@ -41,6 +41,8 @@ export declare class Tensor {
41
41
  sum(dims?: number[] | number, keepDims?: boolean): Tensor;
42
42
  prod(dims?: number[] | number, keepDims?: boolean): Tensor;
43
43
  mean(dims?: number[] | number, keepDims?: boolean): Tensor;
44
+ max(dims?: number[] | number, keepDims?: boolean): Tensor;
45
+ min(dims?: number[] | number, keepDims?: boolean): Tensor;
44
46
  add(other: TensorValue | Tensor): Tensor;
45
47
  sub(other: TensorValue | Tensor): Tensor;
46
48
  subtract: (other: TensorValue | Tensor) => Tensor;
@@ -112,6 +114,12 @@ export declare class Tensor {
112
114
  relu(): Tensor;
113
115
  sigmoid(): Tensor;
114
116
  tanh(): Tensor;
117
+ softplus(): Tensor;
118
+ softsign(): Tensor;
119
+ silu(): Tensor;
120
+ mish(): Tensor;
121
+ maximum(other: TensorValue | Tensor): Tensor;
122
+ minimum(other: TensorValue | Tensor): Tensor;
115
123
  round(): Tensor;
116
124
  floor(): Tensor;
117
125
  ceil(): Tensor;
@@ -120,6 +128,9 @@ export declare class Tensor {
120
128
  frac(): Tensor;
121
129
  clip(min: number, max: number): Tensor;
122
130
  clamp: (min: number, max: number) => Tensor;
131
+ erf(): Tensor;
132
+ erfc(): Tensor;
133
+ erfinv(): Tensor;
123
134
  transpose(dim1: number, dim2: number): Tensor;
124
135
  swapaxes: (dim1: number, dim2: number) => Tensor;
125
136
  swapdims: (dim1: number, dim2: number) => Tensor;
package/dist/core.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Tensor = void 0;
4
+ const utils_1 = require("./utils");
4
5
  class Tensor {
5
6
  value;
6
7
  shape;
@@ -251,7 +252,7 @@ class Tensor {
251
252
  // Tensor squeeze
252
253
  squeeze(dims) {
253
254
  if (typeof this.value === "number")
254
- return new Tensor(this.value);
255
+ return this;
255
256
  if (typeof dims === "number") {
256
257
  dims = [dims];
257
258
  }
@@ -299,10 +300,9 @@ class Tensor {
299
300
  }
300
301
  // Tensor unsqueeze - adds dimension of size 1 at specified position
301
302
  unsqueeze(dim) {
302
- if (typeof this.value === "number")
303
- return new Tensor([this.value]);
304
- if (dim < 0 || dim > this.shape.length) {
305
- throw new Error(`Invalid dimension ${dim} for unsqueeze`);
303
+ let thisValue = this.value;
304
+ if (typeof thisValue === "number") {
305
+ thisValue = [thisValue];
306
306
  }
307
307
  // Insert size-1 dimension at specified position
308
308
  const newShape = [...this.shape];
@@ -319,7 +319,7 @@ class Tensor {
319
319
  newDimStride = this.strides[dim] * this.shape[dim];
320
320
  }
321
321
  newStrides.splice(dim, 0, newDimStride);
322
- const out = new Tensor(this.value, { shape: newShape, strides: newStrides });
322
+ const out = new Tensor(thisValue, { shape: newShape, strides: newStrides });
323
323
  // Set up gradient if needed
324
324
  if (this.requiresGrad) {
325
325
  out.requiresGrad = true;
@@ -333,7 +333,7 @@ class Tensor {
333
333
  // Tensor sum reduction
334
334
  sum(dims, keepDims = false) {
335
335
  if (typeof this.value === "number")
336
- return new Tensor(this.value);
336
+ return this;
337
337
  if (typeof dims === "number") {
338
338
  dims = [dims];
339
339
  }
@@ -363,6 +363,7 @@ class Tensor {
363
363
  const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
364
364
  // Accumulate, outFlatIndex should match multiple realFlatIndexes
365
365
  const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
366
+ // Add into sum
366
367
  outputValue[outFlatIndex] += this.value[realFlatIndex];
367
368
  // Mark for gradient if needed
368
369
  if (this.requiresGrad) {
@@ -387,7 +388,7 @@ class Tensor {
387
388
  // Tensor product reduction
388
389
  prod(dims, keepDims = false) {
389
390
  if (typeof this.value === "number")
390
- return new Tensor(this.value);
391
+ return this;
391
392
  if (typeof dims === "number") {
392
393
  dims = [dims];
393
394
  }
@@ -400,14 +401,6 @@ class Tensor {
400
401
  const outputSize = Tensor.shapeToSize(outputShape);
401
402
  const outputValue = new Array(outputSize).fill(1);
402
403
  const originalSize = Tensor.shapeToSize(this.shape);
403
- // Gradient data
404
- let gradShape, gradStrides, gradValue = [];
405
- // Allocate gradient data only when needed
406
- if (this.requiresGrad) {
407
- gradShape = this.shape;
408
- gradStrides = this.strides;
409
- gradValue = new Array(originalSize).fill(0);
410
- }
411
404
  // Calculate new value after multiplying
412
405
  for (let index = 0; index < originalSize; index++) {
413
406
  const coords = Tensor.indexToCoords(index, this.strides);
@@ -417,6 +410,7 @@ class Tensor {
417
410
  const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
418
411
  // Accumulate, outFlatIndex should match multiple realFlatIndexes
419
412
  const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
413
+ // Multiply into product
420
414
  outputValue[outFlatIndex] *= this.value[realFlatIndex];
421
415
  }
422
416
  const out = new Tensor(outputValue, {
@@ -425,7 +419,7 @@ class Tensor {
425
419
  });
426
420
  // Set up gradient if needed
427
421
  if (this.requiresGrad) {
428
- // Grad is the product of other elements of the same axis, which is product of all els divided by the current value
422
+ const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
429
423
  for (let index = 0; index < originalSize; index++) {
430
424
  const coords = Tensor.indexToCoords(index, this.strides);
431
425
  // Force 0 on reduced axes to collapse into size-1 dims
@@ -434,7 +428,7 @@ class Tensor {
434
428
  const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
435
429
  // Accumulate, outFlatIndex should match multiple realFlatIndexes
436
430
  const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
437
- // Calculate gradient at position
431
+ // Grad is the product of other elements of the same axis, which is product of all els divided by the current value
438
432
  gradValue[realFlatIndex] = outputValue[outFlatIndex] / this.value[realFlatIndex];
439
433
  }
440
434
  out.requiresGrad = true;
@@ -449,7 +443,7 @@ class Tensor {
449
443
  // Tensor mean reduction
450
444
  mean(dims, keepDims = false) {
451
445
  if (typeof this.value === "number")
452
- return new Tensor(this.value);
446
+ return this;
453
447
  if (typeof dims === "number") {
454
448
  dims = [dims];
455
449
  }
@@ -463,14 +457,6 @@ class Tensor {
463
457
  const outputValue = new Array(outputSize).fill(0);
464
458
  const outputFeeders = new Array(outputSize).fill(0);
465
459
  const originalSize = Tensor.shapeToSize(this.shape);
466
- // Gradient data
467
- let gradShape, gradStrides, gradValue = [];
468
- // Allocate gradient data only when needed
469
- if (this.requiresGrad) {
470
- gradShape = this.shape;
471
- gradStrides = this.strides;
472
- gradValue = new Array(originalSize).fill(0);
473
- }
474
460
  // Calculate sums and how many elements contribute to specific positions
475
461
  for (let index = 0; index < originalSize; index++) {
476
462
  const coords = Tensor.indexToCoords(index, this.strides);
@@ -480,6 +466,7 @@ class Tensor {
480
466
  const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
481
467
  // Accumulate, outFlatIndex should match multiple realFlatIndexes
482
468
  const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
469
+ // Calculate sum and contributors to the sum
483
470
  outputValue[outFlatIndex] += this.value[realFlatIndex];
484
471
  outputFeeders[outFlatIndex]++;
485
472
  }
@@ -493,7 +480,8 @@ class Tensor {
493
480
  });
494
481
  // Set up gradient if needed
495
482
  if (this.requiresGrad) {
496
- // Calculate grad by assiging 1 divide by the number of contributors to the position
483
+ const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
484
+ // Calculate grad by assigning 1 divided by the number of contributors to the position
497
485
  for (let index = 0; index < originalSize; index++) {
498
486
  const coords = Tensor.indexToCoords(index, this.strides);
499
487
  // Force 0 on reduced axes to collapse into size-1 dims
@@ -514,6 +502,120 @@ class Tensor {
514
502
  }
515
503
  return keepDims ? out : out.squeeze(dims);
516
504
  }
505
+ // Tensor maximum reduction
506
+ max(dims, keepDims = false) {
507
+ if (typeof this.value === "number")
508
+ return this;
509
+ if (typeof dims === "number") {
510
+ dims = [dims];
511
+ }
512
+ if (typeof dims === "undefined") {
513
+ dims = Array.from({ length: this.shape.length }, (_, index) => index);
514
+ }
515
+ // Dims that are reduced now have size-1
516
+ const outputShape = this.shape.map((dim, i) => dims.includes(i) ? 1 : dim);
517
+ const outputStrides = Tensor.getStrides(outputShape);
518
+ const outputSize = Tensor.shapeToSize(outputShape);
519
+ const outputValue = new Array(outputSize).fill(-Infinity);
520
+ const originalSize = Tensor.shapeToSize(this.shape);
521
+ // Calculate maximum values of axes
522
+ for (let index = 0; index < originalSize; index++) {
523
+ const coords = Tensor.indexToCoords(index, this.strides);
524
+ // Force 0 on reduced axes to collapse into size-1 dims
525
+ const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
526
+ // Convert output coordinates to flat index
527
+ const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
528
+ // Accumulate, outFlatIndex should match multiple realFlatIndexes
529
+ const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
530
+ // Get max over time
531
+ if (this.value[realFlatIndex] > outputValue[outFlatIndex]) {
532
+ outputValue[outFlatIndex] = this.value[realFlatIndex];
533
+ }
534
+ }
535
+ const out = new Tensor(outputValue, {
536
+ shape: outputShape,
537
+ strides: outputStrides
538
+ });
539
+ // Set up gradient if needed
540
+ if (this.requiresGrad) {
541
+ const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
542
+ for (let index = 0; index < originalSize; index++) {
543
+ const coords = Tensor.indexToCoords(index, this.strides);
544
+ // Force 0 on reduced axes to collapse into size-1 dims
545
+ const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
546
+ // Convert output coordinates to flat index
547
+ const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
548
+ // Accumulate, outFlatIndex should match multiple realFlatIndexes
549
+ const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
550
+ // Calculate grad by checking if a positon holds a value equal to the max value
551
+ gradValue[realFlatIndex] = outputValue[outFlatIndex] === this.value[realFlatIndex] ? 1 : 0;
552
+ }
553
+ out.requiresGrad = true;
554
+ out.children.push(this);
555
+ out.gradFn = () => {
556
+ const localGrad = new Tensor(gradValue, { shape: gradShape, strides: gradStrides });
557
+ Tensor.addGrad(this, out.grad.withGrad(false).mul(localGrad));
558
+ };
559
+ }
560
+ return keepDims ? out : out.squeeze(dims);
561
+ }
562
+ // Tensor minimum reduction
563
+ min(dims, keepDims = false) {
564
+ if (typeof this.value === "number")
565
+ return this;
566
+ if (typeof dims === "number") {
567
+ dims = [dims];
568
+ }
569
+ if (typeof dims === "undefined") {
570
+ dims = Array.from({ length: this.shape.length }, (_, index) => index);
571
+ }
572
+ // Dims that are reduced now have size-1
573
+ const outputShape = this.shape.map((dim, i) => dims.includes(i) ? 1 : dim);
574
+ const outputStrides = Tensor.getStrides(outputShape);
575
+ const outputSize = Tensor.shapeToSize(outputShape);
576
+ const outputValue = new Array(outputSize).fill(Infinity);
577
+ const originalSize = Tensor.shapeToSize(this.shape);
578
+ // Calculate minimum values of axes
579
+ for (let index = 0; index < originalSize; index++) {
580
+ const coords = Tensor.indexToCoords(index, this.strides);
581
+ // Force 0 on reduced axes to collapse into size-1 dims
582
+ const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
583
+ // Convert output coordinates to flat index
584
+ const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
585
+ // Accumulate, outFlatIndex should match multiple realFlatIndexes
586
+ const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
587
+ // Get min over time
588
+ if (this.value[realFlatIndex] < outputValue[outFlatIndex]) {
589
+ outputValue[outFlatIndex] = this.value[realFlatIndex];
590
+ }
591
+ }
592
+ const out = new Tensor(outputValue, {
593
+ shape: outputShape,
594
+ strides: outputStrides
595
+ });
596
+ // Set up gradient if needed
597
+ if (this.requiresGrad) {
598
+ const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
599
+ for (let index = 0; index < originalSize; index++) {
600
+ const coords = Tensor.indexToCoords(index, this.strides);
601
+ // Force 0 on reduced axes to collapse into size-1 dims
602
+ const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
603
+ // Convert output coordinates to flat index
604
+ const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
605
+ // Accumulate, outFlatIndex should match multiple realFlatIndexes
606
+ const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
607
+ // Calculate grad by checking if a positon holds a value equal to the min value
608
+ gradValue[realFlatIndex] = outputValue[outFlatIndex] === this.value[realFlatIndex] ? 1 : 0;
609
+ }
610
+ out.requiresGrad = true;
611
+ out.children.push(this);
612
+ out.gradFn = () => {
613
+ const localGrad = new Tensor(gradValue, { shape: gradShape, strides: gradStrides });
614
+ Tensor.addGrad(this, out.grad.withGrad(false).mul(localGrad));
615
+ };
616
+ }
617
+ return keepDims ? out : out.squeeze(dims);
618
+ }
517
619
  // Tensor element-wise addition
518
620
  add(other) {
519
621
  return this.elementWiseABDAG(other, (a, b) => a + b, (self, other, outGrad) => outGrad, (self, other, outGrad) => outGrad);
@@ -534,7 +636,7 @@ class Tensor {
534
636
  }
535
637
  // Tensor element-wise division
536
638
  div(other) {
537
- return this.elementWiseABDAG(other, (a, b) => a / b, (self, other, outGrad) => outGrad.div(other), (self, other, outGrad) => outGrad.mul(self.neg().div(other.pow(2))));
639
+ return this.elementWiseABDAG(other, (a, b) => a / b, (self, other, outGrad) => outGrad.div(other), (self, other, outGrad) => outGrad.mul(self.neg().div(other.square())));
538
640
  }
539
641
  divide = this.div;
540
642
  // Tensor element-wise modulo
@@ -618,7 +720,7 @@ class Tensor {
618
720
  negative = this.neg;
619
721
  // Tensor element-wise reciprocal
620
722
  reciprocal() {
621
- return this.elementWiseSelfDAG((a) => 1 / a, (self, outGrad) => outGrad.mul(self.neg().pow(-2)));
723
+ return this.elementWiseSelfDAG((a) => 1 / a, (self, outGrad) => outGrad.mul(self.pow(-2).neg()));
622
724
  }
623
725
  // Tensor element-wise square
624
726
  square() {
@@ -643,21 +745,21 @@ class Tensor {
643
745
  }
644
746
  // Tensor element-wise tan
645
747
  tan() {
646
- return this.elementWiseSelfDAG((a) => Math.tan(a), (self, outGrad) => outGrad.mul(self.tan().pow(2).add(1)));
748
+ return this.elementWiseSelfDAG((a) => Math.tan(a), (self, outGrad) => outGrad.mul(self.tan().square().add(1)));
647
749
  }
648
750
  // Tensor element-wise asin
649
751
  asin() {
650
- return this.elementWiseSelfDAG((a) => Math.asin(a), (self, outGrad) => outGrad.div(self.pow(2).neg().add(1).sqrt()));
752
+ return this.elementWiseSelfDAG((a) => Math.asin(a), (self, outGrad) => outGrad.div(self.square().neg().add(1).sqrt()));
651
753
  }
652
754
  arcsin = this.asin;
653
755
  // Tensor element-wise acos
654
756
  acos() {
655
- return this.elementWiseSelfDAG((a) => Math.acos(a), (self, outGrad) => outGrad.div(self.pow(2).neg().add(1).sqrt()).neg());
757
+ return this.elementWiseSelfDAG((a) => Math.acos(a), (self, outGrad) => outGrad.div(self.square().neg().add(1).sqrt()).neg());
656
758
  }
657
759
  arccos = this.acos;
658
760
  // Tensor element-wise atan
659
761
  atan() {
660
- return this.elementWiseSelfDAG((a) => Math.atan(a), (self, outGrad) => outGrad.div(self.pow(2).add(1)));
762
+ return this.elementWiseSelfDAG((a) => Math.atan(a), (self, outGrad) => outGrad.div(self.square().add(1)));
661
763
  }
662
764
  arctan = this.atan;
663
765
  // Tensor element-wise atan2
@@ -675,7 +777,7 @@ class Tensor {
675
777
  }
676
778
  // Tensor element-wise asinh
677
779
  asinh() {
678
- return this.elementWiseSelfDAG((a) => Math.asinh(a), (self, outGrad) => outGrad.div(self.pow(2).add(1).sqrt()));
780
+ return this.elementWiseSelfDAG((a) => Math.asinh(a), (self, outGrad) => outGrad.div(self.square().add(1).sqrt()));
679
781
  }
680
782
  arcsinh = this.asinh;
681
783
  // Tensor element-wise acosh
@@ -685,7 +787,7 @@ class Tensor {
685
787
  arccosh = this.acosh;
686
788
  // Tensor element-wise atanh
687
789
  atanh() {
688
- return this.elementWiseSelfDAG((a) => Math.atanh(a), (self, outGrad) => outGrad.div(self.pow(2).neg().add(1)));
790
+ return this.elementWiseSelfDAG((a) => Math.atanh(a), (self, outGrad) => outGrad.div(self.square().neg().add(1)));
689
791
  }
690
792
  arctanh = this.atanh;
691
793
  // Tensor element-wise degree to radian
@@ -734,7 +836,7 @@ class Tensor {
734
836
  }
735
837
  // Tensor element-wise relu
736
838
  relu() {
737
- return this.elementWiseSelfDAG((a) => Math.max(a, 0), (self, outGrad) => outGrad.mul(self.ge(0)));
839
+ return this.elementWiseSelfDAG((a) => Math.max(a, 0), (self, outGrad) => outGrad.mul(self.gt(0)));
738
840
  }
739
841
  // Tensor element-wise sigmoid
740
842
  sigmoid() {
@@ -745,7 +847,39 @@ class Tensor {
745
847
  }
746
848
  // Tensor element-wise tanh
747
849
  tanh() {
748
- return this.elementWiseSelfDAG((a) => Math.tanh(a), (self, outGrad) => outGrad.mul(self.tanh().pow(2).neg().add(1)));
850
+ return this.elementWiseSelfDAG((a) => Math.tanh(a), (self, outGrad) => outGrad.mul(self.tanh().square().neg().add(1)));
851
+ }
852
+ // Tensor element-wise softplus
853
+ softplus() {
854
+ return this.elementWiseSelfDAG((a) => Math.log1p(Math.exp(a)), (self, outGrad) => outGrad.mul(self.sigmoid()));
855
+ }
856
+ // Tensor element-wise softsign
857
+ softsign() {
858
+ return this.elementWiseSelfDAG((a) => a / (1 + Math.abs(a)), (self, outGrad) => outGrad.div(self.abs().add(1).square()));
859
+ }
860
+ // Tensor element-wise silu (swish)
861
+ silu() {
862
+ return this.elementWiseSelfDAG((a) => a / (1 + Math.exp(-a)), (self, outGrad) => {
863
+ const sig = self.sigmoid();
864
+ return outGrad.mul(sig.add(self.mul(sig).mul(sig.neg().add(1))));
865
+ });
866
+ }
867
+ // Tensor element-wise mish
868
+ mish() {
869
+ return this.elementWiseSelfDAG((a) => a * Math.tanh(Math.log1p(Math.exp(a))), (self, outGrad) => {
870
+ const tanhSoftPlus = self.exp().add(1).log().tanh();
871
+ // tanh(softplus(x)) + x * (1 - tanh²(softplus(x))) * sigmoid(x)
872
+ const derivative = tanhSoftPlus.add(self.mul(tanhSoftPlus.square().neg().add(1)).mul(self.sigmoid()));
873
+ return outGrad.mul(derivative);
874
+ });
875
+ }
876
+ // Tensor element-wise maximum
877
+ maximum(other) {
878
+ return this.elementWiseABDAG(other, (a, b) => Math.max(a, b), (self, other, outGrad) => outGrad.mul(self.gt(other).add(self.eq(other).mul(0.5))), (self, other, outGrad) => outGrad.mul(other.gt(self).add(other.eq(self).mul(0.5))));
879
+ }
880
+ // Tensor element-wise minimum
881
+ minimum(other) {
882
+ return this.elementWiseABDAG(other, (a, b) => Math.min(a, b), (self, other, outGrad) => outGrad.mul(self.lt(other).add(self.eq(other).mul(0.5))), (self, other, outGrad) => outGrad.mul(other.lt(self).add(other.eq(self).mul(0.5))));
749
883
  }
750
884
  // Tensor element-wise round
751
885
  round() {
@@ -773,6 +907,18 @@ class Tensor {
773
907
  return this.elementWiseSelfDAG((a) => Math.max(min, Math.min(max, a)), (self, outGrad) => outGrad.mul(self.ge(min).mul(self.le(max))));
774
908
  }
775
909
  clamp = this.clip;
910
+ // Tensor element-wise error function
911
+ erf() {
912
+ return this.elementWiseSelfDAG((a) => (0, utils_1.erf)(a), (self, outGrad) => outGrad.mul(self.square().neg().exp().mul(2 / Math.sqrt(Math.PI))));
913
+ }
914
+ // Tensor element-wise complementary error function
915
+ erfc() {
916
+ return this.elementWiseSelfDAG((a) => (0, utils_1.erfc)(a), (self, outGrad) => outGrad.mul(self.square().neg().exp().mul(2 / Math.sqrt(Math.PI)).neg()));
917
+ }
918
+ // Tensor element-wise inverse error function
919
+ erfinv() {
920
+ return this.elementWiseSelfDAG((a) => (0, utils_1.erfinv)(a), (self, outGrad) => outGrad.mul(self.erfinv().square().exp().mul(Math.sqrt(Math.PI) / 2)));
921
+ }
776
922
  // Transpose
777
923
  transpose(dim1, dim2) {
778
924
  // If dimension out of bound, throw error
@@ -0,0 +1,3 @@
1
+ export declare function erf(x: number): number;
2
+ export declare function erfc(x: number): number;
3
+ export declare function erfinv(x: number): number;
package/dist/utils.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.erf = erf;
4
+ exports.erfc = erfc;
5
+ exports.erfinv = erfinv;
6
+ // Error function using Abramowitz and Stegun approximation
7
+ function erf(x) {
8
+ const a1 = 0.254829592;
9
+ const a2 = -0.284496736;
10
+ const a3 = 1.421413741;
11
+ const a4 = -1.453152027;
12
+ const a5 = 1.061405429;
13
+ const p = 0.3275911;
14
+ const sign = x >= 0 ? 1 : -1;
15
+ x = Math.abs(x);
16
+ // Formula 7.1.26
17
+ const t = 1.0 / (1.0 + p * x);
18
+ const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
19
+ return sign * y;
20
+ }
21
+ // Complementary error function
22
+ function erfc(x) {
23
+ return 1 - erf(x);
24
+ }
25
+ // Inverse error function using Winitzki approximation
26
+ function erfinv(x) {
27
+ if (Math.abs(x) >= 1)
28
+ throw new Error("Input must be in range (-1, 1)");
29
+ const a = 0.147;
30
+ const ln = Math.log(1 - x * x);
31
+ const part1 = 2 / (Math.PI * a) + ln / 2;
32
+ const part2 = ln / a;
33
+ const sign = x >= 0 ? 1 : -1;
34
+ return sign * Math.sqrt(-part1 + Math.sqrt(part1 * part1 - part2));
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "catniff",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "A cute autograd engine for Javascript",
5
5
  "main": "index.js",
6
6
  "scripts": {