1use std::convert::TryInto;
2
3use crate::collections::sparse_matrix::GetGraphblasSparseMatrix;
4use crate::collections::sparse_vector::GetGraphblasSparseVector;
5use crate::context::CallGraphBlasContext;
6use crate::error::SparseLinearAlgebraError;
7use crate::graphblas_bindings::{
8 GrB_Matrix_reduce_BOOL, GrB_Matrix_reduce_FP32, GrB_Matrix_reduce_FP64,
9 GrB_Matrix_reduce_INT16, GrB_Matrix_reduce_INT32, GrB_Matrix_reduce_INT64,
10 GrB_Matrix_reduce_INT8, GrB_Matrix_reduce_Monoid, GrB_Matrix_reduce_UINT16,
11 GrB_Matrix_reduce_UINT32, GrB_Matrix_reduce_UINT64, GrB_Matrix_reduce_UINT8,
12 GrB_Vector_reduce_BOOL, GrB_Vector_reduce_FP32, GrB_Vector_reduce_FP64,
13 GrB_Vector_reduce_INT16, GrB_Vector_reduce_INT32, GrB_Vector_reduce_INT64,
14 GrB_Vector_reduce_INT8, GrB_Vector_reduce_UINT16, GrB_Vector_reduce_UINT32,
15 GrB_Vector_reduce_UINT64, GrB_Vector_reduce_UINT8,
16};
17use crate::operators::binary_operator::AccumulatorBinaryOperator;
18use crate::operators::mask::VectorMask;
19use crate::operators::monoid::Monoid;
20use crate::operators::options::{
21 GetOperatorOptions, GetOptionsForOperatorWithMatrixArgument, WithTransposeMatrixArgument,
22};
23use crate::value_type::utilities_to_implement_traits_for_all_value_types::{
24 convert_mut_scalar_to_type, identity_conversion,
25 implement_macro_for_all_value_types_and_2_typed_graphblas_functions_with_mutable_scalar_type_conversion,
26};
27use crate::value_type::{ConvertScalar, ValueType};
28
29unsafe impl Send for MonoidReducer {}
33unsafe impl Sync for MonoidReducer {}
34
35#[derive(Debug, Clone)]
36pub struct MonoidReducer {}
37
38impl MonoidReducer {
39 pub fn new() -> Self {
40 Self {}
41 }
42}
43
44pub trait MonoidVectorReducer<EvaluationDomain: ValueType> {
45 fn to_column_vector(
46 &self,
47 operator: &impl Monoid<EvaluationDomain>,
48 argument: &impl GetGraphblasSparseMatrix,
49 accumulator: &impl AccumulatorBinaryOperator<EvaluationDomain>,
50 product: &mut impl GetGraphblasSparseVector,
51 mask: &impl VectorMask,
52 options: &impl GetOptionsForOperatorWithMatrixArgument,
53 ) -> Result<(), SparseLinearAlgebraError>;
54
55 fn to_row_vector(
56 &self,
57 operator: &impl Monoid<EvaluationDomain>,
58 argument: &impl GetGraphblasSparseMatrix,
59 accumulator: &impl AccumulatorBinaryOperator<EvaluationDomain>,
60 product: &mut impl GetGraphblasSparseVector,
61 mask: &impl VectorMask,
62 options: &(impl GetOptionsForOperatorWithMatrixArgument + WithTransposeMatrixArgument),
63 ) -> Result<(), SparseLinearAlgebraError>;
64}
65
66impl<EvaluationDomain: ValueType> MonoidVectorReducer<EvaluationDomain> for MonoidReducer {
67 fn to_column_vector(
68 &self,
69 operator: &impl Monoid<EvaluationDomain>,
70 argument: &impl GetGraphblasSparseMatrix,
71 accumulator: &impl AccumulatorBinaryOperator<EvaluationDomain>,
72 product: &mut impl GetGraphblasSparseVector,
73 mask: &impl VectorMask,
74 options: &impl GetOptionsForOperatorWithMatrixArgument,
75 ) -> Result<(), SparseLinearAlgebraError> {
76 let context = product.context_ref();
77
78 context.call(
79 || unsafe {
80 GrB_Matrix_reduce_Monoid(
81 product.graphblas_vector(),
82 mask.graphblas_vector(),
83 accumulator.accumulator_graphblas_type(),
84 operator.graphblas_type(),
85 argument.graphblas_matrix(),
86 options.graphblas_descriptor(),
87 )
88 },
89 unsafe { product.graphblas_vector_ref() },
90 )?;
91
92 Ok(())
93 }
94
95 fn to_row_vector(
96 &self,
97 operator: &impl Monoid<EvaluationDomain>,
98 argument: &impl GetGraphblasSparseMatrix,
99 accumulator: &impl AccumulatorBinaryOperator<EvaluationDomain>,
100 product: &mut impl GetGraphblasSparseVector,
101 mask: &impl VectorMask,
102 options: &(impl GetOptionsForOperatorWithMatrixArgument + WithTransposeMatrixArgument),
103 ) -> Result<(), SparseLinearAlgebraError> {
104 self.to_column_vector(
105 operator,
106 argument,
107 accumulator,
108 product,
109 mask,
110 &options.with_negated_transpose_matrix_argument(),
111 )
112 }
113}
114
115pub trait MonoidScalarReducer<EvaluationDomain: ValueType> {
116 fn matrix_to_scalar(
117 &self,
118 operator: &impl Monoid<EvaluationDomain>,
119 argument: &impl GetGraphblasSparseMatrix,
120 accumulator: &impl AccumulatorBinaryOperator<EvaluationDomain>,
121 product: &mut EvaluationDomain,
122 options: &impl GetOptionsForOperatorWithMatrixArgument,
123 ) -> Result<(), SparseLinearAlgebraError>;
124
125 fn vector_to_scalar(
126 &self,
127 operator: &impl Monoid<EvaluationDomain>,
128 argument: &impl GetGraphblasSparseVector,
129 accumulator: &impl AccumulatorBinaryOperator<EvaluationDomain>,
130 product: &mut EvaluationDomain,
131 options: &impl GetOperatorOptions,
132 ) -> Result<(), SparseLinearAlgebraError>;
133}
134
135macro_rules! implement_monoid_reducer {
136 ($value_type:ty, $graphblas_implementation_type:ty, $matrix_reducer_operator:ident, $vector_reducer_operator:ident, $convert_to_type:ident) => {
137 impl MonoidScalarReducer<$value_type> for MonoidReducer {
138 fn matrix_to_scalar(
139 &self,
140 operator: &impl Monoid<$value_type>,
141 argument: &impl GetGraphblasSparseMatrix,
142 accumulator: &impl AccumulatorBinaryOperator<$value_type>,
143 product: &mut $value_type,
144 options: &impl GetOptionsForOperatorWithMatrixArgument,
145 ) -> Result<(), SparseLinearAlgebraError> {
146 let context = argument.context_ref();
147 let mut tmp_product = product.clone().to_type()?;
148
149 context.call_without_detailed_error_information(|| unsafe {
151 $matrix_reducer_operator(
152 &mut tmp_product,
153 accumulator.accumulator_graphblas_type(),
154 operator.graphblas_type(),
155 argument.graphblas_matrix(),
156 options.graphblas_descriptor(),
157 )
158 })?;
159
160 $convert_to_type!(tmp_product, $value_type);
161 *product = tmp_product;
162 Ok(())
163 }
164
165 fn vector_to_scalar(
167 &self,
168 operator: &impl Monoid<$value_type>,
169 argument: &impl GetGraphblasSparseVector,
170 accumulator: &impl AccumulatorBinaryOperator<$value_type>,
171 product: &mut $value_type,
172 options: &impl GetOperatorOptions,
173 ) -> Result<(), SparseLinearAlgebraError> {
174 let context = argument.context_ref();
175 let mut tmp_product = product.clone().to_type()?;
176
177 context.call_without_detailed_error_information(|| unsafe {
178 $vector_reducer_operator(
179 &mut tmp_product,
180 accumulator.accumulator_graphblas_type(),
181 operator.graphblas_type(),
182 argument.graphblas_vector(),
183 options.graphblas_descriptor(),
184 )
185 })?;
186
187 $convert_to_type!(tmp_product, $value_type);
188 *product = tmp_product;
189 Ok(())
190 }
191 }
192 };
193}
194
195implement_macro_for_all_value_types_and_2_typed_graphblas_functions_with_mutable_scalar_type_conversion!(
196 implement_monoid_reducer,
197 GrB_Matrix_reduce,
198 GrB_Vector_reduce
199);
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 use crate::collections::Collection;
206 use crate::context::Context;
207 use crate::operators::binary_operator::Assignment;
208 use crate::operators::binary_operator::First;
209 use crate::operators::mask::SelectEntireVector;
210 use crate::operators::monoid::Plus as MonoidPlus;
211 use crate::operators::options::OperatorOptions;
212 use crate::operators::options::OptionsForOperatorWithMatrixArgument;
213
214 use crate::collections::sparse_matrix::operations::FromMatrixElementList;
215 use crate::collections::sparse_matrix::GetMatrixDimensions;
216 use crate::collections::sparse_matrix::{MatrixElementList, Size, SparseMatrix};
217 use crate::collections::sparse_vector::operations::FromVectorElementList;
218 use crate::collections::sparse_vector::operations::GetSparseVectorElementValue;
219 use crate::collections::sparse_vector::{SparseVector, VectorElementList};
220 use crate::value_type::utilities_to_implement_traits_for_all_value_types::implement_macro_for_all_value_types_except_bool;
221
222 macro_rules! test_monoid {
223 ($value_type:ty) => {
224 paste::paste! {
225 #[test]
226 fn [<test_monoid_to_vector_reducer_ $value_type>]() {
227 let context = Context::init_default().unwrap();
228
229 let element_list = MatrixElementList::<$value_type>::from_element_vector(vec![
230 (1, 1, 1 as $value_type).into(),
231 (1, 5, 1 as $value_type).into(),
232 (2, 1, 2 as $value_type).into(),
233 (4, 2, 4 as $value_type).into(),
234 (5, 2, 5 as $value_type).into(),
235 ]);
236
237 let matrix_size: Size = (10, 15).into();
238 let matrix = SparseMatrix::<$value_type>::from_element_list(
239 context.clone(),
240 matrix_size,
241 element_list,
242 &First::<$value_type>::new(),
243 )
244 .unwrap();
245
246 let mut product_vector =
247 SparseVector::<$value_type>::new(context.clone(), matrix_size.row_height()).unwrap();
248
249 let reducer = MonoidReducer::new(
250 );
251
252 reducer.to_column_vector(
253 &MonoidPlus::<$value_type>::new(),
254 &matrix, &Assignment::<$value_type>::new(),
255 &mut product_vector, &SelectEntireVector::new(context.clone()),
256 &OptionsForOperatorWithMatrixArgument::new_default()).unwrap();
257
258 println!("{}", product_vector);
259
260 assert_eq!(product_vector.number_of_stored_elements().unwrap(), 4);
261 assert_eq!(product_vector.element_value_or_default(1).unwrap(), 2 as $value_type);
262 assert_eq!(product_vector.element_value_or_default(2).unwrap(), 2 as $value_type);
263 assert_eq!(product_vector.element_value(9).unwrap(), None);
264
265 let mask_element_list = VectorElementList::<$value_type>::from_element_vector(vec![
266 (1, 1 as $value_type).into(),
267 (2, 2 as $value_type).into(),
268 (4, 4 as $value_type).into(),
269 ]);
271
272 let mask = SparseVector::<$value_type>::from_element_list(
273 context.clone(),
274 matrix_size.row_height(),
275 mask_element_list,
276 &First::<$value_type>::new(),
277 )
278 .unwrap();
279
280 let mut product_vector =
281 SparseVector::<$value_type>::new(context.clone(), matrix_size.row_height()).unwrap();
282
283 reducer
284 .to_column_vector(
285 &MonoidPlus::<$value_type>::new(),
286 &matrix, &Assignment::<$value_type>::new(),
287 &mut product_vector,
288 &mask,
289 &OptionsForOperatorWithMatrixArgument::new_default())
290 .unwrap();
291
292 println!("{}", matrix);
293 println!("{}", product_vector);
294
295 assert_eq!(product_vector.number_of_stored_elements().unwrap(), 3);
296 assert_eq!(product_vector.element_value_or_default(1).unwrap(), 2 as $value_type);
297 assert_eq!(product_vector.element_value_or_default(2).unwrap(), 2 as $value_type);
298 assert_eq!(product_vector.element_value(5).unwrap(), None);
299 assert_eq!(product_vector.element_value(9).unwrap(), None);
300 }
301
302 #[test]
303 fn [<test_monoid_to_scalar_reducer_for_matrix_ $value_type>]() {
304 let context = Context::init_default().unwrap();
305
306 let element_list = MatrixElementList::<$value_type>::from_element_vector(vec![
307 (1, 1, 1 as $value_type).into(),
308 (1, 5, 1 as $value_type).into(),
309 (2, 1, 2 as $value_type).into(),
310 (4, 2, 4 as $value_type).into(),
311 (5, 2, 5 as $value_type).into(),
312 ]);
313
314 let matrix_size: Size = (10, 15).into();
315 let matrix = SparseMatrix::<$value_type>::from_element_list(
316 context.clone(),
317 matrix_size,
318 element_list,
319 &First::<$value_type>::new(),
320 )
321 .unwrap();
322
323 let mut product = 1 as $value_type;
324
325 let reducer = MonoidReducer::new(
326 );
327
328 reducer.matrix_to_scalar(
329 &MonoidPlus::<$value_type>::new(),
330 &matrix,
331 &Assignment::new(),
332 &mut product,
333 &OptionsForOperatorWithMatrixArgument::new_default(),).unwrap();
334
335 println!("{}", product);
336
337 assert_eq!(product, 13 as $value_type);
338 }
339
340 #[test]
341 fn [<test_monoid_to_scalar_reducer_for_vector_ $value_type>]() {
342 let context = Context::init_default().unwrap();
343
344 let element_list = VectorElementList::<$value_type>::from_element_vector(vec![
345 (1, 1 as $value_type).into(),
346 (2, 2 as $value_type).into(),
347 (4, 4 as $value_type).into(),
348 (5, 5 as $value_type).into(),
349 ]);
350
351 let vector_length = 10;
352 let vector = SparseVector::<$value_type>::from_element_list(
353 context.clone(),
354 vector_length,
355 element_list,
356 &First::<$value_type>::new(),
357 )
358 .unwrap();
359
360 let mut product = 0 as $value_type;
361
362 let reducer = MonoidReducer::new(
363 );
364
365 reducer.vector_to_scalar(&MonoidPlus::<$value_type>::new(), &vector, &Assignment::new(), &mut product, &OperatorOptions::new_default(),).unwrap();
366
367 println!("{}", product);
368
369 assert_eq!(product, 12 as $value_type);
370 }
371 }
372 };
373 }
374
375 implement_macro_for_all_value_types_except_bool!(test_monoid);
376}