Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Fuzz Test for Add_Z, Sub_Z, Mul_Z, Div_Z, CalcR, FromPolar, Atan1to1 (issue #21) #25

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ComplexHuff/Complex.huff
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down
12 changes: 8 additions & 4 deletions src/complexMath/Complex.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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 ??
Expand Down
168 changes: 166 additions & 2 deletions test/Complex.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down