1
use crate::ast::domains::Int;
2
use crate::ast::domains::range::Range;
3
use funcmap::{FuncMap, TryFuncMap};
4
use itertools::Itertools;
5
use polyquine::Quine;
6
use serde::{Deserialize, Serialize};
7
use std::fmt::{Display, Formatter};
8

            
9
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
10
#[path_prefix(conjure_cp::ast)]
11
pub struct SetAttr<A = Int> {
12
    pub size: Range<A>,
13
    /// Optional user-facing representation preference (short name), e.g. `"packed"`.
14
    ///
15
    /// Written in Essence as `set (representation packed) of …`. When present, representation selection
16
    /// heuristics default to this representation if it is applicable.
17
    pub representation: Option<String>,
18
}
19

            
20
impl<A> SetAttr<A> {
21
653145
    pub fn new(size: Range<A>) -> Self {
22
653145
        Self {
23
653145
            size,
24
653145
            representation: None,
25
653145
        }
26
653145
    }
27

            
28
88
    pub fn new_min_max_size(min: A, max: A) -> Self {
29
88
        Self::new(Range::Bounded(min, max))
30
88
    }
31

            
32
2
    pub fn new_min_size(min: A) -> Self {
33
2
        Self::new(Range::UnboundedR(min))
34
2
    }
35

            
36
21
    pub fn new_max_size(max: A) -> Self {
37
21
        Self::new(Range::UnboundedL(max))
38
21
    }
39

            
40
158
    pub fn new_size(sz: A) -> Self {
41
158
        Self::new(Range::Single(sz))
42
158
    }
43

            
44
    /// Set the representation preference (Essence short name), returning the updated attributes.
45
385
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
46
385
        self.representation = Some(name.into());
47
385
        self
48
385
    }
49
}
50

            
51
impl<A> Default for SetAttr<A> {
52
212946
    fn default() -> Self {
53
212946
        SetAttr {
54
212946
            size: Range::Unbounded,
55
212946
            representation: None,
56
212946
        }
57
212946
    }
58
}
59

            
60
impl<A: Display> Display for SetAttr<A> {
61
720286
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62
720286
        let mut attrs = Vec::new();
63
720286
        if let Some(representation) = &self.representation {
64
16416
            attrs.push(format!("representation {representation}"));
65
703870
        }
66
720286
        let size = fmt_size("size", &self.size);
67
720286
        if !size.is_empty() {
68
446525
            attrs.push(size);
69
273761
        }
70
720286
        if attrs.is_empty() {
71
269230
            Ok(())
72
        } else {
73
451056
            write!(f, "({})", attrs.join(", "))
74
        }
75
720286
    }
76
}
77

            
78
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
79
#[path_prefix(conjure_cp::ast)]
80
pub struct MSetAttr<A = Int> {
81
    pub size: Range<A>,
82
    pub occurrence: Range<A>,
83
    /// Optional user-facing representation preference (short name), e.g. `"repetition"`.
84
    ///
85
    /// Written in Essence as `mset (representation repetition) of …`. When present, representation selection
86
    /// heuristics default to this representation if it is applicable.
87
    #[serde(default)]
88
    pub representation: Option<String>,
89
}
90

            
91
impl<A> MSetAttr<A> {
92
376097
    pub fn new(size: Range<A>, occurrence: Range<A>) -> Self {
93
376097
        Self {
94
376097
            size,
95
376097
            occurrence,
96
376097
            representation: None,
97
376097
        }
98
376097
    }
99

            
100
    pub fn new_min_max_size(min: A, max: A) -> Self {
101
        Self::new(Range::Bounded(min, max), Range::Unbounded)
102
    }
103

            
104
1
    pub fn new_min_size(min: A) -> Self {
105
1
        Self::new(Range::UnboundedR(min), Range::Unbounded)
106
1
    }
107

            
108
11
    pub fn new_max_size(max: A) -> Self {
109
11
        Self::new(Range::UnboundedL(max), Range::Unbounded)
110
11
    }
111

            
112
2
    pub fn new_size(sz: A) -> Self {
113
2
        Self::new(Range::Single(sz), Range::Unbounded)
114
2
    }
115

            
116
    /// Set the representation preference (Essence short name), returning the updated attributes.
117
55
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
118
55
        self.representation = Some(name.into());
119
55
        self
120
55
    }
