Skip to content

Commit 7e4d525

Browse files
committed
Ver 0.37.5
- More generic root finding macros
2 parents e4a811a + 7ba722d commit 7e4d525

File tree

4 files changed

+66
-36
lines changed

4 files changed

+66
-36
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "peroxide"
3-
version = "0.37.4"
3+
version = "0.37.5"
44
authors = ["axect <axect@outlook.kr>"]
55
edition = "2018"
66
description = "Rust comprehensive scientific computation library contains linear algebra, numerical analysis, statistics and machine learning tools with farmiliar syntax"

RELEASES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Release 0.37.5 (2024-06-10)
2+
3+
- More generic & stable root finding macros (except `Newton`)
4+
15
# Release 0.37.4 (2024-05-17)
26

37
- Public ODE Integrator fields

examples/root_macro_test.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,33 @@ use peroxide::fuga::*;
44
use anyhow::Result;
55

66
fn main() -> Result<()> {
7-
let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6);
8-
let root_newton = newton!(f, 0.0, 100, 1e-6);
9-
let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6);
10-
let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6);
7+
let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6)?;
8+
let root_newton = newton!(f, 0.0, 100, 1e-6)?;
9+
let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6)?;
10+
let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6)?;
11+
12+
let closure_bisect = bisection!(|x: f64| (x - 1f64).powi(3), (0.0, 2.0), 100, 1e-6)?;
13+
let closure_false_pos = false_position!(|x: f64| (x - 1f64).powi(3), (0.0, 2.0), 100, 1e-6)?;
14+
let closure_secant = secant!(|x: f64| (x - 1f64).powi(3), (0.0, 2.0), 100, 1e-6)?;
1115

1216
println!("root_bisect: {}", root_bisect);
1317
println!("root_newton: {}", root_newton);
1418
println!("root_false_pos: {}", root_false_pos);
1519
println!("root_secant: {}", root_secant);
1620

21+
println!("closure_bisect: {}", closure_bisect);
22+
println!("closure_false_pos: {}", closure_false_pos);
23+
println!("closure_secant: {}", closure_secant);
24+
1725
assert!(f(root_bisect).abs() < 1e-6);
1826
assert!(f(root_newton).abs() < 1e-6);
1927
assert!(f(root_false_pos).abs() < 1e-6);
2028
assert!(f(root_secant).abs() < 1e-6);
2129

30+
assert!(f(closure_bisect).abs() < 1e-6);
31+
assert!(f(closure_false_pos).abs() < 1e-6);
32+
assert!(f(closure_secant).abs() < 1e-6);
33+
2234
Ok(())
2335
}
2436

src/numerical/root.rs

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@
6868
//! use anyhow::Result;
6969
//!
7070
//! fn main() -> Result<()> {
71-
//! let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6);
72-
//! let root_newton = newton!(f, 0.0, 100, 1e-6);
73-
//! let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6);
74-
//! let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6);
71+
//! let root_bisect = bisection!(f, (0.0, 2.0), 100, 1e-6)?;
72+
//! let root_newton = newton!(f, 0.0, 100, 1e-6)?;
73+
//! let root_false_pos = false_position!(f, (0.0, 2.0), 100, 1e-6)?;
74+
//! let root_secant = secant!(f, (0.0, 2.0), 100, 1e-6)?;
7575
//!
7676
//! println!("root_bisect: {}", root_bisect);
7777
//! println!("root_newton: {}", root_newton);
@@ -225,29 +225,33 @@ use crate::util::non_macro::zeros;
225225
///
226226
/// # Arguments
227227
///
228-
/// - `f`: `fn(f64) -> f64`
228+
/// - `f`: `Fn(f64) -> f64` (allow closure)
229229
/// - `(a, b)`: `(f64, f64)`
230230
/// - `max_iter`: `usize`
231231
/// - `tol`: `f64`
232232
#[macro_export]
233233
macro_rules! bisection {
234-
($f:ident, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
235-
struct BisectionProblem;
234+
($f:expr, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
235+
struct BisectionProblem<F: Fn(f64) -> f64> {
236+
f: F,
237+
};
236238

237-
impl RootFindingProblem<1, 1, (f64, f64)> for BisectionProblem {
239+
impl<F: Fn(f64) -> f64> RootFindingProblem<1, 1, (f64, f64)> for BisectionProblem<F> {
238240
fn initial_guess(&self) -> (f64, f64) {
239241
($a, $b)
240242
}
241243

242244
fn function(&self, x: [f64; 1]) -> Result<[f64; 1]> {
243-
Ok([$f(x[0])])
245+
Ok([(self.f)(x[0])])
244246
}
245247
}
246248

247-
let problem = BisectionProblem;
249+
let problem = BisectionProblem { f: $f };
248250
let bisection = BisectionMethod { max_iter: $max_iter, tol: $tol };
249-
let root = bisection.find(&problem)?;
250-
root[0]
251+
match bisection.find(&problem) {
252+
Ok(root) => Ok(root[0]),
253+
Err(e) => Err(e),
254+
}
251255
}}
252256
}
253257

@@ -268,7 +272,7 @@ macro_rules! bisection {
268272
///
269273
/// # Arguments
270274
///
271-
/// - `f`: `fn(f64) -> f64`
275+
/// - `f`: `fn(f64) -> f64` (not allow closure)
272276
/// - `x`: `f64`
273277
/// - `max_iter`: `usize`
274278
/// - `tol`: `f64`
@@ -297,68 +301,78 @@ macro_rules! newton {
297301

298302
let problem = NewtonProblem;
299303
let newton = NewtonMethod { max_iter: $max_iter, tol: $tol };
300-
let root = newton.find(&problem)?;
301-
root[0]
304+
match newton.find(&problem) {
305+
Ok(root) => Ok(root[0]),
306+
Err(e) => Err(e),
307+
}
302308
}}
303309
}
304310

