Newer
Older
//
// Created by Anna Proost on 11/12/2023.
//
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include "../inputs/headers.hpp"
#include "../methods/headers.hpp"
#include "../outputs/Solution.hpp"
/**
* @brief Evaluates a mono-variable function for a specific value of `x`.
*
* Instantiates a MonoFunction instance for the given equation (no need for `der` or `eq_fp`, as those will not be relevant),
* and then evaluates the function for the given value of `x` by overloading the () operator.
*
* @param eq the equation we want to evaluate in string form
* @param x the value we want to evaluate the function for
*
* @return a double which is the function evaluation for the value `x`.
*/
double Solver::EvaluateFunction(const std::string& eq, double x) {
MonoFunction Eq(eq, "", "");
return Eq(x);
}
/**
* @brief Evaluates a multi-variable function for specific values of its variables (`x, y, ...`).
*
* Instantiates a MultiFunction instance for the given equation (no need for `der`, as this will not be relevant),
* and then evaluates the function for the given values of its variables by overloading the () operator.
*
* @param eq the equation we want to evaluate in string form
* @param x the values we want to evaluate the function for
* @param var the order of the values (first element of `x` maps onto first element, second on second, ...)
*
* @return a double which is the function evaluation for the values in `x`.
*/
double Solver::EvaluateMultiFunction(const std::string& eq, Eigen::VectorXd x, const std::vector<std::string>& var) {
MultiFunction Eq(eq, std::vector<std::string>(var.size(), ""), var);
return Eq(x);
}
/**
* @brief Applies the non-accelerated Newton method to find a root of a given mono-variable equation for given conditions.
*
* This function will initialize the `MonoFunction` with the given `equation` & `der`, then perform the `Newton` method on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`). It returns a `Solution` class which encapsulates all
* relevant & interesting information about the result of the method.
*
* @param eq the equation of the `MonoFunction` we want to find a root of.
* @param der the derivative of the `MonoFunction` we want to find a root of.
* @param start_point the point from which the `Newton` method will start to iterate.
* @param stop_tol the tolerance at which the `Newton` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Newton` method will perform before returning, converged or not.
*
* @return a `Solution` class with all information about the method's result.
*/
Solution Solver::NewtonMethod(const std::string& eq, const std::string& der, double start_point, double stop_tol, int max_iter) {
return NewtonMethod(Eq, start_point, stop_tol, max_iter) ;
/**
* @brief Applies the accelerated `Newton` method to find a root of a given mono-variable equation for given conditions.
*
* This function will initialize the `MonoFunction` with the given `equation` & `der`, then perform the Accelerated `Newton` method on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`), by instantiating the `Aitken` method with this `Newton` class .
* It returns a `Solution` class which encapsulates all relevant & interesting information about the result of the method.
*
* @param eq the equation of the `MonoFunction` we want to find a root of.
* @param der the derivative of the `MonoFunction` we want to find a root of.
* @param start_point the point from which the `Aitken` ( & `Newton`) method will start to iterate.
* @param stop_tol the tolerance at which the `Aitken` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Aitken` method will perform before returning, converged or not.
*
* @return a `Solution` class with all information about the method's result.
*/
Solution Solver::NewtonMethodA(const std::string& eq, const std::string& der, double start_point, double stop_tol, int max_iter) {
MonoFunction Eq(eq, "", der);
Newton NewtonMethod;
Aitken AitkenMethod(&NewtonMethod);
return AitkenMethod(Eq, start_point, stop_tol, max_iter);
/**
* @brief Applies the `Newton` method for Systems to find a root of a given `System` of multi-variable functions for given conditions.
*
* This function will initialize the `MultiFunction`'s with the given `equation`'s & `der`'s, then perform the `Newton` method for Systems on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`). It returns a `Solution` class which encapsulates all
* relevant & interesting information about the result of the method.
*
* @param eqs the equations of the `MultiFunction`'s in the `System` we want to find a root of.
* @param der the Jacobian of the system of equations we want to find a root of.
* @param start_points the vector from which the `Newton` method will start to iterate.
* @param stop_tol the tolerance at which the `Newton` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Newton` method will perform before returning, converged or not.
*
* @return a `Solution` class with all information about the method's result.
*/
Solution Solver::SystemNewtonMethod(const std::vector<std::string>& eqs, const std::vector<std::vector<std::string>>& der, const std::vector<std::string>& var, const std::vector<double>& start_points, double stop_tol, int max_iter) {
functions.reserve((int)eqs.size());
for (int i = 0; i < (int)var.size(); i++) { functions.push_back( MultiFunction(eqs[i], der[i], var) ); }
Eigen::VectorXd startVector = Eigen::VectorXd::Map(start_points.data(), (int)start_points.size());
return NewtonMethod(system, startVector, stop_tol, max_iter) ;
/**
* @brief Applies the non-accelerated `Fixed Point` method to find a root of a given mono-variable equation for given conditions.
*
* This function will initialize the `MonoFunction` with the given `equation` & `fixed point equation`, then perform the `Fixed Point` method on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`). It returns a `Solution` class which encapsulates all
* relevant & interesting information about the result of the method.
*
* @param eq the equation of the `MonoFunction` we want to find a root of.
* @param fp the fixed-point equation `g(x)` such that `f(x) = g(x) - x`
* @param start_point the point from which the `Fixed Point` method will start to iterate.
* @param stop_tol the tolerance at which the `Fixed Point` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Fixed Point` method will perform before returning, converged or not.
*
* @return a `Solution` class with all information about the method's result.
Solution Solver::FixedPointMethod(const std::string& eq, const std::string& fp, double start_point, double stop_tol, int max_iter) {
MonoFunction Eq(eq, fp, "");
FixedPoint FixedPointMethod;
return FixedPointMethod(Eq, start_point, stop_tol, max_iter) ;
/**
* @brief Applies the accelerated `Fixed Point` method to find a root of a given mono-variable equation for given conditions.
*
* This function will initialize the `MonoFunction` with the given `equation` & `fixed-point equation`, then perform the Accelerated `Fixed Point` method on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`), by instantiating the `Aitken` method with this `Fixed Point` class.
* It returns a `Solution` class which encapsulates all relevant & interesting information about the result of the method.
*
* @param eq the equation of the `MonoFunction` we want to find a root of.
* @param fp the fixed-point equation `g(x)` such that `f(x) = g(x) - x`
* @param start_point the point from which the `Aitken` ( & `Fixed Point`) method will start to iterate.
* @param stop_tol the tolerance at which the `Aitken` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Aitken` method will perform before returning, converged or not.
*
* @return a `Solution`class with all information about the method's result.
*/
Solution Solver::FixedPointMethodA(const std::string& eq, const std::string& fp, double start_point, double stop_tol, int max_iter) {
MonoFunction Eq(eq, fp, "");
FixedPoint FixedPointMethod;
Aitken AitkenMethod(&FixedPointMethod);
return AitkenMethod(Eq, start_point, stop_tol, max_iter);
/**
* @brief Applies the `Chord` method to find a root of a given mono-variable equation for given conditions.
*
* This function will initialize the `MonoFunction` with the given `equation` & `der`, then perform the `Chord` method on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`). It returns a `Solution` class which encapsulates all
* relevant & interesting information about the result of the method.
*
* @param eq the equation of the `MonoFunction` we want to find a root of.
* @param start_point the 2 first points/iterations from which the `Chord` method will start to iterate.
* @param stop_tol the tolerance at which the `Chord` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Chord` method will perform before returning, converged or not.
*
* @return a `Solution` class with all information about the method's result.
Solution Solver::ChordMethod(const std::string& eq, std::pair<double, double> start_point, double stop_tol, int max_iter) {
return ChordMethod(Eq, start_point, stop_tol, max_iter) ;
* @brief Applies the `Bisection` method to find a root of a given mono-variable equation for given conditions.
* This function will initialize the `MonoFunction` with the given `equation`, then perform the `Bisection` method on it
* for the given conditions (`max_iter`, `tolerance`, `start_point`). It returns a `Solution` class which encapsulates all
* relevant & interesting information about the result of the method.
*
* @param eq the equation of the `MonoFunction` we want to find a root of.
* @param start_point the interval of points from which the `Bisection` method will start to iterate.
* @param stop_tol the tolerance at which the `Bisection` method considers its sequence to be converged.
* @param max_iter the maximal iterations the `Bisection` method will perform before returning, converged or not.
*
* @return a `Solution` class with all information about the method's result.
Solution Solver::BisectionMethod(const std::string& eq, std::pair<double, double> start_point, double stop_tol, int max_iter) {
MonoFunction Eq(eq, "", "");
Bisection BisectionMethod;
return BisectionMethod(Eq, start_point, stop_tol, max_iter) ;
/**
* @brief Provides a clean terminal output for a given (found) 1-point root of a MonoFunction.
*
* This function will print all (relevant) info included in the `Solution`, customized towards the root being one single point.
* It is called for the showcasing of the solutions of the (accelerated) `Newton`, `Fixed Point`& `Chord` methods.
*
* @param root the root that includes all relevant info about the solution/result of the algorithm.
* @param method the method that was used, in string form.
* @param Aitken whether or not the method was accelerated.
* @param function the function for which we attempted to find a root (in string format).
*
*/
void Solver::PointOutput(Solution root, const std::string& method, bool Aitken, const std::string& function){
if (Aitken) std::cout << "\n\033[1mMethod was run with Aitken acceleration\033[0m\n";
if (root.hasConverged()) std::cout << "The root \033[1m"<< std::fixed << std::setprecision(15) << root.getRoot() << "\033[0m of the function f(x) = " << function <<" was found by the " << method << " method in " << root.getNIterations() <<" iterations. The final function evaluation is " << EvaluateFunction(function, root.getRoot()) << "\n";
else std::cout << "The " << method << " method does not converge for the initial point or within the max. number of iterations. \n";
std::cout << "\nThis is an overview of the results:";
root.printIterations();
}
/**
* @brief Provides a clean terminal output for a given (found) interval root of a MonoFunction.
*
* This function will print all (relevant) info included in the `Solution`, customized towards the root being (within) an interval.
* It is called for the showcasing of the solutions of the `Bisection` method.
*
* @param root the Solution that includes all relevant info about the solution/result of the algorithm.
* @param method the method that was used, in string form.
* @param function the function for which we attempted to find a root (in string format).
*
*/
void Solver::IntervalOutput(Solution root, const std::string& method, const std::string& function){
if (root.hasConverged()) std::cout << "The root \033[1m"<< std::fixed << std::setprecision(15) << root.getRoot() << "\033[0m of the function f(x) = " << function << " in interval [" << root.getIntervalIterations()[root.getNIterations()].first << ", " << root.getIntervalIterations()[root.getNIterations()].second << "] was found by the " << method << " method in " << root.getNIterations() <<" iterations. The final function evaluation is " << EvaluateFunction(function, root.getRoot()) << "\n";
else std::cout << "The " << method << " method does not converge for the initial point or within the max. number of iterations. \n";
std::cout << "\nThis is an overview of the results:";
root.printIterations();
}
/**
* @brief Provides a clean terminal output for a given (found) vector of roots of a System.
*
* This function will print all (relevant) info included in the `Solution`, customized towards the root being a vector of doubles (roots).
* It is called for the showcasing of the solutions of the `Newton` method for Systems.
*
* @param root the Solution that includes all relevant info about the solution/result of the algorithm.
* @param function the system of functions for which we attempted to find a root (in string format).
*
*/
void Solver::SystemOutput(Solution root, std::vector<std::string> functions){
std::string combinedFunctions = std::accumulate(
functions.begin() + 1, functions.end(),
functions[0],
[](const std::string& acc, const std::string& str) {
return acc + ", " + str;
}
);
if (root.hasConverged()) {
std::cout << "The root\033[1m (" << std::fixed << std::setprecision(15) << root.getVectorRoot()[0] << ", "
<< root.getVectorRoot()[1] << ")\033[0m of the functions {" << combinedFunctions <<
"} was found by the Newton method for Systems in "
<< root.getNIterations() << " iterations. \n";
}
else std::cout << "The Newton method for Systems does not converge for the initial points or within the max. number of iterations. \n";
std::cout << "\nThis is an overview of the results:";
root.printIterations();
}