From: Ben Pfaff Date: Mon, 5 Jan 2026 21:26:28 +0000 (-0800) Subject: add lightiweight test X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=083a542d26fbbc7732204cc118506173598df520;p=pspp add lightiweight test --- diff --git a/rust/pspp/src/output/pivot.rs b/rust/pspp/src/output/pivot.rs index dd261b3eca..d37fc0732f 100644 --- a/rust/pspp/src/output/pivot.rs +++ b/rust/pspp/src/output/pivot.rs @@ -485,7 +485,7 @@ impl PivotTable { .iter() .zip(presentation_indexes.iter()) { - data_indexes[dim_index] = self.dimensions[dim_index].presentation_order[pindex]; + data_indexes[dim_index] = self.dimensions[dim_index].ptod[pindex]; } } data_indexes @@ -616,23 +616,17 @@ pub struct Dimension { /// subcategories. root: Group, - /// Ordering of leaves for presentation. + /// Maps from an index in presentation order to a data index ("p" to "d"). /// - /// This is a permutation of `0..n` where `n` is the number of leaves. It - /// maps from an index in presentation order to an index in data order. - pub presentation_order: Vec, + /// This is a permutation of `0..n` where `n` is the number of leaves. + /// Given a [Leaf] that can be found as via `dimension.nth_leaf(leaf_idx)`, + /// the corresponding data index is `ptod[leaf_idx]`. + ptod: Vec, /// Display. pub hide_all_labels: bool, } -impl Dimension { - /// Returns the root [Group] of the dimension. - pub fn root(&self) -> &Group { - &self.root - } -} - /// A vector of references to [Group]s. /// /// Used to represent a sequence of groups along a [Path]. This is a [SmallVec] @@ -653,16 +647,50 @@ pub struct Path<'a> { /// Group indexes visited along a [Path]. pub type IndexVec = SmallVec<[usize; 4]>; +/// Indicates that the argument to [Dimension::set_ptod] was not a valid +/// permutation. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct InvalidPermutation; + impl Dimension { /// Constructs a new [Dimension] with the given `root`. pub fn new(root: Group) -> Self { Dimension { - presentation_order: (0..root.len()).collect(), + ptod: (0..root.len()).collect(), root, hide_all_labels: false, } } + /// Returns the root [Group] of the dimension. + pub fn root(&self) -> &Group { + &self.root + } + + /// Returns the presentation-to-data index mapping. + pub fn ptod(&self) -> &[usize] { + &self.ptod + } + + /// Returns this dimension with its presentation-to-data index mapping + /// replaced by `ptod`, which must be a permutation of `0..self.len()`. + pub fn set_ptod(&mut self, ptod: Vec) -> Result<(), InvalidPermutation> { + if ptod.len() != self.ptod.len() { + return Err(InvalidPermutation); + } + + let mut seen = vec![false; ptod.len()]; + for element in ptod.iter().copied() { + if element >= ptod.len() || seen[element] { + return Err(InvalidPermutation); + } + seen[element] = true; + } + + self.ptod = ptod; + Ok(()) + } + /// Returns this dimension with [Dimension::hide_all_labels] set to true. pub fn with_all_labels_hidden(self) -> Self { self.with_hide_all_labels(true) diff --git a/rust/pspp/src/output/pivot/output.rs b/rust/pspp/src/output/pivot/output.rs index 29b2664e2e..e918401cef 100644 --- a/rust/pspp/src/output/pivot/output.rs +++ b/rust/pspp/src/output/pivot/output.rs @@ -465,9 +465,7 @@ impl<'a> Heading<'a> { let mut columns = Vec::new(); let mut height = 0; for indexes in column_enumeration.iter() { - let mut path = dimension - .leaf_path(dimension.presentation_order[indexes[dim_index]]) - .unwrap(); + let mut path = dimension.leaf_path(indexes[dim_index]).unwrap(); path.groups.retain(|group| group.show_label); height = height.max(1 + path.groups.len()); columns.push(path); diff --git a/rust/pspp/src/spv/read/light.rs b/rust/pspp/src/spv/read/light.rs index 9b6ede22b0..e603b58988 100644 --- a/rust/pspp/src/spv/read/light.rs +++ b/rust/pspp/src/spv/read/light.rs @@ -72,6 +72,9 @@ pub enum LightWarning { /// Dimension with index {0} appears twice in table axes. DuplicateDimensionIndex(usize), + + /// Dimension {0} has invalid leaf index permutation (so categories may appear out of order). + InvalidPermutation(usize), } struct Context { @@ -159,7 +162,6 @@ impl LightTable { } pub fn decode(&self, mut warn: &mut dyn FnMut(LightWarning)) -> PivotTable { - dbg!(self); let encoding = self.formats.encoding(warn); let n1 = self.formats.n1(); @@ -185,13 +187,20 @@ impl LightTable { let dimensions = self .dimensions .iter() - .map(|d| { + .enumerate() + .map(|(dim_index, d)| { let mut root = Group::new(d.name.decode(encoding, &footnotes, warn)) .with_show_label(!d.hide_dim_label); + let mut ptod = Vec::new(); for category in &d.categories { - category.decode(encoding, &footnotes, &mut root, warn); + category.decode(encoding, &footnotes, &mut root, &mut ptod, warn); } - pivot::Dimension::new(root).with_hide_all_labels(d.hide_all_labels) + let mut dimension = + pivot::Dimension::new(root).with_hide_all_labels(d.hide_all_labels); + if dimension.set_ptod(ptod).is_err() { + warn(LightWarning::InvalidPermutation(dim_index)); + }; + dimension }) .collect::>(); let dimensions = match self.axes.decode(dimensions) { @@ -1675,11 +1684,13 @@ impl Category { encoding: &'static Encoding, footnotes: &Footnotes, group: &mut pivot::Group, + ptod: &mut Vec, warn: &mut dyn FnMut(LightWarning), ) { let name = self.name.decode(encoding, footnotes, warn); match &self.child { - Child::Leaf { leaf_index: _ } => { + Child::Leaf { leaf_index } => { + ptod.push(*leaf_index as usize); group.push(pivot::Leaf::new(name)); } Child::Group { @@ -1687,7 +1698,7 @@ impl Category { subcategories, } => { for subcategory in subcategories { - subcategory.decode(encoding, footnotes, group, warn); + subcategory.decode(encoding, footnotes, group, ptod, warn); } } Child::Group { @@ -1696,7 +1707,7 @@ impl Category { } => { let mut subgroup = Group::new(name).with_label_shown(); for subcategory in subcategories { - subcategory.decode(encoding, footnotes, &mut subgroup, warn); + subcategory.decode(encoding, footnotes, &mut subgroup, ptod, warn); } group.push(subgroup); } diff --git a/rust/pspp/src/spv/testdata/light1.expected b/rust/pspp/src/spv/testdata/light1.expected new file mode 100644 index 0000000000..1a91ccc775 --- /dev/null +++ b/rust/pspp/src/spv/testdata/light1.expected @@ -0,0 +1,12 @@ + Chi-Square Tests +╭────────────────────────────┬────────┬──┬─────────────────────┬────────────────────┬────────────────────┬─────────────────╮ +│ │ Value │df│Asymp. Sig. (2-sided)│Exact Sig. (2-sided)│Exact Sig. (1-sided)│Point Probability│ +├────────────────────────────┼────────┼──┼─────────────────────┼────────────────────┼────────────────────┼─────────────────┤ +│Pearson Chi-Square │4.496[a]│ 2│ .106│ .115│ │ │ +│Likelihood Ratio │ 4.646│ 2│ .098│ .108│ │ │ +│Fisher's Exact Test │ 4.446│ │ │ .108│ │ │ +│Linear-by-Linear Association│4.403[b]│ 1│ .036│ .047│ .026│ .015│ +│N of Valid Cases │ 60│ │ │ │ │ │ +╰────────────────────────────┴────────┴──┴─────────────────────┴────────────────────┴────────────────────┴─────────────────╯ +a. 0 cells (.0%) have expected count less than 5. The minimum expected count is 6.97. +b. The standardized statistic is 2.098. diff --git a/rust/pspp/src/spv/testdata/light1.spv b/rust/pspp/src/spv/testdata/light1.spv new file mode 100644 index 0000000000..1095cede1b Binary files /dev/null and b/rust/pspp/src/spv/testdata/light1.spv differ diff --git a/rust/pspp/src/spv/write.rs b/rust/pspp/src/spv/write.rs index 7f241d92cc..1276a29a7c 100644 --- a/rust/pspp/src/spv/write.rs +++ b/rust/pspp/src/spv/write.rs @@ -691,7 +691,7 @@ impl BinWrite for Dimension { ) .write_options(writer, endian, ())?; - let mut data_indexes = self.presentation_order.iter().copied(); + let mut data_indexes = self.ptod().iter().copied(); for child in self.root().children() { child.write_le(writer, &mut data_indexes)?; }