7851fcd37b2f1f2561c0a337cf977b11421fb5cb — axect 3 months ago a4232b4
Ver 0.14.1 Candidates - More BLAS (BLAS Level 1)
5 files changed, 94 insertions(+), 7 deletions(-)

M Cargo.toml
M RELEASES.md
M example_data/lm_test.png
M src/structure/dual.rs
M src/structure/vector.rs
M Cargo.toml => Cargo.toml +1 -1
@@ 1,6 1,6 @@
 [package]
 name = "peroxide"
-version = "0.14.0"
+version = "0.14.1"
 authors = ["axect <edeftg@gmail.com>"]
 description = "Rust comprehensive scientific computation library contains linear algebra, numerical analysis, statistics and machine learning tools with farmiliar syntax"
 repository = "https://github.com/Axect/Peroxide"

M RELEASES.md => RELEASES.md +8 -0
@@ 1,3 1,11 @@
+# Release 0.14.1 (2019-08-24) (Candidates)
+
+* More BLAS
+    * Vector & Vector Addition/Subtraction (`daxpy`)
+    * Vector & Scalar multiplication (`dscal`)
+    * Vector & Vector dot product (`ddot`)
+    * Vector Euclidean norm (`dnrm2`)
+
 # Release 0.14.0 (2019-08-24)
 
 * **[Important]** Finally, BLAS integrated.

M example_data/lm_test.png => example_data/lm_test.png +0 -0

M src/structure/dual.rs => src/structure/dual.rs +4 -0
@@ 609,6 609,10 @@ impl VecOps for Vec<Dual> {
         self.zip_with(|x, y| x * y, other)
     }
 
+    fn s_mul(&self, scala: f64) -> Self {
+        self.fmap(|x| x * scala)
+    }
+
     fn div(&self, other: &Self) -> Self {
         self.zip_with(|x, y| x / y, other)
     }

M src/structure/vector.rs => src/structure/vector.rs +81 -6
@@ 262,6 262,11 @@
 //!     }
 //!     ```
 
+#[cfg(feature = "native")]
+extern crate blas;
+#[cfg(feature = "native")]
+use blas::{daxpy, ddot, dnrm2, dscal};
+
 use operation::extra_ops::Real;
 use std::cmp::min;
 use std::convert;


@@ 528,6 533,7 @@ pub trait VecOps {
     fn add(&self, other: &Self) -> Self;
     fn sub(&self, other: &Self) -> Self;
     fn mul(&self, other: &Self) -> Self;
+    fn s_mul(&self, scala: f64) -> Self;
     fn div(&self, other: &Self) -> Self;
     fn dot(&self, other: &Self) -> Self::Scalar;
     fn norm(&self) -> Self::Scalar;


@@ 540,12 546,38 @@ impl VecOps for Vector {
 
     /// Addition
     fn add(&self, other: &Self) -> Self {
-        self.zip_with(|x, y| x + y, other)
+        match () {
+            #[cfg(feature = "native")]
+            () => {
+                let n_i32 = self.len() as i32;
+                let mut y = other.clone();
+                unsafe {
+                    daxpy(n_i32, 1f64, self, 1, &mut y, 1);
+                }
+                y
+            }
+            _ => {
+                self.zip_with(|x, y| x + y, other)
+            }
+        }
     }
 
     /// Subtraction
     fn sub(&self, other: &Self) -> Self {
-        self.zip_with(|x, y| x - y, other)
+        match () {
+            #[cfg(feature = "native")]
+            () => {
+                let n_i32 = self.len() as i32;
+                let mut y = self.clone();
+                unsafe {
+                    daxpy(n_i32, -1f64, other, 1, &mut y, 1);
+                }
+                y
+            }
+            _ => {
+                self.zip_with(|x, y| x - y, other)
+            }
+        }
     }
 
     /// Multiplication


@@ 553,6 585,23 @@ impl VecOps for Vector {
         self.zip_with(|x, y| x * y, other)
     }
 
+    fn s_mul(&self, scala: f64) -> Self {
+        match () {
+            #[cfg(feature = "native")]
+            () => {
+                let mut x = self.clone();
+                let n_i32 = self.len() as i32;
+                unsafe {
+                    dscal(n_i32, scala, &mut x, 1);
+                }
+                x
+            }
+            _ => {
+                self.fmap(|x| scala * x)
+            }
+        }
+    }
+
     /// Division
     fn div(&self, other: &Self) -> Self {
         self.zip_with(|x, y| x / y, other)


@@ 560,17 609,43 @@ impl VecOps for Vector {
 
     /// Dot product
     fn dot(&self, other: &Self) -> f64 {
-        zip_with(|x, y| x * y, &self, other).reduce(0, |x, y| x + y)
+        match () {
+            #[cfg(feature = "native")]
+            () => {
+                let n_i32 = self.len() as i32;
+                let res: f64;
+                unsafe {
+                    res = ddot(n_i32, self, 1, other, 1);
+                }
+                res
+            }
+            _ => {
+                zip_with(|x, y| x * y, &self, other).reduce(0, |x, y| x + y)
+            }
+        }
     }
 
     /// Norm
     fn norm(&self) -> f64 {
-        self.dot(&self).sqrt()
+        match () {
+            #[cfg(feature = "native")]
+            () => {
+                let n_i32 = self.len() as i32;
+                let res: f64;
+                unsafe {
+                    res = dnrm2(n_i32, self, 1);
+                }
+                res
+            }
+            _ => {
+                self.dot(&self).sqrt()
+            }
+        }
     }
 
     /// Normalize
     fn normalize(&self) -> Self {
-        let n = self.norm();
-        self.fmap(|x| x / n)
+        let alpha = self.norm();
+        self.s_mul(1f64 / alpha)
     }
 }