4个版本 (2个破坏性更新)
0.3.0 | 2023年11月29日 |
---|---|
0.2.0 | 2021年3月31日 |
0.1.1 | 2021年2月26日 |
0.1.0 | 2021年2月19日 |
#304 在 算法
在 2 crate中使用
92KB
1.5K SLoC
rmpfit
非常简单的CMPFIT库纯Rust实现:用于解决最小二乘问题的Levenberg-Marquardt技术。
代码主要直接从CMPFIT复制,几乎未作修改。原始CMPFIT测试(线性(自由参数)、二次(自由和固定参数)和高斯(自由和固定参数)函数)被复制并通过。
仅进行了一些明显的Rust特定优化
- 移除
goto
(fuf)。 - 标准Rust Result作为结果。
- 将几个循环打包以帮助编译器优化代码(实际上并未进行性能测试)。
- 使用trait
MPFitter
调用用户代码。 - 如果可能,使用
bool
类型。
优点
- 纯Rust。
- 无外部依赖(仅assert_approx_eq用于测试)。
- 内部雅可比计算。
缺点
- 尚未实现边、解析或用户提供的导数。
使用示例
用户应为其结构实现trait MPFitter
use rmpfit::{MPFitter, MPResult, mpfit};
struct Linear {
x: Vec<f64>,
y: Vec<f64>,
ye: Vec<f64>,
}
impl MPFitter for Linear {
fn eval(&self, params: &[f64], deviates: &mut [f64]) -> MPResult<()> {
for (((d, x), y), ye) in deviates
.iter_mut()
.zip(self.x.iter())
.zip(self.y.iter())
.zip(self.ye.iter())
{
let f = params[0] + params[1] * *x;
*d = (*y - f) / *ye;
}
Ok(())
}
fn number_of_points(&self) -> usize {
self.x.len()
}
}
fn main() {
let l = Linear {
x: vec![
-1.7237128E+00,
1.8712276E+00,
-9.6608055E-01,
-2.8394297E-01,
1.3416969E+00,
1.3757038E+00,
-1.3703436E+00,
4.2581975E-02,
-1.4970151E-01,
8.2065094E-01,
],
y: vec![
1.9000429E-01,
6.5807428E+00,
1.4582725E+00,
2.7270851E+00,
5.5969253E+00,
5.6249280E+00,
0.787615,
3.2599759E+00,
2.9771762E+00,
4.5936475E+00,
],
ye: vec![0.07; 10],
};
// initializing input parameters
let mut init = [1., 1.];
let res = l.mpfit(&mut init, None, &Default::default()).unwrap();
// actual 3.2
assert_approx_eq!(init[0], 3.20996572);
assert_approx_eq!(status.xerror[0], 0.02221018);
// actual 1.78
assert_approx_eq!(init[1], 1.77095420);
assert_approx_eq!(status.xerror[1], 0.01893756);
}
然后 init
将包含拟合函数的优化参数。如果用户函数无法计算残差,它应返回MPError::Eval
。