1
use super::attrs::SetAttr;
2
use super::ground::GroundDomain;
3
use super::range::Range;
4
use super::unresolved::{IntVal, UnresolvedDomain};
5
use crate::ast::domains::attrs::MSetAttr;
6
use crate::ast::{
7
    DeclarationPtr, DomainOpError, Expression, FuncAttr, Literal, Moo, RecordEntry,
8
    RecordEntryGround, Reference, ReturnType, Typeable,
9
};
10
use itertools::Itertools;
11
use polyquine::Quine;
12
use serde::{Deserialize, Serialize};
13
use std::fmt::{Display, Formatter};
14
use std::thread_local;
15
use uniplate::Uniplate;
16

            
17
/// The integer type used in all domain code (int ranges, set sizes, etc)
18
pub type Int = i32;
19

            
20
pub type DomainPtr = Moo<Domain>;
21

            
22
impl DomainPtr {
23
344640
    pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
24
344640
        self.as_ref().resolve()
25
344640
    }
26

            
27
    /// Convenience method to take [Domain::union] of the [Domain]s behind two [DomainPtr]s
28
    /// and wrap the result in a new [DomainPtr].
29
540
    pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
30
540
        self.as_ref().union(other.as_ref()).map(DomainPtr::new)
31
540
    }
32

            
33
    /// Convenience method to take [Domain::intersect] of the [Domain]s behind two [DomainPtr]s
34
    /// and wrap the result in a new [DomainPtr].
35
    pub fn intersect(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
36
        self.as_ref().intersect(other.as_ref()).map(DomainPtr::new)
37
    }
38
}
39

            
40
impl From<Moo<GroundDomain>> for DomainPtr {
41
90180
    fn from(value: Moo<GroundDomain>) -> Self {
42
90180
        Moo::new(Domain::Ground(value))
43
90180
    }
44
}
45

            
46
impl From<Moo<UnresolvedDomain>> for DomainPtr {
47
    fn from(value: Moo<UnresolvedDomain>) -> Self {
48
        Moo::new(Domain::Unresolved(value))
49
    }
50
}
51

            
52
impl From<GroundDomain> for DomainPtr {
53
19811
    fn from(value: GroundDomain) -> Self {
54
19811
        Moo::new(Domain::Ground(Moo::new(value)))
55
19811
    }
56
}
57

            
58
impl From<UnresolvedDomain> for DomainPtr {
59
    fn from(value: UnresolvedDomain) -> Self {
60
        Moo::new(Domain::Unresolved(Moo::new(value)))
61
    }
62
}
63

            
64
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
65
#[biplate(to=DomainPtr)]
66
#[biplate(to=GroundDomain)]
67
#[biplate(to=UnresolvedDomain)]
68
#[biplate(to=Expression)]
69
#[biplate(to=Reference)]
70
#[biplate(to=RecordEntry)]
71
#[biplate(to=IntVal)]
72
#[path_prefix(conjure_cp::ast)]
73
pub enum Domain {
74
    /// A fully resolved domain
75
    Ground(Moo<GroundDomain>),
76
    /// A domain which may contain references
77
    Unresolved(Moo<UnresolvedDomain>),
78
}
79

            
80
/// Types that have a [`Domain`].
81
pub trait HasDomain {
82
    /// Gets the [`Domain`] of `self`.
83
    fn domain_of(&self) -> DomainPtr;
84
}
85

            
86
impl<T: HasDomain> Typeable for T {
87
95491
    fn return_type(&self) -> ReturnType {
88
95491
        self.domain_of().return_type()
89
95491
    }
90
}
91

            
92
// Domain::Bool is completely static, so reuse the same chunk of memory
93
// for all bool domains to avoid many small memory allocations
94
thread_local! {
95
    static BOOL_DOMAIN: DomainPtr =
96
        Moo::new(Domain::Ground(Moo::new(GroundDomain::Bool)));
97
}
98

            
99
impl Domain {
100
    /// Create a new boolean domain and return a pointer to it.
101
    /// Boolean domains are always ground (see [GroundDomain::Bool]).
102
8476
    pub fn bool() -> DomainPtr {
103
8476
        BOOL_DOMAIN.with(Clone::clone)
104
8476
    }
105

            
106
    /// Create a new empty domain of the given type and return a pointer to it.
107
    /// Empty domains are always ground (see [GroundDomain::Empty]).
108
1
    pub fn empty(ty: ReturnType) -> DomainPtr {
109
1
        Moo::new(Domain::Ground(Moo::new(GroundDomain::Empty(ty))))
110
1
    }
111

            
112
    /// Create a new int domain with the given ranges.
113
    /// If the ranges are all ground, the variant will be [GroundDomain::Int].
114
    /// Otherwise, it will be [UnresolvedDomain::Int].
115
48186
    pub fn int<T>(ranges: Vec<T>) -> DomainPtr
116
48186
    where
117
48186
        T: Into<Range<IntVal>> + TryInto<Range<Int>> + Clone,
118
    {
119
48186
        if let Ok(int_rngs) = ranges
120
48186
            .iter()
121
48186
            .cloned()
122
48186
            .map(TryInto::try_into)
123
48186
            .collect::<Result<Vec<_>, _>>()
124
        {
125
47826
            return Domain::int_ground(int_rngs);
126
360
        }
127
360
        let unresolved_rngs: Vec<Range<IntVal>> = ranges.into_iter().map(Into::into).collect();
128
360
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Int(
129
360
            unresolved_rngs,
130
360
        ))))
