cairn_knowledge_graph/operations/selection/
vertex_selection.rs1use once_cell::sync::Lazy;
2
3use graphblas_sparse_linear_algebra::operators::extract::SubVectorExtractor;
4use graphblas_sparse_linear_algebra::operators::insert::{
5 InsertScalarIntoVector, InsertScalarIntoVectorTrait,
6};
7use graphblas_sparse_linear_algebra::operators::options::OperatorOptions;
8use graphblas_sparse_linear_algebra::operators::{
9 element_wise_multiplication::ElementWiseVectorMultiplicationMonoidOperator, monoid::LogicalAnd,
10};
11use graphblas_sparse_linear_algebra::util::ElementIndexSelector;
12use graphblas_sparse_linear_algebra::value_types::sparse_vector::{
13 GetVectorElementList, SparseVector, VectorElementList,
14};
15
16use crate::error::{GraphComputingError, LogicError, LogicErrorType};
17use crate::graph::graph::{Graph, GraphTrait};
18use crate::graph::vertex::{Vertex, VertexIndex, VertexValue};
19
20static DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS: Lazy<OperatorOptions> =
21 Lazy::new(|| OperatorOptions::new_default());
22
23static GRAPHBLAS_OPERATOR_OPTIONS_TO_USE_MASK_COMPLEMENT: Lazy<OperatorOptions> =
24 Lazy::new(|| OperatorOptions::new(false, false, true, false, false));
25
26static GRAPHBLAS_SUB_VECTOR_EXTRACTOR: Lazy<SubVectorExtractor<bool, bool>> =
27 Lazy::new(|| SubVectorExtractor::<bool, bool>::new(&DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS, None));
28
29static GRAPHBLAS_SCALAR_INTO_VECTOR_INSERTER_WITH_MASK_COMPLEMENT: Lazy<
30 InsertScalarIntoVector<bool, bool>,
31> = Lazy::new(|| {
32 InsertScalarIntoVector::<bool, bool>::new(
33 &GRAPHBLAS_OPERATOR_OPTIONS_TO_USE_MASK_COMPLEMENT,
34 None,
35 )
36});
37
38static GRAPHBLAS_VECTOR_AND_OPERATOR: Lazy<ElementWiseVectorMultiplicationMonoidOperator<bool>> =
39 Lazy::new(|| {
40 ElementWiseVectorMultiplicationMonoidOperator::<bool>::new(
41 &LogicalAnd::<bool>::new(),
42 &DEFAULT_GRAPHBLAS_OPERATOR_OPTIONS,
43 None,
44 )
45 });
46
47#[derive(Clone, Debug)]
55pub struct VertexSelection<'g> {
56 graph: &'g Graph,
57 vertex_mask: SparseVector<bool>,
58}
59
60impl<'g> VertexSelection<'g> {
61 pub(crate) fn new(
62 graph: &'g Graph,
63 vertex_mask: SparseVector<bool>,
64 ) -> Result<Self, GraphComputingError> {
65 #[cfg(debug_assertions)]
66 let graph_vertex_capacity = graph.vertex_capacity()?;
67 if vertex_mask.length()? != graph_vertex_capacity {
68 return Err(LogicError::new(
69 LogicErrorType::DimensionMismatch,
70 format!(
71 "Length of vertex_mask {:?}, does not match the graph's vertex capacity {:?}",
72 vertex_mask.length()?,
73 graph_vertex_capacity
74 ),
75 None,
76 )
77 .into());
78 }
79
80 Ok(Self { graph, vertex_mask })
81 }
82
83 pub(crate) fn vertex_mask_ref(&self) -> &SparseVector<bool> {
84 &self.vertex_mask
85 }
86
87 pub(crate) fn vertex_mask_mut_ref(&mut self) -> &mut SparseVector<bool> {
88 &mut self.vertex_mask
89 }
90
91 pub(crate) fn to_full_vertex_mask(&self) -> Result<SparseVector<bool>, GraphComputingError> {
92 let mut full_vertex_mask = self.vertex_mask.clone();
93 GRAPHBLAS_SCALAR_INTO_VECTOR_INSERTER_WITH_MASK_COMPLEMENT.apply_with_mask(
94 &mut full_vertex_mask,
95 &ElementIndexSelector::Index(
96 &self
97 .graph
98 .index_mask_with_all_vertices()
99 .get_element_list()?
100 .indices_ref()
101 .to_owned(),
102 ),
103 &false,
104 &self.vertex_mask, )?;
106 Ok(full_vertex_mask)
107 }
108
109 pub(crate) fn to_full_vertex_mask_with_mask(
111 &self,
112 mask: &SparseVector<bool>,
113 ) -> Result<SparseVector<bool>, GraphComputingError> {
114 let mut filtered_mask = SparseVector::new(
115 self.graph_ref().graphblas_context_ref(),
116 &self.graph_ref().vertex_capacity()?,
117 )?;
118 GRAPHBLAS_VECTOR_AND_OPERATOR.apply(
119 self.graph_ref().index_mask_with_all_vertices(),
120 mask,
121 &mut filtered_mask,
122 )?;
123
124 let mut filtered_vertex_mask = SparseVector::new(
125 self.graph_ref().graphblas_context_ref(),
126 &self.graph_ref().vertex_capacity()?,
127 )?;
128 GRAPHBLAS_VECTOR_AND_OPERATOR.apply(&self.vertex_mask, mask, &mut filtered_vertex_mask)?;
129
130 let mut full_vertex_mask = SparseVector::new(
131 self.graph_ref().graphblas_context_ref(),
132 &self.graph_ref().vertex_capacity()?,
133 )?;
134 GRAPHBLAS_VECTOR_AND_OPERATOR.apply(
135 &filtered_vertex_mask,
136 &filtered_mask,
137 &mut full_vertex_mask,
138 )?;
139
140 GRAPHBLAS_SCALAR_INTO_VECTOR_INSERTER_WITH_MASK_COMPLEMENT.apply_with_mask(
141 &mut full_vertex_mask,
142 &ElementIndexSelector::Index(
143 &filtered_mask.get_element_list()?.indices_ref().to_owned(),
144 ),
145 &false,
146 &self.vertex_mask,
147 )?;
148
149 Ok(full_vertex_mask)
150 }
151
152 pub(crate) fn graph_ref(&'g self) -> &'g Graph {
153 self.graph
154 }
155
156 fn get_selected_elements(&self) -> Result<VectorElementList<bool>, GraphComputingError> {
157 let mut selected_vertices_mask = SparseVector::new(
158 self.graph.graphblas_context_ref(),
159 &self.graph.vertex_capacity()?,
160 )?;
161 GRAPHBLAS_SUB_VECTOR_EXTRACTOR.apply_with_mask(
162 &self.vertex_mask,
163 &ElementIndexSelector::All,
164 &mut selected_vertices_mask,
165 &self.vertex_mask,
166 )?;
167 Ok(selected_vertices_mask.get_element_list()?)
168 }
169
170 pub(crate) fn vertex_indices_ref(&self) -> Result<Vec<VertexIndex>, GraphComputingError> {
171 let selected_vertex_elements = self.get_selected_elements()?;
172 let raw_vertex_indices = selected_vertex_elements.indices_ref();
173
174 let mut vertex_indices = Vec::with_capacity(raw_vertex_indices.len());
176 for index in raw_vertex_indices.into_iter() {
177 let vertex_index = VertexIndex::new(index.clone());
178 vertex_indices.push(vertex_index);
179 }
180 Ok(vertex_indices)
181 }
182
183 pub fn vertices_ref(&self) -> Result<Vec<&Vertex>, GraphComputingError> {
184 let selected_vertex_elements = self.get_selected_elements()?;
185 let vertex_indices = selected_vertex_elements.indices_ref();
186
187 let mut selected_vertices = Vec::with_capacity(vertex_indices.len());
188 for vertex_index in vertex_indices.into_iter() {
189 let selected_vertex = self
190 .graph
191 .vertex_store_ref()
192 .get_ref(VertexIndex::new(vertex_index.clone()));
193
194 match selected_vertex {
195 Ok(vertex) => selected_vertices.push(vertex),
196 Err(_) => {
197 return Err(LogicError::new(
199 LogicErrorType::VertexMustExist,
200 String::from("A vertex was selected that does not exist"),
201 None,
202 )
203 .into());
204 }
205 }
206 }
207 Ok(selected_vertices)
208 }
209
210 pub fn vertex_keys_ref(&self) -> Result<Vec<&str>, GraphComputingError> {
211 let selected_vertex_elements = self.get_selected_elements()?;
212 let vertex_indices = selected_vertex_elements.indices_ref();
213
214 let mut selected_vertex_keys = Vec::with_capacity(vertex_indices.len());
215 for vertex_index in vertex_indices.into_iter() {
216 let selected_vertex = self
217 .graph
218 .vertex_store_ref()
219 .get_ref(VertexIndex::new(vertex_index.clone()));
220
221 match selected_vertex {
222 Ok(vertex) => selected_vertex_keys.push(vertex.key_ref()),
223 Err(_) => {
224 return Err(LogicError::new(
226 LogicErrorType::VertexMustExist,
227 String::from("A vertex was selected that does not exist"),
228 None,
229 )
230 .into());
231 }
232 }
233 }
234 Ok(selected_vertex_keys)
235 }
236
237 pub fn vertex_values_ref(&self) -> Result<Vec<&VertexValue>, GraphComputingError> {
238 let selected_vertex_elements = self.get_selected_elements()?;
239 let vertex_indices = selected_vertex_elements.indices_ref();
240
241 let mut selected_vertex_values = Vec::with_capacity(vertex_indices.len());
242 for vertex_index in vertex_indices.into_iter() {
243 let selected_vertex = self
244 .graph
245 .vertex_store_ref()
246 .get_ref(VertexIndex::new(vertex_index.clone()));
247
248 match selected_vertex {
249 Ok(vertex) => selected_vertex_values.push(vertex.value_ref()),
250 Err(_) => {
251 return Err(LogicError::new(
253 LogicErrorType::VertexMustExist,
254 String::from("A vertex was selected that does not exist"),
255 None,
256 )
257 .into());
258 }
259 }
260 }
261 Ok(selected_vertex_values)
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 use graphblas_sparse_linear_algebra::value_types::sparse_vector::GetVectorElementValue;
270
271 use crate::graph::edge::DirectedEdgeDefinedByKeys;
272 use crate::graph::graph::GraphTrait;
273 use crate::graph::vertex::VertexKeyAndIndexConversion;
274 use crate::operations::add_edge::AddEdge;
275 use crate::operations::add_vertex::AddVertex;
276 use crate::operations::select_vertex::SelectVertex;
277
278 use crate::tests::standard_graph_for_testing::standard_graph_for_testing;
279
280 #[test]
281 fn test_query_result() {
282 let initial_vertex_capacity = 10;
283 let initial_edge_type_capacity = 10;
284 let mut graph = Graph::new(initial_vertex_capacity, initial_edge_type_capacity).unwrap();
285
286 let vertex_key_1 = String::from("vertex_1");
287 let vertex_value_1 = String::from("value_1").into();
288
289 let vertex_key_2 = String::from("vertex_1");
290 let vertex_value_2 = String::from("value_2").into();
291
292 let vertex_1 = Vertex::new(vertex_key_1, vertex_value_1);
293 let vertex_2 = Vertex::new(vertex_key_2, vertex_value_2);
294
295 let edge_vertex1_vertex2 = DirectedEdgeDefinedByKeys::new(
296 vertex_1.clone().into(),
297 String::from("edge_type_1"),
298 vertex_2.clone().into(),
299 );
300 let edge_vertex2_vertex1 = DirectedEdgeDefinedByKeys::new(
301 vertex_2.clone().into(),
302 String::from("edge_type_1"),
303 vertex_1.clone().into(),
304 );
305 let edge_vertex1_vertex2_type2 = DirectedEdgeDefinedByKeys::new(
306 vertex_1.clone().into(),
307 String::from("edge_type_2"),
308 vertex_2.clone().into(),
309 );
310
311 graph.add_or_replace_vertex(vertex_1.clone()).unwrap();
312 graph.add_or_replace_vertex(vertex_2.clone()).unwrap();
313
314 graph
315 .add_edge_and_edge_type_using_keys(edge_vertex1_vertex2.clone())
316 .unwrap();
317 graph
318 .add_edge_and_edge_type_using_keys(edge_vertex2_vertex1.clone())
319 .unwrap();
320 graph
321 .add_edge_and_edge_type_using_keys(edge_vertex1_vertex2_type2.clone())
322 .unwrap();
323
324 let vertex_mask =
325 SparseVector::new(&graph.graphblas_context_ref(), &initial_vertex_capacity).unwrap();
326 let vertex_selection = VertexSelection::new(&graph, vertex_mask).unwrap();
327
328 let vertices = vertex_selection.vertices_ref().unwrap();
329 assert_eq!(vertices.len(), 0);
330 }
331
332 #[test]
333 fn to_vertex_full_mask() {
334 let graph = standard_graph_for_testing();
335
336 let negative_selection = graph
337 .select_vertices_connected_to_vertex_by_key(String::from("sign"), &"negative")
338 .unwrap();
339
340 let negative_selection_as_full_mask = negative_selection.to_full_vertex_mask().unwrap();
341 assert_eq!(
342 negative_selection_as_full_mask.length().unwrap(),
343 graph.vertex_capacity().unwrap()
344 );
345 assert_eq!(
346 negative_selection_as_full_mask
347 .number_of_stored_elements()
348 .unwrap(),
349 graph.number_of_vertices().unwrap()
350 );
351
352 let index = graph
353 .vertex_key_ref_to_vertex_index_ref("1".into())
354 .unwrap();
355 assert_eq!(
356 negative_selection_as_full_mask
357 .get_element_value(index.index_ref())
358 .unwrap(),
359 false
360 );
361
362 let index = graph
363 .vertex_key_ref_to_vertex_index_ref("0".into())
364 .unwrap();
365 assert_eq!(
366 negative_selection_as_full_mask
367 .get_element_value(index.index_ref())
368 .unwrap(),
369 false
370 );
371
372 let index = graph
373 .vertex_key_ref_to_vertex_index_ref("-1".into())
374 .unwrap();
375 assert_eq!(
376 negative_selection_as_full_mask
377 .get_element_value(index.index_ref())
378 .unwrap(),
379 true
380 );
381
382 let index = graph
383 .vertex_key_ref_to_vertex_index_ref("-1.1".into())
384 .unwrap();
385 assert_eq!(
386 negative_selection_as_full_mask
387 .get_element_value(index.index_ref())
388 .unwrap(),
389 true
390 );
391 }
392
393 #[test]
394 fn to_vertex_full_mask_with_mask() {
395 let graph = standard_graph_for_testing();
396
397 let negative_selection = graph
398 .select_vertices_connected_to_vertex_by_key(String::from("sign"), &"negative")
399 .unwrap();
400
401 let integer_selection = graph
402 .select_vertices_connected_to_vertex_by_key(String::from("is_a"), &"integer")
403 .unwrap();
404
405 let negative_selection_as_full_mask = negative_selection
406 .to_full_vertex_mask_with_mask(integer_selection.vertex_mask_ref())
407 .unwrap();
408
409 assert_eq!(
410 negative_selection_as_full_mask
411 .number_of_stored_elements()
412 .unwrap(),
413 integer_selection
414 .vertex_mask_ref()
415 .number_of_stored_elements()
416 .unwrap()
417 );
418
419 let index = graph
420 .vertex_key_ref_to_vertex_index_ref("1".into())
421 .unwrap();
422 assert_eq!(
423 negative_selection_as_full_mask
424 .get_element_value(index.index_ref())
425 .unwrap(),
426 false
427 );
428
429 let index = graph
430 .vertex_key_ref_to_vertex_index_ref("1_duplicate".into())
431 .unwrap();
432 assert_eq!(
433 negative_selection_as_full_mask
434 .get_element_value(index.index_ref())
435 .unwrap(),
436 false
437 );
438
439 let index = graph
440 .vertex_key_ref_to_vertex_index_ref("0".into())
441 .unwrap();
442 assert_eq!(
443 negative_selection_as_full_mask
444 .get_element_value(index.index_ref())
445 .unwrap(),
446 false
447 );
448
449 let index = graph
450 .vertex_key_ref_to_vertex_index_ref("2".into())
451 .unwrap();
452 assert_eq!(
453 negative_selection_as_full_mask
454 .get_element_value(index.index_ref())
455 .unwrap(),
456 false
457 );
458
459 let index = graph
460 .vertex_key_ref_to_vertex_index_ref("-1".into())
461 .unwrap();
462 assert_eq!(
463 negative_selection_as_full_mask
464 .get_element_value(index.index_ref())
465 .unwrap(),
466 true
467 );
468
469 let index = graph
470 .vertex_key_ref_to_vertex_index_ref("-1.1".into())
471 .unwrap();
472 assert_eq!(
473 negative_selection_as_full_mask
474 .get_element_value(index.index_ref())
475 .unwrap(),
476 false
477 );
478 }
479}