conjure_cp_core/ast/
model.rs

1#![allow(clippy::arc_with_non_send_sync)] // uniplate needs this
2use std::cell::RefCell;
3use std::collections::{HashMap, VecDeque};
4use std::fmt::{Debug, Display};
5use std::rc::Rc;
6use std::sync::{Arc, RwLock};
7
8use derivative::Derivative;
9use serde::{Deserialize, Serialize};
10use uniplate::{Biplate, Tree, Uniplate};
11
12use crate::ast::Expression;
13use crate::context::Context;
14
15use super::serde::{HasId, ObjId};
16use super::types::Typeable;
17use super::{DeclarationPtr, Name, SubModel};
18use super::{ReturnType, SymbolTable};
19
20/// An Essence model.
21///
22/// - This type wraps a [`Submodel`] containing the top-level lexical scope. To manipulate the
23///   model's constraints or symbols, first convert it to a [`Submodel`] using
24///   [`as_submodel`](Model::as_submodel) / [`as_submodel_mut`](Model::as_submodel_mut).
25///
26/// - To de/serialise a model using `serde`, see [`SerdeModel`].
27#[derive(Derivative, Clone, Debug)]
28#[derivative(PartialEq, Eq)]
29pub struct Model {
30    submodel: SubModel,
31    pub search_order: Option<Vec<Name>>,
32    pub dominance: Option<Expression>,
33    #[derivative(PartialEq = "ignore")]
34    pub context: Arc<RwLock<Context<'static>>>,
35}
36
37impl Model {
38    pub fn from_submodel(submodel: SubModel) -> Model {
39        Model {
40            submodel,
41            ..Default::default()
42        }
43    }
44
45    /// Creates a new model from the given context.
46    pub fn new(context: Arc<RwLock<Context<'static>>>) -> Model {
47        Model {
48            submodel: SubModel::new_top_level(),
49            dominance: None,
50            context,
51            search_order: None,
52        }
53    }
54
55    /// Returns this model as a [`Submodel`].
56    pub fn as_submodel(&self) -> &SubModel {
57        &self.submodel
58    }
59
60    /// Returns this model as a mutable [`Submodel`].
61    pub fn as_submodel_mut(&mut self) -> &mut SubModel {
62        &mut self.submodel
63    }
64
65    /// Replaces the model contents with `new_submodel`, returning the old contents.
66    pub fn replace_submodel(&mut self, new_submodel: SubModel) -> SubModel {
67        std::mem::replace(self.as_submodel_mut(), new_submodel)
68    }
69}
70
71impl Default for Model {
72    fn default() -> Self {
73        Model {
74            submodel: SubModel::new_top_level(),
75            dominance: None,
76            context: Arc::new(RwLock::new(Context::default())),
77            search_order: None,
78        }
79    }
80}
81
82impl Typeable for Model {
83    fn return_type(&self) -> Option<ReturnType> {
84        Some(ReturnType::Bool)
85    }
86}
87
88// At time of writing (03/02/2025), the Uniplate derive macro doesn't like the lifetimes inside
89// context, and we do not yet have a way of ignoring this field.
90impl Uniplate for Model {
91    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
92        // Model contains no sub-models.
93        let self2 = self.clone();
94        (Tree::Zero, Box::new(move |_| self2.clone()))
95    }
96}
97
98impl Biplate<Expression> for Model {
99    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
100        // walk into submodel
101        let submodel = self.as_submodel();
102        let (expr_tree, expr_ctx) = <SubModel as Biplate<Expression>>::biplate(submodel);
103
104        // walk into dominance relation if it exists
105        let dom_tree = match &self.dominance {
106            Some(expr) => Tree::One(expr.clone()),
107            None => Tree::Zero,
108        };
109        let tree = Tree::<Expression>::Many(VecDeque::from([expr_tree, dom_tree]));
110
111        let self2 = self.clone();
112        let ctx = Box::new(move |x| match x {
113            Tree::Many(xs) => {
114                if xs.len() != 2 {
115                    panic!("Expected a tree with two children");
116                }
117                let submodel_tree = xs[0].clone();
118                let dom_tree = xs[1].clone();
119
120                // reconstruct the submodel
121                let submodel = expr_ctx(submodel_tree);
122                // reconstruct the dominance relation
123                let dominance = match dom_tree {
124                    Tree::One(expr) => Some(expr),
125                    Tree::Zero => None,
126                    _ => panic!("Expected a tree with two children"),
127                };
128
129                let mut self3 = self2.clone();
130                self3.replace_submodel(submodel);
131                self3.dominance = dominance;
132                self3
133            }
134            _ => {
135                panic!("Expected a tree with two children");
136            }
137        });
138
139        (tree, ctx)
140    }
141}
142
143impl Biplate<SubModel> for Model {
144    fn biplate(&self) -> (Tree<SubModel>, Box<dyn Fn(Tree<SubModel>) -> Self>) {
145        let submodel = self.as_submodel().clone();
146
147        let self2 = self.clone();
148        let ctx = Box::new(move |x| {
149            let Tree::One(submodel) = x else {
150                panic!();
151            };
152
153            let mut self3 = self2.clone();
154            self3.replace_submodel(submodel);
155            self3
156        });
157
158        (Tree::One(submodel), ctx)
159    }
160}
161
162impl Display for Model {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        std::fmt::Display::fmt(self.as_submodel(), f)
165    }
166}
167
168/// A model that is de/serializable using `serde`.
169///
170/// To turn this into a rewritable model, it needs to be initialised using [`initialise`](SerdeModel::initialise).
171///
172/// To deserialise a [`Model`], use `.into()` to convert it into a `SerdeModel` first.
173#[derive(Clone, Debug, Serialize, Deserialize)]
174pub struct SerdeModel {
175    #[serde(flatten)]
176    submodel: SubModel,
177    search_order: Option<Vec<Name>>, // TODO: make this a [expressions]
178    dominance: Option<Expression>,
179}
180
181impl SerdeModel {
182    /// Initialises the model for rewriting.
183    ///
184    /// This swizzles the pointers to symbol tables and declarations using the stored ids.
185    pub fn initialise(mut self, context: Arc<RwLock<Context<'static>>>) -> Option<Model> {
186        // The definitive versions of each symbol table are stored in the submodels. Parent
187        // pointers store dummy values with the correct ids, but nothing else. We need to replace
188        // these dummy values with pointers to the actual parent symbol tables, using the ids to
189        // know which tables should be equal.
190        //
191        // See super::serde::RcRefCellToInner, super::serde::RcRefCellToId.
192
193        // Store the definitive versions of all symbol tables by id.
194        let mut tables: HashMap<ObjId, Rc<RefCell<SymbolTable>>> = HashMap::new();
195
196        // Find the definitive versions by traversing the sub-models.
197        for submodel in self.submodel.universe() {
198            let id = submodel.symbols().id();
199
200            // ids should be unique!
201            assert_eq!(
202                tables.insert(id, submodel.symbols_ptr_unchecked().clone()),
203                None
204            );
205        }
206
207        // Restore parent pointers using `tables`.
208        for table in tables.clone().into_values() {
209            let mut table_mut = table.borrow_mut();
210            let parent_mut = table_mut.parent_mut_unchecked();
211
212            #[allow(clippy::unwrap_used)]
213            if let Some(parent) = parent_mut {
214                let parent_id = parent.borrow().id();
215
216                *parent = tables.get(&parent_id).unwrap().clone();
217            }
218        }
219
220        // The definitive versions of declarations are stored in the symbol table. References store
221        // dummy values with the correct ids, but nothing else.
222
223        // Store the definitive version of all declarations by id.
224        let mut all_declarations: HashMap<ObjId, DeclarationPtr> = HashMap::new();
225        for table in tables.values() {
226            for (_, decl) in table.as_ref().borrow().clone().into_iter_local() {
227                let id = decl.id();
228                all_declarations.insert(id, decl);
229            }
230        }
231
232        // Swizzle declaration pointers in expressions (references, auxdecls) using their ids and `all_declarations`.
233        *self.submodel.constraints_mut() = self.submodel.constraints().transform_bi(&move |decl: DeclarationPtr| {
234                let id = decl.id();
235                        all_declarations
236                            .get(&id)
237                            .unwrap_or_else(|| panic!("A declaration used in the expression tree should exist in the symbol table. The missing declaration has id {id}."))
238                            .clone()
239        });
240
241        Some(Model {
242            submodel: self.submodel,
243            dominance: self.dominance,
244            context,
245            search_order: self.search_order,
246        })
247    }
248}
249
250impl From<Model> for SerdeModel {
251    fn from(val: Model) -> Self {
252        SerdeModel {
253            submodel: val.submodel,
254            dominance: val.dominance,
255            search_order: val.search_order,
256        }
257    }
258}
259
260impl Display for SerdeModel {
261    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262        std::fmt::Display::fmt(&self.submodel, f)
263    }
264}