1#![allow(deprecated)]
4
5use super::goal::{Goal, GoalStatus};
6use super::proof_graph::{FactKey, SharedProofGraph};
7use super::rule_executor::RuleExecutor;
8use crate::engine::rule::Rule;
9use crate::rete::propagation::IncrementalEngine;
10use crate::types::Value;
11use crate::Facts;
12use crate::KnowledgeBase;
13use std::collections::VecDeque;
14use std::sync::{Arc, Mutex};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum SearchStrategy {
19 DepthFirst,
22
23 BreadthFirst,
26
27 Iterative,
30}
31
32#[derive(Debug, Clone)]
34pub struct Solution {
35 pub path: Vec<String>,
37
38 pub bindings: std::collections::HashMap<String, Value>,
40}
41
42#[derive(Debug)]
44pub struct SearchResult {
45 pub success: bool,
47
48 pub path: Vec<String>,
50
51 pub goals_explored: usize,
53
54 pub max_depth_reached: usize,
56
57 pub bindings: std::collections::HashMap<String, Value>,
59
60 pub solutions: Vec<Solution>,
62}
63
64impl SearchResult {
65 pub fn success(path: Vec<String>, goals_explored: usize, max_depth: usize) -> Self {
67 Self {
68 success: true,
69 path,
70 goals_explored,
71 max_depth_reached: max_depth,
72 bindings: std::collections::HashMap::new(),
73 solutions: Vec::new(),
74 }
75 }
76
77 pub fn failure(goals_explored: usize, max_depth: usize) -> Self {
79 Self {
80 success: false,
81 path: Vec::new(),
82 goals_explored,
83 max_depth_reached: max_depth,
84 bindings: std::collections::HashMap::new(),
85 solutions: Vec::new(),
86 }
87 }
88}
89
90pub struct DepthFirstSearch {
92 max_depth: usize,
93 goals_explored: usize,
94 path: Vec<String>,
95 executor: RuleExecutor,
96 max_solutions: usize,
97 solutions: Vec<Solution>,
98 proof_graph: Option<SharedProofGraph>,
99}
100
101impl DepthFirstSearch {
102 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
104 Self {
105 max_depth,
106 goals_explored: 0,
107 path: Vec::new(),
108 executor: RuleExecutor::new_with_inserter(kb, None),
109 max_solutions: 1,
110 solutions: Vec::new(),
111 proof_graph: None,
112 }
113 }
114
115 pub fn with_max_solutions(mut self, max_solutions: usize) -> Self {
117 self.max_solutions = max_solutions;
118 self
119 }
120
121 pub fn new_with_engine(
125 max_depth: usize,
126 kb: KnowledgeBase,
127 engine: Option<Arc<Mutex<IncrementalEngine>>>,
128 ) -> Self {
129 let proof_graph = engine.as_ref().map(|_| super::proof_graph::new_shared());
131 let proof_graph_clone = proof_graph.clone();
132
133 let inserter = engine.map(|eng| {
135 let eng = eng.clone();
136 let pg = proof_graph_clone.clone();
137
138 std::sync::Arc::new(
139 move |fact_type: String,
140 data: crate::rete::TypedFacts,
141 rule_name: String,
142 premises: Vec<String>| {
143 if let Ok(mut e) = eng.lock() {
144 let handles = e.resolve_premise_keys(premises.clone());
146
147 let handle = e.insert_logical(
149 fact_type.clone(),
150 data.clone(),
151 rule_name.clone(),
152 handles.clone(),
153 );
154
155 if let Some(ref graph) = pg {
157 if let Ok(mut g) = graph.lock() {
158 let pattern = format!("{}.{}", fact_type, "derived");
160 let key = FactKey::from_pattern(&pattern);
161
162 g.insert_proof(handle, key, rule_name, handles, premises);
163 }
164 }
165 }
166 },
167 )
168 as std::sync::Arc<
169 dyn Fn(String, crate::rete::TypedFacts, String, Vec<String>) + Send + Sync,
170 >
171 });
172
173 Self {
174 max_depth,
175 goals_explored: 0,
176 path: Vec::new(),
177 executor: RuleExecutor::new_with_inserter(kb, inserter),
178 max_solutions: 1,
179 solutions: Vec::new(),
180 proof_graph,
181 }
182 }
183
184 pub fn search_with_execution(
186 &mut self,
187 goal: &mut Goal,
188 facts: &mut Facts,
189 kb: &KnowledgeBase,
190 ) -> SearchResult {
191 self.goals_explored = 0;
192 self.path.clear();
193 self.solutions.clear();
194
195 let success = self.search_recursive_with_execution(goal, facts, kb, 0);
196
197 SearchResult {
198 success,
199 path: self.path.clone(),
200 goals_explored: self.goals_explored,
201 max_depth_reached: goal.depth,
202 bindings: goal.bindings.to_map(),
203 solutions: self.solutions.clone(),
204 }
205 }
206
207 pub fn search(&mut self, goal: &mut Goal, _facts: &Facts) -> SearchResult {
209 self.goals_explored = 0;
210 self.path.clear();
211
212 let success = self.search_recursive(goal, 0);
213
214 SearchResult {
215 success,
216 path: self.path.clone(),
217 goals_explored: self.goals_explored,
218 max_depth_reached: goal.depth,
219 bindings: goal.bindings.to_map(),
220 solutions: Vec::new(),
221 }
222 }
223
224 fn search_recursive_with_execution(
226 &mut self,
227 goal: &mut Goal,
228 facts: &mut Facts, kb: &KnowledgeBase,
230 depth: usize,
231 ) -> bool {
232 self.goals_explored += 1;
233
234 if depth > self.max_depth {
236 goal.status = GoalStatus::Unprovable;
237 return false;
238 }
239
240 let fact_proven = self.check_goal_in_facts(goal, facts);
242
243 if goal.is_negated {
245 if fact_proven {
247 goal.status = GoalStatus::Unprovable;
248 return false; }
250 } else {
253 if fact_proven {
255 goal.status = GoalStatus::Proven;
256 return true;
257 }
258 }
259
260 if goal.status == GoalStatus::InProgress {
262 goal.status = GoalStatus::Unprovable;
263 return false;
264 }
265
266 goal.status = GoalStatus::InProgress;
267 goal.depth = depth;
268
269 for rule_name in goal.candidate_rules.clone() {
271 self.path.push(rule_name.clone());
272
273 facts.begin_undo_frame();
276
277 if let Some(rule) = kb.get_rule(&rule_name) {
279 match self.executor.try_execute_rule(&rule, facts) {
281 Ok(true) if self.check_goal_in_facts(goal, facts) => {
282 goal.status = GoalStatus::Proven;
284
285 self.solutions.push(Solution {
287 path: self.path.clone(),
288 bindings: goal.bindings.to_map(),
289 });
290
291 if self.max_solutions == 1 || self.solutions.len() >= self.max_solutions {
293 return true; }
295
296 facts.rollback_undo_frame();
298 self.path.pop();
299 continue;
300 }
301 Ok(true) => {
302 }
304 Ok(false) => {
305 if self.try_prove_rule_conditions(&rule, facts, kb, depth + 1) {
307 match self.executor.try_execute_rule(&rule, facts) {
309 Ok(true) if self.check_goal_in_facts(goal, facts) => {
310 goal.status = GoalStatus::Proven;
311
312 self.solutions.push(Solution {
314 path: self.path.clone(),
315 bindings: goal.bindings.to_map(),
316 });
317
318 if self.max_solutions == 1
320 || self.solutions.len() >= self.max_solutions
321 {
322 return true; }
324
325 facts.rollback_undo_frame();
327 self.path.pop();
328 continue;
329 }
330 Ok(true) => {
331 }
333 _ => {
334 }
336 }
337 }
338 }
339 Err(_) => {
340 }
342 }
343 }
344
345 facts.rollback_undo_frame();
347 self.path.pop();
348 }
349
350 let mut all_subgoals_proven = true;
353 if !goal.sub_goals.is_empty() {
354 facts.begin_undo_frame();
355 for sub_goal in &mut goal.sub_goals {
356 if !self.search_recursive_with_execution(sub_goal, facts, kb, depth + 1) {
357 all_subgoals_proven = false;
358 break;
359 }
360 }
361
362 if all_subgoals_proven {
363 facts.commit_undo_frame();
365 goal.status = GoalStatus::Proven;
366 return true;
367 }
368
369 facts.rollback_undo_frame();
371 }
372
373 if !self.solutions.is_empty() {
375 goal.status = GoalStatus::Proven;
376 return !goal.is_negated;
378 }
379
380 if goal.is_negated {
382 goal.status = GoalStatus::Proven;
384 true
385 } else {
386 goal.status = GoalStatus::Unprovable;
388 false
389 }
390 }
391
392 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
397 if let Some(ref graph_arc) = self.proof_graph {
399 if let Ok(mut graph) = graph_arc.lock() {
400 let key = FactKey::from_pattern(&goal.pattern);
401 if graph.is_proven(&key) {
402 return true;
404 }
405 }
406 }
407
408 if goal.is_negated {
410 if let Some(ref expr) = goal.expression {
411 match expr.evaluate(facts) {
413 Ok(Value::Boolean(b)) => return b,
414 Ok(_) => return false, Err(_) => return false,
416 }
417 }
418 return false;
419 }
420
421 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
423 self.executor
425 .evaluate_condition(&condition, facts)
426 .unwrap_or(false)
427 } else {
428 false
429 }
430 }
431
432 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
438 use crate::engine::rule::{Condition, ConditionExpression};
439 use crate::types::Operator;
440
441 let operators = [
443 (">=", Operator::GreaterThanOrEqual),
444 ("<=", Operator::LessThanOrEqual),
445 ("==", Operator::Equal),
446 ("!=", Operator::NotEqual),
447 (" > ", Operator::GreaterThan),
448 (" < ", Operator::LessThan),
449 (" contains ", Operator::Contains),
450 (" not_contains ", Operator::NotContains),
451 (" starts_with ", Operator::StartsWith),
452 (" startsWith ", Operator::StartsWith),
453 (" ends_with ", Operator::EndsWith),
454 (" endsWith ", Operator::EndsWith),
455 (" matches ", Operator::Matches),
456 ];
457
458 for (op_str, operator) in operators {
459 if let Some(pos) = pattern.find(op_str) {
460 let field = pattern[..pos].trim().to_string();
461 let value_str = pattern[pos + op_str.len()..].trim();
462
463 let value = self.parse_value_string(value_str);
465
466 return Some(Condition {
467 field: field.clone(),
468 expression: ConditionExpression::Field(field),
469 operator,
470 value,
471 });
472 }
473 }
474
475 None
476 }
477
478 fn parse_value_string(&self, s: &str) -> Value {
480 let s = s.trim();
481
482 if s == "true" {
484 return Value::Boolean(true);
485 }
486 if s == "false" {
487 return Value::Boolean(false);
488 }
489
490 if s == "null" {
492 return Value::Null;
493 }
494
495 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
497 return Value::String(s[1..s.len() - 1].to_string());
498 }
499
500 if let Ok(n) = s.parse::<f64>() {
502 return Value::Number(n);
503 }
504
505 if let Ok(i) = s.parse::<i64>() {
507 return Value::Integer(i);
508 }
509
510 Value::String(s.to_string())
512 }
513
514 fn try_prove_rule_conditions(
517 &mut self,
518 rule: &Rule,
519 facts: &mut Facts,
520 kb: &KnowledgeBase,
521 depth: usize,
522 ) -> bool {
523 self.try_prove_condition_group(&rule.conditions, facts, kb, depth)
525 }
526
527 fn try_prove_condition_group(
529 &mut self,
530 group: &crate::engine::rule::ConditionGroup,
531 facts: &mut Facts,
532 kb: &KnowledgeBase,
533 depth: usize,
534 ) -> bool {
535 use crate::engine::rule::ConditionGroup;
536
537 match group {
538 ConditionGroup::Single(condition) => {
539 self.try_prove_single_condition(condition, facts, kb, depth)
541 }
542 ConditionGroup::Compound {
543 left,
544 operator,
545 right,
546 } => {
547 use crate::types::LogicalOperator;
549 match operator {
550 LogicalOperator::And => {
551 self.try_prove_condition_group(left, facts, kb, depth)
553 && self.try_prove_condition_group(right, facts, kb, depth)
554 }
555 LogicalOperator::Or => {
556 self.try_prove_condition_group(left, facts, kb, depth)
558 || self.try_prove_condition_group(right, facts, kb, depth)
559 }
560 LogicalOperator::Not => {
561 !self.try_prove_condition_group(left, facts, kb, depth)
563 }
564 }
565 }
566 ConditionGroup::Not(_)
567 | ConditionGroup::Exists(_)
568 | ConditionGroup::Forall(_)
569 | ConditionGroup::Accumulate { .. } => {
570 self.executor
574 .evaluate_conditions(group, facts)
575 .unwrap_or(false)
576 }
577 #[cfg(feature = "streaming")]
578 ConditionGroup::StreamPattern { .. } => {
579 self.executor
581 .evaluate_conditions(group, facts)
582 .unwrap_or(false)
583 }
584 }
585 }
586
587 fn try_prove_single_condition(
589 &mut self,
590 condition: &crate::engine::rule::Condition,
591 facts: &mut Facts,
592 kb: &KnowledgeBase,
593 depth: usize,
594 ) -> bool {
595 if let Ok(satisfied) = self.executor.evaluate_condition(condition, facts) {
597 if satisfied {
598 return true;
599 }
600 }
601
602 let goal_pattern = self.condition_to_goal_pattern(condition);
604
605 let mut sub_goal = Goal::new(goal_pattern.clone());
607 sub_goal.depth = depth;
608
609 for candidate_rule in kb.get_rules() {
611 if self.rule_could_prove_pattern(&candidate_rule, &goal_pattern) {
612 sub_goal.add_candidate_rule(candidate_rule.name.clone());
613 }
614 }
615
616 self.search_recursive_with_execution(&mut sub_goal, facts, kb, depth)
618 }
619
620 fn condition_to_goal_pattern(&self, condition: &crate::engine::rule::Condition) -> String {
622 use crate::engine::rule::ConditionExpression;
623
624 let field = match &condition.expression {
625 ConditionExpression::Field(f) => f.clone(),
626 ConditionExpression::FunctionCall { name, .. } => name.clone(),
627 ConditionExpression::Test { name, .. } => format!("test({})", name),
628 ConditionExpression::MultiField { field, .. } => field.clone(),
629 };
630
631 let op_str = match condition.operator {
632 crate::types::Operator::Equal => "==",
633 crate::types::Operator::NotEqual => "!=",
634 crate::types::Operator::GreaterThan => ">",
635 crate::types::Operator::LessThan => "<",
636 crate::types::Operator::GreaterThanOrEqual => ">=",
637 crate::types::Operator::LessThanOrEqual => "<=",
638 crate::types::Operator::Contains => "contains",
639 crate::types::Operator::NotContains => "not_contains",
640 crate::types::Operator::StartsWith => "starts_with",
641 crate::types::Operator::EndsWith => "ends_with",
642 crate::types::Operator::Matches => "matches",
643 crate::types::Operator::In => "in",
644 };
645
646 let value_str = match &condition.value {
648 Value::Boolean(b) => b.to_string(),
649 Value::Number(n) => n.to_string(),
650 Value::Integer(i) => i.to_string(),
651 Value::String(s) => format!("\"{}\"", s),
652 Value::Null => "null".to_string(),
653 _ => format!("{:?}", condition.value),
654 };
655
656 format!("{} {} {}", field, op_str, value_str)
657 }
658
659 fn rule_could_prove_pattern(&self, rule: &Rule, pattern: &str) -> bool {
661 for action in &rule.actions {
663 match action {
664 crate::types::ActionType::Set { field, .. } if pattern.contains(field) => {
665 return true;
666 }
667 crate::types::ActionType::MethodCall { object, method, .. }
668 if (pattern.contains(object) || pattern.contains(method)) =>
669 {
670 return true;
671 }
672 _ => {}
673 }
674 }
675 false
676 }
677
678 fn search_recursive(&mut self, goal: &mut Goal, depth: usize) -> bool {
680 self.goals_explored += 1;
681
682 if depth > self.max_depth {
684 goal.status = GoalStatus::Unprovable;
685 return false;
686 }
687
688 if goal.status == GoalStatus::InProgress {
690 goal.status = GoalStatus::Unprovable;
691 return false;
692 }
693
694 goal.status = GoalStatus::InProgress;
696 goal.depth = depth;
697
698 if let Some(rule_name) = goal.candidate_rules.clone().into_iter().next() {
700 self.path.push(rule_name.clone());
701
702 goal.status = GoalStatus::Proven;
716 return true;
717 }
718
719 for sub_goal in &mut goal.sub_goals {
721 if !self.search_recursive(sub_goal, depth + 1) {
722 goal.status = GoalStatus::Unprovable;
723 return false;
724 }
725 }
726
727 if goal.sub_goals.is_empty() && goal.candidate_rules.is_empty() {
729 goal.status = GoalStatus::Unprovable;
730 return false;
731 }
732
733 goal.status = GoalStatus::Proven;
734 true
735 }
736}
737
738pub struct BreadthFirstSearch {
740 max_depth: usize,
741 goals_explored: usize,
742 executor: RuleExecutor,
743 proof_graph: Option<SharedProofGraph>,
744}
745
746pub struct IterativeDeepeningSearch {
748 max_depth: usize,
749 goals_explored: usize,
750 kb: KnowledgeBase,
751 engine: Option<Arc<Mutex<IncrementalEngine>>>,
752}
753
754impl IterativeDeepeningSearch {
755 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
757 Self {
758 max_depth,
759 goals_explored: 0,
760 kb,
761 engine: None,
762 }
763 }
764
765 pub fn new_with_engine(
767 max_depth: usize,
768 kb: KnowledgeBase,
769 engine: Option<Arc<Mutex<IncrementalEngine>>>,
770 ) -> Self {
771 Self {
773 max_depth,
774 goals_explored: 0,
775 kb,
776 engine,
777 }
778 }
779
780 pub fn search_with_execution(
783 &mut self,
784 root_goal: &mut Goal,
785 facts: &mut Facts,
786 kb: &KnowledgeBase,
787 ) -> SearchResult {
788 self.goals_explored = 0;
789 let mut cumulative_goals = 0usize;
790
791 for depth_limit in 0..=self.max_depth {
793 let mut probe_goal = root_goal.clone();
795 let probe_kb = self.kb.clone();
796 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
797 let probe_result = probe_dfs.search(&mut probe_goal, facts);
798 cumulative_goals += probe_result.goals_explored;
799
800 if probe_result.success {
801 let exec_kb = self.kb.clone();
803 let mut exec_dfs =
804 DepthFirstSearch::new_with_engine(depth_limit, exec_kb, self.engine.clone());
805 let exec_result = exec_dfs.search_with_execution(root_goal, facts, kb);
806 let mut final_result = exec_result;
808 final_result.goals_explored += cumulative_goals - final_result.goals_explored;
809 return final_result;
810 }
811 }
812
813 SearchResult::failure(cumulative_goals, self.max_depth)
815 }
816
817 pub fn search(&mut self, root_goal: &mut Goal, facts: &Facts) -> SearchResult {
819 self.goals_explored = 0;
820 let mut cumulative_goals = 0usize;
821
822 for depth_limit in 0..=self.max_depth {
823 let mut probe_goal = root_goal.clone();
824 let probe_kb = self.kb.clone();
825 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
826 let probe_result = probe_dfs.search(&mut probe_goal, facts);
827 cumulative_goals += probe_result.goals_explored;
828 if probe_result.success {
829 let mut res = probe_result;
831 res.goals_explored = cumulative_goals;
832 return res;
833 }
834 }
835
836 SearchResult::failure(cumulative_goals, self.max_depth)
837 }
838}
839
840impl BreadthFirstSearch {
841 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
843 Self {
844 max_depth,
845 goals_explored: 0,
846 executor: RuleExecutor::new_with_inserter(kb, None),
847 proof_graph: None,
848 }
849 }
850
851 pub fn new_with_engine(
853 max_depth: usize,
854 kb: KnowledgeBase,
855 engine: Option<Arc<Mutex<IncrementalEngine>>>,
856 ) -> Self {
857 let proof_graph = engine.as_ref().map(|_| super::proof_graph::new_shared());
859 let proof_graph_clone = proof_graph.clone();
860
861 let inserter = engine.map(|eng| {
863 let eng = eng.clone();
864 let pg = proof_graph_clone.clone();
865
866 std::sync::Arc::new(
867 move |fact_type: String,
868 data: crate::rete::TypedFacts,
869 rule_name: String,
870 premises: Vec<String>| {
871 if let Ok(mut e) = eng.lock() {
872 let handles = e.resolve_premise_keys(premises.clone());
873
874 let handle = e.insert_logical(
875 fact_type.clone(),
876 data.clone(),
877 rule_name.clone(),
878 handles.clone(),
879 );
880
881 if let Some(ref graph) = pg {
883 if let Ok(mut g) = graph.lock() {
884 let pattern = format!("{}.{}", fact_type, "derived");
885 let key = FactKey::from_pattern(&pattern);
886 g.insert_proof(handle, key, rule_name, handles, premises);
887 }
888 }
889 }
890 },
891 )
892 as std::sync::Arc<
893 dyn Fn(String, crate::rete::TypedFacts, String, Vec<String>) + Send + Sync,
894 >
895 });
896
897 Self {
898 max_depth,
899 goals_explored: 0,
900 executor: RuleExecutor::new_with_inserter(kb, inserter),
901 proof_graph,
902 }
903 }
904
905 pub fn search_with_execution(
907 &mut self,
908 root_goal: &mut Goal,
909 facts: &mut Facts,
910 kb: &KnowledgeBase,
911 ) -> SearchResult {
912 self.goals_explored = 0;
913 let mut queue = VecDeque::new();
914 let mut path = Vec::new();
915 let mut max_depth = 0;
916
917 queue.push_back((root_goal as *mut Goal, 0));
918
919 while let Some((goal_ptr, depth)) = queue.pop_front() {
920 let goal = unsafe { &mut *goal_ptr };
922
923 self.goals_explored += 1;
924 max_depth = max_depth.max(depth);
925
926 if depth > self.max_depth {
927 continue;
928 }
929
930 goal.depth = depth;
931
932 if self.check_goal_in_facts(goal, facts) {
934 goal.status = GoalStatus::Proven;
935 continue;
936 }
937
938 for rule_name in goal.candidate_rules.clone() {
940 path.push(rule_name.clone());
941
942 if let Some(rule) = kb.get_rule(&rule_name) {
944 match self.executor.try_execute_rule(&rule, facts) {
946 Ok(true) => {
947 if self.check_goal_in_facts(goal, facts) {
950 goal.status = GoalStatus::Proven;
951 break;
952 }
953 }
954 Ok(false) => {
955 }
957 Err(_) => {
958 }
960 }
961 }
962 }
963
964 for sub_goal in &mut goal.sub_goals {
966 queue.push_back((sub_goal as *mut Goal, depth + 1));
967 }
968 }
969
970 let success = root_goal.is_proven();
971
972 SearchResult {
973 success,
974 path,
975 goals_explored: self.goals_explored,
976 max_depth_reached: max_depth,
977 bindings: root_goal.bindings.to_map(),
978 solutions: Vec::new(),
979 }
980 }
981
982 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
987 if let Some(ref graph_arc) = self.proof_graph {
989 if let Ok(mut graph) = graph_arc.lock() {
990 let key = FactKey::from_pattern(&goal.pattern);
991 if graph.is_proven(&key) {
992 return true;
994 }
995 }
996 }
997
998 if goal.is_negated {
1000 if let Some(ref expr) = goal.expression {
1001 match expr.evaluate(facts) {
1003 Ok(Value::Boolean(b)) => return b,
1004 Ok(_) => return false, Err(_) => return false,
1006 }
1007 }
1008 return false;
1009 }
1010
1011 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
1013 self.executor
1015 .evaluate_condition(&condition, facts)
1016 .unwrap_or(false)
1017 } else {
1018 false
1019 }
1020 }
1021
1022 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
1028 use crate::engine::rule::{Condition, ConditionExpression};
1029 use crate::types::Operator;
1030
1031 let operators = [
1033 (">=", Operator::GreaterThanOrEqual),
1034 ("<=", Operator::LessThanOrEqual),
1035 ("==", Operator::Equal),
1036 ("!=", Operator::NotEqual),
1037 (" > ", Operator::GreaterThan),
1038 (" < ", Operator::LessThan),
1039 (" contains ", Operator::Contains),
1040 (" not_contains ", Operator::NotContains),
1041 (" starts_with ", Operator::StartsWith),
1042 (" startsWith ", Operator::StartsWith),
1043 (" ends_with ", Operator::EndsWith),
1044 (" endsWith ", Operator::EndsWith),
1045 (" matches ", Operator::Matches),
1046 ];
1047
1048 for (op_str, operator) in operators {
1049 if let Some(pos) = pattern.find(op_str) {
1050 let field = pattern[..pos].trim().to_string();
1051 let value_str = pattern[pos + op_str.len()..].trim();
1052
1053 let value = self.parse_value_string(value_str);
1055
1056 return Some(Condition {
1057 field: field.clone(),
1058 expression: ConditionExpression::Field(field),
1059 operator,
1060 value,
1061 });
1062 }
1063 }
1064
1065 None
1066 }
1067
1068 fn parse_value_string(&self, s: &str) -> Value {
1070 let s = s.trim();
1071
1072 if s == "true" {
1074 return Value::Boolean(true);
1075 }
1076 if s == "false" {
1077 return Value::Boolean(false);
1078 }
1079
1080 if s == "null" {
1082 return Value::Null;
1083 }
1084
1085 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
1087 return Value::String(s[1..s.len() - 1].to_string());
1088 }
1089
1090 if let Ok(n) = s.parse::<f64>() {
1092 return Value::Number(n);
1093 }
1094
1095 if let Ok(i) = s.parse::<i64>() {
1097 return Value::Integer(i);
1098 }
1099
1100 Value::String(s.to_string())
1102 }
1103
1104 pub fn search(&mut self, root_goal: &mut Goal, _facts: &Facts) -> SearchResult {
1106 self.goals_explored = 0;
1107 let mut queue = VecDeque::new();
1108 let mut path = Vec::new();
1109 let mut max_depth = 0;
1110
1111 queue.push_back((root_goal as *mut Goal, 0));
1112
1113 while let Some((goal_ptr, depth)) = queue.pop_front() {
1114 let goal = unsafe { &mut *goal_ptr };
1116
1117 self.goals_explored += 1;
1118 max_depth = max_depth.max(depth);
1119
1120 if depth > self.max_depth {
1121 continue;
1122 }
1123
1124 goal.depth = depth;
1125
1126 for rule_name in &goal.candidate_rules {
1128 path.push(rule_name.clone());
1129 }
1130
1131 for sub_goal in &mut goal.sub_goals {
1133 queue.push_back((sub_goal as *mut Goal, depth + 1));
1134 }
1135
1136 if !goal.candidate_rules.is_empty() || goal.all_subgoals_proven() {
1138 goal.status = GoalStatus::Proven;
1139 }
1140 }
1141
1142 let success = root_goal.is_proven();
1143
1144 SearchResult {
1145 success,
1146 path,
1147 goals_explored: self.goals_explored,
1148 max_depth_reached: max_depth,
1149 bindings: root_goal.bindings.to_map(),
1150 solutions: Vec::new(),
1151 }
1152 }
1153}
1154
1155#[cfg(test)]
1156mod tests {
1157 use super::*;
1158 use std::collections::HashMap;
1159
1160 #[test]
1161 fn test_search_strategies() {
1162 assert_eq!(SearchStrategy::DepthFirst, SearchStrategy::DepthFirst);
1163 assert_ne!(SearchStrategy::DepthFirst, SearchStrategy::BreadthFirst);
1164 }
1165
1166 #[test]
1167 fn test_search_result_creation() {
1168 let success = SearchResult::success(vec!["Rule1".to_string()], 5, 3);
1169 assert!(success.success);
1170 assert_eq!(success.path.len(), 1);
1171 assert_eq!(success.goals_explored, 5);
1172
1173 let failure = SearchResult::failure(10, 5);
1174 assert!(!failure.success);
1175 assert!(failure.path.is_empty());
1176 }
1177
1178 #[test]
1179 fn test_depth_first_search_creation() {
1180 let kb = KnowledgeBase::new("test");
1181 let dfs = DepthFirstSearch::new(10, kb);
1182 assert_eq!(dfs.max_depth, 10);
1183 assert_eq!(dfs.goals_explored, 0);
1184 }
1185
1186 #[test]
1187 fn test_depth_first_search_simple() {
1188 let kb = KnowledgeBase::new("test");
1189 let mut dfs = DepthFirstSearch::new(10, kb);
1190 let facts = Facts::new();
1191
1192 let mut goal = Goal::new("test".to_string());
1193 goal.add_candidate_rule("TestRule".to_string());
1194
1195 let result = dfs.search(&mut goal, &facts);
1196
1197 assert!(result.success);
1198 assert!(goal.is_proven());
1199 assert!(result.goals_explored > 0);
1200 }
1201
1202 #[test]
1203 fn test_breadth_first_search() {
1204 let kb = KnowledgeBase::new("test");
1205 let mut bfs = BreadthFirstSearch::new(10, kb);
1206 let facts = Facts::new();
1207
1208 let mut goal = Goal::new("test".to_string());
1209 goal.add_candidate_rule("TestRule".to_string());
1210
1211 let result = bfs.search(&mut goal, &facts);
1212
1213 assert!(result.success);
1214 assert_eq!(result.goals_explored, 1);
1215 }
1216
1217 #[test]
1218 fn test_iterative_deepening_search_success() {
1219 let kb = KnowledgeBase::new("test");
1220 let mut ids = IterativeDeepeningSearch::new(5, kb.clone());
1221 let mut root = Goal::new("test".to_string());
1222 root.add_candidate_rule("TestRule".to_string());
1223
1224 let facts = Facts::new();
1226 let res = ids.search(&mut root, &facts);
1227 assert!(res.success);
1228 }
1229
1230 #[test]
1231 fn test_iterative_deepening_search_depth_limit() {
1232 let kb = KnowledgeBase::new("test");
1233 let mut ids = IterativeDeepeningSearch::new(0, kb.clone());
1235 let mut root = Goal::new("test".to_string());
1236 let mut sub = Goal::new("sub".to_string());
1238 sub.add_candidate_rule("SubRule".to_string());
1239 root.sub_goals.push(sub);
1240
1241 let facts = Facts::new();
1242 let res = ids.search(&mut root, &facts);
1243 assert!(!res.success);
1244 }
1245
1246 #[test]
1247 fn test_depth_first_search_max_depth_exceeded() {
1248 let kb = KnowledgeBase::new("test");
1249 let mut dfs = DepthFirstSearch::new(2, kb);
1250 let facts = Facts::new();
1251
1252 let mut root = Goal::new("level0".to_string());
1254 root.depth = 0;
1255 root.add_candidate_rule("Rule0".to_string());
1256
1257 let mut level1 = Goal::new("level1".to_string());
1258 level1.depth = 1;
1259 level1.add_candidate_rule("Rule1".to_string());
1260
1261 let mut level2 = Goal::new("level2".to_string());
1262 level2.depth = 2;
1263 level2.add_candidate_rule("Rule2".to_string());
1264
1265 let mut level3 = Goal::new("level3".to_string());
1266 level3.depth = 3; level3.add_candidate_rule("Rule3".to_string());
1268
1269 level2.add_subgoal(level3);
1270 level1.add_subgoal(level2);
1271 root.add_subgoal(level1);
1272
1273 let result = dfs.search(&mut root, &facts);
1274
1275 assert!(result.max_depth_reached <= 3);
1277 }
1278
1279 #[test]
1280 fn test_breadth_first_search_multiple_candidates() {
1281 let kb = KnowledgeBase::new("test");
1282 let mut bfs = BreadthFirstSearch::new(10, kb);
1283 let facts = Facts::new();
1284
1285 let mut goal = Goal::new("multi_rule_goal".to_string());
1286 goal.add_candidate_rule("Rule1".to_string());
1287 goal.add_candidate_rule("Rule2".to_string());
1288 goal.add_candidate_rule("Rule3".to_string());
1289
1290 let result = bfs.search(&mut goal, &facts);
1291
1292 assert!(result.success);
1293 assert_eq!(goal.candidate_rules.len(), 3);
1294 }
1295
1296 #[test]
1297 fn test_depth_first_search_empty_goal() {
1298 let kb = KnowledgeBase::new("test");
1299 let mut dfs = DepthFirstSearch::new(10, kb);
1300 let facts = Facts::new();
1301
1302 let mut goal = Goal::new("".to_string());
1303 let result = dfs.search(&mut goal, &facts);
1306
1307 assert!(!result.success);
1309 }
1310
1311 #[test]
1312 fn test_search_result_with_bindings() {
1313 use crate::types::Value;
1314 let mut bindings = HashMap::new();
1315 bindings.insert("X".to_string(), Value::String("test".to_string()));
1316 bindings.insert("Y".to_string(), Value::Number(42.0));
1317
1318 let result = SearchResult {
1319 success: true,
1320 path: vec!["Rule1".to_string()],
1321 goals_explored: 5,
1322 max_depth_reached: 3,
1323 bindings: bindings.clone(),
1324 solutions: Vec::new(),
1325 };
1326
1327 assert_eq!(result.bindings.len(), 2);
1328 assert_eq!(
1329 result.bindings.get("X"),
1330 Some(&Value::String("test".to_string()))
1331 );
1332 }
1333
1334 #[test]
1335 fn test_breadth_first_search_with_subgoals() {
1336 let kb = KnowledgeBase::new("test");
1337 let mut bfs = BreadthFirstSearch::new(10, kb);
1338 let facts = Facts::new();
1339
1340 let mut root = Goal::new("root".to_string());
1341 root.add_candidate_rule("RootRule".to_string());
1342
1343 let mut sub1 = Goal::new("sub1".to_string());
1344 sub1.add_candidate_rule("Sub1Rule".to_string());
1345
1346 let mut sub2 = Goal::new("sub2".to_string());
1347 sub2.add_candidate_rule("Sub2Rule".to_string());
1348
1349 root.add_subgoal(sub1);
1350 root.add_subgoal(sub2);
1351
1352 let result = bfs.search(&mut root, &facts);
1353
1354 assert!(result.success);
1355 assert!(result.goals_explored >= 3); }
1357
1358 #[test]
1359 fn test_iterative_deepening_search_no_candidates() {
1360 let kb = KnowledgeBase::new("test");
1361 let mut ids = IterativeDeepeningSearch::new(5, kb);
1362 let mut root = Goal::new("no_rules".to_string());
1363 let facts = Facts::new();
1366 let result = ids.search(&mut root, &facts);
1367
1368 assert!(!result.success);
1369 assert!(result.path.is_empty());
1370 }
1371
1372 #[test]
1373 fn test_search_strategy_equality() {
1374 assert_eq!(SearchStrategy::BreadthFirst, SearchStrategy::BreadthFirst);
1375 assert_eq!(SearchStrategy::Iterative, SearchStrategy::Iterative);
1376 assert_ne!(SearchStrategy::BreadthFirst, SearchStrategy::Iterative);
1377 }
1378
1379 #[test]
1380 fn test_depth_first_search_goals_explored_count() {
1381 let kb = KnowledgeBase::new("test");
1382 let mut dfs = DepthFirstSearch::new(10, kb);
1383 let facts = Facts::new();
1384
1385 let mut root = Goal::new("root".to_string());
1386 root.add_candidate_rule("RootRule".to_string());
1387
1388 let mut sub = Goal::new("sub".to_string());
1389 sub.add_candidate_rule("SubRule".to_string());
1390
1391 root.add_subgoal(sub);
1392
1393 let result = dfs.search(&mut root, &facts);
1394
1395 assert!(result.success);
1397 assert!(result.goals_explored > 0);
1399 }
1400}