1
use crate::ast::domains::unresolved::EnumVariantVal;
2
use 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
};
9
use crate::ast::enumerated::EnumeratedType;
10
use crate::ast::{
11
    DeclarationPtr, DomainOpError, Expression, Field, FuncAttr, Literal, Moo, Reference, RelAttr,
12
    ReturnType, SequenceAttr, Typeable,
13
};
14
use itertools::Itertools;
15
use polyquine::Quine;
16
use serde::{Deserialize, Serialize};
17
use std::fmt::{Display, Formatter};
18
use std::thread_local;
19
use uniplate::Uniplate;
20

            
21
/// The integer type used in all domain code (int ranges, set sizes, etc)
22
pub type Int = i32;
23

            
24
/// Default lower bound used when a finite solver needs bounds for an unbounded integer.
25
///
26
/// One greater than [`i32::MIN`] so the magnitude of `OXIDE_INT_MIN` is representable as a
27
/// positive [`i32`].
28
pub const OXIDE_INT_MIN: Int = Int::MIN + 1;
29

            
30
/// Default upper bound used when a finite solver needs bounds for an unbounded integer.
31
pub const OXIDE_INT_MAX: Int = Int::MAX;
32

            
33
pub type DomainPtr = Moo<Domain>;
34

            
35
impl DomainPtr {
36
    /// This domain with `representation` as its top-level representation preference.
37
    ///
38
    /// Domains that cannot carry a preference are returned unchanged.
39
16761
    pub fn with_representation_preference(&self, representation: &str) -> DomainPtr {
40
16761
        let mut domain = self.clone();
41
16761
        Moo::make_mut(&mut domain).set_representation_preference(representation);
42
16761
        domain
43
16761
    }
44

            
45
5027127840
    pub fn resolve(&self) -> Result<Moo<GroundDomain>, DomainOpError> {
46
5027127840
        self.as_ref().resolve()
47
5027127840
    }
48

            
49
    /// Convenience method to take [Domain::union] of the [Domain]s behind two [DomainPtr]s
50
    /// and wrap the result in a new [DomainPtr].
51
2959143
    pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
52
2959143
        self.as_ref().union(other.as_ref()).map(DomainPtr::new)
53
2959143
    }
54

            
55
    /// Convenience method to take [Domain::intersect] of the [Domain]s behind two [DomainPtr]s
56
    /// and wrap the result in a new [DomainPtr].
57
    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)]
70
/// Variants are ordered from fully resolved to unresolved; keep broad matches in this order.
71
pub enum Domain {
72
    /// A fully resolved domain
73
    Ground(Moo<GroundDomain>),
74
    /// A domain which may contain references
75
    Unresolved(Moo<UnresolvedDomain>),
76
}
77

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

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

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

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

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

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

            
132
    /// Creates an integer domain holding the values of a collection, as in `int([i | i <- nums])`.
133
    ///
134
    /// Resolves to the concrete values once the collection can be evaluated, which for a
135
    /// collection built from `given`s is after instantiation.
136
    pub fn int_from_values(values: Expression) -> DomainPtr {
137
        // Evaluate now when the collection is already constant. Leaving it as an expression means
138
        // re-evaluating it on every domain query during rewriting, which is ruinous: `domain_or_init`
139
        // runs per node per rule attempt.
140
        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
    /// Create a new ground integer domain with the given ranges
150
131869840
    pub fn int_ground(ranges: Vec<Range<Int>>) -> DomainPtr {
151
131869840
        let rngs = Range::squeeze(&ranges);
152
131869840
        Moo::new(Domain::Ground(Moo::new(GroundDomain::Int(rngs, None))))
153
131869840
    }
154

            
155
    /// Create a new set domain with the given element domain and attributes.
156
    /// If the element domain and the attributes are ground, the variant
157
    /// will be [GroundDomain::Set]. Otherwise, it will be [UnresolvedDomain::Set].
158
653671
    pub fn set<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
159
653671
    where
160
653671
        T: Into<SetAttr<IntVal>> + TryInto<SetAttr<Int>> + Clone,
161
    {
162
653671
        if let Domain::Ground(gd) = inner_dom.as_ref()
163
640911
            && let Ok(int_attr) = attr.clone().try_into()
164
        {
165
632732
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Set(
166
632732
                int_attr,
167
632732
                gd.clone(),
168
632732
            ))));
169
20939
        }
170
20939
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Set(
171
20939
            attr.into(),
172
20939
            inner_dom,
173
20939
        ))))
174
653671
    }
175

            
176
    /// Create a new multiset domain with the given element domain and attributes
177
398133
    pub fn mset<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
178
398133
    where
179
398133
        T: Into<MSetAttr<IntVal>> + TryInto<MSetAttr<Int>> + Clone,
180
    {
181
398133
        if let Domain::Ground(gd) = inner_dom.as_ref()
182
387867
            && let Ok(int_attr) = attr.clone().try_into()
183
        {
184
387809
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::MSet(
185
387809
                int_attr,
186
387809
                gd.clone(),
187
387809
            ))));
188
10324
        }
189
10324
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(
190
10324
            attr.into(),
191
10324
            inner_dom,
192
10324
        ))))
193
398133
    }
194

            
195
    /// Create a new matrix domain with the given element domain and index domains.
196
    /// If the given domains are all ground, the variant will be [GroundDomain::Matrix].
197
    /// Otherwise, it will be [UnresolvedDomain::Matrix].
198
1991530
    pub fn matrix(inner_dom: DomainPtr, idx_doms: Vec<DomainPtr>) -> DomainPtr {
199
1991530
        if let Domain::Ground(gd) = inner_dom.as_ref()
200
1814929
            && let Some(idx_gds) = as_grounds(&idx_doms)
201
        {
202
1738715
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Matrix(
203
1738715
                gd.clone(),
204
1738715
                idx_gds,
205
1738715
                None,
206
1738715
            ))));
