pub trait LbfgsMath<T> {
fn vecadd(&mut self, x: &[T], c: T);
fn vecdot(&self, other: &[T]) -> f64;
fn veccpy(&mut self, x: &[T]);
fn vecncpy(&mut self, x: &[T]);
fn vecdiff(&mut self, x: &[T], y: &[T]);
fn vecscale(&mut self, c: T);
fn vec2norm(&self) -> T;
fn vec2norminv(&self) -> T;
}
impl LbfgsMath<f64> for [f64] {
fn vecadd(&mut self, x: &[f64], c: f64) {
for (y, x) in self.iter_mut().zip(x) {
*y += c * x;
}
}
fn vecdot(&self, other: &[f64]) -> f64 {
self.iter().zip(other).map(|(x, y)| x * y).sum()
}
fn vecscale(&mut self, c: f64) {
for y in self.iter_mut() {
*y *= c;
}
}
fn veccpy(&mut self, x: &[f64]) {
for (v, x) in self.iter_mut().zip(x) {
*v = *x;
}
}
fn vecncpy(&mut self, x: &[f64]) {
for (v, x) in self.iter_mut().zip(x) {
*v = -x;
}
}
fn vecdiff(&mut self, x: &[f64], y: &[f64]) {
for ((z, x), y) in self.iter_mut().zip(x).zip(y) {
*z = x - y;
}
}
fn vec2norm(&self) -> f64 {
let n2 = self.vecdot(&self);
n2.sqrt()
}
fn vec2norminv(&self) -> f64 {
1.0 / self.vec2norm()
}
}
#[test]
fn test_lbfgs_math() {
let x = [1.0, 1.0, 1.0];
let c = 2.;
let mut y = [1.0, 2.0, 3.0];
y.vecadd(&x, c);
assert_eq!(3.0, y[0]);
assert_eq!(4.0, y[1]);
assert_eq!(5.0, y[2]);
let v = y.vecdot(&x);
assert_eq!(12.0, v);
y.vecscale(2.0);
assert_eq!(6.0, y[0]);
assert_eq!(8.0, y[1]);
assert_eq!(10.0, y[2]);
let mut z = y.clone();
z.vecdiff(&x, &y);
assert_eq!(-5.0, z[0]);
assert_eq!(-7.0, z[1]);
assert_eq!(-9.0, z[2]);
y.veccpy(&x);
y.vecncpy(&x);
assert_eq!(-1.0, y[0]);
assert_eq!(-1.0, y[1]);
assert_eq!(-1.0, y[2]);
}