Skip to content

Commit

Permalink
Fuzz test by using properties
Browse files Browse the repository at this point in the history
  • Loading branch information
mohammed-talha-ansari committed Mar 19, 2024
1 parent 48e4453 commit cc9a319
Showing 1 changed file with 157 additions and 134 deletions.
291 changes: 157 additions & 134 deletions test/Complex.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit cc9a319

Please sign in to comment.