207
252815
        }
208
252815
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
209
252815
            inner_dom, idx_doms, None,
210
252815
        ))))
211
1991530
    }
212

            
213
    /// Create a new tuple domain with the given element domains.
214
    /// If the given domains are all ground, the variant will be [GroundDomain::Tuple].
215
    /// Otherwise, it will be [UnresolvedDomain::Tuple].
216
357467
    pub fn tuple(inner_doms: Vec<DomainPtr>) -> DomainPtr {
217
357467
        if let Some(inner_gds) = as_grounds(&inner_doms) {
218
357090
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Tuple(
219
357090
                inner_gds, None,
220
357090
            ))));
221
377
        }
222
377
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
223
377
            inner_doms, None,
224
377
        ))))
225
357467
    }
226

            
227
    /// Create a new tuple domain with the given entries.
228
    /// If the entries are all ground, the variant will be [GroundDomain::Record].
229
    /// Otherwise, it will be [UnresolvedDomain::Record].
230
19926
    pub fn record(entries: Vec<Field<DomainPtr>>) -> DomainPtr {
231
19926
        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
232
19607
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Record(
233
19607
                entries_gds,
234
19607
                None,
235
19607
            ))));
236
319
        }
237
319
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
238
319
            entries, None,
239
319
        ))))
240
19926
    }
241

            
242
    /// Create a new [UnresolvedDomain::Reference] domain from a domain letting
243
192881
    pub fn reference(ptr: DeclarationPtr) -> Option<DomainPtr> {
244
192881
        let _ = ptr.as_domain_letting()?;
245
192852
        Some(Moo::new(Domain::Unresolved(Moo::new(
246
192852
            UnresolvedDomain::Reference(Reference::new(ptr)),
247
192852
        ))))
248
192881
    }
249

            
250
    /// Create a new multiset domain with the given element domain and attributes
251
2278
    pub fn partition<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
252
2278
    where
253
2278
        T: Into<PartitionAttr<IntVal>> + TryInto<PartitionAttr<Int>> + Clone,
254
    {
255
2278
        if let Domain::Ground(gd) = inner_dom.as_ref()
256
2278
            && let Ok(int_attr) = attr.clone().try_into()
257
        {
258
2278
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Partition(
259
2278
                int_attr,
260
2278
                gd.clone(),
261
2278
            ))));
262
        }
263
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(
264
            attr.into(),
265
            inner_dom,
266
        ))))
267
2278
    }
268

            
269
    /// Create a new permutation domain with the given element domain and attributes
270
33263
    pub fn permutation<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
271
33263
    where
272
33263
        T: Into<PermutationAttr<IntVal>> + TryInto<PermutationAttr<Int>> + Clone,
273
    {
274
33263
        if let Domain::Ground(gd) = inner_dom.as_ref()
275
30102
            && let Ok(int_attr) = attr.clone().try_into()
276
        {
277
30102
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Permutation(
278
30102
                int_attr,
279
30102
                gd.clone(),
280
30102
            ))));
281
3161
        }
282
3161
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Permutation(
283
3161
            attr.into(),
284
3161
            inner_dom,
285
3161
        ))))
286
33263
    }
287

            
288
    /// Create a new function domain
289
52478
    pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
290
52478
    where
291
52478
        T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
292
    {
293
52478
        if let Ok(attrs_gd) = attrs.clone().try_into()
294
52478
            && let Some(dom_gd) = dom.as_ground()
295
51956
            && let Some(cdom_gd) = cdom.as_ground()
296
        {
297
51956
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
298
51956
                attrs_gd,
299
51956
                Moo::new(dom_gd.clone()),
300
51956
                Moo::new(cdom_gd.clone()),
301
51956
            ))));
302
522
        }
303

            
304
522
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
305
522
            attrs.into(),
306
522
            dom,
307
522
            cdom,
308
522
        ))))
309
52478
    }
310

            
311
    /// Create a new variant domain with the given entries.
312
    /// If the entries are all ground, the variant will be [GroundDomain::Variant].
313
    /// Otherwise, it will be [UnresolvedDomain::Variant].
314
23635
    pub fn variant(entries: Vec<Field<DomainPtr>>) -> DomainPtr {
315
23635
        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
316
23577
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Variant(
317
23577
                entries_gds,
318
23577
                None,
319
23577
            ))));
320
58
        }
321
58
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(
322
58
            entries, None,
323
58
        ))))
324
23635
    }
325

            
326
    /// Create a new relation domain
327
    /// If the entries are all ground, the variant will be [GroundDomain::Relation].
328
    /// Otherwise, it will be [UnresolvedDomain::Relation].
329
5671
    pub fn relation<T>(attrs: T, inner_doms: Vec<DomainPtr>) -> DomainPtr
330
5671
    where
331
5671
        T: Into<RelAttr<IntVal>> + TryInto<RelAttr<Int>> + Clone,
332
    {
333
5671
        if let Ok(attrs_gd) = attrs.clone().try_into()
334
5671
            && let Some(doms_gd) = as_grounds(&inner_doms)
335
        {
336
5613
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Relation(
337
5613
                attrs_gd, doms_gd,
338
5613
            ))));
339
58
        }
340

            
341
58
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
342
58
            attrs.into(),
343
58
            inner_doms,
344
58
        ))))
345
5671
    }
346

            
347
    /// Create a new Sequence domain
348
71583
    pub fn sequence<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
349
71583
    where
350
71583
        T: Into<SequenceAttr<IntVal>> + TryInto<SequenceAttr<Int>> + Clone,