121
}
122

            
123
impl<A: Display> Display for MSetAttr<A> {
124
189363
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125
189363
        let size_str = fmt_size("size", &self.size);
126

            
127
        // It only makes sense in terms of min and max occurrence for the essence language,
128
        // so for single ranges it is still presented as min and max occurrence.
129
189363
        let occ_str = match &self.occurrence {
130
            Range::Single(x) => format!("minOccur({x}), maxOccur({x})"),
131
261
            Range::Bounded(l, r) => format!("minOccur({l}), maxOccur({r})"),
132
167197
            Range::UnboundedL(r) => format!("maxOccur({r})"),
133
62
            Range::UnboundedR(l) => format!("minOccur({l})"),
134
21843
            Range::Unbounded => "".to_string(),
135
        };
136

            
137
189363
        let representation_str = self
138
189363
            .representation
139
189363
            .as_ref()
140
2583
            .map(|name| format!("representation {name}"))
141
            .unwrap_or_default();
142
189363
        let mut strs = [representation_str, size_str, occ_str]
143
189363
            .iter()
144
568089
            .filter(|s| !s.is_empty())
145
189363
            .join(", ");
146
189363
        if !strs.is_empty() {
147
189305
            strs = format!("({})", strs);
148
58
        }
149
189363
        write!(f, "{strs}")
150
189363
    }
151
}
152

            
153
impl<A> Default for MSetAttr<A> {
154
242295
    fn default() -> Self {
155
242295
        MSetAttr {
156
242295
            size: Range::Unbounded,
157
242295
            occurrence: Range::Unbounded,
158
242295
            representation: None,
159
242295
        }
160
242295
    }
161
}
162

            
163
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
164
#[path_prefix(conjure_cp::ast)]
165
pub struct FuncAttr<A = Int> {
166
    pub size: Range<A>,
167
    pub partiality: PartialityAttr,
168
    pub jectivity: JectivityAttr,
169
    /// Optional user-facing representation preference (short name), e.g. `"packed"`.
170
    ///
171
    /// Written in Essence as `function (representation packed, …)`. When present, representation
172
    /// selection heuristics default to this representation if it is applicable.
173
    pub representation: Option<String>,
174
}
175

            
176
impl<A> FuncAttr<A> {
177
    /// Set the representation preference (Essence short name), returning the updated attributes.
178
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
179
        self.representation = Some(name.into());
180
        self
181
    }
182
}
183

            
184
impl<A> Default for FuncAttr<A> {
185
29
    fn default() -> Self {
186
29
        FuncAttr {
187
29
            size: Range::Unbounded,
188
            // Matches Conjure's own default (`Domain.hs`): a bare `function` with no explicit
189
            // `total` attribute is partial.
190
29
            partiality: PartialityAttr::Partial,
191
29
            jectivity: JectivityAttr::None,
192
29
            representation: None,
193
29
        }
194
29
    }
195
}
196

            
197
impl<A: Display> Display for FuncAttr<A> {
198
99214
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
199
99214
        let size_str = fmt_size("size", &self.size);
200
99214
        let mut strs = [
201
99214
            fmt_representation(&self.representation),
202
99214
            size_str,
203
99214
            self.partiality.to_string(),
204
99214
            self.jectivity.to_string(),
205
99214
        ]
206
99214
        .iter()
207
396856
        .filter(|s| !s.is_empty())
208
99214
        .join(", ");
209
99214
        if !strs.is_empty() {
210
93059
            strs = format!("({})", strs);
211
6155
        }
212
99214
        write!(f, "{strs}")
213
99214
    }
214
}
215

            
216
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
217
#[path_prefix(conjure_cp::ast)]
218
pub struct SequenceAttr<A = Int> {
219
    pub size: Range<A>,
220
    pub jectivity: JectivityAttr,
221
    /// Optional user-facing representation preference (short name), e.g. `"packed"`.
222
    ///
223
    /// Written in Essence as `sequence{packed} of …`. When present, representation selection
224
    /// heuristics default to this representation if it is applicable.
225
    pub representation: Option<String>,
226
}
227

            
228
impl<A> SequenceAttr<A> {
229
    /// Set the representation preference (Essence short name), returning the updated attributes.
230
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
231
        self.representation = Some(name.into());
232
        self
233
    }
