openalgebra 0.0.1

Rust linear algebra library for OpenCL
use ::af;

use super::{Vector};
use ::norm::{Norm};

impl Vector {
    pub fn new<T>(data: T) -> Vector where T: Into<Vec<f64>> {
        let data: Vec<f64> = data.into();
        let size = data.len();
        let backend = af::Array::new(&data, af::Dim4::new(&[size as u64, 1, 1, 1]));
        Vector {size, backend, data}
    }

    pub fn from_fn<F>(size: usize, f: F) -> Vector where F: Fn(f64) -> f64 {
        let data: Vec<f64> = (0..size).into_iter().map(|x| f(x as f64)).collect();
        let backend = af::Array::new(&data, af::Dim4::new(&[size as u64,1, 1, 1]));
        Vector {size, backend, data}
    }

    pub fn zeros(size: usize) -> Vector {
        let data = vec![0f64; size];
        Vector::new(data)
    }

    pub fn ones(size: usize) -> Vector {
        let data = vec![1f64; size];
        Vector::new(data)
    }

    pub fn size(&self) -> usize {
        self.size
    }

    pub fn data(&self) -> Vec<f64> {
        self.data.clone()
    }

    pub fn into_vec(self) -> Vec<f64> {
        self.data
    }

    pub fn get(&self, index: usize) -> Option<f64> {
        self.data.get(index).cloned()
    }

    pub fn apply<F>(self, f: F) -> Vector where F: Fn(f64) -> f64 {
        let mut data = Vec::with_capacity(self.size());
        for val in self {
            data.push(f(val));
        }
        Vector::new(data)
    }

    pub fn apply_self<F>(&mut self, f: F) where F: Fn(f64) -> f64 {
        let mut data = self.data();
        for val in &mut data {
            *val = f(*val);
        }
        *self = Vector::new(data);
    }

    pub fn max(&self) -> f64 {
        af::max_all(&self.backend).0
    }

    pub fn min(&self) -> f64 {
        af::min_all(&self.backend).0
    }

    pub fn select(&self, idxs: &[usize]) -> Result<Vector, String> {
        let mut data: Vec<f64> = Vec::with_capacity(idxs.len());
        for idx in idxs {
            let o = self.get(*idx);
            match o {
                Some(x) => data.push(x),
                None => return Err(format!("Tried to access index: {} but length was: {}", idx, self.size()))
            }
        }
        Ok(Vector::new(data))
    }

    pub fn dot(&self, rhs: &Vector) -> Result<f64, String> {
        if let Err(s) = Vector::check_size(self, rhs) {
            return Err(s);
        }
        let result = af::dot(&self.backend, &rhs.backend, af::MatProp::NONE, af::MatProp::NONE);
        // Only one element, easy way to grab it
        Ok(af::max_all(&result).0)
    }

    pub fn sum(&self) -> f64 {
        af::sum_all(&self.backend).0
    }

    pub fn norm(&self, norm_type: Norm) -> f64 {
        match norm_type {
            Norm::Taxicab => af::norm(&self.backend, af::NormType::VECTOR_1, 0.0, 0.0),
            Norm::Euclidean => af::norm(&self.backend, af::NormType::VECTOR_2, 0.0, 0.0),
            Norm::Infinity => af::norm(&self.backend, af::NormType::VECTOR_INF, 0.0, 0.0),
            Norm::LP(p) => af::norm(&self.backend, af::NormType::VECTOR_P, p, 0.0),
        }
    }

    pub fn metric(&self, rhs: &Vector) -> Result<f64, String> {
        if let Err(s) = Vector::check_size(self, rhs) {
            return Err(s);
        }
        let diff: Vector = Vector::from(&self.backend - &rhs.backend);
        Ok(diff.norm(Norm::Euclidean))
    }

    pub fn mean(&self) -> f64 {
        af::mean_all(&self.backend).0
    }

    pub fn variance(&self) -> f64 {
        let mean = self.mean();
        let mut var = 0f64;
        for x in self {
            var += (x - mean).powf(2.0);
        }
        var
    }

    fn check_size(lhs: &Vector, rhs: &Vector) -> Result<(), String> {
        if lhs.size() == rhs.size() {
            Ok(())
        } else {
            Err(format!("The two Vectors must have the same size. The left Vector has size: {} and the right Vector has size: {}",
            lhs.size(), rhs.size()))
        }
    }
}

use std::fmt;

impl fmt::Display for Vector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[");
        for (i, v) in self.data().into_iter().enumerate() {
            write!(f, "{}", v);
            if i != self.size()-1 {
                write!(f, ", ");
            }
        }
        write!(f, "]")
    }
}

impl<'a> From<&'a Vector> for Vector {
    fn from(vector: &Vector) -> Vector {
        vector.clone()
    }
}

impl From<af::Array> for Vector {
    fn from(array: af::Array) -> Vector {
        let dims = array.dims();
        let max = ::std::usize::MAX;
        assert!(dims.get()[0] < max as u64, "Internal array representation contained more than `usize` rows: {} > {}", dims.get()[0], max);
        assert!(dims.get()[1] == 1, "Internal array representation contained data in 2D space");
        assert!(dims.get()[2] == 1, "Internal array representation contained data in 3D space");
        assert!(dims.get()[3] == 1, "Internal array representation contained data in 4D space");
        let size: u64 = array.dims().get().into_iter().fold(1, |acc, &d| acc * d);
        let mut data: Vec<f64> = vec![0.; size as usize];
        array.host(&mut data);
        Vector::new(data)
    }
}

impl From<f64> for Vector {
    fn from(value: f64) -> Vector {
        Vector::new(vec![value])
    }
}

impl<'a> From<&'a f64> for Vector {
    fn from(value: &f64) -> Vector {
        Vector::new(vec![*value])
    }
}

use std::iter::{IntoIterator};

impl IntoIterator for Vector {
    type Item = f64;
    type IntoIter = ::std::vec::IntoIter<f64>;

    fn into_iter(self) -> Self::IntoIter {
        self.data().into_iter()
    }
}

impl<'a> IntoIterator for &'a Vector {
    type Item = f64;
    type IntoIter = ::std::vec::IntoIter<f64>;

    fn into_iter(self) -> Self::IntoIter {
        self.data().into_iter()
    }
}

use std::cmp::{PartialEq, Eq};

impl PartialEq for Vector {
    fn eq(&self, other: &Vector) -> bool {
        self.size() == other.size() && self.data == other.data
    }
}

impl Eq for Vector {}