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中使用

MIT 许可证

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

无运行时依赖