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 tms(&self) -> &TruthMaintenanceSystem {
245 &self.tms
246 }
247
248 pub fn tms_mut(&mut self) -> &mut TruthMaintenanceSystem {
250 &mut self.tms
251 }
252
253 fn propagate_changes_for_type(&mut self, fact_type: &str) {
255 let affected_rules = self.dependencies.get_affected_rules(fact_type);
257
258 if affected_rules.is_empty() {
259 return; }
261
262 let facts_of_type = self.working_memory.get_by_type(fact_type);
264
265 for &rule_idx in &affected_rules {
267 let rule = &self.rules[rule_idx];
268
269 for fact in &facts_of_type {
271 let mut single_fact_data = TypedFacts::new();
273 for (key, value) in fact.data.get_all() {
274 single_fact_data.set(format!("{}.{}", fact_type, key), value.clone());
275 }
276 single_fact_data.set_fact_handle(fact_type.to_string(), fact.handle);
278
279 let matches = super::network::evaluate_rete_ul_node_typed(&rule.node, &single_fact_data);
281
282 if matches {
283 let activation = Activation::new(rule.name.clone(), rule.priority)
285 .with_no_loop(rule.no_loop)
286 .with_matched_fact(fact.handle);
287
288 self.agenda.add_activation(activation);
289 }
290 }
291 }
292 }
293
294 fn propagate_changes(&mut self) {
296 let fact_types: Vec<String> = self.working_memory.get_all_facts()
298 .iter()
299 .map(|f| f.fact_type.clone())
300 .collect::<std::collections::HashSet<_>>()
301 .into_iter()
302 .collect();
303
304 for fact_type in fact_types {
306 let facts_of_type = self.working_memory.get_by_type(&fact_type);
307
308 for (rule_idx, rule) in self.rules.iter().enumerate() {
309 if rule.no_loop && self.agenda.has_fired(&rule.name) {
311 continue;
312 }
313
314 for fact in &facts_of_type {
316 let mut single_fact_data = TypedFacts::new();
317 for (key, value) in fact.data.get_all() {
318 single_fact_data.set(format!("{}.{}", fact_type, key), value.clone());
319 }
320
321 let matches = super::network::evaluate_rete_ul_node_typed(&rule.node, &single_fact_data);
322
323 if matches {
324 let activation = Activation::new(rule.name.clone(), rule.priority)
325 .with_no_loop(rule.no_loop)
326 .with_matched_fact(fact.handle);
327
328 self.agenda.add_activation(activation);
329 }
330 }
331 }
332 }
333 }
334
335 pub fn fire_all(&mut self) -> Vec<String> {
337 let mut fired_rules = Vec::new();
338 let max_iterations = 1000; let mut iteration_count = 0;
340
341 while let Some(activation) = self.agenda.get_next_activation() {
342 iteration_count += 1;
343 if iteration_count > max_iterations {
344 eprintln!("WARNING: Maximum iterations ({}) reached in fire_all(). Possible infinite loop!", max_iterations);
345 break;
346 }
347
348 if let Some((idx, rule)) = self.rules
350 .iter_mut()
351 .enumerate()
352 .find(|(_, r)| r.name == activation.rule_name)
353 {
354 if let Some(matched_handle) = activation.matched_fact_handle {
356 if self.working_memory.get(&matched_handle).is_none() {
357 continue;
359 }
360 }
361
362 let original_facts = self.working_memory.to_typed_facts();
364 let mut modified_facts = original_facts.clone();
365
366 if let Some(matched_handle) = activation.matched_fact_handle {
368 if let Some(fact) = self.working_memory.get(&matched_handle) {
370 modified_facts.set_fact_handle(fact.fact_type.clone(), matched_handle);
371 }
372 }
373
374 let mut action_results = super::ActionResults::new();
375 (rule.action)(&mut modified_facts, &mut action_results);
376
377 let mut updates_by_type: HashMap<String, Vec<(String, FactValue)>> = HashMap::new();
380
381 for (key, value) in modified_facts.get_all() {
382 if let Some(original_value) = original_facts.get(key) {
385 if original_value != value {
386 let parts: Vec<&str> = key.split('.').collect();
388 if parts.len() >= 2 {
389 let fact_type = parts[0].to_string();
390 let field = if parts.len() == 2 {
392 parts[1].to_string()
393 } else {
394 parts[parts.len() - 1].to_string()
395 };
396
397 updates_by_type
398 .entry(fact_type)
399 .or_insert_with(Vec::new)
400 .push((field, value.clone()));
401 }
402 }
403 } else {
404 let parts: Vec<&str> = key.split('.').collect();
406 if parts.len() >= 2 {
407 let fact_type = parts[0].to_string();
408 let field = if parts.len() == 2 {
409 parts[1].to_string()
410 } else {
411 parts[parts.len() - 1].to_string()
412 };
413
414 updates_by_type
415 .entry(fact_type)
416 .or_insert_with(Vec::new)
417 .push((field, value.clone()));
418 }
419 }
420 }
421
422 for (fact_type, field_updates) in updates_by_type {
424 let fact_handles: Vec<FactHandle> = self.working_memory
426 .get_by_type(&fact_type)
427 .iter()
428 .map(|f| f.handle)
429 .collect();
430
431 for handle in fact_handles {
432 if let Some(fact) = self.working_memory.get(&handle) {
433 let mut updated_data = fact.data.clone();
434
435 for (field, value) in &field_updates {
437 updated_data.set(field, value.clone());
438 }
439
440 let _ = self.working_memory.update(handle, updated_data);
441 }
442 }
443 }
444
445 self.propagate_changes();
448
449 self.process_action_results(action_results);
451
452 fired_rules.push(activation.rule_name.clone());
454 self.agenda.mark_rule_fired(&activation);
455 }
456 }
457
458 fired_rules
459 }
460
461 fn process_action_results(&mut self, results: super::ActionResults) {
463 for result in results.results {
464 match result {
465 super::ActionResult::Retract(handle) => {
466 if let Err(e) = self.retract(handle) {
468 eprintln!("❌ Failed to retract fact {:?}: {}", handle, e);
469 }
470 }
471 super::ActionResult::RetractByType(fact_type) => {
472 let facts_of_type = self.working_memory.get_by_type(&fact_type);
474 if let Some(fact) = facts_of_type.first() {
475 let handle = fact.handle;
476 if let Err(e) = self.retract(handle) {
477 eprintln!("❌ Failed to retract fact {:?}: {}", handle, e);
478 }
479 }
480 }
481 super::ActionResult::Update(handle) => {
482 if let Some(fact) = self.working_memory.get(&handle) {
484 let fact_type = fact.fact_type.clone();
485 self.propagate_changes_for_type(&fact_type);
486 }
487 }
488 super::ActionResult::ActivateAgendaGroup(group) => {
489 self.agenda.set_focus(group);
491 }
492 super::ActionResult::InsertFact { fact_type, data } => {
493 self.insert_explicit(fact_type, data);
495 }
496 super::ActionResult::InsertLogicalFact { fact_type, data, rule_name, premises } => {
497 let _handle = self.insert_logical(fact_type, data, rule_name, premises);
499 }
500 super::ActionResult::CallFunction { function_name, args } => {
501 if let Some(func) = self.custom_functions.get(&function_name) {
503 let fact_values: Vec<FactValue> = args.iter()
505 .map(|s| FactValue::String(s.clone()))
506 .collect();
507
508 let all_facts = self.working_memory.to_typed_facts();
510 match func(&fact_values, &all_facts) {
511 Ok(_) => println!("✅ Called function: {}", function_name),
512 Err(e) => eprintln!("❌ Function {} failed: {}", function_name, e),
513 }
514 } else {
515 println!("🔧 Function call queued: {}({:?})", function_name, args);
517 }
518 }
519 super::ActionResult::ScheduleRule { rule_name, delay_ms } => {
520 println!("⏰ Rule scheduled: {} after {}ms", rule_name, delay_ms);
522 }
524 super::ActionResult::None => {
525 }
527 }
528 }
529 }
530
531 pub fn working_memory(&self) -> &WorkingMemory {
533 &self.working_memory
534 }
535
536 pub fn working_memory_mut(&mut self) -> &mut WorkingMemory {
538 &mut self.working_memory
539 }
540
541 pub fn agenda(&self) -> &AdvancedAgenda {
543 &self.agenda
544 }
545
546 pub fn agenda_mut(&mut self) -> &mut AdvancedAgenda {
548 &mut self.agenda
549 }
550
551 pub fn set_conflict_resolution_strategy(
556 &mut self,
557 strategy: super::agenda::ConflictResolutionStrategy,
558 ) {
559 self.agenda.set_strategy(strategy);
560 }
561
562 pub fn conflict_resolution_strategy(&self) -> super::agenda::ConflictResolutionStrategy {
564 self.agenda.strategy()
565 }
566
567 pub fn stats(&self) -> IncrementalEngineStats {
569 IncrementalEngineStats {
570 rules: self.rules.len(),
571 working_memory: self.working_memory.stats(),
572 agenda: self.agenda.stats(),
573 dependencies: self.dependencies.fact_type_to_rules.len(),
574 }
575 }
576
577 pub fn reset(&mut self) {
579 self.agenda.reset_fired_flags();
580 }
581
582 pub fn templates(&self) -> &TemplateRegistry {
584 &self.templates
585 }
586
587 pub fn templates_mut(&mut self) -> &mut TemplateRegistry {
589 &mut self.templates
590 }
591
592 pub fn register_function<F>(&mut self, name: &str, func: F)
611 where
612 F: Fn(&[FactValue], &TypedFacts) -> Result<FactValue> + Send + Sync + 'static,
613 {
614 self.custom_functions.insert(name.to_string(), Arc::new(func));
615 }
616
617 pub fn get_function(&self, name: &str) -> Option<&ReteCustomFunction> {
619 self.custom_functions.get(name)
620 }
621
622 pub fn globals(&self) -> &GlobalsRegistry {
624 &self.globals
625 }
626
627 pub fn globals_mut(&mut self) -> &mut GlobalsRegistry {
629 &mut self.globals
630 }
631
632 pub fn deffacts(&self) -> &DeffactsRegistry {
634 &self.deffacts
635 }
636
637 pub fn deffacts_mut(&mut self) -> &mut DeffactsRegistry {
639 &mut self.deffacts
640 }
641
642 pub fn load_deffacts(&mut self) -> Vec<FactHandle> {
645 let mut handles = Vec::new();
646
647 let all_facts = self.deffacts.get_all_facts();
649
650 for (_deffacts_name, fact_instance) in all_facts {
651 let handle = if self.templates.get(&fact_instance.fact_type).is_some() {
653 match self.insert_with_template(&fact_instance.fact_type, fact_instance.data) {
655 Ok(h) => h,
656 Err(_) => continue, }
658 } else {
659 self.insert(fact_instance.fact_type, fact_instance.data)
661 };
662
663 handles.push(handle);
664 }
665
666 handles
667 }
668
669 pub fn load_deffacts_by_name(&mut self, name: &str) -> crate::errors::Result<Vec<FactHandle>> {
672 let facts_to_insert = {
674 let deffacts = self.deffacts.get(name).ok_or_else(|| {
675 crate::errors::RuleEngineError::EvaluationError {
676 message: format!("Deffacts '{}' not found", name),
677 }
678 })?;
679 deffacts.facts.clone()
680 };
681
682 let mut handles = Vec::new();
683
684 for fact_instance in facts_to_insert {
685 let handle = if self.templates.get(&fact_instance.fact_type).is_some() {
687 self.insert_with_template(&fact_instance.fact_type, fact_instance.data)?
689 } else {
690 self.insert(fact_instance.fact_type, fact_instance.data)
692 };
693
694 handles.push(handle);
695 }
696
697 Ok(handles)
698 }
699
700 pub fn reset_with_deffacts(&mut self) -> Vec<FactHandle> {
703 self.working_memory = WorkingMemory::new();
705 self.agenda.clear();
706 self.rule_matched_facts.clear();
707
708 self.load_deffacts()
710 }
711
712 pub fn insert_with_template(
714 &mut self,
715 template_name: &str,
716 data: TypedFacts,
717 ) -> crate::errors::Result<FactHandle> {
718 self.templates.validate(template_name, &data)?;
720
721 Ok(self.insert(template_name.to_string(), data))
723 }
724}
725
726impl Default for IncrementalEngine {
727 fn default() -> Self {
728 Self::new()
729 }
730}
731
732#[derive(Debug)]
734pub struct IncrementalEngineStats {
735 pub rules: usize,
736 pub working_memory: super::working_memory::WorkingMemoryStats,
737 pub agenda: super::agenda::AgendaStats,
738 pub dependencies: usize,
739}
740
741impl std::fmt::Display for IncrementalEngineStats {
742 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
743 write!(
744 f,
745 "Engine Stats: {} rules, {} fact types tracked\nWM: {}\nAgenda: {}",
746 self.rules,
747 self.dependencies,
748 self.working_memory,
749 self.agenda
750 )
751 }
752}
753
754#[cfg(test)]
755mod tests {
756 use super::*;
757 use crate::rete::network::ReteUlNode;
758 use crate::rete::alpha::AlphaNode;
759
760 #[test]
761 fn test_dependency_graph() {
762 let mut graph = RuleDependencyGraph::new();
763
764 graph.add_dependency(0, "Person".to_string());
765 graph.add_dependency(1, "Person".to_string());
766 graph.add_dependency(1, "Order".to_string());
767
768 let affected = graph.get_affected_rules("Person");
769 assert_eq!(affected.len(), 2);
770 assert!(affected.contains(&0));
771 assert!(affected.contains(&1));
772
773 let deps = graph.get_rule_dependencies(1);
774 assert_eq!(deps.len(), 2);
775 assert!(deps.contains("Person"));
776 assert!(deps.contains("Order"));
777 }
778
779 #[test]
780 fn test_incremental_propagation() {
781 let mut engine = IncrementalEngine::new();
782
783 let node = ReteUlNode::UlAlpha(AlphaNode {
785 field: "Person.age".to_string(),
786 operator: ">".to_string(),
787 value: "18".to_string(),
788 });
789
790 let rule = TypedReteUlRule {
791 name: "IsAdult".to_string(),
792 node,
793 priority: 0,
794 no_loop: true,
795 action: std::sync::Arc::new(|_, _| {}),
796 };
797
798 engine.add_rule(rule, vec!["Person".to_string()]);
799
800 let mut person = TypedFacts::new();
802 person.set("age", 25i64);
803 let handle = engine.insert("Person".to_string(), person);
804
805 let stats = engine.stats();
807 assert!(stats.agenda.total_activations > 0);
808
809 let mut updated = TypedFacts::new();
811 updated.set("age", 15i64); engine.update(handle, updated).unwrap();
813
814 }
816}