From 3e55fd63989d50ab478591e8d0ba091f098fb1e4 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Wed, 10 Dec 2025 14:38:09 +0100 Subject: [PATCH 01/12] docs: update some docstrings and readme structure --- README.md | 39 +++++++++++++++++++++++++-------- ROOT/ROOT/config.hpp | 3 +++ ROOT/ROOT/function_parser.hpp | 3 +++ ROOT/ROOT/reader.hpp | 3 +++ ROOT/ROOT/writer_def.hpp | 25 +++++++++++++++------ libROOT/libROOT/method.hpp | 4 ++++ libROOT/libROOT/solver_def.hpp | 21 +++++++++++++----- libROOT/libROOT/stepper_def.hpp | 7 ++++-- 8 files changed, 82 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index a67a289..63c5b5d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ROOT, but not the [particle physics one](https://github.com/root-project/root). Project submission for MATH-458: Programming concepts in scientific computing. -## Project structure and dependencies +## Project structure The project uses the recommended [Canonical Project Structure](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html) for C++ projects. @@ -37,11 +37,24 @@ The project uses the recommended [Canonical Project Structure](https://www.open- └── tests # Tests for the ROOT library ``` -### Dependencies +Apart from being divided into a library and a user-facing application/executable, the design on the project +is concretely split into three phases. -#### Dependencies for the project +### CLI -##### Required +The CLI application is written (and should be written) within the `main` function, followed by calling the `Reader`, `Solver`, and `Writer` classes in this order. + +### Readers and Parsers + +### Solver and Steppers + +### Writer and Printers + +## Dependencies + +### Dependencies for the project + +#### Required The required dependencies are included within the project as git submodules and are pinned to specific versions for reproducibility. @@ -49,28 +62,28 @@ versions for reproducibility. - `CLI11` (`v2.6.1`): for constructing the CLI interface for the user-facing `root_cli` application. - `Eigen3` (`v5.0.1`): for matric and vector usage / calculations. -##### Optional +#### Optional These can be installed by a user and are not installed through the project's build system. - `gnuplot`: for plotting results -#### Required dependencies for the tests +### Required dependencies for the tests `gnuplot` must be installed before building the project with `-DTEST=ON`. `GoogleTest` is installed automatically if the project is built with `-DTEST=ON`. - `GoogleTest` (`v1.17.0`): for all tests. - `gnuplot`: for testing `gnuplot` related code. -#### Dependencies for the documentation +### Dependencies for the documentation These can be installed by a user and are not installed through the project's build system. -##### Required +#### Required - `doxygen`: for generating the documentation. -##### Optional +#### Optional - `graphviz`: for generating hierarchy and flow diagrams in the documentation. @@ -209,6 +222,10 @@ g++ .cpp -o -I/include All of which can also be set in `CMakeLists.txt`. +## Typical program execution + +Input reading is handled by a CLI implemented using `CLI11`, the `Reader` classes, and the `Parser` classes. The output is passed from the CLI to one of the Reader classes + ## Tests Tests for the library (`libROOT`) can be found in `libROOT/tests`, and the tests for the application (`root_cli`) can be found in `ROOT/tests`. We follow [test-driven development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development), which means that each code changing PR must have tests to validate the changes. @@ -316,3 +333,7 @@ which will write the HTML files to `docs/html`. ### Building docs on GH Pages The documentation is automatically built (on every PR) and deployed (on every push to `main`) to GH Pages using the `build-and-deploy-docs` workflow. + +## Limitations and problems + +Most of the limitations and problems can be found as independent issues in the [issue tracker on GitHub](https://github.com/Saransh-cpp/ROOT/issues). diff --git a/ROOT/ROOT/config.hpp b/ROOT/ROOT/config.hpp index f03d7ea..7627dc7 100644 --- a/ROOT/ROOT/config.hpp +++ b/ROOT/ROOT/config.hpp @@ -6,6 +6,9 @@ * including Bisection, Newton, Secant, and Fixed Point methods. Each configuration * class encapsulates the parameters required for its respective method. * + * This file was written with constant LLM assistance (vibe coded). I built + * the structure and logic, and the LLM helped fill in the details. + * * @author Saransh-cpp * */ diff --git a/ROOT/ROOT/function_parser.hpp b/ROOT/ROOT/function_parser.hpp index 08d049d..06ec087 100644 --- a/ROOT/ROOT/function_parser.hpp +++ b/ROOT/ROOT/function_parser.hpp @@ -6,6 +6,9 @@ * including polynomial and trigonometric functions. The parsers convert string representations * of functions into callable std::function objects. * + * This file was written with constant LLM assistance (vibe coded). I built + * the structure and logic, and the LLM helped fill in the details. + * * @author Saransh-cpp */ #ifndef FUNCTION_HPP diff --git a/ROOT/ROOT/reader.hpp b/ROOT/ROOT/reader.hpp index c537425..aa0e9a0 100644 --- a/ROOT/ROOT/reader.hpp +++ b/ROOT/ROOT/reader.hpp @@ -6,6 +6,9 @@ * which are responsible for reading configuration data from various file formats * (e.g., CSV, DAT) and producing ConfigBase objects. * + * This file was written with constant LLM assistance (vibe coded). I built + * the structure and logic, and the LLM helped fill in the details. + * * @author Saransh-cpp */ #ifndef READER_HPP diff --git a/ROOT/ROOT/writer_def.hpp b/ROOT/ROOT/writer_def.hpp index 82fc0b8..d4aba52 100644 --- a/ROOT/ROOT/writer_def.hpp +++ b/ROOT/ROOT/writer_def.hpp @@ -2,8 +2,6 @@ * @file writer_def.hpp * @brief Contains definitions for classes Writer and Printer to Write on different output destinations * - * @author andreasaporito - * * These classes themselves could be used for other kinds of writing, and do not have any relationship * with the solver process. * The Writer class handles the writing outer process, meanwhile the printers effectively write on the output or @@ -11,6 +9,9 @@ * The Printer classes actually print a given value in the specified output, getting just one value from the * ones stored in Writer object. They can write on the output, on .csv or .dat files, or they can * write on a .dat file and then create a gnuplot. + * + * @author andreasaporito + * */ #ifndef ROOT_WRITER_DEF_HPP #define ROOT_WRITER_DEF_HPP @@ -26,7 +27,7 @@ template class PrinterBase; /** - * @brief Writer class - stores required arguments and handles the printing flow + * @brief Class to store required arguments and handle the printing flow */ template class Writer { @@ -63,20 +64,26 @@ class Writer { void write(); }; -/** @brief Abstract Printer class*/ +/** @brief Abstract Printer class */ template class PrinterBase { public: + /** @brief Default constructor for the PrinterBase class */ PrinterBase() = default; + /** @brief Virtual destructor for the PrinterBase class */ virtual ~PrinterBase() = default; + /** @brief Pure virtual method to write a given value + * + * @param value The given value to be written. + */ virtual void write_values(const V& value) = 0; }; -/** @brief The class to print out the values in the CLI*/ +/** @brief The class to print out the values in the CLI */ template class PrinterCLI : public PrinterBase { public: - /** @brief Constructor for the PrinterCLI class - just prints out a string*/ + /** @brief Constructor for the PrinterCLI class - just prints out a string */ PrinterCLI(); /** @brief Method to actually print a given value in the output * @@ -134,7 +141,11 @@ class PrinterCSV : public PrinterFile { * @param ow_mode Option to overwrite or append the file */ PrinterCSV(const std::string& fname, char sep, bool ow_mode); - /** @brief Writes a given result into the .csv file with the sotred separator */ + /** + * @brief Writes a given result into the .csv file with the sotred separator + * + * @param value The value to write + */ void write_values(const V& value) override; }; diff --git a/libROOT/libROOT/method.hpp b/libROOT/libROOT/method.hpp index 6b92cb3..d670d0f 100644 --- a/libROOT/libROOT/method.hpp +++ b/libROOT/libROOT/method.hpp @@ -1,6 +1,10 @@ #ifndef LIBROOT_METHOD_HPP #define LIBROOT_METHOD_HPP +/** + * @brief Enumeration of available root-finding methods. + * + */ enum Method { BISECTION, NEWTON, CHORDS, FIXED_POINT }; #endif diff --git a/libROOT/libROOT/solver_def.hpp b/libROOT/libROOT/solver_def.hpp index 478b315..14f219f 100644 --- a/libROOT/libROOT/solver_def.hpp +++ b/libROOT/libROOT/solver_def.hpp @@ -2,17 +2,18 @@ * @file solver_def.hpp * @brief Contains definition of class Solver to find the root of a non-linear equation with some numerical methods * - * @author andreasaporito - * * The Solver class will handle all the methods and arguments required for managing a solving process to find * the root of a Non-linear function. * For this scope, it will run a while loop and compute the error to check convergence, and will create an object * of the Stepper class to actually computing the step, passing the required arguments to it. * The results will be eventually stored in a Matrix, which will we passed to a Writer object to print it out in * a file or in the output window. + * + * @author andreasaporito */ #ifndef ROOT_SOLVER_DEF_HPP #define ROOT_SOLVER_DEF_HPP + #include #include #include @@ -37,9 +38,6 @@ class Solver { bool verbose; //!< Verbose mode flag std::function derivative_or_function_g; //!< Stores the derivative or g_function of the function if needed - /** \brief Stores in the first column the points computed at each step, in - * the second the value of the function at those points. - */ Eigen::MatrixX2d results; //!< Stores in the first column the points computed at each step, in the second the value //!< of the function at those points. std::function @@ -85,6 +83,7 @@ class Solver { public: /** * @brief Constructor for Solver object + * * @param fun The function to find the root of * @param initial_guess The initial guess(es) or interval * @param method The method which will be used for the Solution @@ -95,6 +94,18 @@ class Solver { */ Solver(std::function fun, T initial_guess, const Method method, int max_iterations, double tolerance, bool aitken_mode, bool verbose); + /** + * @brief Constructor for Solver object + * + * @param fun The function to find the root of + * @param initial_guess The initial guess(es) or interval + * @param method The method which will be used for the Solution + * @param max_iterations Maximum iterations in which the method has to converge + * @param tolerance The tolerance below which the error/function will make the method converge + * @param aitken_mode Option to apply Aitken's acceleration + * @param verbose Option to give verbose output + * @param derivative_or_function_g The derivative of the function (for Newton) or g_function (for Fixed Point) + */ Solver(std::function fun, T initial_guess, const Method method, int max_iterations, double tolerance, bool aitken_mode, bool verbose, std::function derivative_or_function_g); /** @brief Calls everything required to Solve with a method. diff --git a/libROOT/libROOT/stepper_def.hpp b/libROOT/libROOT/stepper_def.hpp index 867233f..efa7b24 100644 --- a/libROOT/libROOT/stepper_def.hpp +++ b/libROOT/libROOT/stepper_def.hpp @@ -3,13 +3,13 @@ * @brief Contains definitions for all the Classes Stepper to compute steps of numerical methods to find the root * of non-linear equations * - * @author andreasaporito - * * The stepper classes will store the required functions, derivatives, and booleans to define how to compute the * step. * Each inherited class specializes the abstract Stepper to a real Stepper of a certain method. * The computation step is overridden in each class, and some additional arguments are saved depending on the * method. The generic Stepper constructor is inherited and the new specialized object will type the templated one. + * + * @author andreasaporito */ #ifndef ROOT_STEPPER_DEF_HPP #define ROOT_STEPPER_DEF_HPP @@ -27,6 +27,9 @@ class StepperBase { bool aitken_requirement; //!< Option to use Aitken's acceleration /** * @brief Virtual function to compute the step for the method -> overridden by all the methods + * + * @param previous_iteration 2-dimensional vector storing x(i-1) and f(x(i-1)) - previous guesses + * @return 2-dimensional vector storing x(i) and f(x(i)) - new guesses */ virtual Eigen::Vector2d compute_step(Eigen::Vector2d) = 0; /** From cf1483f0561f3744ed798a70fb0d314f27c89fe4 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Wed, 10 Dec 2025 15:23:42 +0100 Subject: [PATCH 02/12] merge relic --- README.md | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 63c5b5d..9f1b026 100644 --- a/README.md +++ b/README.md @@ -206,22 +206,6 @@ the equation x^3-8 starting from the two initial points 1 and 3: root_cli --wdat output --wgnuplot output cli --function x^3-8 chords --x0 --x1 3 ``` -The installed CLI application can simply be used by: - -``` -$ /bin/root_cli -# or just root_cli if installed in /usr/local/bin/ on unix for instance -``` - -And the shared library can be used inside `cxx` files using: - -``` -# pass the path of headers -g++ .cpp -o -I/include -``` - -All of which can also be set in `CMakeLists.txt`. - ## Typical program execution Input reading is handled by a CLI implemented using `CLI11`, the `Reader` classes, and the `Parser` classes. The output is passed from the CLI to one of the Reader classes @@ -337,3 +321,5 @@ The documentation is automatically built (on every PR) and deployed (on every pu ## Limitations and problems Most of the limitations and problems can be found as independent issues in the [issue tracker on GitHub](https://github.com/Saransh-cpp/ROOT/issues). + +## Authors and their contributions From bee05dc276ae1e2a9ec8fd327207dcb60525d845 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Wed, 10 Dec 2025 15:36:06 +0100 Subject: [PATCH 03/12] add authors --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9f1b026..54398b1 100644 --- a/README.md +++ b/README.md @@ -323,3 +323,7 @@ The documentation is automatically built (on every PR) and deployed (on every pu Most of the limitations and problems can be found as independent issues in the [issue tracker on GitHub](https://github.com/Saransh-cpp/ROOT/issues). ## Authors and their contributions + +- **Andrea Saporito** (@andreasaporito): Stepper, Solver, Writer, Printer classes/functionalities, most of the integration tests and some unit tests, and some fixes/refactoring here and there (touching Reader and Parser classes/functionalities, and the build system). + +- **Saransh Chopra** (@Saransh-cpp): Top-level CLI executable/application, Reader and Parser classes/functionalities, Project infrastructure (build system {code, docs, tests}, project structure, CI/CD), most of the unit tests and some integration tests, and some refactoring here and there (touching Stepper, Solver, Writer, and Printer classes/functionalities). From 8ef3eb9164d0b8ba8ecb8da215b54d9f51213cd0 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Wed, 10 Dec 2025 16:00:34 +0100 Subject: [PATCH 04/12] complete reader part --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 54398b1..f41ad66 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ ROOT, but not the [particle physics one](https://github.com/root-project/root). Project submission for MATH-458: Programming concepts in scientific computing. +The project bundles a header-only C++ library (`libROOT`) implementing root-finding algorithms and a CLI application (`root_cli`) to read and parse input, run the algorithms implemented in libROOT, and write the output to a file of specific format. + ## Project structure The project uses the recommended [Canonical Project Structure](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html) for C++ projects. @@ -38,14 +40,16 @@ The project uses the recommended [Canonical Project Structure](https://www.open- ``` Apart from being divided into a library and a user-facing application/executable, the design on the project -is concretely split into three phases. +is concretely split into four phases. ### CLI -The CLI application is written (and should be written) within the `main` function, followed by calling the `Reader`, `Solver`, and `Writer` classes in this order. +The CLI application is written (and should be written) within the `main` function. The `main` function further calls the `Reader`, `Solver`, and `Writer` classes (in this order) on the input passed through the CLI application. ### Readers and Parsers +Reading and parsing is handled by the `ReaderBase` and `FunctionParserBase` daughter classes. Adding a new reading method should include writing a new `ReaderBase` daughter class and adding functionality to parse a new type of function should include writing a new `FunctionParserBase` daughter class. The information read is stored by the `ConfigBase` daughter classes (these are data classes to be specific, and can ideally by just `struct`s, but they use some object-oriented features, requiring them to be `class`es). Adding a new stepper type should include adding a new `ConfigBase` daughter class. The `read` method of the `ReaderBase` daughter classes accept a pointer of the type `CLI::App` and return a pointer to an object of the type of one of the daughter classes of `ConfigBase`. The `Reader` classes further implement helper methods for reading and parsing different things, and functions for constructing the `ConfigBase` object itself. Similarly, the `parse` function of the `FunctionParser` classes takes in a `string` and returns a C++ function (parses a specific type of function). The classes also include helper methods for parsing functions, and a method (in `FunctionParserBase`) to infer the type of the function (from the string) and dispatch the appropriate daughter class objects (and methods) to parse the function. + ### Solver and Steppers ### Writer and Printers @@ -208,7 +212,11 @@ the equation x^3-8 starting from the two initial points 1 and 3: ## Typical program execution -Input reading is handled by a CLI implemented using `CLI11`, the `Reader` classes, and the `Parser` classes. The output is passed from the CLI to one of the Reader classes +Input reading is handled by a CLI implemented using `CLI11`, which passes the read options to the appropriate `ReaderBase` daughter class. The `read` method of the `ReaderBase` daughter classes construct and return a `ConfigBase` daughter class object. The `ReaderBase` daughter classes also use the `FunctionParserBase` daughter classes internally to parse the function (and derivation + g function) inputted by user (string to a C++ function). The information stored in `ConfigBase` daughter classes is then passed down to the `Solver` class to run the algorithm. + + + + ## Tests From 285018161fdd2b36896b7549c9b0e70b2080f1b9 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Wed, 10 Dec 2025 16:17:23 +0100 Subject: [PATCH 05/12] fix example + bug in iterative method reading --- README.md | 37 ++++++++++++++++++++++++------------- ROOT/ROOT/main.cpp | 2 +- ROOT/ROOT/reader.cpp | 4 ++++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f41ad66..130336b 100644 --- a/README.md +++ b/README.md @@ -171,10 +171,10 @@ Here's a list of examples of possible execution syntax: root_cli --wcli cli --function "x^2-4" newton --initial 1.0 --derivative "2*x" ``` -- DAT input file called input.dat with first row not being header and " " separating different values, .dat file output called output.dat, Bisection method to find the root of x^3-1, with initial interval [-2,2], verbose output (given tolerance and maximum iterations): +- DAT input file called input.dat, DAT output file called output.dat, Bisection method to find the root of x^3-1, with initial interval [-2,2], verbose output (given tolerance and maximum iterations): ``` - root_cli --verbose --wdat output dat input + root_cli --verbose --wdat output dat --file input.dat ``` where input.dat is: @@ -182,32 +182,43 @@ Here's a list of examples of possible execution syntax: ``` function = x^3-1 method = bisection - initial = -1 + interval_a = -2 + interval_b = 2 tolerance = 1e-5 max-iterations = 100 derivative = 2*x ``` -- CSV input file called input.csv with first row which is a header and "," separating different values, .csv file ouput -called output.csv, Fixed Point Method to find the root of cos(x), with -initial guess 0.5, fixed point function cos(x): +- CSV input file called input.csv with first row which is a header and "," separating different values, CSV output file called output.csv, Fixed Point Method to find the root of x^2-x, with initial guess 0.5, fixed point function x^2: ``` - root_cli --wcsv output --ocsvsep , csv input --sep , --header + root_cli --verbose --wcsv output --ocsvsep , csv --file input.csv --sep , --header ``` where input.csv is: ``` function,method,initial,tolerance,max_iterations,g-function - 'cos(x)',fixed_point,0.5,1e-5,100,'cos(x)' + x^2-x,fixed_point,0.5,1e-5,100,x^2 ``` -- CLI input, .dat output file called output.dat and moreover a GNU Plot is created from it as output.png. Chords method to solve -the equation x^3-8 starting from the two initial points 1 and 3: +- Same as above but with aitken acceleration (will converge faster): ``` - root_cli --wdat output --wgnuplot output cli --function x^3-8 chords --x0 --x1 3 + root_cli --verbose --wcsv output --ocsvsep , csv --file input.csv --sep , --header + ``` + + where input.csv is: + + ``` + function,method,initial,tolerance,max_iterations,g-function,aitken + x^2-x,fixed_point,0.5,1e-5,100,x^2,true + ``` + +- CLI input, DAT output file called output.dat, gnuplot writing method (a GNU Plot named output.png is created), Chords method to solve the equation x^3-8 starting from the two initial points 1 and 3: + + ``` + root_cli --wgnuplot output cli --function x^3-8 chords --x0 1 --x1 3 ``` ## Typical program execution @@ -332,6 +343,6 @@ Most of the limitations and problems can be found as independent issues in the [ ## Authors and their contributions -- **Andrea Saporito** (@andreasaporito): Stepper, Solver, Writer, Printer classes/functionalities, most of the integration tests and some unit tests, and some fixes/refactoring here and there (touching Reader and Parser classes/functionalities, and the build system). +- **Andrea Saporito** ([@andreasaporito](https://github.com/andreasaporito)): Stepper, Solver, Writer, Printer classes/functionalities, most of the integration tests and some unit tests, and some fixes/refactoring here and there (touching Reader and Parser classes/functionalities, and the build system). -- **Saransh Chopra** (@Saransh-cpp): Top-level CLI executable/application, Reader and Parser classes/functionalities, Project infrastructure (build system {code, docs, tests}, project structure, CI/CD), most of the unit tests and some integration tests, and some refactoring here and there (touching Stepper, Solver, Writer, and Printer classes/functionalities). +- **Saransh Chopra** ([@Saransh-cpp](https://github.com/Saransh-cpp)): Top-level CLI executable/application, Reader and Parser classes/functionalities, Project infrastructure (build system {code, docs, tests}, project structure, CI/CD), most of the unit tests and some integration tests, and some refactoring here and there (touching Stepper, Solver, Writer, and Printer classes/functionalities). diff --git a/ROOT/ROOT/main.cpp b/ROOT/ROOT/main.cpp index f0defc4..864320c 100644 --- a/ROOT/ROOT/main.cpp +++ b/ROOT/ROOT/main.cpp @@ -60,7 +60,7 @@ int main(int argc, char** argv) { char csv_quote = '"'; csv->add_option("--quote", csv_quote, "Quote/delimiter character for CSV file")->capture_default_str(); bool csv_header = true; - csv->add_option("--header", csv_header, "Indicates whether the first row is a header row")->capture_default_str(); + csv->add_flag("--header", csv_header, "Indicates whether the first row is a header row")->capture_default_str(); // DAT auto* dat = app.add_subcommand("dat", "Use DAT input"); diff --git a/ROOT/ROOT/reader.cpp b/ROOT/ROOT/reader.cpp index 80ff684..d5d6850 100644 --- a/ROOT/ROOT/reader.cpp +++ b/ROOT/ROOT/reader.cpp @@ -208,6 +208,10 @@ std::unique_ptr ReaderBase::make_config_from_map( std::exit(EXIT_FAILURE); } double initial = 0.0; + if (!parseDouble(it_x0->second, initial)) { + std::cerr << "\033[31mmake_config_from_map: invalid initial\033[0m\n"; + std::exit(EXIT_FAILURE); + } auto g_function = FunctionParserBase::parseFunction(it_g->second); return std::make_unique(tolerance, max_iter, aitken, function, initial, g_function, verbose); From edd654b7502830bd9d0a9cfd4c90c8caf1b1f7d4 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Wed, 10 Dec 2025 16:30:22 +0100 Subject: [PATCH 06/12] no header option --- .clang-tidy | 2 +- README.md | 11 ++++++----- ROOT/ROOT/main.cpp | 2 -- ROOT/ROOT/reader.cpp | 43 ++++++++++++------------------------------- ROOT/ROOT/reader.hpp | 1 - input.csv | 2 ++ output.csv | 3 +++ 7 files changed, 24 insertions(+), 40 deletions(-) create mode 100644 input.csv create mode 100644 output.csv diff --git a/.clang-tidy b/.clang-tidy index 343c2de..8dda7a6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -15,6 +15,6 @@ Checks: > google-* CheckOptions: - key: readability-function-cognitive-complexity.Threshold - value: '37' + value: '40' ExtraArgs: ['-std=c++20'] WarningsAsErrors: '*' diff --git a/README.md b/README.md index 130336b..13e9f3e 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,8 @@ root_cli In order to print out more information about the arguments and the subcommands: ``` -root_cli +root_cli --help +root_cli --help ``` Every additional needed function must be added together with the function to find the root of. @@ -171,7 +172,7 @@ Here's a list of examples of possible execution syntax: root_cli --wcli cli --function "x^2-4" newton --initial 1.0 --derivative "2*x" ``` -- DAT input file called input.dat, DAT output file called output.dat, Bisection method to find the root of x^3-1, with initial interval [-2,2], verbose output (given tolerance and maximum iterations): +- DAT input file called input.dat, DAT output file called output.dat, Bisection method to find the root of x^3-1, with initial interval [-2,2], and verbose output (given tolerance and maximum iterations): ``` root_cli --verbose --wdat output dat --file input.dat @@ -189,10 +190,10 @@ Here's a list of examples of possible execution syntax: derivative = 2*x ``` -- CSV input file called input.csv with first row which is a header and "," separating different values, CSV output file called output.csv, Fixed Point Method to find the root of x^2-x, with initial guess 0.5, fixed point function x^2: +- CSV input file called input.csv with first row which is a header and "," separating different values, CSV output file called output.csv, Fixed Point Method to find the root of x^2-x, with initial guess 0.5, fixed point function x^2, and verbose output (given tolerance and maximum iterations):: ``` - root_cli --verbose --wcsv output --ocsvsep , csv --file input.csv --sep , --header + root_cli --verbose --wcsv output --ocsvsep , csv --file input.csv --sep , ``` where input.csv is: @@ -205,7 +206,7 @@ Here's a list of examples of possible execution syntax: - Same as above but with aitken acceleration (will converge faster): ``` - root_cli --verbose --wcsv output --ocsvsep , csv --file input.csv --sep , --header + root_cli --verbose --wcsv output --ocsvsep , csv --file input.csv --sep , ``` where input.csv is: diff --git a/ROOT/ROOT/main.cpp b/ROOT/ROOT/main.cpp index 864320c..0584083 100644 --- a/ROOT/ROOT/main.cpp +++ b/ROOT/ROOT/main.cpp @@ -59,8 +59,6 @@ int main(int argc, char** argv) { csv->add_option("--sep", csv_sep, "Separator character for CSV file")->capture_default_str(); char csv_quote = '"'; csv->add_option("--quote", csv_quote, "Quote/delimiter character for CSV file")->capture_default_str(); - bool csv_header = true; - csv->add_flag("--header", csv_header, "Indicates whether the first row is a header row")->capture_default_str(); // DAT auto* dat = app.add_subcommand("dat", "Use DAT input"); diff --git a/ROOT/ROOT/reader.cpp b/ROOT/ROOT/reader.cpp index d5d6850..2a11f53 100644 --- a/ROOT/ROOT/reader.cpp +++ b/ROOT/ROOT/reader.cpp @@ -259,7 +259,6 @@ std::unique_ptr ReaderCSV::read(CLI::App* app, bool verbose) { this->filename = app->get_option("--file")->as(); this->sep = app->get_option("--sep")->as(); this->quote = app->get_option("--quote")->as(); - this->has_header = app->get_option("--header")->as(); std::ifstream ifs(filename); if (!ifs) { std::cerr << "\033[31mReaderCSV: failed to open file: " << filename << "\033[0m\n"; @@ -269,32 +268,19 @@ std::unique_ptr ReaderCSV::read(CLI::App* app, bool verbose) { std::string headerLine; std::string valueLine; - if (this->has_header) { - if (!std::getline(ifs, headerLine)) { - std::cerr << "\033[31mReaderCSV: empty file (expecting header)\033[0m\n"; - std::exit(EXIT_FAILURE); - } - if (!std::getline(ifs, valueLine)) { - std::cerr << "\033[31mReaderCSV: missing value row\033[0m\n"; - std::exit(EXIT_FAILURE); - } - } else { - if (!std::getline(ifs, valueLine)) { - std::cerr << "\033[31mReaderCSV: empty file\033[0m\n"; - std::exit(EXIT_FAILURE); - } - headerLine.clear(); + if (!std::getline(ifs, headerLine)) { + std::cerr << "\033[31mReaderCSV: empty file (expecting header)\033[0m\n"; + std::exit(EXIT_FAILURE); + } + if (!std::getline(ifs, valueLine)) { + std::cerr << "\033[31mReaderCSV: missing value row\033[0m\n"; + std::exit(EXIT_FAILURE); } std::vector headers; - if (this->has_header) { - headers = splitCsvLine(headerLine); - for (auto& header : headers) { - header = trim(header); - } - } else { - std::cerr << "\033[31mReaderCSV: no headers provided\033[0m\n"; - std::exit(EXIT_FAILURE); + headers = splitCsvLine(headerLine); + for (auto& header : headers) { + header = trim(header); } auto values = splitCsvLine(valueLine); @@ -315,13 +301,8 @@ std::unique_ptr ReaderCSV::read(CLI::App* app, bool verbose) { config_map[key] = values[i]; } } else { - // positional mapping documented here: - std::vector posnames = {"method", "tolerance", "max-iterations", "aitken", "function", - "derivative", "interval_a", "interval_b", "function-g", "initial", - "x0", "x1"}; - for (size_t i = 0; i < values.size() && i < posnames.size(); ++i) { - config_map[posnames[i]] = values[i]; - } + std::cerr << "\033[31mReaderCSV: empty header row\033[0m\n"; + std::exit(EXIT_FAILURE); } if (verbose) { diff --git a/ROOT/ROOT/reader.hpp b/ROOT/ROOT/reader.hpp index aa0e9a0..707533c 100644 --- a/ROOT/ROOT/reader.hpp +++ b/ROOT/ROOT/reader.hpp @@ -34,7 +34,6 @@ class ReaderBase { std::string filename; //!< The input filename to read from. char sep; //!< Field separator character. char quote; //!< Quote/delimiter character. - bool has_header; //!< Indicates whether the first row is a header row. /** * @brief Virtual destructor for ReaderBase. * diff --git a/input.csv b/input.csv new file mode 100644 index 0000000..a8b56a0 --- /dev/null +++ b/input.csv @@ -0,0 +1,2 @@ +function,method,initial,tolerance,max_iterations,g-function,aitken +x^2-x,fixed_point,0.5,1e-5,100,x^2,true diff --git a/output.csv b/output.csv new file mode 100644 index 0000000..c5241b5 --- /dev/null +++ b/output.csv @@ -0,0 +1,3 @@ +0.5,-0.25 +0.015625,-0.0153809 +-3.69457e-06,3.69458e-06 From a4fcc4ed1e8805e9ecd10a67018a243f34b8a776 Mon Sep 17 00:00:00 2001 From: andreasaporito Date: Thu, 11 Dec 2025 09:16:59 +0100 Subject: [PATCH 07/12] Add Solver and Writer project structure in README --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 13e9f3e..287f675 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,23 @@ Reading and parsing is handled by the `ReaderBase` and `FunctionParserBase` daug ### Solver and Steppers +The solution of the non-linear equation is completely handled by two types of `class`es: `Solver` and `StepperBase`, with her daughter specialized for each method (for now: Newton-Raphson, Bisection, Chords, Fixed Point). +The `Solver` class is constructed with all the inputs required and taken from the previous reading and configuring steps, and has methods to manage the outer passages involved in the solution, all of which are called inside a unique `solve` method. These steps involve mainly the convergence check, the results saving, and the definition and call of the object specialized in computing the single step of the numerical method itself. +`Solver` has no daughter classes but could be refactored to be daughter of a `SolverBase` class which does everything which is in common for all the numerical methods (convergence check and while loop); this refactored `SolverNonLinear` would inherit all the methods from the mother class and add arguments for the functions and the boolean to require Aitken's acceleration. This new `SolverNonLinear` could have daughter classes for solving single equations (our current `Solver`) or systems of them, which would differ just in the type of the arguments saved (e.g. derivative/jacobian for Newton-Raphson). This draft idea, which could be substituted by a fully templated version of the `SolverNonLinear` class, comes from the fact that templating is already used to define the different kinds of initial guesses allowed, and it is not possible (in C++) to partially specialize different templates. Another more brute-force idea could be to define all the different arguments as matrices and then use them as 1 by 1 matrices (or vectors) for the single equation case, without creating two daughter classes. All of these ideas would have to be adapted for the `Stepper` classes too. +A `StepperBase` object is constructed inside the `Solver::solve` method, initially as completely virtual. Then it is converted into a specialized daughter class of it, with all the required arguments to use for the single step computation. +The only method executed by the Steppers is `compute_step` which computes a single step of the numerical method and returns the results for it. +To allow more numerical methods, it is possible to simply define new daughter classes with different `compute_step` algorithms and potentially different arguments to store. + ### Writer and Printers +The writing part of the project is done again by two major `class`es: `Writer` and `PrinterBase`, with her daughter classes for each output destination available. +All the inputs required to define how and where to write the results are defined in the reading and configuring step. +What is important to point out is that these classes are not defined as only applicable for our specific project, but can write anything correctly passed (potentially with slight refactoring of the code). +This classes' methods are coded just for the typed version required in out project, but different typed version would be easy to add. +`Writer` has arguments to store what to write and how, and methods (all of which are called by a unique `write` one) to define, convert and handle a `PrinterBase` object. +`PrinterBase` is then specialized for a certain output destination, all of which have a overriden `write_values` method which prints a given input on a stored output. +To allow different writing destinations, new daughter classes can be defined inheriting from existing ones. + ## Dependencies ### Dependencies for the project From d82bbe0d1abd3de56a26e10ccf9b43c9cfc7f0a2 Mon Sep 17 00:00:00 2001 From: andreasaporito Date: Thu, 11 Dec 2025 09:27:57 +0100 Subject: [PATCH 08/12] Add Solver and Writer program execution --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 287f675..944e0da 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Here's a list of examples of possible execution syntax: ``` function,method,initial,tolerance,max_iterations,g-function - x^2-x,fixed_point,0.5,1e-5,100,x^2 + x^2-x,fixed_point,0.5,1e-65,100,x^2 ``` - Same as above but with aitken acceleration (will converge faster): @@ -241,9 +241,12 @@ Here's a list of examples of possible execution syntax: Input reading is handled by a CLI implemented using `CLI11`, which passes the read options to the appropriate `ReaderBase` daughter class. The `read` method of the `ReaderBase` daughter classes construct and return a `ConfigBase` daughter class object. The `ReaderBase` daughter classes also use the `FunctionParserBase` daughter classes internally to parse the function (and derivation + g function) inputted by user (string to a C++ function). The information stored in `ConfigBase` daughter classes is then passed down to the `Solver` class to run the algorithm. - +The `solve` method of `Solver` construct and converts a `StepperBase` daughter class object, handles its methods calls, and finally returns the matrix of the results of the computation performed. +`compute_step` method of each `StepperBase` daughter class gets the previous iteration and computes and returns the new guess, which will be saved and checked by `Solver`'s methods. +The final results returned by `solve` are then passed down to the `Writer` class to write them. - +The `write` method of `Writer` construct and converts a `PrinterBase` daughter class object, and handles its methods calls. +`write_values` method of each `StepperBase` daughter class gets a certain value to be printed and prints it out in a defined destination. ## Tests @@ -355,7 +358,7 @@ The documentation is automatically built (on every PR) and deployed (on every pu ## Limitations and problems -Most of the limitations and problems can be found as independent issues in the [issue tracker on GitHub](https://github.com/Saransh-cpp/ROOT/issues). +Most of the limitations and problems can be found as independent issues in the [issue tracker on GitHub](https://github.com/Saransh-cpp/ROOT/issues), or in the previous Project Structure section. ## Authors and their contributions From 9fb248232e9519989e4cf2d83c86b4331ab39be0 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Thu, 11 Dec 2025 13:16:35 +0100 Subject: [PATCH 09/12] update some reader bits --- README.md | 2 +- input.csv | 2 -- output.csv | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 input.csv delete mode 100644 output.csv diff --git a/README.md b/README.md index 944e0da..2f46327 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ The CLI application is written (and should be written) within the `main` functio ### Readers and Parsers -Reading and parsing is handled by the `ReaderBase` and `FunctionParserBase` daughter classes. Adding a new reading method should include writing a new `ReaderBase` daughter class and adding functionality to parse a new type of function should include writing a new `FunctionParserBase` daughter class. The information read is stored by the `ConfigBase` daughter classes (these are data classes to be specific, and can ideally by just `struct`s, but they use some object-oriented features, requiring them to be `class`es). Adding a new stepper type should include adding a new `ConfigBase` daughter class. The `read` method of the `ReaderBase` daughter classes accept a pointer of the type `CLI::App` and return a pointer to an object of the type of one of the daughter classes of `ConfigBase`. The `Reader` classes further implement helper methods for reading and parsing different things, and functions for constructing the `ConfigBase` object itself. Similarly, the `parse` function of the `FunctionParser` classes takes in a `string` and returns a C++ function (parses a specific type of function). The classes also include helper methods for parsing functions, and a method (in `FunctionParserBase`) to infer the type of the function (from the string) and dispatch the appropriate daughter class objects (and methods) to parse the function. +Reading and parsing is handled by the `ReaderBase` and `FunctionParserBase` daughter classes. Adding a new reading method should include writing a new `ReaderBase` daughter class and adding functionality to parse a new type of function should include writing a new `FunctionParserBase` daughter class. The information read is stored by the `ConfigBase` daughter classes (these are data classes to be specific, and can ideally by just structs, but they use some object-oriented features, requiring them to be classes). Adding a new stepper type should include adding a new `ConfigBase` daughter class. The `read` method of the `ReaderBase` daughter classes accept a pointer of the type `CLI::App` and return a pointer to an object of the type of one of the daughter classes of `ConfigBase`. The `Reader` classes further implement helper methods for reading and parsing different things, and functions for constructing the `ConfigBase` object itself. Similarly, the `parse` function of the `FunctionParser` classes takes in a `string` and returns a C++ function (parses a specific type of function). The classes also include helper methods for parsing functions, and a method (in `FunctionParserBase`) to infer the type of the function (from the string) and dispatch the appropriate daughter class objects (and methods) to parse the function. In the future, it would make sense to add a wrapper around `Reader` classes to abstract `Config` creation and pointer manipulation from the `main` function (just how it is done by the `Solver` and `Writer` classes). ### Solver and Steppers diff --git a/input.csv b/input.csv deleted file mode 100644 index a8b56a0..0000000 --- a/input.csv +++ /dev/null @@ -1,2 +0,0 @@ -function,method,initial,tolerance,max_iterations,g-function,aitken -x^2-x,fixed_point,0.5,1e-5,100,x^2,true diff --git a/output.csv b/output.csv deleted file mode 100644 index c5241b5..0000000 --- a/output.csv +++ /dev/null @@ -1,3 +0,0 @@ -0.5,-0.25 -0.015625,-0.0153809 --3.69457e-06,3.69458e-06 From d15816b27908b589f9e09b53953fbdba7cf8f72e Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Thu, 11 Dec 2025 14:23:15 +0100 Subject: [PATCH 10/12] add docs link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f46327..04e3faf 100644 --- a/README.md +++ b/README.md @@ -354,7 +354,7 @@ which will write the HTML files to `docs/html`. ### Building docs on GH Pages -The documentation is automatically built (on every PR) and deployed (on every push to `main`) to GH Pages using the `build-and-deploy-docs` workflow. +The documentation is automatically built (on every PR) and deployed (on every push to `main` here - [https://saransh-cpp.github.io/ROOT/](https://saransh-cpp.github.io/ROOT/)) to GH Pages using the `build-and-deploy-docs` workflow. ## Limitations and problems From efdd98d542f13315fd9b2d08fbe97d930456c5c2 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Thu, 11 Dec 2025 16:57:34 +0100 Subject: [PATCH 11/12] Rewrite some text --- README.md | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 04e3faf..5d1960e 100644 --- a/README.md +++ b/README.md @@ -52,22 +52,19 @@ Reading and parsing is handled by the `ReaderBase` and `FunctionParserBase` daug ### Solver and Steppers -The solution of the non-linear equation is completely handled by two types of `class`es: `Solver` and `StepperBase`, with her daughter specialized for each method (for now: Newton-Raphson, Bisection, Chords, Fixed Point). -The `Solver` class is constructed with all the inputs required and taken from the previous reading and configuring steps, and has methods to manage the outer passages involved in the solution, all of which are called inside a unique `solve` method. These steps involve mainly the convergence check, the results saving, and the definition and call of the object specialized in computing the single step of the numerical method itself. -`Solver` has no daughter classes but could be refactored to be daughter of a `SolverBase` class which does everything which is in common for all the numerical methods (convergence check and while loop); this refactored `SolverNonLinear` would inherit all the methods from the mother class and add arguments for the functions and the boolean to require Aitken's acceleration. This new `SolverNonLinear` could have daughter classes for solving single equations (our current `Solver`) or systems of them, which would differ just in the type of the arguments saved (e.g. derivative/jacobian for Newton-Raphson). This draft idea, which could be substituted by a fully templated version of the `SolverNonLinear` class, comes from the fact that templating is already used to define the different kinds of initial guesses allowed, and it is not possible (in C++) to partially specialize different templates. Another more brute-force idea could be to define all the different arguments as matrices and then use them as 1 by 1 matrices (or vectors) for the single equation case, without creating two daughter classes. All of these ideas would have to be adapted for the `Stepper` classes too. -A `StepperBase` object is constructed inside the `Solver::solve` method, initially as completely virtual. Then it is converted into a specialized daughter class of it, with all the required arguments to use for the single step computation. -The only method executed by the Steppers is `compute_step` which computes a single step of the numerical method and returns the results for it. -To allow more numerical methods, it is possible to simply define new daughter classes with different `compute_step` algorithms and potentially different arguments to store. +Solving non-linear equation is completely handled by two classes: `Solver` and `StepperBase`. `StepperBase` has specialized child classes for each method (for now: Newton-Raphson, Bisection, Chords, Fixed Point). +The `Solver` class is constructed with the data stored in `ConfigBase` child classes, and has methods to manage the high-level API involved in solving an equation. The `solve` method of the `Solver` class comprises of multiple internal calls, mainly involving convergence check, results saving, instantiating an object of one of the specialized `StepperBase` child classes, and calling the relevant method to compute single step of the numerical method. + +`Solver` has no child classes but it could be refactored to be child of a `SolverBase` class (refactoring and abstracting common steps, such as the convergence check and the solve loop). The refactored `SolverNonLinear` class would inherit all the methods from the abstract class and add arguments for the functions and the boolean to require Aitken's acceleration. The new `SolverNonLinear` could have child classes for solving single equations (our current `Solver`) or systems of equations, which would differ just in the type of the arguments saved (e.g. derivative/jacobian for Newton-Raphson). This draft idea, which could be substituted by a fully templated version of the `SolverNonLinear` class, comes from the fact that templating is already used to define the different kinds of initial guesses allowed, and it is not possible (in C++) to partially specialize different templates. Another more brute-force idea could be to define all the different arguments as matrices and then use them as 1 X 1 matrices (or vectors) for the single equation case, without creating two daughter classes. All of these ideas would have to be adapted for the `Stepper` classes too. + +`Solver::solve` declares a `StepperBase` pointer and later instantiated it to point to an object of one of its child class, passing down all the required arguments to use for a single step computation. The only public method executed by the `Stepper`s is `compute_step`, which computes a single step of the numerical method and returns the results. To allow more numerical methods, it is possible to simply define new child classes with different `compute_step` algorithms and potentially different arguments to store. ### Writer and Printers -The writing part of the project is done again by two major `class`es: `Writer` and `PrinterBase`, with her daughter classes for each output destination available. -All the inputs required to define how and where to write the results are defined in the reading and configuring step. -What is important to point out is that these classes are not defined as only applicable for our specific project, but can write anything correctly passed (potentially with slight refactoring of the code). -This classes' methods are coded just for the typed version required in out project, but different typed version would be easy to add. -`Writer` has arguments to store what to write and how, and methods (all of which are called by a unique `write` one) to define, convert and handle a `PrinterBase` object. -`PrinterBase` is then specialized for a certain output destination, all of which have a overriden `write_values` method which prints a given input on a stored output. -To allow different writing destinations, new daughter classes can be defined inheriting from existing ones. +The writing part of the project is handled by two classes: `Writer` and `PrinterBase`, with `PrinterBase` having child classes for each output type. The output type and other relevant information is carried down through the `ConfigBase` classes (defined by the `Reader`s). +Importantly, these classes are not only defined for our specific project, but can write anything correctly passed (potentially with slight refactoring of the code). The classes' methods are implemented just for the type required in our project, but different typed versions would be easy to add. + +`Writer` stores what to write and how, the writing method, and implements a high-level `write` method to instantiate an object of one of the `PrinterBase` child classes. `PrinterBase` has child classes specialized for certain output types, all of which have an overwritten `write_values` method which prints a given input on a stored output. To allow different writing destinations, new child classes can be defined inheriting from the existing ones. ## Dependencies @@ -241,12 +238,9 @@ Here's a list of examples of possible execution syntax: Input reading is handled by a CLI implemented using `CLI11`, which passes the read options to the appropriate `ReaderBase` daughter class. The `read` method of the `ReaderBase` daughter classes construct and return a `ConfigBase` daughter class object. The `ReaderBase` daughter classes also use the `FunctionParserBase` daughter classes internally to parse the function (and derivation + g function) inputted by user (string to a C++ function). The information stored in `ConfigBase` daughter classes is then passed down to the `Solver` class to run the algorithm. -The `solve` method of `Solver` construct and converts a `StepperBase` daughter class object, handles its methods calls, and finally returns the matrix of the results of the computation performed. -`compute_step` method of each `StepperBase` daughter class gets the previous iteration and computes and returns the new guess, which will be saved and checked by `Solver`'s methods. -The final results returned by `solve` are then passed down to the `Writer` class to write them. +The `solve` method of `Solver` constructs a `StepperBase` child class object, handles its methods calls, and finally returns the matrix of the results of the computation performed. `compute_step` method of each `StepperBase` child class gets the previous iteration and computes and returns the new guess, which will be saved and checked by `Solver`'s methods. The final results returned by `solve` are then passed down to the `Writer` class to write them. -The `write` method of `Writer` construct and converts a `PrinterBase` daughter class object, and handles its methods calls. -`write_values` method of each `StepperBase` daughter class gets a certain value to be printed and prints it out in a defined destination. +The `write` method of `Writer` construct a `PrinterBase` child class object, and handles its methods calls. `write_values` method of each `StepperBase` child class gets a certain value to be printed and prints it out in a defined destination. ## Tests From 11a9ee5116044fefa178f57cb4c4779360da8513 Mon Sep 17 00:00:00 2001 From: Saransh Chopra Date: Thu, 11 Dec 2025 16:59:57 +0100 Subject: [PATCH 12/12] final typos --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5d1960e..7227c7f 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,11 @@ The `Solver` class is constructed with the data stored in `ConfigBase` child cla `Solver` has no child classes but it could be refactored to be child of a `SolverBase` class (refactoring and abstracting common steps, such as the convergence check and the solve loop). The refactored `SolverNonLinear` class would inherit all the methods from the abstract class and add arguments for the functions and the boolean to require Aitken's acceleration. The new `SolverNonLinear` could have child classes for solving single equations (our current `Solver`) or systems of equations, which would differ just in the type of the arguments saved (e.g. derivative/jacobian for Newton-Raphson). This draft idea, which could be substituted by a fully templated version of the `SolverNonLinear` class, comes from the fact that templating is already used to define the different kinds of initial guesses allowed, and it is not possible (in C++) to partially specialize different templates. Another more brute-force idea could be to define all the different arguments as matrices and then use them as 1 X 1 matrices (or vectors) for the single equation case, without creating two daughter classes. All of these ideas would have to be adapted for the `Stepper` classes too. -`Solver::solve` declares a `StepperBase` pointer and later instantiated it to point to an object of one of its child class, passing down all the required arguments to use for a single step computation. The only public method executed by the `Stepper`s is `compute_step`, which computes a single step of the numerical method and returns the results. To allow more numerical methods, it is possible to simply define new child classes with different `compute_step` algorithms and potentially different arguments to store. +`Solver::solve` declares a `StepperBase` pointer and later instantiates it to point to an object of one of its child class, passing down all the required arguments to use for a single step computation. The only public method executed by the `Stepper`s is `compute_step`, which computes a single step of the numerical method and returns the results. To allow more numerical methods, it is possible to simply define new child classes with different `compute_step` algorithms and potentially different arguments to store. ### Writer and Printers -The writing part of the project is handled by two classes: `Writer` and `PrinterBase`, with `PrinterBase` having child classes for each output type. The output type and other relevant information is carried down through the `ConfigBase` classes (defined by the `Reader`s). -Importantly, these classes are not only defined for our specific project, but can write anything correctly passed (potentially with slight refactoring of the code). The classes' methods are implemented just for the type required in our project, but different typed versions would be easy to add. +The writing part of the project is handled by two classes: `Writer` and `PrinterBase`, with `PrinterBase` having child classes for each output type. The output type and other relevant information is carried down through the `ConfigBase` classes (defined by the `Reader`s). Importantly, these classes are not only defined for our specific project, but can write anything correctly passed (potentially with slight refactoring of the code). The classes' methods are implemented just for the type required in our project, but different typed versions would be easy to add. `Writer` stores what to write and how, the writing method, and implements a high-level `write` method to instantiate an object of one of the `PrinterBase` child classes. `PrinterBase` has child classes specialized for certain output types, all of which have an overwritten `write_values` method which prints a given input on a stored output. To allow different writing destinations, new child classes can be defined inheriting from the existing ones.