9个版本 (破坏性)
新版本 0.7.1 | 2024年8月23日 |
---|---|
0.7.0 | 2024年8月23日 |
0.6.0 | 2024年8月17日 |
0.5.0 | 2024年8月15日 |
0.1.0 | 2024年7月13日 |
#240 in 数学
每月下载 873次
在 4 个Crates中使用了(直接使用2个)
1MB
1K SLoC
Rust中函数最小化,简化版
ganesh
(/ɡəˈneɪʃ/),以印度智慧之神的名字命名,提供了一些常见的最小化算法以及一个简单、基于特质的接口来创建自己的扩展。这个crate旨在尽可能简单。用户需要在某些结构体上实现Function
特质,该特质将接受一个参数向量并返回一个单值Result
($f(\mathbb{R}^n) \to \mathbb{R}
$)。用户可以选择提供一个梯度函数以加快某些算法的速度,但提供了一个默认的中心有限差分实现,以便所有算法都能直接使用。
[!警告] 这个crate仍处于早期开发阶段,API不稳定。在1.0.0版本发布之前(希望之后不会太多),它可能会(并可能确实会)受到破坏性更改。
目录
关键特性
- 简单但强大的特质导向库,试图遵循Unix哲学“做一件事,做好一件事”。
- 泛型以允许在提供的算法中使用不同的数值类型。
- 简单易用、默认设置合理的算法。
- 特质使得开发未来的算法简单且一致。
快速入门
此crate在test_functions
模块中提供了一些常见的测试函数。考虑以下Rosenbrock函数的实现
use std::convert::Infallible;
use ganesh::prelude::*;
pub struct Rosenbrock {
pub n: usize,
}
impl Function<f64, (), Infallible> for Rosenbrock {
fn evaluate(&self, x: &[f64], _user_data: &mut ()) -> Result<f64, Infallible> {
Ok((0..(self.n - 1))
.map(|i| 100.0 * (x[i + 1] - x[i].powi(2)).powi(2) + (1.0 - x[i]).powi(2))
.sum())
}
}
为了最小化此函数,我们可以考虑使用Nelder-Mead算法
use ganesh::prelude::*;
use ganesh::algorithms::NelderMead;
let problem = Rosenbrock { n: 2 };
let nm = NelderMead::default();
let mut m = Minimizer::new(nm, 2);
let x0 = &[2.0, 2.0];
m.minimize(&problem, x0, &mut ()).unwrap();
println!("{}", m.status);
这将输出
MSG: term_f = STDDEV
X: [0.9999999946231828, 0.9999999884539057]
F(X): 0.00000000000000009170942877687133
N_EVALS: 160
CONVERGED: true
边界
ganesh
中的所有最小化器都拥有一个功能,允许通常在无界参数空间中运行的算法只在边界框内返回结果。这是通过参数变换实现的,与LMFIT
和MINUIT
使用的相同。当用户在边界内输入参数时,无界算法可以将这些值转换为一系列无界的“内部”参数。然而,在调用函数时,这些内部参数通过以下变换重新转换为有界的“外部”参数:
上界和下界
x_\text{int} = \arcsin\left(2\frac{x_\text{ext} - x_\text{min}}{x_\text{max} - x_\text{min}} - 1\right)
x_\text{ext} = x_\text{min} + \left(\sin(x_\text{int}) + 1\right)\frac{x_\text{max} - x_\text{min}}{2}
仅上界
x_\text{int} = \sqrt{(x_\text{max} - x_\text{ext} + 1)^2 - 1}
x_\text{ext} = x_\text{max} + 1 - \sqrt{x_\text{int}^2 + 1}
仅下界
x_\text{int} = \sqrt{(x_\text{ext} - x_\text{min} + 1)^2 - 1}
x_\text{ext} = x_\text{min} - 1 + \sqrt{x_\text{int}^2 + 1}
如LMFIT
和MINUIT
的文档所述,应谨慎使用这些边界。它们将线性问题转化为非线性问题,可能会干扰误差传播,甚至影响拟合收敛,更不用说增加函数复杂性了。如果需要输出协方差矩阵的方法,在有限制的情况下需要调整,而MINUIT
建议在没有边界的最小值附近进行第二次拟合,以确保正确的误差传播。
未来计划
- 最终,我打算实现BGFS及其变体、MCMC算法以及一些更现代的无梯度优化技术。
- 我可能错过了许多优化和算法扩展,因为我只是想首先让它运行起来。
- 测试套件
依赖项
~3MB
~57K SLoC