131
48186
    }
132

            
133
    /// Create a new ground integer domain with the given ranges
134
51546
    pub fn int_ground(ranges: Vec<Range<Int>>) -> DomainPtr {
135
51546
        let rngs = Range::squeeze(&ranges);
136
51546
        Moo::new(Domain::Ground(Moo::new(GroundDomain::Int(rngs))))
137
51546
    }
138

            
139
    /// Create a new set domain with the given element domain and attributes.
140
    /// If the element domain and the attributes are ground, the variant
141
    /// will be [GroundDomain::Set]. Otherwise, it will be [UnresolvedDomain::Set].
142
232
    pub fn set<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
143
232
    where
144
232
        T: Into<SetAttr<IntVal>> + TryInto<SetAttr<Int>> + Clone,
145
    {
146
232
        if let Domain::Ground(gd) = inner_dom.as_ref()
147
232
            && let Ok(int_attr) = attr.clone().try_into()
148
        {
149
232
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Set(
150
232
                int_attr,
151
232
                gd.clone(),
152
232
            ))));
153
        }
154
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Set(
155
            attr.into(),
156
            inner_dom,
157
        ))))
158
232
    }
159

            
160
    /// Create a new multiset domain with the given element domain and attributes
161
360
    pub fn mset<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
162
360
    where
163
360
        T: Into<MSetAttr<IntVal>> + TryInto<MSetAttr<Int>> + Clone,
164
    {
165
360
        if let Domain::Ground(gd) = inner_dom.as_ref()
166
360
            && let Ok(int_attr) = attr.clone().try_into()
167
        {
168
360
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::MSet(
169
360
                int_attr,
170
360
                gd.clone(),
171
360
            ))));
172
        }
173
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(
174
            attr.into(),
175
            inner_dom,
176
        ))))
177
360
    }
178

            
179
    /// Create a new matrix domain with the given element domain and index domains.
180
    /// If the given domains are all ground, the variant will be [GroundDomain::Matrix].
181
    /// Otherwise, it will be [UnresolvedDomain::Matrix].
182
2284
    pub fn matrix(inner_dom: DomainPtr, idx_doms: Vec<DomainPtr>) -> DomainPtr {
183
2284
        if let Domain::Ground(gd) = inner_dom.as_ref()
184
2164
            && let Some(idx_gds) = as_grounds(&idx_doms)
185
        {
186
2064
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Matrix(
187
2064
                gd.clone(),
188
2064
                idx_gds,
189
2064
            ))));