305311
/// High level macro for false position
306312
///
307313
/// # Arguments
308314
///
309-
/// - `f`: `fn(f64) -> f64`
315+
/// - `f`: `Fn(f64) -> f64` (allow closure)
310316
/// - `(a, b)`: `(f64, f64)`
311317
/// - `max_iter`: `usize`
312318
/// - `tol`: `f64`
313319
#[macro_export]
314320
macro_rules! false_position {
315-
($f:ident, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
316-
struct FalsePositionProblem;
321+
($f:expr, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
322+
struct FalsePositionProblem<F: Fn(f64) -> f64> {
323+
f: F,
324+
};
317325

318-
impl RootFindingProblem<1, 1, (f64, f64)> for FalsePositionProblem {
326+
impl<F: Fn(f64) -> f64> RootFindingProblem<1, 1, (f64, f64)> for FalsePositionProblem<F> {
319327
fn initial_guess(&self) -> (f64, f64) {
320328
($a, $b)
321329
}
322330

323331
fn function(&self, x: [f64; 1]) -> Result<[f64; 1]> {
324-
Ok([$f(x[0])])
332+
Ok([(self.f)(x[0])])
325333
}
326334
}
327335

328-
let problem = FalsePositionProblem;
336+
let problem = FalsePositionProblem { f: $f };
329337
let false_position = FalsePositionMethod { max_iter: $max_iter, tol: $tol };
330-
let root = false_position.find(&problem)?;
331-
root[0]
338+
match false_position.find(&problem) {
339+
Ok(root) => Ok(root[0]),
340+
Err(e) => Err(e),
341+
}
332342
}}
333343
}
334344

335345
/// High level macro for secant
336346
///
337347
/// # Arguments
338348
///
339-
/// - `f`: `fn(f64) -> f64`
349+
/// - `f`: `Fn(f64) -> f64` (allow closure)
340350
/// - `(a, b)`: `(f64, f64)`
341351
/// - `max_iter`: `usize`
342352
/// - `tol`: `f64`
343353
#[macro_export]
344354
macro_rules! secant {
345-
($f:ident, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
346-
struct SecantProblem;
355+
($f:expr, ($a:expr, $b:expr), $max_iter:expr, $tol:expr) => {{
356+
struct SecantProblem<F: Fn(f64) -> f64> {
357+
f: F,
358+
};
347359

348-
impl RootFindingProblem<1, 1, (f64, f64)> for SecantProblem {
360+
impl<F: Fn(f64) -> f64> RootFindingProblem<1, 1, (f64, f64)> for SecantProblem<F> {
349361
fn initial_guess(&self) -> (f64, f64) {
350362
($a, $b)
351363
}
352364

353365
fn function(&self, x: [f64; 1]) -> Result<[f64; 1]> {
354-
Ok([$f(x[0])])
366+
Ok([(self.f)(x[0])])
355367
}
356368
}
357369

358-
let problem = SecantProblem;
370+
let problem = SecantProblem { f: $f };
359371
let secant = SecantMethod { max_iter: $max_iter, tol: $tol };
360-
let root = secant.find(&problem)?;
361-
root[0]
372+
match secant.find(&problem) {
373+
Ok(root) => Ok(root[0]),
374+
Err(e) => Err(e),
375+
}
362376
}}
363377
}
364378

0 commit comments

Comments
 (0)