conjure_core/rule_engine/mod.rs
1pub use linkme::distributed_slice;
2
3/// This procedural macro registers a decorated function with `conjure_rules`' global registry, and
4/// adds the rule to one or more `RuleSet`'s.
5///
6/// It may be used in any downstream crate.
7/// For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate.
8///
9/// **IMPORTANT**: Since the resulting rule may not be explicitly referenced, it may be removed by the compiler's dead code elimination.
10/// To prevent this, you must ensure that either:
11/// 1. codegen-units is set to 1, i.e. in Cargo.toml:
12/// ```toml
13/// [profile.release]
14/// codegen-units = 1
15/// ```
16/// 2. The function is included somewhere else in the code
17///
18/// <hr>
19///
20/// Functions must have the signature `fn(&Expr) -> ApplicationResult`.
21/// The created rule will have the same name as the function.
22///
23/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`.
24/// Please ensure that other variable names in the same scope do not conflict with these.
25///
26/// This macro must decorate a function with the given signature.
27/// As arguments, it excepts a tuple of 2-tuples in the format:
28/// `((<RuleSet name>, <Priority in RuleSet>), ...)`
29///
30/// <hr>
31///
32/// For example:
33/// ```rust
34/// use conjure_core::ast::Expression;
35/// use conjure_core::ast::SymbolTable;
36/// use conjure_core::rule_engine::{ApplicationError, ApplicationResult, Reduction};
37/// use conjure_core::rule_engine::register_rule;
38///
39/// #[register_rule(("RuleSetName", 10))]
40/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
41/// Ok(Reduction::pure(expr.clone()))
42/// }
43/// ```
44pub use conjure_rule_macros::register_rule;
45
46/// This procedural macro registers a rule set with the global registry.
47/// It may be used in any downstream crate.
48///
49/// For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate.
50///
51/// This macro uses the following syntax:
52///
53/// ```text
54/// register_rule_set!(<RuleSet name>, (<DependencyRuleSet1>, <DependencyRuleSet2>, ...), <SolverFamily>);
55/// ```
56///
57/// # Example
58///
59/// Register a rule set with no dependencies:
60///
61/// ```rust
62/// use conjure_core::rule_engine::register_rule_set;
63/// register_rule_set!("MyRuleSet");
64/// ```
65///
66/// Register a rule set with dependencies:
67///
68/// ```rust
69/// use conjure_core::rule_engine::register_rule_set;
70/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
71/// ```
72///
73/// Register a rule set for a specific solver family or families:
74///
75/// ```rust
76/// use conjure_core::rule_engine::register_rule_set;
77/// use conjure_core::solver::SolverFamily;
78/// register_rule_set!("MyRuleSet", (), SolverFamily::Minion);
79/// register_rule_set!("AnotherRuleSet", (), (SolverFamily::Minion, SolverFamily::Sat));
80/// ```
81#[doc(inline)]
82pub use conjure_rule_macros::register_rule_set;
83pub use resolve_rules::{get_rules, get_rules_grouped, resolve_rule_sets, RuleData};
84pub use rewrite_naive::rewrite_naive;
85pub use rewriter_common::RewriteError;
86pub use rule::{ApplicationError, ApplicationResult, Reduction, Rule, RuleFn};
87pub use rule_set::RuleSet;
88
89mod submodel_zipper;
90
91#[doc(hidden)]
92pub use submodel_zipper::SubmodelZipper;
93
94use crate::solver::SolverFamily;
95
96mod resolve_rules;
97mod rewrite_naive;
98mod rewriter_common;
99mod rule;
100mod rule_set;
101
102#[doc(hidden)]
103#[distributed_slice]
104pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>];
105
106#[doc(hidden)]
107#[distributed_slice]
108pub static RULE_SETS_DISTRIBUTED_SLICE: [RuleSet<'static>];
109
110pub mod _dependencies {
111 pub use linkme;
112 pub use linkme::distributed_slice;
113}
114
115/// Returns a copied `Vec` of all rules registered with the `register_rule` macro.
116///
117/// Rules are not guaranteed to be in any particular order.
118///
119/// # Example
120/// ```rust
121/// # use conjure_core::rule_engine::{ApplicationResult, Reduction, get_all_rules};
122/// # use conjure_core::ast::Expression;
123/// # use conjure_core::ast::SymbolTable;
124/// # use conjure_core::rule_engine::register_rule;
125///
126/// #[register_rule]
127/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
128/// Ok(Reduction::pure(expr.clone()))
129/// }
130///
131/// fn main() {
132/// println!("Rules: {:?}", get_all_rules());
133/// }
134/// ```
135///
136/// This will print (if no other rules are registered):
137/// ```text
138/// Rules: [Rule { name: "identity", application: MEM }]
139/// ```
140/// Where `MEM` is the memory address of the `identity` function.
141pub fn get_all_rules() -> Vec<&'static Rule<'static>> {
142 RULES_DISTRIBUTED_SLICE.iter().collect()
143}
144
145/// Get a rule by name.
146/// Returns the rule with the given name or None if it doesn't exist.
147///
148/// # Example
149/// ```rust
150/// use conjure_core::rule_engine::register_rule;
151/// use conjure_core::rule_engine::{Rule, ApplicationResult, Reduction, get_rule_by_name};
152/// use conjure_core::ast::Expression;
153/// use conjure_core::ast::SymbolTable;
154///
155/// #[register_rule]
156/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
157/// Ok(Reduction::pure(expr.clone()))
158/// }
159///
160/// fn main() {
161/// println!("Rule: {:?}", get_rule_by_name("identity"));
162/// }
163/// ```
164///
165/// This will print:
166/// ```text
167/// Rule: Some(Rule { name: "identity", application: MEM })
168/// ```
169pub fn get_rule_by_name(name: &str) -> Option<&'static Rule<'static>> {
170 get_all_rules()
171 .iter()
172 .find(|rule| rule.name == name)
173 .cloned()
174}
175
176/// Get all rule sets
177/// Returns a `Vec` of static references to all rule sets registered with the `register_rule_set` macro.
178/// Rule sets are not guaranteed to be in any particular order.
179///
180/// # Example
181/// ```rust
182/// use conjure_core::rule_engine::register_rule_set;
183/// use conjure_core::rule_engine::get_all_rule_sets;
184///
185/// register_rule_set!("MyRuleSet", ("AnotherRuleSet"));
186/// register_rule_set!("AnotherRuleSet", ());
187///
188/// println!("Rule sets: {:?}", get_all_rule_sets());
189/// ```
190///
191/// This will print (if no other rule sets are registered):
192/// ```text
193/// Rule sets: [
194/// RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["AnotherRuleSet"] },
195/// RuleSet { name: "AnotherRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: [] }
196/// ]
197/// ```
198///
199pub fn get_all_rule_sets() -> Vec<&'static RuleSet<'static>> {
200 RULE_SETS_DISTRIBUTED_SLICE.iter().collect()
201}
202
203/// Get a rule set by name.
204/// Returns the rule set with the given name or None if it doesn't exist.
205///
206/// # Example
207/// ```rust
208/// use conjure_core::rule_engine::register_rule_set;
209/// use conjure_core::rule_engine::get_rule_set_by_name;
210///
211/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
212///
213/// println!("Rule set: {:?}", get_rule_set_by_name("MyRuleSet"));
214/// ```
215///
216/// This will print:
217/// ```text
218/// Rule set: Some(RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["DependencyRuleSet", "AnotherRuleSet"] })
219/// ```
220pub fn get_rule_set_by_name(name: &str) -> Option<&'static RuleSet<'static>> {
221 get_all_rule_sets()
222 .iter()
223 .find(|rule_set| rule_set.name == name)
224 .cloned()
225}
226
227/// Get all rule sets for a given solver family.
228/// Returns a `Vec` of static references to all rule sets that are applicable to the given solver family.
229///
230/// # Example
231///
232/// ```rust
233/// use conjure_core::solver::SolverFamily;
234/// use conjure_core::rule_engine::{get_rule_sets_for_solver_family, register_rule_set};
235///
236/// register_rule_set!("CNF", (), SolverFamily::Sat);
237///
238/// let rule_sets = get_rule_sets_for_solver_family(SolverFamily::Sat);
239/// assert_eq!(rule_sets.len(), 1);
240/// assert_eq!(rule_sets[0].name, "CNF");
241/// ```
242pub fn get_rule_sets_for_solver_family(
243 solver_family: SolverFamily,
244) -> Vec<&'static RuleSet<'static>> {
245 get_all_rule_sets()
246 .iter()
247 .filter(|rule_set| {
248 rule_set
249 .solver_families
250 .iter()
251 .any(|family| family.eq(&solver_family))
252 })
253 .cloned()
254 .collect()
255}