190
220
        }
191
220
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
192
220
            inner_dom, idx_doms,
193
220
        ))))
194
2284
    }
195

            
196
    /// Create a new tuple domain with the given element domains.
197
    /// If the given domains are all ground, the variant will be [GroundDomain::Tuple].
198
    /// Otherwise, it will be [UnresolvedDomain::Tuple].
199
141
    pub fn tuple(inner_doms: Vec<DomainPtr>) -> DomainPtr {
200
141
        if let Some(inner_gds) = as_grounds(&inner_doms) {
201
141
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Tuple(inner_gds))));
202
        }
203
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
204
            inner_doms,
205
        ))))
206
141
    }
207

            
208
    /// Create a new tuple domain with the given entries.
209
    /// If the entries are all ground, the variant will be [GroundDomain::Record].
210
    /// Otherwise, it will be [UnresolvedDomain::Record].
211
21
    pub fn record(entries: Vec<RecordEntry>) -> DomainPtr {
212
21
        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
213
21
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Record(entries_gds))));
214
        }
215
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
216
            entries,
217
        ))))
218
21
    }
219

            
220
    /// Create a new [UnresolvedDomain::Reference] domain from a domain letting
221
640
    pub fn reference(ptr: DeclarationPtr) -> Option<DomainPtr> {
222
640
        let _ = ptr.as_domain_letting()?;
223
640
        Some(Moo::new(Domain::Unresolved(Moo::new(
224
640
            UnresolvedDomain::Reference(Reference::new(ptr)),
225
640
        ))))
226
640
    }
227

            
228
    /// Create a new function domain
229
520
    pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
230
520
    where
231
520
        T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
232
    {
233
520
        if let Ok(attrs_gd) = attrs.clone().try_into()
234
520
            && let Some(dom_gd) = dom.as_ground()
235
520
            && let Some(cdom_gd) = cdom.as_ground()
236
        {
237
520
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
238
520
                attrs_gd,
239
520
                Moo::new(dom_gd.clone()),
240
520
                Moo::new(cdom_gd.clone()),
241
520
            ))));
242
        }
243

            
244
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
245
            attrs.into(),
246
            dom,
247
            cdom,
248
        ))))
249
520
    }
250

            
251
    /// If this domain is ground, return a [Moo] to the underlying [GroundDomain].
252
    /// Otherwise, try to resolve it; Return None if this is not yet possible.
253
    /// Domains which contain references to givens cannot be resolved until these
254
    /// givens are substituted for their concrete values.
255
344640
    pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
256
344640
        match self {
257
298860
            Domain::Ground(gd) => Some(gd.clone()),
258
45780
            Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
259
        }
260
344640
    }
261

            
262
    /// If this domain is already ground, return a reference to the underlying [GroundDomain].
263
    /// Otherwise, return None. This method does NOT perform any resolution.
264
    /// See also: [Domain::resolve].
265
357124
    pub fn as_ground(&self) -> Option<&GroundDomain> {
266
357124
        match self {
267
354664
            Domain::Ground(gd) => Some(gd.as_ref()),
268
2460
            _ => None,
269
        }
270
357124
    }
271

            
272
    /// If this domain is already ground, return a mutable reference to the underlying [GroundDomain].
273
    /// Otherwise, return None. This method does NOT perform any resolution.
274
    pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
275
        match self {
276
            Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
277
            _ => None,
278
        }
279
    }
280

            
281
    /// If this domain is unresolved, return a reference to the underlying [UnresolvedDomain].
282
3140
    pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
283
3140
        match self {
284
1320
            Domain::Unresolved(ud) => Some(ud.as_ref()),
285
1820
            _ => None,
286
        }
287
3140
    }
