Skip to content

Commit

Permalink
Ver 0.37.5
Browse files Browse the repository at this point in the history
- More generic root finding macros
  • Loading branch information
Axect committed Jun 10, 2024
2 parents e4a811a + 7ba722d commit 7e4d525
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "peroxide"
version = "0.37.4"
version = "0.37.5"
authors = ["axect <axect@outlook.kr>"]
edition = "2018"
description = "Rust comprehensive scientific computation library contains linear algebra, numerical analysis, statistics and machine learning tools with farmiliar syntax"
Expand Down
4 changes: 4 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Release 0.37.5 (2024-06-10)

- More generic & stable root finding macros (except `Newton`)

# Release 0.37.4 (2024-05-17)

- Public ODE Integrator fields
Expand Down
20 changes: 16 additions & 4 deletions examples/root_macro_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,33 @@ use peroxide::fuga::*;
use anyhow::Result;

fn main() -> Result<()> {
let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6);
let root_newton = newton!(f, 0.0, 100, 1e-6);
let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6);
let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6);
let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6)?;
let root_newton = newton!(f, 0.0, 100, 1e-6)?;
let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6)?;
let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6)?;

let closure_bisect = bisection!(|x: f64| (x - 1f64).powi(3), (0.0, 2.0), 100, 1e-6)?;
let closure_false_pos = false_position!(|x: f64| (x - 1f64).powi(3), (0.0, 2.0), 100, 1e-6)?;
let closure_secant = secant!(|x: f64| (x - 1f64).powi(3), (0.0, 2.0), 100, 1e-6)?;

println!("root_bisect: {}", root_bisect);
println!("root_newton: {}", root_newton);
println!("root_false_pos: {}", root_false_pos);
println!("root_secant: {}", root_secant);

println!("closure_bisect: {}", closure_bisect);
println!("closure_false_pos: {}", closure_false_pos);
println!("closure_secant: {}", closure_secant);

assert!(f(root_bisect).abs() < 1e-6);
assert!(f(root_newton).abs() < 1e-6);
assert!(f(root_false_pos).abs() < 1e-6);
assert!(f(root_secant).abs() < 1e-6);

assert!(f(closure_bisect).abs() < 1e-6);
assert!(f(closure_false_pos).abs() < 1e-6);
assert!(f(closure_secant).abs() < 1e-6);

Ok(())
}

Expand Down
76 changes: 45 additions & 31 deletions src/numerical/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@
//! use anyhow::Result;
//!
//! fn main() -> Result<()> {
//! let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6);
//! let root_newton = newton!(f, 0.0, 100, 1e-6);
//! let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6);
//! let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6);
//! let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6)?;
//! let root_newton = newton!(f, 0.0, 100, 1e-6)?;
//! let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6)?;
//! let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6)?;
//!
//! println!("root_bisect: {}", root_bisect);
//! println!("root_newton: {}", root_newton);
Expand Down Expand Up @@ -225,29 +225,33 @@ use crate::util::non_macro::zeros;
///
/// # Arguments
///
/// - `f`: `fn(f64) -> f64`
/// - `f`: `Fn(f64) -> f64` (allow closure)
/// - `(a, b)`: `(f64, f64)`
/// - `max_iter`: `usize`
/// - `tol`: `f64`
#[macro_export]
macro_rules! bisection {
($f:ident, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
struct BisectionProblem;
($f:expr, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
struct BisectionProblem<F: Fn(f64) -> f64> {
f: F,
};

impl RootFindingProblem<1, 1, (f64, f64)> for BisectionProblem {
impl<F: Fn(f64) -> f64> RootFindingProblem<1, 1, (f64, f64)> for BisectionProblem<F> {
fn initial_guess(&self) -> (f64, f64) {
($a, $b)
}

fn function(&self, x: [f64; 1]) -> Result<[f64; 1]> {
Ok([$f(x[0])])
Ok([(self.f)(x[0])])
}
}

let problem = BisectionProblem;
let problem = BisectionProblem { f: $f };
let bisection = BisectionMethod { max_iter: $max_iter, tol: $tol };
let root = bisection.find(&problem)?;
root[0]
match bisection.find(&problem) {
Ok(root) => Ok(root[0]),
Err(e) => Err(e),
}
}}
}

Expand All @@ -268,7 +272,7 @@ macro_rules! bisection {
///
/// # Arguments
///
/// - `f`: `fn(f64) -> f64`
/// - `f`: `fn(f64) -> f64` (not allow closure)
/// - `x`: `f64`
/// - `max_iter`: `usize`
/// - `tol`: `f64`
Expand Down Expand Up @@ -297,68 +301,78 @@ macro_rules! newton {

let problem = NewtonProblem;
let newton = NewtonMethod { max_iter: $max_iter, tol: $tol };
let root = newton.find(&problem)?;
root[0]
match newton.find(&problem) {
Ok(root) => Ok(root[0]),
Err(e) => Err(e),
}
}}
}

/// High level macro for false position
///
/// # Arguments
///
/// - `f`: `fn(f64) -> f64`
/// - `f`: `Fn(f64) -> f64` (allow closure)
/// - `(a, b)`: `(f64, f64)`
/// - `max_iter`: `usize`
/// - `tol`: `f64`
#[macro_export]
macro_rules! false_position {
($f:ident, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
struct FalsePositionProblem;
($f:expr, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
struct FalsePositionProblem<F: Fn(f64) -> f64> {
f: F,
};

impl RootFindingProblem<1, 1, (f64, f64)> for FalsePositionProblem {
impl<F: Fn(f64) -> f64> RootFindingProblem<1, 1, (f64, f64)> for FalsePositionProblem<F> {
fn initial_guess(&self) -> (f64, f64) {
($a, $b)
}

fn function(&self, x: [f64; 1]) -> Result<[f64; 1]> {
Ok([$f(x[0])])
Ok([(self.f)(x[0])])
}
}

let problem = FalsePositionProblem;
let problem = FalsePositionProblem { f: $f };
let false_position = FalsePositionMethod { max_iter: $max_iter, tol: $tol };
let root = false_position.find(&problem)?;
root[0]
match false_position.find(&problem) {
Ok(root) => Ok(root[0]),
Err(e) => Err(e),
}
}}
}

/// High level macro for secant
///
/// # Arguments
///
/// - `f`: `fn(f64) -> f64`
/// - `f`: `Fn(f64) -> f64` (allow closure)
/// - `(a, b)`: `(f64, f64)`
/// - `max_iter`: `usize`
/// - `tol`: `f64`
#[macro_export]
macro_rules! secant {
($f:ident, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
struct SecantProblem;
($f:expr, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
struct SecantProblem<F: Fn(f64) -> f64> {
f: F,
};

impl RootFindingProblem<1, 1, (f64, f64)> for SecantProblem {
impl<F: Fn(f64) -> f64> RootFindingProblem<1, 1, (f64, f64)> for SecantProblem<F> {
fn initial_guess(&self) -> (f64, f64) {
($a, $b)
}

fn function(&self, x: [f64; 1]) -> Result<[f64; 1]> {
Ok([$f(x[0])])
Ok([(self.f)(x[0])])
}
}

let problem = SecantProblem;
let problem = SecantProblem { f: $f };
let secant = SecantMethod { max_iter: $max_iter, tol: $tol };
let root = secant.find(&problem)?;
root[0]
match secant.find(&problem) {
Ok(root) => Ok(root[0]),
Err(e) => Err(e),
}
}}
}

Expand Down

0 comments on commit 7e4d525

Please sign in to comment.