Co-authored-by: Luis Moreno <morenol@users.noreply.github.com> Co-authored-by: Lorenzo <tunedconsulting@gmail.com> * Implement rand. Use the new derive [#default] * Use custom range * Use range seed * Bump version * Add array length checks for
176 lines
3.8 KiB
Rust
176 lines
3.8 KiB
Rust
//! # 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 rand::rngs::SmallRng;
|
||
use rand::{Rng, SeedableRng};
|
||
|
||
use num_traits::Float;
|
||
|
||
use crate::numbers::basenum::Number;
|
||
use crate::rand_custom::get_rng_impl;
|
||
|
||
/// 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 {
|
||
let mut small_rng = get_rng_impl(None);
|
||
|
||
let mut rngs: Vec<SmallRng> = (0..3)
|
||
.map(|_| SmallRng::from_rng(&mut small_rng).unwrap())
|
||
.collect();
|
||
rngs[0].gen::<f64>()
|
||
}
|
||
|
||
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 {
|
||
let mut small_rng = get_rng_impl(None);
|
||
|
||
let mut rngs: Vec<SmallRng> = (0..3)
|
||
.map(|_| SmallRng::from_rng(&mut small_rng).unwrap())
|
||
.collect();
|
||
rngs[0].gen::<f32>()
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
#[test]
|
||
fn f64_rand() {
|
||
f64::rand();
|
||
}
|
||
|
||
#[test]
|
||
fn f32_rand() {
|
||
f32::rand();
|
||
}
|
||
}
|