1 //------------------------------------------------------------------------------
2 // isequal: check two matrices for exact equality
3 //------------------------------------------------------------------------------
4 
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7 
8 //------------------------------------------------------------------------------
9 
10 // isequal: check if two matrices are identically equal (same size,type,
11 // pattern, size, and values).  Checking for the same type requires a function
12 // that is an extension in SuiteSparse:GraphBLAS.  For the standard API, there
13 // is no way to determine the type of a matrix.
14 
15 // isequal_type: uses just the standard API.
16 
17 // For both methods, if the two matrices are FP32 or FP64, and have NaNs, then
18 // these functions will return false, since NaN == NaN is false.  To check for
19 // NaN equality (like isequalwithequalnans in MATLAB), use isequal_type with a
20 // user-defined operator f(x,y) that returns true if x and y are both NaN.
21 
22 #include "GraphBLAS.h"
23 #undef GB_PUBLIC
24 #define GB_LIBRARY
25 #include "graphblas_demos.h"
26 
27 // call a GraphBLAS method and return if an error occurs
28 #undef  OK
29 #define OK(method)                                          \
30 {                                                           \
31     GrB_Info info = method ;                                \
32     if (! (info == GrB_SUCCESS || info == GrB_NO_VALUE))    \
33     {                                                       \
34         /* error occured: free workspace and return */      \
35         GrB_Matrix_free (&C) ;                              \
36         return (info) ;                                     \
37     }                                                       \
38 }
39 
40 //------------------------------------------------------------------------------
41 // isequal_type: check two matrices, works in any GraphBLAS
42 //------------------------------------------------------------------------------
43 
44 GB_PUBLIC
isequal_type(bool * result,GrB_Matrix A,GrB_Matrix B,GrB_BinaryOp op)45 GrB_Info isequal_type       // return GrB_SUCCESS if successful
46 (
47     bool *result,           // true if A == B, false if A != B or error
48     GrB_Matrix A,
49     GrB_Matrix B,
50     GrB_BinaryOp op         // should be GrB_EQ_<type>, for the type of A and B
51 )
52 {
53 
54     GrB_Matrix C = NULL ;
55     GrB_Index nrows1, ncols1, nrows2, ncols2, nvals, nvals1, nvals2 ;
56 
57     if (result == NULL)
58     {
59         // error: required parameter, result, is NULL
60         return (GrB_NULL_POINTER) ;
61     }
62     (*result) = false ;
63 
64     // check the size of A and B
65     OK (GrB_Matrix_nrows (&nrows1, A)) ;
66     OK (GrB_Matrix_nrows (&nrows2, B)) ;
67     if (nrows1 != nrows2)
68     {
69         // # of rows differ
70         return (GrB_SUCCESS) ;
71     }
72 
73     OK (GrB_Matrix_ncols (&ncols1, A)) ;
74     OK (GrB_Matrix_ncols (&ncols2, B)) ;
75     if (ncols1 != ncols2)
76     {
77         // # of cols differ
78         return (GrB_SUCCESS) ;
79     }
80 
81     // check the # entries in A and B
82     OK (GrB_Matrix_nvals (&nvals1, A)) ;
83     OK (GrB_Matrix_nvals (&nvals2, B)) ;
84     if (nvals1 != nvals2)
85     {
86         // # of entries differ
87         return (GrB_SUCCESS) ;
88     }
89 
90     // C = A .* B, where the pattern of C is the intersection of A and B
91     OK (GrB_Matrix_new (&C, GrB_BOOL, nrows1, ncols1)) ;
92     OK (GrB_Matrix_eWiseMult_BinaryOp (C, NULL, NULL, op, A, B, NULL)) ;
93 
94     // ensure C has the same number of entries as A and B
95     OK (GrB_Matrix_nvals (&nvals, C)) ;
96     if (nvals != nvals1)
97     {
98         // pattern of A and B are different
99         GrB_Matrix_free (&C) ;
100         return (GrB_SUCCESS) ;
101     }
102 
103     // result = and (C)
104     OK (GrB_Matrix_reduce_BOOL (result, NULL, GrB_LAND_MONOID_BOOL, C, NULL)) ;
105 
106     // free workspace and return result
107     GrB_Matrix_free (&C) ;
108     return (GrB_SUCCESS) ;
109 }
110 
111 //------------------------------------------------------------------------------
112 // isequal: for SuiteSparse/GraphBLAS only; also check if types are the same
113 //------------------------------------------------------------------------------
114 
115 #ifdef GxB_SUITESPARSE_GRAPHBLAS
116 // the isequal function only works with SuiteSparse:GraphBLAS
117 
isequal(bool * result,GrB_Matrix A,GrB_Matrix B,GrB_BinaryOp userop)118 GrB_Info isequal            // return GrB_SUCCESS if successful
119 (
120     bool *result,           // true if A == B, false if A != B or error
121     GrB_Matrix A,
122     GrB_Matrix B,
123     GrB_BinaryOp userop     // for A and B with user-defined types.  ignored
124                             // if A and B are of built-in types
125 )
126 {
127     GrB_Matrix C = NULL ;
128     GrB_Type atype, btype ;
129     GrB_BinaryOp op ;
130 
131     if (result == NULL)
132     {
133         // error: required parameter, result, is NULL
134         return (GrB_NULL_POINTER) ;
135     }
136     (*result) = false ;
137 
138     // check the type of A and B
139     OK (GxB_Matrix_type (&atype, A)) ;
140     OK (GxB_Matrix_type (&btype, B)) ;
141     if (atype != btype)
142     {
143         // types differ
144         return (GrB_SUCCESS) ;
145     }
146 
147     // select the comparator operator
148     if      (atype == GrB_BOOL  ) op = GrB_EQ_BOOL ;
149     else if (atype == GrB_INT8  ) op = GrB_EQ_INT8 ;
150     else if (atype == GrB_INT16 ) op = GrB_EQ_INT16 ;
151     else if (atype == GrB_INT32 ) op = GrB_EQ_INT32 ;
152     else if (atype == GrB_INT64 ) op = GrB_EQ_INT64 ;
153     else if (atype == GrB_UINT8 ) op = GrB_EQ_UINT8 ;
154     else if (atype == GrB_UINT16) op = GrB_EQ_UINT16 ;
155     else if (atype == GrB_UINT32) op = GrB_EQ_UINT32 ;
156     else if (atype == GrB_UINT64) op = GrB_EQ_UINT64 ;
157     else if (atype == GrB_FP32  ) op = GrB_EQ_FP32   ;
158     else if (atype == GrB_FP64  ) op = GrB_EQ_FP64   ;
159     else if (atype == GxB_FC32  ) op = GxB_EQ_FC32   ;
160     else if (atype == GxB_FC64  ) op = GxB_EQ_FC64   ;
161     else                          op = userop ; // A and B are user-defined
162 
163     // check the size, pattern, and values of A and B
164     OK (isequal_type (result, A, B, op)) ;
165 
166     // return result
167     return (GrB_SUCCESS) ;
168 }
169 #endif
170 
171