use std::collections::BTreeSet;
use quickcheck::{Arbitrary, Gen};
use rand::Rng;
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct DistinctMatrix {
matrix: Vec<f64>,
len: usize,
}
impl DistinctMatrix {
pub fn new(mut mat: Vec<f64>) -> DistinctMatrix {
make_distinct(&mut mat);
if !mat.is_empty() {
let mut n = observations(mat.len());
let mut should = (n * (n - 1)) / 2;
while should > mat.len() {
n -= 1;
should = (n * (n - 1)) / 2;
}
mat.truncate(should);
for v in &mut mat {
if v.is_nan() {
*v = 0.0;
}
}
}
let n = observations(mat.len());
DistinctMatrix { matrix: mat, len: n }
}
pub fn matrix(&self) -> Vec<f64> {
self.matrix.to_vec()
}
pub fn len(&self) -> usize {
self.len
}
}
impl Arbitrary for DistinctMatrix {
fn arbitrary(_g: &mut Gen) -> DistinctMatrix {
let mut rng = rand::thread_rng();
let size = rng.gen_range(0..30);
let mut dis = vec![];
for i in 0..size {
for _ in i + 1..size {
dis.push(rng.gen_range(-0.5..=0.5));
}
}
DistinctMatrix::new(dis)
}
fn shrink(&self) -> Box<dyn Iterator<Item = DistinctMatrix>> {
Box::new(self.matrix.shrink().map(DistinctMatrix::new))
}
}
fn make_distinct(xs: &mut Vec<f64>) {
use std::cmp::Ordering;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
struct NonNanF64(f64);
impl Eq for NonNanF64 {}
impl Ord for NonNanF64 {
fn cmp(&self, other: &NonNanF64) -> Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
if xs.is_empty() {
return;
}
let mut next =
1.0 + xs.iter().fold(xs[0], |a, &b| if a > b { a } else { b });
let mut seen = BTreeSet::new();
for i in 0..xs.len() {
let x = NonNanF64(xs[i]);
if !seen.contains(&x) {
seen.insert(x);
continue;
}
xs[i] = next;
next += 1.0;
}
}
fn observations(condensed_matrix_size: usize) -> usize {
((condensed_matrix_size as f64) * 2.0).sqrt().ceil() as usize
}