conjure_cp_core/rule_engine/
rewriter_common.rs1use super::{
3 Reduction,
4 resolve_rules::{ResolveRulesError, RuleData},
5};
6use crate::ast::{
7 Expression, SubModel,
8 pretty::{pretty_variable_declaration, pretty_vec},
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
33 let new_top_string = if !red.new_top.is_empty() {
36 pretty_vec(&red.new_top)
37 } else {
38 pretty_vec(&red.new_clauses)
39 };
40
41 info!(
42 %new_top_string,
43 "Applying rule: {} ({:?}), to expression: {}, resulting in: {}",
44 rule.name,
45 rule.rule_sets,
46 initial_expression,
47 red.new_expression
48 );
49
50 let top_level_str = if !red.new_top.is_empty() {
52 let mut exprs: Vec<String> = vec![];
53
54 for expr in &red.new_top {
55 exprs.push(format!(" {expr}"));
56 }
57
58 let exprs = exprs.iter().join("\n");
59
60 format!("new constraints:\n{exprs}\n")
61 } else if !red.new_clauses.is_empty() {
62 let mut exprs: Vec<String> = vec![];
63
64 for clause in &red.new_clauses {
65 exprs.push(format!(" {clause}"));
66 }
67
68 let exprs = exprs.iter().join("\n");
69
70 format!("new clauses:\n{exprs}\n")
71 } else {
72 String::new()
73 };
74
75 let new_variables_str = {
78 let mut vars: Vec<String> = vec![];
79
80 for var_name in red.added_symbols(&initial_model.symbols()) {
81 #[allow(clippy::unwrap_used)]
82 vars.push(format!(
83 " {}",
84 pretty_variable_declaration(&red.symbols, &var_name).unwrap()
85 ));
86 }
87 if vars.is_empty() {
88 String::new()
89 } else {
90 format!("new variables:\n{}", vars.join("\n"))
91 }
92 };
93
94 trace!(
95 target: "rule_engine_human",
96 "{}, \n ~~> {} ({:?}) \n{} \n{}\n{}--\n",
97 initial_expression,
98 rule.name,
99 rule.rule_sets,
100 red.new_expression,
101 new_variables_str,
102 top_level_str
103 );
104
105 trace!(
106 target: "rule_engine",
107 "{}",
108 json!({
109 "rule_name": result.rule_data.rule.name,
110 "rule_priority": result.rule_data.priority,
111 "rule_set": {
112 "name": result.rule_data.rule_set.name,
113 },
114 "initial_expression": serde_json::to_value(initial_expression).unwrap(),
115 "transformed_expression": serde_json::to_value(&red.new_expression).unwrap()
116 })
117
118 )
119}
120
121#[derive(Debug, Error)]
123pub enum RewriteError {
124 #[error("Error resolving rules {0}")]
125 ResolveRulesError(ResolveRulesError),
126}
127
128impl From<ResolveRulesError> for RewriteError {
129 fn from(error: ResolveRulesError) -> Self {
130 RewriteError::ResolveRulesError(error)
131 }
132}