conjure_cp_core/rule_engine/
mod.rs

1pub use linkme::distributed_slice;
2
3mod rewrite_morph;
4pub 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/// ```
47pub 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::solver::SolverFamily;
81/// register_rule_set!("MyRuleSet", (), SolverFamily::Minion);
82/// register_rule_set!("AnotherRuleSet", (), (SolverFamily::Minion, SolverFamily::Sat));
83/// ```
84#[doc(inline)]
85pub use conjure_cp_rule_macros::register_rule_set;
86pub use resolve_rules::{RuleData, get_rules, get_rules_grouped, resolve_rule_sets};
87pub use rewrite_naive::rewrite_naive;
88pub use rewriter_common::RewriteError;
89pub use rule::{ApplicationError, ApplicationResult, Reduction, Rule, RuleFn};
90pub use rule_set::RuleSet;
91
92mod submodel_zipper;
93
94#[doc(hidden)]
95pub use submodel_zipper::SubmodelZipper;
96
97use crate::solver::SolverFamily;
98
99mod resolve_rules;
100mod rewrite_naive;
101mod rewriter_common;
102mod rule;
103mod rule_set;
104
105#[doc(hidden)]
106#[distributed_slice]
107pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>];
108
109#[doc(hidden)]
110#[distributed_slice]
111pub static RULE_SETS_DISTRIBUTED_SLICE: [RuleSet<'static>];
112
113pub mod _dependencies {
114    pub use linkme;
115    pub use linkme::distributed_slice;
116}
117
118/// Returns a copied `Vec` of all rules registered with the `register_rule` macro.
119///
120/// Rules are not guaranteed to be in any particular order.
121///
122/// # Example
123/// ```rust
124/// # use conjure_cp_core::rule_engine::{ApplicationResult, Reduction, get_all_rules};
125/// # use conjure_cp_core::ast::Expression;
126/// # use conjure_cp_core::ast::SymbolTable;
127/// # use conjure_cp_core::rule_engine::register_rule;
128///
129/// #[register_rule]
130/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
131///   Ok(Reduction::pure(expr.clone()))
132/// }
133///
134/// fn main() {
135///   println!("Rules: {:?}", get_all_rules());
136/// }
137/// ```
138///
139/// This will print (if no other rules are registered):
140/// ```text
141///   Rules: [Rule { name: "identity", application: MEM }]
142/// ```
143/// Where `MEM` is the memory address of the `identity` function.
144pub fn get_all_rules() -> Vec<&'static Rule<'static>> {
145    RULES_DISTRIBUTED_SLICE.iter().collect()
146}
147
148/// Get a rule by name.
149/// Returns the rule with the given name or None if it doesn't exist.
150///
151/// # Example
152/// ```rust
153/// use conjure_cp_core::rule_engine::register_rule;
154/// use conjure_cp_core::rule_engine::{Rule, ApplicationResult, Reduction, get_rule_by_name};
155/// use conjure_cp_core::ast::Expression;
156/// use conjure_cp_core::ast::SymbolTable;
157///
158/// #[register_rule]
159/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
160///  Ok(Reduction::pure(expr.clone()))
161/// }
162///
163/// fn main() {
164/// println!("Rule: {:?}", get_rule_by_name("identity"));
165/// }
166/// ```
167///
168/// This will print:
169/// ```text
170/// Rule: Some(Rule { name: "identity", application: MEM })
171/// ```
172pub fn get_rule_by_name(name: &str) -> Option<&'static Rule<'static>> {
173    get_all_rules()
174        .iter()
175        .find(|rule| rule.name == name)
176        .copied()
177}
178
179/// Get all rule sets
180/// Returns a `Vec` of static references to all rule sets registered with the `register_rule_set` macro.
181/// Rule sets are not guaranteed to be in any particular order.
182///
183/// # Example
184/// ```rust
185/// use conjure_cp_core::rule_engine::register_rule_set;
186/// use conjure_cp_core::rule_engine::get_all_rule_sets;
187///
188/// register_rule_set!("MyRuleSet", ("AnotherRuleSet"));
189/// register_rule_set!("AnotherRuleSet", ());
190///
191/// println!("Rule sets: {:?}", get_all_rule_sets());
192/// ```
193///
194/// This will print (if no other rule sets are registered):
195/// ```text
196/// Rule sets: [
197///   RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["AnotherRuleSet"] },
198///   RuleSet { name: "AnotherRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: [] }
199/// ]
200/// ```
201///
202pub fn get_all_rule_sets() -> Vec<&'static RuleSet<'static>> {
203    RULE_SETS_DISTRIBUTED_SLICE.iter().collect()
204}
205
206/// Get a rule set by name.
207/// Returns the rule set with the given name or None if it doesn't exist.
208///
209/// # Example
210/// ```rust
211/// use conjure_cp_core::rule_engine::register_rule_set;
212/// use conjure_cp_core::rule_engine::get_rule_set_by_name;
213///
214/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
215///
216/// println!("Rule set: {:?}", get_rule_set_by_name("MyRuleSet"));
217/// ```
218///
219/// This will print:
220/// ```text
221/// Rule set: Some(RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["DependencyRuleSet", "AnotherRuleSet"] })
222/// ```
223pub fn get_rule_set_by_name(name: &str) -> Option<&'static RuleSet<'static>> {
224    get_all_rule_sets()
225        .iter()
226        .find(|rule_set| rule_set.name == name)
227        .copied()
228}
229
230/// Get all rule sets for a given solver family.
231/// Returns a `Vec` of static references to all rule sets that are applicable to the given solver family.
232///
233/// # Example
234///
235/// ```rust
236/// use conjure_cp_core::solver::SolverFamily;
237/// use conjure_cp_core::rule_engine::{get_rule_sets_for_solver_family, register_rule_set};
238///
239/// register_rule_set!("CNF", (), SolverFamily::Sat);
240///
241/// let rule_sets = get_rule_sets_for_solver_family(SolverFamily::Sat);
242/// assert_eq!(rule_sets.len(), 2);
243/// assert_eq!(rule_sets[0].name, "CNF");
244/// ```
245pub fn get_rule_sets_for_solver_family(
246    solver_family: SolverFamily,
247) -> Vec<&'static RuleSet<'static>> {
248    get_all_rule_sets()
249        .iter()
250        .filter(|rule_set| {
251            rule_set
252                .solver_families
253                .iter()
254                .any(|family| family.eq(&solver_family))
255        })
256        .copied()
257        .collect()
258}