Skip to content
Snippets Groups Projects
Solver.cpp 15.3 KiB
Newer Older
//
// Created by Anna  Proost on 11/12/2023.
//

annaproost's avatar
annaproost committed
#include <fstream>
#include <string>
annaproost's avatar
annaproost committed
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
annaproost's avatar
annaproost committed

#include "../inputs/headers.hpp"
#include "../methods/headers.hpp"
#include "../outputs/Solution.hpp"
#include "Solver.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);
}
annaproost's avatar
annaproost committed

/**
  * @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) {
annaproost's avatar
annaproost committed

    MonoFunction Eq(eq, "", der);

    Newton NewtonMethod;
    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) {
annaproost's avatar
annaproost committed

    MonoFunction Eq(eq, "", der);

    Newton NewtonMethod;
    Aitken AitkenMethod(&NewtonMethod);
    return AitkenMethod(Eq, start_point, stop_tol, max_iter);
annaproost's avatar
annaproost committed

}
/**
  * @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) {
annaproost's avatar
annaproost committed
    std::vector<MultiFunction> functions;
annaproost's avatar
annaproost committed
    functions.reserve((int)eqs.size());
    for (int i = 0; i < (int)var.size(); i++) { functions.push_back( MultiFunction(eqs[i], der[i], var) ); }
annaproost's avatar
annaproost committed
    Eigen::VectorXd startVector = Eigen::VectorXd::Map(start_points.data(), (int)start_points.size());
annaproost's avatar
annaproost committed
    System system(functions);

    Newton NewtonMethod;
annaproost's avatar
annaproost committed
    return NewtonMethod(system, startVector, stop_tol, max_iter) ;
annaproost's avatar
annaproost committed

/**
  * @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) {
annaproost's avatar
annaproost committed

    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) {
annaproost's avatar
annaproost committed

    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) {
annaproost's avatar
annaproost committed

    MonoFunction Eq(eq, "", "");

    Chord ChordMethod;
    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) {
annaproost's avatar
annaproost committed

    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).
  *
  */
annaproost's avatar
annaproost committed
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";
annaproost's avatar
annaproost committed
    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){
annaproost's avatar
annaproost committed
    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).
  *
  */
annaproost's avatar
annaproost committed
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();

}