Skip to main content

conjure_cp_core/ast/
submodel.rs

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