234
}
235

            
236
impl<A> Default for SequenceAttr<A> {
237
102287
    fn default() -> Self {
238
102287
        SequenceAttr {
239
102287
            size: Range::Unbounded,
240
102287
            jectivity: JectivityAttr::None,
241
102287
            representation: None,
242
102287
        }
243
102287
    }
244
}
245

            
246
impl<A: Display> Display for SequenceAttr<A> {
247
118419
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
248
118419
        let size_str = fmt_size("size", &self.size);
249
118419
        let mut strs = [
250
118419
            fmt_representation(&self.representation),
251
118419
            size_str,
252
118419
            self.jectivity.to_string(),
253
118419
        ]
254
118419
        .iter()
255
355257
        .filter(|s| !s.is_empty())
256
118419
        .join(", ");
257
118419
        if !strs.is_empty() {
258
118419
            strs = format!("({})", strs);
259
        }
260
118419
        write!(f, "{strs}")
261
118419
    }
262
}
263

            
264
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
265
#[path_prefix(conjure_cp::ast)]
266
pub struct PartitionAttr<A = Int> {
267
    pub num_parts: Range<A>, // i.e. how many parts there are in the partition
268
    pub part_len: Range<A>,  // i.e. the size of each constitutent part
269
    pub is_regular: bool,
270
    /// Optional user-facing representation preference (short name), e.g. `"packed"`.
271
    ///
272
    /// Written in Essence as `partition (representation packed, …)`. When present, representation
273
    /// selection heuristics default to this representation if it is applicable.
274
    pub representation: Option<String>,
275
}
276

            
277
impl<A> PartitionAttr<A> {
278
    /// Set the representation preference (Essence short name), returning the updated attributes.
279
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
280
        self.representation = Some(name.into());
281
        self
282
    }
283
}
284

            
285
impl<A: Display> Display for PartitionAttr<A> {
286
1992
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
287
1992
        let num_parts_str = fmt_size("numParts", &self.num_parts);
288
1992
        let part_len_str = fmt_size("partSize", &self.part_len);
289

            
290
1992
        let regular_str = match &self.is_regular {
291
174
            true => "regular".to_string(),
292
1818
            false => String::new(),
293
        };
294

            
295
1992
        let mut strs = [
296
1992
            fmt_representation(&self.representation),
297
1992
            num_parts_str,
298
1992
            part_len_str,
299
1992
            regular_str,
300
1992
        ]
301
1992
        .iter()
302
7968
        .filter(|s| !s.is_empty())
303
1992
        .join(", ");
304
1992
        if !strs.is_empty() {
305
658
            strs = format!("({})", strs);
306
1334
        }
307
1992
        write!(f, "{strs}")
308
1992
    }
309
}
310

            
311
impl<A> Default for PartitionAttr<A> {
312
377
    fn default() -> Self {
313
377
        PartitionAttr {
314
377
            num_parts: Range::Unbounded,
315
377
            part_len: Range::Unbounded,
316
377
            is_regular: false,
317
377
            representation: None,
318
377
        }
319
377
    }
320
}
321

            
322
/// A permutation is inherently total and bijective by definition, so unlike partition or
323
/// function, its only attribute is a size constraint on `numMoved`, the number of moved points
324
/// (i.e. the points not fixed by the permutation) -- confirmed against real Conjure's own
325
/// `numMoved`/`minNumMoved`/`maxNumMoved` keywords (real Conjure does not accept
326
/// `size`/`minSize`/`maxSize` here, unlike set/relation/etc).
327
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
328
#[path_prefix(conjure_cp::ast)]
329
pub struct PermutationAttr<A = Int> {
330
    pub num_moved: Range<A>,
331
    /// Optional user-facing representation preference (short name), e.g. `"packed"`.
332
    ///
333
    /// Written in Essence as `permutation (representation packed, …)`. When present, representation
334
    /// selection heuristics default to this representation if it is applicable.
335
    pub representation: Option<String>,
336
}
337

            
338
impl<A> PermutationAttr<A> {
339
    /// Set the representation preference (Essence short name), returning the updated attributes.
340
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
341
        self.representation = Some(name.into());
342
        self
343
    }
