Skip to main content

conjure_cp_core/ast/domains/
domain.rs

1use crate::ast::domains::{
2    attrs::{MSetAttr, PartitionAttr, SetAttr},
3    ground::{FieldGround, GroundDomain},
4    int_val::IntVal,
5    range::Range,
6    unresolved::{FieldUnresolved, UnresolvedDomain},
7};
8use crate::ast::{
9    DeclarationPtr, DomainOpError, Expression, Field, FuncAttr, Literal, Moo, Reference, RelAttr,
10    ReturnType, SequenceAttr, Typeable,
11};
12use itertools::Itertools;
13use polyquine::Quine;
14use serde::{Deserialize, Serialize};
15use std::fmt::{Display, Formatter};
16use std::thread_local;
17use uniplate::Uniplate;
18
19/// The integer type used in all domain code (int ranges, set sizes, etc)
20pub type Int = i32;
21
22pub type DomainPtr = Moo<Domain>;
23
24impl DomainPtr {
25    pub fn resolve(&self) -> Result<Moo<GroundDomain>, DomainOpError> {
26        self.as_ref().resolve()
27    }
28
29    /// Convenience method to take [Domain::union] of the [Domain]s behind two [DomainPtr]s
30    /// and wrap the result in a new [DomainPtr].
31    pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
32        self.as_ref().union(other.as_ref()).map(DomainPtr::new)
33    }
34
35    /// Convenience method to take [Domain::intersect] of the [Domain]s behind two [DomainPtr]s
36    /// and wrap the result in a new [DomainPtr].
37    pub fn intersect(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
38        self.as_ref().intersect(other.as_ref()).map(DomainPtr::new)
39    }
40}
41
42#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
43#[biplate(to=DomainPtr)]
44#[biplate(to=GroundDomain)]
45#[biplate(to=UnresolvedDomain)]
46#[biplate(to=Expression)]
47#[biplate(to=Reference)]
48#[biplate(to=IntVal)]
49#[path_prefix(conjure_cp::ast)]
50pub enum Domain {
51    /// A fully resolved domain
52    Ground(Moo<GroundDomain>),
53    /// A domain which may contain references
54    Unresolved(Moo<UnresolvedDomain>),
55}
56
57/// Types that have a [`Domain`].
58pub trait HasDomain {
59    /// Gets the [`Domain`] of `self`.
60    fn domain_of(&self) -> DomainPtr;
61}
62
63impl<T: HasDomain> Typeable for T {
64    fn return_type(&self) -> ReturnType {
65        self.domain_of().return_type()
66    }
67}
68
69// Domain::Bool is completely static, so reuse the same chunk of memory
70// for all bool domains to avoid many small memory allocations
71thread_local! {
72    static BOOL_DOMAIN: DomainPtr =
73        Moo::new(Domain::Ground(Moo::new(GroundDomain::Bool)));
74}
75
76impl Domain {
77    /// Create a new boolean domain and return a pointer to it.
78    /// Boolean domains are always ground (see [GroundDomain::Bool]).
79    pub fn bool() -> DomainPtr {
80        BOOL_DOMAIN.with(Clone::clone)
81    }
82
83    /// Create a new empty domain of the given type and return a pointer to it.
84    /// Empty domains are always ground (see [GroundDomain::Empty]).
85    pub fn empty(ty: ReturnType) -> DomainPtr {
86        Moo::new(Domain::Ground(Moo::new(GroundDomain::Empty(ty))))
87    }
88
89    /// Create a new int domain with the given ranges.
90    /// If the ranges are all ground, the variant will be [GroundDomain::Int].
91    /// Otherwise, it will be [UnresolvedDomain::Int].
92    pub fn int<T>(ranges: Vec<T>) -> DomainPtr
93    where
94        T: Into<Range<IntVal>> + TryInto<Range<Int>> + Clone,
95    {
96        if let Ok(int_rngs) = ranges
97            .iter()
98            .cloned()
99            .map(TryInto::try_into)
100            .collect::<Result<Vec<_>, _>>()
101        {
102            return Domain::int_ground(int_rngs);
103        }
104        let unresolved_rngs: Vec<Range<IntVal>> = ranges.into_iter().map(Into::into).collect();
105        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Int(
106            unresolved_rngs,
107        ))))
108    }
109
110    /// Create a new ground integer domain with the given ranges
111    pub fn int_ground(ranges: Vec<Range<Int>>) -> DomainPtr {
112        let rngs = Range::squeeze(&ranges);
113        Moo::new(Domain::Ground(Moo::new(GroundDomain::Int(rngs))))
114    }
115
116    /// Create a new set domain with the given element domain and attributes.
117    /// If the element domain and the attributes are ground, the variant
118    /// will be [GroundDomain::Set]. Otherwise, it will be [UnresolvedDomain::Set].
119    pub fn set<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
120    where
121        T: Into<SetAttr<IntVal>> + TryInto<SetAttr<Int>> + Clone,
122    {
123        if let Domain::Ground(gd) = inner_dom.as_ref()
124            && let Ok(int_attr) = attr.clone().try_into()
125        {
126            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Set(
127                int_attr,
128                gd.clone(),
129            ))));
130        }
131        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Set(
132            attr.into(),
133            inner_dom,
134        ))))
135    }
136
137    /// Create a new multiset domain with the given element domain and attributes
138    pub fn mset<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
139    where
140        T: Into<MSetAttr<IntVal>> + TryInto<MSetAttr<Int>> + Clone,
141    {
142        if let Domain::Ground(gd) = inner_dom.as_ref()
143            && let Ok(int_attr) = attr.clone().try_into()
144        {
145            return Moo::new(Domain::Ground(Moo::new(GroundDomain::MSet(
146                int_attr,
147                gd.clone(),
148            ))));
149        }
150        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(
151            attr.into(),
152            inner_dom,
153        ))))
154    }
155
156    /// Create a new matrix domain with the given element domain and index domains.
157    /// If the given domains are all ground, the variant will be [GroundDomain::Matrix].
158    /// Otherwise, it will be [UnresolvedDomain::Matrix].
159    pub fn matrix(inner_dom: DomainPtr, idx_doms: Vec<DomainPtr>) -> DomainPtr {
160        if let Domain::Ground(gd) = inner_dom.as_ref()
161            && let Some(idx_gds) = as_grounds(&idx_doms)
162        {
163            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Matrix(
164                gd.clone(),
165                idx_gds,
166            ))));
167        }
168        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
169            inner_dom, idx_doms,
170        ))))
171    }
172
173    /// Create a new tuple domain with the given element domains.
174    /// If the given domains are all ground, the variant will be [GroundDomain::Tuple].
175    /// Otherwise, it will be [UnresolvedDomain::Tuple].
176    pub fn tuple(inner_doms: Vec<DomainPtr>) -> DomainPtr {
177        if let Some(inner_gds) = as_grounds(&inner_doms) {
178            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Tuple(inner_gds))));
179        }
180        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
181            inner_doms,
182        ))))
183    }
184
185    /// Create a new tuple domain with the given entries.
186    /// If the entries are all ground, the variant will be [GroundDomain::Record].
187    /// Otherwise, it will be [UnresolvedDomain::Record].
188    pub fn record(entries: Vec<Field<DomainPtr>>) -> DomainPtr {
189        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
190            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Record(entries_gds))));
191        }
192        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
193            entries,
194        ))))
195    }
196
197    /// Create a new [UnresolvedDomain::Reference] domain from a domain letting
198    pub fn reference(ptr: DeclarationPtr) -> Option<DomainPtr> {
199        let _ = ptr.as_domain_letting()?;
200        Some(Moo::new(Domain::Unresolved(Moo::new(
201            UnresolvedDomain::Reference(Reference::new(ptr)),
202        ))))
203    }
204
205    /// Create a new multiset domain with the given element domain and attributes
206    pub fn partition<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
207    where
208        T: Into<PartitionAttr<IntVal>> + TryInto<PartitionAttr<Int>> + Clone,
209    {
210        if let Domain::Ground(gd) = inner_dom.as_ref()
211            && let Ok(int_attr) = attr.clone().try_into()
212        {
213            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Partition(
214                int_attr,
215                gd.clone(),
216            ))));
217        }
218        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(
219            attr.into(),
220            inner_dom,
221        ))))
222    }
223
224    /// Create a new function domain
225    pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
226    where
227        T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
228    {
229        if let Ok(attrs_gd) = attrs.clone().try_into()
230            && let Some(dom_gd) = dom.as_ground()
231            && let Some(cdom_gd) = cdom.as_ground()
232        {
233            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
234                attrs_gd,
235                Moo::new(dom_gd.clone()),
236                Moo::new(cdom_gd.clone()),
237            ))));
238        }
239
240        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
241            attrs.into(),
242            dom,
243            cdom,
244        ))))
245    }
246
247    /// Create a new variant domain with the given entries.
248    /// If the entries are all ground, the variant will be [GroundDomain::Variant].
249    /// Otherwise, it will be [UnresolvedDomain::Variant].
250    pub fn variant(entries: Vec<Field<DomainPtr>>) -> DomainPtr {
251        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
252            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Variant(entries_gds))));
253        }
254        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(
255            entries,
256        ))))
257    }
258
259    /// Create a new relation domain
260    /// If the entries are all ground, the variant will be [GroundDomain::Relation].
261    /// Otherwise, it will be [UnresolvedDomain::Relation].
262    pub fn relation<T>(attrs: T, inner_doms: Vec<DomainPtr>) -> DomainPtr
263    where
264        T: Into<RelAttr<IntVal>> + TryInto<RelAttr<Int>> + Clone,
265    {
266        if let Ok(attrs_gd) = attrs.clone().try_into()
267            && let Some(doms_gd) = as_grounds(&inner_doms)
268        {
269            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Relation(
270                attrs_gd, doms_gd,
271            ))));
272        }
273
274        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
275            attrs.into(),
276            inner_doms,
277        ))))
278    }
279
280    /// Create a new Sequence domain
281    pub fn sequence<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
282    where
283        T: Into<SequenceAttr<IntVal>> + TryInto<SequenceAttr<Int>> + Clone,
284    {
285        if let Domain::Ground(gd) = inner_dom.as_ref()
286            && let Ok(int_attr) = attr.clone().try_into()
287        {
288            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Sequence(
289                int_attr,
290                gd.clone(),
291            ))));
292        }
293        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
294            attr.into(),
295            inner_dom,
296        ))))
297    }
298
299    /// If this domain is ground, return a [Moo] to the underlying [GroundDomain].
300    /// Otherwise, try to resolve it; Return None if this is not yet possible.
301    /// Domains which contain references to givens cannot be resolved until these
302    /// givens are substituted for their concrete values.
303    pub fn resolve(&self) -> Result<Moo<GroundDomain>, DomainOpError> {
304        match self {
305            Domain::Ground(gd) => Ok(gd.clone()),
306            Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
307        }
308    }
309
310    /// If this domain is already ground, return a reference to the underlying [GroundDomain].
311    /// Otherwise, return None. This method does NOT perform any resolution.
312    /// See also: [Domain::resolve].
313    pub fn as_ground(&self) -> Option<&GroundDomain> {
314        match self {
315            Domain::Ground(gd) => Some(gd.as_ref()),
316            _ => None,
317        }
318    }
319
320    /// If this domain is already ground, return a mutable reference to the underlying [GroundDomain].
321    /// Otherwise, return None. This method does NOT perform any resolution.
322    pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
323        match self {
324            Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
325            _ => None,
326        }
327    }
328
329    /// If this domain is unresolved, return a reference to the underlying [UnresolvedDomain].
330    pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
331        match self {
332            Domain::Unresolved(ud) => Some(ud.as_ref()),
333            _ => None,
334        }
335    }
336
337    /// If this domain is unresolved, return a mutable reference to the underlying [UnresolvedDomain].
338    pub fn as_unresolved_mut(&mut self) -> Option<&mut UnresolvedDomain> {
339        match self {
340            Domain::Unresolved(ud) => Some(Moo::<UnresolvedDomain>::make_mut(ud)),
341            _ => None,
342        }
343    }
344
345    /// If this is [GroundDomain::Empty(ty)], get a reference to the return type `ty`
346    pub fn as_dom_empty(&self) -> Option<&ReturnType> {
347        if let Some(GroundDomain::Empty(ty)) = self.as_ground() {
348            return Some(ty);
349        }
350        None
351    }
352
353    /// If this is [GroundDomain::Empty(ty)], get a mutable reference to the return type `ty`
354    pub fn as_dom_empty_mut(&mut self) -> Option<&mut ReturnType> {
355        if let Some(GroundDomain::Empty(ty)) = self.as_ground_mut() {
356            return Some(ty);
357        }
358        None
359    }
360
361    /// True if this is [GroundDomain::Bool]
362    pub fn is_bool(&self) -> bool {
363        self.return_type() == ReturnType::Bool
364    }
365
366    /// True if this is a [GroundDomain::Int] or an [UnresolvedDomain::Int]
367    pub fn is_int(&self) -> bool {
368        self.return_type() == ReturnType::Int
369    }
370
371    /// If this domain is [GroundDomain::Int] or [UnresolveDomain::Int], get
372    /// its ranges. The ranges are cloned and upcast to Range<IntVal> if necessary.
373    pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
374        if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
375            return Some(rngs.iter().cloned().map(|r| r.into()).collect());
376        }
377        if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved() {
378            return Some(rngs.clone());
379        }
380        None
381    }
382
383    /// If this is an int domain, get a mutable reference to its ranges.
384    /// The domain always becomes [UnresolvedDomain::Int] after this operation.
385    pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
386        // We're "upcasting" ground ranges (Range<Int>) to the more general
387        // Range<IntVal>, which may contain references or expressions.
388        // We know that for now they are still ground, but we're giving the user a mutable
389        // reference, so they can overwrite the ranges with values that aren't ground.
390        // So, the entire domain has to become non-ground as well.
391        if let Some(GroundDomain::Int(rngs_gds)) = self.as_ground() {
392            let rngs: Vec<Range<IntVal>> = rngs_gds.iter().cloned().map(|r| r.into()).collect();
393            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Int(rngs)))
394        }
395
396        if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved_mut() {
397            return Some(rngs);
398        }
399        None
400    }
401
402    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
403    pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
404        if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
405            return Some(rngs);
406        }
407        None
408    }
409
410    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
411    pub fn as_int_ground_mut(&mut self) -> Option<&mut Vec<Range<Int>>> {
412        if let Some(GroundDomain::Int(rngs)) = self.as_ground_mut() {
413            return Some(rngs);
414        }
415        None
416    }
417
418    /// If this is a matrix domain, get pointers to its element domain
419    /// and index domains.
420    pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
421        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
422            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
423            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
424            return Some((inner_dom, idx_doms));
425        }
426        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved() {
427            return Some((inner_dom.clone(), idx_doms.clone()));
428        }
429        None
430    }
431
432    /// If this is a matrix domain, get mutable references to its element
433    /// domain and its vector of index domains.
434    /// The domain always becomes [UnresolvedDomain::Matrix] after this operation.
435    pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
436        // "upcast" the entire domain to UnresolvedDomain
437        // See [Domain::as_dom_int_mut] for an explanation of why this is necessary
438        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
439            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
440            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
441            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(inner_dom, idx_doms)));
442        }
443
444        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved_mut() {
445            return Some((inner_dom, idx_doms));
446        }
447        None
448    }
449
450    /// If this is a [GroundDomain::Matrix], get immutable references to its element and index domains
451    pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
452        if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground() {
453            return Some((inner_dom, idx_doms));
454        }
455        None
456    }
457
458    /// If this is a [GroundDomain::Matrix], get mutable references to its element and index domains
459    pub fn as_matrix_ground_mut(
460        &mut self,
461    ) -> Option<(&mut Moo<GroundDomain>, &mut Vec<Moo<GroundDomain>>)> {
462        if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground_mut() {
463            return Some((inner_dom, idx_doms));
464        }
465        None
466    }
467
468    /// If this is a set domain, get its attributes and a pointer to its element domain.
469    pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
470        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
471            return Some((attr.clone().into(), inner_dom.clone().into()));
472        }
473        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
474            return Some((attr.clone(), inner_dom.clone()));
475        }
476        None
477    }
478
479    /// If this is a set domain, get mutable reference to its attributes and element domain.
480    /// The domain always becomes [UnresolvedDomain::Set] after this operation.
481    pub fn as_set_mut(&mut self) -> Option<(&mut SetAttr<IntVal>, &mut DomainPtr)> {
482        if let Some(GroundDomain::Set(attr_gd, inner_dom_gd)) = self.as_ground() {
483            let attr: SetAttr<IntVal> = attr_gd.clone().into();
484            let inner_dom = inner_dom_gd.clone().into();
485            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Set(attr, inner_dom)));
486        }
487
488        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved_mut() {
489            return Some((attr, inner_dom));
490        }
491        None
492    }
493
494    /// If this is a [GroundDomain::Set], get immutable references to its attributes and inner domain
495    pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
496        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
497            return Some((attr, inner_dom));
498        }
499        None
500    }
501
502    /// If this is a [GroundDomain::Set], get mutable references to its attributes and inner domain
503    pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
504        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
505            return Some((attr, inner_dom));
506        }
507        None
508    }
509
510    /// If this is a mset domain, get its attributes and a pointer to its element domain.
511    pub fn as_mset(&self) -> Option<(MSetAttr<IntVal>, DomainPtr)> {
512        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
513            return Some((attr.clone().into(), inner_dom.clone().into()));
514        }
515        if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved() {
516            return Some((attr.clone(), inner_dom.clone()));
517        }
518        None
519    }
520
521    /// If this is a set domain, get mutable reference to its attributes and element domain.
522    /// The domain always becomes [UnresolvedDomain::MSet] after this operation.
523    pub fn as_mset_mut(&mut self) -> Option<(&mut MSetAttr<IntVal>, &mut DomainPtr)> {
524        if let Some(GroundDomain::MSet(attr_gd, inner_dom_gd)) = self.as_ground() {
525            let attr: MSetAttr<IntVal> = attr_gd.clone().into();
526            let inner_dom = inner_dom_gd.clone().into();
527            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(attr, inner_dom)));
528        }
529
530        if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved_mut() {
531            return Some((attr, inner_dom));
532        }
533        None
534    }
535
536    /// If this is a [GroundDomain::MSet], get immutable references to its attributes and inner domain
537    pub fn as_mset_ground(&self) -> Option<(&MSetAttr<Int>, &Moo<GroundDomain>)> {
538        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
539            return Some((attr, inner_dom));
540        }
541        None
542    }
543
544    /// If this is a [GroundDomain::MSet], get mutable references to its attributes and inner domain
545    pub fn as_mset_ground_mut(&mut self) -> Option<(&mut MSetAttr<Int>, &mut Moo<GroundDomain>)> {
546        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground_mut() {
547            return Some((attr, inner_dom));
548        }
549        None
550    }
551
552    /// If this is a tuple domain, get pointers to its element domains.
553    pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
554        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
555            return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
556        }
557        if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved() {
558            return Some(inner_doms.clone());
559        }
560        None
561    }
562
563    /// If this is a tuple domain, get a mutable reference to its vector of element domains.
564    /// The domain always becomes [UnresolvedDomain::Tuple] after this operation.
565    pub fn as_tuple_mut(&mut self) -> Option<&mut Vec<DomainPtr>> {
566        if let Some(GroundDomain::Tuple(inner_doms_gds)) = self.as_ground() {
567            let inner_doms: Vec<DomainPtr> =
568                inner_doms_gds.iter().cloned().map(|d| d.into()).collect();
569            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(inner_doms)));
570        }
571
572        if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved_mut() {
573            return Some(inner_doms);
574        }
575        None
576    }
577
578    /// If this is a [GroundDomain::Tuple], get immutable references to its element domains
579    pub fn as_tuple_ground(&self) -> Option<&Vec<Moo<GroundDomain>>> {
580        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
581            return Some(inner_doms);
582        }
583        None
584    }
585
586    /// If this is a [GroundDomain::Tuple], get mutable reference to its element domains
587    pub fn as_tuple_ground_mut(&mut self) -> Option<&mut Vec<Moo<GroundDomain>>> {
588        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground_mut() {
589            return Some(inner_doms);
590        }
591        None
592    }
593
594    /// If this is a record domain, clone and return its entries.
595    pub fn as_record(&self) -> Option<Vec<FieldUnresolved>> {
596        if let Some(GroundDomain::Record(record_entries)) = self.as_ground() {
597            return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
598        }
599        if let Some(UnresolvedDomain::Record(record_entries)) = self.as_unresolved() {
600            return Some(record_entries.clone());
601        }
602        None
603    }
604
605    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
606    pub fn as_record_ground(&self) -> Option<&Vec<FieldGround>> {
607        if let Some(GroundDomain::Record(entries)) = self.as_ground() {
608            return Some(entries);
609        }
610        None
611    }
612
613    /// If this is a record domain, get a mutable reference to its list of entries.
614    /// The domain always becomes [UnresolvedDomain::Record] after this operation.
615    pub fn as_record_mut(&mut self) -> Option<&mut Vec<FieldUnresolved>> {
616        if let Some(GroundDomain::Record(entries_gds)) = self.as_ground() {
617            let entries: Vec<FieldUnresolved> =
618                entries_gds.iter().cloned().map(|r| r.into()).collect();
619            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Record(entries)));
620        }
621
622        if let Some(UnresolvedDomain::Record(entries_gds)) = self.as_unresolved_mut() {
623            return Some(entries_gds);
624        }
625        None
626    }
627
628    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
629    pub fn as_record_ground_mut(&mut self) -> Option<&mut Vec<FieldGround>> {
630        if let Some(GroundDomain::Record(entries)) = self.as_ground_mut() {
631            return Some(entries);
632        }
633        None
634    }
635
636    /// If this is a sequence domain, get its (attributes, domain)
637    pub fn as_sequence(&self) -> Option<(SequenceAttr<IntVal>, Moo<Domain>)> {
638        if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
639            return Some((attrs.clone().into(), dom.clone().into()));
640        }
641        if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved() {
642            return Some((attrs.clone(), dom.clone()));
643        }
644        None
645    }
646
647    /// If this is a function domain, convert it to unresolved and get mutable references to
648    /// its (attrs, domain, co-domain).
649    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
650    pub fn as_sequence_mut(&mut self) -> Option<(&mut SequenceAttr<IntVal>, &mut Moo<Domain>)> {
651        if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
652            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
653                attrs.clone().into(),
654                dom.clone().into(),
655            )));
656        }
657
658        if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved_mut() {
659            return Some((attrs, dom));
660        }
661        None
662    }
663
664    /// If this is a function domain, get its (attributes, domain, co-domain)
665    pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
666        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
667            return Some((
668                attrs.clone().into(),
669                dom.clone().into(),
670                codom.clone().into(),
671            ));
672        }
673        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
674            return Some((attrs.clone(), dom.clone(), codom.clone()));
675        }
676        None
677    }
678
679    /// If this is a function domain, convert it to unresolved and get mutable references to
680    /// its (attrs, domain, co-domain).
681    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
682    pub fn as_function_mut(
683        &mut self,
684    ) -> Option<(&mut FuncAttr<IntVal>, &mut Moo<Domain>, &mut Moo<Domain>)> {
685        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
686            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
687                attrs.clone().into(),
688                dom.clone().into(),
689                codom.clone().into(),
690            )));
691        }
692
693        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved_mut() {
694            return Some((attrs, dom, codom));
695        }
696        None
697    }
698
699    /// If this is a [GroundDomain::Function], get its (attrs, domain, co-domain)
700    pub fn as_function_ground(
701        &self,
702    ) -> Option<(&FuncAttr, &Moo<GroundDomain>, &Moo<GroundDomain>)> {
703        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
704            return Some((attrs, dom, codom));
705        }
706        None
707    }
708
709    /// If this is a [GroundDomain::Function], get mutable references to its (attrs, domain, co-domain)
710    pub fn as_function_ground_mut(
711        &mut self,
712    ) -> Option<(
713        &mut FuncAttr,
714        &mut Moo<GroundDomain>,
715        &mut Moo<GroundDomain>,
716    )> {
717        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground_mut() {
718            return Some((attrs, dom, codom));
719        }
720        None
721    }
722
723    /// If this is a partition domain, get its (attributes, domain)
724    pub fn as_partition(&self) -> Option<(PartitionAttr<IntVal>, Moo<Domain>)> {
725        if let Some(GroundDomain::Partition(attrs, doms)) = self.as_ground() {
726            return Some((attrs.clone().into(), doms.clone().into()));
727        }
728        if let Some(UnresolvedDomain::Partition(attrs, doms)) = self.as_unresolved() {
729            return Some((attrs.clone(), doms.clone()));
730        }
731        None
732    }
733
734    /// If this is a partition domain, get mutable reference to its attributes and element domain.
735    /// The domain always becomes [UnresolvedDomain::Partition] after this operation.
736    pub fn as_partition_mut(&mut self) -> Option<(&mut PartitionAttr<IntVal>, &mut DomainPtr)> {
737        if let Some(GroundDomain::Partition(attr_gd, inner_dom_gd)) = self.as_ground() {
738            let attr: PartitionAttr<IntVal> = attr_gd.clone().into();
739            let inner_dom = inner_dom_gd.clone().into();
740            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(attr, inner_dom)));
741        }
742
743        if let Some(UnresolvedDomain::Partition(attr, inner_dom)) = self.as_unresolved_mut() {
744            return Some((attr, inner_dom));
745        }
746        None
747    }
748
749    /// If this is a [GroundDomain::Partition], get immutable references to its attributes and inner domain
750    pub fn as_partition_ground(&self) -> Option<(&PartitionAttr<Int>, &Moo<GroundDomain>)> {
751        if let Some(GroundDomain::Partition(attr, inner_dom)) = self.as_ground() {
752            return Some((attr, inner_dom));
753        }
754        None
755    }
756
757    /// If this is a [GroundDomain::Partition], get mutable references to its attributes and inner domain
758    pub fn as_partition_ground_mut(
759        &mut self,
760    ) -> Option<(&mut PartitionAttr<Int>, &mut Moo<GroundDomain>)> {
761        if let Some(GroundDomain::Partition(attr, inner_dom)) = self.as_ground_mut() {
762            return Some((attr, inner_dom));
763        }
764        None
765    }
766
767    /// If this is a variant domain, clone and return its entries.
768    pub fn as_variant(&self) -> Option<Vec<FieldUnresolved>> {
769        if let Some(GroundDomain::Variant(entries)) = self.as_ground() {
770            return Some(entries.iter().cloned().map(|r| r.into()).collect());
771        }
772        if let Some(UnresolvedDomain::Variant(entries)) = self.as_unresolved() {
773            return Some(entries.clone());
774        }
775        None
776    }
777
778    /// If this is a [GroundDomain::Variant], get a mutable reference to its entries
779    pub fn as_variant_ground(&self) -> Option<&Vec<FieldGround>> {
780        if let Some(GroundDomain::Variant(entries)) = self.as_ground() {
781            return Some(entries);
782        }
783        None
784    }
785
786    /// If this is a variant domain, get a mutable reference to its list of entries.
787    /// The domain always becomes [UnresolvedDomain::Variant] after this operation.
788    pub fn as_variant_mut(&mut self) -> Option<&mut Vec<FieldUnresolved>> {
789        if let Some(GroundDomain::Variant(entries_gds)) = self.as_ground() {
790            let entries: Vec<FieldUnresolved> =
791                entries_gds.iter().cloned().map(|r| r.into()).collect();
792            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(entries)));
793        }
794
795        if let Some(UnresolvedDomain::Variant(entries_gds)) = self.as_unresolved_mut() {
796            return Some(entries_gds);
797        }
798        None
799    }
800
801    /// If this is a [GroundDomain::Variant], get a mutable reference to its entries
802    pub fn as_variant_ground_mut(&mut self) -> Option<&mut Vec<FieldGround>> {
803        if let Some(GroundDomain::Variant(entries)) = self.as_ground_mut() {
804            return Some(entries);
805        }
806        None
807    }
808
809    /// If this is a relation domain, get its (attributes, [domains])
810    pub fn as_relation(&self) -> Option<(RelAttr<IntVal>, Vec<Moo<Domain>>)> {
811        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
812            return Some((
813                attrs.clone().into(),
814                doms.iter().cloned().map(|d| d.into()).collect(),
815            ));
816        }
817        if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved() {
818            return Some((attrs.clone(), doms.clone()));
819        }
820        None
821    }
822
823    /// If this is a relation domain, convert it to unresolved and get mutable references to
824    /// its (attrs, [domains]).
825    /// The domain always becomes [UnresolvedDomain::Relation] after this operation.
826    pub fn as_relation_mut(&mut self) -> Option<(&mut RelAttr<IntVal>, &mut Vec<Moo<Domain>>)> {
827        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
828            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
829                attrs.clone().into(),
830                doms.iter().cloned().map(|d| d.into()).collect(),
831            )));
832        }
833
834        if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved_mut() {
835            return Some((attrs, doms));
836        }
837        None
838    }
839
840    /// If this is a [GroundDomain::Relation], get its (attrs, [domains])
841    pub fn as_relation_ground(&self) -> Option<(&RelAttr, &Vec<Moo<GroundDomain>>)> {
842        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
843            return Some((attrs, doms));
844        }
845        None
846    }
847
848    /// If this is a [GroundDomain::Relation], get mutable references to its (attrs, [domains])
849    pub fn as_relation_ground_mut(
850        &mut self,
851    ) -> Option<(&mut RelAttr, &mut Vec<Moo<GroundDomain>>)> {
852        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground_mut() {
853            return Some((attrs, doms));
854        }
855        None
856    }
857
858    /// Compute the intersection of two domains
859    pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
860        match (self, other) {
861            (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
862            (Domain::Unresolved(a), Domain::Unresolved(b)) => {
863                Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
864            }
865            (Domain::Unresolved(u), Domain::Ground(g))
866            | (Domain::Ground(g), Domain::Unresolved(u)) => {
867                todo!("Union of unresolved domain {u} and ground domain {g} is not yet implemented")
868            }
869        }
870    }
871
872    /// Compute the intersection of two ground domains
873    pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
874        match (self, other) {
875            (Domain::Ground(a), Domain::Ground(b)) => {
876                a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
877            }
878            _ => Err(DomainOpError::NotGround),
879        }
880    }
881
882    /// If the domain is ground, return an iterator over its values
883    pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
884        if let Some(gd) = self.as_ground() {
885            return gd.values();
886        }
887        Err(DomainOpError::NotGround)
888    }
889
890    /// If the domain is ground, return its size bound
891    pub fn length(&self) -> Result<u64, DomainOpError> {
892        if let Some(gd) = self.as_ground() {
893            return gd.length();
894        }
895        Err(DomainOpError::NotGround)
896    }
897    /// Get the size of some domain
898    ///
899    /// As opposed to `Domain::length`, this function returns a signed integer (`i32`) rather than unsigned.
900    /// * `DomainOpError::NotGround` - This function only applies to `ground` domains
901    /// * `DomainOpError::TooLarge` - Converting to an integer my not be possible if the domain is too big
902    pub fn length_signed(&self) -> Result<i32, DomainOpError> {
903        let gd = self.as_ground().ok_or(DomainOpError::NotGround)?;
904        let len = gd.length()?;
905        len.try_into().map_err(|_| DomainOpError::TooLarge)
906    }
907
908    /// Construct a ground domain from a slice of values
909    pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
910        GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
911    }
912
913    /// Returns true if `lit` is a valid value of this domain
914    pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
915        if let Some(gd) = self.as_ground() {
916            return gd.contains(lit);
917        }
918        Err(DomainOpError::NotGround)
919    }
920
921    pub fn element_domain(&self) -> Option<DomainPtr> {
922        match self {
923            Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
924            Domain::Unresolved(ud) => ud.element_domain(),
925        }
926    }
927}
928
929impl Typeable for Domain {
930    fn return_type(&self) -> ReturnType {
931        match self {
932            Domain::Ground(dom) => dom.return_type(),
933            Domain::Unresolved(dom) => dom.return_type(),
934        }
935    }
936}
937
938impl Display for Domain {
939    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
940        match &self {
941            Domain::Ground(gd) => gd.fmt(f),
942            Domain::Unresolved(ud) => ud.fmt(f),
943        }
944    }
945}
946
947fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
948    doms.iter()
949        .map(|idx| match idx.as_ref() {
950            Domain::Ground(idx_gd) => Some(idx_gd.clone()),
951            _ => None,
952        })
953        .collect()
954}
955
956#[cfg(test)]
957mod tests {
958    use super::*;
959    use crate::ast::Name;
960    use crate::{domain_int, range};
961
962    #[test]
963    fn test_negative_product() {
964        let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
965        let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
966        let res = d1
967            .as_ground()
968            .unwrap()
969            .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
970            .unwrap();
971
972        assert!(matches!(res, GroundDomain::Int(_)));
973        if let GroundDomain::Int(ranges) = res {
974            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
975        }
976    }
977
978    #[test]
979    fn test_negative_div() {
980        let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
981        let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
982        let res = d1
983            .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
984            .unwrap();
985
986        assert!(matches!(res, GroundDomain::Int(_)));
987        if let GroundDomain::Int(ranges) = res {
988            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
989        }
990    }
991
992    #[test]
993    fn test_length_basic() {
994        assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
995        assert_eq!(Domain::bool().length(), Ok(2));
996        assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
997        assert_eq!(
998            domain_int!(1..2, 5..).length(),
999            Err(DomainOpError::Unbounded)
1000        );
1001    }
1002    #[test]
1003    fn test_length_set_basic() {
1004        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
1005        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
1006        assert_eq!(s.length(), Ok(8));
1007
1008        // {{1,2}, {1,3}, {2,3}}
1009        let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
1010        assert_eq!(s.length(), Ok(3));
1011
1012        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
1013        let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
1014        assert_eq!(s.length(), Ok(6));
1015
1016        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
1017        let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
1018        assert_eq!(s.length(), Ok(7));
1019
1020        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
1021        let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
1022        assert_eq!(s.length(), Ok(7));
1023    }
1024
1025    #[test]
1026    fn test_length_set_nested() {
1027        // {
1028        // ∅,                                          -- all size 0
1029        // {∅}, {{1}}, {{2}}, {{1, 2}},                -- all size 1
1030        // {∅, {1}}, {∅, {2}}, {∅, {1, 2}},            -- all size 2
1031        // {{1}, {2}}, {{1}, {1, 2}}, {{2}, {1, 2}}
1032        // }
1033        let s2 = Domain::set(
1034            SetAttr::new_max_size(2),
1035            // {∅, {1}, {2}, {1,2}}
1036            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1037        );
1038        assert_eq!(s2.length(), Ok(11));
1039    }
1040
1041    #[test]
1042    fn test_length_set_unbounded_inner() {
1043        // leaf domain is unbounded
1044        let s2_bad = Domain::set(
1045            SetAttr::new_max_size(2),
1046            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
1047        );
1048        assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
1049    }
1050
1051    #[test]
1052    fn test_length_set_overflow() {
1053        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
1054        assert!(s.length().is_ok());
1055
1056        // current way of calculating the formula overflows for anything larger than this
1057        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
1058        assert_eq!(s.length(), Err(DomainOpError::TooLarge));
1059    }
1060
1061    #[test]
1062    fn test_length_tuple() {
1063        // 3 ways to pick first element, 2 ways to pick second element
1064        let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
1065        assert_eq!(t.length(), Ok(6));
1066    }
1067
1068    #[test]
1069    fn test_length_record() {
1070        // 3 ways to pick rec.a, 2 ways to pick rec.b
1071        let t = Domain::record(vec![
1072            Field {
1073                name: Name::user("a"),
1074                value: domain_int!(1..3),
1075            },
1076            Field {
1077                name: Name::user("b"),
1078                value: Domain::bool(),
1079            },
1080        ]);
1081        assert_eq!(t.length(), Ok(6));
1082    }
1083
1084    #[test]
1085    fn test_length_matrix_basic() {
1086        // 3 booleans -> [T, T, T], [T, T, F], ..., [F, F, F]
1087        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
1088        assert_eq!(m.length(), Ok(8));
1089
1090        // 2 numbers, each 1..3 -> 3*3 options
1091        let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
1092        assert_eq!(m.length(), Ok(9));
1093    }
1094
1095    #[test]
1096    fn test_length_matrix_2d() {
1097        // 2x3 matrix of booleans -> (2**2)**3 = 64 options
1098        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
1099        assert_eq!(m.length(), Ok(64));
1100    }
1101
1102    #[test]
1103    fn test_length_matrix_of_sets() {
1104        // 3 sets drawn from 1..2; 4**3 = 64 total options
1105        let m = Domain::matrix(
1106            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1107            vec![domain_int!(1..3)],
1108        );
1109        assert_eq!(m.length(), Ok(64));
1110    }
1111}