1use std::error::Error;
2use std::fmt::{Debug, Display, Formatter};
3use std::time::Instant;
4use crate::engine::storage::{RelationIdentifier, StorageLayer};
5use crate::builders::fact::Fact;
6use crate::builders::goal::{Goal, pattern_match};
7use crate::builders::rule::Rule;
8use crate::engine::compute::{ComputeLayer, Weight};
9use crate::interning::hash::reproducible_hash_one;
10use crate::interning::herbrand_universe::InternmentLayer;
11use crate::rewriting::atom::{decode_fact, encode_fact};
12
13pub struct MaterializedDatalogView {
15 compute_layer: ComputeLayer,
16 internment_layer: InternmentLayer,
17 storage_layer: StorageLayer,
18 safe: bool,
19}
20
21pub const EMPTY_PROGRAM: Vec<Rule> = vec![];
22
23type RelationSymbol<'a> = &'a str;
24
25pub struct PollingError;
26
27impl Display for PollingError {
28 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29 f.write_str("polling is needed to obtain correct results")
30 }
31}
32
33impl Debug for PollingError {
34 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
35 f.write_str("polling is needed to obtain correct results")
36 }
37}
38
39impl Error for PollingError {}
40
41impl MaterializedDatalogView {
42 pub fn push_fact(&mut self, relation_symbol: RelationSymbol, fact: impl Into<Fact>) -> bool {
62 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
63 let interned_fact = self.internment_layer.intern_fact(fact.into());
64
65 let encoded_fact = encode_fact(&interned_fact);
66 self.compute_layer.send_fact(hashed_relation_symbol, encoded_fact);
67 self.safe = false;
68
69 self.storage_layer.contains(&hashed_relation_symbol, &encoded_fact)
70 }
71 pub fn retract_fact(&mut self, relation_symbol: RelationSymbol, fact: impl Into<Fact>) -> bool {
109 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
110 if let Some(resolved_fact) = self.internment_layer.resolve_fact(fact.into()) {
111 let encoded_resolved_fact = encode_fact(&resolved_fact);
112
113 self.compute_layer.retract_fact(hashed_relation_symbol, encoded_resolved_fact);
114 self.safe = false;
115
116 return self.storage_layer.contains(&hashed_relation_symbol, &encoded_resolved_fact)
117 };
118
119 false
120 }
121 fn ensure_relation_exists(&mut self, relation_identifier: &RelationIdentifier) {
122 self.storage_layer.inner.entry(*relation_identifier).or_default();
123 }
124 fn ensure_rule_relations_exist(&mut self, rule: &Rule) {
125 self.ensure_relation_exists(&rule.head.symbol);
126
127 rule.body.iter().for_each(|body_atom| {
128 self.ensure_relation_exists(&body_atom.symbol);
129 });
130 }
131 pub fn push_rule(&mut self, rule: impl Into<Rule>) {
154 let rule = rule.into();
155 self.ensure_rule_relations_exist(&rule);
156 self.compute_layer.send_rule(self.internment_layer.intern_rule(rule));
157
158 self.safe = false;
159 }
160 pub fn retract_rule(&mut self, rule: impl Into<Rule>) {
183 let rule = rule.into();
184 if let Some(resolved_rule) = &self.internment_layer.resolve_rule(rule) {
185 self.compute_layer.retract_rule(resolved_rule);
186 }
187
188 self.safe = false;
189 }
190 pub fn contains(
210 &self,
211 relation_symbol: RelationSymbol,
212 fact: impl Into<Fact>,
213 ) -> Result<bool, PollingError> {
214 if !self.safe() {
215 return Err(PollingError)
216 }
217
218 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
219 if let Some(interned_fact) = self.internment_layer.resolve_fact(fact.into()) {
220 return Ok(self.storage_layer.contains(&hashed_relation_symbol, &encode_fact(&interned_fact)))
221 }
222
223 Ok(false)
224 }
225 pub fn query_unary<'a, T: 'static>(
248 &self,
249 relation_symbol: RelationSymbol,
250 goal: impl Into<Goal>,
251 ) -> Result<impl Iterator<Item=(&T, )>, PollingError> {
252 if !self.safe() {
253 return Err(PollingError)
254 }
255
256 let goal = goal.into();
257 let resolved_goal = self.internment_layer.resolve_goal(goal).unwrap();
258 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
259 let fact_storage = &self.storage_layer.get_relations(&hashed_relation_symbol).1;
260
261 Ok(fact_storage
262 .iter()
263 .filter(move |interned_constant_terms| pattern_match(&resolved_goal, &interned_constant_terms))
264 .map(|encoded_fact| {
265 let resolved_interned_constant_term = self.internment_layer.resolve_interned_constant::<T>(decode_fact(*encoded_fact)[0]).unwrap();
266
267 (resolved_interned_constant_term,)
268 }))
269 }
270 pub fn query_frontier_unary<'a, T: 'static>(
295 &self,
296 relation_symbol: RelationSymbol,
297 goal: impl Into<Goal>,
298 ) -> Result<impl Iterator<Item=((&T, ), Weight)>, PollingError> {
299 if !self.safe() {
300 return Err(PollingError)
301 }
302
303 let goal = goal.into();
304 let resolved_goal = self.internment_layer.resolve_goal(goal).unwrap();
305 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
306 let frontier = &self.storage_layer.get_relations(&hashed_relation_symbol).0;
307
308 Ok(frontier
309 .iter()
310 .filter(move |interned_constant_terms| pattern_match(&resolved_goal, &interned_constant_terms.0))
311 .map(|(encoded_fact, weight)| {
312 let resolved_interned_constant_term = self.internment_layer.resolve_interned_constant::<T>(decode_fact(*encoded_fact)[0]).unwrap();
313
314 ((resolved_interned_constant_term,), *weight)
315 }))
316 }
317 pub fn query_binary<'a, T: 'static, R: 'static>(
346 &self,
347 relation_symbol: RelationSymbol,
348 goal: impl Into<Goal>,
349 ) -> Result<impl Iterator<Item=(&T, &R)>, PollingError> {
350 if !self.safe() {
351 return Err(PollingError);
352 }
353
354 let goal = goal.into();
355 let resolved_goal = self.internment_layer.resolve_goal(goal).unwrap();
356 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
357 let fact_storage = &self.storage_layer.get_relations(&hashed_relation_symbol).1;
358
359 Ok(fact_storage
360 .iter()
361 .filter(move |interned_constant_terms| pattern_match(&resolved_goal, &interned_constant_terms))
362 .map(|encoded_fact| {
363 let resolved_interned_constant_term_one = self.internment_layer.resolve_interned_constant::<T>(decode_fact(*encoded_fact)[0]).unwrap();
364 let resolved_interned_constant_term_two = self.internment_layer.resolve_interned_constant::<R>(decode_fact(*encoded_fact)[1]).unwrap();
365
366 (resolved_interned_constant_term_one, resolved_interned_constant_term_two)
367 }))
368 }
369 pub fn query_frontier_binary<'a, T: 'static, R: 'static>(
399 &self,
400 relation_symbol: RelationSymbol,
401 goal: impl Into<Goal>,
402 ) -> Result<impl Iterator<Item=((&T, &R), Weight)>, PollingError> {
403 if !self.safe() {
404 return Err(PollingError)
405 }
406
407 let goal = goal.into();
408 let resolved_goal = self.internment_layer.resolve_goal(goal).unwrap();
409 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
410 let frontier = &self.storage_layer.get_relations(&hashed_relation_symbol).0;
411
412 Ok(frontier
413 .iter()
414 .filter(move |interned_constant_terms| pattern_match(&resolved_goal, &interned_constant_terms.0))
415 .map(|(encoded_fact, weight)| {
416 let resolved_interned_constant_term_one = self.internment_layer.resolve_interned_constant::<T>(decode_fact(*encoded_fact)[0]).unwrap();
417 let resolved_interned_constant_term_two = self.internment_layer.resolve_interned_constant::<R>(decode_fact(*encoded_fact)[1]).unwrap();
418
419 ((resolved_interned_constant_term_one, resolved_interned_constant_term_two), *weight)
420 }))
421 }
422 pub fn query_ternary<'a, T: 'static, R: 'static, S: 'static>(
450 &self,
451 relation_symbol: RelationSymbol,
452 goal: impl Into<Goal>,
453 ) -> Result<impl Iterator<Item=(&T, &R, &S)>, PollingError> {
454 if !self.safe() {
455 return Err(PollingError);
456 }
457
458 let goal = goal.into();
459 let resolved_goal = self.internment_layer.resolve_goal(goal).unwrap();
460 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
461 let fact_storage = &self.storage_layer.get_relations(&hashed_relation_symbol).1;
462
463 Ok(fact_storage
464 .iter()
465 .filter(move |interned_constant_terms| pattern_match(&resolved_goal, &interned_constant_terms))
466 .map(|encoded_fact| {
467 let resolved_interned_constant_term_one = self.internment_layer.resolve_interned_constant::<T>(decode_fact(*encoded_fact)[0]).unwrap();
468 let resolved_interned_constant_term_two = self.internment_layer.resolve_interned_constant::<R>(decode_fact(*encoded_fact)[1]).unwrap();
469 let resolved_interned_constant_term_three = self.internment_layer.resolve_interned_constant::<S>(decode_fact(*encoded_fact)[2]).unwrap();
470
471 (resolved_interned_constant_term_one, resolved_interned_constant_term_two, resolved_interned_constant_term_three)
472 }))
473 }
474 pub fn query_frontier_ternary<'a, T: 'static, R: 'static, S: 'static>(
501 &self,
502 relation_symbol: RelationSymbol,
503 goal: impl Into<Goal>,
504 ) -> Result<impl Iterator<Item=((&T, &R, &S), Weight)>, PollingError> {
505 if !self.safe() {
506 return Err(PollingError)
507 }
508
509 let goal = goal.into();
510 let resolved_goal = self.internment_layer.resolve_goal(goal).unwrap();
511 let hashed_relation_symbol = reproducible_hash_one(&relation_symbol);
512 let frontier = &self.storage_layer.get_relations(&hashed_relation_symbol).0;
513
514 Ok(frontier
515 .iter()
516 .filter(move |interned_constant_terms| pattern_match(&resolved_goal, &interned_constant_terms.0))
517 .map(|(encoded_fact, weight)| {
518 let resolved_interned_constant_term_one = self.internment_layer.resolve_interned_constant::<T>(decode_fact(*encoded_fact)[0]).unwrap();
519 let resolved_interned_constant_term_two = self.internment_layer.resolve_interned_constant::<R>(decode_fact(*encoded_fact)[1]).unwrap();
520 let resolved_interned_constant_term_three = self.internment_layer.resolve_interned_constant::<S>(decode_fact(*encoded_fact)[2]).unwrap();
521
522 ((resolved_interned_constant_term_one, resolved_interned_constant_term_two, resolved_interned_constant_term_three), *weight)
523 }))
524 }
525 fn step(&mut self) {
526 let now = Instant::now();
527 self.compute_layer.step();
528 println!("Step: {} ms", now.elapsed().as_millis());
529 }
530 fn consolidate(&mut self) {
531 self.compute_layer.consolidate_into_storage_layer(&mut self.storage_layer)
532 }
533 pub fn poll(&mut self) {
535 self.storage_layer.move_frontier();
536 self.step();
537 self.consolidate();
538 self.safe = true;
539 }
540 pub fn new(program: Vec<impl Into<Rule>>) -> Self {
542 let storage_layer: StorageLayer = Default::default();
543 let herbrand_universe = InternmentLayer::default();
544 let compute_layer = ComputeLayer::new();
545 let mut materialized_datalog_view = Self { compute_layer, internment_layer: herbrand_universe, storage_layer, safe: true };
546
547 program.into_iter().for_each(|rule| {
548 materialized_datalog_view.push_rule(rule);
549 });
550
551 materialized_datalog_view
552 }
553 pub fn safe(&self) -> bool {
555 self.safe
556 }
557 pub fn len(&self) -> usize {
559 self.storage_layer.len()
560 }
561}
562
563impl<'a, R> Extend<(&'a str, R)> for MaterializedDatalogView
564where R: Into<Fact> {
565 fn extend<T: IntoIterator<Item=(&'a str, R)>>(&mut self, iter: T) {
566 iter
567 .into_iter()
568 .for_each(|(relation_name, fact)| { self.push_fact(relation_name, fact); });
569 }
570}
571
572impl<R> Extend<R> for MaterializedDatalogView
573 where R: Into<Rule> {
574 fn extend<T: IntoIterator<Item=R>>(&mut self, iter: T) {
575 iter
576 .into_iter()
577 .for_each(|rule| { self.push_rule(rule); });
578 }
579}
580
581#[cfg(test)]
582mod tests {
583 use crate::engine::datalog::{EMPTY_PROGRAM, MaterializedDatalogView};
584 use datalog_syntax_macros::{program, rule};
585 use datalog_syntax::*;
586 use std::collections::HashSet;
587 use crate::builders::goal::ANY_VALUE;
588 use crate::builders::rule;
589 use crate::builders::rule::{Const, Var};
590
591 type NodeIndex = usize;
592 type Edge = (NodeIndex, NodeIndex);
593
594 fn assemble_tc_program() -> Vec<Rule> {
595 program! {
596 tc(?x, ?y) <- [e(?x, ?y)],
597 tc(?x, ?z) <- [e(?x, ?y), tc(?y, ?z)]
598 }
599 }
600
601 #[test]
602 fn integration_test_push_fact() {
603 let tc_program = assemble_tc_program();
604
605 let mut materialized_datalog_view = MaterializedDatalogView::new(tc_program);
606 vec![
607 (1, 2),
608 (2, 3),
609 (3, 4),
610 ]
611 .into_iter()
612 .for_each(|edge: Edge| {
613 materialized_datalog_view.push_fact("e", edge);
614 });
615
616 materialized_datalog_view.poll();
617 assert_eq!(materialized_datalog_view.len(), 9);
618
619 let actual_all: HashSet<Edge> =
620 materialized_datalog_view
621 .query_binary("tc", (ANY_VALUE, ANY_VALUE))
622 .unwrap()
623 .map(|(x, y)| (*x, *y))
624 .collect();
625 let expected_all: HashSet<Edge> = vec![
626 (1, 2),
627 (2, 3),
628 (3, 4),
629 (1, 3),
631 (2, 4),
632 (1, 4),
634 ]
635 .into_iter()
636 .collect();
637 assert_eq!(expected_all, actual_all);
638
639 let actual_all_from_a: HashSet<Edge> =
640 materialized_datalog_view.query_binary("tc", (Some(1), ANY_VALUE)).unwrap().map(|(x, y)| (*x, *y)).collect();
641 let expected_all_from_a: HashSet<Edge> = vec![
642 (1, 2),
643 (1, 3),
644 (1, 4),
645 ]
646 .into_iter()
647 .collect();
648 assert_eq!(expected_all_from_a, actual_all_from_a);
649
650 expected_all.iter().for_each(|fact| {
651 assert!(materialized_datalog_view.contains("tc", *fact).unwrap());
652 });
653
654 expected_all_from_a.iter().for_each(|fact| {
655 assert!(materialized_datalog_view.contains("tc", *fact).unwrap());
656 });
657
658 materialized_datalog_view.push_fact("e", (4usize, 5usize));
660 assert!(!materialized_datalog_view.safe());
661 materialized_datalog_view.poll();
662 assert!(materialized_datalog_view.safe());
663
664 let actual_all_after_update: HashSet<Edge> =
665 materialized_datalog_view
666 .query_binary("tc", (ANY_VALUE, ANY_VALUE))
667 .unwrap()
668 .map(|(x, y)| (*x, *y))
669 .collect();
670 let expected_all_after_update: HashSet<Edge> = vec![
671 (1, 2),
672 (2, 3),
673 (3, 4),
674 (1, 3),
676 (2, 4),
677 (1, 4),
679 (4, 5),
681 (3, 5),
682 (2, 5),
683 (1, 5),
684 ]
685 .into_iter()
686 .collect();
687 assert_eq!(expected_all_after_update, actual_all_after_update);
688
689 let actual_all_from_a_after_update: HashSet<Edge> = materialized_datalog_view
690 .query_binary("tc", (Some(1), ANY_VALUE))
691 .unwrap()
692 .map(|(x, y)| (*x, *y))
693 .collect();
694 let expected_all_from_a_after_update: HashSet<Edge> = vec![
695 (1, 2),
696 (1, 3),
697 (1, 4),
698 (1, 5),
699 ]
700 .into_iter()
701 .collect();
702 assert_eq!(
703 expected_all_from_a_after_update,
704 actual_all_from_a_after_update
705 );
706 }
707 #[test]
708 fn integration_test_retract_fact() {
709 let tc_program = assemble_tc_program();
710
711 let mut materialized_datalog_view = MaterializedDatalogView::new(tc_program);
712 vec![
713 (1, 2),
714 (1, 5),
716 (2, 3),
717 (3, 4),
718 (4, 5),
719 ]
720 .into_iter()
721 .for_each(|edge: Edge| {
722 materialized_datalog_view.push_fact("e", edge);
723 });
724 materialized_datalog_view.poll();
725
726 let actual_all: HashSet<Edge> =
727 materialized_datalog_view.query_binary("tc", (ANY_VALUE, ANY_VALUE)).unwrap().map(|(x, y)| (*x, *y)).collect();
728 let expected_all: HashSet<Edge> = vec![
729 (1, 2),
730 (1, 5),
731 (2, 3),
732 (3, 4),
733 (1, 3),
735 (2, 4),
736 (1, 4),
738 (4, 5),
740 (3, 5),
741 (2, 5),
742 ]
743 .into_iter()
744 .collect();
745 assert_eq!(expected_all, actual_all);
746
747 let actual_all_from_a: HashSet<Edge> = materialized_datalog_view
748 .query_binary("tc", (Some(1), ANY_VALUE))
749 .unwrap()
750 .map(|(x, y)| (*x, *y))
751 .collect();
752 let expected_all_from_a: HashSet<Edge> = vec![
753 (1, 2),
754 (1, 3),
755 (1, 4),
756 (1, 5),
757 ]
758 .into_iter()
759 .collect();
760 assert_eq!(expected_all_from_a, actual_all_from_a);
761
762 materialized_datalog_view.retract_fact("e", (4usize, 5usize));
764 assert!(!materialized_datalog_view.safe());
765 materialized_datalog_view.poll();
766 assert!(materialized_datalog_view.safe());
767
768 let actual_all_after_update: HashSet<Edge> =
769 materialized_datalog_view.query_binary("tc", (ANY_VALUE, ANY_VALUE)).unwrap().map(|(x, y)| (*x, *y)).collect();
770 let expected_all_after_update: HashSet<Edge> = vec![
771 (1, 2),
772 (2, 3),
773 (3, 4),
774 (1, 3),
776 (2, 4),
777 (1, 4),
779 (1, 5),
781 ]
782 .into_iter()
783 .collect();
784 assert_eq!(expected_all_after_update, actual_all_after_update);
785
786 let actual_all_from_a_after_update: HashSet<Edge> = materialized_datalog_view
787 .query_binary("tc", (Some(1), ANY_VALUE))
788 .unwrap()
789 .map(|(x, y)| (*x, *y))
790 .collect();
791 let expected_all_from_a_after_update: HashSet<Edge> = vec![
792 (1, 2),
793 (1, 3),
794 (1, 4),
795 (1, 5),
796 ]
797 .into_iter()
798 .collect();
799 assert_eq!(
800 expected_all_from_a_after_update,
801 actual_all_from_a_after_update
802 );
803 }
804
805 #[test]
806 fn integration_test_push_rule() {
807 let tc_program = assemble_tc_program();
808
809 let mut materialized_datalog_view = MaterializedDatalogView::new(tc_program);
810 vec![
811 (1, 2),
812 (2, 3),
813 (3, 4),
814 ]
815 .into_iter()
816 .for_each(|edge: Edge| {
817 materialized_datalog_view.push_fact("e", edge);
818 });
819
820 let actual_all_from_1_rule_dyn = rule::Rule::from((("tc1", (Const(1usize), Var("x"))), vec![("tc", (Const(1usize), Var("x")))]));
821 let actual_all_from_1_rule_compiled = rule::Rule::from(rule!{ tc1(1usize, ?x) <- [tc(1usize, ?x)] });
822 assert_eq!(actual_all_from_1_rule_dyn, actual_all_from_1_rule_compiled);
823 materialized_datalog_view.push_rule(actual_all_from_1_rule_dyn);
824 assert!(!materialized_datalog_view.safe());
825 materialized_datalog_view.poll();
826 assert!(materialized_datalog_view.safe());
827
828 let actual_all_from_1: HashSet<Edge> =
829 materialized_datalog_view.query_binary("tc1", (ANY_VALUE, ANY_VALUE)).unwrap().map(|(x, y)| (*x, *y)).collect();
830 let expected_all_from_1: HashSet<Edge> = vec![
831 (1, 2),
832 (1, 3),
833 (1, 4),
834 ]
835 .into_iter()
836 .collect();
837 assert_eq!(expected_all_from_1, actual_all_from_1);
838
839 expected_all_from_1.iter().for_each(|fact| {
840 assert!(materialized_datalog_view.contains("tc", *fact).unwrap());
841 assert!(materialized_datalog_view.contains("tc1", *fact).unwrap());
842 });
843
844 materialized_datalog_view.push_fact("e", (4usize, 5usize));
845 materialized_datalog_view.poll();
846
847 let actual_all_from_1_after_update: HashSet<Edge> = materialized_datalog_view
848 .query_binary("tc1", (ANY_VALUE, ANY_VALUE))
849 .unwrap()
850 .map(|(x, y)| (*x, *y))
851 .collect();
852 let expected_all_from_1_after_update: HashSet<Edge> = vec![
853 (1, 2),
854 (1, 3),
855 (1, 4),
856 (1, 5),
857 ]
858 .into_iter()
859 .collect();
860 assert_eq!(
861 expected_all_from_1_after_update,
862 actual_all_from_1_after_update
863 );
864 }
865 #[test]
866 fn integration_test_retract_rule() {
867 let tc_program = assemble_tc_program();
868
869 let mut materialized_datalog_view = MaterializedDatalogView::new(EMPTY_PROGRAM);
870 vec![
871 (1, 2),
872 (2, 3),
873 (3, 4),
874 ]
875 .into_iter()
876 .for_each(|edge: Edge| {
877 materialized_datalog_view.push_fact("e", edge);
878 });
879 materialized_datalog_view.poll();
880 assert_eq!(materialized_datalog_view.len(), 3);
881 materialized_datalog_view.push_rule(tc_program[0].clone());
882 materialized_datalog_view.poll();
883 assert_eq!(materialized_datalog_view.len(), 6);
884 materialized_datalog_view.push_rule(tc_program[1].clone());
885 materialized_datalog_view.poll();
886
887 assert_eq!(materialized_datalog_view.len(), 9);
888
889 materialized_datalog_view.push_rule(rule!{ tc1(1usize, ?x) <- [tc(1usize, ?x)] });
890 materialized_datalog_view.poll();
891 assert_eq!(materialized_datalog_view.len(), 12);
892
893 vec![
894 (1, 2),
895 (1, 3),
896 (1, 4),
897 ]
898 .into_iter()
899 .for_each(|fact: Edge| {
900 assert!(materialized_datalog_view.contains("tc", fact).unwrap());
901 assert!(materialized_datalog_view.contains("tc1", fact).unwrap());
902 });
903
904 materialized_datalog_view.retract_rule(rule!{ tc1(1usize, ?x) <- [tc(1usize, ?x)] });
905 assert!(!materialized_datalog_view.safe);
906 materialized_datalog_view.poll();
907 assert!(materialized_datalog_view.safe);
908 assert_eq!(materialized_datalog_view.len(), 9);
909 materialized_datalog_view.retract_rule(rule!{ tc(?x, ?z) <- [e(?x, ?y), tc(?y, ?z)] });
910 materialized_datalog_view.poll();
911 assert_eq!(materialized_datalog_view.len(), 6);
912 materialized_datalog_view.retract_rule(rule!{ tc(?x, ?y) <- [e(?x, ?y)] });
913 materialized_datalog_view.poll();
914 assert_eq!(materialized_datalog_view.len(), 3);
915 }
916
917 #[test]
918 fn integration_test_triangle_query() {
919 let tc_program = program! {
920 t(?a, ?b, ?c) <- [e(?a, ?b), e(?b, ?c), e(?c, ?a)],
921 };
922
923 let mut materialized_datalog_view = MaterializedDatalogView::new(tc_program);
924 vec![
925 (1, 2),
926 (2, 3),
927 (3, 1),
928 (4, 5),
929 (5, 6)
930 ]
931 .into_iter()
932 .for_each(|edge: Edge| {
933 materialized_datalog_view.push_fact("e", edge);
934 });
935 materialized_datalog_view.poll();
936 assert_eq!(materialized_datalog_view.len(), 8);
937
938 type Triangle = (NodeIndex, NodeIndex, NodeIndex);
939 let actual_all: HashSet<Triangle> =
940 materialized_datalog_view
941 .query_ternary("t", (ANY_VALUE, ANY_VALUE, ANY_VALUE))
942 .unwrap()
943 .map(|(x, y, z)| (*x, *y, *z))
944 .collect();
945 let expected_all: HashSet<Triangle> = vec![
946 (1, 2, 3),
947 (2, 3, 1),
948 (3, 1, 2),
949 ]
950 .into_iter()
951 .collect();
952 assert_eq!(expected_all, actual_all);
953 }
954}