Skip to main content

cairn_knowledge_graph/operations/selection/operators/
or.rs

1use once_cell::sync::Lazy;
2
3use graphblas_sparse_linear_algebra::operators::{
4    element_wise_addition::ElementWiseVectorAdditionMonoidOperator, monoid::LogicalOr,
5    options::OperatorOptions,
6};
7
8use crate::error::GraphComputingError;
9
10use crate::operations::selection::vertex_selection::VertexSelection;
11
12static DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS: Lazy<OperatorOptions> =
13    Lazy::new(|| OperatorOptions::new_default());
14
15static GRAPHBLAS_VECTOR_OR_OPERATOR: Lazy<ElementWiseVectorAdditionMonoidOperator<bool>> =
16    Lazy::new(|| {
17        ElementWiseVectorAdditionMonoidOperator::<bool>::new(
18            &LogicalOr::<bool>::new(),
19            &DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS,
20            None,
21        )
22    });
23
24pub trait OrOperator<RightHandSide = Self> {
25    type Output;
26    fn or(&self, right_hand_side: &RightHandSide) -> Result<Self::Output, GraphComputingError>;
27    fn or_with_mask(
28        &self,
29        right_hand_side: &RightHandSide,
30        mask: &RightHandSide,
31    ) -> Result<Self::Output, GraphComputingError>;
32}
33
34impl<'g> OrOperator for VertexSelection<'g> {
35    type Output = VertexSelection<'g>;
36
37    fn or(&self, right_hand_side: &Self) -> Result<Self, GraphComputingError> {
38        // TODO: Size checking
39
40        let mut resulting_vertex_selection = self.clone();
41        GRAPHBLAS_VECTOR_OR_OPERATOR.apply(
42            self.vertex_mask_ref(),
43            right_hand_side.vertex_mask_ref(),
44            resulting_vertex_selection.vertex_mask_mut_ref(),
45        )?;
46        Ok(resulting_vertex_selection)
47    }
48
49    /// The operator applies to all coordinates that the mask selects. Elements in the left-hand-side that the mask does not select remain unchanged.
50    // TODO: consider introducing a selection/exclusion mask for improved API clarity
51    fn or_with_mask(
52        &self,
53        right_hand_side: &Self,
54        mask: &Self,
55    ) -> Result<Self, GraphComputingError> {
56        // TODO: Size checking
57
58        let mut resulting_vertex_selection = self.clone();
59        GRAPHBLAS_VECTOR_OR_OPERATOR.apply_with_mask(
60            mask.vertex_mask_ref(),
61            self.vertex_mask_ref(),
62            right_hand_side.vertex_mask_ref(),
63            resulting_vertex_selection.vertex_mask_mut_ref(),
64        )?;
65        Ok(resulting_vertex_selection)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    use crate::graph::vertex::VertexValue;
74    use crate::operations::select_vertex::SelectVertex;
75
76    use crate::tests::standard_graph_for_testing::standard_graph_for_testing;
77
78    #[test]
79    fn test_or_operator_for_vertex_selection() {
80        let graph = standard_graph_for_testing();
81
82        let larger_than_one_selection = graph
83            .select_vertices_connected_to_vertex_by_key(String::from("larger_than"), &"1")
84            .unwrap();
85        let equal_to_one_selection = graph
86            .select_vertices_connected_to_vertex_by_key(String::from("equal_to"), &"1_duplicate")
87            .unwrap();
88
89        let larger_than_or_equal_to_one_selection = larger_than_one_selection
90            .or(&equal_to_one_selection)
91            .unwrap();
92        let mut larger_than_or_equal_to_one = larger_than_or_equal_to_one_selection
93            .vertex_values_ref()
94            .unwrap();
95
96        larger_than_or_equal_to_one.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
97        ();
98        larger_than_or_equal_to_one.dedup();
99
100        assert_eq!(larger_than_or_equal_to_one.len(), 4);
101        assert!(larger_than_or_equal_to_one.contains(&&VertexValue::UnsignedInteger8Bit(1)));
102        assert!(larger_than_or_equal_to_one.contains(&&VertexValue::FloatingPoint32Bit(1.1)));
103        assert!(larger_than_or_equal_to_one.contains(&&VertexValue::FloatingPoint32Bit(1.2)));
104        assert!(larger_than_or_equal_to_one.contains(&&VertexValue::UnsignedInteger8Bit(2)));
105    }
106
107    #[test]
108    fn test_or_operator_for_vertex_selection_with_mask() {
109        let graph = standard_graph_for_testing();
110
111        let larger_than_one_selection = graph
112            .select_vertices_connected_to_vertex_by_key(String::from("larger_than"), &"1")
113            .unwrap();
114        let equal_to_one_selection = graph
115            .select_vertices_connected_to_vertex_by_key(String::from("equal_to"), &"1_duplicate")
116            .unwrap();
117        let integer_selection = graph
118            .select_vertices_connected_to_vertex_by_key(String::from("is_a"), &"integer")
119            .unwrap();
120
121        let selection_of_integers_equal_to_or_larger_than_one = equal_to_one_selection
122            .or_with_mask(&larger_than_one_selection, &integer_selection)
123            .unwrap();
124        let mut integers_equal_to_or_larger_than_one =
125            selection_of_integers_equal_to_or_larger_than_one
126                .vertex_values_ref()
127                .unwrap();
128
129        integers_equal_to_or_larger_than_one.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
130        ();
131        integers_equal_to_or_larger_than_one.dedup();
132
133        assert_eq!(integers_equal_to_or_larger_than_one.len(), 2);
134        assert!(
135            integers_equal_to_or_larger_than_one.contains(&&VertexValue::UnsignedInteger8Bit(1))
136        );
137        assert!(
138            integers_equal_to_or_larger_than_one.contains(&&VertexValue::UnsignedInteger8Bit(2))
139        );
140    }
141}