use std::f64;
use std::cmp;
#[derive(Debug, PartialEq, Clone)]
pub struct Vector {
data: Vec<f64>
}
#[derive(Debug, PartialEq)]
pub struct Matrix {
rows: usize,
cols: usize,
data: Vec<Vec<f64>>
}
impl Vector {
pub fn new(v: Vec<f64>) -> Vector {
Vector { data: v }
}
pub fn len(&self) -> usize { self.data.len() }
pub fn get(&self, i: usize) -> f64 { self.data[i] }
pub fn is_positive(&self) -> bool {
let has_neg = self.data.iter().any(|&item| item < 0.);
!has_neg
}
pub fn add_vector(&self, u: &Vector) -> Vector {
let data = self.data.iter().zip(&u.data).map(|(x, y)| x + y).collect();
Vector::new(data)
}
pub fn minus_log(&self) -> Vector {
Vector::new(self.data.iter().map(|i| -i.log2()).collect())
}
pub fn argmin(&self) -> usize {
let mut min_index = 0;
let mut min_value = self.data[0];
for (i,v) in self.data.iter().enumerate() {
if v < &min_value {
min_value = v.clone();
min_index = i.clone();
}
}
min_index
}
}
impl Matrix {
pub fn new(data: Vec<Vec<f64>>) -> Option<Matrix> {
if data.len() < 1 { return None }
let cols = data[0].len();
if data.iter().any(|r| r.len() != cols) { return None }
Some(Matrix { rows: data.len(), cols: cols, data: data })
}
pub fn cols(&self) -> usize { self.cols }
pub fn is_positive(&self) -> bool {
let has_neg = self.data.iter().any(|r| r.iter().any(|&item| item < 0.));
!has_neg
}
pub fn minus_log(&self) -> Matrix {
Matrix { rows: self.rows,
cols: self.cols,
data: self.data.iter().map(|r| r.iter().map(|i| -i.log2()).collect()).collect()}
}
pub fn column(&self, index: usize) -> Option<Vector> {
if index >= self.cols { return None }
let data = self.data.iter().map(|r| r[index]).collect();
Some(Vector::new(data))
}
pub fn add_to_columns(&self, v: &Vector) -> Matrix {
let n = cmp::min(self.rows, v.len());
let mut data = self.data.clone();
for i in 0..n {
for j in 0..self.cols {
data[i][j] += v.get(i)
}
}
Matrix { rows: self.rows,
cols: self.cols,
data: data}
}
pub fn min_by_column(&self) -> Vector {
let mut v = vec![f64::MAX; self.cols];
for row in &self.data {
for (i, &item) in row.iter().enumerate() {
if item < v[i] { v[i] = item}
}
}
Vector::new(v)
}
pub fn argmin_by_column(&self) -> Vec<usize> {
let mut v = vec![f64::MAX; self.cols];
let mut args = vec![0; self.cols];
for (i, ref row) in self.data.iter().enumerate() {
for (j, &item) in row.iter().enumerate() {
if item < v[j] {
v[j] = item;
args[j] = i;
}
}
}
args
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let d = vec![vec![0.75, 0.25],
vec![0.25, 0.75]];
assert!(Matrix::new(d).is_some());
}
#[test]
fn test_new_none1() {
let d = vec![];
assert!(Matrix::new(d).is_none());
}
#[test]
fn test_none2() {
let d = vec![vec![0.75, 0.25],
vec![0.25, 0.75, 1.]];
assert!(Matrix::new(d).is_none());
}
#[test]
fn test_positive() {
let mat = Matrix::new(vec![vec![0.75, 0.25],
vec![0.25, 0.75]]).unwrap();
assert!(mat.is_positive());
}
#[test]
fn test_negative() {
let mat = Matrix::new(vec![vec![0.75, 0.25],
vec![0.25, -0.75]]).unwrap();
assert!(mat.is_positive() == false);
}
#[test]
fn test_get_column() {
let mat = Matrix::new(vec![vec![1., 2.],
vec![3., 4.]]).unwrap();
let expected = Vector::new(vec![2., 4.]);
assert!(mat.column(1) == Some(expected));
}
#[test]
fn test_add_vectors() {
let v = Vector::new(vec![1., 2.]);
let u = Vector::new(vec![3., 4.]);
let expected = Vector::new(vec![4., 6.]);
assert!(v.add_vector(&u) == expected);
}
#[test]
fn test_add_to_column() {
let mat = Matrix::new(vec![vec![1., 2.],
vec![3., 4.]]).unwrap();
let v = Vector::new(vec![3., 4.]);
let expected = Matrix::new(vec![vec![4., 5.],
vec![7., 8.]]).unwrap();
assert!(mat.add_to_columns(&v) == expected);
}
#[test]
fn test_min_by_column() {
let mat = Matrix::new(vec![vec![1., 4.],
vec![3., 2.]]).unwrap();
let expected = Vector::new(vec![1., 2.]);
assert!(mat.min_by_column() == expected);
}
#[test]
fn test_argmin_by_column() {
let mat = Matrix::new(vec![vec![1., 4.],
vec![3., 2.]]).unwrap();
let expected = vec![0, 1];
assert!(mat.argmin_by_column() == expected);
}
#[test]
fn test_argmin() {
let v = Vector::new(vec![1., 4., 0.34, 12.]);
assert!(v.argmin() == 2);
}
}