1use std::collections::{HashMap, HashSet};
9use std::sync::Arc;
10use super::working_memory::{WorkingMemory, FactHandle};
11use super::network::{ReteUlNode, TypedReteUlRule};
12use super::facts::{TypedFacts, FactValue};
13use super::agenda::{AdvancedAgenda, Activation};
14use super::template::TemplateRegistry;
15use super::globals::GlobalsRegistry;
16use super::deffacts::DeffactsRegistry;
17use super::tms::TruthMaintenanceSystem;
18use crate::errors::{Result, RuleEngineError};
19
20#[derive(Debug)]
22pub struct RuleDependencyGraph {
23 fact_type_to_rules: HashMap<String, HashSet<usize>>,
25 rule_to_fact_types: HashMap<usize, HashSet<String>>,
27}
28
29impl RuleDependencyGraph {
30 pub fn new() -> Self {
32 Self {
33 fact_type_to_rules: HashMap::new(),
34 rule_to_fact_types: HashMap::new(),
35 }
36 }
37
38 pub fn add_dependency(&mut self, rule_idx: usize, fact_type: String) {
40 self.fact_type_to_rules
41 .entry(fact_type.clone())
42 .or_insert_with(HashSet::new)
43 .insert(rule_idx);
44
45 self.rule_to_fact_types
46 .entry(rule_idx)
47 .or_insert_with(HashSet::new)
48 .insert(fact_type);
49 }
50
51 pub fn get_affected_rules(&self, fact_type: &str) -> HashSet<usize> {
53 self.fact_type_to_rules
54 .get(fact_type)
55 .cloned()
56 .unwrap_or_else(HashSet::new)
57 }
58
59 pub fn get_rule_dependencies(&self, rule_idx: usize) -> HashSet<String> {
61 self.rule_to_fact_types
62 .get(&rule_idx)
63 .cloned()
64 .unwrap_or_else(HashSet::new)
65 }
66}
67
68impl Default for RuleDependencyGraph {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74pub type ReteCustomFunction = Arc<dyn Fn(&[FactValue], &TypedFacts) -> Result<FactValue> + Send + Sync>;
77
78pub struct IncrementalEngine {
81 working_memory: WorkingMemory,
83 rules: Vec<TypedReteUlRule>,
85 dependencies: RuleDependencyGraph,
87 agenda: AdvancedAgenda,
89 rule_matched_facts: HashMap<usize, HashSet<FactHandle>>,
91 templates: TemplateRegistry,
93 globals: GlobalsRegistry,
95 deffacts: DeffactsRegistry,
97 custom_functions: HashMap<String, ReteCustomFunction>,
99 tms: TruthMaintenanceSystem,
101}
102
103impl IncrementalEngine {
104 pub fn new() -> Self {
106 Self {
107 working_memory: WorkingMemory::new(),
108 rules: Vec::new(),
109 dependencies: RuleDependencyGraph::new(),
110 agenda: AdvancedAgenda::new(),
111 rule_matched_facts: HashMap::new(),
112 custom_functions: HashMap::new(),
113 templates: TemplateRegistry::new(),
114 globals: GlobalsRegistry::new(),
115 deffacts: DeffactsRegistry::new(),
116 tms: TruthMaintenanceSystem::new(),
117 }
118 }
119
120 pub fn add_rule(&mut self, rule: TypedReteUlRule, depends_on: Vec<String>) {
122 let rule_idx = self.rules.len();
123
124 for fact_type in depends_on {
126 self.dependencies.add_dependency(rule_idx, fact_type);
127 }
128
129 self.rules.push(rule);
130 }
131
132 pub fn insert(&mut self, fact_type: String, data: TypedFacts) -> FactHandle {
134 let handle = self.working_memory.insert(fact_type.clone(), data);
135
136 self.tms.add_explicit_justification(handle);
138
139 self.propagate_changes_for_type(&fact_type);
141
142 handle
143 }
144
145 pub fn update(&mut self, handle: FactHandle, data: TypedFacts) -> Result<()> {
147 let fact_type = self.working_memory
149 .get(&handle)
150 .map(|f| f.fact_type.clone())
151 .ok_or_else(|| RuleEngineError::FieldNotFound {
152 field: format!("FactHandle {} not found", handle),
153 })?;
154
155 self.working_memory.update(handle, data).map_err(|e| RuleEngineError::EvaluationError {
156 message: e,
157 })?;
158
159 self.propagate_changes_for_type(&fact_type);
161
162 Ok(())
163 }
164
165 pub fn retract(&mut self, handle: FactHandle) -> Result<()> {
167 let fact_type = self.working_memory
169 .get(&handle)
170 .map(|f| f.fact_type.clone())
171 .ok_or_else(|| RuleEngineError::FieldNotFound {
172 field: format!("FactHandle {} not found", handle),
173 })?;
174
175 self.working_memory.retract(handle).map_err(|e| RuleEngineError::EvaluationError {
176 message: e,
177 })?;
178
179 let cascaded_facts = self.tms.retract_with_cascade(handle);
181
182 for cascaded_handle in cascaded_facts {
184 if let Ok(fact_type) = self.working_memory
185 .get(&cascaded_handle)
186 .map(|f| f.fact_type.clone())
187 .ok_or_else(|| RuleEngineError::FieldNotFound {
188 field: format!("FactHandle {} not found", cascaded_handle),
189 })
190 {
191 let _ = self.working_memory.retract(cascaded_handle);
192 self.propagate_changes_for_type(&fact_type);
194 }
195 }
196
197 self.propagate_changes_for_type(&fact_type);
199
200 Ok(())
201 }
202
203 pub fn insert_explicit(&mut self, fact_type: String, data: TypedFacts) -> FactHandle {
206 let handle = self.working_memory.insert(fact_type.clone(), data);
207
208 self.tms.add_explicit_justification(handle);
210
211 self.propagate_changes_for_type(&fact_type);
213
214 handle
215 }
216
217 pub fn insert_logical(
226 &mut self,
227 fact_type: String,
228 data: TypedFacts,
229 source_rule: String,
230 premise_handles: Vec<FactHandle>,
231 ) -> FactHandle {
232 let handle = self.working_memory.insert(fact_type.clone(), data);
233
234 self.tms.add_logical_justification(handle, source_rule, premise_handles);
236
237 self.propagate_changes_for_type(&fact_type);
239
240 handle
241 }
242
243 pub fn resolve_premise_keys(&self, premise_keys: Vec<String>) -> Vec<FactHandle> {
248 let mut handles = Vec::new();
249
250 for key in premise_keys {
251 if let Some(eq_pos) = key.find('=') {
253 let left = &key[..eq_pos];
254 let value_part = &key[eq_pos + 1..];
255
256 if let Some(dot_pos) = left.find('.') {
257 let fact_type = &left[..dot_pos];
258 let field = &left[dot_pos + 1..];
259
260 let facts = self.working_memory.get_by_type(fact_type);
262 if value_part.is_empty() {
264 if let Some(fact) = facts.iter().rev().find(|f| !f.metadata.retracted) {
266 handles.push(fact.handle);
267 continue;
268 }
269 } else {
270 fn parse_literal(s: &str) -> super::facts::FactValue {
274 let s = s.trim();
275 if s == "true" {
276 return super::facts::FactValue::Boolean(true);
277 }
278 if s == "false" {
279 return super::facts::FactValue::Boolean(false);
280 }
281 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
283 return super::facts::FactValue::String(s[1..s.len()-1].to_string());
284 }
285 if let Ok(i) = s.parse::<i64>() {
287 return super::facts::FactValue::Integer(i);
288 }
289 if let Ok(f) = s.parse::<f64>() {
291 return super::facts::FactValue::Float(f);
292 }
293
294 super::facts::FactValue::String(s.to_string())
296 }
297
298 fn fact_value_equal(a: &super::facts::FactValue, b: &super::facts::FactValue) -> bool {
299 use super::facts::FactValue;
300 match (a, b) {
301 (FactValue::Boolean(x), FactValue::Boolean(y)) => x == y,
302 (FactValue::Integer(x), FactValue::Integer(y)) => x == y,
303 (FactValue::Float(x), FactValue::Float(y)) => (x - y).abs() < 1e-9,
304 (FactValue::Integer(x), FactValue::Float(y)) => ((*x as f64) - *y).abs() < 1e-9,
306 (FactValue::Float(x), FactValue::Integer(y)) => (*x - (*y as f64)).abs() < 1e-9,
307 (FactValue::String(x), FactValue::String(y)) => x == y,
308 _ => a.as_string() == b.as_string(),
310 }
311 }
312
313 let expected = parse_literal(value_part);
314
315 if let Some(fact) = facts.iter().rev().find(|fact| {
317 if fact.metadata.retracted { return false; }
318 if let Some(fv) = fact.data.get(field) {
319 fact_value_equal(fv, &expected) || fv.as_string() == value_part
320 } else {
321 false
322 }
323 }) {
324 handles.push(fact.handle);
325 }
326 }
327 }
328 }
329 }
330
331 handles
332 }
333
334 pub fn tms(&self) -> &TruthMaintenanceSystem {
336 &self.tms
337 }
338
339 pub fn tms_mut(&mut self) -> &mut TruthMaintenanceSystem {
341 &mut self.tms
342 }
343
344 fn propagate_changes_for_type(&mut self, fact_type: &str) {
346 let affected_rules = self.dependencies.get_affected_rules(fact_type);
348
349 if affected_rules.is_empty() {
350 return; }
352
353 let facts_of_type = self.working_memory.get_by_type(fact_type);
355
356 for &rule_idx in &affected_rules {
358 let rule = &self.rules[rule_idx];
359
360 for fact in &facts_of_type {
362 let mut single_fact_data = TypedFacts::new();
364 for (key, value) in fact.data.get_all() {
365 single_fact_data.set(format!("{}.{}", fact_type, key), value.clone());
366 }
367 single_fact_data.set_fact_handle(fact_type.to_string(), fact.handle);
369
370 let matches = super::network::evaluate_rete_ul_node_typed(&rule.node, &single_fact_data);
372
373 if matches {
374 let activation = Activation::new(rule.name.clone(), rule.priority)
376 .with_no_loop(rule.no_loop)
377 .with_matched_fact(fact.handle);
378
379 self.agenda.add_activation(activation);
380 }
381 }
382 }
383 }
384
385 fn propagate_changes(&mut self) {
387 let fact_types: Vec<String> = self.working_memory.get_all_facts()
389 .iter()
390 .map(|f| f.fact_type.clone())
391 .collect::<std::collections::HashSet<_>>()
392 .into_iter()
393 .collect();
394
395 for fact_type in fact_types {
397 let facts_of_type = self.working_memory.get_by_type(&fact_type);
398
399 for (rule_idx, rule) in self.rules.iter().enumerate() {
400 if rule.no_loop && self.agenda.has_fired(&rule.name) {
402 continue;
403 }
404
405 for fact in &facts_of_type {
407 let mut single_fact_data = TypedFacts::new();
408 for (key, value) in fact.data.get_all() {
409 single_fact_data.set(format!("{}.{}", fact_type, key), value.clone());
410 }
411
412 let matches = super::network::evaluate_rete_ul_node_typed(&rule.node, &single_fact_data);
413
414 if matches {
415 let activation = Activation::new(rule.name.clone(), rule.priority)
416 .with_no_loop(rule.no_loop)
417 .with_matched_fact(fact.handle);
418
419 self.agenda.add_activation(activation);
420 }
421 }
422 }
423 }
424 }
425
426 pub fn fire_all(&mut self) -> Vec<String> {
428 let mut fired_rules = Vec::new();
429 let max_iterations = 1000; let mut iteration_count = 0;
431
432 while let Some(activation) = self.agenda.get_next_activation() {
433 iteration_count += 1;
434 if iteration_count > max_iterations {
435 eprintln!("WARNING: Maximum iterations ({}) reached in fire_all(). Possible infinite loop!", max_iterations);
436 break;
437 }
438
439 if let Some((idx, rule)) = self.rules
441 .iter_mut()
442 .enumerate()
443 .find(|(_, r)| r.name == activation.rule_name)
444 {
445 if let Some(matched_handle) = activation.matched_fact_handle {
447 if self.working_memory.get(&matched_handle).is_none() {
448 continue;
450 }
451 }
452
453 let original_facts = self.working_memory.to_typed_facts();
455 let mut modified_facts = original_facts.clone();
456
457 if let Some(matched_handle) = activation.matched_fact_handle {
459 if let Some(fact) = self.working_memory.get(&matched_handle) {
461 modified_facts.set_fact_handle(fact.fact_type.clone(), matched_handle);
462 }
463 }
464
465 let mut action_results = super::ActionResults::new();
466 (rule.action)(&mut modified_facts, &mut action_results);
467
468 let mut updates_by_type: HashMap<String, Vec<(String, FactValue)>> = HashMap::new();
471
472 for (key, value) in modified_facts.get_all() {
473 if let Some(original_value) = original_facts.get(key) {
476 if original_value != value {
477 let parts: Vec<&str> = key.split('.').collect();
479 if parts.len() >= 2 {
480 let fact_type = parts[0].to_string();
481 let field = if parts.len() == 2 {
483 parts[1].to_string()
484 } else {
485 parts[parts.len() - 1].to_string()
486 };
487
488 updates_by_type
489 .entry(fact_type)
490 .or_insert_with(Vec::new)
491 .push((field, value.clone()));
492 }
493 }
494 } else {
495 let parts: Vec<&str> = key.split('.').collect();
497 if parts.len() >= 2 {
498 let fact_type = parts[0].to_string();
499 let field = if parts.len() == 2 {
500 parts[1].to_string()
501 } else {
502 parts[parts.len() - 1].to_string()
503 };
504
505 updates_by_type
506 .entry(fact_type)
507 .or_insert_with(Vec::new)
508 .push((field, value.clone()));
509 }
510 }
511 }
512
513 for (fact_type, field_updates) in updates_by_type {
515 let fact_handles: Vec<FactHandle> = self.working_memory
517 .get_by_type(&fact_type)
518 .iter()
519 .map(|f| f.handle)
520 .collect();
521
522 for handle in fact_handles {
523 if let Some(fact) = self.working_memory.get(&handle) {
524 let mut updated_data = fact.data.clone();
525
526 for (field, value) in &field_updates {
528 updated_data.set(field, value.clone());
529 }
530
531 let _ = self.working_memory.update(handle, updated_data);
532 }
533 }
534 }
535
536 self.propagate_changes();
539
540 self.process_action_results(action_results);
542
543 fired_rules.push(activation.rule_name.clone());
545 self.agenda.mark_rule_fired(&activation);
546 }
547 }
548
549 fired_rules
550 }
551
552 fn process_action_results(&mut self, results: super::ActionResults) {
554 for result in results.results {
555 match result {
556 super::ActionResult::Retract(handle) => {
557 if let Err(e) = self.retract(handle) {
559 eprintln!("❌ Failed to retract fact {:?}: {}", handle, e);
560 }
561 }
562 super::ActionResult::RetractByType(fact_type) => {
563 let facts_of_type = self.working_memory.get_by_type(&fact_type);
565 if let Some(fact) = facts_of_type.first() {
566 let handle = fact.handle;
567 if let Err(e) = self.retract(handle) {
568 eprintln!("❌ Failed to retract fact {:?}: {}", handle, e);
569 }
570 }
571 }
572 super::ActionResult::Update(handle) => {
573 if let Some(fact) = self.working_memory.get(&handle) {
575 let fact_type = fact.fact_type.clone();
576 self.propagate_changes_for_type(&fact_type);
577 }
578 }
579 super::ActionResult::ActivateAgendaGroup(group) => {
580 self.agenda.set_focus(group);
582 }
583 super::ActionResult::InsertFact { fact_type, data } => {
584 self.insert_explicit(fact_type, data);
586 }
587 super::ActionResult::InsertLogicalFact { fact_type, data, rule_name, premises } => {
588 let _handle = self.insert_logical(fact_type, data, rule_name, premises);
590 }
591 super::ActionResult::CallFunction { function_name, args } => {
592 if let Some(func) = self.custom_functions.get(&function_name) {
594 let fact_values: Vec<FactValue> = args.iter()
596 .map(|s| FactValue::String(s.clone()))
597 .collect();
598
599 let all_facts = self.working_memory.to_typed_facts();
601 match func(&fact_values, &all_facts) {
602 Ok(_) => println!("✅ Called function: {}", function_name),
603 Err(e) => eprintln!("❌ Function {} failed: {}", function_name, e),
604 }
605 } else {
606 println!("🔧 Function call queued: {}({:?})", function_name, args);
608 }
609 }
610 super::ActionResult::ScheduleRule { rule_name, delay_ms } => {
611 println!("⏰ Rule scheduled: {} after {}ms", rule_name, delay_ms);
613 }
615 super::ActionResult::None => {
616 }
618 }
619 }
620 }
621
622 pub fn working_memory(&self) -> &WorkingMemory {
624 &self.working_memory
625 }
626
627 pub fn working_memory_mut(&mut self) -> &mut WorkingMemory {
629 &mut self.working_memory
630 }
631
632 pub fn agenda(&self) -> &AdvancedAgenda {
634 &self.agenda
635 }
636
637 pub fn agenda_mut(&mut self) -> &mut AdvancedAgenda {
639 &mut self.agenda
640 }
641
642 pub fn set_conflict_resolution_strategy(
647 &mut self,
648 strategy: super::agenda::ConflictResolutionStrategy,
649 ) {
650 self.agenda.set_strategy(strategy);
651 }
652
653 pub fn conflict_resolution_strategy(&self) -> super::agenda::ConflictResolutionStrategy {
655 self.agenda.strategy()
656 }
657
658 pub fn stats(&self) -> IncrementalEngineStats {
660 IncrementalEngineStats {
661 rules: self.rules.len(),
662 working_memory: self.working_memory.stats(),
663 agenda: self.agenda.stats(),
664 dependencies: self.dependencies.fact_type_to_rules.len(),
665 }
666 }
667
668 pub fn reset(&mut self) {
670 self.agenda.reset_fired_flags();
671 }
672
673 pub fn templates(&self) -> &TemplateRegistry {
675 &self.templates
676 }
677
678 pub fn templates_mut(&mut self) -> &mut TemplateRegistry {
680 &mut self.templates
681 }
682
683 pub fn register_function<F>(&mut self, name: &str, func: F)
702 where
703 F: Fn(&[FactValue], &TypedFacts) -> Result<FactValue> + Send + Sync + 'static,
704 {
705 self.custom_functions.insert(name.to_string(), Arc::new(func));
706 }
707
708 pub fn get_function(&self, name: &str) -> Option<&ReteCustomFunction> {
710 self.custom_functions.get(name)
711 }
712
713 pub fn globals(&self) -> &GlobalsRegistry {
715 &self.globals
716 }
717
718 pub fn globals_mut(&mut self) -> &mut GlobalsRegistry {
720 &mut self.globals
721 }
722
723 pub fn deffacts(&self) -> &DeffactsRegistry {
725 &self.deffacts
726 }
727
728 pub fn deffacts_mut(&mut self) -> &mut DeffactsRegistry {
730 &mut self.deffacts
731 }
732
733 pub fn load_deffacts(&mut self) -> Vec<FactHandle> {
736 let mut handles = Vec::new();
737
738 let all_facts = self.deffacts.get_all_facts();
740
741 for (_deffacts_name, fact_instance) in all_facts {
742 let handle = if self.templates.get(&fact_instance.fact_type).is_some() {
744 match self.insert_with_template(&fact_instance.fact_type, fact_instance.data) {
746 Ok(h) => h,
747 Err(_) => continue, }
749 } else {
750 self.insert(fact_instance.fact_type, fact_instance.data)
752 };
753
754 handles.push(handle);
755 }
756
757 handles
758 }
759
760 pub fn load_deffacts_by_name(&mut self, name: &str) -> crate::errors::Result<Vec<FactHandle>> {
763 let facts_to_insert = {
765 let deffacts = self.deffacts.get(name).ok_or_else(|| {
766 crate::errors::RuleEngineError::EvaluationError {
767 message: format!("Deffacts '{}' not found", name),
768 }
769 })?;
770 deffacts.facts.clone()
771 };
772
773 let mut handles = Vec::new();
774
775 for fact_instance in facts_to_insert {
776 let handle = if self.templates.get(&fact_instance.fact_type).is_some() {
778 self.insert_with_template(&fact_instance.fact_type, fact_instance.data)?
780 } else {
781 self.insert(fact_instance.fact_type, fact_instance.data)
783 };
784
785 handles.push(handle);
786 }
787
788 Ok(handles)
789 }
790
791 pub fn reset_with_deffacts(&mut self) -> Vec<FactHandle> {
794 self.working_memory = WorkingMemory::new();
796 self.agenda.clear();
797 self.rule_matched_facts.clear();
798
799 self.load_deffacts()
801 }
802
803 pub fn insert_with_template(
805 &mut self,
806 template_name: &str,
807 data: TypedFacts,
808 ) -> crate::errors::Result<FactHandle> {
809 self.templates.validate(template_name, &data)?;
811
812 Ok(self.insert(template_name.to_string(), data))
814 }
815}
816
817impl Default for IncrementalEngine {
818 fn default() -> Self {
819 Self::new()
820 }
821}
822
823#[derive(Debug)]
825pub struct IncrementalEngineStats {
826 pub rules: usize,
827 pub working_memory: super::working_memory::WorkingMemoryStats,
828 pub agenda: super::agenda::AgendaStats,
829 pub dependencies: usize,
830}
831
832impl std::fmt::Display for IncrementalEngineStats {
833 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
834 write!(
835 f,
836 "Engine Stats: {} rules, {} fact types tracked\nWM: {}\nAgenda: {}",
837 self.rules,
838 self.dependencies,
839 self.working_memory,
840 self.agenda
841 )
842 }
843}
844
845#[cfg(test)]
846mod tests {
847 use super::*;
848 use crate::rete::network::ReteUlNode;
849 use crate::rete::alpha::AlphaNode;
850
851 #[test]
852 fn test_dependency_graph() {
853 let mut graph = RuleDependencyGraph::new();
854
855 graph.add_dependency(0, "Person".to_string());
856 graph.add_dependency(1, "Person".to_string());
857 graph.add_dependency(1, "Order".to_string());
858
859 let affected = graph.get_affected_rules("Person");
860 assert_eq!(affected.len(), 2);
861 assert!(affected.contains(&0));
862 assert!(affected.contains(&1));
863
864 let deps = graph.get_rule_dependencies(1);
865 assert_eq!(deps.len(), 2);
866 assert!(deps.contains("Person"));
867 assert!(deps.contains("Order"));
868 }
869
870 #[test]
871 fn test_incremental_propagation() {
872 let mut engine = IncrementalEngine::new();
873
874 let node = ReteUlNode::UlAlpha(AlphaNode {
876 field: "Person.age".to_string(),
877 operator: ">".to_string(),
878 value: "18".to_string(),
879 });
880
881 let rule = TypedReteUlRule {
882 name: "IsAdult".to_string(),
883 node,
884 priority: 0,
885 no_loop: true,
886 action: std::sync::Arc::new(|_, _| {}),
887 };
888
889 engine.add_rule(rule, vec!["Person".to_string()]);
890
891 let mut person = TypedFacts::new();
893 person.set("age", 25i64);
894 let handle = engine.insert("Person".to_string(), person);
895
896 let stats = engine.stats();
898 assert!(stats.agenda.total_activations > 0);
899
900 let mut updated = TypedFacts::new();
902 updated.set("age", 15i64); engine.update(handle, updated).unwrap();
904
905 }
907}