1use crate::ast::domains::unresolved::EnumVariantVal;
2use crate::ast::domains::{
3 attrs::{MSetAttr, PartitionAttr, PermutationAttr, SetAttr},
4 ground::{FieldGround, GroundDomain},
5 int_val::IntVal,
6 range::Range,
7 unresolved::{FieldUnresolved, UnresolvedDomain},
8};
9use crate::ast::enumerated::EnumeratedType;
10use crate::ast::{
11 DeclarationPtr, DomainOpError, Expression, Field, FuncAttr, Literal, Moo, Reference, RelAttr,
12 ReturnType, SequenceAttr, Typeable,
13};
14use itertools::Itertools;
15use polyquine::Quine;
16use serde::{Deserialize, Serialize};
17use std::fmt::{Display, Formatter};
18use std::thread_local;
19use uniplate::Uniplate;
20
21pub type Int = i32;
23
24pub const OXIDE_INT_MIN: Int = Int::MIN + 1;
29
30pub const OXIDE_INT_MAX: Int = Int::MAX;
32
33pub type DomainPtr = Moo<Domain>;
34
35impl DomainPtr {
36 pub fn with_representation_preference(&self, representation: &str) -> DomainPtr {
40 let mut domain = self.clone();
41 Moo::make_mut(&mut domain).set_representation_preference(representation);
42 domain
43 }
44
45 pub fn resolve(&self) -> Result<Moo<GroundDomain>, DomainOpError> {
46 self.as_ref().resolve()
47 }
48
49 pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
52 self.as_ref().union(other.as_ref()).map(DomainPtr::new)
53 }
54
55 pub fn intersect(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
58 self.as_ref().intersect(other.as_ref()).map(DomainPtr::new)
59 }
60}
61
62#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
63#[biplate(to=DomainPtr)]
64#[biplate(to=GroundDomain)]
65#[biplate(to=UnresolvedDomain)]
66#[biplate(to=Expression)]
67#[biplate(to=Reference)]
68#[biplate(to=IntVal)]
69#[path_prefix(conjure_cp::ast)]
70pub enum Domain {
72 Ground(Moo<GroundDomain>),
74 Unresolved(Moo<UnresolvedDomain>),
76}
77
78pub trait HasDomain {
80 fn domain_of(&self) -> DomainPtr;
82}
83
84impl<T: HasDomain> Typeable for T {
85 fn return_type(&self) -> ReturnType {
86 self.domain_of().return_type()
87 }
88}
89
90thread_local! {
93 static BOOL_DOMAIN: DomainPtr =
94 Moo::new(Domain::Ground(Moo::new(GroundDomain::Bool)));
95}
96
97impl Domain {
98 pub fn bool() -> DomainPtr {
101 BOOL_DOMAIN.with(Clone::clone)
102 }
103
104 pub fn empty(ty: ReturnType) -> DomainPtr {
107 Moo::new(Domain::Ground(Moo::new(GroundDomain::Empty(ty))))
108 }
109
110 pub fn int<T>(ranges: Vec<T>) -> DomainPtr
114 where
115 T: Into<Range<IntVal>> + TryInto<Range<Int>> + Clone,
116 {
117 if let Ok(int_rngs) = ranges
118 .iter()
119 .cloned()
120 .map(TryInto::try_into)
121 .collect::<Result<Vec<_>, _>>()
122 {
123 return Domain::int_ground(int_rngs);
124 }
125 let unresolved_rngs: Vec<Range<IntVal>> = ranges.into_iter().map(Into::into).collect();
126 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Int(
127 unresolved_rngs,
128 None,
129 ))))
130 }
131
132 pub fn int_from_values(values: Expression) -> DomainPtr {
137 if let Some(ranges) = int_ranges_from_constant_collection(&values) {
141 return Domain::int_ground(ranges);
142 }
143
144 Moo::new(Domain::Unresolved(Moo::new(
145 UnresolvedDomain::IntFromValues(Moo::new(values)),
146 )))
147 }
148
149 pub fn int_ground(ranges: Vec<Range<Int>>) -> DomainPtr {
151 let rngs = Range::squeeze(&ranges);
152 Moo::new(Domain::Ground(Moo::new(GroundDomain::Int(rngs, None))))
153 }
154
155 pub fn set<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
159 where
160 T: Into<SetAttr<IntVal>> + TryInto<SetAttr<Int>> + Clone,
161 {
162 if let Domain::Ground(gd) = inner_dom.as_ref()
163 && let Ok(int_attr) = attr.clone().try_into()
164 {
165 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Set(
166 int_attr,
167 gd.clone(),
168 ))));
169 }
170 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Set(
171 attr.into(),
172 inner_dom,
173 ))))
174 }
175
176 pub fn mset<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
178 where
179 T: Into<MSetAttr<IntVal>> + TryInto<MSetAttr<Int>> + Clone,
180 {
181 if let Domain::Ground(gd) = inner_dom.as_ref()
182 && let Ok(int_attr) = attr.clone().try_into()
183 {
184 return Moo::new(Domain::Ground(Moo::new(GroundDomain::MSet(
185 int_attr,
186 gd.clone(),
187 ))));
188 }
189 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(
190 attr.into(),
191 inner_dom,
192 ))))
193 }
194
195 pub fn matrix(inner_dom: DomainPtr, idx_doms: Vec<DomainPtr>) -> DomainPtr {
199 if let Domain::Ground(gd) = inner_dom.as_ref()
200 && let Some(idx_gds) = as_grounds(&idx_doms)
201 {
202 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Matrix(
203 gd.clone(),
204 idx_gds,
205 None,
206 ))));
207 }
208 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
209 inner_dom, idx_doms, None,
210 ))))
211 }
212
213 pub fn tuple(inner_doms: Vec<DomainPtr>) -> DomainPtr {
217 if let Some(inner_gds) = as_grounds(&inner_doms) {
218 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Tuple(
219 inner_gds, None,
220 ))));
221 }
222 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
223 inner_doms, None,
224 ))))
225 }
226
227 pub fn record(entries: Vec<Field<DomainPtr>>) -> DomainPtr {
231 if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
232 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Record(
233 entries_gds,
234 None,
235 ))));
236 }
237 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
238 entries, None,
239 ))))
240 }
241
242 pub fn reference(ptr: DeclarationPtr) -> Option<DomainPtr> {
244 let _ = ptr.as_domain_letting()?;
245 Some(Moo::new(Domain::Unresolved(Moo::new(
246 UnresolvedDomain::Reference(Reference::new(ptr)),
247 ))))
248 }
249
250 pub fn partition<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
252 where
253 T: Into<PartitionAttr<IntVal>> + TryInto<PartitionAttr<Int>> + Clone,
254 {
255 if let Domain::Ground(gd) = inner_dom.as_ref()
256 && let Ok(int_attr) = attr.clone().try_into()
257 {
258 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Partition(
259 int_attr,
260 gd.clone(),
261 ))));
262 }
263 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(
264 attr.into(),
265 inner_dom,
266 ))))
267 }
268
269 pub fn permutation<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
271 where
272 T: Into<PermutationAttr<IntVal>> + TryInto<PermutationAttr<Int>> + Clone,
273 {
274 if let Domain::Ground(gd) = inner_dom.as_ref()
275 && let Ok(int_attr) = attr.clone().try_into()
276 {
277 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Permutation(
278 int_attr,
279 gd.clone(),
280 ))));
281 }
282 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Permutation(
283 attr.into(),
284 inner_dom,
285 ))))
286 }
287
288 pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
290 where
291 T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
292 {
293 if let Ok(attrs_gd) = attrs.clone().try_into()
294 && let Some(dom_gd) = dom.as_ground()
295 && let Some(cdom_gd) = cdom.as_ground()
296 {
297 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
298 attrs_gd,
299 Moo::new(dom_gd.clone()),
300 Moo::new(cdom_gd.clone()),
301 ))));
302 }
303
304 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
305 attrs.into(),
306 dom,
307 cdom,
308 ))))
309 }
310
311 pub fn variant(entries: Vec<Field<DomainPtr>>) -> DomainPtr {
315 if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
316 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Variant(
317 entries_gds,
318 None,
319 ))));
320 }
321 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(
322 entries, None,
323 ))))
324 }
325
326 pub fn relation<T>(attrs: T, inner_doms: Vec<DomainPtr>) -> DomainPtr
330 where
331 T: Into<RelAttr<IntVal>> + TryInto<RelAttr<Int>> + Clone,
332 {
333 if let Ok(attrs_gd) = attrs.clone().try_into()
334 && let Some(doms_gd) = as_grounds(&inner_doms)
335 {
336 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Relation(
337 attrs_gd, doms_gd,
338 ))));
339 }
340
341 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
342 attrs.into(),
343 inner_doms,
344 ))))
345 }
346
347 pub fn sequence<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
349 where
350 T: Into<SequenceAttr<IntVal>> + TryInto<SequenceAttr<Int>> + Clone,
351 {
352 if let Domain::Ground(gd) = inner_dom.as_ref()
353 && let Ok(int_attr) = attr.clone().try_into()
354 {
355 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Sequence(
356 int_attr,
357 gd.clone(),
358 ))));
359 }
360 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
361 attr.into(),
362 inner_dom,
363 ))))
364 }
365
366 pub fn enumerated_ground(ty: Moo<EnumeratedType>, ranges: Vec<Range<u32>>) -> DomainPtr {
368 Moo::new(Domain::Ground(Moo::new(GroundDomain::EnumeratedType(
369 ty, ranges,
370 ))))
371 }
372
373 pub fn enumerated(ty: Moo<EnumeratedType>, ranges: Vec<Range<EnumVariantVal>>) -> DomainPtr {
375 Moo::new(Domain::Unresolved(Moo::new(
376 UnresolvedDomain::EnumeratedType(ty, ranges),
377 )))
378 }
379
380 pub fn resolve(&self) -> Result<Moo<GroundDomain>, DomainOpError> {
385 match self {
386 Domain::Ground(gd) => Ok(gd.clone()),
387 Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
388 }
389 }
390
391 pub fn as_ground(&self) -> Option<&GroundDomain> {
395 match self {
396 Domain::Ground(gd) => Some(gd.as_ref()),
397 _ => None,
398 }
399 }
400
401 pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
404 match self {
405 Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
406 _ => None,
407 }
408 }
409
410 pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
412 match self {
413 Domain::Unresolved(ud) => Some(ud.as_ref()),
414 _ => None,
415 }
416 }
417
418 pub fn as_unresolved_mut(&mut self) -> Option<&mut UnresolvedDomain> {
420 match self {
421 Domain::Unresolved(ud) => Some(Moo::<UnresolvedDomain>::make_mut(ud)),
422 _ => None,
423 }
424 }
425
426 pub fn as_dom_empty(&self) -> Option<&ReturnType> {
428 if let Some(GroundDomain::Empty(ty)) = self.as_ground() {
429 return Some(ty);
430 }
431 None
432 }
433
434 pub fn as_dom_empty_mut(&mut self) -> Option<&mut ReturnType> {
436 if let Some(GroundDomain::Empty(ty)) = self.as_ground_mut() {
437 return Some(ty);
438 }
439 None
440 }
441
442 pub fn is_bool(&self) -> bool {
444 self.return_type() == ReturnType::Bool
445 }
446
447 pub fn is_int(&self) -> bool {
449 self.return_type() == ReturnType::Int
450 }
451
452 pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
455 if let Some(GroundDomain::Int(rngs, _)) = self.as_ground() {
456 return Some(rngs.iter().cloned().map(|r| r.into()).collect());
457 }
458 if let Some(UnresolvedDomain::Int(rngs, _)) = self.as_unresolved() {
459 return Some(rngs.clone());
460 }
461 None
462 }
463
464 pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
467 if let Some(GroundDomain::Int(rngs_gds, representation)) = self.as_ground() {
473 let rngs: Vec<Range<IntVal>> = rngs_gds.iter().cloned().map(|r| r.into()).collect();
474 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Int(
475 rngs,
476 representation.clone(),
477 )))
478 }
479
480 if let Some(UnresolvedDomain::Int(rngs, _)) = self.as_unresolved_mut() {
481 return Some(rngs);
482 }
483 None
484 }
485
486 pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
488 if let Some(GroundDomain::Int(rngs, _)) = self.as_ground() {
489 return Some(rngs);
490 }
491 None
492 }
493
494 pub fn as_int_ground_mut(&mut self) -> Option<&mut Vec<Range<Int>>> {
496 if let Some(GroundDomain::Int(rngs, _)) = self.as_ground_mut() {
497 return Some(rngs);
498 }
499 None
500 }
501
502 pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
505 if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds, _)) = self.as_ground() {
506 let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
507 let inner_dom: DomainPtr = inner_dom_gd.clone().into();
508 return Some((inner_dom, idx_doms));
509 }
510 if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms, _)) = self.as_unresolved() {
511 return Some((inner_dom.clone(), idx_doms.clone()));
512 }
513 None
514 }
515
516 pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
520 if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds, representation)) =
523 self.as_ground()
524 {
525 let inner_dom: DomainPtr = inner_dom_gd.clone().into();
526 let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
527 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
528 inner_dom,
529 idx_doms,
530 representation.clone(),
531 )));
532 }
533
534 if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms, _)) = self.as_unresolved_mut() {
535 return Some((inner_dom, idx_doms));
536 }
537 None
538 }
539
540 pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
542 if let Some(GroundDomain::Matrix(inner_dom, idx_doms, _)) = self.as_ground() {
543 return Some((inner_dom, idx_doms));
544 }
545 None
546 }
547
548 pub fn as_matrix_ground_mut(
550 &mut self,
551 ) -> Option<(&mut Moo<GroundDomain>, &mut Vec<Moo<GroundDomain>>)> {
552 if let Some(GroundDomain::Matrix(inner_dom, idx_doms, _)) = self.as_ground_mut() {
553 return Some((inner_dom, idx_doms));
554 }
555 None
556 }
557
558 pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
560 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
561 return Some((attr.clone().into(), inner_dom.clone().into()));
562 }
563 if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
564 return Some((attr.clone(), inner_dom.clone()));
565 }
566 None
567 }
568
569 pub fn as_set_mut(&mut self) -> Option<(&mut SetAttr<IntVal>, &mut DomainPtr)> {
572 if let Some(GroundDomain::Set(attr_gd, inner_dom_gd)) = self.as_ground() {
573 let attr: SetAttr<IntVal> = attr_gd.clone().into();
574 let inner_dom = inner_dom_gd.clone().into();
575 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Set(attr, inner_dom)));
576 }
577
578 if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved_mut() {
579 return Some((attr, inner_dom));
580 }
581 None
582 }
583
584 pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
586 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
587 return Some((attr, inner_dom));
588 }
589 None
590 }
591
592 pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
594 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
595 return Some((attr, inner_dom));
596 }
597 None
598 }
599
600 pub fn representation_preference(&self) -> Option<&str> {
607 match self {
608 Domain::Ground(gd) => match gd.as_ref() {
609 GroundDomain::Int(_, representation)
610 | GroundDomain::Tuple(_, representation)
611 | GroundDomain::Record(_, representation)
612 | GroundDomain::Variant(_, representation)
613 | GroundDomain::Matrix(_, _, representation) => representation.as_deref(),
614 GroundDomain::Set(attr, _) => attr.representation.as_deref(),
615 GroundDomain::MSet(attr, _) => attr.representation.as_deref(),
616 GroundDomain::Sequence(attr, _) => attr.representation.as_deref(),
617 GroundDomain::Function(attr, _, _) => attr.representation.as_deref(),
618 GroundDomain::Relation(attr, _) => attr.representation.as_deref(),
619 GroundDomain::Partition(attr, _) => attr.representation.as_deref(),
620 GroundDomain::Permutation(attr, _) => attr.representation.as_deref(),
621 GroundDomain::Empty(_)
622 | GroundDomain::Bool
623 | GroundDomain::EnumeratedType(_, _)
624 | GroundDomain::UnnamedType(_) => None,
625 },
626 Domain::Unresolved(ud) => match ud.as_ref() {
627 UnresolvedDomain::Int(_, representation)
628 | UnresolvedDomain::Tuple(_, representation)
629 | UnresolvedDomain::Record(_, representation)
630 | UnresolvedDomain::Variant(_, representation)
631 | UnresolvedDomain::Matrix(_, _, representation) => representation.as_deref(),
632 UnresolvedDomain::Set(attr, _) => attr.representation.as_deref(),
633 UnresolvedDomain::MSet(attr, _) => attr.representation.as_deref(),
634 UnresolvedDomain::Sequence(attr, _) => attr.representation.as_deref(),
635 UnresolvedDomain::Function(attr, _, _) => attr.representation.as_deref(),
636 UnresolvedDomain::Relation(attr, _) => attr.representation.as_deref(),
637 UnresolvedDomain::Partition(attr, _) => attr.representation.as_deref(),
638 UnresolvedDomain::Permutation(attr, _) => attr.representation.as_deref(),
639 UnresolvedDomain::IntFromValues(_)
640 | UnresolvedDomain::Reference(_)
641 | UnresolvedDomain::EnumeratedType(_, _)
642 | UnresolvedDomain::UnnamedType(_) => None,
643 },
644 }
645 }
646
647 pub fn set_representation_preference(&mut self, representation: &str) {
649 let representation = Some(representation.to_owned());
650 match self {
651 Domain::Ground(gd) => match Moo::make_mut(gd) {
652 GroundDomain::Int(_, preference)
653 | GroundDomain::Tuple(_, preference)
654 | GroundDomain::Record(_, preference)
655 | GroundDomain::Variant(_, preference)
656 | GroundDomain::Matrix(_, _, preference) => *preference = representation,
657 GroundDomain::Set(attr, _) => attr.representation = representation,
658 GroundDomain::MSet(attr, _) => attr.representation = representation,
659 GroundDomain::Sequence(attr, _) => attr.representation = representation,
660 GroundDomain::Function(attr, _, _) => attr.representation = representation,
661 GroundDomain::Relation(attr, _) => attr.representation = representation,
662 GroundDomain::Partition(attr, _) => attr.representation = representation,
663 GroundDomain::Permutation(attr, _) => attr.representation = representation,
664 GroundDomain::Empty(_)
665 | GroundDomain::Bool
666 | GroundDomain::EnumeratedType(_, _)
667 | GroundDomain::UnnamedType(_) => {}
668 },
669 Domain::Unresolved(ud) => match Moo::make_mut(ud) {
670 UnresolvedDomain::Int(_, preference)
671 | UnresolvedDomain::Tuple(_, preference)
672 | UnresolvedDomain::Record(_, preference)
673 | UnresolvedDomain::Variant(_, preference)
674 | UnresolvedDomain::Matrix(_, _, preference) => *preference = representation,
675 UnresolvedDomain::Set(attr, _) => attr.representation = representation,
676 UnresolvedDomain::MSet(attr, _) => attr.representation = representation,
677 UnresolvedDomain::Sequence(attr, _) => attr.representation = representation,
678 UnresolvedDomain::Function(attr, _, _) => attr.representation = representation,
679 UnresolvedDomain::Relation(attr, _) => attr.representation = representation,
680 UnresolvedDomain::Partition(attr, _) => attr.representation = representation,
681 UnresolvedDomain::Permutation(attr, _) => attr.representation = representation,
682 UnresolvedDomain::IntFromValues(_)
683 | UnresolvedDomain::Reference(_)
684 | UnresolvedDomain::EnumeratedType(_, _)
685 | UnresolvedDomain::UnnamedType(_) => {}
686 },
687 }
688 }
689
690 pub fn has_representation_preference(&self) -> bool {
692 if self.representation_preference().is_some() {
693 return true;
694 }
695 match self {
696 Domain::Ground(gd) => gd.has_representation_preference(),
697 Domain::Unresolved(ud) => ud.has_representation_preference(),
698 }
699 }
700
701 pub fn as_type_string(&self) -> String {
704 match self {
705 Domain::Ground(gd) => gd.as_type_string(),
706 Domain::Unresolved(ud) => ud.as_type_string(),
707 }
708 }
709
710 pub fn as_mset(&self) -> Option<(MSetAttr<IntVal>, DomainPtr)> {
712 if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
713 return Some((attr.clone().into(), inner_dom.clone().into()));
714 }
715 if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved() {
716 return Some((attr.clone(), inner_dom.clone()));
717 }
718 None
719 }
720
721 pub fn as_mset_mut(&mut self) -> Option<(&mut MSetAttr<IntVal>, &mut DomainPtr)> {
724 if let Some(GroundDomain::MSet(attr_gd, inner_dom_gd)) = self.as_ground() {
725 let attr: MSetAttr<IntVal> = attr_gd.clone().into();
726 let inner_dom = inner_dom_gd.clone().into();
727 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(attr, inner_dom)));
728 }
729
730 if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved_mut() {
731 return Some((attr, inner_dom));
732 }
733 None
734 }
735
736 pub fn as_mset_ground(&self) -> Option<(&MSetAttr<Int>, &Moo<GroundDomain>)> {
738 if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
739 return Some((attr, inner_dom));
740 }
741 None
742 }
743
744 pub fn as_mset_ground_mut(&mut self) -> Option<(&mut MSetAttr<Int>, &mut Moo<GroundDomain>)> {
746 if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground_mut() {
747 return Some((attr, inner_dom));
748 }
749 None
750 }
751
752 pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
754 if let Some(GroundDomain::Tuple(inner_doms, _)) = self.as_ground() {
755 return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
756 }
757 if let Some(UnresolvedDomain::Tuple(inner_doms, _)) = self.as_unresolved() {
758 return Some(inner_doms.clone());
759 }
760 None
761 }
762
763 pub fn as_tuple_mut(&mut self) -> Option<&mut Vec<DomainPtr>> {
766 if let Some(GroundDomain::Tuple(inner_doms_gds, representation)) = self.as_ground() {
767 let inner_doms: Vec<DomainPtr> =
768 inner_doms_gds.iter().cloned().map(|d| d.into()).collect();
769 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
770 inner_doms,
771 representation.clone(),
772 )));
773 }
774
775 if let Some(UnresolvedDomain::Tuple(inner_doms, _)) = self.as_unresolved_mut() {
776 return Some(inner_doms);
777 }
778 None
779 }
780
781 pub fn as_tuple_ground(&self) -> Option<&Vec<Moo<GroundDomain>>> {
783 if let Some(GroundDomain::Tuple(inner_doms, _)) = self.as_ground() {
784 return Some(inner_doms);
785 }
786 None
787 }
788
789 pub fn as_tuple_ground_mut(&mut self) -> Option<&mut Vec<Moo<GroundDomain>>> {
791 if let Some(GroundDomain::Tuple(inner_doms, _)) = self.as_ground_mut() {
792 return Some(inner_doms);
793 }
794 None
795 }
796
797 pub fn as_record(&self) -> Option<Vec<FieldUnresolved>> {
799 if let Some(GroundDomain::Record(record_entries, _)) = self.as_ground() {
800 return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
801 }
802 if let Some(UnresolvedDomain::Record(record_entries, _)) = self.as_unresolved() {
803 return Some(record_entries.clone());
804 }
805 None
806 }
807
808 pub fn as_record_ground(&self) -> Option<&Vec<FieldGround>> {
810 if let Some(GroundDomain::Record(entries, _)) = self.as_ground() {
811 return Some(entries);
812 }
813 None
814 }
815
816 pub fn as_record_mut(&mut self) -> Option<&mut Vec<FieldUnresolved>> {
819 if let Some(GroundDomain::Record(entries_gds, representation)) = self.as_ground() {
820 let entries: Vec<FieldUnresolved> =
821 entries_gds.iter().cloned().map(|r| r.into()).collect();
822 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
823 entries,
824 representation.clone(),
825 )));
826 }
827
828 if let Some(UnresolvedDomain::Record(entries_gds, _)) = self.as_unresolved_mut() {
829 return Some(entries_gds);
830 }
831 None
832 }
833
834 pub fn as_record_ground_mut(&mut self) -> Option<&mut Vec<FieldGround>> {
836 if let Some(GroundDomain::Record(entries, _)) = self.as_ground_mut() {
837 return Some(entries);
838 }
839 None
840 }
841
842 pub fn as_sequence(&self) -> Option<(SequenceAttr<IntVal>, Moo<Domain>)> {
844 if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
845 return Some((attrs.clone().into(), dom.clone().into()));
846 }
847 if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved() {
848 return Some((attrs.clone(), dom.clone()));
849 }
850 None
851 }
852
853 pub fn as_sequence_mut(&mut self) -> Option<(&mut SequenceAttr<IntVal>, &mut Moo<Domain>)> {
857 if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
858 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
859 attrs.clone().into(),
860 dom.clone().into(),
861 )));
862 }
863
864 if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved_mut() {
865 return Some((attrs, dom));
866 }
867 None
868 }
869
870 pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
872 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
873 return Some((
874 attrs.clone().into(),
875 dom.clone().into(),
876 codom.clone().into(),
877 ));
878 }
879 if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
880 return Some((attrs.clone(), dom.clone(), codom.clone()));
881 }
882 None
883 }
884
885 pub fn as_function_mut(
889 &mut self,
890 ) -> Option<(&mut FuncAttr<IntVal>, &mut Moo<Domain>, &mut Moo<Domain>)> {
891 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
892 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
893 attrs.clone().into(),
894 dom.clone().into(),
895 codom.clone().into(),
896 )));
897 }
898
899 if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved_mut() {
900 return Some((attrs, dom, codom));
901 }
902 None
903 }
904
905 pub fn as_function_ground(
907 &self,
908 ) -> Option<(&FuncAttr, &Moo<GroundDomain>, &Moo<GroundDomain>)> {
909 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
910 return Some((attrs, dom, codom));
911 }
912 None
913 }
914
915 pub fn as_function_ground_mut(
917 &mut self,
918 ) -> Option<(
919 &mut FuncAttr,
920 &mut Moo<GroundDomain>,
921 &mut Moo<GroundDomain>,
922 )> {
923 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground_mut() {
924 return Some((attrs, dom, codom));
925 }
926 None
927 }
928
929 pub fn as_partition(&self) -> Option<(PartitionAttr<IntVal>, Moo<Domain>)> {
931 if let Some(GroundDomain::Partition(attrs, doms)) = self.as_ground() {
932 return Some((attrs.clone().into(), doms.clone().into()));
933 }
934 if let Some(UnresolvedDomain::Partition(attrs, doms)) = self.as_unresolved() {
935 return Some((attrs.clone(), doms.clone()));
936 }
937 None
938 }
939
940 pub fn as_partition_mut(&mut self) -> Option<(&mut PartitionAttr<IntVal>, &mut DomainPtr)> {
943 if let Some(GroundDomain::Partition(attr_gd, inner_dom_gd)) = self.as_ground() {
944 let attr: PartitionAttr<IntVal> = attr_gd.clone().into();
945 let inner_dom = inner_dom_gd.clone().into();
946 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(attr, inner_dom)));
947 }
948
949 if let Some(UnresolvedDomain::Partition(attr, inner_dom)) = self.as_unresolved_mut() {
950 return Some((attr, inner_dom));
951 }
952 None
953 }
954
955 pub fn as_partition_ground(&self) -> Option<(&PartitionAttr<Int>, &Moo<GroundDomain>)> {
957 if let Some(GroundDomain::Partition(attr, inner_dom)) = self.as_ground() {
958 return Some((attr, inner_dom));
959 }
960 None
961 }
962
963 pub fn as_partition_ground_mut(
965 &mut self,
966 ) -> Option<(&mut PartitionAttr<Int>, &mut Moo<GroundDomain>)> {
967 if let Some(GroundDomain::Partition(attr, inner_dom)) = self.as_ground_mut() {
968 return Some((attr, inner_dom));
969 }
970 None
971 }
972
973 pub fn as_permutation(&self) -> Option<(PermutationAttr<IntVal>, Moo<Domain>)> {
975 if let Some(GroundDomain::Permutation(attrs, doms)) = self.as_ground() {
976 return Some((attrs.clone().into(), doms.clone().into()));
977 }
978 if let Some(UnresolvedDomain::Permutation(attrs, doms)) = self.as_unresolved() {
979 return Some((attrs.clone(), doms.clone()));
980 }
981 None
982 }
983
984 pub fn as_permutation_mut(&mut self) -> Option<(&mut PermutationAttr<IntVal>, &mut DomainPtr)> {
987 if let Some(GroundDomain::Permutation(attr_gd, inner_dom_gd)) = self.as_ground() {
988 let attr: PermutationAttr<IntVal> = attr_gd.clone().into();
989 let inner_dom = inner_dom_gd.clone().into();
990 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Permutation(attr, inner_dom)));
991 }
992
993 if let Some(UnresolvedDomain::Permutation(attr, inner_dom)) = self.as_unresolved_mut() {
994 return Some((attr, inner_dom));
995 }
996 None
997 }
998
999 pub fn as_permutation_ground(&self) -> Option<(&PermutationAttr<Int>, &Moo<GroundDomain>)> {
1001 if let Some(GroundDomain::Permutation(attr, inner_dom)) = self.as_ground() {
1002 return Some((attr, inner_dom));
1003 }
1004 None
1005 }
1006
1007 pub fn as_permutation_ground_mut(
1009 &mut self,
1010 ) -> Option<(&mut PermutationAttr<Int>, &mut Moo<GroundDomain>)> {
1011 if let Some(GroundDomain::Permutation(attr, inner_dom)) = self.as_ground_mut() {
1012 return Some((attr, inner_dom));
1013 }
1014 None
1015 }
1016
1017 pub fn as_variant(&self) -> Option<Vec<FieldUnresolved>> {
1019 if let Some(GroundDomain::Variant(entries, _)) = self.as_ground() {
1020 return Some(entries.iter().cloned().map(|r| r.into()).collect());
1021 }
1022 if let Some(UnresolvedDomain::Variant(entries, _)) = self.as_unresolved() {
1023 return Some(entries.clone());
1024 }
1025 None
1026 }
1027
1028 pub fn as_variant_ground(&self) -> Option<&Vec<FieldGround>> {
1030 if let Some(GroundDomain::Variant(entries, _)) = self.as_ground() {
1031 return Some(entries);
1032 }
1033 None
1034 }
1035
1036 pub fn as_variant_mut(&mut self) -> Option<&mut Vec<FieldUnresolved>> {
1039 if let Some(GroundDomain::Variant(entries_gds, representation)) = self.as_ground() {
1040 let entries: Vec<FieldUnresolved> =
1041 entries_gds.iter().cloned().map(|r| r.into()).collect();
1042 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(
1043 entries,
1044 representation.clone(),
1045 )));
1046 }
1047
1048 if let Some(UnresolvedDomain::Variant(entries_gds, _)) = self.as_unresolved_mut() {
1049 return Some(entries_gds);
1050 }
1051 None
1052 }
1053
1054 pub fn as_variant_ground_mut(&mut self) -> Option<&mut Vec<FieldGround>> {
1056 if let Some(GroundDomain::Variant(entries, _)) = self.as_ground_mut() {
1057 return Some(entries);
1058 }
1059 None
1060 }
1061
1062 pub fn as_relation(&self) -> Option<(RelAttr<IntVal>, Vec<Moo<Domain>>)> {
1064 if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
1065 return Some((
1066 attrs.clone().into(),
1067 doms.iter().cloned().map(|d| d.into()).collect(),
1068 ));
1069 }
1070 if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved() {
1071 return Some((attrs.clone(), doms.clone()));
1072 }
1073 None
1074 }
1075
1076 pub fn as_relation_mut(&mut self) -> Option<(&mut RelAttr<IntVal>, &mut Vec<Moo<Domain>>)> {
1080 if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
1081 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
1082 attrs.clone().into(),
1083 doms.iter().cloned().map(|d| d.into()).collect(),
1084 )));
1085 }
1086
1087 if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved_mut() {
1088 return Some((attrs, doms));
1089 }
1090 None
1091 }
1092
1093 pub fn as_relation_ground(&self) -> Option<(&RelAttr, &Vec<Moo<GroundDomain>>)> {
1095 if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
1096 return Some((attrs, doms));
1097 }
1098 None
1099 }
1100
1101 pub fn as_relation_ground_mut(
1103 &mut self,
1104 ) -> Option<(&mut RelAttr, &mut Vec<Moo<GroundDomain>>)> {
1105 if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground_mut() {
1106 return Some((attrs, doms));
1107 }
1108 None
1109 }
1110
1111 pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
1116 if let Domain::Unresolved(domain) = self
1117 && let UnresolvedDomain::Reference(reference) = domain.as_ref()
1118 {
1119 let referenced_domain = reference.domain().unwrap_or_else(|| {
1120 crate::bug!("domain reference should point to a domain letting: {reference}")
1121 });
1122 return referenced_domain.as_ref().union(other);
1123 }
1124
1125 if let Domain::Unresolved(domain) = other
1126 && let UnresolvedDomain::Reference(reference) = domain.as_ref()
1127 {
1128 let referenced_domain = reference.domain().unwrap_or_else(|| {
1129 crate::bug!("domain reference should point to a domain letting: {reference}")
1130 });
1131 return self.union(referenced_domain.as_ref());
1132 }
1133
1134 match (self, other) {
1135 (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
1136 (Domain::Unresolved(a), Domain::Unresolved(b)) => {
1137 Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
1138 }
1139 (Domain::Unresolved(u), Domain::Ground(g))
1140 | (Domain::Ground(g), Domain::Unresolved(u)) => {
1141 if let GroundDomain::Empty(ty) = g.as_ref() {
1142 return if *ty == u.return_type() {
1143 Ok(Domain::Unresolved(u.clone()))
1144 } else {
1145 Err(DomainOpError::WrongType)
1146 };
1147 }
1148
1149 let ground_as_unresolved =
1150 UnresolvedDomain::from_ground(g).ok_or(DomainOpError::WrongType)?;
1151 Ok(Domain::Unresolved(Moo::new(
1152 u.union_unresolved(&ground_as_unresolved)?,
1153 )))
1154 }
1155 }
1156 }
1157
1158 pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
1160 match (self, other) {
1161 (Domain::Ground(a), Domain::Ground(b)) => {
1162 a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
1163 }
1164 _ => Err(DomainOpError::NotGround),
1165 }
1166 }
1167
1168 pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
1170 if let Some(gd) = self.as_ground() {
1171 return gd.values();
1172 }
1173 Err(DomainOpError::NotGround)
1174 }
1175
1176 pub fn length(&self) -> Result<u64, DomainOpError> {
1178 if let Some(gd) = self.as_ground() {
1179 return gd.length();
1180 }
1181 Err(DomainOpError::NotGround)
1182 }
1183 pub fn length_signed(&self) -> Result<i32, DomainOpError> {
1189 let gd = self.as_ground().ok_or(DomainOpError::NotGround)?;
1190 let len = gd.length()?;
1191 len.try_into().map_err(|_| DomainOpError::TooLarge)
1192 }
1193
1194 pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
1196 GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
1197 }
1198
1199 pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
1201 if let Some(gd) = self.as_ground() {
1202 return gd.contains(lit);
1203 }
1204 Err(DomainOpError::NotGround)
1205 }
1206
1207 pub fn element_domain(&self) -> Option<DomainPtr> {
1208 match self {
1209 Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
1210 Domain::Unresolved(ud) => ud.element_domain(),
1211 }
1212 }
1213}
1214
1215impl Typeable for Domain {
1216 fn return_type(&self) -> ReturnType {
1217 match self {
1218 Domain::Ground(dom) => dom.return_type(),
1219 Domain::Unresolved(dom) => dom.return_type(),
1220 }
1221 }
1222}
1223
1224impl Display for Domain {
1225 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1226 match &self {
1227 Domain::Ground(gd) => gd.fmt(f),
1228 Domain::Unresolved(ud) => ud.fmt(f),
1229 }
1230 }
1231}
1232
1233fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
1234 doms.iter()
1235 .map(|idx| match idx.as_ref() {
1236 Domain::Ground(idx_gd) => Some(idx_gd.clone()),
1237 _ => None,
1238 })
1239 .collect()
1240}
1241
1242#[cfg(test)]
1243mod tests {
1244 use super::*;
1245 use crate::ast::Name;
1246 use crate::{domain_int, range};
1247
1248 #[test]
1249 fn unresolved_int_domain_resolve_squeezes_ranges() {
1250 let domain = UnresolvedDomain::Int(
1251 vec![
1252 Range::Single(IntVal::Const(5)),
1253 Range::Bounded(IntVal::Const(3), IntVal::Const(7)),
1254 Range::Bounded(IntVal::Const(5), IntVal::Const(3)),
1255 Range::Single(IntVal::Const(7)),
1256 ],
1257 None,
1258 );
1259
1260 assert_eq!(
1261 domain.resolve(),
1262 Ok(GroundDomain::Int(vec![Range::Bounded(3, 7)], None))
1263 );
1264 }
1265
1266 #[test]
1267 fn union_dereferences_domain_lettings() {
1268 let declaration = DeclarationPtr::new_domain_letting(
1269 Name::user("Alias"),
1270 Domain::int(vec![Range::Bounded(1, 3)]),
1271 );
1272 let alias = Domain::reference(declaration).unwrap();
1273
1274 assert_eq!(
1275 alias
1276 .union(&Domain::int(vec![Range::Bounded(5, 7)]))
1277 .unwrap()
1278 .resolve(),
1279 Ok(Moo::new(GroundDomain::Int(
1280 vec![Range::Bounded(1, 3), Range::Bounded(5, 7),],
1281 None
1282 )))
1283 );
1284 }
1285
1286 #[test]
1287 fn union_preserves_symbolic_domain_bounds() {
1288 let upper_bound =
1289 DeclarationPtr::new_given(Name::user("n"), Domain::int(vec![Range::Bounded(1, 10)]));
1290 let symbolic_upper = IntVal::new_ref(&Reference::new(upper_bound)).unwrap();
1291 let symbolic_domain = Domain::int(vec![Range::Bounded(
1292 IntVal::Const(1),
1293 symbolic_upper.clone(),
1294 )]);
1295 let declaration = DeclarationPtr::new_domain_letting(Name::user("Alias"), symbolic_domain);
1296 let alias = Domain::reference(declaration).unwrap();
1297
1298 let union = alias.union(&Domain::int(vec![Range::Single(20)])).unwrap();
1299
1300 assert_eq!(
1301 union.as_int(),
1302 Some(vec![
1303 Range::Bounded(IntVal::Const(1), symbolic_upper),
1304 Range::Single(IntVal::Const(20)),
1305 ])
1306 );
1307 assert_eq!(union.resolve(), Err(DomainOpError::NotGround));
1308 }
1309
1310 #[test]
1311 fn test_negative_product() {
1312 let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
1313 let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
1314 let res = d1
1315 .as_ground()
1316 .unwrap()
1317 .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
1318 .unwrap();
1319
1320 assert!(matches!(res, GroundDomain::Int(_, _)));
1321 if let GroundDomain::Int(ranges, _) = res {
1322 assert!(!ranges.contains(&Range::Bounded(-4, 4)));
1323 }
1324 }
1325
1326 #[test]
1327 fn test_negative_div() {
1328 let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)], None);
1329 let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)], None);
1330 let res = d1
1331 .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
1332 .unwrap();
1333
1334 assert!(matches!(res, GroundDomain::Int(_, _)));
1335 if let GroundDomain::Int(ranges, _) = res {
1336 assert!(!ranges.contains(&Range::Bounded(-4, 4)));
1337 }
1338 }
1339
1340 #[test]
1341 fn test_length_basic() {
1342 assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
1343 assert_eq!(Domain::bool().length(), Ok(2));
1344 assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
1345 assert_eq!(
1346 domain_int!(1..2, 5..).length(),
1347 Err(DomainOpError::Unbounded)
1348 );
1349 }
1350 #[test]
1351 fn test_length_set_basic() {
1352 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
1354 assert_eq!(s.length(), Ok(8));
1355
1356 let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
1358 assert_eq!(s.length(), Ok(3));
1359
1360 let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
1362 assert_eq!(s.length(), Ok(6));
1363
1364 let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
1366 assert_eq!(s.length(), Ok(7));
1367
1368 let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
1370 assert_eq!(s.length(), Ok(7));
1371 }
1372
1373 #[test]
1374 fn test_set_representation_preference_display() {
1375 let s = Domain::set(
1376 SetAttr::new_max_size(3).with_representation("packed"),
1377 domain_int!(1..4),
1378 );
1379 assert_eq!(
1380 s.to_string(),
1381 "set (representation packed, maxSize 3) of int(1..4)"
1382 );
1383 assert_eq!(s.as_type_string(), "set (representation packed) of int");
1384 assert_eq!(s.representation_preference(), Some("packed"));
1385
1386 let nested = Domain::set(
1387 SetAttr::<IntVal>::default().with_representation("explicit"),
1388 Domain::set(
1389 SetAttr::<IntVal>::default().with_representation("occurrence"),
1390 domain_int!(1..2),
1391 ),
1392 );
1393 assert_eq!(
1394 nested.to_string(),
1395 "set (representation explicit) of set (representation occurrence) of int(1..2)"
1396 );
1397 assert_eq!(
1398 nested.as_type_string(),
1399 "set (representation explicit) of set (representation occurrence) of int"
1400 );
1401 }
1402
1403 #[test]
1404 fn test_mset_representation_preference_survives_nesting() {
1405 let mset = Domain::mset(
1406 MSetAttr::new_max_size(IntVal::Const(6)).with_representation("repetition"),
1407 domain_int!(1..9),
1408 );
1409 let nested = Domain::matrix(
1410 Domain::record(vec![Field {
1411 name: Name::user("before"),
1412 value: mset.clone(),
1413 }]),
1414 vec![domain_int!(1..2)],
1415 );
1416
1417 assert_eq!(mset.representation_preference(), Some("repetition"));
1418 assert_eq!(
1419 mset.as_type_string(),
1420 "mset (representation repetition) of int"
1421 );
1422 assert_eq!(
1423 mset.to_string(),
1424 "mset (representation repetition, maxSize 6) of int(1..9)"
1425 );
1426 assert!(nested.has_representation_preference());
1427 assert_eq!(
1428 nested.to_string(),
1429 "matrix indexed by [int(1..2)] of record {before: mset (representation repetition, maxSize 6) of int(1..9)}"
1430 );
1431 }
1432
1433 #[test]
1434 fn test_length_set_nested() {
1435 let s2 = Domain::set(
1442 SetAttr::new_max_size(2),
1443 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1445 );
1446 assert_eq!(s2.length(), Ok(11));
1447 }
1448
1449 #[test]
1450 fn test_length_set_unbounded_inner() {
1451 let s2_bad = Domain::set(
1453 SetAttr::new_max_size(2),
1454 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
1455 );
1456 assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
1457 }
1458
1459 #[test]
1460 fn test_length_set_overflow() {
1461 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
1462 assert!(s.length().is_ok());
1463
1464 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
1466 assert_eq!(s.length(), Err(DomainOpError::TooLarge));
1467 }
1468
1469 #[test]
1470 fn test_length_tuple() {
1471 let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
1473 assert_eq!(t.length(), Ok(6));
1474 }
1475
1476 #[test]
1477 fn test_length_record() {
1478 let t = Domain::record(vec![
1480 Field {
1481 name: Name::user("a"),
1482 value: domain_int!(1..3),
1483 },
1484 Field {
1485 name: Name::user("b"),
1486 value: Domain::bool(),
1487 },
1488 ]);
1489 assert_eq!(t.length(), Ok(6));
1490 }
1491
1492 #[test]
1493 fn test_length_matrix_basic() {
1494 let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
1496 assert_eq!(m.length(), Ok(8));
1497
1498 let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
1500 assert_eq!(m.length(), Ok(9));
1501 }
1502
1503 #[test]
1504 fn test_length_matrix_2d() {
1505 let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
1507 assert_eq!(m.length(), Ok(64));
1508 }
1509
1510 #[test]
1511 fn test_length_matrix_of_sets() {
1512 let m = Domain::matrix(
1514 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1515 vec![domain_int!(1..3)],
1516 );
1517 assert_eq!(m.length(), Ok(64));
1518 }
1519}
1520
1521fn int_ranges_from_constant_collection(values: &Expression) -> Option<Vec<Range<Int>>> {
1523 let values = crate::ast::eval::generator_values_from_expr(values)?;
1524 let mut ranges = Vec::with_capacity(values.len());
1525 for value in values {
1526 let crate::ast::Literal::Int(value) = value else {
1527 return None;
1528 };
1529 ranges.push(Range::Single(value));
1530 }
1531 Some(ranges)
1532}