1 //------------------------------------------------------------------------------
2 // GB_mx_Monoid: construct a monoid from a built-in operator
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 // Also defines the identity of the monoid
11 
12 #define GET_DEEP_COPY ;
13 #define FREE_DEEP_COPY ;
14 #define FREE_ALL ;
15 
16 #include "GB_mex.h"
17 
GB_mx_Monoid(GrB_Monoid * handle,const GrB_BinaryOp add,const bool malloc_debug)18 bool GB_mx_Monoid               // true if successful, false otherwise
19 (
20     GrB_Monoid *handle,         // monoid to construct
21     const GrB_BinaryOp add,     // monoid operator
22     const bool malloc_debug     // true if malloc debug should be done
23 )
24 {
25 
26     GrB_Monoid M = NULL ;
27     (*handle) = NULL ;
28     if (add == NULL)
29     {
30         mexWarnMsgIdAndTxt ("GB:warn", "monoid operator missing") ;
31         return (false) ;
32     }
33 
34     switch (add->opcode)
35     {
36         case GB_MIN_opcode     :
37 
38             // 11 MIN monoids
39             switch (add->xtype->code)
40             {
41                 // bool case redundant with AND
42                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_  (&M, add, (bool    ) true)) ;        break ;
43                 case GB_INT8_code   : METHOD (GrB_Monoid_new_INT8_  (&M, add, (int8_t  ) INT8_MAX)) ;    break ;
44                 case GB_INT16_code  : METHOD (GrB_Monoid_new_INT16_ (&M, add, (int16_t ) INT16_MAX)) ;   break ;
45                 case GB_INT32_code  : METHOD (GrB_Monoid_new_INT32_ (&M, add, (int32_t ) INT32_MAX)) ;   break ;
46                 case GB_INT64_code  : METHOD (GrB_Monoid_new_INT64_ (&M, add, (int64_t ) INT64_MAX)) ;   break ;
47                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) UINT8_MAX)) ;   break ;
48                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) UINT16_MAX)) ;  break ;
49                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) UINT32_MAX)) ;  break ;
50                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) UINT64_MAX)) ;  break ;
51                 case GB_FP32_code   : METHOD (GrB_Monoid_new_FP32_  (&M, add, (float   ) INFINITY)) ;    break ;
52                 case GB_FP64_code   : METHOD (GrB_Monoid_new_FP64_  (&M, add, (double  ) INFINITY)) ;    break ;
53                 default:
54                     mexWarnMsgIdAndTxt ("GB:warn", "unknown type for MIN") ;
55                     return (false) ;
56             }
57             break ;
58 
59         case GB_MAX_opcode     :
60 
61             // 11 MAX monoids
62             switch (add->xtype->code)
63             {
64                 // bool case redundant with OR
65                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_  (&M, add, (bool    ) false)) ;       break ;
66                 case GB_INT8_code   : METHOD (GrB_Monoid_new_INT8_  (&M, add, (int8_t  ) INT8_MIN)) ;    break ;
67                 case GB_INT16_code  : METHOD (GrB_Monoid_new_INT16_ (&M, add, (int16_t ) INT16_MIN)) ;   break ;
68                 case GB_INT32_code  : METHOD (GrB_Monoid_new_INT32_ (&M, add, (int32_t ) INT32_MIN)) ;   break ;
69                 case GB_INT64_code  : METHOD (GrB_Monoid_new_INT64_ (&M, add, (int64_t ) INT64_MIN)) ;   break ;
70                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0)) ;           break ;
71                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0)) ;           break ;
72                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0)) ;           break ;
73                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0)) ;           break ;
74                 case GB_FP32_code   : METHOD (GrB_Monoid_new_FP32_  (&M, add, (float   ) -INFINITY)) ;   break ;
75                 case GB_FP64_code   : METHOD (GrB_Monoid_new_FP64_  (&M, add, (double  ) -INFINITY)) ;   break ;
76                 default:
77                     mexWarnMsgIdAndTxt ("GB:warn", "unknown type for MAX") ;
78                     return (false) ;
79             }
80             break ;
81 
82         case GB_PLUS_opcode    :
83 
84             // 13 PLUS monoids
85             switch (add->xtype->code)
86             {
87                 // bool case redundant with OR
88                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_  (&M, add, (bool    ) 0)) ;           break ;
89                 case GB_INT8_code   : METHOD (GrB_Monoid_new_INT8_  (&M, add, (int8_t  ) 0)) ;           break ;
90                 case GB_INT16_code  : METHOD (GrB_Monoid_new_INT16_ (&M, add, (int16_t ) 0)) ;           break ;
91                 case GB_INT32_code  : METHOD (GrB_Monoid_new_INT32_ (&M, add, (int32_t ) 0)) ;           break ;
92                 case GB_INT64_code  : METHOD (GrB_Monoid_new_INT64_ (&M, add, (int64_t ) 0)) ;           break ;
93                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0)) ;           break ;
94                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0)) ;           break ;
95                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0)) ;           break ;
96                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0)) ;           break ;
97                 case GB_FP32_code   : METHOD (GrB_Monoid_new_FP32_  (&M, add, (float   ) 0)) ;           break ;
98                 case GB_FP64_code   : METHOD (GrB_Monoid_new_FP64_  (&M, add, (double  ) 0)) ;           break ;
99                 case GB_FC32_code   : METHOD (GxB_Monoid_new_FC32_  (&M, add, (GxB_CMPLXF(0,0)))) ;      break ;
100                 case GB_FC64_code   : METHOD (GxB_Monoid_new_FC64_  (&M, add, (GxB_CMPLX (0,0)))) ;      break ;
101                 default:
102                     mexWarnMsgIdAndTxt ("GB:warn", "unknown type for (PLUS)") ;
103                     return (false) ;
104             }
105             break ;
106 
107         case GB_TIMES_opcode   :
108 
109             // 13 TIMES monoids
110             switch (add->xtype->code)
111             {
112                 // bool case redundant with AND
113                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_  (&M, add, (bool    ) true)) ;        break ;
114                 case GB_INT8_code   : METHOD (GrB_Monoid_new_INT8_  (&M, add, (int8_t  ) 1)) ;           break ;
115                 case GB_INT16_code  : METHOD (GrB_Monoid_new_INT16_ (&M, add, (int16_t ) 1)) ;           break ;
116                 case GB_INT32_code  : METHOD (GrB_Monoid_new_INT32_ (&M, add, (int32_t ) 1)) ;           break ;
117                 case GB_INT64_code  : METHOD (GrB_Monoid_new_INT64_ (&M, add, (int64_t ) 1)) ;           break ;
118                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 1)) ;           break ;
119                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 1)) ;           break ;
120                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 1)) ;           break ;
121                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 1)) ;           break ;
122                 case GB_FP32_code   : METHOD (GrB_Monoid_new_FP32_  (&M, add, (float   ) 1)) ;           break ;
123                 case GB_FP64_code   : METHOD (GrB_Monoid_new_FP64_  (&M, add, (double  ) 1)) ;           break ;
124                 case GB_FC32_code   : METHOD (GxB_Monoid_new_FC32_  (&M, add, (GxB_CMPLXF(1,0)))) ;      break ;
125                 case GB_FC64_code   : METHOD (GxB_Monoid_new_FC64_  (&M, add, (GxB_CMPLX (1,0)))) ;      break ;
126                 default:
127                     mexWarnMsgIdAndTxt ("GB:warn", "unknown type for (TIMES)") ;
128                     return (false) ;
129             }
130             break ;
131 
132         case GB_ANY_opcode   :
133 
134             // 13 ANY monoids
135             switch (add->xtype->code)
136             {
137                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL   (&M, add, (bool    ) false)) ;       break ;
138                 case GB_INT8_code   : METHOD (GrB_Monoid_new_INT8_  (&M, add, (int8_t  ) 0)) ;           break ;
139                 case GB_INT16_code  : METHOD (GrB_Monoid_new_INT16_ (&M, add, (int16_t ) 0)) ;           break ;
140                 case GB_INT32_code  : METHOD (GrB_Monoid_new_INT32_ (&M, add, (int32_t ) 0)) ;           break ;
141                 case GB_INT64_code  : METHOD (GrB_Monoid_new_INT64_ (&M, add, (int64_t ) 0)) ;           break ;
142                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0)) ;           break ;
143                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0)) ;           break ;
144                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0)) ;           break ;
145                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0)) ;           break ;
146                 case GB_FP32_code   : METHOD (GrB_Monoid_new_FP32_  (&M, add, (float   ) 0)) ;           break ;
147                 case GB_FP64_code   : METHOD (GrB_Monoid_new_FP64_  (&M, add, (double  ) 0)) ;           break ;
148                 case GB_FC32_code   : METHOD (GxB_Monoid_new_FC32_  (&M, add, (GxB_CMPLXF(0,0)))) ;      break ;
149                 case GB_FC64_code   : METHOD (GxB_Monoid_new_FC64_  (&M, add, (GxB_CMPLX (0,0)))) ;      break ;
150                 default:
151                     mexWarnMsgIdAndTxt ("GB:warn", "unknown type for (ANY)") ;
152                     return (false) ;
153             }
154             break ;
155 
156         case GB_LOR_opcode      :
157 
158             // both GrB_LOR and GxB_LOR_BOOL (same opcode)
159             switch (add->xtype->code)
160             {
161                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_(&M, add, (bool    ) false)) ;        break ;
162                 default:
163                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (OR)") ;
164                     return (false) ;
165             }
166             break ;
167 
168         case GB_LAND_opcode     :
169 
170             // both GrB_LAND and GxB_LAND_BOOL (same opcode)
171             switch (add->xtype->code)
172             {
173                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_(&M, add, (bool    ) true)) ;        break ;
174                 default:
175                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (AND)") ;
176                     return (false) ;
177             }
178             break ;
179 
180         case GB_LXOR_opcode     :
181 
182             // both GrB_LXOR and GxB_LXOR_BOOL (same opcode)
183             switch (add->xtype->code)
184             {
185                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_(&M, add, (bool    ) false)) ;        break ;
186                 default:
187                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (XOR)") ;
188                     return (false) ;
189             }
190             break ;
191 
192         case GB_ISEQ_opcode     :
193         case GB_EQ_opcode     :
194 
195             // both GrB_EQ_BOOL and GxB_ISEQ_BOOL (same opcode), also GrB_LXNOR
196             switch (add->xtype->code)
197             {
198                 case GB_BOOL_code   : METHOD (GrB_Monoid_new_BOOL_(&M, add, (bool    ) true)) ;         break ;
199                 default:
200                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (EQ)") ;
201                     return (false) ;
202             }
203             break ;
204 
205         case GB_BOR_opcode     :
206 
207             // BOR monoids (bitwise or):
208             // GxB_BOR_UINT8_MONOID,         // identity: 0   terminal: 0xFF
209             // GxB_BOR_UINT16_MONOID,        // identity: 0   terminal: 0xFFFF
210             // GxB_BOR_UINT32_MONOID,        // identity: 0   terminal: 0xFFFFFFFF
211             // GxB_BOR_UINT64_MONOID,        // identity: 0   terminal: 0xFFFFFFFFFFFFFFFF
212 
213             switch (add->xtype->code)
214             {
215                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0)) ;         break ;
216                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0)) ;         break ;
217                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0)) ;         break ;
218                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0)) ;         break ;
219                 default:
220                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (BOR)") ;
221                     return (false) ;
222             }
223             break ;
224 
225         case GB_BAND_opcode     :
226 
227             // BAND monoids (bitwise and):
228             // GxB_BAND_UINT8_MONOID,        // identity: 0xFF               terminal: 0
229             // GxB_BAND_UINT16_MONOID,       // identity: 0xFFFF             terminal: 0
230             // GxB_BAND_UINT32_MONOID,       // identity: 0xFFFFFFFF         terminal: 0
231             // GxB_BAND_UINT64_MONOID,       // identity: 0xFFFFFFFFFFFFFFFF terminal: 0
232 
233             switch (add->xtype->code)
234             {
235                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0xFF)) ;               break ;
236                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0xFFFF)) ;             break ;
237                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0xFFFFFFFF)) ;         break ;
238                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0xFFFFFFFFFFFFFFFF)) ; break ;
239                 default:
240                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (BAND)") ;
241                     return (false) ;
242             }
243             break ;
244 
245         case GB_BXOR_opcode     :
246 
247             // BXOR monoids (bitwise xor):
248             // GxB_BXOR_UINT8_MONOID,        // identity: 0
249             // GxB_BXOR_UINT16_MONOID,       // identity: 0
250             // GxB_BXOR_UINT32_MONOID,       // identity: 0
251             // GxB_BXOR_UINT64_MONOID,       // identity: 0
252 
253             switch (add->xtype->code)
254             {
255                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0)) ;         break ;
256                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0)) ;         break ;
257                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0)) ;         break ;
258                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0)) ;         break ;
259                 default:
260                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (BXOR)") ;
261                     return (false) ;
262             }
263             break ;
264 
265         case GB_BXNOR_opcode     :
266 
267             // BXNOR monoids (bitwise xnor):
268             // GxB_BXNOR_UINT8_MONOID,       // identity: 0xFF
269             // GxB_BXNOR_UINT16_MONOID,      // identity: 0xFFFF
270             // GxB_BXNOR_UINT32_MONOID,      // identity: 0xFFFFFFFF
271             // GxB_BXNOR_UINT64_MONOID ;     // identity: 0xFFFFFFFFFFFFFFFF
272 
273             switch (add->xtype->code)
274             {
275                 case GB_UINT8_code  : METHOD (GrB_Monoid_new_UINT8_ (&M, add, (uint8_t ) 0xFF)) ;               break ;
276                 case GB_UINT16_code : METHOD (GrB_Monoid_new_UINT16_(&M, add, (uint16_t) 0xFFFF)) ;             break ;
277                 case GB_UINT32_code : METHOD (GrB_Monoid_new_UINT32_(&M, add, (uint32_t) 0xFFFFFFFF)) ;         break ;
278                 case GB_UINT64_code : METHOD (GrB_Monoid_new_UINT64_(&M, add, (uint64_t) 0xFFFFFFFFFFFFFFFF)) ; break ;
279                 default:
280                     mexWarnMsgIdAndTxt ("GB:warn", "invalid monoid for (BXNOR)") ;
281                     return (false) ;
282             }
283             break ;
284 
285         default:
286             mexWarnMsgIdAndTxt ("GB:warn", "unsupported add operator") ;
287             return (false) ;
288     }
289 
290     ASSERT_MONOID_OK (M, "monoid", GB0) ;
291     (*handle) = M ;
292     return (true) ;
293 }
294 
295