Merge potential next release v0.4 (#187) Breaking Changes

* First draft of the new n-dimensional arrays + NB use case
* Improves default implementation of multiple Array methods
* Refactors tree methods
* Adds matrix decomposition routines
* Adds matrix decomposition methods to ndarray and nalgebra bindings
* Refactoring + linear regression now uses array2
* Ridge & Linear regression
* LBFGS optimizer & logistic regression
* LBFGS optimizer & logistic regression
* Changes linear methods, metrics and model selection methods to new n-dimensional arrays
* Switches KNN and clustering algorithms to new n-d array layer
* Refactors distance metrics
* Optimizes knn and clustering methods
* Refactors metrics module
* Switches decomposition methods to n-dimensional arrays
* Linalg refactoring - cleanup rng merge (#172)
* Remove legacy DenseMatrix and BaseMatrix implementation. Port the new Number, FloatNumber and Array implementation into module structure.
* Exclude AUC metrics. Needs reimplementation
* Improve developers walkthrough

New traits system in place at `src/numbers` and `src/linalg`
Co-authored-by: Lorenzo <tunedconsulting@gmail.com>

* Provide SupervisedEstimator with a constructor to avoid explicit dynamical box allocation in 'cross_validate' and 'cross_validate_predict' as required by the use of 'dyn' as per Rust 2021
* Implement getters to use as_ref() in src/neighbors
* Implement getters to use as_ref() in src/naive_bayes
* Implement getters to use as_ref() in src/linear
* Add Clone to src/naive_bayes
* Change signature for cross_validate and other model_selection functions to abide to use of dyn in Rust 2021
* Implement ndarray-bindings. Remove FloatNumber from implementations
* Drop nalgebra-bindings support (as decided in conf-call to go for ndarray)
* Remove benches. Benches will have their own repo at smartcore-benches
* Implement SVC
* Implement SVC serialization. Move search parameters in dedicated module
* Implement SVR. Definitely too slow
* Fix compilation issues for wasm (#202)

Co-authored-by: Luis Moreno <morenol@users.noreply.github.com>
* Fix tests (#203)

* Port linalg/traits/stats.rs
* Improve methods naming
* Improve Display for DenseMatrix

Co-authored-by: Montana Low <montanalow@users.noreply.github.com>
Co-authored-by: VolodymyrOrlov <volodymyr.orlov@gmail.com>
This commit is contained in:
Lorenzo
2022-10-31 10:44:57 +00:00
committed by GitHub
parent bb71656137
commit 52eb6ce023
110 changed files with 10327 additions and 9107 deletions
+51
View File
@@ -0,0 +1,51 @@
use num_traits::{Bounded, FromPrimitive, Num, NumCast, ToPrimitive};
use std::fmt::{Debug, Display};
use std::iter::{Product, Sum};
use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
/// Define a `Number` set that acquires traits from `num_traits` to make available a base trait
/// to be used by other usable sets like `FloatNumber`.
pub trait Number:
Num
+ FromPrimitive
+ ToPrimitive
+ Debug
+ Display
+ Copy
+ Sum
+ Product
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ Bounded
+ NumCast
{
}
impl Number for f64 {}
impl Number for f32 {}
impl Number for i8 {}
impl Number for i16 {}
impl Number for i32 {}
impl Number for i64 {}
impl Number for u8 {}
impl Number for u16 {}
impl Number for u32 {}
impl Number for u64 {}
impl Number for usize {}
#[cfg(test)]
mod tests {
use std::str::FromStr;
#[test]
fn i32_from_string() {
assert_eq!(i32::from_str("1").unwrap(), 1)
}
#[test]
fn i8_from_string() {
assert_eq!(i8::from_str("1").unwrap(), 1)
}
}
+117
View File
@@ -0,0 +1,117 @@
use rand::Rng;
use num_traits::{Float, Signed};
use crate::numbers::basenum::Number;
/// Defines float number
/// <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_CHTML"></script>
pub trait FloatNumber: Number + Float + Signed {
/// Copy sign from `sign` - another real number
fn copysign(self, sign: Self) -> Self;
/// Calculates natural \\( \ln(1+e^x) \\) without overflow.
fn ln_1pe(self) -> Self;
/// Efficient implementation of Sigmoid function, \\( S(x) = \frac{1}{1 + e^{-x}} \\), see [Sigmoid function](https://en.wikipedia.org/wiki/Sigmoid_function)
fn sigmoid(self) -> Self;
/// Returns pseudorandom number between 0 and 1
fn rand() -> Self;
/// Returns 2
fn two() -> Self;
/// Returns .5
fn half() -> Self;
/// Returns \\( x^2 \\)
fn square(self) -> Self {
self * self
}
/// Raw transmutation to u64
fn to_f32_bits(self) -> u32;
}
impl FloatNumber for f64 {
fn copysign(self, sign: Self) -> Self {
self.copysign(sign)
}
fn ln_1pe(self) -> f64 {
if self > 15. {
self
} else {
self.exp().ln_1p()
}
}
fn sigmoid(self) -> f64 {
if self < -40. {
0.
} else if self > 40. {
1.
} else {
1. / (1. + f64::exp(-self))
}
}
fn rand() -> f64 {
let mut rng = rand::thread_rng();
rng.gen()
}
fn two() -> Self {
2f64
}
fn half() -> Self {
0.5f64
}
fn to_f32_bits(self) -> u32 {
self.to_bits() as u32
}
}
impl FloatNumber for f32 {
fn copysign(self, sign: Self) -> Self {
self.copysign(sign)
}
fn ln_1pe(self) -> f32 {
if self > 15. {
self
} else {
self.exp().ln_1p()
}
}
fn sigmoid(self) -> f32 {
if self < -40. {
0.
} else if self > 40. {
1.
} else {
1. / (1. + f32::exp(-self))
}
}
fn rand() -> f32 {
let mut rng = rand::thread_rng();
rng.gen()
}
fn two() -> Self {
2f32
}
fn half() -> Self {
0.5f32
}
fn to_f32_bits(self) -> u32 {
self.to_bits()
}
}
+10
View File
@@ -0,0 +1,10 @@
// this module has been ported from https://github.com/smartcorelib/smartcore/pull/108
/// Base `Number` from `std` and `num-traits`
pub mod basenum;
/// implementation for `RealNumber`
pub mod realnum;
/// implementation for `FloatNumber`
pub mod floatnum;
+151
View File
@@ -0,0 +1,151 @@
//! # Real Number
//! Most algorithms in SmartCore rely on basic linear algebra operations like dot product, matrix decomposition and other subroutines that are defined for a set of real numbers, .
//! This module defines real number and some useful functions that are used in [Linear Algebra](../../linalg/index.html) module.
use num_traits::Float;
use crate::numbers::basenum::Number;
/// Defines real number
/// <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_CHTML"></script>
pub trait RealNumber: Number + Float {
/// Copy sign from `sign` - another real number
fn copysign(self, sign: Self) -> Self;
/// Calculates natural \\( \ln(1+e^x) \\) without overflow.
fn ln_1pe(self) -> Self;
/// Efficient implementation of Sigmoid function, \\( S(x) = \frac{1}{1 + e^{-x}} \\), see [Sigmoid function](https://en.wikipedia.org/wiki/Sigmoid_function)
fn sigmoid(self) -> Self;
/// Returns pseudorandom number between 0 and 1
fn rand() -> Self;
/// Returns 2
fn two() -> Self;
/// Returns .5
fn half() -> Self;
/// Returns \\( x^2 \\)
fn square(self) -> Self {
self * self
}
/// Raw transmutation to u32
fn to_f32_bits(self) -> u32;
/// Raw transmutation to u64
fn to_f64_bits(self) -> u64;
}
impl RealNumber for f64 {
fn copysign(self, sign: Self) -> Self {
self.copysign(sign)
}
fn ln_1pe(self) -> f64 {
if self > 15. {
self
} else {
self.exp().ln_1p()
}
}
fn sigmoid(self) -> f64 {
if self < -40. {
0.
} else if self > 40. {
1.
} else {
1. / (1. + f64::exp(-self))
}
}
fn rand() -> f64 {
1.0
}
fn two() -> Self {
2f64
}
fn half() -> Self {
0.5f64
}
fn to_f32_bits(self) -> u32 {
self.to_bits() as u32
}
fn to_f64_bits(self) -> u64 {
self.to_bits()
}
}
impl RealNumber for f32 {
fn copysign(self, sign: Self) -> Self {
self.copysign(sign)
}
fn ln_1pe(self) -> f32 {
if self > 15. {
self
} else {
self.exp().ln_1p()
}
}
fn sigmoid(self) -> f32 {
if self < -40. {
0.
} else if self > 40. {
1.
} else {
1. / (1. + f32::exp(-self))
}
}
fn rand() -> f32 {
1.0
}
fn two() -> Self {
2f32
}
fn half() -> Self {
0.5f32
}
fn to_f32_bits(self) -> u32 {
self.to_bits()
}
fn to_f64_bits(self) -> u64 {
self.to_bits() as u64
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn sigmoid() {
assert_eq!(1.0.sigmoid(), 0.7310585786300049);
assert_eq!(41.0.sigmoid(), 1.);
assert_eq!((-41.0).sigmoid(), 0.);
}
#[test]
fn f32_from_string() {
assert_eq!(f32::from_str("1.111111").unwrap(), 1.111111)
}
#[test]
fn f64_from_string() {
assert_eq!(f64::from_str("1.111111111").unwrap(), 1.111111111)
}
}