288

            
289
    /// If this domain is unresolved, return a mutable reference to the underlying [UnresolvedDomain].
290
    pub fn as_unresolved_mut(&mut self) -> Option<&mut UnresolvedDomain> {
291
        match self {
292
            Domain::Unresolved(ud) => Some(Moo::<UnresolvedDomain>::make_mut(ud)),
293
            _ => None,
294
        }
295
    }
296

            
297
    /// If this is [GroundDomain::Empty(ty)], get a reference to the return type `ty`
298
    pub fn as_dom_empty(&self) -> Option<&ReturnType> {
299
        if let Some(GroundDomain::Empty(ty)) = self.as_ground() {
300
            return Some(ty);
301
        }
302
        None
303
    }
304

            
305
    /// If this is [GroundDomain::Empty(ty)], get a mutable reference to the return type `ty`
306
    pub fn as_dom_empty_mut(&mut self) -> Option<&mut ReturnType> {
307
        if let Some(GroundDomain::Empty(ty)) = self.as_ground_mut() {
308
            return Some(ty);
309
        }
310
        None
311
    }
312

            
313
    /// True if this is [GroundDomain::Bool]
314
240
    pub fn is_bool(&self) -> bool {
315
240
        self.return_type() == ReturnType::Bool
316
240
    }
317

            
318
    /// True if this is a [GroundDomain::Int] or an [UnresolvedDomain::Int]
319
    pub fn is_int(&self) -> bool {
320
        self.return_type() == ReturnType::Int
321
    }
322

            
323
    /// If this domain is [GroundDomain::Int] or [UnresolveDomain::Int], get
324
    /// its ranges. The ranges are cloned and upcast to Range<IntVal> if necessary.
325
4120
    pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
326
4120
        if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
327
4120
            return Some(rngs.iter().cloned().map(|r| r.into()).collect());
328
        }
329
        if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved() {
330
            return Some(rngs.clone());
331
        }
332
        None
333
4120
    }
334

            
335
    /// If this is an int domain, get a mutable reference to its ranges.
336
    /// The domain always becomes [UnresolvedDomain::Int] after this operation.
337
    pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
338
        // We're "upcasting" ground ranges (Range<Int>) to the more general
339
        // Range<IntVal>, which may contain references or expressions.
340
        // We know that for now they are still ground, but we're giving the user a mutable
341
        // reference, so they can overwrite the ranges with values that aren't ground.
342
        // So, the entire domain has to become non-ground as well.
343
        if let Some(GroundDomain::Int(rngs_gds)) = self.as_ground() {
344
            let rngs: Vec<Range<IntVal>> = rngs_gds.iter().cloned().map(|r| r.into()).collect();
345
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Int(rngs)))
346
        }
347

            
348
        if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved_mut() {
349
            return Some(rngs);
350
        }
351
        None
352
    }
353

            
354
    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
355
80
    pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
356
80
        if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
357
80
            return Some(rngs);
358
        }
359
        None
360
80
    }
361

            
362
    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
363
    pub fn as_int_ground_mut(&mut self) -> Option<&mut Vec<Range<Int>>> {
364
        if let Some(GroundDomain::Int(rngs)) = self.as_ground_mut() {
365
            return Some(rngs);
366
        }
367
        None
368
    }
369

            
370
    /// If this is a matrix domain, get pointers to its element domain
371
    /// and index domains.
372
30220
    pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
373
30220
        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
374
48600
            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
375
27080
            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
376
27080
            return Some((inner_dom, idx_doms));
377
3140
        }
378
3140
        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved() {
379
1200
            return Some((inner_dom.clone(), idx_doms.clone()));
380
1940
        }
381
1940
        None
382
30220
    }
383

            
384
    /// If this is a matrix domain, get mutable references to its element
385
    /// domain and its vector of index domains.
386
    /// The domain always becomes [UnresolvedDomain::Matrix] after this operation.
387
    pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
388
        // "upcast" the entire domain to UnresolvedDomain