351
    {
352
71583
        if let Domain::Ground(gd) = inner_dom.as_ref()
353
71463
            && let Ok(int_attr) = attr.clone().try_into()
354
        {
355
71463
            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Sequence(
356
71463
                int_attr,
357
71463
                gd.clone(),
358
71463
            ))));
359
120
        }
360
120
        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
361
120
            attr.into(),
362
120
            inner_dom,
363
120
        ))))
364
71583
    }
365

            
366
    /// Create a new enumerated type domain
367
392
    pub fn enumerated_ground(ty: Moo<EnumeratedType>, ranges: Vec<Range<u32>>) -> DomainPtr {
368
392
        Moo::new(Domain::Ground(Moo::new(GroundDomain::EnumeratedType(
369
392
            ty, ranges,
370
392
        ))))
371
392
    }
372

            
373
    /// Create a new enumerated type domain
374
4
    pub fn enumerated(ty: Moo<EnumeratedType>, ranges: Vec<Range<EnumVariantVal>>) -> DomainPtr {
375
4
        Moo::new(Domain::Unresolved(Moo::new(
376
4
            UnresolvedDomain::EnumeratedType(ty, ranges),
377
4
        )))
378
4
    }
379

            
380
    /// If this domain is ground, return a [Moo] to the underlying [GroundDomain].
381
    /// Otherwise, try to resolve it; Return None if this is not yet possible.
382
    /// Domains which contain references to givens cannot be resolved until these
383
    /// givens are substituted for their concrete values.
384
5027127840
    pub fn resolve(&self) -> Result<Moo<GroundDomain>, DomainOpError> {
385
5027127840
        match self {
386
4936184459
            Domain::Ground(gd) => Ok(gd.clone()),
387
90943381
            Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
388
        }
389
5027127840
    }
390

            
391
    /// If this domain is already ground, return a reference to the underlying [GroundDomain].
392
    /// Otherwise, return None. This method does NOT perform any resolution.
393
    /// See also: [Domain::resolve].
394
153409295
    pub fn as_ground(&self) -> Option<&GroundDomain> {
395
153409295
        match self {
396
147462393
            Domain::Ground(gd) => Some(gd.as_ref()),
397
5946902
            _ => None,
398
        }
399
153409295
    }
400

            
401
    /// If this domain is already ground, return a mutable reference to the underlying [GroundDomain].
402
    /// Otherwise, return None. This method does NOT perform any resolution.
403
1075
    pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
404
1075
        match self {
405
1075
            Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
406
            _ => None,
407
        }
408
1075
    }
409

            
410
    /// If this domain is unresolved, return a reference to the underlying [UnresolvedDomain].
411
20336330
    pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
412
20336330
        match self {
413
5871375
            Domain::Unresolved(ud) => Some(ud.as_ref()),
414
14464955
            _ => None,
415
        }
416
20336330
    }
417

            
418
    /// If this domain is unresolved, return a mutable reference to the underlying [UnresolvedDomain].
419
    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
    /// If this is [GroundDomain::Empty(ty)], get a reference to the return type `ty`
427
    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
    /// If this is [GroundDomain::Empty(ty)], get a mutable reference to the return type `ty`
435
    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
    /// True if this is [GroundDomain::Bool]
443
2161773042
    pub fn is_bool(&self) -> bool {
444
2161773042
        self.return_type() == ReturnType::Bool
445
2161773042
    }
446

            
447
    /// True if this is a [GroundDomain::Int] or an [UnresolvedDomain::Int]
448
73667350
    pub fn is_int(&self) -> bool {
449
73667350
        self.return_type() == ReturnType::Int
450
73667350
    }
451

            
452
    /// If this domain is [GroundDomain::Int] or [UnresolveDomain::Int], get
453
    /// its ranges. The ranges are cloned and upcast to Range<IntVal> if necessary.
454
11144206
    pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
455
11144206
        if let Some(GroundDomain::Int(rngs, _)) = self.as_ground() {
456
9740945
            return Some(rngs.iter().cloned().map(|r| r.into()).collect());
457
1900598
        }
458
1900598
        if let Some(UnresolvedDomain::Int(rngs, _)) = self.as_unresolved() {
459
46686
            return Some(rngs.clone());
460
1853912
        }
461
1853912
        None
462
11144206
    }
463

            
464
    /// If this is an int domain, get a mutable reference to its ranges.
465
    /// The domain always becomes [UnresolvedDomain::Int] after this operation.
466
    pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
467
        // We're "upcasting" ground ranges (Range<Int>) to the more general
468
        // Range<IntVal>, which may contain references or expressions.
469
        // We know that for now they are still ground, but we're giving the user a mutable
470
        // reference, so they can overwrite the ranges with values that aren't ground.
471
        // So, the entire domain has to become non-ground as well.
472
        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
    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
487
149712
    pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
488
149712
        if let Some(GroundDomain::Int(rngs, _)) = self.as_ground() {
489
149712
            return Some(rngs);
490
        }
491
        None
492
149712
    }
493

            
494
    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
495
    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
    /// If this is a matrix domain, get pointers to its element domain
503
    /// and index domains.
504
71029294
    pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
505
71029294
        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds, _)) = self.as_ground() {
506
67979933
            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
507
64548720
            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
508
64548720
            return Some((inner_dom, idx_doms));
509
6480574
        }
510
6480574
        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms, _)) = self.as_unresolved() {
511
5072329
            return Some((inner_dom.clone(), idx_doms.clone()));
512
1408245
        }
513
1408245
        None
514
71029294
    }
515

            
516
    /// If this is a matrix domain, get mutable references to its element
517
    /// domain and its vector of index domains.
518
    /// The domain always becomes [UnresolvedDomain::Matrix] after this operation.
519
    pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
520
        // "upcast" the entire domain to UnresolvedDomain
