1
pub use linkme::distributed_slice;
2

            
3
mod rewrite_morph;
4
pub use crate::settings::MorphConfig;
5
pub use rewrite_morph::rewrite_morph;
6

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

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

            
94
mod submodel_zipper;
95

            
96
#[doc(hidden)]
97
pub use submodel_zipper::SubmodelZipper;
98

            
99
use crate::{
100
    Model,
101
    settings::{Rewriter, SolverFamily},
102
};
103

            
104
mod resolve_rules;
105
mod rewrite_naive;
106
mod rewriter_common;
107
mod rule;
108
mod rule_set;
109

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

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

            
118
pub mod _dependencies {
119
    pub use linkme;
120
    pub use linkme::distributed_slice;
121
}
122

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

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

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

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

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

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