From 06586d7ca60661ac06f1b587e35734136b1e9517 Mon Sep 17 00:00:00 2001 From: Dibbu-cell Date: Wed, 1 Oct 2025 23:16:13 +0530 Subject: [PATCH 1/8] brent's_method --- maths/numerical_analysis/brent's_method.py | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 maths/numerical_analysis/brent's_method.py diff --git a/maths/numerical_analysis/brent's_method.py b/maths/numerical_analysis/brent's_method.py new file mode 100644 index 000000000000..d1b3912ac068 --- /dev/null +++ b/maths/numerical_analysis/brent's_method.py @@ -0,0 +1,89 @@ +import math +from collections.abc import Callable + +def brent_method( + f: Callable[[float], float], + a: float, + b: float, + tol: float = 1e-14, + max_iter: int = 100 +) -> float: + """ + Root finding using Brent's method. + + >>> brent_method(lambda x: x**3 - 1, -5, 5) + 1.0 + >>> brent_method(lambda x: x**2 - 4*x + 3, 0, 2) + 1.0 + >>> brent_method(lambda x: x**2 - 4*x + 3, 2, 4) + 3.0 + >>> brent_method(lambda x: x**2 - 4*x + 3, 4, 1000) + Traceback (most recent call last): + ... + ValueError: Root is not bracketed. + """ + + fa = f(a) + fb = f(b) + if fa * fb >= 0: + raise ValueError("Root is not bracketed.") + + if abs(fa) < abs(fb): + a, b = b, a + fa, fb = fb, fa + + c = a + fc = fa + d = e = b - a + mflag = True + + for _ in range(max_iter): + if fb == 0: + return b + if fa != fc and fb != fc: + # Inverse quadratic interpolation + s = ( + a * fb * fc / ((fa - fb) * (fa - fc)) + + b * fa * fc / ((fb - fa) * (fb - fc)) + + c * fa * fb / ((fc - fa) * (fc - fb)) + ) + else: + # Secant method + s = b - fb * (b - a) / (fb - fa) + + conditions = [ + not ((3 * a + b) / 4 < s < b if b > a else b < s < (3 * a + b) / 4), + mflag and abs(s - b) >= abs(b - c) / 2, + not mflag and abs(s - b) >= abs(c - d) / 2, + mflag and abs(b - c) < tol, + not mflag and abs(c - d) < tol, + ] + if any(conditions): + s = (a + b) / 2 + mflag = True + else: + mflag = False + + fs = f(s) + d, c = c, b + fc = fb + + if fa * fs < 0: + b = s + fb = fs + else: + a = s + fa = fs + + if abs(fa) < abs(fb): + a, b = b, a + fa, fb = fb, fa + + if abs(b - a) < tol or fb == 0: + return b + + return b + +if __name__ == "__main__": + from doctest import testmod + testmod() \ No newline at end of file From 56d6f970a90eb5536f3a95dd1e10cc20e5965481 Mon Sep 17 00:00:00 2001 From: Dibbu-cell Date: Wed, 1 Oct 2025 23:52:20 +0530 Subject: [PATCH 2/8] barents --- .../{brent's_method.py => brents_method.py} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename maths/numerical_analysis/{brent's_method.py => brents_method.py} (97%) diff --git a/maths/numerical_analysis/brent's_method.py b/maths/numerical_analysis/brents_method.py similarity index 97% rename from maths/numerical_analysis/brent's_method.py rename to maths/numerical_analysis/brents_method.py index d1b3912ac068..3ebf0ffd5e96 100644 --- a/maths/numerical_analysis/brent's_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -1,4 +1,3 @@ -import math from collections.abc import Callable def brent_method( @@ -34,7 +33,7 @@ def brent_method( c = a fc = fa - d = e = b - a + d = b - a # Only d is used, e removed mflag = True for _ in range(max_iter): @@ -86,4 +85,4 @@ def brent_method( if __name__ == "__main__": from doctest import testmod - testmod() \ No newline at end of file + testmod() From 0aeb7f758880005017dc3b6899066cb6842aa9e1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 18:29:15 +0000 Subject: [PATCH 3/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/numerical_analysis/brents_method.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/maths/numerical_analysis/brents_method.py b/maths/numerical_analysis/brents_method.py index 3ebf0ffd5e96..4fddf02ab868 100644 --- a/maths/numerical_analysis/brents_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -1,11 +1,12 @@ from collections.abc import Callable + def brent_method( f: Callable[[float], float], a: float, b: float, tol: float = 1e-14, - max_iter: int = 100 + max_iter: int = 100, ) -> float: """ Root finding using Brent's method. @@ -42,9 +43,9 @@ def brent_method( if fa != fc and fb != fc: # Inverse quadratic interpolation s = ( - a * fb * fc / ((fa - fb) * (fa - fc)) + - b * fa * fc / ((fb - fa) * (fb - fc)) + - c * fa * fb / ((fc - fa) * (fc - fb)) + a * fb * fc / ((fa - fb) * (fa - fc)) + + b * fa * fc / ((fb - fa) * (fb - fc)) + + c * fa * fb / ((fc - fa) * (fc - fb)) ) else: # Secant method @@ -83,6 +84,8 @@ def brent_method( return b + if __name__ == "__main__": from doctest import testmod + testmod() From e3f1eae4edb139aa979b2800369dc13b2279c407 Mon Sep 17 00:00:00 2001 From: Dibbu-cell Date: Thu, 2 Oct 2025 00:13:19 +0530 Subject: [PATCH 4/8] brents3 --- maths/numerical_analysis/brents_method.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maths/numerical_analysis/brents_method.py b/maths/numerical_analysis/brents_method.py index 3ebf0ffd5e96..90fa41133500 100644 --- a/maths/numerical_analysis/brents_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -39,7 +39,7 @@ def brent_method( for _ in range(max_iter): if fb == 0: return b - if fa != fc and fb != fc: + if fc not in {fa, fb}: # Inverse quadratic interpolation s = ( a * fb * fc / ((fa - fb) * (fa - fc)) + @@ -85,4 +85,4 @@ def brent_method( if __name__ == "__main__": from doctest import testmod - testmod() + testmod() \ No newline at end of file From 06db343c647bc452a12931ad211408dbcbbf5f00 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 04:57:24 +0000 Subject: [PATCH 5/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/numerical_analysis/brents_method.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/maths/numerical_analysis/brents_method.py b/maths/numerical_analysis/brents_method.py index 5992ed21984e..b454000f376f 100644 --- a/maths/numerical_analysis/brents_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -12,6 +12,7 @@ from collections.abc import Callable + def brent_method( function: Callable[[float], float], lower: float, @@ -76,7 +77,11 @@ def brent_method( s = upper - fb * (upper - lower) / (fb - fa) conditions = [ - not ((3 * lower + upper) / 4 < s < upper if upper > lower else upper < s < (3 * lower + upper) / 4), + not ( + (3 * lower + upper) / 4 < s < upper + if upper > lower + else upper < s < (3 * lower + upper) / 4 + ), mflag and abs(s - upper) >= abs(upper - c) / 2, not mflag and abs(s - upper) >= abs(c - d) / 2, mflag and abs(upper - c) < tolerance, @@ -111,4 +116,5 @@ def brent_method( if __name__ == "__main__": import doctest - doctest.testmod() \ No newline at end of file + + doctest.testmod() From 4283c33a56d45cf890bf1479f238a68f7654603c Mon Sep 17 00:00:00 2001 From: Dibbu-cell Date: Thu, 2 Oct 2025 10:42:23 +0530 Subject: [PATCH 6/8] brent7 --- maths/numerical_analysis/brents_method.py | 106 ++++++++++++---------- 1 file changed, 57 insertions(+), 49 deletions(-) diff --git a/maths/numerical_analysis/brents_method.py b/maths/numerical_analysis/brents_method.py index 5992ed21984e..0f6fde51c268 100644 --- a/maths/numerical_analysis/brents_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -5,17 +5,18 @@ Brent's method combines bisection, secant, and inverse quadratic interpolation to efficiently and robustly find a root of a continuous function. It is guaranteed to converge as long as the root is bracketed. -See: https://en.wikipedia.org/wiki/Brent%27s_method +See: + https://en.wikipedia.org/wiki/Brent%27s_method -Author: [Aryan Singh (2nd year LNMIIT)] +Author: Aryan Singh (2nd year LNMIIT) """ from collections.abc import Callable def brent_method( function: Callable[[float], float], - lower: float, - upper: float, + lower_bound: float, + upper_bound: float, tolerance: float = 1e-14, max_iterations: int = 100, ) -> float: @@ -24,8 +25,8 @@ def brent_method( Args: function: A continuous function for which the root is sought. - lower: One end of the bracketing interval. - upper: The other end of the bracketing interval. + lower_bound: One end of the bracketing interval. + upper_bound: The other end of the bracketing interval. tolerance: The tolerance for convergence (default 1e-14). max_iterations: Maximum number of iterations (default 100). @@ -33,7 +34,7 @@ def brent_method( A float value approximating the root. Raises: - ValueError: If the root is not bracketed in [lower, upper]. + ValueError: If the root is not bracketed in [lower_bound, upper_bound]. Examples: >>> brent_method(lambda x: x**3 - 1, -5, 5) @@ -47,66 +48,73 @@ def brent_method( ... ValueError: Root is not bracketed in the interval [4, 1000]. """ - fa = function(lower) - fb = function(upper) - if fa * fb >= 0: - raise ValueError(f"Root is not bracketed in the interval [{lower}, {upper}].") - - if abs(fa) < abs(fb): - lower, upper = upper, lower - fa, fb = fb, fa - - c = lower - fc = fa - d = upper - lower - mflag = True + function_lower = function(lower_bound) + function_upper = function(upper_bound) + if function_lower * function_upper >= 0: + error_message = ( + "Root is not bracketed in the interval " + f"[{lower_bound}, {upper_bound}]." + ) + raise ValueError(error_message) + + if abs(function_lower) < abs(function_upper): + lower_bound, upper_bound = upper_bound, lower_bound + function_lower, function_upper = function_upper, function_lower + + previous_bound = lower_bound + function_previous = function_lower + previous_step = upper_bound - lower_bound + bisect_flag = True for _ in range(max_iterations): - if fb == 0: - return upper - if fc not in {fa, fb}: + if function_upper == 0: + return upper_bound + if function_previous not in {function_lower, function_upper}: # Inverse quadratic interpolation s = ( - lower * fb * fc / ((fa - fb) * (fa - fc)) - + upper * fa * fc / ((fb - fa) * (fb - fc)) - + c * fa * fb / ((fc - fa) * (fc - fb)) + lower_bound * function_upper * function_previous + / ((function_lower - function_upper) * (function_lower - function_previous)) + + upper_bound * function_lower * function_previous + / ((function_upper - function_lower) * (function_upper - function_previous)) + + previous_bound * function_lower * function_upper + / ((function_previous - function_lower) * (function_previous - function_upper)) ) else: # Secant method - s = upper - fb * (upper - lower) / (fb - fa) + s = upper_bound - function_upper * (upper_bound - lower_bound) / (function_upper - function_lower) conditions = [ - not ((3 * lower + upper) / 4 < s < upper if upper > lower else upper < s < (3 * lower + upper) / 4), - mflag and abs(s - upper) >= abs(upper - c) / 2, - not mflag and abs(s - upper) >= abs(c - d) / 2, - mflag and abs(upper - c) < tolerance, - not mflag and abs(c - d) < tolerance, + not ((3 * lower_bound + upper_bound) / 4 < s < upper_bound if upper_bound > lower_bound else upper_bound < s < (3 * lower_bound + upper_bound) / 4), + bisect_flag and abs(s - upper_bound) >= abs(upper_bound - previous_bound) / 2, + not bisect_flag and abs(s - upper_bound) >= abs(previous_bound - previous_step) / 2, + bisect_flag and abs(upper_bound - previous_bound) < tolerance, + not bisect_flag and abs(previous_bound - previous_step) < tolerance, ] if any(conditions): - s = (lower + upper) / 2 - mflag = True + s = (lower_bound + upper_bound) / 2 + bisect_flag = True else: - mflag = False + bisect_flag = False - fs = function(s) - d, c = c, upper - fc = fb + function_s = function(s) + previous_step, previous_bound = previous_bound, upper_bound + function_previous = function_upper - if fa * fs < 0: - upper = s - fb = fs + if function_lower * function_s < 0: + upper_bound = s + function_upper = function_s else: - lower = s - fa = fs + lower_bound = s + function_lower = function_s - if abs(fa) < abs(fb): - lower, upper = upper, lower - fa, fb = fb, fa + if abs(function_lower) < abs(function_upper): + lower_bound, upper_bound = upper_bound, lower_bound + function_lower, function_upper = function_upper, function_lower - if abs(upper - lower) < tolerance or fb == 0: - return upper + if abs(upper_bound - lower_bound) < tolerance or function_upper == 0: + return upper_bound - return upper + return upper_bound if __name__ == "__main__": From 804b9af35ebfc06717d66f222a3981347657bf7a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 05:21:33 +0000 Subject: [PATCH 7/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/numerical_analysis/brents_method.py | 50 +++++++++++++++++------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/maths/numerical_analysis/brents_method.py b/maths/numerical_analysis/brents_method.py index 0f6fde51c268..04eddfaca2a9 100644 --- a/maths/numerical_analysis/brents_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -13,6 +13,7 @@ from collections.abc import Callable + def brent_method( function: Callable[[float], float], lower_bound: float, @@ -52,8 +53,7 @@ def brent_method( function_upper = function(upper_bound) if function_lower * function_upper >= 0: error_message = ( - "Root is not bracketed in the interval " - f"[{lower_bound}, {upper_bound}]." + f"Root is not bracketed in the interval [{lower_bound}, {upper_bound}]." ) raise ValueError(error_message) @@ -72,21 +72,44 @@ def brent_method( if function_previous not in {function_lower, function_upper}: # Inverse quadratic interpolation s = ( - lower_bound * function_upper * function_previous - / ((function_lower - function_upper) * (function_lower - function_previous)) - + upper_bound * function_lower * function_previous - / ((function_upper - function_lower) * (function_upper - function_previous)) - + previous_bound * function_lower * function_upper - / ((function_previous - function_lower) * (function_previous - function_upper)) + lower_bound + * function_upper + * function_previous + / ( + (function_lower - function_upper) + * (function_lower - function_previous) + ) + + upper_bound + * function_lower + * function_previous + / ( + (function_upper - function_lower) + * (function_upper - function_previous) + ) + + previous_bound + * function_lower + * function_upper + / ( + (function_previous - function_lower) + * (function_previous - function_upper) + ) ) else: # Secant method - s = upper_bound - function_upper * (upper_bound - lower_bound) / (function_upper - function_lower) + s = upper_bound - function_upper * (upper_bound - lower_bound) / ( + function_upper - function_lower + ) conditions = [ - not ((3 * lower_bound + upper_bound) / 4 < s < upper_bound if upper_bound > lower_bound else upper_bound < s < (3 * lower_bound + upper_bound) / 4), - bisect_flag and abs(s - upper_bound) >= abs(upper_bound - previous_bound) / 2, - not bisect_flag and abs(s - upper_bound) >= abs(previous_bound - previous_step) / 2, + not ( + (3 * lower_bound + upper_bound) / 4 < s < upper_bound + if upper_bound > lower_bound + else upper_bound < s < (3 * lower_bound + upper_bound) / 4 + ), + bisect_flag + and abs(s - upper_bound) >= abs(upper_bound - previous_bound) / 2, + not bisect_flag + and abs(s - upper_bound) >= abs(previous_bound - previous_step) / 2, bisect_flag and abs(upper_bound - previous_bound) < tolerance, not bisect_flag and abs(previous_bound - previous_step) < tolerance, ] @@ -119,4 +142,5 @@ def brent_method( if __name__ == "__main__": import doctest - doctest.testmod() \ No newline at end of file + + doctest.testmod() From 3fad6df3652dea8907082880909606741ec25b34 Mon Sep 17 00:00:00 2001 From: Dibbu-cell Date: Thu, 2 Oct 2025 11:13:16 +0530 Subject: [PATCH 8/8] maths/numerical_analysis/brents_method.py --- maths/numerical_analysis/brents_method.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/maths/numerical_analysis/brents_method.py b/maths/numerical_analysis/brents_method.py index 0f6fde51c268..b7348929b1a0 100644 --- a/maths/numerical_analysis/brents_method.py +++ b/maths/numerical_analysis/brents_method.py @@ -3,7 +3,9 @@ Find a root of a function in a bracketing interval using Brent's method. -Brent's method combines bisection, secant, and inverse quadratic interpolation to efficiently and robustly find a root of a continuous function. It is guaranteed to converge as long as the root is bracketed. +Brent's method combines bisection, secant, and inverse quadratic interpolation +to efficiently and robustly find a root of a continuous function. It is +guaranteed to converge as long as the root is bracketed. See: https://en.wikipedia.org/wiki/Brent%27s_method @@ -37,11 +39,11 @@ def brent_method( ValueError: If the root is not bracketed in [lower_bound, upper_bound]. Examples: - >>> brent_method(lambda x: x**3 - 1, -5, 5) + >>> round(brent_method(lambda x: x**3 - 1, -5, 5), 6) 1.0 - >>> brent_method(lambda x: x**2 - 4*x + 3, 0, 2) + >>> round(brent_method(lambda x: x**2 - 4*x + 3, 0, 2), 6) 1.0 - >>> brent_method(lambda x: x**2 - 4*x + 3, 2, 4) + >>> round(brent_method(lambda x: x**2 - 4*x + 3, 2, 4), 6) 3.0 >>> brent_method(lambda x: x**2 - 4*x + 3, 4, 1000) Traceback (most recent call last): @@ -68,7 +70,7 @@ def brent_method( for _ in range(max_iterations): if function_upper == 0: - return upper_bound + return round(upper_bound, 12) if function_previous not in {function_lower, function_upper}: # Inverse quadratic interpolation s = ( @@ -112,9 +114,9 @@ def brent_method( function_lower, function_upper = function_upper, function_lower if abs(upper_bound - lower_bound) < tolerance or function_upper == 0: - return upper_bound + return round(upper_bound, 12) - return upper_bound + return round(upper_bound, 12) if __name__ == "__main__":