521
        // See [Domain::as_dom_int_mut] for an explanation of why this is necessary
522
        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
    /// If this is a [GroundDomain::Matrix], get immutable references to its element and index domains
541
277706
    pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
542
277706
        if let Some(GroundDomain::Matrix(inner_dom, idx_doms, _)) = self.as_ground() {
543
237889
            return Some((inner_dom, idx_doms));
544
39817
        }
545
39817
        None
546
277706
    }
547

            
548
    /// If this is a [GroundDomain::Matrix], get mutable references to its element and index domains
549
    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
    /// If this is a set domain, get its attributes and a pointer to its element domain.
559
2028508
    pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
560
2028508
        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
561
193790
            return Some((attr.clone().into(), inner_dom.clone().into()));
562
1834718
        }
563
1834718
        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
564
2
            return Some((attr.clone(), inner_dom.clone()));
565
1834716
        }
566
1834716
        None
567
2028508
    }
568

            
569
    /// If this is a set domain, get mutable reference to its attributes and element domain.
570
    /// The domain always becomes [UnresolvedDomain::Set] after this operation.
571
    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
    /// If this is a [GroundDomain::Set], get immutable references to its attributes and inner domain
585
17
    pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
586
17
        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
587
17
            return Some((attr, inner_dom));
588
        }
589
        None
590
17
    }
591

            
592
    /// If this is a [GroundDomain::Set], get mutable references to its attributes and inner domain
593
1075
    pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
594
1075
        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
595
1075
            return Some((attr, inner_dom));
596
        }
597
        None
598
1075
    }
599

            
600
    /// User-specified representation preference on this domain, if any (Essence short name).
601
    ///
602
    /// For set, multiset, and sequence domains this is the optional name in
603
    /// `set (representation packed) of …` / `mset (representation repetition) of …`. Nested
604
    /// preferences on element domains are not returned here; only the preference attached to
605
    /// this domain node.
606
2975813
    pub fn representation_preference(&self) -> Option<&str> {
607
2975813
        match self {
608
2864892
            Domain::Ground(gd) => match gd.as_ref() {
609
                GroundDomain::Int(_, representation)
610
                | GroundDomain::Tuple(_, representation)
611
                | GroundDomain::Record(_, representation)
612
                | GroundDomain::Variant(_, representation)
613
2170035
                | GroundDomain::Matrix(_, _, representation) => representation.as_deref(),
614
240425
                GroundDomain::Set(attr, _) => attr.representation.as_deref(),
615
84557
                GroundDomain::MSet(attr, _) => attr.representation.as_deref(),
616
45385
                GroundDomain::Sequence(attr, _) => attr.representation.as_deref(),
617
46342
                GroundDomain::Function(attr, _, _) => attr.representation.as_deref(),
618
37787
                GroundDomain::Relation(attr, _) => attr.representation.as_deref(),
619
                GroundDomain::Partition(attr, _) => attr.representation.as_deref(),
620
232
                GroundDomain::Permutation(attr, _) => attr.representation.as_deref(),
621
                GroundDomain::Empty(_)
622
                | GroundDomain::Bool
623
                | GroundDomain::EnumeratedType(_, _)
624
240129
                | GroundDomain::UnnamedType(_) => None,
625
            },
626
110921
            Domain::Unresolved(ud) => match ud.as_ref() {
627
                UnresolvedDomain::Int(_, representation)
628
                | UnresolvedDomain::Tuple(_, representation)
629
                | UnresolvedDomain::Record(_, representation)
630
                | UnresolvedDomain::Variant(_, representation)
631
73161
                | UnresolvedDomain::Matrix(_, _, representation) => representation.as_deref(),
632
2
                UnresolvedDomain::Set(attr, _) => attr.representation.as_deref(),
633
10614
                UnresolvedDomain::MSet(attr, _) => attr.representation.as_deref(),
634
                UnresolvedDomain::Sequence(attr, _) => attr.representation.as_deref(),
635
522
                UnresolvedDomain::Function(attr, _, _) => attr.representation.as_deref(),
636
                UnresolvedDomain::Relation(attr, _) => attr.representation.as_deref(),
637
                UnresolvedDomain::Partition(attr, _) => attr.representation.as_deref(),
638
174
                UnresolvedDomain::Permutation(attr, _) => attr.representation.as_deref(),
639
                UnresolvedDomain::IntFromValues(_)
640
                | UnresolvedDomain::Reference(_)
641
                | UnresolvedDomain::EnumeratedType(_, _)
642
26448
                | UnresolvedDomain::UnnamedType(_) => None,
643
            },
644
        }
645
2975813
    }
646

            
647
    /// Set the top-level representation preference of this domain, if its kind can carry one.
648
16761
    pub fn set_representation_preference(&mut self, representation: &str) {
649
16761
        let representation = Some(representation.to_owned());
650
16761
        match self {
651
16413
            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
679
                | GroundDomain::Matrix(_, _, preference) => *preference = representation,
657
13646
                GroundDomain::Set(attr, _) => attr.representation = representation,
658
2088
                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
348
            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
348
                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
16761
    }
689

            
690
    /// Whether any representation preference appears anywhere in this domain tree.
691
30
    pub fn has_representation_preference(&self) -> bool {
692
30
        if self.representation_preference().is_some() {
693
            return true;
694
30
        }
695
30
        match self {
696
30
            Domain::Ground(gd) => gd.has_representation_preference(),
697
            Domain::Unresolved(ud) => ud.has_representation_preference(),
698
        }
699
30
    }
700

            
701
    /// Format this domain in Essence type style (`int`, `set (representation packed) of int`, …),
702
    /// omitting size attributes and integer ranges.
703
873
    pub fn as_type_string(&self) -> String {
704
873
        match self {
705
873
            Domain::Ground(gd) => gd.as_type_string(),
706
            Domain::Unresolved(ud) => ud.as_type_string(),
707
        }
708
873
    }
709

            
710
    /// If this is a mset domain, get its attributes and a pointer to its element domain.
711
2077261
    pub fn as_mset(&self) -> Option<(MSetAttr<IntVal>, DomainPtr)> {
712
2077261
        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
713
246575
            return Some((attr.clone().into(), inner_dom.clone().into()));
714
1830686
        }
715
1830686
        if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved() {
716
464
            return Some((attr.clone(), inner_dom.clone()));
717
1830222
        }
718
1830222
        None
719
2077261
    }
