1use super::goal::{Goal, GoalManager, GoalStatus};
4use super::search::{DepthFirstSearch, BreadthFirstSearch, IterativeDeepeningSearch, SearchStrategy, SearchResult};
5use super::query::{QueryParser, QueryResult, QueryStats, ProofTrace};
6use crate::{Facts, KnowledgeBase};
7use crate::errors::Result;
8use std::sync::Arc;
9
10#[derive(Debug, Clone)]
12pub struct BackwardConfig {
13 pub max_depth: usize,
15
16 pub strategy: SearchStrategy,
18
19 pub enable_memoization: bool,
21
22 pub max_solutions: usize,
24}
25
26impl Default for BackwardConfig {
27 fn default() -> Self {
28 Self {
29 max_depth: 10,
30 strategy: SearchStrategy::DepthFirst,
31 enable_memoization: true,
32 max_solutions: 1,
33 }
34 }
35}
36
37pub struct BackwardEngine {
39 knowledge_base: Arc<KnowledgeBase>,
40 config: BackwardConfig,
41 goal_manager: GoalManager,
42}
43
44impl BackwardEngine {
45 pub fn new(kb: KnowledgeBase) -> Self {
47 Self {
48 knowledge_base: Arc::new(kb),
49 config: BackwardConfig::default(),
50 goal_manager: GoalManager::default(),
51 }
52 }
53
54 pub fn with_config(kb: KnowledgeBase, config: BackwardConfig) -> Self {
56 Self {
57 knowledge_base: Arc::new(kb),
58 goal_manager: GoalManager::new(config.max_depth),
59 config,
60 }
61 }
62
63 pub fn set_config(&mut self, config: BackwardConfig) {
65 self.goal_manager = GoalManager::new(config.max_depth);
66 self.config = config;
67 }
68
69 pub fn query(&mut self, query_str: &str, facts: &mut Facts) -> Result<QueryResult> {
82 self.query_with_rete_engine(query_str, facts, None)
84 }
85
86 pub fn query_with_rete_engine(
88 &mut self,
89 query_str: &str,
90 facts: &mut Facts,
91 rete_engine: Option<std::sync::Arc<std::sync::Mutex<crate::rete::propagation::IncrementalEngine>>>,
92 ) -> Result<QueryResult> {
93 let mut goal = QueryParser::parse(query_str)
95 .map_err(|e| crate::errors::RuleEngineError::ParseError { message: e })?;
96
97 if self.config.enable_memoization {
99 if let Some(cached) = self.goal_manager.is_cached(query_str) {
100 return Ok(if cached {
101 QueryResult::success(
102 goal.bindings.to_map(), ProofTrace::from_goal(&goal),
104 QueryStats::default(),
105 )
106 } else {
107 QueryResult::failure(vec![], QueryStats::default())
108 });
109 }
110 }
111
112 self.find_candidate_rules(&mut goal)?;
114
115 let search_result = match self.config.strategy {
117 SearchStrategy::DepthFirst => {
118 let mut dfs = DepthFirstSearch::new_with_engine(self.config.max_depth, (*self.knowledge_base).clone(), rete_engine.clone());
119 dfs.search_with_execution(&mut goal, facts, &self.knowledge_base)
120 }
121 SearchStrategy::BreadthFirst => {
122 let mut bfs = BreadthFirstSearch::new_with_engine(self.config.max_depth, (*self.knowledge_base).clone(), rete_engine.clone());
123 bfs.search_with_execution(&mut goal, facts, &self.knowledge_base)
124 }
125 SearchStrategy::Iterative => {
126 let mut ids = IterativeDeepeningSearch::new_with_engine(self.config.max_depth, (*self.knowledge_base).clone(), rete_engine.clone());
127 ids.search_with_execution(&mut goal, facts, &self.knowledge_base)
128 }
129 };
130
131 if self.config.enable_memoization {
133 self.goal_manager.cache_result(query_str.to_string(), search_result.success);
134 }
135
136 let stats = QueryStats {
138 goals_explored: search_result.goals_explored,
139 rules_evaluated: search_result.path.len(),
140 max_depth: search_result.max_depth_reached,
141 duration_ms: None,
142 };
143
144 Ok(if search_result.success {
145 QueryResult::success(
146 search_result.bindings,
147 ProofTrace::from_goal(&goal),
148 stats,
149 )
150 } else {
151 QueryResult::failure(self.find_missing_facts(&goal), stats)
152 })
153 }
154
155 fn find_candidate_rules(&self, goal: &mut Goal) -> Result<()> {
157 for rule in self.knowledge_base.get_rules() {
164 if self.rule_could_prove_goal(&rule, goal) {
166 goal.add_candidate_rule(rule.name.clone());
167 }
168 }
169
170 Ok(())
171 }
172
173 fn rule_could_prove_goal(&self, rule: &crate::engine::rule::Rule, goal: &Goal) -> bool {
175 if goal.pattern.contains(&rule.name) {
180 return true;
181 }
182
183 for action in &rule.actions {
185 match action {
186 crate::types::ActionType::Set { field, .. } => {
187 if goal.pattern.contains(field) {
188 return true;
189 }
190 }
191 crate::types::ActionType::MethodCall { object, method, .. } => {
192 if goal.pattern.contains(object) || goal.pattern.contains(method) {
193 return true;
194 }
195 }
196 _ => {}
197 }
198 }
199
200 false
201 }
202
203 fn find_missing_facts(&self, goal: &Goal) -> Vec<String> {
205 let mut missing = Vec::new();
206
207 self.collect_missing_recursive(goal, &mut missing);
209
210 missing
211 }
212
213 fn collect_missing_recursive(&self, goal: &Goal, missing: &mut Vec<String>) {
214 if goal.status == GoalStatus::Unprovable {
215 missing.push(goal.pattern.clone());
216 }
217
218 for sub_goal in &goal.sub_goals {
219 self.collect_missing_recursive(sub_goal, missing);
220 }
221 }
222
223 pub fn explain_why(&mut self, query_str: &str, facts: &mut Facts) -> Result<String> {
225 let result = self.query(query_str, facts)?;
226
227 if result.provable {
228 Ok(format!(
229 "Goal '{}' is PROVABLE\nProof trace:\n{:#?}",
230 query_str, result.proof_trace
231 ))
232 } else {
233 Ok(format!(
234 "Goal '{}' is NOT provable\nMissing facts: {:?}",
235 query_str, result.missing_facts
236 ))
237 }
238 }
239
240 pub fn config(&self) -> &BackwardConfig {
242 &self.config
243 }
244
245 pub fn knowledge_base(&self) -> &KnowledgeBase {
247 &self.knowledge_base
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 use crate::KnowledgeBase;
255 use crate::types::Value;
256
257 #[test]
258 fn test_engine_creation() {
259 let kb = KnowledgeBase::new("test");
260 let engine = BackwardEngine::new(kb);
261
262 assert_eq!(engine.config.max_depth, 10);
263 assert_eq!(engine.config.strategy, SearchStrategy::DepthFirst);
264 }
265
266 #[test]
267 fn test_config_customization() {
268 let kb = KnowledgeBase::new("test");
269 let config = BackwardConfig {
270 max_depth: 5,
271 strategy: SearchStrategy::BreadthFirst,
272 enable_memoization: false,
273 max_solutions: 10,
274 };
275
276 let engine = BackwardEngine::with_config(kb, config);
277 assert_eq!(engine.config.max_depth, 5);
278 assert_eq!(engine.config.strategy, SearchStrategy::BreadthFirst);
279 assert!(!engine.config.enable_memoization);
280 }
281
282 #[test]
283 fn test_query_simple() {
284 let kb = KnowledgeBase::new("test");
285 let mut engine = BackwardEngine::new(kb);
286 let mut facts = Facts::new();
287
288 let result = engine.query("User.IsVIP == true", &mut facts);
290 assert!(result.is_ok());
291 }
292
293 #[test]
294 fn test_function_call_condition_len() {
295 use crate::engine::rule::{Rule, Condition, ConditionGroup};
296 use crate::types::{Operator, ActionType};
297
298 let mut kb = KnowledgeBase::new("test");
299
300 let conditions = ConditionGroup::Single(
302 Condition::with_function(
303 "len".to_string(),
304 vec!["User.Name".to_string()],
305 Operator::GreaterThan,
306 Value::Number(3.0),
307 )
308 );
309 let actions = vec![ActionType::Set {
310 field: "User.HasLongName".to_string(),
311 value: Value::Boolean(true),
312 }];
313
314 let rule = Rule::new("CheckNameLength".to_string(), conditions, actions);
315 kb.add_rule(rule);
316
317 let mut engine = BackwardEngine::new(kb);
318 let mut facts = Facts::new();
319 facts.set("User.Name", Value::String("John".to_string()));
320
321 let result = engine.query("User.HasLongName == true", &mut facts);
323 assert!(result.is_ok());
324 let query_result = result.unwrap();
325
326 assert!(query_result.provable, "Query should be provable with len() function");
328 }
329
330 #[test]
331 fn test_function_call_condition_isempty() {
332 use crate::engine::rule::{Rule, Condition, ConditionGroup};
333 use crate::types::{Operator, ActionType};
334
335 let mut kb = KnowledgeBase::new("test");
336
337 let conditions = ConditionGroup::Single(
339 Condition::with_function(
340 "isEmpty".to_string(),
341 vec!["User.Description".to_string()],
342 Operator::Equal,
343 Value::Boolean(false),
344 )
345 );
346 let actions = vec![ActionType::Set {
347 field: "User.HasDescription".to_string(),
348 value: Value::Boolean(true),
349 }];
350
351 let rule = Rule::new("CheckDescription".to_string(), conditions, actions);
352 kb.add_rule(rule);
353
354 let mut engine = BackwardEngine::new(kb);
355 let mut facts = Facts::new();
356 facts.set("User.Description", Value::String("A great user".to_string()));
357
358 let result = engine.query("User.HasDescription == true", &mut facts);
359 assert!(result.is_ok());
360 let query_result = result.unwrap();
361
362 assert!(query_result.provable, "Query should be provable with isEmpty() function");
364 }
365
366 #[test]
367 fn test_test_expression_exists() {
368 use crate::engine::rule::{Rule, Condition, ConditionGroup, ConditionExpression};
369 use crate::types::{Operator, ActionType};
370
371 let mut kb = KnowledgeBase::new("test");
372
373 let condition = Condition {
375 field: "User.Email".to_string(), expression: ConditionExpression::Test {
377 name: "exists".to_string(),
378 args: vec!["User.Email".to_string()],
379 },
380 operator: Operator::Equal,
381 value: Value::Boolean(true),
382 };
383 let conditions = ConditionGroup::Single(condition);
384 let actions = vec![ActionType::Set {
385 field: "User.HasEmail".to_string(),
386 value: Value::Boolean(true),
387 }];
388
389 let rule = Rule::new("CheckEmail".to_string(), conditions, actions);
390 kb.add_rule(rule);
391
392 let mut engine = BackwardEngine::new(kb);
393 let mut facts = Facts::new();
394 facts.set("User.Email", Value::String("user@example.com".to_string()));
395
396 let result = engine.query("User.HasEmail == true", &mut facts);
397 assert!(result.is_ok());
398 let query_result = result.unwrap();
399
400 assert!(query_result.provable, "Query should be provable with exists test");
402 }
403
404 #[test]
405 fn test_multifield_count_operation() {
406 use crate::engine::rule::{Rule, Condition, ConditionGroup, ConditionExpression};
407 use crate::types::{Operator, ActionType};
408
409 let mut kb = KnowledgeBase::new("test");
410
411 let condition = Condition {
413 field: "User.Orders".to_string(), expression: ConditionExpression::MultiField {
415 field: "User.Orders".to_string(),
416 operation: "count".to_string(),
417 variable: None,
418 },
419 operator: Operator::GreaterThan,
420 value: Value::Number(5.0),
421 };
422 let conditions = ConditionGroup::Single(condition);
423 let actions = vec![ActionType::Set {
424 field: "User.IsFrequentBuyer".to_string(),
425 value: Value::Boolean(true),
426 }];
427
428 let rule = Rule::new("CheckFrequentBuyer".to_string(), conditions, actions);
429 kb.add_rule(rule);
430
431 let mut engine = BackwardEngine::new(kb);
432 let mut facts = Facts::new();
433
434 let orders = Value::Array(vec![
436 Value::Number(1.0),
437 Value::Number(2.0),
438 Value::Number(3.0),
439 Value::Number(4.0),
440 Value::Number(5.0),
441 Value::Number(6.0),
442 ]);
443 facts.set("User.Orders", orders);
444
445 let result = engine.query("User.IsFrequentBuyer == true", &mut facts);
446 assert!(result.is_ok());
447 let query_result = result.unwrap();
448
449 assert!(query_result.provable, "Query should be provable with count multifield operation");
451 }
452
453 #[test]
454 fn test_fact_derivation_basic() {
455 use crate::engine::rule::{Rule, Condition, ConditionGroup};
456 use crate::types::{Operator, ActionType};
457
458 let mut kb = KnowledgeBase::new("test");
459
460 let conditions = ConditionGroup::Single(
462 Condition::new(
463 "User.Age".to_string(),
464 Operator::GreaterThan,
465 Value::Number(18.0),
466 )
467 );
468 let actions = vec![ActionType::Set {
469 field: "User.IsAdult".to_string(),
470 value: Value::Boolean(true),
471 }];
472
473 let rule = Rule::new("DetermineAdult".to_string(), conditions, actions);
474 kb.add_rule(rule);
475
476 let mut engine = BackwardEngine::new(kb);
477 let mut facts = Facts::new();
478 facts.set("User.Age", Value::Number(25.0));
479
480 let result = engine.query("User.IsAdult == true", &mut facts);
482 assert!(result.is_ok());
483 let query_result = result.unwrap();
484
485 assert!(query_result.provable, "Fact should be derived by rule action");
486 }
487
488 #[test]
489 fn test_rule_chaining_two_levels() {
490 use crate::engine::rule::{Rule, Condition, ConditionGroup};
491 use crate::types::{Operator, ActionType, LogicalOperator};
492
493 let mut kb = KnowledgeBase::new("test");
494
495 let conditions1 = ConditionGroup::Single(
497 Condition::new(
498 "User.LoyaltyPoints".to_string(),
499 Operator::GreaterThan,
500 Value::Number(100.0),
501 )
502 );
503 let actions1 = vec![ActionType::Set {
504 field: "User.IsVIP".to_string(),
505 value: Value::Boolean(true),
506 }];
507 let rule1 = Rule::new("DetermineVIP".to_string(), conditions1, actions1);
508
509 let conditions2 = ConditionGroup::Compound {
511 left: Box::new(ConditionGroup::Single(
512 Condition::new(
513 "User.IsVIP".to_string(),
514 Operator::Equal,
515 Value::Boolean(true),
516 )
517 )),
518 operator: LogicalOperator::And,
519 right: Box::new(ConditionGroup::Single(
520 Condition::new(
521 "Order.Amount".to_string(),
522 Operator::LessThan,
523 Value::Number(10000.0),
524 )
525 )),
526 };
527 let actions2 = vec![ActionType::Set {
528 field: "Order.AutoApproved".to_string(),
529 value: Value::Boolean(true),
530 }];
531 let rule2 = Rule::new("AutoApproveVIP".to_string(), conditions2, actions2);
532
533 kb.add_rule(rule1);
534 kb.add_rule(rule2);
535
536 let mut engine = BackwardEngine::new(kb);
537 let mut facts = Facts::new();
538 facts.set("User.LoyaltyPoints", Value::Number(150.0));
539 facts.set("Order.Amount", Value::Number(5000.0));
540
541 let result = engine.query("Order.AutoApproved == true", &mut facts);
549 assert!(result.is_ok());
550 let query_result = result.unwrap();
551
552 assert!(query_result.provable, "Query should be provable through 2-level rule chaining");
553 }
554
555 #[test]
556 fn test_fact_derivation_with_log_action() {
557 use crate::engine::rule::{Rule, Condition, ConditionGroup};
558 use crate::types::{Operator, ActionType};
559
560 let mut kb = KnowledgeBase::new("test");
561
562 let conditions = ConditionGroup::Single(
564 Condition::new(
565 "User.Score".to_string(),
566 Operator::GreaterThan,
567 Value::Number(90.0),
568 )
569 );
570 let actions = vec![
571 ActionType::Log {
572 message: "High score achieved!".to_string(),
573 },
574 ActionType::Set {
575 field: "User.HasHighScore".to_string(),
576 value: Value::Boolean(true),
577 }
578 ];
579
580 let rule = Rule::new("HighScoreRule".to_string(), conditions, actions);
581 kb.add_rule(rule);
582
583 let mut engine = BackwardEngine::new(kb);
584 let mut facts = Facts::new();
585 facts.set("User.Score", Value::Number(95.0));
586
587 let result = engine.query("User.HasHighScore == true", &mut facts);
588 assert!(result.is_ok());
589 let query_result = result.unwrap();
590
591 assert!(query_result.provable, "Query should be provable with log action");
593 }
594}