use super::{EvaluatedInput, MultiIndex, Strategy, Tuple, index_fn_size, lex::lex_multi_indices};
use crate::iteration::comprehension::metadata::IndexFn;
use crate::iteration::comprehension::strategy::StrategyName;
pub struct ReverseLex;
impl Strategy for ReverseLex {
fn name(&self) -> StrategyName {
StrategyName::ReverseLex
}
fn accepts_input(&self, idx: Option<&IndexFn>) -> bool {
match idx {
None => false,
Some(i) => !i.has_continuous_axis(),
}
}
fn has_closed_form_for(&self, idx: &IndexFn) -> bool {
!idx.has_continuous_axis()
}
fn apply(&self, input: &EvaluatedInput, truncation: Option<u64>) -> Vec<Tuple> {
let mut out: Vec<Tuple> = input.tuples.iter().rev().cloned().collect();
if let Some(n) = truncation {
out.truncate(n as usize);
}
out
}
}
#[allow(dead_code)] pub(crate) fn reverse_lex_multi_indices(idx: &IndexFn, truncation: Option<u64>) -> Vec<MultiIndex> {
let total = index_fn_size(idx);
let n = match truncation {
Some(t) => t.min(total),
None => total,
};
let lex = lex_multi_indices(idx, None);
let mut rev: Vec<MultiIndex> = lex.into_iter().rev().collect();
rev.truncate(n as usize);
rev
}
#[cfg(test)]
mod tests {
use super::*;
use crate::iteration::comprehension::strategies::TupleValue;
fn tup(k: i64) -> Tuple {
Tuple::new().with("k", TupleValue::I64(k))
}
fn input_with(tuples: Vec<Tuple>) -> EvaluatedInput {
let n = tuples.len() as u64;
EvaluatedInput {
tuples,
cardinality: n,
index_fn: IndexFn::Lattice { axis_sizes: vec![n] },
}
}
#[test]
fn apply_reverses() {
let inp = input_with(vec![tup(1), tup(2), tup(3)]);
let out = ReverseLex.apply(&inp, None);
assert_eq!(out, vec![tup(3), tup(2), tup(1)]);
}
#[test]
fn apply_truncates_after_reverse() {
let inp = input_with(vec![tup(1), tup(2), tup(3), tup(4)]);
let out = ReverseLex.apply(&inp, Some(2));
assert_eq!(out, vec![tup(4), tup(3)]);
}
#[test]
fn reverse_lex_multi_indices_2d() {
let idx = IndexFn::Lattice { axis_sizes: vec![2, 2] };
let out = reverse_lex_multi_indices(&idx, None);
assert_eq!(out, vec![vec![1, 1], vec![1, 0], vec![0, 1], vec![0, 0]]);
}
#[test]
fn accepts_discrete_only() {
use crate::iteration::comprehension::cardinality::{Interval, ProductMeasure};
assert!(ReverseLex.accepts_input(Some(&IndexFn::Lattice { axis_sizes: vec![3] })));
assert!(!ReverseLex.accepts_input(Some(&IndexFn::Continuous {
intervals: vec![Interval::closed(0.0, 1.0)],
measure: ProductMeasure::Uniform,
})));
assert!(!ReverseLex.accepts_input(None));
}
}