conjure_core/rule_engine/
rewriter_common.rs1use super::{
3 resolve_rules::{ResolveRulesError, RuleData},
4 Reduction,
5};
6use crate::ast::{
7 pretty::{pretty_variable_declaration, pretty_vec},
8 Expression, SubModel,
9};
10
11use itertools::Itertools;
12use serde_json::json;
13use std::fmt::Debug;
14use thiserror::Error;
15use tracing::{info, trace};
16
17#[derive(Debug, Clone)]
18pub struct RuleResult<'a> {
19 pub rule_data: RuleData<'a>,
20 pub reduction: Reduction,
21}
22
23pub fn log_rule_application(
26 result: &RuleResult,
27 initial_expression: &Expression,
28 initial_model: &SubModel,
29) {
30 let red = &result.reduction;
31 let rule = result.rule_data.rule;
32 let new_top_string = pretty_vec(&red.new_top);
33
34 info!(
35 %new_top_string,
36 "Applying rule: {} ({:?}), to expression: {}, resulting in: {}",
37 rule.name,
38 rule.rule_sets,
39 initial_expression,
40 red.new_expression
41 );
42
43 let top_level_str = if red.new_top.is_empty() {
45 String::new()
46 } else {
47 let mut exprs: Vec<String> = vec![];
48
49 for expr in &red.new_top {
50 exprs.push(format!(" {}", expr));
51 }
52
53 let exprs = exprs.iter().join("\n");
54
55 format!("new constraints:\n{}\n", exprs)
56 };
57
58 let new_variables_str = {
61 let mut vars: Vec<String> = vec![];
62
63 for var_name in red.added_symbols(&initial_model.symbols()) {
64 #[allow(clippy::unwrap_used)]
65 vars.push(format!(
66 " {}",
67 pretty_variable_declaration(&red.symbols, &var_name).unwrap()
68 ));
69 }
70 if vars.is_empty() {
71 String::new()
72 } else {
73 format!("new variables:\n{}", vars.join("\n"))
74 }
75 };
76
77 trace!(
78 target: "rule_engine_human",
79 "{}, \n ~~> {} ({:?}) \n{} \n{}\n{}--\n",
80 initial_expression,
81 rule.name,
82 rule.rule_sets,
83 red.new_expression,
84 new_variables_str,
85 top_level_str
86 );
87
88 trace!(
89 target: "rule_engine",
90 "{}",
91 json!({
92 "rule_name": result.rule_data.rule.name,
93 "rule_priority": result.rule_data.priority,
94 "rule_set": {
95 "name": result.rule_data.rule_set.name,
96 },
97 "initial_expression": serde_json::to_value(initial_expression).unwrap(),
98 "transformed_expression": serde_json::to_value(&red.new_expression).unwrap()
99 })
100
101 )
102}
103
104#[derive(Debug, Error)]
106pub enum RewriteError {
107 #[error("Error resolving rules {0}")]
108 ResolveRulesError(ResolveRulesError),
109}
110
111impl From<ResolveRulesError> for RewriteError {
112 fn from(error: ResolveRulesError) -> Self {
113 RewriteError::ResolveRulesError(error)
114 }
115}