720

            
721
    /// If this is a set domain, get mutable reference to its attributes and element domain.
722
    /// The domain always becomes [UnresolvedDomain::MSet] after this operation.
723
    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
    /// If this is a [GroundDomain::MSet], get immutable references to its attributes and inner domain
737
33
    pub fn as_mset_ground(&self) -> Option<(&MSetAttr<Int>, &Moo<GroundDomain>)> {
738
33
        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
739
33
            return Some((attr, inner_dom));
740
        }
741
        None
742
33
    }
743

            
744
    /// If this is a [GroundDomain::MSet], get mutable references to its attributes and inner domain
745
    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
    /// If this is a tuple domain, get pointers to its element domains.
753
4024860
    pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
754
4024860
        if let Some(GroundDomain::Tuple(inner_doms, _)) = self.as_ground() {
755
688489
            return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
756
3680775
        }
757
3680775
        if let Some(UnresolvedDomain::Tuple(inner_doms, _)) = self.as_unresolved() {
758
            return Some(inner_doms.clone());
759
3680775
        }
760
3680775
        None
761
4024860
    }
762

            
763
    /// If this is a tuple domain, get a mutable reference to its vector of element domains.
764
    /// The domain always becomes [UnresolvedDomain::Tuple] after this operation.
765
    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
    /// If this is a [GroundDomain::Tuple], get immutable references to its element domains
782
    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
    /// If this is a [GroundDomain::Tuple], get mutable reference to its element domains
790
    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
    /// If this is a record domain, clone and return its entries.
798
2448198
    pub fn as_record(&self) -> Option<Vec<FieldUnresolved>> {
799
2448198
        if let Some(GroundDomain::Record(record_entries, _)) = self.as_ground() {
800
494
            return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
801
2447936
        }
802
2447936
        if let Some(UnresolvedDomain::Record(record_entries, _)) = self.as_unresolved() {
803
            return Some(record_entries.clone());
804
2447936
        }
805
2447936
        None
806
2448198
    }
807

            
808
    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
809
    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
    /// If this is a record domain, get a mutable reference to its list of entries.
817
    /// The domain always becomes [UnresolvedDomain::Record] after this operation.
818
    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
    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
835
    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
    /// If this is a sequence domain, get its (attributes, domain)
843
5362
    pub fn as_sequence(&self) -> Option<(SequenceAttr<IntVal>, Moo<Domain>)> {
844
5362
        if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
845
4528
            return Some((attrs.clone().into(), dom.clone().into()));
846
834
        }
847
834
        if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved() {
848
58
            return Some((attrs.clone(), dom.clone()));
849
776
        }
850
776
        None
851
5362
    }
852

            
853
    /// If this is a function domain, convert it to unresolved and get mutable references to
854
    /// its (attrs, domain, co-domain).
855
    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
856
    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
    /// If this is a function domain, get its (attributes, domain, co-domain)
871
15314
    pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
872
15314
        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
873
15135
            return Some((
874
15135
                attrs.clone().into(),
875
15135
                dom.clone().into(),
876
15135
                codom.clone().into(),
877
15135
            ));
878
179
        }
879
179
        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
880
            return Some((attrs.clone(), dom.clone(), codom.clone()));
881
179
        }
882
179
        None
883
15314
    }
884

            
885
    /// If this is a function domain, convert it to unresolved and get mutable references to
886
    /// its (attrs, domain, co-domain).
887
    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
888
    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
    /// If this is a [GroundDomain::Function], get its (attrs, domain, co-domain)
906
    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
    /// If this is a [GroundDomain::Function], get mutable references to its (attrs, domain, co-domain)
916
    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
    /// If this is a partition domain, get its (attributes, domain)
