pub use self::maths_utils::{factorial, rising_factorial, erf, erfinv, euclidean_distance, derivative, definite_integral};
pub use self::minimal_spanning_tree::{MSTDistance, MSTNode, MSTEdge, MST};
pub use self::numerical_engines::{
ScalarFunctionWrapper, VectorFunctionWrapper, ScalarNumericalMinimiser, VectorNumericalMinimiser, NumericalOptimisationResult,
GoldenRatio, LineSearch, GradientDescent, LBFGS, NelderMead,
};
pub use self::loss_functions::{LossFunction, MSE, MAE, MSLE, MLE, SSE, StraddleLoss};
pub use self::data_transformations::{
min_max_scaling, percent_change, log_return_transformation, differencing, rank_transformation, unit_vector_normalization,
TransformationType, DataTransformations,
};
pub use self::time_value_utils::{
CompoundingType, present_value, net_present_value, future_value, internal_rate_of_return, real_interest_rate,
ptp_compounding_transformation, ptc_compounding_transformation, ctp_compounding_transformation, Compounding, forward_rate, Cashflow, Perpetuity, Annuity,
};
pub use self::feature_collection::FeatureCollection;
#[cfg(feature = "sample_data")]
pub use self::sample_data::SampleData;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
pub mod maths_utils;
pub mod minimal_spanning_tree;
pub mod numerical_engines;
pub mod loss_functions;
pub mod data_transformations;
pub mod time_value_utils;
mod feature_collection;
#[cfg(feature = "sample_data")]
pub mod sample_data;
use ndarray::{Array1, Array2};
use nalgebra::DMatrix;
use crate::error::{DigiFiError, ErrorTitle};
pub const TEST_ACCURACY: f64 = 0.00000001;
pub const NUMERICAL_CORRECTION: f64 = 0.00000000000001;
pub const LARGE_TEXT_BREAK: &str = "--------------------------------------------------------------------------------------\n";
pub const SMALL_TEXT_BREAK: &str = "\t----------------------------------------------------\n";
#[derive(Clone, Debug)]
pub enum ParameterType {
Value { value: f64 },
TimeSeries { values: Array1<f64> },
}
impl ParameterType {
pub fn into_array(self, len: usize) -> Result<Array1<f64>, DigiFiError> {
match self {
Self::Value { value } => Ok(Array1::from_vec(vec![value; len])),
Self::TimeSeries { values } => {
if values.len() != len {
return Err(DigiFiError::WrongLength { title: Self::error_title(), arg: "values".to_owned(), len, });
}
Ok(values)
},
}
}
}
impl ErrorTitle for ParameterType {
fn error_title() -> String {
String::from("Parameter Type")
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Time(Array1<f64>);
impl Time {
pub fn new(time_array: Array1<f64>) -> Self {
Self(time_array)
}
pub fn new_from_range(initial_time: f64, final_time: f64, dt: f64) -> Self {
Self(Array1::range(initial_time, final_time + dt, dt))
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn time_array(&self) -> &Array1<f64> {
&self.0
}
pub fn time_array_mut(&mut self) -> &mut Array1<f64> {
&mut self.0
}
}
pub fn compare_len<U: ExactSizeIterator, V: ExactSizeIterator>(iter_1: &U, iter_2: &V, iter_1_name: &str, iter_2_name: &str) -> Result<(), DigiFiError> {
if iter_1.len() != iter_2.len() {
return Err(DigiFiError::UnmatchingLength { array_1: iter_1_name.to_owned(), array_2: iter_2_name.to_owned(), });
}
Ok(())
}
pub struct MatrixConversion;
impl MatrixConversion {
pub fn ndarray_to_nalgebra(matrix: Array2<f64>) -> DMatrix<f64> {
let (n_rows, n_columns) = matrix.dim();
let n_matrix: DMatrix<f64> = DMatrix::from_vec(n_columns, n_rows, matrix.clone().into_raw_vec_and_offset().0);
n_matrix.transpose()
}
pub fn nalgebra_to_ndarray(matrix: DMatrix<f64>) -> Result<Array2<f64>, DigiFiError> {
let dim = (matrix.row(0).len(), matrix.column(0).len());
Ok(Array2::from_shape_vec(dim, matrix.as_slice().to_vec())?)
}
}
#[cfg(test)]
mod tests {
use ndarray::{Array1, Array2};
use nalgebra::DMatrix;
use crate::utilities::TEST_ACCURACY;
#[test]
fn unit_test_time_struct() -> () {
use crate::utilities::Time;
let time_1: Time = Time::new_from_range(0.0, 1.0, 0.2);
let time_2: Time = Time::new(Array1::from_vec(vec![0.0, 0.2, 0.4, 0.6, 0.8, 1.0]));
assert!((time_1.time_array() - time_2.time_array()).map(|v| v.abs() ).sum() < TEST_ACCURACY);
}
#[test]
fn unit_test_compare_len() -> () {
use crate::utilities::compare_len;
let a: Vec<i32> = vec![1, 2, 3];
let b: Vec<i32> = vec![4, 5, 6];
compare_len(&a.iter(), &b.iter(), "a", "b").unwrap();
}
#[test]
fn unit_test_ndarray_to_nalgebra() -> () {
use ndarray::arr2;
use crate::utilities::MatrixConversion;
let matrix: Array2<f64> = arr2(&[[0.0, 1.0], [2.0, 3.0], [4.0, 5.0]]);
let matrix_dim: (usize, usize) = matrix.dim();
let result: DMatrix<f64> = MatrixConversion::ndarray_to_nalgebra(matrix);
assert_eq!(result.row(0).len(), matrix_dim.1);
assert_eq!(result.column(0).len(), matrix_dim.0);
}
}