389
        // See [Domain::as_dom_int_mut] for an explanation of why this is necessary
390
        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
391
            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
392
            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
393
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(inner_dom, idx_doms)));
394
        }
395

            
396
        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved_mut() {
397
            return Some((inner_dom, idx_doms));
398
        }
399
        None
400
    }
401

            
402
    /// If this is a [GroundDomain::Matrix], get immutable references to its element and index domains
403
10680
    pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
404
10680
        if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground() {
405
740
            return Some((inner_dom, idx_doms));
406
9940
        }
407
9940
        None
408
10680
    }
409

            
410
    /// If this is a [GroundDomain::Matrix], get mutable references to its element and index domains
411
    pub fn as_matrix_ground_mut(
412
        &mut self,
413
    ) -> Option<(&mut Moo<GroundDomain>, &mut Vec<Moo<GroundDomain>>)> {
414
        if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground_mut() {
415
            return Some((inner_dom, idx_doms));
416
        }
417
        None
418
    }
419

            
420
    /// If this is a set domain, get its attributes and a pointer to its element domain.
421
    pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
422
        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
423
            return Some((attr.clone().into(), inner_dom.clone().into()));
424
        }
425
        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
426
            return Some((attr.clone(), inner_dom.clone()));
427
        }
428
        None
429
    }
430

            
431
    /// If this is a set domain, get mutable reference to its attributes and element domain.
432
    /// The domain always becomes [UnresolvedDomain::Set] after this operation.
433
    pub fn as_set_mut(&mut self) -> Option<(&mut SetAttr<IntVal>, &mut DomainPtr)> {
434
        if let Some(GroundDomain::Set(attr_gd, inner_dom_gd)) = self.as_ground() {
435
            let attr: SetAttr<IntVal> = attr_gd.clone().into();
436
            let inner_dom = inner_dom_gd.clone().into();
437
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Set(attr, inner_dom)));
438
        }
439

            
440
        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved_mut() {
441
            return Some((attr, inner_dom));
442
        }
443
        None
444
    }
445

            
446
    /// If this is a [GroundDomain::Set], get immutable references to its attributes and inner domain
447
    pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
448
        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
449
            return Some((attr, inner_dom));
450
        }
451
        None
452
    }
453

            
454
    /// If this is a [GroundDomain::Set], get mutable references to its attributes and inner domain
455
    pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
456
        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
457
            return Some((attr, inner_dom));
458
        }
459
        None
460
    }
461

            
462
    /// If this is a tuple domain, get pointers to its element domains.
463
40
    pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
464
40
        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
465
80
            return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
466
        }
467
        if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved() {
468
            return Some(inner_doms.clone());
469
        }
470
        None
471
40
    }
472

            
473
    /// If this is a tuple domain, get a mutable reference to its vector of element domains.
474
    /// The domain always becomes [UnresolvedDomain::Tuple] after this operation.
475
    pub fn as_tuple_mut(&mut self) -> Option<&mut Vec<DomainPtr>> {
476
        if let Some(GroundDomain::Tuple(inner_doms_gds)) = self.as_ground() {
477
            let inner_doms: Vec<DomainPtr> =
478
                inner_doms_gds.iter().cloned().map(|d| d.into()).collect();
479
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(inner_doms)));
480
        }
481

            
482
        if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved_mut() {
483
            return Some(inner_doms);
484
        }
485
        None
486
    }
487

            
488
    /// If this is a [GroundDomain::Tuple], get immutable references to its element domains
489
    pub fn as_tuple_ground(&self) -> Option<&Vec<Moo<GroundDomain>>> {
490
        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
491
            return Some(inner_doms);
492
        }
493
        None
494
    }
495

            
496
    /// If this is a [GroundDomain::Tuple], get mutable reference to its element domains
