conjure_cp_core/rule_engine/
rule.rs1use std::cell::RefCell;
2use std::collections::BTreeSet;
3use std::fmt::{self, Display, Formatter};
4use std::hash::Hash;
5use std::rc::Rc;
6
7use thiserror::Error;
8
9use crate::Model;
10use crate::ast::{CnfClause, DeclarationPtr, Expression, Name, SymbolTable};
11use crate::rule_engine::RuleData;
12use crate::rule_engine::rewriter_common::{RuleResult, log_rule_application};
13use tree_morph::prelude::Commands;
14use tree_morph::prelude::Rule as MorphRule;
15
16#[derive(Clone, Debug, Default)]
17pub(crate) struct MorphState {
18 pub symbols: SymbolTable,
19 pub clauses: Vec<CnfClause>,
20}
21
22#[derive(Debug, Error)]
23pub enum ApplicationError {
24 #[error("Rule is not applicable")]
25 RuleNotApplicable,
26
27 #[error("Could not calculate the expression domain")]
28 DomainError,
29}
30
31#[non_exhaustive]
67#[derive(Clone, Debug)]
68pub struct Reduction {
69 pub new_expression: Expression,
70 pub new_top: Vec<Expression>,
71 pub symbols: SymbolTable,
72 pub new_clauses: Vec<CnfClause>,
73}
74
75pub type ApplicationResult = Result<Reduction, ApplicationError>;
78
79impl Reduction {
80 pub fn new(new_expression: Expression, new_top: Vec<Expression>, symbols: SymbolTable) -> Self {
81 Self {
82 new_expression,
83 new_top,
84 symbols,
85 new_clauses: Vec::new(),
86 }
87 }
88
89 pub fn pure(new_expression: Expression) -> Self {
91 Self {
92 new_expression,
93 new_top: Vec::new(),
94 symbols: SymbolTable::new(),
95 new_clauses: Vec::new(),
96 }
97 }
98
99 pub fn with_symbols(new_expression: Expression, symbols: SymbolTable) -> Self {
101 Self {
102 new_expression,
103 new_top: Vec::new(),
104 symbols,
105 new_clauses: Vec::new(),
106 }
107 }
108
109 pub fn with_top(new_expression: Expression, new_top: Vec<Expression>) -> Self {
111 Self {
112 new_expression,
113 new_top,
114 symbols: SymbolTable::new(),
115 new_clauses: Vec::new(),
116 }
117 }
118
119 pub fn cnf(
121 new_expression: Expression,
122 new_clauses: Vec<CnfClause>,
123 symbols: SymbolTable,
124 ) -> Self {
125 Self {
126 new_expression,
127 new_top: Vec::new(),
128 symbols,
129 new_clauses,
130 }
131 }
132
133 pub fn apply(self, model: &mut Model) {
135 model.symbols_mut().extend(self.symbols); model.add_constraints(self.new_top.clone());
137 model.add_clauses(self.new_clauses);
138 }
139
140 pub fn added_symbols(&self, initial_symbols: &SymbolTable) -> BTreeSet<Name> {
142 let initial_symbols_set: BTreeSet<Name> = initial_symbols
143 .clone()
144 .into_iter_local()
145 .map(|x| x.0)
146 .collect();
147 let new_symbols_set: BTreeSet<Name> = self
148 .symbols
149 .clone()
150 .into_iter_local()
151 .map(|x| x.0)
152 .collect();
153
154 new_symbols_set
155 .difference(&initial_symbols_set)
156 .cloned()
157 .collect()
158 }
159
160 pub fn changed_symbols(
164 &self,
165 initial_symbols: &SymbolTable,
166 ) -> Vec<(Name, DeclarationPtr, DeclarationPtr)> {
167 let mut changes: Vec<(Name, DeclarationPtr, DeclarationPtr)> = vec![];
168
169 for (var_name, initial_value) in initial_symbols.clone().into_iter_local() {
170 let Some(new_value) = self.symbols.lookup(&var_name) else {
171 continue;
172 };
173
174 if new_value != initial_value {
175 changes.push((var_name.clone(), initial_value.clone(), new_value.clone()));
176 }
177 }
178 changes
179 }
180}
181
182pub type RuleFn = fn(&Expression, &SymbolTable) -> ApplicationResult;
184
185#[derive(Clone, Debug)]
194pub struct Rule<'a> {
195 pub name: &'a str,
196 pub application: RuleFn,
197 pub rule_sets: &'a [(&'a str, u16)], pub applicable_to: Option<&'static [usize]>,
200}
201
202impl<'a> Rule<'a> {
203 pub const fn new(
204 name: &'a str,
205 application: RuleFn,
206 rule_sets: &'a [(&'static str, u16)],
207 ) -> Self {
208 Self {
209 name,
210 application,
211 rule_sets,
212 applicable_to: None,
213 }
214 }
215
216 pub fn apply(&self, expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
217 (self.application)(expr, symbols)
218 }
219}
220
221impl Display for Rule<'_> {
222 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
223 write!(f, "{}", self.name)
224 }
225}
226
227impl PartialEq for Rule<'_> {
228 fn eq(&self, other: &Self) -> bool {
229 self.name == other.name
230 }
231}
232
233impl Eq for Rule<'_> {}
234
235impl Hash for Rule<'_> {
236 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
237 self.name.hash(state);
238 }
239}
240
241impl MorphRule<Expression, MorphState> for Rule<'_> {
242 fn apply(
243 &self,
244 commands: &mut Commands<Expression, MorphState>,
245 subtree: &Expression,
246 meta: &MorphState,
247 ) -> Option<Expression> {
248 let reduction = self.apply(subtree, &meta.symbols).ok()?;
249 let new_expression = reduction.new_expression;
250 let new_top = reduction.new_top;
251 let added_symbols = reduction.symbols;
252 let added_clauses = reduction.new_clauses;
253 commands.mut_meta(Box::new(move |m: &mut MorphState| {
254 m.symbols.extend(added_symbols);
255 m.clauses.extend(added_clauses);
256 }));
257 if !new_top.is_empty() {
258 commands.transform(Box::new(move |m| m.extend_root(new_top)));
259 }
260 Some(new_expression)
261 }
262
263 fn name(&self) -> &str {
264 self.name
265 }
266
267 fn applicable_to(&self) -> Option<Vec<usize>> {
268 self.applicable_to.map(|s| s.to_vec())
269 }
270}
271
272impl MorphRule<Expression, MorphState> for &Rule<'_> {
273 fn apply(
274 &self,
275 commands: &mut Commands<Expression, MorphState>,
276 subtree: &Expression,
277 meta: &MorphState,
278 ) -> Option<Expression> {
279 let reduction = Rule::apply(self, subtree, &meta.symbols).ok()?;
280 let new_expression = reduction.new_expression;
281 let new_top = reduction.new_top;
282 let added_symbols = reduction.symbols;
283 let added_clauses = reduction.new_clauses;
284 commands.mut_meta(Box::new(move |m: &mut MorphState| {
285 m.symbols.extend(added_symbols);
286 m.clauses.extend(added_clauses);
287 }));
288 if !new_top.is_empty() {
289 commands.transform(Box::new(move |m| m.extend_root(new_top)));
290 }
291 Some(new_expression)
292 }
293
294 fn name(&self) -> &str {
295 self.name
296 }
297}
298
299impl MorphRule<Expression, Rc<RefCell<MorphState>>> for Rule<'_> {
300 fn apply(
301 &self,
302 commands: &mut Commands<Expression, Rc<RefCell<MorphState>>>,
303 subtree: &Expression,
304 meta: &Rc<RefCell<MorphState>>,
305 ) -> Option<Expression> {
306 let state = meta.borrow();
307 let reduction = self.apply(subtree, &state.symbols).ok()?;
308 let new_expression = reduction.new_expression;
309 let new_top = reduction.new_top;
310 let added_symbols = reduction.symbols;
311 let added_clauses = reduction.new_clauses;
312 commands.mut_meta(Box::new(move |m| {
313 let mut state = m.borrow_mut();
314 state.symbols.extend(added_symbols);
315 state.clauses.extend(added_clauses);
316 }));
317
318 if !new_top.is_empty() {
319 commands.transform(Box::new(move |m| m.extend_root(new_top)));
320 }
321
322 Some(new_expression)
323 }
324
325 fn name(&self) -> &str {
326 self.name
327 }
328}
329
330impl MorphRule<Expression, MorphState> for RuleData<'_> {
331 fn apply(
332 &self,
333 commands: &mut Commands<Expression, MorphState>,
334 subtree: &Expression,
335 meta: &MorphState,
336 ) -> Option<Expression> {
337 let reduction = self.rule.apply(subtree, &meta.symbols).ok()?;
338 let result = RuleResult {
339 rule_data: self.clone(),
340 reduction: reduction.clone(),
341 };
342
343 log_rule_application(&result, subtree, &meta.symbols, None);
344
345 let new_expression = reduction.new_expression;
346 let new_top = reduction.new_top;
347 let added_symbols = reduction.symbols;
348 let added_clauses = reduction.new_clauses;
349 commands.mut_meta(Box::new(move |m: &mut MorphState| {
350 m.symbols.extend(added_symbols);
351 m.clauses.extend(added_clauses);
352 }));
353
354 if !new_top.is_empty() {
355 commands.transform(Box::new(move |m| m.extend_root(new_top)));
356 }
357 Some(new_expression)
358 }
359
360 fn name(&self) -> &str {
361 self.rule.name
362 }
363
364 fn applicable_to(&self) -> Option<Vec<usize>> {
365 self.rule.applicable_to.map(|s| s.to_vec())
366 }
367}