liblbfgs/
math.rs

1//! Backend for lbfgs vector operations
2
3// trait
4
5// [[file:~/Workspace/Programming/rust-libs/lbfgs/lbfgs.note::*trait][trait:1]]
6/// Abstracting lbfgs required math operations
7pub trait LbfgsMath<T> {
8    /// y += c*x
9    fn vecadd(&mut self, x: &[T], c: T);
10
11    /// vector dot product
12    /// s = x.dot(y)
13    fn vecdot(&self, other: &[T]) -> f64;
14
15    /// y = z
16    fn veccpy(&mut self, x: &[T]);
17
18    /// y = -x
19    fn vecncpy(&mut self, x: &[T]);
20
21    /// z = x - y
22    fn vecdiff(&mut self, x: &[T], y: &[T]);
23
24    /// y *= c
25    fn vecscale(&mut self, c: T);
26
27    /// ||x||
28    fn vec2norm(&self) -> T;
29
30    /// 1 / ||x||
31    fn vec2norminv(&self) -> T;
32}
33
34impl LbfgsMath<f64> for [f64] {
35    /// y += c*x
36    fn vecadd(&mut self, x: &[f64], c: f64) {
37        for (y, x) in self.iter_mut().zip(x) {
38            *y += c * x;
39        }
40    }
41
42    /// s = y.dot(x)
43    fn vecdot(&self, other: &[f64]) -> f64 {
44        self.iter().zip(other).map(|(x, y)| x * y).sum()
45    }
46
47    /// y *= c
48    fn vecscale(&mut self, c: f64) {
49        for y in self.iter_mut() {
50            *y *= c;
51        }
52    }
53
54    /// y = x
55    fn veccpy(&mut self, x: &[f64]) {
56        for (v, x) in self.iter_mut().zip(x) {
57            *v = *x;
58        }
59    }
60
61    /// y = -x
62    fn vecncpy(&mut self, x: &[f64]) {
63        for (v, x) in self.iter_mut().zip(x) {
64            *v = -x;
65        }
66    }
67
68    /// z = x - y
69    fn vecdiff(&mut self, x: &[f64], y: &[f64]) {
70        for ((z, x), y) in self.iter_mut().zip(x).zip(y) {
71            *z = x - y;
72        }
73    }
74
75    /// ||x||
76    fn vec2norm(&self) -> f64 {
77        let n2 = self.vecdot(&self);
78        n2.sqrt()
79    }
80
81    /// 1/||x||
82    fn vec2norminv(&self) -> f64 {
83        1.0 / self.vec2norm()
84    }
85}
86
87#[test]
88fn test_lbfgs_math() {
89    // vector scaled add
90    let x = [1.0, 1.0, 1.0];
91    let c = 2.;
92
93    let mut y = [1.0, 2.0, 3.0];
94    y.vecadd(&x, c);
95
96    assert_eq!(3.0, y[0]);
97    assert_eq!(4.0, y[1]);
98    assert_eq!(5.0, y[2]);
99
100    // vector dot
101    let v = y.vecdot(&x);
102    assert_eq!(12.0, v);
103
104    // vector scale
105    y.vecscale(2.0);
106    assert_eq!(6.0, y[0]);
107    assert_eq!(8.0, y[1]);
108    assert_eq!(10.0, y[2]);
109
110    // vector diff
111    let mut z = y.clone();
112    z.vecdiff(&x, &y);
113    assert_eq!(-5.0, z[0]);
114    assert_eq!(-7.0, z[1]);
115    assert_eq!(-9.0, z[2]);
116
117    // vector copy
118    y.veccpy(&x);
119
120    // y = -x
121    y.vecncpy(&x);
122    assert_eq!(-1.0, y[0]);
123    assert_eq!(-1.0, y[1]);
124    assert_eq!(-1.0, y[2]);
125}
126// trait:1 ends here