1use super::goal::{Goal, GoalStatus};
4use super::rule_executor::RuleExecutor;
5use crate::Facts;
6use crate::types::Value;
7use crate::KnowledgeBase;
8use crate::engine::rule::Rule;
9use std::collections::VecDeque;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum SearchStrategy {
14 DepthFirst,
17
18 BreadthFirst,
21
22 Iterative,
25}
26
27#[derive(Debug)]
29pub struct SearchResult {
30 pub success: bool,
32
33 pub path: Vec<String>,
35
36 pub goals_explored: usize,
38
39 pub max_depth_reached: usize,
41
42 pub bindings: std::collections::HashMap<String, Value>,
44}
45
46impl SearchResult {
47 pub fn success(path: Vec<String>, goals_explored: usize, max_depth: usize) -> Self {
49 Self {
50 success: true,
51 path,
52 goals_explored,
53 max_depth_reached: max_depth,
54 bindings: std::collections::HashMap::new(),
55 }
56 }
57
58 pub fn failure(goals_explored: usize, max_depth: usize) -> Self {
60 Self {
61 success: false,
62 path: Vec::new(),
63 goals_explored,
64 max_depth_reached: max_depth,
65 bindings: std::collections::HashMap::new(),
66 }
67 }
68}
69
70pub struct DepthFirstSearch {
72 max_depth: usize,
73 goals_explored: usize,
74 path: Vec<String>,
75 executor: RuleExecutor,
76}
77
78impl DepthFirstSearch {
79 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
81 Self {
82 max_depth,
83 goals_explored: 0,
84 path: Vec::new(),
85 executor: RuleExecutor::new(kb),
86 }
87 }
88
89 pub fn search_with_execution(&mut self, goal: &mut Goal, facts: &mut Facts, kb: &KnowledgeBase) -> SearchResult {
91 self.goals_explored = 0;
92 self.path.clear();
93
94 let success = self.search_recursive_with_execution(goal, facts, kb, 0);
95
96 SearchResult {
97 success,
98 path: self.path.clone(),
99 goals_explored: self.goals_explored,
100 max_depth_reached: goal.depth,
101 bindings: goal.bindings.to_map(),
102 }
103 }
104
105 pub fn search(&mut self, goal: &mut Goal, _facts: &Facts) -> SearchResult {
107 self.goals_explored = 0;
108 self.path.clear();
109
110 let success = self.search_recursive(goal, 0);
111
112 SearchResult {
113 success,
114 path: self.path.clone(),
115 goals_explored: self.goals_explored,
116 max_depth_reached: goal.depth,
117 bindings: goal.bindings.to_map(),
118 }
119 }
120
121 fn search_recursive_with_execution(
123 &mut self,
124 goal: &mut Goal,
125 facts: &mut Facts, kb: &KnowledgeBase,
127 depth: usize
128 ) -> bool {
129 self.goals_explored += 1;
130
131 if depth > self.max_depth {
133 goal.status = GoalStatus::Unprovable;
134 return false;
135 }
136
137 if self.check_goal_in_facts(goal, facts) {
139 goal.status = GoalStatus::Proven;
140 return true;
141 }
142
143 if goal.status == GoalStatus::InProgress {
145 goal.status = GoalStatus::Unprovable;
146 return false;
147 }
148
149 goal.status = GoalStatus::InProgress;
150 goal.depth = depth;
151
152 for rule_name in goal.candidate_rules.clone() {
154 self.path.push(rule_name.clone());
155
156 if let Some(rule) = kb.get_rule(&rule_name) {
158 match self.executor.try_execute_rule(&rule, facts) {
160 Ok(true) => {
161 if self.check_goal_in_facts(goal, facts) {
164 goal.status = GoalStatus::Proven;
165 return true;
166 }
167 }
168 Ok(false) => {
169 if self.try_prove_rule_conditions(&rule, facts, kb, depth + 1) {
171 match self.executor.try_execute_rule(&rule, facts) {
173 Ok(true) => {
174 if self.check_goal_in_facts(goal, facts) {
175 goal.status = GoalStatus::Proven;
176 self.path.pop();
177 return true;
178 }
179 }
180 _ => {}
181 }
182 }
183 }
184 Err(_) => {
185 }
187 }
188 }
189
190 self.path.pop();
191 }
192
193 let mut all_subgoals_proven = true;
195 for sub_goal in &mut goal.sub_goals {
196 if !self.search_recursive_with_execution(sub_goal, facts, kb, depth + 1) {
197 all_subgoals_proven = false;
198 break;
199 }
200 }
201
202 if !goal.sub_goals.is_empty() && all_subgoals_proven {
204 goal.status = GoalStatus::Proven;
205 return true;
206 }
207
208 goal.status = GoalStatus::Unprovable;
210 false
211 }
212
213 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
215 let pattern = &goal.pattern;
217
218 if let Some(eq_pos) = pattern.find("==") {
220 let field = pattern[..eq_pos].trim();
221 let expected = pattern[eq_pos + 2..].trim();
222
223 if let Some(actual) = facts.get(field) {
224 return self.value_matches(&actual, expected);
225 }
226 return false;
227 }
228
229 if let Some(ne_pos) = pattern.find("!=") {
230 let field = pattern[..ne_pos].trim();
231 let not_expected = pattern[ne_pos + 2..].trim();
232
233 if let Some(actual) = facts.get(field) {
234 return !self.value_matches(&actual, not_expected);
235 }
236 return true;
238 }
239
240 false
241 }
242
243 fn value_matches(&self, value: &Value, expected: &str) -> bool {
245 match value {
246 Value::Boolean(b) => {
247 expected == "true" && *b || expected == "false" && !*b
248 }
249 Value::String(s) => {
250 s == expected || s == expected.trim_matches('"')
251 }
252 Value::Number(n) => {
253 expected.parse::<f64>().map(|e| (n - e).abs() < 0.0001).unwrap_or(false)
254 }
255 _ => false,
256 }
257 }
258
259 fn check_rule_conditions(&self, rule: &Rule, facts: &Facts) -> bool {
261 self.executor.evaluate_conditions(&rule.conditions, facts).unwrap_or(false)
263 }
264
265 fn try_prove_rule_conditions(
268 &mut self,
269 rule: &Rule,
270 facts: &mut Facts,
271 kb: &KnowledgeBase,
272 depth: usize,
273 ) -> bool {
274 self.try_prove_condition_group(&rule.conditions, facts, kb, depth)
276 }
277
278 fn try_prove_condition_group(
280 &mut self,
281 group: &crate::engine::rule::ConditionGroup,
282 facts: &mut Facts,
283 kb: &KnowledgeBase,
284 depth: usize,
285 ) -> bool {
286 use crate::engine::rule::ConditionGroup;
287
288 match group {
289 ConditionGroup::Single(condition) => {
290 self.try_prove_single_condition(condition, facts, kb, depth)
292 }
293 ConditionGroup::Compound { left, operator, right } => {
294 use crate::types::LogicalOperator;
296 match operator {
297 LogicalOperator::And => {
298 self.try_prove_condition_group(left, facts, kb, depth)
300 && self.try_prove_condition_group(right, facts, kb, depth)
301 }
302 LogicalOperator::Or => {
303 self.try_prove_condition_group(left, facts, kb, depth)
305 || self.try_prove_condition_group(right, facts, kb, depth)
306 }
307 LogicalOperator::Not => {
308 !self.try_prove_condition_group(left, facts, kb, depth)
310 }
311 }
312 }
313 ConditionGroup::Not(_) | ConditionGroup::Exists(_) | ConditionGroup::Forall(_) | ConditionGroup::Accumulate { .. } => {
314 true
316 }
317 }
318 }
319
320 fn try_prove_single_condition(
322 &mut self,
323 condition: &crate::engine::rule::Condition,
324 facts: &mut Facts,
325 kb: &KnowledgeBase,
326 depth: usize,
327 ) -> bool {
328 let goal_pattern = self.condition_to_goal_pattern(condition);
330
331 let mut sub_goal = Goal::new(goal_pattern.clone());
333 sub_goal.depth = depth;
334
335 for candidate_rule in kb.get_rules() {
337 if self.rule_could_prove_pattern(&candidate_rule, &goal_pattern) {
338 sub_goal.add_candidate_rule(candidate_rule.name.clone());
339 }
340 }
341
342 self.search_recursive_with_execution(&mut sub_goal, facts, kb, depth)
344 }
345
346 fn condition_to_goal_pattern(&self, condition: &crate::engine::rule::Condition) -> String {
348 use crate::engine::rule::ConditionExpression;
349
350 let field = match &condition.expression {
351 ConditionExpression::Field(f) => f.clone(),
352 ConditionExpression::FunctionCall { name, .. } => name.clone(),
353 ConditionExpression::Test { name, .. } => format!("test({})", name),
354 ConditionExpression::MultiField { field, .. } => field.clone(),
355 };
356
357 let op_str = match condition.operator {
358 crate::types::Operator::Equal => "==",
359 crate::types::Operator::NotEqual => "!=",
360 crate::types::Operator::GreaterThan => ">",
361 crate::types::Operator::LessThan => "<",
362 crate::types::Operator::GreaterThanOrEqual => ">=",
363 crate::types::Operator::LessThanOrEqual => "<=",
364 crate::types::Operator::Contains => "contains",
365 crate::types::Operator::NotContains => "not_contains",
366 crate::types::Operator::StartsWith => "starts_with",
367 crate::types::Operator::EndsWith => "ends_with",
368 crate::types::Operator::Matches => "matches",
369 };
370
371 let value_str = format!("{:?}", condition.value);
372
373 format!("{} {} {}", field, op_str, value_str)
374 }
375
376 fn rule_could_prove_pattern(&self, rule: &Rule, pattern: &str) -> bool {
378 for action in &rule.actions {
380 match action {
381 crate::types::ActionType::Set { field, .. } => {
382 if pattern.contains(field) {
383 return true;
384 }
385 }
386 crate::types::ActionType::MethodCall { object, method, .. } => {
387 if pattern.contains(object) || pattern.contains(method) {
388 return true;
389 }
390 }
391 _ => {}
392 }
393 }
394 false
395 }
396
397 fn search_recursive(&mut self, goal: &mut Goal, depth: usize) -> bool {
399 self.goals_explored += 1;
400
401 if depth > self.max_depth {
403 goal.status = GoalStatus::Unprovable;
404 return false;
405 }
406
407 if goal.status == GoalStatus::InProgress {
409 goal.status = GoalStatus::Unprovable;
410 return false;
411 }
412
413 goal.status = GoalStatus::InProgress;
415 goal.depth = depth;
416
417 for rule_name in goal.candidate_rules.clone() {
419 self.path.push(rule_name.clone());
420
421 goal.status = GoalStatus::Proven;
435 return true;
436 }
437
438 for sub_goal in &mut goal.sub_goals {
440 if !self.search_recursive(sub_goal, depth + 1) {
441 goal.status = GoalStatus::Unprovable;
442 return false;
443 }
444 }
445
446 if goal.sub_goals.is_empty() && goal.candidate_rules.is_empty() {
448 goal.status = GoalStatus::Unprovable;
449 return false;
450 }
451
452 goal.status = GoalStatus::Proven;
453 true
454 }
455}
456
457pub struct BreadthFirstSearch {
459 max_depth: usize,
460 goals_explored: usize,
461 executor: RuleExecutor,
462}
463
464impl BreadthFirstSearch {
465 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
467 Self {
468 max_depth,
469 goals_explored: 0,
470 executor: RuleExecutor::new(kb),
471 }
472 }
473
474 pub fn search_with_execution(&mut self, root_goal: &mut Goal, facts: &mut Facts, kb: &KnowledgeBase) -> SearchResult {
476 self.goals_explored = 0;
477 let mut queue = VecDeque::new();
478 let mut path = Vec::new();
479 let mut max_depth = 0;
480
481 queue.push_back((root_goal as *mut Goal, 0));
482
483 while let Some((goal_ptr, depth)) = queue.pop_front() {
484 let goal = unsafe { &mut *goal_ptr };
486
487 self.goals_explored += 1;
488 max_depth = max_depth.max(depth);
489
490 if depth > self.max_depth {
491 continue;
492 }
493
494 goal.depth = depth;
495
496 if self.check_goal_in_facts(goal, facts) {
498 goal.status = GoalStatus::Proven;
499 continue;
500 }
501
502 for rule_name in goal.candidate_rules.clone() {
504 path.push(rule_name.clone());
505
506 if let Some(rule) = kb.get_rule(&rule_name) {
508 match self.executor.try_execute_rule(&rule, facts) {
510 Ok(true) => {
511 if self.check_goal_in_facts(goal, facts) {
514 goal.status = GoalStatus::Proven;
515 break;
516 }
517 }
518 Ok(false) => {
519 }
521 Err(_) => {
522 }
524 }
525 }
526 }
527
528 for sub_goal in &mut goal.sub_goals {
530 queue.push_back((sub_goal as *mut Goal, depth + 1));
531 }
532 }
533
534 let success = root_goal.is_proven();
535
536 SearchResult {
537 success,
538 path,
539 goals_explored: self.goals_explored,
540 max_depth_reached: max_depth,
541 bindings: root_goal.bindings.to_map(),
542 }
543 }
544
545 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
547 let pattern = &goal.pattern;
548
549 if let Some(eq_pos) = pattern.find("==") {
550 let field = pattern[..eq_pos].trim();
551 let expected = pattern[eq_pos + 2..].trim();
552
553 if let Some(actual) = facts.get(field) {
554 return self.value_matches(&actual, expected);
555 }
556 return false;
557 }
558
559 if let Some(ne_pos) = pattern.find("!=") {
560 let field = pattern[..ne_pos].trim();
561 let not_expected = pattern[ne_pos + 2..].trim();
562
563 if let Some(actual) = facts.get(field) {
564 return !self.value_matches(&actual, not_expected);
565 }
566 return true;
567 }
568
569 false
570 }
571
572 fn value_matches(&self, value: &Value, expected: &str) -> bool {
574 match value {
575 Value::Boolean(b) => {
576 expected == "true" && *b || expected == "false" && !*b
577 }
578 Value::String(s) => {
579 s == expected || s == expected.trim_matches('"')
580 }
581 Value::Number(n) => {
582 expected.parse::<f64>().map(|e| (n - e).abs() < 0.0001).unwrap_or(false)
583 }
584 _ => false,
585 }
586 }
587
588 fn check_rule_conditions(&self, rule: &Rule, facts: &Facts) -> bool {
590 self.executor.evaluate_conditions(&rule.conditions, facts).unwrap_or(false)
592 }
593
594 pub fn search(&mut self, root_goal: &mut Goal, _facts: &Facts) -> SearchResult {
596 self.goals_explored = 0;
597 let mut queue = VecDeque::new();
598 let mut path = Vec::new();
599 let mut max_depth = 0;
600
601 queue.push_back((root_goal as *mut Goal, 0));
602
603 while let Some((goal_ptr, depth)) = queue.pop_front() {
604 let goal = unsafe { &mut *goal_ptr };
606
607 self.goals_explored += 1;
608 max_depth = max_depth.max(depth);
609
610 if depth > self.max_depth {
611 continue;
612 }
613
614 goal.depth = depth;
615
616 for rule_name in &goal.candidate_rules {
618 path.push(rule_name.clone());
619 }
620
621 for sub_goal in &mut goal.sub_goals {
623 queue.push_back((sub_goal as *mut Goal, depth + 1));
624 }
625
626 if !goal.candidate_rules.is_empty() || goal.all_subgoals_proven() {
628 goal.status = GoalStatus::Proven;
629 }
630 }
631
632 let success = root_goal.is_proven();
633
634 SearchResult {
635 success,
636 path,
637 goals_explored: self.goals_explored,
638 max_depth_reached: max_depth,
639 bindings: root_goal.bindings.to_map(),
640 }
641 }
642}
643
644#[cfg(test)]
645mod tests {
646 use super::*;
647
648 #[test]
649 fn test_search_strategies() {
650 assert_eq!(SearchStrategy::DepthFirst, SearchStrategy::DepthFirst);
651 assert_ne!(SearchStrategy::DepthFirst, SearchStrategy::BreadthFirst);
652 }
653
654 #[test]
655 fn test_search_result_creation() {
656 let success = SearchResult::success(vec!["Rule1".to_string()], 5, 3);
657 assert!(success.success);
658 assert_eq!(success.path.len(), 1);
659 assert_eq!(success.goals_explored, 5);
660
661 let failure = SearchResult::failure(10, 5);
662 assert!(!failure.success);
663 assert!(failure.path.is_empty());
664 }
665
666 #[test]
667 fn test_depth_first_search_creation() {
668 let kb = KnowledgeBase::new("test");
669 let dfs = DepthFirstSearch::new(10, kb);
670 assert_eq!(dfs.max_depth, 10);
671 assert_eq!(dfs.goals_explored, 0);
672 }
673
674 #[test]
675 fn test_depth_first_search_simple() {
676 let kb = KnowledgeBase::new("test");
677 let mut dfs = DepthFirstSearch::new(10, kb);
678 let facts = Facts::new();
679
680 let mut goal = Goal::new("test".to_string());
681 goal.add_candidate_rule("TestRule".to_string());
682
683 let result = dfs.search(&mut goal, &facts);
684
685 assert!(result.success);
686 assert!(goal.is_proven());
687 assert!(result.goals_explored > 0);
688 }
689
690 #[test]
691 fn test_breadth_first_search() {
692 let kb = KnowledgeBase::new("test");
693 let mut bfs = BreadthFirstSearch::new(10, kb);
694 let facts = Facts::new();
695
696 let mut goal = Goal::new("test".to_string());
697 goal.add_candidate_rule("TestRule".to_string());
698
699 let result = bfs.search(&mut goal, &facts);
700
701 assert!(result.success);
702 assert_eq!(result.goals_explored, 1);
703 }
704}