Skip to content

Commit

Permalink
Merge pull request #28 from mohammed-talha-ansari/talha
Browse files Browse the repository at this point in the history
Fuzz test by using properties
  • Loading branch information
0xpanicError authored Mar 23, 2024
2 parents 1f4841a + 59b9710 commit 5b561de
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 27 deletions.
36 changes: 18 additions & 18 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 @@ -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
Expand Down Expand Up @@ -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]
Expand All @@ -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,..]
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
204 changes: 199 additions & 5 deletions test/Complex.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ 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";
import {PRBMathSD59x18} from "../src/complexMath/prbMath/PRBMathSD59x18.sol";

contract ComplexTest is Test {
WRAPPER public complex;
Expand Down Expand Up @@ -34,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 {
Expand Down Expand Up @@ -75,8 +77,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 +90,198 @@ contract ComplexTest is Test {
int256 r = complex.atan1to1(9 * 1e17);
assertEq((r * 100) / scale, 73);
}

// 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);
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

//Commutative A + B = B + A
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(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_Br, ar);
assertEq(complexA_Bi, ai);
//Existance of additive inverse A + (-A)=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);
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
//Commutative A - B != B - A
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(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_Br, ar);
assertEq(complexA_Bi, ai);
}

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(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);
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
//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(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(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_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(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 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);
// }
}

interface WRAPPER {
Expand Down

0 comments on commit 5b561de

Please sign in to comment.