1use crate::ast::domains::attrs::{PartitionAttr, PermutationAttr};
2use crate::ast::domains::{JectivityAttr, MSetAttr, PartialityAttr, SequenceAttr};
3use crate::ast::pretty::pretty_vec;
4use crate::ast::{
5 AbstractLiteral, DomainOpError, FuncAttr, Literal, Moo, Name, RelAttr, SetAttr, Typeable,
6 domains::{domain::Int, range::Range},
7 matrix,
8 records::Field,
9};
10use crate::bug_assert;
11use crate::range;
12use crate::utils::{
13 count_combinations, count_permutations, derangements, restricted_partition_count,
14 stirling_second_kind,
15};
16use conjure_cp_core::ast::ReturnType;
17use funcmap::FuncMap;
18use itertools::{Itertools, izip};
19use num_traits::ToPrimitive;
20use polyquine::Quine;
21use serde::{Deserialize, Serialize};
22use std::collections::{BTreeMap, BTreeSet};
23use std::fmt::{Display, Formatter};
24use std::iter::zip;
25use uniplate::Uniplate;
26
27pub(super) type FieldGround = Field<Moo<GroundDomain>>;
28
29#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
30#[path_prefix(conjure_cp::ast)]
31pub enum GroundDomain {
33 Empty(ReturnType),
35 Bool,
37 Int(Vec<Range<Int>>),
39 Tuple(Vec<Moo<GroundDomain>>),
41 Record(Vec<FieldGround>),
43 Variant(Vec<FieldGround>),
45 Matrix(Moo<GroundDomain>, Vec<Moo<GroundDomain>>),
48 Sequence(SequenceAttr, Moo<GroundDomain>),
50 Set(SetAttr<Int>, Moo<GroundDomain>),
52 MSet(MSetAttr<Int>, Moo<GroundDomain>),
54 Function(FuncAttr, Moo<GroundDomain>, Moo<GroundDomain>),
56 Relation(RelAttr, Vec<Moo<GroundDomain>>),
58 Partition(PartitionAttr, Moo<GroundDomain>),
60 Permutation(PermutationAttr, Moo<GroundDomain>),
62}
63
64fn regular_partition_count(n: u64, block_size: u64) -> Result<u64, DomainOpError> {
70 if n == 0 {
71 return Ok(1);
72 }
73 if block_size == 0 || !n.is_multiple_of(block_size) {
74 return Ok(0);
75 }
76 let num_parts = n / block_size;
77 let mut numerator = 1u64;
78 let mut remaining = n;
79 for _ in 0..num_parts {
80 let choose = count_combinations(remaining, block_size)?;
81 numerator = numerator
82 .checked_mul(choose)
83 .ok_or(DomainOpError::TooLarge)?;
84 remaining -= block_size;
85 }
86 let num_parts_factorial = (1..=num_parts)
87 .try_fold(1u64, |acc, x| acc.checked_mul(x))
88 .ok_or(DomainOpError::TooLarge)?;
89 numerator
90 .checked_div(num_parts_factorial)
91 .ok_or(DomainOpError::TooLarge)
92}
93
94fn restricted_partitions(
103 elements: &[Literal],
104 block_min: usize,
105 block_max: usize,
106) -> Vec<Vec<Vec<Literal>>> {
107 let block_min = block_min.max(1);
108 if elements.is_empty() {
109 return vec![vec![]];
110 }
111 let (first, rest) = elements.split_first().expect("checked non-empty above");
112
113 let max_extra = block_max.saturating_sub(1).min(rest.len());
114 if block_min.saturating_sub(1) > max_extra {
115 return vec![];
116 }
117
118 let mut results = vec![];
119 for extra in block_min.saturating_sub(1)..=max_extra {
120 for combo in rest.iter().cloned().combinations(extra) {
121 let mut block = vec![first.clone()];
122 block.extend(combo.iter().cloned());
123
124 let remaining: Vec<Literal> = rest
125 .iter()
126 .filter(|elem| !combo.contains(elem))
127 .cloned()
128 .collect();
129
130 for sub_partition in restricted_partitions(&remaining, block_min, block_max) {
131 let mut whole = vec![block.clone()];
132 whole.extend(sub_partition);
133 results.push(whole);
134 }
135 }
136 }
137 results
138}
139
140fn restricted_permutations(
144 elements: &[Literal],
145 moved_min: usize,
146 moved_max: usize,
147) -> impl Iterator<Item = Vec<Literal>> + '_ {
148 let n = elements.len();
149 (0..n)
150 .permutations(n)
151 .filter(move |perm| {
152 let moved = perm.iter().enumerate().filter(|&(i, p)| i != *p).count();
153 moved >= moved_min && moved <= moved_max
154 })
155 .map(move |perm| perm.into_iter().map(|i| elements[i].clone()).collect())
156}
157
158fn permutation_mapping_to_cycles(elements: &[Literal], mapped: &[Literal]) -> Vec<Vec<Literal>> {
164 let forward: std::collections::HashMap<&Literal, &Literal> =
165 elements.iter().zip(mapped.iter()).collect();
166 let mut visited: std::collections::HashSet<&Literal> = std::collections::HashSet::new();
167 let mut cycles = vec![];
168 for start in elements {
169 if visited.contains(start) {
170 continue;
171 }
172 let image = forward[start];
173 if image == start {
174 visited.insert(start);
175 continue;
176 }
177 let mut cycle = vec![start.clone()];
178 visited.insert(start);
179 let mut current = image;
180 while current != start {
181 visited.insert(current);
182 cycle.push(current.clone());
183 current = forward[current];
184 }
185 cycles.push(cycle);
186 }
187 cycles
188}
189
190fn union_sequence_sizes(left: &Range<i32>, right: &Range<i32>) -> Range<i32> {
195 let bounds = |range: &Range<i32>| match range {
196 Range::Single(size) => (*size, Some(*size)),
197 Range::Bounded(min, max) => (*min, Some(*max)),
198 Range::UnboundedL(max) => (0, Some(*max)),
199 Range::UnboundedR(min) => (*min, None),
200 Range::Unbounded => (0, None),
201 };
202
203 let (left_min, left_max) = bounds(left);
204 let (right_min, right_max) = bounds(right);
205 let min = left_min.min(right_min);
206
207 match (left_max, right_max) {
208 (Some(left_max), Some(right_max)) => {
209 let max = left_max.max(right_max);
210 if min == max {
211 Range::Single(min)
212 } else {
213 Range::Bounded(min, max)
214 }
215 }
216 _ => Range::UnboundedR(min),
217 }
218}
219
220impl GroundDomain {
221 pub fn union(&self, other: &GroundDomain) -> Result<GroundDomain, DomainOpError> {
222 match (self, other) {
226 (GroundDomain::Empty(ty), dom) | (dom, GroundDomain::Empty(ty)) => {
227 if *ty == dom.return_type() {
228 Ok(dom.clone())
229 } else {
230 Err(DomainOpError::WrongType)
231 }
232 }
233 (GroundDomain::Bool, GroundDomain::Bool) => Ok(GroundDomain::Bool),
234 (GroundDomain::Bool, _) | (_, GroundDomain::Bool) => Err(DomainOpError::WrongType),
235 (GroundDomain::Int(r1), GroundDomain::Int(r2)) => {
236 let mut rngs = r1.clone();
237 rngs.extend(r2.clone());
238 Ok(GroundDomain::Int(Range::squeeze(&rngs)))
239 }
240 (GroundDomain::Int(_), _) | (_, GroundDomain::Int(_)) => Err(DomainOpError::WrongType),
241 (GroundDomain::Tuple(in1s), GroundDomain::Tuple(in2s)) if in1s.len() == in2s.len() => {
242 let mut inners = Vec::new();
243 for (in1, in2) in zip(in1s, in2s) {
244 inners.push(Moo::new(in1.union(in2)?));
245 }
246 Ok(GroundDomain::Tuple(inners))
247 }
248 (GroundDomain::Tuple(_), _) | (_, GroundDomain::Tuple(_)) => {
249 Err(DomainOpError::WrongType)
250 }
251 (GroundDomain::Record(in1s), GroundDomain::Record(in2s))
252 if in1s.len() == in2s.len() =>
253 {
254 let lhs_fields: BTreeMap<&Name, &Moo<GroundDomain>> =
255 in1s.iter().map(|x| (&x.name, &x.value)).collect();
256 let rhs_fields: BTreeMap<&Name, &Moo<GroundDomain>> =
257 in2s.iter().map(|x| (&x.name, &x.value)).collect();
258 let mut new_fields = Vec::with_capacity(in1s.len());
259 for (n, d) in lhs_fields {
260 let d2 = rhs_fields.get(&n).ok_or(DomainOpError::WrongType)?;
261 let dom = d.union(d2)?;
262 new_fields.push(Field {
263 name: n.clone(),
264 value: dom.into(),
265 });
266 }
267 Ok(GroundDomain::Record(new_fields))
268 }
269 (GroundDomain::Record(_), _) | (_, GroundDomain::Record(_)) => {
270 Err(DomainOpError::WrongType)
271 }
272 (GroundDomain::Matrix(in1, idx1), GroundDomain::Matrix(in2, idx2)) if idx1 == idx2 => {
273 Ok(GroundDomain::Matrix(
274 Moo::new(in1.union(in2)?),
275 idx1.clone(),
276 ))
277 }
278 (GroundDomain::Matrix(_, _), _) | (_, GroundDomain::Matrix(_, _)) => {
279 Err(DomainOpError::WrongType)
280 }
281 (GroundDomain::Set(_, in1), GroundDomain::Set(_, in2)) => Ok(GroundDomain::Set(
282 SetAttr::default(),
283 Moo::new(in1.union(in2)?),
284 )),
285 (GroundDomain::Set(_, _), _) | (_, GroundDomain::Set(_, _)) => {
286 Err(DomainOpError::WrongType)
287 }
288 (GroundDomain::MSet(_, in1), GroundDomain::MSet(_, in2)) => Ok(GroundDomain::MSet(
289 MSetAttr::default(),
290 Moo::new(in1.union(in2)?),
291 )),
292 (GroundDomain::Sequence(attr1, in1), GroundDomain::Sequence(attr2, in2)) => {
293 Ok(GroundDomain::Sequence(
294 SequenceAttr {
295 size: union_sequence_sizes(&attr1.size, &attr2.size),
296 ..SequenceAttr::default()
297 },
298 Moo::new(in1.union(in2)?),
299 ))
300 }
301 (GroundDomain::Sequence(_, _), _) | (_, GroundDomain::Sequence(_, _)) => {
302 Err(DomainOpError::WrongType)
303 }
304 (GroundDomain::Relation(_, in1s), GroundDomain::Relation(_, in2s)) => {
305 let mut inners = Vec::new();
306 for (in1, in2) in zip(in1s, in2s) {
307 inners.push(Moo::new(in1.union(in2)?));
308 }
309 Ok(GroundDomain::Relation(RelAttr::default(), inners))
310 }
311 (GroundDomain::Relation(..), _) | (_, GroundDomain::Relation(..)) => {
312 Err(DomainOpError::WrongType)
313 }
314 #[allow(unreachable_patterns)]
315 (GroundDomain::Variant(_), _) | (_, GroundDomain::Variant(_)) => {
316 todo!("union variant domains")
317 }
318 #[allow(unreachable_patterns)]
319 (GroundDomain::Function(..), _) | (_, GroundDomain::Function(..)) => {
320 todo!("union function domains")
321 }
322 #[allow(unreachable_patterns)]
323 (GroundDomain::Partition(..), _) | (_, GroundDomain::Partition(..)) => {
324 todo!("union partition domains")
325 }
326 #[allow(unreachable_patterns)]
327 (GroundDomain::Permutation(..), _) | (_, GroundDomain::Permutation(..)) => {
328 todo!("union permutation domains")
329 }
330 }
331 }
332
333 pub fn intersect(&self, other: &GroundDomain) -> Result<GroundDomain, DomainOpError> {
340 match (self, other) {
344 (d @ GroundDomain::Empty(ReturnType::Int), GroundDomain::Int(_)) => Ok(d.clone()),
346 (GroundDomain::Int(_), d @ GroundDomain::Empty(ReturnType::Int)) => Ok(d.clone()),
347 (GroundDomain::Empty(ReturnType::Int), d @ GroundDomain::Empty(ReturnType::Int)) => {
348 Ok(d.clone())
349 }
350
351 (GroundDomain::Set(_, inner1), d @ GroundDomain::Empty(ReturnType::Set(inner2)))
353 if matches!(
354 **inner1,
355 GroundDomain::Int(_) | GroundDomain::Empty(ReturnType::Int)
356 ) && matches!(**inner2, ReturnType::Int) =>
357 {
358 Ok(d.clone())
359 }
360 (d @ GroundDomain::Empty(ReturnType::Set(inner1)), GroundDomain::Set(_, inner2))
361 if matches!(**inner1, ReturnType::Int)
362 && matches!(
363 **inner2,
364 GroundDomain::Int(_) | GroundDomain::Empty(ReturnType::Int)
365 ) =>
366 {
367 Ok(d.clone())
368 }
369 (
370 d @ GroundDomain::Empty(ReturnType::Set(inner1)),
371 GroundDomain::Empty(ReturnType::Set(inner2)),
372 ) if matches!(**inner1, ReturnType::Int) && matches!(**inner2, ReturnType::Int) => {
373 Ok(d.clone())
374 }
375
376 (GroundDomain::Set(_, x), GroundDomain::Set(_, y)) => Ok(GroundDomain::Set(
378 SetAttr::default(),
379 Moo::new((*x).intersect(y)?),
380 )),
381
382 (GroundDomain::Int(_), GroundDomain::Int(_)) => {
383 let mut v: BTreeSet<i32> = BTreeSet::new();
384
385 let v1 = self.values_i32()?;
386 let v2 = other.values_i32()?;
387 for value1 in v1.iter() {
388 if v2.contains(value1) && !v.contains(value1) {
389 v.insert(*value1);
390 }
391 }
392 Ok(GroundDomain::from_set_i32(&v))
393 }
394 (GroundDomain::Relation(_, _), GroundDomain::Relation(_, _)) => {
395 todo!("Relation union not yet supported")
396 }
397 _ => Err(DomainOpError::WrongType),
398 }
399 }
400
401 pub fn values(&self) -> Result<Box<dyn Iterator<Item = Literal>>, DomainOpError> {
402 match self {
403 GroundDomain::Empty(_) => Ok(Box::new(vec![].into_iter())),
404 GroundDomain::Bool => Ok(Box::new(
405 vec![Literal::from(false), Literal::from(true)].into_iter(),
406 )),
407 GroundDomain::Int(rngs) => {
408 let rng_iters = rngs
409 .iter()
410 .map(Range::iter)
411 .collect::<Option<Vec<_>>>()
412 .ok_or(DomainOpError::Unbounded)?;
413 Ok(Box::new(
414 rng_iters.into_iter().flat_map(|ri| ri.map(Literal::from)),
415 ))
416 }
417 GroundDomain::Tuple(elem_doms) => {
418 let elem_value_pools: Vec<Vec<Literal>> = elem_doms
420 .iter()
421 .map(|d| d.values().map(|it| it.collect()))
422 .collect::<Result<_, _>>()?;
423
424 let iter = elem_value_pools
426 .into_iter()
427 .multi_cartesian_product()
428 .map(|elems| Literal::AbstractLiteral(AbstractLiteral::Tuple(elems)));
429
430 Ok(Box::new(iter))
431 }
432 GroundDomain::Record(entries) => {
433 let mut sorted: Vec<&_> = entries.iter().collect();
435 sorted.sort_by(|a, b| a.name.cmp(&b.name));
436
437 let names: Vec<_> = sorted.iter().map(|e| e.name.clone()).collect();
438 let value_pools: Vec<Vec<Literal>> = sorted
439 .iter()
440 .map(|e| e.value.values().map(|it| it.collect()))
441 .collect::<Result<_, _>>()?;
442
443 let iter = value_pools
445 .into_iter()
446 .multi_cartesian_product()
447 .map(move |vals| {
448 let record_entries = names
449 .iter()
450 .cloned()
451 .zip(vals)
452 .map(|(name, value)| Field { name, value })
453 .collect();
454 Literal::AbstractLiteral(AbstractLiteral::Record(record_entries))
455 });
456
457 Ok(Box::new(iter))
458 }
459 GroundDomain::Variant(entries) => {
460 let values = entries
461 .iter()
462 .map(|entry| {
463 let name = entry.name.clone();
464 entry.value.values().map(|values| {
465 values.map(move |value| {
466 Literal::AbstractLiteral(AbstractLiteral::Variant(Moo::new(
467 Field {
468 name: name.clone(),
469 value,
470 },
471 )))
472 })
473 })
474 })
475 .collect::<Result<Vec<_>, _>>()?;
476 Ok(Box::new(values.into_iter().flatten()))
477 }
478 GroundDomain::Matrix(elem_dom, idx_doms) => {
479 let shape = matrix::shape_of_dom(self)?;
480 let idx_doms = idx_doms.clone();
481
482 let elem_values: Vec<Literal> = elem_dom.values()?.collect();
484
485 let iter = std::iter::repeat_n(elem_values, shape.size)
487 .multi_cartesian_product()
488 .map(move |flat_elems| {
489 matrix::unflatten_matrix::<Literal>(&flat_elems, &idx_doms, &shape.strides)
490 });
491
492 Ok(Box::new(iter))
493 }
494 GroundDomain::Sequence(attrs, inner_dom) => {
495 if attrs.jectivity != JectivityAttr::None {
496 todo!("Enumerating jective sequence domains is not yet supported")
500 }
501
502 let min_sz = attrs.size.low().copied().unwrap_or(0).max(0);
503 let max_sz = attrs.size.high().copied().ok_or(DomainOpError::Unbounded)?;
504
505 let pool = inner_dom.values()?.collect_vec();
506
507 let iter = (min_sz..=max_sz)
508 .flat_map(move |sz| {
509 std::iter::repeat_n(pool.clone(), sz.max(0) as usize)
510 .multi_cartesian_product()
511 })
512 .map(|elems| Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)));
513
514 Ok(Box::new(iter))
515 }
516 GroundDomain::Set(attrs, inner_dom) => {
517 let n: Int = inner_dom.len_usize()?.try_into()?;
518 let min_sz = attrs.size.low().copied().unwrap_or(0);
519 let max_sz = attrs.size.high().copied().unwrap_or(n);
520
521 let pool = inner_dom.values()?.collect_vec();
522
523 Ok(Box::new(
524 (min_sz..=max_sz)
525 .flat_map(move |sz| pool.clone().into_iter().combinations(sz as usize))
526 .map(|elems| Literal::AbstractLiteral(AbstractLiteral::Set(elems))),
527 ))
528 }
529 GroundDomain::MSet(..) => todo!("Enumerating multi-set domains is not yet supported"),
530 GroundDomain::Function(..) => {
531 todo!("Enumerating function domains is not yet supported")
532 }
533 GroundDomain::Relation(..) => {
534 todo!("Enumerating relation domains is not yet supported")
535 }
536 GroundDomain::Partition(attr, inner_dom) => {
537 let elements: Vec<Literal> = inner_dom.values()?.collect();
538 let n = elements.len();
539
540 let block_lo = attr.part_len.low().copied().unwrap_or(1).max(1) as usize;
541 let block_hi = attr
542 .part_len
543 .high()
544 .copied()
545 .map(|h| (h.max(0) as usize).min(n))
546 .unwrap_or(n);
547 let parts_lo = attr.num_parts.low().copied().unwrap_or(0).max(0) as usize;
548 let parts_hi = attr
549 .num_parts
550 .high()
551 .copied()
552 .map(|h| (h.max(0) as usize).min(n))
553 .unwrap_or(n);
554 let is_regular = attr.is_regular;
555
556 let partitions = if block_lo > block_hi {
557 vec![]
558 } else {
559 restricted_partitions(&elements, block_lo, block_hi)
560 };
561 let iter = partitions.into_iter().filter(move |parts| {
562 let k = parts.len();
563 if k < parts_lo || k > parts_hi {
564 return false;
565 }
566 !is_regular
567 || parts
568 .first()
569 .is_none_or(|first| parts.iter().all(|p| p.len() == first.len()))
570 });
571 Ok(Box::new(iter.map(|parts| {
572 Literal::AbstractLiteral(AbstractLiteral::Partition(parts))
573 })))
574 }
575 GroundDomain::Permutation(attr, inner_dom) => {
576 let elements: Vec<Literal> = inner_dom.values()?.collect();
577 let n = elements.len();
578
579 let moved_lo = attr.num_moved.low().copied().unwrap_or(0).max(0) as usize;
580 let moved_hi = attr
581 .num_moved
582 .high()
583 .copied()
584 .map(|h| (h.max(0) as usize).min(n))
585 .unwrap_or(n);
586
587 if moved_lo > moved_hi {
588 return Ok(Box::new(std::iter::empty()));
589 }
590 let mappings: Vec<Vec<Literal>> =
591 restricted_permutations(&elements, moved_lo, moved_hi).collect();
592 let values = mappings.into_iter().map(move |mapped| {
593 let cycles = permutation_mapping_to_cycles(&elements, &mapped);
594 Literal::AbstractLiteral(AbstractLiteral::Permutation(cycles))
595 });
596 Ok(Box::new(values.collect_vec().into_iter()))
597 }
598 }
599 }
600
601 pub fn length(&self) -> Result<u64, DomainOpError> {
607 match self {
608 GroundDomain::Empty(_) => Ok(0),
609 GroundDomain::Bool => Ok(2),
610 GroundDomain::Int(ranges) => {
611 if ranges.is_empty() {
612 return Ok(0);
613 }
614
615 let mut length = 0u64;
616 for range in ranges {
617 if let Some(range_length) = range.length() {
618 length += range_length as u64;
619 } else {
620 return Err(DomainOpError::Unbounded);
621 }
622 }
623 Ok(length)
624 }
625 GroundDomain::Tuple(domains) => {
626 let mut ans = 1u64;
627 for domain in domains {
628 ans = ans
629 .checked_mul(domain.length()?)
630 .ok_or(DomainOpError::TooLarge)?;
631 }
632 Ok(ans)
633 }
634 GroundDomain::Record(entries) => {
635 let mut ans = 1u64;
637 for entry in entries {
638 let sz = entry.value.length()?;
639 ans = ans.checked_mul(sz).ok_or(DomainOpError::TooLarge)?;
640 }
641 Ok(ans)
642 }
643 GroundDomain::Variant(entries) => {
644 let mut ans = 0u64;
645 for entry in entries {
646 let sz = entry.value.length()?;
647 ans = ans.checked_add(sz).ok_or(DomainOpError::TooLarge)?;
649 }
650 Ok(ans)
651 }
652 GroundDomain::Matrix(inner_domain, idx_domains) => {
653 let inner_sz = inner_domain.length()?;
654 let exp = idx_domains.iter().try_fold(1u32, |acc, val| {
655 let len = val.length()? as u32;
656 acc.checked_mul(len).ok_or(DomainOpError::TooLarge)
657 })?;
658 inner_sz.checked_pow(exp).ok_or(DomainOpError::TooLarge)
659 }
660 GroundDomain::Sequence(seq_attr, inner_domain) => {
661 if seq_attr.jectivity != JectivityAttr::None {
662 todo!("Length bound of jective sequences is not yet supported");
664 }
665
666 let inner_len = inner_domain.length()?;
667 let min_sz = seq_attr.size.low().copied().unwrap_or(0).max(0) as u64;
668 let max_sz = seq_attr
669 .size
670 .high()
671 .copied()
672 .ok_or(DomainOpError::Unbounded)? as u64;
673
674 if min_sz > max_sz {
675 return Ok(0);
676 }
677
678 let mut ans = 0u64;
679 for sz in min_sz..=max_sz {
680 let sz: u32 = sz.try_into().map_err(|_| DomainOpError::TooLarge)?;
681 let c = inner_len.checked_pow(sz).ok_or(DomainOpError::TooLarge)?;
682 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
683 }
684 Ok(ans)
685 }
686 GroundDomain::Set(set_attr, inner_domain) => {
687 let inner_len = inner_domain.length()?;
688 let (min_sz, max_sz) = match set_attr.size {
689 Range::Unbounded => (0, inner_len),
690 Range::Single(n) => (n as u64, n as u64),
691 Range::UnboundedR(n) => (n as u64, inner_len),
692 Range::UnboundedL(n) => (0, n as u64),
693 Range::Bounded(min, max) => (min as u64, max as u64),
694 };
695 let max_sz = max_sz.min(inner_len);
698 if min_sz > max_sz {
699 return Ok(0);
700 }
701 let mut ans = 0u64;
702 for sz in min_sz..=max_sz {
703 let c = count_combinations(inner_len, sz)?;
704 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
705 }
706 Ok(ans)
707 }
708 GroundDomain::MSet(mset_attr, inner_domain) => {
709 let inner_len = inner_domain.length()?;
710 let (min_sz, max_sz) = match mset_attr.size {
711 Range::Unbounded => (0, inner_len),
712 Range::Single(n) => (n as u64, n as u64),
713 Range::UnboundedR(n) => (n as u64, inner_len),
714 Range::UnboundedL(n) => (0, n as u64),
715 Range::Bounded(min, max) => (min as u64, max as u64),
716 };
717 let mut ans = 0u64;
718 for sz in min_sz..=max_sz {
719 let c = count_combinations(inner_len + sz - 1, sz)?;
722 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
723 }
724 Ok(ans)
725 }
726 GroundDomain::Function(attr, domain, codomain) => {
727 let domain_len = domain.length()?;
728 let codomain_len = codomain.length()?;
729
730 match (attr.partiality.clone(), attr.jectivity.clone()) {
731 (PartialityAttr::Total, JectivityAttr::None) => {
732 let exp: u32 = domain_len.try_into()?;
733 codomain_len.checked_pow(exp).ok_or(DomainOpError::TooLarge)
734 }
735 (PartialityAttr::Total, JectivityAttr::Injective) => {
736 if domain_len > codomain_len {
737 return Ok(0);
738 }
739 Ok(count_permutations(codomain_len, domain_len)?)
740 }
741 (PartialityAttr::Total, JectivityAttr::Bijective) => {
742 if domain_len != codomain_len {
743 return Ok(0);
744 }
745 Ok(count_permutations(domain_len, domain_len)?)
746 }
747 (PartialityAttr::Total, JectivityAttr::Surjective) => {
748 let partitions = stirling_second_kind(domain_len, codomain_len)?;
749 let arrangements = count_permutations(codomain_len, codomain_len)?;
750 partitions
751 .checked_mul(arrangements)
752 .ok_or(DomainOpError::TooLarge)
753 }
754 (PartialityAttr::Partial, jectivity) => {
755 let (min_sz, max_sz) = match attr.size {
756 Range::Unbounded => (0, domain_len),
757 Range::Single(n) => (n as u64, n as u64),
758 Range::UnboundedR(n) => (n as u64, domain_len),
759 Range::UnboundedL(n) => (0, n as u64),
760 Range::Bounded(min, max) => (min as u64, max as u64),
761 };
762 let max_sz = max_sz.min(domain_len);
763 if min_sz > max_sz {
764 return Ok(0);
765 }
766
767 let mut ans = 0u64;
768 for sz in min_sz..=max_sz {
769 let choose = count_combinations(domain_len, sz)?;
772 let assign = match jectivity {
773 JectivityAttr::None => codomain_len
774 .checked_pow(sz.try_into()?)
775 .ok_or(DomainOpError::TooLarge)?,
776 JectivityAttr::Injective => {
777 if sz > codomain_len {
778 0
779 } else {
780 count_permutations(codomain_len, sz)?
781 }
782 }
783 JectivityAttr::Bijective => {
784 if sz != codomain_len {
785 0
786 } else {
787 count_permutations(codomain_len, codomain_len)?
788 }
789 }
790 JectivityAttr::Surjective => {
791 let partitions = stirling_second_kind(sz, codomain_len)?;
792 let arrangements =
793 count_permutations(codomain_len, codomain_len)?;
794 partitions
795 .checked_mul(arrangements)
796 .ok_or(DomainOpError::TooLarge)?
797 }
798 };
799 let term = choose.checked_mul(assign).ok_or(DomainOpError::TooLarge)?;
800 ans = ans.checked_add(term).ok_or(DomainOpError::TooLarge)?;
801 }
802 Ok(ans)
803 }
804 }
805 }
806 GroundDomain::Relation(attr, domains) => {
807 let dom_sizes_result: Result<Vec<u64>, DomainOpError> =
808 domains.iter().map(|x| x.length()).collect();
809 let dom_sizes = dom_sizes_result?;
810 let inner_len: u64 = dom_sizes.iter().product();
811
812 let (min_sz, max_sz) = match attr.size {
813 Range::Unbounded => (0, inner_len),
814 Range::Single(n) => (n as u64, n as u64),
815 Range::UnboundedR(n) => (n as u64, inner_len),
816 Range::UnboundedL(n) => (0, n as u64),
817 Range::Bounded(min, max) => (min as u64, max as u64),
818 };
819 let max_sz = max_sz.min(inner_len);
820 if min_sz > max_sz {
821 return Ok(0);
822 }
823
824 let mut ans = 0u64;
825 for sz in min_sz..=max_sz {
826 let c = count_combinations(inner_len, sz)?;
827 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
828 }
829 Ok(ans)
830 }
831 GroundDomain::Partition(attr, inner_domain) => {
832 let n = inner_domain.length()?;
833 let block_lo = attr.part_len.low().copied().unwrap_or(1).max(1) as u64;
834 let block_hi = attr
835 .part_len
836 .high()
837 .copied()
838 .map(|h| (h.max(0) as u64).min(n))
839 .unwrap_or(n);
840 let parts_lo = attr.num_parts.low().copied().unwrap_or(0).max(0) as u64;
841 let parts_hi = attr
842 .num_parts
843 .high()
844 .copied()
845 .map(|h| (h.max(0) as u64).min(n))
846 .unwrap_or(n);
847 if block_lo > block_hi || parts_lo > parts_hi {
848 return Ok(0);
849 }
850
851 if attr.is_regular {
852 let mut ans = 0u64;
853 for block_size in block_lo..=block_hi {
854 if n % block_size != 0 {
855 continue;
856 }
857 let num_parts = n / block_size;
858 if num_parts < parts_lo || num_parts > parts_hi {
859 continue;
860 }
861 let c = regular_partition_count(n, block_size)?;
862 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
863 }
864 Ok(ans)
865 } else {
866 let mut ans = 0u64;
867 for num_parts in parts_lo..=parts_hi {
868 let c = restricted_partition_count(n, num_parts, block_lo, block_hi)?;
869 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
870 }
871 Ok(ans)
872 }
873 }
874 GroundDomain::Permutation(attr, inner_domain) => {
875 let n = inner_domain.length()?;
876 let moved_lo = attr.num_moved.low().copied().unwrap_or(0).max(0) as u64;
877 let moved_hi = attr
878 .num_moved
879 .high()
880 .copied()
881 .map(|h| (h.max(0) as u64).min(n))
882 .unwrap_or(n);
883 if moved_lo > moved_hi {
884 return Ok(0);
885 }
886
887 let mut ans = 0u64;
888 for moved in moved_lo..=moved_hi {
889 let choose = count_combinations(n, moved)?;
890 let derange = derangements(moved)?;
891 let term = choose.checked_mul(derange).ok_or(DomainOpError::TooLarge)?;
892 ans = ans.checked_add(term).ok_or(DomainOpError::TooLarge)?;
893 }
894 Ok(ans)
895 }
896 }
897 }
898
899 pub fn len_usize(&self) -> Result<usize, DomainOpError> {
901 self.length()?
902 .try_into()
903 .map_err(|_| DomainOpError::TooLarge)
904 }
905
906 pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
907 match self {
910 GroundDomain::Empty(_) => Ok(false),
912 GroundDomain::Bool => match lit {
913 Literal::Bool(_) => Ok(true),
914 _ => Ok(false),
915 },
916 GroundDomain::Int(ranges) => match lit {
917 Literal::Int(x) => {
918 if ranges.is_empty() {
919 return Ok(false);
920 };
921
922 Ok(ranges.iter().any(|range| range.contains(x)))
923 }
924 _ => Ok(false),
925 },
926 GroundDomain::Tuple(elem_domains) => {
927 match lit {
928 Literal::AbstractLiteral(AbstractLiteral::Tuple(literal_elems)) => {
929 if elem_domains.len() != literal_elems.len() {
930 return Ok(false);
931 }
932
933 for (elem_domain, elem) in itertools::izip!(elem_domains, literal_elems) {
935 if !elem_domain.contains(elem)? {
936 return Ok(false);
937 }
938 }
939
940 Ok(true)
941 }
942 _ => Ok(false),
943 }
944 }
945 GroundDomain::Record(entries) => match lit {
946 Literal::AbstractLiteral(AbstractLiteral::Record(lit_entries)) => {
947 if entries.len() != lit_entries.len() {
948 return Ok(false);
949 }
950
951 for (entry, lit_entry) in itertools::izip!(entries, lit_entries) {
952 if entry.name != lit_entry.name
953 || !(entry.value.contains(&lit_entry.value)?)
954 {
955 return Ok(false);
956 }
957 }
958 Ok(true)
959 }
960 _ => Ok(false),
961 },
962 GroundDomain::Variant(entries) => match lit {
963 Literal::AbstractLiteral(AbstractLiteral::Variant(lit_entry)) => {
964 let Some(entry) = entries.iter().find(|entry| entry.name == lit_entry.name)
965 else {
966 return Ok(false);
967 };
968 entry.value.contains(&lit_entry.value)
969 }
970 _ => Ok(false),
971 },
972 GroundDomain::Matrix(elem_domain, index_domains) => {
973 match lit {
974 Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx_domain)) => {
975 if elems.is_empty()
979 && index_domains
980 .iter()
981 .any(|index_domain| index_domain.length() == Ok(0))
982 {
983 return Ok(true);
984 }
985
986 let Some((current_index_domain, remaining_index_domains)) =
987 index_domains.split_first()
988 else {
989 panic!("a matrix should have at least one index domain");
990 };
991
992 if *current_index_domain != *idx_domain {
993 return Ok(false);
994 };
995
996 let next_elem_domain = if remaining_index_domains.is_empty() {
997 elem_domain.as_ref().clone()
1000 } else {
1001 GroundDomain::Matrix(
1003 elem_domain.clone(),
1004 remaining_index_domains.to_vec(),
1005 )
1006 };
1007
1008 for elem in elems {
1009 if !next_elem_domain.contains(elem)? {
1010 return Ok(false);
1011 }
1012 }
1013
1014 Ok(true)
1015 }
1016 _ => Ok(false),
1017 }
1018 }
1019 GroundDomain::Sequence(seq_attr, inner_dom) => match lit {
1020 Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)) => {
1021 let sz = elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1022 if !seq_attr.size.contains(&sz) {
1023 return Ok(false);
1024 }
1025
1026 for elem in elems {
1027 if !inner_dom.contains(elem)? {
1028 return Ok(false);
1029 }
1030 }
1031 Ok(true)
1032 }
1033 _ => Ok(false),
1034 },
1035 GroundDomain::Set(set_attr, inner_domain) => match lit {
1036 Literal::AbstractLiteral(AbstractLiteral::Set(lit_elems)) => {
1037 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1039 if !set_attr.size.contains(&sz) {
1040 return Ok(false);
1041 }
1042
1043 for elem in lit_elems {
1044 if !inner_domain.contains(elem)? {
1045 return Ok(false);
1046 }
1047 }
1048 Ok(true)
1049 }
1050 _ => Ok(false),
1051 },
1052 GroundDomain::MSet(mset_attr, inner_domain) => match lit {
1053 Literal::AbstractLiteral(AbstractLiteral::MSet(lit_elems)) => {
1054 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1056 if !mset_attr.size.contains(&sz) {
1057 return Ok(false);
1058 }
1059
1060 for elem in lit_elems {
1061 if !inner_domain.contains(elem)? {
1062 return Ok(false);
1063 }
1064 }
1065 Ok(true)
1066 }
1067 _ => Ok(false),
1068 },
1069 GroundDomain::Function(func_attr, domain, codomain) => match lit {
1070 Literal::AbstractLiteral(AbstractLiteral::Function(lit_elems)) => {
1071 let sz = Int::try_from(lit_elems.len()).expect("Should convert");
1072 if !func_attr.size.contains(&sz) {
1073 return Ok(false);
1074 }
1075 for lit in lit_elems {
1076 let domain_element = &lit.0;
1077 let codomain_element = &lit.1;
1078 if !domain.contains(domain_element)? {
1079 return Ok(false);
1080 }
1081 if !codomain.contains(codomain_element)? {
1082 return Ok(false);
1083 }
1084 }
1085 Ok(true)
1086 }
1087 _ => Ok(false),
1088 },
1089 GroundDomain::Relation(rel_attr, inner_domains) => match lit {
1090 Literal::AbstractLiteral(AbstractLiteral::Relation(lit_elems)) => {
1091 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1093 if !rel_attr.size.contains(&sz) {
1094 return Ok(false);
1095 }
1096
1097 for elem_tuple in lit_elems {
1098 if elem_tuple.len() == inner_domains.len() {
1099 for (elem, inner_dom) in elem_tuple.iter().zip(inner_domains.iter()) {
1100 if !inner_dom.contains(elem)? {
1101 return Ok(false);
1102 }
1103 }
1104 } else {
1105 return Ok(false);
1106 }
1107 }
1108 Ok(true)
1109 }
1110 _ => Ok(false),
1111 },
1112 GroundDomain::Partition(attr, dom) => match lit {
1113 Literal::AbstractLiteral(AbstractLiteral::Partition(lit_elems)) => {
1114 let sz: i32 = lit_elems
1116 .iter()
1117 .flatten()
1118 .count()
1119 .to_i32()
1120 .ok_or(DomainOpError::TooLarge)?;
1121
1122 let min: Option<i32> = match (attr.num_parts.low(), attr.part_len.low()) {
1123 (Some(x), Some(y)) => Some(x * y),
1124 _ => None,
1125 };
1126
1127 let max: Option<i32> = match (attr.num_parts.high(), attr.part_len.high()) {
1128 (Some(x), Some(y)) => Some(x * y),
1129 _ => None,
1130 };
1131
1132 let rng = Range::new(min, max);
1133 if !rng.contains(&sz) {
1134 return Ok(false);
1135 }
1136
1137 for elem in lit_elems.iter().flatten() {
1138 if !dom.contains(elem)? {
1139 return Ok(false);
1140 }
1141 }
1142 Ok(true)
1143 }
1144 _ => Ok(false),
1145 },
1146 GroundDomain::Permutation(attr, dom) => match lit {
1147 Literal::AbstractLiteral(AbstractLiteral::Permutation(cycles)) => {
1148 let sz: i32 = cycles
1152 .iter()
1153 .flatten()
1154 .count()
1155 .to_i32()
1156 .ok_or(DomainOpError::TooLarge)?;
1157 if !attr.num_moved.contains(&sz) {
1158 return Ok(false);
1159 }
1160
1161 for elem in cycles.iter().flatten() {
1162 if !dom.contains(elem)? {
1163 return Ok(false);
1164 }
1165 }
1166 Ok(true)
1167 }
1168 _ => Ok(false),
1169 },
1170 }
1171 }
1172
1173 pub fn values_i32(&self) -> Result<Vec<i32>, DomainOpError> {
1180 if let GroundDomain::Empty(ReturnType::Int) = self {
1181 return Ok(vec![]);
1182 }
1183 let GroundDomain::Int(ranges) = self else {
1184 return Err(DomainOpError::NotInteger(self.return_type()));
1185 };
1186
1187 if ranges.is_empty() {
1188 return Ok(vec![]);
1189 }
1190
1191 let mut values = vec![];
1192 for range in ranges {
1193 match range {
1194 Range::Single(i) => {
1195 values.push(*i);
1196 }
1197 Range::Bounded(i, j) => {
1198 values.extend(*i..=*j);
1199 }
1200 Range::UnboundedR(_) | Range::UnboundedL(_) | Range::Unbounded => {
1201 return Err(DomainOpError::Unbounded);
1202 }
1203 }
1204 }
1205
1206 Ok(values)
1207 }
1208
1209 pub fn from_set_i32(elements: &BTreeSet<i32>) -> GroundDomain {
1248 if elements.is_empty() {
1249 return GroundDomain::Empty(ReturnType::Int);
1250 }
1251 if elements.len() == 1 {
1252 return GroundDomain::Int(vec![Range::Single(*elements.first().unwrap())]);
1253 }
1254
1255 let mut elems_iter = elements.iter().copied();
1256
1257 let mut ranges: Vec<Range<i32>> = vec![];
1258
1259 let mut lower = elems_iter
1264 .next()
1265 .expect("if we get here, elements should have => 2 elements");
1266 let mut upper = lower;
1267
1268 for current in elems_iter {
1269 if current == upper + 1 {
1272 upper = current;
1275 } else {
1276 if lower == upper {
1281 ranges.push(range!(lower));
1282 } else {
1283 ranges.push(range!(lower..upper));
1284 }
1285
1286 lower = current;
1287 upper = current;
1288 }
1289 }
1290
1291 if lower == upper {
1293 ranges.push(range!(lower));
1294 } else {
1295 ranges.push(range!(lower..upper));
1296 }
1297
1298 ranges = Range::squeeze(&ranges);
1299 GroundDomain::Int(ranges)
1300 }
1301
1302 pub fn apply_i32(
1312 &self,
1313 op: fn(i32, i32) -> Option<i32>,
1314 other: &GroundDomain,
1315 ) -> Result<GroundDomain, DomainOpError> {
1316 let vs1 = self.values_i32()?;
1317 let vs2 = other.values_i32()?;
1318
1319 let mut set = BTreeSet::new();
1320 for (v1, v2) in itertools::iproduct!(vs1, vs2) {
1321 if let Some(v) = op(v1, v2) {
1322 set.insert(v);
1323 }
1324 }
1325
1326 Ok(GroundDomain::from_set_i32(&set))
1327 }
1328
1329 pub fn is_finite(&self) -> bool {
1331 for domain in self.universe() {
1332 if let GroundDomain::Int(ranges) = domain
1333 && ranges.iter().any(|range| {
1334 matches!(
1335 range,
1336 Range::UnboundedL(_) | Range::UnboundedR(_) | Range::Unbounded
1337 )
1338 })
1339 {
1340 return false;
1341 }
1342 }
1343 true
1344 }
1345
1346 pub fn from_literal_vec(literals: &[Literal]) -> Result<GroundDomain, DomainOpError> {
1427 if literals.is_empty() {
1430 return Ok(GroundDomain::Empty(ReturnType::Unknown));
1431 }
1432
1433 let first_literal = literals.first().unwrap();
1434
1435 match first_literal {
1436 Literal::Int(_) => {
1437 let mut ints = BTreeSet::new();
1439 for lit in literals {
1440 let Literal::Int(i) = lit else {
1441 return Err(DomainOpError::WrongType);
1442 };
1443
1444 ints.insert(*i);
1445 }
1446
1447 Ok(GroundDomain::from_set_i32(&ints))
1448 }
1449 Literal::Bool(_) => {
1450 if literals.iter().any(|x| !matches!(x, Literal::Bool(_))) {
1452 Err(DomainOpError::WrongType)
1453 } else {
1454 Ok(GroundDomain::Bool)
1455 }
1456 }
1457 Literal::AbstractLiteral(AbstractLiteral::Set(_)) => {
1458 let mut all_elems = vec![];
1459
1460 for lit in literals {
1461 let Literal::AbstractLiteral(AbstractLiteral::Set(elems)) = lit else {
1462 return Err(DomainOpError::WrongType);
1463 };
1464
1465 all_elems.extend(elems.clone());
1466 }
1467 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1468
1469 Ok(GroundDomain::Set(SetAttr::default(), Moo::new(elem_domain)))
1470 }
1471 Literal::AbstractLiteral(AbstractLiteral::MSet(_)) => {
1472 let mut all_elems = vec![];
1473
1474 for lit in literals {
1475 let Literal::AbstractLiteral(AbstractLiteral::MSet(elems)) = lit else {
1476 return Err(DomainOpError::WrongType);
1477 };
1478
1479 all_elems.extend(elems.clone());
1480 }
1481 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1482
1483 Ok(GroundDomain::MSet(
1484 MSetAttr::default(),
1485 Moo::new(elem_domain),
1486 ))
1487 }
1488 Literal::AbstractLiteral(AbstractLiteral::Partition(_)) => {
1489 todo!("Need to figure out how this is going to work")
1490 }
1491 Literal::AbstractLiteral(AbstractLiteral::Permutation(_)) => {
1492 todo!("Need to figure out how this is going to work")
1493 }
1494 l @ Literal::AbstractLiteral(AbstractLiteral::Matrix(_, _)) => {
1495 let mut first_index_domain = vec![];
1496 let mut l = l.clone();
1498 while let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = l {
1499 bug_assert!(
1500 !matches!(idx.as_ref(), GroundDomain::Matrix(_, _)),
1501 "n-dimensional matrix literals should be represented as a matrix inside a matrix"
1502 );
1503 first_index_domain.push(idx);
1504 let Some(first_elem) = elems.first() else {
1505 break;
1506 };
1507 l = first_elem.clone();
1508 }
1509
1510 let mut all_elems: Vec<Literal> = vec![];
1511
1512 for lit in literals {
1514 let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = lit else {
1515 return Err(DomainOpError::NotGround);
1516 };
1517
1518 all_elems.extend(elems.clone());
1519
1520 let mut index_domain = vec![idx.clone()];
1521 let Some(first_elem) = elems.first() else {
1522 if index_domain != first_index_domain {
1523 return Err(DomainOpError::WrongType);
1524 }
1525 continue;
1526 };
1527 let mut l = first_elem.clone();
1528 while let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = l {
1529 bug_assert!(
1530 !matches!(idx.as_ref(), GroundDomain::Matrix(_, _)),
1531 "n-dimensional matrix literals should be represented as a matrix inside a matrix"
1532 );
1533 index_domain.push(idx);
1534 let Some(first_elem) = elems.first() else {
1535 break;
1536 };
1537 l = first_elem.clone();
1538 }
1539
1540 if index_domain != first_index_domain {
1541 return Err(DomainOpError::WrongType);
1542 }
1543 }
1544
1545 let mut terminal_elements: Vec<Literal> = vec![];
1547 while let Some(elem) = all_elems.pop() {
1548 if let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, _)) = elem {
1549 all_elems.extend(elems);
1550 } else {
1551 terminal_elements.push(elem);
1552 }
1553 }
1554
1555 let element_domain = GroundDomain::from_literal_vec(&terminal_elements)?;
1556
1557 Ok(GroundDomain::Matrix(
1558 Moo::new(element_domain),
1559 first_index_domain,
1560 ))
1561 }
1562
1563 Literal::AbstractLiteral(AbstractLiteral::Tuple(first_elems)) => {
1564 let n_fields = first_elems.len();
1565
1566 let mut elem_domains = vec![];
1568
1569 for i in 0..n_fields {
1570 let mut all_elems = vec![];
1571 for lit in literals {
1572 let Literal::AbstractLiteral(AbstractLiteral::Tuple(elems)) = lit else {
1573 return Err(DomainOpError::NotGround);
1574 };
1575
1576 if elems.len() != n_fields {
1577 return Err(DomainOpError::NotGround);
1578 }
1579
1580 all_elems.push(elems[i].clone());
1581 }
1582
1583 elem_domains.push(Moo::new(GroundDomain::from_literal_vec(&all_elems)?));
1584 }
1585
1586 Ok(GroundDomain::Tuple(elem_domains))
1587 }
1588
1589 Literal::AbstractLiteral(AbstractLiteral::Sequence(_)) => {
1590 let mut all_elems = vec![];
1591 let mut lengths = Vec::new();
1592
1593 for lit in literals {
1594 let Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)) = lit else {
1595 return Err(DomainOpError::WrongType);
1596 };
1597
1598 lengths.push(i32::try_from(elems.len()).map_err(|_| DomainOpError::TooLarge)?);
1599 all_elems.extend(elems.clone());
1600 }
1601 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1602
1603 let min = lengths.iter().copied().min().unwrap_or(0);
1606 let max = lengths.iter().copied().max().unwrap_or(0);
1607 let size = if min == max {
1608 Range::Single(min)
1609 } else {
1610 Range::Bounded(min, max)
1611 };
1612
1613 Ok(GroundDomain::Sequence(
1614 SequenceAttr {
1615 size,
1616 ..SequenceAttr::default()
1617 },
1618 Moo::new(elem_domain),
1619 ))
1620 }
1621
1622 Literal::AbstractLiteral(AbstractLiteral::Record(first_elems)) => {
1623 let n_fields = first_elems.len();
1624 let field_names = first_elems.iter().map(|x| x.name.clone()).collect_vec();
1625
1626 let mut elem_domains = vec![];
1628
1629 for i in 0..n_fields {
1630 let mut all_elems = vec![];
1631 for lit in literals {
1632 let Literal::AbstractLiteral(AbstractLiteral::Record(elems)) = lit else {
1633 return Err(DomainOpError::NotGround);
1634 };
1635
1636 if elems.len() != n_fields {
1637 return Err(DomainOpError::NotGround);
1638 }
1639
1640 let elem = elems[i].clone();
1641 if elem.name != field_names[i] {
1642 return Err(DomainOpError::NotGround);
1643 }
1644
1645 all_elems.push(elem.value);
1646 }
1647
1648 elem_domains.push(Moo::new(GroundDomain::from_literal_vec(&all_elems)?));
1649 }
1650
1651 Ok(GroundDomain::Record(
1652 izip!(field_names, elem_domains)
1653 .map(|(name, value)| FieldGround { name, value })
1654 .collect(),
1655 ))
1656 }
1657 Literal::AbstractLiteral(AbstractLiteral::Function(_)) => {
1658 let mut all_keys = vec![];
1659 let mut all_values = vec![];
1660
1661 for lit in literals {
1662 let Literal::AbstractLiteral(AbstractLiteral::Function(pairs)) = lit else {
1663 return Err(DomainOpError::WrongType);
1664 };
1665
1666 for (key, value) in pairs {
1667 all_keys.push(key.clone());
1668 all_values.push(value.clone());
1669 }
1670 }
1671
1672 let domain = GroundDomain::from_literal_vec(&all_keys)?;
1673 let codomain = GroundDomain::from_literal_vec(&all_values)?;
1674
1675 Ok(GroundDomain::Function(
1676 FuncAttr::default(),
1677 Moo::new(domain),
1678 Moo::new(codomain),
1679 ))
1680 }
1681 Literal::AbstractLiteral(AbstractLiteral::Variant(_)) => {
1682 let mut alternatives: Vec<(Name, Vec<Literal>)> = Vec::new();
1683 for literal in literals {
1684 let Literal::AbstractLiteral(AbstractLiteral::Variant(field)) = literal else {
1685 return Err(DomainOpError::WrongType);
1686 };
1687 if let Some((_, values)) = alternatives
1688 .iter_mut()
1689 .find(|(name, _)| name == &field.name)
1690 {
1691 values.push(field.value.clone());
1692 } else {
1693 alternatives.push((field.name.clone(), vec![field.value.clone()]));
1694 }
1695 }
1696
1697 Ok(GroundDomain::Variant(
1698 alternatives
1699 .into_iter()
1700 .map(|(name, values)| {
1701 Ok(FieldGround {
1702 name,
1703 value: Moo::new(GroundDomain::from_literal_vec(&values)?),
1704 })
1705 })
1706 .collect::<Result<Vec<_>, DomainOpError>>()?,
1707 ))
1708 }
1709 Literal::AbstractLiteral(AbstractLiteral::Relation(_)) => {
1710 let mut columns: Vec<Vec<Literal>> = vec![];
1711 for lit in literals {
1712 let Literal::AbstractLiteral(AbstractLiteral::Relation(tuples)) = lit else {
1713 return Err(DomainOpError::WrongType);
1714 };
1715 for tuple in tuples {
1716 if columns.is_empty() {
1717 columns = vec![Vec::new(); tuple.len()];
1718 }
1719 if tuple.len() != columns.len() {
1720 return Err(DomainOpError::NotGround);
1721 }
1722 for (column, field) in columns.iter_mut().zip(tuple) {
1723 column.push(field.clone());
1724 }
1725 }
1726 }
1727
1728 let inner_domains = columns
1729 .iter()
1730 .map(|column| GroundDomain::from_literal_vec(column).map(Moo::new))
1731 .collect::<Result<Vec<_>, _>>()?;
1732
1733 Ok(GroundDomain::Relation(RelAttr::default(), inner_domains))
1734 }
1735 }
1736 }
1737
1738 pub fn element_domain(&self) -> Option<Moo<GroundDomain>> {
1739 match self {
1740 GroundDomain::Matrix(inner, _) => Some(inner.clone()),
1741 GroundDomain::Set(_, inner) => Some(inner.clone()),
1742 GroundDomain::MSet(_, inner) => Some(inner.clone()),
1743 GroundDomain::Relation(_, inner_doms) => {
1744 Some(Moo::new(GroundDomain::Tuple(inner_doms.clone())))
1745 }
1746 GroundDomain::Sequence(attr, inner) => {
1749 let max = match attr.size {
1750 Range::Single(max) | Range::UnboundedL(max) | Range::Bounded(_, max) => max,
1751 Range::UnboundedR(_) | Range::Unbounded => return None,
1752 };
1753 Some(Moo::new(GroundDomain::Tuple(vec![
1754 Moo::new(GroundDomain::Int(vec![Range::Bounded(1, max)])),
1755 inner.clone(),
1756 ])))
1757 }
1758 _ => None,
1759 }
1760 }
1761
1762 pub fn has_representation_preference(&self) -> bool {
1764 match self {
1765 GroundDomain::Empty(_) => false,
1766 GroundDomain::Bool => false,
1767 GroundDomain::Int(_) => false,
1768 GroundDomain::Tuple(inners) => inners.iter().any(|d| d.has_representation_preference()),
1769 GroundDomain::Record(entries) => entries
1770 .iter()
1771 .any(|f| f.value.has_representation_preference()),
1772 GroundDomain::Variant(entries) => entries
1773 .iter()
1774 .any(|f| f.value.has_representation_preference()),
1775 GroundDomain::Matrix(inner, idxs) => {
1776 inner.has_representation_preference()
1777 || idxs.iter().any(|d| d.has_representation_preference())
1778 }
1779 GroundDomain::Sequence(attr, inner) => {
1780 attr.representation.is_some() || inner.has_representation_preference()
1781 }
1782 GroundDomain::Set(attr, inner) => {
1783 attr.representation.is_some() || inner.has_representation_preference()
1784 }
1785 GroundDomain::MSet(attr, inner) => {
1786 attr.representation.is_some() || inner.has_representation_preference()
1787 }
1788 GroundDomain::Function(_, dom, cdom) => {
1789 dom.has_representation_preference() || cdom.has_representation_preference()
1790 }
1791 GroundDomain::Relation(_, inners) => {
1792 inners.iter().any(|d| d.has_representation_preference())
1793 }
1794 GroundDomain::Partition(_, inner) => inner.has_representation_preference(),
1795 GroundDomain::Permutation(_, inner) => inner.has_representation_preference(),
1796 }
1797 }
1798
1799 pub fn as_type_string(&self) -> String {
1801 match self {
1802 GroundDomain::Empty(ty) => format!("empty({ty})"),
1803 GroundDomain::Bool => "bool".to_string(),
1804 GroundDomain::Int(_) => "int".to_string(),
1805 GroundDomain::Tuple(inners) => {
1806 format!(
1807 "tuple ({})",
1808 inners.iter().map(|d| d.as_type_string()).join(", ")
1809 )
1810 }
1811 GroundDomain::Record(entries) => {
1812 let inners = entries
1813 .iter()
1814 .map(|f| format!("{}: {}", f.name, f.value.as_type_string()))
1815 .join(", ");
1816 format!("record {{{inners}}}")
1817 }
1818 GroundDomain::Variant(entries) => {
1819 let inners = entries
1820 .iter()
1821 .map(|f| format!("{}: {}", f.name, f.value.as_type_string()))
1822 .join(", ");
1823 format!("variant {{{inners}}}")
1824 }
1825 GroundDomain::Matrix(inner, idxs) => {
1826 let idxs = idxs.iter().map(|d| d.as_type_string()).join(", ");
1827 format!("matrix indexed by [{idxs}] of {}", inner.as_type_string())
1828 }
1829 GroundDomain::Sequence(_, inner) => format!("sequence of {}", inner.as_type_string()),
1830 GroundDomain::Set(attrs, inner) => {
1831 let mut out = String::from("set");
1832 if let Some(repr) = &attrs.representation {
1833 out.push_str(" (representation ");
1834 out.push_str(repr);
1835 out.push(')');
1836 }
1837 out.push_str(" of ");
1838 out.push_str(&inner.as_type_string());
1839 out
1840 }
1841 GroundDomain::MSet(attrs, inner) => {
1842 let mut out = String::from("mset");
1843 if let Some(repr) = &attrs.representation {
1844 out.push_str(" (representation ");
1845 out.push_str(repr);
1846 out.push(')');
1847 }
1848 out.push_str(" of ");
1849 out.push_str(&inner.as_type_string());
1850 out
1851 }
1852 GroundDomain::Function(_, dom, cdom) => {
1853 format!(
1854 "function {} --> {}",
1855 dom.as_type_string(),
1856 cdom.as_type_string()
1857 )
1858 }
1859 GroundDomain::Relation(_, inners) => {
1860 format!(
1861 "relation of ({})",
1862 inners.iter().map(|d| d.as_type_string()).join(" * ")
1863 )
1864 }
1865 GroundDomain::Partition(_, inner) => {
1866 format!("partition from {}", inner.as_type_string())
1867 }
1868 GroundDomain::Permutation(_, inner) => {
1869 format!("permutation of {}", inner.as_type_string())
1870 }
1871 }
1872 }
1873}
1874
1875impl Typeable for GroundDomain {
1876 fn return_type(&self) -> ReturnType {
1877 match self {
1878 GroundDomain::Empty(ty) => ty.clone(),
1879 GroundDomain::Bool => ReturnType::Bool,
1880 GroundDomain::Int(_) => ReturnType::Int,
1881 GroundDomain::Tuple(inners) => {
1882 let mut inner_types = Vec::new();
1883 for inner in inners {
1884 inner_types.push(inner.return_type());
1885 }
1886 ReturnType::Tuple(inner_types)
1887 }
1888 GroundDomain::Record(entries) => {
1889 let mut entry_types = Vec::new();
1890 for entry in entries {
1891 entry_types.push(entry.clone().func_map(|x| x.return_type()));
1892 }
1893 ReturnType::Record(entry_types)
1894 }
1895 GroundDomain::Variant(entries) => {
1896 let mut entry_types = Vec::new();
1897 for entry in entries {
1898 entry_types.push(entry.clone().func_map(|x| x.return_type()));
1899 }
1900 ReturnType::Variant(entry_types)
1901 }
1902 GroundDomain::Matrix(inner, _idx) => ReturnType::Matrix(Box::new(inner.return_type())),
1903 GroundDomain::Sequence(_attr, inner) => {
1904 ReturnType::Sequence(Box::new(inner.return_type()))
1905 }
1906 GroundDomain::Set(_attr, inner) => ReturnType::Set(Box::new(inner.return_type())),
1907 GroundDomain::MSet(_attr, inner) => ReturnType::MSet(Box::new(inner.return_type())),
1908 GroundDomain::Function(_, dom, cdom) => {
1909 ReturnType::Function(Box::new(dom.return_type()), Box::new(cdom.return_type()))
1910 }
1911 GroundDomain::Relation(_, inners) => {
1912 let mut inner_types = Vec::new();
1913 for inner in inners {
1914 inner_types.push(inner.return_type());
1915 }
1916 ReturnType::Relation(inner_types)
1917 }
1918 GroundDomain::Partition(_, inner) => {
1919 ReturnType::Partition(Box::new(inner.return_type()))
1920 }
1921 GroundDomain::Permutation(_, inner) => {
1922 ReturnType::Permutation(Box::new(inner.return_type()))
1923 }
1924 }
1925 }
1926}
1927
1928impl Display for FieldGround {
1929 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1930 write!(f, "{}: {}", self.name, self.value)
1931 }
1932}
1933
1934impl Display for GroundDomain {
1935 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1936 match &self {
1937 GroundDomain::Empty(ty) => write!(f, "empty({ty})"),
1938 GroundDomain::Bool => write!(f, "bool"),
1939 GroundDomain::Int(ranges) => {
1940 if ranges.iter().all(Range::is_lower_or_upper_bounded) {
1941 let rngs: String = ranges.iter().map(|r| format!("{r}")).join(", ");
1942 write!(f, "int({})", rngs)
1943 } else {
1944 write!(f, "int")
1945 }
1946 }
1947 GroundDomain::Tuple(domains) => {
1948 write!(f, "tuple ({})", domains.iter().join(", "))
1949 }
1950 GroundDomain::Record(entries) => {
1951 let inners = entries.iter().map(|t| format!("{}", t)).join(", ");
1952 write!(f, "record {{{inners}}}",)
1953 }
1954 GroundDomain::Variant(entries) => {
1955 let inners = entries.iter().map(|t| format!("{}", t)).join(", ");
1956 write!(f, "variant {{{inners}}}",)
1957 }
1958 GroundDomain::Matrix(value_domain, index_domains) => {
1959 write!(
1960 f,
1961 "matrix indexed by {} of {value_domain}",
1962 pretty_vec(&index_domains.iter().collect_vec())
1963 )
1964 }
1965 GroundDomain::Sequence(attrs, inner_dom) => {
1966 write!(f, "sequence {attrs} of {inner_dom}")
1967 }
1968 GroundDomain::Set(attrs, inner_dom) => {
1969 write!(f, "set")?;
1970 let attrs = attrs.to_string();
1971 if attrs.is_empty() {
1972 write!(f, " of {inner_dom}")
1973 } else {
1974 write!(f, " {attrs} of {inner_dom}")
1975 }
1976 }
1977 GroundDomain::MSet(attrs, inner_dom) => {
1978 write!(f, "mset")?;
1979 let attrs = attrs.to_string();
1980 if attrs.is_empty() {
1981 write!(f, " of {inner_dom}")
1982 } else {
1983 write!(f, " {attrs} of {inner_dom}")
1984 }
1985 }
1986 GroundDomain::Function(attribute, domain, codomain) => {
1987 write!(f, "function {} {} --> {} ", attribute, domain, codomain)
1988 }
1989 GroundDomain::Relation(attrs, domains) => {
1990 write!(f, "relation {} of ({})", attrs, domains.iter().join(" * "))
1991 }
1992 GroundDomain::Partition(attrs, inner) => {
1993 write!(f, "partition {attrs} from {inner}")
1994 }
1995 GroundDomain::Permutation(attrs, inner) => {
1996 write!(f, "permutation {attrs} of {inner}")
1997 }
1998 }
1999 }
2000}
2001
2002#[cfg(test)]
2003mod tests {
2004 use super::*;
2005 use crate::ast::Name;
2006 use crate::{domain_int_ground, matrix_lit};
2007
2008 #[test]
2009 fn matrix_values_1d_bool_of_bool() {
2010 let dom = GroundDomain::Matrix(
2013 Moo::new(GroundDomain::Bool),
2014 vec![Moo::new(GroundDomain::Bool)],
2015 );
2016
2017 let values: Vec<Literal> = dom.values().unwrap().collect();
2018
2019 assert_eq!(values.len(), 4);
2020 assert_eq!(
2021 values[0],
2022 matrix_lit![false, false; Moo::new(GroundDomain::Bool)]
2023 );
2024 assert_eq!(
2025 values[1],
2026 matrix_lit![false, true; Moo::new(GroundDomain::Bool)]
2027 );
2028 assert_eq!(
2029 values[2],
2030 matrix_lit![true, false; Moo::new(GroundDomain::Bool)]
2031 );
2032 assert_eq!(
2033 values[3],
2034 matrix_lit![true, true; Moo::new(GroundDomain::Bool)]
2035 );
2036 }
2037
2038 #[test]
2039 fn matrix_values_1d_int() {
2040 let dom = GroundDomain::Matrix(domain_int_ground!(0..1), vec![domain_int_ground!(1..2)]);
2043
2044 let values: Vec<Literal> = dom.values().unwrap().collect();
2045
2046 assert_eq!(values.len(), 4);
2047 assert_eq!(values[0], matrix_lit![0, 0; domain_int_ground!(1..2)]);
2048 assert_eq!(values[1], matrix_lit![0, 1; domain_int_ground!(1..2)]);
2049 assert_eq!(values[2], matrix_lit![1, 0; domain_int_ground!(1..2)]);
2050 assert_eq!(values[3], matrix_lit![1, 1; domain_int_ground!(1..2)]);
2051 }
2052
2053 #[test]
2054 fn matrix_values_2d_lexicographic() {
2055 let dom = GroundDomain::Matrix(
2058 domain_int_ground!(0..1),
2059 vec![domain_int_ground!(1..2), domain_int_ground!(1..2)],
2060 );
2061
2062 let values: Vec<Literal> = dom.values().unwrap().collect();
2063
2064 assert_eq!(values.len(), 16);
2065
2066 assert_eq!(
2068 values[0],
2069 matrix_lit![[0, 0], [0, 0]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2070 );
2071 assert_eq!(
2073 values[1],
2074 matrix_lit![[0, 0], [0, 1]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2075 );
2076 assert_eq!(
2078 values[2],
2079 matrix_lit![[0, 0], [1, 0]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2080 );
2081 assert_eq!(
2083 values[3],
2084 matrix_lit![[0, 0], [1, 1]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2085 );
2086 assert_eq!(
2088 values[15],
2089 matrix_lit![[1, 1], [1, 1]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2090 );
2091 }
2092
2093 #[test]
2094 fn matrix_values_count_matches_length() {
2095 let dom = GroundDomain::Matrix(domain_int_ground!(0..1), vec![domain_int_ground!(1..3)]);
2098
2099 let count = dom.values().unwrap().count();
2100 let length = dom.length().unwrap();
2101
2102 assert_eq!(count as u64, length);
2103 }
2104
2105 #[test]
2106 fn tuple_values_two_bools() {
2107 let dom = GroundDomain::Tuple(vec![
2109 Moo::new(GroundDomain::Bool),
2110 Moo::new(GroundDomain::Bool),
2111 ]);
2112
2113 let values: Vec<Literal> = dom.values().unwrap().collect();
2114
2115 assert_eq!(values.len(), 4);
2116 let t = |a, b| {
2117 Literal::AbstractLiteral(AbstractLiteral::Tuple(vec![
2118 Literal::Bool(a),
2119 Literal::Bool(b),
2120 ]))
2121 };
2122 assert_eq!(values[0], t(false, false));
2123 assert_eq!(values[1], t(false, true));
2124 assert_eq!(values[2], t(true, false));
2125 assert_eq!(values[3], t(true, true));
2126 }
2127
2128 #[test]
2129 fn tuple_values_mixed_domains() {
2130 let dom = GroundDomain::Tuple(vec![Moo::new(GroundDomain::Bool), domain_int_ground!(0..2)]);
2132
2133 let values: Vec<Literal> = dom.values().unwrap().collect();
2134
2135 assert_eq!(values.len(), 6);
2136 let t = |b: bool, i: i32| {
2137 Literal::AbstractLiteral(AbstractLiteral::Tuple(vec![
2138 Literal::Bool(b),
2139 Literal::Int(i),
2140 ]))
2141 };
2142 assert_eq!(values[0], t(false, 0));
2144 assert_eq!(values[1], t(false, 1));
2145 assert_eq!(values[2], t(false, 2));
2146 assert_eq!(values[3], t(true, 0));
2148 assert_eq!(values[4], t(true, 1));
2149 assert_eq!(values[5], t(true, 2));
2150 }
2151
2152 #[test]
2153 fn tuple_values_count_matches_length() {
2154 let dom = GroundDomain::Tuple(vec![
2155 domain_int_ground!(1..3),
2156 Moo::new(GroundDomain::Bool),
2157 domain_int_ground!(0..1),
2158 ]);
2159 let count = dom.values().unwrap().count();
2160 let length = dom.length().unwrap();
2161 assert_eq!(count as u64, length);
2162 }
2163
2164 #[test]
2165 fn record_values_lexicographic_by_name() {
2166 let dom = GroundDomain::Record(vec![
2169 Field {
2170 name: Name::user("b"),
2171 value: Moo::new(GroundDomain::Bool),
2172 },
2173 Field {
2174 name: Name::user("a"),
2175 value: domain_int_ground!(0..1),
2176 },
2177 ]);
2178
2179 let values: Vec<Literal> = dom.values().unwrap().collect();
2180
2181 assert_eq!(values.len(), 4);
2183
2184 let r = |a_val: i32, b_val: bool| {
2186 Literal::AbstractLiteral(AbstractLiteral::Record(vec![
2187 Field {
2188 name: Name::user("a"),
2189 value: Literal::Int(a_val),
2190 },
2191 Field {
2192 name: Name::user("b"),
2193 value: Literal::Bool(b_val),
2194 },
2195 ]))
2196 };
2197
2198 assert_eq!(values[0], r(0, false));
2200 assert_eq!(values[1], r(0, true));
2201 assert_eq!(values[2], r(1, false));
2202 assert_eq!(values[3], r(1, true));
2203 }
2204
2205 #[test]
2206 fn record_values_count_matches_length() {
2207 let dom = GroundDomain::Record(vec![
2208 Field {
2209 name: Name::user("x"),
2210 value: domain_int_ground!(1..3),
2211 },
2212 Field {
2213 name: Name::user("y"),
2214 value: Moo::new(GroundDomain::Bool),
2215 },
2216 ]);
2217 let count = dom.values().unwrap().count();
2218 let length = dom.length().unwrap();
2219 assert_eq!(count as u64, length);
2220 }
2221
2222 #[test]
2223 fn variant_values_follow_alternative_order_and_match_length() {
2224 let dom = GroundDomain::Variant(vec![
2225 Field {
2226 name: Name::user("flag"),
2227 value: Moo::new(GroundDomain::Bool),
2228 },
2229 Field {
2230 name: Name::user("value"),
2231 value: domain_int_ground!(2..3),
2232 },
2233 ]);
2234 let values = dom.values().unwrap().collect::<Vec<_>>();
2235 assert_eq!(values.len() as u64, dom.length().unwrap());
2236 assert_eq!(values.len(), 4);
2237 assert!(matches!(
2238 &values[0],
2239 Literal::AbstractLiteral(AbstractLiteral::Variant(field))
2240 if field.name == Name::user("flag") && field.value == Literal::Bool(false)
2241 ));
2242 assert!(matches!(
2243 &values[3],
2244 Literal::AbstractLiteral(AbstractLiteral::Variant(field))
2245 if field.name == Name::user("value") && field.value == Literal::Int(3)
2246 ));
2247 assert!(dom.contains(&values[2]).unwrap());
2248 }
2249
2250 #[test]
2251 fn infers_variant_domain_from_all_observed_alternatives() {
2252 let variant = |name: &str, value: i32| {
2253 Literal::AbstractLiteral(AbstractLiteral::Variant(Moo::new(Field {
2254 name: Name::user(name),
2255 value: Literal::Int(value),
2256 })))
2257 };
2258 let domain =
2259 GroundDomain::from_literal_vec(&[variant("a", 10), variant("a", 13), variant("b", 7)])
2260 .unwrap();
2261 let GroundDomain::Variant(fields) = domain else {
2262 panic!("expected variant domain");
2263 };
2264
2265 assert_eq!(fields.len(), 2);
2266 assert_eq!(fields[0].name, Name::user("a"));
2267 assert!(fields[0].value.contains(&Literal::Int(10)).unwrap());
2268 assert!(fields[0].value.contains(&Literal::Int(13)).unwrap());
2269 assert_eq!(fields[1].name, Name::user("b"));
2270 assert!(fields[1].value.contains(&Literal::Int(7)).unwrap());
2271 }
2272
2273 fn set_lit(elems: Vec<i32>) -> Literal {
2274 Literal::AbstractLiteral(AbstractLiteral::Set(
2275 elems.into_iter().map(Literal::Int).collect(),
2276 ))
2277 }
2278
2279 #[test]
2280 fn set_values_unbounded() {
2281 let dom = GroundDomain::Set(SetAttr::default(), domain_int_ground!(1..3));
2283
2284 let values: Vec<Literal> = dom.values().unwrap().collect();
2285
2286 assert_eq!(values.len(), 8);
2287 assert_eq!(values[0], set_lit(vec![])); assert_eq!(values[1], set_lit(vec![1])); assert_eq!(values[2], set_lit(vec![2]));
2290 assert_eq!(values[3], set_lit(vec![3]));
2291 assert_eq!(values[4], set_lit(vec![1, 2])); assert_eq!(values[5], set_lit(vec![1, 3]));
2293 assert_eq!(values[6], set_lit(vec![2, 3]));
2294 assert_eq!(values[7], set_lit(vec![1, 2, 3])); }
2296
2297 #[test]
2298 fn set_values_fixed_size() {
2299 let dom = GroundDomain::Set(SetAttr::new_size(2), domain_int_ground!(1..3));
2301
2302 let values: Vec<Literal> = dom.values().unwrap().collect();
2303
2304 assert_eq!(values.len(), 3);
2305 assert_eq!(values[0], set_lit(vec![1, 2]));
2306 assert_eq!(values[1], set_lit(vec![1, 3]));
2307 assert_eq!(values[2], set_lit(vec![2, 3]));
2308 }
2309
2310 #[test]
2311 fn set_values_bounded_size() {
2312 let dom = GroundDomain::Set(SetAttr::new_min_max_size(1, 2), domain_int_ground!(1..3));
2314
2315 let values: Vec<Literal> = dom.values().unwrap().collect();
2316
2317 assert_eq!(values.len(), 6);
2318 assert_eq!(values[0], set_lit(vec![1]));
2319 assert_eq!(values[1], set_lit(vec![2]));
2320 assert_eq!(values[2], set_lit(vec![3]));
2321 assert_eq!(values[3], set_lit(vec![1, 2]));
2322 assert_eq!(values[4], set_lit(vec![1, 3]));
2323 assert_eq!(values[5], set_lit(vec![2, 3]));
2324 }
2325
2326 #[test]
2327 fn set_length_clamps_max_size_to_inner_domain() {
2328 let dom = GroundDomain::Set(SetAttr::new_max_size(3), domain_int_ground!(1..2));
2330 assert_eq!(dom.length().unwrap(), 4);
2331 }
2332
2333 #[test]
2334 fn set_values_count_matches_length() {
2335 let dom = GroundDomain::Set(SetAttr::default(), domain_int_ground!(1..4));
2336 let count = dom.values().unwrap().count();
2337 let length = dom.length().unwrap();
2338 assert_eq!(count as u64, length);
2339 }
2340
2341 fn func_attr(partiality: PartialityAttr, jectivity: JectivityAttr) -> FuncAttr {
2342 FuncAttr {
2343 size: Range::Unbounded,
2344 partiality,
2345 jectivity,
2346 }
2347 }
2348
2349 #[test]
2350 fn total_bijective_function_length_is_factorial_of_the_shared_size() {
2351 let dom = GroundDomain::Function(
2352 func_attr(PartialityAttr::Total, JectivityAttr::Bijective),
2353 domain_int_ground!(1..3),
2354 domain_int_ground!(1..3),
2355 );
2356 assert_eq!(dom.length().unwrap(), 6); }
2358
2359 #[test]
2360 fn total_bijective_function_length_is_zero_for_mismatched_sizes() {
2361 let dom = GroundDomain::Function(
2362 func_attr(PartialityAttr::Total, JectivityAttr::Bijective),
2363 domain_int_ground!(1..3),
2364 domain_int_ground!(1..2),
2365 );
2366 assert_eq!(dom.length().unwrap(), 0);
2367 }
2368
2369 #[test]
2370 fn total_injective_function_length_is_a_falling_factorial() {
2371 let dom = GroundDomain::Function(
2373 func_attr(PartialityAttr::Total, JectivityAttr::Injective),
2374 domain_int_ground!(1..2),
2375 domain_int_ground!(1..4),
2376 );
2377 assert_eq!(dom.length().unwrap(), 12);
2378 }
2379
2380 #[test]
2381 fn total_surjective_function_length_uses_stirling_numbers() {
2382 let dom = GroundDomain::Function(
2384 func_attr(PartialityAttr::Total, JectivityAttr::Surjective),
2385 domain_int_ground!(1..3),
2386 domain_int_ground!(1..2),
2387 );
2388 assert_eq!(dom.length().unwrap(), 6);
2389 }
2390
2391 #[test]
2392 fn partial_injective_function_length_sums_over_defined_sizes() {
2393 let mut attr = func_attr(PartialityAttr::Partial, JectivityAttr::Injective);
2396 attr.size = Range::Bounded(0, 2);
2397 let dom = GroundDomain::Function(attr, domain_int_ground!(1..3), domain_int_ground!(1..2));
2398 assert_eq!(dom.length().unwrap(), 13);
2399 }
2400
2401 fn partition_attr(num_parts: Range<i32>, part_len: Range<i32>) -> PartitionAttr {
2402 PartitionAttr {
2403 num_parts,
2404 part_len,
2405 is_regular: false,
2406 }
2407 }
2408
2409 fn partition_lit(parts: Vec<Vec<i32>>) -> Literal {
2410 Literal::AbstractLiteral(AbstractLiteral::Partition(
2411 parts
2412 .into_iter()
2413 .map(|part| part.into_iter().map(Literal::Int).collect())
2414 .collect(),
2415 ))
2416 }
2417
2418 #[test]
2419 fn partition_contains_accepts_a_literal_whose_size_exactly_matches_num_parts_times_part_len() {
2420 let dom = GroundDomain::Partition(
2422 partition_attr(Range::Single(2), Range::Single(2)),
2423 domain_int_ground!(1..6),
2424 );
2425 let lit = partition_lit(vec![vec![1, 2], vec![3, 4]]);
2426 assert!(
2427 dom.contains(&lit).unwrap(),
2428 "a 4-element partition literal should be a valid member of a \
2429 (numParts 2, partSize 2) domain"
2430 );
2431 }
2432
2433 #[test]
2434 fn partition_contains_rejects_a_literal_with_the_wrong_covered_size() {
2435 let dom = GroundDomain::Partition(
2437 partition_attr(Range::Single(2), Range::Single(2)),
2438 domain_int_ground!(1..6),
2439 );
2440 let lit = partition_lit(vec![vec![1, 2, 3]]);
2441 assert!(
2442 !dom.contains(&lit).unwrap(),
2443 "a 3-element partition literal should not be a valid member of a \
2444 (numParts 2, partSize 2) domain, which requires exactly 4 covered elements"
2445 );
2446 }
2447
2448 #[test]
2449 fn partition_contains_accepts_any_size_when_attributes_are_unbounded() {
2450 let dom = GroundDomain::Partition(
2454 partition_attr(Range::Unbounded, Range::Unbounded),
2455 domain_int_ground!(1..6),
2456 );
2457 let lit = partition_lit(vec![vec![1, 2], vec![3, 4, 5, 6]]);
2458 assert!(
2459 dom.contains(&lit).unwrap(),
2460 "an unattributed partition domain should accept a literal covering its whole inner \
2461 domain"
2462 );
2463 }
2464
2465 #[test]
2466 fn partition_length_unattributed_matches_the_bell_number() {
2467 let dom = GroundDomain::Partition(
2469 partition_attr(Range::Unbounded, Range::Unbounded),
2470 domain_int_ground!(1..4),
2471 );
2472 assert_eq!(dom.length().unwrap(), 15);
2473 }
2474
2475 #[test]
2476 fn partition_length_fixed_num_parts_matches_stirling_second_kind() {
2477 let dom = GroundDomain::Partition(
2481 partition_attr(Range::Single(2), Range::Unbounded),
2482 domain_int_ground!(1..4),
2483 );
2484 assert_eq!(dom.length().unwrap(), stirling_second_kind(4, 2).unwrap());
2485 assert_eq!(dom.length().unwrap(), 7);
2486 }
2487
2488 #[test]
2489 fn partition_length_regular_fixed_block_size_matches_a_hand_computed_multinomial() {
2490 let mut attr = partition_attr(Range::Unbounded, Range::Single(3));
2492 attr.is_regular = true;
2493 let dom = GroundDomain::Partition(attr, domain_int_ground!(1..6));
2494 assert_eq!(dom.length().unwrap(), 10);
2495 }
2496
2497 #[test]
2498 fn partition_values_count_matches_length_and_every_value_is_a_valid_member() {
2499 let dom = GroundDomain::Partition(
2500 partition_attr(Range::Bounded(2, 3), Range::Unbounded),
2501 domain_int_ground!(1..4),
2502 );
2503 let values: Vec<Literal> = dom.values().unwrap().collect();
2504 assert_eq!(values.len() as u64, dom.length().unwrap());
2505 for value in &values {
2506 assert!(dom.contains(value).unwrap());
2507 }
2508 }
2509
2510 fn permutation_attr(num_moved: Range<i32>) -> PermutationAttr {
2511 PermutationAttr { num_moved }
2512 }
2513
2514 #[test]
2515 fn permutation_length_unattributed_matches_factorial() {
2516 let dom =
2518 GroundDomain::Permutation(permutation_attr(Range::Unbounded), domain_int_ground!(1..4));
2519 assert_eq!(dom.length().unwrap(), 24);
2520 }
2521
2522 #[test]
2523 fn permutation_length_fully_moved_matches_the_derangement_number() {
2524 let dom =
2526 GroundDomain::Permutation(permutation_attr(Range::Single(4)), domain_int_ground!(1..4));
2527 assert_eq!(dom.length().unwrap(), 9);
2528 }
2529
2530 #[test]
2531 fn permutation_values_count_matches_length_and_every_value_is_a_valid_member() {
2532 let dom = GroundDomain::Permutation(
2533 permutation_attr(Range::Bounded(1, 2)),
2534 domain_int_ground!(1..3),
2535 );
2536 let values: Vec<Literal> = dom.values().unwrap().collect();
2537 assert_eq!(values.len() as u64, dom.length().unwrap());
2538 for value in &values {
2539 assert!(dom.contains(value).unwrap());
2540 }
2541 }
2542}