1pub mod parse;
78
79pub mod pretty;
87
88pub mod token_parser;
92
93pub mod normal;
95
96pub mod test_utils;
97
98use std::collections::BTreeSet;
99use std::collections::HashMap;
100use std::collections::HashSet;
101use std::fmt;
102
103use rand::RngExt as _;
104use serde::Deserialize;
105use serde::Serialize;
106
107use crate::Slice;
108use crate::selection::normal::NormalizedSelection;
109use crate::selection::normal::RewriteRuleExt;
110use crate::shape;
111use crate::shape::ShapeError;
112use crate::slice::SliceError;
113
114pub trait SelectionSYM {
119 fn false_() -> Self;
121
122 fn true_() -> Self;
124
125 fn all(selection: Self) -> Self;
128
129 fn first(selection: Self) -> Self;
132
133 fn range<R: Into<shape::Range>>(range: R, selection: Self) -> Self;
136
137 fn label<L: Into<LabelKey>>(labels: Vec<L>, selection: Self) -> Self;
140
141 fn any(selection: Self) -> Self;
144
145 fn intersection(lhs: Self, selection: Self) -> Self;
147
148 fn union(lhs: Self, selection: Self) -> Self;
150}
151
152pub mod dsl {
155
156 use super::LabelKey;
157 use super::Selection;
158 use super::SelectionSYM;
159 use crate::shape;
160
161 pub fn false_() -> Selection {
162 SelectionSYM::false_()
163 }
164 pub fn true_() -> Selection {
165 SelectionSYM::true_()
166 }
167 pub fn all(inner: Selection) -> Selection {
168 SelectionSYM::all(inner)
169 }
170 pub fn first(inner: Selection) -> Selection {
171 SelectionSYM::first(inner)
172 }
173 pub fn range<R: Into<shape::Range>>(r: R, inner: Selection) -> Selection {
174 SelectionSYM::range(r, inner)
175 }
176 pub fn label<L: Into<LabelKey>>(labels: Vec<L>, inner: Selection) -> Selection {
177 SelectionSYM::label(labels, inner)
178 }
179 pub fn any(inner: Selection) -> Selection {
180 SelectionSYM::any(inner)
181 }
182 pub fn intersection(lhs: Selection, rhs: Selection) -> Selection {
183 SelectionSYM::intersection(lhs, rhs)
184 }
185 pub fn union(lhs: Selection, rhs: Selection) -> Selection {
186 SelectionSYM::union(lhs, rhs)
187 }
188}
189
190impl SelectionSYM for Selection {
191 fn false_() -> Self {
192 ast::false_()
193 }
194 fn true_() -> Self {
195 ast::true_()
196 }
197 fn all(selection: Self) -> Self {
198 ast::all(selection)
199 }
200 fn first(selection: Self) -> Self {
201 ast::first(selection)
202 }
203 fn range<R: Into<shape::Range>>(range: R, selection: Self) -> Self {
204 ast::range(range, selection)
205 }
206 fn label<L: Into<LabelKey>>(labels: Vec<L>, selection: Selection) -> Selection {
207 let labels = labels.into_iter().map(|l| l.into()).collect();
208 Selection::Label(labels, Box::new(selection))
209 }
210 fn any(selection: Self) -> Self {
211 ast::any(selection)
212 }
213 fn intersection(lhs: Self, rhs: Self) -> Self {
214 ast::intersection(lhs, rhs)
215 }
216 fn union(lhs: Self, rhs: Self) -> Self {
217 ast::union(lhs, rhs)
218 }
219}
220
221impl fmt::Display for Selection {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 write!(f, "{}", pretty::pretty(self))
224 }
225}
226
227#[derive(
245 Clone,
246 Debug,
247 PartialEq,
248 Eq,
249 Hash,
250 Serialize,
251 Deserialize,
252 PartialOrd,
253 Ord
254)]
255pub enum LabelKey {
256 Value(String),
258}
259
260impl From<String> for LabelKey {
261 fn from(s: String) -> Self {
262 LabelKey::Value(s)
263 }
264}
265
266impl From<&str> for LabelKey {
267 fn from(s: &str) -> Self {
268 LabelKey::Value(s.to_string())
269 }
270}
271
272impl std::fmt::Display for LabelKey {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 match self {
275 LabelKey::Value(s) => write!(f, "\"{}\"", s),
276 }
277 }
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
282#[non_exhaustive]
283pub enum Selection {
284 False,
286
287 True,
289
290 All(Box<Selection>),
293
294 First(Box<Selection>),
297
298 Range(shape::Range, Box<Selection>),
301
302 Label(Vec<LabelKey>, Box<Selection>),
305
306 Any(Box<Selection>),
309
310 Intersection(Box<Selection>, Box<Selection>),
312
313 Union(Box<Selection>, Box<Selection>),
315}
316
317fn _assert_selection_traits()
320where
321 Selection: Send + Sync + 'static,
322{
323}
324
325pub fn structurally_equal(a: &Selection, b: &Selection) -> bool {
331 use Selection::*;
332 match (a, b) {
333 (False, False) => true,
334 (True, True) => true,
335 (All(x), All(y)) => structurally_equal(x, y),
336 (Any(x), Any(y)) => structurally_equal(x, y),
337 (First(x), First(y)) => structurally_equal(x, y),
338 (Range(r1, x), Range(r2, y)) => r1 == r2 && structurally_equal(x, y),
339 (Intersection(x1, y1), Intersection(x2, y2)) => {
340 structurally_equal(x1, x2) && structurally_equal(y1, y2)
341 }
342 (Union(x1, y1), Union(x2, y2)) => structurally_equal(x1, x2) && structurally_equal(y1, y2),
343 _ => false,
344 }
345}
346
347pub fn normalize(sel: &Selection) -> NormalizedSelection {
359 let rule = normal::FlatteningRules
360 .then(normal::IdentityRules)
361 .then(normal::AbsorbtionRules);
362 sel.fold::<normal::NormalizedSelection>()
363 .rewrite_bottom_up(&rule)
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Hash)]
372pub struct NormalizedSelectionKey(NormalizedSelection);
373
374impl NormalizedSelectionKey {
375 pub fn new(sel: &Selection) -> Self {
378 Self(crate::selection::normalize(sel))
379 }
380
381 pub fn inner(&self) -> &NormalizedSelection {
383 &self.0
384 }
385
386 pub fn into_inner(self) -> NormalizedSelection {
388 self.0
389 }
390}
391
392mod ast {
393 use super::LabelKey;
394 use super::Selection;
395 use crate::shape;
396
397 pub(crate) fn false_() -> Selection {
398 Selection::False
399 }
400 pub(crate) fn true_() -> Selection {
401 Selection::True
402 }
403 pub(crate) fn all(selection: Selection) -> Selection {
404 Selection::All(Box::new(selection))
405 }
406 pub(crate) fn first(selection: Selection) -> Selection {
407 Selection::First(Box::new(selection))
408 }
409 pub(crate) fn range<R: Into<shape::Range>>(range: R, selection: Selection) -> Selection {
410 Selection::Range(range.into(), Box::new(selection))
411 }
412 #[allow(dead_code)] pub(crate) fn label<L: Into<LabelKey>>(labels: Vec<L>, selection: Selection) -> Selection {
414 let labels = labels.into_iter().map(Into::into).collect();
415 Selection::Label(labels, Box::new(selection))
416 }
417 pub(crate) fn any(selection: Selection) -> Selection {
418 Selection::Any(Box::new(selection))
419 }
420 pub(crate) fn intersection(lhs: Selection, rhs: Selection) -> Selection {
421 Selection::Intersection(Box::new(lhs), Box::new(rhs))
422 }
423 pub(crate) fn union(lhs: Selection, rhs: Selection) -> Selection {
424 Selection::Union(Box::new(lhs), Box::new(rhs))
425 }
426}
427
428pub struct EvalOpts {
431 pub disallow_empty_ranges: bool,
433
434 pub disallow_out_of_range: bool,
437
438 pub disallow_dynamic_selections: bool,
440}
441
442impl EvalOpts {
443 pub fn lenient() -> Self {
445 Self {
446 disallow_empty_ranges: false,
447 disallow_out_of_range: false,
448 disallow_dynamic_selections: false,
449 }
450 }
451
452 #[allow(dead_code)]
455 pub fn strict() -> Self {
456 Self {
457 disallow_empty_ranges: true,
458 disallow_out_of_range: true,
459 ..Self::lenient()
460 }
461 }
462}
463
464impl Selection {
465 pub(crate) fn validate(&self, opts: &EvalOpts, slice: &Slice) -> Result<&Self, ShapeError> {
466 let depth = 0;
467 self.validate_rec(opts, slice, self, depth).map(|_| self)
468 }
469
470 fn validate_rec(
471 &self,
472 opts: &EvalOpts,
473 slice: &Slice,
474 top: &Selection,
475 dim: usize,
476 ) -> Result<(), ShapeError> {
477 if dim == slice.num_dim() {
478 match self {
481 Selection::True | Selection::False => return Ok(()),
482 _ => {
483 return Err(ShapeError::SelectionTooDeep {
484 expr: top.clone(),
485 num_dim: slice.num_dim(),
486 });
487 }
488 }
489 }
490
491 match self {
492 Selection::False | Selection::True => Ok(()),
493 Selection::Range(range, s) => {
494 if range.is_empty() && opts.disallow_empty_ranges {
495 return Err(ShapeError::EmptyRange {
496 range: range.clone(),
497 });
498 } else {
499 if opts.disallow_out_of_range {
500 let size = slice.sizes()[dim];
501 let (min, _, _) = range.resolve(size);
502 if min >= size {
503 return Err(ShapeError::EmptyRange {
506 range: range.clone(),
507 });
508 }
509 }
510
511 s.validate_rec(opts, slice, top, dim + 1)?;
512 }
513
514 Ok(())
515 }
516 Selection::Any(s) => {
517 if opts.disallow_dynamic_selections {
518 return Err(ShapeError::SelectionDynamic { expr: top.clone() });
519 }
520 s.validate_rec(opts, slice, top, dim + 1)?;
521 Ok(())
522 }
523 Selection::All(s) | Selection::Label(_, s) | Selection::First(s) => {
524 s.validate_rec(opts, slice, top, dim + 1)?;
525 Ok(())
526 }
527 Selection::Intersection(a, b) | Selection::Union(a, b) => {
528 a.validate_rec(opts, slice, top, dim)?;
529 b.validate_rec(opts, slice, top, dim)?;
530 Ok(())
531 }
532 }
533 }
534
535 pub fn eval<'a>(
575 &self,
576 opts: &EvalOpts,
577 slice: &'a Slice,
578 ) -> Result<Box<dyn Iterator<Item = usize> + 'a>, ShapeError> {
579 if slice.num_dim() == 0 {
581 let slice = Slice::new(slice.offset(), vec![1], vec![1]).unwrap();
582 return Ok(Box::new(
583 self.validate(opts, &slice)?
584 .eval_rec(&slice, vec![0; 1], 0)
585 .collect::<Vec<_>>()
586 .into_iter(),
587 ));
588 }
589
590 Ok(self
591 .validate(opts, slice)?
592 .eval_rec(slice, vec![0; slice.num_dim()], 0))
593 }
594
595 fn eval_rec<'a>(
596 &self,
597 slice: &'a Slice,
598 env: Vec<usize>,
599 dim: usize,
600 ) -> Box<dyn Iterator<Item = usize> + 'a> {
601 if dim == slice.num_dim() {
602 match self {
603 Selection::True => return Box::new(std::iter::once(slice.location(&env).unwrap())),
604 Selection::False => return Box::new(std::iter::empty()),
605 _ => {
606 panic!("structural combinator {self:?} at leaf level (dim = {dim}))",);
607 }
608 }
609 }
610
611 use itertools;
612 use itertools::EitherOrBoth;
613
614 match self {
615 Selection::False => Box::new(std::iter::empty()),
616 Selection::True => Box::new((0..slice.sizes()[dim]).flat_map(move |i| {
617 let mut env = env.clone();
618 env[dim] = i;
619 Selection::True.eval_rec(slice, env, dim + 1)
620 })),
621 Selection::All(select) => {
622 let select = Box::clone(select);
623 Box::new((0..slice.sizes()[dim]).flat_map(move |i| {
624 let mut env = env.clone();
625 env[dim] = i;
626 select.eval_rec(slice, env, dim + 1)
627 }))
628 }
629 Selection::First(select) => {
630 let select = Box::clone(select);
631 Box::new(iterutils::first(slice.sizes()[dim], move |i| {
632 let mut env = env.clone();
633 env[dim] = i;
634 select.eval_rec(slice, env, dim + 1)
635 }))
636 }
637 Selection::Range(range, select) => {
638 let select = Box::clone(select);
639 let (min, max, step) = range.resolve(slice.sizes()[dim]);
640 Box::new((min..max).step_by(step).flat_map(move |i| {
641 let mut env = env.clone();
642 env[dim] = i;
643 select.eval_rec(slice, env, dim + 1)
644 }))
645 }
646
647 Selection::Label(labels, inner) => {
673 Self::eval_label(labels, inner, slice, env, dim )
674 }
675 Selection::Any(select) => {
676 let select = Box::clone(select);
677 let r = {
678 let upper = slice.sizes()[dim];
679 let mut rng = rand::rng();
680 rng.random_range(0..upper)
681 };
682 Box::new((r..r + 1).flat_map(move |i| {
683 let mut env = env.clone();
684 env[dim] = i;
685 select.eval_rec(slice, env, dim + 1)
686 }))
687 }
688 Selection::Intersection(a, b) => Box::new(
689 itertools::merge_join_by(
690 a.eval_rec(slice, env.clone(), dim),
691 b.eval_rec(slice, env.clone(), dim),
692 |x, y| x.cmp(y),
693 )
694 .filter_map(|either| match either {
695 EitherOrBoth::Both(x, _) => Some(x),
696 _ => None,
697 }),
698 ),
699 Selection::Union(a, b) => Box::new(
700 itertools::merge_join_by(
701 a.eval_rec(slice, env.clone(), dim),
702 b.eval_rec(slice, env.clone(), dim),
703 |x, y| x.cmp(y),
704 )
705 .map(|either| match either {
706 EitherOrBoth::Left(x) => x,
707 EitherOrBoth::Right(y) => y,
708 EitherOrBoth::Both(x, _) => x,
709 }),
710 ),
711 }
712 }
713
714 fn eval_label<'a>(
739 _labels: &[LabelKey],
740 inner: &Selection,
741 slice: &'a Slice,
742 env: Vec<usize>,
743 dim: usize,
744 ) -> Box<dyn Iterator<Item = usize> + 'a> {
746 match inner {
747 Selection::Any(sub_inner) => {
754 let matching: Vec<usize> = (0..slice.sizes()[dim])
755 .filter(|&i| {
756 let mut prefix = env.clone();
757 prefix[dim] = i;
758 true })
760 .collect();
761
762 if matching.is_empty() {
763 return Box::new(std::iter::empty());
764 }
765
766 let mut rng = rand::rng();
767 let chosen = matching[rng.random_range(0..matching.len())];
768
769 let mut coord = env;
770 coord[dim] = chosen;
771 sub_inner.eval_rec(slice, coord, dim + 1 )
772 }
773 _ => {
784 let iter = inner.eval_rec(slice, env.clone(), dim );
786 Box::new(iter.filter(move |&flat| {
787 let _coord = slice.coordinates(flat);
788 true }))
790 }
791 }
792 }
793
794 pub fn is_equivalent_to_true(mut sel: &Selection) -> bool {
823 while let Selection::All(inner) = sel {
824 sel = inner;
825 }
826 matches!(sel, Selection::True)
827 }
828
829 pub fn contains(&self, coords: &[usize]) -> bool {
841 self.contains_rec(coords, 0)
842 }
843
844 fn contains_rec(&self, coords: &[usize], dim: usize) -> bool {
845 if dim >= coords.len() {
846 return matches!(self, Selection::True);
847 }
848
849 match self {
850 Selection::False => false,
851 Selection::True => true,
852 Selection::All(inner) => inner.contains_rec(coords, dim + 1),
853 Selection::Range(range, inner) => {
854 let (min, max, step) = range.resolve(coords.len());
855 let index = coords[dim];
856 index >= min
857 && index < max
858 && (index - min).is_multiple_of(step)
859 && inner.contains_rec(coords, dim + 1)
860 }
861 Selection::Intersection(a, b) => {
862 a.contains_rec(coords, dim) && b.contains_rec(coords, dim)
863 }
864 Selection::Union(a, b) => a.contains_rec(coords, dim) || b.contains_rec(coords, dim),
865 Selection::Label(_, _) | Selection::First(_) | Selection::Any(_) => {
866 unimplemented!()
867 }
868 }
869 }
870
871 pub fn reduce_intersection(self: Selection, b: Selection) -> Selection {
885 match (&self, &b) {
886 (Selection::False, _) | (_, Selection::False) => Selection::False,
887 (Selection::True, other) | (other, Selection::True) => other.clone(),
888 _ => Selection::Intersection(Box::new(self), Box::new(b)),
889 }
890 }
891
892 pub fn fold<S: SelectionSYM>(&self) -> S {
905 match self {
906 Selection::False => S::false_(),
907 Selection::True => S::true_(),
908 Selection::All(inner) => S::all(inner.fold::<S>()),
909 Selection::First(inner) => S::first(inner.fold::<S>()),
910 Selection::Range(r, inner) => S::range(r.clone(), inner.fold::<S>()),
911 Selection::Label(labels, inner) => S::label(labels.clone(), inner.fold::<S>()),
912 Selection::Any(inner) => S::any(inner.fold::<S>()),
913 Selection::Intersection(a, b) => S::intersection(a.fold::<S>(), b.fold::<S>()),
914 Selection::Union(a, b) => S::union(a.fold::<S>(), b.fold::<S>()),
915 }
916 }
917
918 pub fn difference<'a>(
926 &self,
927 opts: &EvalOpts,
928 slice: &'a Slice,
929 exclusions: &'a HashSet<usize>,
930 ) -> Result<impl Iterator<Item = usize> + use<'a>, ShapeError> {
931 Ok(self
932 .eval(opts, slice)?
933 .filter(move |idx| !exclusions.contains(idx)))
934 }
935
936 pub fn without(
947 &self,
948 slice: &Slice,
949 exclusions: &HashSet<usize>,
950 ) -> Result<Selection, ShapeError> {
951 let remaining = self
952 .difference(&EvalOpts::strict(), slice, exclusions)?
953 .collect::<BTreeSet<_>>();
954 Ok(Selection::of_ranks(slice, &remaining)?)
955 }
956
957 pub fn of_ranks(slice: &Slice, ranks: &BTreeSet<usize>) -> Result<Selection, SliceError> {
979 let selections = ranks
980 .iter()
981 .map(|&i| {
982 Ok(slice
983 .coordinates(i)?
984 .into_iter()
985 .rev()
986 .fold(dsl::true_(), |acc, i| dsl::range(i..=i, acc)))
987 })
988 .collect::<Result<Vec<_>, SliceError>>()?;
989
990 Ok(selections
991 .into_iter()
992 .reduce(dsl::union)
993 .unwrap_or_else(dsl::false_))
994 }
995} mod sealed {
998 pub trait Sealed {}
999 impl Sealed for crate::slice::Slice {}
1000}
1001
1002pub trait ReifySlice: sealed::Sealed {
1010 fn reify_slice(&self, slice: &Slice) -> Result<Selection, SliceError>;
1013
1014 fn reify_slices<V: AsRef<[Slice]>>(&self, slices: V) -> Result<Selection, SliceError>;
1017}
1018
1019impl ReifySlice for Slice {
1020 fn reify_slice(&self, slice: &Slice) -> Result<Selection, SliceError> {
1052 if !self.is_contiguous() {
1054 return Err(SliceError::NonContiguous);
1055 }
1056
1057 if slice.is_empty() {
1058 return Ok(dsl::false_());
1059 }
1060
1061 if slice.num_dim() != self.num_dim()
1062 || slice.sizes().iter().zip(self.sizes()).any(|(&v, &s)| v > s)
1063 {
1064 return Selection::of_ranks(self, &slice.iter().collect::<BTreeSet<usize>>());
1065 }
1066
1067 let origin = self.coordinates(slice.offset())?;
1068 let mut acc = dsl::true_();
1069 for dim in (0..self.num_dim()).rev() {
1070 let start = origin[dim];
1071 let len = slice.sizes()[dim];
1072 let slice_stride = slice.strides()[dim];
1073 let base_stride = self.strides()[dim];
1074
1075 if slice_stride.is_multiple_of(base_stride) {
1076 let step = slice_stride / base_stride;
1078 let end = start + step * len;
1079 if end - 1 > self.sizes()[dim] {
1081 let bad = origin
1082 .iter()
1083 .enumerate()
1084 .map(|(d, &x)| if d == dim { end } else { x })
1085 .collect::<Vec<_>>();
1086 return Err(SliceError::ValueNotInSlice {
1087 value: self.location(&bad).unwrap(),
1088 });
1089 }
1090 acc = dsl::range(crate::shape::Range(start, Some(end), step), acc);
1091 } else {
1092 return Selection::of_ranks(self, &slice.iter().collect::<BTreeSet<_>>());
1094 }
1095 }
1096
1097 Ok(acc)
1098 }
1099
1100 fn reify_slices<V: AsRef<[Slice]>>(&self, slices: V) -> Result<Selection, SliceError> {
1135 let slices = slices.as_ref();
1136 let mut selections = Vec::with_capacity(slices.len());
1137
1138 for slice in slices {
1139 if slice.is_empty() {
1140 continue;
1141 }
1142 selections.push(self.reify_slice(slice)?);
1143 }
1144
1145 let mut iter = selections.into_iter();
1146 let first = iter.next().unwrap_or_else(dsl::false_);
1147 Ok(iter.fold(first, dsl::union))
1148 }
1149}
1150
1151pub fn is_equivalent_true(sel: impl std::borrow::Borrow<Selection>) -> bool {
1153 Selection::is_equivalent_to_true(sel.borrow())
1154}
1155
1156mod iterutils {
1157 pub(crate) fn first<'a, F>(size: usize, mut mk_iter: F) -> impl Iterator<Item = usize> + 'a
1160 where
1161 F: FnMut(usize) -> Box<dyn Iterator<Item = usize> + 'a>,
1162 {
1163 (0..size)
1164 .find_map(move |i| {
1165 let mut iter = mk_iter(i).peekable();
1166 if iter.peek().is_some() {
1167 Some(iter)
1168 } else {
1169 None
1170 }
1171 })
1172 .into_iter()
1173 .flatten()
1174 }
1175}
1176
1177pub fn selection_from_one<R>(
1212 shape: &shape::Shape,
1213 label: &str,
1214 rng: R,
1215) -> Result<Selection, ShapeError>
1216where
1217 R: Into<shape::Range>,
1218{
1219 use crate::selection::dsl;
1220
1221 let Some(pos) = shape.labels().iter().position(|l| l == label) else {
1222 return Err(ShapeError::InvalidLabels {
1223 labels: vec![label.to_string()],
1224 });
1225 };
1226
1227 let mut selection = dsl::range(rng.into(), dsl::true_());
1228 for _ in 0..pos {
1229 selection = dsl::all(selection)
1230 }
1231
1232 Ok(selection)
1233}
1234
1235pub fn selection_from<'a, R>(
1272 shape: &shape::Shape,
1273 constraints: &[(&'a str, R)],
1274) -> Result<Selection, ShapeError>
1275where
1276 R: Clone + Into<shape::Range> + 'a,
1277{
1278 use crate::selection::dsl::*;
1279
1280 let mut label_to_constraint = HashMap::new();
1281 for (label, r) in constraints {
1282 if !shape.labels().iter().any(|l| l == label) {
1283 return Err(ShapeError::InvalidLabels {
1284 labels: vec![label.to_string()],
1285 });
1286 }
1287 label_to_constraint.insert(*label, r.clone().into());
1288 }
1289
1290 let selection = shape.labels().iter().rev().fold(true_(), |acc, label| {
1291 if let Some(rng) = label_to_constraint.get(label.as_str()) {
1292 range(rng.clone(), acc)
1293 } else {
1294 all(acc)
1295 }
1296 });
1297
1298 Ok(selection)
1299}
1300
1301#[macro_export]
1347macro_rules! sel_from_shape {
1348 ($shape:expr, $label:ident = $range:expr) => {
1349 $crate::selection::selection_from_one($shape, stringify!($label), $range).unwrap()
1350 };
1351
1352 ($shape:expr, $($label:ident = $val:literal),* $(,)?) => {
1353 $crate::selection::selection_from($shape,
1354 &[
1355 $((stringify!($label), $val..$val+1)),*
1356 ]).unwrap()
1357 };
1358
1359 ($shape:expr, $($label:ident = $range:expr),* $(,)?) => {
1360 $crate::selection::selection_from($shape, &[
1361 $((stringify!($label), $range)),*
1362 ]).unwrap()
1363 };
1364}
1365
1366#[cfg(test)]
1367mod tests {
1368 use std::assert_matches;
1369 use std::collections::BTreeSet;
1370
1371 use super::EvalOpts;
1372 use super::ReifySlice;
1373 use super::Selection;
1374 use super::dsl::*;
1375 use super::is_equivalent_true;
1376 use crate::Range;
1377 use crate::Slice;
1378 use crate::assert_structurally_eq;
1379 use crate::select;
1380 use crate::shape;
1381 use crate::shape::ShapeError;
1382
1383 fn test_slice() -> Slice {
1385 Slice::new(0usize, vec![2, 4, 8], vec![32, 8, 1]).unwrap()
1386 }
1387
1388 fn eval(expr: Selection, slice: &Slice) -> Vec<usize> {
1396 expr.eval(&EvalOpts::lenient(), slice).unwrap().collect()
1397 }
1398
1399 #[test]
1400 fn test_selection_00() {
1401 let slice = &test_slice();
1402
1403 assert!(eval(false_(), slice).is_empty());
1405 assert!(eval(all(false_()), slice).is_empty());
1406 assert!(eval(all(all(false_())), slice).is_empty());
1407
1408 assert_eq!((0..=63).collect::<Vec<_>>(), eval(true_(), slice));
1410 assert_eq!(eval(true_(), slice), eval(all(true_()), slice));
1411 assert_eq!(eval(all(true_()), slice), eval(all(all(true_())), slice));
1412
1413 assert_eq!(eval(true_(), slice), eval(all(all(all(true_()))), slice));
1416 assert!(eval(all(all(all(false_()))), slice).is_empty());
1417 }
1418
1419 #[test]
1420 fn test_selection_01() {
1421 let slice = &test_slice();
1422
1423 let expr = all(all(all(all(true_()))));
1426 let result = expr.validate(&EvalOpts::lenient(), slice);
1427 assert!(
1428 matches!(result, Err(ShapeError::SelectionTooDeep { .. })),
1429 "Unexpected: {:?}",
1430 result
1431 );
1432 assert_eq!(
1433 format!("{}", result.unwrap_err()),
1434 "selection `all(all(all(all(true_()))))` exceeds dimensionality 3"
1435 );
1436 }
1437
1438 #[test]
1439 fn test_selection_02() {
1440 let slice = &test_slice();
1441
1442 let select = range(0..=0, range(0..=0, range(0..=0, true_())));
1444 assert_eq!((0..=0).collect::<Vec<_>>(), eval(select, slice));
1445
1446 let select = range(1..=1, range(1..=1, range(1..=1, true_())));
1448 assert_eq!((41..=41).collect::<Vec<_>>(), eval(select, slice));
1449
1450 let select = all(range(0..=0, all(true_())));
1452 assert_eq!(
1453 (0..=7).chain(32..=39).collect::<Vec<_>>(),
1454 eval(select, slice)
1455 );
1456
1457 let select = all(range(1..=1, all(true_())));
1459 assert_eq!(
1460 (8..=15).chain(40..=47).collect::<Vec<_>>(),
1461 eval(select, slice)
1462 );
1463
1464 let select = all(all(range(0..4, true_())));
1466 assert_eq!(
1467 (0..=3)
1468 .chain(8..=11)
1469 .chain(16..=19)
1470 .chain(24..=27)
1471 .chain(32..=35)
1472 .chain(40..=43)
1473 .chain(48..=51)
1474 .chain(56..=59)
1475 .collect::<Vec<_>>(),
1476 eval(select, slice)
1477 );
1478
1479 let select = all(all(range(4..8, true_())));
1481 assert_eq!(
1482 (4..=7)
1483 .chain(12..=15)
1484 .chain(20..=23)
1485 .chain(28..=31)
1486 .chain(36..=39)
1487 .chain(44..=47)
1488 .chain(52..=55)
1489 .chain(60..=63)
1490 .collect::<Vec<_>>(),
1491 eval(select, slice)
1492 );
1493
1494 let select = all(all(range(shape::Range(1, None, 2), true_())));
1496 assert_eq!(
1497 (1..8)
1498 .step_by(2)
1499 .chain((9..16).step_by(2))
1500 .chain((17..24).step_by(2))
1501 .chain((25..32).step_by(2))
1502 .chain((33..40).step_by(2))
1503 .chain((41..48).step_by(2))
1504 .chain((49..56).step_by(2))
1505 .chain((57..64).step_by(2))
1506 .collect::<Vec<_>>(),
1507 eval(select, slice)
1508 );
1509 }
1510
1511 #[test]
1512 fn test_selection_03() {
1513 let slice = &test_slice();
1514
1515 assert_eq!(
1516 eval(intersection(true_(), true_()), slice),
1517 eval(true_(), slice)
1518 );
1519 assert_eq!(
1520 eval(intersection(true_(), false_()), slice),
1521 eval(false_(), slice)
1522 );
1523 assert_eq!(
1524 eval(intersection(false_(), true_()), slice),
1525 eval(false_(), slice)
1526 );
1527 assert_eq!(
1528 eval(intersection(false_(), false_()), slice),
1529 eval(false_(), slice)
1530 );
1531 assert_eq!(
1532 eval(
1533 intersection(
1534 all(all(range(0..=3, true_()))),
1535 all(all(range(4..=7, true_())))
1536 ),
1537 slice
1538 ),
1539 eval(false_(), slice)
1540 );
1541 assert_eq!(
1542 eval(intersection(true_(), all(all(range(4..8, true_())))), slice),
1543 eval(all(all(range(4..8, true_()))), slice)
1544 );
1545 assert_eq!(
1546 eval(
1547 intersection(
1548 all(all(range(0..=4, true_()))),
1549 all(all(range(4..=7, true_())))
1550 ),
1551 slice
1552 ),
1553 eval(all(all(range(4..=4, true_()))), slice)
1554 );
1555 }
1556
1557 #[test]
1558 fn test_selection_04() {
1559 let slice = &test_slice();
1560
1561 assert_eq!(eval(union(true_(), true_()), slice), eval(true_(), slice));
1562 assert_eq!(eval(union(false_(), true_()), slice), eval(true_(), slice));
1563 assert_eq!(eval(union(true_(), false_()), slice), eval(true_(), slice));
1564 assert_eq!(
1565 eval(union(false_(), false_()), slice),
1566 eval(false_(), slice)
1567 );
1568 assert_eq!(
1569 eval(
1570 union(
1571 all(all(range(0..4, true_()))),
1572 all(all(range(4.., true_())))
1573 ),
1574 slice
1575 ),
1576 eval(true_(), slice)
1577 );
1578
1579 let s = all(range(0..=0, range(0..4, true_())));
1582 let t = all(range(1..=1, range(4.., true_())));
1583 assert_eq!(
1584 (0..=3)
1585 .chain(12..=15)
1586 .chain(32..=35)
1587 .chain(44..=47)
1588 .collect::<Vec<_>>(),
1589 eval(union(s, t), slice)
1590 );
1591
1592 assert_eq!(
1594 (0..=1)
1596 .chain(6..=7)
1597 .chain(8..=9)
1599 .chain(14..=15)
1600 .chain(16..=17)
1602 .chain(22..=23)
1603 .chain(24..=25)
1605 .chain(30..=31)
1606 .chain(32..=33)
1608 .chain(38..=39)
1609 .chain(40..=41)
1611 .chain(46..=47)
1612 .chain(48..=49)
1614 .chain(54..=55)
1615 .chain(56..=57)
1617 .chain(62..=63)
1618 .collect::<Vec<_>>(),
1619 eval(
1620 all(all(union(range(0..2, true_()), range(6..8, true_())))),
1621 slice
1622 )
1623 );
1624
1625 assert_eq!(
1627 (1..8)
1628 .step_by(2)
1629 .chain((9..16).step_by(2))
1630 .chain((17..24).step_by(2))
1631 .chain((25..32).step_by(2))
1632 .chain((33..40).step_by(2))
1633 .chain((41..48).step_by(2))
1634 .chain((49..56).step_by(2))
1635 .chain((57..64).step_by(2))
1636 .collect::<Vec<_>>(),
1637 eval(
1638 all(all(union(
1639 range(shape::Range(1, Some(4), 2), true_()),
1640 range(shape::Range(5, Some(8), 2), true_())
1641 ))),
1642 slice
1643 )
1644 );
1645 assert_eq!(
1646 eval(
1647 all(all(union(
1648 range(shape::Range(1, Some(4), 2), true_()),
1649 range(shape::Range(5, Some(8), 2), true_())
1650 ))),
1651 slice
1652 ),
1653 eval(
1654 all(all(union(
1655 union(range(1..=1, true_()), range(3..=3, true_()),),
1656 union(range(5..=5, true_()), range(7..=7, true_()),),
1657 ))),
1658 slice
1659 ),
1660 );
1661 }
1662
1663 #[test]
1664 fn test_selection_05() {
1665 let slice = &test_slice();
1666
1667 assert!(eval(first(first(false_())), slice).is_empty());
1669 assert_eq!(vec![0], eval(first(first(range(0..1, true_()))), slice));
1671 assert_eq!(
1673 (0..8).collect::<Vec<_>>(),
1674 eval(first(first(true_())), slice)
1675 );
1676
1677 assert!(eval(first(first(first(false_()))), slice).is_empty());
1681 assert_eq!(vec![0], eval(first(first(first(true_()))), slice));
1683
1684 assert_eq!(
1686 (0..8).chain(32..40).collect::<Vec<_>>(),
1687 eval(all(first(true_())), slice)
1688 );
1689
1690 assert_eq!(
1692 (0..3).collect::<Vec<_>>(),
1693 eval(first(first(range(0..=2, true_()))), slice)
1694 );
1695 }
1696
1697 #[test]
1698 fn test_selection_06() {
1699 let slice = &test_slice();
1700
1701 let expr = first(first(first(first(true_()))));
1704 let result = expr.validate(&EvalOpts::lenient(), slice);
1705 assert!(
1706 matches!(result, Err(ShapeError::SelectionTooDeep { .. })),
1707 "Unexpected: {:?}",
1708 result
1709 );
1710 assert_eq!(
1711 format!("{}", result.unwrap_err()),
1712 "selection `first(first(first(first(true_()))))` exceeds dimensionality 3"
1713 );
1714 }
1715
1716 #[test]
1717 fn test_selection_07() {
1718 use crate::select;
1719 use crate::shape;
1720
1721 let s = shape!(host = 2, gpu = 8);
1723
1724 assert_eq!(
1726 select!(s, host = 1)
1727 .unwrap()
1728 .slice()
1729 .iter()
1730 .collect::<Vec<_>>(),
1731 eval(range(1..2, true_()), s.slice())
1732 );
1733
1734 assert_eq!(
1736 select!(s, gpu = 2..)
1737 .unwrap()
1738 .slice()
1739 .iter()
1740 .collect::<Vec<_>>(),
1741 eval(all(range(2.., true_())), s.slice())
1742 );
1743
1744 assert_eq!(
1746 select!(s, gpu = 3..5)
1747 .unwrap()
1748 .slice()
1749 .iter()
1750 .collect::<Vec<_>>(),
1751 eval(all(range(3..5, true_())), s.slice())
1752 );
1753
1754 assert_eq!(
1756 select!(s, gpu = 3..5, host = 1)
1757 .unwrap()
1758 .slice()
1759 .iter()
1760 .collect::<Vec<_>>(),
1761 eval(range(1..=1, range(3..5, true_())), s.slice())
1762 );
1763
1764 assert_matches!(
1766 select!(s, gpu = 1..1).unwrap_err(),
1767 ShapeError::EmptyRange {
1768 range: shape::Range(1, Some(1), 1)
1769 },
1770 );
1771 assert!(eval(all(range(1..1, true_())), s.slice()).is_empty());
1772
1773 assert_matches!(
1775 select!(s, gpu = 8).unwrap_err(),
1776 ShapeError::OutOfRange {
1777 range: shape::Range(8, Some(9), 1),
1778 dim,
1779 size: 8,
1780 } if dim == "gpu",
1781 );
1782 assert!(eval(all(range(8..8, true_())), s.slice()).is_empty());
1783 }
1784
1785 #[test]
1786 fn test_selection_08() {
1787 let s = &shape!(host = 2, gpu = 8);
1788
1789 assert_eq!(
1790 eval(range(1..2, true_()), s.slice()),
1791 eval(sel_from_shape!(s, host = 1), s.slice())
1792 );
1793
1794 assert_eq!(
1795 eval(all(range(2.., true_())), s.slice()),
1796 eval(sel_from_shape!(s, gpu = 2..), s.slice())
1797 );
1798
1799 assert_eq!(
1800 eval(all(range(3..5, true_())), s.slice()),
1801 eval(sel_from_shape!(s, gpu = 3..5), s.slice())
1802 );
1803
1804 assert_eq!(
1805 eval(range(1..2, range(3..5, true_())), s.slice()),
1806 eval(sel_from_shape!(s, host = 1..2, gpu = 3..5), s.slice())
1807 );
1808
1809 assert_eq!(
1810 eval(
1811 union(
1812 sel_from_shape!(s, host = 0..1, gpu = 0..4),
1813 sel_from_shape!(s, host = 1..2, gpu = 4..5)
1814 ),
1815 s.slice()
1816 ),
1817 eval(
1818 union(
1819 range(0..1, range(0..4, true_())),
1820 range(1..2, range(4..5, true_()))
1821 ),
1822 s.slice()
1823 )
1824 );
1825 }
1826
1827 #[test]
1828 fn test_selection_09() {
1829 let slice = &test_slice(); assert_eq!(eval(any(false_()), slice), eval(false_(), slice));
1833
1834 let res = eval(any(any(any(true_()))), slice);
1836 assert_eq!(res.len(), 1);
1837 assert!(res[0] < 64);
1838
1839 let res = eval(range(0, any(range(0..4, true_()))), slice);
1841 assert!((0..4).any(|host| res == eval(range(0, range(host, range(0..4, true_()))), slice)));
1842
1843 let res = eval(range(0, range(0, any(true_()))), slice);
1845 assert_eq!(res.len(), 1);
1846 assert!(res[0] < 8);
1847
1848 let res = eval(range(0, any(true_())), slice);
1850 assert!((0..4).any(|host| res == eval(range(0, range(host, true_())), slice)));
1851
1852 let res = eval(range(1, any(true_())), slice);
1854 assert!((0..4).any(|host| res == eval(range(1, range(host, true_())), slice)));
1855
1856 let mut res = vec![];
1858 while res.len() < 2 {
1859 res = eval(
1860 union(
1861 range(0, range(0, any(true_()))),
1862 range(0, range(0, any(true_()))),
1863 ),
1864 slice,
1865 );
1866 }
1867 assert_matches!(res.as_slice(), [i, j] if *i < *j && *i < 8 && *j < 8);
1868 }
1869
1870 #[test]
1871 fn test_eval_zero_dim_slice() {
1872 let slice_0d = Slice::new(1, vec![], vec![]).unwrap();
1873 assert_eq!(slice_0d.coordinates(1).unwrap(), Vec::<usize>::new());
1876
1877 assert_eq!(eval(true_(), &slice_0d), vec![1]);
1878 assert_eq!(eval(false_(), &slice_0d), Vec::<usize>::new());
1879 assert_eq!(eval(all(true_()), &slice_0d), vec![1]);
1880 assert_eq!(eval(all(false_()), &slice_0d), Vec::<usize>::new());
1881 assert_eq!(eval(union(true_(), true_()), &slice_0d), vec![1]);
1882 assert_eq!(
1883 eval(intersection(true_(), false_()), &slice_0d),
1884 Vec::<usize>::new()
1885 );
1886 }
1887
1888 #[test]
1889 fn test_selection_10() {
1890 let slice = &test_slice();
1891 let opts = EvalOpts {
1892 disallow_dynamic_selections: true,
1893 ..EvalOpts::lenient()
1894 };
1895 let expr = any(any(any(true_())));
1896 let res = expr.validate(&opts, slice);
1897 assert_matches!(res, Err(ShapeError::SelectionDynamic { .. }));
1898 }
1899
1900 #[test]
1901 fn test_13() {
1902 assert!(is_equivalent_true(true_()));
1904 assert!(is_equivalent_true(all(true_())));
1905 assert!(is_equivalent_true(all(all(true_()))));
1906 assert!(is_equivalent_true(all(all(all(true_())))));
1907 assert!(is_equivalent_true(all(all(all(all(true_()))))));
1908 assert!(is_equivalent_true(all(all(all(all(all(true_())))))));
1909 assert!(!is_equivalent_true(false_()));
1912 assert!(!is_equivalent_true(union(true_(), true_())));
1913 assert!(!is_equivalent_true(range(0..=0, true_())));
1914 assert!(!is_equivalent_true(all(false_())));
1915 }
1916
1917 #[test]
1918 fn test_14() {
1919 use std::collections::HashSet;
1920
1921 use crate::selection::NormalizedSelectionKey;
1922 use crate::selection::dsl::*;
1923
1924 let a = all(all(true_()));
1925 let b = all(all(true_()));
1926
1927 let key_a = NormalizedSelectionKey::new(&a);
1928 let key_b = NormalizedSelectionKey::new(&b);
1929
1930 assert_eq!(key_a, key_b);
1932
1933 let mut set = HashSet::new();
1935 set.insert(key_a);
1936 assert!(set.contains(&key_b));
1937 }
1938
1939 #[test]
1940 fn test_contains_true() {
1941 let selection = true_();
1942 assert!(selection.contains(&[0, 0, 0]));
1943 assert!(selection.contains(&[1, 2, 3]));
1944 }
1945
1946 #[test]
1947 fn test_contains_false() {
1948 let selection = false_();
1949 assert!(!selection.contains(&[0, 0, 0]));
1950 assert!(!selection.contains(&[1, 2, 3]));
1951 }
1952
1953 #[test]
1954 fn test_contains_all() {
1955 let selection = all(true_());
1956 assert!(selection.contains(&[0, 0, 0]));
1957 assert!(selection.contains(&[1, 2, 3]));
1958 }
1959
1960 #[test]
1961 fn test_contains_range() {
1962 let selection = range(1..3, true_());
1963 assert!(selection.contains(&[1, 0, 0]));
1964 assert!(!selection.contains(&[3, 0, 0]));
1965 }
1966
1967 #[test]
1968 fn test_contains_intersection() {
1969 let selection = intersection(range(1..3, true_()), range(2..4, true_()));
1970 assert!(selection.contains(&[2, 0, 0]));
1971 assert!(!selection.contains(&[1, 0, 0]));
1972 }
1973
1974 #[test]
1975 fn test_contains_union() {
1976 let selection = union(range(1..2, true_()), range(3..4, true_()));
1977 assert!(selection.contains(&[1, 0, 0]));
1978 assert!(!selection.contains(&[2, 0, 0]));
1979 }
1980
1981 #[test]
1982 #[should_panic(expected = "not implemented")]
1983 fn test_contains_any() {
1984 let selection = any(true_());
1985 selection.contains(&[0, 0, 0]);
1986 }
1987
1988 #[test]
1989 #[should_panic(expected = "not implemented")]
1990 fn test_contains_label() {
1991 let selection = label(vec!["zone".to_string()], true_());
1992 selection.contains(&[1, 2, 3]);
1993 }
1994
1995 #[test]
1996 #[should_panic(expected = "not implemented")]
1997 fn test_contains_first() {
1998 let selection = first(true_());
1999 selection.contains(&[0, 0, 0]);
2000 }
2001
2002 #[test]
2003 fn test_difference_1d() {
2004 assert_eq!(
2005 true_()
2006 .difference(
2007 &EvalOpts::strict(),
2008 &Slice::new_row_major([5]),
2009 &[2usize, 4].into(),
2010 )
2011 .unwrap()
2012 .collect::<Vec<_>>(),
2013 vec![0, 1, 3]
2014 );
2015 }
2016
2017 #[test]
2018 fn test_difference_empty_selection() {
2019 assert_eq!(
2020 false_()
2021 .difference(
2022 &EvalOpts::strict(),
2023 &Slice::new_row_major([3]),
2024 &[0usize, 1].into(),
2025 )
2026 .unwrap()
2027 .collect::<Vec<_>>(),
2028 Vec::<usize>::new()
2029 );
2030 }
2031
2032 #[test]
2033 fn test_difference_2d() {
2034 assert_eq!(
2038 all(all(true_()))
2039 .difference(
2040 &EvalOpts::strict(),
2041 &Slice::new_row_major([2, 3]),
2042 &[3usize, 4, 5].into(),
2043 )
2044 .unwrap()
2045 .collect::<Vec<_>>(),
2046 vec![0, 1, 2]
2047 );
2048 }
2049
2050 #[test]
2051 fn test_of_ranks_1d() {
2052 let slice = Slice::new_row_major([5]);
2053 let ranks = BTreeSet::from([1, 3]);
2054 let selection = Selection::of_ranks(&slice, &ranks).unwrap();
2055 assert_eq!(
2056 selection
2057 .eval(&EvalOpts::strict(), &slice)
2058 .unwrap()
2059 .collect::<Vec<_>>(),
2060 vec![1, 3]
2061 )
2062 }
2063
2064 #[test]
2065 fn test_of_ranks_empty_set() {
2066 let slice = Slice::new_row_major([4]);
2067 let ranks = BTreeSet::new();
2068 let selection = Selection::of_ranks(&slice, &ranks).unwrap();
2069 assert_eq!(
2070 selection
2071 .eval(&EvalOpts::strict(), &slice)
2072 .unwrap()
2073 .collect::<Vec<_>>(),
2074 Vec::<usize>::new()
2075 )
2076 }
2077
2078 #[test]
2079 fn test_of_ranks_singleton_structural() {
2080 let slice = Slice::new_row_major([5]);
2081 let ranks = BTreeSet::from([2]);
2082 let actual = Selection::of_ranks(&slice, &ranks).unwrap();
2083 let expected = range(2..=2, true_());
2084 assert_structurally_eq!(&actual, &expected);
2085 }
2086
2087 #[test]
2088 fn test_of_ranks_union_2d_structural() {
2089 let slice = Slice::new_row_major([2, 3]);
2090 let ranks = BTreeSet::from([2, 3, 4]);
2094 let actual = Selection::of_ranks(&slice, &ranks).unwrap();
2095 let expected = union(
2102 union(range(0, range(2, true_())), range(1, range(0, true_()))),
2103 range(1, range(1, true_())),
2104 );
2105 assert_structurally_eq!(&actual, &expected);
2106 }
2107
2108 #[test]
2109 fn test_of_ranks_3d_structural() {
2110 let slice = Slice::new_row_major([2, 2, 2]);
2111 let ranks = BTreeSet::from([1, 6]);
2116 let actual = Selection::of_ranks(&slice, &ranks).unwrap();
2117 let expected = union(
2118 range(0, range(0, range(1, true_()))), range(1, range(1, range(0, true_()))), );
2121 assert_structurally_eq!(&actual, &expected);
2122 }
2123
2124 #[test]
2125 fn test_of_ranks_invalid_index() {
2126 let slice = Slice::new_row_major([4]);
2127 let ranks = BTreeSet::from([0, 4]); assert!(
2129 Selection::of_ranks(&slice, &ranks).is_err(),
2130 "expected out-of-bounds error"
2131 );
2132 }
2133
2134 #[test]
2135 fn test_reify_slice_empty() {
2136 let slice = Slice::new_row_major([0]);
2137 let selection = slice.reify_slice(&slice).unwrap();
2138 let expected = false_();
2139 assert_structurally_eq!(&selection, expected);
2140 assert_eq!(
2141 selection
2142 .eval(&EvalOpts::lenient(), &slice)
2143 .unwrap()
2144 .collect::<Vec<_>>(),
2145 Vec::<usize>::new()
2146 );
2147 }
2148
2149 #[test]
2150 fn test_reify_slice_1d() {
2151 let shape = shape!(x = 6); let base = shape.slice();
2153
2154 let selected = select!(shape, x = 2..5).unwrap();
2155 let view = selected.slice();
2156
2157 let selection = base.reify_slice(view).unwrap();
2158 let expected = range(2..5, true_());
2159 assert_structurally_eq!(&selection, expected);
2160
2161 let flat: Vec<_> = selection.eval(&EvalOpts::strict(), base).unwrap().collect();
2162 assert_eq!(flat, vec![2, 3, 4]);
2163 }
2164
2165 #[test]
2166 fn test_reify_slice_2d() {
2167 let shape = shape!(x = 4, y = 5); let base = shape.slice();
2169
2170 let selected = select!(shape, x = 1..3, y = 2..5).unwrap();
2172 let view = selected.slice();
2173 let selection = base.reify_slice(view).unwrap();
2174 let expected = range(1..3, range(2..5, true_()));
2175 assert_structurally_eq!(&selection, expected);
2176
2177 let flat: Vec<_> = selection.eval(&EvalOpts::strict(), base).unwrap().collect();
2178 assert_eq!(
2179 flat,
2180 vec![
2181 base.location(&[1, 2]).unwrap(),
2182 base.location(&[1, 3]).unwrap(),
2183 base.location(&[1, 4]).unwrap(),
2184 base.location(&[2, 2]).unwrap(),
2185 base.location(&[2, 3]).unwrap(),
2186 base.location(&[2, 4]).unwrap(),
2187 ]
2188 );
2189 }
2190
2191 #[test]
2192 #[allow(clippy::identity_op)]
2193 fn test_reify_slice_1d_with_stride() {
2194 let shape = shape!(x = 7); let selected = shape.select("x", Range(0, None, 2)).unwrap();
2196 let view = selected.slice();
2197 assert_eq!(view, &Slice::new(0, vec![4], vec![1 * 2]).unwrap());
2198
2199 let base = shape.slice();
2200 let selection = base.reify_slice(view).unwrap();
2201 let expected = range(Range(0, Some(8), 2), true_());
2205 assert_structurally_eq!(&selection, expected);
2206
2207 let flat: Vec<_> = selection.eval(&EvalOpts::strict(), base).unwrap().collect();
2208 assert_eq!(flat, vec![0, 2, 4, 6]);
2209 }
2210
2211 #[test]
2212 #[allow(clippy::identity_op)]
2213 fn test_reify_slice_2d_with_stride() {
2214 let base = shape!(x = 4, y = 4);
2216 let shape = base.select("x", Range(1, Some(4), 2)).unwrap();
2218 let shape = shape.select("y", Range(1, Some(4), 2)).unwrap();
2220 let view = shape.slice();
2221 assert_eq!(
2222 view,
2223 &Slice::new(5, vec![2, 2], vec![4 * 2, 1 * 2]).unwrap()
2224 );
2225
2226 let base = base.slice();
2227 let selection = base.reify_slice(view).unwrap();
2228 let expected = range(Range(1, Some(5), 2), range(Range(1, Some(5), 2), true_()));
2234 assert_structurally_eq!(&selection, expected);
2235
2236 let flat: Vec<_> = selection.eval(&EvalOpts::strict(), base).unwrap().collect();
2237 assert_eq!(flat, vec![5, 7, 13, 15]);
2238 }
2239
2240 #[test]
2241 fn test_reify_slice_selects_column_across_rows() {
2242 let shape = shape!(host = 2, gpu = 4); let base = shape.slice();
2244
2245 let selected = select!(shape, gpu = 2).unwrap(); let view = selected.slice();
2248 let coordinates: Vec<_> = view.iter().map(|i| view.coordinates(i).unwrap()).collect();
2249 assert_eq!(coordinates, [[0, 0], [1, 0]]);
2250
2251 let selection = base.reify_slice(view).unwrap();
2252 let expected = range(0..2, range(2..3, true_()));
2253 assert_structurally_eq!(&selection, expected);
2254
2255 let actual = selection
2256 .eval(&EvalOpts::strict(), base)
2257 .unwrap()
2258 .collect::<Vec<_>>();
2259 assert_eq!(
2260 actual,
2261 vec![
2262 base.location(&[0, 2]).unwrap(),
2263 base.location(&[1, 2]).unwrap()
2264 ]
2265 );
2266 }
2267
2268 #[test]
2269 fn test_reify_slice_dimension_mismatch() {
2270 let shape = shape!(host = 2, gpu = 4);
2271 let base = shape.slice();
2272
2273 let indices = vec![
2276 base.location(&[0, 2]).unwrap(),
2277 base.location(&[1, 2]).unwrap(),
2278 ];
2279
2280 let view = Slice::new(indices[0], vec![indices.len()], vec![4]).unwrap();
2281 let selection = base.reify_slice(&view).unwrap();
2282
2283 let expected = Selection::of_ranks(base, &indices.iter().cloned().collect()).unwrap();
2284 assert_structurally_eq!(&selection, expected);
2285
2286 let actual: Vec<_> = selection.eval(&EvalOpts::strict(), base).unwrap().collect();
2287 assert_eq!(actual, indices);
2288 }
2289
2290 #[test]
2291 fn test_union_of_slices_empty() {
2292 let base = Slice::new_row_major([2]);
2293 let sel = base.reify_slices(&[]).unwrap();
2294 assert_structurally_eq!(&sel, &false_());
2295 assert_eq!(
2296 sel.eval(&EvalOpts::strict(), &base)
2297 .unwrap()
2298 .collect::<Vec<_>>(),
2299 Vec::<usize>::new()
2300 );
2301 }
2302
2303 #[test]
2304 fn test_union_of_slices_singleton() {
2305 let shape = shape!(x = 3);
2306 let base = shape.slice();
2307 let selected = select!(shape, x = 1).unwrap();
2308 let view = selected.slice().clone();
2309
2310 let selection = base.reify_slices(&[view]).unwrap();
2311 let expected = range(1..=1, true_());
2312 assert_structurally_eq!(&selection, &expected);
2313
2314 assert_eq!(
2315 selection
2316 .eval(&EvalOpts::strict(), base)
2317 .unwrap()
2318 .collect::<Vec<_>>(),
2319 vec![1],
2320 );
2321 }
2322
2323 #[test]
2324 fn test_union_of_slices_disjoint() {
2325 let shape = shape!(x = 2, y = 2); let base = shape.slice();
2327
2328 let a = select!(shape, x = 0).unwrap();
2330 let view_a = a.slice().clone();
2331
2332 let b = select!(shape, x = 1).unwrap();
2334 let view_b = b.slice().clone();
2335
2336 let selection = base.reify_slices(&[view_a, view_b]).unwrap();
2337 let expected = union(
2338 range(0..1, range(0..2, true_())),
2339 range(1..2, range(0..2, true_())),
2340 );
2341 assert_structurally_eq!(&selection, &expected);
2342 assert_eq!(
2343 selection
2344 .eval(&EvalOpts::strict(), base)
2345 .unwrap()
2346 .collect::<Vec<_>>(),
2347 base.iter().collect::<Vec<_>>()
2348 );
2349 }
2350
2351 #[test]
2352 fn test_union_of_slices_overlapping() {
2353 let shape = shape!(x = 1, y = 4); let base = shape.slice();
2355
2356 let selected1 = select!(shape, y = 0..2).unwrap();
2357 let view1 = selected1.slice().clone();
2358
2359 let selected2 = select!(shape, y = 1..4).unwrap();
2360 let view2 = selected2.slice().clone();
2361
2362 let selection = base.reify_slices(&[view1, view2]).unwrap();
2363 let expected = union(
2364 range(0..1, range(0..2, true_())),
2365 range(0..1, range(1..4, true_())),
2366 );
2367 assert_structurally_eq!(&selection, &expected);
2368
2369 assert_eq!(
2370 selection
2371 .eval(&EvalOpts::strict(), base)
2372 .unwrap()
2373 .collect::<Vec<_>>(),
2374 base.iter().collect::<Vec<_>>()
2375 );
2376 }
2377}