Skip to main content

conjure_cp_core/ast/
submodel.rs

1use super::{
2    Atom, CnfClause, DeclarationPtr, Expression, Literal, Metadata, Moo, ReturnType, SymbolTable,
3    Typeable,
4    comprehension::Comprehension,
5    declaration::DeclarationKind,
6    pretty::{
7        pretty_clauses, pretty_domain_letting_declaration, pretty_expressions_as_top_level,
8        pretty_value_letting_declaration, pretty_variable_declaration,
9    },
10    serde::RcRefCellAsInner,
11};
12use itertools::izip;
13use serde::{Deserialize, Serialize};
14use serde_with::serde_as;
15use uniplate::{Biplate, Tree, Uniplate};
16
17use crate::{bug, into_matrix_expr};
18use std::hash::{Hash, Hasher};
19use std::{
20    cell::{Ref, RefCell, RefMut},
21    collections::VecDeque,
22    fmt::Display,
23    rc::Rc,
24};
25
26/// A sub-model, representing a lexical scope in the model.
27///
28/// Each sub-model contains a symbol table representing its scope, as well as a expression tree.
29///
30/// The expression tree is formed of a root node of type [`Expression::Root`], which contains a
31/// vector of top-level constraints.
32#[serde_as]
33#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
34pub struct SubModel {
35    constraints: Moo<Expression>,
36    #[serde_as(as = "RcRefCellAsInner")]
37    symbols: Rc<RefCell<SymbolTable>>,
38    cnf_clauses: Vec<CnfClause>, // CNF clauses
39}
40
41impl SubModel {
42    /// Creates a new [`Submodel`] with no parent scope.
43    ///
44    /// Top level models are represented as [`Model`](super::model): consider using
45    /// [`Model::new`](super::Model::new) instead.
46    #[doc(hidden)]
47    pub(super) fn new_top_level() -> SubModel {
48        SubModel {
49            constraints: Moo::new(Expression::Root(Metadata::new(), vec![])),
50            symbols: Rc::new(RefCell::new(SymbolTable::new())),
51            cnf_clauses: Vec::new(),
52        }
53    }
54
55    /// Creates a new [`Submodel`] as a child scope of `parent`.
56    ///
57    /// `parent` should be the symbol table of the containing scope of this sub-model.
58    pub fn new(parent: Rc<RefCell<SymbolTable>>) -> SubModel {
59        SubModel {
60            constraints: Moo::new(Expression::Root(Metadata::new(), vec![])),
61            symbols: Rc::new(RefCell::new(SymbolTable::with_parent(parent))),
62            cnf_clauses: Vec::new(),
63        }
64    }
65
66    /// The symbol table for this sub-model as a pointer.
67    ///
68    /// The caller should only mutate the returned symbol table if this method was called on a
69    /// mutable model.
70    pub fn symbols_ptr_unchecked(&self) -> &Rc<RefCell<SymbolTable>> {
71        &self.symbols
72    }
73
74    /// The symbol table for this sub-model as a mutable pointer.
75    ///
76    /// The caller should only mutate the returned symbol table if this method was called on a
77    /// mutable model.
78    pub fn symbols_ptr_unchecked_mut(&mut self) -> &mut Rc<RefCell<SymbolTable>> {
79        &mut self.symbols
80    }
81
82    /// The symbol table for this sub-model as a reference.
83    pub fn symbols(&self) -> Ref<'_, SymbolTable> {
84        (*self.symbols).borrow()
85    }
86
87    /// The symbol table for this sub-model as a mutable reference.
88    pub fn symbols_mut(&mut self) -> RefMut<'_, SymbolTable> {
89        (*self.symbols).borrow_mut()
90    }
91
92    /// The root node of this sub-model.
93    ///
94    /// The root node is an [`Expression::Root`] containing a vector of the top level constraints
95    /// in this sub-model.
96    pub fn root(&self) -> &Expression {
97        &self.constraints
98    }
99
100    /// The root node of this sub-model, as a mutable reference.
101    ///
102    /// The caller is responsible for ensuring that the root node remains an [`Expression::Root`].
103    ///
104    pub fn root_mut_unchecked(&mut self) -> &mut Expression {
105        Moo::make_mut(&mut self.constraints)
106    }
107
108    /// Replaces the root node with `new_root`, returning the old root node.
109    ///
110    /// # Panics
111    ///
112    /// - If `new_root` is not an [`Expression::Root`].
113    pub fn replace_root(&mut self, new_root: Expression) -> Expression {
114        let Expression::Root(_, _) = new_root else {
115            tracing::error!(new_root=?new_root,"new_root is not an Expression::root");
116            panic!("new_root is not an Expression::Root");
117        };
118
119        // INVARIANT: already checked that `new_root` is an [`Expression::Root`]
120        std::mem::replace(self.root_mut_unchecked(), new_root)
121    }
122
123    /// The top-level constraints in this sub-model.
124    pub fn constraints(&self) -> &Vec<Expression> {
125        let Expression::Root(_, constraints) = self.constraints.as_ref() else {
126            bug!("The top level expression in a submodel should be Expr::Root");
127        };
128
129        constraints
130    }
131
132    /// The cnf clauses in this sub-model.
133    pub fn clauses(&self) -> &Vec<CnfClause> {
134        &self.cnf_clauses
135    }
136
137    /// The top-level constraints in this sub-model as a mutable vector.
138    pub fn constraints_mut(&mut self) -> &mut Vec<Expression> {
139        let Expression::Root(_, constraints) = Moo::make_mut(&mut self.constraints) else {
140            bug!("The top level expression in a submodel should be Expr::Root");
141        };
142
143        constraints
144    }
145
146    /// The cnf clauses in this sub-model as a mutable vector.
147    pub fn clauses_mut(&mut self) -> &mut Vec<CnfClause> {
148        &mut self.cnf_clauses
149    }
150
151    /// Replaces the top-level constraints with `new_constraints`, returning the old ones.
152    pub fn replace_constraints(&mut self, new_constraints: Vec<Expression>) -> Vec<Expression> {
153        std::mem::replace(self.constraints_mut(), new_constraints)
154    }
155
156    /// Replaces the cnf clauses with `new_clauses`, returning the old ones.
157    pub fn replace_clauses(&mut self, new_clauses: Vec<CnfClause>) -> Vec<CnfClause> {
158        std::mem::replace(self.clauses_mut(), new_clauses)
159    }
160
161    /// Adds a top-level constraint.
162    pub fn add_constraint(&mut self, constraint: Expression) {
163        self.constraints_mut().push(constraint);
164    }
165
166    /// Adds a cnf clause.
167    pub fn add_clause(&mut self, clause: CnfClause) {
168        self.clauses_mut().push(clause);
169    }
170
171    /// Adds top-level constraints.
172    pub fn add_constraints(&mut self, constraints: Vec<Expression>) {
173        self.constraints_mut().extend(constraints);
174    }
175
176    /// Adds cnf clauses.
177    pub fn add_clauses(&mut self, clauses: Vec<CnfClause>) {
178        self.clauses_mut().extend(clauses);
179    }
180
181    /// Adds a new symbol to the symbol table
182    /// (Wrapper over `SymbolTable.insert`)
183    pub fn add_symbol(&mut self, decl: DeclarationPtr) -> Option<()> {
184        self.symbols_mut().insert(decl)
185    }
186
187    /// Converts the constraints in this submodel to a single expression suitable for use inside
188    /// another expression tree.
189    ///
190    /// * If this submodel has no constraints, true is returned.
191    /// * If this submodel has a single constraint, that constraint is returned.
192    /// * If this submodel has multiple constraints, they are returned as an `and` constraint.
193    pub fn into_single_expression(self) -> Expression {
194        let constraints = self.constraints().clone();
195        match constraints.len() {
196            0 => Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(true))),
197            1 => constraints[0].clone(),
198            _ => Expression::And(Metadata::new(), Moo::new(into_matrix_expr![constraints])),
199        }
200    }
201}
202
203impl Typeable for SubModel {
204    fn return_type(&self) -> ReturnType {
205        ReturnType::Bool
206    }
207}
208
209impl Hash for SubModel {
210    fn hash<H: Hasher>(&self, state: &mut H) {
211        self.symbols.borrow().hash(state);
212        self.constraints.hash(state);
213        self.cnf_clauses.hash(state);
214    }
215}
216
217impl Display for SubModel {
218    #[allow(clippy::unwrap_used)] // [rustdocs]: should only fail iff the formatter fails
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        for (name, decl) in self.symbols().clone().into_iter_local() {
221            match &decl.kind() as &DeclarationKind {
222                DeclarationKind::DecisionVariable(_) => {
223                    writeln!(
224                        f,
225                        "{}",
226                        pretty_variable_declaration(&self.symbols(), &name).unwrap()
227                    )?;
228                }
229                DeclarationKind::ValueLetting(_) => {
230                    writeln!(
231                        f,
232                        "{}",
233                        pretty_value_letting_declaration(&self.symbols(), &name).unwrap()
234                    )?;
235                }
236                DeclarationKind::DomainLetting(_) => {
237                    writeln!(
238                        f,
239                        "{}",
240                        pretty_domain_letting_declaration(&self.symbols(), &name).unwrap()
241                    )?;
242                }
243                DeclarationKind::Given(d) => {
244                    writeln!(f, "given {name}: {d}")?;
245                }
246                DeclarationKind::GivenQuantified(inner) => {
247                    writeln!(f, "given {name}: {}", inner.domain())?;
248                }
249
250                DeclarationKind::RecordField(_) => {
251                    // Do not print a record field as it is an internal type
252                    writeln!(f)?;
253                    // TODO: is this correct?
254                }
255            }
256        }
257
258        if !self.constraints().is_empty() {
259            writeln!(f, "\nsuch that\n")?;
260            writeln!(f, "{}", pretty_expressions_as_top_level(self.constraints()))?;
261        }
262
263        if !self.clauses().is_empty() {
264            writeln!(f, "\nclauses:\n")?;
265
266            writeln!(f, "{}", pretty_clauses(self.clauses()))?;
267        }
268        Ok(())
269    }
270}
271
272// Using manual implementations of Uniplate so that we can update the old Rc<RefCell<<>>> with the
273// new value instead of creating a new one. This will keep the parent pointers in sync.
274//
275// I considered adding Rc RefCell shared-mutability to Uniplate, but I think this is unsound in
276// generality: e.g. two pointers to the same object are in our tree, and both get modified in
277// different ways.
278//
279// Shared mutability is probably fine here, as we only have one pointer to each symbol table
280// reachable via Uniplate, the one in its Submodel. The SymbolTable implementation doesn't return
281// or traverse through the parent pointers.
282//
283// -- nd60
284
285impl Uniplate for SubModel {
286    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
287        // Look inside constraint tree and symbol tables.
288
289        let (expr_tree, expr_ctx) = <Expression as Biplate<SubModel>>::biplate(self.root());
290
291        let symtab_ptr = self.symbols();
292        let (symtab_tree, symtab_ctx) = <SymbolTable as Biplate<SubModel>>::biplate(&symtab_ptr);
293
294        let tree = Tree::Many(VecDeque::from([expr_tree, symtab_tree]));
295
296        let self2 = self.clone();
297        let ctx = Box::new(move |x| {
298            let Tree::Many(xs) = x else {
299                panic!();
300            };
301
302            let root = expr_ctx(xs[0].clone());
303            let symtab = symtab_ctx(xs[1].clone());
304
305            let mut self3 = self2.clone();
306
307            let Expression::Root(_, _) = root else {
308                bug!("root expression not root");
309            };
310
311            *self3.root_mut_unchecked() = root;
312
313            *self3.symbols_mut() = symtab;
314
315            self3
316        });
317
318        (tree, ctx)
319    }
320}
321
322impl Biplate<Expression> for SubModel {
323    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
324        // Return constraints tree and look inside symbol table.
325        let symtab_ptr = self.symbols();
326        let (symtab_tree, symtab_ctx) = <SymbolTable as Biplate<Expression>>::biplate(&symtab_ptr);
327
328        let tree = Tree::Many(VecDeque::from([
329            Tree::One(self.root().clone()),
330            symtab_tree,
331        ]));
332
333        let self2 = self.clone();
334        let ctx = Box::new(move |x| {
335            let Tree::Many(xs) = x else {
336                panic!();
337            };
338
339            let Tree::One(root) = xs[0].clone() else {
340                panic!();
341            };
342
343            let symtab = symtab_ctx(xs[1].clone());
344
345            let mut self3 = self2.clone();
346
347            let Expression::Root(_, _) = root else {
348                bug!("root expression not root");
349            };
350
351            *self3.root_mut_unchecked() = root;
352
353            *self3.symbols_mut() = symtab;
354
355            self3
356        });
357
358        (tree, ctx)
359    }
360}
361
362impl Biplate<SubModel> for SubModel {
363    fn biplate(&self) -> (Tree<SubModel>, Box<dyn Fn(Tree<SubModel>) -> Self>) {
364        (
365            Tree::One(self.clone()),
366            Box::new(move |x| {
367                let Tree::One(x) = x else {
368                    panic!();
369                };
370                x
371            }),
372        )
373    }
374}
375
376impl Biplate<Atom> for SubModel {
377    fn biplate(&self) -> (Tree<Atom>, Box<dyn Fn(Tree<Atom>) -> Self>) {
378        // As atoms are only found in expressions, create a tree of atoms by
379        //
380        //  1. getting the expression tree
381        //  2. Turning that into a list
382        //  3. For each expression in the list, use Biplate<Atom> to turn it into an atom
383        //
384        //  Reconstruction works in reverse.
385
386        let (expression_tree, rebuild_self) = <SubModel as Biplate<Expression>>::biplate(self);
387        let (expression_list, rebuild_expression_tree) = expression_tree.list();
388
389        // Let the atom tree be a Tree::Many where each element is the result of running Biplate<Atom>::biplate on an expression in the expression list.
390        let (atom_trees, reconstruct_exprs): (VecDeque<_>, VecDeque<_>) = expression_list
391            .iter()
392            .map(|e| <Expression as Biplate<Atom>>::biplate(e))
393            .unzip();
394
395        let tree = Tree::Many(atom_trees);
396        let ctx = Box::new(move |atom_tree: Tree<Atom>| {
397            // 1. reconstruct expression_list from the atom tree
398
399            let Tree::Many(atoms) = atom_tree else {
400                panic!();
401            };
402
403            assert_eq!(
404                atoms.len(),
405                reconstruct_exprs.len(),
406                "the number of children should not change when using Biplate"
407            );
408
409            let expression_list: VecDeque<Expression> = izip!(atoms, &reconstruct_exprs)
410                .map(|(atom, recons)| recons(atom))
411                .collect();
412
413            // 2. reconstruct expression_tree from expression_list
414            let expression_tree = rebuild_expression_tree(expression_list);
415
416            // 3. reconstruct submodel from expression_tree
417            rebuild_self(expression_tree)
418        });
419
420        (tree, ctx)
421    }
422}
423
424impl Biplate<Comprehension> for SubModel {
425    fn biplate(
426        &self,
427    ) -> (
428        Tree<Comprehension>,
429        Box<dyn Fn(Tree<Comprehension>) -> Self>,
430    ) {
431        let (f1_tree, f1_ctx) = <_ as Biplate<Comprehension>>::biplate(&self.constraints);
432        let (f2_tree, f2_ctx) =
433            <SymbolTable as Biplate<Comprehension>>::biplate(&self.symbols.borrow());
434
435        let tree = Tree::Many(VecDeque::from([f1_tree, f2_tree]));
436        let self2 = self.clone();
437        let ctx = Box::new(move |x| {
438            let Tree::Many(xs) = x else {
439                panic!();
440            };
441
442            let root = f1_ctx(xs[0].clone());
443            let symtab = f2_ctx(xs[1].clone());
444
445            let mut self3 = self2.clone();
446
447            let Expression::Root(_, _) = &*root else {
448                bug!("root expression not root");
449            };
450
451            *self3.symbols_mut() = symtab;
452            self3.constraints = root;
453
454            self3
455        });
456
457        (tree, ctx)
458    }
459}