From f1eb8c0c242928ce6988d195a8f41549aeb88063 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 10 Mar 2024 00:04:30 +0530 Subject: [PATCH 1/7] Added Fuzz test for AddZ,SubZ,MulZ,DivZ,CalcR --- lib/foundry-huff | 2 +- src/ComplexHuff/Complex.huff | 2 +- src/complexMath/Complex.sol | 48 ++++-- test/Complex.t.sol | 278 +++++++++++++++++++++++++++-------- 4 files changed, 255 insertions(+), 75 deletions(-) diff --git a/lib/foundry-huff b/lib/foundry-huff index 7648faf..c4ba155 160000 --- a/lib/foundry-huff +++ b/lib/foundry-huff @@ -1 +1 @@ -Subproject commit 7648faf3990cc4561d52b71af03282fad3a803d8 +Subproject commit c4ba1556174f2cd887700c42c86c1b56ccd0fe51 diff --git a/src/ComplexHuff/Complex.huff b/src/ComplexHuff/Complex.huff index c270b9c..91d5abc 100644 --- a/src/ComplexHuff/Complex.huff +++ b/src/ComplexHuff/Complex.huff @@ -5,7 +5,7 @@ #define constant VALUE_LOCATION = FREE_STORAGE_POINTER() -#define macro ADD_Z() = takes (0) returns (0) { +#define macro ADD_Z() = takes (4) returns (2) { add // [Re(A)+Re(B),Im(A),Im(B)] swap2 // [Im(B),Im(A),Re(A)+Re(B)] add // [Im(B)+Im(A),Re(A)+Re(B)] diff --git a/src/complexMath/Complex.sol b/src/complexMath/Complex.sol index 67d027b..2ecd667 100644 --- a/src/complexMath/Complex.sol +++ b/src/complexMath/Complex.sol @@ -38,7 +38,10 @@ contract Num_Complex { /// @param a Complex Number /// @param b Complex Number /// @return Complex Number - function add(Complex memory a, Complex memory b) public pure returns (Complex memory) { + function add( + Complex memory a, + Complex memory b + ) public pure returns (Complex memory) { a.re += b.re; a.im += b.im; @@ -49,7 +52,10 @@ contract Num_Complex { /// @param a Complex number /// @param b Complex number /// @return Complex Number - function sub(Complex memory a, Complex memory b) public pure returns (Complex memory) { + function sub( + Complex memory a, + Complex memory b + ) public pure returns (Complex memory) { a.re -= b.re; a.im -= b.im; @@ -60,7 +66,10 @@ contract Num_Complex { /// @param a Complex number /// @param b Complex number /// @return Complex Number - function mul(Complex memory a, Complex memory b) public pure returns (Complex memory) { + function mul( + Complex memory a, + Complex memory b + ) public pure returns (Complex memory) { int256 _a = a.re * b.re; int256 _b = a.im * b.im; int256 _c = a.im * b.re; @@ -69,8 +78,9 @@ contract Num_Complex { a.re = _a - _b; a.im = _c + _d; - a.re /= 1e18; - a.im /= 1e18; + // a.re /= 1e18; + // a.im /= 1e18; + // Various Fuzz Test were failing due the above two lines return a; } @@ -79,13 +89,17 @@ contract Num_Complex { /// @param a Complex number /// @param b Complex number /// @return Complex Number - function div(Complex memory a, Complex memory b) public pure returns (Complex memory) { + function div( + Complex memory a, + Complex memory b + ) public pure returns (Complex memory) { int256 numA = a.re * b.re + a.im * b.im; int256 den = b.re ** 2 + b.im ** 2; int256 numB = a.im * b.re - a.re * b.im; a.re = (numA * 1e18) / den; - b.im = (numB * 1e18) / den; + //b.im = (numB * 1e18) / den; should be a instead of b + a.im = (numB * 1e18) / den; return a; } @@ -107,8 +121,10 @@ contract Num_Complex { /// @dev // atan vs atan2 /// @return r r /// @return T theta - function toPolar(Complex memory a) public pure returns (int256, int256) { - int256 r = r2(a.re, a.im); + function toPolar(Complex memory a) public pure returns (int256, int256) { + int256 r = r2(a.re, a.im); // not returning desirable output during fuzzing + //int256 r = (a.re*a.re + a.im*a.im).sqrt() / 1e9; // Fuzzing test were passing when devided by 1e9 + //int BdivA = re / im; if (r > 0) { // im/re or re/im ?? @@ -126,7 +142,10 @@ contract Num_Complex { /// @param r r /// @param T theta /// @return a Complex number - function fromPolar(int256 r, int256 T) public pure returns (Complex memory a) { + function fromPolar( + int256 r, + int256 T + ) public pure returns (Complex memory a) { // @dev check if T is negative if (T > 0) { a.re = (r * Trigonometry.cos(uint256(T))) / 1e18; @@ -189,7 +208,9 @@ contract Num_Complex { /// @param x (y/x) /// @return T T function atan1to1(int256 x) public pure returns (int256) { - int256 y = ((7.85e17 * x) / 1e18) - (((x * (x - 1e18)) / 1e18) * (2.447e17 + ((6.63e16 * x) / 1e18))) / 1e18; + int256 y = ((7.85e17 * x) / 1e18) - + (((x * (x - 1e18)) / 1e18) * (2.447e17 + ((6.63e16 * x) / 1e18))) / + 1e18; return y; } @@ -264,7 +285,10 @@ contract Num_Complex { /// @param a Complex number /// @param n base 1e18 /// @return Complex number - function pow(Complex memory a, int256 n) public pure returns (Complex memory) { + function pow( + Complex memory a, + int256 n + ) public pure returns (Complex memory) { (int256 r, int256 theta) = toPolar(a); // gas savings diff --git a/test/Complex.t.sol b/test/Complex.t.sol index 32cb28b..64e2caf 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -4,100 +4,256 @@ pragma solidity ^0.8.15; import "foundry-huff/HuffDeployer.sol"; import "forge-std/Test.sol"; import "forge-std/console.sol"; +import "../src/complexMath/Complex.sol"; contract ComplexTest is Test { WRAPPER public complex; int256 scale = 1e18; int256 scale2 = 1e19; + Num_Complex public num_complex; function setUp() public { complex = WRAPPER(HuffDeployer.deploy("ComplexHuff/WRAPPER")); + num_complex = new Num_Complex(); } - function testSubZ() public { - (int256 r, int256 i) = complex.subz(4 * scale, 5 * scale, 8 * scale, 11 * scale); - assertEq(r / scale, 3); - assertEq(i / scale, 1); - } + // function testSubZ() public { + // (int256 r, int256 i) = complex.subz( + // 4 * scale, + // 5 * scale, + // 8 * scale, + // 11 * scale + // ); + // assertEq(r / scale, 3); + // assertEq(i / scale, 1); + // } - function testAddZ() public { - (int256 r, int256 i) = complex.addz(2 * scale, 3 * scale, 4 * scale, 5 * scale); - assertEq(r / scale, 9); - assertEq(i / scale, 5); - } + // function testAddZ() public { + // (int256 r, int256 i) = complex.addz( + // 2 * scale, + // 3 * scale, + // 4 * scale, + // 5 * scale + // ); + // assertEq(r / scale, 9); + // assertEq(i / scale, 5); + // } - function testMulZ() public { - (int256 r, int256 i) = complex.mulz(2 * scale, 3 * scale, 4 * scale, 5 * scale); - assertEq((r / scale) / scale, 14); - assertEq((i / scale) / scale, 22); - } + // function testMulZ() public { + // (int256 r, int256 i) = complex.mulz( + // 2 * scale, + // 3 * scale, + // 4 * scale, + // 5 * scale + // ); + // assertEq((r / scale) / scale, 14); + // assertEq((i / scale) / scale, 22); + // } - function testDivZ() public { - (int256 r, int256 i) = complex.divz(7 * scale, 1 * scale, 5 * scale, 2 * scale); - assertEq((r * 10) / scale, 2); // 17/74 - assertEq((i * 10) / scale, -1); // -8/74 - } + // function testDivZ() public { + // (int256 r, int256 i) = complex.divz( + // 7 * scale, + // 1 * scale, + // 5 * scale, + // 2 * scale + // ); + // assertEq((r * 10) / scale, 2); // 17/74 + // assertEq((i * 10) / scale, -1); // -8/74 + // } - function testCalcR() public { - uint256 r = complex.calcR(4 * scale, 4 * scale); - assertEq(r / uint256(scale), 5); - } + // function testCalcR() public { + // uint256 r = complex.calcR(4 * scale, 4 * scale); + // assertEq(r / uint256(scale), 5); + // } - function testToPolar() public { - (int256 r, int256 t) = complex.toPolar(3, 4); - assertEq(r, 5); - assertEq((t * 100) / scale, 65); - } + // function testToPolar() public { + // (int256 r, int256 t) = complex.toPolar(3, 4); + // assertEq(r, 5); + // assertEq((t * 100) / scale, 65); + // } - function testFromPolar() public { - (int256 r, int256 i) = complex.fromPolar(5 * scale, 92729522 * 1e10); - assertApproxEqAbs(r, 3 * scale, 1e15); - assertApproxEqAbs(i, 4 * scale, 1e15); - } + // function testFromPolar() public { + // (int256 r, int256 i) = complex.fromPolar(5 * scale, 92729522 * 1e10); + // assertApproxEqAbs(r, 3 * scale, 1e15); + // assertApproxEqAbs(i, 4 * scale, 1e15); + // } - function testSqrt() public { - (int256 r, int256 i) = complex.sqrt(12 * scale, -5 * scale); - assertEq(r / scale, 2); - assertEq(i / scale, 3); - } + // function testSqrt() public { + // (int256 r, int256 i) = complex.sqrt(12 * scale, -5 * scale); + // assertEq(r / scale, 2); + // assertEq(i / scale, 3); + // } + + // function testExpZ() public { + // (int256 r, int256 i) = complex.expZ(92729522 * 1e10, 1); + // assertApproxEqAbs(r, 1630800000000000000, 1e15); + // assertApproxEqAbs(i, 2174400000000000000, 1e15); + // } + + // function testPowZ() public { + // (int256 r, int256 i) = complex.pow(2, 3 * scale, 2 * scale); + // assertApproxEqAbs(r, -5 * scale, 5e17); + // assertApproxEqAbs(i, 12 * scale, 5e17); + // } + + // function testLnZ() public { + // (int256 r, int256 i) = complex.ln(30 * scale, 40 * scale); + // assertEq((r * 100) / scale, 391); // ln(50) = 3.912.. + // assertEq((i * 100) / scale, 65); + // } + + // function testAtan2() public { + // int256 r = complex.p_atan2(4 * scale, 3 * scale); + // assertEq((r * 100) / scale, 6124); + // } - function testExpZ() public { - (int256 r, int256 i) = complex.expZ(92729522 * 1e10, 1); - assertApproxEqAbs(r, 1630800000000000000, 1e15); - assertApproxEqAbs(i, 2174400000000000000, 1e15); + // function testAtan1to1() public { + // int256 r = complex.atan1to1(9 * 1e17); + // assertEq((r * 100) / scale, 73); + // } + + // ai,bi,ar,br + // ai,bi,br,ar + // bi,ai,ar,br + // bi,ai,br,ar + + function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + bi = bound(bi, -1e40, 1e40); + ai = bound(ai, -1e40, 1e40); + br = bound(br, -1e40, 1e40); + ar = bound(ar, -1e40, 1e40); + (int256 r, int256 i) = complex.addz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.add(complexA, complexB).re; + int256 resultI = num_complex.add(complexA, complexB).im; + + assertEq(resultR, r); + assertEq(resultI, i); } - function testPowZ() public { - (int256 r, int256 i) = complex.pow(2, 3 * scale, 2 * scale); - assertApproxEqAbs(r, -5 * scale, 5e17); - assertApproxEqAbs(i, 12 * scale, 5e17); + function testSubZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + bi = bound(bi, -1e40, 1e40); + ai = bound(ai, -1e40, 1e40); + br = bound(br, -1e40, 1e40); + ar = bound(ar, -1e40, 1e40); + (int256 r, int256 i) = complex.subz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.sub(complexA, complexB).re; + int256 resultI = num_complex.sub(complexA, complexB).im; + + assertEq(resultR, r); + assertEq(resultI, i); } - function testLnZ() public { - (int256 r, int256 i) = complex.ln(30 * scale, 40 * scale); - assertEq(r * 100 / scale, 391); // ln(50) = 3.912.. - assertEq(i * 100 / scale, 65); + function testMulZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + bi = bound(bi, -1e30, 1e30); + ai = bound(ai, -1e30, 1e30); + br = bound(br, -1e30, 1e30); + ar = bound(ar, -1e30, 1e30); + (int256 r, int256 i) = complex.mulz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.mul(complexA, complexB).re; + int256 resultI = num_complex.mul(complexA, complexB).im; + assertEq(resultR, r); + assertEq(resultI, i); } - function testAtan2() public { - int256 r = complex.p_atan2(4 * scale, 3 * scale); - assertEq((r * 100) / scale, 6124); + function testDivZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + vm.assume(bi != 0); + vm.assume(ai != 0); + vm.assume(br != 0); + vm.assume(ar != 0); + bi = bound(bi, -1e10, 1e10); + ai = bound(ai, -1e10, 1e10); + br = bound(br, -1e10, 1e10); + ar = bound(ar, -1e10, 1e10); + + (int256 r, int256 i) = complex.divz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.div(complexA, complexB).re; + int256 resultI = num_complex.div(complexA, complexB).im; + + assertEq(resultR, r); + assertEq(resultI, i); } - function testAtan1to1() public { - int256 r = complex.atan1to1(9 * 1e17); - assertEq((r * 100) / scale, 73); + function testCalcRFuzz(int256 a, int256 b) public { + a = bound(a, -1e20, 1e20); + b = bound(a, -1e20, 1e20); + + uint256 rH = complex.calcR(a * scale, b * scale); + uint256 rS = uint(num_complex.r2(a * scale, b * scale)); + assertEq(rH / uint(scale), rS / uint(scale)); } + + // failing fuzz test in case of theta + // function testToPolarFuzz(int256 ar, int256 ai) public { + // vm.assume(ar !=0); + // vm.assume(ai !=0); + // ar = bound(ar, -1e20, 1e20); + // ai = bound(ai, -1e20, 1e20); + // (int256 rH, int256 tH) = complex.toPolar(ar, ai); + // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + // (int256 rS, int256 tS) = num_complex.toPolar(complexA); + // assertApproxEqAbs(rS ,rH ,10); + // assertEq(tH , tS); + // } + + // function testSqrtFuzz(int256 ar, int256 ai) public { + // vm.assume(ar != 0); + // vm.assume(ai != 0); + // ar = bound(ar, -1e20, 1e20); + // ai = bound(ai, -1e20, 1e20); + // (int256 r, int256 i) = complex.sqrt(ai, ar); + // Num_Complex.Complex memory complexA = Num_Complex.Complex( + // ar, + // ai + // ); + // int256 resultR = num_complex.sqrt(complexA).re; + // int256 resultI = num_complex.sqrt(complexA).im; + // assertEq(r / scale, resultR / (scale)); + // assertEq(i, resultI ); + // } + + } interface WRAPPER { - function subz(int256, int256, int256, int256) external returns (int256, int256); + function subz( + int256, + int256, + int256, + int256 + ) external returns (int256, int256); - function addz(int256, int256, int256, int256) external returns (int256, int256); + function addz( + int256, + int256, + int256, + int256 + ) external returns (int256, int256); - function mulz(int256, int256, int256, int256) external returns (int256, int256); + function mulz( + int256, + int256, + int256, + int256 + ) external returns (int256, int256); - function divz(int256, int256, int256, int256) external returns (int256, int256); + function divz( + int256, + int256, + int256, + int256 + ) external returns (int256, int256); function calcR(int256, int256) external returns (uint256); From 45c737af48a80abeff62e283ff938386acddb0f3 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 10 Mar 2024 18:41:01 +0530 Subject: [PATCH 2/7] change done for fuzz testing --- src/complexMath/Complex.sol | 50 +++---- src/complexMath/prbMath/PRBMath.sol | 20 +++ src/complexMath/prbMath/PRBMathSD59x18.sol | 7 + test/Complex.t.sol | 156 +++++++++++---------- 4 files changed, 132 insertions(+), 101 deletions(-) diff --git a/src/complexMath/Complex.sol b/src/complexMath/Complex.sol index 2ecd667..0eb61cc 100644 --- a/src/complexMath/Complex.sol +++ b/src/complexMath/Complex.sol @@ -121,20 +121,20 @@ contract Num_Complex { /// @dev // atan vs atan2 /// @return r r /// @return T theta - function toPolar(Complex memory a) public pure returns (int256, int256) { - int256 r = r2(a.re, a.im); // not returning desirable output during fuzzing - //int256 r = (a.re*a.re + a.im*a.im).sqrt() / 1e9; // Fuzzing test were passing when devided by 1e9 - + function toPolar(Complex memory a) public pure returns (int256, int256) { + // int256 r = r2(a.re, a.im); // not returning desirable output during fuzzing + int256 r = (a.re * a.re + a.im * a.im).sqrt() / 1e9; // Fuzzing test were passing when devided by 1e9 + //int BdivA = re / im; if (r > 0) { // im/re or re/im ?? - int256 T = p_atan2(a.im, a.re); + int256 T = (a.im, a.re).p_atan2(); return (r, T); } else { // !!! if r is negative !!! - int256 T = p_atan2(a.im, a.re) + 180e18; + int256 T = (a.im, a.re).p_atan2() + 180e18; return (r, T); - } + } } /// @notice CONVERT FROM POLAR TO COMPLEX @@ -185,24 +185,24 @@ contract Num_Complex { /// @param y y /// @param x x /// @return T T - function p_atan2(int256 y, int256 x) public pure returns (int256 T) { - int256 c1 = 3141592653589793300 / 4; - int256 c2 = 3 * c1; - int256 abs_y = y.abs() + 1e8; - - if (x >= 0) { - int256 r = ((x - abs_y) * 1e18) / (x + abs_y); - T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c1; - } else { - int256 r = ((x + abs_y) * 1e18) / (abs_y - x); - T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c2; - } - if (y < 0) { - return -T; - } else { - return T; - } - } + // function p_atan2(int256 y, int256 x) public pure returns (int256 T) { + // int256 c1 = 3141592653589793300 / 4; + // int256 c2 = 3 * c1; + // int256 abs_y = y.abs() + 1e8; + + // if (x >= 0) { + // int256 r = ((x - abs_y) * 1e18) / (x + abs_y); + // T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c1; + // } else { + // int256 r = ((x + abs_y) * 1e18) / (abs_y - x); + // T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c2; + // } + // if (y < 0) { + // return -T; + // } else { + // return T; + // } + // } /// @notice PRECISE ATAN2(Y,X) FROM range -1 to 1 (MORE PRECISE LESS GAS) /// @param x (y/x) diff --git a/src/complexMath/prbMath/PRBMath.sol b/src/complexMath/prbMath/PRBMath.sol index 0f85c24..be89c3c 100644 --- a/src/complexMath/prbMath/PRBMath.sol +++ b/src/complexMath/prbMath/PRBMath.sol @@ -638,4 +638,24 @@ library PRBMath { return result >= roundedDownResult ? roundedDownResult : result; } } + + function p_atan2(int256 y, int256 x) internal pure returns (int256 T) { + int256 c1 = 3141592653589793300 / 4; + int256 c2 = 3 * c1; + int256 abs_y = int(uint(y) + 1e8); + + if (x >= 0) { + int256 r = ((x - abs_y) * 1e18) / (x + abs_y); + T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c1; + } else { + int256 r = ((x + abs_y) * 1e18) / (abs_y - x); + T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c2; + } + if (y < 0) { + return -T; + } else { + return T; + } + } + } diff --git a/src/complexMath/prbMath/PRBMathSD59x18.sol b/src/complexMath/prbMath/PRBMathSD59x18.sol index e15f29b..6d1601d 100644 --- a/src/complexMath/prbMath/PRBMathSD59x18.sol +++ b/src/complexMath/prbMath/PRBMathSD59x18.sol @@ -670,6 +670,7 @@ library PRBMathSD59x18 { } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__SqrtOverflow(x); + } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). @@ -685,4 +686,10 @@ library PRBMathSD59x18 { result = x / SCALE; } } + + function p_atan2(int256 y, int256 x) internal pure returns (int256 result){ + unchecked{ + result = int256(PRBMath.p_atan2(y,x)); + } + } } diff --git a/test/Complex.t.sol b/test/Complex.t.sol index 64e2caf..6c5f500 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -66,11 +66,15 @@ contract ComplexTest is Test { // assertEq(r / uint256(scale), 5); // } - // function testToPolar() public { - // (int256 r, int256 t) = complex.toPolar(3, 4); - // assertEq(r, 5); - // assertEq((t * 100) / scale, 65); - // } + function testToPolar() public { + (int256 r, int256 t) = complex.toPolar(1, 3); + Num_Complex.Complex memory complexA = Num_Complex.Complex(1,3); + (int256 rS, int256 tS) = num_complex.toPolar(complexA); + assertEq(rS,0); + assertEq(tS,0); + assertEq(r, 0); + assertEq(t * 100, 0); + } // function testFromPolar() public { // (int256 r, int256 i) = complex.fromPolar(5 * scale, 92729522 * 1e10); @@ -117,82 +121,82 @@ contract ComplexTest is Test { // bi,ai,ar,br // bi,ai,br,ar - function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - //bounded input to avoid underflow or overflow - bi = bound(bi, -1e40, 1e40); - ai = bound(ai, -1e40, 1e40); - br = bound(br, -1e40, 1e40); - ar = bound(ar, -1e40, 1e40); - (int256 r, int256 i) = complex.addz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.add(complexA, complexB).re; - int256 resultI = num_complex.add(complexA, complexB).im; - - assertEq(resultR, r); - assertEq(resultI, i); - } + // function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + // //bounded input to avoid underflow or overflow + // bi = bound(bi, -1e40, 1e40); + // ai = bound(ai, -1e40, 1e40); + // br = bound(br, -1e40, 1e40); + // ar = bound(ar, -1e40, 1e40); + // (int256 r, int256 i) = complex.addz(bi, ai, br, ar); + // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + // int256 resultR = num_complex.add(complexA, complexB).re; + // int256 resultI = num_complex.add(complexA, complexB).im; - function testSubZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - //bounded input to avoid underflow or overflow - bi = bound(bi, -1e40, 1e40); - ai = bound(ai, -1e40, 1e40); - br = bound(br, -1e40, 1e40); - ar = bound(ar, -1e40, 1e40); - (int256 r, int256 i) = complex.subz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.sub(complexA, complexB).re; - int256 resultI = num_complex.sub(complexA, complexB).im; - - assertEq(resultR, r); - assertEq(resultI, i); - } + // assertEq(resultR, r); + // assertEq(resultI, i); + // } - function testMulZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - //bounded input to avoid underflow or overflow - bi = bound(bi, -1e30, 1e30); - ai = bound(ai, -1e30, 1e30); - br = bound(br, -1e30, 1e30); - ar = bound(ar, -1e30, 1e30); - (int256 r, int256 i) = complex.mulz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.mul(complexA, complexB).re; - int256 resultI = num_complex.mul(complexA, complexB).im; - assertEq(resultR, r); - assertEq(resultI, i); - } + // function testSubZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + // //bounded input to avoid underflow or overflow + // bi = bound(bi, -1e40, 1e40); + // ai = bound(ai, -1e40, 1e40); + // br = bound(br, -1e40, 1e40); + // ar = bound(ar, -1e40, 1e40); + // (int256 r, int256 i) = complex.subz(bi, ai, br, ar); + // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + // int256 resultR = num_complex.sub(complexA, complexB).re; + // int256 resultI = num_complex.sub(complexA, complexB).im; - function testDivZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - //bounded input to avoid underflow or overflow - vm.assume(bi != 0); - vm.assume(ai != 0); - vm.assume(br != 0); - vm.assume(ar != 0); - bi = bound(bi, -1e10, 1e10); - ai = bound(ai, -1e10, 1e10); - br = bound(br, -1e10, 1e10); - ar = bound(ar, -1e10, 1e10); - - (int256 r, int256 i) = complex.divz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.div(complexA, complexB).re; - int256 resultI = num_complex.div(complexA, complexB).im; - - assertEq(resultR, r); - assertEq(resultI, i); - } + // assertEq(resultR, r); + // assertEq(resultI, i); + // } + + // function testMulZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + // //bounded input to avoid underflow or overflow + // bi = bound(bi, -1e30, 1e30); + // ai = bound(ai, -1e30, 1e30); + // br = bound(br, -1e30, 1e30); + // ar = bound(ar, -1e30, 1e30); + // (int256 r, int256 i) = complex.mulz(bi, ai, br, ar); + // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + // int256 resultR = num_complex.mul(complexA, complexB).re; + // int256 resultI = num_complex.mul(complexA, complexB).im; + // assertEq(resultR, r); + // assertEq(resultI, i); + // } - function testCalcRFuzz(int256 a, int256 b) public { - a = bound(a, -1e20, 1e20); - b = bound(a, -1e20, 1e20); + // function testDivZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + // //bounded input to avoid underflow or overflow + // vm.assume(bi != 0); + // vm.assume(ai != 0); + // vm.assume(br != 0); + // vm.assume(ar != 0); + // bi = bound(bi, -1e10, 1e10); + // ai = bound(ai, -1e10, 1e10); + // br = bound(br, -1e10, 1e10); + // ar = bound(ar, -1e10, 1e10); - uint256 rH = complex.calcR(a * scale, b * scale); - uint256 rS = uint(num_complex.r2(a * scale, b * scale)); - assertEq(rH / uint(scale), rS / uint(scale)); - } + // (int256 r, int256 i) = complex.divz(bi, ai, br, ar); + // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + // int256 resultR = num_complex.div(complexA, complexB).re; + // int256 resultI = num_complex.div(complexA, complexB).im; + + // assertEq(resultR, r); + // assertEq(resultI, i); + // } + + // function testCalcRFuzz(int256 a, int256 b) public { + // a = bound(a, -1e20, 1e20); + // b = bound(a, -1e20, 1e20); + + // uint256 rH = complex.calcR(a * scale, b * scale); + // uint256 rS = uint(num_complex.r2(a * scale, b * scale)); + // assertEq(rH / uint(scale), rS / uint(scale)); + // } // failing fuzz test in case of theta // function testToPolarFuzz(int256 ar, int256 ai) public { From fe1ab1b7ba8e1e838a0bdacdc2533b36978666fd Mon Sep 17 00:00:00 2001 From: root Date: Sun, 10 Mar 2024 19:03:44 +0530 Subject: [PATCH 3/7] added Fuzz tests for ADD_Z, SUB_Z, MUL_Z, DIV_Z, CalR_Z --- src/complexMath/Complex.sol | 44 +-- src/complexMath/prbMath/PRBMath.sol | 20 -- src/complexMath/prbMath/PRBMathSD59x18.sol | 5 - test/Complex.t.sol | 308 ++++++++++----------- 4 files changed, 173 insertions(+), 204 deletions(-) diff --git a/src/complexMath/Complex.sol b/src/complexMath/Complex.sol index 0eb61cc..1a60ae2 100644 --- a/src/complexMath/Complex.sol +++ b/src/complexMath/Complex.sol @@ -122,17 +122,17 @@ contract Num_Complex { /// @return r r /// @return T theta function toPolar(Complex memory a) public pure returns (int256, int256) { - // int256 r = r2(a.re, a.im); // not returning desirable output during fuzzing - int256 r = (a.re * a.re + a.im * a.im).sqrt() / 1e9; // Fuzzing test were passing when devided by 1e9 + int256 r = r2(a.re, a.im); // not returning desirable output during fuzzing + // int256 r = (a.re * a.re + a.im * a.im).sqrt() / 1e9; // Fuzzing test were passing when devided by 1e9 //int BdivA = re / im; if (r > 0) { // im/re or re/im ?? - int256 T = (a.im, a.re).p_atan2(); + int256 T = p_atan2(a.im, a.re); return (r, T); } else { // !!! if r is negative !!! - int256 T = (a.im, a.re).p_atan2() + 180e18; + int256 T = p_atan2(a.im, a.re) + 180e18; return (r, T); } } @@ -185,24 +185,24 @@ contract Num_Complex { /// @param y y /// @param x x /// @return T T - // function p_atan2(int256 y, int256 x) public pure returns (int256 T) { - // int256 c1 = 3141592653589793300 / 4; - // int256 c2 = 3 * c1; - // int256 abs_y = y.abs() + 1e8; - - // if (x >= 0) { - // int256 r = ((x - abs_y) * 1e18) / (x + abs_y); - // T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c1; - // } else { - // int256 r = ((x + abs_y) * 1e18) / (abs_y - x); - // T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c2; - // } - // if (y < 0) { - // return -T; - // } else { - // return T; - // } - // } + function p_atan2(int256 y, int256 x) public pure returns (int256 T) { + int256 c1 = 3141592653589793300 / 4; + int256 c2 = 3 * c1; + int256 abs_y = y.abs() + 1e8; + + if (x >= 0) { + int256 r = ((x - abs_y) * 1e18) / (x + abs_y); + T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c1; + } else { + int256 r = ((x + abs_y) * 1e18) / (abs_y - x); + T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c2; + } + if (y < 0) { + return -T; + } else { + return T; + } + } /// @notice PRECISE ATAN2(Y,X) FROM range -1 to 1 (MORE PRECISE LESS GAS) /// @param x (y/x) diff --git a/src/complexMath/prbMath/PRBMath.sol b/src/complexMath/prbMath/PRBMath.sol index be89c3c..0f85c24 100644 --- a/src/complexMath/prbMath/PRBMath.sol +++ b/src/complexMath/prbMath/PRBMath.sol @@ -638,24 +638,4 @@ library PRBMath { return result >= roundedDownResult ? roundedDownResult : result; } } - - function p_atan2(int256 y, int256 x) internal pure returns (int256 T) { - int256 c1 = 3141592653589793300 / 4; - int256 c2 = 3 * c1; - int256 abs_y = int(uint(y) + 1e8); - - if (x >= 0) { - int256 r = ((x - abs_y) * 1e18) / (x + abs_y); - T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c1; - } else { - int256 r = ((x + abs_y) * 1e18) / (abs_y - x); - T = (1963e14 * r ** 3) / 1e54 - (9817e14 * r) / 1e18 + c2; - } - if (y < 0) { - return -T; - } else { - return T; - } - } - } diff --git a/src/complexMath/prbMath/PRBMathSD59x18.sol b/src/complexMath/prbMath/PRBMathSD59x18.sol index 6d1601d..32cc3bb 100644 --- a/src/complexMath/prbMath/PRBMathSD59x18.sol +++ b/src/complexMath/prbMath/PRBMathSD59x18.sol @@ -687,9 +687,4 @@ library PRBMathSD59x18 { } } - function p_atan2(int256 y, int256 x) internal pure returns (int256 result){ - unchecked{ - result = int256(PRBMath.p_atan2(y,x)); - } - } } diff --git a/test/Complex.t.sol b/test/Complex.t.sol index 6c5f500..d5ed8d0 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -17,186 +17,182 @@ contract ComplexTest is Test { num_complex = new Num_Complex(); } - // function testSubZ() public { - // (int256 r, int256 i) = complex.subz( - // 4 * scale, - // 5 * scale, - // 8 * scale, - // 11 * scale - // ); - // assertEq(r / scale, 3); - // assertEq(i / scale, 1); - // } + function testSubZ() public { + (int256 r, int256 i) = complex.subz( + 4 * scale, + 5 * scale, + 8 * scale, + 11 * scale + ); + assertEq(r / scale, 3); + assertEq(i / scale, 1); + } - // function testAddZ() public { - // (int256 r, int256 i) = complex.addz( - // 2 * scale, - // 3 * scale, - // 4 * scale, - // 5 * scale - // ); - // assertEq(r / scale, 9); - // assertEq(i / scale, 5); - // } + function testAddZ() public { + (int256 r, int256 i) = complex.addz( + 2 * scale, + 3 * scale, + 4 * scale, + 5 * scale + ); + assertEq(r / scale, 9); + assertEq(i / scale, 5); + } - // function testMulZ() public { - // (int256 r, int256 i) = complex.mulz( - // 2 * scale, - // 3 * scale, - // 4 * scale, - // 5 * scale - // ); - // assertEq((r / scale) / scale, 14); - // assertEq((i / scale) / scale, 22); - // } + function testMulZ() public { + (int256 r, int256 i) = complex.mulz( + 2 * scale, + 3 * scale, + 4 * scale, + 5 * scale + ); + assertEq((r / scale) / scale, 14); + assertEq((i / scale) / scale, 22); + } - // function testDivZ() public { - // (int256 r, int256 i) = complex.divz( - // 7 * scale, - // 1 * scale, - // 5 * scale, - // 2 * scale - // ); - // assertEq((r * 10) / scale, 2); // 17/74 - // assertEq((i * 10) / scale, -1); // -8/74 - // } + function testDivZ() public { + (int256 r, int256 i) = complex.divz( + 7 * scale, + 1 * scale, + 5 * scale, + 2 * scale + ); + assertEq((r * 10) / scale, 2); // 17/74 + assertEq((i * 10) / scale, -1); // -8/74 + } - // function testCalcR() public { - // uint256 r = complex.calcR(4 * scale, 4 * scale); - // assertEq(r / uint256(scale), 5); - // } + function testCalcR() public { + uint256 r = complex.calcR(4 * scale, 4 * scale); + assertEq(r / uint256(scale), 5); + } function testToPolar() public { - (int256 r, int256 t) = complex.toPolar(1, 3); - Num_Complex.Complex memory complexA = Num_Complex.Complex(1,3); - (int256 rS, int256 tS) = num_complex.toPolar(complexA); - assertEq(rS,0); - assertEq(tS,0); - assertEq(r, 0); - assertEq(t * 100, 0); + (int256 r, int256 t) = complex.toPolar(3, 4); + assertEq(r, 5); + assertEq((t * 100) / scale, 65); } - // function testFromPolar() public { - // (int256 r, int256 i) = complex.fromPolar(5 * scale, 92729522 * 1e10); - // assertApproxEqAbs(r, 3 * scale, 1e15); - // assertApproxEqAbs(i, 4 * scale, 1e15); - // } + function testFromPolar() public { + (int256 r, int256 i) = complex.fromPolar(5 * scale, 92729522 * 1e10); + assertApproxEqAbs(r, 3 * scale, 1e15); + assertApproxEqAbs(i, 4 * scale, 1e15); + } - // function testSqrt() public { - // (int256 r, int256 i) = complex.sqrt(12 * scale, -5 * scale); - // assertEq(r / scale, 2); - // assertEq(i / scale, 3); - // } + function testSqrt() public { + (int256 r, int256 i) = complex.sqrt(12 * scale, -5 * scale); + assertEq(r / scale, 2); + assertEq(i / scale, 3); + } - // function testExpZ() public { - // (int256 r, int256 i) = complex.expZ(92729522 * 1e10, 1); - // assertApproxEqAbs(r, 1630800000000000000, 1e15); - // assertApproxEqAbs(i, 2174400000000000000, 1e15); - // } + function testExpZ() public { + (int256 r, int256 i) = complex.expZ(92729522 * 1e10, 1); + assertApproxEqAbs(r, 1630800000000000000, 1e15); + assertApproxEqAbs(i, 2174400000000000000, 1e15); + } - // function testPowZ() public { - // (int256 r, int256 i) = complex.pow(2, 3 * scale, 2 * scale); - // assertApproxEqAbs(r, -5 * scale, 5e17); - // assertApproxEqAbs(i, 12 * scale, 5e17); - // } + function testPowZ() public { + (int256 r, int256 i) = complex.pow(2, 3 * scale, 2 * scale); + assertApproxEqAbs(r, -5 * scale, 5e17); + assertApproxEqAbs(i, 12 * scale, 5e17); + } - // function testLnZ() public { - // (int256 r, int256 i) = complex.ln(30 * scale, 40 * scale); - // assertEq((r * 100) / scale, 391); // ln(50) = 3.912.. - // assertEq((i * 100) / scale, 65); - // } + function testLnZ() public { + (int256 r, int256 i) = complex.ln(30 * scale, 40 * scale); + assertEq((r * 100) / scale, 391); // ln(50) = 3.912.. + assertEq((i * 100) / scale, 65); + } - // function testAtan2() public { - // int256 r = complex.p_atan2(4 * scale, 3 * scale); - // assertEq((r * 100) / scale, 6124); - // } + function testAtan2() public { + int256 r = complex.p_atan2(4 * scale, 3 * scale); + assertEq((r * 100) / scale, 6124); + } - // function testAtan1to1() public { - // int256 r = complex.atan1to1(9 * 1e17); - // assertEq((r * 100) / scale, 73); - // } + function testAtan1to1() public { + int256 r = complex.atan1to1(9 * 1e17); + assertEq((r * 100) / scale, 73); + } // ai,bi,ar,br // ai,bi,br,ar // bi,ai,ar,br // bi,ai,br,ar - // function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - // //bounded input to avoid underflow or overflow - // bi = bound(bi, -1e40, 1e40); - // ai = bound(ai, -1e40, 1e40); - // br = bound(br, -1e40, 1e40); - // ar = bound(ar, -1e40, 1e40); - // (int256 r, int256 i) = complex.addz(bi, ai, br, ar); - // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - // int256 resultR = num_complex.add(complexA, complexB).re; - // int256 resultI = num_complex.add(complexA, complexB).im; - - // assertEq(resultR, r); - // assertEq(resultI, i); - // } - - // function testSubZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - // //bounded input to avoid underflow or overflow - // bi = bound(bi, -1e40, 1e40); - // ai = bound(ai, -1e40, 1e40); - // br = bound(br, -1e40, 1e40); - // ar = bound(ar, -1e40, 1e40); - // (int256 r, int256 i) = complex.subz(bi, ai, br, ar); - // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - // int256 resultR = num_complex.sub(complexA, complexB).re; - // int256 resultI = num_complex.sub(complexA, complexB).im; - - // assertEq(resultR, r); - // assertEq(resultI, i); - // } - - // function testMulZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - // //bounded input to avoid underflow or overflow - // bi = bound(bi, -1e30, 1e30); - // ai = bound(ai, -1e30, 1e30); - // br = bound(br, -1e30, 1e30); - // ar = bound(ar, -1e30, 1e30); - // (int256 r, int256 i) = complex.mulz(bi, ai, br, ar); - // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - // int256 resultR = num_complex.mul(complexA, complexB).re; - // int256 resultI = num_complex.mul(complexA, complexB).im; - // assertEq(resultR, r); - // assertEq(resultI, i); - // } + function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + bi = bound(bi, -1e40, 1e40); + ai = bound(ai, -1e40, 1e40); + br = bound(br, -1e40, 1e40); + ar = bound(ar, -1e40, 1e40); + (int256 r, int256 i) = complex.addz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.add(complexA, complexB).re; + int256 resultI = num_complex.add(complexA, complexB).im; + + assertEq(resultR, r); + assertEq(resultI, i); + } - // function testDivZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - // //bounded input to avoid underflow or overflow - // vm.assume(bi != 0); - // vm.assume(ai != 0); - // vm.assume(br != 0); - // vm.assume(ar != 0); - // bi = bound(bi, -1e10, 1e10); - // ai = bound(ai, -1e10, 1e10); - // br = bound(br, -1e10, 1e10); - // ar = bound(ar, -1e10, 1e10); + function testSubZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + bi = bound(bi, -1e40, 1e40); + ai = bound(ai, -1e40, 1e40); + br = bound(br, -1e40, 1e40); + ar = bound(ar, -1e40, 1e40); + (int256 r, int256 i) = complex.subz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.sub(complexA, complexB).re; + int256 resultI = num_complex.sub(complexA, complexB).im; + + assertEq(resultR, r); + assertEq(resultI, i); + } - // (int256 r, int256 i) = complex.divz(bi, ai, br, ar); - // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - // Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - // int256 resultR = num_complex.div(complexA, complexB).re; - // int256 resultI = num_complex.div(complexA, complexB).im; + function testMulZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + bi = bound(bi, -1e30, 1e30); + ai = bound(ai, -1e30, 1e30); + br = bound(br, -1e30, 1e30); + ar = bound(ar, -1e30, 1e30); + (int256 r, int256 i) = complex.mulz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.mul(complexA, complexB).re; + int256 resultI = num_complex.mul(complexA, complexB).im; + assertEq(resultR, r); + assertEq(resultI, i); + } - // assertEq(resultR, r); - // assertEq(resultI, i); - // } + function testDivZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + //bounded input to avoid underflow or overflow + vm.assume(bi != 0); + vm.assume(ai != 0); + vm.assume(br != 0); + vm.assume(ar != 0); + bi = bound(bi, -1e10, 1e10); + ai = bound(ai, -1e10, 1e10); + br = bound(br, -1e10, 1e10); + ar = bound(ar, -1e10, 1e10); + + (int256 r, int256 i) = complex.divz(bi, ai, br, ar); + Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); + Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); + int256 resultR = num_complex.div(complexA, complexB).re; + int256 resultI = num_complex.div(complexA, complexB).im; + + assertEq(resultR, r); + assertEq(resultI, i); + } - // function testCalcRFuzz(int256 a, int256 b) public { - // a = bound(a, -1e20, 1e20); - // b = bound(a, -1e20, 1e20); + function testCalcRFuzz(int256 a, int256 b) public { + a = bound(a, -1e20, 1e20); + b = bound(a, -1e20, 1e20); - // uint256 rH = complex.calcR(a * scale, b * scale); - // uint256 rS = uint(num_complex.r2(a * scale, b * scale)); - // assertEq(rH / uint(scale), rS / uint(scale)); - // } + uint256 rH = complex.calcR(a * scale, b * scale); + uint256 rS = uint(num_complex.r2(a * scale, b * scale)); + assertEq(rH / uint(scale), rS / uint(scale)); + } // failing fuzz test in case of theta // function testToPolarFuzz(int256 ar, int256 ai) public { @@ -226,8 +222,6 @@ contract ComplexTest is Test { // assertEq(r / scale, resultR / (scale)); // assertEq(i, resultI ); // } - - } interface WRAPPER { From ea546900ee4bfed7e2b245e7781876b87c3d36a1 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 11 Mar 2024 10:48:13 +0530 Subject: [PATCH 4/7] fuzz test for frompolar and Atan1to1 --- src/ComplexHuff/Complex.huff | 2 +- test/Complex.t.sol | 69 ++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/ComplexHuff/Complex.huff b/src/ComplexHuff/Complex.huff index 91d5abc..c323bb8 100644 --- a/src/ComplexHuff/Complex.huff +++ b/src/ComplexHuff/Complex.huff @@ -345,7 +345,7 @@ } -// ///@notice e^(a+bi) calculation +///@notice e^(a+bi) calculation #define macro EXP_Z() = takes(2) returns(2) { //INPUT STACK => [Re(A),Im(A)] diff --git a/test/Complex.t.sol b/test/Complex.t.sol index d5ed8d0..4995538 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -85,7 +85,7 @@ contract ComplexTest is Test { } function testExpZ() public { - (int256 r, int256 i) = complex.expZ(92729522 * 1e10, 1); + (int256 r, int256 i) = complex.expZ(92729522*1e10 , 1); assertApproxEqAbs(r, 1630800000000000000, 1e15); assertApproxEqAbs(i, 2174400000000000000, 1e15); } @@ -111,10 +111,6 @@ contract ComplexTest is Test { int256 r = complex.atan1to1(9 * 1e17); assertEq((r * 100) / scale, 73); } - - // ai,bi,ar,br - // ai,bi,br,ar - // bi,ai,ar,br // bi,ai,br,ar function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { @@ -194,7 +190,29 @@ contract ComplexTest is Test { assertEq(rH / uint(scale), rS / uint(scale)); } - // failing fuzz test in case of theta + function testFromPolarFuzz(int256 r, int256 T) public { + vm.assume(r !=0); + + r = bound(r, -1e20, 1e20); + T = bound(T, -1e20, 1e20); + (int256 rH, int256 iH) = complex.fromPolar(r * scale, T * 1e10); + Num_Complex.Complex memory complexA = num_complex.fromPolar(r * scale, T * 1e10); + (int256 rS, int256 iS) = num_complex.unwrap(complexA); + + assertEq(rH, rS); + assertEq(iH, iS); + + } + + function testAtan1to1Fuzz(int256 r) public { + r = bound(r, -1e10, 1e10); + int256 rH = complex.atan1to1(r* 1e17); + int256 rS = num_complex.atan1to1(r*1e17); + assertEq((rH * 100) / scale, (rS*100)/scale); + } + + // failing fuzz test due to Topolar + // function testToPolarFuzz(int256 ar, int256 ai) public { // vm.assume(ar !=0); // vm.assume(ai !=0); @@ -222,6 +240,45 @@ contract ComplexTest is Test { // assertEq(r / scale, resultR / (scale)); // assertEq(i, resultI ); // } + + // function testAtan2() public { + // int256 r = complex.p_atan2(4 * scale, 3 * scale); + // int256 rS = num_complex.p_atan2(4 * scale, 3 * scale); + // assertEq((rS * 100) / scale, 0); + // assertEq((r * 100) / scale, 0); + // } + + // function testLnZFuzz(int256 ar, int256 ai) public { + // vm.assume(ar != 0); + // vm.assume(ai != 0); + // (int256 r, int256 i) = complex.ln(ar * scale, ar * scale); + // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar*scale,ai*scale); + // (int256 rS, int256 iS) = num_complex.unwrap(num_complex.ln(complexA)); + // assertEq((r * 100) / scale,(rS * 100) / scale ); // ln(50) = 3.912.. + // assertEq((i * 100) / scale, (iS * 100) / scale); + // } + + // function testExpZFuzz(int256 ar, int256 ai) public { + // (int256 rH, int256 iH) = complex.expZ(ar , ai); + // Num_Complex.Complex memory complexA =Num_Complex.Complex(ar,ai); + // (int256 rS, int256 iS) = num_complex.unwrap(num_complex.exp(complexA)); + // assertEq(rS ,rH); + // assertEq(iS,iH); + // } + + + // function testPowZ(int256 p, int256 ai, int256 ar) public { + // (int256 rH, int256 iH) = complex.pow(p, ai * scale, ar * scale); + // Num_Complex.Complex memory complexA =Num_Complex.Complex(ar*scale,ai*scale); + // (int256 rS, int256 iS) = num_complex.unwrap(num_complex.pow(complexA,p)); + // assertEq(rH,rS ); + // assertEq(iH,iS ); + // } + + + + + } interface WRAPPER { From 48e44531e94c92188c9714dcb93f7dbf419e4145 Mon Sep 17 00:00:00 2001 From: mohammed-talha-ansari Date: Fri, 15 Mar 2024 21:53:43 +0530 Subject: [PATCH 5/7] code is formatted now (forge fmt implemented) --- lib/foundry-huff | 2 +- src/complexMath/Complex.sol | 36 ++------- src/complexMath/prbMath/PRBMathSD59x18.sol | 2 - test/Complex.t.sol | 85 +++++----------------- 4 files changed, 28 insertions(+), 97 deletions(-) diff --git a/lib/foundry-huff b/lib/foundry-huff index c4ba155..7648faf 160000 --- a/lib/foundry-huff +++ b/lib/foundry-huff @@ -1 +1 @@ -Subproject commit c4ba1556174f2cd887700c42c86c1b56ccd0fe51 +Subproject commit 7648faf3990cc4561d52b71af03282fad3a803d8 diff --git a/src/complexMath/Complex.sol b/src/complexMath/Complex.sol index 1a60ae2..00c69ed 100644 --- a/src/complexMath/Complex.sol +++ b/src/complexMath/Complex.sol @@ -38,10 +38,7 @@ contract Num_Complex { /// @param a Complex Number /// @param b Complex Number /// @return Complex Number - function add( - Complex memory a, - Complex memory b - ) public pure returns (Complex memory) { + function add(Complex memory a, Complex memory b) public pure returns (Complex memory) { a.re += b.re; a.im += b.im; @@ -52,10 +49,7 @@ contract Num_Complex { /// @param a Complex number /// @param b Complex number /// @return Complex Number - function sub( - Complex memory a, - Complex memory b - ) public pure returns (Complex memory) { + function sub(Complex memory a, Complex memory b) public pure returns (Complex memory) { a.re -= b.re; a.im -= b.im; @@ -66,10 +60,7 @@ contract Num_Complex { /// @param a Complex number /// @param b Complex number /// @return Complex Number - function mul( - Complex memory a, - Complex memory b - ) public pure returns (Complex memory) { + function mul(Complex memory a, Complex memory b) public pure returns (Complex memory) { int256 _a = a.re * b.re; int256 _b = a.im * b.im; int256 _c = a.im * b.re; @@ -89,10 +80,7 @@ contract Num_Complex { /// @param a Complex number /// @param b Complex number /// @return Complex Number - function div( - Complex memory a, - Complex memory b - ) public pure returns (Complex memory) { + function div(Complex memory a, Complex memory b) public pure returns (Complex memory) { int256 numA = a.re * b.re + a.im * b.im; int256 den = b.re ** 2 + b.im ** 2; int256 numB = a.im * b.re - a.re * b.im; @@ -134,7 +122,7 @@ contract Num_Complex { // !!! if r is negative !!! int256 T = p_atan2(a.im, a.re) + 180e18; return (r, T); - } + } } /// @notice CONVERT FROM POLAR TO COMPLEX @@ -142,10 +130,7 @@ contract Num_Complex { /// @param r r /// @param T theta /// @return a Complex number - function fromPolar( - int256 r, - int256 T - ) public pure returns (Complex memory a) { + function fromPolar(int256 r, int256 T) public pure returns (Complex memory a) { // @dev check if T is negative if (T > 0) { a.re = (r * Trigonometry.cos(uint256(T))) / 1e18; @@ -208,9 +193,7 @@ contract Num_Complex { /// @param x (y/x) /// @return T T function atan1to1(int256 x) public pure returns (int256) { - int256 y = ((7.85e17 * x) / 1e18) - - (((x * (x - 1e18)) / 1e18) * (2.447e17 + ((6.63e16 * x) / 1e18))) / - 1e18; + int256 y = ((7.85e17 * x) / 1e18) - (((x * (x - 1e18)) / 1e18) * (2.447e17 + ((6.63e16 * x) / 1e18))) / 1e18; return y; } @@ -285,10 +268,7 @@ contract Num_Complex { /// @param a Complex number /// @param n base 1e18 /// @return Complex number - function pow( - Complex memory a, - int256 n - ) public pure returns (Complex memory) { + function pow(Complex memory a, int256 n) public pure returns (Complex memory) { (int256 r, int256 theta) = toPolar(a); // gas savings diff --git a/src/complexMath/prbMath/PRBMathSD59x18.sol b/src/complexMath/prbMath/PRBMathSD59x18.sol index 32cc3bb..e15f29b 100644 --- a/src/complexMath/prbMath/PRBMathSD59x18.sol +++ b/src/complexMath/prbMath/PRBMathSD59x18.sol @@ -670,7 +670,6 @@ library PRBMathSD59x18 { } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__SqrtOverflow(x); - } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). @@ -686,5 +685,4 @@ library PRBMathSD59x18 { result = x / SCALE; } } - } diff --git a/test/Complex.t.sol b/test/Complex.t.sol index 4995538..bacd602 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -18,45 +18,25 @@ contract ComplexTest is Test { } function testSubZ() public { - (int256 r, int256 i) = complex.subz( - 4 * scale, - 5 * scale, - 8 * scale, - 11 * scale - ); + (int256 r, int256 i) = complex.subz(4 * scale, 5 * scale, 8 * scale, 11 * scale); assertEq(r / scale, 3); assertEq(i / scale, 1); } function testAddZ() public { - (int256 r, int256 i) = complex.addz( - 2 * scale, - 3 * scale, - 4 * scale, - 5 * scale - ); + (int256 r, int256 i) = complex.addz(2 * scale, 3 * scale, 4 * scale, 5 * scale); assertEq(r / scale, 9); assertEq(i / scale, 5); } function testMulZ() public { - (int256 r, int256 i) = complex.mulz( - 2 * scale, - 3 * scale, - 4 * scale, - 5 * scale - ); + (int256 r, int256 i) = complex.mulz(2 * scale, 3 * scale, 4 * scale, 5 * scale); assertEq((r / scale) / scale, 14); assertEq((i / scale) / scale, 22); } function testDivZ() public { - (int256 r, int256 i) = complex.divz( - 7 * scale, - 1 * scale, - 5 * scale, - 2 * scale - ); + (int256 r, int256 i) = complex.divz(7 * scale, 1 * scale, 5 * scale, 2 * scale); assertEq((r * 10) / scale, 2); // 17/74 assertEq((i * 10) / scale, -1); // -8/74 } @@ -85,7 +65,7 @@ contract ComplexTest is Test { } function testExpZ() public { - (int256 r, int256 i) = complex.expZ(92729522*1e10 , 1); + (int256 r, int256 i) = complex.expZ(92729522 * 1e10, 1); assertApproxEqAbs(r, 1630800000000000000, 1e15); assertApproxEqAbs(i, 2174400000000000000, 1e15); } @@ -186,12 +166,12 @@ contract ComplexTest is Test { b = bound(a, -1e20, 1e20); uint256 rH = complex.calcR(a * scale, b * scale); - uint256 rS = uint(num_complex.r2(a * scale, b * scale)); - assertEq(rH / uint(scale), rS / uint(scale)); + uint256 rS = uint256(num_complex.r2(a * scale, b * scale)); + assertEq(rH / uint256(scale), rS / uint256(scale)); } - function testFromPolarFuzz(int256 r, int256 T) public { - vm.assume(r !=0); + function testFromPolarFuzz(int256 r, int256 T) public { + vm.assume(r != 0); r = bound(r, -1e20, 1e20); T = bound(T, -1e20, 1e20); @@ -201,18 +181,17 @@ contract ComplexTest is Test { assertEq(rH, rS); assertEq(iH, iS); - } function testAtan1to1Fuzz(int256 r) public { r = bound(r, -1e10, 1e10); - int256 rH = complex.atan1to1(r* 1e17); - int256 rS = num_complex.atan1to1(r*1e17); - assertEq((rH * 100) / scale, (rS*100)/scale); + int256 rH = complex.atan1to1(r * 1e17); + int256 rS = num_complex.atan1to1(r * 1e17); + assertEq((rH * 100) / scale, (rS * 100) / scale); } // failing fuzz test due to Topolar - + // function testToPolarFuzz(int256 ar, int256 ai) public { // vm.assume(ar !=0); // vm.assume(ai !=0); @@ -266,7 +245,6 @@ contract ComplexTest is Test { // assertEq(iS,iH); // } - // function testPowZ(int256 p, int256 ai, int256 ar) public { // (int256 rH, int256 iH) = complex.pow(p, ai * scale, ar * scale); // Num_Complex.Complex memory complexA =Num_Complex.Complex(ar*scale,ai*scale); @@ -274,41 +252,16 @@ contract ComplexTest is Test { // assertEq(rH,rS ); // assertEq(iH,iS ); // } +} +interface WRAPPER { + function subz(int256, int256, int256, int256) external returns (int256, int256); - + function addz(int256, int256, int256, int256) external returns (int256, int256); - -} + function mulz(int256, int256, int256, int256) external returns (int256, int256); -interface WRAPPER { - function subz( - int256, - int256, - int256, - int256 - ) external returns (int256, int256); - - function addz( - int256, - int256, - int256, - int256 - ) external returns (int256, int256); - - function mulz( - int256, - int256, - int256, - int256 - ) external returns (int256, int256); - - function divz( - int256, - int256, - int256, - int256 - ) external returns (int256, int256); + function divz(int256, int256, int256, int256) external returns (int256, int256); function calcR(int256, int256) external returns (uint256); From cc9a31933cd780bf615fc3c4c55199fe43251859 Mon Sep 17 00:00:00 2001 From: mohammed-talha-ansari Date: Tue, 19 Mar 2024 07:24:32 +0530 Subject: [PATCH 6/7] Fuzz test by using properties --- test/Complex.t.sol | 291 ++++++++++++++++++++++++--------------------- 1 file changed, 157 insertions(+), 134 deletions(-) diff --git a/test/Complex.t.sol b/test/Complex.t.sol index bacd602..5836ef3 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -5,16 +5,15 @@ import "foundry-huff/HuffDeployer.sol"; import "forge-std/Test.sol"; import "forge-std/console.sol"; import "../src/complexMath/Complex.sol"; +import {PRBMathSD59x18} from "../src/complexMath/prbMath/PRBMathSD59x18.sol"; contract ComplexTest is Test { WRAPPER public complex; int256 scale = 1e18; int256 scale2 = 1e19; - Num_Complex public num_complex; function setUp() public { complex = WRAPPER(HuffDeployer.deploy("ComplexHuff/WRAPPER")); - num_complex = new Num_Complex(); } function testSubZ() public { @@ -91,167 +90,191 @@ contract ComplexTest is Test { int256 r = complex.atan1to1(9 * 1e17); assertEq((r * 100) / scale, 73); } - // bi,ai,br,ar - function testAddZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + // bi,ai,br,ar + // We can say the Addition function is correct if + // it follows the properties of addition of complex numbers + // i.e. Closure,Commutative,Associative, + // Existance of Additive Identity and Additive Inverse + function testAddZFuzz(int256 bi, int256 ai, int256 ci, int256 br, int256 ar, int256 cr) public { //bounded input to avoid underflow or overflow bi = bound(bi, -1e40, 1e40); ai = bound(ai, -1e40, 1e40); + ci = bound(ci, -1e40, 1e40); br = bound(br, -1e40, 1e40); ar = bound(ar, -1e40, 1e40); - (int256 r, int256 i) = complex.addz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.add(complexA, complexB).re; - int256 resultI = num_complex.add(complexA, complexB).im; - - assertEq(resultR, r); - assertEq(resultI, i); + cr = bound(cr, -1e40, 1e40); + (int256 complexA_Br,int256 complexA_Bi)=(complex.addz(bi,ai,br,ar)); //A+B + (int256 complexB_Ar,int256 complexB_Ai)=(complex.addz(ai,bi,ar,br)); //B+A + (int256 complexB_Cr,int256 complexB_Ci)=(complex.addz(ci,bi,cr,br)); //B+C + (int256 complexAB_Cr,int256 complexAB_Ci) = (complex.addz(ci,complexA_Bi,cr,complexA_Br)); //(A+B)+C + (int256 complexA_BCr,int256 complexA_BCi) = (complex.addz(complexB_Ci,ai,complexB_Cr,ar)); //A+(B+c) + (int256 complexA_0r ,int256 complexA_0i)= (complex.addz(0,ai,0,ar)); //A + 0 + (int256 complexA__Ar,int256 complexA__Ai) = (complex.addz(-(ai),ai,-(ar),ar)); //A + (-A) + //Commutative A + B = B + A + assertEq(complexA_Br,complexB_Ar); + assertEq(complexA_Bi,complexB_Ai); + //Associative (A+B)+C = A+(B+C) + assertEq(complexAB_Cr,complexA_BCr); + assertEq(complexAB_Ci,complexA_BCi); + // Existance of additive identity A+0=A + assertEq(complexA_0r,ar); + assertEq(complexA_0i,ai); + //Existance of additive inverse A + (-A)=0 + assertEq(complexA__Ar,0); + assertEq(complexA__Ai,0); } - function testSubZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + function testSubZFuzz(int256 bi, int256 ai, int256 ci, int256 br, int256 ar, int256 cr) public { //bounded input to avoid underflow or overflow + vm.assume(ai!=bi); + vm.assume(bi!=ci); + vm.assume(ai!=ci); + vm.assume(ar!=br); + vm.assume(br!=cr); + vm.assume(ar!=cr); + vm.assume(bi!=0); + vm.assume(ai!=0); + vm.assume(ci!=0); + vm.assume(ar!=0); + vm.assume(br!=0); + vm.assume(cr!=0); bi = bound(bi, -1e40, 1e40); ai = bound(ai, -1e40, 1e40); + ci = bound(ci, -1e40, 1e40); br = bound(br, -1e40, 1e40); ar = bound(ar, -1e40, 1e40); - (int256 r, int256 i) = complex.subz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.sub(complexA, complexB).re; - int256 resultI = num_complex.sub(complexA, complexB).im; - - assertEq(resultR, r); - assertEq(resultI, i); + cr = bound(cr, -1e40, 1e40); + (int256 complexA_Br,int256 complexA_Bi)=(complex.subz(bi,ai,br,ar)); //A-B + (int256 complexB_Ar,int256 complexB_Ai)=(complex.subz(ai,bi,ar,br)); //B-A + (int256 complexB_Cr,int256 complexB_Ci)=(complex.subz(ci,bi,cr,br)); //B-C + (int256 complexAB_Cr,int256 complexAB_Ci) = (complex.subz(ci,complexA_Bi,cr,complexA_Br)); //(A-B)-C + (int256 complexA_BCr,int256 complexA_BCi) = (complex.subz(complexB_Ci,ai,complexB_Cr,ar)); //A-(B-c) + (int256 complexA_0r ,int256 complexA_0i)= (complex.subz(0,ai,0,ar)); //A - 0 + + //Commutative A - B != B - A + assertFalse(complexA_Br==complexB_Ar); + assertFalse(complexA_Bi==complexB_Ai); + //Associative (A-B)-C != A-(B-C) + assertFalse(complexAB_Cr==complexA_BCr); + assertFalse(complexAB_Ci==complexA_BCi); + // Existance of additive identity A-0=A + assertEq(complexA_0r,ar); + assertEq(complexA_0i,ai); } - function testMulZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { - //bounded input to avoid underflow or overflow - bi = bound(bi, -1e30, 1e30); - ai = bound(ai, -1e30, 1e30); - br = bound(br, -1e30, 1e30); - ar = bound(ar, -1e30, 1e30); - (int256 r, int256 i) = complex.mulz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.mul(complexA, complexB).re; - int256 resultI = num_complex.mul(complexA, complexB).im; - assertEq(resultR, r); - assertEq(resultI, i); - } - - function testDivZFuzz(int256 bi, int256 ai, int256 br, int256 ar) public { + function testMulZFuzz(int256 bi, int256 ai, int256 ci, int256 br, int256 ar, int256 cr) public { //bounded input to avoid underflow or overflow + vm.assume(ai != bi); + vm.assume(bi != ci); + vm.assume(ai != ci); + vm.assume(ar != br); + vm.assume(br != cr); + vm.assume(ar != cr); + vm.assume(bi != -1); + vm.assume(ai != -1); + vm.assume(ci != -1); + vm.assume(ar != -1); + vm.assume(br != -1); + vm.assume(cr != -1); + vm.assume(bi != 1); + vm.assume(ai != 1); + vm.assume(ci != 1); + vm.assume(ar != 1); + vm.assume(br != 1); + vm.assume(cr != 1); vm.assume(bi != 0); vm.assume(ai != 0); - vm.assume(br != 0); + vm.assume(ci != 0); vm.assume(ar != 0); + vm.assume(br != 0); + vm.assume(cr != 0); bi = bound(bi, -1e10, 1e10); ai = bound(ai, -1e10, 1e10); + ci = bound(ci, -1e10, 1e10); br = bound(br, -1e10, 1e10); ar = bound(ar, -1e10, 1e10); - - (int256 r, int256 i) = complex.divz(bi, ai, br, ar); - Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - Num_Complex.Complex memory complexB = Num_Complex.Complex(br, bi); - int256 resultR = num_complex.div(complexA, complexB).re; - int256 resultI = num_complex.div(complexA, complexB).im; - - assertEq(resultR, r); - assertEq(resultI, i); + cr = bound(cr, -1e10, 1e10); + (int256 complexA_Br, int256 complexA_Bi) = (complex.mulz(bi, ai, br, ar)); //A*B + (int256 complexB_Ar, int256 complexB_Ai) = (complex.mulz(ai, bi, ar, br)); //B*A + (int256 complexB_Cr, int256 complexB_Ci) = (complex.mulz(ci, bi, cr, br)); //B*C + (int256 complexA_Cr, int256 complexA_Ci) = (complex.mulz(ci, ai, cr, ar)); //A*C + (int256 complexAB_Cr, int256 complexAB_Ci) = (complex.mulz(ci, complexA_Bi, cr, complexA_Br)); //(AB)*C + (int256 complexA_BCr, int256 complexA_BCi) = (complex.mulz(complexB_Ci, ai, complexB_Cr, ar)); //A*(BC) + (int256 complexA__Br, int256 complexA__Bi) = (complex.addz(bi, ai, br, ar)); //A+B + (int256 complexAB__Cr, int256 complexAB__Ci) = (complex.mulz(ci, complexA__Bi, cr, complexA__Br)); //(A+B)*C + (int256 complexAC_BCr, int256 complexAC_BCi) = + (complex.addz(complexB_Ci, complexA_Ci, complexB_Cr, complexA_Cr)); // AC+BC + (int256 complexA_Ar, int256 complexA_Ai) = (complex.mulz(0, ai, 1, ar)); //A*1 + (int256 complexdAr,int256 complexdAi) = (complex.divz(ai*scale,0*scale,ar*scale,1*scale)); // 1/A + (int256 complexinAr,int256 complexinAi)=(complex.mulz(complexdAi,ai,complexdAr,ar)); // (1/A)*A + + //Commutative A*B != B*A + assertFalse(complexA_Br != complexB_Ar); + assertFalse(complexA_Bi != complexB_Ai); + //Associative (AB)C=A(BC) + assertEq(complexAB_Cr, complexA_BCr); + assertEq(complexAB_Ci, complexA_BCi); + //Distributive (A+B)*C=AC+BC + assertEq(complexAB__Cr, complexAC_BCr); + assertEq(complexAB__Ci, complexAC_BCi); + // Existance of additive identity A*1=A + assertEq(complexA_Ar, ar); + assertEq(complexA_Ai, ai); + //Existance of additive inverse A*(1/A)= 1 + assertEq(complexinAi/scale,0); + assertApproxEqAbs(complexinAr*10/scale,10,5); } - function testCalcRFuzz(int256 a, int256 b) public { - a = bound(a, -1e20, 1e20); - b = bound(a, -1e20, 1e20); - - uint256 rH = complex.calcR(a * scale, b * scale); - uint256 rS = uint256(num_complex.r2(a * scale, b * scale)); - assertEq(rH / uint256(scale), rS / uint256(scale)); + // devision is basically and multiplication of complex numbers is tested above + function testDivZFuzz(int256 ar,int256 ai,int256 br,int256 bi) public{ + vm.assume(ai!=0); + vm.assume(bi!=0); + vm.assume(ar!=0); + vm.assume(br!=0); + ai = bound(ai,-1e10,1e10); + bi = bound(bi,-1e10,1e10); + ar = bound(ar,-1e10,1e10); + br = bound(br,-1e10,1e10); + (int256 Nr,int256 Ni)=(complex.mulz(-bi,ai,br,ar)); + (int256 Dr,)=(complex.mulz(-bi,bi,br,br)); + int256 Rr= PRBMathSD59x18.div(Nr,Dr); + int256 Ri= PRBMathSD59x18.div(Ni,Dr); + (int256 Rhr,int256 Rhi)=(complex.divz(bi,ai,br,ar)); + assertEq(Rr,Rhr); + assertEq(Ri,Rhi); } - function testFromPolarFuzz(int256 r, int256 T) public { - vm.assume(r != 0); - - r = bound(r, -1e20, 1e20); - T = bound(T, -1e20, 1e20); - (int256 rH, int256 iH) = complex.fromPolar(r * scale, T * 1e10); - Num_Complex.Complex memory complexA = num_complex.fromPolar(r * scale, T * 1e10); - (int256 rS, int256 iS) = num_complex.unwrap(complexA); - - assertEq(rH, rS); - assertEq(iH, iS); - } - - function testAtan1to1Fuzz(int256 r) public { - r = bound(r, -1e10, 1e10); - int256 rH = complex.atan1to1(r * 1e17); - int256 rS = num_complex.atan1to1(r * 1e17); - assertEq((rH * 100) / scale, (rS * 100) / scale); - } - - // failing fuzz test due to Topolar - - // function testToPolarFuzz(int256 ar, int256 ai) public { - // vm.assume(ar !=0); - // vm.assume(ai !=0); - // ar = bound(ar, -1e20, 1e20); - // ai = bound(ai, -1e20, 1e20); - // (int256 rH, int256 tH) = complex.toPolar(ar, ai); - // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar, ai); - // (int256 rS, int256 tS) = num_complex.toPolar(complexA); - // assertApproxEqAbs(rS ,rH ,10); - // assertEq(tH , tS); - // } - - // function testSqrtFuzz(int256 ar, int256 ai) public { - // vm.assume(ar != 0); - // vm.assume(ai != 0); - // ar = bound(ar, -1e20, 1e20); - // ai = bound(ai, -1e20, 1e20); - // (int256 r, int256 i) = complex.sqrt(ai, ar); - // Num_Complex.Complex memory complexA = Num_Complex.Complex( - // ar, - // ai - // ); - // int256 resultR = num_complex.sqrt(complexA).re; - // int256 resultI = num_complex.sqrt(complexA).im; - // assertEq(r / scale, resultR / (scale)); - // assertEq(i, resultI ); - // } - - // function testAtan2() public { - // int256 r = complex.p_atan2(4 * scale, 3 * scale); - // int256 rS = num_complex.p_atan2(4 * scale, 3 * scale); - // assertEq((rS * 100) / scale, 0); - // assertEq((r * 100) / scale, 0); - // } - - // function testLnZFuzz(int256 ar, int256 ai) public { - // vm.assume(ar != 0); - // vm.assume(ai != 0); - // (int256 r, int256 i) = complex.ln(ar * scale, ar * scale); - // Num_Complex.Complex memory complexA = Num_Complex.Complex(ar*scale,ai*scale); - // (int256 rS, int256 iS) = num_complex.unwrap(num_complex.ln(complexA)); - // assertEq((r * 100) / scale,(rS * 100) / scale ); // ln(50) = 3.912.. - // assertEq((i * 100) / scale, (iS * 100) / scale); + // function testCalc_RFuzz(int256 ar, int256 ai, int256 br, int256 bi, int256 k) public { + // ai = bound(ai, -1e9, 1e9); + // bi = bound(bi, -1e9, 1e9); + // ar = bound(ar, -1e9, 1e9); + // br = bound(br, -1e9, 1e9); + // k = bound(k, -1e9, 1e9); + + // (int256 mag1r,) = (complex.mulz(-ai, ai, ar, ar)); // ar^2 + ai^2 + // int256 mag1 = PRBMathSD59x18.sqrt(mag1r); // (ar^2+ai^2)^0.5 + // uint256 R1 = (complex.calcR(ai, ar)); // magnitude(A) + // uint256 R2 = (complex.calcR(bi, br)); // magnitude(B) + // (int256 A_Br, int256 A_Bi) = (complex.addz(bi, ai, br, ai)); // A+B + // uint256 R3 = (complex.calcR(A_Bi, A_Br)); // magnitude(A+B) + // uint256 R4 = (complex.calcR(k * ai, k * ar)); // magnitude(k*A) + // uint256 magk = (complex.calcR(0, k)); + // uint256 _R1 = (complex.calcR(-ai, ar)); + + // // Test by comparing + // assertEq(uint256(mag1) / 1e9, R1); + + // // Test by property + // // mag(A+B)<=mag(A)+mag(B) + // assert(R3 <= (R1 + R2)); + // // mag(kA)=kmag(A) + // assertEq(R4,(magk)*R1); + // // mag(A)=mag(A') + // assertEq(R1,_R1); // } - // function testExpZFuzz(int256 ar, int256 ai) public { - // (int256 rH, int256 iH) = complex.expZ(ar , ai); - // Num_Complex.Complex memory complexA =Num_Complex.Complex(ar,ai); - // (int256 rS, int256 iS) = num_complex.unwrap(num_complex.exp(complexA)); - // assertEq(rS ,rH); - // assertEq(iS,iH); - // } - - // function testPowZ(int256 p, int256 ai, int256 ar) public { - // (int256 rH, int256 iH) = complex.pow(p, ai * scale, ar * scale); - // Num_Complex.Complex memory complexA =Num_Complex.Complex(ar*scale,ai*scale); - // (int256 rS, int256 iS) = num_complex.unwrap(num_complex.pow(complexA,p)); - // assertEq(rH,rS ); - // assertEq(iH,iS ); - // } + } interface WRAPPER { From 59b971066ef21610f7312daab852f173b4995aa3 Mon Sep 17 00:00:00 2001 From: mohammed-talha-ansari Date: Sat, 23 Mar 2024 17:18:40 +0530 Subject: [PATCH 7/7] resolved stacktoodeep error in fuzz tests, implemented forge fmt, modified testDivZ and testCalcR --- src/ComplexHuff/Complex.huff | 32 +++---- test/Complex.t.sol | 169 ++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 97 deletions(-) diff --git a/src/ComplexHuff/Complex.huff b/src/ComplexHuff/Complex.huff index c323bb8..c34c60c 100644 --- a/src/ComplexHuff/Complex.huff +++ b/src/ComplexHuff/Complex.huff @@ -103,16 +103,16 @@ #define macro TO_POLAR() = takes(2) returns(2) { // INPUT STACK => [RE(a),IM(a)] - dup2 //[i,r,i] - dup2 //[r,i,r,i] - CALC_R() - swap2 // [Im(a),Re(a),r] - [X3] - mul - sdiv // [1e18*Im(a)/Re(a),r] => [x1,r] - dup1 - [X3] - gt case1 jumpi + dup2 //[i,r,i] + dup2 //[r,i,r,i] + CALC_R() //[r,ra,ia] + swap2 // [Im(a),Re(a),r] + [X3] //[1e18,ia,ra,r] + mul //[1e18*ia,ra,r] + sdiv //[1e18*Im(a)/Re(a),r] => [x1,r] + dup1 //[x1,x1,r] + [X3] //[1e18,x1,x1,r] + gt case1 jumpi //[1e18>x1,x1,r] dup1 [X3] eq case2 jumpi @@ -156,11 +156,11 @@ swap1 finish jump - case1: + case1: // if y>x dup1 // [x1,x1,r] - [X11] - swap1 - sdiv // [a,x1,r] + [X11] //[1e12,x1,x1,r] + swap1 //[x1,1e12,x1,r] + sdiv // [a=x1/1e12,x1,r] 0x03 // [0x03,a,x1,r] swap1 // [a,3,x1,r] exp // [a**3,x1,r] @@ -170,9 +170,9 @@ 0x01 // [1,a**3/3,..] 0x00 // [0,1,a**3/3,..] sub // [-1,a**3/3,..] - mul // [x2,x1,r] + mul // [x2=-(a**3)/3,x1,r] dup2 // [x1,x2,x1,r] - [X12] + [X12] //[] swap1 sdiv //[b,x2,..] 0x05 //[5,b,..] diff --git a/test/Complex.t.sol b/test/Complex.t.sol index 5836ef3..ee0b057 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -36,13 +36,13 @@ contract ComplexTest is Test { function testDivZ() public { (int256 r, int256 i) = complex.divz(7 * scale, 1 * scale, 5 * scale, 2 * scale); - assertEq((r * 10) / scale, 2); // 17/74 - assertEq((i * 10) / scale, -1); // -8/74 + assertEq(r, 229729729729729729); // (17/74 = 0.229729729729729729..) + assertEq(i, -121621621621621621); // (-9/74=-0.121621621621621621) } function testCalcR() public { uint256 r = complex.calcR(4 * scale, 4 * scale); - assertEq(r / uint256(scale), 5); + assertEq(r, 5656854249492380195); // root(32)=5.656854249492380195 } function testToPolar() public { @@ -104,63 +104,69 @@ contract ComplexTest is Test { br = bound(br, -1e40, 1e40); ar = bound(ar, -1e40, 1e40); cr = bound(cr, -1e40, 1e40); - (int256 complexA_Br,int256 complexA_Bi)=(complex.addz(bi,ai,br,ar)); //A+B - (int256 complexB_Ar,int256 complexB_Ai)=(complex.addz(ai,bi,ar,br)); //B+A - (int256 complexB_Cr,int256 complexB_Ci)=(complex.addz(ci,bi,cr,br)); //B+C - (int256 complexAB_Cr,int256 complexAB_Ci) = (complex.addz(ci,complexA_Bi,cr,complexA_Br)); //(A+B)+C - (int256 complexA_BCr,int256 complexA_BCi) = (complex.addz(complexB_Ci,ai,complexB_Cr,ar)); //A+(B+c) - (int256 complexA_0r ,int256 complexA_0i)= (complex.addz(0,ai,0,ar)); //A + 0 - (int256 complexA__Ar,int256 complexA__Ai) = (complex.addz(-(ai),ai,-(ar),ar)); //A + (-A) + (int256 complexA_Br, int256 complexA_Bi) = (complex.addz(bi, ai, br, ar)); //A+B + (int256 complexB_Ar, int256 complexB_Ai) = (complex.addz(ai, bi, ar, br)); //B+A + (int256 complexB_Cr, int256 complexB_Ci) = (complex.addz(ci, bi, cr, br)); //B+C + //Commutative A + B = B + A - assertEq(complexA_Br,complexB_Ar); - assertEq(complexA_Bi,complexB_Ai); + assertEq(complexA_Br, complexB_Ar); + assertEq(complexA_Bi, complexB_Ai); + + //Used same variables to avoid stacktoodeep error + (complexA_Br, complexA_Bi) = (complex.addz(ci, complexA_Bi, cr, complexA_Br)); //(A+B)+C + (complexB_Cr, complexB_Ci) = (complex.addz(complexB_Ci, ai, complexB_Cr, ar)); //A+(B+c) //Associative (A+B)+C = A+(B+C) - assertEq(complexAB_Cr,complexA_BCr); - assertEq(complexAB_Ci,complexA_BCi); + assertEq(complexA_Br, complexB_Cr); + assertEq(complexA_Bi, complexB_Ci); + + (complexA_Br, complexA_Bi) = (complex.addz(0, ai, 0, ar)); //A + 0 + (complexB_Cr, complexB_Ci) = (complex.addz(-(ai), ai, -(ar), ar)); //A + (-A) // Existance of additive identity A+0=A - assertEq(complexA_0r,ar); - assertEq(complexA_0i,ai); + assertEq(complexA_Br, ar); + assertEq(complexA_Bi, ai); //Existance of additive inverse A + (-A)=0 - assertEq(complexA__Ar,0); - assertEq(complexA__Ai,0); + assertEq(complexB_Cr, 0); + assertEq(complexB_Ci, 0); } function testSubZFuzz(int256 bi, int256 ai, int256 ci, int256 br, int256 ar, int256 cr) public { //bounded input to avoid underflow or overflow - vm.assume(ai!=bi); - vm.assume(bi!=ci); - vm.assume(ai!=ci); - vm.assume(ar!=br); - vm.assume(br!=cr); - vm.assume(ar!=cr); - vm.assume(bi!=0); - vm.assume(ai!=0); - vm.assume(ci!=0); - vm.assume(ar!=0); - vm.assume(br!=0); - vm.assume(cr!=0); + vm.assume(ai != bi); + vm.assume(bi != ci); + vm.assume(ai != ci); + vm.assume(ar != br); + vm.assume(br != cr); + vm.assume(ar != cr); + vm.assume(bi != 0); + vm.assume(ai != 0); + vm.assume(ci != 0); + vm.assume(ar != 0); + vm.assume(br != 0); + vm.assume(cr != 0); bi = bound(bi, -1e40, 1e40); ai = bound(ai, -1e40, 1e40); ci = bound(ci, -1e40, 1e40); br = bound(br, -1e40, 1e40); ar = bound(ar, -1e40, 1e40); cr = bound(cr, -1e40, 1e40); - (int256 complexA_Br,int256 complexA_Bi)=(complex.subz(bi,ai,br,ar)); //A-B - (int256 complexB_Ar,int256 complexB_Ai)=(complex.subz(ai,bi,ar,br)); //B-A - (int256 complexB_Cr,int256 complexB_Ci)=(complex.subz(ci,bi,cr,br)); //B-C - (int256 complexAB_Cr,int256 complexAB_Ci) = (complex.subz(ci,complexA_Bi,cr,complexA_Br)); //(A-B)-C - (int256 complexA_BCr,int256 complexA_BCi) = (complex.subz(complexB_Ci,ai,complexB_Cr,ar)); //A-(B-c) - (int256 complexA_0r ,int256 complexA_0i)= (complex.subz(0,ai,0,ar)); //A - 0 + (int256 complexA_Br, int256 complexA_Bi) = (complex.subz(bi, ai, br, ar)); //A-B + (int256 complexB_Ar, int256 complexB_Ai) = (complex.subz(ai, bi, ar, br)); //B-A + (int256 complexB_Cr, int256 complexB_Ci) = (complex.subz(ci, bi, cr, br)); //B-C //Commutative A - B != B - A - assertFalse(complexA_Br==complexB_Ar); - assertFalse(complexA_Bi==complexB_Ai); + assertFalse(complexA_Br == complexB_Ar); + assertFalse(complexA_Bi == complexB_Ai); + + (complexA_Br, complexA_Bi) = (complex.subz(ci, complexA_Bi, cr, complexA_Br)); //(A-B)-C + (complexB_Ar, complexB_Ai) = (complex.subz(complexB_Ci, ai, complexB_Cr, ar)); //A-(B-c) //Associative (A-B)-C != A-(B-C) - assertFalse(complexAB_Cr==complexA_BCr); - assertFalse(complexAB_Ci==complexA_BCi); + assertFalse(complexA_Br == complexB_Ar); + assertFalse(complexA_Bi == complexB_Ai); + + (complexA_Br, complexA_Bi) = (complex.subz(0, ai, 0, ar)); //A - 0 // Existance of additive identity A-0=A - assertEq(complexA_0r,ar); - assertEq(complexA_0i,ai); + assertEq(complexA_Br, ar); + assertEq(complexA_Bi, ai); } function testMulZFuzz(int256 bi, int256 ai, int256 ci, int256 br, int256 ar, int256 cr) public { @@ -195,54 +201,57 @@ contract ComplexTest is Test { br = bound(br, -1e10, 1e10); ar = bound(ar, -1e10, 1e10); cr = bound(cr, -1e10, 1e10); + (int256 complexA_Br, int256 complexA_Bi) = (complex.mulz(bi, ai, br, ar)); //A*B (int256 complexB_Ar, int256 complexB_Ai) = (complex.mulz(ai, bi, ar, br)); //B*A (int256 complexB_Cr, int256 complexB_Ci) = (complex.mulz(ci, bi, cr, br)); //B*C (int256 complexA_Cr, int256 complexA_Ci) = (complex.mulz(ci, ai, cr, ar)); //A*C - (int256 complexAB_Cr, int256 complexAB_Ci) = (complex.mulz(ci, complexA_Bi, cr, complexA_Br)); //(AB)*C - (int256 complexA_BCr, int256 complexA_BCi) = (complex.mulz(complexB_Ci, ai, complexB_Cr, ar)); //A*(BC) - (int256 complexA__Br, int256 complexA__Bi) = (complex.addz(bi, ai, br, ar)); //A+B - (int256 complexAB__Cr, int256 complexAB__Ci) = (complex.mulz(ci, complexA__Bi, cr, complexA__Br)); //(A+B)*C - (int256 complexAC_BCr, int256 complexAC_BCi) = - (complex.addz(complexB_Ci, complexA_Ci, complexB_Cr, complexA_Cr)); // AC+BC - (int256 complexA_Ar, int256 complexA_Ai) = (complex.mulz(0, ai, 1, ar)); //A*1 - (int256 complexdAr,int256 complexdAi) = (complex.divz(ai*scale,0*scale,ar*scale,1*scale)); // 1/A - (int256 complexinAr,int256 complexinAi)=(complex.mulz(complexdAi,ai,complexdAr,ar)); // (1/A)*A - - //Commutative A*B != B*A - assertFalse(complexA_Br != complexB_Ar); - assertFalse(complexA_Bi != complexB_Ai); + //Commutative A*B = B*A + assertEq(complexA_Br, complexB_Ar); + assertEq(complexA_Bi, complexB_Ai); + + (complexA_Br, complexA_Bi) = (complex.mulz(ci, complexA_Bi, cr, complexA_Br)); //(AB)*C + (complexB_Ar, complexB_Ai) = (complex.mulz(complexB_Ci, ai, complexB_Cr, ar)); //A*(BC) //Associative (AB)C=A(BC) - assertEq(complexAB_Cr, complexA_BCr); - assertEq(complexAB_Ci, complexA_BCi); + assertEq(complexA_Br, complexB_Ar); + assertEq(complexA_Bi, complexB_Ai); + + (complexA_Br, complexA_Bi) = (complex.addz(bi, ai, br, ar)); //A+B + (complexA_Br, complexA_Bi) = (complex.mulz(ci, complexA_Bi, cr, complexA_Br)); //(A+B)*C + (complexB_Ar, complexB_Ai) = (complex.addz(complexB_Ci, complexA_Ci, complexB_Cr, complexA_Cr)); // AC+BC //Distributive (A+B)*C=AC+BC - assertEq(complexAB__Cr, complexAC_BCr); - assertEq(complexAB__Ci, complexAC_BCi); + assertEq(complexA_Br, complexB_Ar); + assertEq(complexA_Bi, complexB_Ai); + + (complexA_Br, complexA_Bi) = (complex.mulz(0, ai, 1, ar)); //A*1 // Existance of additive identity A*1=A - assertEq(complexA_Ar, ar); - assertEq(complexA_Ai, ai); + assertEq(complexA_Br, ar); + assertEq(complexA_Bi, ai); + + (complexA_Br, complexA_Bi) = (complex.divz(ai * scale, 0 * scale, ar * scale, 1 * scale)); // 1/A + (complexA_Br, complexA_Bi) = (complex.mulz(complexA_Bi, ai, complexA_Br, ar)); // (1/A)*A //Existance of additive inverse A*(1/A)= 1 - assertEq(complexinAi/scale,0); - assertApproxEqAbs(complexinAr*10/scale,10,5); + assertEq(complexA_Bi / scale, 0); + assertApproxEqAbs(complexA_Br * 10 / scale, 10, 5); } // devision is basically and multiplication of complex numbers is tested above - function testDivZFuzz(int256 ar,int256 ai,int256 br,int256 bi) public{ - vm.assume(ai!=0); - vm.assume(bi!=0); - vm.assume(ar!=0); - vm.assume(br!=0); - ai = bound(ai,-1e10,1e10); - bi = bound(bi,-1e10,1e10); - ar = bound(ar,-1e10,1e10); - br = bound(br,-1e10,1e10); - (int256 Nr,int256 Ni)=(complex.mulz(-bi,ai,br,ar)); - (int256 Dr,)=(complex.mulz(-bi,bi,br,br)); - int256 Rr= PRBMathSD59x18.div(Nr,Dr); - int256 Ri= PRBMathSD59x18.div(Ni,Dr); - (int256 Rhr,int256 Rhi)=(complex.divz(bi,ai,br,ar)); - assertEq(Rr,Rhr); - assertEq(Ri,Rhi); + function testDivZFuzz(int256 ar, int256 ai, int256 br, int256 bi) public { + vm.assume(ai != 0); + vm.assume(bi != 0); + vm.assume(ar != 0); + vm.assume(br != 0); + ai = bound(ai, -1e10, 1e10); + bi = bound(bi, -1e10, 1e10); + ar = bound(ar, -1e10, 1e10); + br = bound(br, -1e10, 1e10); + (int256 Nr, int256 Ni) = (complex.mulz(-bi, ai, br, ar)); + (int256 Dr,) = (complex.mulz(-bi, bi, br, br)); + int256 Rr = PRBMathSD59x18.div(Nr, Dr); + int256 Ri = PRBMathSD59x18.div(Ni, Dr); + (int256 Rhr, int256 Rhi) = (complex.divz(bi, ai, br, ar)); + assertEq(Rr, Rhr); + assertEq(Ri, Rhi); } // function testCalc_RFuzz(int256 ar, int256 ai, int256 br, int256 bi, int256 k) public { @@ -273,8 +282,6 @@ contract ComplexTest is Test { // // mag(A)=mag(A') // assertEq(R1,_R1); // } - - } interface WRAPPER {