opensrdk-linear-algebra 0.9.1

Standard linear algebra library using blas and lapack for OpenSRDK toolchain.
Documentation
use crate::sparse::RankIndex;
use crate::tensor::Tensor;
use crate::{sparse::SparseTensor, Number};
use rand::prelude::*;
use std::collections::HashMap;

pub trait DirectProduct<T>
where
    T: Number,
{
    fn direct_product(self) -> SparseTensor<T>;
}

impl<'a, I, T> DirectProduct<T> for I
where
    I: Iterator<Item = &'a SparseTensor<T>>,
    T: Number + 'a,
{
    fn direct_product(self) -> SparseTensor<T> {
        let terms = self.collect::<Vec<_>>();
        let new_sizes = terms.iter().fold(vec![], |mut acc, &next| {
            if acc.len() < next.sizes.len() {
                for i in 0..acc.len() {
                    acc[i] *= next.size(i);
                }
                acc.extend(next.sizes[acc.len()..].iter());
            } else {
                for i in 0..next.sizes.len() {
                    acc[i] *= next.size(i);
                }
            }
            acc
        });

        let new_elems = terms
            .iter()
            .enumerate()
            .fold(
                Vec::<Vec<(usize, &Vec<usize>)>>::new(),
                |accum, (term_index, &next_term)| {
                    accum
                        .into_iter()
                        .flat_map(|acc| {
                            next_term
                                .elems
                                .keys()
                                .map(|indices| [&acc[..], &[(term_index, indices)]].concat())
                                .collect::<Vec<_>>()
                        })
                        .collect::<Vec<_>>()
                },
            )
            .into_iter()
            .map(|combination| {
                combination.into_iter().fold(
                    (Vec::<usize>::new(), T::default()),
                    |(mut accum_indices, mut accum_value), (term_index, indices)| {
                        if accum_indices.len() < indices.len() {
                            for i in 0..accum_indices.len() {
                                accum_indices[i] = (accum_indices[i] + 1) * (indices[i] + 1) - 1;
                            }
                            accum_indices.extend(indices[accum_indices.len()..].iter());
                        } else {
                            for i in 0..indices.len() {
                                accum_indices[i] = (accum_indices[i] + 1) * (indices[i] + 1) - 1;
                            }
                        }
                        accum_value *= terms[term_index].elem(&indices).clone();

                        (accum_indices, accum_value)
                    },
                )
            })
            .collect();

        SparseTensor::<T>::from(new_sizes, new_elems).unwrap()
    }
}

impl<T> SparseTensor<T>
where
    T: Number,
{
    pub fn direct(&self, rhs: &Self) -> Self {
        vec![self, rhs].into_iter().direct_product()
    }
}