Skip to main content

conjure_cp_core/ast/
literals.rs

1use funcmap::FuncMap;
2use itertools::Itertools;
3use serde::{Deserialize, Serialize};
4use std::fmt::{Debug, Display, Formatter};
5use std::hash::Hash;
6use ustr::Ustr;
7
8use super::{
9    Atom, Domain, DomainPtr, Expression, GroundDomain, Metadata, Moo, PartitionAttr, Range,
10    ReturnType, SetAttr, Typeable, domains::HasDomain, domains::Int, records::Field,
11};
12use crate::ast::domains::{MSetAttr, SequenceAttr};
13use crate::ast::pretty::pretty_vec;
14use crate::bug;
15use polyquine::Quine;
16use uniplate::{Biplate, Tree, Uniplate};
17
18#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate, Hash, Quine)]
19#[uniplate(walk_into=[AbstractLiteral<Literal>])]
20#[biplate(to=Atom)]
21#[biplate(to=AbstractLiteral<Literal>)]
22#[biplate(to=AbstractLiteral<Expression>)]
23#[biplate(to=Field<Literal>)]
24#[biplate(to=Field<Expression>)]
25#[biplate(to=Expression)]
26#[path_prefix(conjure_cp::ast)]
27/// A literal value, equivalent to constants in Conjure.
28pub enum Literal {
29    Int(i32),
30    Bool(bool),
31    //abstract literal variant ends in Literal, but that's ok
32    #[allow(clippy::enum_variant_names)]
33    AbstractLiteral(AbstractLiteral<Literal>),
34}
35
36impl HasDomain for Literal {
37    fn domain_of(&self) -> DomainPtr {
38        match self {
39            Literal::Int(i) => Domain::int(vec![Range::Single(*i)]),
40            Literal::Bool(_) => Domain::bool(),
41            Literal::AbstractLiteral(abstract_literal) => abstract_literal.domain_of(),
42        }
43    }
44}
45
46// make possible values of an AbstractLiteral a closed world to make the trait bounds more sane (particularly in Uniplate instances!!)
47pub trait AbstractLiteralValue:
48    Clone + Eq + PartialEq + Display + Uniplate + Biplate<Field<Self>> + 'static
49{
50    type Dom: Clone
51        + Eq
52        + PartialEq
53        + Debug
54        + Display
55        + Quine
56        + From<GroundDomain>
57        + Into<DomainPtr>;
58}
59impl AbstractLiteralValue for Expression {
60    type Dom = DomainPtr;
61}
62impl AbstractLiteralValue for Literal {
63    type Dom = Moo<GroundDomain>;
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Quine)]
67#[path_prefix(conjure_cp::ast)]
68pub enum AbstractLiteral<T: AbstractLiteralValue> {
69    Set(Vec<T>),
70
71    MSet(Vec<T>),
72
73    /// A 1 dimensional matrix slice with an index domain.
74    Matrix(Vec<T>, T::Dom),
75
76    // a tuple of literals
77    Tuple(Vec<T>),
78
79    Record(Vec<Field<T>>),
80
81    Sequence(Vec<T>),
82
83    Function(Vec<(T, T)>),
84
85    // Variants only contain one of their name-domain pairs
86    Variant(Moo<Field<T>>),
87
88    // A list of partitions, each part has a set of values
89    Partition(Vec<Vec<T>>),
90    Relation(Vec<Vec<T>>),
91}
92
93// TODO: use HasDomain instead once Expression::domain_of returns Domain not Option<Domain>
94impl AbstractLiteral<Expression> {
95    pub fn domain_of(&self) -> Option<DomainPtr> {
96        match self {
97            AbstractLiteral::Set(items) => {
98                // ensure that all items have a domain, or return None
99                let item_domains: Vec<DomainPtr> = items
100                    .iter()
101                    .map(|x| x.domain_of())
102                    .collect::<Option<Vec<DomainPtr>>>()?;
103
104                // union all item domains together
105                let mut item_domain_iter = item_domains.iter().cloned();
106                let first_item = item_domain_iter.next()?;
107                let item_domain = item_domains
108                    .iter()
109                    .try_fold(first_item, |x, y| x.union(y))
110                    .expect("taking the union of all item domains of a set literal should succeed");
111
112                Some(Domain::set(SetAttr::<Int>::default(), item_domain))
113            }
114
115            AbstractLiteral::MSet(items) => {
116                // ensure that all items have a domain, or return None
117                let item_domains: Vec<DomainPtr> = items
118                    .iter()
119                    .map(|x| x.domain_of())
120                    .collect::<Option<Vec<DomainPtr>>>()?;
121
122                // union all item domains together
123                let mut item_domain_iter = item_domains.iter().cloned();
124                let first_item = item_domain_iter.next()?;
125                let item_domain = item_domains
126                    .iter()
127                    .try_fold(first_item, |x, y| x.union(y))
128                    .expect("taking the union of all item domains of a set literal should succeed");
129
130                Some(Domain::mset(MSetAttr::<Int>::default(), item_domain))
131            }
132
133            AbstractLiteral::Sequence(elems) => {
134                let item_domains: Vec<DomainPtr> = elems
135                    .iter()
136                    .map(|x| x.domain_of())
137                    .collect::<Option<Vec<DomainPtr>>>()?;
138
139                // Get the union of all domains in the sequence.
140                // i.e. if <(1..3), (1..3), (5), (8..9)> then seq dom is (1..3, 5, 8..9)
141                let mut item_domain_iter = item_domains.iter().cloned();
142                let first_item = item_domain_iter.next()?;
143                let item_domain = item_domains
144                    .iter()
145                    .try_fold(first_item, |x, y| x.union(y))
146                    .expect("taking the union of all item domains of a set literal should succeed");
147
148                Some(Domain::sequence(
149                    SequenceAttr::<Int>::default(),
150                    item_domain,
151                ))
152            }
153
154            AbstractLiteral::Partition(items) => {
155                // Flatten the Vec<Vec< into a single vec
156                // ensure that all elemes in each part have a domain, or return None
157
158                let item_domains: Vec<DomainPtr> = items
159                    .iter()
160                    .flatten()
161                    .map(|x| x.domain_of())
162                    .collect::<Option<Vec<DomainPtr>>>()?;
163
164                // union all item domains together
165                let mut item_domain_iter = item_domains.iter().cloned();
166                let first_item = item_domain_iter.next()?;
167                let item_domain = item_domains
168                    .iter()
169                    .try_fold(first_item, |x, y| x.union(y))
170                    .expect("taking the union of all item domains of a partition literal should succeed");
171
172                Some(Domain::partition(
173                    PartitionAttr::<Int>::default(),
174                    item_domain,
175                ))
176            }
177
178            AbstractLiteral::Matrix(items, _) => {
179                // ensure that all items have a domain, or return None
180                let item_domains = items
181                    .iter()
182                    .map(|x| x.domain_of())
183                    .collect::<Option<Vec<DomainPtr>>>()?;
184
185                // union all item domains together
186                let mut item_domain_iter = item_domains.iter().cloned();
187
188                let first_item = item_domain_iter.next()?;
189
190                let item_domain = item_domains
191                    .iter()
192                    .try_fold(first_item, |x, y| x.union(y))
193                    .expect(
194                        "taking the union of all item domains of a matrix literal should succeed",
195                    );
196
197                let mut new_index_domain = vec![];
198
199                // flatten index domains of n-d matrix into list
200                let mut e = Expression::AbstractLiteral(Metadata::new(), self.clone());
201                while let Expression::AbstractLiteral(_, AbstractLiteral::Matrix(elems, idx)) = e {
202                    assert!(
203                        idx.as_matrix().is_none(),
204                        "n-dimensional matrix literals should be represented as a matrix inside a matrix, got {idx}"
205                    );
206                    new_index_domain.push(idx);
207                    e = elems[0].clone();
208                }
209                Some(Domain::matrix(item_domain, new_index_domain))
210            }
211            AbstractLiteral::Tuple(_) => None,
212            AbstractLiteral::Record(_) => None,
213            AbstractLiteral::Function(_) => None,
214            AbstractLiteral::Variant(_) => None,
215            AbstractLiteral::Relation(_) => None,
216        }
217    }
218}
219
220impl HasDomain for AbstractLiteral<Literal> {
221    fn domain_of(&self) -> DomainPtr {
222        Domain::from_literal_vec(&[Literal::AbstractLiteral(self.clone())])
223            .expect("abstract literals should be correctly typed")
224    }
225}
226
227impl Typeable for AbstractLiteral<Expression> {
228    fn return_type(&self) -> ReturnType {
229        match self {
230            AbstractLiteral::Set(items) if items.is_empty() => {
231                ReturnType::Set(Box::new(ReturnType::Unknown))
232            }
233            AbstractLiteral::Set(items) => {
234                let item_type = items[0].return_type();
235
236                // if any items do not have a type, return none.
237                let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
238
239                assert!(
240                    item_types.iter().all(|x| x == &item_type),
241                    "all items in a set should have the same type"
242                );
243
244                ReturnType::Set(Box::new(item_type))
245            }
246            AbstractLiteral::MSet(items) if items.is_empty() => {
247                ReturnType::MSet(Box::new(ReturnType::Unknown))
248            }
249            AbstractLiteral::MSet(items) => {
250                let item_type = items[0].return_type();
251
252                // if any items do not have a type, return none.
253                let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
254
255                assert!(
256                    item_types.iter().all(|x| x == &item_type),
257                    "all items in a set should have the same type"
258                );
259
260                ReturnType::MSet(Box::new(item_type))
261            }
262            AbstractLiteral::Sequence(items) if items.is_empty() => {
263                ReturnType::Sequence(Box::new(ReturnType::Unknown))
264            }
265            AbstractLiteral::Sequence(items) => {
266                let item_type = items[0].return_type();
267
268                // if any items do not have a type, return none.
269                let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
270
271                assert!(
272                    item_types.iter().all(|x| x == &item_type),
273                    "all items in a sequence should have the same type"
274                );
275
276                ReturnType::Sequence(Box::new(item_type))
277            }
278            AbstractLiteral::Partition(items) if items.is_empty() || items[0].is_empty() => {
279                ReturnType::Partition(Box::new(ReturnType::Unknown))
280            }
281            AbstractLiteral::Partition(items) => {
282                let item_type = items[0][0].return_type();
283
284                // if any items do not have a type, return none.
285                let item_types: Vec<ReturnType> =
286                    items.iter().flatten().map(|x| x.return_type()).collect();
287
288                assert!(
289                    item_types.iter().all(|x| x == &item_type),
290                    "all items in every part of a partition should have the same type"
291                );
292
293                ReturnType::Partition(Box::new(item_type))
294            }
295            AbstractLiteral::Matrix(items, _) if items.is_empty() => {
296                ReturnType::Matrix(Box::new(ReturnType::Unknown))
297            }
298            AbstractLiteral::Matrix(items, _) => {
299                let item_type = items[0].return_type();
300
301                // if any items do not have a type, return none.
302                let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
303
304                assert!(
305                    item_types.iter().all(|x| x == &item_type),
306                    "all items in a matrix should have the same type. items: {items} types: {types:#?}",
307                    items = pretty_vec(items),
308                    types = items
309                        .iter()
310                        .map(|x| x.return_type())
311                        .collect::<Vec<ReturnType>>()
312                );
313
314                ReturnType::Matrix(Box::new(item_type))
315            }
316            AbstractLiteral::Tuple(items) => {
317                let mut item_types = vec![];
318                for item in items {
319                    item_types.push(item.return_type());
320                }
321                ReturnType::Tuple(item_types)
322            }
323            AbstractLiteral::Record(items) => {
324                let mut item_types = vec![];
325                for item in items {
326                    item_types.push(item.clone().func_map(|x| x.return_type()));
327                }
328                ReturnType::Record(item_types)
329            }
330            AbstractLiteral::Function(items) => {
331                if items.is_empty() {
332                    return ReturnType::Function(
333                        Box::new(ReturnType::Unknown),
334                        Box::new(ReturnType::Unknown),
335                    );
336                }
337
338                // Check that all items have the same return type
339                let (x1, y1) = &items[0];
340                let (t1, t2) = (x1.return_type(), y1.return_type());
341                for (x, y) in items {
342                    let (tx, ty) = (x.return_type(), y.return_type());
343                    if tx != t1 {
344                        bug!("Expected {t1}, got {x}: {tx}");
345                    }
346                    if ty != t2 {
347                        bug!("Expected {t2}, got {y}: {ty}");
348                    }
349                }
350
351                ReturnType::Function(Box::new(t1), Box::new(t2))
352            }
353            AbstractLiteral::Variant(item) => {
354                // Variants hold multiple possible types. In the case of a literal we know which type it chose
355                ReturnType::Variant(vec![item.as_ref().clone().func_map(|x| x.return_type())])
356            }
357            AbstractLiteral::Relation(items) => {
358                if items.is_empty() {
359                    return ReturnType::Relation(vec![ReturnType::Unknown]);
360                }
361                let mut item_types = vec![];
362                let x1 = &items[0];
363                let size = x1.len();
364                for item in x1 {
365                    item_types.push(item.return_type());
366                }
367                for x in items {
368                    if x.len() != size {
369                        let strs = item_types.iter().map(|x| format!("{}", x)).join(",");
370                        bug!("Expected ({strs}) with length {size}, got size {}", x.len());
371                    }
372                    for i in 1..size {
373                        if let Some(new_type) = x.get(i)
374                            && let Some(old_type) = item_types.get(i)
375                            && new_type.return_type() != *old_type
376                        {
377                            bug!("Expected {old_type}, got {new_type}");
378                        }
379                    }
380                }
381                ReturnType::Relation(item_types)
382            }
383        }
384    }
385}
386
387impl<T> AbstractLiteral<T>
388where
389    T: AbstractLiteralValue,
390{
391    /// Creates a matrix with elements `elems`, with domain `int(1..)`.
392    ///
393    /// This acts as a variable sized list.
394    pub fn matrix_implied_indices(elems: Vec<T>) -> Self {
395        AbstractLiteral::Matrix(elems, GroundDomain::Int(vec![Range::UnboundedR(1)]).into())
396    }
397
398    /// If the AbstractLiteral is a list, returns its elements.
399    ///
400    /// A list is any a matrix with the domain `int(1..)`. This includes matrix literals without
401    /// any explicitly specified domain.
402    pub fn unwrap_list(&self) -> Option<&Vec<T>> {
403        let AbstractLiteral::Matrix(elems, domain) = self else {
404            return None;
405        };
406
407        let domain: DomainPtr = domain.clone().into();
408        let Some(GroundDomain::Int(ranges)) = domain.as_ground() else {
409            return None;
410        };
411
412        let [Range::UnboundedR(1)] = ranges[..] else {
413            return None;
414        };
415
416        Some(elems)
417    }
418}
419
420impl<T> Display for AbstractLiteral<T>
421where
422    T: AbstractLiteralValue,
423{
424    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
425        match self {
426            AbstractLiteral::Set(elems) => {
427                let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
428                write!(f, "{{{elems_str}}}")
429            }
430            AbstractLiteral::MSet(elems) => {
431                let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
432                write!(f, "mset({elems_str})")
433            }
434            AbstractLiteral::Matrix(elems, index_domain) => {
435                let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
436                write!(f, "[{elems_str};{index_domain}]")
437            }
438            AbstractLiteral::Tuple(elems) => {
439                let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
440                write!(f, "({elems_str})")
441            }
442            AbstractLiteral::Sequence(elems) => {
443                let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
444                write!(f, "sequence({elems_str})")
445            }
446            AbstractLiteral::Partition(parts) => {
447                let elems_str: String = parts
448                    .iter()
449                    .map(|inner| {
450                        let elems_str = inner.iter().map(|x| format!("{x}")).join(",");
451                        format!("{{{}}}", elems_str)
452                    })
453                    .join(", ");
454
455                write!(f, "partition({elems_str})")
456            }
457            AbstractLiteral::Record(entries) => {
458                let entries_str: String = entries
459                    .iter()
460                    .map(|entry| format!("{} = {}", entry.name, entry.value))
461                    .join(",");
462                write!(f, "record {{{entries_str}}}")
463            }
464            AbstractLiteral::Function(entries) => {
465                let entries_str: String = entries
466                    .iter()
467                    .map(|entry| format!("{} --> {}", entry.0, entry.1))
468                    .join(",");
469                write!(f, "function({entries_str})")
470            }
471            AbstractLiteral::Variant(entry) => {
472                write!(f, "variant{{{} = {}}}", entry.name, entry.value)
473            }
474            AbstractLiteral::Relation(elems) => {
475                let elems_str: String = elems
476                    .iter()
477                    .map(|x| format!("({})", x.iter().map(|x| format!("{x}")).join(",")))
478                    .join(",");
479                write!(f, "relation({elems_str})")
480            }
481        }
482    }
483}
484
485impl<T> Uniplate for AbstractLiteral<T>
486where
487    T: AbstractLiteralValue + Biplate<AbstractLiteral<T>>,
488{
489    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
490        // walking into T
491        match self {
492            AbstractLiteral::Set(vec) => {
493                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(vec);
494                (f1_tree, Box::new(move |x| AbstractLiteral::Set(f1_ctx(x))))
495            }
496            AbstractLiteral::MSet(vec) => {
497                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(vec);
498                (f1_tree, Box::new(move |x| AbstractLiteral::MSet(f1_ctx(x))))
499            }
500            AbstractLiteral::Matrix(elems, index_domain) => {
501                let index_domain = index_domain.clone();
502                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(elems);
503                (
504                    f1_tree,
505                    Box::new(move |x| AbstractLiteral::Matrix(f1_ctx(x), index_domain.clone())),
506                )
507            }
508            AbstractLiteral::Sequence(vec) => {
509                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(vec);
510                (
511                    f1_tree,
512                    Box::new(move |x| AbstractLiteral::Sequence(f1_ctx(x))),
513                )
514            }
515            AbstractLiteral::Tuple(elems) => {
516                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(elems);
517                (
518                    f1_tree,
519                    Box::new(move |x| AbstractLiteral::Tuple(f1_ctx(x))),
520                )
521            }
522            AbstractLiteral::Record(entries) => {
523                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(entries);
524                (
525                    f1_tree,
526                    Box::new(move |x| AbstractLiteral::Record(f1_ctx(x))),
527                )
528            }
529            AbstractLiteral::Function(entries) => {
530                let entry_count = entries.len();
531                let flattened: Vec<T> = entries
532                    .iter()
533                    .flat_map(|(lhs, rhs)| [lhs.clone(), rhs.clone()])
534                    .collect();
535
536                let (f1_tree, f1_ctx) =
537                    <Vec<T> as Biplate<AbstractLiteral<T>>>::biplate(&flattened);
538                (
539                    f1_tree,
540                    Box::new(move |x| {
541                        let rebuilt = f1_ctx(x);
542                        assert_eq!(
543                            rebuilt.len(),
544                            entry_count * 2,
545                            "number of function literal children should remain unchanged"
546                        );
547
548                        let mut iter = rebuilt.into_iter();
549                        let mut pairs = Vec::with_capacity(entry_count);
550                        while let (Some(lhs), Some(rhs)) = (iter.next(), iter.next()) {
551                            pairs.push((lhs, rhs));
552                        }
553
554                        AbstractLiteral::Function(pairs)
555                    }),
556                )
557            }
558            AbstractLiteral::Variant(entries) => {
559                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(entries);
560                (
561                    f1_tree,
562                    Box::new(move |x| AbstractLiteral::Variant(f1_ctx(x))),
563                )
564            }
565            AbstractLiteral::Relation(elems) => {
566                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(elems);
567                (
568                    f1_tree,
569                    Box::new(move |x| AbstractLiteral::Relation(f1_ctx(x))),
570                )
571            }
572            AbstractLiteral::Partition(elems) => {
573                let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(elems);
574                (
575                    f1_tree,
576                    Box::new(move |x| AbstractLiteral::Partition(f1_ctx(x))),
577                )
578            }
579        }
580    }
581}
582
583impl<U, To> Biplate<To> for AbstractLiteral<U>
584where
585    To: Uniplate,
586    U: AbstractLiteralValue + Biplate<AbstractLiteral<U>> + Biplate<To>,
587    Field<U>: Biplate<AbstractLiteral<U>> + Biplate<To>,
588{
589    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
590        if std::any::TypeId::of::<To>() == std::any::TypeId::of::<AbstractLiteral<U>>() {
591            // To ==From => return One(self)
592
593            unsafe {
594                // SAFETY: asserted the type equality above
595                let self_to = std::mem::transmute::<&AbstractLiteral<U>, &To>(self).clone();
596                let tree = Tree::One(self_to);
597                let ctx = Box::new(move |x| {
598                    let Tree::One(x) = x else {
599                        panic!();
600                    };
601
602                    std::mem::transmute::<&To, &AbstractLiteral<U>>(&x).clone()
603                });
604
605                (tree, ctx)
606            }
607        } else {
608            // walking into T
609            match self {
610                AbstractLiteral::Set(vec) => {
611                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(vec);
612                    (f1_tree, Box::new(move |x| AbstractLiteral::Set(f1_ctx(x))))
613                }
614                AbstractLiteral::MSet(vec) => {
615                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(vec);
616                    (f1_tree, Box::new(move |x| AbstractLiteral::MSet(f1_ctx(x))))
617                }
618                AbstractLiteral::Matrix(elems, index_domain) => {
619                    let index_domain = index_domain.clone();
620                    let (f1_tree, f1_ctx) = <Vec<U> as Biplate<To>>::biplate(elems);
621                    (
622                        f1_tree,
623                        Box::new(move |x| AbstractLiteral::Matrix(f1_ctx(x), index_domain.clone())),
624                    )
625                }
626                AbstractLiteral::Sequence(vec) => {
627                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(vec);
628                    (
629                        f1_tree,
630                        Box::new(move |x| AbstractLiteral::Sequence(f1_ctx(x))),
631                    )
632                }
633                AbstractLiteral::Tuple(elems) => {
634                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(elems);
635                    (
636                        f1_tree,
637                        Box::new(move |x| AbstractLiteral::Tuple(f1_ctx(x))),
638                    )
639                }
640                AbstractLiteral::Record(entries) => {
641                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(entries);
642                    (
643                        f1_tree,
644                        Box::new(move |x| AbstractLiteral::Record(f1_ctx(x))),
645                    )
646                }
647                AbstractLiteral::Function(entries) => {
648                    let entry_count = entries.len();
649                    let flattened: Vec<U> = entries
650                        .iter()
651                        .flat_map(|(lhs, rhs)| [lhs.clone(), rhs.clone()])
652                        .collect();
653
654                    let (f1_tree, f1_ctx) = <Vec<U> as Biplate<To>>::biplate(&flattened);
655                    (
656                        f1_tree,
657                        Box::new(move |x| {
658                            let rebuilt = f1_ctx(x);
659                            assert_eq!(
660                                rebuilt.len(),
661                                entry_count * 2,
662                                "number of function literal children should remain unchanged"
663                            );
664
665                            let mut iter = rebuilt.into_iter();
666                            let mut pairs = Vec::with_capacity(entry_count);
667                            while let (Some(lhs), Some(rhs)) = (iter.next(), iter.next()) {
668                                pairs.push((lhs, rhs));
669                            }
670
671                            AbstractLiteral::Function(pairs)
672                        }),
673                    )
674                }
675                AbstractLiteral::Variant(entries) => {
676                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(entries);
677                    (
678                        f1_tree,
679                        Box::new(move |x| AbstractLiteral::Variant(f1_ctx(x))),
680                    )
681                }
682                AbstractLiteral::Relation(elems) => {
683                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(elems);
684                    (
685                        f1_tree,
686                        Box::new(move |x| AbstractLiteral::Relation(f1_ctx(x))),
687                    )
688                }
689                AbstractLiteral::Partition(elems) => {
690                    let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(elems);
691                    (
692                        f1_tree,
693                        Box::new(move |x| AbstractLiteral::Partition(f1_ctx(x))),
694                    )
695                }
696            }
697        }
698    }
699}
700
701impl TryFrom<Literal> for i32 {
702    type Error = &'static str;
703
704    fn try_from(value: Literal) -> Result<Self, Self::Error> {
705        match value {
706            Literal::Int(i) => Ok(i),
707            _ => Err("Cannot convert non-i32 literal to i32"),
708        }
709    }
710}
711
712impl TryFrom<Box<Literal>> for i32 {
713    type Error = &'static str;
714
715    fn try_from(value: Box<Literal>) -> Result<Self, Self::Error> {
716        (*value).try_into()
717    }
718}
719
720impl TryFrom<&Box<Literal>> for i32 {
721    type Error = &'static str;
722
723    fn try_from(value: &Box<Literal>) -> Result<Self, Self::Error> {
724        TryFrom::<&Literal>::try_from(value.as_ref())
725    }
726}
727
728impl TryFrom<&Moo<Literal>> for i32 {
729    type Error = &'static str;
730
731    fn try_from(value: &Moo<Literal>) -> Result<Self, Self::Error> {
732        TryFrom::<&Literal>::try_from(value.as_ref())
733    }
734}
735
736impl TryFrom<&Literal> for i32 {
737    type Error = &'static str;
738
739    fn try_from(value: &Literal) -> Result<Self, Self::Error> {
740        match value {
741            Literal::Int(i) => Ok(*i),
742            _ => Err("Cannot convert non-i32 literal to i32"),
743        }
744    }
745}
746
747impl TryFrom<Literal> for bool {
748    type Error = &'static str;
749
750    fn try_from(value: Literal) -> Result<Self, Self::Error> {
751        match value {
752            Literal::Bool(b) => Ok(b),
753            _ => Err("Cannot convert non-bool literal to bool"),
754        }
755    }
756}
757
758impl TryFrom<&Literal> for bool {
759    type Error = &'static str;
760
761    fn try_from(value: &Literal) -> Result<Self, Self::Error> {
762        match value {
763            Literal::Bool(b) => Ok(*b),
764            _ => Err("Cannot convert non-bool literal to bool"),
765        }
766    }
767}
768
769impl From<i32> for Literal {
770    fn from(i: i32) -> Self {
771        Literal::Int(i)
772    }
773}
774
775impl From<bool> for Literal {
776    fn from(b: bool) -> Self {
777        Literal::Bool(b)
778    }
779}
780
781impl From<Literal> for Ustr {
782    fn from(value: Literal) -> Self {
783        // TODO: avoid the temporary-allocation of a string by format! here?
784        Ustr::from(&format!("{value}"))
785    }
786}
787
788impl From<AbstractLiteral<Literal>> for Literal {
789    fn from(literal: AbstractLiteral<Literal>) -> Self {
790        Literal::AbstractLiteral(literal)
791    }
792}
793
794impl AbstractLiteral<Expression> {
795    /// If all the elements are literals, returns this as an AbstractLiteral<Literal>.
796    /// Otherwise, returns `None`.
797    pub fn into_literals(self) -> Option<AbstractLiteral<Literal>> {
798        match self {
799            AbstractLiteral::Set(elements) => {
800                let literals = elements
801                    .into_iter()
802                    .map(|expr| match expr {
803                        Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
804                        Expression::AbstractLiteral(_, abslit) => {
805                            Some(Literal::AbstractLiteral(abslit.into_literals()?))
806                        }
807                        _ => None,
808                    })
809                    .collect::<Option<Vec<_>>>()?;
810                Some(AbstractLiteral::Set(literals))
811            }
812            AbstractLiteral::MSet(elements) => {
813                let literals = elements
814                    .into_iter()
815                    .map(|expr| match expr {
816                        Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
817                        Expression::AbstractLiteral(_, abslit) => {
818                            Some(Literal::AbstractLiteral(abslit.into_literals()?))
819                        }
820                        _ => None,
821                    })
822                    .collect::<Option<Vec<_>>>()?;
823                Some(AbstractLiteral::MSet(literals))
824            }
825            AbstractLiteral::Partition(elems) => {
826                // want to ascertain if every elem in Vec<Vec<Expr>> is a literal. If any are not, return none
827                // otherwise confirm it is an abslit<lit>
828                let mut partition: Vec<Vec<_>> = Vec::new();
829
830                for part in elems {
831                    let literals = part
832                        .into_iter()
833                        .map(|expr| match expr {
834                            Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
835                            Expression::AbstractLiteral(_, abslit) => {
836                                Some(Literal::AbstractLiteral(abslit.into_literals()?))
837                            }
838                            _ => None,
839                        })
840                        .collect::<Option<Vec<_>>>()?;
841
842                    partition.push(literals);
843                }
844
845                Some(AbstractLiteral::Partition(partition))
846            }
847            AbstractLiteral::Matrix(items, domain) => {
848                let mut literals = vec![];
849                for item in items {
850                    let literal = match item {
851                        Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
852                        Expression::AbstractLiteral(_, abslit) => {
853                            Some(Literal::AbstractLiteral(abslit.into_literals()?))
854                        }
855                        _ => None,
856                    }?;
857                    literals.push(literal);
858                }
859
860                Some(AbstractLiteral::Matrix(literals, domain.resolve().ok()?))
861            }
862            AbstractLiteral::Sequence(elements) => {
863                let literals = elements
864                    .into_iter()
865                    .map(|expr| match expr {
866                        Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
867                        Expression::AbstractLiteral(_, abslit) => {
868                            Some(Literal::AbstractLiteral(abslit.into_literals()?))
869                        }
870                        _ => None,
871                    })
872                    .collect::<Option<Vec<_>>>()?;
873                Some(AbstractLiteral::Sequence(literals))
874            }
875            AbstractLiteral::Tuple(items) => {
876                let mut literals = vec![];
877                for item in items {
878                    let literal = match item {
879                        Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
880                        Expression::AbstractLiteral(_, abslit) => {
881                            Some(Literal::AbstractLiteral(abslit.into_literals()?))
882                        }
883                        _ => None,
884                    }?;
885                    literals.push(literal);
886                }
887
888                Some(AbstractLiteral::Tuple(literals))
889            }
890            AbstractLiteral::Record(entries) => {
891                let mut literals = vec![];
892                for entry in entries {
893                    let literal = match entry.value {
894                        Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
895                        Expression::AbstractLiteral(_, abslit) => {
896                            Some(Literal::AbstractLiteral(abslit.into_literals()?))
897                        }
898                        _ => None,
899                    }?;
900
901                    literals.push((entry.name, literal));
902                }
903                Some(AbstractLiteral::Record(
904                    literals
905                        .into_iter()
906                        .map(|(name, literal)| Field {
907                            name,
908                            value: literal,
909                        })
910                        .collect(),
911                ))
912            }
913            AbstractLiteral::Function(_) => todo!("Implement into_literals for functions"),
914            AbstractLiteral::Variant(entry) => {
915                let literal = match entry.value.clone() {
916                    Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
917                    Expression::AbstractLiteral(_, abslit) => {
918                        Some(Literal::AbstractLiteral(abslit.into_literals()?))
919                    }
920                    _ => None,
921                }?;
922                Some(AbstractLiteral::Variant(Moo::new(Field {
923                    name: entry.name.clone(),
924                    value: literal,
925                })))
926            }
927            AbstractLiteral::Relation(_) => todo!("Implement into_literals for relations"),
928        }
929    }
930}
931
932// need display implementations for other types as well
933impl Display for Literal {
934    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
935        match &self {
936            Literal::Int(i) => write!(f, "{i}"),
937            Literal::Bool(b) => write!(f, "{b}"),
938            Literal::AbstractLiteral(l) => write!(f, "{l}"),
939        }
940    }
941}
942
943#[cfg(test)]
944mod tests {
945
946    use super::*;
947    use crate::ast::matrix::{flatten, partial_flatten, shape_of};
948    use crate::{domain_int_ground, into_matrix, matrix, matrix_lit, range};
949    use uniplate::Uniplate;
950
951    #[test]
952    fn matrix_uniplate_universe() {
953        // Can we traverse through matrices with uniplate?
954        let my_matrix: AbstractLiteral<Literal> = into_matrix![
955            vec![Literal::AbstractLiteral(matrix![Literal::Bool(true);Moo::new(GroundDomain::Bool)]); 5];
956            Moo::new(GroundDomain::Bool)
957        ];
958
959        let expected_index_domains = vec![Moo::new(GroundDomain::Bool); 6];
960        let actual_index_domains: Vec<Moo<GroundDomain>> =
961            my_matrix.cata(&move |elem, children| {
962                let mut res = vec![];
963                res.extend(children.into_iter().flatten());
964                if let AbstractLiteral::Matrix(_, index_domain) = elem {
965                    res.push(index_domain);
966                }
967
968                res
969            });
970
971        assert_eq!(actual_index_domains, expected_index_domains);
972    }
973
974    #[test]
975    fn matrix_flatten() {
976        let tensor: AbstractLiteral<Literal> = matrix![
977            [
978                // batch 1
979                [1, 2, 3, 4],
980                [5, 6, 7, 8],
981                [9, 10, 11, 12]
982            ],
983            [
984                // batch 2
985                [13, 14, 15, 16],
986                [17, 18, 19, 20],
987                [21, 22, 23, 24]
988            ]
989        ];
990
991        let actual_elems: Vec<Literal> = flatten(&tensor).cloned().collect();
992        let expected_elems = (1..25).map(Literal::from).collect::<Vec<_>>();
993        assert_eq!(actual_elems, expected_elems);
994    }
995
996    #[test]
997    fn matrix_domain_1d() {
998        let matrix = matrix_lit![10, 11, 12, 13; domain_int_ground!(1..4)];
999        let dom = matrix.domain_of();
1000
1001        let (inner_dom, idx_doms) = dom.as_matrix_ground().expect("must be ground matrix");
1002        assert_eq!(inner_dom, &domain_int_ground!(10..13));
1003        assert_eq!(idx_doms.len(), 1);
1004        assert_eq!(&idx_doms[0], &domain_int_ground!(1..4));
1005    }
1006
1007    #[test]
1008    fn matrix_domain_2d() {
1009        let matrix = matrix_lit![
1010            [1, 2, 3, 4],
1011            [5, 6, 7, 8];
1012            [
1013                domain_int_ground!(1..2),
1014                domain_int_ground!(1..4)
1015            ]
1016        ];
1017        let dom = matrix.domain_of();
1018
1019        let (inner_dom, idx_doms) = dom.as_matrix_ground().expect("must be ground matrix");
1020        assert_eq!(inner_dom, &domain_int_ground!(1..8));
1021        assert_eq!(idx_doms.len(), 2);
1022        assert_eq!(&idx_doms[0], &domain_int_ground!(1..2));
1023        assert_eq!(&idx_doms[1], &domain_int_ground!(1..4));
1024    }
1025
1026    #[test]
1027    fn matrix_shape_3d() {
1028        let tensor: AbstractLiteral<Literal> = matrix![
1029            [
1030                [1, 2, 3, 4],
1031                [5, 6, 7, 8],
1032                [9, 10, 11, 12]
1033            ],
1034            [
1035                [13, 14, 15, 16],
1036                [17, 18, 19, 20],
1037                [21, 22, 23, 24]
1038            ];
1039            [
1040                domain_int_ground!(1..2),
1041                domain_int_ground!(1..3),
1042                domain_int_ground!(1..4)
1043            ]
1044        ];
1045        let shape = shape_of(&tensor).expect("shape_of to work on a 3D matrix");
1046
1047        assert_eq!(shape.size, 24);
1048        assert_eq!(shape.dims, vec![2, 3, 4]);
1049        assert_eq!(shape.strides, vec![12, 4, 1]);
1050        assert_eq!(
1051            shape.idx_doms,
1052            vec![
1053                domain_int_ground!(1..2),
1054                domain_int_ground!(1..3),
1055                domain_int_ground!(1..4)
1056            ]
1057        );
1058    }
1059
1060    #[test]
1061    fn matrix_partial_flatten() {
1062        let tensor: AbstractLiteral<Literal> = matrix![
1063            [
1064                // batch 1
1065                [1, 2, 3, 4],
1066                [5, 6, 7, 8],
1067                [9, 10, 11, 12]
1068            ],
1069            [
1070                // batch 2
1071                [13, 14, 15, 16],
1072                [17, 18, 19, 20],
1073                [21, 22, 23, 24]
1074            ]
1075        ];
1076        assert_eq!(partial_flatten(0, tensor.clone()), tensor);
1077
1078        let expected_flatten_1: AbstractLiteral<Literal> = matrix![
1079            [1, 2, 3, 4],
1080            [5, 6, 7, 8],
1081            [9, 10, 11, 12],
1082            [13, 14, 15, 16],
1083            [17, 18, 19, 20],
1084            [21, 22, 23, 24]
1085        ];
1086        assert_eq!(partial_flatten(1, tensor.clone()), expected_flatten_1);
1087
1088        let expected_flatten_2 =
1089            AbstractLiteral::matrix_implied_indices((1..25).map(Literal::from).collect());
1090        assert_eq!(partial_flatten(2, tensor), expected_flatten_2);
1091    }
1092}