conjure_core/ast/
submodel.rs

1use super::{
2    comprehension::Comprehension,
3    declaration::DeclarationKind,
4    pretty::{
5        pretty_domain_letting_declaration, pretty_expressions_as_top_level,
6        pretty_value_letting_declaration, pretty_variable_declaration,
7    },
8    serde::RcRefCellAsInner,
9    Atom, Declaration, Literal,
10};
11use serde::{Deserialize, Serialize};
12use serde_with::serde_as;
13use uniplate::{Biplate, Tree, Uniplate};
14
15use crate::{bug, into_matrix_expr, metadata::Metadata};
16use std::{
17    cell::{Ref, RefCell, RefMut},
18    collections::VecDeque,
19    fmt::Display,
20    rc::Rc,
21};
22
23use super::{types::Typeable, Expression, ReturnType, SymbolTable};
24
25/// A sub-model, representing a lexical scope in the model.
26///
27/// Each sub-model contains a symbol table representing its scope, as well as a expression tree.
28///
29/// The expression tree is formed of a root node of type [`Expression::Root`], which contains a
30/// vector of top-level constraints.
31#[serde_as]
32#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
33pub struct SubModel {
34    constraints: Expression,
35    #[serde_as(as = "RcRefCellAsInner")]
36    symbols: Rc<RefCell<SymbolTable>>,
37}
38
39impl SubModel {
40    /// Creates a new [`Submodel`] with no parent scope.
41    ///
42    /// Top level models are represented as [`Model`](super::model): consider using
43    /// [`Model::new`](super::Model::new) instead.
44    #[doc(hidden)]
45    pub(super) fn new_top_level() -> SubModel {
46        SubModel {
47            constraints: Expression::Root(Metadata::new(), vec![]),
48            symbols: Rc::new(RefCell::new(SymbolTable::new())),
49        }
50    }
51
52    /// Creates a new [`Submodel`] as a child scope of `parent`.
53    ///
54    /// `parent` should be the symbol table of the containing scope of this sub-model.
55    pub fn new(parent: Rc<RefCell<SymbolTable>>) -> SubModel {
56        SubModel {
57            constraints: Expression::Root(Metadata::new(), vec![]),
58            symbols: Rc::new(RefCell::new(SymbolTable::with_parent(parent))),
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) -> &Rc<RefCell<SymbolTable>> {
67        &self.symbols
68    }
69
70    /// The symbol table for this sub-model as a reference.
71    pub fn symbols(&self) -> Ref<SymbolTable> {
72        (*self.symbols).borrow()
73    }
74
75    /// The symbol table for this sub-model as a mutable reference.
76    pub fn symbols_mut(&mut self) -> RefMut<SymbolTable> {
77        (*self.symbols).borrow_mut()
78    }
79
80    /// The root node of this sub-model.
81    ///
82    /// The root node is an [`Expression::Root`] containing a vector of the top level constraints
83    /// in this sub-model.
84    pub fn root(&self) -> &Expression {
85        &self.constraints
86    }
87
88    /// The root node of this sub-model, as a mutable reference.
89    ///
90    /// The caller is responsible for ensuring that the root node remains an [`Expression::Root`].
91    ///
92    pub fn root_mut_unchecked(&mut self) -> &mut Expression {
93        &mut self.constraints
94    }
95
96    /// Replaces the root node with `new_root`, returning the old root node.
97    ///
98    /// # Panics
99    ///
100    /// - If `new_root` is not an [`Expression::Root`].
101    pub fn replace_root(&mut self, new_root: Expression) -> Expression {
102        let Expression::Root(_, _) = new_root else {
103            panic!("new_root is not an Expression::Root");
104        };
105
106        // INVARIANT: already checked that `new_root` is an [`Expression::Root`]
107        std::mem::replace(self.root_mut_unchecked(), new_root)
108    }
109
110    /// The top-level constraints in this sub-model.
111    pub fn constraints(&self) -> &Vec<Expression> {
112        let Expression::Root(_, constraints) = &self.constraints else {
113            bug!("The top level expression in a submodel should be Expr::Root");
114        };
115
116        constraints
117    }
118
119    /// The top-level constraints in this sub-model as a mutable vector.
120    pub fn constraints_mut(&mut self) -> &mut Vec<Expression> {
121        let Expression::Root(_, constraints) = &mut self.constraints else {
122            bug!("The top level expression in a submodel should be Expr::Root");
123        };
124
125        constraints
126    }
127
128    /// Replaces the top-level constraints with `new_constraints`, returning the old ones.
129    pub fn replace_constraints(&mut self, new_constraints: Vec<Expression>) -> Vec<Expression> {
130        std::mem::replace(self.constraints_mut(), new_constraints)
131    }
132
133    /// Adds a top-level constraint.
134    pub fn add_constraint(&mut self, constraint: Expression) {
135        self.constraints_mut().push(constraint);
136    }
137
138    /// Adds top-level constraints.
139    pub fn add_constraints(&mut self, constraints: Vec<Expression>) {
140        self.constraints_mut().extend(constraints);
141    }
142
143    /// Adds a new symbol to the symbol table
144    /// (Wrapper over `SymbolTable.insert`)
145    pub fn add_symbol(&mut self, sym: Declaration) -> Option<()> {
146        self.symbols_mut().insert(Rc::new(sym))
147    }
148
149    /// Converts the constraints in this submodel to a single expression suitable for use inside
150    /// another expression tree.
151    ///
152    /// * If this submodel has no constraints, true is returned.
153    /// * If this submodel has a single constraint, that constraint is returned.
154    /// * If this submodel has multiple constraints, they are returned as an `and` constraint.
155    pub fn into_single_expression(self) -> Expression {
156        let constraints = self.constraints().clone();
157        match constraints.len() {
158            0 => Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(true))),
159            1 => constraints[0].clone(),
160            _ => Expression::And(Metadata::new(), Box::new(into_matrix_expr![constraints])),
161        }
162    }
163}
164
165impl Typeable for SubModel {
166    fn return_type(&self) -> Option<super::ReturnType> {
167        Some(ReturnType::Bool)
168    }
169}
170
171impl Display for SubModel {
172    #[allow(clippy::unwrap_used)] // [rustdocs]: should only fail iff the formatter fails
173    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174        for (name, decl) in self.symbols().clone().into_iter_local() {
175            match decl.kind() {
176                DeclarationKind::DecisionVariable(_) => {
177                    writeln!(
178                        f,
179                        "{}",
180                        pretty_variable_declaration(&self.symbols(), &name).unwrap()
181                    )?;
182                }
183                DeclarationKind::ValueLetting(_) => {
184                    writeln!(
185                        f,
186                        "{}",
187                        pretty_value_letting_declaration(&self.symbols(), &name).unwrap()
188                    )?;
189                }
190                DeclarationKind::DomainLetting(_) => {
191                    writeln!(
192                        f,
193                        "{}",
194                        pretty_domain_letting_declaration(&self.symbols(), &name).unwrap()
195                    )?;
196                }
197                DeclarationKind::Given(d) => {
198                    writeln!(f, "given {name}: {d}")?;
199                }
200            }
201        }
202
203        writeln!(f, "\nsuch that\n")?;
204
205        writeln!(f, "{}", pretty_expressions_as_top_level(self.constraints()))?;
206
207        Ok(())
208    }
209}
210
211// Using manual implementations of Uniplate so that we can update the old Rc<RefCell<<>>> with the
212// new value instead of creating a new one. This will keep the parent pointers in sync.
213//
214// I considered adding Rc RefCell shared-mutability to Uniplate, but I think this is unsound in
215// generality: e.g. two pointers to the same object are in our tree, and both get modified in
216// different ways.
217//
218// Shared mutability is probably fine here, as we only have one pointer to each symbol table
219// reachable via Uniplate, the one in its Submodel. The SymbolTable implementation doesn't return
220// or traverse through the parent pointers.
221//
222// -- nd60
223
224impl Uniplate for SubModel {
225    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
226        // Look inside constraint tree and symbol tables.
227
228        let (expr_tree, expr_ctx) = <Expression as Biplate<SubModel>>::biplate(self.root());
229
230        let symtab_ptr = self.symbols();
231        let (symtab_tree, symtab_ctx) = <SymbolTable as Biplate<SubModel>>::biplate(&symtab_ptr);
232
233        let tree = Tree::Many(VecDeque::from([expr_tree, symtab_tree]));
234
235        let self2 = self.clone();
236        let ctx = Box::new(move |x| {
237            let Tree::Many(xs) = x else {
238                panic!();
239            };
240
241            let root = expr_ctx(xs[0].clone());
242            let symtab = symtab_ctx(xs[1].clone());
243
244            let mut self3 = self2.clone();
245
246            let Expression::Root(_, _) = root else {
247                bug!("root expression not root");
248            };
249
250            *self3.root_mut_unchecked() = root;
251
252            *self3.symbols_mut() = symtab;
253
254            self3
255        });
256
257        (tree, ctx)
258    }
259}
260
261impl Biplate<Expression> for SubModel {
262    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
263        // Return constraints tree and look inside symbol table.
264        let symtab_ptr = self.symbols();
265        let (symtab_tree, symtab_ctx) = <SymbolTable as Biplate<Expression>>::biplate(&symtab_ptr);
266
267        let tree = Tree::Many(VecDeque::from([
268            Tree::One(self.root().clone()),
269            symtab_tree,
270        ]));
271
272        let self2 = self.clone();
273        let ctx = Box::new(move |x| {
274            let Tree::Many(xs) = x else {
275                panic!();
276            };
277
278            let Tree::One(root) = xs[0].clone() else {
279                panic!();
280            };
281
282            let symtab = symtab_ctx(xs[1].clone());
283
284            let mut self3 = self2.clone();
285
286            let Expression::Root(_, _) = root else {
287                bug!("root expression not root");
288            };
289
290            *self3.root_mut_unchecked() = root;
291
292            *self3.symbols_mut() = symtab;
293
294            self3
295        });
296
297        (tree, ctx)
298    }
299}
300
301impl Biplate<Atom> for SubModel {
302    fn biplate(&self) -> (Tree<Atom>, Box<dyn Fn(Tree<Atom>) -> Self>) {
303        // look into expressions
304        let (tree, expr_ctx) = <Expression as Biplate<Atom>>::biplate(&self.constraints);
305
306        let self2 = self.clone();
307        let ctx = Box::new(move |x| {
308            let mut self3 = self2.clone();
309            self3.constraints = expr_ctx(x);
310            self3
311        });
312
313        (tree, ctx)
314    }
315}
316
317impl Biplate<SubModel> for SubModel {
318    fn biplate(&self) -> (Tree<SubModel>, Box<dyn Fn(Tree<SubModel>) -> Self>) {
319        (
320            Tree::One(self.clone()),
321            Box::new(move |x| {
322                let Tree::One(x) = x else {
323                    panic!();
324                };
325                x
326            }),
327        )
328    }
329}
330
331impl Biplate<Comprehension> for SubModel {
332    fn biplate(
333        &self,
334    ) -> (
335        Tree<Comprehension>,
336        Box<dyn Fn(Tree<Comprehension>) -> Self>,
337    ) {
338        let (f1_tree, f1_ctx) = <_ as Biplate<Comprehension>>::biplate(&self.constraints);
339        let (f2_tree, f2_ctx) =
340            <SymbolTable as Biplate<Comprehension>>::biplate(&self.symbols.borrow());
341
342        let tree = Tree::Many(VecDeque::from([f1_tree, f2_tree]));
343        let self2 = self.clone();
344        let ctx = Box::new(move |x| {
345            let Tree::Many(xs) = x else {
346                panic!();
347            };
348
349            let root = f1_ctx(xs[0].clone());
350            let symtab = f2_ctx(xs[1].clone());
351
352            let mut self3 = self2.clone();
353
354            let Expression::Root(_, _) = root else {
355                bug!("root expression not root");
356            };
357
358            *self3.symbols_mut() = symtab;
359            *self3.root_mut_unchecked() = root;
360
361            self3
362        });
363
364        (tree, ctx)
365    }
366}