extern crate csv;
#[cfg(feature = "O3")]
extern crate blas;
#[cfg(feature = "O3")]
extern crate lapack;
#[cfg(feature = "O3")]
use blas::{daxpy, dgemm, dgemv};
#[cfg(feature = "O3")]
use lapack::{dgecon, dgeqrf, dgetrf, dgetri, dgetrs, dorgqr};
#[cfg(feature = "O3")]
use std::f64::NAN;
use self::csv::{ReaderBuilder, StringRecord, WriterBuilder};
use ::matrixmultiply;
pub use self::Shape::{Col, Row};
use std::cmp::{max, min};
use std::convert;
pub use std::error::Error;
use std::fmt;
use std::ops::{Add, Index, IndexMut, Mul, Neg, Sub, Div};
use crate::traits::{
mutable::MutMatrix,
fp::{FPVector, FPMatrix},
math::{Vector, Normed, Norm, InnerProduct, LinearOp},
general::Algorithm,
};
use crate::util::{
low_level::{swap_vec_ptr, copy_vec_ptr},
non_macro::{eye, zeros},
useful::{nearly_eq, tab}
};
use crate::numerical::eigen::{eigen, EigenMethod};
pub type Perms = Vec<(usize, usize)>;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Shape {
Row,
Col,
}
impl fmt::Display for Shape {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let to_display = match self {
Row => "Row",
Col => "Col",
};
write!(f, "{}", to_display)
}
}
#[derive(Debug, Clone)]
pub struct Matrix {
pub data: Vec<f64>,
pub row: usize,
pub col: usize,
pub shape: Shape,
}
pub fn matrix<T>(v: Vec<T>, r: usize, c: usize, shape: Shape) -> Matrix
where
T: convert::Into<f64>,
{
Matrix {
data: v.into_iter().map(|t| t.into()).collect::<Vec<f64>>(),
row: r,
col: c,
shape,
}
}
pub fn r_matrix<T>(v: Vec<T>, r: usize, c: usize, shape: Shape) -> Matrix
where
T: convert::Into<f64>,
{
matrix(v, r, c, shape)
}
pub fn py_matrix<T>(v: Vec<Vec<T>>) -> Matrix
where
T: convert::Into<f64> + Copy,
{
let r = v.len();
let c = v[0].len();
let mut data = vec![0f64; r * c];
for i in 0..r {
for j in 0..c {
let idx = i * c + j;
data[idx] = v[i][j].into();
}
}
matrix(data, r, c, Row)
}
pub fn ml_matrix(s: &str) -> Matrix where {
let str_rows: Vec<&str> = s.split(';').collect();
let r = str_rows.len();
let str_data = str_rows
.into_iter()
.map(|x| x.trim().split(' ').collect::<Vec<&str>>())
.collect::<Vec<Vec<&str>>>();
let c = str_data[0].len();
let data = str_data
.into_iter()
.flat_map(|t| {
t.into_iter()
.map(|x| x.parse::<f64>().unwrap())
.collect::<Vec<f64>>()
})
.collect::<Vec<f64>>();
matrix(data, r, c, Row)
}
impl fmt::Display for Matrix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.spread())
}
}
impl PartialEq for Matrix {
fn eq(&self, other: &Matrix) -> bool {
if self.shape == other.shape {
self.data
.clone()
.into_iter()
.zip(other.data.clone())
.all(|(x, y)| nearly_eq(x, y))
&& self.row == other.row
} else {
self.eq(&other.change_shape())
}
}
}
#[allow(dead_code)]
impl Matrix {
pub fn ptr(&self) -> *const f64 {
&self.data[0] as *const f64
}
pub fn mut_ptr(&mut self) -> *mut f64 {
&mut self.data[0] as *mut f64
}
pub fn as_slice<'a>(&'a self) -> &'a [f64] {
&self.data[..]
}
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [f64] {
&mut self.data[..]
}
pub fn change_shape(&self) -> Self {
let r = self.row;
let c = self.col;
assert_eq!(r * c, self.data.len());
let l = r * c - 1;
let mut data: Vec<f64> = self.data.clone();
let ref_data = &self.data;
match self.shape {
Row => {
for i in 0..l {
let s = (i * c) % l;
data[i] = ref_data[s];
}
data[l] = ref_data[l];
matrix(data,r,c,Col)
}
Col => {
for i in 0..l {
let s = (i * r) % l;
data[i] = ref_data[s];
}
data[l] = ref_data[l];
matrix(data,r,c,Row)
}
}
}
pub fn change_shape_mut(&mut self) {
let r = self.row;
let c = self.col;
assert_eq!(r * c, self.data.len());
let l = r * c - 1;
let ref_data = self.data.clone();
match self.shape {
Row => {
for i in 0..l {
let s = (i * c) % l;
self.data[i] = ref_data[s];
}
self.data[l] = ref_data[l];
self.shape = Col;
}
Col => {
for i in 0..l {
let s = (i * r) % l;
self.data[i] = ref_data[s];
}
self.data[l] = ref_data[l];
self.shape = Row;
}
}
}
pub fn spread(&self) -> String {
assert_eq!(self.row * self.col, self.data.len());
let r = self.row;
let c = self.col;
let mut key_row = 20usize;
let mut key_col = 20usize;
if r > 100 || c > 100 || (r > 20 && c > 20) {
let part = if r <= 10 {
key_row = r;
key_col = 100;
self.take_col(100)
} else if c <= 10 {
key_row = 100;
key_col = c;
self.take_row(100)
} else {
self.take_row(20).take_col(20)
};
return format!(
"Result is too large to print - {}x{}\nonly print {}x{} parts:\n{}",
self.row.to_string(),
self.col.to_string(),
key_row.to_string(),
key_col.to_string(),
part.spread()
);
}
let sample = self.data.clone();
let mut space: usize = sample
.into_iter()
.map(
|x| min(format!("{:.4}", x).len(), x.to_string().len()), )
.fold(0, |x, y| max(x, y))
+ 1;
if space < 5 {
space = 5;
}
let mut result = String::new();
result.push_str(&tab("", 5));
for i in 0..c {
result.push_str(&tab(&format!("c[{}]", i), space)); }
result.push('\n');
for i in 0..r {
result.push_str(&tab(&format!("r[{}]", i), 5));
for j in 0..c {
let st1 = format!("{:.4}", self[(i, j)]); let st2 = self[(i, j)].to_string(); let mut st = st2.clone();
if st1.len() < st2.len() {
st = st1;
}
result.push_str(&tab(&st, space));
}
if i == (r - 1) {
break;
}
result.push('\n');
}
return result;
}
pub fn col(&self, index: usize) -> Vec<f64> {
assert!(index < self.col);
let mut container: Vec<f64> = vec![0f64; self.row];
for i in 0..self.row {
container[i] = self[(i, index)];
}
container
}
pub fn row(&self, index: usize) -> Vec<f64> {
assert!(index < self.row);
let mut container: Vec<f64> = vec![0f64; self.col];
for i in 0..self.col {
container[i] = self[(index, i)];
}
container
}
pub fn diag(&self) -> Vec<f64> {
let mut container = vec![0f64; self.row];
let r = self.row;
let c = self.col;
assert_eq!(r, c);
let c2 = c + 1;
for i in 0..r {
container[i] = self.data[i * c2];
}
container
}
pub fn transpose(&self) -> Self {
match self.shape {
Row => matrix(self.data.clone(), self.col, self.row, Col),
Col => matrix(self.data.clone(), self.col, self.row, Row),
}
}
pub fn t(&self) -> Self {
self.transpose()
}
pub fn write(&self, file_path: &str) -> Result<(), Box<dyn Error>> {
let mut wtr = WriterBuilder::new().from_path(file_path)?;
let r = self.row;
let c = self.col;
for i in 0..r {
let mut record: Vec<String> = vec!["".to_string(); c];
for j in 0..c {
record[j] = self[(i, j)].to_string();
}
wtr.write_record(record)?;
}
wtr.flush()?;
Ok(())
}
pub fn write_round(&self, file_path: &str, round: usize) -> Result<(), Box<dyn Error>> {
let mut wtr = WriterBuilder::new().from_path(file_path)?;
let r = self.row;
let c = self.col;
for i in 0..r {
let mut record: Vec<String> = vec!["".to_string(); c];
for j in 0..c {
record[j] = format!("{:.*}", round, self[(i, j)]);
}
wtr.write_record(record)?;
}
wtr.flush()?;
Ok(())
}
pub fn write_with_header(
&self,
file_path: &str,
header: Vec<&str>,
) -> Result<(), Box<dyn Error>> {
let mut wtr = WriterBuilder::new().from_path(file_path)?;
let r = self.row;
let c = self.col;
assert_eq!(c, header.len());
wtr.write_record(header)?;
for i in 0..r {
let mut record: Vec<String> = vec!["".to_string(); c];
for j in 0..c {
record[j] = self[(i, j)].to_string();
}
wtr.write_record(record)?;
}
wtr.flush()?;
Ok(())
}
pub fn write_with_header_round(
&self,
file_path: &str,
header: Vec<&str>,
round: usize,
) -> Result<(), Box<dyn Error>> {
let mut wtr = WriterBuilder::new().from_path(file_path)?;
let r = self.row;
let c = self.col;
assert_eq!(c, header.len());
wtr.write_record(header)?;
for i in 0..r {
let mut record: Vec<String> = vec!["".to_string(); c];
for j in 0..c {
record[j] = format!("{:.*}", round, self[(i, j)]);
}
wtr.write_record(record)?;
}
wtr.flush()?;
Ok(())
}
pub fn read(file_path: &str, header: bool, delimiter: char) -> Result<Matrix, Box<dyn Error>> {
let mut rdr = ReaderBuilder::new()
.has_headers(header)
.delimiter(delimiter as u8)
.from_path(file_path)?;
let records = rdr
.records()
.collect::<Result<Vec<StringRecord>, csv::Error>>()?;
let result = records;
let l_row = result.len();
let l_col = result[0].len();
let mut m = matrix(vec![0f64; l_row * l_col], l_row, l_col, Row);
for i in 0..l_row {
for j in 0..l_col {
m[(i, j)] = result[i][j].parse::<f64>().unwrap();
}
}
Ok(m)
}
pub fn subs(&mut self, idx: usize, v: &Vec<f64>) {
let p = &mut self.mut_ptr();
match self.shape {
Row => {
let c = self.col;
unsafe {
p.add(idx * c).copy_from(v.as_ptr(), c);
}
}
Col => {
let r = self.row;
unsafe {
p.add(idx * r).copy_from(v.as_ptr(), r);
}
}
}
}
#[inline]
pub fn subs_col(&mut self, idx: usize, v: &Vec<f64>) {
for i in 0..self.row {
self[(i, idx)] = v[i];
}
}
#[inline]
pub fn subs_row(&mut self, idx: usize, v: &Vec<f64>) {
for j in 0..self.col {
self[(idx, j)] = v[j];
}
}
pub fn from_index<F, G>(f: F, size: (usize, usize)) -> Matrix
where
F: Fn(usize, usize) -> G + Copy,
G: Into<f64>,
{
let row = size.0;
let col = size.1;
let mut mat = matrix(vec![0f64; row * col], row, col, Row);
for i in 0..row {
for j in 0..col {
mat[(i, j)] = f(i, j).into();
}
}
mat
}
pub fn to_vec(&self) -> Vec<Vec<f64>> {
let mut result = vec![vec![0f64; self.col]; self.row];
for i in 0..self.row {
result[i] = self.row(i);
}
result
}
pub fn to_diag(&self) -> Matrix {
assert!(self.row == self.col, "Should be square matrix");
let mut result = matrix(vec![0f64; self.row * self.col], self.row, self.col, Row);
let diag = self.diag();
for i in 0..self.row {
result[(i, i)] = diag[i];
}
result
}
}
impl Vector for Matrix {
fn add_vec(&self, other: &Self) -> Self {
assert_eq!(self.row, other.row);
assert_eq!(self.col, other.col);
match () {
#[cfg(feature = "O3")]
() => {
if self.shape != other.shape {
return self.add(&other.change_shape());
}
let x = &self.data;
let mut y = other.data.clone();
let n_i32 = x.len() as i32;
let a_f64 = 1f64;
unsafe {
daxpy(n_i32, a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => {
let mut result = matrix(self.data.clone(), self.row, self.col, self.shape);
for i in 0..self.row {
for j in 0..self.col {
result[(i, j)] += other[(i, j)];
}
}
result
}
}
}
fn sub_vec(&self, other: &Self) -> Self {
assert_eq!(self.row, other.row);
assert_eq!(self.col, other.col);
match () {
#[cfg(feature = "O3")]
() => {
if self.shape != other.shape {
return self.sub(&other.change_shape());
}
let x = &other.data;
let mut y = self.data.clone();
let n_i32 = x.len() as i32;
let a_f64 = -1f64;
unsafe {
daxpy(n_i32, a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => {
let mut result = matrix(self.data.clone(), self.row, self.col, self.shape);
for i in 0..self.row {
for j in 0..self.col {
result[(i, j)] -= other[(i, j)];
}
}
result
}
}
}
fn mul_scalar<T: Into<f64>>(&self, other: T) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![0f64; x.len()];
let a_f64 = other.into();
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => {
let scalar = other.into();
self.fmap(|x| x * scalar)
}
}
}
}
impl Normed for Matrix {
type Scalar = f64;
fn norm(&self, kind: Norm) -> f64 {
match kind {
Norm::F => {
let mut s = 0f64;
for i in 0..self.data.len() {
s += self.data[i].powi(2);
}
s.sqrt()
}
Norm::Lpq(p, q) => {
let mut s = 0f64;
for j in 0..self.col {
let mut s_row = 0f64;
for i in 0..self.row {
s_row += self[(i, j)].powi(p as i32);
}
s += s_row.powf(q as f64 / (p as f64));
}
s.powf(1f64 / (q as f64))
}
Norm::L1 => {
let mut m = std::f64::MIN;
match self.shape {
Row => self.change_shape().norm(Norm::L1),
Col => {
for c in 0..self.col {
let s = self.col(c).iter().sum();
if s > m {
m = s;
}
}
m
}
}
}
Norm::LInf => {
let mut m = std::f64::MIN;
match self.shape {
Col => self.change_shape().norm(Norm::LInf),
Row => {
for r in 0..self.row {
let s = self.row(r).iter().sum();
if s > m {
m = s;
}
}
m
}
}
}
Norm::L2 => {
let a = &self.t() * self;
let eig = eigen(&a, EigenMethod::Jacobi);
eig.eigenvalue.norm(Norm::LInf)
}
Norm::Lp(_) => {
unimplemented!()
}
}
}
fn normalize(&self, _kind: Norm) -> Self where Self: Sized {
unimplemented!()
}
}
impl InnerProduct for Matrix {
fn dot(&self, rhs: &Self) -> f64 {
if self.shape == rhs.shape {
self.data.dot(&rhs.data)
} else {
self.data.dot(&rhs.change_shape().data)
}
}
}
impl LinearOp<Vec<f64>, Vec<f64>> for Matrix {
fn apply(&self, other: &Vec<f64>) -> Vec<f64> {
match () {
#[cfg(feature = "O3")]
() => {
let x = other;
let mut y = vec![0f64; self.row];
let A = &self.data;
let m_i32 = self.row as i32;
let n_i32 = self.col as i32;
match self.shape {
Row => unsafe {
dgemv(b'T', m_i32, n_i32, 1f64, A, n_i32, x, 1, 0f64, &mut y, 1);
},
Col => unsafe {
dgemv(b'N', m_i32, n_i32, 1f64, A, m_i32, x, 1, 0f64, &mut y, 1);
},
}
y
}
_ => {
let mut c = vec![0f64; self.row];
gemv(1f64, self, other, 0f64, &mut c);
c
}
}
}
}
impl Into<Vec<f64>> for Matrix {
fn into(self) -> Vec<f64> {
self.data
}
}
impl<'a> Into<&'a Vec<f64>> for &'a Matrix {
fn into(self) -> &'a Vec<f64> {
&self.data
}
}
impl Into<Matrix> for Vec<f64> {
fn into(self) -> Matrix {
let l = self.len();
matrix(self, l, 1, Col)
}
}
impl Into<Matrix> for &Vec<f64> {
fn into(self) -> Matrix {
let l = self.len();
matrix(self.clone(), l, 1, Col)
}
}
impl Add<Matrix> for Matrix {
type Output = Self;
fn add(self, other: Self) -> Self {
assert_eq!(&self.row, &other.row);
assert_eq!(&self.col, &other.col);
match () {
#[cfg(feature = "O3")]
() => {
if self.shape != other.shape {
return self.add(other.change_shape());
}
let x = &self.data;
let mut y = other.data.clone();
let n_i32 = x.len() as i32;
let a_f64 = 1f64;
unsafe {
daxpy(n_i32, a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => {
let mut result = matrix(self.data.clone(), self.row, self.col, self.shape);
for i in 0..self.row {
for j in 0..self.col {
result[(i, j)] += other[(i, j)];
}
}
result
}
}
}
}
impl<'a, 'b> Add<&'b Matrix> for &'a Matrix {
type Output = Matrix;
fn add(self, rhs: &'b Matrix) -> Self::Output {
self.add_vec(rhs)
}
}
impl<T> Add<T> for Matrix
where
T: convert::Into<f64> + Copy,
{
type Output = Self;
fn add(self, other: T) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![other.into(); x.len()];
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, 1f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x + other.into()),
}
}
}
impl<'a, T> Add<T> for &'a Matrix
where
T: convert::Into<f64> + Copy,
{
type Output = Matrix;
fn add(self, other: T) -> Self::Output {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![other.into(); x.len()];
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, 1f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x + other.into()),
}
}
}
impl Add<Matrix> for f64 {
type Output = Matrix;
fn add(self, other: Matrix) -> Matrix {
other.add(self)
}
}
impl<'a> Add<&'a Matrix> for f64 {
type Output = Matrix;
fn add(self, other: &'a Matrix) -> Self::Output {
other.add(self)
}
}
impl Add<Matrix> for i32 {
type Output = Matrix;
fn add(self, other: Matrix) -> Matrix {
other.add(self)
}
}
impl<'a> Add<&'a Matrix> for i32 {
type Output = Matrix;
fn add(self, other: &'a Matrix) -> Self::Output {
other.add(self)
}
}
impl Add<Matrix> for usize {
type Output = Matrix;
fn add(self, other: Matrix) -> Matrix {
other.add(self as f64)
}
}
impl<'a> Add<&'a Matrix> for usize {
type Output = Matrix;
fn add(self, other: &'a Matrix) -> Self::Output {
other.add(self as f64)
}
}
impl Neg for Matrix {
type Output = Self;
fn neg(self) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![0f64; x.len()];
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, -1f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => matrix(
self.data.into_iter().map(|x: f64| -x).collect::<Vec<f64>>(),
self.row,
self.col,
self.shape,
),
}
}
}
impl<'a> Neg for &'a Matrix {
type Output = Matrix;
fn neg(self) -> Self::Output {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![0f64; x.len()];
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, -1f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => matrix(
self.data
.clone()
.into_iter()
.map(|x: f64| -x)
.collect::<Vec<f64>>(),
self.row,
self.col,
self.shape,
),
}
}
}
impl Sub<Matrix> for Matrix {
type Output = Self;
fn sub(self, other: Self) -> Self {
assert_eq!(&self.row, &other.row);
assert_eq!(&self.col, &other.col);
match () {
#[cfg(feature = "O3")]
() => {
if self.shape != other.shape {
return self.sub(other.change_shape());
}
let x = &other.data;
let mut y = self.data.clone();
let n_i32 = x.len() as i32;
let a_f64 = -1f64;
unsafe {
daxpy(n_i32, a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => {
let mut result = matrix(self.data.clone(), self.row, self.col, self.shape);
for i in 0..self.row {
for j in 0..self.col {
result[(i, j)] -= other[(i, j)];
}
}
result
}
}
}
}
impl<'a, 'b> Sub<&'b Matrix> for &'a Matrix {
type Output = Matrix;
fn sub(self, rhs: &'b Matrix) -> Matrix {
self.sub_vec(rhs)
}
}
impl<T> Sub<T> for Matrix
where
T: convert::Into<f64> + Copy,
{
type Output = Self;
fn sub(self, other: T) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let mut y = self.data;
let x = vec![other.into(); y.len()];
let n_i32 = y.len() as i32;
unsafe {
daxpy(n_i32, -1f64, &x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x - other.into()),
}
}
}
impl<'a, T> Sub<T> for &'a Matrix
where
T: convert::Into<f64> + Copy,
{
type Output = Matrix;
fn sub(self, other: T) -> Self::Output {
match () {
#[cfg(feature = "O3")]
() => {
let mut y = self.data.clone();
let x = vec![other.into(); y.len()];
let n_i32 = y.len() as i32;
unsafe {
daxpy(n_i32, -1f64, &x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x - other.into()),
}
}
}
impl Sub<Matrix> for f64 {
type Output = Matrix;
fn sub(self, other: Matrix) -> Matrix {
-other.sub(self)
}
}
impl<'a> Sub<&'a Matrix> for f64 {
type Output = Matrix;
fn sub(self, other: &'a Matrix) -> Self::Output {
-other.sub(self)
}
}
impl Sub<Matrix> for i32 {
type Output = Matrix;
fn sub(self, other: Matrix) -> Matrix {
-other.sub(self)
}
}
impl<'a> Sub<&'a Matrix> for i32 {
type Output = Matrix;
fn sub(self, other: &'a Matrix) -> Self::Output {
-other.sub(self)
}
}
impl Sub<Matrix> for usize {
type Output = Matrix;
fn sub(self, other: Matrix) -> Matrix {
-other.sub(self as f64)
}
}
impl<'a> Sub<&'a Matrix> for usize {
type Output = Matrix;
fn sub(self, other: &'a Matrix) -> Self::Output {
-other.sub(self as f64)
}
}
impl Mul<f64> for Matrix {
type Output = Self;
fn mul(self, other: f64) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![0f64; x.len()];
let a_f64 = other;
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x * other),
}
}
}
impl Mul<i64> for Matrix {
type Output = Self;
fn mul(self, other: i64) -> Self {
self.mul(other as f64)
}
}
impl Mul<i32> for Matrix {
type Output = Self;
fn mul(self, other: i32) -> Self {
self.mul(other as f64)
}
}
impl Mul<usize> for Matrix {
type Output = Self;
fn mul(self, other: usize) -> Self {
self.mul(other as f64)
}
}
impl Mul<Matrix> for f64 {
type Output = Matrix;
fn mul(self, other: Matrix) -> Matrix {
other.mul(self)
}
}
impl Mul<Matrix> for i64 {
type Output = Matrix;
fn mul(self, other: Matrix) -> Matrix {
other.mul(self as f64)
}
}
impl Mul<Matrix> for i32 {
type Output = Matrix;
fn mul(self, other: Matrix) -> Matrix {
other.mul(self)
}
}
impl Mul<Matrix> for usize {
type Output = Matrix;
fn mul(self, other: Matrix) -> Matrix {
other.mul(self as f64)
}
}
impl<'a> Mul<&'a Matrix> for f64 {
type Output = Matrix;
fn mul(self, other: &'a Matrix) -> Matrix {
other.mul_scalar(self)
}
}
impl<'a> Mul<&'a Matrix> for i64 {
type Output = Matrix;
fn mul(self, other: &'a Matrix) -> Matrix {
other.mul_scalar(self as f64)
}
}
impl<'a> Mul<&'a Matrix> for i32 {
type Output = Matrix;
fn mul(self, other: &'a Matrix) -> Matrix {
other.mul_scalar(self as f64)
}
}
impl<'a> Mul<&'a Matrix> for usize {
type Output = Matrix;
fn mul(self, other: &'a Matrix) -> Matrix {
other.mul_scalar(self as f64)
}
}
impl Mul<Matrix> for Matrix {
type Output = Self;
fn mul(self, other: Self) -> Self {
match () {
#[cfg(feature = "O3")]
() => blas_mul(&self, &other),
_ => matmul(&self, &other),
}
}
}
impl<'a, 'b> Mul<&'b Matrix> for &'a Matrix {
type Output = Matrix;
fn mul(self, other: &'b Matrix) -> Self::Output {
match () {
#[cfg(feature = "O3")]
() => blas_mul(self, other),
_ => matmul(self, other),
}
}
}
#[allow(non_snake_case)]
impl Mul<Vec<f64>> for Matrix {
type Output = Vec<f64>;
fn mul(self, other: Vec<f64>) -> Self::Output {
self.apply(&other)
}
}
#[allow(non_snake_case)]
impl<'a, 'b> Mul<&'b Vec<f64>> for &'a Matrix {
type Output = Vec<f64>;
fn mul(self, other: &'b Vec<f64>) -> Self::Output {
self.apply(other)
}
}
impl Mul<Matrix> for Vec<f64> {
type Output = Vec<f64>;
fn mul(self, other: Matrix) -> Self::Output {
assert_eq!(self.len(), other.row);
let mut c = vec![0f64; other.col];
gevm(1f64, &self, &other, 0f64, &mut c);
c
}
}
impl<'a, 'b> Mul<&'b Matrix> for &'a Vec<f64> {
type Output = Vec<f64>;
fn mul(self, other: &'b Matrix) -> Self::Output {
assert_eq!(self.len(), other.row);
let mut c = vec![0f64; other.col];
gevm(1f64, self, other, 0f64, &mut c);
c
}
}
impl Div<f64> for Matrix {
type Output = Self;
fn div(self, other: f64) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![0f64; x.len()];
let a_f64 = other;
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, 1f64/a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x / other),
}
}
}
impl Div<i64> for Matrix {
type Output = Self;
fn div(self, other: i64) -> Self {
self.div(other as f64)
}
}
impl Div<i32> for Matrix {
type Output = Self;
fn div(self, other: i32) -> Self {
self.div(other as f64)
}
}
impl Div<usize> for Matrix {
type Output = Self;
fn div(self, other: usize) -> Self {
self.div(other as f64)
}
}
impl<'a> Div<f64> for &'a Matrix {
type Output = Matrix;
fn div(self, other: f64) -> Self::Output {
match () {
#[cfg(feature = "O3")]
() => {
let x = &self.data;
let mut y = vec![0f64; x.len()];
let a_f64 = other;
let n_i32 = x.len() as i32;
unsafe {
daxpy(n_i32, 1f64 / a_f64, x, 1, &mut y, 1);
}
matrix(y, self.row, self.col, self.shape)
}
_ => self.fmap(|x| x / other),
}
}
}
impl<'a> Div<i64> for &'a Matrix {
type Output = Matrix;
fn div(self, other: i64) -> Self::Output {
self.div(other as f64)
}
}
impl<'a> Div<i32> for &'a Matrix {
type Output = Matrix;
fn div(self, other: i32) -> Self::Output {
self.div(other as f64)
}
}
impl<'a> Div<usize> for &'a Matrix {
type Output = Matrix;
fn div(self, other: usize) -> Self::Output {
self.div(other as f64)
}
}
impl Index<(usize, usize)> for Matrix {
type Output = f64;
fn index(&self, pair: (usize, usize)) -> &f64 {
let p = self.ptr();
let i = pair.0;
let j = pair.1;
assert!(i < self.row && j < self.col, "Index out of range");
match self.shape {
Row => {
unsafe {
&*p.add(i * self.col + j)
}
}
Col => {
unsafe {
&*p.add(i + j * self.row)
}
},
}
}
}
impl IndexMut<(usize, usize)> for Matrix {
fn index_mut(&mut self, pair: (usize, usize)) -> &mut f64 {
let i = pair.0;
let j = pair.1;
let r = self.row;
let c = self.col;
assert!(i < self.row && j < self.col, "Index out of range");
let p = self.mut_ptr();
match self.shape {
Row => {
let idx = i * c + j;
unsafe {
&mut *p.add(idx)
}
}
Col => {
let idx = i + j * r;
unsafe {
&mut *p.add(idx)
}
}
}
}
}
impl FPMatrix for Matrix {
fn take_row(&self, n: usize) -> Self {
if n >= self.row {
return self.clone();
}
match self.shape {
Row => {
let new_data = self
.data
.clone()
.into_iter()
.take(n * self.col)
.collect::<Vec<f64>>();
matrix(new_data, n, self.col, Row)
}
Col => {
let mut temp_data: Vec<f64> = Vec::new();
for i in 0..n {
temp_data.extend(self.row(i));
}
matrix(temp_data, n, self.col, Row)
}
}
}
fn take_col(&self, n: usize) -> Self {
if n >= self.col {
return self.clone();
}
match self.shape {
Col => {
let new_data = self
.data
.clone()
.into_iter()
.take(n * self.row)
.collect::<Vec<f64>>();
matrix(new_data, self.row, n, Col)
}
Row => {
let mut temp_data: Vec<f64> = Vec::new();
for i in 0..n {
temp_data.extend(self.col(i));
}
matrix(temp_data, self.row, n, Col)
}
}
}
fn skip_row(&self, n: usize) -> Self {
assert!(n < self.row, "Skip range is larger than row of matrix");
let mut temp_data: Vec<f64> = Vec::new();
for i in n..self.row {
temp_data.extend(self.row(i));
}
matrix(temp_data, self.row - n, self.col, Row)
}
fn skip_col(&self, n: usize) -> Self {
assert!(n < self.col, "Skip range is larger than col of matrix");
let mut temp_data: Vec<f64> = Vec::new();
for i in n..self.col {
temp_data.extend(self.col(i));
}
matrix(temp_data, self.row, self.col - n, Col)
}
fn fmap<F>(&self, f: F) -> Matrix
where
F: Fn(f64) -> f64,
{
let result = self
.data
.iter()
.map(|x| f(*x))
.collect::<Vec<f64>>();
matrix(result, self.row, self.col, self.shape)
}
fn col_map<F>(&self, f: F) -> Matrix
where
F: Fn(Vec<f64>) -> Vec<f64>,
{
let mut result = matrix(vec![0f64; self.row * self.col], self.row, self.col, Col);
for i in 0..self.row {
result.subs_col(i, &f(self.col(i)));
}
result
}
fn row_map<F>(&self, f: F) -> Matrix
where
F: Fn(Vec<f64>) -> Vec<f64>,
{
let mut result = matrix(vec![0f64; self.row * self.col], self.row, self.col, Row);
for i in 0..self.col {
result.subs_row(i, &f(self.row(i)));
}
result
}
fn col_mut_map<F>(&mut self, f: F)
where
F: Fn(Vec<f64>) -> Vec<f64>,
{
for i in 0 .. self.col {
unsafe {
let mut p = self.col_mut(i);
let fv = f(self.col(i));
for j in 0..p.len() {
*p[j] = fv[j];
}
}
}
}
fn row_mut_map<F>(&mut self, f: F)
where
F: Fn(Vec<f64>) -> Vec<f64>,
{
for i in 0 .. self.col {
unsafe {
let mut p = self.row_mut(i);
let fv = f(self.row(i));
for j in 0 .. p.len() {
*p[j] = fv[j];
}
}
}
}
fn reduce<F, T>(&self, init: T, f: F) -> f64
where
F: Fn(f64, f64) -> f64,
T: convert::Into<f64>,
{
self.data
.iter()
.fold(init.into(), |x, y| f(x, *y))
}
fn zip_with<F>(&self, f: F, other: &Matrix) -> Self
where
F: Fn(f64, f64) -> f64,
{
assert_eq!(self.data.len(), other.data.len());
let mut a = other.clone();
if self.shape != other.shape {
a = a.change_shape();
}
let result = self
.data
.iter()
.zip(a.data.iter())
.map(|(x, y)| f(*x, *y))
.collect::<Vec<f64>>();
matrix(result, self.row, self.col, self.shape)
}
fn col_reduce<F>(&self, f: F) -> Vec<f64>
where F: Fn(Vec<f64>) -> f64 {
let mut v = vec![0f64; self.col];
for i in 0 .. self.col {
v[i] = f(self.col(i));
}
v
}
fn row_reduce<F>(&self, f: F) -> Vec<f64>
where F: Fn(Vec<f64>) -> f64 {
let mut v = vec![0f64; self.row];
for i in 0 .. self.row {
v[i] = f(self.row(i));
}
v
}
}
pub trait LinearAlgebra {
fn back_subs(&self, b: &Vec<f64>) -> Vec<f64>;
fn forward_subs(&self, b: &Vec<f64>) -> Vec<f64>;
fn lu(&self) -> PQLU;
fn waz(&self, d_form: Form) -> Option<WAZD>;
fn qr(&self) -> QR;
fn rref(&self) -> Matrix;
fn det(&self) -> f64;
fn block(&self) -> (Matrix, Matrix, Matrix, Matrix);
fn inv(&self) -> Matrix;
fn pseudo_inv(&self) -> Matrix;
fn solve(&self, b: &Vec<f64>, sk: SolveKind) -> Vec<f64>;
fn solve_mat(&self, m: &Matrix, sk: SolveKind) -> Matrix;
}
pub fn diag(n: usize) -> Matrix {
let mut v: Vec<f64> = vec![0f64; n * n];
for i in 0..n {
let idx = i * (n + 1);
v[idx] = 1f64;
}
matrix(v, n, n, Row)
}
#[derive(Debug, Clone)]
pub struct PQLU {
pub p: Vec<usize>,
pub q: Vec<usize>,
pub l: Matrix,
pub u: Matrix,
}
impl PQLU {
pub fn extract(&self) -> (Vec<usize>, Vec<usize>, Matrix, Matrix) {
(
self.p.clone(),
self.q.clone(),
self.l.clone(),
self.u.clone(),
)
}
pub fn det(&self) -> f64 {
let mut sgn_p = 1f64;
let mut sgn_q = 1f64;
for (i, &j) in self.p.iter().enumerate() {
if i != j {
sgn_p *= -1f64;
}
}
for (i, &j) in self.q.iter().enumerate() {
if i != j {
sgn_q *= -1f64;
}
}
self.u.diag().reduce(1f64, |x, y| x * y) * sgn_p * sgn_q
}
pub fn inv(&self) -> Matrix {
let (p, q, l, u) = self.extract();
let mut m = inv_u(u) * inv_l(l);
for (idx1, idx2) in q.into_iter().enumerate().rev() {
unsafe {
m.swap(idx1, idx2, Row);
}
}
for (idx1, idx2) in p.into_iter().enumerate().rev() {
unsafe {
m.swap(idx1, idx2, Col);
}
}
m
}
}
#[derive(Debug, Clone)]
pub struct WAZD {
pub w: Matrix,
pub z: Matrix,
pub d: Matrix,
}
#[derive(Debug, Copy, Clone)]
pub enum Form {
Diagonal,
Identity,
}
#[derive(Debug, Clone)]
pub struct QR {
pub q: Matrix,
pub r: Matrix,
}
impl QR {
pub fn q(&self) -> &Matrix {
&self.q
}
pub fn r(&self) -> &Matrix {
&self.r
}
}
#[derive(Debug, Copy, Clone)]
pub enum SolveKind {
LU,
WAZ,
}
impl LinearAlgebra for Matrix {
fn back_subs(&self, b: &Vec<f64>) -> Vec<f64> {
let n = self.col;
let mut y = vec![0f64; n];
y[n-1] = b[n-1] / self[(n-1, n-1)];
for i in (0 .. n - 1).rev() {
let mut s = 0f64;
for j in i+1 .. n {
s += self[(i, j)] * y[j];
}
y[i] = 1f64 / self[(i, i)] * (b[i] - s);
}
y
}
fn forward_subs(&self, b: &Vec<f64>) -> Vec<f64> {
let n = self.col;
let mut y = vec![0f64; n];
y[0] = b[0] / self[(0, 0)];
for i in 1 .. n {
let mut s = 0f64;
for j in 0 .. i {
s += self[(i, j)] * y[j];
}
y[i] = 1f64 / self[(i, i)] * (b[i] - s);
}
y
}
fn lu(&self) -> PQLU {
assert_eq!(self.col, self.row);
let n = self.row;
let len: usize = n * n;
let mut l = eye(n);
let mut u = matrix(vec![0f64; len], n, n, self.shape);
let mut temp = self.clone();
let (p, q) = gecp(&mut temp);
for i in 0 .. n {
for j in 0 .. i {
l[(i, j)] = -temp[(i, j)];
}
for j in i .. n {
u[(i, j)] = temp[(i, j)];
}
}
for i in 0 .. n - 1 {
unsafe {
let l_i = l.col_mut(i);
for j in i+1 .. l.col-1 {
let dst = p[j];
std::ptr::swap(l_i[j], l_i[dst]);
}
}
}
PQLU { p, q, l, u }
}
fn waz(&self, d_form: Form) -> Option<WAZD> {
match d_form {
Form::Diagonal => {
let n = self.row;
let mut w = eye(n);
let mut z = eye(n);
let mut d = eye(n);
let mut q = vec![0f64; n];
let mut p = vec![0f64; n];
for i in 0 .. n {
let m_i = self.col(i);
let pq = w.col(i).dot(&m_i);
d[(i, i)] = pq;
if pq == 0f64 {
return None;
}
for j in i+1 .. n {
q[j] = w.col(j).dot(&m_i) / pq;
p[j] = z.col(j).dot(&self.row(i)) / pq;
}
for j in i+1 .. n {
for k in 0 .. i+1 {
w[(k, j)] -= q[j] * w[(k, i)];
z[(k, j)] -= p[j] * z[(k, i)];
}
}
}
Some(
WAZD {
w,
z,
d
}
)
}
Form::Identity => {
let n = self.row;
let mut w = eye(n);
let mut z = eye(n);
let mut p = zeros(n, n);
let mut q = zeros(n, n);
for i in 0 .. n {
let m_i = self.col(i);
let p_ii = w.col(i).dot(&m_i);
p[(i,i)] = p_ii;
if p_ii == 0f64 {
return None;
}
for j in i+1 .. n {
q[(i, j)] = w.col(j).dot(&m_i) / p_ii;
p[(i, j)] = z.col(j).dot(&self.row(i)) / p_ii;
for k in 0 .. j {
w[(k, j)] -= q[(i, j)] * w[(k, i)];
z[(k, j)] -= p[(i, j)] * z[(k, i)];
}
}
unsafe {
let col_ptr = z.col_mut(i);
col_ptr.into_iter().for_each(|x| *x /= p_ii);
}
}
Some(
WAZD {
w,
z,
d: eye(n),
}
)
}
}
}
#[allow(non_snake_case)]
fn qr(&self) -> QR {
let m = self.row;
let n = self.col;
let mut r = self.clone();
let mut q = eye(m);
let sub = if m == n { 1 } else { 0 };
for i in 0 .. n - sub {
let mut H = eye(m);
let hh = gen_householder(&self.col(i).skip(i));
for j in i .. m {
for k in i .. m {
H[(j, k)] = hh[(j-i, k-i)];
}
}
q = &q * &H;
r = &H * &r;
}
QR {
q,
r,
}
}
fn rref(&self) -> Matrix {
let mut lead = 0usize;
let mut result = self.clone();
for r in 0 .. self.row {
if self.col <= lead {
break;
}
let mut i = r;
while result[(i, lead)] == 0f64 {
i += 1;
if self.row == i {
i = r;
lead += 1;
if self.col == lead {
break;
}
}
}
unsafe {
result.swap(i, r, Row);
}
let tmp = result[(r, lead)];
if tmp != 0f64 {
unsafe {
result.row_mut(r).iter_mut().for_each(|t| *(*t) /= tmp);
}
}
for j in 0 .. result.row {
if j != r {
let tmp1 = result.row(r).mul_scalar(result[(j, lead)]);
let tmp2 = result.row(j).sub_vec(&tmp1);
result.subs_row(j, &tmp2);
}
}
lead += 1;
}
result
}
fn det(&self) -> f64 {
assert_eq!(self.row, self.col);
match () {
#[cfg(feature = "O3")]
() => {
let opt_dgrf = lapack_dgetrf(self);
match opt_dgrf {
None => NAN,
Some(dgrf) => match dgrf.status {
LAPACK_STATUS::Singular => 0f64,
LAPACK_STATUS::NonSingular => {
let mat = &dgrf.fact_mat;
let ipiv = &dgrf.ipiv;
let n = mat.col;
let mut sgn = 1i32;
let mut d = 1f64;
for i in 0..n {
d *= mat[(i, i)];
}
for i in 0..ipiv.len() {
if ipiv[i] - 1 != i as i32 {
sgn *= -1;
}
}
(sgn as f64) * d
}
},
}
}
_ => {
self.lu().det()
}
}
}
fn block(&self) -> (Self, Self, Self, Self) {
let r = self.row;
let c = self.col;
let l_r = self.row / 2;
let l_c = self.col / 2;
let r_l = r - l_r;
let c_l = c - l_c;
let mut m1 = matrix(vec![0f64; l_r * l_c], l_r, l_c, self.shape);
let mut m2 = matrix(vec![0f64; l_r * c_l], l_r, c_l, self.shape);
let mut m3 = matrix(vec![0f64; r_l * l_c], r_l, l_c, self.shape);
let mut m4 = matrix(vec![0f64; r_l * c_l], r_l, c_l, self.shape);
for idx_row in 0..r {
for idx_col in 0..c {
match (idx_row, idx_col) {
(i, j) if (i < l_r) && (j < l_c) => {
m1[(i, j)] = self[(i, j)];
}
(i, j) if (i < l_r) && (j >= l_c) => {
m2[(i, j - l_c)] = self[(i, j)];
}
(i, j) if (i >= l_r) && (j < l_c) => {
m3[(i - l_r, j)] = self[(i, j)];
}
(i, j) if (i >= l_r) && (j >= l_c) => {
m4[(i - l_r, j - l_c)] = self[(i, j)];
}
_ => (),
}
}
}
(m1, m2, m3, m4)
}
fn inv(&self) -> Self {
match () {
#[cfg(feature = "O3")]
() => {
let opt_dgrf = lapack_dgetrf(self);
match opt_dgrf {
None => panic!("Singular matrix (opt_dgrf)"),
Some(dgrf) => lapack_dgetri(&dgrf).unwrap(),
}
}
_ => self.lu().inv(),
}
}
fn pseudo_inv(&self) -> Self {
let xt = self.t();
let xtx = &xt * self;
xtx.inv() * xt
}
fn solve(&self, b: &Vec<f64>, sk: SolveKind) -> Vec<f64> {
match sk {
#[cfg(feature = "O3")]
SolveKind::LU => {
let opt_dgrf = lapack_dgetrf(self);
match opt_dgrf {
None => panic!("Try solve for Singluar matrix"),
Some(dgrf) => match dgrf.status {
LAPACK_STATUS::Singular => panic!("Try solve for Singluar matrix"),
LAPACK_STATUS::NonSingular => lapack_dgetrs(&dgrf, &(b.into())).unwrap().into(),
},
}
}
#[cfg(not(feature = "O3"))]
SolveKind::LU => {
let lu = self.lu();
let (p, q, l, u) = lu.extract();
let mut v = b.clone();
v.swap_with_perm(&p.into_iter().enumerate().collect());
let z = l.forward_subs(&v);
let mut y = u.back_subs(&z);
y.swap_with_perm(&q.into_iter().enumerate().rev().collect());
y
}
SolveKind::WAZ => {
let wazd = match self.waz(Form::Identity) {
None => panic!("Can't solve by WAZ with Singular matrix!"),
Some(obj) => obj,
};
let x = &wazd.w.t() * b;
let x = &wazd.z * &x;
x
}
}
}
fn solve_mat(&self, m: &Matrix, sk: SolveKind) -> Matrix {
match sk {
#[cfg(feature = "O3")]
SolveKind::LU => {
let opt_dgrf = lapack_dgetrf(self);
match opt_dgrf {
None => panic!("Try solve for Singluar matrix"),
Some(dgrf) => match dgrf.status {
LAPACK_STATUS::Singular => panic!("Try solve for Singluar matrix"),
LAPACK_STATUS::NonSingular => lapack_dgetrs(&dgrf, m).unwrap(),
},
}
}
#[cfg(not(feature = "O3"))]
SolveKind::LU => {
let lu = self.lu();
let (p, q, l, u) = lu.extract();
let mut x = matrix(vec![0f64; self.col * m.col], self.col, m.col, Col);
for i in 0 .. m.col {
let mut v = m.col(i).clone();
for (r, &s) in p.iter().enumerate() {
v.swap(r, s);
}
let z = l.forward_subs(&v);
let mut y = u.back_subs(&z);
for (r, &s) in q.iter().enumerate() {
y.swap(r, s);
}
unsafe {
let mut c = x.col_mut(i);
copy_vec_ptr(&mut c, &y);
}
}
x
}
SolveKind::WAZ => {
let wazd = match self.waz(Form::Identity) {
None => panic!("Try solve for Singular matrix"),
Some(obj) => obj,
};
let x = &wazd.w.t() * m;
let x = &wazd.z * &x;
x
}
}
}
}
#[allow(non_snake_case)]
pub fn solve(A: &Matrix, b: &Matrix, sk: SolveKind) -> Matrix {
A.solve_mat(b, sk)
}
impl MutMatrix for Matrix {
unsafe fn col_mut(&mut self, idx: usize) -> Vec<*mut f64> {
assert!(idx < self.col, "Index out of range");
match self.shape {
Shape::Col => {
let mut v: Vec<*mut f64> = Vec::with_capacity(self.row);
v.set_len(self.row);
let start_idx = idx * self.row;
let p = self.mut_ptr();
for (i, j) in (start_idx .. start_idx + v.len()).enumerate() {
v[i] = p.add(j);
}
v
}
Shape::Row => {
let mut v: Vec<*mut f64> = Vec::with_capacity(self.row);
v.set_len(self.row);
let p = self.mut_ptr();
for i in 0 .. v.len() {
v[i] = p.add(idx + i * self.col);
}
v
}
}
}
unsafe fn row_mut(&mut self, idx: usize) -> Vec<*mut f64> {
assert!(idx < self.row, "Index out of range");
match self.shape {
Shape::Row => {
let mut v: Vec<*mut f64> = Vec::with_capacity(self.col);
v.set_len(self.col);
let start_idx = idx * self.col;
let p = self.mut_ptr();
for (i, j) in (start_idx .. start_idx + v.len()).enumerate() {
v[i] = p.add(j);
}
v
}
Shape::Col => {
let mut v: Vec<*mut f64> = Vec::with_capacity(self.col);
v.set_len(self.col);
let p = self.mut_ptr();
for i in 0 .. v.len() {
v[i] = p.add(idx + i * self.row);
}
v
}
}
}
unsafe fn swap(&mut self, idx1: usize, idx2: usize, shape: Shape) {
match shape {
Shape::Col => {
swap_vec_ptr(&mut self.col_mut(idx1), &mut self.col_mut(idx2))
}
Shape::Row => {
swap_vec_ptr(&mut self.row_mut(idx1), &mut self.row_mut(idx2))
}
}
}
unsafe fn swap_with_perm(&mut self, p: &Vec<(usize, usize)>, shape: Shape) {
for (i, j) in p.iter() {
self.swap(*i, *j, shape)
}
}
}
pub fn combine(m1: Matrix, m2: Matrix, m3: Matrix, m4: Matrix) -> Matrix {
let l_r = m1.row;
let l_c = m1.col;
let c_l = m2.col;
let r_l = m3.row;
let r = l_r + r_l;
let c = l_c + c_l;
let mut m = matrix(vec![0f64; r * c], r, c, m1.shape);
for idx_row in 0..r {
for idx_col in 0..c {
match (idx_row, idx_col) {
(i, j) if (i < l_r) && (j < l_c) => {
m[(i, j)] = m1[(i, j)];
}
(i, j) if (i < l_r) && (j >= l_c) => {
m[(i, j)] = m2[(i, j - l_c)];
}
(i, j) if (i >= l_r) && (j < l_c) => {
m[(i, j)] = m3[(i - l_r, j)];
}
(i, j) if (i >= l_r) && (j >= l_c) => {
m[(i, j)] = m4[(i - l_r, j - l_c)];
}
_ => (),
}
}
}
m
}
pub fn inv_l(l: Matrix) -> Matrix {
let mut m = l.clone();
match l.row {
1 => l,
2 => {
m[(1, 0)] = -m[(1, 0)];
m
}
_ => {
let (l1, l2, l3, l4) = l.block();
let m1 = inv_l(l1);
let m2 = l2;
let m4 = inv_l(l4);
let m3 = -(&(&m4 * &l3) * &m1);
combine(m1, m2, m3, m4)
}
}
}
pub fn inv_u(u: Matrix) -> Matrix {
let mut w = u.clone();
match u.row {
1 => {
w[(0, 0)] = 1f64 / w[(0, 0)];
w
}
2 => {
let a = w[(0, 0)];
let b = w[(0, 1)];
let c = w[(1, 1)];
let d = a * c;
w[(0, 0)] = 1f64 / a;
w[(0, 1)] = -b / d;
w[(1, 1)] = 1f64 / c;
w
}
_ => {
let (u1, u2, u3, u4) = u.block();
let m1 = inv_u(u1);
let m3 = u3;
let m4 = inv_u(u4);
let m2 = -(m1.clone() * u2 * m4.clone());
combine(m1, m2, m3, m4)
}
}
}
fn matmul(a: &Matrix, b: &Matrix) -> Matrix {
let mut c = matrix(vec![0f64; a.row * b.col], a.row, b.col, a.shape);
gemm(1f64, a, b, 0f64, &mut c);
c
}
pub fn gemm(alpha: f64, a: &Matrix, b: &Matrix, beta: f64, c: &mut Matrix) {
let m = a.row;
let k = a.col;
let n = b.col;
let (rsa, csa) = match a.shape {
Row => {
(a.col as isize, 1isize)
}
Col => {
(1isize, a.row as isize)
}
};
let (rsb, csb) = match b.shape {
Row => {
(b.col as isize, 1isize)
}
Col => {
(1isize, b.row as isize)
}
};
let (rsc, csc) = match c.shape {
Row => {
(c.col as isize, 1isize)
}
Col => {
(1isize, c.row as isize)
}
};
unsafe {
matrixmultiply::dgemm(
m,
k,
n,
alpha,
a.ptr(),
rsa,
csa,
b.ptr(),
rsb,
csb,
beta,
c.mut_ptr(),
rsc,
csc,
)
}
}
pub fn gemv(alpha: f64, a: &Matrix, b: &Vec<f64>, beta: f64, c: &mut Vec<f64>) {
let m = a.row;
let k = a.col;
let n = 1usize;
let (rsa, csa) = match a.shape {
Row => (a.col as isize, 1isize),
Col => (1isize, a.row as isize)
};
let (rsb, csb) = (1isize, 1isize);
let (rsc, csc) = (1isize, 1isize);
unsafe {
matrixmultiply::dgemm(
m,
k,
n,
alpha,
a.ptr(),
rsa,
csa,
b.as_ptr(),
rsb,
csb,
beta,
c.as_mut_ptr(),
rsc,
csc,
)
}
}
pub fn gevm(alpha: f64, a: &Vec<f64>, b: &Matrix, beta: f64, c: &mut Vec<f64>) {
let m = 1usize;
let k = a.len();
let n = b.col;
let (rsa, csa) = (1isize, 1isize);
let (rsb, csb) = match b.shape {
Row => (b.col as isize, 1isize),
Col => (1isize, b.row as isize)
};
let (rsc, csc) = (1isize, 1isize);
unsafe {
matrixmultiply::dgemm(
m,
k,
n,
alpha,
a.as_ptr(),
rsa,
csa,
b.ptr(),
rsb,
csb,
beta,
c.as_mut_ptr(),
rsc,
csc,
)
}
}
#[cfg(feature = "O3")]
pub fn blas_mul(m1: &Matrix, m2: &Matrix) -> Matrix {
let m = m1.row;
let k = m1.col;
assert_eq!(k, m2.row);
let n = m2.col;
let m_i32 = m as i32;
let n_i32 = n as i32;
let k_i32 = k as i32;
let a = &m1.data;
let b = &m2.data;
let mut c = vec![0f64; m * n];
match (m1.shape, m2.shape) {
(Row, Row) => {
unsafe {
dgemm(
b'N', b'N', n_i32, m_i32, k_i32, 1f64, b, n_i32, a, k_i32, 0f64, &mut c, n_i32,
);
}
matrix(c, m, n, Row)
}
(Row, Col) => {
unsafe {
dgemm(
b'T', b'N', n_i32, m_i32, k_i32, 1f64, b, k_i32, a, k_i32, 0f64, &mut c, n_i32,
);
}
matrix(c, m, n, Row)
}
(Col, Col) => {
unsafe {
dgemm(
b'N', b'N', m_i32, n_i32, k_i32, 1f64, a, m_i32, b, k_i32, 0f64, &mut c, m_i32,
);
}
matrix(c, m, n, Col)
}
(Col, Row) => {
unsafe {
dgemm(
b'N', b'T', m_i32, n_i32, k_i32, 1f64, a, m_i32, b, n_i32, 0f64, &mut c, m_i32,
);
}
matrix(c, m, n, Col)
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum LAPACK_STATUS {
Singular,
NonSingular,
}
#[derive(Debug, Clone)]
pub struct DGETRF {
pub fact_mat: Matrix,
pub ipiv: Vec<i32>,
pub status: LAPACK_STATUS,
}
#[derive(Debug, Clone)]
pub struct DGEQRF {
pub fact_mat: Matrix,
pub tau: Vec<f64>,
pub status: LAPACK_STATUS,
}
#[cfg(feature = "O3")]
pub fn lapack_dgetrf(mat: &Matrix) -> Option<DGETRF> {
let m = mat.row;
let n = mat.col;
let m_i32 = m as i32;
let n_i32 = n as i32;
let mut a = match mat.shape {
Row => mat.change_shape().data.clone(),
Col => mat.data.clone(),
};
let mut info = 0i32;
let mut ipiv: Vec<i32> = vec![0i32; std::cmp::min(m, n)];
unsafe {
dgetrf(m_i32, n_i32, &mut a, m_i32, &mut ipiv, &mut info);
}
if info < 0 {
None
} else if info == 0 {
Some(DGETRF {
fact_mat: matrix(a, m, n, Col),
ipiv,
status: LAPACK_STATUS::NonSingular,
})
} else {
Some(DGETRF {
fact_mat: matrix(a, m, n, Col),
ipiv,
status: LAPACK_STATUS::Singular,
})
}
}
#[cfg(feature = "O3")]
pub fn lapack_dgetri(dgrf: &DGETRF) -> Option<Matrix> {
let mut result = dgrf.fact_mat.clone();
let ipiv = &dgrf.ipiv;
let (n, lda) = (result.col as i32, result.row as i32);
let mut info = 0i32;
let mut work = vec![0f64; result.col];
unsafe {
dgetri(n, &mut result.data, lda, ipiv, &mut work, -1, &mut info);
}
let optimal_lwork = work[0] as usize;
let mut optimal_work = vec![0f64; optimal_lwork];
unsafe {
dgetri(
n,
&mut result.data,
lda,
ipiv,
&mut optimal_work,
optimal_lwork as i32,
&mut info,
);
}
if info == 0 {
Some(result)
} else {
None
}
}
#[allow(non_snake_case)]
#[cfg(feature = "O3")]
pub fn lapack_dgetrs(dgrf: &DGETRF, b: &Matrix) -> Option<Matrix> {
match b.shape {
Row => lapack_dgetrs(dgrf, &b.change_shape()),
Col => {
let A = &dgrf.fact_mat;
let mut b_vec = b.data.clone();
let ipiv = &dgrf.ipiv;
let n = A.col as i32;
let nrhs = b.col as i32;
let lda = A.row as i32;
let ldb = b.row as i32;
let mut info = 0i32;
unsafe {
dgetrs(
b'N', n, nrhs, &A.data, lda, ipiv, &mut b_vec, ldb, &mut info,
);
}
if info == 0 {
Some(matrix(b_vec, A.col, b.col, Col))
} else {
None
}
}
}
}
#[allow(non_snake_case)]
#[cfg(feature = "O3")]
pub fn lapack_dgeqrf(mat: &Matrix) -> Option<DGEQRF> {
match mat.shape {
Row => lapack_dgeqrf(&mat.change_shape()),
Col => {
let m = mat.row as i32;
let n = mat.col as i32;
let mut A = mat.clone();
let mut tau = vec![0f64; min(mat.row, mat.col)];
let mut work = vec![0f64; mat.col];
let mut info = 0i32;
unsafe {
dgeqrf(m, n, &mut A.data, m, &mut tau, &mut work, -1, &mut info);
}
let optimal_lwork = work[0] as usize;
let mut optimal_work = vec![0f64; optimal_lwork];
unsafe {
dgeqrf(
m,
n,
&mut A.data,
m,
&mut tau,
&mut optimal_work,
optimal_lwork as i32,
&mut info,
);
}
if info == 0 {
Some(DGEQRF {
fact_mat: A,
tau,
status: LAPACK_STATUS::NonSingular,
})
} else if info > 0 {
Some(DGEQRF {
fact_mat: A,
tau,
status: LAPACK_STATUS::Singular,
})
} else {
None
}
}
}
}
#[allow(non_snake_case)]
#[cfg(feature = "O3")]
impl DGETRF {
pub fn get_P(&self) -> Vec<i32> {
self.ipiv.clone()
}
pub fn get_L(&self) -> Matrix {
let mut l = self.fact_mat.clone();
for i in 0..l.row {
l[(i, i)] = 1f64;
for j in i + 1..l.col {
l[(i, j)] = 0f64;
}
}
l
}
pub fn get_U(&self) -> Matrix {
let mut u = self.fact_mat.clone();
for i in 0..u.row {
for j in 0..i {
u[(i, j)] = 0f64;
}
}
u
}
pub fn get_cond(&self) -> Option<f64> {
let A = &self.fact_mat;
let lda = A.row as i32;
let n = A.col as i32;
let anorm = A.norm(Norm::L1);
let mut work = vec![0f64; 4 * A.col];
let mut iwork = vec![0i32; A.col];
let mut info = 0i32;
let mut rcond = 0f64;
unsafe {
dgecon(
b'1', n, &A.data, lda, anorm, &mut rcond, &mut work, &mut iwork, &mut info,
);
}
if info == 0 {
Some(rcond)
} else {
None
}
}
}
#[allow(non_snake_case)]
#[cfg(feature = "O3")]
impl DGEQRF {
pub fn get_Q(&self) -> Matrix {
let mut A = self.fact_mat.clone();
let m = A.row as i32;
let n = A.col as i32;
let k = min(m, n);
let lda = m;
let tau = &self.tau;
let mut lwork = -1i32;
let mut work = vec![0f64; 1];
let mut info = 0i32;
unsafe {
dorgqr(m, n, k, &mut A.data, lda, tau, &mut work, lwork, &mut info);
}
lwork = work[0] as i32;
work = vec![0f64; lwork as usize];
unsafe {
dorgqr(m, n, k, &mut A.data, lda, tau, &mut work, lwork, &mut info);
}
A
}
pub fn get_R(&self) -> Matrix {
let qr = &self.fact_mat;
let row = min(qr.row, qr.col);
let col = qr.col;
let mut result = matrix(vec![0f64; row * col], row, col, qr.shape);
for i in 0..row {
for j in i..col {
result[(i, j)] = qr[(i, j)];
}
}
result
}
}
#[allow(non_snake_case)]
pub fn gen_householder(a: &Vec<f64>) -> Matrix {
let mut v = a.fmap(|t| t / (a[0] + a.norm(Norm::L2) * a[0].signum()));
v[0] = 1f64;
let mut H = eye(a.len());
let vt: Matrix = v.clone().into();
H = H - 2f64 / v.dot(&v) * (&vt * &vt.t());
H
}
#[allow(dead_code)]
fn gepp(m: &mut Matrix) -> Vec<usize> {
let mut r = vec![0usize; m.col-1];
for k in 0 .. (m.col - 1) {
let r_k = m.col(k).into_iter().skip(k).enumerate().max_by(|x1, x2| x1.1.abs().partial_cmp(&x2.1.abs()).unwrap()).unwrap().0 + k;
r[k] = r_k;
for j in k .. m.col {
unsafe {
std::ptr::swap(&mut m[(k,j)], &mut m[(r_k, j)]);
println!("Swap! k:{}, r_k:{}", k, r_k);
}
}
for i in k+1 .. m.col {
m[(i,k)] = - m[(i,k)] / m[(k,k)];
}
for i in k+1 .. m.col {
for j in k+1 .. m.col {
m[(i, j)] += m[(i, k)] * m[(k, j)];
}
}
}
r
}
fn gecp(m: &mut Matrix) -> (Vec<usize>, Vec<usize>) {
let n = m.col;
let mut r = vec![0usize; n-1];
let mut s = vec![0usize; n-1];
for k in 0 .. n - 1 {
let (r_k, s_k) = match m.shape {
Col => {
let mut row_ics = 0usize;
let mut col_ics = 0usize;
let mut max_val = 0f64;
for i in k .. n {
let c = m.col(i)
.into_iter()
.skip(k)
.enumerate()
.max_by(|x1, x2| x1.1.abs().partial_cmp(&x2.1.abs()).unwrap()).unwrap();
let c_ics = c.0 + k;
let c_val = c.1.abs();
if c_val > max_val {
row_ics = c_ics;
col_ics = i;
max_val = c_val;
}
}
(row_ics, col_ics)
}
Row => {
let mut row_ics = 0usize;
let mut col_ics = 0usize;
let mut max_val = 0f64;
for i in k .. n {
let c = m.row(i)
.into_iter()
.skip(k)
.enumerate()
.max_by(|x1, x2| x1.1.abs().partial_cmp(&x2.1.abs()).unwrap()).unwrap();
let c_ics = c.0 + k;
let c_val = c.1.abs();
if c_val > max_val {
col_ics = c_ics;
row_ics = i;
max_val = c_val;
}
}
(row_ics, col_ics)
}
};
r[k] = r_k;
s[k] = s_k;
for j in k .. n {
unsafe {
std::ptr::swap(&mut m[(k, j)], &mut m[(r_k, j)]);
}
}
for i in 0 .. n {
unsafe {
std::ptr::swap(&mut m[(i, k)], &mut m[(i, s_k)]);
}
}
for i in k+1 .. n {
m[(i, k)] = - m[(i, k)] / m[(k, k)];
for j in k+1 .. n {
m[(i, j)] += m[(i, k)] * m[(k, j)];
}
}
}
(r, s)
}