Skip to content

Commit

Permalink
[series] add complex type, drop gmpxx dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
spj101 committed Dec 22, 2021
1 parent efd835e commit 33038e9
Show file tree
Hide file tree
Showing 17 changed files with 439 additions and 130 deletions.
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ Example: (taken from `examples/intro`) Parse the expression `x+2*y^3` for `x=5/6

```cpp
#include <iostream>
#include <gmpxx.h>
#include "exparse.hpp"

int main()
Expand All @@ -36,14 +35,14 @@ int main()

parser.substitution_table =
{
{"a",5_mpq/6_mpq},
{"b",7_mpq/3_mpq},
{"c",11_mpq/5_mpq}
{"a","5/6"},
{"b","7/3"},
{"c","11/5"}
};

std::string expression = "a+2*b^3+x*a*b";

std::map<std::vector<long long int>, mpq_class> result = parser.parse_expression(expression);
std::map<std::vector<long long int>, mpqc_class> result = parser.parse_expression(expression);

// Print symbols in order declared
for(auto symbol : parser.symbol_table)
Expand All @@ -64,14 +63,14 @@ int main()

Compile:
```shell
$ c++ -std=c++17 -O3 -I<path/to/exparse.hpp> intro.cpp -lgmpxx -lgmp -o intro
$ c++ -std=c++17 -O3 -I<path/to/exparse.hpp> intro.cpp -lgmp -o intro
```

Output:
```shell
x
0 : 1417/54
1 : 35/18
0 : (1417/54,0)
1 : (35/18,0)
```

For further examples see the [examples folder](examples).
Expand All @@ -86,15 +85,15 @@ A single instance of `exparse` should not be used concurrently by multiple threa

A vector of the names of each series variable. The code will output the coefficients of each term in the series.

`std::unordered_map<std::string,mpq_class> substitution_table;`
`std::unordered_map<std::string,mpqc_class> substitution_table;`

An unordered map between variables (represented by a string) and their values (represented by a rational number). The substitution table is used during expression parsing to replace variables by their value.

### Public Member Functions

`mpq_class parse_expression(std::string& expression)`
`std::map<std::vector<int_t>, rational_t> parse_expression(const std::string& expression)`

Parse the expression (represented by a string) and return a rational number.
Parse the expression (represented by a string) and return a map of symbol powers to rational numbers. Each element of the map represents a term in the expression, the symbol powers represent the power of each symbol in the `symbol_table` and the rational numbers represent their coefficient.

## Authors

Expand Down
94 changes: 46 additions & 48 deletions check/exparse_core/test_exparse_core.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#include "catch.hpp"
#include "exparse.hpp"

#include <gmpxx.h>

TEST_CASE( "Operations" , "[exparse]" )
{
typedef mpq_class rational_t;
typedef mpqc_class rational_t;

std::string n = "5/7";
std::string pn = "+5/7";
Expand Down Expand Up @@ -45,14 +43,14 @@ TEST_CASE( "Operations" , "[exparse]" )
{
Exparse parser;

REQUIRE( parser.parse_expression(n).begin()->second == 5_mpq/7_mpq );
REQUIRE( parser.parse_expression(pn).begin()->second == 5_mpq/7_mpq );
REQUIRE( parser.parse_expression(mn).begin()->second == -5_mpq/7_mpq );
REQUIRE( parser.parse_expression(n1).begin()->second == 5_mpq/7_mpq );
REQUIRE( parser.parse_expression(nsq).begin()->second == 25_mpq/49_mpq );
REQUIRE( parser.parse_expression(nmsq).begin()->second == 49_mpq/25_mpq );
REQUIRE( parser.parse_expression(mnsq).begin()->second == -25_mpq/49_mpq );
REQUIRE( parser.parse_expression(mnmsq).begin()->second == -49_mpq/25_mpq );
REQUIRE( parser.parse_expression(n).begin()->second == mpqc_class("5/7") );
REQUIRE( parser.parse_expression(pn).begin()->second == mpqc_class("5/7") );
REQUIRE( parser.parse_expression(mn).begin()->second == mpqc_class("-5/7") );
REQUIRE( parser.parse_expression(n1).begin()->second == mpqc_class("5/7") );
REQUIRE( parser.parse_expression(nsq).begin()->second == mpqc_class("25/49") );
REQUIRE( parser.parse_expression(nmsq).begin()->second == mpqc_class("49/25") );
REQUIRE( parser.parse_expression(mnsq).begin()->second == mpqc_class("-25/49") );
REQUIRE( parser.parse_expression(mnmsq).begin()->second == mpqc_class("-49/25") );

};

Expand All @@ -61,30 +59,30 @@ TEST_CASE( "Operations" , "[exparse]" )
Exparse parser;
parser.substitution_table =
{
{"x",3_mpq/2_mpq}
{"x",mpqc_class("3/2")}
};

REQUIRE( parser.parse_expression(x).begin()->second == 3_mpq/2_mpq );
REQUIRE( parser.parse_expression(px).begin()->second == 3_mpq/2_mpq );
REQUIRE( parser.parse_expression(mx).begin()->second == -3_mpq/2_mpq );
REQUIRE( parser.parse_expression(x1).begin()->second == 3_mpq/2_mpq );
REQUIRE( parser.parse_expression(xsq).begin()->second == 9_mpq/4_mpq );
REQUIRE( parser.parse_expression(xmsq).begin()->second == 4_mpq/9_mpq );
REQUIRE( parser.parse_expression(mxsq).begin()->second == -9_mpq/4_mpq );
REQUIRE( parser.parse_expression(mxmsq).begin()->second == -4_mpq/9_mpq );
REQUIRE( parser.parse_expression(x).begin()->second == mpqc_class("3/2") );
REQUIRE( parser.parse_expression(px).begin()->second == mpqc_class("3/2") );
REQUIRE( parser.parse_expression(mx).begin()->second == mpqc_class("-3/2") );
REQUIRE( parser.parse_expression(x1).begin()->second == mpqc_class("3/2") );
REQUIRE( parser.parse_expression(xsq).begin()->second == mpqc_class("9/4") );
REQUIRE( parser.parse_expression(xmsq).begin()->second == mpqc_class("4/9") );
REQUIRE( parser.parse_expression(mxsq).begin()->second == mpqc_class("-9/4") );
REQUIRE( parser.parse_expression(mxmsq).begin()->second == mpqc_class("-4/9") );

};