344
}
345

            
346
impl<A: Display> Display for PermutationAttr<A> {
347
28478
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
348
28478
        let size_str = fmt_size("numMoved", &self.num_moved);
349
28478
        match &self.representation {
350
            // Without a preference the size is printed bare, as it always has been.
351
28362
            None => write!(f, "{size_str}"),
352
116
            Some(representation) if size_str.is_empty() => {
353
116
                write!(f, "(representation {representation})")
354
            }
355
            Some(representation) => write!(f, "(representation {representation}, {size_str})"),
356
        }
357
28478
    }
358
}
359

            
360
impl<A> Default for PermutationAttr<A> {
361
20735
    fn default() -> Self {
362
20735
        PermutationAttr {
363
20735
            num_moved: Range::Unbounded,
364
20735
            representation: None,
365
20735
        }
366
20735
    }
367
}
368

            
369
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine)]
370
pub enum PartialityAttr {
371
    Total,
372
    Partial,
373
}
374

            
375
impl Display for PartialityAttr {
376
99214
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
377
99214
        match self {
378
90537
            PartialityAttr::Total => write!(f, "total"),
379
8677
            PartialityAttr::Partial => write!(f, ""),
380
        }
381
99214
    }
382
}
383

            
384
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine)]
385
pub enum JectivityAttr {
386
    None,
387
    Injective,
388
    Surjective,
389
    Bijective,
390
}
391

            
392
impl Display for JectivityAttr {
393
217633
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
394
217633
        match self {
395
204144
            JectivityAttr::None => write!(f, ""),
396
10517
            JectivityAttr::Injective => write!(f, "injective"),
397
1084
            JectivityAttr::Surjective => write!(f, "surjective"),
398
1888
            JectivityAttr::Bijective => write!(f, "bijective"),
399
        }
400
217633
    }
401
}
402

            
403
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
404
#[path_prefix(conjure_cp::ast)]
405
pub struct RelAttr<A = Int> {
406
    pub size: Range<A>,
407
    pub binary: Vec<BinaryAttr>,
408
    /// Optional user-facing representation preference (short name), e.g. `"packed"`.
409
    ///
410
    /// Written in Essence as `relation (representation packed, …)`. When present, representation
411
    /// selection heuristics default to this representation if it is applicable.
412
    pub representation: Option<String>,
413
}
414

            
415
impl<A> RelAttr<A> {
416
    /// Set the representation preference (Essence short name), returning the updated attributes.
417
    pub fn with_representation(mut self, name: impl Into<String>) -> Self {
418
        self.representation = Some(name.into());
419
        self
420
    }
421
}
422

            
423
impl<A> Default for RelAttr<A> {
424
120
    fn default() -> Self {
425
120
        RelAttr {
426
120
            size: Range::Unbounded,
427
120
            binary: Vec::new(),
428
120
            representation: None,
429
120
        }
430
120
    }
431
}
432

            
433
impl<A: Display> Display for RelAttr<A> {
434
8368
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
435
8368
        let size_str = fmt_size("size", &self.size);
436
8368
        let mut strs = [
437
8368
            fmt_representation(&self.representation),
438
8368
            size_str,
439
8368
            self.binary.iter().join(", "),
440
8368
        ]
441
8368
        .iter()
442
25104
        .filter(|s| !s.is_empty())
443
8368
        .join(", ");
444
8368
        if !strs.is_empty() {
445
3484
            strs = format!("({})", strs);
446
4884
        }
447
8368
        write!(f, "{strs}")
448
8368
    }
