1
pub 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
1
/// 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
/// ```
44
1
pub 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
1
/// use conjure_core::rule_engine::register_rule_set;
61
///
62
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
63
/// ```
64
1
#[doc(inline)]
65
pub use conjure_macros::register_rule_set;
66
pub use resolve_rules::{get_rules, get_rules_grouped, resolve_rule_sets, RuleData};
67
pub use rewrite::rewrite_model;
68
pub use rewrite_naive::rewrite_naive;
69
pub use rewriter_common::RewriteError;
70
pub use rule::{ApplicationError, ApplicationResult, Reduction, Rule};
71
pub use rule_set::RuleSet;
72
mod submodel_zipper;
73

            
74
use crate::solver::SolverFamily;
75

            
76
mod resolve_rules;
77
mod rewrite;
78
mod rewrite_naive;
79
mod rewriter_common;
80
mod rule;
81
mod rule_set;
82

            
83
#[doc(hidden)]
84
#[distributed_slice]
85
pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>];
86

            
87
#[doc(hidden)]
88
#[distributed_slice]
89
pub static RULE_SETS_DISTRIBUTED_SLICE: [RuleSet<'static>];
90

            
91
pub 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
1
///   println!("Rules: {:?}", get_all_rules());
114
1
/// }
115
1
/// ```
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.
122
990
pub fn get_all_rules() -> Vec<&'static Rule<'static>> {
123
990
    RULES_DISTRIBUTED_SLICE.iter().collect()
124
990
}
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
1
/// println!("Rule: {:?}", get_rule_by_name("identity"));
143
1
/// }
144
1
/// ```
145
///
146
/// This will print:
147
/// ```text
148
/// Rule: Some(Rule { name: "identity", application: MEM })
149
/// ```
150
594
pub fn get_rule_by_name(name: &str) -> Option<&'static Rule<'static>> {
151
594
    get_all_rules()
152
594
        .iter()
153
11898
        .find(|rule| rule.name == name)
154
594
        .cloned()
155
594
}
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
1
/// 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
1
/// ```
171
1
///
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
///
180
7452
pub fn get_all_rule_sets() -> Vec<&'static RuleSet<'static>> {
181
7452
    RULE_SETS_DISTRIBUTED_SLICE.iter().collect()
182
7452
}
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
1
/// 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
1
/// ```
196
1
///
197
/// This will print:
198
/// ```text
199
/// Rule set: Some(RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["DependencyRuleSet", "AnotherRuleSet"] })
200
/// ```
201
5544
pub fn get_rule_set_by_name(name: &str) -> Option<&'static RuleSet<'static>> {
202
5544
    get_all_rule_sets()
203
5544
        .iter()
204
20250
        .find(|rule_set| rule_set.name == name)
205
5544
        .cloned()
206
5544
}
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
1
/// 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
1
/// assert_eq!(rule_sets.len(), 1);
219
1
/// assert_eq!(rule_sets[0].name, "CNF");
220
1
/// ```
221
1786
pub fn get_rule_sets_for_solver_family(
222
1890
    solver_family: SolverFamily,
223
1890
) -> Vec<&'static RuleSet<'static>> {
224
1890
    get_all_rule_sets()
225
1890
        .iter()
226
9450
        .filter(|rule_set| {
227
9450
            rule_set
228
9450
                .solver_families
229
9450
                .iter()
230
9450
                .any(|family| family.eq(&solver_family))
231
9450
        })
232
1890
        .cloned()
233
1890
        .collect()
234
1890
}