497
    pub fn as_tuple_ground_mut(&mut self) -> Option<&mut Vec<Moo<GroundDomain>>> {
498
        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground_mut() {
499
            return Some(inner_doms);
500
        }
501
        None
502
    }
503

            
504
    /// If this is a record domain, clone and return its entries.
505
    pub fn as_record(&self) -> Option<Vec<RecordEntry>> {
506
        if let Some(GroundDomain::Record(record_entries)) = self.as_ground() {
507
            return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
508
        }
509
        if let Some(UnresolvedDomain::Record(record_entries)) = self.as_unresolved() {
510
            return Some(record_entries.clone());
511
        }
512
        None
513
    }
514

            
515
    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
516
    pub fn as_record_ground(&self) -> Option<&Vec<RecordEntryGround>> {
517
        if let Some(GroundDomain::Record(entries)) = self.as_ground() {
518
            return Some(entries);
519
        }
520
        None
521
    }
522

            
523
    /// If this is a record domain, get a mutable reference to its list of entries.
524
    /// The domain always becomes [UnresolvedDomain::Record] after this operation.
525
    pub fn as_record_mut(&mut self) -> Option<&mut Vec<RecordEntry>> {
526
        if let Some(GroundDomain::Record(entries_gds)) = self.as_ground() {
527
            let entries: Vec<RecordEntry> = entries_gds.iter().cloned().map(|r| r.into()).collect();
528
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Record(entries)));
529
        }
530

            
531
        if let Some(UnresolvedDomain::Record(entries_gds)) = self.as_unresolved_mut() {
532
            return Some(entries_gds);
533
        }
534
        None
535
    }
536

            
537
    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
538
    pub fn as_record_ground_mut(&mut self) -> Option<&mut Vec<RecordEntryGround>> {
539
        if let Some(GroundDomain::Record(entries)) = self.as_ground_mut() {
540
            return Some(entries);
541
        }
542
        None
543
    }
544

            
545
    /// If this is a function domain, get its (attributes, domain, co-domain)
546
    pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
547
        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
548
            return Some((
549
                attrs.clone().into(),
550
                dom.clone().into(),
551
                codom.clone().into(),
552
            ));
553
        }
554
        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
555
            return Some((attrs.clone(), dom.clone(), codom.clone()));
556
        }
557
        None
558
    }
559

            
560
    /// If this is a function domain, convert it to unresolved and get mutable references to
561
    /// its (attrs, domain, co-domain).
562
    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
563
    pub fn as_function_mut(
564
        &mut self,
565
    ) -> Option<(&mut FuncAttr<IntVal>, &mut Moo<Domain>, &mut Moo<Domain>)> {
566
        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
567
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
568
                attrs.clone().into(),
569
                dom.clone().into(),
570
                codom.clone().into(),
571
            )));
572
        }
573

            
574
        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved_mut() {
575
            return Some((attrs, dom, codom));
576
        }
577
        None
578
    }
579

            
580
    /// If this is a [GroundDomain::Function], get its (attrs, domain, co-domain)
581
    pub fn as_function_ground(
582
        &self,
583
    ) -> Option<(&FuncAttr, &Moo<GroundDomain>, &Moo<GroundDomain>)> {
584
        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
585
            return Some((attrs, dom, codom));
586
        }
587
        None
588
    }
589

            
590
    /// If this is a [GroundDomain::Function], get mutable references to its (attrs, domain, co-domain)
591
    pub fn as_function_ground_mut(
592
        &mut self,
593
    ) -> Option<(
594
        &mut FuncAttr,
595
        &mut Moo<GroundDomain>,
596
        &mut Moo<GroundDomain>,
597
    )> {
598
        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground_mut() {
599
            return Some((attrs, dom, codom));
600
        }
601
        None
602
    }
603

            
604
    /// Compute the intersection of two domains
605
540
    pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