449
}
450

            
451
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine)]
452
pub enum BinaryAttr {
453
    Reflexive,
454
    Irreflexive,
455
    Coreflexive,
456
    Symmetric,
457
    AntiSymmetric,
458
    ASymmetric,
459
    Transitive,
460
    Total,
461
    Connex,
462
    Euclidean,
463
    Serial,
464
    Equivalence,
465
    PartialOrder,
466
    LeftTotal,
467
    RightTotal,
468
    LinearOrder,
469
    WeakOrder,
470
    PreOrder,
471
    StrictPartialOrder,
472
}
473

            
474
impl Display for BinaryAttr {
475
1972
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
476
1972
        match self {
477
58
            BinaryAttr::Reflexive => write!(f, "reflexive"),
478
261
            BinaryAttr::Irreflexive => write!(f, "irreflexive"),
479
58
            BinaryAttr::Coreflexive => write!(f, "coreflexive"),
480
261
            BinaryAttr::Symmetric => write!(f, "symmetric"),
481
58
            BinaryAttr::AntiSymmetric => write!(f, "antiSymmetric"),
482
58
            BinaryAttr::ASymmetric => write!(f, "aSymmetric"),
483
58
            BinaryAttr::Transitive => write!(f, "transitive"),
484
58
            BinaryAttr::Total => write!(f, "total"),
485
58
            BinaryAttr::Connex => write!(f, "connex"),
486
261
            BinaryAttr::Euclidean => write!(f, "Euclidean"),
487
261
            BinaryAttr::Serial => write!(f, "serial"),
488
261
            BinaryAttr::Equivalence => write!(f, "equivalence"),
489
261
            BinaryAttr::PartialOrder => write!(f, "partialOrder"),
490
            BinaryAttr::LeftTotal => write!(f, "leftTotal"),
491
            BinaryAttr::RightTotal => write!(f, "rightTotal"),
492
            BinaryAttr::LinearOrder => write!(f, "linearOrder"),
493
            BinaryAttr::WeakOrder => write!(f, "weakOrder"),
494
            BinaryAttr::PreOrder => write!(f, "preOrder"),
495
            BinaryAttr::StrictPartialOrder => write!(f, "strictPartialOrder"),
496
        }
497
1972
    }
498
}
499

            
500
impl BinaryAttr {
501
    /// Parses the Essence keyword for a binary relation attribute (the inverse of `Display`).
502
    /// Used both by native domain-attribute parsing (`relation (reflexive, ...) of ...`) and by
503
    /// attribute-as-constraint lifting (`reflexive(r)`).
504
1363
    pub fn from_keyword(s: &str) -> Option<Self> {
505
1363
        Some(match s {
506
116
            "reflexive" => BinaryAttr::Reflexive,
507
203
            "irreflexive" => BinaryAttr::Irreflexive,
508
            "coreflexive" => BinaryAttr::Coreflexive,
509
203
            "symmetric" => BinaryAttr::Symmetric,
510
            "antiSymmetric" => BinaryAttr::AntiSymmetric,
511
            "aSymmetric" => BinaryAttr::ASymmetric,
512
            "transitive" => BinaryAttr::Transitive,
513
            "total" => BinaryAttr::Total,
514
            "connex" => BinaryAttr::Connex,
515
203
            "Euclidean" => BinaryAttr::Euclidean,
516
203
            "serial" => BinaryAttr::Serial,
517
203
            "equivalence" => BinaryAttr::Equivalence,
518
203
            "partialOrder" => BinaryAttr::PartialOrder,
519
            "leftTotal" => BinaryAttr::LeftTotal,
520
            "rightTotal" => BinaryAttr::RightTotal,
521
            "linearOrder" => BinaryAttr::LinearOrder,
522
            "weakOrder" => BinaryAttr::WeakOrder,
523
            "preOrder" => BinaryAttr::PreOrder,
524
            "strictPartialOrder" => BinaryAttr::StrictPartialOrder,
525
29
            _ => return None,
526
        })
527
1363
    }
528
}
529

            
530
/// Format a representation preference as an Essence attribute, or nothing without one.
531
227993
fn fmt_representation(representation: &Option<String>) -> String {
532
227993
    match representation {
533
464
        Some(representation) => format!("representation {representation}"),
534
227529
        None => String::new(),
535
    }
536
227993
}
537

            
538
/// Format a range as Essence size attribute
539
#[inline]
540
1168112
fn fmt_size<A: Display>(suffix: &str, sz: &Range<A>) -> String {
541
1168112
    let cap_suffix = capitalize(suffix);
542
1168112
    match sz {
543
309495
        Range::Single(x) => format!("{suffix} {x}"),
544
16982
        Range::Bounded(l, r) => format!("min{cap_suffix} {l}, max{cap_suffix} {r}"),
545
272763
        Range::UnboundedL(r) => format!("max{cap_suffix} {r}"),
546
150811
        Range::UnboundedR(l) => format!("min{cap_suffix} {l}"),
547
418061
        Range::Unbounded => "".to_string(),
548
    }
549
1168112
}
550

            
551
#[inline]
552
1168112
fn capitalize(s: &str) -> String {
553
1168112
    let mut c = s.chars();
554
1168112
    match c.next() {
555
        None => String::new(),
556
1168112
        Some(f) => f.to_uppercase().to_string() + c.as_str(),
557
    }
558
1168112
}