cairn_knowledge_graph/operations/selection/operators/
exclusive_or.rs1use once_cell::sync::Lazy;
2
3use graphblas_sparse_linear_algebra::operators::{
4 element_wise_addition::ElementWiseVectorAdditionMonoidOperator, monoid::LogicalExclusiveOr,
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_EXCLUSIVE_OR_OPERATOR: Lazy<ElementWiseVectorAdditionMonoidOperator<bool>> =
16 Lazy::new(|| {
17 ElementWiseVectorAdditionMonoidOperator::<bool>::new(
18 &LogicalExclusiveOr::<bool>::new(),
19 &DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS,
20 None,
21 )
22 });
23
24pub trait ExclusiveOrOperator<RightHandSide = Self> {
25 type Output;
26 fn exclusive_or(
27 &self,
28 right_hand_side: &RightHandSide,
29 ) -> Result<Self::Output, GraphComputingError>;
30 fn exclusive_or_with_mask(
31 &self,
32 right_hand_side: &RightHandSide,
33 mask: &RightHandSide,
34 ) -> Result<Self::Output, GraphComputingError>;
35}
36
37impl<'g> ExclusiveOrOperator for VertexSelection<'g> {
38 type Output = VertexSelection<'g>;
39
40 fn exclusive_or(&self, right_hand_side: &Self) -> Result<Self, GraphComputingError> {
41 let mut resulting_vertex_selection = self.clone();
44 GRAPHBLAS_VECTOR_EXCLUSIVE_OR_OPERATOR.apply(
45 self.vertex_mask_ref(),
46 right_hand_side.vertex_mask_ref(),
47 resulting_vertex_selection.vertex_mask_mut_ref(),
48 )?;
49 Ok(resulting_vertex_selection)
50 }
51
52 fn exclusive_or_with_mask(
54 &self,
55 right_hand_side: &Self,
56 mask: &Self,
57 ) -> Result<Self, GraphComputingError> {
58 let mut resulting_vertex_selection = self.clone();
61 GRAPHBLAS_VECTOR_EXCLUSIVE_OR_OPERATOR.apply_with_mask(
62 mask.vertex_mask_ref(),
63 self.vertex_mask_ref(),
64 right_hand_side.vertex_mask_ref(),
65 resulting_vertex_selection.vertex_mask_mut_ref(),
66 )?;
67 Ok(resulting_vertex_selection)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 use crate::graph::vertex::VertexValue;
76 use crate::operations::select_vertex::SelectVertex;
77
78 use crate::tests::standard_graph_for_testing::standard_graph_for_testing;
79
80 #[test]
81 fn test_exclusive_or_operator_for_vertex_selection() {
82 let graph = standard_graph_for_testing();
83
84 let larger_than_one_selection = graph
85 .select_vertices_connected_to_vertex_by_key(String::from("larger_than"), &"1")
86 .unwrap();
87 let integer_selection = graph
88 .select_vertices_connected_to_vertex_by_key(String::from("is_a"), &"integer")
89 .unwrap();
90
91 let larger_than_one_or_integer_but_not_both_selection = larger_than_one_selection
92 .exclusive_or(&integer_selection)
93 .unwrap();
94 let mut larger_than_one_or_integer_but_not_both =
95 larger_than_one_or_integer_but_not_both_selection
96 .vertex_values_ref()
97 .unwrap();
98
99 larger_than_one_or_integer_but_not_both.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
100 ();
101 larger_than_one_or_integer_but_not_both.dedup();
102
103 assert_eq!(larger_than_one_or_integer_but_not_both.len(), 5);
104 assert!(larger_than_one_or_integer_but_not_both.contains(&&VertexValue::Integer8Bit(-1)));
105 assert!(
106 larger_than_one_or_integer_but_not_both.contains(&&VertexValue::UnsignedInteger8Bit(0))
107 );
108 assert!(
109 larger_than_one_or_integer_but_not_both.contains(&&VertexValue::UnsignedInteger8Bit(1))
110 );
111 assert!(larger_than_one_or_integer_but_not_both
112 .contains(&&VertexValue::FloatingPoint32Bit(1.1)));
113 assert!(larger_than_one_or_integer_but_not_both
114 .contains(&&VertexValue::FloatingPoint32Bit(1.2)));
115 }
116
117 #[test]
118 fn test_exclusive_or_operator_for_vertex_selection_with_mask() {
119 let graph = standard_graph_for_testing();
120
121 let larger_than_one_selection = graph
122 .select_vertices_connected_to_vertex_by_key(String::from("larger_than"), &"1")
123 .unwrap();
124 let equal_to_one_selection = graph
125 .select_vertices_connected_to_vertex_by_key(String::from("equal_to"), &"1_duplicate")
126 .unwrap();
127 let integer_selection = graph
128 .select_vertices_connected_to_vertex_by_key(String::from("is_a"), &"integer")
129 .unwrap();
130
131 let selection_of_integers_equal_to_or_larger_than_one = equal_to_one_selection
132 .exclusive_or_with_mask(&larger_than_one_selection, &integer_selection)
133 .unwrap();
134 let mut integers_equal_to_or_larger_than_one =
135 selection_of_integers_equal_to_or_larger_than_one
136 .vertex_values_ref()
137 .unwrap();
138
139 integers_equal_to_or_larger_than_one.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
140 ();
141 integers_equal_to_or_larger_than_one.dedup();
142
143 assert_eq!(integers_equal_to_or_larger_than_one.len(), 2);
144 assert!(
145 integers_equal_to_or_larger_than_one.contains(&&VertexValue::UnsignedInteger8Bit(1))
146 );
147 assert!(
148 integers_equal_to_or_larger_than_one.contains(&&VertexValue::UnsignedInteger8Bit(2))
149 );
150 }
151}