graphblas_sparse_linear_algebra/operators/binary_operator/
binary_operator.rs

1use std::marker::PhantomData;
2use std::ptr;
3
4use crate::graphblas_bindings::*;
5use crate::value_type::utilities_to_implement_traits_for_all_value_types::{
6    implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types,
7    implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_graphblas_index_integer_value_types,
8    implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types,
9    implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types,
10};
11use crate::value_type::ValueType;
12
13pub trait AccumulatorBinaryOperator<T>
14where
15    T: ValueType,
16{
17    fn accumulator_graphblas_type(&self) -> GrB_BinaryOp;
18}
19
20pub trait BinaryOperator<T>: AccumulatorBinaryOperator<T>
21where
22    T: ValueType,
23{
24    fn graphblas_type(&self) -> GrB_BinaryOp;
25}
26
27pub trait ReturnsBool {}
28
29macro_rules! implement_binary_operator {
30    ($operator_name:ident, $graphblas_operator_trait_name:ident) => {
31        pub trait $graphblas_operator_trait_name<T: ValueType> {
32            fn graphblas_type() -> GrB_BinaryOp;
33        }
34
35        impl<T: ValueType + $graphblas_operator_trait_name<T>> BinaryOperator<T>
36            for $operator_name<T>
37        {
38            fn graphblas_type(&self) -> GrB_BinaryOp {
39                T::graphblas_type()
40            }
41        }
42
43        impl<T: ValueType + $graphblas_operator_trait_name<T>> AccumulatorBinaryOperator<T>
44            for $operator_name<T>
45        {
46            fn accumulator_graphblas_type(&self) -> GrB_BinaryOp {
47                T::graphblas_type()
48            }
49        }
50
51        impl<T: ValueType> $operator_name<T> {
52            pub fn new() -> Self {
53                Self {
54                    _evaluation_domain: PhantomData,
55                }
56            }
57        }
58    };
59}
60
61macro_rules! implement_typed_binary_operator {
62    ($operator_trait_name:ident,
63        $graphblas_operator_name:ident,
64        $value_type:ty
65    ) => {
66        impl $operator_trait_name<$value_type> for $value_type {
67            fn graphblas_type() -> GrB_BinaryOp {
68                unsafe { $graphblas_operator_name }
69            }
70        }
71    };
72}
73
74// macro_rules! implement_binary_operator_with_bool_return_type {
75//     (
76//         $operator_name:ident,
77//         $graphblas_operator_name:ident,
78//         $evaluation_domain: ty
79//     ) => {
80//         impl BinaryOperator<$evaluation_domain> for $operator_name<$evaluation_domain> {
81//             fn graphblas_type(&self) -> GrB_BinaryOp {
82//                 unsafe { $graphblas_operator_name }
83//             }
84//         }
85
86//         impl AccumulatorBinaryOperator<$evaluation_domain> for $operator_name<$evaluation_domain> {
87//             fn accumulator_graphblas_type(&self) -> GrB_BinaryOp {
88//                 unsafe { $graphblas_operator_name }
89//             }
90//         }
91
92//         impl $operator_name<$evaluation_domain> {
93//             pub fn new() -> Self {
94//                 Self {
95//                     _evaluation_domain: PhantomData,
96//                 }
97//             }
98//         }
99
100//         impl ReturnsBool for $operator_name<$evaluation_domain> {}
101//     };
102// }
103
104macro_rules! implement_binary_operator_with_bool_return_type {
105    ($operator_name:ident, $graphblas_operator_trait_name:ident) => {
106        pub trait $graphblas_operator_trait_name<T: ValueType> {
107            fn graphblas_type() -> GrB_BinaryOp;
108        }
109
110        impl<T: ValueType + $graphblas_operator_trait_name<T>> BinaryOperator<T>
111            for $operator_name<T>
112        {
113            fn graphblas_type(&self) -> GrB_BinaryOp {
114                T::graphblas_type()
115            }
116        }
117
118        impl<T: ValueType + $graphblas_operator_trait_name<T>> AccumulatorBinaryOperator<T>
119            for $operator_name<T>
120        {
121            fn accumulator_graphblas_type(&self) -> GrB_BinaryOp {
122                T::graphblas_type()
123            }
124        }
125
126        impl<T: ValueType> $operator_name<T> {
127            pub fn new() -> Self {
128                Self {
129                    _evaluation_domain: PhantomData,
130                }
131            }
132        }
133
134        impl<T: ValueType> ReturnsBool for $operator_name<T> {}
135    };
136}
137
138macro_rules! implement_typed_binary_operator_with_bool_return_type {
139    ($operator_trait_name:ident,
140        $graphblas_operator_name:ident,
141        $value_type:ty
142    ) => {
143        impl $operator_trait_name<$value_type> for $value_type {
144            fn graphblas_type() -> GrB_BinaryOp {
145                unsafe { $graphblas_operator_name }
146            }
147        }
148    };
149}
150
151macro_rules! implement_binary_operator_for_boolean {
152    (
153        $operator_name:ident,
154        $graphblas_operator_name:ident
155    ) => {
156        impl BinaryOperator<bool> for $operator_name<bool> {
157            fn graphblas_type(&self) -> GrB_BinaryOp {
158                unsafe { $graphblas_operator_name }
159            }
160        }
161
162        impl AccumulatorBinaryOperator<bool> for $operator_name<bool> {
163            fn accumulator_graphblas_type(&self) -> GrB_BinaryOp {
164                unsafe { $graphblas_operator_name }
165            }
166        }
167
168        impl $operator_name<bool> {
169            pub fn new() -> Self {
170                Self {
171                    _evaluation_domain: PhantomData,
172                }
173            }
174        }
175
176        impl ReturnsBool for $operator_name<bool> {}
177    };
178}
179
180macro_rules! define_binary_operator {
181    ($identifier: ident) => {
182        #[derive(Debug, Clone)]
183        pub struct $identifier<T>
184        where
185            T: ValueType,
186        {
187            _evaluation_domain: PhantomData<T>,
188        }
189    };
190}
191
192define_binary_operator!(Assignment);
193impl<T: ValueType> AccumulatorBinaryOperator<T> for Assignment<T> {
194    fn accumulator_graphblas_type(&self) -> GrB_BinaryOp {
195        ptr::null_mut()
196    }
197}
198
199// TODO
200/// Type will be ignored, type-casting depends on ValueType of the input and output collections
201impl<T: ValueType> Assignment<T> {
202    pub fn new() -> Self {
203        Self {
204            _evaluation_domain: PhantomData,
205        }
206    }
207}
208
209// x = first(x,y)
210define_binary_operator!(First);
211implement_binary_operator!(First, FirstTyped);
212implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
213    implement_typed_binary_operator,
214    FirstTyped,
215    GrB_FIRST
216);
217
218// y = second(x,y)
219define_binary_operator!(Second);
220implement_binary_operator!(Second, SecondTyped);
221implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
222    implement_typed_binary_operator,
223    SecondTyped,
224    GrB_SECOND
225);
226
227// z = 1
228define_binary_operator!(One);
229implement_binary_operator!(One, OneTyped);
230implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
231    implement_typed_binary_operator,
232    OneTyped,
233    GrB_ONEB
234);
235
236// z = x^y (z = x.pow(y))
237define_binary_operator!(Power);
238implement_binary_operator!(Power, PowerTyped);
239implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
240    implement_typed_binary_operator,
241    PowerTyped,
242    GxB_POW
243);
244
245// z = x+y
246define_binary_operator!(Plus);
247implement_binary_operator!(Plus, PlusTyped);
248implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
249    implement_typed_binary_operator,
250    PlusTyped,
251    GrB_PLUS
252);
253
254// z = x-y
255define_binary_operator!(Minus);
256implement_binary_operator!(Minus, MinusTyped);
257implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
258    implement_typed_binary_operator,
259    MinusTyped,
260    GrB_MINUS
261);
262
263// z = y-x
264define_binary_operator!(ReverseMinus);
265implement_binary_operator!(ReverseMinus, ReverseMinusTyped);
266implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
267    implement_typed_binary_operator,
268    ReverseMinusTyped,
269    GxB_RMINUS
270);
271
272// z = x*y
273define_binary_operator!(Times);
274implement_binary_operator!(Times, TimesTyped);
275implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
276    implement_typed_binary_operator,
277    TimesTyped,
278    GrB_TIMES
279);
280
281// z = x/y
282define_binary_operator!(Divide);
283implement_binary_operator!(Divide, DivideTyped);
284implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
285    implement_typed_binary_operator,
286    DivideTyped,
287    GrB_DIV
288);
289
290// z = x/y
291define_binary_operator!(ReverseDivide);
292implement_binary_operator!(ReverseDivide, ReverseDivideTyped);
293implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
294    implement_typed_binary_operator,
295    ReverseDivideTyped,
296    GxB_RDIV
297);
298
299// z = x==y
300#[derive(Debug, Clone)]
301pub struct IsEqual<T>
302where
303    T: ValueType,
304{
305    _evaluation_domain: PhantomData<T>,
306}
307
308implement_binary_operator_with_bool_return_type!(IsEqual, IsEqualTyped);
309implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
310    implement_typed_binary_operator_with_bool_return_type,
311    IsEqualTyped,
312    GrB_EQ
313);
314
315// z = x==y
316define_binary_operator!(TypedIsEqual);
317implement_binary_operator!(TypedIsEqual, TypedIsEqualTyped);
318implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
319    implement_typed_binary_operator,
320    TypedIsEqualTyped,
321    GxB_ISEQ
322);
323
324// z = x!=y
325#[derive(Debug, Clone)]
326pub struct IsNotEqual<T>
327where
328    T: ValueType,
329{
330    _evaluation_domain: PhantomData<T>,
331}
332
333implement_binary_operator_with_bool_return_type!(IsNotEqual, IsNotEqualTyped);
334implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
335    implement_typed_binary_operator_with_bool_return_type,
336    IsNotEqualTyped,
337    GrB_NE
338);
339
340// z = x==y
341define_binary_operator!(TypedIsNotEqual);
342implement_binary_operator!(TypedIsNotEqual, TypedIsNotEqualTyped);
343implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
344    implement_typed_binary_operator,
345    TypedIsNotEqualTyped,
346    GxB_ISNE
347);
348
349// z = any(x,y), selected according to fastest computation speed
350define_binary_operator!(Any);
351implement_binary_operator!(Any, AnyTyped);
352implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
353    implement_typed_binary_operator,
354    AnyTyped,
355    GxB_ANY
356);
357
358// z = min(x,y)
359define_binary_operator!(Min);
360implement_binary_operator!(Min, MinTyped);
361implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
362    implement_typed_binary_operator,
363    MinTyped,
364    GrB_MIN
365);
366
367// z = max(x,y)
368define_binary_operator!(Max);
369implement_binary_operator!(Max, MaxTyped);
370implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
371    implement_typed_binary_operator,
372    MaxTyped,
373    GrB_MAX
374);
375
376// z = (x>y)
377#[derive(Debug, Clone)]
378pub struct IsGreaterThan<T>
379where
380    T: ValueType,
381{
382    _evaluation_domain: PhantomData<T>,
383}
384
385implement_binary_operator_with_bool_return_type!(IsGreaterThan, IsGreaterThanTyped);
386implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
387    implement_typed_binary_operator_with_bool_return_type,
388    IsGreaterThanTyped,
389    GrB_GT
390);
391
392// z = (x>y)
393define_binary_operator!(TypedIsGreaterThan);
394implement_binary_operator!(TypedIsGreaterThan, TypedIsGreaterThanTyped);
395implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
396    implement_typed_binary_operator,
397    TypedIsGreaterThanTyped,
398    GxB_ISGT
399);
400
401// z = (x>=y)
402#[derive(Debug, Clone)]
403pub struct IsGreaterThanOrEqualTo<T>
404where
405    T: ValueType,
406{
407    _evaluation_domain: PhantomData<T>,
408}
409
410implement_binary_operator_with_bool_return_type!(
411    IsGreaterThanOrEqualTo,
412    IsGreaterThanOrEqualToTyped
413);
414implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
415    implement_typed_binary_operator_with_bool_return_type,
416    IsGreaterThanOrEqualToTyped,
417    GrB_GE
418);
419
420// z = (x>=y)
421define_binary_operator!(TypedIsGreaterThanOrEqualTo);
422implement_binary_operator!(
423    TypedIsGreaterThanOrEqualTo,
424    TypedIsGreaterThanOrEqualToTyped
425);
426implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
427    implement_typed_binary_operator,
428    TypedIsGreaterThanOrEqualToTyped,
429    GxB_ISGE
430);
431
432// z = (x<y)
433#[derive(Debug, Clone)]
434pub struct IsLessThan<T>
435where
436    T: ValueType,
437{
438    _evaluation_domain: PhantomData<T>,
439}
440
441implement_binary_operator_with_bool_return_type!(IsLessThan, IsLessThanTyped);
442implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
443    implement_typed_binary_operator_with_bool_return_type,
444    IsLessThanTyped,
445    GrB_LT
446);
447
448// z = (x<y)
449define_binary_operator!(TypedIsLessThan);
450implement_binary_operator!(TypedIsLessThan, TypedIsLessThanTyped);
451implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
452    implement_typed_binary_operator,
453    TypedIsLessThanTyped,
454    GxB_ISLT
455);
456
457// z = (x<=y)
458#[derive(Debug, Clone)]
459pub struct IsLessThanOrEqualTo<T>
460where
461    T: ValueType,
462{
463    _evaluation_domain: PhantomData<T>,
464}
465
466implement_binary_operator_with_bool_return_type!(IsLessThanOrEqualTo, IsLessThanOrEqualToTyped);
467implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
468    implement_typed_binary_operator_with_bool_return_type,
469    IsLessThanOrEqualToTyped,
470    GrB_LE
471);
472
473// z = (x<=y)
474define_binary_operator!(TypedIsLessThanOrEqualTo);
475implement_binary_operator!(TypedIsLessThanOrEqualTo, TypedIsLessThanOrEqualToTyped);
476implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
477    implement_typed_binary_operator,
478    TypedIsLessThanOrEqualToTyped,
479    GxB_ISLE
480);
481
482// z = (x|y)
483define_binary_operator!(LogicalOr);
484implement_binary_operator_for_boolean!(LogicalOr, GrB_LOR);
485
486// z = (x|y)
487define_binary_operator!(TypedLogicalOr);
488implement_binary_operator!(TypedLogicalOr, TypedLogicalOrTyped);
489implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
490    implement_typed_binary_operator,
491    TypedLogicalOrTyped,
492    GxB_LOR
493);
494
495// z = (x&y)
496define_binary_operator!(LogicalAnd);
497implement_binary_operator_for_boolean!(LogicalAnd, GrB_LAND);
498
499// z = (x&y)
500define_binary_operator!(TypedLogicalAnd);
501implement_binary_operator!(TypedLogicalAnd, TypedLogicalAndTyped);
502implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
503    implement_typed_binary_operator,
504    TypedLogicalAndTyped,
505    GxB_LAND
506);
507
508// z = (x|y)
509define_binary_operator!(LogicalExclusiveOr);
510implement_binary_operator_for_boolean!(LogicalExclusiveOr, GrB_LXOR);
511
512// z = (x&y)
513define_binary_operator!(TypedLogicalExclusiveOr);
514implement_binary_operator!(TypedLogicalExclusiveOr, TypedLogicalExclusiveOrTyped);
515implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_value_types!(
516    implement_typed_binary_operator,
517    TypedLogicalExclusiveOrTyped,
518    GxB_LXOR
519);
520
521// z = tan^{-1}(y/x)
522define_binary_operator!(FloatingPointFourQuadrantArcTangent);
523implement_binary_operator!(
524    FloatingPointFourQuadrantArcTangent,
525    FloatingPointFourQuadrantArcTangentTyped
526);
527implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types!(
528    implement_typed_binary_operator,
529    FloatingPointFourQuadrantArcTangentTyped,
530    GxB_ATAN2
531);
532
533// z = sqrt(x^2 + y^2)
534define_binary_operator!(FloatingPointHypotenuse);
535implement_binary_operator!(FloatingPointHypotenuse, FloatingPointHypotenuseTyped);
536implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types!(
537    implement_typed_binary_operator,
538    FloatingPointHypotenuseTyped,
539    GxB_HYPOT
540);
541
542// z = remainder(x,y)
543// Distance to multiple of y closest to x
544define_binary_operator!(FloatingPointRemainder);
545implement_binary_operator!(FloatingPointRemainder, FloatingPointRemainderTyped);
546implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types!(
547    implement_typed_binary_operator,
548    FloatingPointRemainderTyped,
549    GxB_REMAINDER
550);
551
552// z = fmod(x,y)
553// Distance to last full multiple of y smaller than or equal to x
554define_binary_operator!(FloatingPointModulus);
555implement_binary_operator!(FloatingPointModulus, FloatingPointModulusTyped);
556implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types!(
557    implement_typed_binary_operator,
558    FloatingPointModulusTyped,
559    GxB_FMOD
560);
561
562// TODO: test for non-integer y
563// z = x*2^y
564define_binary_operator!(LDExp);
565implement_binary_operator!(LDExp, LDExpTyped);
566implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types!(
567    implement_typed_binary_operator,
568    LDExpTyped,
569    GxB_LDEXP
570);
571
572// z = copysign(x,y) => z~f(magnitude(x), sign(y))
573define_binary_operator!(FloatingPointFromMagnitudeAndSign);
574implement_binary_operator!(
575    FloatingPointFromMagnitudeAndSign,
576    FloatingPointFromMagnitudeAndSignTyped
577);
578implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_floating_point_types!(
579    implement_typed_binary_operator,
580    FloatingPointFromMagnitudeAndSignTyped,
581    GxB_COPYSIGN
582);
583
584// NOTE: bitwise operations on signed integers may behave differently between different compilers
585
586define_binary_operator!(BitWiseLogicalOr);
587implement_binary_operator!(BitWiseLogicalOr, BitWiseLogicalOrTyped);
588implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
589    implement_typed_binary_operator,
590    BitWiseLogicalOrTyped,
591    GrB_BOR
592);
593
594define_binary_operator!(BitWiseLogicalAnd);
595implement_binary_operator!(BitWiseLogicalAnd, BitWiseLogicalAndTyped);
596implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
597    implement_typed_binary_operator,
598    BitWiseLogicalAndTyped,
599    GrB_BAND
600);
601
602define_binary_operator!(BitWiseLogicalExclusiveNotOr);
603implement_binary_operator!(
604    BitWiseLogicalExclusiveNotOr,
605    BitWiseLogicalExclusiveNotOrTyped
606);
607implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
608    implement_typed_binary_operator,
609    BitWiseLogicalExclusiveNotOrTyped,
610    GrB_BXNOR
611);
612
613define_binary_operator!(BitWiseLogicalExclusiveOr);
614implement_binary_operator!(BitWiseLogicalExclusiveOr, BitWiseLogicalExclusiveOrTyped);
615implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
616    implement_typed_binary_operator,
617    BitWiseLogicalExclusiveOrTyped,
618    GrB_BXOR
619);
620
621define_binary_operator!(GetBit);
622implement_binary_operator!(GetBit, GetBitTyped);
623implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
624    implement_typed_binary_operator,
625    GetBitTyped,
626    GxB_BGET
627);
628
629define_binary_operator!(SetBit);
630implement_binary_operator!(SetBit, SetBitTyped);
631implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
632    implement_typed_binary_operator,
633    SetBitTyped,
634    GxB_BSET
635);
636
637define_binary_operator!(ClearBit);
638implement_binary_operator!(ClearBit, ClearBitTyped);
639implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
640    implement_typed_binary_operator,
641    ClearBitTyped,
642    GxB_BCLR
643);
644
645// TODO: consider restricting input to u8. This would improve performance and predictability
646define_binary_operator!(ShiftBit);
647implement_binary_operator!(ShiftBit, ShiftBitTyped);
648implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_integer_value_types!(
649    implement_typed_binary_operator,
650    ShiftBitTyped,
651    GxB_BSHIFT
652);
653
654define_binary_operator!(RowIndexFirstArgument);
655implement_binary_operator!(RowIndexFirstArgument, RowIndexFirstArgumentTyped);
656implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_graphblas_index_integer_value_types!(
657    implement_typed_binary_operator,
658    RowIndexFirstArgumentTyped,
659    GxB_FIRSTI
660);
661
662define_binary_operator!(ColumnIndexFirstArgument);
663implement_binary_operator!(ColumnIndexFirstArgument, ColumnIndexFirstArgumentTyped);
664implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_graphblas_index_integer_value_types!(
665    implement_typed_binary_operator,
666    ColumnIndexFirstArgumentTyped,
667    GxB_FIRSTJ
668);
669
670define_binary_operator!(RowIndexSecondArgument);
671implement_binary_operator!(RowIndexSecondArgument, RowIndexSecondArgumentTyped);
672implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_graphblas_index_integer_value_types!(
673    implement_typed_binary_operator,
674    RowIndexSecondArgumentTyped,
675    GxB_SECONDI
676);
677
678define_binary_operator!(ColumnIndexSecondArgument);
679implement_binary_operator!(ColumnIndexSecondArgument, ColumnIndexSecondArgumentTyped);
680implement_macro_with_1_type_trait_and_typed_graphblas_function_for_all_graphblas_index_integer_value_types!(
681    implement_typed_binary_operator,
682    ColumnIndexSecondArgumentTyped,
683    GxB_SECONDJ
684);
685
686#[cfg(test)]
687mod tests {
688    use crate::{
689        collections::{
690            sparse_matrix::{
691                operations::{FromMatrixElementList, GetSparseMatrixElementValue},
692                MatrixElementList, Size, SparseMatrix,
693            },
694            sparse_scalar::SparseScalar,
695            sparse_vector::{
696                operations::{FromVectorElementList, GetSparseVectorElementValue},
697                SparseVector, VectorElementList,
698            },
699            Collection,
700        },
701        context::Context,
702        operators::{
703            apply::{ApplyBinaryOperatorWithSparseScalar, BinaryOperatorApplier},
704            mask::{SelectEntireMatrix, SelectEntireVector},
705            options::{OperatorOptions, OptionsForOperatorWithMatrixAsFirstArgument},
706        },
707    };
708
709    use super::*;
710
711    #[test]
712    fn new_binary_operator() {
713        let first = First::<bool>::new();
714        let _graphblas_type = first.graphblas_type();
715
716        let plus = Plus::<i8>::new();
717        let _graphblas_type = plus.graphblas_type();
718    }
719
720    #[test]
721    fn test_divide_by_zero() {
722        let context = Context::init_default().unwrap();
723
724        let element_list =
725            VectorElementList::<u8>::from_element_vector(vec![(1, 1).into(), (2, 0).into()]);
726
727        let vector_length: usize = 10;
728        let vector = SparseVector::<u8>::from_element_list(
729            context.clone(),
730            vector_length,
731            element_list,
732            &First::<u8>::new(),
733        )
734        .unwrap();
735
736        let mut product_vector = SparseVector::<u8>::new(context.clone(), vector_length).unwrap();
737
738        let operator = BinaryOperatorApplier::new();
739
740        let second_argument = SparseScalar::<u8>::from_value(context.clone(), 0).unwrap();
741        operator
742            .apply_with_vector_as_left_argument(
743                &vector,
744                &Divide::<u8>::new(),
745                &second_argument,
746                &Assignment::new(),
747                &mut product_vector,
748                &SelectEntireVector::new(context.clone()),
749                &OperatorOptions::new_default(),
750            )
751            .unwrap();
752
753        println!("{}", product_vector);
754        assert_eq!(product_vector.element_value_or_default(1).unwrap(), u8::MAX);
755        assert_eq!(product_vector.element_value(2).unwrap(), Some(0));
756
757        let operator = BinaryOperatorApplier::new();
758
759        let mut product_vector = SparseVector::<f32>::new(context.clone(), vector_length).unwrap();
760        operator
761            .apply_with_vector_as_left_argument(
762                &vector,
763                &Divide::<u8>::new(),
764                &second_argument,
765                &Assignment::new(),
766                &mut product_vector,
767                &SelectEntireVector::new(context.clone()),
768                &OperatorOptions::new_default(),
769            )
770            .unwrap();
771
772        println!("{}", product_vector);
773        assert_eq!(
774            product_vector.element_value_or_default(1).unwrap(),
775            u8::MAX as f32
776        );
777        assert_eq!(product_vector.element_value_or_default(2).unwrap(), 0f32);
778
779        let operator = BinaryOperatorApplier::new();
780        operator
781            .apply_with_vector_as_left_argument(
782                &vector,
783                &Divide::<f32>::new(),
784                &second_argument,
785                &Assignment::new(),
786                &mut product_vector,
787                &SelectEntireVector::new(context.clone()),
788                &OperatorOptions::new_default(),
789            )
790            .unwrap();
791        println!("{}", product_vector);
792        assert_eq!(
793            product_vector.element_value_or_default(1).unwrap(),
794            f32::INFINITY
795        );
796        assert!(f32::is_nan(
797            product_vector.element_value_or_default(2).unwrap()
798        ));
799    }
800
801    #[test]
802    fn test_ldexp_and_type_casting_for_floating_point_operators() {
803        let context = Context::init_default().unwrap();
804
805        let element_list = VectorElementList::<u8>::from_element_vector(vec![
806            (0, 1).into(),
807            (1, 2).into(),
808            (2, 3).into(),
809        ]);
810
811        let vector_length: usize = 10;
812        let vector = SparseVector::<u8>::from_element_list(
813            context.clone(),
814            vector_length,
815            element_list,
816            &First::<u8>::new(),
817        )
818        .unwrap();
819
820        let mut product_vector = SparseVector::<u8>::new(context.clone(), vector_length).unwrap();
821
822        let operator = BinaryOperatorApplier::new();
823
824        let second_argument = SparseScalar::<f32>::from_value(context.clone(), 0.5).unwrap();
825        operator
826            .apply_with_vector_as_left_argument(
827                &vector,
828                &LDExp::<f32>::new(),
829                &second_argument,
830                &Assignment::new(),
831                &mut product_vector,
832                &SelectEntireVector::new(context.clone()),
833                &OperatorOptions::new_default(),
834            )
835            .unwrap();
836
837        println!("{}", product_vector);
838        assert_eq!(product_vector.element_value_or_default(0).unwrap(), 1);
839        assert_eq!(product_vector.element_value_or_default(1).unwrap(), 2);
840        assert_eq!(product_vector.element_value_or_default(2).unwrap(), 3);
841    }
842
843    #[test]
844    fn test_bitshift() {
845        let context = Context::init_default().unwrap();
846
847        let element_list = VectorElementList::<f64>::from_element_vector(vec![
848            (0, u16::MAX as f64).into(),
849            (1, u16::MAX as f64).into(),
850            (2, u16::MAX as f64 + 0.5).into(),
851        ]);
852
853        let vector_length: usize = 10;
854        let vector = SparseVector::<f64>::from_element_list(
855            context.clone(),
856            vector_length,
857            element_list,
858            &First::<f64>::new(),
859        )
860        .unwrap();
861
862        let mut product_vector = SparseVector::<f32>::new(context.clone(), vector_length).unwrap();
863
864        let operator = BinaryOperatorApplier::new();
865
866        for i in 0..3 {
867            let second_argument =
868                SparseScalar::<f32>::from_value(context.clone(), i as f32 + 0.5).unwrap();
869            operator
870                .apply_with_vector_as_left_argument(
871                    &vector,
872                    &ShiftBit::<u8>::new(),
873                    &second_argument,
874                    &Assignment::new(),
875                    &mut product_vector,
876                    &SelectEntireVector::new(context.clone()),
877                    &OperatorOptions::new_default(),
878                )
879                .unwrap();
880
881            println!("{}", product_vector);
882            match i {
883                0 => {
884                    assert_eq!(product_vector.element_value_or_default(2).unwrap(), 255f32);
885                }
886                1 => {
887                    assert_eq!(product_vector.element_value_or_default(2).unwrap(), 254f32);
888                }
889                2 => {
890                    assert_eq!(product_vector.element_value_or_default(2).unwrap(), 252f32);
891                }
892                3 => {
893                    assert_eq!(product_vector.element_value_or_default(2).unwrap(), 248f32);
894                }
895                _ => {}
896            }
897        }
898    }
899
900    #[test]
901    fn test_index() {
902        let context = Context::init_default().unwrap();
903
904        let element_list = MatrixElementList::<u8>::from_element_vector(vec![
905            (1, 1, 1).into(),
906            (2, 1, 2).into(),
907            (4, 2, 4).into(),
908            (5, 2, 5).into(),
909        ]);
910
911        let matrix_size: Size = (10, 15).into();
912        let matrix = SparseMatrix::<u8>::from_element_list(
913            context.clone(),
914            matrix_size,
915            element_list,
916            &First::<u8>::new(),
917        )
918        .unwrap();
919
920        let mut product_matrix = SparseMatrix::<u8>::new(context.clone(), matrix_size).unwrap();
921
922        let operator = BinaryOperatorApplier::new();
923
924        let second_argument = SparseScalar::<u8>::from_value(context.clone(), 10).unwrap();
925        operator
926            .apply_with_matrix_as_left_argument(
927                &matrix,
928                &RowIndexFirstArgument::<i64>::new(),
929                &second_argument,
930                &Assignment::new(),
931                &mut product_matrix,
932                &SelectEntireMatrix::new(context.clone()),
933                &OptionsForOperatorWithMatrixAsFirstArgument::new_default(),
934            )
935            .unwrap();
936
937        println!("{}", product_matrix);
938
939        assert_eq!(product_matrix.number_of_stored_elements().unwrap(), 4);
940        assert_eq!(product_matrix.element_value_or_default(1, 1).unwrap(), 1);
941        assert_eq!(product_matrix.element_value_or_default(2, 1).unwrap(), 2);
942        assert_eq!(product_matrix.element_value_or_default(4, 2).unwrap(), 4);
943        assert_eq!(product_matrix.element_value_or_default(5, 2).unwrap(), 5);
944    }
945}