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