From 0fed69b41259f20d2bf19c76ea2b7d182c62ccbb Mon Sep 17 00:00:00 2001 From: KeyKyrios Date: Mon, 20 Oct 2025 13:45:57 +0530 Subject: [PATCH 1/2] feat(maths): Add Neville's algorithm for interpolation --- numerical_methods/nevilles_algorithm.cpp | 105 +++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 numerical_methods/nevilles_algorithm.cpp diff --git a/numerical_methods/nevilles_algorithm.cpp b/numerical_methods/nevilles_algorithm.cpp new file mode 100644 index 00000000000..52d31e2c54b --- /dev/null +++ b/numerical_methods/nevilles_algorithm.cpp @@ -0,0 +1,105 @@ +/** + * @file + * @brief Implementation of Neville's Algorithm for polynomial interpolation. + * @details Neville's algorithm is an iterative method to find the value of a + * polynomial that passes through a given set of n+1 points. It evaluates the + * polynomial at a specific point `x` without needing to compute the + * polynomial's coefficients. For more details, see: + * https://en.wikipedia.org/wiki/Neville%27s_algorithm + * @author [Mitrajit Ghorui](https://github.com/KeyKyrios) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::invalid_argument +#include /// for std::vector +#include /// for fabs + +/** + * @namespace maths + * @brief Mathematical algorithms + */ +namespace maths { +/** + * @namespace nevilles_algorithm + * @brief Functions for Neville's Algorithm + */ +namespace nevilles_algorithm { +/** + * @brief Evaluates the interpolating polynomial at a specific point. + * @param x_coords Vector of x-coordinates of the given points. + * @param y_coords Vector of y-coordinates of the given points. + * @param target The x-coordinate at which to evaluate the polynomial. + * @returns The interpolated y-value at the target x-coordinate. + * @throws std::invalid_argument if input vectors are empty or have mismatched + * sizes. + */ +double interpolate(const std::vector& x_coords, + const std::vector& y_coords, double target) { + if (x_coords.empty() || y_coords.empty()) { + throw std::invalid_argument("Input vectors cannot be empty."); + } + if (x_coords.size() != y_coords.size()) { + throw std::invalid_argument( + "x and y coordinate vectors must be the same size."); + } + + int n = x_coords.size(); + std::vector p = y_coords; // Initialize p with y values + + for (int k = 1; k < n; ++k) { + for (int i = 0; i < n - k; ++i) { + p[i] = ((target - x_coords[i + k]) * p[i] + + (x_coords[i] - target) * p[i + 1]) / + (x_coords[i] - x_coords[i + k]); + } + } + + return p[0]; +} +} // namespace nevilles_algorithm +} // namespace maths + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // Test 1: Linear interpolation y = 2x + 1 + // Points (0, 1), (2, 5). Target x=1, expected y=3. + std::vector x1 = {0, 2}; + std::vector y1 = {1, 5}; + double target1 = 1; + double expected1 = 3.0; + assert(fabs(maths::nevilles_algorithm::interpolate(x1, y1, target1) - expected1) < 1e-9); + std::cout << "Linear test passed." << std::endl; + + // Test 2: Quadratic interpolation y = x^2 + // Points (0, 0), (1, 1), (3, 9). Target x=2, expected y=4. + std::vector x2 = {0, 1, 3}; + std::vector y2 = {0, 1, 9}; + double target2 = 2; + double expected2 = 4.0; + assert(fabs(maths::nevilles_algorithm::interpolate(x2, y2, target2) - expected2) < 1e-9); + std::cout << "Quadratic test passed." << std::endl; + + // Test 3: Negative numbers y = x^2 - 2x + 1 + // Points (-1, 4), (0, 1), (2, 1). Target x=1, expected y=0. + std::vector x3 = {-1, 0, 2}; + std::vector y3 = {4, 1, 1}; + double target3 = 1; + double expected3 = 0.0; + assert(fabs(maths::nevilles_algorithm::interpolate(x3, y3, target3) - expected3) < 1e-9); + std::cout << "Negative numbers test passed." << std::endl; + + std::cout << "All tests have successfully passed!" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} \ No newline at end of file From 1e133f53aea5c37e3b96b5b5ca49e118965b5e37 Mon Sep 17 00:00:00 2001 From: Keykyrios Date: Mon, 20 Oct 2025 15:20:14 +0530 Subject: [PATCH 2/2] Update nevilles_algorithm.cpp --- numerical_methods/nevilles_algorithm.cpp | 59 ++++++++++++++++-------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/numerical_methods/nevilles_algorithm.cpp b/numerical_methods/nevilles_algorithm.cpp index 52d31e2c54b..a9440d1877e 100644 --- a/numerical_methods/nevilles_algorithm.cpp +++ b/numerical_methods/nevilles_algorithm.cpp @@ -9,17 +9,18 @@ * @author [Mitrajit Ghorui](https://github.com/KeyKyrios) */ -#include /// for assert -#include /// for IO operations -#include /// for std::invalid_argument -#include /// for std::vector -#include /// for fabs +#include /// for assert +#include /// for fabs +#include /// for IO operations +#include /// for std::invalid_argument +#include /// for std::unordered_set +#include /// for std::vector /** - * @namespace maths - * @brief Mathematical algorithms + * @namespace numerical_methods + * @brief Numerical Methods */ -namespace maths { +namespace numerical_methods { /** * @namespace nevilles_algorithm * @brief Functions for Neville's Algorithm @@ -31,8 +32,8 @@ namespace nevilles_algorithm { * @param y_coords Vector of y-coordinates of the given points. * @param target The x-coordinate at which to evaluate the polynomial. * @returns The interpolated y-value at the target x-coordinate. - * @throws std::invalid_argument if input vectors are empty or have mismatched - * sizes. + * @throws std::invalid_argument if vectors are empty, have mismatched + * sizes, or if x-coordinates are not unique. */ double interpolate(const std::vector& x_coords, const std::vector& y_coords, double target) { @@ -44,11 +45,18 @@ double interpolate(const std::vector& x_coords, "x and y coordinate vectors must be the same size."); } - int n = x_coords.size(); + std::unordered_set seenX; + for (double val : x_coords) { + if (!seenX.insert(val).second) { + throw std::invalid_argument("Input x-coordinates must be unique."); + } + } + + size_t n = x_coords.size(); std::vector p = y_coords; // Initialize p with y values - for (int k = 1; k < n; ++k) { - for (int i = 0; i < n - k; ++i) { + for (size_t k = 1; k < n; ++k) { + for (size_t i = 0; i < n - k; ++i) { p[i] = ((target - x_coords[i + k]) * p[i] + (x_coords[i] - target) * p[i + 1]) / (x_coords[i] - x_coords[i + k]); @@ -58,7 +66,7 @@ double interpolate(const std::vector& x_coords, return p[0]; } } // namespace nevilles_algorithm -} // namespace maths +} // namespace numerical_methods /** * @brief Self-test implementations @@ -71,7 +79,8 @@ static void test() { std::vector y1 = {1, 5}; double target1 = 1; double expected1 = 3.0; - assert(fabs(maths::nevilles_algorithm::interpolate(x1, y1, target1) - expected1) < 1e-9); + assert(fabs(numerical_methods::nevilles_algorithm::interpolate(x1, y1, target1) - + expected1) < 1e-9); std::cout << "Linear test passed." << std::endl; // Test 2: Quadratic interpolation y = x^2 @@ -80,7 +89,8 @@ static void test() { std::vector y2 = {0, 1, 9}; double target2 = 2; double expected2 = 4.0; - assert(fabs(maths::nevilles_algorithm::interpolate(x2, y2, target2) - expected2) < 1e-9); + assert(fabs(numerical_methods::nevilles_algorithm::interpolate(x2, y2, target2) - + expected2) < 1e-9); std::cout << "Quadratic test passed." << std::endl; // Test 3: Negative numbers y = x^2 - 2x + 1 @@ -89,9 +99,22 @@ static void test() { std::vector y3 = {4, 1, 1}; double target3 = 1; double expected3 = 0.0; - assert(fabs(maths::nevilles_algorithm::interpolate(x3, y3, target3) - expected3) < 1e-9); + assert(fabs(numerical_methods::nevilles_algorithm::interpolate(x3, y3, target3) - + expected3) < 1e-9); std::cout << "Negative numbers test passed." << std::endl; + // Test 4: Exception for duplicate x-coordinates + std::vector x4 = {1, 2, 1}; + std::vector y4 = {5, 8, 3}; + bool exception_thrown = false; + try { + numerical_methods::nevilles_algorithm::interpolate(x4, y4, 1.5); + } catch (const std::invalid_argument& e) { + exception_thrown = true; + } + assert(exception_thrown); + std::cout << "Duplicate X coordinate test passed." << std::endl; + std::cout << "All tests have successfully passed!" << std::endl; } @@ -102,4 +125,4 @@ static void test() { int main() { test(); // run self-test implementations return 0; -} \ No newline at end of file +}