use crate::math::pow2;
use crate::multiset::Multiset;
use alloc::{vec, vec::Vec};
use core::cmp::Ordering;
#[derive(PartialEq)]
struct MaxItem(f64);
impl Eq for MaxItem {}
impl PartialOrd for MaxItem {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MaxItem {
fn cmp(&self, other: &MaxItem) -> Ordering {
other.0.partial_cmp(&self.0).unwrap()
}
}
#[derive(PartialEq)]
struct MinItem(f64);
impl Eq for MinItem {}
impl PartialOrd for MinItem {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MinItem {
fn cmp(&self, other: &MinItem) -> Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
fn insert_element(m: &mut Multiset<MinItem>, m2: &mut Multiset<MaxItem>, x: f64) {
if m.is_empty() || x < m.first().unwrap().0 {
m2.insert(MaxItem(x));
} else {
m.insert(MinItem(x));
}
if m.len() > m2.len() + 1 {
let i = m.first().unwrap().0;
m2.insert(MaxItem(i));
m.remove(MinItem(i));
} else if m2.len() > m.len() + 1 {
let i = m2.first().unwrap().0;
m.insert(MinItem(i));
m2.remove(MaxItem(i));
}
}
fn remove_element(m: &mut Multiset<MinItem>, m2: &mut Multiset<MaxItem>, x: f64) {
if x < m.first().unwrap().0 {
m2.remove(MaxItem(x));
} else {
m.remove(MinItem(x));
}
if m.len() > m2.len() + 1 {
let i = m.first().unwrap().0;
m2.insert(MaxItem(i));
m.remove(MinItem(i));
} else if m2.len() > m.len() + 1 {
let i = m2.first().unwrap().0;
m.insert(MinItem(i));
m2.remove(MaxItem(i));
}
}
fn get_median(m: &Multiset<MinItem>, m2: &Multiset<MaxItem>) -> f64 {
match m.len().cmp(&m2.len()) {
Ordering::Greater => m.first().unwrap().0,
Ordering::Less => m2.first().unwrap().0,
Ordering::Equal => (m2.first().unwrap().0 + m.first().unwrap().0) / 2.0,
}
}
fn linear(_x: f64) -> f64 {
1.0
}
fn constant(_x: f64) -> f64 {
0.0
}
fn quadratic(x: f64) -> f64 {
2.0 * x + 1.0
}
pub fn edm_multi(z: &[f64], min_size: usize, beta: f64, degree: i32) -> Vec<usize> {
let g: fn(f64) -> f64 = match degree {
1 => linear,
2 => quadratic,
_ => constant,
};
let n = z.len();
let mut beta = beta;
if beta < 0.0 {
beta = -beta;
}
let mut prev = vec![0; n + 1];
let mut number = vec![0; n + 1];
let mut f = vec![-3.0; n + 1];
let mut right_min = Multiset::new();
let mut left_min = Multiset::new();
let mut right_max = Multiset::new();
let mut left_max = Multiset::new();
for s in 2 * min_size..n + 1 {
right_max.clear();
right_min.clear();
left_max.clear();
left_min.clear();
for i in prev[min_size - 1]..min_size - 1 {
insert_element(&mut left_min, &mut left_max, z[i]);
}
for i in min_size - 1..s {
insert_element(&mut right_min, &mut right_max, z[i]);
}
for t in min_size..s - min_size + 1 {
insert_element(&mut left_min, &mut left_max, z[t - 1]);
remove_element(&mut right_min, &mut right_max, z[t - 1]);
if prev[t] > prev[t - 1] {
for i in prev[t - 1]..prev[t] {
remove_element(&mut left_min, &mut left_max, z[i]);
}
} else if prev[t] < prev[t - 1] {
for i in prev[t]..prev[t - 1] {
insert_element(&mut left_min, &mut left_max, z[i]);
}
}
let left_median = get_median(&left_min, &left_max);
let right_median = get_median(&right_min, &right_max);
let normalize = ((t - prev[t]) * (s - t)) as f64 / pow2((s - prev[t]) as f64);
let tmp =
f[t] + normalize * pow2(left_median - right_median) - beta * g(number[t] as f64);
if tmp > f[s] {
number[s] = number[t] + 1;
f[s] = tmp;
prev[s] = t;
}
}
}
let mut ret = Vec::new();
let mut at = n;
while at != 0 {
if prev[at] != 0 {
ret.push(prev[at]);
}
at = prev[at];
}
ret.sort_unstable();
ret
}
pub fn edm_percent(z: &[f64], min_size: usize, percent: f64, degree: i32) -> Vec<usize> {
let g: fn(f64) -> f64 = match degree {
1 => linear,
2 => quadratic,
_ => constant,
};
let n = z.len();
let mut prev = vec![0; n + 1];
let mut number = vec![0; n + 1];
let mut f = vec![0.0; n + 1];
let mut right_min = Multiset::new();
let mut left_min = Multiset::new();
let mut right_max = Multiset::new();
let mut left_max = Multiset::new();
for s in 2 * min_size..n + 1 {
right_max.clear();
right_min.clear();
left_max.clear();
left_min.clear();
for i in prev[min_size - 1]..min_size - 1 {
insert_element(&mut left_min, &mut left_max, z[i]);
}
for i in min_size - 1..s {
insert_element(&mut right_min, &mut right_max, z[i]);
}
for t in min_size..s - min_size + 1 {
insert_element(&mut left_min, &mut left_max, z[t - 1]);
remove_element(&mut right_min, &mut right_max, z[t - 1]);
if prev[t] > prev[t - 1] {
for i in prev[t - 1]..prev[t] {
remove_element(&mut left_min, &mut left_max, z[i]);
}
} else if prev[t] < prev[t - 1] {
for i in prev[t]..prev[t - 1] {
insert_element(&mut left_min, &mut left_max, z[i]);
}
}
let left_median = get_median(&left_min, &left_max);
let right_median = get_median(&right_min, &right_max);
let normalize = ((t - prev[t]) * (s - t)) as f64 / pow2((s - prev[t]) as f64);
let tmp = f[t] + normalize * pow2(left_median - right_median);
if tmp > f[s] {
number[s] = number[t] + 1;
f[s] = tmp;
prev[s] = t;
}
}
if prev[s] != 0 && f[s] - f[prev[s]] < percent * g(number[prev[s]] as f64) * f[prev[s]] {
number[s] = number[prev[s]];
f[s] = f[prev[s]];
prev[s] = prev[prev[s]];
}
}
let mut ret = Vec::new();
let mut at = n;
while at != 0 {
if prev[at] != 0 {
ret.push(prev[at]);
}
at = prev[at];
}
ret.sort_unstable();
ret
}