use std::string::String;
use std::fs::File;
use std::io::Write;
use std::fmt;
use crate::types::{IndexType, ValueType};
use crate::sparsevec::SparseVec;
use crate::vector::Vector;
#[derive(Clone, Debug)]
pub struct SparseMatError {
msg: String,
}
impl SparseMatError {
pub fn new(error: &str) -> SparseMatError {
SparseMatError {
msg: String::from(error),
}
}
}
impl fmt::Display for SparseMatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.msg)
}
}
pub struct Iter<'a, M>
where M: SparseMatrix<'a>,
M::Value: ValueType,
M::Index: IndexType {
mat: &'a M,
row: usize,
iter_row: M::IterRow,
}
impl<'a, M> Iterator for Iter<'a, M>
where M: SparseMatrix<'a>,
M::Value: ValueType,
M::Index: IndexType {
type Item = (usize, usize, &'a M::Value);
fn next(&mut self) -> Option<Self::Item> {
let mut ret = match self.iter_row.next() {
Some((col, val)) => Some((self.row, col.as_usize(), val)),
None => None
};
while ret == None && self.row < (self.mat.n_rows() - 1) {
self.row += 1;
self.iter_row = self.mat.iter_row(self.row);
ret = match self.iter_row.next() {
Some((col, val)) => Some((self.row, col.as_usize(), val)),
None => None
};
}
ret
}
}
pub trait SparseMatrix<'a>
where Self: Sized + Clone {
type Value: 'a + ValueType;
type Index: 'a + IndexType;
const UNSET: Self::Index = Self::Index::MAX;
type IterRow: Iterator<Item = (&'a Self::Index, &'a Self::Value)>;
fn iter_row(&'a self, row: usize) -> Self::IterRow;
fn iter(&'a self) -> Iter<Self> {
Iter {
mat: &self,
row: 0,
iter_row: self.iter_row(0),
}
}
fn with_capacity(cap: usize) -> Self;
fn new() -> Self {
Self::with_capacity(0)
}
fn eye(dim: usize) -> Self {
let mut ret = Self::with_capacity(dim);
for i in 0..dim {
ret.set(i, i, Self::Value::one());
}
ret
}
fn n_rows(&self) -> usize;
fn n_cols(&self) -> usize;
fn n_non_zero_entries(&self) -> usize;
fn get(&self, i: usize, j: usize) -> Self::Value;
fn get_mut(&mut self, i: usize, j: usize) -> &mut Self::Value;
fn scale(&mut self, rhs: Self::Value);
fn empty(&self) -> bool {
self.n_rows() == 0
}
fn add<S>(&'a mut self, rhs: &'a S)
where S: SparseMatrix<'a, Value = Self::Value> {
for i in 0..rhs.n_rows() {
for (&col, &val) in rhs.iter_row(i) {
let j = col.as_usize();
*self.get_mut(i, j) += val;
}
}
}
fn sub<S>(&'a mut self, rhs: &'a S)
where S: SparseMatrix<'a, Value = Self::Value> {
for i in 0..rhs.n_rows() {
for (&col, &val) in rhs.iter_row(i) {
let j = col.as_usize();
*self.get_mut(i, j) -= val;
}
}
}
fn mvp<V>(&'a self, rhs: &V) -> V
where V: Vector<'a, Value = Self::Value> {
let mut ret = V::with_capacity(self.n_rows());
for i in 0..self.n_rows() {
let mut sum = Self::Value::zero();
for (&col, &val) in self.iter_row(i) {
let j = col.as_usize();
sum += rhs.get(j) * val;
}
ret.set(i, sum);
}
ret
}
fn inner_prod<V>(&'a self, lhs: &V, rhs: &V) -> Self::Value
where V: Vector<'a, Value = Self::Value> {
let mut sum = Self::Value::zero();
for i in 0..self.n_rows() {
for (&col, &val) in self.iter_row(i) {
let j = col.as_usize();
sum += lhs.get(i) * val * rhs.get(j);
}
}
sum
}
fn transpose(&'a self) -> Self {
let mut ret = Self::with_capacity(self.n_non_zero_entries());
for i in 0..self.n_rows() {
for (&col, &val) in self.iter_row(i) {
let j = col.as_usize();
ret.set(j, i, val);
}
}
ret
}
fn prod<M>(&'a self, rhs: &'a M) -> Result<Self, SparseMatError>
where M: ColumnIter<'a, Index = Self::Index, Value = Self::Value> {
if self.n_rows() != rhs.n_cols() || self.n_cols() != rhs.n_rows() {
return Err(SparseMatError::new("Dimension mismatch"));
}
let mut ret = Self::with_capacity(self.n_non_zero_entries());
for i in 0..self.n_rows() {
let mut cols_vals_i = self.iter_row(i).map(|(&c, &v)| (c, v)).collect::<Vec<(Self::Index, Self::Value)>>();
cols_vals_i.sort_by(|(c1, _v1), (c2, _v2)| c1.partial_cmp(c2).unwrap());
for j in 0..rhs.n_cols() {
let mut sum = Self::Value::zero();
rhs.iter_col(j).unwrap().for_each(|(&row, &val_rhs)| {
cols_vals_i.iter().take_while(|(col, _v)| *col <= row).for_each(|(col, val)| {
if *col == row{
sum += *val * val_rhs;
}
})
});
if sum != Self::Value::zero() {
ret.set(i, j, sum);
}
}
}
Ok(ret)
}
fn is_symmetric(&'a self) -> bool {
for i in 0..self.n_rows() {
for (&col, &val) in self.iter_row(i) {
let j = col.as_usize();
if self.get(j, i) != val {
return false;
}
}
}
true
}
fn set(&mut self, i: usize, j: usize, val: Self::Value) {
*self.get_mut(i, j) = val;
}
fn add_to(&mut self, i: usize, j: usize, val: Self::Value) {
*self.get_mut(i, j) += val;
}
fn density(&self) -> f64 {
let nnz = self.n_non_zero_entries() as f64;
let n_entries = (self.n_rows() * self.n_cols()) as f64;
nnz / n_entries
}
fn sparsity(&self) -> f64 {
1.0f64 - self.density()
}
fn is_sorted_row(&'a self, i: usize) -> bool {
let mut prev = 0;
for (&col, &_val) in self.iter_row(i) {
let j = col.as_usize();
if j < prev {
return false;
}
prev = j;
}
true
}
fn is_sorted(&'a self) -> bool {
for i in 0..self.n_rows() {
if !self.is_sorted_row(i) {
return false;
}
}
true
}
fn get_row(&'a self, i: usize) -> SparseVec<Self::Value, Self::Index> {
let mut ret = SparseVec::<Self::Value, Self::Index>::new();
for (&col, &val) in self.iter_row(i) {
let j = col.as_usize();
ret.set(j, val);
}
ret.sort();
ret
}
fn to_string_row(&'a self, i: usize) -> String {
let mut ret = String::from("");
let mut j = Self::Index::ZERO;
let row_vec = self.get_row(i);
for (&col, &val) in row_vec.iter_sparse() {
while j < col {
ret += "0 ";
j += Self::Index::ONE;
}
ret += &val.to_string();
ret += " ";
j += Self::Index::ONE;
}
ret
}
fn to_string(&'a self) -> String {
let mut ret = String::from("");
for i in 0..self.n_rows() {
ret += &self.to_string_row(i);
ret += "\n";
}
ret
}
fn to_pbm(&'a self, filename: String) {
let mut file = File::create(filename).unwrap();
file.write_all(b"P1\n").unwrap();
file.write_all(self.n_rows().to_string().as_bytes()).unwrap();
file.write_all(b" ").unwrap();
file.write_all(self.n_cols().to_string().as_bytes()).unwrap();
file.write_all(b"\n").unwrap();
for i in 0..self.n_rows() {
let mut j = Self::Index::ZERO;
let mut tmp = String::from("");
let mut cols = self.iter_row(i).map(|(&c, &_v)| c).collect::<Vec<Self::Index>>();
cols.sort_by(|c1, c2| c1.partial_cmp(c2).unwrap());
for col in cols {
while j < col {
tmp += "1";
j += Self::Index::ONE;
}
tmp += "0";
j += Self::Index::ONE;
}
tmp += "\n";
file.write_all(tmp.as_bytes()).unwrap();
}
}
}
pub trait ColumnIter<'a>
where Self: SparseMatrix<'a> {
type IterCol: Iterator<Item = (&'a Self::Index, &'a Self::Value)>;
fn assemble_column_info(&mut self);
fn iter_col(&'a self, col: usize) -> Result<Self::IterCol, SparseMatError>;
}
pub trait Sortable<'a>
where Self: SparseMatrix<'a> {
fn sort_row(&mut self, i: usize);
fn sort(&mut self) {
for i in 0..self.n_rows() {
self.sort_row(i);
}
}
}
macro_rules! sparsemat_ops {
($Name: ident) => {
impl<T, I> std::ops::AddAssign for $Name<T, I>
where T: ValueType,
I: IndexType {
fn add_assign(&mut self, rhs: Self) {
self.add(&rhs);
}
}
impl<T, I> std::ops::SubAssign for $Name<T, I>
where T: ValueType,
I: IndexType {
fn sub_assign(&mut self, rhs: Self) {
self.sub(&rhs);
}
}
impl<T, I> std::ops::MulAssign<T> for $Name<T, I>
where T: ValueType,
I: IndexType {
fn mul_assign(&mut self, rhs: T) {
self.scale(rhs);
}
}
impl<T, I> std::ops::Add for $Name<T, I>
where T: ValueType,
I: IndexType {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut ret = self.clone();
ret += rhs;
ret
}
}
impl<T, I> std::ops::Sub for $Name<T, I>
where T: ValueType,
I: IndexType {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut ret = self.clone();
ret -= rhs;
ret
}
}
impl<T, I> std::ops::Mul<T> for $Name<T, I>
where T: ValueType,
I: IndexType {
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
let mut ret = self.clone();
ret *= rhs;
ret
}
}
impl<T, I> std::ops::Mul<DenseVec<T>> for $Name<T, I>
where T: ValueType,
I: IndexType {
type Output = DenseVec<T>;
fn mul(self, rhs: DenseVec<T>) -> Self::Output {
self.mvp(&rhs)
}
}
}
}