1use crate::ast::domains::attrs::PartitionAttr;
2use crate::ast::domains::{MSetAttr, SequenceAttr};
3use crate::ast::pretty::pretty_vec;
4use crate::ast::{
5 AbstractLiteral, Domain, DomainOpError, FieldEntry, FuncAttr, HasDomain, Literal, Moo, RelAttr,
6 SetAttr, Typeable,
7 domains::{domain::Int, range::Range},
8};
9use crate::range;
10use crate::utils::count_combinations;
11use conjure_cp_core::ast::{Name, ReturnType};
12use itertools::{Itertools, izip};
13use num_traits::ToPrimitive;
14use polyquine::Quine;
15use serde::{Deserialize, Serialize};
16use std::collections::BTreeSet;
17use std::fmt::{Display, Formatter};
18use std::iter::zip;
19use uniplate::Uniplate;
20
21#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Uniplate, Quine)]
22#[path_prefix(conjure_cp::ast)]
23pub struct FieldEntryGround {
24 pub name: Name,
25 pub domain: Moo<GroundDomain>,
26}
27
28impl From<FieldEntryGround> for FieldEntry {
29 fn from(value: FieldEntryGround) -> Self {
30 FieldEntry {
31 name: value.name,
32 domain: value.domain.into(),
33 }
34 }
35}
36
37impl TryFrom<FieldEntry> for FieldEntryGround {
38 type Error = DomainOpError;
39
40 fn try_from(value: FieldEntry) -> Result<Self, Self::Error> {
41 match value.domain.as_ref() {
42 Domain::Ground(gd) => Ok(FieldEntryGround {
43 name: value.name,
44 domain: gd.clone(),
45 }),
46 Domain::Unresolved(_) => Err(DomainOpError::NotGround),
47 }
48 }
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
52#[path_prefix(conjure_cp::ast)]
53pub enum GroundDomain {
54 Empty(ReturnType),
56 Bool,
58 Int(Vec<Range<Int>>),
60 Set(SetAttr<Int>, Moo<GroundDomain>),
62 MSet(MSetAttr<Int>, Moo<GroundDomain>),
64 Matrix(Moo<GroundDomain>, Vec<Moo<GroundDomain>>),
67 Tuple(Vec<Moo<GroundDomain>>),
69 Record(Vec<FieldEntryGround>),
71 Partition(PartitionAttr, Moo<GroundDomain>),
73 Sequence(SequenceAttr, Moo<GroundDomain>),
75 Function(FuncAttr, Moo<GroundDomain>, Moo<GroundDomain>),
77 Relation(RelAttr, Vec<Moo<GroundDomain>>),
79 Variant(Vec<FieldEntryGround>),
81}
82
83impl GroundDomain {
84 pub fn union(&self, other: &GroundDomain) -> Result<GroundDomain, DomainOpError> {
85 match (self, other) {
86 (GroundDomain::Empty(ty), dom) | (dom, GroundDomain::Empty(ty)) => {
87 if *ty == dom.return_type() {
88 Ok(dom.clone())
89 } else {
90 Err(DomainOpError::WrongType)
91 }
92 }
93 (GroundDomain::Bool, GroundDomain::Bool) => Ok(GroundDomain::Bool),
94 (GroundDomain::Bool, _) | (_, GroundDomain::Bool) => Err(DomainOpError::WrongType),
95 (GroundDomain::Int(r1), GroundDomain::Int(r2)) => {
96 let mut rngs = r1.clone();
97 rngs.extend(r2.clone());
98 Ok(GroundDomain::Int(Range::squeeze(&rngs)))
99 }
100 (GroundDomain::Int(_), _) | (_, GroundDomain::Int(_)) => Err(DomainOpError::WrongType),
101 (GroundDomain::Set(_, in1), GroundDomain::Set(_, in2)) => Ok(GroundDomain::Set(
102 SetAttr::default(),
103 Moo::new(in1.union(in2)?),
104 )),
105 (GroundDomain::Set(_, _), _) | (_, GroundDomain::Set(_, _)) => {
106 Err(DomainOpError::WrongType)
107 }
108 (GroundDomain::MSet(_, in1), GroundDomain::MSet(_, in2)) => Ok(GroundDomain::MSet(
109 MSetAttr::default(),
110 Moo::new(in1.union(in2)?),
111 )),
112 (GroundDomain::Matrix(in1, idx1), GroundDomain::Matrix(in2, idx2)) if idx1 == idx2 => {
113 Ok(GroundDomain::Matrix(
114 Moo::new(in1.union(in2)?),
115 idx1.clone(),
116 ))
117 }
118 (GroundDomain::Matrix(_, _), _) | (_, GroundDomain::Matrix(_, _)) => {
119 Err(DomainOpError::WrongType)
120 }
121 (GroundDomain::Sequence(_, _), _) | (_, GroundDomain::Sequence(_, _)) => {
122 Err(DomainOpError::WrongType)
123 }
124 (GroundDomain::Tuple(in1s), GroundDomain::Tuple(in2s)) if in1s.len() == in2s.len() => {
125 let mut inners = Vec::new();
126 for (in1, in2) in zip(in1s, in2s) {
127 inners.push(Moo::new(in1.union(in2)?));
128 }
129 Ok(GroundDomain::Tuple(inners))
130 }
131 (GroundDomain::Tuple(_), _) | (_, GroundDomain::Tuple(_)) => {
132 Err(DomainOpError::WrongType)
133 }
134 #[allow(unreachable_patterns)]
136 (GroundDomain::Record(_), _) | (_, GroundDomain::Record(_)) => {
138 Err(DomainOpError::WrongType)
139 }
140 #[allow(unreachable_patterns)]
141 (GroundDomain::Variant(_), _) | (_, GroundDomain::Variant(_)) => {
143 Err(DomainOpError::WrongType)
144 }
145 #[allow(unreachable_patterns)]
146 (GroundDomain::Function(_, _, _), _) | (_, GroundDomain::Function(_, _, _)) => {
148 Err(DomainOpError::WrongType)
149 }
150 (GroundDomain::Relation(_, in1s), GroundDomain::Relation(_, in2s)) => {
151 let mut inners = Vec::new();
152 for (in1, in2) in zip(in1s, in2s) {
153 inners.push(Moo::new(in1.union(in2)?));
154 }
155 Ok(GroundDomain::Tuple(inners))
156 }
157 (GroundDomain::Relation(_, _), _) | (_, GroundDomain::Relation(_, _)) => {
158 Err(DomainOpError::WrongType)
159 }
160 #[allow(unreachable_patterns)]
161 (GroundDomain::Partition(_, _), _) | (_, GroundDomain::Partition(_, _)) => {
162 Err(DomainOpError::WrongType)
163 }
164 }
165 }
166
167 pub fn intersect(&self, other: &GroundDomain) -> Result<GroundDomain, DomainOpError> {
174 match (self, other) {
178 (d @ GroundDomain::Empty(ReturnType::Int), GroundDomain::Int(_)) => Ok(d.clone()),
180 (GroundDomain::Int(_), d @ GroundDomain::Empty(ReturnType::Int)) => Ok(d.clone()),
181 (GroundDomain::Empty(ReturnType::Int), d @ GroundDomain::Empty(ReturnType::Int)) => {
182 Ok(d.clone())
183 }
184
185 (GroundDomain::Set(_, inner1), d @ GroundDomain::Empty(ReturnType::Set(inner2)))
187 if matches!(
188 **inner1,
189 GroundDomain::Int(_) | GroundDomain::Empty(ReturnType::Int)
190 ) && matches!(**inner2, ReturnType::Int) =>
191 {
192 Ok(d.clone())
193 }
194 (d @ GroundDomain::Empty(ReturnType::Set(inner1)), GroundDomain::Set(_, inner2))
195 if matches!(**inner1, ReturnType::Int)
196 && matches!(
197 **inner2,
198 GroundDomain::Int(_) | GroundDomain::Empty(ReturnType::Int)
199 ) =>
200 {
201 Ok(d.clone())
202 }
203 (
204 d @ GroundDomain::Empty(ReturnType::Set(inner1)),
205 GroundDomain::Empty(ReturnType::Set(inner2)),
206 ) if matches!(**inner1, ReturnType::Int) && matches!(**inner2, ReturnType::Int) => {
207 Ok(d.clone())
208 }
209
210 (GroundDomain::Set(_, x), GroundDomain::Set(_, y)) => Ok(GroundDomain::Set(
212 SetAttr::default(),
213 Moo::new((*x).intersect(y)?),
214 )),
215
216 (GroundDomain::Int(_), GroundDomain::Int(_)) => {
217 let mut v: BTreeSet<i32> = BTreeSet::new();
218
219 let v1 = self.values_i32()?;
220 let v2 = other.values_i32()?;
221 for value1 in v1.iter() {
222 if v2.contains(value1) && !v.contains(value1) {
223 v.insert(*value1);
224 }
225 }
226 Ok(GroundDomain::from_set_i32(&v))
227 }
228 (GroundDomain::Relation(_, _), GroundDomain::Relation(_, _)) => {
229 todo!("Relation union not yet supported")
230 }
231 _ => Err(DomainOpError::WrongType),
232 }
233 }
234
235 pub fn values(&self) -> Result<Box<dyn Iterator<Item = Literal>>, DomainOpError> {
236 match self {
237 GroundDomain::Empty(_) => Ok(Box::new(vec![].into_iter())),
238 GroundDomain::Bool => Ok(Box::new(
239 vec![Literal::from(true), Literal::from(false)].into_iter(),
240 )),
241 GroundDomain::Int(rngs) => {
242 let rng_iters = rngs
243 .iter()
244 .map(Range::iter)
245 .collect::<Option<Vec<_>>>()
246 .ok_or(DomainOpError::Unbounded)?;
247 Ok(Box::new(
248 rng_iters.into_iter().flat_map(|ri| ri.map(Literal::from)),
249 ))
250 }
251 GroundDomain::Matrix(elem_domain, index_domains) => Ok(Box::new(
252 enumerate_matrix_values(elem_domain.as_ref(), index_domains)?.into_iter(),
253 )),
254 _ => todo!("Enumerating nested domains is not yet supported"),
255 }
256 }
257
258 pub fn length(&self) -> Result<u64, DomainOpError> {
264 match self {
265 GroundDomain::Empty(_) => Ok(0),
266 GroundDomain::Bool => Ok(2),
267 GroundDomain::Int(ranges) => {
268 if ranges.is_empty() {
269 return Err(DomainOpError::Unbounded);
270 }
271
272 let mut length = 0u64;
273 for range in ranges {
274 if let Some(range_length) = range.length() {
275 length += range_length as u64;
276 } else {
277 return Err(DomainOpError::Unbounded);
278 }
279 }
280 Ok(length)
281 }
282 GroundDomain::Set(set_attr, inner_domain) => {
283 let inner_len = inner_domain.length()?;
284 let (min_sz, max_sz) = match set_attr.size {
285 Range::Unbounded => (0, inner_len),
286 Range::Single(n) => (n as u64, n as u64),
287 Range::UnboundedR(n) => (n as u64, inner_len),
288 Range::UnboundedL(n) => (0, n as u64),
289 Range::Bounded(min, max) => (min as u64, max as u64),
290 };
291 let mut ans = 0u64;
292 for sz in min_sz..=max_sz {
293 let c = count_combinations(inner_len, sz)?;
294 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
295 }
296 Ok(ans)
297 }
298 GroundDomain::MSet(mset_attr, inner_domain) => {
299 let inner_len = inner_domain.length()?;
300 let (min_sz, max_sz) = match mset_attr.size {
301 Range::Unbounded => (0, inner_len),
302 Range::Single(n) => (n as u64, n as u64),
303 Range::UnboundedR(n) => (n as u64, inner_len),
304 Range::UnboundedL(n) => (0, n as u64),
305 Range::Bounded(min, max) => (min as u64, max as u64),
306 };
307 let mut ans = 0u64;
308 for sz in min_sz..=max_sz {
309 let c = count_combinations(inner_len + sz - 1, sz)?;
312 ans = ans.checked_add(c).ok_or(DomainOpError::TooLarge)?;
313 }
314 Ok(ans)
315 }
316 GroundDomain::Sequence(_, _) => {
317 todo!("Length bound currently not supported");
320 }
321 GroundDomain::Tuple(domains) => {
322 let mut ans = 1u64;
323 for domain in domains {
324 ans = ans
325 .checked_mul(domain.length()?)
326 .ok_or(DomainOpError::TooLarge)?;
327 }
328 Ok(ans)
329 }
330 GroundDomain::Record(entries) => {
331 let mut ans = 1u64;
333 for entry in entries {
334 let sz = entry.domain.length()?;
335 ans = ans.checked_mul(sz).ok_or(DomainOpError::TooLarge)?;
336 }
337 Ok(ans)
338 }
339 GroundDomain::Matrix(inner_domain, idx_domains) => {
340 let inner_sz = inner_domain.length()?;
341 let exp = idx_domains.iter().try_fold(1u32, |acc, val| {
342 let len = val.length()? as u32;
343 acc.checked_mul(len).ok_or(DomainOpError::TooLarge)
344 })?;
345 inner_sz.checked_pow(exp).ok_or(DomainOpError::TooLarge)
346 }
347 GroundDomain::Function(_, _, _) => {
348 todo!("Length bound of functions is not yet supported")
349 }
350 GroundDomain::Variant(entries) => {
351 let mut ans = 1u64;
352 for entry in entries {
353 let sz = entry.domain.length()?;
354 ans = ans.checked_add(sz).ok_or(DomainOpError::TooLarge)?;
356 }
357 Ok(ans)
358 }
359 GroundDomain::Relation(_, domains) => {
360 let dom_sizes_result: Result<Vec<u64>, DomainOpError> =
362 domains.iter().map(|x| x.length()).collect();
363 let dom_sizes = dom_sizes_result?;
364 Ok(dom_sizes.iter().product())
365 }
366 GroundDomain::Partition(_, _) => {
367 todo!("Length bound of Partitions is not yet supported")
368 }
369 }
370 }
371
372 pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
373 match self {
376 GroundDomain::Empty(_) => Ok(false),
378 GroundDomain::Bool => match lit {
379 Literal::Bool(_) => Ok(true),
380 _ => Ok(false),
381 },
382 GroundDomain::Int(ranges) => match lit {
383 Literal::Int(x) => {
384 if ranges.is_empty() {
386 return Ok(true);
387 };
388
389 Ok(ranges.iter().any(|range| range.contains(x)))
390 }
391 _ => Ok(false),
392 },
393 GroundDomain::Set(set_attr, inner_domain) => match lit {
394 Literal::AbstractLiteral(AbstractLiteral::Set(lit_elems)) => {
395 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
397 if !set_attr.size.contains(&sz) {
398 return Ok(false);
399 }
400
401 for elem in lit_elems {
402 if !inner_domain.contains(elem)? {
403 return Ok(false);
404 }
405 }
406 Ok(true)
407 }
408 _ => Ok(false),
409 },
410 GroundDomain::MSet(mset_attr, inner_domain) => match lit {
411 Literal::AbstractLiteral(AbstractLiteral::MSet(lit_elems)) => {
412 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
414 if !mset_attr.size.contains(&sz) {
415 return Ok(false);
416 }
417
418 for elem in lit_elems {
419 if !inner_domain.contains(elem)? {
420 return Ok(false);
421 }
422 }
423 Ok(true)
424 }
425 _ => Ok(false),
426 },
427 GroundDomain::Sequence(seq_attr, inner_dom) => match lit {
428 Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)) => {
429 let sz = elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
430 if !seq_attr.size.contains(&sz) {
431 return Ok(false);
432 }
433
434 for elem in elems {
435 if !inner_dom.contains(elem)? {
436 return Ok(false);
437 }
438 }
439 Ok(true)
440 }
441 _ => Ok(false),
442 },
443 GroundDomain::Matrix(elem_domain, index_domains) => {
444 match lit {
445 Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx_domain)) => {
446 let Some((current_index_domain, remaining_index_domains)) =
450 index_domains.split_first()
451 else {
452 panic!("a matrix should have at least one index domain");
453 };
454
455 if *current_index_domain != *idx_domain {
456 return Ok(false);
457 };
458
459 let next_elem_domain = if remaining_index_domains.is_empty() {
460 elem_domain.as_ref().clone()
463 } else {
464 GroundDomain::Matrix(
466 elem_domain.clone(),
467 remaining_index_domains.to_vec(),
468 )
469 };
470
471 for elem in elems {
472 if !next_elem_domain.contains(elem)? {
473 return Ok(false);
474 }
475 }
476
477 Ok(true)
478 }
479 _ => Ok(false),
480 }
481 }
482 GroundDomain::Tuple(elem_domains) => {
483 match lit {
484 Literal::AbstractLiteral(AbstractLiteral::Tuple(literal_elems)) => {
485 if elem_domains.len() != literal_elems.len() {
486 return Ok(false);
487 }
488
489 for (elem_domain, elem) in itertools::izip!(elem_domains, literal_elems) {
491 if !elem_domain.contains(elem)? {
492 return Ok(false);
493 }
494 }
495
496 Ok(true)
497 }
498 _ => Ok(false),
499 }
500 }
501 GroundDomain::Record(entries) => match lit {
502 Literal::AbstractLiteral(AbstractLiteral::Record(lit_entries)) => {
503 if entries.len() != lit_entries.len() {
504 return Ok(false);
505 }
506
507 for (entry, lit_entry) in itertools::izip!(entries, lit_entries) {
508 if entry.name != lit_entry.name
509 || !(entry.domain.contains(&lit_entry.value)?)
510 {
511 return Ok(false);
512 }
513 }
514 Ok(true)
515 }
516 _ => Ok(false),
517 },
518 GroundDomain::Function(func_attr, domain, codomain) => match lit {
519 Literal::AbstractLiteral(AbstractLiteral::Function(lit_elems)) => {
520 let sz = Int::try_from(lit_elems.len()).expect("Should convert");
521 if !func_attr.size.contains(&sz) {
522 return Ok(false);
523 }
524 for lit in lit_elems {
525 let domain_element = &lit.0;
526 let codomain_element = &lit.1;
527 if !domain.contains(domain_element)? {
528 return Ok(false);
529 }
530 if !codomain.contains(codomain_element)? {
531 return Ok(false);
532 }
533 }
534 Ok(true)
535 }
536 _ => Ok(false),
537 },
538 GroundDomain::Variant(entries) => match lit {
539 Literal::AbstractLiteral(AbstractLiteral::Variant(lit_entry)) => {
540 for entry in entries {
541 if entry.name == lit_entry.name
542 && !(entry.domain.contains(&lit_entry.value)?)
543 {
544 return Ok(true);
545 }
546 }
547 Ok(false)
548 }
549 _ => Ok(false),
550 },
551 GroundDomain::Relation(rel_attr, inner_domains) => match lit {
552 Literal::AbstractLiteral(AbstractLiteral::Relation(lit_elems)) => {
553 let sz = lit_elems.len().to_i32().ok_or(DomainOpError::TooLarge)?;
555 if !rel_attr.size.contains(&sz) {
556 return Ok(false);
557 }
558
559 for elem_tuple in lit_elems {
560 if elem_tuple.len() == inner_domains.len() {
561 for (elem, inner_dom) in elem_tuple.iter().zip(inner_domains.iter()) {
562 if !inner_dom.contains(elem)? {
563 return Ok(false);
564 }
565 }
566 } else {
567 return Ok(false);
568 }
569 }
570 Ok(true)
571 }
572 _ => Ok(false),
573 },
574 GroundDomain::Partition(attr, dom) => match lit {
575 Literal::AbstractLiteral(AbstractLiteral::Partition(lit_elems)) => {
576 let sz: i32 = lit_elems
578 .iter()
579 .flatten()
580 .count()
581 .to_i32()
582 .ok_or(DomainOpError::TooLarge)?;
583
584 let min: Option<i32> = match (attr.num_parts.low(), attr.part_len.low()) {
585 (Some(x), Some(y)) => Some(x * y),
586 _ => None,
587 };
588
589 let max: Option<i32> = match (attr.num_parts.high(), attr.part_len.high()) {
590 (Some(x), Some(y)) => Some(x * y),
591 _ => None,
592 };
593
594 let rng = Range::new(min, max);
595 if rng.contains(&sz) {
596 return Ok(false);
597 }
598
599 for elem in lit_elems.iter().flatten() {
600 if !dom.contains(elem)? {
601 return Ok(false);
602 }
603 }
604 Ok(true)
605 }
606 _ => Ok(false),
607 },
608 }
609 }
610
611 pub fn values_i32(&self) -> Result<Vec<i32>, DomainOpError> {
618 if let GroundDomain::Empty(ReturnType::Int) = self {
619 return Ok(vec![]);
620 }
621 let GroundDomain::Int(ranges) = self else {
622 return Err(DomainOpError::NotInteger(self.return_type()));
623 };
624
625 if ranges.is_empty() {
626 return Err(DomainOpError::Unbounded);
627 }
628
629 let mut values = vec![];
630 for range in ranges {
631 match range {
632 Range::Single(i) => {
633 values.push(*i);
634 }
635 Range::Bounded(i, j) => {
636 values.extend(*i..=*j);
637 }
638 Range::UnboundedR(_) | Range::UnboundedL(_) | Range::Unbounded => {
639 return Err(DomainOpError::Unbounded);
640 }
641 }
642 }
643
644 Ok(values)
645 }
646
647 pub fn from_set_i32(elements: &BTreeSet<i32>) -> GroundDomain {
686 if elements.is_empty() {
687 return GroundDomain::Empty(ReturnType::Int);
688 }
689 if elements.len() == 1 {
690 return GroundDomain::Int(vec![Range::Single(*elements.first().unwrap())]);
691 }
692
693 let mut elems_iter = elements.iter().copied();
694
695 let mut ranges: Vec<Range<i32>> = vec![];
696
697 let mut lower = elems_iter
702 .next()
703 .expect("if we get here, elements should have => 2 elements");
704 let mut upper = lower;
705
706 for current in elems_iter {
707 if current == upper + 1 {
710 upper = current;
713 } else {
714 if lower == upper {
719 ranges.push(range!(lower));
720 } else {
721 ranges.push(range!(lower..upper));
722 }
723
724 lower = current;
725 upper = current;
726 }
727 }
728
729 if lower == upper {
731 ranges.push(range!(lower));
732 } else {
733 ranges.push(range!(lower..upper));
734 }
735
736 ranges = Range::squeeze(&ranges);
737 GroundDomain::Int(ranges)
738 }
739
740 pub fn apply_i32(
750 &self,
751 op: fn(i32, i32) -> Option<i32>,
752 other: &GroundDomain,
753 ) -> Result<GroundDomain, DomainOpError> {
754 let vs1 = self.values_i32()?;
755 let vs2 = other.values_i32()?;
756
757 let mut set = BTreeSet::new();
758 for (v1, v2) in itertools::iproduct!(vs1, vs2) {
759 if let Some(v) = op(v1, v2) {
760 set.insert(v);
761 }
762 }
763
764 Ok(GroundDomain::from_set_i32(&set))
765 }
766
767 pub fn is_finite(&self) -> bool {
769 for domain in self.universe() {
770 if let GroundDomain::Int(ranges) = domain {
771 if ranges.is_empty() {
772 return false;
773 }
774
775 if ranges.iter().any(|range| {
776 matches!(
777 range,
778 Range::UnboundedL(_) | Range::UnboundedR(_) | Range::Unbounded
779 )
780 }) {
781 return false;
782 }
783 }
784 }
785 true
786 }
787
788 pub fn from_literal_vec(literals: &[Literal]) -> Result<GroundDomain, DomainOpError> {
869 if literals.is_empty() {
872 return Ok(GroundDomain::Empty(ReturnType::Unknown));
873 }
874
875 let first_literal = literals.first().unwrap();
876
877 match first_literal {
878 Literal::Int(_) => {
879 let mut ints = BTreeSet::new();
881 for lit in literals {
882 let Literal::Int(i) = lit else {
883 return Err(DomainOpError::WrongType);
884 };
885
886 ints.insert(*i);
887 }
888
889 Ok(GroundDomain::from_set_i32(&ints))
890 }
891 Literal::Bool(_) => {
892 if literals.iter().any(|x| !matches!(x, Literal::Bool(_))) {
894 Err(DomainOpError::WrongType)
895 } else {
896 Ok(GroundDomain::Bool)
897 }
898 }
899 Literal::AbstractLiteral(AbstractLiteral::Set(_)) => {
900 let mut all_elems = vec![];
901
902 for lit in literals {
903 let Literal::AbstractLiteral(AbstractLiteral::Set(elems)) = lit else {
904 return Err(DomainOpError::WrongType);
905 };
906
907 all_elems.extend(elems.clone());
908 }
909 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
910
911 Ok(GroundDomain::Set(SetAttr::default(), Moo::new(elem_domain)))
912 }
913 Literal::AbstractLiteral(AbstractLiteral::MSet(_)) => {
914 let mut all_elems = vec![];
915
916 for lit in literals {
917 let Literal::AbstractLiteral(AbstractLiteral::MSet(elems)) = lit else {
918 return Err(DomainOpError::WrongType);
919 };
920
921 all_elems.extend(elems.clone());
922 }
923 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
924
925 Ok(GroundDomain::MSet(
926 MSetAttr::default(),
927 Moo::new(elem_domain),
928 ))
929 }
930 Literal::AbstractLiteral(AbstractLiteral::Partition(_)) => {
931 todo!("Need to figure out how this is going to work")
932 }
933 l @ Literal::AbstractLiteral(AbstractLiteral::Matrix(_, _)) => {
934 let mut first_index_domain = vec![];
935 let mut l = l.clone();
937 while let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = l {
938 assert!(
939 !matches!(idx.as_ref(), GroundDomain::Matrix(_, _)),
940 "n-dimensional matrix literals should be represented as a matrix inside a matrix"
941 );
942 first_index_domain.push(idx);
943 l = elems[0].clone();
944 }
945
946 let mut all_elems: Vec<Literal> = vec![];
947
948 for lit in literals {
950 let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = lit else {
951 return Err(DomainOpError::NotGround);
952 };
953
954 all_elems.extend(elems.clone());
955
956 let mut index_domain = vec![idx.clone()];
957 let mut l = elems[0].clone();
958 while let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, idx)) = l {
959 assert!(
960 !matches!(idx.as_ref(), GroundDomain::Matrix(_, _)),
961 "n-dimensional matrix literals should be represented as a matrix inside a matrix"
962 );
963 index_domain.push(idx);
964 l = elems[0].clone();
965 }
966
967 if index_domain != first_index_domain {
968 return Err(DomainOpError::WrongType);
969 }
970 }
971
972 let mut terminal_elements: Vec<Literal> = vec![];
974 while let Some(elem) = all_elems.pop() {
975 if let Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, _)) = elem {
976 all_elems.extend(elems);
977 } else {
978 terminal_elements.push(elem);
979 }
980 }
981
982 let element_domain = GroundDomain::from_literal_vec(&terminal_elements)?;
983
984 Ok(GroundDomain::Matrix(
985 Moo::new(element_domain),
986 first_index_domain,
987 ))
988 }
989
990 Literal::AbstractLiteral(AbstractLiteral::Tuple(first_elems)) => {
991 let n_fields = first_elems.len();
992
993 let mut elem_domains = vec![];
995
996 for i in 0..n_fields {
997 let mut all_elems = vec![];
998 for lit in literals {
999 let Literal::AbstractLiteral(AbstractLiteral::Tuple(elems)) = lit else {
1000 return Err(DomainOpError::NotGround);
1001 };
1002
1003 if elems.len() != n_fields {
1004 return Err(DomainOpError::NotGround);
1005 }
1006
1007 all_elems.push(elems[i].clone());
1008 }
1009
1010 elem_domains.push(Moo::new(GroundDomain::from_literal_vec(&all_elems)?));
1011 }
1012
1013 Ok(GroundDomain::Tuple(elem_domains))
1014 }
1015
1016 Literal::AbstractLiteral(AbstractLiteral::Sequence(_)) => {
1017 let mut all_elems = vec![];
1018
1019 for lit in literals {
1020 let Literal::AbstractLiteral(AbstractLiteral::Sequence(elems)) = lit else {
1021 return Err(DomainOpError::WrongType);
1022 };
1023
1024 all_elems.extend(elems.clone());
1025 }
1026 let elem_domain = GroundDomain::from_literal_vec(&all_elems)?;
1027
1028 Ok(GroundDomain::Sequence(
1029 SequenceAttr::default(),
1030 Moo::new(elem_domain),
1031 ))
1032 }
1033
1034 Literal::AbstractLiteral(AbstractLiteral::Record(first_elems)) => {
1035 let n_fields = first_elems.len();
1036 let field_names = first_elems.iter().map(|x| x.name.clone()).collect_vec();
1037
1038 let mut elem_domains = vec![];
1040
1041 for i in 0..n_fields {
1042 let mut all_elems = vec![];
1043 for lit in literals {
1044 let Literal::AbstractLiteral(AbstractLiteral::Record(elems)) = lit else {
1045 return Err(DomainOpError::NotGround);
1046 };
1047
1048 if elems.len() != n_fields {
1049 return Err(DomainOpError::NotGround);
1050 }
1051
1052 let elem = elems[i].clone();
1053 if elem.name != field_names[i] {
1054 return Err(DomainOpError::NotGround);
1055 }
1056
1057 all_elems.push(elem.value);
1058 }
1059
1060 elem_domains.push(Moo::new(GroundDomain::from_literal_vec(&all_elems)?));
1061 }
1062
1063 Ok(GroundDomain::Record(
1064 izip!(field_names, elem_domains)
1065 .map(|(name, domain)| FieldEntryGround { name, domain })
1066 .collect(),
1067 ))
1068 }
1069 Literal::AbstractLiteral(AbstractLiteral::Function(items)) => {
1070 if items.is_empty() {
1071 return Err(DomainOpError::NotGround);
1072 }
1073
1074 let (x1, y1) = &items[0];
1075 let d1 = x1.domain_of();
1076 let d1 = d1.as_ground().ok_or(DomainOpError::NotGround)?;
1077 let d2 = y1.domain_of();
1078 let d2 = d2.as_ground().ok_or(DomainOpError::NotGround)?;
1079
1080 for (x, y) in items {
1082 let dx = x.domain_of();
1083 let dx = dx.as_ground().ok_or(DomainOpError::NotGround)?;
1084
1085 let dy = y.domain_of();
1086 let dy = dy.as_ground().ok_or(DomainOpError::NotGround)?;
1087
1088 if (dx != d1) || (dy != d2) {
1089 return Err(DomainOpError::WrongType);
1090 }
1091 }
1092
1093 todo!();
1094 }
1095 Literal::AbstractLiteral(AbstractLiteral::Variant(_)) => {
1096 todo!();
1097 }
1098 Literal::AbstractLiteral(AbstractLiteral::Relation(_)) => {
1099 todo!();
1100 }
1101 }
1102 }
1103
1104 pub fn element_domain(&self) -> Option<Moo<GroundDomain>> {
1105 match self {
1106 GroundDomain::Set(_, inner) => Some(inner.clone()),
1107 GroundDomain::MSet(_, inner) => Some(inner.clone()),
1108 GroundDomain::Matrix(_, _) => todo!("Unwrap one dimension of the domain"),
1109 _ => None,
1110 }
1111 }
1112}
1113
1114impl Typeable for GroundDomain {
1115 fn return_type(&self) -> ReturnType {
1116 match self {
1117 GroundDomain::Empty(ty) => ty.clone(),
1118 GroundDomain::Bool => ReturnType::Bool,
1119 GroundDomain::Int(_) => ReturnType::Int,
1120 GroundDomain::Set(_attr, inner) => ReturnType::Set(Box::new(inner.return_type())),
1121 GroundDomain::MSet(_attr, inner) => ReturnType::MSet(Box::new(inner.return_type())),
1122 GroundDomain::Sequence(_attr, inner) => {
1123 ReturnType::Sequence(Box::new(inner.return_type()))
1124 }
1125 GroundDomain::Matrix(inner, _idx) => ReturnType::Matrix(Box::new(inner.return_type())),
1126 GroundDomain::Tuple(inners) => {
1127 let mut inner_types = Vec::new();
1128 for inner in inners {
1129 inner_types.push(inner.return_type());
1130 }
1131 ReturnType::Tuple(inner_types)
1132 }
1133 GroundDomain::Record(entries) => {
1134 let mut entry_types = Vec::new();
1135 for entry in entries {
1136 entry_types.push(entry.domain.return_type());
1137 }
1138 ReturnType::Record(entry_types)
1139 }
1140 GroundDomain::Function(_, dom, cdom) => {
1141 ReturnType::Function(Box::new(dom.return_type()), Box::new(cdom.return_type()))
1142 }
1143 GroundDomain::Variant(entries) => {
1144 let mut entry_types = Vec::new();
1145 for entry in entries {
1146 entry_types.push(entry.domain.return_type());
1147 }
1148 ReturnType::Record(entry_types)
1149 }
1150 GroundDomain::Relation(_, inners) => {
1151 let mut inner_types = Vec::new();
1152 for inner in inners {
1153 inner_types.push(inner.return_type());
1154 }
1155 ReturnType::Relation(inner_types)
1156 }
1157 GroundDomain::Partition(_, inner) => ReturnType::Set(Box::new(inner.return_type())),
1158 }
1159 }
1160}
1161
1162impl Display for GroundDomain {
1163 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1164 match &self {
1165 GroundDomain::Empty(ty) => write!(f, "empty({ty})"),
1166 GroundDomain::Bool => write!(f, "bool"),
1167 GroundDomain::Int(ranges) => {
1168 if ranges.iter().all(Range::is_lower_or_upper_bounded) {
1169 let rngs: String = ranges.iter().map(|r| format!("{r}")).join(", ");
1170 write!(f, "int({})", rngs)
1171 } else {
1172 write!(f, "int")
1173 }
1174 }
1175 GroundDomain::Set(attrs, inner_dom) => write!(f, "set {attrs} of {inner_dom}"),
1176 GroundDomain::MSet(attrs, inner_dom) => write!(f, "mset {attrs} of {inner_dom}"),
1177 GroundDomain::Sequence(attrs, inner_dom) => {
1178 write!(f, "sequence {attrs} of {inner_dom}")
1179 }
1180 GroundDomain::Matrix(value_domain, index_domains) => {
1181 write!(
1182 f,
1183 "matrix indexed by {} of {value_domain}",
1184 pretty_vec(&index_domains.iter().collect_vec())
1185 )
1186 }
1187 GroundDomain::Tuple(domains) => {
1188 write!(f, "tuple ({})", &domains.iter().join(", "))
1189 }
1190 GroundDomain::Record(entries) => {
1191 write!(
1192 f,
1193 "record {{{}}}",
1194 entries
1195 .iter()
1196 .map(|entry| format!("{}: {}", entry.name, entry.domain))
1197 .join(", ")
1198 )
1199 }
1200 GroundDomain::Function(attribute, domain, codomain) => {
1201 write!(f, "function {} {} --> {} ", attribute, domain, codomain)
1202 }
1203 GroundDomain::Variant(entries) => {
1204 write!(
1205 f,
1206 "variant {{{}}}",
1207 entries
1208 .iter()
1209 .map(|entry| format!("{}: {}", entry.name, entry.domain))
1210 .join(", ")
1211 )
1212 }
1213 GroundDomain::Relation(attrs, domains) => {
1214 write!(f, "relation {} of ({})", attrs, domains.iter().join(" * "))
1215 }
1216 GroundDomain::Partition(attrs, inner) => {
1217 write!(f, "partition {attrs} from {inner}")
1218 }
1219 }
1220 }
1221}
1222
1223fn enumerate_matrix_values(
1224 elem_domain: &GroundDomain,
1225 index_domains: &[Moo<GroundDomain>],
1226) -> Result<Vec<Literal>, DomainOpError> {
1227 let Some((current_index_domain, remaining_index_domains)) = index_domains.split_first() else {
1228 panic!("a matrix should have at least one index domain");
1229 };
1230
1231 let current_dimension_len =
1232 usize::try_from(current_index_domain.length()?).map_err(|_| DomainOpError::TooLarge)?;
1233
1234 let entry_values = if remaining_index_domains.is_empty() {
1235 elem_domain.values()?.collect_vec()
1236 } else {
1237 enumerate_matrix_values(elem_domain, remaining_index_domains)?
1238 };
1239
1240 Ok((0..current_dimension_len)
1241 .map(|_| entry_values.iter().cloned())
1242 .multi_cartesian_product()
1243 .map(|elems| {
1244 Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, current_index_domain.clone()))
1245 })
1246 .collect())
1247}