|
@@ -1,6 +1,7 @@
|
|
use crate::{BridgeInfo, BridgeInfoType};
|
|
use crate::{BridgeInfo, BridgeInfoType};
|
|
use lox_library::proto::trust_promotion::UNTRUSTED_INTERVAL;
|
|
use lox_library::proto::trust_promotion::UNTRUSTED_INTERVAL;
|
|
-use nalgebra::DVector;
|
|
|
|
|
|
+use nalgebra::{Cholesky, DMatrix, DVector};
|
|
|
|
+use rand::Rng;
|
|
use statrs::distribution::{Continuous, MultivariateNormal, Normal};
|
|
use statrs::distribution::{Continuous, MultivariateNormal, Normal};
|
|
use std::{
|
|
use std::{
|
|
cmp::min,
|
|
cmp::min,
|
|
@@ -212,7 +213,9 @@ impl NormalAnalyzer {
|
|
}
|
|
}
|
|
|
|
|
|
// Returns the mean vector, vector of individual standard deviations, and
|
|
// Returns the mean vector, vector of individual standard deviations, and
|
|
- // covariance matrix
|
|
|
|
|
|
+ // covariance matrix. If the standard deviation for a variable is 0 and/or
|
|
|
|
+ // the covariance matrix is not positive definite, add some noise to the
|
|
|
|
+ // data and recompute.
|
|
fn stats(data: &[&[u32]]) -> (Vec<f64>, Vec<f64>, Vec<f64>) {
|
|
fn stats(data: &[&[u32]]) -> (Vec<f64>, Vec<f64>, Vec<f64>) {
|
|
let n = data.len();
|
|
let n = data.len();
|
|
|
|
|
|
@@ -267,7 +270,33 @@ impl NormalAnalyzer {
|
|
cov_mat
|
|
cov_mat
|
|
};
|
|
};
|
|
|
|
|
|
- (mean_vec, sd_vec, cov_mat)
|
|
|
|
|
|
+ // If any standard deviation is 0 or the covariance matrix is not
|
|
|
|
+ // positive definite, add some noise and recompute.
|
|
|
|
+ let mut recompute = false;
|
|
|
|
+ for sd in &sd_vec {
|
|
|
|
+ if *sd <= 0.0 {
|
|
|
|
+ recompute = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if Cholesky::new(DMatrix::from_vec(n, n, cov_mat.clone())).is_none() {
|
|
|
|
+ recompute = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if !recompute {
|
|
|
|
+ (mean_vec, sd_vec, cov_mat)
|
|
|
|
+ } else {
|
|
|
|
+ // Add random noise and recompute
|
|
|
|
+ let mut new_data = vec![vec![0; data[0].len()]; n];
|
|
|
|
+ let mut rng = rand::thread_rng();
|
|
|
|
+ for i in 0..n {
|
|
|
|
+ for j in 0..data[i].len() {
|
|
|
|
+ // Add 1 to some randomly selected values
|
|
|
|
+ new_data[i][j] = data[i][j] + rng.gen_range(0..=1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Compute stats on modified data
|
|
|
|
+ Self::stats(&new_data.iter().map(Vec::as_slice).collect::<Vec<&[u32]>>())
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|