1#![allow(deprecated)]
4
5use super::goal::{Goal, GoalStatus};
6use super::rule_executor::RuleExecutor;
7use crate::engine::rule::Rule;
8use crate::rete::propagation::IncrementalEngine;
9use crate::types::Value;
10use crate::Facts;
11use crate::KnowledgeBase;
12use std::collections::VecDeque;
13use std::sync::{Arc, Mutex};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum SearchStrategy {
18 DepthFirst,
21
22 BreadthFirst,
25
26 Iterative,
29}
30
31#[derive(Debug, Clone)]
33pub struct Solution {
34 pub path: Vec<String>,
36
37 pub bindings: std::collections::HashMap<String, Value>,
39}
40
41#[derive(Debug)]
43pub struct SearchResult {
44 pub success: bool,
46
47 pub path: Vec<String>,
49
50 pub goals_explored: usize,
52
53 pub max_depth_reached: usize,
55
56 pub bindings: std::collections::HashMap<String, Value>,
58
59 pub solutions: Vec<Solution>,
61}
62
63impl SearchResult {
64 pub fn success(path: Vec<String>, goals_explored: usize, max_depth: usize) -> Self {
66 Self {
67 success: true,
68 path,
69 goals_explored,
70 max_depth_reached: max_depth,
71 bindings: std::collections::HashMap::new(),
72 solutions: Vec::new(),
73 }
74 }
75
76 pub fn failure(goals_explored: usize, max_depth: usize) -> Self {
78 Self {
79 success: false,
80 path: Vec::new(),
81 goals_explored,
82 max_depth_reached: max_depth,
83 bindings: std::collections::HashMap::new(),
84 solutions: Vec::new(),
85 }
86 }
87}
88
89pub struct DepthFirstSearch {
91 max_depth: usize,
92 goals_explored: usize,
93 path: Vec<String>,
94 executor: RuleExecutor,
95 max_solutions: usize,
96 solutions: Vec<Solution>,
97}
98
99impl DepthFirstSearch {
100 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
102 Self {
103 max_depth,
104 goals_explored: 0,
105 path: Vec::new(),
106 executor: RuleExecutor::new_with_inserter(kb, None),
107 max_solutions: 1,
108 solutions: Vec::new(),
109 }
110 }
111
112 pub fn with_max_solutions(mut self, max_solutions: usize) -> Self {
114 self.max_solutions = max_solutions;
115 self
116 }
117
118 pub fn new_with_engine(
122 max_depth: usize,
123 kb: KnowledgeBase,
124 engine: Option<Arc<Mutex<IncrementalEngine>>>,
125 ) -> Self {
126 let inserter = engine.map(|eng| {
128 let eng = eng.clone();
129 std::sync::Arc::new(
130 move |fact_type: String,
131 data: crate::rete::TypedFacts,
132 rule_name: String,
133 premises: Vec<String>| {
134 if let Ok(mut e) = eng.lock() {
135 let handles = e.resolve_premise_keys(premises);
137 let _ = e.insert_logical(fact_type, data, rule_name, handles);
138 }
139 },
140 )
141 as std::sync::Arc<
142 dyn Fn(String, crate::rete::TypedFacts, String, Vec<String>) + Send + Sync,
143 >
144 });
145
146 Self {
147 max_depth,
148 goals_explored: 0,
149 path: Vec::new(),
150 executor: RuleExecutor::new_with_inserter(kb, inserter),
151 max_solutions: 1,
152 solutions: Vec::new(),
153 }
154 }
155
156 pub fn search_with_execution(
158 &mut self,
159 goal: &mut Goal,
160 facts: &mut Facts,
161 kb: &KnowledgeBase,
162 ) -> SearchResult {
163 self.goals_explored = 0;
164 self.path.clear();
165 self.solutions.clear();
166
167 let success = self.search_recursive_with_execution(goal, facts, kb, 0);
168
169 SearchResult {
170 success,
171 path: self.path.clone(),
172 goals_explored: self.goals_explored,
173 max_depth_reached: goal.depth,
174 bindings: goal.bindings.to_map(),
175 solutions: self.solutions.clone(),
176 }
177 }
178
179 pub fn search(&mut self, goal: &mut Goal, _facts: &Facts) -> SearchResult {
181 self.goals_explored = 0;
182 self.path.clear();
183
184 let success = self.search_recursive(goal, 0);
185
186 SearchResult {
187 success,
188 path: self.path.clone(),
189 goals_explored: self.goals_explored,
190 max_depth_reached: goal.depth,
191 bindings: goal.bindings.to_map(),
192 solutions: Vec::new(),
193 }
194 }
195
196 fn search_recursive_with_execution(
198 &mut self,
199 goal: &mut Goal,
200 facts: &mut Facts, kb: &KnowledgeBase,
202 depth: usize,
203 ) -> bool {
204 self.goals_explored += 1;
205
206 if depth > self.max_depth {
208 goal.status = GoalStatus::Unprovable;
209 return false;
210 }
211
212 let fact_proven = self.check_goal_in_facts(goal, facts);
214
215 if goal.is_negated {
217 if fact_proven {
219 goal.status = GoalStatus::Unprovable;
220 return false; }
222 } else {
225 if fact_proven {
227 goal.status = GoalStatus::Proven;
228 return true;
229 }
230 }
231
232 if goal.status == GoalStatus::InProgress {
234 goal.status = GoalStatus::Unprovable;
235 return false;
236 }
237
238 goal.status = GoalStatus::InProgress;
239 goal.depth = depth;
240
241 for rule_name in goal.candidate_rules.clone() {
243 self.path.push(rule_name.clone());
244
245 facts.begin_undo_frame();
248
249 if let Some(rule) = kb.get_rule(&rule_name) {
251 match self.executor.try_execute_rule(&rule, facts) {
253 Ok(true) => {
254 if self.check_goal_in_facts(goal, facts) {
257 goal.status = GoalStatus::Proven;
258
259 self.solutions.push(Solution {
261 path: self.path.clone(),
262 bindings: goal.bindings.to_map(),
263 });
264
265 if self.max_solutions == 1 || self.solutions.len() >= self.max_solutions
267 {
268 return true; }
270
271 facts.rollback_undo_frame();
274 self.path.pop();
275 continue;
276 }
277 }
279 Ok(false) => {
280 if self.try_prove_rule_conditions(&rule, facts, kb, depth + 1) {
282 match self.executor.try_execute_rule(&rule, facts) {
284 Ok(true) => {
285 if self.check_goal_in_facts(goal, facts) {
286 goal.status = GoalStatus::Proven;
287
288 self.solutions.push(Solution {
290 path: self.path.clone(),
291 bindings: goal.bindings.to_map(),
292 });
293
294 if self.max_solutions == 1
296 || self.solutions.len() >= self.max_solutions
297 {
298 return true; }
300
301 facts.rollback_undo_frame();
303 self.path.pop();
304 continue;
305 }
306 }
307 _ => {
308 }
310 }
311 }
312 }
313 Err(_) => {
314 }
316 }
317 }
318
319 facts.rollback_undo_frame();
321 self.path.pop();
322 }
323
324 let mut all_subgoals_proven = true;
327 if !goal.sub_goals.is_empty() {
328 facts.begin_undo_frame();
329 for sub_goal in &mut goal.sub_goals {
330 if !self.search_recursive_with_execution(sub_goal, facts, kb, depth + 1) {
331 all_subgoals_proven = false;
332 break;
333 }
334 }
335
336 if all_subgoals_proven {
337 facts.commit_undo_frame();
339 goal.status = GoalStatus::Proven;
340 return true;
341 }
342
343 facts.rollback_undo_frame();
345 }
346
347 if !self.solutions.is_empty() {
349 goal.status = GoalStatus::Proven;
350 return !goal.is_negated;
352 }
353
354 if goal.is_negated {
356 goal.status = GoalStatus::Proven;
358 true
359 } else {
360 goal.status = GoalStatus::Unprovable;
362 false
363 }
364 }
365
366 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
370 if goal.is_negated {
372 if let Some(ref expr) = goal.expression {
373 match expr.evaluate(facts) {
375 Ok(Value::Boolean(b)) => return b,
376 Ok(_) => return false, Err(_) => return false,
378 }
379 }
380 return false;
381 }
382
383 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
385 self.executor
387 .evaluate_condition(&condition, facts)
388 .unwrap_or(false)
389 } else {
390 false
391 }
392 }
393
394 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
400 use crate::engine::rule::{Condition, ConditionExpression};
401 use crate::types::Operator;
402
403 let operators = [
405 (">=", Operator::GreaterThanOrEqual),
406 ("<=", Operator::LessThanOrEqual),
407 ("==", Operator::Equal),
408 ("!=", Operator::NotEqual),
409 (" > ", Operator::GreaterThan),
410 (" < ", Operator::LessThan),
411 (" contains ", Operator::Contains),
412 (" not_contains ", Operator::NotContains),
413 (" starts_with ", Operator::StartsWith),
414 (" startsWith ", Operator::StartsWith),
415 (" ends_with ", Operator::EndsWith),
416 (" endsWith ", Operator::EndsWith),
417 (" matches ", Operator::Matches),
418 ];
419
420 for (op_str, operator) in operators {
421 if let Some(pos) = pattern.find(op_str) {
422 let field = pattern[..pos].trim().to_string();
423 let value_str = pattern[pos + op_str.len()..].trim();
424
425 let value = self.parse_value_string(value_str);
427
428 return Some(Condition {
429 field: field.clone(),
430 expression: ConditionExpression::Field(field),
431 operator,
432 value,
433 });
434 }
435 }
436
437 None
438 }
439
440 fn parse_value_string(&self, s: &str) -> Value {
442 let s = s.trim();
443
444 if s == "true" {
446 return Value::Boolean(true);
447 }
448 if s == "false" {
449 return Value::Boolean(false);
450 }
451
452 if s == "null" {
454 return Value::Null;
455 }
456
457 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
459 return Value::String(s[1..s.len() - 1].to_string());
460 }
461
462 if let Ok(n) = s.parse::<f64>() {
464 return Value::Number(n);
465 }
466
467 if let Ok(i) = s.parse::<i64>() {
469 return Value::Integer(i);
470 }
471
472 Value::String(s.to_string())
474 }
475
476 fn try_prove_rule_conditions(
479 &mut self,
480 rule: &Rule,
481 facts: &mut Facts,
482 kb: &KnowledgeBase,
483 depth: usize,
484 ) -> bool {
485 self.try_prove_condition_group(&rule.conditions, facts, kb, depth)
487 }
488
489 fn try_prove_condition_group(
491 &mut self,
492 group: &crate::engine::rule::ConditionGroup,
493 facts: &mut Facts,
494 kb: &KnowledgeBase,
495 depth: usize,
496 ) -> bool {
497 use crate::engine::rule::ConditionGroup;
498
499 match group {
500 ConditionGroup::Single(condition) => {
501 self.try_prove_single_condition(condition, facts, kb, depth)
503 }
504 ConditionGroup::Compound {
505 left,
506 operator,
507 right,
508 } => {
509 use crate::types::LogicalOperator;
511 match operator {
512 LogicalOperator::And => {
513 self.try_prove_condition_group(left, facts, kb, depth)
515 && self.try_prove_condition_group(right, facts, kb, depth)
516 }
517 LogicalOperator::Or => {
518 self.try_prove_condition_group(left, facts, kb, depth)
520 || self.try_prove_condition_group(right, facts, kb, depth)
521 }
522 LogicalOperator::Not => {
523 !self.try_prove_condition_group(left, facts, kb, depth)
525 }
526 }
527 }
528 ConditionGroup::Not(_)
529 | ConditionGroup::Exists(_)
530 | ConditionGroup::Forall(_)
531 | ConditionGroup::Accumulate { .. } => {
532 self.executor
536 .evaluate_conditions(group, facts)
537 .unwrap_or(false)
538 }
539 #[cfg(feature = "streaming")]
540 ConditionGroup::StreamPattern { .. } => {
541 self.executor
543 .evaluate_conditions(group, facts)
544 .unwrap_or(false)
545 }
546 }
547 }
548
549 fn try_prove_single_condition(
551 &mut self,
552 condition: &crate::engine::rule::Condition,
553 facts: &mut Facts,
554 kb: &KnowledgeBase,
555 depth: usize,
556 ) -> bool {
557 if let Ok(satisfied) = self.executor.evaluate_condition(condition, facts) {
559 if satisfied {
560 return true;
561 }
562 }
563
564 let goal_pattern = self.condition_to_goal_pattern(condition);
566
567 let mut sub_goal = Goal::new(goal_pattern.clone());
569 sub_goal.depth = depth;
570
571 for candidate_rule in kb.get_rules() {
573 if self.rule_could_prove_pattern(&candidate_rule, &goal_pattern) {
574 sub_goal.add_candidate_rule(candidate_rule.name.clone());
575 }
576 }
577
578 self.search_recursive_with_execution(&mut sub_goal, facts, kb, depth)
580 }
581
582 fn condition_to_goal_pattern(&self, condition: &crate::engine::rule::Condition) -> String {
584 use crate::engine::rule::ConditionExpression;
585
586 let field = match &condition.expression {
587 ConditionExpression::Field(f) => f.clone(),
588 ConditionExpression::FunctionCall { name, .. } => name.clone(),
589 ConditionExpression::Test { name, .. } => format!("test({})", name),
590 ConditionExpression::MultiField { field, .. } => field.clone(),
591 };
592
593 let op_str = match condition.operator {
594 crate::types::Operator::Equal => "==",
595 crate::types::Operator::NotEqual => "!=",
596 crate::types::Operator::GreaterThan => ">",
597 crate::types::Operator::LessThan => "<",
598 crate::types::Operator::GreaterThanOrEqual => ">=",
599 crate::types::Operator::LessThanOrEqual => "<=",
600 crate::types::Operator::Contains => "contains",
601 crate::types::Operator::NotContains => "not_contains",
602 crate::types::Operator::StartsWith => "starts_with",
603 crate::types::Operator::EndsWith => "ends_with",
604 crate::types::Operator::Matches => "matches",
605 };
606
607 let value_str = match &condition.value {
609 Value::Boolean(b) => b.to_string(),
610 Value::Number(n) => n.to_string(),
611 Value::Integer(i) => i.to_string(),
612 Value::String(s) => format!("\"{}\"", s),
613 Value::Null => "null".to_string(),
614 _ => format!("{:?}", condition.value),
615 };
616
617 format!("{} {} {}", field, op_str, value_str)
618 }
619
620 fn rule_could_prove_pattern(&self, rule: &Rule, pattern: &str) -> bool {
622 for action in &rule.actions {
624 match action {
625 crate::types::ActionType::Set { field, .. } => {
626 if pattern.contains(field) {
627 return true;
628 }
629 }
630 crate::types::ActionType::MethodCall { object, method, .. } => {
631 if pattern.contains(object) || pattern.contains(method) {
632 return true;
633 }
634 }
635 _ => {}
636 }
637 }
638 false
639 }
640
641 fn search_recursive(&mut self, goal: &mut Goal, depth: usize) -> bool {
643 self.goals_explored += 1;
644
645 if depth > self.max_depth {
647 goal.status = GoalStatus::Unprovable;
648 return false;
649 }
650
651 if goal.status == GoalStatus::InProgress {
653 goal.status = GoalStatus::Unprovable;
654 return false;
655 }
656
657 goal.status = GoalStatus::InProgress;
659 goal.depth = depth;
660
661 if let Some(rule_name) = goal.candidate_rules.clone().into_iter().next() {
663 self.path.push(rule_name.clone());
664
665 goal.status = GoalStatus::Proven;
679 return true;
680 }
681
682 for sub_goal in &mut goal.sub_goals {
684 if !self.search_recursive(sub_goal, depth + 1) {
685 goal.status = GoalStatus::Unprovable;
686 return false;
687 }
688 }
689
690 if goal.sub_goals.is_empty() && goal.candidate_rules.is_empty() {
692 goal.status = GoalStatus::Unprovable;
693 return false;
694 }
695
696 goal.status = GoalStatus::Proven;
697 true
698 }
699}
700
701pub struct BreadthFirstSearch {
703 max_depth: usize,
704 goals_explored: usize,
705 executor: RuleExecutor,
706}
707
708pub struct IterativeDeepeningSearch {
710 max_depth: usize,
711 goals_explored: usize,
712 kb: KnowledgeBase,
713 engine: Option<Arc<Mutex<IncrementalEngine>>>,
714}
715
716impl IterativeDeepeningSearch {
717 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
719 Self {
720 max_depth,
721 goals_explored: 0,
722 kb,
723 engine: None,
724 }
725 }
726
727 pub fn new_with_engine(
729 max_depth: usize,
730 kb: KnowledgeBase,
731 engine: Option<Arc<Mutex<IncrementalEngine>>>,
732 ) -> Self {
733 Self {
735 max_depth,
736 goals_explored: 0,
737 kb,
738 engine,
739 }
740 }
741
742 pub fn search_with_execution(
745 &mut self,
746 root_goal: &mut Goal,
747 facts: &mut Facts,
748 kb: &KnowledgeBase,
749 ) -> SearchResult {
750 self.goals_explored = 0;
751 let mut cumulative_goals = 0usize;
752
753 for depth_limit in 0..=self.max_depth {
755 let mut probe_goal = root_goal.clone();
757 let probe_kb = self.kb.clone();
758 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
759 let probe_result = probe_dfs.search(&mut probe_goal, facts);
760 cumulative_goals += probe_result.goals_explored;
761
762 if probe_result.success {
763 let exec_kb = self.kb.clone();
765 let mut exec_dfs =
766 DepthFirstSearch::new_with_engine(depth_limit, exec_kb, self.engine.clone());
767 let exec_result = exec_dfs.search_with_execution(root_goal, facts, kb);
768 let mut final_result = exec_result;
770 final_result.goals_explored += cumulative_goals - final_result.goals_explored;
771 return final_result;
772 }
773 }
774
775 SearchResult::failure(cumulative_goals, self.max_depth)
777 }
778
779 pub fn search(&mut self, root_goal: &mut Goal, facts: &Facts) -> SearchResult {
781 self.goals_explored = 0;
782 let mut cumulative_goals = 0usize;
783
784 for depth_limit in 0..=self.max_depth {
785 let mut probe_goal = root_goal.clone();
786 let probe_kb = self.kb.clone();
787 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
788 let probe_result = probe_dfs.search(&mut probe_goal, facts);
789 cumulative_goals += probe_result.goals_explored;
790 if probe_result.success {
791 let mut res = probe_result;
793 res.goals_explored = cumulative_goals;
794 return res;
795 }
796 }
797
798 SearchResult::failure(cumulative_goals, self.max_depth)
799 }
800}
801
802impl BreadthFirstSearch {
803 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
805 Self {
806 max_depth,
807 goals_explored: 0,
808 executor: RuleExecutor::new_with_inserter(kb, None),
809 }
810 }
811
812 pub fn new_with_engine(
814 max_depth: usize,
815 kb: KnowledgeBase,
816 engine: Option<Arc<Mutex<IncrementalEngine>>>,
817 ) -> Self {
818 let inserter = engine.map(|eng| {
820 let eng = eng.clone();
821 std::sync::Arc::new(
822 move |fact_type: String,
823 data: crate::rete::TypedFacts,
824 rule_name: String,
825 _premises: Vec<String>| {
826 if let Ok(mut e) = eng.lock() {
827 let _ = e.insert_logical(fact_type, data, rule_name, Vec::new());
828 }
829 },
830 )
831 as std::sync::Arc<
832 dyn Fn(String, crate::rete::TypedFacts, String, Vec<String>) + Send + Sync,
833 >
834 });
835
836 Self {
837 max_depth,
838 goals_explored: 0,
839 executor: RuleExecutor::new_with_inserter(kb, inserter),
840 }
841 }
842
843 pub fn search_with_execution(
845 &mut self,
846 root_goal: &mut Goal,
847 facts: &mut Facts,
848 kb: &KnowledgeBase,
849 ) -> SearchResult {
850 self.goals_explored = 0;
851 let mut queue = VecDeque::new();
852 let mut path = Vec::new();
853 let mut max_depth = 0;
854
855 queue.push_back((root_goal as *mut Goal, 0));
856
857 while let Some((goal_ptr, depth)) = queue.pop_front() {
858 let goal = unsafe { &mut *goal_ptr };
860
861 self.goals_explored += 1;
862 max_depth = max_depth.max(depth);
863
864 if depth > self.max_depth {
865 continue;
866 }
867
868 goal.depth = depth;
869
870 if self.check_goal_in_facts(goal, facts) {
872 goal.status = GoalStatus::Proven;
873 continue;
874 }
875
876 for rule_name in goal.candidate_rules.clone() {
878 path.push(rule_name.clone());
879
880 if let Some(rule) = kb.get_rule(&rule_name) {
882 match self.executor.try_execute_rule(&rule, facts) {
884 Ok(true) => {
885 if self.check_goal_in_facts(goal, facts) {
888 goal.status = GoalStatus::Proven;
889 break;
890 }
891 }
892 Ok(false) => {
893 }
895 Err(_) => {
896 }
898 }
899 }
900 }
901
902 for sub_goal in &mut goal.sub_goals {
904 queue.push_back((sub_goal as *mut Goal, depth + 1));
905 }
906 }
907
908 let success = root_goal.is_proven();
909
910 SearchResult {
911 success,
912 path,
913 goals_explored: self.goals_explored,
914 max_depth_reached: max_depth,
915 bindings: root_goal.bindings.to_map(),
916 solutions: Vec::new(),
917 }
918 }
919
920 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
924 if goal.is_negated {
926 if let Some(ref expr) = goal.expression {
927 match expr.evaluate(facts) {
929 Ok(Value::Boolean(b)) => return b,
930 Ok(_) => return false, Err(_) => return false,
932 }
933 }
934 return false;
935 }
936
937 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
939 self.executor
941 .evaluate_condition(&condition, facts)
942 .unwrap_or(false)
943 } else {
944 false
945 }
946 }
947
948 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
954 use crate::engine::rule::{Condition, ConditionExpression};
955 use crate::types::Operator;
956
957 let operators = [
959 (">=", Operator::GreaterThanOrEqual),
960 ("<=", Operator::LessThanOrEqual),
961 ("==", Operator::Equal),
962 ("!=", Operator::NotEqual),
963 (" > ", Operator::GreaterThan),
964 (" < ", Operator::LessThan),
965 (" contains ", Operator::Contains),
966 (" not_contains ", Operator::NotContains),
967 (" starts_with ", Operator::StartsWith),
968 (" startsWith ", Operator::StartsWith),
969 (" ends_with ", Operator::EndsWith),
970 (" endsWith ", Operator::EndsWith),
971 (" matches ", Operator::Matches),
972 ];
973
974 for (op_str, operator) in operators {
975 if let Some(pos) = pattern.find(op_str) {
976 let field = pattern[..pos].trim().to_string();
977 let value_str = pattern[pos + op_str.len()..].trim();
978
979 let value = self.parse_value_string(value_str);
981
982 return Some(Condition {
983 field: field.clone(),
984 expression: ConditionExpression::Field(field),
985 operator,
986 value,
987 });
988 }
989 }
990
991 None
992 }
993
994 fn parse_value_string(&self, s: &str) -> Value {
996 let s = s.trim();
997
998 if s == "true" {
1000 return Value::Boolean(true);
1001 }
1002 if s == "false" {
1003 return Value::Boolean(false);
1004 }
1005
1006 if s == "null" {
1008 return Value::Null;
1009 }
1010
1011 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
1013 return Value::String(s[1..s.len() - 1].to_string());
1014 }
1015
1016 if let Ok(n) = s.parse::<f64>() {
1018 return Value::Number(n);
1019 }
1020
1021 if let Ok(i) = s.parse::<i64>() {
1023 return Value::Integer(i);
1024 }
1025
1026 Value::String(s.to_string())
1028 }
1029
1030 pub fn search(&mut self, root_goal: &mut Goal, _facts: &Facts) -> SearchResult {
1032 self.goals_explored = 0;
1033 let mut queue = VecDeque::new();
1034 let mut path = Vec::new();
1035 let mut max_depth = 0;
1036
1037 queue.push_back((root_goal as *mut Goal, 0));
1038
1039 while let Some((goal_ptr, depth)) = queue.pop_front() {
1040 let goal = unsafe { &mut *goal_ptr };
1042
1043 self.goals_explored += 1;
1044 max_depth = max_depth.max(depth);
1045
1046 if depth > self.max_depth {
1047 continue;
1048 }
1049
1050 goal.depth = depth;
1051
1052 for rule_name in &goal.candidate_rules {
1054 path.push(rule_name.clone());
1055 }
1056
1057 for sub_goal in &mut goal.sub_goals {
1059 queue.push_back((sub_goal as *mut Goal, depth + 1));
1060 }
1061
1062 if !goal.candidate_rules.is_empty() || goal.all_subgoals_proven() {
1064 goal.status = GoalStatus::Proven;
1065 }
1066 }
1067
1068 let success = root_goal.is_proven();
1069
1070 SearchResult {
1071 success,
1072 path,
1073 goals_explored: self.goals_explored,
1074 max_depth_reached: max_depth,
1075 bindings: root_goal.bindings.to_map(),
1076 solutions: Vec::new(),
1077 }
1078 }
1079}
1080
1081#[cfg(test)]
1082mod tests {
1083 use super::*;
1084 use std::collections::HashMap;
1085
1086 #[test]
1087 fn test_search_strategies() {
1088 assert_eq!(SearchStrategy::DepthFirst, SearchStrategy::DepthFirst);
1089 assert_ne!(SearchStrategy::DepthFirst, SearchStrategy::BreadthFirst);
1090 }
1091
1092 #[test]
1093 fn test_search_result_creation() {
1094 let success = SearchResult::success(vec!["Rule1".to_string()], 5, 3);
1095 assert!(success.success);
1096 assert_eq!(success.path.len(), 1);
1097 assert_eq!(success.goals_explored, 5);
1098
1099 let failure = SearchResult::failure(10, 5);
1100 assert!(!failure.success);
1101 assert!(failure.path.is_empty());
1102 }
1103
1104 #[test]
1105 fn test_depth_first_search_creation() {
1106 let kb = KnowledgeBase::new("test");
1107 let dfs = DepthFirstSearch::new(10, kb);
1108 assert_eq!(dfs.max_depth, 10);
1109 assert_eq!(dfs.goals_explored, 0);
1110 }
1111
1112 #[test]
1113 fn test_depth_first_search_simple() {
1114 let kb = KnowledgeBase::new("test");
1115 let mut dfs = DepthFirstSearch::new(10, kb);
1116 let facts = Facts::new();
1117
1118 let mut goal = Goal::new("test".to_string());
1119 goal.add_candidate_rule("TestRule".to_string());
1120
1121 let result = dfs.search(&mut goal, &facts);
1122
1123 assert!(result.success);
1124 assert!(goal.is_proven());
1125 assert!(result.goals_explored > 0);
1126 }
1127
1128 #[test]
1129 fn test_breadth_first_search() {
1130 let kb = KnowledgeBase::new("test");
1131 let mut bfs = BreadthFirstSearch::new(10, kb);
1132 let facts = Facts::new();
1133
1134 let mut goal = Goal::new("test".to_string());
1135 goal.add_candidate_rule("TestRule".to_string());
1136
1137 let result = bfs.search(&mut goal, &facts);
1138
1139 assert!(result.success);
1140 assert_eq!(result.goals_explored, 1);
1141 }
1142
1143 #[test]
1144 fn test_iterative_deepening_search_success() {
1145 let kb = KnowledgeBase::new("test");
1146 let mut ids = IterativeDeepeningSearch::new(5, kb.clone());
1147 let mut root = Goal::new("test".to_string());
1148 root.add_candidate_rule("TestRule".to_string());
1149
1150 let facts = Facts::new();
1152 let res = ids.search(&mut root, &facts);
1153 assert!(res.success);
1154 }
1155
1156 #[test]
1157 fn test_iterative_deepening_search_depth_limit() {
1158 let kb = KnowledgeBase::new("test");
1159 let mut ids = IterativeDeepeningSearch::new(0, kb.clone());
1161 let mut root = Goal::new("test".to_string());
1162 let mut sub = Goal::new("sub".to_string());
1164 sub.add_candidate_rule("SubRule".to_string());
1165 root.sub_goals.push(sub);
1166
1167 let facts = Facts::new();
1168 let res = ids.search(&mut root, &facts);
1169 assert!(!res.success);
1170 }
1171
1172 #[test]
1173 fn test_depth_first_search_max_depth_exceeded() {
1174 let kb = KnowledgeBase::new("test");
1175 let mut dfs = DepthFirstSearch::new(2, kb);
1176 let facts = Facts::new();
1177
1178 let mut root = Goal::new("level0".to_string());
1180 root.depth = 0;
1181 root.add_candidate_rule("Rule0".to_string());
1182
1183 let mut level1 = Goal::new("level1".to_string());
1184 level1.depth = 1;
1185 level1.add_candidate_rule("Rule1".to_string());
1186
1187 let mut level2 = Goal::new("level2".to_string());
1188 level2.depth = 2;
1189 level2.add_candidate_rule("Rule2".to_string());
1190
1191 let mut level3 = Goal::new("level3".to_string());
1192 level3.depth = 3; level3.add_candidate_rule("Rule3".to_string());
1194
1195 level2.add_subgoal(level3);
1196 level1.add_subgoal(level2);
1197 root.add_subgoal(level1);
1198
1199 let result = dfs.search(&mut root, &facts);
1200
1201 assert!(result.max_depth_reached <= 3);
1203 }
1204
1205 #[test]
1206 fn test_breadth_first_search_multiple_candidates() {
1207 let kb = KnowledgeBase::new("test");
1208 let mut bfs = BreadthFirstSearch::new(10, kb);
1209 let facts = Facts::new();
1210
1211 let mut goal = Goal::new("multi_rule_goal".to_string());
1212 goal.add_candidate_rule("Rule1".to_string());
1213 goal.add_candidate_rule("Rule2".to_string());
1214 goal.add_candidate_rule("Rule3".to_string());
1215
1216 let result = bfs.search(&mut goal, &facts);
1217
1218 assert!(result.success);
1219 assert_eq!(goal.candidate_rules.len(), 3);
1220 }
1221
1222 #[test]
1223 fn test_depth_first_search_empty_goal() {
1224 let kb = KnowledgeBase::new("test");
1225 let mut dfs = DepthFirstSearch::new(10, kb);
1226 let facts = Facts::new();
1227
1228 let mut goal = Goal::new("".to_string());
1229 let result = dfs.search(&mut goal, &facts);
1232
1233 assert!(!result.success);
1235 }
1236
1237 #[test]
1238 fn test_search_result_with_bindings() {
1239 use crate::types::Value;
1240 let mut bindings = HashMap::new();
1241 bindings.insert("X".to_string(), Value::String("test".to_string()));
1242 bindings.insert("Y".to_string(), Value::Number(42.0));
1243
1244 let result = SearchResult {
1245 success: true,
1246 path: vec!["Rule1".to_string()],
1247 goals_explored: 5,
1248 max_depth_reached: 3,
1249 bindings: bindings.clone(),
1250 solutions: Vec::new(),
1251 };
1252
1253 assert_eq!(result.bindings.len(), 2);
1254 assert_eq!(
1255 result.bindings.get("X"),
1256 Some(&Value::String("test".to_string()))
1257 );
1258 }
1259
1260 #[test]
1261 fn test_breadth_first_search_with_subgoals() {
1262 let kb = KnowledgeBase::new("test");
1263 let mut bfs = BreadthFirstSearch::new(10, kb);
1264 let facts = Facts::new();
1265
1266 let mut root = Goal::new("root".to_string());
1267 root.add_candidate_rule("RootRule".to_string());
1268
1269 let mut sub1 = Goal::new("sub1".to_string());
1270 sub1.add_candidate_rule("Sub1Rule".to_string());
1271
1272 let mut sub2 = Goal::new("sub2".to_string());
1273 sub2.add_candidate_rule("Sub2Rule".to_string());
1274
1275 root.add_subgoal(sub1);
1276 root.add_subgoal(sub2);
1277
1278 let result = bfs.search(&mut root, &facts);
1279
1280 assert!(result.success);
1281 assert!(result.goals_explored >= 3); }
1283
1284 #[test]
1285 fn test_iterative_deepening_search_no_candidates() {
1286 let kb = KnowledgeBase::new("test");
1287 let mut ids = IterativeDeepeningSearch::new(5, kb);
1288 let mut root = Goal::new("no_rules".to_string());
1289 let facts = Facts::new();
1292 let result = ids.search(&mut root, &facts);
1293
1294 assert!(!result.success);
1295 assert!(result.path.is_empty());
1296 }
1297
1298 #[test]
1299 fn test_search_strategy_equality() {
1300 assert_eq!(SearchStrategy::BreadthFirst, SearchStrategy::BreadthFirst);
1301 assert_eq!(SearchStrategy::Iterative, SearchStrategy::Iterative);
1302 assert_ne!(SearchStrategy::BreadthFirst, SearchStrategy::Iterative);
1303 }
1304
1305 #[test]
1306 fn test_depth_first_search_goals_explored_count() {
1307 let kb = KnowledgeBase::new("test");
1308 let mut dfs = DepthFirstSearch::new(10, kb);
1309 let facts = Facts::new();
1310
1311 let mut root = Goal::new("root".to_string());
1312 root.add_candidate_rule("RootRule".to_string());
1313
1314 let mut sub = Goal::new("sub".to_string());
1315 sub.add_candidate_rule("SubRule".to_string());
1316
1317 root.add_subgoal(sub);
1318
1319 let result = dfs.search(&mut root, &facts);
1320
1321 assert!(result.success);
1323 assert!(result.goals_explored > 0);
1325 }
1326}