collections::{BTreeMap, HashMap},
fmt::Debug,
io::{Cursor, ErrorKind},
- iter::{repeat, zip},
+ iter::{chain, repeat, zip},
mem::take,
num::NonZeroUsize,
ops::{Not, Range},
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
struct SeriesValue {
value: Datum<String>,
label: Option<String>,
self.unique_values = Self::unique_values(&self.values, self.categorical);
self
}
+
+ fn with_values(&self, values: Vec<SeriesValue>) -> Self {
+ Self {
+ name: self.name.clone(),
+ _label: self._label.clone(),
+ _short_label: self._short_label.clone(),
+ _weight: self._weight,
+ _key: self._key,
+ unique_values: Self::unique_values(&values, self.categorical),
+ values,
+ categorical: self.categorical,
+ formatter: self.formatter.clone(),
+ }
+ }
+
+ fn append(&self, other: &Self) -> Self {
+ self.with_values(chain(&self.values, &other.values).cloned().collect_vec())
+ }
+
+ fn reordered(mut self, ordering: &[usize]) -> Self {
+ assert_eq!(self.values.len(), ordering.len());
+ debug_assert!(ordering.iter().copied().all_unique());
+ let mut new_values = vec![SeriesValue::default(); self.values.len()];
+ for (&index, value) in zip(ordering, &self.values) {
+ new_values[index] = value.clone();
+ }
+ self.values = new_values;
+ self.unique_values = Self::unique_values(&self.values, self.categorical);
+ self
+ }
}
#[derive(Deserialize, Debug)]
};
use either::Either;
-use itertools::Itertools as _;
+use itertools::{Itertools as _, merge, zip_eq};
use crate::spv::read::graph::{Series, format::Formatter};
}
}
+ pub fn blend(self, other: Domain) -> Self {
+ Self::Blend(Box::new([self, other]))
+ }
+
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
}
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub struct VarSet {
data: Vec<Series>,
domain: Domain,
todo!()
}
- pub fn blend(self, _other: Self) -> Self {
- todo!()
+ pub fn blend(self, other: Self) -> Self {
+ Self {
+ data: {
+ let ordering = self.case_mapping.blend_ordering(&other.case_mapping);
+ zip_eq(&self.data, &other.data)
+ .map(|(left, right)| left.append(right).reordered(&ordering))
+ .collect_vec()
+ },
+ domain: self.domain.blend(other.domain),
+ case_mapping: self.case_mapping.blend(&other.case_mapping),
+ }
}
}
// `PartialEq` might need to be implemented manually if we introduce a field for
// caching the reverse mapping.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
struct CaseMapping {
map: Vec<usize>,
}
self.map = indexes.into_iter().map(|index| self.map[index]).collect();
self
}
+
+ pub fn blend(&self, other: &Self) -> Self {
+ Self {
+ map: merge(self.map.iter().copied(), other.map.iter().copied()).collect(),
+ }
+ }
+
+ pub fn blend_ordering(&self, other: &Self) -> Vec<usize> {
+ let mut ordering = vec![0; self.len() + other.len()];
+ let mut indexes = [0, self.len()];
+ for (index, side) in merge(
+ self.map.iter().map(|&index| (index, 0)),
+ other.map.iter().map(|&index| (index, 1)),
+ )
+ .map(|(_index, side)| side)
+ .enumerate()
+ {
+ ordering[indexes[side]] = index;
+ indexes[side] += 1;
+ }
+ ordering
+ }
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
- use crate::spv::read::graph::var_set::{Expression, ExpressionParseError, Operator};
+ use crate::{
+ data::Datum,
+ locale::data::EN,
+ spv::read::graph::{
+ Series, SeriesValue,
+ format::Formatter,
+ var_set::{Expression, ExpressionParseError, Operator, VarSet},
+ },
+ };
#[test]
fn parse_expression() {
Err(ExpressionParseError::UnexpectedEof)
);
}
+
+ #[test]
+ fn algebra() {
+ let lhs = VarSet::for_variable(&Series::new(
+ String::from("lhs"),
+ vec![
+ SeriesValue::from(Datum::String(String::from("x"))),
+ SeriesValue::from(Datum::String(String::from("y"))),
+ SeriesValue::from(Datum::String(String::from("z"))),
+ ],
+ true,
+ Formatter::default_for_locale(&EN),
+ ));
+ dbg!(&lhs);
+ let rhs = VarSet::for_variable(&Series::new(
+ String::from("lhs"),
+ vec![
+ SeriesValue::from(Datum::String(String::from("a"))),
+ SeriesValue::from(Datum::String(String::from("b"))),
+ SeriesValue::from(Datum::String(String::from("c"))),
+ ],
+ true,
+ Formatter::default_for_locale(&EN),
+ ));
+ dbg!(&rhs);
+ let cross = lhs.clone().cross(rhs.clone());
+ dbg!(&cross);
+ let nest = lhs.nest(rhs);
+ dbg!(&nest);
+ }
}