1
pub use linkme::distributed_slice;
2

            
3
mod rewrite_morph;
4
pub use rewrite_morph::rewrite_morph;
5

            
6
/// This procedural macro registers a decorated function with `conjure_cp_rules`' global registry, and
7
/// adds the rule to one or more `RuleSet`'s.
8
///
9
/// It may be used in any downstream crate.
10
/// For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate.
11
///
12
/// **IMPORTANT**: Since the resulting rule may not be explicitly referenced, it may be removed by the compiler's dead code elimination.
13
/// To prevent this, you must ensure that either:
14
/// 1. codegen-units is set to 1, i.e. in Cargo.toml:
15
/// ```toml
16
/// [profile.release]
17
/// codegen-units = 1
18
/// ```
19
/// 2. The function is included somewhere else in the code
20
///
21
/// <hr>
22
///
23
/// Functions must have the signature `fn(&Expr) -> ApplicationResult`.
24
/// The created rule will have the same name as the function.
25
///
26
/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`.
27
/// Please ensure that other variable names in the same scope do not conflict with these.
28
///
29
/// This macro must decorate a function with the given signature.
30
/// As arguments, it excepts a tuple of 2-tuples in the format:
31
/// `((<RuleSet name>, <Priority in RuleSet>), ...)`
32
///
33
/// <hr>
34
///
35
/// For example:
36
/// ```rust
37
/// use conjure_cp_core::ast::Expression;
38
/// use conjure_cp_core::ast::SymbolTable;
39
/// use conjure_cp_core::rule_engine::{ApplicationError, ApplicationResult, Reduction};
40
/// use conjure_cp_core::rule_engine::register_rule;
41
///
42
/// #[register_rule(("RuleSetName", 10))]
43
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
44
///   Ok(Reduction::pure(expr.clone()))
45
/// }
46
/// ```
47
pub use conjure_cp_rule_macros::register_rule;
48

            
49
/// This procedural macro registers a rule set with the global registry.
50
/// It may be used in any downstream crate.
51
///
52
/// For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate.
53
///
54
/// This macro uses the following syntax:
55
///
56
/// ```text
57
/// register_rule_set!(<RuleSet name>, (<DependencyRuleSet1>, <DependencyRuleSet2>, ...), <SolverFamily>);
58
/// ```
59
///
60
/// # Example
61
///
62
/// Register a rule set with no dependencies:
63
///
64
/// ```rust
65
/// use conjure_cp_core::rule_engine::register_rule_set;
66
/// register_rule_set!("MyRuleSet");
67
/// ```
68
///
69
/// Register a rule set with dependencies:
70
///
71
/// ```rust
72
/// use conjure_cp_core::rule_engine::register_rule_set;
73
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
74
/// ```
75
///
76
/// Register a rule set for a specific solver family or families:
77
///
78
/// ```rust
79
/// use conjure_cp_core::rule_engine::register_rule_set;
80
/// use conjure_cp_core::settings::SolverFamily;
81
/// register_rule_set!("MyRuleSet", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion));
82
/// register_rule_set!("AnotherRuleSet", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion | SolverFamily::Sat(_)));
83
/// ```
84
#[doc(inline)]
85
pub use conjure_cp_rule_macros::register_rule_set;
86
pub use resolve_rules::{RuleData, get_rules, get_rules_grouped, resolve_rule_sets};
87
pub use rewrite_naive::rewrite_naive;
88
pub use rewriter_common::RewriteError;
89
pub use rule::{ApplicationError, ApplicationResult, Reduction, Rule, RuleFn};
90
pub use rule_set::RuleSet;
91

            
92
mod submodel_zipper;
93

            
94
#[doc(hidden)]
95
pub use submodel_zipper::SubmodelZipper;
96

            
97
use crate::{
98
    Model,
99
    settings::{Rewriter, SolverFamily},
100
};
101

            
102
mod resolve_rules;
103
mod rewrite_naive;
104
mod rewriter_common;
105
mod rule;
106
mod rule_set;
107

            
108
#[doc(hidden)]
109
#[distributed_slice]
110
pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>];
111

            
112
#[doc(hidden)]
113
#[distributed_slice]
114
pub static RULE_SETS_DISTRIBUTED_SLICE: [RuleSet<'static>];
115

            
116
pub mod _dependencies {
117
    pub use linkme;
118
    pub use linkme::distributed_slice;
119
}
120

            
121
/// Returns a copied `Vec` of all rules registered with the `register_rule` macro.
122
///
123
/// Rules are not guaranteed to be in any particular order.
124
///
125
/// # Example
126
/// ```rust
127
/// # use conjure_cp_core::rule_engine::{ApplicationResult, Reduction, get_all_rules};
128
/// # use conjure_cp_core::ast::Expression;
129
/// # use conjure_cp_core::ast::SymbolTable;
130
/// # use conjure_cp_core::rule_engine::register_rule;
131
///
132
/// #[register_rule]
133
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
134
///   Ok(Reduction::pure(expr.clone()))
135
/// }
136
///
137
/// fn main() {
138
///   println!("Rules: {:?}", get_all_rules());
139
/// }
140
/// ```
141
///
142
/// This will print (if no other rules are registered):
143
/// ```text
144
///   Rules: [Rule { name: "identity", application: MEM }]
145
/// ```
146
/// Where `MEM` is the memory address of the `identity` function.
147
980
pub fn get_all_rules() -> Vec<&'static Rule<'static>> {
148
980
    RULES_DISTRIBUTED_SLICE.iter().collect()
149
980
}
150

            
151
/// Get a rule by name.
152
/// Returns the rule with the given name or None if it doesn't exist.
153
///
154
/// # Example
155
/// ```rust
156
/// use conjure_cp_core::rule_engine::register_rule;
157
/// use conjure_cp_core::rule_engine::{Rule, ApplicationResult, Reduction, get_rule_by_name};
158
/// use conjure_cp_core::ast::Expression;
159
/// use conjure_cp_core::ast::SymbolTable;
160
///
161
/// #[register_rule]
162
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
163
///  Ok(Reduction::pure(expr.clone()))
164
/// }
165
///
166
/// fn main() {
167
/// println!("Rule: {:?}", get_rule_by_name("identity"));
168
/// }
169
/// ```
170
///
171
/// This will print:
172
/// ```text
173
/// Rule: Some(Rule { name: "identity", application: MEM })
174
/// ```
175
34806
pub fn get_rule_by_name(name: &str) -> Option<&'static Rule<'static>> {
176
948
    get_all_rules()
177
948
        .iter()
178
22360
        .find(|rule| rule.name == name)
179
340
        .copied()
180
340
}
181

            
182
/// Get all rule sets
183
/// Returns a `Vec` of static references to all rule sets registered with the `register_rule_set` macro.
184
/// Rule sets are not guaranteed to be in any particular order.
185
///
186
/// # Example
187
/// ```rust
188
/// use conjure_cp_core::rule_engine::register_rule_set;
189
/// use conjure_cp_core::rule_engine::get_all_rule_sets;
190
///
191
/// register_rule_set!("MyRuleSet", ("AnotherRuleSet"));
192
/// register_rule_set!("AnotherRuleSet", ());
193
///
194
/// println!("Rule sets: {:?}", get_all_rule_sets());
195
/// ```
196
///
197
/// This will print (if no other rule sets are registered):
198
/// ```text
199
/// Rule sets: [
200
///   RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["AnotherRuleSet"] },
201
///   RuleSet { name: "AnotherRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: [] }
202
/// ]
203
/// ```
204
///
205
48280
pub fn get_all_rule_sets() -> Vec<&'static RuleSet<'static>> {
206
48280
    RULE_SETS_DISTRIBUTED_SLICE.iter().collect()
207
48280
}
208

            
209
/// Rewrites a model using the supplied rewriter configuration.
210
2665
pub fn rewrite_model_with_configured_rewriter<'a>(
211
2665
    model: Model,
212
2665
    rule_sets: &Vec<&'a RuleSet<'a>>,
213
2665
    configured_rewriter: Rewriter,
214
2665
) -> Result<Model, RewriteError> {
215
2665
    match configured_rewriter {
216
        Rewriter::Morph => Ok(rewrite_morph(model, rule_sets, false)),
217
2665
        Rewriter::Naive => rewrite_naive(&model, rule_sets, false),
218
    }
219
2665
}
220

            
221
/// Get a rule set by name.
222
/// Returns the rule set with the given name or None if it doesn't exist.
223
///
224
/// # Example
225
/// ```rust
226
/// use conjure_cp_core::rule_engine::register_rule_set;
227
/// use conjure_cp_core::rule_engine::get_rule_set_by_name;
228
///
229
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
230
///
231
/// println!("Rule set: {:?}", get_rule_set_by_name("MyRuleSet"));
232
/// ```
233
///
234
/// This will print:
235
/// ```text
236
/// Rule set: Some(RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["DependencyRuleSet", "AnotherRuleSet"] })
237
/// ```
238
36864
pub fn get_rule_set_by_name(name: &str) -> Option<&'static RuleSet<'static>> {
239
36864
    get_all_rule_sets()
240
36864
        .iter()
241
163524
        .find(|rule_set| rule_set.name == name)
242
36864
        .copied()
243
36864
}
244

            
245
/// Get all rule sets for a given solver family.
246
/// Returns a `Vec` of static references to all rule sets that are applicable to the given solver family.
247
///
248
/// # Example
249
///
250
/// ```rust
251
/// use conjure_cp_core::settings::SolverFamily;
252
/// use conjure_cp_core::rule_engine::{get_rule_sets_for_solver_family, register_rule_set};
253
///
254
/// register_rule_set!("CNF", (), |f: &SolverFamily| matches!(f, SolverFamily::Sat(_)));
255
///
256
/// let rule_sets = get_rule_sets_for_solver_family(SolverFamily::Sat(Default::default()));
257
/// assert_eq!(rule_sets.len(), 2);
258
/// assert_eq!(rule_sets[0].name, "CNF");
259
/// ```
260
11396
pub fn get_rule_sets_for_solver_family(
261
11396
    solver_family: SolverFamily,
262
11396
) -> Vec<&'static RuleSet<'static>> {
263
11396
    get_all_rule_sets()
264
11396
        .iter()
265
136672
        .filter(|rule_set| rule_set.applies_to_family(&solver_family))
266
11396
        .copied()
267
11396
        .collect()
268
11396
}