use crate::error::IError;
use crate::error::IResult;
use crate::matrix::Matrix;
use crate::num::number::Fractional;
use crate::num::number::Number;
use crate::num::number::One;
use crate::num::number::Zero;
use crate::utils::state::SColumn;
use crate::utils::state::SRow;
pub type RowVector<T> = Matrix<T, SRow>;
pub type ColumnVector<T> = Matrix<T, SColumn>;
pub fn identity_vector_row<T>(col: usize, index: usize) -> IResult<RowVector<T>>
where
T: Clone + Zero + One,
{
let mut vector = RowVector::zeros(1, col)?;
vector.set_element(1, index, T::one())?;
Ok(vector)
}
pub fn identity_vector_column<T>(row: usize, index: usize) -> IResult<ColumnVector<T>>
where
T: Clone + Zero + One,
{
let mut vector = ColumnVector::zeros(row, 1)?;
vector.set_element(index, 1, T::one())?;
Ok(vector)
}
pub fn times_c<T>(vec1: ColumnVector<T>, vec2: ColumnVector<T>) -> IResult<ColumnVector<T>>
where
T: Number,
{
if vec1.row() != 3 {
Err(IError::IncompatibleShape((3, 1), (vec1.row(), 1)))
} else if vec2.row() != 3 {
Err(IError::IncompatibleShape((3, 1), (vec2.row(), 1)))
} else {
ColumnVector::create(
3,
1,
vec![
vec1.get_element(2, 1)?.clone() * vec2.get_element(3, 1)?.clone()
- vec1.get_element(3, 1)?.clone() * vec2.get_element(2, 1)?.clone(),
vec1.get_element(3, 1)?.clone() * vec2.get_element(1, 1)?.clone()
- vec1.get_element(1, 1)?.clone() * vec2.get_element(3, 1)?.clone(),
vec1.get_element(1, 1)?.clone() * vec2.get_element(2, 1)?.clone()
- vec1.get_element(2, 1)?.clone() * vec2.get_element(1, 1)?.clone(),
],
)
}
}
pub fn times_d<T>(vec1: RowVector<T>, vec2: ColumnVector<T>) -> IResult<T>
where
T: Number,
{
if vec1.column() != vec2.row() {
Err(IError::IncompatibleShape(
(vec1.column(), 1),
(vec2.row(), 1),
))
} else {
Ok(vec1
.get_inner()
.zip(vec2.get_inner())
.map(|(e1, e2)| e1.clone() * e2.clone())
.sum())
}
}
pub fn convolution<T>(vec1: ColumnVector<T>, vec2: ColumnVector<T>) -> IResult<ColumnVector<T>>
where
T: Number,
{
let edge: usize = vec1.row() + vec2.row() - 1;
let mut conv: ColumnVector<T> = ColumnVector::zeros(edge, 1)?;
for k in 1..=edge {
for i in 1..=(k.min(vec1.row())) {
let j = k + 1 - i;
if (1..=vec2.row()).contains(&j) {
conv.set_element(
k,
1,
conv.get_element(k, 1)?.clone()
+ vec1.get_element(i, 1)?.clone() * vec2.get_element(j, 1)?.clone(),
)?;
}
}
}
Ok(conv)
}
pub fn times_v<T>(vector_c: ColumnVector<T>, vector_r: RowVector<T>) -> IResult<Matrix<T>>
where
T: Number,
{
let mut mat = Matrix::<T>::create(
vector_c.row(),
vector_r.column(),
vec![T::default(); vector_c.row() * vector_r.column()],
)?;
for r in 1..=vector_c.row() {
for c in 1..=vector_r.column() {
mat.set_element(
r,
c,
vector_c.get_element(r, 1)?.clone() * vector_r.get_element(1, c)?.clone(),
)?;
}
}
Ok(mat)
}
pub fn euclid_norm<T>(vc: ColumnVector<T>) -> IResult<T>
where
T: Fractional,
{
times_d(vc.conjugate_transpose()?, vc)?.nsqrt()
}
pub fn root_mean_square<T>(vc: ColumnVector<T>) -> IResult<T>
where
T: Fractional,
{
let row = vc.row();
euclid_norm(vc)?.ndiv(T::from_usize(row).nsqrt()?)
}