extern crate rand;
use self::rand::prelude::*;
use crate::structure::{
matrix::Shape::{Col, Row},
matrix::{matrix, Matrix, Shape},
};
use crate::traits::float::FloatWithPrecision;
use crate::traits::matrix::MatrixTrait;
use anyhow::{bail, Result};
use rand_distr::{Distribution, Uniform};
#[derive(Debug, Copy, Clone)]
pub enum ConcatenateError {
DifferentLength,
}
impl std::fmt::Display for ConcatenateError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
ConcatenateError::DifferentLength => write!(
f,
"To concatenate, vectors or matrices must have the same length"
),
}
}
}
pub fn seq<S, T, U>(start: S, end: T, step: U) -> Vec<f64>
where
S: Into<f64> + Copy,
T: Into<f64> + Copy,
U: Into<f64> + Copy,
{
let s = start.into();
let e = end.into();
let step = step.into();
assert!(e >= s);
let factor: f64 = (e - s) / step;
let l: usize = factor.floor() as usize + 1;
let mut v: Vec<f64> = vec![0f64; l];
for (i, v) in v.iter_mut().enumerate() {
*v = s + step * (i as f64);
}
v
}
pub fn seq_with_precision<S, T, U>(start: S, end: T, step: U, precision: usize) -> Vec<f64>
where
S: Into<f64> + Copy,
T: Into<f64> + Copy,
U: Into<f64> + Copy,
{
let s = start.into();
let e = end.into();
let step = step.into();
assert!(e >= s);
let factor: f64 = (e - s) / step;
let l: usize = factor.floor() as usize + 1;
let mut v: Vec<f64> = vec![0f64; l];
for (i, v) in v.iter_mut().enumerate() {
*v = (s + step * (i as f64)).round_with_precision(precision);
}
v
}
pub fn cbind(m1: Matrix, m2: Matrix) -> Result<Matrix> {
let mut temp = m1;
if temp.shape != Col {
temp = temp.change_shape();
}
let mut temp2 = m2;
if temp2.shape != Col {
temp2 = temp2.change_shape();
}
let mut v = temp.data;
let mut c = temp.col;
let r = temp.row;
if r != temp2.row {
bail!(ConcatenateError::DifferentLength);
}
v.extend_from_slice(&temp2.data[..]);
c += temp2.col;
Ok(matrix(v, r, c, Col))
}
pub fn rbind(m1: Matrix, m2: Matrix) -> Result<Matrix> {
let mut temp = m1;
if temp.shape != Row {
temp = temp.change_shape();
}
let mut temp2 = m2;
if temp2.shape != Row {
temp2 = temp2.change_shape();
}
let mut v = temp.data;
let c = temp.col;
let mut r = temp.row;
if c != temp2.col {
bail!(ConcatenateError::DifferentLength);
}
v.extend_from_slice(&temp2.data[..]);
r += temp2.row;
Ok(matrix(v, r, c, Row))
}
pub fn zeros(r: usize, c: usize) -> Matrix {
matrix(vec![0f64; r * c], r, c, Row)
}
pub fn zeros_shape(r: usize, c: usize, shape: Shape) -> Matrix {
matrix(vec![0f64; r * c], r, c, shape)
}
pub fn eye(n: usize) -> Matrix {
let mut m = zeros(n, n);
for i in 0..n {
m[(i, i)] = 1f64;
}
m
}
pub fn eye_shape(n: usize, shape: Shape) -> Matrix {
let mut m = zeros_shape(n, n, shape);
for i in 0..n {
m[(i, i)] = 1f64;
}
m
}
pub fn linspace<S, T>(start: S, end: T, length: usize) -> Vec<f64>
where
S: Into<f64> + Copy,
T: Into<f64> + Copy,
{
let step: f64 = if length > 1 {
(end.into() - start.into()) / (length as f64 - 1f64)
} else {
0f64
};
let mut v = vec![0f64; length];
v[0] = start.into();
v[length - 1] = end.into();
for i in 1..length - 1 {
v[i] = v[0] + step * (i as f64);
}
v
}
pub fn linspace_with_precision<S, T>(start: S, end: T, length: usize, precision: usize) -> Vec<f64>
where
S: Into<f64> + Copy,
T: Into<f64> + Copy,
{
let step: f64 = if length > 1 {
(end.into() - start.into()) / (length as f64 - 1f64)
} else {
0f64
};
let mut v = vec![0f64; length];
v[0] = start.into().round_with_precision(precision);
v[length - 1] = end.into().round_with_precision(precision);
for i in 1..length - 1 {
v[i] = (v[0] + step * (i as f64)).round_with_precision(precision);
}
v
}
pub fn rand(r: usize, c: usize) -> Matrix {
let mut rng = rand::rng();
rand_with_rng(r, c, &mut rng)
}
pub fn rand_with_rng<R: Rng>(r: usize, c: usize, rng: &mut R) -> Matrix {
let uniform = Uniform::new_inclusive(0f64, 1f64).unwrap();
rand_with_dist(r, c, rng, uniform)
}
pub fn rand_with_dist<T: Into<f64>, R: Rng, D: Distribution<T>>(
r: usize,
c: usize,
rng: &mut R,
dist: D,
) -> Matrix {
matrix(rng.sample_iter(dist).take(r * c).collect(), r, c, Row)
}
pub fn logspace<S, T, U>(start: S, end: T, length: usize, base: U) -> Vec<f64>
where
S: Into<f64> + Copy,
T: Into<f64> + Copy,
U: Into<f64> + Copy,
{
let s: f64 = start.into();
let e: f64 = end.into();
let b: f64 = base.into();
assert!(e >= s);
let step: f64 = if length > 1 {
(e - s) / (length as f64 - 1f64)
} else {
0f64
};
let mut v: Vec<f64> = vec![0f64; length];
for (i, v) in v.iter_mut().enumerate() {
*v = b.powf(s + step * (i as f64));
}
v
}
pub fn column_stack(v: &[Vec<f64>]) -> Result<Matrix> {
let row = v[0].len();
if v.iter().any(|x| x.len() != row) {
bail!(ConcatenateError::DifferentLength);
}
let data = v.iter().flatten().copied().collect();
Ok(matrix(data, row, v.len(), Col))
}
pub fn row_stack(v: &[Vec<f64>]) -> Result<Matrix> {
let col = v[0].len();
if v.iter().any(|x| x.len() != col) {
bail!(ConcatenateError::DifferentLength);
}
let data = v.iter().flatten().copied().collect();
Ok(matrix(data, v.len(), col, Row))
}
pub fn concat<T: Clone + Copy>(v1: &[T], v2: &[T]) -> Vec<T> {
let mut v = v1.to_vec();
v.extend_from_slice(v2);
v
}
pub fn cat<T: Clone + Copy + Default>(val: T, vec: &[T]) -> Vec<T> {
let mut v = vec![val];
v.extend_from_slice(vec);
v
}