Skip to main content

conjure_cp_core/ast/domains/
unresolved.rs

1use std::fmt::{Display, Formatter};
2use std::iter::zip;
3
4use crate::ast::domains::attrs::MSetAttr;
5use crate::ast::domains::attrs::PartitionAttr;
6use crate::ast::domains::attrs::SetAttr;
7use crate::ast::domains::ground::FieldGround;
8use crate::ast::records::Field;
9use crate::ast::{
10    DomainOpError, Expression, FuncAttr, Moo, Reference, RelAttr, ReturnType, SequenceAttr,
11    Typeable,
12    domains::{DomainPtr, GroundDomain, int_val::IntVal, range::Range},
13    pretty::pretty_vec,
14};
15use crate::bug;
16
17use funcmap::{FuncMap, TryFuncMap};
18use itertools::Itertools;
19use polyquine::Quine;
20use serde::{Deserialize, Serialize};
21use uniplate::Uniplate;
22
23pub(super) type FieldUnresolved = Field<DomainPtr>;
24
25impl From<FieldGround> for FieldUnresolved {
26    fn from(v: FieldGround) -> Self {
27        v.func_map(DomainPtr::from)
28    }
29}
30
31impl TryFrom<FieldUnresolved> for FieldGround {
32    type Error = DomainOpError;
33    fn try_from(v: FieldUnresolved) -> Result<Self, Self::Error> {
34        v.try_func_map(DomainPtr::try_into)
35    }
36}
37
38#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
39#[path_prefix(conjure_cp::ast)]
40#[biplate(to=Expression)]
41#[biplate(to=Reference)]
42#[biplate(to=IntVal)]
43#[biplate(to=DomainPtr)]
44pub enum UnresolvedDomain {
45    Int(Vec<Range<IntVal>>),
46    /// A set of elements drawn from the inner domain
47    Set(SetAttr<IntVal>, DomainPtr),
48    MSet(MSetAttr<IntVal>, DomainPtr),
49    /// A n-dimensional matrix with a value domain and n-index domains
50    Matrix(DomainPtr, Vec<DomainPtr>),
51    /// A tuple of N elements, each with its own domain
52    Tuple(Vec<DomainPtr>),
53    Sequence(SequenceAttr<IntVal>, DomainPtr),
54    /// A reference to a domain letting
55    #[polyquine_skip]
56    Reference(Reference),
57    /// A record
58    Record(Vec<FieldUnresolved>),
59    /// A function with attributes, domain, and range
60    Function(FuncAttr<IntVal>, DomainPtr, DomainPtr),
61    /// A variant domain with its domain options (reusing field entries)
62    Variant(Vec<FieldUnresolved>),
63    /// A relation as a set of tuples
64    Relation(RelAttr<IntVal>, Vec<DomainPtr>),
65    Partition(PartitionAttr<IntVal>, DomainPtr),
66}
67
68impl UnresolvedDomain {
69    pub fn resolve(&self) -> Result<GroundDomain, DomainOpError> {
70        match self {
71            UnresolvedDomain::Int(rngs) => rngs
72                .iter()
73                .map(Range::<IntVal>::resolve)
74                .collect::<Result<_, _>>()
75                .map(GroundDomain::Int),
76            UnresolvedDomain::Set(attr, inner) => {
77                Ok(GroundDomain::Set(attr.resolve()?, inner.resolve()?))
78            }
79            UnresolvedDomain::MSet(attr, inner) => {
80                Ok(GroundDomain::MSet(attr.resolve()?, inner.resolve()?))
81            }
82            UnresolvedDomain::Partition(attr, inner) => {
83                Ok(GroundDomain::Partition(attr.resolve()?, inner.resolve()?))
84            }
85            UnresolvedDomain::Matrix(inner, idx_doms) => {
86                let inner_gd = inner.resolve()?;
87                idx_doms
88                    .iter()
89                    .map(DomainPtr::resolve)
90                    .collect::<Result<_, _>>()
91                    .map(|idx| GroundDomain::Matrix(inner_gd, idx))
92            }
93            UnresolvedDomain::Sequence(attr, inner) => {
94                Ok(GroundDomain::Sequence(attr.resolve()?, inner.resolve()?))
95            }
96            UnresolvedDomain::Tuple(inners) => inners
97                .iter()
98                .map(DomainPtr::resolve)
99                .collect::<Result<_, _>>()
100                .map(GroundDomain::Tuple),
101            UnresolvedDomain::Record(entries) => entries
102                .iter()
103                .map(|f| {
104                    f.value.resolve().map(|gd| FieldGround {
105                        name: f.name.clone(),
106                        value: gd,
107                    })
108                })
109                .collect::<Result<_, _>>()
110                .map(GroundDomain::Record),
111            UnresolvedDomain::Reference(re) => re
112                .ptr
113                .as_domain_letting()
114                .unwrap_or_else(|| {
115                    bug!("Reference domain should point to domain letting, but got {re}")
116                })
117                .resolve()
118                .map(Moo::unwrap_or_clone),
119            UnresolvedDomain::Function(attr, dom, cdom) => Ok(GroundDomain::Function(
120                attr.resolve()?,
121                dom.resolve()?,
122                cdom.resolve()?,
123            )),
124            UnresolvedDomain::Variant(entries) => entries
125                .iter()
126                .map(|f| {
127                    f.value.resolve().map(|gd| FieldGround {
128                        name: f.name.clone(),
129                        value: gd,
130                    })
131                })
132                .collect::<Result<_, _>>()
133                .map(GroundDomain::Variant),
134            UnresolvedDomain::Relation(attr, inners) => {
135                let resolved_attr = attr.resolve()?;
136                inners
137                    .iter()
138                    .map(DomainPtr::resolve)
139                    .collect::<Result<_, _>>()
140                    .map(|items| GroundDomain::Relation(resolved_attr, items))
141            }
142        }
143    }
144
145    pub(super) fn union_unresolved(
146        &self,
147        other: &UnresolvedDomain,
148    ) -> Result<UnresolvedDomain, DomainOpError> {
149        match (self, other) {
150            (UnresolvedDomain::Int(lhs), UnresolvedDomain::Int(rhs)) => {
151                let merged = lhs.iter().chain(rhs.iter()).cloned().collect_vec();
152                Ok(UnresolvedDomain::Int(merged))
153            }
154            (UnresolvedDomain::Int(_), _) | (_, UnresolvedDomain::Int(_)) => {
155                Err(DomainOpError::WrongType)
156            }
157            (UnresolvedDomain::Set(_, in1), UnresolvedDomain::Set(_, in2)) => {
158                Ok(UnresolvedDomain::Set(SetAttr::default(), in1.union(in2)?))
159            }
160            (UnresolvedDomain::Set(_, _), _) | (_, UnresolvedDomain::Set(_, _)) => {
161                Err(DomainOpError::WrongType)
162            }
163            (UnresolvedDomain::MSet(_, in1), UnresolvedDomain::MSet(_, in2)) => {
164                Ok(UnresolvedDomain::MSet(MSetAttr::default(), in1.union(in2)?))
165            }
166            (UnresolvedDomain::MSet(_, _), _) | (_, UnresolvedDomain::MSet(_, _)) => {
167                Err(DomainOpError::WrongType)
168            }
169            (UnresolvedDomain::Matrix(in1, idx1), UnresolvedDomain::Matrix(in2, idx2))
170                if idx1 == idx2 =>
171            {
172                Ok(UnresolvedDomain::Matrix(in1.union(in2)?, idx1.clone()))
173            }
174            (UnresolvedDomain::Matrix(_, _), _) | (_, UnresolvedDomain::Matrix(_, _)) => {
175                Err(DomainOpError::WrongType)
176            }
177            (UnresolvedDomain::Tuple(lhs), UnresolvedDomain::Tuple(rhs))
178                if lhs.len() == rhs.len() =>
179            {
180                let mut merged = Vec::new();
181                for (l, r) in zip(lhs, rhs) {
182                    merged.push(l.union(r)?)
183                }
184                Ok(UnresolvedDomain::Tuple(merged))
185            }
186            (UnresolvedDomain::Tuple(_), _) | (_, UnresolvedDomain::Tuple(_)) => {
187                Err(DomainOpError::WrongType)
188            }
189            (UnresolvedDomain::Relation(_, in1s), UnresolvedDomain::Relation(_, in2s)) => {
190                let mut inners = Vec::new();
191                for (in1, in2) in in1s.iter().zip(in2s.iter()) {
192                    inners.push(in1.union(in2)?)
193                }
194                Ok(UnresolvedDomain::Relation(RelAttr::default(), inners))
195            }
196            (UnresolvedDomain::Relation(_, _), _) | (_, UnresolvedDomain::Relation(_, _)) => {
197                Err(DomainOpError::WrongType)
198            }
199            // TODO: Could we support unions of reference domains symbolically?
200            (UnresolvedDomain::Reference(_), _) | (_, UnresolvedDomain::Reference(_)) => {
201                Err(DomainOpError::NotGround)
202            }
203            // TODO: Could we define semantics for merging record domains?
204            #[allow(unreachable_patterns)]
205            (UnresolvedDomain::Record(_), _) | (_, UnresolvedDomain::Record(_)) => {
206                Err(DomainOpError::WrongType)
207            }
208            #[allow(unreachable_patterns)]
209            (UnresolvedDomain::Function(_, _, _), _) | (_, UnresolvedDomain::Function(_, _, _)) => {
210                Err(DomainOpError::WrongType)
211            }
212            #[allow(unreachable_patterns)]
213            (UnresolvedDomain::Partition(_, _), _) | (_, UnresolvedDomain::Partition(_, _)) => {
214                Err(DomainOpError::WrongType)
215            }
216            #[allow(unreachable_patterns)]
217            (UnresolvedDomain::Variant(_), _) | (_, UnresolvedDomain::Variant(_)) => {
218                Err(DomainOpError::WrongType)
219            }
220            #[allow(unreachable_patterns)]
221            (UnresolvedDomain::Sequence(_, _), _) | (_, UnresolvedDomain::Sequence(_, _)) => {
222                Err(DomainOpError::WrongType)
223            }
224        }
225    }
226
227    pub fn element_domain(&self) -> Option<DomainPtr> {
228        match self {
229            UnresolvedDomain::Set(_, inner_dom) => Some(inner_dom.clone()),
230            UnresolvedDomain::Sequence(_, inner_dom) => Some(inner_dom.clone()),
231            UnresolvedDomain::Matrix(_, _) => {
232                todo!("Unwrap one dimension of the domain")
233            }
234            _ => None,
235        }
236    }
237}
238
239impl Typeable for UnresolvedDomain {
240    fn return_type(&self) -> ReturnType {
241        match self {
242            UnresolvedDomain::Reference(re) => re.return_type(),
243            UnresolvedDomain::Int(_) => ReturnType::Int,
244            UnresolvedDomain::Set(_attr, inner) => ReturnType::Set(Box::new(inner.return_type())),
245            UnresolvedDomain::MSet(_attr, inner) => ReturnType::MSet(Box::new(inner.return_type())),
246            UnresolvedDomain::Partition(_, inner) => {
247                ReturnType::Partition(Box::new(inner.return_type()))
248            }
249            UnresolvedDomain::Sequence(_attr, inner) => {
250                ReturnType::Sequence(Box::new(inner.return_type()))
251            }
252            UnresolvedDomain::Matrix(inner, _idx) => {
253                ReturnType::Matrix(Box::new(inner.return_type()))
254            }
255            UnresolvedDomain::Tuple(inners) => {
256                let mut inner_types = Vec::new();
257                for inner in inners {
258                    inner_types.push(inner.return_type());
259                }
260                ReturnType::Tuple(inner_types)
261            }
262            UnresolvedDomain::Record(entries) => {
263                let mut entry_types = Vec::new();
264                for entry in entries {
265                    entry_types.push(entry.clone().func_map(|x| x.return_type()));
266                }
267                ReturnType::Record(entry_types)
268            }
269            UnresolvedDomain::Variant(entries) => {
270                let mut entry_types = Vec::new();
271                for entry in entries {
272                    entry_types.push(entry.clone().func_map(|x| x.return_type()));
273                }
274                ReturnType::Variant(entry_types)
275            }
276            UnresolvedDomain::Function(_, dom, cdom) => {
277                ReturnType::Function(Box::new(dom.return_type()), Box::new(cdom.return_type()))
278            }
279            UnresolvedDomain::Relation(_, inners) => {
280                let mut inner_types = Vec::new();
281                for inner in inners {
282                    inner_types.push(inner.return_type());
283                }
284                ReturnType::Relation(inner_types)
285            }
286        }
287    }
288}
289
290impl Display for FieldUnresolved {
291    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
292        write!(f, "{}: {}", self.name, self.value)
293    }
294}
295
296impl Display for UnresolvedDomain {
297    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
298        match &self {
299            UnresolvedDomain::Reference(re) => write!(f, "{re}"),
300            UnresolvedDomain::Int(ranges) => {
301                if ranges.iter().all(Range::is_lower_or_upper_bounded) {
302                    let rngs: String = ranges.iter().map(|r| format!("{r}")).join(", ");
303                    write!(f, "int({})", rngs)
304                } else {
305                    write!(f, "int")
306                }
307            }
308            UnresolvedDomain::Set(attrs, inner_dom) => write!(f, "set {attrs} of {inner_dom}"),
309            UnresolvedDomain::MSet(attrs, inner_dom) => write!(f, "mset {attrs} of {inner_dom}"),
310            UnresolvedDomain::Partition(attrs, inner_dom) => {
311                write!(f, "partition {attrs} from {inner_dom}")
312            }
313            UnresolvedDomain::Sequence(attrs, inner_dom) => {
314                write!(f, "sequence {attrs} of {inner_dom}")
315            }
316            UnresolvedDomain::Matrix(value_domain, index_domains) => {
317                write!(
318                    f,
319                    "matrix indexed by {} of {value_domain}",
320                    pretty_vec(&index_domains.iter().collect_vec())
321                )
322            }
323            UnresolvedDomain::Tuple(domains) => {
324                write!(f, "tuple ({})", &domains.iter().join(","))
325            }
326            UnresolvedDomain::Record(entries) => {
327                let inners = entries.iter().map(|t| format!("{}", t)).join(", ");
328                write!(f, "record {{{inners}}}",)
329            }
330            UnresolvedDomain::Variant(entries) => {
331                let inners = entries.iter().map(|t| format!("{}", t)).join(", ");
332                write!(f, "variant {{{inners}}}",)
333            }
334            UnresolvedDomain::Function(attribute, domain, codomain) => {
335                write!(f, "function {} {} --> {} ", attribute, domain, codomain)
336            }
337            UnresolvedDomain::Relation(attrs, domains) => {
338                write!(f, "relation {} of ({})", attrs, domains.iter().join(" * "))
339            }
340        }
341    }
342}