930
194
    pub fn as_partition(&self) -> Option<(PartitionAttr<IntVal>, Moo<Domain>)> {
931
194
        if let Some(GroundDomain::Partition(attrs, doms)) = self.as_ground() {
932
194
            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
194
    }
939

            
940
    /// If this is a partition domain, get mutable reference to its attributes and element domain.
941
    /// The domain always becomes [UnresolvedDomain::Partition] after this operation.
942
    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
    /// If this is a [GroundDomain::Partition], get immutable references to its attributes and inner domain
956
    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
    /// If this is a [GroundDomain::Partition], get mutable references to its attributes and inner domain
964
    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
    /// If this is a permutation domain, get its (attributes, domain)
974
    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
    /// If this is a permutation domain, get mutable reference to its attributes and element
985
    /// domain. The domain always becomes [UnresolvedDomain::Permutation] after this operation.
986
    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
    /// If this is a [GroundDomain::Permutation], get immutable references to its attributes and inner domain
    pub fn as_permutation_ground(&self) -> Option<(&PermutationAttr<Int>, &Moo<GroundDomain>)> {
        if let Some(GroundDomain::Permutation(attr, inner_dom)) = self.as_ground() {
            return Some((attr, inner_dom));
        }
        None
    }
    /// If this is a [GroundDomain::Permutation], get mutable references to its attributes and inner domain
    pub fn as_permutation_ground_mut(
        &mut self,
    ) -> Option<(&mut PermutationAttr<Int>, &mut Moo<GroundDomain>)> {
        if let Some(GroundDomain::Permutation(attr, inner_dom)) = self.as_ground_mut() {
            return Some((attr, inner_dom));
        }
        None
    }
    /// If this is a variant domain, clone and return its entries.
2154601
    pub fn as_variant(&self) -> Option<Vec<FieldUnresolved>> {
2154601
        if let Some(GroundDomain::Variant(entries, _)) = self.as_ground() {
232
            return Some(entries.iter().cloned().map(|r| r.into()).collect());
2154485
        }
2154485
        if let Some(UnresolvedDomain::Variant(entries, _)) = self.as_unresolved() {
            return Some(entries.clone());
2154485
        }
2154485
        None
2154601
    }
    /// If this is a [GroundDomain::Variant], get a mutable reference to its entries
    pub fn as_variant_ground(&self) -> Option<&Vec<FieldGround>> {
        if let Some(GroundDomain::Variant(entries, _)) = self.as_ground() {
            return Some(entries);
        }
        None
    }
    /// If this is a variant domain, get a mutable reference to its list of entries.
    /// The domain always becomes [UnresolvedDomain::Variant] after this operation.
    pub fn as_variant_mut(&mut self) -> Option<&mut Vec<FieldUnresolved>> {
        if let Some(GroundDomain::Variant(entries_gds, representation)) = self.as_ground() {
            let entries: Vec<FieldUnresolved> =
                entries_gds.iter().cloned().map(|r| r.into()).collect();
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(
                entries,
                representation.clone(),
            )));
        }
        if let Some(UnresolvedDomain::Variant(entries_gds, _)) = self.as_unresolved_mut() {
            return Some(entries_gds);
        }
        None
    }
    /// If this is a [GroundDomain::Variant], get a mutable reference to its entries
    pub fn as_variant_ground_mut(&mut self) -> Option<&mut Vec<FieldGround>> {
        if let Some(GroundDomain::Variant(entries, _)) = self.as_ground_mut() {
            return Some(entries);
        }
        None
    }
    /// If this is a relation domain, get its (attributes, [domains])
5549
    pub fn as_relation(&self) -> Option<(RelAttr<IntVal>, Vec<Moo<Domain>>)> {
5549
        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
            return Some((
8
                attrs.clone().into(),
24
                doms.iter().cloned().map(|d| d.into()).collect(),
            ));
5541
        }
5541
        if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved() {
            return Some((attrs.clone(), doms.clone()));
5541
        }
5541
        None
5549
    }
    /// If this is a relation domain, convert it to unresolved and get mutable references to
    /// its (attrs, [domains]).
    /// The domain always becomes [UnresolvedDomain::Relation] after this operation.
    pub fn as_relation_mut(&mut self) -> Option<(&mut RelAttr<IntVal>, &mut Vec<Moo<Domain>>)> {
        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
                attrs.clone().into(),
                doms.iter().cloned().map(|d| d.into()).collect(),
            )));
        }
        if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved_mut() {
            return Some((attrs, doms));
        }
        None
    }
    /// If this is a [GroundDomain::Relation], get its (attrs, [domains])
    pub fn as_relation_ground(&self) -> Option<(&RelAttr, &Vec<Moo<GroundDomain>>)> {
        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
            return Some((attrs, doms));
        }
        None
    }
    /// If this is a [GroundDomain::Relation], get mutable references to its (attrs, [domains])
    pub fn as_relation_ground_mut(
        &mut self,
    ) -> Option<(&mut RelAttr, &mut Vec<Moo<GroundDomain>>)> {
        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground_mut() {
            return Some((attrs, doms));
        }
        None
    }
    /// Compute the union of two domains.
    ///
    /// Domain-letting references are transparent here: the result may remain unresolved when the
    /// referenced domain has symbolic bounds.
2980491
    pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
2980491
        if let Domain::Unresolved(domain) = self
4
            && let UnresolvedDomain::Reference(reference) = domain.as_ref()
        {
3
            let referenced_domain = reference.domain().unwrap_or_else(|| {
                crate::bug!("domain reference should point to a domain letting: {reference}")
            });
3
            return referenced_domain.as_ref().union(other);
2980488
        }
2980488
        if let Domain::Unresolved(domain) = other
1
            && let UnresolvedDomain::Reference(reference) = domain.as_ref()
        {
1
            let referenced_domain = reference.domain().unwrap_or_else(|| {
                crate::bug!("domain reference should point to a domain letting: {reference}")
            });
1
            return self.union(referenced_domain.as_ref());
2980487
        }
2980487
        match (self, other) {
2980486
            (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
            (Domain::Unresolved(a), Domain::Unresolved(b)) => {
                Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
            }
            (Domain::Unresolved(u), Domain::Ground(g))
            | (Domain::Ground(g), Domain::Unresolved(u)) => {
1
                if let GroundDomain::Empty(ty) = g.as_ref() {
                    return if *ty == u.return_type() {
                        Ok(Domain::Unresolved(u.clone()))
                    } else {
                        Err(DomainOpError::WrongType)
                    };
1
                }
                let ground_as_unresolved =
1
                    UnresolvedDomain::from_ground(g).ok_or(DomainOpError::WrongType)?;
1
                Ok(Domain::Unresolved(Moo::new(
1
                    u.union_unresolved(&ground_as_unresolved)?,
                )))
            }
        }
2980491
    }
    /// Compute the intersection of two ground domains
    pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
        match (self, other) {
            (Domain::Ground(a), Domain::Ground(b)) => {
                a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
            }
            _ => Err(DomainOpError::NotGround),
        }
    }
    /// If the domain is ground, return an iterator over its values
986
    pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
