use super::values::Values;
use ndarray::{Array1, ArrayView1};
use ndarray_stats::QuantileExt;
use std::convert::TryFrom;
pub fn rescale_vector(v: ArrayView1<f64>, shift: f64, scaling_factor: f64) -> Array1<f64> {
let shift_vector = Array1::from_elem(v.len(), shift);
(&v - shift_vector) * scaling_factor
}
pub fn rescale_and_invert_vector(
v: ArrayView1<f64>,
shift: f64,
scaling_factor: f64,
) -> Array1<f64> {
let ones = Array1::ones(v.len());
(&rescale_vector(v, shift, scaling_factor) - ones) * -1.0
}
pub fn autorescale_vector(v: &Values, inverted: bool) -> Values {
let values = v.values();
let shift = values.min().unwrap();
let max_value = values.max().unwrap();
let scaling_factor = 1.0 / (max_value - shift);
if scaling_factor.is_finite() {
if inverted {
Values::try_from(rescale_and_invert_vector(values, *shift, scaling_factor)).unwrap()
} else {
Values::try_from(rescale_vector(values, *shift, scaling_factor)).unwrap()
}
} else {
Values::try_from(Array1::zeros(values.len())).unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_ulps_eq;
use ndarray::array;
use std::convert::TryFrom;
#[test]
fn rescale_vector_size_one() {
let v = Values::try_from(array![1.]).unwrap();
let expected_scaled = array![0.];
assert_ulps_eq!(autorescale_vector(&v, false).values(), expected_scaled);
assert_ulps_eq!(autorescale_vector(&v, true).values(), expected_scaled);
}
#[test]
fn rescale_vector_all_values_with_small_precision() {
let v = Values::try_from(array![3., 3., 3.]).unwrap();
let expected_scaled = array![0., 0., 0.];
assert_ulps_eq!(autorescale_vector(&v, false).values(), expected_scaled);
assert_ulps_eq!(autorescale_vector(&v, true).values(), expected_scaled);
}
#[test]
fn rescale_vector_pos_already_scaled() {
let v = Values::try_from(array![0., 0.5, 1.]).unwrap();
assert_ulps_eq!(rescale_vector(v.values(), 0., 1.), v.values());
assert_ulps_eq!(autorescale_vector(&v, false).values(), v.values());
}
#[test]
fn rescale_vector_pos_scaling() {
let v = Values::try_from(array![1., 6., 11.]).unwrap();
let expected_scaled = array![0., 0.5, 1.];
assert_ulps_eq!(rescale_vector(v.values(), 1.0, 0.1), expected_scaled);
assert_ulps_eq!(autorescale_vector(&v, false).values(), expected_scaled);
}
#[test]
fn rescale_vector_neg_scaling() {
let v = Values::try_from(array![-3., -2., -1.]).unwrap();
let expected_scaled = array![0., 0.5, 1.];
assert_ulps_eq!(rescale_vector(v.values(), -3.0, 0.5), expected_scaled);
assert_ulps_eq!(autorescale_vector(&v, false).values(), expected_scaled);
}
#[test]
fn rescale_vector_scaling() {
let v = Values::try_from(array![0., 1., 6., 11., 12.]).unwrap();
assert_ulps_eq!(
rescale_vector(v.values(), 1., 0.1),
array![-0.1, 0., 0.5, 1., 1.1]
);
assert_ulps_eq!(
autorescale_vector(&v, false).values(),
array![0., 0.08333333333333333, 0.5, 0.9166666666666666, 1.]
);
}
#[test]
fn rescale_and_invert_vector_full() {
let v = Values::try_from(array![0., 1., 6., 11., 12.]).unwrap();
assert_ulps_eq!(
rescale_and_invert_vector(v.values(), 1., 0.1),
array![1.1, 1., 0.5, 0., -0.1]
);
assert_ulps_eq!(
autorescale_vector(&v, true).values(),
array![1., 0.9166666666666666, 0.5, 0.08333333333333337, 0.]
);
}
}