1
/// This procedural macro registers a decorated function with `conjure_cp_rules`' global registry, and
2
/// adds the rule to one or more `RuleSet`'s.
3
///
4
/// It may be used in any downstream crate.
5
/// For more information on registration, see the [`inventory`](https://docs.rs/inventory/latest/inventory/) crate.
6
///
7
/// <hr>
8
///
9
/// Functions must have the signature `fn(&Expr) -> ApplicationResult`.
10
/// The created rule will have the same name as the function.
11
///
12
/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`.
13
/// Please ensure that other variable names in the same scope do not conflict with these.
14
///
15
/// This macro must decorate a function with the given signature.
16
/// As arguments, it excepts a tuple of 2-tuples in the format:
17
/// `((<RuleSet name>, <Priority in RuleSet>), ...)`
18
///
19
/// <hr>
20
///
21
/// For example:
22
/// ```rust
23
/// use conjure_cp_core::ast::Expression;
24
/// use conjure_cp_core::ast::SymbolTable;
25
/// use conjure_cp_core::rule_engine::{ApplicationError, ApplicationResult, RuleEffect};
26
/// use conjure_cp_core::rule_engine::register_rule;
27
///
28
/// #[register_rule("RuleSetName", 10)]
29
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
30
///   Ok(RuleEffect::pure(expr.clone()))
31
/// }
32
/// ```
33
pub use conjure_cp_rule_macros::register_rule;
34

            
35
/// This procedural macro registers a rule set with the global registry.
36
/// It may be used in any downstream crate.
37
///
38
/// For more information on registration, see the [`inventory`](https://docs.rs/inventory/latest/inventory/) crate.
39
///
40
/// This macro uses the following syntax:
41
///
42
/// ```text
43
/// register_rule_set!(<RuleSet name>, (<DependencyRuleSet1>, <DependencyRuleSet2>, ...), <SolverFamily>);
44
/// ```
45
///
46
/// # Example
47
///
48
/// Register a rule set with no dependencies:
49
///
50
/// ```rust
51
/// use conjure_cp_core::rule_engine::register_rule_set;
52
/// register_rule_set!("MyRuleSet");
53
/// ```
54
///
55
/// Register a rule set with dependencies:
56
///
57
/// ```rust
58
/// use conjure_cp_core::rule_engine::register_rule_set;
59
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
60
/// ```
61
///
62
/// Register a rule set for a specific solver family or families:
63
///
64
/// ```rust
65
/// use conjure_cp_core::rule_engine::register_rule_set;
66
/// use conjure_cp_core::settings::SolverFamily;
67
/// register_rule_set!("MyRuleSet", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion));
68
/// register_rule_set!("AnotherRuleSet", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion | SolverFamily::Sat));
69
/// ```
70
#[doc(inline)]
71
pub use conjure_cp_rule_macros::register_rule_set;
72
pub use resolve_rules::{RuleData, get_rules, get_rules_grouped, resolve_rule_sets};
73
pub use rewrite::rewrite_model;
74
pub use rewriter_common::RewriteError;
75
pub use rule::{
76
    ApplicationError, ApplicationResult, AtomKind, Rule, RuleEffect, RuleFailureInvalidation,
77
    RuleFn, RulePrefilter,
78
};
79
pub use rule_set::RuleSet;
80

            
81
mod expression_zipper;
82

            
83
#[doc(hidden)]
84
pub use expression_zipper::ExpressionZipper;
85

            
86
use crate::{
87
    Model,
88
    settings::{Rewriter, SolverFamily},
89
};
90

            
91
mod encoding_selection;
92
mod resolve_rules;
93
mod rewrite;
94
mod rewriter_common;
95
mod rule;
96
mod rule_set;
97

            
98
inventory::collect!(&'static Rule<'static>);
99

            
100
inventory::collect!(&'static RuleSet<'static>);
101

            
102
pub mod _dependencies {
103
    pub use inventory;
104
}
105

            
106
/// Returns a copied `Vec` of all rules registered with the `register_rule` macro.
107
///
108
/// Rules are not guaranteed to be in any particular order.
109
///
110
/// # Example
111
/// ```rust
112
/// # use conjure_cp_core::rule_engine::{ApplicationResult, RuleEffect, get_all_rules};
113
/// # use conjure_cp_core::ast::Expression;
114
/// # use conjure_cp_core::ast::SymbolTable;
115
/// # use conjure_cp_core::rule_engine::register_rule;
116
///
117
/// #[register_rule]
118
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
119
///   Ok(RuleEffect::pure(expr.clone()))
120
/// }
121
///
122
/// fn main() {
123
///   println!("Rules: {:?}", get_all_rules());
124
/// }
125
/// ```
126
///
127
/// This will print (if no other rules are registered):
128
/// ```text
129
///   Rules: [Rule { name: "identity", application: MEM }]
130
/// ```
131
/// Where `MEM` is the memory address of the `identity` function.
132
221972
pub fn get_all_rules() -> Vec<&'static Rule<'static>> {
133
221972
    inventory::iter::<&'static Rule<'static>>
134
221972
        .into_iter()
135
221972
        .copied()
136
221972
        .collect()
137
221972
}
138

            
139
/// Get a rule by name.
140
/// Returns the rule with the given name or None if it doesn't exist.
141
///
142
/// # Example
143
/// ```rust
144
/// use conjure_cp_core::rule_engine::register_rule;
145
/// use conjure_cp_core::rule_engine::{Rule, ApplicationResult, RuleEffect, get_rule_by_name};
146
/// use conjure_cp_core::ast::Expression;
147
/// use conjure_cp_core::ast::SymbolTable;
148
///
149
/// #[register_rule]
150
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
151
///  Ok(RuleEffect::pure(expr.clone()))
152
/// }
153
///
154
/// fn main() {
155
/// println!("Rule: {:?}", get_rule_by_name("identity"));
156
/// }
157
/// ```
158
///
159
/// This will print:
160
/// ```text
161
/// Rule: Some(Rule { name: "identity", application: MEM })
162
/// ```
163
2204
pub fn get_rule_by_name(name: &str) -> Option<&'static Rule<'static>> {
164
2204
    get_all_rules()
165
2204
        .iter()
166
351596
        .find(|rule| rule.name == name)
167
        .copied()
168
2204
}
169

            
170
/// Get all rule sets
171
/// Returns a `Vec` of static references to all rule sets registered with the `register_rule_set` macro.
172
/// Rule sets are not guaranteed to be in any particular order.
173
///
174
/// # Example
175
/// ```rust
176
/// use conjure_cp_core::rule_engine::register_rule_set;
177
/// use conjure_cp_core::rule_engine::get_all_rule_sets;
178
///
179
/// register_rule_set!("MyRuleSet", ("AnotherRuleSet"));
180
/// register_rule_set!("AnotherRuleSet", ());
181
///
182
/// println!("Rule sets: {:?}", get_all_rule_sets());
183
/// ```
184
///
185
/// This will print (if no other rule sets are registered):
186
/// ```text
187
/// Rule sets: [
188
///   RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["AnotherRuleSet"] },
189
///   RuleSet { name: "AnotherRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: [] }
190
/// ]
191
/// ```
192
///
193
3868333
pub fn get_all_rule_sets() -> Vec<&'static RuleSet<'static>> {
194
3868333
    inventory::iter::<&'static RuleSet<'static>>
195
3868333
        .into_iter()
196
3868333
        .copied()
197
3868333
        .collect()
198
3868333
}
199

            
200
/// Rewrites a model using the supplied rewriter configuration.
201
139474
pub fn rewrite_model_with_configured_rewriter<'a>(
202
139474
    model: Model,
