Skip to main content

conjure_cp_core/representation/
default_impls.rs

1//! Default implementations of some Repr trait methods using functors;
2//! These methods are used by the register_repr! macro
3
4use super::errors::ReprUpError;
5use super::types::{LookupFn, ReprDomainLevel, ReprInstantiateResult};
6use super::util::try_up_via;
7use crate::ast::{
8    DeclarationKind, DeclarationPtr, DomainPtr, Expression, Literal, Name, SymbolTable,
9    eval_constant,
10};
11use crate::representation::ReprInstantiateError;
12use anyhow::anyhow;
13use funcmap::{FuncMap, TryFuncMap};
14/// Returns the number of values in a representation-variable domain.
15/// Domains whose size is unknown or does not fit in `usize` rank as least compact.
16pub fn domain_size(domain: &DomainPtr) -> usize {
17    domain
18        .length()
19        .ok()
20        .and_then(|size| usize::try_from(size).ok())
21        .unwrap_or(usize::MAX)
22}
23
24/// Implement [ReprDeclLevel::lookup_via] as a functor `S<DeclarationPtr> -> S<Literal>`.
25pub fn lookup_via_default_impl<DeclL, A>(
26    decl_level: &DeclL,
27    lookup: &LookupFn<'_>,
28) -> Result<A, ReprUpError>
29where
30    DeclL: Clone + TryFuncMap<DeclarationPtr, Literal, Output = A>,
31{
32    decl_level
33        .clone()
34        .try_func_map(|decl: DeclarationPtr| try_up_via(decl, lookup))
35}
36
37/// Implement [ReprDeclLevel::to_domain_level] as a functor `S<DeclarationPtr> -> S<DomainPtr>`.
38pub fn to_domain_level_default_impl<DomL, DecL>(decl_level: DecL) -> DomL
39where
40    DecL: FuncMap<DeclarationPtr, DomainPtr, Output = DomL>,
41{
42    let field_dom = |decl: DeclarationPtr| decl.domain().expect("variable must have a domain");
43    decl_level.func_map(field_dom)
44}
45
46/// Implement [ReprDomainLevel::instantiate] as a functor `S<DomainPtr> -> S<DeclarationPtr>`.
47/// Needs the following additional arguments:
48/// - `structural` - function which takes `&S<DeclarationPtr>` and generates its structural constraints
49pub fn instantiate_default_impl<DomL, DecL, A, SF>(
50    dom_level: DomL,
51    decl: DeclarationPtr,
52    structural: SF,
53) -> ReprInstantiateResult<DecL>
54where
55    DomL: ReprDomainLevel<Assignment = A, DeclLevel = DecL>
56        + FuncMap<DomainPtr, DeclarationPtr, Output = DecL>,
57    A: FuncMap<Literal, DeclarationPtr, Output = DecL>,
58    SF: Fn(&DecL) -> Vec<Expression>,
59{
60    let src_name = decl.name();
61    let repr_name = <DomL as ReprDomainLevel>::RULE.id();
62    let mut symtab = SymbolTable::new();
63    let mut counter = 1;
64    let element_domains = decl.as_find().and_then(|var| var.element_domains.clone());
65
66    match &decl.kind() as &DeclarationKind {
67        DeclarationKind::Find(_) | DeclarationKind::FindAuxiliary(_) => {
68            let declare_field_var = |dom: DomainPtr| {
69                let dom = element_domains
70                    .as_ref()
71                    .and_then(|domains| domains.get(counter - 1))
72                    .cloned()
73                    .unwrap_or(dom);
74                let name = Name::repr(src_name.clone(), repr_name, &counter.to_string());
75                let mut field_decl = if decl.is_find_auxiliary() {
76                    DeclarationPtr::new_find_auxiliary(name, dom)
77                } else {
78                    DeclarationPtr::new_find(name, dom)
79                };
80                *(field_decl.source_mut()) = Some(decl.clone());
81                symtab
82                    .insert(field_decl.clone())
83                    .expect("declaration already exists");
84                counter += 1;
85                field_decl
86            };
87
88            let decl_level = dom_level.func_map(declare_field_var);
89            let constraints = structural(&decl_level);
90            Ok((decl_level, symtab, constraints))
91        }
92        DeclarationKind::ValueLetting(expr, _) | DeclarationKind::TemporaryValueLetting(expr) => {
93            let declare_field_value_letting = |lit: Literal| {
94                let name = Name::repr(src_name.clone(), repr_name, &counter.to_string());
95                let mut field_decl = DeclarationPtr::new_value_letting(name, lit.into());
96                *(field_decl.source_mut()) = Some(decl.clone());
97                symtab
98                    .insert(field_decl.clone())
99                    .expect("declaration already exists");
100                counter += 1;
101                field_decl
102            };
103
104            let val = eval_constant(expr).ok_or(ReprInstantiateError::Other(anyhow!(
105                "expression {expr} is not constant"
106            )))?;
107            let val_down = dom_level.down(val).unwrap();
108            let decl_level = val_down.func_map(declare_field_value_letting);
109            // no constraints for value letting reprs
110            let constraints = vec![];
111            Ok((decl_level, symtab, constraints))
112        }
113        _ => Err(ReprInstantiateError::BadKind(
114            decl.clone(),
115            String::from("expected a variable or value letting"),
116        )),
117    }
118}