#[cfg(test)]
use crate::{GroupingRelation, ReStructure, Sizing};
#[derive(Debug, Clone, Default, PartialEq)]
pub struct GroupIds {
pub primary: Vec<u32>,
pub extra: Vec<Vec<u32>>,
}
impl GroupIds {
#[cfg(test)]
pub(crate) fn from_sizing(re: &ReStructure, n: usize) -> Self {
let primary: Vec<u32> = (0..n).map(|i| re.sizing.cluster_of_row(i) as u32).collect();
let extra: Vec<Vec<u32>> = (0..re.extra_groupings.len())
.map(|g| (0..n).map(|i| extra_level_of_row(re, g, i)).collect())
.collect();
GroupIds { primary, extra }
}
}
#[cfg(test)]
pub(crate) fn extra_level_of_row(re: &ReStructure, g: usize, i: usize) -> u32 {
let rel = &re.extra_groupings[g].relation;
let level = match &re.sizing {
Sizing::FixedClusters { n_clusters } => {
let s = (*n_clusters).max(1) as usize;
let mut stride = s;
for h in &re.extra_groupings[..g] {
stride *= block_levels(&h.relation);
}
let within = (i / stride) % block_levels(rel);
match rel {
GroupingRelation::Crossed { .. } => within,
GroupingRelation::NestedWithin { n_per_parent } => {
(i % s) * (*n_per_parent).max(1) as usize + within
}
}
}
Sizing::FixedSize { cluster_size } => {
let cs = (*cluster_size).max(1) as usize;
let np = block_levels(rel);
(i / cs) * np + (i % cs) % np
}
};
level as u32
}
#[cfg(test)]
pub(crate) fn block_levels(rel: &GroupingRelation) -> usize {
match rel {
GroupingRelation::Crossed { n_clusters } => (*n_clusters).max(1) as usize,
GroupingRelation::NestedWithin { n_per_parent } => (*n_per_parent).max(1) as usize,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Grouping, GroupingRelation, ReStructure, Sizing};
#[test]
fn from_sizing_crossed_matches_positional() {
let re = ReStructure {
sizing: Sizing::FixedClusters { n_clusters: 4 },
slopes: vec![],
extra_groupings: vec![Grouping {
relation: GroupingRelation::Crossed { n_clusters: 3 },
slopes: vec![],
}],
};
let ids = GroupIds::from_sizing(&re, 12);
assert_eq!(
ids.primary,
(0..12).map(|i| (i % 4) as u32).collect::<Vec<_>>()
);
assert_eq!(ids.extra.len(), 1);
assert_eq!(
ids.extra[0],
(0..12).map(|i| ((i / 4) % 3) as u32).collect::<Vec<_>>()
);
}
}