From 67430508e45107c7846d30ba3069e019264e2baf Mon Sep 17 00:00:00 2001
From: annaproost <proost.anna@gmail.com>
Date: Wed, 13 Dec 2023 11:54:44 +0100
Subject: [PATCH] added more relevant tests

---
 CMakeLists.txt                                |   6 +-
 README.md                                     |  22 ++-
 doxygen_documentation/html/search/all_12.js   |   4 +
 .../html/search/functions_d.js                |   4 +
 .../html/search/functions_e.js                |   8 ++
 exec/ReadFile.cpp                             |   9 +-
 outputs/Solution.cpp                          |   2 +
 tests.cpp                                     | 133 ++++++++++++++++++
 8 files changed, 182 insertions(+), 6 deletions(-)
 create mode 100644 doxygen_documentation/html/search/all_12.js
 create mode 100644 doxygen_documentation/html/search/functions_d.js
 create mode 100644 doxygen_documentation/html/search/functions_e.js

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 886f5e40..10219417 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 be40d3a8..4904ecec 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 00000000..8662a1d9
--- /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 00000000..eee5727d
--- /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 00000000..79f7f2a5
--- /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&lt; double &gt; iterations, bool converged, MethodType type)'],['../class_solution.html#ad48d50a1172938dc6011b20da692a3c6',1,'Solution::Solution(std::vector&lt; std::pair&lt; double, double &gt; &gt; iterations, bool converged, MethodType type)'],['../class_solution.html#af65308c40949272c9c559122b9c65e41',1,'Solution::Solution(std::vector&lt; Eigen::VectorXd &gt; 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 d30124b0..7e13ebb3 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 1f63515c..76231eb7 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 0e97c3b3..1ff9ab33 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();
-- 
GitLab