rust_rule_engine/backward/
nested.rs1use super::goal::Goal;
27use super::unification::Bindings;
28
29#[derive(Debug, Clone)]
31pub struct NestedQuery {
32 pub outer_goal: Goal,
34
35 pub subquery: Box<Query>,
37
38 pub shared_variables: Vec<String>,
40}
41
42#[derive(Debug, Clone)]
44pub struct Query {
45 pub goals: Vec<Goal>,
47
48 pub nested: Vec<NestedQuery>,
50
51 pub pattern: String,
53}
54
55impl Query {
56 pub fn new(pattern: String) -> Self {
58 Self {
59 goals: Vec::new(),
60 nested: Vec::new(),
61 pattern,
62 }
63 }
64
65 pub fn add_goal(&mut self, goal: Goal) {
67 self.goals.push(goal);
68 }
69
70 pub fn add_nested(&mut self, nested: NestedQuery) {
72 self.nested.push(nested);
73 }
74
75 pub fn has_nested(&self) -> bool {
77 !self.nested.is_empty()
78 }
79
80 pub fn variables(&self) -> Vec<String> {
82 let mut vars = Vec::new();
83
84 for goal in &self.goals {
85 let pattern_vars = Self::extract_variables(&goal.pattern);
87 for var in pattern_vars {
88 if !vars.contains(&var) {
89 vars.push(var);
90 }
91 }
92 }
93
94 vars
95 }
96
97 fn extract_variables(pattern: &str) -> Vec<String> {
99 let mut vars = Vec::new();
100 let chars: Vec<char> = pattern.chars().collect();
101 let mut i = 0;
102
103 while i < chars.len() {
104 if chars[i] == '?' {
105 let mut var = String::from("?");
107 i += 1;
108 while i < chars.len() && (chars[i].is_alphanumeric() || chars[i] == '_') {
109 var.push(chars[i]);
110 i += 1;
111 }
112 if !vars.contains(&var) {
113 vars.push(var);
114 }
115 } else {
116 i += 1;
117 }
118 }
119
120 vars
121 }
122}
123
124impl NestedQuery {
125 pub fn new(outer_goal: Goal, subquery: Query) -> Self {
127 let outer_vars = Query::extract_variables(&outer_goal.pattern);
129 let subquery_vars = subquery.variables();
130
131 let shared_variables: Vec<String> = outer_vars
132 .iter()
133 .filter(|v| subquery_vars.contains(v))
134 .cloned()
135 .collect();
136
137 Self {
138 outer_goal,
139 subquery: Box::new(subquery),
140 shared_variables,
141 }
142 }
143
144 pub fn has_shared_variables(&self) -> bool {
146 !self.shared_variables.is_empty()
147 }
148}
149
150#[derive(Debug, Clone)]
152pub struct NestedQueryResult {
153 pub subquery_solutions: Vec<Bindings>,
155
156 pub final_solutions: Vec<Bindings>,
158
159 pub success: bool,
161
162 pub subquery_count: usize,
164}
165
166impl NestedQueryResult {
167 pub fn new() -> Self {
169 Self {
170 subquery_solutions: Vec::new(),
171 final_solutions: Vec::new(),
172 success: false,
173 subquery_count: 0,
174 }
175 }
176
177 pub fn success(subquery_solutions: Vec<Bindings>, final_solutions: Vec<Bindings>) -> Self {
179 Self {
180 success: !final_solutions.is_empty(),
181 subquery_count: subquery_solutions.len(),
182 subquery_solutions,
183 final_solutions,
184 }
185 }
186
187 pub fn failure() -> Self {
189 Self {
190 subquery_solutions: Vec::new(),
191 final_solutions: Vec::new(),
192 success: false,
193 subquery_count: 0,
194 }
195 }
196}
197
198impl Default for NestedQueryResult {
199 fn default() -> Self {
200 Self::new()
201 }
202}
203
204pub struct NestedQueryParser;
206
207impl NestedQueryParser {
208 pub fn parse(query_str: &str) -> Query {
216 let mut query = Query::new(query_str.to_string());
217
218 if let Some(where_idx) = query_str.find(" WHERE ") {
222 let conditions = &query_str[where_idx + 7..].trim();
223
224 let goals = Self::parse_conditions(conditions);
226 for goal in goals {
227 query.add_goal(goal);
228 }
229 }
230
231 query
232 }
233
234 fn parse_conditions(conditions: &str) -> Vec<Goal> {
236 let mut goals = Vec::new();
237
238 for condition in conditions.split(" AND ") {
240 let condition = condition.trim();
241
242 if condition.contains(" WHERE ") {
244 continue;
246 }
247
248 if !condition.is_empty() && !condition.starts_with('(') {
250 goals.push(Goal::new(condition.to_string()));
251 }
252 }
253
254 goals
255 }
256
257 pub fn has_nested(query_str: &str) -> bool {
259 let mut paren_depth = 0;
261 let mut in_parens = false;
262
263 let chars: Vec<char> = query_str.chars().collect();
264 for i in 0..chars.len() {
265 match chars[i] {
266 '(' => {
267 paren_depth += 1;
268 in_parens = true;
269 }
270 ')' => {
271 paren_depth -= 1;
272 if paren_depth == 0 {
273 in_parens = false;
274 }
275 }
276 'W' if in_parens && paren_depth > 0 => {
277 if i + 5 < chars.len() {
279 let substr: String = chars[i..i+5].iter().collect();
280 if substr == "WHERE" {
281 return true;
282 }
283 }
284 }
285 _ => {}
286 }
287 }
288
289 false
290 }
291}
292
293pub struct NestedQueryEvaluator;
295
296impl NestedQueryEvaluator {
297 pub fn evaluate(
305 nested: &NestedQuery,
306 initial_bindings: &Bindings,
307 ) -> NestedQueryResult {
308 NestedQueryResult::new()
313 }
314
315 fn merge_bindings(
317 outer_bindings: &Bindings,
318 subquery_bindings: &Bindings,
319 shared_vars: &[String],
320 ) -> Bindings {
321 let mut merged = outer_bindings.clone();
322
323 for var in shared_vars {
325 if let Some(value) = subquery_bindings.get(var) {
326 let _ = merged.bind(var.clone(), value.clone());
328 }
329 }
330
331 merged
332 }
333}
334
335#[derive(Debug, Clone, Default)]
337pub struct NestedQueryStats {
338 pub total_nested: usize,
340
341 pub total_subquery_evals: usize,
343
344 pub max_depth: usize,
346
347 pub avg_subquery_solutions: f64,
349}
350
351impl NestedQueryStats {
352 pub fn new() -> Self {
354 Self::default()
355 }
356
357 pub fn record_evaluation(&mut self, depth: usize, subquery_solutions: usize) {
359 self.total_nested += 1;
360 self.total_subquery_evals += subquery_solutions;
361 self.max_depth = self.max_depth.max(depth);
362
363 self.avg_subquery_solutions =
365 self.total_subquery_evals as f64 / self.total_nested as f64;
366 }
367
368 pub fn summary(&self) -> String {
370 format!(
371 "Nested queries: {} | Subquery evals: {} | Max depth: {} | Avg solutions: {:.2}",
372 self.total_nested,
373 self.total_subquery_evals,
374 self.max_depth,
375 self.avg_subquery_solutions
376 )
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[test]
385 fn test_query_creation() {
386 let query = Query::new("test(?x)".to_string());
387 assert_eq!(query.pattern, "test(?x)");
388 assert!(query.goals.is_empty());
389 assert!(!query.has_nested());
390 }
391
392 #[test]
393 fn test_query_add_goal() {
394 let mut query = Query::new("test".to_string());
395 let goal = Goal::new("parent(?x, ?y)".to_string());
396 query.add_goal(goal);
397
398 assert_eq!(query.goals.len(), 1);
399 }
400
401 #[test]
402 fn test_query_variables() {
403 let mut query = Query::new("test".to_string());
404
405 let goal1 = Goal::new("parent(?x, ?y)".to_string());
406 let goal2 = Goal::new("age(?x, ?age)".to_string());
407
408 query.add_goal(goal1);
409 query.add_goal(goal2);
410
411 let vars = query.variables();
412 assert!(vars.contains(&"?x".to_string()));
413 assert!(vars.contains(&"?y".to_string()));
414 assert!(vars.contains(&"?age".to_string()));
415 }
416
417 #[test]
418 fn test_nested_query_creation() {
419 let outer_goal = Goal::new("grandparent(?x, ?z)".to_string());
420 let mut subquery = Query::new("parent(?y, ?z)".to_string());
421
422 let sub_goal = Goal::new("parent(?y, ?z)".to_string());
423 subquery.add_goal(sub_goal);
424
425 let nested = NestedQuery::new(outer_goal, subquery);
426
427 assert!(!nested.subquery.goals.is_empty());
428 }
429
430 #[test]
431 fn test_nested_query_shared_variables() {
432 let outer_goal = Goal::new("grandparent(?x, ?z)".to_string());
433
434 let mut subquery = Query::new("parent(?y, ?z)".to_string());
435 let sub_goal = Goal::new("parent(?y, ?z)".to_string());
436 subquery.add_goal(sub_goal);
437
438 let nested = NestedQuery::new(outer_goal, subquery);
439
440 assert!(nested.has_shared_variables());
442 assert!(nested.shared_variables.contains(&"?z".to_string()));
443 }
444
445 #[test]
446 fn test_nested_query_result() {
447 let result = NestedQueryResult::new();
448 assert!(!result.success);
449 assert_eq!(result.subquery_count, 0);
450
451 let success = NestedQueryResult::success(vec![], vec![]);
452 assert!(!success.success); }
454
455 #[test]
456 fn test_nested_query_parser_has_nested() {
457 assert!(NestedQueryParser::has_nested(
458 "grandparent(?x, ?z) WHERE parent(?x, ?y) AND (parent(?y, ?z) WHERE child(?z, ?y))"
459 ));
460
461 assert!(!NestedQueryParser::has_nested(
462 "parent(?x, ?y) WHERE person(?x) AND person(?y)"
463 ));
464 }
465
466 #[test]
467 fn test_nested_query_stats() {
468 let mut stats = NestedQueryStats::new();
469
470 stats.record_evaluation(1, 5);
471 stats.record_evaluation(2, 10);
472
473 assert_eq!(stats.total_nested, 2);
474 assert_eq!(stats.total_subquery_evals, 15);
475 assert_eq!(stats.max_depth, 2);
476 assert_eq!(stats.avg_subquery_solutions, 7.5);
477 }
478
479 #[test]
480 fn test_parser_simple_query() {
481 let query = NestedQueryParser::parse("parent(?x, ?y) WHERE person(?x) AND person(?y)");
482 assert!(!query.goals.is_empty());
483 }
484}