203
139474
    rule_sets: &Vec<&'a RuleSet<'a>>,
204
139474
    configured_rewriter: Rewriter,
205
139474
) -> Result<Model, RewriteError> {
206
139474
    match configured_rewriter {
207
139474
        Rewriter::Rewrite(config) => rewrite_model(&model, rule_sets, config),
208
139474
    }
209
139474
}
210

            
211
/// Get a rule set by name.
212
/// Returns the rule set with the given name or None if it doesn't exist.
213
///
214
/// # Example
215
/// ```rust
216
/// use conjure_cp_core::rule_engine::register_rule_set;
217
/// use conjure_cp_core::rule_engine::get_rule_set_by_name;
218
///
219
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
220
///
221
/// println!("Rule set: {:?}", get_rule_set_by_name("MyRuleSet"));
222
/// ```
223
///
224
/// This will print:
225
/// ```text
226
/// Rule set: Some(RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["DependencyRuleSet", "AnotherRuleSet"] })
227
/// ```
228
2647633
pub fn get_rule_set_by_name(name: &str) -> Option<&'static RuleSet<'static>> {
229
2647633
    get_all_rule_sets()
230
2647633
        .iter()
231
9973656
        .find(|rule_set| rule_set.name == name)
232
        .copied()
233
2647633
}
234

            
235
/// Get all rule sets for a given solver family.
236
/// Returns a `Vec` of static references to all rule sets that are applicable to the given solver family.
237
/// Rule sets are not guaranteed to be in any particular order.
238
///
239
/// # Example
240
///
241
/// ```rust
242
/// use conjure_cp_core::settings::SolverFamily;
243
/// use conjure_cp_core::rule_engine::{get_rule_sets_for_solver_family, register_rule_set};
244
///
245
/// register_rule_set!("CNF", (), |f: &SolverFamily| matches!(f, SolverFamily::Sat));
246
/// register_rule_set!("MinionOnly", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion));
247
///
248
/// let rule_sets = get_rule_sets_for_solver_family(SolverFamily::Sat);
249
/// assert!(rule_sets.iter().any(|rule_set| rule_set.name == "CNF"));
250
/// assert!(!rule_sets.iter().any(|rule_set| rule_set.name == "MinionOnly"));
251
/// ```
252
1220671
pub fn get_rule_sets_for_solver_family(
253
1220671
    solver_family: SolverFamily,
254
1220671
) -> Vec<&'static RuleSet<'static>> {
255
1220671
    get_all_rule_sets()
256
1220671
        .iter()
257
15868594
        .filter(|rule_set| rule_set.applies_to_family(&solver_family))
258
        .copied()
259
        .collect()
260
1220671
}