discorec 0.3.0

Recommendations for Rust using collaborative filtering
Documentation
use std::iter::Zip;
use std::slice::{ChunksExact, ChunksExactMut, Iter};

/// A dense matrix.
pub struct DenseMatrix {
    pub(crate) cols: usize,
    data: Vec<f32>,
}

impl DenseMatrix {
    pub fn new(rows: usize, cols: usize) -> Self {
        let data = vec![0.0; rows * cols];
        Self { cols, data }
    }

    pub fn rows(&self) -> ChunksExact<'_, f32> {
        self.data.chunks_exact(self.cols)
    }

    pub fn rows_mut(&mut self) -> ChunksExactMut<'_, f32> {
        self.data.chunks_exact_mut(self.cols)
    }

    pub fn row(&self, i: usize) -> &[f32] {
        let idx = i * self.cols;
        &self.data[idx..(idx + self.cols)]
    }

    pub fn row_mut(&mut self, i: usize) -> &mut [f32] {
        let idx = i * self.cols;
        &mut self.data[idx..(idx + self.cols)]
    }

    pub fn dot(&self, x: &[f32]) -> Vec<f32> {
        self.rows()
            .map(|row| row.iter().zip(x).map(|(ri, xi)| ri * xi).sum())
            .collect()
    }
}

/// A coordinate list (COO) matrix.
pub struct CooMatrix {
    // separate vectors to avoid padding
    row_indices: Vec<usize>,
    col_indices: Vec<usize>,
    values: Vec<f32>,
}

impl CooMatrix {
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            row_indices: Vec::with_capacity(capacity),
            col_indices: Vec::with_capacity(capacity),
            values: Vec::with_capacity(capacity),
        }
    }

    pub fn push(&mut self, row_index: usize, col_index: usize, value: f32) {
        self.row_indices.push(row_index);
        self.col_indices.push(col_index);
        self.values.push(value);
    }

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

    pub fn get(&self, i: usize) -> (usize, usize, f32) {
        (self.row_indices[i], self.col_indices[i], self.values[i])
    }
}

impl<'a> IntoIterator for &'a CooMatrix {
    type Item = ((&'a usize, &'a usize), &'a f32);
    type IntoIter = Zip<Zip<Iter<'a, usize>, Iter<'a, usize>>, Iter<'a, f32>>;

    fn into_iter(self) -> Self::IntoIter {
        self.row_indices
            .iter()
            .zip(self.col_indices.iter())
            .zip(self.values.iter())
    }
}

/// A list of lists (LIL) matrix.
pub struct LilMatrix {
    row_list: Vec<Vec<(usize, f32)>>,
}

impl LilMatrix {
    pub fn new() -> Self {
        Self {
            row_list: Vec::new(),
        }
    }

    pub fn push(&mut self, row_index: usize, col_index: usize, value: f32) {
        if row_index == self.row_list.len() {
            self.row_list.push(Vec::new());
        }
        self.row_list[row_index].push((col_index, value));
    }
}

impl<'a> IntoIterator for &'a LilMatrix {
    type Item = &'a Vec<(usize, f32)>;
    type IntoIter = Iter<'a, Vec<(usize, f32)>>;

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