1 //------------------------------------------------------------------------------
2 // GB_stringify_terminal: convert terminal condition into a string or enum
3 //------------------------------------------------------------------------------
4
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7
8 //------------------------------------------------------------------------------
9
10 // The terminal_expression_macro(cij) should return true if the value of
11 // cij has reached its terminal value, or false otherwise. If the monoid is
12 // not terminal, then the macro should always return false. The ANY monoid
13 // should always return true.
14
15 // The terminal_statement_macro is a macro containing a full statement. If the
16 // monoid is never terminal, it becomes the empty statement. Otherwise,
17 // it checks the terminal condition and does a "break" if true. The statement
18 // has no trailing semicolon.
19
20 #include "GB.h"
21 #include "GB_stringify.h"
22
23 //------------------------------------------------------------------------------
24 // GB_stringify_terminal: macros for terminal value and condition
25 //------------------------------------------------------------------------------
26
GB_stringify_terminal(bool * is_monoid_terminal,char * terminal_expression_macro,char * terminal_statement_macro,const char * terminal_expression_macro_name,const char * terminal_statement_macro_name,GB_Opcode opcode,GB_Type_code zcode)27 void GB_stringify_terminal // return strings to check terminal
28 (
29 // outputs:
30 bool *is_monoid_terminal, // true if monoid is terminal
31 char *terminal_expression_macro, // #define for terminal expression macro
32 char *terminal_statement_macro, // #define for terminal statement macro
33 // inputs:
34 const char *terminal_expression_macro_name, // name of expression macro
35 const char *terminal_statement_macro_name, // name of statement macro
36 GB_Opcode opcode, // must be a built-in binary operator from a monoid
37 GB_Type_code zcode // type code of the binary operator
38 )
39 {
40
41 char *terminal_value ;
42 char terminal_expression [GB_CUDA_STRLEN+1] ;
43 char terminal_statement [GB_CUDA_STRLEN+1] ;
44 int ecode ;
45
46 // get ecode and bool (is_monoid_terminal) from the opcode and zcode
47 GB_enumify_terminal (&ecode, opcode, zcode) ;
48 (*is_monoid_terminal) = (ecode <= 29) ;
49
50 // convert ecode and is_monoid_terminal to strings
51 GB_charify_identity_or_terminal (&terminal_value, ecode) ;
52 GB_charify_terminal_expression (terminal_expression,
53 terminal_value, is_monoid_terminal, ecode) ;
54 GB_charify_terminal_statement (terminal_statement,
55 terminal_value, is_monoid_terminal, ecode) ;
56
57 // convert strings to macros
58 GB_macrofy_terminal_expression (terminal_expression_macro,
59 terminal_expression_macro_name, terminal_expression) ;
60 GB_macrofy_terminal_statement (terminal_statement_macro,
61 terminal_statement_macro_name, terminal_statement) ;
62 }
63
64 //------------------------------------------------------------------------------
65 // GB_enumify_terminal: return enum of terminal value
66 //------------------------------------------------------------------------------
67
GB_enumify_terminal(int * ecode,GB_Opcode opcode,GB_Type_code zcode)68 void GB_enumify_terminal // return enum of terminal value
69 (
70 // output:
71 int *ecode, // enumerated terminal, 0 to 31 (-1 if fail)
72 // input:
73 GB_Opcode opcode, // built-in binary opcode of a monoid
74 GB_Type_code zcode // type code used in the opcode we want
75 )
76 {
77
78 int e = -1 ;
79
80 switch (opcode)
81 {
82
83 case GB_PLUS_opcode :
84
85 if (zcode == GB_BOOL_code)
86 {
87 e = 2 ; // true (boolean OR)
88 }
89 else
90 {
91 e = 31 ; // builtin with no terminal value
92 }
93 break ;
94
95 case GB_TIMES_opcode :
96
97 switch (zcode)
98 {
99 case GB_BOOL_code :
100 e = 3 ; // false (boolean AND)
101 break ;
102 case GB_INT8_code :
103 case GB_INT16_code :
104 case GB_INT32_code :
105 case GB_INT64_code :
106 case GB_UINT8_code :
107 case GB_UINT16_code :
108 case GB_UINT32_code :
109 case GB_UINT64_code :
110 e = 0 ; // 0
111 break ;
112 default :
113 e = 31 ; // builtin with no terminal value
114 break ;
115 }
116 break ;
117
118 case GB_LOR_opcode :
119
120 e = 2 ; // true
121 break ;
122
123 case GB_LAND_opcode :
124
125 e = 3 ; // false
126 break ;
127
128 case GB_MIN_opcode :
129
130 switch (zcode)
131 {
132 case GB_BOOL_code : e = 3 ; break ; // false
133 case GB_INT8_code : e = 13 ; break ; // INT8_MIN
134 case GB_INT16_code : e = 14 ; break ; // INT16_MIN
135 case GB_INT32_code : e = 15 ; break ; // INT32_MIN
136 case GB_INT64_code : e = 16 ; break ; // INT64_MIN
137 case GB_UINT8_code :
138 case GB_UINT16_code :
139 case GB_UINT32_code :
140 case GB_UINT64_code : e = 0 ; break ; // 0
141 case GB_FP32_code :
142 case GB_FP64_code : e = 17 ; break ; // -INFINITY
143 default : e = -1 ; break ;
144 }
145 break ;
146
147 case GB_MAX_opcode :
148
149 switch (zcode)
150 {
151 case GB_BOOL_code : e = 2 ; break ; // true
152 case GB_INT8_code : e = 4 ; break ; // INT8_MAX
153 case GB_INT16_code : e = 5 ; break ; // INT16_MAX
154 case GB_INT32_code : e = 6 ; break ; // INT32_MAX
155 case GB_INT64_code : e = 7 ; break ; // INT64_MAX
156 case GB_UINT8_code : e = 8 ; break ; // UINT8_MAX
157 case GB_UINT16_code : e = 9 ; break ; // UINT16_MAX
158 case GB_UINT32_code : e = 10 ; break ; // UINT32_MAX
159 case GB_UINT64_code : e = 11 ; break ; // UINT64_MAX
160 case GB_FP32_code :
161 case GB_FP64_code : e = 12 ; break ; // INFINITY
162 default : e = -1 ; break ;
163 }
164 break ;
165
166 case GB_ANY_opcode :
167
168 e = 18 ; // no specific terminal value
169 break ;
170
171 case GB_LXOR_opcode :
172 // case GB_LXNOR_opcode :
173 case GB_EQ_opcode :
174 default :
175
176 e = 31 ; // builtin with no terminal value
177 break ;
178
179 case GB_USER_opcode :
180
181 }
182
183 (*ecode) = e ;
184 }
185
186 //------------------------------------------------------------------------------
187 // GB_charify_terminal_expression: string to evaluate terminal expression
188 //------------------------------------------------------------------------------
189
GB_charify_terminal_expression(char * terminal_expression,char * terminal_string,bool is_monoid_terminal,int ecode)190 void GB_charify_terminal_expression // string for terminal expression
191 (
192 // output:
193 char *terminal_expression, // string with terminal expression
194 // input:
195 char *terminal_string, // string with terminal value
196 bool is_monoid_terminal, // true if monoid is terminal
197 int ecode // ecode of monoid operator
198 )
199 {
200
201 if (is_monoid_terminal)
202 {
203 // the monoid is terminal
204 if (ecode == 18)
205 {
206 // ANY monoid: terminal expression is always true
207 snprintf (terminal_expression, GB_CUDA_STRLEN, "(true)") ;
208 }
209 else
210 {
211 // typical terminal monoids: check if C(i,j) has reached its
212 // terminal value
213 snprintf (terminal_expression, GB_CUDA_STRLEN,
214 "((cij) == %s)", terminal_string) ;
215 }
216 }
217 else
218 {
219 // the monoid is not terminal: the expression is always false
220 snprintf (terminal_expression, GB_CUDA_STRLEN, "(false)") ;
221 }
222 }
223
224 //------------------------------------------------------------------------------
225 // GB_charify_terminal_statement: string for terminal statement
226 //------------------------------------------------------------------------------
227
GB_charify_terminal_statement(char * terminal_statement,char * terminal_string,bool is_monoid_terminal,int ecode)228 void GB_charify_terminal_statement // string for terminal statement
229 (
230 // output:
231 char *terminal_statement, // string with terminal statement
232 // input:
233 char *terminal_string, // string with terminal value
234 bool is_monoid_terminal, // true if monoid is terminal
235 int ecode // ecode of monoid operator
236 )
237 {
238
239 if (is_monoid_terminal)
240 {
241 // the monoid is terminal
242 if (ecode == 18)
243 {
244 // ANY monoid: always break
245 snprintf (terminal_statement, GB_CUDA_STRLEN, "break") ;
246 }
247 else
248 {
249 // typical terminal monoids: break if C(i,j) has reached its
250 // terminal value
251 snprintf (terminal_statement, GB_CUDA_STRLEN,
252 "if ((cij) == %s) break", terminal_string) ;
253 }
254 }
255 else
256 {
257 // the monoid is not terminal: the terminal statement is empty
258 snprintf (terminal_statement, GB_CUDA_STRLEN, "") ;
259 }
260 }
261
262 //------------------------------------------------------------------------------
263 // GB_macrofy_terminal_expression: macro for terminal expression
264 //------------------------------------------------------------------------------
265
GB_macrofy_terminal_expression(char * terminal_expression_macro,const char * terminal_expression_macro_name,const char * terminal_expression)266 void GB_macrofy_terminal_expression // macro for terminal expression
267 (
268 // output:
269 char *terminal_expression_macro,
270 // intput:
271 const char *terminal_expression_macro_name,
272 const char *terminal_expression
273 )
274 {
275
276 snprintf (terminal_expression_macro, GB_CUDA_STRLEN,
277 "#define %s(cij) %s",
278 terminal_expression_macro_name, terminal_expression) ;
279 }
280
281 //------------------------------------------------------------------------------
282 // GB_macrofy_terminal_statement: macro for terminal statement
283 //------------------------------------------------------------------------------
284
GB_macrofy_terminal_statement(char * terminal_statement_macro,const char * terminal_statement_macro_name,const char * terminal_statement)285 void GB_macrofy_terminal_statement // macro for terminal statement
286 (
287 // output:
288 char *terminal_statement_macro,
289 // intput:
290 const char *terminal_statement_macro_name,
291 const char *terminal_statement
292 )
293 {
294
295 snprintf (terminal_statement_macro, GB_CUDA_STRLEN,
296 "#define %s %s",
297 terminal_statement_macro_name, terminal_statement) ;
298 }
299
300