1use crate::ast::domains::attrs::{PartitionAttr, PermutationAttr};
2use crate::ast::domains::{JectivityAttr, MSetAttr, PartialityAttr, SequenceAttr};
3use crate::ast::enumerated::EnumeratedType;
4use crate::ast::pretty::pretty_vec;
5use crate::ast::unnamed::UnnamedType;
6use crate::ast::{
7 AbstractLiteral, DomainOpError, FuncAttr, Literal, Moo, Name, RelAttr, SetAttr, Typeable,
8 domains::{domain::Int, range::Range},
9 matrix,
10 records::Field,
11};
12use crate::bug_assert;
13use crate::range;
14use crate::utils::{
15 count_combinations, count_permutations, derangements, restricted_partition_count,
16 stirling_second_kind,
17};
18use conjure_cp_core::ast::ReturnType;
19use funcmap::FuncMap;
20use itertools::{Itertools, izip};
21use num_traits::ToPrimitive;
22use polyquine::Quine;
23use serde::{Deserialize, Serialize};
24use std::collections::{BTreeMap, BTreeSet};
25use std::fmt::{Display, Formatter};
26use std::iter::zip;
27use uniplate::Uniplate;
28
29pub(super) type FieldGround = Field<Moo<GroundDomain>>;
30
31pub(super) fn write_int_domain<A>(
34 f: &mut Formatter<'_>,
35 ranges: &[Range<A>],
36 representation: Option<&str>,
37) -> std::fmt::Result
38where
39 Range<A>: Display,
40{
41 let mut args = Vec::new();
42 if let Some(representation) = representation {
43 args.push(format!("representation {representation}"));
44 }
45 let bounded = ranges.iter().all(Range::is_lower_or_upper_bounded);
46 if bounded {
47 args.extend(ranges.iter().map(|r| r.to_string()));
48 }
49 if !bounded && args.is_empty() {
51 write!(f, "int")
52 } else {
53 write!(f, "int({})", args.join(", "))
54 }
55}
56
57pub(super) fn representation_attribute(representation: &Option<String>) -> String {
60 match representation {
61 Some(representation) => format!(" (representation {representation})"),
62 None => String::new(),
63 }
64}
65
66pub(super) fn int_type_string(representation: Option<&str>) -> String {
68 match representation {
69 Some(representation) => format!("int(representation {representation})"),
70 None => "int".to_string(),
71 }
72}
73
74#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
75#[path_prefix(conjure_cp::ast)]
76pub enum GroundDomain {
78 Empty(ReturnType),
80 Bool,
82 Int(Vec<Range<Int>>, Option<String>),
85 Tuple(Vec<Moo<GroundDomain>>, Option<String>),
87 Record(Vec<FieldGround>, Option<String>),
89 Variant(Vec<FieldGround>, Option<String>),
92 Matrix(Moo<GroundDomain>, Vec<Moo<GroundDomain>>, Option<String>),
95 Sequence(SequenceAttr, Moo<GroundDomain>),
97 Set(SetAttr<Int>, Moo<GroundDomain>),
99 MSet(MSetAttr<Int>, Moo<GroundDomain>),
101 Function(FuncAttr, Moo<GroundDomain>, Moo<GroundDomain>),
103 Relation(RelAttr, Vec<Moo<GroundDomain>>),
105 EnumeratedType(Moo<EnumeratedType>, Vec<Range<u32>>),
107 UnnamedType(Moo<UnnamedType>),
109 Partition(PartitionAttr, Moo<GroundDomain>),
111 Permutation(PermutationAttr, Moo<GroundDomain>),
113}
114
115fn regular_partition_count(n: u64, block_size: u64) -> Result<u64, DomainOpError> {
121 if n == 0 {
122 return Ok(1);
123 }
124 if block_size == 0 || !n.is_multiple_of(block_size) {
125 return Ok(0);
126 }
127 let num_parts = n / block_size;
128 let mut numerator = 1u64;
129 let mut remaining = n;
130 for _ in 0..num_parts {
131 let choose = count_combinations(remaining, block_size)?;
132 numerator = numerator
133 .checked_mul(choose)
134 .ok_or(DomainOpError::TooLarge)?;
135 remaining -= block_size;
136 }
137 let num_parts_factorial = (1..=num_parts)
138 .try_fold(1u64, |acc, x| acc.checked_mul(x))
139 .ok_or(DomainOpError::TooLarge)?;
140 numerator
141 .checked_div(num_parts_factorial)
142 .ok_or(DomainOpError::TooLarge)
143}
144
145fn restricted_partitions(
154 elements: &[Literal],
155 block_min: usize,
156 block_max: usize,
157) -> Vec<Vec<Vec<Literal>>> {
158 let block_min = block_min.max(1);
159 if elements.is_empty() {
160 return vec![vec![]];
161 }
162 let (first, rest) = elements.split_first().expect("checked non-empty above");
163
164 let max_extra = block_max.saturating_sub(1).min(rest.len());
165 if block_min.saturating_sub(1) > max_extra {
166 return vec![];
167 }
168
169 let mut results = vec![];
170 for extra in block_min.saturating_sub(1)..=max_extra {
171 for combo in rest.iter().cloned().combinations(extra) {
172 let mut block = vec![first.clone()];
173 block.extend(combo.iter().cloned());
174
175 let remaining: Vec<Literal> = rest
176 .iter()
177 .filter(|elem| !combo.contains(elem))
178 .cloned()
179 .collect();
180
181 for sub_partition in restricted_partitions(&remaining, block_min, block_max) {
182 let mut whole = vec![block.clone()];
183 whole.extend(sub_partition);
184 results.push(whole);
185 }
186 }
187 }
188 results
189}
190
191fn restricted_permutations(
195 elements: &[Literal],
196 moved_min: usize,
197 moved_max: usize,
198) -> impl Iterator<Item = Vec<Literal>> + '_ {
199 let n = elements.len();
200 (0..n)
201 .permutations(n)
202 .filter(move |perm| {
203 let moved = perm.iter().enumerate().filter(|&(i, p)| i != *p).count();
204 moved >= moved_min && moved <= moved_max
205 })
206 .map(move |perm| perm.into_iter().map(|i| elements[i].clone()).collect())
207}
208
209fn permutation_mapping_to_cycles(elements: &[Literal], mapped: &[Literal]) -> Vec<Vec<Literal>> {
215 let forward: std::collections::HashMap<&Literal, &Literal> =
216 elements.iter().zip(mapped.iter()).collect();
217 let mut visited: std::collections::HashSet<&Literal> = std::collections::HashSet::new();
218 let mut cycles = vec![];
219 for start in elements {
220 if visited.contains(start) {
221 continue;
222 }
223 let image = forward[start];
224 if image == start {
225 visited.insert(start);
226 continue;
227 }
228 let mut cycle = vec![start.clone()];
229 visited.insert(start);
230 let mut current = image;
231 while current != start {
232 visited.insert(current);
233 cycle.push(current.clone());
234 current = forward[current];
235 }
236 cycles.push(cycle);
237 }
238 cycles
239}
240
241fn union_sequence_sizes(left: &Range<i32>, right: &Range<i32>) -> Range<i32> {
246 let bounds = |range: &Range<i32>| match range {
247 Range::Single(size) => (*size, Some(*size)),
248 Range::Bounded(min, max) => (*min, Some(*max)),
249 Range::UnboundedL(max) => (0, Some(*max)),
250 Range::UnboundedR(min) => (*min, None),
251 Range::Unbounded => (0, None),
252 };
253
254 let (left_min, left_max) = bounds(left);
255 let (right_min, right_max) = bounds(right);
256 let min = left_min.min(right_min);
257
258 match (left_max, right_max) {
259 (Some(left_max), Some(right_max)) => {
260 let max = left_max.max(right_max);
261 if min == max {
262 Range::Single(min)
263 } else {
264 Range::Bounded(min, max)
265 }
266 }
267 _ => Range::UnboundedR(min),
268 }
269}
270
271impl GroundDomain {
272 pub fn union(&self, other: &GroundDomain) -> Result<GroundDomain, DomainOpError> {
273 match (self, other) {
277 (GroundDomain::UnnamedType(lhs), GroundDomain::UnnamedType(rhs)) if lhs == rhs => {
278 Ok(self.clone())
279 }
280 (GroundDomain::EnumeratedType(_, _) | GroundDomain::UnnamedType(_), _)
281 | (_, GroundDomain::EnumeratedType(_, _) | GroundDomain::UnnamedType(_)) => {
282 Err(DomainOpError::WrongType)
283 }
284 (GroundDomain::Empty(ty), dom) | (dom, GroundDomain::Empty(ty)) => {
285 if *ty == dom.return_type() {
286 Ok(dom.clone())
287 } else {
288 Err(DomainOpError::WrongType)
289 }
290 }
291 (GroundDomain::Bool, GroundDomain::Bool) => Ok(GroundDomain::Bool),
292 (GroundDomain::Bool, _) | (_, GroundDomain::Bool) => Err(DomainOpError::WrongType),
293 (GroundDomain::Int(r1, _), GroundDomain::Int(r2, _)) => {
294 let mut rngs = r1.clone();
295 rngs.extend(r2.clone());
296 Ok(GroundDomain::Int(Range::squeeze(&rngs), None))
297 }
298 (GroundDomain::Int(_, _), _) | (_, GroundDomain::Int(_, _)) => {
299 Err(DomainOpError::WrongType)
300 }
301 (GroundDomain::Tuple(in1s, _), GroundDomain::Tuple(in2s, _))
302 if in1s.len() == in2s.len() =>
303 {
304 let mut inners = Vec::new();
305 for (in1, in2) in zip(in1s, in2s) {
306 inners.push(Moo::new(in1.union(in2)?));
307 }
308 Ok(GroundDomain::Tuple(inners, None))
309 }
310 (GroundDomain::Tuple(_, _), _) | (_, GroundDomain::Tuple(_, _)) => {
311 Err(DomainOpError::WrongType)
312 }
313 (GroundDomain::Record(in1s, _), GroundDomain::Record(in2s, _))
314 if in1s.len() == in2s.len() =>
315 {
316 let lhs_fields: BTreeMap<&Name, &Moo<GroundDomain>> =
317 in1s.iter().map(|x| (&x.name, &x.value)).collect();
318 let rhs_fields: BTreeMap<&Name, &Moo<GroundDomain>> =
319 in2s.iter().map(|x| (&x.name, &x.value)).collect();
320 let mut new_fields = Vec::with_capacity(in1s.len());
321 for (n, d) in lhs_fields {
322 let d2 = rhs_fields.get(&n).ok_or(DomainOpError::WrongType)?;
323 let dom = d.union(d2)?;
324 new_fields.push(Field {
325 name: n.clone(),
326 value: dom.into(),
327 });
328 }
329 Ok(GroundDomain::Record(new_fields, None))
330 }
331 (GroundDomain::Record(_, _), _) | (_, GroundDomain::Record(_, _)) => {
332 Err(DomainOpError::WrongType)
333 }
334 (GroundDomain::Matrix(in1, idx1, _), GroundDomain::Matrix(in2, idx2, _))
335 if idx1 == idx2 =>
336 {
337 Ok(GroundDomain::Matrix(
338 Moo::new(in1.union(in2)?),
339 idx1.clone(),
340 None,
341 ))
342 }
343 (GroundDomain::Matrix(_, _, _), _) | (_, GroundDomain::Matrix(_, _, _)) => {
344 Err(DomainOpError::WrongType)
345 }
346 (GroundDomain::Set(_, in1), GroundDomain::Set(_, in2)) => Ok(GroundDomain::Set(
347 SetAttr::default(),
348 Moo::new(in1.union(in2)?),
349 )),
350 (GroundDomain::Set(_, _), _) | (_, GroundDomain::Set(_, _)) => {
351 Err(DomainOpError::WrongType)
352 }
353 (GroundDomain::MSet(_, in1), GroundDomain::MSet(_, in2)) => Ok(GroundDomain::MSet(
354 MSetAttr::default(),
355 Moo::new(in1.union(in2)?),
356 )),
357 (GroundDomain::Sequence(attr1, in1), GroundDomain::Sequence(attr2, in2)) => {
358 Ok(GroundDomain::Sequence(
359 SequenceAttr {
360 size: union_sequence_sizes(&attr1.size, &attr2.size),
361 ..SequenceAttr::default()
362 },
363 Moo::new(in1.union(in2)?),
364 ))
365 }
366 (GroundDomain::Sequence(_, _), _) | (_, GroundDomain::Sequence(_, _)) => {
367 Err(DomainOpError::WrongType)
368 }
369 (GroundDomain::Relation(_, in1s), GroundDomain::Relation(_, in2s)) => {
370 let mut inners = Vec::new();
371 for (in1, in2) in zip(in1s, in2s) {
372 inners.push(Moo::new(in1.union(in2)?));
373 }
374 Ok(GroundDomain::Relation(RelAttr::default(), inners))
375 }
376 (GroundDomain::Relation(..), _) | (_, GroundDomain::Relation(..)) => {
377 Err(DomainOpError::WrongType)
378 }
379 #[allow(unreachable_patterns)]
380 (GroundDomain::Variant(_, _), _) | (_, GroundDomain::Variant(_, _)) => {
381 todo!("union variant domains")
382 }
383 #[allow(unreachable_patterns)]
384 (GroundDomain::Function(..), _) | (_, GroundDomain::Function(..)) => {
385 todo!("union function domains")
386 }
387 #[allow(unreachable_patterns)]
388 (GroundDomain::Partition(..), _) | (_, GroundDomain::Partition(..)) => {
389 todo!("union partition domains")
390 }
391 #[allow(unreachable_patterns)]
392 (GroundDomain::Permutation(..), _) | (_, GroundDomain::Permutation(..)) => {
393 todo!("union permutation domains")
394 }
395 }
396 }
397
398 pub fn intersect(&self, other: &GroundDomain) -> Result<GroundDomain, DomainOpError> {
405 match (self, other) {
409 (GroundDomain::UnnamedType(lhs), GroundDomain::UnnamedType(rhs)) if lhs == rhs => {
410 Ok(self.clone())
411 }
412 (d @ GroundDomain::Empty(ReturnType::Int), GroundDomain::Int(_, _)) => Ok(d.clone()),
414 (GroundDomain::Int(_, _), d @ GroundDomain::Empty(ReturnType::Int)) => Ok(d.clone()),
415 (GroundDomain::Empty(ReturnType::Int), d @ GroundDomain::Empty(ReturnType::Int)) => {
416 Ok(d.clone())
417 }
418
419 (GroundDomain::Set(_, inner1), d @ GroundDomain::Empty(ReturnType::Set(inner2)))
421 if matches!(
422 **inner1,
423 GroundDomain::Int(_, _) | GroundDomain::Empty(ReturnType::Int)
424 ) && matches!(**inner2, ReturnType::Int) =>
425 {
426 Ok(d.clone())
427 }
428 (d @ GroundDomain::Empty(ReturnType::Set(inner1)), GroundDomain::Set(_, inner2))
429 if matches!(**inner1, ReturnType::Int)
430 && matches!(
431 **inner2,
432 GroundDomain::Int(_, _) | GroundDomain::Empty(ReturnType::Int)
433 ) =>
434 {
435 Ok(d.clone())
436 }
437 (
438 d @ GroundDomain::Empty(ReturnType::Set(inner1)),
439 GroundDomain::Empty(ReturnType::Set(inner2)),
440 ) if matches!(**inner1, ReturnType::Int) && matches!(**inner2, ReturnType::Int) => {
441 Ok(d.clone())
442 }
443
444 (GroundDomain::Set(_, x), GroundDomain::Set(_, y)) => Ok(GroundDomain::Set(
446 SetAttr::default(),
447 Moo::new((*x).intersect(y)?),
448 )),
449
450 (GroundDomain::Int(a, _), GroundDomain::Int(b, _)) => {
451 if a.iter().chain(b).any(|range| !range.is_finite()) {
454 return Err(DomainOpError::Unbounded);
455 }
456 let mut intersections = Vec::new();
457 for left in a {
458 for right in b {
459 let lo = *left
460 .low()
461 .ok_or(DomainOpError::Unbounded)?
462 .max(right.low().ok_or(DomainOpError::Unbounded)?);
463 let hi = *left
464 .high()
465 .ok_or(DomainOpError::Unbounded)?
466 .min(right.high().ok_or(DomainOpError::Unbounded)?);
467 if lo <= hi {
468 intersections.push((lo, hi));
469 }
470 }
471 }
472 intersections.sort_unstable();
473 let mut merged: Vec<(i32, i32)> = Vec::new();
474 for (lo, hi) in intersections {
475 if let Some(last) = merged.last_mut()
476 && i64::from(lo) <= i64::from(last.1) + 1
477 {
478 last.1 = last.1.max(hi);
479 } else {
480 merged.push((lo, hi));
481 }
482 }
483 if merged.is_empty() {
484 Ok(GroundDomain::Empty(ReturnType::Int))
485 } else {
486 Ok(GroundDomain::Int(
487 merged
488 .into_iter()
489 .map(|(lo, hi)| Range::new(Some(lo), Some(hi)))
490 .collect(),
491 None,
492 ))
493 }
494 }
495 (GroundDomain::Relation(_, _), GroundDomain::Relation(_, _)) => {
496 todo!("Relation union not yet supported")
497 }
498 _ => Err(DomainOpError::WrongType),
499 }
500 }
501
502 pub fn values(&self) -> Result<Box<dyn Iterator<Item = Literal>>, DomainOpError> {
503 match self {
504 GroundDomain::Empty(_) => Ok(Box::new(vec![].into_iter())),
505 GroundDomain::EnumeratedType(ty, ranges) => {
506 let values = enum_indices(ty, ranges)
507 .map(|index| {
508 Literal::EnumVariant(crate::ast::enumerated::EnumVariant::new(
509 ty.clone(),
510 index,
511 ))
512 })
513 .collect::<Vec<_>>();
514 Ok(Box::new(values.into_iter()))
515 }
516 GroundDomain::UnnamedType(ty) => {
517 let ty = ty.clone();
518 Ok(Box::new((1..=ty.size).map(move |value| {
519 Literal::Unnamed(crate::ast::unnamed::UnnamedValue {
520 ty: ty.clone(),
521 value,
522 })
523 })))
524 }
525 GroundDomain::Bool => Ok(Box::new(
526 vec![Literal::from(false), Literal::from(true)].into_iter(),
527 )),
528 GroundDomain::Int(rngs, _) => {
529 let rng_iters = rngs
530 .iter()
531 .map(Range::iter)
532 .collect::<Option<Vec<_>>>()
533 .ok_or(DomainOpError::Unbounded)?;
534 Ok(Box::new(
535 rng_iters.into_iter().flat_map(|ri| ri.map(Literal::from)),
536 ))
537 }
538 GroundDomain::Tuple(elem_doms, _) => {
539 let elem_value_pools: Vec<Vec<Literal>> = elem_doms
541 .iter()
542 .map(|d| d.values().map(|it| it.collect()))
543 .collect::<Result<_, _>>()?;
544
545 let iter = elem_value_pools
547 .into_iter()
548 .multi_cartesian_product()
549 .map(|elems| Literal::AbstractLiteral(AbstractLiteral::Tuple(elems)));
550
551 Ok(Box::new(iter))
552 }
553 GroundDomain::Record(entries, _) => {
554 let mut sorted: Vec<&_> = entries.iter().collect();
556 sorted.sort_by(|a, b| a.name.cmp(&b.name));
557
558 let names: Vec<_> = sorted.iter().map(|e| e.name.clone()).collect();
559 let value_pools: Vec<Vec<Literal>> = sorted
560 .iter()
561 .map(|e| e.value.values().map(|it| it.collect()))
562 .collect::<Result<_, _>>()?;
563
564 let iter = value_pools
566 .into_iter()
567 .multi_cartesian_product()
568 .map(move |vals| {
569 let record_entries = names
570 .iter()
571 .cloned()
572 .zip(vals)
573 .map(|(name, value)| Field { name, value })
574 .collect();
575 Literal::AbstractLiteral(AbstractLiteral::Record(record_entries))
576 });
577
578 Ok(Box::new(iter))
579 }
580 GroundDomain::Variant(entries, _) => {
581 let values = entries
582 .iter()
583 .map(|entry| {
584 let name = entry.name.clone();
585 entry.value.values().map(|values| {
586 values.map(move |value| {
587 Literal::AbstractLiteral(AbstractLiteral::Variant(Moo::new(
588 Field {
589 name: name.clone(),
590 value,
591 },
592 )))
593 })
594 })
595 })
596 .collect::<Result<Vec<_>, _>>()?;
597 Ok(Box::new(values.into_iter().flatten()))
598 }
599 GroundDomain::Matrix(elem_dom, idx_doms, _) => {
600 let shape = matrix::shape_of_dom(self)?;
601 let idx_doms = idx_doms.clone();
602
603 let elem_values: Vec<Literal> = elem_dom.values()?.collect();
605
606 let iter = std::iter::repeat_n(elem_values, shape.size)
608 .multi_cartesian_product()
609 .map(move |flat_elems| {
610 matrix::unflatten_matrix::<Literal>(&flat_elems, &idx_doms, &shape.strides)
611 });
612
613 Ok(Box::new(iter))
614 }
615 GroundDomain::Sequence(attrs, inner_dom) => {
616 if attrs.jectivity != JectivityAttr::None {
617 todo!("Enumerating jective sequence domains is not yet supported")
621 }
622
623 let min_sz = attrs.size.low().copied().unwrap_or(0).max(0);
624 let max_sz = attrs.size.high().copied().ok_or(DomainOpError::Unbounded)?;
625
626 let pool = inner_dom.values()?.collect_vec();
627
628 let iter = (min_sz..=max_sz)
629 .flat_map(move |sz| {
630 std::iter::repeat_n(pool.clone(), sz.max(0) as usize)
631 .multi_cartesian_product()
632 })
633 .map(|elems| Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)));
634
635 Ok(Box::new(iter))
636 }
637 GroundDomain::Set(attrs, inner_dom) => {
638 let n: Int = inner_dom.len_usize()?.try_into()?;
639 let min_sz = attrs.size.low().copied().unwrap_or(0);
640 let max_sz = attrs.size.high().copied().unwrap_or(n);
641
642 let pool = inner_dom.values()?.collect_vec();
643
644 Ok(Box::new(
645 (min_sz..=max_sz)
646 .flat_map(move |sz| pool.clone().into_iter().combinations(sz as usize))
647 .map(|elems| Literal::AbstractLiteral(AbstractLiteral::Set(elems))),
648 ))
649 }
650 GroundDomain::MSet(..) => todo!("Enumerating multi-set domains is not yet supported"),
651 GroundDomain::Function(..) => {
652 todo!("Enumerating function domains is not yet supported")
653 }
654 GroundDomain::Relation(..) => {
655 todo!("Enumerating relation domains is not yet supported")
656 }
657 GroundDomain::Partition(attr, inner_dom) => {
658 let elements: Vec<Literal> = inner_dom.values()?.collect();
659 let n = elements.len();
660
661 let block_lo = attr.part_len.low().copied().unwrap_or(1).max(1) as usize;
662 let block_hi = attr
663 .part_len
664 .high()
665 .copied()
666 .map(|h| (h.max(0) as usize).min(n))
667 .unwrap_or(n);
668 let parts_lo = attr.num_parts.low().copied().unwrap_or(0).max(0) as usize;
669 let parts_hi = attr
670 .num_parts
671 .high()
672 .copied()
673 .map(|h| (h.max(0) as usize).min(n))
674 .unwrap_or(n);
675 let is_regular = attr.is_regular;
676
677 let partitions = if block_lo > block_hi {
678 vec![]
679 } else {
680 restricted_partitions(&elements, block_lo, block_hi)
681 };
682 let iter = partitions.into_iter().filter(move |parts| {
683 let k = parts.len();
684 if k < parts_lo || k > parts_hi {
685 return false;
686 }
687 !is_regular
688 || parts
689 .first()
690 .is_none_or(|first| parts.iter().all(|p| p.len() == first.len()))
691 });
692 Ok(Box::new(iter.map(|parts| {
693 Literal::AbstractLiteral(AbstractLiteral::Partition(parts))
694 })))
695 }
696 GroundDomain::Permutation(attr, inner_dom) => {
697 let elements: Vec<Literal> = inner_dom.values()?.collect();
698 let n = elements.len();
699
700 let moved_lo = attr.num_moved.low().copied().unwrap_or(0).max(0) as usize;
701 let moved_hi = attr
702 .num_moved
703 .high()
704 .copied()
705 .map(|h| (h.max(0) as usize).min(n))
706 .unwrap_or(n);
707
708 if moved_lo > moved_hi {
709 return Ok(Box::new(std::iter::empty()));
710 }
711 let mappings: Vec<Vec<Literal>> =
712 restricted_permutations(&elements, moved_lo, moved_hi).collect();
713 let values = mappings.into_iter().map(move |mapped| {
714 let cycles = permutation_mapping_to_cycles(&elements, &mapped);
715 Literal::AbstractLiteral(AbstractLiteral::Permutation(cycles))
716 });
717 Ok(Box::new(values.collect_vec().into_iter()))
718 }
719 }
720 }
721
722 pub fn length(&self) -> Result<u64, DomainOpError> {
728 match self {
729 GroundDomain::Empty(_) => Ok(0),
730 GroundDomain::Bool => Ok(2),
731 GroundDomain::Int(ranges, _) => {
732 if ranges.is_empty() {
733 return Ok(0);
734 }
735
736 let mut length = 0u64;
737 for range in ranges {
738 if let Some(range_length) = range.length() {
739 length += range_length as u64;
740 } else {
741 return Err(DomainOpError::Unbounded);
742 }
743 }
744 Ok(length)
745 }
746 GroundDomain::Tuple(domains, _) => {
747 let mut ans = 1u64;
748 for domain in domains {
749 ans = ans
750 .checked_mul(domain.length()?)
751 .ok_or(DomainOpError::TooLarge)?;
752 }
753 Ok(ans)
754 }
755 GroundDomain::Record(entries, _) => {
756 let mut ans = 1u64;
758 for entry in entries {
759 let sz = entry.value.length()?;
760 ans = ans.checked_mul(sz).ok_or(DomainOpError::TooLarge)?;
761 }
762 Ok(ans)
763 }
764 GroundDomain::Variant(entries, _) => {
765 let mut ans = 0u64;
766 for entry in entries {
767 let sz = entry.value.length()?;
768 ans = ans.checked_add(sz).ok_or(DomainOpError::TooLarge)?;
770 }
771 Ok(ans)
772 }
773 GroundDomain::Matrix(inner_domain, idx_domains, _) => {
774 let inner_sz = inner_domain.length()?;
775 let exp = idx_domains.iter().try_fold(1u32, |acc, val| {
776 let len = val.length()? as u32;
777 acc.checked_mul(len).ok_or(DomainOpError::TooLarge)
778 })?;
779 inner_sz.checked_pow(exp).ok_or(DomainOpError::TooLarge)
780 }
781 GroundDomain::Sequence(seq_attr, inner_domain) => {
782 if seq_attr.jectivity != JectivityAttr::None {
783 todo!("Length bound of jective sequences is not yet supported");
785 }
786
787 let inner_len = inner_domain.length()?;
788 let min_sz = seq_attr.size.low().copied().unwrap_or(0).max(0) as u64;
789 let max_sz = seq_attr
790 .size
791 .high()
792 .copied()
793 .ok_or(DomainOpError::Unbounded)? as u64;
794
795 if min_sz > max_sz {
796 return Ok(0);
797 }
798
799 let mut ans = 0u64;
800 for sz in min_sz..=max_sz {
801 let sz: u32 = sz.try_into().map_err(|_| DomainOpError::TooLarge)?;
802 let c = inner_len.checked_pow(sz).ok_or(DomainOpError::TooLarge)?;
803 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
804 }
805 Ok(ans)
806 }
807 GroundDomain::Set(set_attr, inner_domain) => {
808 let inner_len = inner_domain.length()?;
809 let (min_sz, max_sz) = match set_attr.size {
810 Range::Unbounded => (0, inner_len),
811 Range::Single(n) => (n as u64, n as u64),
812 Range::UnboundedR(n) => (n as u64, inner_len),
813 Range::UnboundedL(n) => (0, n as u64),
814 Range::Bounded(min, max) => (min as u64, max as u64),
815 };
816 let max_sz = max_sz.min(inner_len);
819 if min_sz > max_sz {
820 return Ok(0);
821 }
822 let mut ans = 0u64;
823 for sz in min_sz..=max_sz {
824 let c = count_combinations(inner_len, sz)?;
825 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
826 }
827 Ok(ans)
828 }
829 GroundDomain::MSet(mset_attr, inner_domain) => {
830 let inner_len = inner_domain.length()?;
831 let (min_sz, max_sz) = match mset_attr.size {
832 Range::Unbounded => (0, inner_len),
833 Range::Single(n) => (n as u64, n as u64),
834 Range::UnboundedR(n) => (n as u64, inner_len),
835 Range::UnboundedL(n) => (0, n as u64),
836 Range::Bounded(min, max) => (min as u64, max as u64),
837 };
838 let mut ans = 0u64;
839 for sz in min_sz..=max_sz {
840 let c = count_combinations(inner_len + sz - 1, sz)?;
843 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
844 }
845 Ok(ans)
846 }
847 GroundDomain::Function(attr, domain, codomain) => {
848 let domain_len = domain.length()?;
849 let codomain_len = codomain.length()?;
850
851 match (attr.partiality.clone(), attr.jectivity.clone()) {
852 (PartialityAttr::Total, JectivityAttr::None) => {
853 let exp: u32 = domain_len.try_into()?;
854 codomain_len.checked_pow(exp).ok_or(DomainOpError::TooLarge)
855 }
856 (PartialityAttr::Total, JectivityAttr::Injective) => {
857 if domain_len > codomain_len {
858 return Ok(0);
859 }
860 Ok(count_permutations(codomain_len, domain_len)?)
861 }
862 (PartialityAttr::Total, JectivityAttr::Bijective) => {
863 if domain_len != codomain_len {
864 return Ok(0);
865 }
866 Ok(count_permutations(domain_len, domain_len)?)
867 }
868 (PartialityAttr::Total, JectivityAttr::Surjective) => {
869 let partitions = stirling_second_kind(domain_len, codomain_len)?;
870 let arrangements = count_permutations(codomain_len, codomain_len)?;
871 partitions
872 .checked_mul(arrangements)
873 .ok_or(DomainOpError::TooLarge)
874 }
875 (PartialityAttr::Partial, jectivity) => {
876 let (min_sz, max_sz) = match attr.size {
877 Range::Unbounded => (0, domain_len),
878 Range::Single(n) => (n as u64, n as u64),
879 Range::UnboundedR(n) => (n as u64, domain_len),
880 Range::UnboundedL(n) => (0, n as u64),
881 Range::Bounded(min, max) => (min as u64, max as u64),
882 };
883 let max_sz = max_sz.min(domain_len);
884 if min_sz > max_sz {
885 return Ok(0);
886 }
887
888 let mut ans = 0u64;
889 for sz in min_sz..=max_sz {
890 let choose = count_combinations(domain_len, sz)?;
893 let assign = match jectivity {
894 JectivityAttr::None => codomain_len
895 .checked_pow(sz.try_into()?)
896 .ok_or(DomainOpError::TooLarge)?,
897 JectivityAttr::Injective => {
898 if sz > codomain_len {
899 0
900 } else {
901 count_permutations(codomain_len, sz)?
902 }
903 }
904 JectivityAttr::Bijective => {
905 if sz != codomain_len {
906 0
907 } else {
908 count_permutations(codomain_len, codomain_len)?
909 }
910 }
911 JectivityAttr::Surjective => {
912 let partitions = stirling_second_kind(sz, codomain_len)?;
913 let arrangements =
914 count_permutations(codomain_len, codomain_len)?;
915 partitions
916 .checked_mul(arrangements)
917 .ok_or(DomainOpError::TooLarge)?
918 }
919 };
920 let term = choose.checked_mul(assign).ok_or(DomainOpError::TooLarge)?;
921 ans = ans.checked_add(term).ok_or(DomainOpError::TooLarge)?;
922 }
923 Ok(ans)
924 }
925 }
926 }
927 GroundDomain::Relation(attr, domains) => {
928 let dom_sizes_result: Result<Vec<u64>, DomainOpError> =
929 domains.iter().map(|x| x.length()).collect();
930 let dom_sizes = dom_sizes_result?;
931 let inner_len: u64 = dom_sizes.iter().product();
932
933 let (min_sz, max_sz) = match attr.size {
934 Range::Unbounded => (0, inner_len),
935 Range::Single(n) => (n as u64, n as u64),
936 Range::UnboundedR(n) => (n as u64, inner_len),
937 Range::UnboundedL(n) => (0, n as u64),
938 Range::Bounded(min, max) => (min as u64, max as u64),
939 };
940 let max_sz = max_sz.min(inner_len);
941 if min_sz > max_sz {
942 return Ok(0);
943 }
944
945 let mut ans = 0u64;
946 for sz in min_sz..=max_sz {
947 let c = count_combinations(inner_len, sz)?;
948 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
949 }
950 Ok(ans)
951 }
952 GroundDomain::Partition(attr, inner_domain) => {
953 let n = inner_domain.length()?;
954 let block_lo = attr.part_len.low().copied().unwrap_or(1).max(1) as u64;
955 let block_hi = attr
956 .part_len
957 .high()
958 .copied()
959 .map(|h| (h.max(0) as u64).min(n))
960 .unwrap_or(n);
961 let parts_lo = attr.num_parts.low().copied().unwrap_or(0).max(0) as u64;
962 let parts_hi = attr
963 .num_parts
964 .high()
965 .copied()
966 .map(|h| (h.max(0) as u64).min(n))
967 .unwrap_or(n);
968 if block_lo > block_hi || parts_lo > parts_hi {
969 return Ok(0);
970 }
971
972 if attr.is_regular {
973 let mut ans = 0u64;
974 for block_size in block_lo..=block_hi {
975 if n % block_size != 0 {
976 continue;
977 }
978 let num_parts = n / block_size;
979 if num_parts < parts_lo || num_parts > parts_hi {
980 continue;
981 }
982 let c = regular_partition_count(n, block_size)?;
983 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
984 }
985 Ok(ans)
986 } else {
987 let mut ans = 0u64;
988 for num_parts in parts_lo..=parts_hi {
989 let c = restricted_partition_count(n, num_parts, block_lo, block_hi)?;
990 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
991 }
992 Ok(ans)
993 }
994 }
995 GroundDomain::Permutation(attr, inner_domain) => {
996 let n = inner_domain.length()?;
997 let moved_lo = attr.num_moved.low().copied().unwrap_or(0).max(0) as u64;
998 let moved_hi = attr
999 .num_moved
1000 .high()
1001 .copied()
1002 .map(|h| (h.max(0) as u64).min(n))
1003 .unwrap_or(n);
1004 if moved_lo > moved_hi {
1005 return Ok(0);
1006 }
1007
1008 let mut ans = 0u64;
1009 for moved in moved_lo..=moved_hi {
1010 let choose = count_combinations(n, moved)?;
1011 let derange = derangements(moved)?;
1012 let term = choose.checked_mul(derange).ok_or(DomainOpError::TooLarge)?;
1013 ans = ans.checked_add(term).ok_or(DomainOpError::TooLarge)?;
1014 }
1015 Ok(ans)
1016 }
1017 GroundDomain::EnumeratedType(et, ranges) => Ok(enum_indices(et, ranges).count() as u64),
1018 GroundDomain::UnnamedType(ty) => Ok(ty.size as u64),
1019 }
1020 }
1021
1022 pub fn len_usize(&self) -> Result<usize, DomainOpError> {
1024 self.length()?
1025 .try_into()
1026 .map_err(|_| DomainOpError::TooLarge)
1027 }
1028
1029 pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
1030 match self {
1033 GroundDomain::Empty(_) => Ok(false),
1035 GroundDomain::Bool => match lit {
1036 Literal::Bool(_) => Ok(true),
1037 _ => Ok(false),
1038 },
1039 GroundDomain::Int(ranges, _) => match lit {
1040 Literal::Int(x) => {
1041 if ranges.is_empty() {
1042 return Ok(false);
1043 };
1044
1045 Ok(ranges.iter().any(|range| range.contains(x)))
1046 }
1047 _ => Ok(false),
1048 },
1049 GroundDomain::Tuple(elem_domains, _) => {
1050 match lit {
1051 Literal::AbstractLiteral(AbstractLiteral::Tuple(literal_elems)) => {
1052 if elem_domains.len() != literal_elems.len() {
1053 return Ok(false);
1054 }
1055
1056 for (elem_domain, elem) in itertools::izip!(elem_domains, literal_elems) {
1058 if !elem_domain.contains(elem)? {
1059 return Ok(false);
1060 }
1061 }
1062
1063 Ok(true)
1064 }
1065 _ => Ok(false),
1066 }
1067 }
1068 GroundDomain::Record(entries, _) => match lit {
1069 Literal::AbstractLiteral(AbstractLiteral::Record(lit_entries)) => {
1070 if entries.len() != lit_entries.len() {
1071 return Ok(false);
1072 }
1073
1074 let fields = lit_entries
1075 .iter()
1076 .map(|field| (&field.name, &field.value))
1077 .collect::<BTreeMap<_, _>>();
1078 if fields.len() != entries.len() {
1079 return Ok(false);
1080 }
1081 for entry in entries {
1082 let Some(value) = fields.get(&entry.name) else {
1083 return Ok(false);
1084 };
1085 if !entry.value.contains(value)? {
1086 return Ok(false);
1087 }
1088 }
1089 Ok(true)
1090 }
1091 _ => Ok(false),
1092 },
1093 GroundDomain::Variant(entries, _) => match lit {
1094 Literal::AbstractLiteral(AbstractLiteral::Variant(lit_entry)) => {
1095 let Some(entry) = entries.iter().find(|entry| entry.name == lit_entry.name)
1096 else {
1097 return Ok(false);
1098 };
1099 entry.value.contains(&lit_entry.value)
1100 }
1101 _ => Ok(false),
1102 },
1103 GroundDomain::Matrix(elem_domain, index_domains, _) => {
1104 match lit {
1105 Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx_domain)) => {
1106 if elems.is_empty()
1110 && index_domains
1111 .iter()
1112 .any(|index_domain| index_domain.length() == Ok(0))
1113 {
1114 return Ok(true);
1115 }
1116
1117 let Some((current_index_domain, remaining_index_domains)) =
1118 index_domains.split_first()
1119 else {
1120 panic!("a matrix should have at least one index domain");
1121 };
1122
1123 if *current_index_domain != *idx_domain {
1124 return Ok(false);
1125 };
1126
1127 let next_elem_domain = if remaining_index_domains.is_empty() {
1128 elem_domain.as_ref().clone()
1131 } else {
1132 GroundDomain::Matrix(
1134 elem_domain.clone(),
1135 remaining_index_domains.to_vec(),
1136 None,
1137 )
1138 };
1139
1140 for elem in elems {
1141 if !next_elem_domain.contains(elem)? {
1142 return Ok(false);
1143 }
1144 }
1145
1146 Ok(true)
1147 }
1148 _ => Ok(false),
1149 }
1150 }
1151 GroundDomain::Sequence(seq_attr, inner_dom) => match lit {
1152 Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)) => {
1153 let sz = elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1154 if !seq_attr.size.contains(&sz) {
1155 return Ok(false);
1156 }
1157
1158 for elem in elems {
1159 if !inner_dom.contains(elem)? {
1160 return Ok(false);
1161 }
1162 }
1163 Ok(true)
1164 }
1165 _ => Ok(false),
1166 },
1167 GroundDomain::Set(set_attr, inner_domain) => match lit {
1168 Literal::AbstractLiteral(AbstractLiteral::Set(lit_elems)) => {
1169 let sz = crate::ast::literals::distinct_literal_count(lit_elems)
1171 .to_i32()
1172 .ok_or(DomainOpError::TooLarge)?;
1173 if !set_attr.size.contains(&sz) {
1174 return Ok(false);
1175 }
1176
1177 for elem in lit_elems {
1178 if !inner_domain.contains(elem)? {
1179 return Ok(false);
1180 }
1181 }
1182 Ok(true)
1183 }
1184 _ => Ok(false),
1185 },
1186 GroundDomain::MSet(mset_attr, inner_domain) => match lit {
1187 Literal::AbstractLiteral(AbstractLiteral::MSet(lit_elems)) => {
1188 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1190 if !mset_attr.size.contains(&sz) {
1191 return Ok(false);
1192 }
1193
1194 for elem in lit_elems {
1195 if !inner_domain.contains(elem)? {
1196 return Ok(false);
1197 }
1198 }
1199 Ok(true)
1200 }
1201 _ => Ok(false),
1202 },
1203 GroundDomain::Function(func_attr, domain, codomain) => match lit {
1204 Literal::AbstractLiteral(AbstractLiteral::Function(lit_elems)) => {
1205 let sz = Int::try_from(lit_elems.len()).expect("Should convert");
1206 if !func_attr.size.contains(&sz) {
1207 return Ok(false);
1208 }
1209 for lit in lit_elems {
1210 let domain_element = &lit.0;
1211 let codomain_element = &lit.1;
1212 if !domain.contains(domain_element)? {
1213 return Ok(false);
1214 }
1215 if !codomain.contains(codomain_element)? {
1216 return Ok(false);
1217 }
1218 }
1219 Ok(true)
1220 }
1221 _ => Ok(false),
1222 },
1223 GroundDomain::Relation(rel_attr, inner_domains) => match lit {
1224 Literal::AbstractLiteral(AbstractLiteral::Relation(lit_elems)) => {
1225 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
1227 if !rel_attr.size.contains(&sz) {
1228 return Ok(false);
1229 }
1230
1231 for elem_tuple in lit_elems {
1232 if elem_tuple.len() == inner_domains.len() {
1233 for (elem, inner_dom) in elem_tuple.iter().zip(inner_domains.iter()) {
1234 if !inner_dom.contains(elem)? {
1235 return Ok(false);
1236 }
1237 }
1238 } else {
1239 return Ok(false);
1240 }
1241 }
1242 Ok(true)
1243 }
1244 _ => Ok(false),
1245 },
1246 GroundDomain::Partition(attr, dom) => match lit {
1247 Literal::AbstractLiteral(AbstractLiteral::Partition(lit_elems)) => {
1248 let sz: i32 = lit_elems
1250 .iter()
1251 .flatten()
1252 .count()
1253 .to_i32()
1254 .ok_or(DomainOpError::TooLarge)?;
1255
1256 let min: Option<i32> = match (attr.num_parts.low(), attr.part_len.low()) {
1257 (Some(x), Some(y)) => Some(x * y),
1258 _ => None,
1259 };
1260
1261 let max: Option<i32> = match (attr.num_parts.high(), attr.part_len.high()) {
1262 (Some(x), Some(y)) => Some(x * y),
1263 _ => None,
1264 };
1265
1266 let rng = Range::new(min, max);
1267 if !rng.contains(&sz) {
1268 return Ok(false);
1269 }
1270
1271 for elem in lit_elems.iter().flatten() {
1272 if !dom.contains(elem)? {
1273 return Ok(false);
1274 }
1275 }
1276 Ok(true)
1277 }
1278 _ => Ok(false),
1279 },
1280 GroundDomain::EnumeratedType(ty, ranges) => Ok(matches!(lit,
1281 Literal::EnumVariant(value) if value.ty == *ty && (value.variant as usize) < ty.len()
1282 && (ranges.is_empty() || ranges.iter().any(|range| range.contains(&value.variant)))
1283 )),
1284 GroundDomain::UnnamedType(ty) => Ok(
1285 matches!(lit, Literal::Unnamed(value) if value.ty == *ty && (1..=ty.size).contains(&value.value)),
1286 ),
1287 GroundDomain::Permutation(attr, dom) => match lit {
1288 Literal::AbstractLiteral(AbstractLiteral::Permutation(cycles)) => {
1289 let sz: i32 = cycles
1293 .iter()
1294 .flatten()
1295 .count()
1296 .to_i32()
1297 .ok_or(DomainOpError::TooLarge)?;
1298 if !attr.num_moved.contains(&sz) {
1299 return Ok(false);
1300 }
1301
1302 for elem in cycles.iter().flatten() {
1303 if !dom.contains(elem)? {
1304 return Ok(false);
1305 }
1306 }
1307 Ok(true)
1308 }
1309 _ => Ok(false),
1310 },
1311 }
1312 }
1313
1314 pub fn values_i32(&self) -> Result<Vec<i32>, DomainOpError> {
1321 if let GroundDomain::Empty(ReturnType::Int) = self {
1322 return Ok(vec![]);
1323 }
1324 let GroundDomain::Int(ranges, _) = self else {
1325 return Err(DomainOpError::NotInteger(self.return_type()));
1326 };
1327
1328 if ranges.is_empty() {
1329 return Ok(vec![]);
1330 }
1331
1332 let mut values = vec![];
1333 for range in ranges {
1334 match range {
1335 Range::Single(i) => {
1336 values.push(*i);
1337 }
1338 Range::Bounded(i, j) => {
1339 values.extend(*i..=*j);
1340 }
1341 Range::UnboundedR(_) | Range::UnboundedL(_) | Range::Unbounded => {
1342 return Err(DomainOpError::Unbounded);
1343 }
1344 }
1345 }
1346
1347 Ok(values)
1348 }
1349
1350 pub fn from_set_i32(elements: &BTreeSet<i32>) -> GroundDomain {
1389 if elements.is_empty() {
1390 return GroundDomain::Empty(ReturnType::Int);
1391 }
1392 if elements.len() == 1 {
1393 return GroundDomain::Int(vec![Range::Single(*elements.first().unwrap())], None);
1394 }
1395
1396 let mut elems_iter = elements.iter().copied();
1397
1398 let mut ranges: Vec<Range<i32>> = vec![];
1399
1400 let mut lower = elems_iter
1405 .next()
1406 .expect("if we get here, elements should have => 2 elements");
1407 let mut upper = lower;
1408
1409 for current in elems_iter {
1410 if current == upper + 1 {
1413 upper = current;
1416 } else {
1417 if lower == upper {
1422 ranges.push(range!(lower));
1423 } else {
1424 ranges.push(range!(lower..upper));
1425 }
1426
1427 lower = current;
1428 upper = current;
1429 }
1430 }
1431
1432 if lower == upper {
1434 ranges.push(range!(lower));
1435 } else {
1436 ranges.push(range!(lower..upper));
1437 }
1438
1439 ranges = Range::squeeze(&ranges);
1440 GroundDomain::Int(ranges, None)
1441 }
1442
1443 pub fn apply_i32(
1453 &self,
1454 op: fn(i32, i32) -> Option<i32>,
1455 other: &GroundDomain,
1456 ) -> Result<GroundDomain, DomainOpError> {
1457 let vs1 = self.values_i32()?;
1458 let vs2 = other.values_i32()?;
1459
1460 let mut set = BTreeSet::new();
1461 for (v1, v2) in itertools::iproduct!(vs1, vs2) {
1462 if let Some(v) = op(v1, v2) {
1463 set.insert(v);
1464 }
1465 }
1466
1467 Ok(GroundDomain::from_set_i32(&set))
1468 }
1469
1470 pub fn is_finite(&self) -> bool {
1472 for domain in self.universe() {
1473 if let GroundDomain::Int(ranges, _) = domain
1474 && ranges.iter().any(|range| {
1475 matches!(
1476 range,
1477 Range::UnboundedL(_) | Range::UnboundedR(_) | Range::Unbounded
1478 )
1479 })
1480 {
1481 return false;
1482 }
1483 }
1484 true
1485 }
1486
1487 pub fn from_literal_vec(literals: &[Literal]) -> Result<GroundDomain, DomainOpError> {
1569 if literals.is_empty() {
1572 return Ok(GroundDomain::Empty(ReturnType::Unknown));
1573 }
1574
1575 let first_literal = literals.first().unwrap();
1576
1577 match first_literal {
1578 Literal::Int(_) => {
1579 let mut ints = BTreeSet::new();
1581 for lit in literals {
1582 let Literal::Int(i) = lit else {
1583 return Err(DomainOpError::WrongType);
1584 };
1585
1586 ints.insert(*i);
1587 }
1588
1589 Ok(GroundDomain::from_set_i32(&ints))
1590 }
1591 Literal::Bool(_) => {
1592 if literals.iter().any(|x| !matches!(x, Literal::Bool(_))) {
1594 Err(DomainOpError::WrongType)
1595 } else {
1596 Ok(GroundDomain::Bool)
1597 }
1598 }
1599 Literal::Unnamed(first) => {
1600 if literals
1601 .iter()
1602 .all(|value| matches!(value, Literal::Unnamed(value) if value.ty == first.ty))
1603 {
1604 Ok(GroundDomain::UnnamedType(first.ty.clone()))
1605 } else {
1606 Err(DomainOpError::WrongType)
1607 }
1608 }
1609 Literal::EnumVariant(first_ev) => {
1610 let mut variants = BTreeSet::new();
1611
1612 for lit in literals {
1613 let Literal::EnumVariant(current_ev) = lit else {
1614 return Err(DomainOpError::WrongType);
1615 };
1616
1617 if current_ev.ty != first_ev.ty {
1618 return Err(DomainOpError::WrongType);
1619 }
1620
1621 variants.insert(current_ev.variant);
1622 }
1623
1624 Ok(GroundDomain::EnumeratedType(
1625 first_ev.ty.clone(),
1626 variants.into_iter().map(Range::Single).collect(),
1627 ))
1628 }
1629 Literal::AbstractLiteral(AbstractLiteral::Set(_)) => {
1630 let mut all_elems = vec![];
1631
1632 for lit in literals {
1633 let Literal::AbstractLiteral(AbstractLiteral::Set(elems)) = lit else {
1634 return Err(DomainOpError::WrongType);
1635 };
1636
1637 all_elems.extend(elems.clone());
1638 }
1639 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1640
1641 Ok(GroundDomain::Set(SetAttr::default(), Moo::new(elem_domain)))
1642 }
1643 Literal::AbstractLiteral(AbstractLiteral::MSet(_)) => {
1644 let mut all_elems = vec![];
1645
1646 for lit in literals {
1647 let Literal::AbstractLiteral(AbstractLiteral::MSet(elems)) = lit else {
1648 return Err(DomainOpError::WrongType);
1649 };
1650
1651 all_elems.extend(elems.clone());
1652 }
1653 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1654
1655 Ok(GroundDomain::MSet(
1656 MSetAttr::default(),
1657 Moo::new(elem_domain),
1658 ))
1659 }
1660 Literal::AbstractLiteral(AbstractLiteral::Partition(_)) => {
1661 todo!("Need to figure out how this is going to work")
1662 }
1663 Literal::AbstractLiteral(AbstractLiteral::Permutation(_)) => {
1664 todo!("Need to figure out how this is going to work")
1665 }
1666 l @ Literal::AbstractLiteral(AbstractLiteral::Matrix(_, _)) => {
1667 let mut first_index_domain = vec![];
1668 let mut l = l.clone();
1670 while let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = l {
1671 bug_assert!(
1672 !matches!(idx.as_ref(), GroundDomain::Matrix(_, _, _)),
1673 "n-dimensional matrix literals should be represented as a matrix inside a matrix"
1674 );
1675 first_index_domain.push(idx);
1676 let Some(first_elem) = elems.first() else {
1677 break;
1678 };
1679 l = first_elem.clone();
1680 }
1681
1682 let mut all_elems: Vec<Literal> = vec![];
1683
1684 for lit in literals {
1686 let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = lit else {
1687 return Err(DomainOpError::NotGround);
1688 };
1689
1690 all_elems.extend(elems.clone());
1691
1692 let mut index_domain = vec![idx.clone()];
1693 let Some(first_elem) = elems.first() else {
1694 if index_domain != first_index_domain {
1695 return Err(DomainOpError::WrongType);
1696 }
1697 continue;
1698 };
1699 let mut l = first_elem.clone();
1700 while let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = l {
1701 bug_assert!(
1702 !matches!(idx.as_ref(), GroundDomain::Matrix(_, _, _)),
1703 "n-dimensional matrix literals should be represented as a matrix inside a matrix"
1704 );
1705 index_domain.push(idx);
1706 let Some(first_elem) = elems.first() else {
1707 break;
1708 };
1709 l = first_elem.clone();
1710 }
1711
1712 if index_domain != first_index_domain {
1713 return Err(DomainOpError::WrongType);
1714 }
1715 }
1716
1717 let mut terminal_elements: Vec<Literal> = vec![];
1719 while let Some(elem) = all_elems.pop() {
1720 if let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, _)) = elem {
1721 all_elems.extend(elems);
1722 } else {
1723 terminal_elements.push(elem);
1724 }
1725 }
1726
1727 let element_domain = GroundDomain::from_literal_vec(&terminal_elements)?;
1728
1729 Ok(GroundDomain::Matrix(
1730 Moo::new(element_domain),
1731 first_index_domain,
1732 None,
1733 ))
1734 }
1735
1736 Literal::AbstractLiteral(AbstractLiteral::Tuple(first_elems)) => {
1737 let n_fields = first_elems.len();
1738
1739 let mut elem_domains = vec![];
1741
1742 for i in 0..n_fields {
1743 let mut all_elems = vec![];
1744 for lit in literals {
1745 let Literal::AbstractLiteral(AbstractLiteral::Tuple(elems)) = lit else {
1746 return Err(DomainOpError::NotGround);
1747 };
1748
1749 if elems.len() != n_fields {
1750 return Err(DomainOpError::NotGround);
1751 }
1752
1753 all_elems.push(elems[i].clone());
1754 }
1755
1756 elem_domains.push(Moo::new(GroundDomain::from_literal_vec(&all_elems)?));
1757 }
1758
1759 Ok(GroundDomain::Tuple(elem_domains, None))
1760 }
1761
1762 Literal::AbstractLiteral(AbstractLiteral::Sequence(_)) => {
1763 let mut all_elems = vec![];
1764 let mut lengths = Vec::new();
1765
1766 for lit in literals {
1767 let Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)) = lit else {
1768 return Err(DomainOpError::WrongType);
1769 };
1770
1771 lengths.push(i32::try_from(elems.len()).map_err(|_| DomainOpError::TooLarge)?);
1772 all_elems.extend(elems.clone());
1773 }
1774 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1775
1776 let min = lengths.iter().copied().min().unwrap_or(0);
1779 let max = lengths.iter().copied().max().unwrap_or(0);
1780 let size = if min == max {
1781 Range::Single(min)
1782 } else {
1783 Range::Bounded(min, max)
1784 };
1785
1786 Ok(GroundDomain::Sequence(
1787 SequenceAttr {
1788 size,
1789 ..SequenceAttr::default()
1790 },
1791 Moo::new(elem_domain),
1792 ))
1793 }
1794
1795 Literal::AbstractLiteral(AbstractLiteral::Record(first_elems)) => {
1796 let n_fields = first_elems.len();
1797 let field_names = first_elems.iter().map(|x| x.name.clone()).collect_vec();
1798
1799 let mut elem_domains = vec![];
1801
1802 for i in 0..n_fields {
1803 let mut all_elems = vec![];
1804 for lit in literals {
1805 let Literal::AbstractLiteral(AbstractLiteral::Record(elems)) = lit else {
1806 return Err(DomainOpError::NotGround);
1807 };
1808
1809 if elems.len() != n_fields {
1810 return Err(DomainOpError::NotGround);
1811 }
1812
1813 let elem = elems[i].clone();
1814 if elem.name != field_names[i] {
1815 return Err(DomainOpError::NotGround);
1816 }
1817
1818 all_elems.push(elem.value);
1819 }
1820
1821 elem_domains.push(Moo::new(GroundDomain::from_literal_vec(&all_elems)?));
1822 }
1823
1824 Ok(GroundDomain::Record(
1825 izip!(field_names, elem_domains)
1826 .map(|(name, value)| FieldGround { name, value })
1827 .collect(),
1828 None,
1829 ))
1830 }
1831 Literal::AbstractLiteral(AbstractLiteral::Function(_)) => {
1832 let mut all_keys = vec![];
1833 let mut all_values = vec![];
1834
1835 for lit in literals {
1836 let Literal::AbstractLiteral(AbstractLiteral::Function(pairs)) = lit else {
1837 return Err(DomainOpError::WrongType);
1838 };
1839
1840 for (key, value) in pairs {
1841 all_keys.push(key.clone());
1842 all_values.push(value.clone());
1843 }
1844 }
1845
1846 let domain = GroundDomain::from_literal_vec(&all_keys)?;
1847 let codomain = GroundDomain::from_literal_vec(&all_values)?;
1848
1849 Ok(GroundDomain::Function(
1850 FuncAttr::default(),
1851 Moo::new(domain),
1852 Moo::new(codomain),
1853 ))
1854 }
1855 Literal::AbstractLiteral(AbstractLiteral::Variant(_)) => {
1856 let mut alternatives: Vec<(Name, Vec<Literal>)> = Vec::new();
1857 for literal in literals {
1858 let Literal::AbstractLiteral(AbstractLiteral::Variant(field)) = literal else {
1859 return Err(DomainOpError::WrongType);
1860 };
1861 if let Some((_, values)) = alternatives
1862 .iter_mut()
1863 .find(|(name, _)| name == &field.name)
1864 {
1865 values.push(field.value.clone());
1866 } else {
1867 alternatives.push((field.name.clone(), vec![field.value.clone()]));
1868 }
1869 }
1870
1871 Ok(GroundDomain::Variant(
1872 alternatives
1873 .into_iter()
1874 .map(|(name, values)| {
1875 Ok(FieldGround {
1876 name,
1877 value: Moo::new(GroundDomain::from_literal_vec(&values)?),
1878 })
1879 })
1880 .collect::<Result<Vec<_>, DomainOpError>>()?,
1881 None,
1882 ))
1883 }
1884 Literal::AbstractLiteral(AbstractLiteral::Relation(_)) => {
1885 let mut columns: Vec<Vec<Literal>> = vec![];
1886 for lit in literals {
1887 let Literal::AbstractLiteral(AbstractLiteral::Relation(tuples)) = lit else {
1888 return Err(DomainOpError::WrongType);
1889 };
1890 for tuple in tuples {
1891 if columns.is_empty() {
1892 columns = vec![Vec::new(); tuple.len()];
1893 }
1894 if tuple.len() != columns.len() {
1895 return Err(DomainOpError::NotGround);
1896 }
1897 for (column, field) in columns.iter_mut().zip(tuple) {
1898 column.push(field.clone());
1899 }
1900 }
1901 }
1902
1903 let inner_domains = columns
1904 .iter()
1905 .map(|column| GroundDomain::from_literal_vec(column).map(Moo::new))
1906 .collect::<Result<Vec<_>, _>>()?;
1907
1908 Ok(GroundDomain::Relation(RelAttr::default(), inner_domains))
1909 }
1910 }
1911 }
1912
1913 pub fn element_domain(&self) -> Option<Moo<GroundDomain>> {
1914 match self {
1915 GroundDomain::Matrix(inner, _, _) => Some(inner.clone()),
1916 GroundDomain::Set(_, inner) => Some(inner.clone()),
1917 GroundDomain::MSet(_, inner) => Some(inner.clone()),
1918 GroundDomain::Relation(_, inner_doms) => {
1919 Some(Moo::new(GroundDomain::Tuple(inner_doms.clone(), None)))
1920 }
1921 GroundDomain::Sequence(attr, inner) => {
1924 let max = match attr.size {
1925 Range::Single(max) | Range::UnboundedL(max) | Range::Bounded(_, max) => max,
1926 Range::UnboundedR(_) | Range::Unbounded => return None,
1927 };
1928 Some(Moo::new(GroundDomain::Tuple(
1929 vec![
1930 Moo::new(GroundDomain::Int(vec![Range::Bounded(1, max)], None)),
1931 inner.clone(),
1932 ],
1933 None,
1934 )))
1935 }
1936 _ => None,
1937 }
1938 }
1939
1940 pub fn has_representation_preference(&self) -> bool {
1942 match self {
1943 GroundDomain::Empty(_)
1944 | GroundDomain::EnumeratedType(_, _)
1945 | GroundDomain::UnnamedType(_) => false,
1946 GroundDomain::Bool => false,
1947 GroundDomain::Int(_, representation) => representation.is_some(),
1948 GroundDomain::Tuple(inners, representation) => {
1949 representation.is_some() || inners.iter().any(|d| d.has_representation_preference())
1950 }
1951 GroundDomain::Record(entries, representation) => {
1952 representation.is_some()
1953 || entries
1954 .iter()
1955 .any(|f| f.value.has_representation_preference())
1956 }
1957 GroundDomain::Variant(entries, representation) => {
1958 representation.is_some()
1959 || entries
1960 .iter()
1961 .any(|f| f.value.has_representation_preference())
1962 }
1963 GroundDomain::Matrix(inner, idxs, representation) => {
1964 representation.is_some()
1965 || inner.has_representation_preference()
1966 || idxs.iter().any(|d| d.has_representation_preference())
1967 }
1968 GroundDomain::Sequence(attr, inner) => {
1969 attr.representation.is_some() || inner.has_representation_preference()
1970 }
1971 GroundDomain::Set(attr, inner) => {
1972 attr.representation.is_some() || inner.has_representation_preference()
1973 }
1974 GroundDomain::MSet(attr, inner) => {
1975 attr.representation.is_some() || inner.has_representation_preference()
1976 }
1977 GroundDomain::Function(attr, dom, cdom) => {
1978 attr.representation.is_some()
1979 || dom.has_representation_preference()
1980 || cdom.has_representation_preference()
1981 }
1982 GroundDomain::Relation(attr, inners) => {
1983 attr.representation.is_some()
1984 || inners.iter().any(|d| d.has_representation_preference())
1985 }
1986 GroundDomain::Partition(attr, inner) => {
1987 attr.representation.is_some() || inner.has_representation_preference()
1988 }
1989 GroundDomain::Permutation(attr, inner) => {
1990 attr.representation.is_some() || inner.has_representation_preference()
1991 }
1992 }
1993 }
1994
1995 pub fn as_type_string(&self) -> String {
1997 match self {
1998 GroundDomain::Empty(ty) => format!("empty({ty})"),
1999 GroundDomain::EnumeratedType(ty, _) => ty.to_string(),
2000 GroundDomain::UnnamedType(_) => "unnamed type".to_string(),
2001 GroundDomain::Bool => "bool".to_string(),
2002 GroundDomain::Int(_, representation) => int_type_string(representation.as_deref()),
2003 GroundDomain::Tuple(inners, representation) => {
2004 let args = representation
2005 .iter()
2006 .map(|r| format!("representation {r}"))
2007 .chain(inners.iter().map(|d| d.as_type_string()))
2008 .join(", ");
2009 format!("tuple ({args})")
2010 }
2011 GroundDomain::Record(entries, representation) => {
2012 let inners = entries
2013 .iter()
2014 .map(|f| format!("{}: {}", f.name, f.value.as_type_string()))
2015 .join(", ");
2016 format!(
2017 "record{} {{{inners}}}",
2018 representation_attribute(representation)
2019 )
2020 }
2021 GroundDomain::Variant(entries, representation) => {
2022 let inners = entries
2023 .iter()
2024 .map(|f| format!("{}: {}", f.name, f.value.as_type_string()))
2025 .join(", ");
2026 format!(
2027 "variant{} {{{inners}}}",
2028 representation_attribute(representation)
2029 )
2030 }
2031 GroundDomain::Matrix(inner, idxs, representation) => {
2032 let idxs = idxs.iter().map(|d| d.as_type_string()).join(", ");
2033 format!(
2034 "matrix{} indexed by [{idxs}] of {}",
2035 representation_attribute(representation),
2036 inner.as_type_string()
2037 )
2038 }
2039 GroundDomain::Sequence(attrs, inner) => format!(
2040 "sequence{} of {}",
2041 representation_attribute(&attrs.representation),
2042 inner.as_type_string()
2043 ),
2044 GroundDomain::Set(attrs, inner) => {
2045 let mut out = String::from("set");
2046 if let Some(repr) = &attrs.representation {
2047 out.push_str(" (representation ");
2048 out.push_str(repr);
2049 out.push(')');
2050 }
2051 out.push_str(" of ");
2052 out.push_str(&inner.as_type_string());
2053 out
2054 }
2055 GroundDomain::MSet(attrs, inner) => {
2056 let mut out = String::from("mset");
2057 if let Some(repr) = &attrs.representation {
2058 out.push_str(" (representation ");
2059 out.push_str(repr);
2060 out.push(')');
2061 }
2062 out.push_str(" of ");
2063 out.push_str(&inner.as_type_string());
2064 out
2065 }
2066 GroundDomain::Function(attr, dom, cdom) => {
2067 format!(
2068 "function{} {} --> {}",
2069 representation_attribute(&attr.representation),
2070 dom.as_type_string(),
2071 cdom.as_type_string()
2072 )
2073 }
2074 GroundDomain::Relation(attr, inners) => {
2075 format!(
2076 "relation{} of ({})",
2077 representation_attribute(&attr.representation),
2078 inners.iter().map(|d| d.as_type_string()).join(" * ")
2079 )
2080 }
2081 GroundDomain::Partition(attr, inner) => {
2082 format!(
2083 "partition{} from {}",
2084 representation_attribute(&attr.representation),
2085 inner.as_type_string()
2086 )
2087 }
2088 GroundDomain::Permutation(attr, inner) => {
2089 format!(
2090 "permutation{} of {}",
2091 representation_attribute(&attr.representation),
2092 inner.as_type_string()
2093 )
2094 }
2095 }
2096 }
2097}
2098
2099impl Typeable for GroundDomain {
2100 fn return_type(&self) -> ReturnType {
2101 match self {
2102 GroundDomain::Empty(ty) => ty.clone(),
2103 GroundDomain::Bool => ReturnType::Bool,
2104 GroundDomain::Int(_, _) => ReturnType::Int,
2105 GroundDomain::Tuple(inners, _) => {
2106 let mut inner_types = Vec::new();
2107 for inner in inners {
2108 inner_types.push(inner.return_type());
2109 }
2110 ReturnType::Tuple(inner_types)
2111 }
2112 GroundDomain::Record(entries, _) => {
2113 let mut entry_types = Vec::new();
2114 for entry in entries {
2115 entry_types.push(entry.clone().func_map(|x| x.return_type()));
2116 }
2117 entry_types.sort();
2118 ReturnType::Record(entry_types)
2119 }
2120 GroundDomain::Variant(entries, _) => {
2121 let mut entry_types = Vec::new();
2122 for entry in entries {
2123 entry_types.push(entry.clone().func_map(|x| x.return_type()));
2124 }
2125 ReturnType::Variant(entry_types)
2126 }
2127 GroundDomain::Matrix(inner, _idx, _) => {
2128 ReturnType::Matrix(Box::new(inner.return_type()))
2129 }
2130 GroundDomain::Sequence(_attr, inner) => {
2131 ReturnType::Sequence(Box::new(inner.return_type()))
2132 }
2133 GroundDomain::Set(_attr, inner) => ReturnType::Set(Box::new(inner.return_type())),
2134 GroundDomain::MSet(_attr, inner) => ReturnType::MSet(Box::new(inner.return_type())),
2135 GroundDomain::Function(_, dom, cdom) => {
2136 ReturnType::Function(Box::new(dom.return_type()), Box::new(cdom.return_type()))
2137 }
2138 GroundDomain::Relation(_, inners) => {
2139 let mut inner_types = Vec::new();
2140 for inner in inners {
2141 inner_types.push(inner.return_type());
2142 }
2143 ReturnType::Relation(inner_types)
2144 }
2145 GroundDomain::Partition(_, inner) => {
2146 ReturnType::Partition(Box::new(inner.return_type()))
2147 }
2148 GroundDomain::Permutation(_, inner) => {
2149 ReturnType::Permutation(Box::new(inner.return_type()))
2150 }
2151 GroundDomain::EnumeratedType(et, _) => ReturnType::EnumeratedType(et.clone()),
2152 GroundDomain::UnnamedType(ty) => ReturnType::UnnamedType(ty.clone()),
2154 }
2155 }
2156}
2157
2158impl Display for FieldGround {
2159 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2160 write!(f, "{}: {}", self.name, self.value)
2161 }
2162}
2163
2164impl Display for GroundDomain {
2165 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2166 match &self {
2167 GroundDomain::Empty(ty) => write!(f, "empty({ty})"),
2168 GroundDomain::Bool => write!(f, "bool"),
2169 GroundDomain::Int(ranges, representation) => {
2170 write_int_domain(f, ranges, representation.as_deref())
2171 }
2172 GroundDomain::Tuple(domains, representation) => {
2173 let args = representation
2174 .iter()
2175 .map(|r| format!("representation {r}"))
2176 .chain(domains.iter().map(|d| d.to_string()))
2177 .join(", ");
2178 write!(f, "tuple ({args})")
2179 }
2180 GroundDomain::Record(entries, representation) => {
2181 let inners = entries.iter().map(|t| format!("{}", t)).join(", ");
2182 let attrs = representation_attribute(representation);
2183 write!(f, "record{attrs} {{{inners}}}",)
2184 }
2185 GroundDomain::Variant(entries, representation) => {
2186 let inners = entries.iter().map(|t| format!("{}", t)).join(", ");
2187 let attrs = representation_attribute(representation);
2188 write!(f, "variant{attrs} {{{inners}}}",)
2189 }
2190 GroundDomain::Matrix(value_domain, index_domains, representation) => {
2191 write!(
2192 f,
2193 "matrix{} indexed by {} of {value_domain}",
2194 representation_attribute(representation),
2195 pretty_vec(&index_domains.iter().collect_vec())
2196 )
2197 }
2198 GroundDomain::Sequence(attrs, inner_dom) => {
2199 write!(f, "sequence {attrs} of {inner_dom}")
2200 }
2201 GroundDomain::Set(attrs, inner_dom) => {
2202 write!(f, "set")?;
2203 let attrs = attrs.to_string();
2204 if attrs.is_empty() {
2205 write!(f, " of {inner_dom}")
2206 } else {
2207 write!(f, " {attrs} of {inner_dom}")
2208 }
2209 }
2210 GroundDomain::MSet(attrs, inner_dom) => {
2211 write!(f, "mset")?;
2212 let attrs = attrs.to_string();
2213 if attrs.is_empty() {
2214 write!(f, " of {inner_dom}")
2215 } else {
2216 write!(f, " {attrs} of {inner_dom}")
2217 }
2218 }
2219 GroundDomain::Function(attribute, domain, codomain) => {
2220 write!(f, "function {} {} --> {} ", attribute, domain, codomain)
2221 }
2222 GroundDomain::Relation(attrs, domains) => {
2223 write!(f, "relation {} of ({})", attrs, domains.iter().join(" * "))
2224 }
2225 GroundDomain::Partition(attrs, inner) => {
2226 write!(f, "partition {attrs} from {inner}")
2227 }
2228 GroundDomain::EnumeratedType(et, ranges) => {
2229 if !ranges.is_empty() && ranges.iter().all(Range::is_lower_or_upper_bounded) {
2230 let ranges = ranges
2231 .iter()
2232 .cloned()
2233 .map(|range| {
2234 range.func_map(|index| {
2235 et.variants
2236 .get(index as usize)
2237 .map(ToString::to_string)
2238 .unwrap_or_else(|| index.to_string())
2239 })
2240 })
2241 .join(", ");
2242 write!(f, "{}({ranges})", et.name)
2243 } else {
2244 write!(f, "{}", et.name)
2245 }
2246 }
2247 GroundDomain::UnnamedType(ty) => {
2248 write!(f, "{}", ty.name)
2249 }
2250 GroundDomain::Permutation(attrs, inner) => {
2251 write!(f, "permutation {attrs} of {inner}")
2252 }
2253 }
2254 }
2255}
2256
2257#[cfg(test)]
2258mod tests {
2259 use super::*;
2260 use crate::ast::Name;
2261 use crate::{domain_int_ground, matrix_lit};
2262
2263 #[test]
2264 fn integer_intersection_matches_all_small_sparse_sets() {
2265 for a_mask in 0..128 {
2266 let a = GroundDomain::Int(
2267 (-3..=3)
2268 .filter(|i| a_mask & (1 << (i + 3)) != 0)
2269 .map(Range::Single)
2270 .collect(),
2271 None,
2272 );
2273 for b_mask in 0..128 {
2274 let b = GroundDomain::Int(
2275 (-3..=3)
2276 .filter(|i| b_mask & (1 << (i + 3)) != 0)
2277 .map(Range::Single)
2278 .collect(),
2279 None,
2280 );
2281 let expected: BTreeSet<_> = (-3..=3)
2282 .filter(|i| (a_mask & b_mask) & (1 << (i + 3)) != 0)
2283 .collect();
2284 let actual = a
2285 .intersect(&b)
2286 .unwrap()
2287 .values_i32()
2288 .unwrap()
2289 .into_iter()
2290 .collect::<BTreeSet<_>>();
2291 assert_eq!(actual, expected);
2292 }
2293 }
2294 }
2295
2296 #[test]
2297 fn integer_intersection_handles_large_overlapping_and_empty_ranges() {
2298 let full = GroundDomain::Int(vec![Range::Bounded(i32::MIN, i32::MAX)], None);
2299 let positive = GroundDomain::Int(vec![Range::Bounded(0, i32::MAX)], None);
2300 assert_eq!(full.intersect(&positive).unwrap(), positive);
2301 assert_eq!(full.intersect(&full).unwrap(), full);
2302 let empty = GroundDomain::Empty(ReturnType::Int);
2303 assert_eq!(full.intersect(&empty).unwrap(), empty);
2304 let unsorted = GroundDomain::Int(
2305 vec![
2306 Range::Bounded(5, 10),
2307 Range::Bounded(-8, 6),
2308 Range::Single(i32::MAX),
2309 ],
2310 None,
2311 );
2312 let overlap = GroundDomain::Int(
2313 vec![
2314 Range::Bounded(0, 12),
2315 Range::Bounded(3, 8),
2316 Range::Single(i32::MAX),
2317 ],
2318 None,
2319 );
2320 assert_eq!(
2321 unsorted.intersect(&overlap).unwrap(),
2322 GroundDomain::Int(vec![Range::Bounded(0, 10), Range::Single(i32::MAX)], None)
2323 );
2324 let negative = GroundDomain::Int(vec![Range::Bounded(i32::MIN, -1)], None);
2325 assert_eq!(negative.intersect(&positive).unwrap(), empty);
2326 let unbounded = GroundDomain::Int(vec![Range::Unbounded], None);
2327 assert!(matches!(
2328 full.intersect(&unbounded),
2329 Err(DomainOpError::Unbounded)
2330 ));
2331 let no_ranges = GroundDomain::Int(Vec::new(), None);
2332 assert!(matches!(
2333 no_ranges.intersect(&unbounded),
2334 Err(DomainOpError::Unbounded)
2335 ));
2336 }
2337
2338 #[test]
2339 fn matrix_values_1d_bool_of_bool() {
2340 let dom = GroundDomain::Matrix(
2343 Moo::new(GroundDomain::Bool),
2344 vec![Moo::new(GroundDomain::Bool)],
2345 None,
2346 );
2347
2348 let values: Vec<Literal> = dom.values().unwrap().collect();
2349
2350 assert_eq!(values.len(), 4);
2351 assert_eq!(
2352 values[0],
2353 matrix_lit![false, false; Moo::new(GroundDomain::Bool)]
2354 );
2355 assert_eq!(
2356 values[1],
2357 matrix_lit![false, true; Moo::new(GroundDomain::Bool)]
2358 );
2359 assert_eq!(
2360 values[2],
2361 matrix_lit![true, false; Moo::new(GroundDomain::Bool)]
2362 );
2363 assert_eq!(
2364 values[3],
2365 matrix_lit![true, true; Moo::new(GroundDomain::Bool)]
2366 );
2367 }
2368
2369 #[test]
2370 fn matrix_values_1d_int() {
2371 let dom = GroundDomain::Matrix(
2374 domain_int_ground!(0..1),
2375 vec![domain_int_ground!(1..2)],
2376 None,
2377 );
2378
2379 let values: Vec<Literal> = dom.values().unwrap().collect();
2380
2381 assert_eq!(values.len(), 4);
2382 assert_eq!(values[0], matrix_lit![0, 0; domain_int_ground!(1..2)]);
2383 assert_eq!(values[1], matrix_lit![0, 1; domain_int_ground!(1..2)]);
2384 assert_eq!(values[2], matrix_lit![1, 0; domain_int_ground!(1..2)]);
2385 assert_eq!(values[3], matrix_lit![1, 1; domain_int_ground!(1..2)]);
2386 }
2387
2388 #[test]
2389 fn matrix_values_2d_lexicographic() {
2390 let dom = GroundDomain::Matrix(
2393 domain_int_ground!(0..1),
2394 vec![domain_int_ground!(1..2), domain_int_ground!(1..2)],
2395 None,
2396 );
2397
2398 let values: Vec<Literal> = dom.values().unwrap().collect();
2399
2400 assert_eq!(values.len(), 16);
2401
2402 assert_eq!(
2404 values[0],
2405 matrix_lit![[0, 0], [0, 0]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2406 );
2407 assert_eq!(
2409 values[1],
2410 matrix_lit![[0, 0], [0, 1]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2411 );
2412 assert_eq!(
2414 values[2],
2415 matrix_lit![[0, 0], [1, 0]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2416 );
2417 assert_eq!(
2419 values[3],
2420 matrix_lit![[0, 0], [1, 1]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2421 );
2422 assert_eq!(
2424 values[15],
2425 matrix_lit![[1, 1], [1, 1]; [domain_int_ground!(1..2), domain_int_ground!(1..2)]]
2426 );
2427 }
2428
2429 #[test]
2430 fn matrix_values_count_matches_length() {
2431 let dom = GroundDomain::Matrix(
2434 domain_int_ground!(0..1),
2435 vec![domain_int_ground!(1..3)],
2436 None,
2437 );
2438
2439 let count = dom.values().unwrap().count();
2440 let length = dom.length().unwrap();
2441
2442 assert_eq!(count as u64, length);
2443 }
2444
2445 #[test]
2446 fn tuple_values_two_bools() {
2447 let dom = GroundDomain::Tuple(
2449 vec![Moo::new(GroundDomain::Bool), Moo::new(GroundDomain::Bool)],
2450 None,
2451 );
2452
2453 let values: Vec<Literal> = dom.values().unwrap().collect();
2454
2455 assert_eq!(values.len(), 4);
2456 let t = |a, b| {
2457 Literal::AbstractLiteral(AbstractLiteral::Tuple(vec![
2458 Literal::Bool(a),
2459 Literal::Bool(b),
2460 ]))
2461 };
2462 assert_eq!(values[0], t(false, false));
2463 assert_eq!(values[1], t(false, true));
2464 assert_eq!(values[2], t(true, false));
2465 assert_eq!(values[3], t(true, true));
2466 }
2467
2468 #[test]
2469 fn tuple_values_mixed_domains() {
2470 let dom = GroundDomain::Tuple(
2472 vec![Moo::new(GroundDomain::Bool), domain_int_ground!(0..2)],
2473 None,
2474 );
2475
2476 let values: Vec<Literal> = dom.values().unwrap().collect();
2477
2478 assert_eq!(values.len(), 6);
2479 let t = |b: bool, i: i32| {
2480 Literal::AbstractLiteral(AbstractLiteral::Tuple(vec![
2481 Literal::Bool(b),
2482 Literal::Int(i),
2483 ]))
2484 };
2485 assert_eq!(values[0], t(false, 0));
2487 assert_eq!(values[1], t(false, 1));
2488 assert_eq!(values[2], t(false, 2));
2489 assert_eq!(values[3], t(true, 0));
2491 assert_eq!(values[4], t(true, 1));
2492 assert_eq!(values[5], t(true, 2));
2493 }
2494
2495 #[test]
2496 fn tuple_values_count_matches_length() {
2497 let dom = GroundDomain::Tuple(
2498 vec![
2499 domain_int_ground!(1..3),
2500 Moo::new(GroundDomain::Bool),
2501 domain_int_ground!(0..1),
2502 ],
2503 None,
2504 );
2505 let count = dom.values().unwrap().count();
2506 let length = dom.length().unwrap();
2507 assert_eq!(count as u64, length);
2508 }
2509
2510 #[test]
2511 fn record_values_lexicographic_by_name() {
2512 let dom = GroundDomain::Record(
2515 vec![
2516 Field {
2517 name: Name::user("b"),
2518 value: Moo::new(GroundDomain::Bool),
2519 },
2520 Field {
2521 name: Name::user("a"),
2522 value: domain_int_ground!(0..1),
2523 },
2524 ],
2525 None,
2526 );
2527
2528 let values: Vec<Literal> = dom.values().unwrap().collect();
2529
2530 assert_eq!(values.len(), 4);
2532
2533 let r = |a_val: i32, b_val: bool| {
2535 Literal::AbstractLiteral(AbstractLiteral::Record(vec![
2536 Field {
2537 name: Name::user("a"),
2538 value: Literal::Int(a_val),
2539 },
2540 Field {
2541 name: Name::user("b"),
2542 value: Literal::Bool(b_val),
2543 },
2544 ]))
2545 };
2546
2547 assert_eq!(values[0], r(0, false));
2549 assert_eq!(values[1], r(0, true));
2550 assert_eq!(values[2], r(1, false));
2551 assert_eq!(values[3], r(1, true));
2552 for value in &values {
2553 assert!(dom.contains(value).unwrap(), "{value}");
2554 }
2555 assert!(!dom.contains(&r(2, false)).unwrap());
2556 }
2557
2558 #[test]
2559 fn record_values_count_matches_length() {
2560 let dom = GroundDomain::Record(
2561 vec![
2562 Field {
2563 name: Name::user("x"),
2564 value: domain_int_ground!(1..3),
2565 },
2566 Field {
2567 name: Name::user("y"),
2568 value: Moo::new(GroundDomain::Bool),
2569 },
2570 ],
2571 None,
2572 );
2573 let count = dom.values().unwrap().count();
2574 let length = dom.length().unwrap();
2575 assert_eq!(count as u64, length);
2576 }
2577
2578 #[test]
2579 fn variant_values_follow_alternative_order_and_match_length() {
2580 let dom = GroundDomain::Variant(
2581 vec![
2582 Field {
2583 name: Name::user("flag"),
2584 value: Moo::new(GroundDomain::Bool),
2585 },
2586 Field {
2587 name: Name::user("value"),
2588 value: domain_int_ground!(2..3),
2589 },
2590 ],
2591 None,
2592 );
2593 let values = dom.values().unwrap().collect::<Vec<_>>();
2594 assert_eq!(values.len() as u64, dom.length().unwrap());
2595 assert_eq!(values.len(), 4);
2596 assert!(matches!(
2597 &values[0],
2598 Literal::AbstractLiteral(AbstractLiteral::Variant(field))
2599 if field.name == Name::user("flag") && field.value == Literal::Bool(false)
2600 ));
2601 assert!(matches!(
2602 &values[3],
2603 Literal::AbstractLiteral(AbstractLiteral::Variant(field))
2604 if field.name == Name::user("value") && field.value == Literal::Int(3)
2605 ));
2606 assert!(dom.contains(&values[2]).unwrap());
2607 }
2608
2609 #[test]
2610 fn infers_variant_domain_from_all_observed_alternatives() {
2611 let variant = |name: &str, value: i32| {
2612 Literal::AbstractLiteral(AbstractLiteral::Variant(Moo::new(Field {
2613 name: Name::user(name),
2614 value: Literal::Int(value),
2615 })))
2616 };
2617 let domain =
2618 GroundDomain::from_literal_vec(&[variant("a", 10), variant("a", 13), variant("b", 7)])
2619 .unwrap();
2620 let GroundDomain::Variant(fields, _) = domain else {
2621 panic!("expected variant domain");
2622 };
2623
2624 assert_eq!(fields.len(), 2);
2625 assert_eq!(fields[0].name, Name::user("a"));
2626 assert!(fields[0].value.contains(&Literal::Int(10)).unwrap());
2627 assert!(fields[0].value.contains(&Literal::Int(13)).unwrap());
2628 assert_eq!(fields[1].name, Name::user("b"));
2629 assert!(fields[1].value.contains(&Literal::Int(7)).unwrap());
2630 }
2631
2632 fn set_lit(elems: Vec<i32>) -> Literal {
2633 Literal::AbstractLiteral(AbstractLiteral::Set(
2634 elems.into_iter().map(Literal::Int).collect(),
2635 ))
2636 }
2637
2638 #[test]
2639 fn set_values_unbounded() {
2640 let dom = GroundDomain::Set(SetAttr::default(), domain_int_ground!(1..3));
2642
2643 let values: Vec<Literal> = dom.values().unwrap().collect();
2644
2645 assert_eq!(values.len(), 8);
2646 assert_eq!(values[0], set_lit(vec![])); assert_eq!(values[1], set_lit(vec![1])); assert_eq!(values[2], set_lit(vec![2]));
2649 assert_eq!(values[3], set_lit(vec![3]));
2650 assert_eq!(values[4], set_lit(vec![1, 2])); assert_eq!(values[5], set_lit(vec![1, 3]));
2652 assert_eq!(values[6], set_lit(vec![2, 3]));
2653 assert_eq!(values[7], set_lit(vec![1, 2, 3])); }
2655
2656 #[test]
2657 fn set_values_fixed_size() {
2658 let dom = GroundDomain::Set(SetAttr::new_size(2), domain_int_ground!(1..3));
2660
2661 let values: Vec<Literal> = dom.values().unwrap().collect();
2662
2663 assert_eq!(values.len(), 3);
2664 assert_eq!(values[0], set_lit(vec![1, 2]));
2665 assert_eq!(values[1], set_lit(vec![1, 3]));
2666 assert_eq!(values[2], set_lit(vec![2, 3]));
2667 }
2668
2669 #[test]
2670 fn set_values_bounded_size() {
2671 let dom = GroundDomain::Set(SetAttr::new_min_max_size(1, 2), domain_int_ground!(1..3));
2673
2674 let values: Vec<Literal> = dom.values().unwrap().collect();
2675
2676 assert_eq!(values.len(), 6);
2677 assert_eq!(values[0], set_lit(vec![1]));
2678 assert_eq!(values[1], set_lit(vec![2]));
2679 assert_eq!(values[2], set_lit(vec![3]));
2680 assert_eq!(values[3], set_lit(vec![1, 2]));
2681 assert_eq!(values[4], set_lit(vec![1, 3]));
2682 assert_eq!(values[5], set_lit(vec![2, 3]));
2683 }
2684
2685 #[test]
2686 fn set_length_clamps_max_size_to_inner_domain() {
2687 let dom = GroundDomain::Set(SetAttr::new_max_size(3), domain_int_ground!(1..2));
2689 assert_eq!(dom.length().unwrap(), 4);
2690 }
2691
2692 #[test]
2693 fn set_values_count_matches_length() {
2694 let dom = GroundDomain::Set(SetAttr::default(), domain_int_ground!(1..4));
2695 let count = dom.values().unwrap().count();
2696 let length = dom.length().unwrap();
2697 assert_eq!(count as u64, length);
2698 }
2699
2700 fn func_attr(partiality: PartialityAttr, jectivity: JectivityAttr) -> FuncAttr {
2701 FuncAttr {
2702 representation: None,
2703 size: Range::Unbounded,
2704 partiality,
2705 jectivity,
2706 }
2707 }
2708
2709 #[test]
2710 fn total_bijective_function_length_is_factorial_of_the_shared_size() {
2711 let dom = GroundDomain::Function(
2712 func_attr(PartialityAttr::Total, JectivityAttr::Bijective),
2713 domain_int_ground!(1..3),
2714 domain_int_ground!(1..3),
2715 );
2716 assert_eq!(dom.length().unwrap(), 6); }
2718
2719 #[test]
2720 fn total_bijective_function_length_is_zero_for_mismatched_sizes() {
2721 let dom = GroundDomain::Function(
2722 func_attr(PartialityAttr::Total, JectivityAttr::Bijective),
2723 domain_int_ground!(1..3),
2724 domain_int_ground!(1..2),
2725 );
2726 assert_eq!(dom.length().unwrap(), 0);
2727 }
2728
2729 #[test]
2730 fn total_injective_function_length_is_a_falling_factorial() {
2731 let dom = GroundDomain::Function(
2733 func_attr(PartialityAttr::Total, JectivityAttr::Injective),
2734 domain_int_ground!(1..2),
2735 domain_int_ground!(1..4),
2736 );
2737 assert_eq!(dom.length().unwrap(), 12);
2738 }
2739
2740 #[test]
2741 fn total_surjective_function_length_uses_stirling_numbers() {
2742 let dom = GroundDomain::Function(
2744 func_attr(PartialityAttr::Total, JectivityAttr::Surjective),
2745 domain_int_ground!(1..3),
2746 domain_int_ground!(1..2),
2747 );
2748 assert_eq!(dom.length().unwrap(), 6);
2749 }
2750
2751 #[test]
2752 fn partial_injective_function_length_sums_over_defined_sizes() {
2753 let mut attr = func_attr(PartialityAttr::Partial, JectivityAttr::Injective);
2756 attr.size = Range::Bounded(0, 2);
2757 let dom = GroundDomain::Function(attr, domain_int_ground!(1..3), domain_int_ground!(1..2));
2758 assert_eq!(dom.length().unwrap(), 13);
2759 }
2760
2761 fn partition_attr(num_parts: Range<i32>, part_len: Range<i32>) -> PartitionAttr {
2762 PartitionAttr {
2763 representation: None,
2764 num_parts,
2765 part_len,
2766 is_regular: false,
2767 }
2768 }
2769
2770 fn partition_lit(parts: Vec<Vec<i32>>) -> Literal {
2771 Literal::AbstractLiteral(AbstractLiteral::Partition(
2772 parts
2773 .into_iter()
2774 .map(|part| part.into_iter().map(Literal::Int).collect())
2775 .collect(),
2776 ))
2777 }
2778
2779 #[test]
2780 fn partition_contains_accepts_a_literal_whose_size_exactly_matches_num_parts_times_part_len() {
2781 let dom = GroundDomain::Partition(
2783 partition_attr(Range::Single(2), Range::Single(2)),
2784 domain_int_ground!(1..6),
2785 );
2786 let lit = partition_lit(vec![vec![1, 2], vec![3, 4]]);
2787 assert!(
2788 dom.contains(&lit).unwrap(),
2789 "a 4-element partition literal should be a valid member of a \
2790 (numParts 2, partSize 2) domain"
2791 );
2792 }
2793
2794 #[test]
2795 fn partition_contains_rejects_a_literal_with_the_wrong_covered_size() {
2796 let dom = GroundDomain::Partition(
2798 partition_attr(Range::Single(2), Range::Single(2)),
2799 domain_int_ground!(1..6),
2800 );
2801 let lit = partition_lit(vec![vec![1, 2, 3]]);
2802 assert!(
2803 !dom.contains(&lit).unwrap(),
2804 "a 3-element partition literal should not be a valid member of a \
2805 (numParts 2, partSize 2) domain, which requires exactly 4 covered elements"
2806 );
2807 }
2808
2809 #[test]
2810 fn partition_contains_accepts_any_size_when_attributes_are_unbounded() {
2811 let dom = GroundDomain::Partition(
2815 partition_attr(Range::Unbounded, Range::Unbounded),
2816 domain_int_ground!(1..6),
2817 );
2818 let lit = partition_lit(vec![vec![1, 2], vec![3, 4, 5, 6]]);
2819 assert!(
2820 dom.contains(&lit).unwrap(),
2821 "an unattributed partition domain should accept a literal covering its whole inner \
2822 domain"
2823 );
2824 }
2825
2826 #[test]
2827 fn partition_length_unattributed_matches_the_bell_number() {
2828 let dom = GroundDomain::Partition(
2830 partition_attr(Range::Unbounded, Range::Unbounded),
2831 domain_int_ground!(1..4),
2832 );
2833 assert_eq!(dom.length().unwrap(), 15);
2834 }
2835
2836 #[test]
2837 fn partition_length_fixed_num_parts_matches_stirling_second_kind() {
2838 let dom = GroundDomain::Partition(
2842 partition_attr(Range::Single(2), Range::Unbounded),
2843 domain_int_ground!(1..4),
2844 );
2845 assert_eq!(dom.length().unwrap(), stirling_second_kind(4, 2).unwrap());
2846 assert_eq!(dom.length().unwrap(), 7);
2847 }
2848
2849 #[test]
2850 fn partition_length_regular_fixed_block_size_matches_a_hand_computed_multinomial() {
2851 let mut attr = partition_attr(Range::Unbounded, Range::Single(3));
2853 attr.is_regular = true;
2854 let dom = GroundDomain::Partition(attr, domain_int_ground!(1..6));
2855 assert_eq!(dom.length().unwrap(), 10);
2856 }
2857
2858 #[test]
2859 fn partition_values_count_matches_length_and_every_value_is_a_valid_member() {
2860 let dom = GroundDomain::Partition(
2861 partition_attr(Range::Bounded(2, 3), Range::Unbounded),
2862 domain_int_ground!(1..4),
2863 );
2864 let values: Vec<Literal> = dom.values().unwrap().collect();
2865 assert_eq!(values.len() as u64, dom.length().unwrap());
2866 for value in &values {
2867 assert!(dom.contains(value).unwrap());
2868 }
2869 }
2870
2871 fn permutation_attr(num_moved: Range<i32>) -> PermutationAttr {
2872 PermutationAttr {
2873 representation: None,
2874 num_moved,
2875 }
2876 }
2877
2878 #[test]
2879 fn permutation_length_unattributed_matches_factorial() {
2880 let dom =
2882 GroundDomain::Permutation(permutation_attr(Range::Unbounded), domain_int_ground!(1..4));
2883 assert_eq!(dom.length().unwrap(), 24);
2884 }
2885
2886 #[test]
2887 fn permutation_length_fully_moved_matches_the_derangement_number() {
2888 let dom =
2890 GroundDomain::Permutation(permutation_attr(Range::Single(4)), domain_int_ground!(1..4));
2891 assert_eq!(dom.length().unwrap(), 9);
2892 }
2893
2894 #[test]
2895 fn permutation_values_count_matches_length_and_every_value_is_a_valid_member() {
2896 let dom = GroundDomain::Permutation(
2897 permutation_attr(Range::Bounded(1, 2)),
2898 domain_int_ground!(1..3),
2899 );
2900 let values: Vec<Literal> = dom.values().unwrap().collect();
2901 assert_eq!(values.len() as u64, dom.length().unwrap());
2902 for value in &values {
2903 assert!(dom.contains(value).unwrap());
2904 }
2905 }
2906}
2907
2908fn enum_indices<'a>(
2909 ty: &'a Moo<EnumeratedType>,
2910 ranges: &'a [Range<u32>],
2911) -> impl Iterator<Item = u32> + 'a {
2912 (0..ty.len() as u32)
2913 .filter(move |index| ranges.is_empty() || ranges.iter().any(|range| range.contains(index)))
2914}