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) => {
282 if self.check_goal_in_facts(goal, facts) {
285 goal.status = GoalStatus::Proven;
286
287 self.solutions.push(Solution {
289 path: self.path.clone(),
290 bindings: goal.bindings.to_map(),
291 });
292
293 if self.max_solutions == 1 || self.solutions.len() >= self.max_solutions
295 {
296 return true; }
298
299 facts.rollback_undo_frame();
302 self.path.pop();
303 continue;
304 }
305 }
307 Ok(false) => {
308 if self.try_prove_rule_conditions(&rule, facts, kb, depth + 1) {
310 match self.executor.try_execute_rule(&rule, facts) {
312 Ok(true) => {
313 if self.check_goal_in_facts(goal, facts) {
314 goal.status = GoalStatus::Proven;
315
316 self.solutions.push(Solution {
318 path: self.path.clone(),
319 bindings: goal.bindings.to_map(),
320 });
321
322 if self.max_solutions == 1
324 || self.solutions.len() >= self.max_solutions
325 {
326 return true; }
328
329 facts.rollback_undo_frame();
331 self.path.pop();
332 continue;
333 }
334 }
335 _ => {
336 }
338 }
339 }
340 }
341 Err(_) => {
342 }
344 }
345 }
346
347 facts.rollback_undo_frame();
349 self.path.pop();
350 }
351
352 let mut all_subgoals_proven = true;
355 if !goal.sub_goals.is_empty() {
356 facts.begin_undo_frame();
357 for sub_goal in &mut goal.sub_goals {
358 if !self.search_recursive_with_execution(sub_goal, facts, kb, depth + 1) {
359 all_subgoals_proven = false;
360 break;
361 }
362 }
363
364 if all_subgoals_proven {
365 facts.commit_undo_frame();
367 goal.status = GoalStatus::Proven;
368 return true;
369 }
370
371 facts.rollback_undo_frame();
373 }
374
375 if !self.solutions.is_empty() {
377 goal.status = GoalStatus::Proven;
378 return !goal.is_negated;
380 }
381
382 if goal.is_negated {
384 goal.status = GoalStatus::Proven;
386 true
387 } else {
388 goal.status = GoalStatus::Unprovable;
390 false
391 }
392 }
393
394 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
399 if let Some(ref graph_arc) = self.proof_graph {
401 if let Ok(mut graph) = graph_arc.lock() {
402 let key = FactKey::from_pattern(&goal.pattern);
403 if graph.is_proven(&key) {
404 return true;
406 }
407 }
408 }
409
410 if goal.is_negated {
412 if let Some(ref expr) = goal.expression {
413 match expr.evaluate(facts) {
415 Ok(Value::Boolean(b)) => return b,
416 Ok(_) => return false, Err(_) => return false,
418 }
419 }
420 return false;
421 }
422
423 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
425 self.executor
427 .evaluate_condition(&condition, facts)
428 .unwrap_or(false)
429 } else {
430 false
431 }
432 }
433
434 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
440 use crate::engine::rule::{Condition, ConditionExpression};
441 use crate::types::Operator;
442
443 let operators = [
445 (">=", Operator::GreaterThanOrEqual),
446 ("<=", Operator::LessThanOrEqual),
447 ("==", Operator::Equal),
448 ("!=", Operator::NotEqual),
449 (" > ", Operator::GreaterThan),
450 (" < ", Operator::LessThan),
451 (" contains ", Operator::Contains),
452 (" not_contains ", Operator::NotContains),
453 (" starts_with ", Operator::StartsWith),
454 (" startsWith ", Operator::StartsWith),
455 (" ends_with ", Operator::EndsWith),
456 (" endsWith ", Operator::EndsWith),
457 (" matches ", Operator::Matches),
458 ];
459
460 for (op_str, operator) in operators {
461 if let Some(pos) = pattern.find(op_str) {
462 let field = pattern[..pos].trim().to_string();
463 let value_str = pattern[pos + op_str.len()..].trim();
464
465 let value = self.parse_value_string(value_str);
467
468 return Some(Condition {
469 field: field.clone(),
470 expression: ConditionExpression::Field(field),
471 operator,
472 value,
473 });
474 }
475 }
476
477 None
478 }
479
480 fn parse_value_string(&self, s: &str) -> Value {
482 let s = s.trim();
483
484 if s == "true" {
486 return Value::Boolean(true);
487 }
488 if s == "false" {
489 return Value::Boolean(false);
490 }
491
492 if s == "null" {
494 return Value::Null;
495 }
496
497 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
499 return Value::String(s[1..s.len() - 1].to_string());
500 }
501
502 if let Ok(n) = s.parse::<f64>() {
504 return Value::Number(n);
505 }
506
507 if let Ok(i) = s.parse::<i64>() {
509 return Value::Integer(i);
510 }
511
512 Value::String(s.to_string())
514 }
515
516 fn try_prove_rule_conditions(
519 &mut self,
520 rule: &Rule,
521 facts: &mut Facts,
522 kb: &KnowledgeBase,
523 depth: usize,
524 ) -> bool {
525 self.try_prove_condition_group(&rule.conditions, facts, kb, depth)
527 }
528
529 fn try_prove_condition_group(
531 &mut self,
532 group: &crate::engine::rule::ConditionGroup,
533 facts: &mut Facts,
534 kb: &KnowledgeBase,
535 depth: usize,
536 ) -> bool {
537 use crate::engine::rule::ConditionGroup;
538
539 match group {
540 ConditionGroup::Single(condition) => {
541 self.try_prove_single_condition(condition, facts, kb, depth)
543 }
544 ConditionGroup::Compound {
545 left,
546 operator,
547 right,
548 } => {
549 use crate::types::LogicalOperator;
551 match operator {
552 LogicalOperator::And => {
553 self.try_prove_condition_group(left, facts, kb, depth)
555 && self.try_prove_condition_group(right, facts, kb, depth)
556 }
557 LogicalOperator::Or => {
558 self.try_prove_condition_group(left, facts, kb, depth)
560 || self.try_prove_condition_group(right, facts, kb, depth)
561 }
562 LogicalOperator::Not => {
563 !self.try_prove_condition_group(left, facts, kb, depth)
565 }
566 }
567 }
568 ConditionGroup::Not(_)
569 | ConditionGroup::Exists(_)
570 | ConditionGroup::Forall(_)
571 | ConditionGroup::Accumulate { .. } => {
572 self.executor
576 .evaluate_conditions(group, facts)
577 .unwrap_or(false)
578 }
579 #[cfg(feature = "streaming")]
580 ConditionGroup::StreamPattern { .. } => {
581 self.executor
583 .evaluate_conditions(group, facts)
584 .unwrap_or(false)
585 }
586 }
587 }
588
589 fn try_prove_single_condition(
591 &mut self,
592 condition: &crate::engine::rule::Condition,
593 facts: &mut Facts,
594 kb: &KnowledgeBase,
595 depth: usize,
596 ) -> bool {
597 if let Ok(satisfied) = self.executor.evaluate_condition(condition, facts) {
599 if satisfied {
600 return true;
601 }
602 }
603
604 let goal_pattern = self.condition_to_goal_pattern(condition);
606
607 let mut sub_goal = Goal::new(goal_pattern.clone());
609 sub_goal.depth = depth;
610
611 for candidate_rule in kb.get_rules() {
613 if self.rule_could_prove_pattern(&candidate_rule, &goal_pattern) {
614 sub_goal.add_candidate_rule(candidate_rule.name.clone());
615 }
616 }
617
618 self.search_recursive_with_execution(&mut sub_goal, facts, kb, depth)
620 }
621
622 fn condition_to_goal_pattern(&self, condition: &crate::engine::rule::Condition) -> String {
624 use crate::engine::rule::ConditionExpression;
625
626 let field = match &condition.expression {
627 ConditionExpression::Field(f) => f.clone(),
628 ConditionExpression::FunctionCall { name, .. } => name.clone(),
629 ConditionExpression::Test { name, .. } => format!("test({})", name),
630 ConditionExpression::MultiField { field, .. } => field.clone(),
631 };
632
633 let op_str = match condition.operator {
634 crate::types::Operator::Equal => "==",
635 crate::types::Operator::NotEqual => "!=",
636 crate::types::Operator::GreaterThan => ">",
637 crate::types::Operator::LessThan => "<",
638 crate::types::Operator::GreaterThanOrEqual => ">=",
639 crate::types::Operator::LessThanOrEqual => "<=",
640 crate::types::Operator::Contains => "contains",
641 crate::types::Operator::NotContains => "not_contains",
642 crate::types::Operator::StartsWith => "starts_with",
643 crate::types::Operator::EndsWith => "ends_with",
644 crate::types::Operator::Matches => "matches",
645 };
646
647 let value_str = match &condition.value {
649 Value::Boolean(b) => b.to_string(),
650 Value::Number(n) => n.to_string(),
651 Value::Integer(i) => i.to_string(),
652 Value::String(s) => format!("\"{}\"", s),
653 Value::Null => "null".to_string(),
654 _ => format!("{:?}", condition.value),
655 };
656
657 format!("{} {} {}", field, op_str, value_str)
658 }
659
660 fn rule_could_prove_pattern(&self, rule: &Rule, pattern: &str) -> bool {
662 for action in &rule.actions {
664 match action {
665 crate::types::ActionType::Set { field, .. } => {
666 if pattern.contains(field) {
667 return true;
668 }
669 }
670 crate::types::ActionType::MethodCall { object, method, .. } => {
671 if pattern.contains(object) || pattern.contains(method) {
672 return true;
673 }
674 }
675 _ => {}
676 }
677 }
678 false
679 }
680
681 fn search_recursive(&mut self, goal: &mut Goal, depth: usize) -> bool {
683 self.goals_explored += 1;
684
685 if depth > self.max_depth {
687 goal.status = GoalStatus::Unprovable;
688 return false;
689 }
690
691 if goal.status == GoalStatus::InProgress {
693 goal.status = GoalStatus::Unprovable;
694 return false;
695 }
696
697 goal.status = GoalStatus::InProgress;
699 goal.depth = depth;
700
701 if let Some(rule_name) = goal.candidate_rules.clone().into_iter().next() {
703 self.path.push(rule_name.clone());
704
705 goal.status = GoalStatus::Proven;
719 return true;
720 }
721
722 for sub_goal in &mut goal.sub_goals {
724 if !self.search_recursive(sub_goal, depth + 1) {
725 goal.status = GoalStatus::Unprovable;
726 return false;
727 }
728 }
729
730 if goal.sub_goals.is_empty() && goal.candidate_rules.is_empty() {
732 goal.status = GoalStatus::Unprovable;
733 return false;
734 }
735
736 goal.status = GoalStatus::Proven;
737 true
738 }
739}
740
741pub struct BreadthFirstSearch {
743 max_depth: usize,
744 goals_explored: usize,
745 executor: RuleExecutor,
746 proof_graph: Option<SharedProofGraph>,
747}
748
749pub struct IterativeDeepeningSearch {
751 max_depth: usize,
752 goals_explored: usize,
753 kb: KnowledgeBase,
754 engine: Option<Arc<Mutex<IncrementalEngine>>>,
755}
756
757impl IterativeDeepeningSearch {
758 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
760 Self {
761 max_depth,
762 goals_explored: 0,
763 kb,
764 engine: None,
765 }
766 }
767
768 pub fn new_with_engine(
770 max_depth: usize,
771 kb: KnowledgeBase,
772 engine: Option<Arc<Mutex<IncrementalEngine>>>,
773 ) -> Self {
774 Self {
776 max_depth,
777 goals_explored: 0,
778 kb,
779 engine,
780 }
781 }
782
783 pub fn search_with_execution(
786 &mut self,
787 root_goal: &mut Goal,
788 facts: &mut Facts,
789 kb: &KnowledgeBase,
790 ) -> SearchResult {
791 self.goals_explored = 0;
792 let mut cumulative_goals = 0usize;
793
794 for depth_limit in 0..=self.max_depth {
796 let mut probe_goal = root_goal.clone();
798 let probe_kb = self.kb.clone();
799 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
800 let probe_result = probe_dfs.search(&mut probe_goal, facts);
801 cumulative_goals += probe_result.goals_explored;
802
803 if probe_result.success {
804 let exec_kb = self.kb.clone();
806 let mut exec_dfs =
807 DepthFirstSearch::new_with_engine(depth_limit, exec_kb, self.engine.clone());
808 let exec_result = exec_dfs.search_with_execution(root_goal, facts, kb);
809 let mut final_result = exec_result;
811 final_result.goals_explored += cumulative_goals - final_result.goals_explored;
812 return final_result;
813 }
814 }
815
816 SearchResult::failure(cumulative_goals, self.max_depth)
818 }
819
820 pub fn search(&mut self, root_goal: &mut Goal, facts: &Facts) -> SearchResult {
822 self.goals_explored = 0;
823 let mut cumulative_goals = 0usize;
824
825 for depth_limit in 0..=self.max_depth {
826 let mut probe_goal = root_goal.clone();
827 let probe_kb = self.kb.clone();
828 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
829 let probe_result = probe_dfs.search(&mut probe_goal, facts);
830 cumulative_goals += probe_result.goals_explored;
831 if probe_result.success {
832 let mut res = probe_result;
834 res.goals_explored = cumulative_goals;
835 return res;
836 }
837 }
838
839 SearchResult::failure(cumulative_goals, self.max_depth)
840 }
841}
842
843impl BreadthFirstSearch {
844 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
846 Self {
847 max_depth,
848 goals_explored: 0,
849 executor: RuleExecutor::new_with_inserter(kb, None),
850 proof_graph: None,
851 }
852 }
853
854 pub fn new_with_engine(
856 max_depth: usize,
857 kb: KnowledgeBase,
858 engine: Option<Arc<Mutex<IncrementalEngine>>>,
859 ) -> Self {
860 let proof_graph = engine.as_ref().map(|_| super::proof_graph::new_shared());
862 let proof_graph_clone = proof_graph.clone();
863
864 let inserter = engine.map(|eng| {
866 let eng = eng.clone();
867 let pg = proof_graph_clone.clone();
868
869 std::sync::Arc::new(
870 move |fact_type: String,
871 data: crate::rete::TypedFacts,
872 rule_name: String,
873 premises: Vec<String>| {
874 if let Ok(mut e) = eng.lock() {
875 let handles = e.resolve_premise_keys(premises.clone());
876
877 let handle = e.insert_logical(
878 fact_type.clone(),
879 data.clone(),
880 rule_name.clone(),
881 handles.clone(),
882 );
883
884 if let Some(ref graph) = pg {
886 if let Ok(mut g) = graph.lock() {
887 let pattern = format!("{}.{}", fact_type, "derived");
888 let key = FactKey::from_pattern(&pattern);
889 g.insert_proof(handle, key, rule_name, handles, premises);
890 }
891 }
892 }
893 },
894 )
895 as std::sync::Arc<
896 dyn Fn(String, crate::rete::TypedFacts, String, Vec<String>) + Send + Sync,
897 >
898 });
899
900 Self {
901 max_depth,
902 goals_explored: 0,
903 executor: RuleExecutor::new_with_inserter(kb, inserter),
904 proof_graph,
905 }
906 }
907
908 pub fn search_with_execution(
910 &mut self,
911 root_goal: &mut Goal,
912 facts: &mut Facts,
913 kb: &KnowledgeBase,
914 ) -> SearchResult {
915 self.goals_explored = 0;
916 let mut queue = VecDeque::new();
917 let mut path = Vec::new();
918 let mut max_depth = 0;
919
920 queue.push_back((root_goal as *mut Goal, 0));
921
922 while let Some((goal_ptr, depth)) = queue.pop_front() {
923 let goal = unsafe { &mut *goal_ptr };
925
926 self.goals_explored += 1;
927 max_depth = max_depth.max(depth);
928
929 if depth > self.max_depth {
930 continue;
931 }
932
933 goal.depth = depth;
934
935 if self.check_goal_in_facts(goal, facts) {
937 goal.status = GoalStatus::Proven;
938 continue;
939 }
940
941 for rule_name in goal.candidate_rules.clone() {
943 path.push(rule_name.clone());
944
945 if let Some(rule) = kb.get_rule(&rule_name) {
947 match self.executor.try_execute_rule(&rule, facts) {
949 Ok(true) => {
950 if self.check_goal_in_facts(goal, facts) {
953 goal.status = GoalStatus::Proven;
954 break;
955 }
956 }
957 Ok(false) => {
958 }
960 Err(_) => {
961 }
963 }
964 }
965 }
966
967 for sub_goal in &mut goal.sub_goals {
969 queue.push_back((sub_goal as *mut Goal, depth + 1));
970 }
971 }
972
973 let success = root_goal.is_proven();
974
975 SearchResult {
976 success,
977 path,
978 goals_explored: self.goals_explored,
979 max_depth_reached: max_depth,
980 bindings: root_goal.bindings.to_map(),
981 solutions: Vec::new(),
982 }
983 }
984
985 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
990 if let Some(ref graph_arc) = self.proof_graph {
992 if let Ok(mut graph) = graph_arc.lock() {
993 let key = FactKey::from_pattern(&goal.pattern);
994 if graph.is_proven(&key) {
995 return true;
997 }
998 }
999 }
1000
1001 if goal.is_negated {
1003 if let Some(ref expr) = goal.expression {
1004 match expr.evaluate(facts) {
1006 Ok(Value::Boolean(b)) => return b,
1007 Ok(_) => return false, Err(_) => return false,
1009 }
1010 }
1011 return false;
1012 }
1013
1014 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
1016 self.executor
1018 .evaluate_condition(&condition, facts)
1019 .unwrap_or(false)
1020 } else {
1021 false
1022 }
1023 }
1024
1025 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
1031 use crate::engine::rule::{Condition, ConditionExpression};
1032 use crate::types::Operator;
1033
1034 let operators = [
1036 (">=", Operator::GreaterThanOrEqual),
1037 ("<=", Operator::LessThanOrEqual),
1038 ("==", Operator::Equal),
1039 ("!=", Operator::NotEqual),
1040 (" > ", Operator::GreaterThan),
1041 (" < ", Operator::LessThan),
1042 (" contains ", Operator::Contains),
1043 (" not_contains ", Operator::NotContains),
1044 (" starts_with ", Operator::StartsWith),
1045 (" startsWith ", Operator::StartsWith),
1046 (" ends_with ", Operator::EndsWith),
1047 (" endsWith ", Operator::EndsWith),
1048 (" matches ", Operator::Matches),
1049 ];
1050
1051 for (op_str, operator) in operators {
1052 if let Some(pos) = pattern.find(op_str) {
1053 let field = pattern[..pos].trim().to_string();
1054 let value_str = pattern[pos + op_str.len()..].trim();
1055
1056 let value = self.parse_value_string(value_str);
1058
1059 return Some(Condition {
1060 field: field.clone(),
1061 expression: ConditionExpression::Field(field),
1062 operator,
1063 value,
1064 });
1065 }
1066 }
1067
1068 None
1069 }
1070
1071 fn parse_value_string(&self, s: &str) -> Value {
1073 let s = s.trim();
1074
1075 if s == "true" {
1077 return Value::Boolean(true);
1078 }
1079 if s == "false" {
1080 return Value::Boolean(false);
1081 }
1082
1083 if s == "null" {
1085 return Value::Null;
1086 }
1087
1088 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
1090 return Value::String(s[1..s.len() - 1].to_string());
1091 }
1092
1093 if let Ok(n) = s.parse::<f64>() {
1095 return Value::Number(n);
1096 }
1097
1098 if let Ok(i) = s.parse::<i64>() {
1100 return Value::Integer(i);
1101 }
1102
1103 Value::String(s.to_string())
1105 }
1106
1107 pub fn search(&mut self, root_goal: &mut Goal, _facts: &Facts) -> SearchResult {
1109 self.goals_explored = 0;
1110 let mut queue = VecDeque::new();
1111 let mut path = Vec::new();
1112 let mut max_depth = 0;
1113
1114 queue.push_back((root_goal as *mut Goal, 0));
1115
1116 while let Some((goal_ptr, depth)) = queue.pop_front() {
1117 let goal = unsafe { &mut *goal_ptr };
1119
1120 self.goals_explored += 1;
1121 max_depth = max_depth.max(depth);
1122
1123 if depth > self.max_depth {
1124 continue;
1125 }
1126
1127 goal.depth = depth;
1128
1129 for rule_name in &goal.candidate_rules {
1131 path.push(rule_name.clone());
1132 }
1133
1134 for sub_goal in &mut goal.sub_goals {
1136 queue.push_back((sub_goal as *mut Goal, depth + 1));
1137 }
1138
1139 if !goal.candidate_rules.is_empty() || goal.all_subgoals_proven() {
1141 goal.status = GoalStatus::Proven;
1142 }
1143 }
1144
1145 let success = root_goal.is_proven();
1146
1147 SearchResult {
1148 success,
1149 path,
1150 goals_explored: self.goals_explored,
1151 max_depth_reached: max_depth,
1152 bindings: root_goal.bindings.to_map(),
1153 solutions: Vec::new(),
1154 }
1155 }
1156}
1157
1158#[cfg(test)]
1159mod tests {
1160 use super::*;
1161 use std::collections::HashMap;
1162
1163 #[test]
1164 fn test_search_strategies() {
1165 assert_eq!(SearchStrategy::DepthFirst, SearchStrategy::DepthFirst);
1166 assert_ne!(SearchStrategy::DepthFirst, SearchStrategy::BreadthFirst);
1167 }
1168
1169 #[test]
1170 fn test_search_result_creation() {
1171 let success = SearchResult::success(vec!["Rule1".to_string()], 5, 3);
1172 assert!(success.success);
1173 assert_eq!(success.path.len(), 1);
1174 assert_eq!(success.goals_explored, 5);
1175
1176 let failure = SearchResult::failure(10, 5);
1177 assert!(!failure.success);
1178 assert!(failure.path.is_empty());
1179 }
1180
1181 #[test]
1182 fn test_depth_first_search_creation() {
1183 let kb = KnowledgeBase::new("test");
1184 let dfs = DepthFirstSearch::new(10, kb);
1185 assert_eq!(dfs.max_depth, 10);
1186 assert_eq!(dfs.goals_explored, 0);
1187 }
1188
1189 #[test]
1190 fn test_depth_first_search_simple() {
1191 let kb = KnowledgeBase::new("test");
1192 let mut dfs = DepthFirstSearch::new(10, kb);
1193 let facts = Facts::new();
1194
1195 let mut goal = Goal::new("test".to_string());
1196 goal.add_candidate_rule("TestRule".to_string());
1197
1198 let result = dfs.search(&mut goal, &facts);
1199
1200 assert!(result.success);
1201 assert!(goal.is_proven());
1202 assert!(result.goals_explored > 0);
1203 }
1204
1205 #[test]
1206 fn test_breadth_first_search() {
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("test".to_string());
1212 goal.add_candidate_rule("TestRule".to_string());
1213
1214 let result = bfs.search(&mut goal, &facts);
1215
1216 assert!(result.success);
1217 assert_eq!(result.goals_explored, 1);
1218 }
1219
1220 #[test]
1221 fn test_iterative_deepening_search_success() {
1222 let kb = KnowledgeBase::new("test");
1223 let mut ids = IterativeDeepeningSearch::new(5, kb.clone());
1224 let mut root = Goal::new("test".to_string());
1225 root.add_candidate_rule("TestRule".to_string());
1226
1227 let facts = Facts::new();
1229 let res = ids.search(&mut root, &facts);
1230 assert!(res.success);
1231 }
1232
1233 #[test]
1234 fn test_iterative_deepening_search_depth_limit() {
1235 let kb = KnowledgeBase::new("test");
1236 let mut ids = IterativeDeepeningSearch::new(0, kb.clone());
1238 let mut root = Goal::new("test".to_string());
1239 let mut sub = Goal::new("sub".to_string());
1241 sub.add_candidate_rule("SubRule".to_string());
1242 root.sub_goals.push(sub);
1243
1244 let facts = Facts::new();
1245 let res = ids.search(&mut root, &facts);
1246 assert!(!res.success);
1247 }
1248
1249 #[test]
1250 fn test_depth_first_search_max_depth_exceeded() {
1251 let kb = KnowledgeBase::new("test");
1252 let mut dfs = DepthFirstSearch::new(2, kb);
1253 let facts = Facts::new();
1254
1255 let mut root = Goal::new("level0".to_string());
1257 root.depth = 0;
1258 root.add_candidate_rule("Rule0".to_string());
1259
1260 let mut level1 = Goal::new("level1".to_string());
1261 level1.depth = 1;
1262 level1.add_candidate_rule("Rule1".to_string());
1263
1264 let mut level2 = Goal::new("level2".to_string());
1265 level2.depth = 2;
1266 level2.add_candidate_rule("Rule2".to_string());
1267
1268 let mut level3 = Goal::new("level3".to_string());
1269 level3.depth = 3; level3.add_candidate_rule("Rule3".to_string());
1271
1272 level2.add_subgoal(level3);
1273 level1.add_subgoal(level2);
1274 root.add_subgoal(level1);
1275
1276 let result = dfs.search(&mut root, &facts);
1277
1278 assert!(result.max_depth_reached <= 3);
1280 }
1281
1282 #[test]
1283 fn test_breadth_first_search_multiple_candidates() {
1284 let kb = KnowledgeBase::new("test");
1285 let mut bfs = BreadthFirstSearch::new(10, kb);
1286 let facts = Facts::new();
1287
1288 let mut goal = Goal::new("multi_rule_goal".to_string());
1289 goal.add_candidate_rule("Rule1".to_string());
1290 goal.add_candidate_rule("Rule2".to_string());
1291 goal.add_candidate_rule("Rule3".to_string());
1292
1293 let result = bfs.search(&mut goal, &facts);
1294
1295 assert!(result.success);
1296 assert_eq!(goal.candidate_rules.len(), 3);
1297 }
1298
1299 #[test]
1300 fn test_depth_first_search_empty_goal() {
1301 let kb = KnowledgeBase::new("test");
1302 let mut dfs = DepthFirstSearch::new(10, kb);
1303 let facts = Facts::new();
1304
1305 let mut goal = Goal::new("".to_string());
1306 let result = dfs.search(&mut goal, &facts);
1309
1310 assert!(!result.success);
1312 }
1313
1314 #[test]
1315 fn test_search_result_with_bindings() {
1316 use crate::types::Value;
1317 let mut bindings = HashMap::new();
1318 bindings.insert("X".to_string(), Value::String("test".to_string()));
1319 bindings.insert("Y".to_string(), Value::Number(42.0));
1320
1321 let result = SearchResult {
1322 success: true,
1323 path: vec!["Rule1".to_string()],
1324 goals_explored: 5,
1325 max_depth_reached: 3,
1326 bindings: bindings.clone(),
1327 solutions: Vec::new(),
1328 };
1329
1330 assert_eq!(result.bindings.len(), 2);
1331 assert_eq!(
1332 result.bindings.get("X"),
1333 Some(&Value::String("test".to_string()))
1334 );
1335 }
1336
1337 #[test]
1338 fn test_breadth_first_search_with_subgoals() {
1339 let kb = KnowledgeBase::new("test");
1340 let mut bfs = BreadthFirstSearch::new(10, kb);
1341 let facts = Facts::new();
1342
1343 let mut root = Goal::new("root".to_string());
1344 root.add_candidate_rule("RootRule".to_string());
1345
1346 let mut sub1 = Goal::new("sub1".to_string());
1347 sub1.add_candidate_rule("Sub1Rule".to_string());
1348
1349 let mut sub2 = Goal::new("sub2".to_string());
1350 sub2.add_candidate_rule("Sub2Rule".to_string());
1351
1352 root.add_subgoal(sub1);
1353 root.add_subgoal(sub2);
1354
1355 let result = bfs.search(&mut root, &facts);
1356
1357 assert!(result.success);
1358 assert!(result.goals_explored >= 3); }
1360
1361 #[test]
1362 fn test_iterative_deepening_search_no_candidates() {
1363 let kb = KnowledgeBase::new("test");
1364 let mut ids = IterativeDeepeningSearch::new(5, kb);
1365 let mut root = Goal::new("no_rules".to_string());
1366 let facts = Facts::new();
1369 let result = ids.search(&mut root, &facts);
1370
1371 assert!(!result.success);
1372 assert!(result.path.is_empty());
1373 }
1374
1375 #[test]
1376 fn test_search_strategy_equality() {
1377 assert_eq!(SearchStrategy::BreadthFirst, SearchStrategy::BreadthFirst);
1378 assert_eq!(SearchStrategy::Iterative, SearchStrategy::Iterative);
1379 assert_ne!(SearchStrategy::BreadthFirst, SearchStrategy::Iterative);
1380 }
1381
1382 #[test]
1383 fn test_depth_first_search_goals_explored_count() {
1384 let kb = KnowledgeBase::new("test");
1385 let mut dfs = DepthFirstSearch::new(10, kb);
1386 let facts = Facts::new();
1387
1388 let mut root = Goal::new("root".to_string());
1389 root.add_candidate_rule("RootRule".to_string());
1390
1391 let mut sub = Goal::new("sub".to_string());
1392 sub.add_candidate_rule("SubRule".to_string());
1393
1394 root.add_subgoal(sub);
1395
1396 let result = dfs.search(&mut root, &facts);
1397
1398 assert!(result.success);
1400 assert!(result.goals_explored > 0);
1402 }
1403}