Skip to main content

conjure_cp_core/representation/
util.rs

1use super::errors::ReprUpError;
2use super::types::LookupFn;
3use crate::ast::{GroundDomain, Literal, Name};
4use conjure_cp_core::ast::DeclarationPtr;
5use std::collections::HashMap;
6
7pub fn try_up_via(decl: DeclarationPtr, lu: &LookupFn<'_>) -> Result<Literal, ReprUpError> {
8    // Look up the variable directly
9    if let Some(mut result) = lu(&decl) {
10        if decl
11            .domain()
12            .and_then(|domain| domain.resolve().ok())
13            .is_some_and(|domain| domain.as_ref() == &GroundDomain::Bool)
14        {
15            result = match result {
16                Literal::Int(0) => Literal::Bool(false),
17                Literal::Int(1) => Literal::Bool(true),
18                result => result,
19            };
20        }
21        return Ok(result);
22    }
23
24    // Variable not mapped to a value and has no representations
25    let reprs = decl.reprs();
26    if reprs.is_empty() {
27        return Err(ReprUpError::NotFound(decl.clone()));
28    }
29
30    // Go up via the first representation
31    let mut itr = reprs.iter();
32    let (_fst_name, fst) = itr.next().expect("checked that reprs is non-empty");
33    let fst_res = fst.up_via(lu)?;
34
35    // In debug mode, check that all other representations agree
36    #[cfg(debug_assertions)]
37    for (repr_name, repr) in itr {
38        let res = repr.up_via(lu)?;
39        assert_eq!(
40            res,
41            fst_res,
42            "representations `{}` and `{}` disagree for variable `{}`",
43            _fst_name,
44            repr_name,
45            decl.name()
46        );
47    }
48
49    Ok(fst_res)
50}
51
52pub fn try_up(
53    decl: DeclarationPtr,
54    raw_assignment: &HashMap<Name, Literal>,
55) -> Result<Literal, ReprUpError> {
56    let lu: LookupFn<'_> =
57        Box::new(|decl: &DeclarationPtr| raw_assignment.get(&decl.name()).cloned());
58    try_up_via(decl, &lu)
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::ast::{DeclarationPtr, Domain};
65    use crate::{domain_int, range};
66
67    #[test]
68    fn represented_boolean_leaf_coerces_minion_zero_one_values() {
69        let declaration = DeclarationPtr::new_find(Name::user("flag"), Domain::bool());
70        let lookup: LookupFn<'_> = Box::new(|_| Some(Literal::Int(1)));
71        assert_eq!(
72            try_up_via(declaration, &lookup).unwrap(),
73            Literal::Bool(true)
74        );
75    }
76
77    #[test]
78    fn integer_zero_one_leaf_remains_an_integer() {
79        let declaration = DeclarationPtr::new_find(Name::user("value"), domain_int!(0..1));
80        let lookup: LookupFn<'_> = Box::new(|_| Some(Literal::Int(1)));
81        assert_eq!(try_up_via(declaration, &lookup).unwrap(), Literal::Int(1));
82    }
83}