SECTION( "Binary operations (number)" )
{
Exparse parser;

REQUIRE( parser.parse_expression(npn).begin()->second == 31_mpq/14_mpq );
REQUIRE( parser.parse_expression(nmn).begin()->second == 11_mpq/14_mpq );
REQUIRE( parser.parse_expression(ntn).begin()->second == 15_mpq/14_mpq );
REQUIRE( parser.parse_expression(pnpn).begin()->second == 31_mpq/14_mpq );
REQUIRE( parser.parse_expression(mnpn).begin()->second == -11_mpq/14_mpq );
REQUIRE( parser.parse_expression(inmn).begin()->second == -29_mpq/21_mpq );
REQUIRE( parser.parse_expression(npn).begin()->second == mpqc_class("31/14") );
REQUIRE( parser.parse_expression(nmn).begin()->second == mpqc_class("11/14") );
REQUIRE( parser.parse_expression(ntn).begin()->second == mpqc_class("15/14") );
REQUIRE( parser.parse_expression(pnpn).begin()->second == mpqc_class("31/14") );
REQUIRE( parser.parse_expression(mnpn).begin()->second == mpqc_class("-11/14") );
REQUIRE( parser.parse_expression(inmn).begin()->second == mpqc_class("-29/21") );

};

Expand All @@ -93,17 +91,17 @@ TEST_CASE( "Operations" , "[exparse]" )
Exparse parser;
parser.substitution_table =
{
{"x",3_mpq/2_mpq},
{"y",5_mpq/7_mpq}
{"x",mpqc_class("3/2")},
{"y",mpqc_class("5/7")}
};

REQUIRE( parser.parse_expression(xpy).begin()->second == 31_mpq/14_mpq );
REQUIRE( parser.parse_expression(xmy).begin()->second == 11_mpq/14_mpq );
REQUIRE( parser.parse_expression(xty).begin()->second == 15_mpq/14_mpq );
REQUIRE( parser.parse_expression(xdy).begin()->second == 21_mpq/10_mpq );
REQUIRE( parser.parse_expression(pxpy).begin()->second == 31_mpq/14_mpq );
REQUIRE( parser.parse_expression(mxpy).begin()->second == -11_mpq/14_mpq );
REQUIRE( parser.parse_expression(ixmy).begin()->second == -29_mpq/21_mpq );
REQUIRE( parser.parse_expression(xpy).begin()->second == mpqc_class("31/14") );
REQUIRE( parser.parse_expression(xmy).begin()->second == mpqc_class("11/14") );
REQUIRE( parser.parse_expression(xty).begin()->second == mpqc_class("15/14") );
REQUIRE( parser.parse_expression(xdy).begin()->second == mpqc_class("21/10") );
REQUIRE( parser.parse_expression(pxpy).begin()->second == mpqc_class("31/14") );
REQUIRE( parser.parse_expression(mxpy).begin()->second == mpqc_class("-11/14") );
REQUIRE( parser.parse_expression(ixmy).begin()->second == mpqc_class("-29/21") );


};
Expand All @@ -112,7 +110,7 @@ TEST_CASE( "Operations" , "[exparse]" )