986
        if let Some(gd) = self.as_ground() {
986
            return gd.values();
        }
        Err(DomainOpError::NotGround)
986
    }
    /// If the domain is ground, return its size bound
8439137
    pub fn length(&self) -> Result<u64, DomainOpError> {
8439137
        if let Some(gd) = self.as_ground() {
8439137
            return gd.length();
        }
        Err(DomainOpError::NotGround)
8439137
    }
    /// Get the size of some domain
    ///
    /// As opposed to `Domain::length`, this function returns a signed integer (`i32`) rather than unsigned.
    /// * `DomainOpError::NotGround` - This function only applies to `ground` domains
    /// * `DomainOpError::TooLarge` - Converting to an integer my not be possible if the domain is too big
704
    pub fn length_signed(&self) -> Result<i32, DomainOpError> {
704
        let gd = self.as_ground().ok_or(DomainOpError::NotGround)?;
704
        let len = gd.length()?;
704
        len.try_into().map_err(|_| DomainOpError::TooLarge)
704
    }
    /// Construct a ground domain from a slice of values
1625702
    pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
1625702
        GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
1625702
    }
    /// Returns true if `lit` is a valid value of this domain
    pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
        if let Some(gd) = self.as_ground() {
            return gd.contains(lit);
        }
        Err(DomainOpError::NotGround)
    }
316593
    pub fn element_domain(&self) -> Option<DomainPtr> {
316593
        match self {
176871
            Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
139722
            Domain::Unresolved(ud) => ud.element_domain(),
        }
316593
    }
}
impl Typeable for Domain {
3193210765
    fn return_type(&self) -> ReturnType {
3193210765
        match self {
3178847232
            Domain::Ground(dom) => dom.return_type(),
14363533
            Domain::Unresolved(dom) => dom.return_type(),
        }
3193210765
    }
}
impl Display for Domain {
17594274
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
17594274
        match &self {
15785882
            Domain::Ground(gd) => gd.fmt(f),
1808392
            Domain::Unresolved(ud) => ud.fmt(f),
        }
17594274
    }
}
2178067
fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
2178067
    doms.iter()
2649792
        .map(|idx| match idx.as_ref() {
2573143
            Domain::Ground(idx_gd) => Some(idx_gd.clone()),
76649
            _ => None,
2649792
        })
        .collect()
2178067
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::ast::Name;
    use crate::{domain_int, range};
    #[test]
1
    fn unresolved_int_domain_resolve_squeezes_ranges() {
1
        let domain = UnresolvedDomain::Int(
1
            vec![
1
                Range::Single(IntVal::Const(5)),
1
                Range::Bounded(IntVal::Const(3), IntVal::Const(7)),
1
                Range::Bounded(IntVal::Const(5), IntVal::Const(3)),
1
                Range::Single(IntVal::Const(7)),
1
            ],
1
            None,
1
        );
1
        assert_eq!(
1
            domain.resolve(),
1
            Ok(GroundDomain::Int(vec![Range::Bounded(3, 7)], None))
        );
1
    }
    #[test]
1
    fn union_dereferences_domain_lettings() {
1
        let declaration = DeclarationPtr::new_domain_letting(
1
            Name::user("Alias"),
1
            Domain::int(vec![Range::Bounded(1, 3)]),
1
        );
1
        let alias = Domain::reference(declaration).unwrap();
1
        assert_eq!(
1
            alias
1
                .union(&Domain::int(vec![Range::Bounded(5, 7)]))
1
                .unwrap()
1
                .resolve(),
1
            Ok(Moo::new(GroundDomain::Int(
1
                vec![Range::Bounded(1, 3), Range::Bounded(5, 7),],
1
                None
1
            )))
        );
1
    }
    #[test]
1
    fn union_preserves_symbolic_domain_bounds() {
        let upper_bound =
1
            DeclarationPtr::new_given(Name::user("n"), Domain::int(vec![Range::Bounded(1, 10)]));
1
        let symbolic_upper = IntVal::new_ref(&Reference::new(upper_bound)).unwrap();
1
        let symbolic_domain = Domain::int(vec![Range::Bounded(
1
            IntVal::Const(1),
1
            symbolic_upper.clone(),
1
        )]);
1
        let declaration = DeclarationPtr::new_domain_letting(Name::user("Alias"), symbolic_domain);
1
        let alias = Domain::reference(declaration).unwrap();
1
        let union = alias.union(&Domain::int(vec![Range::Single(20)])).unwrap();
1
        assert_eq!(
1
            union.as_int(),
1
            Some(vec![
1
                Range::Bounded(IntVal::Const(1), symbolic_upper),
1
                Range::Single(IntVal::Const(20)),
1
            ])
        );
1
        assert_eq!(union.resolve(), Err(DomainOpError::NotGround));
1
    }
    #[test]
1
    fn test_negative_product() {
1
        let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
1
        let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
1
        let res = d1
1
            .as_ground()
1
            .unwrap()
16
            .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
            .unwrap();
1
        assert!(matches!(res, GroundDomain::Int(_, _)));
1
        if let GroundDomain::Int(ranges, _) = res {
1
            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
        }
1
    }
    #[test]
1
    fn test_negative_div() {
1
        let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)], None);
1
        let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)], None);
1
        let res = d1
16
            .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
            .unwrap();
1
        assert!(matches!(res, GroundDomain::Int(_, _)));
1
        if let GroundDomain::Int(ranges, _) = res {
1
            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
        }
1
    }
    #[test]
1
    fn test_length_basic() {
1
        assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
1
        assert_eq!(Domain::bool().length(), Ok(2));
1
        assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
1
        assert_eq!(
1
            domain_int!(1..2, 5..).length(),
1
            Err(DomainOpError::Unbounded)
        );
1
    }
    #[test]
