diff --git a/CMakeLists.txt b/CMakeLists.txt index 886f5e40161d6ccc8c44004121e4e6900c0373c7..10219417fc2a3d9757a96fb07c1554210ead40f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,9 +29,9 @@ add_executable(test_suite methods/Aitken.cpp outputs/Solution.cpp - inputs/headers.hpp + + exec/ReadFile.cpp exec/Solver.cpp - exec/Solver.hpp ) @@ -54,9 +54,7 @@ add_executable(main_exec outputs/Solution.cpp exec/ReadFile.cpp - inputs/headers.hpp exec/Solver.cpp - exec/Solver.hpp ) diff --git a/README.md b/README.md index be40d3a8a8ba5379b9684373d246459e8e960375..4904ecec9ecc0929b3ed24d068f5a45b4e2f9ceb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,16 @@ How to compile --- -The `CMakeLists.txt` is already properly configured (with all libraries linked, ...) to compile & build the project. +As the Egigen/Dense library is added at a submodule, the first thing to do is to populate it before anything else. You can +do this by running the following command in the terminal of the main project: + +``` +git submodule update --init eigen +``` + +All other libraries (muparser, googletest) are added as subtrees, so they will already be 'filled' and ready to be used. + +Next, the `CMakeLists.txt` is already properly configured (with all libraries linked, ...) to compile & build the project. Either use the build interface (button top right) that is provided in Clion or navigate into the `cmake-build-debug` directory and run the following commands: @@ -13,6 +22,17 @@ cmake .. make ``` +If there is no `cmake-build-debug` directory, please create one, running the commands as follows (in the main dir terminal): + +``` +mkdir cmake-build-debug +# move into the dir to make the executables +cd cmake-build-debug + +cmake .. +make +``` + If any errors (e.g. Makefile is not found) occur, please delete the `CMakeCache.txt` and try running both commands again. Like this, up-to-date executables have been built for both `main_exec` and `test_suite`. They can now be run as follows, diff --git a/doxygen_documentation/html/search/all_12.js b/doxygen_documentation/html/search/all_12.js new file mode 100644 index 0000000000000000000000000000000000000000..8662a1d92eaa4e16a502a29401cade9dc356d92d --- /dev/null +++ b/doxygen_documentation/html/search/all_12.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['vector_5fiterations_0',['vector_iterations',['../class_solution.html#a5d21778491fa7e35f6cf66847e6ad75c',1,'Solution']]] +]; diff --git a/doxygen_documentation/html/search/functions_d.js b/doxygen_documentation/html/search/functions_d.js new file mode 100644 index 0000000000000000000000000000000000000000..eee5727db8bdab0ecf6da5ba41f080a8cc01866f --- /dev/null +++ b/doxygen_documentation/html/search/functions_d.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['readconfigfile_0',['readConfigFile',['../class_config_file_reader.html#a23597cebabf7142367c35b52ea393bb6',1,'ConfigFileReader']]] +]; diff --git a/doxygen_documentation/html/search/functions_e.js b/doxygen_documentation/html/search/functions_e.js new file mode 100644 index 0000000000000000000000000000000000000000..79f7f2a55afda1d63b5576ca2b755d85820565ba --- /dev/null +++ b/doxygen_documentation/html/search/functions_e.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['solution_0',['solution',['../class_solution.html#a87abff475c54b6a8ef4b115d8928c192',1,'Solution::Solution(std::vector< double > iterations, bool converged, MethodType type)'],['../class_solution.html#ad48d50a1172938dc6011b20da692a3c6',1,'Solution::Solution(std::vector< std::pair< double, double > > iterations, bool converged, MethodType type)'],['../class_solution.html#af65308c40949272c9c559122b9c65e41',1,'Solution::Solution(std::vector< Eigen::VectorXd > iterations, bool converged, MethodType type)']]], + ['step_1',['step',['../class_accelerable_method.html#a603556ebe275f5d6e6d9cf757c081e75',1,'AccelerableMethod::step()'],['../class_chord.html#a239e2b5a0046722218e5b22d844b30d2',1,'Chord::step()'],['../class_fixed_point.html#aeaf2c41acae806f3668fe1c0fefe5989',1,'FixedPoint::step()'],['../class_newton.html#a4b464d8d11b0483d1cf19a0f1703e537',1,'Newton::step()']]], + ['system_2',['System',['../class_system.html#afc4fcf375baa8e3c25693cf772b57a4f',1,'System']]], + ['systemnewtonmethod_3',['SystemNewtonMethod',['../class_solver.html#a984b89dede2d8eee892429fad01f70a3',1,'Solver']]], + ['systemoutput_4',['SystemOutput',['../class_solver.html#ad48c51e91ce3d59fe24007f1348228cc',1,'Solver']]] +]; diff --git a/exec/ReadFile.cpp b/exec/ReadFile.cpp index d30124b087661a2b6e53a1f80496efd5e5d3c542..7e13ebb3bffee82f4eb8cc9b5815740c0369666d 100644 --- a/exec/ReadFile.cpp +++ b/exec/ReadFile.cpp @@ -127,6 +127,9 @@ std::string ConfigFileReader::getFunction() const { * @return The fixed-point equation. */ std::string ConfigFileReader::getFixedPoint() const { + if (getMethod() != "FP") { + throw std::invalid_argument("This method " + getValueByKey(ALGORITHM) + " does not have a fixed point equation that needs to be inputted\n"); + } return getValueByKey(FIXED_POINT); } @@ -136,6 +139,10 @@ std::string ConfigFileReader::getFixedPoint() const { * @return The derivative. */ std::string ConfigFileReader::getDerivative() const { + if (getMethod() != "N") { + throw std::invalid_argument("This method " + getValueByKey(ALGORITHM) + " does not have a derivative that needs to be inputted\n"); + } + return getValueByKey(DERIVATIVE); } @@ -263,7 +270,7 @@ int ConfigFileReader::getIterations() const { if (iter < 1) { throw std::invalid_argument("Invalid iterations " + std::to_string(iter)); } - return iter + 1; + return iter; } /** diff --git a/outputs/Solution.cpp b/outputs/Solution.cpp index 1f63515c31582886faf90fb49b98e609785813d0..76231eb79033a7775e0b752ff4c227db089c62bc 100644 --- a/outputs/Solution.cpp +++ b/outputs/Solution.cpp @@ -63,6 +63,7 @@ std::vector<double> Solution::getIterations() const { * @return The number of iterations as an integer. */ int Solution::getNIterations() const { + if(type==MethodType::Chord) {return (int)iter_length - 2;} return (int)iter_length - 1; } /** @@ -70,6 +71,7 @@ int Solution::getNIterations() const { * @return A vector of pairs of doubles representing the interval iterations. */ std::vector<std::pair<double,double>> Solution::getIntervalIterations() const { + return interval_iterations; } /** diff --git a/tests.cpp b/tests.cpp index 0e97c3b386d08c6ee15ea0680e31245683bf8dd3..1ff9ab33769046c32a5af2498a8ac4f3836f0355 100644 --- a/tests.cpp +++ b/tests.cpp @@ -7,6 +7,66 @@ #include "gtest/gtest.h" +TEST(InputTest, MonoFunction) { + + MonoFunction test1("x^2 + exp(-x)", "-exp(-x)/x", "2*x - exp(-x)"); + EXPECT_EQ(std::pow(2,2) + exp(-2), test1(2.0)); + EXPECT_EQ(-exp(-2)/2, test1.fixed(2.0)); + EXPECT_EQ(4 -exp(-2), test1.der(2.0)); + + EXPECT_EQ(std::pow(-3,2) + exp(3), test1(-3.0)); + EXPECT_EQ(exp(3)/3, test1.fixed(-3.0)); + EXPECT_EQ(-6 - exp(3), test1.der(-3.0)); + +} + +TEST(InputTest, MultiFunction) { + + MultiFunction test1("x^2 + exp(-y) + y*x", {"2*x + y", "-exp(-y) + x"}, {"x", "y"}); + Eigen::VectorXd input(2); + + input << 2.0, -1.0; + EXPECT_EQ(std::pow(2,2) + exp(1) - 2, test1(input)); + EXPECT_EQ(3, test1.der(input)[0]); + EXPECT_EQ(-exp(1) + 2, test1.der(input)[1]); + + input << -3.0, 2.5; + + EXPECT_EQ(std::pow(-3,2) + exp(-2.5) - 2.5*3, test1(input)); + EXPECT_EQ(-3.5, test1.der(input)[0]); + EXPECT_EQ(-exp(-2.5) -3, test1.der(input)[1]); + +} + +TEST(InputTest, System) { + + MultiFunction m1("x^2 + exp(-y) + y*x", {"2*x + y", "-exp(-y) + x"}, {"x", "y"}); + MultiFunction m2("x^3 - 2*y*x", {"3*x^2 - 2*y", "-2*x"}, {"x", "y"}); + System test1({m1, m2}); + + Eigen::VectorXd input(2); + + input << 2.0, -1.0; + EXPECT_EQ(std::pow(2,2) + exp(1) - 2, test1(input)[0]); + EXPECT_EQ(std::pow(2,3) + 2*2, test1(input)[1]); + + EXPECT_EQ(3, test1.getJacobian(input)(0,0)); + EXPECT_EQ(-exp(1) + 2, test1.getJacobian(input)(0,1)); + EXPECT_EQ(3*std::pow(2,2) +2, test1.getJacobian(input)(1,0)); + EXPECT_EQ(-4, test1.getJacobian(input)(1,1)); + + input << -3.0, 2.5; + EXPECT_EQ(std::pow(-3,2) + exp(-2.5) - 3*2.5, test1(input)[0]); + EXPECT_EQ(std::pow(-3,3) + 3*2*2.5, test1(input)[1]); + + EXPECT_EQ(-3.5, test1.getJacobian(input)(0,0)); + EXPECT_EQ(-exp(-2.5) -3, test1.getJacobian(input)(0,1)); + EXPECT_EQ(3 * std::pow(-3,2) - 2*2.5, test1.getJacobian(input)(1,0)); + EXPECT_EQ(6, test1.getJacobian(input)(1,1)); + +} + + TEST(NewtonTest, Converging) { Solver solver; @@ -224,6 +284,79 @@ TEST(BisectionTest, Diverging) { } +TEST(ConfigFile, Inputs) { + + ConfigFileReader read_test("../input_config/input1.txt"); + + /* + * # General settings + * function = x^2 + y^2 - 10 | x*y-5 + * variables = x | y + * fixed_point = + * derivative = 2*x | 2*y | y | x + * + * # Method settings + * algorithm = SN + * aitken = no + * tolerance = 1e-10 + * max_iterations = 1e3 + * start_point = 2.1 , 2.0 + */ + + EXPECT_EQ(read_test.getIterations(), 1e3); + EXPECT_EQ(read_test.getTolerance(), 1e-10); + EXPECT_EQ(read_test.getMethod(), "SN"); + + EXPECT_EQ(read_test.getVariables()[1], "y"); + EXPECT_EQ(read_test.getFunctions()[0], "x^2 + y^2 - 10"); + + EXPECT_EQ(read_test.getDerivatives()[0][1], "2*y"); + EXPECT_EQ(read_test.getDerivatives()[1][0], "y"); + + std::vector<double> points; + std::visit([&points](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, std::vector<double>>) {points = std::forward<T>(arg);}}, read_test.getStartPoint()); + + EXPECT_EQ(points[0], 2.1); + EXPECT_EQ(points[1], 2.0); +} + +TEST(ConfigFile, Errors) { + + ConfigFileReader read_test("../input_config/input2.txt"); + + /* + * # General settings + * function = x^2 - 612 + * variables = + * fixed_point = + * derivative = + * + * # Method settings + * algorithm = C + * aitken = no + * tolerance = 1e-10 + * max_iterations = 1e3 + * start_point = 100.0 , 30.0 + */ + + EXPECT_EQ(read_test.getIterations(), 1e3); + EXPECT_EQ(read_test.getTolerance(), 1e-10); + EXPECT_EQ(read_test.getMethod(), "C"); + + std::vector<double> points; + std::visit([&points](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, std::vector<double>>) {points = std::forward<T>(arg);}}, read_test.getStartPoint()); + + EXPECT_EQ(points[0], 100.0); + EXPECT_EQ(points[1], 30.0); + + EXPECT_THROW(read_test.getFunctions(), std::invalid_argument); + EXPECT_THROW(read_test.getVariables(), std::invalid_argument); + EXPECT_THROW(read_test.getDerivatives(), std::invalid_argument); + + EXPECT_THROW(read_test.getDerivative(), std::invalid_argument); + EXPECT_THROW(read_test.getFixedPoint(), std::invalid_argument); +} + int main() { testing::InitGoogleTest();