#[cfg(feature = "O3")]
extern crate blas;
#[cfg(feature = "parallel")]
use crate::rayon::iter::{
IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
IntoParallelRefMutIterator, ParallelIterator,
};
#[cfg(feature = "O3")]
use blas::{daxpy, ddot, dnrm2, idamax};
use crate::structure::matrix::{matrix, Matrix, Row};
use crate::traits::{
fp::FPVector,
general::Algorithm,
math::{InnerProduct, LinearOp, Norm, Normed, Vector, VectorProduct},
mutable::MutFP,
pointer::{Oxide, Redox, RedoxCommon},
};
#[cfg(feature = "parallel")]
use crate::traits::{
fp::ParallelFPVector,
math::{ParallelInnerProduct, ParallelNormed, ParallelVectorProduct},
mutable::ParallelMutFP,
};
use std::cmp::min;
impl FPVector for Vec<f64> {
type Scalar = f64;
fn fmap<F>(&self, f: F) -> Vec<f64>
where
F: Fn(f64) -> f64,
{
let mut v = self.clone();
v.iter_mut().for_each(|x| *x = f(*x));
v
}
fn reduce<F, T>(&self, init: T, f: F) -> f64
where
F: Fn(f64, f64) -> f64,
T: Into<f64> + Copy,
{
self.iter().fold(init.into(), |x, &y| f(x, y))
}
fn zip_with<F>(&self, f: F, other: &Vec<f64>) -> Vec<f64>
where
F: Fn(f64, f64) -> f64,
{
self.iter()
.zip(other)
.map(|(x, y)| f(*x, *y))
.collect::<Vec<f64>>()
}
fn filter<F>(&self, f: F) -> Vec<f64>
where
F: Fn(f64) -> bool,
{
self.clone()
.into_iter()
.filter(|x| f(*x))
.collect::<Vec<f64>>()
}
fn take(&self, n: usize) -> Vec<f64> {
let mut v = vec![0f64; n];
v[..n].copy_from_slice(&self[..n]);
v
}
fn skip(&self, n: usize) -> Vec<f64> {
let l = self.len();
let mut v = vec![0f64; l - n];
for (i, j) in (n..l).enumerate() {
v[i] = self[j];
}
v
}
fn sum(&self) -> f64 {
self.iter().sum()
}
fn prod(&self) -> f64 {
self.iter().product()
}
}
#[cfg(feature = "parallel")]
impl ParallelFPVector for Vec<f64> {
type Scalar = f64;
fn par_fmap<F>(&self, f: F) -> Vec<f64>
where
F: Fn(f64) -> f64 + Sync + Send,
{
let mut v = self.clone();
v.par_iter_mut().for_each(|x| *x = f(*x));
v
}
fn par_reduce<F, T>(&self, _init: T, f: F) -> f64
where
F: Fn(f64, f64) -> f64 + Send + Sync,
T: Into<f64> + Send + Sync + Copy,
{
self.par_iter()
.cloned()
.reduce_with(f)
.expect("Unable to perform parallel reduce operation")
}
fn par_zip_with<F>(&self, f: F, other: &Vec<f64>) -> Vec<f64>
where
F: Fn(f64, f64) -> f64 + Send + Sync,
{
self.par_iter()
.zip(other)
.map(|(x, y)| f(*x, *y))
.collect::<Vec<f64>>()
}
fn par_filter<F>(&self, f: F) -> Vec<f64>
where
F: Fn(f64) -> bool + Send + Sync,
{
self.clone()
.into_par_iter()
.filter(|x| f(*x))
.collect::<Vec<f64>>()
}
}
pub fn map<F, T>(f: F, xs: &[T]) -> Vec<T>
where
F: Fn(T) -> T,
T: Default + Copy,
{
let l = xs.len();
let mut result = vec![T::default(); l];
for i in 0..l {
result[i] = f(xs[i]);
}
result
}
#[cfg(feature = "parallel")]
pub fn par_map<F, T>(f: F, xs: &[T]) -> Vec<T>
where
F: Fn(T) -> T + Send + Sync,
T: Default + Copy + Send + Sync,
{
let mut result = vec![T::default(); xs.len()];
result.par_iter_mut().for_each(|x| *x = f(*x));
result
}
pub fn reduce<F, T>(f: F, init: T, xs: &[T]) -> T
where
F: Fn(T, T) -> T,
T: Copy,
{
let mut s = init;
for &x in xs {
s = f(s, x);
}
s
}
pub fn zip_with<F, T>(f: F, xs: &[T], ys: &[T]) -> Vec<T>
where
F: Fn(T, T) -> T,
T: Default + Copy,
{
let l = min(xs.len(), ys.len());
let mut result = vec![T::default(); l];
for i in 0..l {
result[i] = f(xs[i], ys[i]);
}
result
}
#[cfg(feature = "parallel")]
pub fn par_zip_with<F, T>(f: F, xs: &[T], ys: &[T]) -> Vec<T>
where
F: Fn(T, T) -> T + Send + Sync,
T: Default + Copy + Send + Sync,
{
xs.par_iter()
.zip(ys.into_par_iter())
.map(|(x, y)| f(*x, *y))
.collect::<Vec<T>>()
}
impl MutFP for Vec<f64> {
type Scalar = f64;
fn mut_map<F>(&mut self, f: F)
where
F: Fn(Self::Scalar) -> Self::Scalar,
{
for x in self.iter_mut() {
*x = f(*x);
}
}
fn mut_zip_with<F>(&mut self, f: F, other: &Self)
where
F: Fn(Self::Scalar, Self::Scalar) -> Self::Scalar,
{
for i in 0..self.len() {
self[i] = f(self[i], other[i]);
}
}
}
#[cfg(feature = "parallel")]
impl ParallelMutFP for Vec<f64> {
type Scalar = f64;
fn par_mut_map<F>(&mut self, f: F)
where
F: Fn(Self::Scalar) -> Self::Scalar + Send + Sync,
{
self.par_iter_mut().for_each(|x| *x = f(*x));
}
fn par_mut_zip_with<F>(&mut self, f: F, other: &Self)
where
F: Fn(Self::Scalar, Self::Scalar) -> Self::Scalar + Send + Sync,
{
self.par_iter_mut()
.zip(other.into_par_iter())
.for_each(|(x, y)| *x = f(*x, *y));
}
}
impl Algorithm for Vec<f64> {
type Scalar = f64;
fn rank(&self) -> Vec<usize> {
let l = self.len();
let idx = (1..(l + 1)).collect::<Vec<usize>>();
let mut vec_tup = self
.clone()
.into_iter()
.zip(idx.clone())
.collect::<Vec<(f64, usize)>>();
vec_tup.sort_by(|x, y| x.0.partial_cmp(&y.0).unwrap().reverse());
let indices = vec_tup.into_iter().map(|(_, y)| y).collect::<Vec<usize>>();
idx.into_iter()
.map(|x| indices.clone().into_iter().position(|t| t == x).unwrap())
.collect::<Vec<usize>>()
}
fn sign(&self) -> f64 {
let l = self.len();
let mut v = self.clone();
let mut sgn = 1f64;
for i in 0..(l - 1) {
for j in 0..(l - 1 - i) {
if v[j] > v[j + 1] {
sgn *= -1f64;
let (a, b) = (v[j], v[j + 1]);
v[j] = b;
v[j + 1] = a;
}
}
}
sgn
}
fn arg_max(&self) -> usize {
#[cfg(feature = "O3")]
{
let n_i32 = self.len() as i32;
let idx: usize;
unsafe {
idx = idamax(n_i32, self, 1) - 1;
}
idx
}
#[cfg(not(feature = "O3"))]
{
self.iter()
.enumerate()
.fold((0usize, f64::MIN), |acc, (ics, &val)| {
if acc.1 < val {
(ics, val)
} else {
acc
}
})
.0
}
}
fn arg_min(&self) -> usize {
self.iter()
.enumerate()
.fold((0usize, f64::MAX), |acc, (ics, &val)| {
if acc.1 > val {
(ics, val)
} else {
acc
}
})
.0
}
fn max(&self) -> f64 {
#[cfg(feature = "O3")]
{
let n_i32 = self.len() as i32;
let idx: usize;
unsafe {
idx = idamax(n_i32, self, 1) - 1;
}
self[idx]
}
#[cfg(not(feature = "O3"))]
{
self.iter()
.fold(f64::MIN, |acc, &val| if acc < val { val } else { acc })
}
}
fn min(&self) -> f64 {
self.iter()
.fold(f64::MAX, |acc, &val| if acc > val { val } else { acc })
}
fn swap_with_perm(&mut self, p: &[(usize, usize)]) {
for (i, j) in p.iter() {
self.swap(*i, *j);
}
}
}
impl Vector for Vec<f64> {
type Scalar = f64;
fn add_vec(&self, rhs: &Self) -> Self {
self.zip_with(|x, y| x + y, rhs)
}
fn sub_vec(&self, rhs: &Self) -> Self {
self.zip_with(|x, y| x - y, rhs)
}
fn mul_scalar(&self, rhs: Self::Scalar) -> Self {
let alpha: f64 = rhs;
self.fmap(|x| x * alpha)
}
}
impl Normed for Vec<f64> {
type UnsignedScalar = f64;
fn norm(&self, kind: Norm) -> f64 {
match kind {
Norm::L1 => self.iter().map(|x| x.abs()).sum(),
Norm::L2 => {
#[cfg(feature = "O3")]
{
let n_i32 = self.len() as i32;
let res: f64;
unsafe {
res = dnrm2(n_i32, self, 1);
}
res
}
#[cfg(not(feature = "O3"))]
{
self.iter().map(|x| x.powi(2)).sum::<f64>().sqrt()
}
}
Norm::Lp(p) => {
assert!(
p >= 1f64,
"lp norm is only defined for p>=1, the given value was p={}",
p
);
self.iter().map(|x| x.powf(p)).sum::<f64>().powf(1f64 / p)
}
Norm::LInf => self.iter().fold(0f64, |x, y| x.max(y.abs())),
Norm::F => unimplemented!(),
Norm::Lpq(_, _) => unimplemented!(),
}
}
fn normalize(&self, kind: Norm) -> Self
where
Self: Sized,
{
let denom = self.norm(kind);
self.fmap(|x| x / denom)
}
}
#[cfg(feature = "parallel")]
impl ParallelNormed for Vec<f64> {
type UnsignedScalar = f64;
fn par_norm(&self, kind: Norm) -> f64 {
match kind {
Norm::L1 => self.iter().map(|x| x.abs()).sum(),
Norm::L2 => {
#[cfg(feature = "O3")]
{
let n_i32 = self.len() as i32;
let res: f64;
unsafe {
res = dnrm2(n_i32, self, 1);
}
res
}
#[cfg(not(feature = "O3"))]
{
self.par_iter()
.map(|x| x.powi(2))
.sum::<Self::UnsignedScalar>()
.sqrt()
}
}
Norm::Lp(p) => {
assert!(
p >= 1f64,
"lp norm is only defined for p>=1, the given value was p={}",
p
);
self.par_iter()
.map(|x| x.powf(p))
.sum::<Self::UnsignedScalar>()
.powf(1_f64 / p)
}
Norm::LInf => self
.par_iter()
.fold(|| 0f64, |x, y| x.max(y.abs()))
.reduce(|| 0f64, |acc1, acc2| acc1.max(acc2.abs())),
Norm::F => unimplemented!(),
Norm::Lpq(_, _) => unimplemented!(),
}
}
}
impl InnerProduct for Vec<f64> {
fn dot(&self, rhs: &Self) -> f64 {
#[cfg(feature = "O3")]
{
let n_i32 = self.len() as i32;
let res: f64;
unsafe {
res = ddot(n_i32, self, 1, rhs, 1);
}
res
}
#[cfg(not(feature = "O3"))]
{
self.iter()
.zip(rhs.iter())
.fold(0f64, |x, (y1, y2)| x + y1 * y2)
}
}
}
#[cfg(feature = "parallel")]
impl ParallelInnerProduct for Vec<f64> {
fn par_dot(&self, rhs: &Self) -> f64 {
#[cfg(feature = "O3")]
{
let n_i32 = self.len() as i32;
let res: f64;
unsafe {
res = ddot(n_i32, self, 1, rhs, 1);
}
res
}
#[cfg(not(feature = "O3"))]
{
self.par_iter()
.zip(rhs.into_par_iter())
.fold(|| 0_f64, |x, (y1, y2)| x + y1 * y2)
.sum::<f64>()
}
}
}
impl LinearOp<Vec<f64>, f64> for Vec<f64> {
fn apply(&self, rhs: &Vec<f64>) -> f64 {
self.dot(rhs)
}
}
impl Oxide for Vec<f64> {
fn ox(self) -> Redox<Vec<f64>> {
Redox::<Vec<f64>>::from_vec(self)
}
}
impl VectorProduct for Vec<f64> {
fn cross(&self, other: &Self) -> Self {
assert_eq!(self.len(), other.len());
match self.len() {
2 => {
let mut v = vec![0f64; 1];
v[0] = self[0] * other[1] - self[1] * other[0];
v
}
3 => {
let mut v = vec![0f64; 3];
v[0] = self[1] * other[2] - self[2] * other[1];
v[1] = self[2] * other[0] - self[0] * other[2];
v[2] = self[0] * other[1] - self[1] * other[0];
v
}
_ => {
panic!("Cross product can be defined only in 2 or 3 dimension")
}
}
}
fn outer(&self, other: &Self) -> Matrix {
let m: Matrix = self.into();
let n = matrix(other.to_owned(), 1, other.len(), Row);
m * n
}
}
#[cfg(feature = "parallel")]
impl ParallelVectorProduct for Vec<f64> {
fn par_cross(&self, other: &Self) -> Self {
assert_eq!(self.len(), other.len());
match self.len() {
2 => {
let mut v = vec![0f64; 1];
v[0] = self[0] * other[1] - self[1] * other[0];
v
}
3 => {
(0..3)
.into_par_iter()
.map(|index| {
self[(index + 1) % 3] * other[(index + 2) % 3]
- self[(index + 2) % 3] * other[(index + 1) % 3]
})
.collect::<Vec<f64>>()
}
_ => {
panic!("Cross product can be defined only in 2 or 3 dimension")
}
}
}
}
#[cfg(feature = "O3")]
pub fn blas_daxpy(a: f64, x: &[f64], y: &mut [f64]) {
assert_eq!(x.len(), y.len());
unsafe {
let n = x.len() as i32;
daxpy(n, a, x, 1, y, 1)
}
}
#[cfg(feature = "O3")]
pub fn blas_daxpy_return(a: f64, x: &[f64], y: &[f64]) -> Vec<f64> {
assert_eq!(x.len(), y.len());
let mut result = y.to_vec();
let n = x.len() as i32;
unsafe {
daxpy(n, a, x, 1, &mut result, 1);
}
result
}