TEST_CASE( "Large Numbers" , "[exparse]" )
{
typedef mpq_class rational_t;
typedef mpqc_class rational_t;

std::string n = "71000043264436482494390107093282688489573565181808197812372585399504446035316648916494607917902486755089085920784044945470018034238513473/193009412417169166913227997343359008248674987410944756537819741916377891027577630518186101344938906882203617750986183368800846654482519887699";
std::string pn = "+71000043264436482494390107093282688489573565181808197812372585399504446035316648916494607917902486755089085920784044945470018034238513473/193009412417169166913227997343359008248674987410944756537819741916377891027577630518186101344938906882203617750986183368800846654482519887699";
Expand All @@ -126,14 +124,14 @@ TEST_CASE( "Large Numbers" , "[exparse]" )
{
Exparse parser;

mpq_class num = 71000043264436482494390107093282688489573565181808197812372585399504446035316648916494607917902486755089085920784044945470018034238513473_mpq;
mpq_class den = 193009412417169166913227997343359008248674987410944756537819741916377891027577630518186101344938906882203617750986183368800846654482519887699_mpq;
mpqc_class num = "71000043264436482494390107093282688489573565181808197812372585399504446035316648916494607917902486755089085920784044945470018034238513473";
mpqc_class den = "193009412417169166913227997343359008248674987410944756537819741916377891027577630518186101344938906882203617750986183368800846654482519887699";

mpq_class num10 = num*num*num*num*num*num*num*num*num*num;
mpq_class den10 = den*den*den*den*den*den*den*den*den*den;
mpqc_class num10 = num*num*num*num*num*num*num*num*num*num;
mpqc_class den10 = den*den*den*den*den*den*den*den*den*den;

mpq_class num50 = num10*num10*num10*num10*num10;
mpq_class den50 = den10*den10*den10*den10*den10;
mpqc_class num50 = num10*num10*num10*num10*num10;
mpqc_class den50 = den10*den10*den10*den10*den10;

REQUIRE( parser.parse_expression(n).begin()->second == num/den );
REQUIRE( parser.parse_expression(pn).begin()->second == num/den );
Expand All @@ -149,7 +147,7 @@ TEST_CASE( "Large Numbers" , "[exparse]" )

TEST_CASE( "Edge Cases" , "[exparse]" )
{
typedef mpq_class rational_t;
typedef mpqc_class rational_t;

std::string n0 = "5^0";
std::string nm0 = "5^-0";
Expand All @@ -160,20 +158,20 @@ TEST_CASE( "Edge Cases" , "[exparse]" )
{
Exparse parser;

REQUIRE( parser.parse_expression(n0).begin()->second == 1_mpq );
REQUIRE( parser.parse_expression(nm0).begin()->second == 1_mpq );
REQUIRE( parser.parse_expression(n0).begin()->second == mpqc_class("1") );
REQUIRE( parser.parse_expression(nm0).begin()->second == mpqc_class("1") );
};

SECTION( "Power 0 (symbol)" )
{
Exparse parser;
parser.substitution_table =
{
{"x",3_mpq/2_mpq}
{"x",mpqc_class("3/2")}
};

REQUIRE( parser.parse_expression(x0).begin()->second == 1_mpq );
REQUIRE( parser.parse_expression(xm0).begin()->second == 1_mpq );
REQUIRE( parser.parse_expression(x0).begin()->second == mpqc_class("1") );
REQUIRE( parser.parse_expression(xm0).begin()->second == mpqc_class("1") );
};

};
28 changes: 28 additions & 0 deletions check/exparse_mpqc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
include ./Makefile.conf
include ../test_suite/Makefile.conf

.PHONY : compile
compile : $(TEST_NAME)

.PHONY : test
test : test.log
test.log : $(TEST_NAME)
./$< 2>&1 >test.log \
&& printf "\n@@@ SUCCESS @@@" >> test.log || printf "\n@@@ FAILURE @@@" >> test.log

ifneq ($(CXX), nvcc)

.PHONY : coverage
coverage : coverage.html

coverage.log : $(TEST_NAME) test.log
$(GCOV) $(GCOVFLAGS) $< 2>&1 >coverage.log

coverage.html : %.html : %.log
$(GCOVR) $(GCOVRFLAGS) -o $@

endif

.PHONY : clean
clean :
rm -rf coverage.log test.log *.o *.gcov *.dSYM *.gcda *.gcno *.html $(TEST_NAME)
1 change: 1 addition & 0 deletions check/exparse_mpqc/Makefile.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST_NAME = test_exparse_mpqc
65 changes: 65 additions & 0 deletions check/exparse_mpqc/test_exparse_mpqc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "catch.hpp"
#include "exparse.hpp"

TEST_CASE( "Operations" , "[mpqc]" )
{
mpqc_class one_char("1");
mpqc_class hq_char("1/2","1/4");
mpqc_class a_mpq("2","3");
mpqc_class b_mpq("4","5");
mpqc_class a_char("2","3");
mpqc_class c_double(123.,456.);

SECTION( "Comparator Operators" )
{
REQUIRE( a_char == mpqc_class("2","3") );
REQUIRE( a_char != mpqc_class("4","5") );
};

SECTION( "Constructors" )
{
REQUIRE( mpqc_class() == mpqc_class("0","0") ); // no args => (0,0)
REQUIRE( one_char == mpqc_class("1","0") );
REQUIRE( hq_char == mpqc_class("1/2","1/4") );
REQUIRE( mpq_get_d(c_double.re) == Approx(123.));
REQUIRE( mpq_get_d(c_double.im) == Approx(456.));
};

SECTION( "Unary Operators" )
{
REQUIRE( -a_mpq == mpqc_class("-2","-3") );
REQUIRE( +a_mpq == mpqc_class("2","3") );
};

SECTION( "Assignment Operators [+]" )
{
a_mpq += b_mpq;
REQUIRE( a_mpq == mpqc_class("6","8") );
};

SECTION( "Assignment Operators [-]" )
{
a_mpq -= b_mpq;
REQUIRE( a_mpq == mpqc_class("-2","-2") );
};

SECTION( "Assignment Operators [*]" )
{
a_mpq *= b_mpq;
REQUIRE( a_mpq == mpqc_class("-7","22") );
};

SECTION( "Assignment Operators [/]" )
{
a_mpq /= b_mpq;
REQUIRE( a_mpq == mpqc_class("23/41","2/41") );
};

SECTION( "Binary Operators (2)" )
{
REQUIRE( a_mpq + b_mpq == mpqc_class("6","8") );
REQUIRE( a_mpq - b_mpq == mpqc_class("-2","-2") );
REQUIRE( a_mpq * b_mpq == mpqc_class("-7","22") );
REQUIRE( a_mpq / b_mpq == mpqc_class("23/41","2/41") );
};
};
2 changes: 1 addition & 1 deletion check/test_suite/Makefile.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ifeq ($(MAKELEVEL),0)

CXXFLAGS += -std=c++11 -g -O0 --coverage -fprofile-arcs -ftest-coverage -fno-inline -fno-inline-small-functions -fno-default-inline -I$(PACKAGE_HEADERS_DIR) -I$(TEST_FRAMEWORK_DIR)
LDFLAGS += -pthread -fprofile-arcs -ftest-coverage
LDLIBS += $(TEST_FRAMEWORK_DIR)/catch.o -lgmpxx -lgmp
LDLIBS += $(TEST_FRAMEWORK_DIR)/catch.o -lgmp

export CXXFLAGS LDFLAGS LDLIBS

Expand Down
4 changes: 2 additions & 2 deletions examples/binomial/Makefile.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ CC = $(CXX)

ifeq ($(MAKELEVEL),0)

CXXFLAGS += -std=c++11 -O3 -I$(PACKAGE_HEADERS_DIR)
CXXFLAGS += -std=c++17 -O3 -I$(PACKAGE_HEADERS_DIR)
LDFLAGS +=
LDLIBS += -lgmpxx -lgmp
LDLIBS += -lgmp

export CXXFLAGS LDFLAGS LDLIBS

Expand Down
16 changes: 7 additions & 9 deletions examples/binomial/binomial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#include <string>
#include <fstream> // ifstream

#include <gmpxx.h>

#include "exparse.hpp"

int main()
Expand All @@ -13,12 +11,12 @@ int main()

parser.substitution_table =
{
{"a1",252097800623_mpq/7732459473917_mpq},
{"a2",790645490059_mpq/13730453361421_mpq},
{"a3",1344326694119_mpq/19819454169467_mpq},
{"a4",1906555030411_mpq/25971199844383_mpq},
{"a5",2474799787573_mpq/32170948946749_mpq},
{"a6",3047695447799_mpq/38409597323033_mpq}
{"a1","252097800623/7732459473917"},
{"a2","790645490059/13730453361421"},
{"a3","1344326694119/19819454169467"},
{"a4","1906555030411/25971199844383"},
{"a5","2474799787573/32170948946749"},
{"a6","3047695447799/38409597323033"}
};

std::ifstream infile("expr.txt");
Expand All @@ -33,7 +31,7 @@ int main()
while (std::getline(infile, expression))
{
std::cout << "expression.length(): " << expression.length() << std::endl;
mpq_class result = parser.parse_expression(expression).begin()->second;
mpqc_class result = parser.parse_expression(expression).begin()->second;
std::cout << "result:" << result << std::endl;
}

Expand Down
Loading

0 comments on commit 33038e9

Please sign in to comment.