Skip to main content

oxirs_rule/
lib.rs

1//! # OxiRS Rule Engine
2//!
3//! [![Version](https://img.shields.io/badge/version-0.3.3-blue)](https://github.com/cool-japan/oxirs/releases)
4//! [![docs.rs](https://docs.rs/oxirs-rule/badge.svg)](https://docs.rs/oxirs-rule)
5//!
6//! **Status**: Production Release (v0.3.3)
7//! **Stability**: Public APIs are stable. Production-ready with comprehensive testing.
8//!
9//! Forward/backward rule engine for RDFS, OWL, and SWRL reasoning with RETE optimization.
10//! Provides Jena-compatible rule-based inference for knowledge graphs.
11//!
12//! ## Features
13//!
14//! - **Forward Chaining** - Data-driven rule inference
15//! - **Backward Chaining** - Goal-driven query answering
16//! - **RETE Algorithm** - Efficient pattern matching
17//! - **RDFS/OWL Support** - Standard ontology reasoning
18//! - **SWRL Integration** - Semantic Web Rule Language
19//! - **Rule Composition** - Complex multi-step reasoning
20//!
21//! ## Quick Start
22//!
23//! ```rust
24//! use oxirs_rule::{RuleEngine, Rule, RuleAtom, Term};
25//!
26//! let mut engine = RuleEngine::new();
27//!
28//! // Define rule: parent(X,Y) → ancestor(X,Y)
29//! engine.add_rule(Rule {
30//!     name: "ancestor".to_string(),
31//!     body: vec![RuleAtom::Triple {
32//!         subject: Term::Variable("X".to_string()),
33//!         predicate: Term::Constant("parent".to_string()),
34//!         object: Term::Variable("Y".to_string()),
35//!     }],
36//!     head: vec![RuleAtom::Triple {
37//!         subject: Term::Variable("X".to_string()),
38//!         predicate: Term::Constant("ancestor".to_string()),
39//!         object: Term::Variable("Y".to_string()),
40//!     }],
41//! });
42//!
43//! // Add facts and infer
44//! let facts = vec![RuleAtom::Triple {
45//!     subject: Term::Constant("john".to_string()),
46//!     predicate: Term::Constant("parent".to_string()),
47//!     object: Term::Constant("mary".to_string()),
48//! }];
49//!
50//! let results = engine.forward_chain(&facts)?;
51//! # Ok::<(), anyhow::Error>(())
52//! ```
53//!
54//! ## See Also
55//!
56//! - [`oxirs-core`](https://docs.rs/oxirs-core) - RDF data model
57//! - [`oxirs-arq`](https://docs.rs/oxirs-arq) - SPARQL query engine
58
59use anyhow::Result;
60
61pub mod active_learning;
62pub mod adaptive_strategies;
63pub mod advanced_integration_example;
64pub mod asp;
65pub mod backward;
66pub mod benchmark_suite;
67pub mod cache;
68pub mod chr;
69pub mod composition;
70pub mod comprehensive_tutorial;
71pub mod conflict;
72pub mod coverage;
73pub mod datalog_engine;
74pub mod debug;
75pub mod dempster_shafer;
76pub mod description_logic;
77pub mod distributed;
78pub mod entailment;
79pub mod explainable_generation;
80pub mod explanation;
81pub mod forward;
82pub mod fuzzy;
83pub mod getting_started;
84pub mod gpu_matching;
85pub mod hermit_reasoner;
86pub mod incremental;
87pub mod integration;
88pub mod integration_benchmarks;
89pub mod language;
90pub mod lazy_materialization;
91pub mod lockfree;
92pub mod materialization;
93pub mod migration;
94pub mod negation;
95pub mod optimization;
96pub mod owl;
97pub mod owl2;
98pub mod owl_dl;
99pub mod owl_el;
100pub mod owl_el_axioms;
101pub mod owl_el_reasoner;
102pub mod owl_el_tests;
103pub mod owl_profiles;
104pub mod owl_ql;
105pub mod owl_rl;
106pub mod owl_rl_reasoner;
107pub mod owl_rl_rules;
108#[cfg(test)]
109pub mod owl_rl_tests;
110pub use owl_ql::{Owl2QLTBox, QueryAtom, QueryRewriter, RewrittenQuery};
111pub mod datalog;
112pub mod n3logic;
113pub mod parallel;
114pub mod pellet_classifier;
115pub mod performance;
116pub mod possibilistic;
117pub mod probabilistic;
118pub mod probabilistic_rdf;
119pub mod problog;
120pub mod problog_inference;
121pub mod problog_solver;
122mod problog_tests;
123pub mod problog_types;
124pub mod production_utils;
125pub mod profiler;
126pub mod quantum_optimizer;
127pub mod rdf_integration;
128pub mod rdf_processing_simple;
129pub mod rdfs;
130pub mod rete;
131pub mod rete_enhanced;
132pub mod rif;
133pub mod rule_compression;
134pub mod rule_index;
135pub mod rule_index_store;
136#[cfg(test)]
137pub mod rule_index_tests;
138pub mod rule_index_types;
139pub mod rule_learning;
140pub mod rule_refinement;
141pub mod shacl_integration;
142pub mod simd_ops;
143pub mod skos;
144pub mod skos_inference;
145pub mod skos_mappings;
146pub mod skos_reasoner;
147#[cfg(test)]
148mod skos_tests;
149pub mod skos_types;
150pub mod skos_validation;
151pub mod sparql_integration;
152pub mod statistical_relational;
153pub mod swrl;
154pub mod tabling;
155pub mod temporal;
156pub mod test_generator;
157pub mod transaction;
158pub mod transfer_learning;
159pub mod uncertainty_propagation;
160
161/// Rule representation
162#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
163pub struct Rule {
164    pub name: String,
165    pub body: Vec<RuleAtom>,
166    pub head: Vec<RuleAtom>,
167}
168
169/// Rule atom (triple pattern or builtin)
170#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
171pub enum RuleAtom {
172    Triple {
173        subject: Term,
174        predicate: Term,
175        object: Term,
176    },
177    Builtin {
178        name: String,
179        args: Vec<Term>,
180    },
181    NotEqual {
182        left: Term,
183        right: Term,
184    },
185    GreaterThan {
186        left: Term,
187        right: Term,
188    },
189    LessThan {
190        left: Term,
191        right: Term,
192    },
193}
194
195/// Rule term
196#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
197pub enum Term {
198    Variable(String),
199    Constant(String),
200    Literal(String),
201    Function { name: String, args: Vec<Term> },
202}
203
204/// Integrated rule engine combining all reasoning modes
205#[derive(Debug)]
206pub struct RuleEngine {
207    rules: Vec<Rule>,
208    forward_chainer: forward::ForwardChainer,
209    backward_chainer: backward::BackwardChainer,
210    rete_network: rete::ReteNetwork,
211    cache: Option<crate::cache::RuleCache>,
212}
213
214impl RuleEngine {
215    pub fn new() -> Self {
216        Self {
217            rules: Vec::new(),
218            forward_chainer: forward::ForwardChainer::new(),
219            backward_chainer: backward::BackwardChainer::new(),
220            rete_network: rete::ReteNetwork::new(),
221            cache: Some(crate::cache::RuleCache::new()),
222        }
223    }
224
225    /// Add a rule to the engine
226    pub fn add_rule(&mut self, rule: Rule) {
227        self.rules.push(rule.clone());
228        self.forward_chainer.add_rule(rule.clone());
229        self.backward_chainer.add_rule(rule.clone());
230        if let Err(e) = self.rete_network.add_rule(&rule) {
231            // The RETE network can reject a rule whose pattern it cannot compile
232            // (e.g. an unsupported atom shape). Surface this rather than silently
233            // dropping it: rete_forward_chain() would otherwise diverge from
234            // forward_chain()/backward_chain() for this rule with no signal to
235            // the caller.
236            tracing::warn!(
237                "RETE network rejected rule '{}': {}; rete_forward_chain results may \
238                 differ from forward_chain/backward_chain for this rule",
239                rule.name,
240                e
241            );
242        }
243    }
244
245    /// Add multiple rules
246    pub fn add_rules(&mut self, rules: Vec<Rule>) {
247        for rule in rules {
248            self.add_rule(rule);
249        }
250    }
251
252    /// Add facts to the knowledge base
253    pub fn add_facts(&mut self, facts: Vec<RuleAtom>) {
254        self.forward_chainer.add_facts(facts.clone());
255        self.backward_chainer.add_facts(facts);
256    }
257
258    /// Perform forward chaining inference
259    pub fn forward_chain(&mut self, facts: &[RuleAtom]) -> Result<Vec<RuleAtom>> {
260        self.forward_chainer.add_facts(facts.to_vec());
261        self.forward_chainer.infer()
262    }
263
264    /// Perform backward chaining to prove a goal
265    pub fn backward_chain(&mut self, goal: &RuleAtom) -> Result<bool> {
266        self.backward_chainer.prove(goal)
267    }
268
269    /// Perform RETE-based forward chaining
270    pub fn rete_forward_chain(&mut self, facts: Vec<RuleAtom>) -> Result<Vec<RuleAtom>> {
271        self.rete_network.forward_chain(facts)
272    }
273
274    /// Get all current facts
275    pub fn get_facts(&self) -> Vec<RuleAtom> {
276        self.forward_chainer.get_facts()
277    }
278
279    /// Clear all facts and caches
280    pub fn clear(&mut self) {
281        self.forward_chainer.clear_facts();
282        self.backward_chainer.clear_facts();
283        self.rete_network.clear();
284        self.clear_cache();
285    }
286
287    /// Set maximum proof depth for backward chaining
288    ///
289    /// This limits the recursion depth to prevent stack overflow.
290    /// Lower values (e.g., 20-30) are safer for large datasets.
291    /// Default is 100.
292    pub fn set_backward_chain_max_depth(&mut self, max_depth: usize) {
293        self.backward_chainer = backward::BackwardChainer::with_config(max_depth, false);
294        // Re-add existing rules to the new backward chainer
295        for rule in &self.rules {
296            self.backward_chainer.add_rule(rule.clone());
297        }
298    }
299
300    /// Add a single fact to the knowledge base
301    pub fn add_fact(&mut self, fact: RuleAtom) {
302        self.add_facts(vec![fact]);
303    }
304
305    /// Set cache for the rule engine
306    ///
307    /// Enables or disables caching by setting the cache instance.
308    /// Pass `Some(cache)` to enable caching with a specific cache configuration,
309    /// or `None` to disable caching.
310    pub fn set_cache(&mut self, cache: Option<crate::cache::RuleCache>) {
311        self.cache = cache;
312        tracing::debug!(
313            "Rule engine cache {}",
314            if self.cache.is_some() {
315                "enabled"
316            } else {
317                "disabled"
318            }
319        );
320    }
321
322    /// Get a reference to the cache
323    ///
324    /// Returns a reference to the cache if enabled.
325    /// The cache is wrapped in Option to allow disabling caching.
326    pub fn get_cache(&self) -> Option<&crate::cache::RuleCache> {
327        self.cache.as_ref()
328    }
329
330    /// Get mutable reference to the cache
331    ///
332    /// Returns a mutable reference to the cache if enabled.
333    /// Useful for clearing cache, updating statistics, etc.
334    pub fn get_cache_mut(&mut self) -> Option<&mut crate::cache::RuleCache> {
335        self.cache.as_mut()
336    }
337
338    /// Enable caching with default settings
339    ///
340    /// Creates a new cache with default configuration and enables it.
341    pub fn enable_cache(&mut self) {
342        self.cache = Some(crate::cache::RuleCache::new());
343        tracing::info!("Rule engine cache enabled with default settings");
344    }
345
346    /// Disable caching
347    ///
348    /// Removes the cache and disables caching functionality.
349    pub fn disable_cache(&mut self) {
350        self.cache = None;
351        tracing::info!("Rule engine cache disabled");
352    }
353
354    /// Check if caching is enabled
355    pub fn is_cache_enabled(&self) -> bool {
356        self.cache.is_some()
357    }
358
359    /// Clear the cache if enabled
360    ///
361    /// Clears all cached rule results, derivations, unifications, and patterns.
362    pub fn clear_cache(&mut self) {
363        if let Some(cache) = &self.cache {
364            cache.clear_all();
365            tracing::debug!("Rule engine cache cleared");
366        }
367    }
368
369    /// Get cache statistics if caching is enabled
370    ///
371    /// Returns combined statistics for all cache types (rule results, derivations, etc.)
372    pub fn get_cache_statistics(&self) -> Option<crate::cache::CachingStatistics> {
373        self.cache.as_ref().map(|cache| cache.get_statistics())
374    }
375
376    /// Warm up the cache with current rules and common facts
377    ///
378    /// Pre-populates the cache with patterns from the current rule set
379    /// and provided common facts to improve initial query performance.
380    pub fn warm_cache(&self, common_facts: &[RuleAtom]) {
381        if let Some(cache) = &self.cache {
382            cache.warm_cache(&self.rules, common_facts);
383            tracing::info!(
384                "Cache warmed up with {} rules and {} facts",
385                self.rules.len(),
386                common_facts.len()
387            );
388        }
389    }
390}
391
392impl Default for RuleEngine {
393    fn default() -> Self {
394        Self::new()
395    }
396}
397
398// RDFS entailment regime (v1.1.0 round 5)
399pub mod rdfs_entailment;
400
401// Semi-naive forward chaining rule engine (v1.1.0 round 6)
402pub mod forward_chainer;
403
404// N3/Notation3 rule syntax parser (v1.1.0 round 7)
405pub mod rule_parser;
406
407// Simplified Rete algorithm network for forward-chain rule matching (v1.1.0 round 8)
408pub mod rete_network;
409
410// Conflict detection and resolution for rule-based reasoning (v1.1.0 round 9)
411pub mod conflict_resolver;
412
413// Goal-directed backward-chaining reasoner (v1.1.0 round 10)
414pub mod backward_chainer;
415
416// Rule dependency graph for optimization (v1.1.0 round 11)
417pub mod rule_graph;
418
419// Rule compilation to bytecode-like IR (v1.1.0 round 12)
420pub mod rule_compiler;
421
422// Truth Maintenance System for belief revision (v1.1.0 round 13)
423pub mod truth_maintenance;
424
425// Rule execution tracing and debugging (v1.1.0 round 12)
426pub mod rule_tracer;
427
428// Rule serialization/deserialization — N3 and JSON formats (v1.1.0 round 13)
429pub mod rule_serializer;
430
431// Rule syntax and semantic validation (v1.1.0 round 14)
432pub mod rule_validator;
433
434// Forward-chaining rule execution engine (v1.1.0 round 15)
435pub mod rule_executor;
436
437// Rule execution statistics and profiling (v1.1.0 round 16)
438pub mod rule_statistics;
439
440// Jena Rule Language (.rules) parser and lowering
441pub mod jena_rl;
442pub use jena_rl::{parse_and_lower, parse_jrl, JrlParseError, JrlRuleSet, LoweringError};
443
444// OWL Manchester Syntax parser and emitter (v0.3.1 Track C24)
445pub mod manchester;
446pub use manchester::{
447    emit as manchester_emit, parse as manchester_parse, ManchesterError, ManchesterExpr,
448};
449
450#[cfg(test)]
451mod comprehensive_tests;
452#[cfg(test)]
453mod comprehensive_tests_extended;