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 crate::types::Operator::In => "in",
646 };
647
648 let value_str = match &condition.value {
650 Value::Boolean(b) => b.to_string(),
651 Value::Number(n) => n.to_string(),
652 Value::Integer(i) => i.to_string(),
653 Value::String(s) => format!("\"{}\"", s),
654 Value::Null => "null".to_string(),
655 _ => format!("{:?}", condition.value),
656 };
657
658 format!("{} {} {}", field, op_str, value_str)
659 }
660
661 fn rule_could_prove_pattern(&self, rule: &Rule, pattern: &str) -> bool {
663 for action in &rule.actions {
665 match action {
666 crate::types::ActionType::Set { field, .. } => {
667 if pattern.contains(field) {
668 return true;
669 }
670 }
671 crate::types::ActionType::MethodCall { object, method, .. } => {
672 if pattern.contains(object) || pattern.contains(method) {
673 return true;
674 }
675 }
676 _ => {}
677 }
678 }
679 false
680 }
681
682 fn search_recursive(&mut self, goal: &mut Goal, depth: usize) -> bool {
684 self.goals_explored += 1;
685
686 if depth > self.max_depth {
688 goal.status = GoalStatus::Unprovable;
689 return false;
690 }
691
692 if goal.status == GoalStatus::InProgress {
694 goal.status = GoalStatus::Unprovable;
695 return false;
696 }
697
698 goal.status = GoalStatus::InProgress;
700 goal.depth = depth;
701
702 if let Some(rule_name) = goal.candidate_rules.clone().into_iter().next() {
704 self.path.push(rule_name.clone());
705
706 goal.status = GoalStatus::Proven;
720 return true;
721 }
722
723 for sub_goal in &mut goal.sub_goals {
725 if !self.search_recursive(sub_goal, depth + 1) {
726 goal.status = GoalStatus::Unprovable;
727 return false;
728 }
729 }
730
731 if goal.sub_goals.is_empty() && goal.candidate_rules.is_empty() {
733 goal.status = GoalStatus::Unprovable;
734 return false;
735 }
736
737 goal.status = GoalStatus::Proven;
738 true
739 }
740}
741
742pub struct BreadthFirstSearch {
744 max_depth: usize,
745 goals_explored: usize,
746 executor: RuleExecutor,
747 proof_graph: Option<SharedProofGraph>,
748}
749
750pub struct IterativeDeepeningSearch {
752 max_depth: usize,
753 goals_explored: usize,
754 kb: KnowledgeBase,
755 engine: Option<Arc<Mutex<IncrementalEngine>>>,
756}
757
758impl IterativeDeepeningSearch {
759 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
761 Self {
762 max_depth,
763 goals_explored: 0,
764 kb,
765 engine: None,
766 }
767 }
768
769 pub fn new_with_engine(
771 max_depth: usize,
772 kb: KnowledgeBase,
773 engine: Option<Arc<Mutex<IncrementalEngine>>>,
774 ) -> Self {
775 Self {
777 max_depth,
778 goals_explored: 0,
779 kb,
780 engine,
781 }
782 }
783
784 pub fn search_with_execution(
787 &mut self,
788 root_goal: &mut Goal,
789 facts: &mut Facts,
790 kb: &KnowledgeBase,
791 ) -> SearchResult {
792 self.goals_explored = 0;
793 let mut cumulative_goals = 0usize;
794
795 for depth_limit in 0..=self.max_depth {
797 let mut probe_goal = root_goal.clone();
799 let probe_kb = self.kb.clone();
800 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
801 let probe_result = probe_dfs.search(&mut probe_goal, facts);
802 cumulative_goals += probe_result.goals_explored;
803
804 if probe_result.success {
805 let exec_kb = self.kb.clone();
807 let mut exec_dfs =
808 DepthFirstSearch::new_with_engine(depth_limit, exec_kb, self.engine.clone());
809 let exec_result = exec_dfs.search_with_execution(root_goal, facts, kb);
810 let mut final_result = exec_result;
812 final_result.goals_explored += cumulative_goals - final_result.goals_explored;
813 return final_result;
814 }
815 }
816
817 SearchResult::failure(cumulative_goals, self.max_depth)
819 }
820
821 pub fn search(&mut self, root_goal: &mut Goal, facts: &Facts) -> SearchResult {
823 self.goals_explored = 0;
824 let mut cumulative_goals = 0usize;
825
826 for depth_limit in 0..=self.max_depth {
827 let mut probe_goal = root_goal.clone();
828 let probe_kb = self.kb.clone();
829 let mut probe_dfs = DepthFirstSearch::new(depth_limit, probe_kb);
830 let probe_result = probe_dfs.search(&mut probe_goal, facts);
831 cumulative_goals += probe_result.goals_explored;
832 if probe_result.success {
833 let mut res = probe_result;
835 res.goals_explored = cumulative_goals;
836 return res;
837 }
838 }
839
840 SearchResult::failure(cumulative_goals, self.max_depth)
841 }
842}
843
844impl BreadthFirstSearch {
845 pub fn new(max_depth: usize, kb: KnowledgeBase) -> Self {
847 Self {
848 max_depth,
849 goals_explored: 0,
850 executor: RuleExecutor::new_with_inserter(kb, None),
851 proof_graph: None,
852 }
853 }
854
855 pub fn new_with_engine(
857 max_depth: usize,
858 kb: KnowledgeBase,
859 engine: Option<Arc<Mutex<IncrementalEngine>>>,
860 ) -> Self {
861 let proof_graph = engine.as_ref().map(|_| super::proof_graph::new_shared());
863 let proof_graph_clone = proof_graph.clone();
864
865 let inserter = engine.map(|eng| {
867 let eng = eng.clone();
868 let pg = proof_graph_clone.clone();
869
870 std::sync::Arc::new(
871 move |fact_type: String,
872 data: crate::rete::TypedFacts,
873 rule_name: String,
874 premises: Vec<String>| {
875 if let Ok(mut e) = eng.lock() {
876 let handles = e.resolve_premise_keys(premises.clone());
877
878 let handle = e.insert_logical(
879 fact_type.clone(),
880 data.clone(),
881 rule_name.clone(),
882 handles.clone(),
883 );
884
885 if let Some(ref graph) = pg {
887 if let Ok(mut g) = graph.lock() {
888 let pattern = format!("{}.{}", fact_type, "derived");
889 let key = FactKey::from_pattern(&pattern);
890 g.insert_proof(handle, key, rule_name, handles, premises);
891 }
892 }
893 }
894 },
895 )
896 as std::sync::Arc<
897 dyn Fn(String, crate::rete::TypedFacts, String, Vec<String>) + Send + Sync,
898 >
899 });
900
901 Self {
902 max_depth,
903 goals_explored: 0,
904 executor: RuleExecutor::new_with_inserter(kb, inserter),
905 proof_graph,
906 }
907 }
908
909 pub fn search_with_execution(
911 &mut self,
912 root_goal: &mut Goal,
913 facts: &mut Facts,
914 kb: &KnowledgeBase,
915 ) -> SearchResult {
916 self.goals_explored = 0;
917 let mut queue = VecDeque::new();
918 let mut path = Vec::new();
919 let mut max_depth = 0;
920
921 queue.push_back((root_goal as *mut Goal, 0));
922
923 while let Some((goal_ptr, depth)) = queue.pop_front() {
924 let goal = unsafe { &mut *goal_ptr };
926
927 self.goals_explored += 1;
928 max_depth = max_depth.max(depth);
929
930 if depth > self.max_depth {
931 continue;
932 }
933
934 goal.depth = depth;
935
936 if self.check_goal_in_facts(goal, facts) {
938 goal.status = GoalStatus::Proven;
939 continue;
940 }
941
942 for rule_name in goal.candidate_rules.clone() {
944 path.push(rule_name.clone());
945
946 if let Some(rule) = kb.get_rule(&rule_name) {
948 match self.executor.try_execute_rule(&rule, facts) {
950 Ok(true) => {
951 if self.check_goal_in_facts(goal, facts) {
954 goal.status = GoalStatus::Proven;
955 break;
956 }
957 }
958 Ok(false) => {
959 }
961 Err(_) => {
962 }
964 }
965 }
966 }
967
968 for sub_goal in &mut goal.sub_goals {
970 queue.push_back((sub_goal as *mut Goal, depth + 1));
971 }
972 }
973
974 let success = root_goal.is_proven();
975
976 SearchResult {
977 success,
978 path,
979 goals_explored: self.goals_explored,
980 max_depth_reached: max_depth,
981 bindings: root_goal.bindings.to_map(),
982 solutions: Vec::new(),
983 }
984 }
985
986 fn check_goal_in_facts(&self, goal: &Goal, facts: &Facts) -> bool {
991 if let Some(ref graph_arc) = self.proof_graph {
993 if let Ok(mut graph) = graph_arc.lock() {
994 let key = FactKey::from_pattern(&goal.pattern);
995 if graph.is_proven(&key) {
996 return true;
998 }
999 }
1000 }
1001
1002 if goal.is_negated {
1004 if let Some(ref expr) = goal.expression {
1005 match expr.evaluate(facts) {
1007 Ok(Value::Boolean(b)) => return b,
1008 Ok(_) => return false, Err(_) => return false,
1010 }
1011 }
1012 return false;
1013 }
1014
1015 if let Some(condition) = self.parse_goal_pattern(&goal.pattern) {
1017 self.executor
1019 .evaluate_condition(&condition, facts)
1020 .unwrap_or(false)
1021 } else {
1022 false
1023 }
1024 }
1025
1026 fn parse_goal_pattern(&self, pattern: &str) -> Option<crate::engine::rule::Condition> {
1032 use crate::engine::rule::{Condition, ConditionExpression};
1033 use crate::types::Operator;
1034
1035 let operators = [
1037 (">=", Operator::GreaterThanOrEqual),
1038 ("<=", Operator::LessThanOrEqual),
1039 ("==", Operator::Equal),
1040 ("!=", Operator::NotEqual),
1041 (" > ", Operator::GreaterThan),
1042 (" < ", Operator::LessThan),
1043 (" contains ", Operator::Contains),
1044 (" not_contains ", Operator::NotContains),
1045 (" starts_with ", Operator::StartsWith),
1046 (" startsWith ", Operator::StartsWith),
1047 (" ends_with ", Operator::EndsWith),
1048 (" endsWith ", Operator::EndsWith),
1049 (" matches ", Operator::Matches),
1050 ];
1051
1052 for (op_str, operator) in operators {
1053 if let Some(pos) = pattern.find(op_str) {
1054 let field = pattern[..pos].trim().to_string();
1055 let value_str = pattern[pos + op_str.len()..].trim();
1056
1057 let value = self.parse_value_string(value_str);
1059
1060 return Some(Condition {
1061 field: field.clone(),
1062 expression: ConditionExpression::Field(field),
1063 operator,
1064 value,
1065 });
1066 }
1067 }
1068
1069 None
1070 }
1071
1072 fn parse_value_string(&self, s: &str) -> Value {
1074 let s = s.trim();
1075
1076 if s == "true" {
1078 return Value::Boolean(true);
1079 }
1080 if s == "false" {
1081 return Value::Boolean(false);
1082 }
1083
1084 if s == "null" {
1086 return Value::Null;
1087 }
1088
1089 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
1091 return Value::String(s[1..s.len() - 1].to_string());
1092 }
1093
1094 if let Ok(n) = s.parse::<f64>() {
1096 return Value::Number(n);
1097 }
1098
1099 if let Ok(i) = s.parse::<i64>() {
1101 return Value::Integer(i);
1102 }
1103
1104 Value::String(s.to_string())
1106 }
1107
1108 pub fn search(&mut self, root_goal: &mut Goal, _facts: &Facts) -> SearchResult {
1110 self.goals_explored = 0;
1111 let mut queue = VecDeque::new();
1112 let mut path = Vec::new();
1113 let mut max_depth = 0;
1114
1115 queue.push_back((root_goal as *mut Goal, 0));
1116
1117 while let Some((goal_ptr, depth)) = queue.pop_front() {
1118 let goal = unsafe { &mut *goal_ptr };
1120
1121 self.goals_explored += 1;
1122 max_depth = max_depth.max(depth);
1123
1124 if depth > self.max_depth {
1125 continue;
1126 }
1127
1128 goal.depth = depth;
1129
1130 for rule_name in &goal.candidate_rules {
1132 path.push(rule_name.clone());
1133 }
1134
1135 for sub_goal in &mut goal.sub_goals {
1137 queue.push_back((sub_goal as *mut Goal, depth + 1));
1138 }
1139
1140 if !goal.candidate_rules.is_empty() || goal.all_subgoals_proven() {
1142 goal.status = GoalStatus::Proven;
1143 }
1144 }
1145
1146 let success = root_goal.is_proven();
1147
1148 SearchResult {
1149 success,
1150 path,
1151 goals_explored: self.goals_explored,
1152 max_depth_reached: max_depth,
1153 bindings: root_goal.bindings.to_map(),
1154 solutions: Vec::new(),
1155 }
1156 }
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161 use super::*;
1162 use std::collections::HashMap;
1163
1164 #[test]
1165 fn test_search_strategies() {
1166 assert_eq!(SearchStrategy::DepthFirst, SearchStrategy::DepthFirst);
1167 assert_ne!(SearchStrategy::DepthFirst, SearchStrategy::BreadthFirst);
1168 }
1169
1170 #[test]
1171 fn test_search_result_creation() {
1172 let success = SearchResult::success(vec!["Rule1".to_string()], 5, 3);
1173 assert!(success.success);
1174 assert_eq!(success.path.len(), 1);
1175 assert_eq!(success.goals_explored, 5);
1176
1177 let failure = SearchResult::failure(10, 5);
1178 assert!(!failure.success);
1179 assert!(failure.path.is_empty());
1180 }
1181
1182 #[test]
1183 fn test_depth_first_search_creation() {
1184 let kb = KnowledgeBase::new("test");
1185 let dfs = DepthFirstSearch::new(10, kb);
1186 assert_eq!(dfs.max_depth, 10);
1187 assert_eq!(dfs.goals_explored, 0);
1188 }
1189
1190 #[test]
1191 fn test_depth_first_search_simple() {
1192 let kb = KnowledgeBase::new("test");
1193 let mut dfs = DepthFirstSearch::new(10, kb);
1194 let facts = Facts::new();
1195
1196 let mut goal = Goal::new("test".to_string());
1197 goal.add_candidate_rule("TestRule".to_string());
1198
1199 let result = dfs.search(&mut goal, &facts);
1200
1201 assert!(result.success);
1202 assert!(goal.is_proven());
1203 assert!(result.goals_explored > 0);
1204 }
1205
1206 #[test]
1207 fn test_breadth_first_search() {
1208 let kb = KnowledgeBase::new("test");
1209 let mut bfs = BreadthFirstSearch::new(10, kb);
1210 let facts = Facts::new();
1211
1212 let mut goal = Goal::new("test".to_string());
1213 goal.add_candidate_rule("TestRule".to_string());
1214
1215 let result = bfs.search(&mut goal, &facts);
1216
1217 assert!(result.success);
1218 assert_eq!(result.goals_explored, 1);
1219 }
1220
1221 #[test]
1222 fn test_iterative_deepening_search_success() {
1223 let kb = KnowledgeBase::new("test");
1224 let mut ids = IterativeDeepeningSearch::new(5, kb.clone());
1225 let mut root = Goal::new("test".to_string());
1226 root.add_candidate_rule("TestRule".to_string());
1227
1228 let facts = Facts::new();
1230 let res = ids.search(&mut root, &facts);
1231 assert!(res.success);
1232 }
1233
1234 #[test]
1235 fn test_iterative_deepening_search_depth_limit() {
1236 let kb = KnowledgeBase::new("test");
1237 let mut ids = IterativeDeepeningSearch::new(0, kb.clone());
1239 let mut root = Goal::new("test".to_string());
1240 let mut sub = Goal::new("sub".to_string());
1242 sub.add_candidate_rule("SubRule".to_string());
1243 root.sub_goals.push(sub);
1244
1245 let facts = Facts::new();
1246 let res = ids.search(&mut root, &facts);
1247 assert!(!res.success);
1248 }
1249
1250 #[test]
1251 fn test_depth_first_search_max_depth_exceeded() {
1252 let kb = KnowledgeBase::new("test");
1253 let mut dfs = DepthFirstSearch::new(2, kb);
1254 let facts = Facts::new();
1255
1256 let mut root = Goal::new("level0".to_string());
1258 root.depth = 0;
1259 root.add_candidate_rule("Rule0".to_string());
1260
1261 let mut level1 = Goal::new("level1".to_string());
1262 level1.depth = 1;
1263 level1.add_candidate_rule("Rule1".to_string());
1264
1265 let mut level2 = Goal::new("level2".to_string());
1266 level2.depth = 2;
1267 level2.add_candidate_rule("Rule2".to_string());
1268
1269 let mut level3 = Goal::new("level3".to_string());
1270 level3.depth = 3; level3.add_candidate_rule("Rule3".to_string());
1272
1273 level2.add_subgoal(level3);
1274 level1.add_subgoal(level2);
1275 root.add_subgoal(level1);
1276
1277 let result = dfs.search(&mut root, &facts);
1278
1279 assert!(result.max_depth_reached <= 3);
1281 }
1282
1283 #[test]
1284 fn test_breadth_first_search_multiple_candidates() {
1285 let kb = KnowledgeBase::new("test");
1286 let mut bfs = BreadthFirstSearch::new(10, kb);
1287 let facts = Facts::new();
1288
1289 let mut goal = Goal::new("multi_rule_goal".to_string());
1290 goal.add_candidate_rule("Rule1".to_string());
1291 goal.add_candidate_rule("Rule2".to_string());
1292 goal.add_candidate_rule("Rule3".to_string());
1293
1294 let result = bfs.search(&mut goal, &facts);
1295
1296 assert!(result.success);
1297 assert_eq!(goal.candidate_rules.len(), 3);
1298 }
1299
1300 #[test]
1301 fn test_depth_first_search_empty_goal() {
1302 let kb = KnowledgeBase::new("test");
1303 let mut dfs = DepthFirstSearch::new(10, kb);
1304 let facts = Facts::new();
1305
1306 let mut goal = Goal::new("".to_string());
1307 let result = dfs.search(&mut goal, &facts);
1310
1311 assert!(!result.success);
1313 }
1314
1315 #[test]
1316 fn test_search_result_with_bindings() {
1317 use crate::types::Value;
1318 let mut bindings = HashMap::new();
1319 bindings.insert("X".to_string(), Value::String("test".to_string()));
1320 bindings.insert("Y".to_string(), Value::Number(42.0));
1321
1322 let result = SearchResult {
1323 success: true,
1324 path: vec!["Rule1".to_string()],
1325 goals_explored: 5,
1326 max_depth_reached: 3,
1327 bindings: bindings.clone(),
1328 solutions: Vec::new(),
1329 };
1330
1331 assert_eq!(result.bindings.len(), 2);
1332 assert_eq!(
1333 result.bindings.get("X"),
1334 Some(&Value::String("test".to_string()))
1335 );
1336 }
1337
1338 #[test]
1339 fn test_breadth_first_search_with_subgoals() {
1340 let kb = KnowledgeBase::new("test");
1341 let mut bfs = BreadthFirstSearch::new(10, kb);
1342 let facts = Facts::new();
1343
1344 let mut root = Goal::new("root".to_string());
1345 root.add_candidate_rule("RootRule".to_string());
1346
1347 let mut sub1 = Goal::new("sub1".to_string());
1348 sub1.add_candidate_rule("Sub1Rule".to_string());
1349
1350 let mut sub2 = Goal::new("sub2".to_string());
1351 sub2.add_candidate_rule("Sub2Rule".to_string());
1352
1353 root.add_subgoal(sub1);
1354 root.add_subgoal(sub2);
1355
1356 let result = bfs.search(&mut root, &facts);
1357
1358 assert!(result.success);
1359 assert!(result.goals_explored >= 3); }
1361
1362 #[test]
1363 fn test_iterative_deepening_search_no_candidates() {
1364 let kb = KnowledgeBase::new("test");
1365 let mut ids = IterativeDeepeningSearch::new(5, kb);
1366 let mut root = Goal::new("no_rules".to_string());
1367 let facts = Facts::new();
1370 let result = ids.search(&mut root, &facts);
1371
1372 assert!(!result.success);
1373 assert!(result.path.is_empty());
1374 }
1375
1376 #[test]
1377 fn test_search_strategy_equality() {
1378 assert_eq!(SearchStrategy::BreadthFirst, SearchStrategy::BreadthFirst);
1379 assert_eq!(SearchStrategy::Iterative, SearchStrategy::Iterative);
1380 assert_ne!(SearchStrategy::BreadthFirst, SearchStrategy::Iterative);
1381 }
1382
1383 #[test]
1384 fn test_depth_first_search_goals_explored_count() {
1385 let kb = KnowledgeBase::new("test");
1386 let mut dfs = DepthFirstSearch::new(10, kb);
1387 let facts = Facts::new();
1388
1389 let mut root = Goal::new("root".to_string());
1390 root.add_candidate_rule("RootRule".to_string());
1391
1392 let mut sub = Goal::new("sub".to_string());
1393 sub.add_candidate_rule("SubRule".to_string());
1394
1395 root.add_subgoal(sub);
1396
1397 let result = dfs.search(&mut root, &facts);
1398
1399 assert!(result.success);
1401 assert!(result.goals_explored > 0);
1403 }
1404}