606
540
        match (self, other) {
607
540
            (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
608
            (Domain::Unresolved(a), Domain::Unresolved(b)) => {
609
                Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
610
            }
611
            (Domain::Unresolved(u), Domain::Ground(g))
612
            | (Domain::Ground(g), Domain::Unresolved(u)) => {
613
                todo!("Union of unresolved domain {u} and ground domain {g} is not yet implemented")
614
            }
615
        }
616
540
    }
617

            
618
    /// Compute the intersection of two ground domains
619
    pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
620
        match (self, other) {
621
            (Domain::Ground(a), Domain::Ground(b)) => {
622
                a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
623
            }
624
            _ => Err(DomainOpError::NotGround),
625
        }
626
    }
627

            
628
    /// If the domain is ground, return an iterator over its values
629
20
    pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
630
20
        if let Some(gd) = self.as_ground() {
631
20
            return gd.values();
632
        }
633
        Err(DomainOpError::NotGround)
634
20
    }
635

            
636
    /// If the domain is ground, return its size bound
637
19
    pub fn length(&self) -> Result<u64, DomainOpError> {
638
19
        if let Some(gd) = self.as_ground() {
639
19
            return gd.length();
640
        }
641
        Err(DomainOpError::NotGround)
642
19
    }
643

            
644
    /// Construct a ground domain from a slice of values
645
1460
    pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
646
1460
        GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
647
1460
    }
648

            
649
    /// Returns true if `lit` is a valid value of this domain
650
3160
    pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
651
3160
        if let Some(gd) = self.as_ground() {
652
3160
            return gd.contains(lit);
653
        }
654
        Err(DomainOpError::NotGround)
655
3160
    }
656

            
657
20
    pub fn element_domain(&self) -> Option<DomainPtr> {
658
20
        match self {
659
20
            Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
660
            Domain::Unresolved(ud) => ud.element_domain(),
661
        }
662
20
    }
663
}
664

            
665
impl Typeable for Domain {
666
100700
    fn return_type(&self) -> ReturnType {
667
100700
        match self {
668
90220
            Domain::Ground(dom) => dom.return_type(),
669
10480
            Domain::Unresolved(dom) => dom.return_type(),
670
        }
671
100700
    }
672
}
673

            
674
impl Display for Domain {
675
191908
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
676
191908
        match &self {
677
186828
            Domain::Ground(gd) => gd.fmt(f),
678
5080
            Domain::Unresolved(ud) => ud.fmt(f),
679
        }
680
191908
    }
681
}
682

            
683
2305
fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
684
2305
    doms.iter()
685
2727
        .map(|idx| match idx.as_ref() {
686
2627
            Domain::Ground(idx_gd) => Some(idx_gd.clone()),
687
100
            _ => None,
688
2727
        })
689
2305
        .collect()
