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 && i + 5 < chars.len() => {
277 let substr: String = chars[i..i + 5].iter().collect();
279 if substr == "WHERE" {
280 return true;
281 }
282 }
283 _ => {}
284 }
285 }
286
287 false
288 }
289}
290
291pub struct NestedQueryEvaluator;
293
294impl NestedQueryEvaluator {
295 pub fn evaluate(_nested: &NestedQuery, _initial_bindings: &Bindings) -> NestedQueryResult {
303 NestedQueryResult::new()
308 }
309
310 #[allow(dead_code)]
312 fn merge_bindings(
313 outer_bindings: &Bindings,
314 subquery_bindings: &Bindings,
315 shared_vars: &[String],
316 ) -> Bindings {
317 let mut merged = outer_bindings.clone();
318
319 for var in shared_vars {
321 if let Some(value) = subquery_bindings.get(var) {
322 let _ = merged.bind(var.clone(), value.clone());
324 }
325 }
326
327 merged
328 }
329}
330
331#[derive(Debug, Clone, Default)]
333pub struct NestedQueryStats {
334 pub total_nested: usize,
336
337 pub total_subquery_evals: usize,
339
340 pub max_depth: usize,
342
343 pub avg_subquery_solutions: f64,
345}
346
347impl NestedQueryStats {
348 pub fn new() -> Self {
350 Self::default()
351 }
352
353 pub fn record_evaluation(&mut self, depth: usize, subquery_solutions: usize) {
355 self.total_nested += 1;
356 self.total_subquery_evals += subquery_solutions;
357 self.max_depth = self.max_depth.max(depth);
358
359 self.avg_subquery_solutions = self.total_subquery_evals as f64 / self.total_nested as f64;
361 }
362
363 pub fn summary(&self) -> String {
365 format!(
366 "Nested queries: {} | Subquery evals: {} | Max depth: {} | Avg solutions: {:.2}",
367 self.total_nested,
368 self.total_subquery_evals,
369 self.max_depth,
370 self.avg_subquery_solutions
371 )
372 }
373}
374
375#[cfg(test)]
376mod tests {
377 use super::*;
378
379 #[test]
380 fn test_query_creation() {
381 let query = Query::new("test(?x)".to_string());
382 assert_eq!(query.pattern, "test(?x)");
383 assert!(query.goals.is_empty());
384 assert!(!query.has_nested());
385 }
386
387 #[test]
388 fn test_query_add_goal() {
389 let mut query = Query::new("test".to_string());
390 let goal = Goal::new("parent(?x, ?y)".to_string());
391 query.add_goal(goal);
392
393 assert_eq!(query.goals.len(), 1);
394 }
395
396 #[test]
397 fn test_query_variables() {
398 let mut query = Query::new("test".to_string());
399
400 let goal1 = Goal::new("parent(?x, ?y)".to_string());
401 let goal2 = Goal::new("age(?x, ?age)".to_string());
402
403 query.add_goal(goal1);
404 query.add_goal(goal2);
405
406 let vars = query.variables();
407 assert!(vars.contains(&"?x".to_string()));
408 assert!(vars.contains(&"?y".to_string()));
409 assert!(vars.contains(&"?age".to_string()));
410 }
411
412 #[test]
413 fn test_nested_query_creation() {
414 let outer_goal = Goal::new("grandparent(?x, ?z)".to_string());
415 let mut subquery = Query::new("parent(?y, ?z)".to_string());
416
417 let sub_goal = Goal::new("parent(?y, ?z)".to_string());
418 subquery.add_goal(sub_goal);
419
420 let nested = NestedQuery::new(outer_goal, subquery);
421
422 assert!(!nested.subquery.goals.is_empty());
423 }
424
425 #[test]
426 fn test_nested_query_shared_variables() {
427 let outer_goal = Goal::new("grandparent(?x, ?z)".to_string());
428
429 let mut subquery = Query::new("parent(?y, ?z)".to_string());
430 let sub_goal = Goal::new("parent(?y, ?z)".to_string());
431 subquery.add_goal(sub_goal);
432
433 let nested = NestedQuery::new(outer_goal, subquery);
434
435 assert!(nested.has_shared_variables());
437 assert!(nested.shared_variables.contains(&"?z".to_string()));
438 }
439
440 #[test]
441 fn test_nested_query_result() {
442 let result = NestedQueryResult::new();
443 assert!(!result.success);
444 assert_eq!(result.subquery_count, 0);
445
446 let success = NestedQueryResult::success(vec![], vec![]);
447 assert!(!success.success); }
449
450 #[test]
451 fn test_nested_query_parser_has_nested() {
452 assert!(NestedQueryParser::has_nested(
453 "grandparent(?x, ?z) WHERE parent(?x, ?y) AND (parent(?y, ?z) WHERE child(?z, ?y))"
454 ));
455
456 assert!(!NestedQueryParser::has_nested(
457 "parent(?x, ?y) WHERE person(?x) AND person(?y)"
458 ));
459 }
460
461 #[test]
462 fn test_nested_query_stats() {
463 let mut stats = NestedQueryStats::new();
464
465 stats.record_evaluation(1, 5);
466 stats.record_evaluation(2, 10);
467
468 assert_eq!(stats.total_nested, 2);
469 assert_eq!(stats.total_subquery_evals, 15);
470 assert_eq!(stats.max_depth, 2);
471 assert_eq!(stats.avg_subquery_solutions, 7.5);
472 }
473
474 #[test]
475 fn test_parser_simple_query() {
476 let query = NestedQueryParser::parse("parent(?x, ?y) WHERE person(?x) AND person(?y)");
477 assert!(!query.goals.is_empty());
478 }
479}