1
    fn test_length_set_basic() {
        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
1
        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
1
        assert_eq!(s.length(), Ok(8));
        // {{1,2}, {1,3}, {2,3}}
1
        let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
1
        assert_eq!(s.length(), Ok(3));
        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
1
        let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
1
        assert_eq!(s.length(), Ok(6));
        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
1
        let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
1
        assert_eq!(s.length(), Ok(7));
        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
1
        let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
1
        assert_eq!(s.length(), Ok(7));
1
    }
    #[test]
1
    fn test_set_representation_preference_display() {
1
        let s = Domain::set(
1
            SetAttr::new_max_size(3).with_representation("packed"),
1
            domain_int!(1..4),
1
        );
1
        assert_eq!(
1
            s.to_string(),
1
            "set (representation packed, maxSize 3) of int(1..4)"
        );
1
        assert_eq!(s.as_type_string(), "set (representation packed) of int");
1
        assert_eq!(s.representation_preference(), Some("packed"));
1
        let nested = Domain::set(
1
            SetAttr::<IntVal>::default().with_representation("explicit"),
1
            Domain::set(
1
                SetAttr::<IntVal>::default().with_representation("occurrence"),
1
                domain_int!(1..2),
1
            ),
1
        );
1
        assert_eq!(
1
            nested.to_string(),
1
            "set (representation explicit) of set (representation occurrence) of int(1..2)"
        );
1
        assert_eq!(
1
            nested.as_type_string(),
1
            "set (representation explicit) of set (representation occurrence) of int"
        );
1
    }
    #[test]
1
    fn test_mset_representation_preference_survives_nesting() {
1
        let mset = Domain::mset(
1
            MSetAttr::new_max_size(IntVal::Const(6)).with_representation("repetition"),
1
            domain_int!(1..9),
1
        );
1
        let nested = Domain::matrix(
1
            Domain::record(vec![Field {
1
                name: Name::user("before"),
1
                value: mset.clone(),
1
            }]),
1
            vec![domain_int!(1..2)],
1
        );
1
        assert_eq!(mset.representation_preference(), Some("repetition"));
1
        assert_eq!(
1
            mset.as_type_string(),
1
            "mset (representation repetition) of int"
        );
1
        assert_eq!(
1
            mset.to_string(),
1
            "mset (representation repetition, maxSize 6) of int(1..9)"
        );
1
        assert!(nested.has_representation_preference());
1
        assert_eq!(
1
            nested.to_string(),
1
            "matrix indexed by [int(1..2)] of record {before: mset (representation repetition, maxSize 6) of int(1..9)}"
        );
1
    }
    #[test]
1
    fn test_length_set_nested() {
        // {
        // ∅,                                          -- all size 0
        // {∅}, {{1}}, {{2}}, {{1, 2}},                -- all size 1
        // {∅, {1}}, {∅, {2}}, {∅, {1, 2}},            -- all size 2
        // {{1}, {2}}, {{1}, {1, 2}}, {{2}, {1, 2}}
        // }
1
        let s2 = Domain::set(
1
            SetAttr::new_max_size(2),
            // {∅, {1}, {2}, {1,2}}
1
            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1
        );
1
        assert_eq!(s2.length(), Ok(11));
1
    }
    #[test]
1
    fn test_length_set_unbounded_inner() {
        // leaf domain is unbounded
1
        let s2_bad = Domain::set(
1
            SetAttr::new_max_size(2),
1
            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
1
        );
1
        assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
1
    }
    #[test]
1
    fn test_length_set_overflow() {
1
        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
1
        assert!(s.length().is_ok());
        // current way of calculating the formula overflows for anything larger than this
1
        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
1
        assert_eq!(s.length(), Err(DomainOpError::TooLarge));
1
    }
    #[test]
1
    fn test_length_tuple() {
        // 3 ways to pick first element, 2 ways to pick second element
1
        let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
1
        assert_eq!(t.length(), Ok(6));
1
    }
    #[test]
1
    fn test_length_record() {
        // 3 ways to pick rec.a, 2 ways to pick rec.b
1
        let t = Domain::record(vec![
1
            Field {
1
                name: Name::user("a"),
1
                value: domain_int!(1..3),
1
            },
1
            Field {
1
                name: Name::user("b"),
1
                value: Domain::bool(),
1
            },
1
        ]);
1
        assert_eq!(t.length(), Ok(6));
1
    }
    #[test]
1
    fn test_length_matrix_basic() {
        // 3 booleans -> [T, T, T], [T, T, F], ..., [F, F, F]
1
        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
1
        assert_eq!(m.length(), Ok(8));
        // 2 numbers, each 1..3 -> 3*3 options
1
        let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
1
        assert_eq!(m.length(), Ok(9));
1
    }
    #[test]
1
    fn test_length_matrix_2d() {
        // 2x3 matrix of booleans -> (2**2)**3 = 64 options
1
        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
1
        assert_eq!(m.length(), Ok(64));
1
    }
    #[test]
1
    fn test_length_matrix_of_sets() {
        // 3 sets drawn from 1..2; 4**3 = 64 total options
1
        let m = Domain::matrix(
1
            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1
            vec![domain_int!(1..3)],
1
        );
1
        assert_eq!(m.length(), Ok(64));
1
    }
}
/// The ranges of an integer collection that can already be evaluated, if it can.
fn int_ranges_from_constant_collection(values: &Expression) -> Option<Vec<Range<Int>>> {
    let values = crate::ast::eval::generator_values_from_expr(values)?;
    let mut ranges = Vec::with_capacity(values.len());
    for value in values {
        let crate::ast::Literal::Int(value) = value else {
            return None;
        };
        ranges.push(Range::Single(value));
    }
    Some(ranges)
}