690
2305
}
691

            
692
#[cfg(test)]
693
mod tests {
694
    use super::*;
695
    use crate::ast::Name;
696
    use crate::{domain_int, range};
697

            
698
    #[test]
699
1
    fn test_negative_product() {
700
1
        let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
701
1
        let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
702
1
        let res = d1
703
1
            .as_ground()
704
1
            .unwrap()
705
16
            .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
706
1
            .unwrap();
707

            
708
1
        assert!(matches!(res, GroundDomain::Int(_)));
709
1
        if let GroundDomain::Int(ranges) = res {
710
1
            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
711
        }
712
1
    }
713

            
714
    #[test]
715
1
    fn test_negative_div() {
716
1
        let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
717
1
        let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
718
1
        let res = d1
719
16
            .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
720
1
            .unwrap();
721

            
722
1
        assert!(matches!(res, GroundDomain::Int(_)));
723
1
        if let GroundDomain::Int(ranges) = res {
724
1
            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
725
        }
726
1
    }
727

            
728
    #[test]
729
1
    fn test_length_basic() {
730
1
        assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
731
1
        assert_eq!(Domain::bool().length(), Ok(2));
732
1
        assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
733
1
        assert_eq!(
734
1
            domain_int!(1..2, 5..).length(),
735
            Err(DomainOpError::Unbounded)
736
        );
737
1
    }
738
    #[test]
739
1
    fn test_length_set_basic() {
740
        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
741
1
        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
742
1
        assert_eq!(s.length(), Ok(8));
743

            
744
        // {{1,2}, {1,3}, {2,3}}
745
1
        let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
746
1
        assert_eq!(s.length(), Ok(3));
747

            
748
        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
749
1
        let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
750
1
        assert_eq!(s.length(), Ok(6));
751

            
752
        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
753
1
        let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
754
1
        assert_eq!(s.length(), Ok(7));
755

            
756
        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
757
1
        let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
758
1
        assert_eq!(s.length(), Ok(7));
759
1
    }
760

            
761
    #[test]
762
1
    fn test_length_set_nested() {
763
        // {
764
        // ∅,                                          -- all size 0
765
        // {∅}, {{1}}, {{2}}, {{1, 2}},                -- all size 1
766
        // {∅, {1}}, {∅, {2}}, {∅, {1, 2}},            -- all size 2
767
        // {{1}, {2}}, {{1}, {1, 2}}, {{2}, {1, 2}}
768
        // }
769
1
        let s2 = Domain::set(
770
1
            SetAttr::new_max_size(2),
771
            // {∅, {1}, {2}, {1,2}}
772
1
            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
773
        );
774
1
        assert_eq!(s2.length(), Ok(11));
775
1
    }
776

            
777
    #[test]
778
1
    fn test_length_set_unbounded_inner() {
779
        // leaf domain is unbounded
780
1
        let s2_bad = Domain::set(
781
1
            SetAttr::new_max_size(2),
782
1
            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
783
        );
784
1
        assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
785
1
    }
786

            
787
    #[test]
788
1
    fn test_length_set_overflow() {
789
1
        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
790
1
        assert!(s.length().is_ok());
791

            
792
        // current way of calculating the formula overflows for anything larger than this
793
1
        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
794
1
        assert_eq!(s.length(), Err(DomainOpError::TooLarge));
795
1
    }
796

            
797
    #[test]
798
1
    fn test_length_tuple() {
799
        // 3 ways to pick first element, 2 ways to pick second element
800
1
        let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
801
1
        assert_eq!(t.length(), Ok(6));
802
1
    }
803

            
804
    #[test]
805
1
    fn test_length_record() {
806
        // 3 ways to pick rec.a, 2 ways to pick rec.b
807
1
        let t = Domain::record(vec![
808
1
            RecordEntry {
809
1
                name: Name::user("a"),
810
1
                domain: domain_int!(1..3),
811
1
            },
812
1
            RecordEntry {
813
1
                name: Name::user("b"),
814
1
                domain: Domain::bool(),
815
1
            },
816
        ]);
817
1
        assert_eq!(t.length(), Ok(6));
818
1
    }
819

            
820
    #[test]
821
1
    fn test_length_matrix_basic() {
822
        // 3 booleans -> [T, T, T], [T, T, F], ..., [F, F, F]
823
1
        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
824
1
        assert_eq!(m.length(), Ok(8));
825

            
826
        // 2 numbers, each 1..3 -> 3*3 options
827
1
        let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
828
1
        assert_eq!(m.length(), Ok(9));
829
1
    }
830

            
831
    #[test]
832
1
    fn test_length_matrix_2d() {
833
        // 2x3 matrix of booleans -> (2**2)**3 = 64 options
834
1
        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
835
1
        assert_eq!(m.length(), Ok(64));
836
1
    }
837

            
838
    #[test]
839
1
    fn test_length_matrix_of_sets() {
840
        // 3 sets drawn from 1..2; 4**3 = 64 total options
841
1
        let m = Domain::matrix(
842
1
            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
843
1
            vec![domain_int!(1..3)],
844
        );
845
1
        assert_eq!(m.length(), Ok(64));
846
1
    }
847
}