1function [opname optype ztype xtype ytype] = GB_spec_operator (op,optype_default)
2%GB_SPEC_OPERATOR get the contents of an operator
3%
4% On input, op can be a struct with a string op.opname that gives the operator
5% name, and a string op.optype with the operator type.  Alternatively, op can
6% be a string with the operator name, in which case the operator type is given
7% by optype_default.
8%
9% ztype, xtype, and ytype are the types of z, x, and y for z = f(x,y), if
10% f is a binary operator, or z = f(x) if f is a unary operator.
11
12% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
13% SPDX-License-Identifier: Apache-2.0
14
15if (isempty (op))
16    % No operator has been defined; return an empty operator.  GB_spec_accum
17    % uses this condition just like the (accum == NULL) condition in the C
18    % version of GraphBLAS.  It means C<Mask>=T is to be done instead of
19    % C<Mask>=accum(C,T).
20    opname = '' ;
21    optype = '' ;
22    xtype = '' ;
23    ytype = '' ;
24    ztype = '' ;
25    return
26elseif (isstruct (op))
27    % op is a struct with opname and optype
28    opname = op.opname ;
29    optype = op.optype ;
30else
31    % op is a string
32    opname = op ;
33    if (nargin == 1 && GB_spec_is_positional (opname))
34        % optype_default is ignored
35        optype = 'int64' ;
36    else
37        optype = optype_default ;
38    end
39end
40
41% xtype is always the optype
42xtype = optype ;
43
44% for binary ops: ytype is usually the optype, except for bitshift.
45% for unary ops:  ytype is 'none'.
46ytype = optype ;
47
48% ztype is usually the optype, except for the cases below
49ztype = optype ;
50
51is_float   = contains (optype, 'single') || contains (optype, 'double') ;
52is_complex = contains (optype, 'complex') ;
53is_int     = contains (optype, 'int') ; % int or uint
54is_logical = isequal (optype, 'logical') ;
55is_real_float = is_float && ~is_complex ;
56
57%-------------------------------------------------------------------------------
58% boolean rename:
59%-------------------------------------------------------------------------------
60
61if (is_logical)
62
63    switch (opname)
64
65        case { 'div' }
66            opname = 'first' ;
67
68        case { 'rdiv' }
69            opname = 'second' ;
70
71        case { 'min', 'times' }
72            opname = 'and' ;
73
74        case { 'max', 'plus' }
75            opname = 'or' ;
76
77        case { 'minus', 'rminus', 'isne', 'ne' }
78            opname = 'xor' ;
79
80        case { 'iseq' }
81            opname = 'eq' ;
82
83        case { 'isgt' }
84            opname = 'gt' ;
85
86        case { 'islt' }
87            opname = 'lt' ;
88
89        case { 'isge', 'pow' }
90            opname = 'ge' ;
91
92        case { 'isle' }
93            opname = 'le' ;
94
95        otherwise
96            % op not renamed
97    end
98end
99
100%-------------------------------------------------------------------------------
101% get the x,y,z types of the operator and check if valid
102%-------------------------------------------------------------------------------
103
104switch opname
105
106    %--------------------------------------------------------------------------
107    % binary ops for all 13 types
108    %--------------------------------------------------------------------------
109
110    case { 'first', 'second', 'pow', 'plus', 'minus', 'times', 'div', ...
111           'rminus', 'rdiv', 'pair', 'any', 'iseq', 'isne' }
112        % x,y,z types are all the same.
113
114    case { 'eq', 'ne' }
115        % x,y types the the same, z is logical
116        ztype = 'logical' ;
117
118    %--------------------------------------------------------------------------
119    % binary ops for 11 types (all but complex)
120    %--------------------------------------------------------------------------
121
122    case { 'max', 'min', 'isgt', 'islt', 'isge', 'isle', 'or', 'and', 'xor' }
123        % x,y,z types are all the same.
124        % available for 11 real types, not complex
125        if (is_complex)
126            error ('invalid op') ;
127        end
128
129    case { 'gt', 'lt', 'ge', 'le' }
130        % x,y types the the same, z is logical
131        % available for 11 real types, not complex
132        ztype = 'logical' ;
133        if (is_complex)
134            error ('invalid op') ;
135        end
136
137    %--------------------------------------------------------------------------
138    % binary ops for real floating point
139    %--------------------------------------------------------------------------
140
141    case { 'atan2', 'hypot', 'fmod', 'remainder', 'ldexp', 'copysign' }
142        % x,y,z types are all the same.
143        % available for real float and double only
144        if (~is_real_float)
145            error ('invalid op') ;
146        end
147
148    case { 'cmplx', 'complex' }
149        % x and y are real (float or double).  z is the corresponding complex
150        if (~is_real_float)
151            error ('invalid op') ;
152        elseif (isequal (optype, 'single'))
153            ztype = 'single complex' ;
154        else
155            ztype = 'double complex' ;
156        end
157        opname = 'cmplx' ;
158
159    %--------------------------------------------------------------------------
160    % binary ops for integer only
161    %--------------------------------------------------------------------------
162
163    case { 'bitor', 'bitand', 'bitxor', 'bitxnor', ...
164           'bitget', 'bitset', 'bitclr', ...
165           'bor', 'band', 'bxor', 'bxnor', ...
166           'bget', 'bset', 'bclr' }
167
168        % x,y,z types are all the same.
169        % available for int and uint only
170        if (~(is_int))
171            error ('invalid op') ;
172        end
173
174        switch (opname)
175            case { 'bitor', 'bor' }
176                opname = 'bor' ;
177            case { 'bitand', 'band' }
178                opname = 'band' ;
179            case { 'bitxor', 'bxor' }
180                opname = 'bxor' ;
181            case { 'bitxnor', 'bxnor' }
182                opname = 'bxnor' ;
183            case { 'bitget', 'bget' }
184                opname = 'bget' ;
185            case { 'bitset', 'bset' }
186                opname = 'bset' ;
187            case { 'bitclr', 'bclr' }
188                opname = 'bclr' ;
189        end
190
191    case { 'bitshift' , 'bshift' }
192        % x,z types are the same.  y is int8
193        % available for int and uint only
194        ytype = 'int8' ;
195        if (~(is_int))
196            error ('invalid op') ;
197        end
198
199    %--------------------------------------------------------------------------
200    % unary ops for all 13 types
201    %--------------------------------------------------------------------------
202
203    case { 'identity', 'one', 'ainv', 'minv' }
204        % x,y,z types are all the same.
205
206    case { 'abs' }
207        % x,y the same.  z is the same as x, except if x is complex
208        if (isequal (optype, 'single complex'))
209            ztype = 'single' ;
210        elseif (isequal (optype, 'double complex'))
211            ztype = 'double' ;
212        else
213            ztype = xtype ;
214        end
215
216    %--------------------------------------------------------------------------
217    % unary ops for 11 real types
218    %--------------------------------------------------------------------------
219
220    case { 'not' }
221        % x and z have the same type
222        if (is_complex)
223            error ('invalid op') ;
224        end
225        ytype = 'none' ;
226
227    %--------------------------------------------------------------------------
228    % unary ops for integer only
229    %--------------------------------------------------------------------------
230
231    case { 'bitnot', 'bnot', 'bitcmp', 'bcmp' }
232        % x and z have the same type
233        if (~is_int)
234            error ('invalid op') ;
235        end
236        ytype = 'none' ;
237        opname = 'bnot' ;
238
239    %--------------------------------------------------------------------------
240    % unary ops for floating-point only (both real and complex)
241    %--------------------------------------------------------------------------
242
243    case { 'sqrt',     'log',      'exp',           'log2',    ...
244           'sin',      'cos',      'tan',                      ...
245           'acos',     'asin',     'atan',                     ...
246           'sinh',     'cosh',     'tanh',                     ...
247           'acosh',    'asinh',    'atanh',                    ...
248           'ceil',     'floor',    'round',         'trunc',   ...
249           'exp2',     'expm1',    'log10',         'log1p',   ...
250           'signum' }
251        % x and z have the same type
252        if (~is_float)
253            error ('invalid op') ;
254        end
255        ytype = 'none' ;
256
257    case { 'isinf', 'isnan', 'isfinite' }
258        % z is logical
259        ztype = 'logical' ;
260        if (~is_float)
261            error ('invalid op') ;
262        end
263        ytype = 'none' ;
264
265    %--------------------------------------------------------------------------
266    % unary ops for real floating-point only
267    %--------------------------------------------------------------------------
268
269    case { 'lgamma', 'tgamma', 'erf', 'erfc', 'frexpx',  'frexpe' }
270        % x and z have the same type
271        if (~is_real_float)
272            error ('invalid op') ;
273        end
274        ytype = 'none' ;
275
276    %--------------------------------------------------------------------------
277    % unary ops for complex only
278    %--------------------------------------------------------------------------
279
280    case { 'conj' }
281        if (~is_complex)
282            error ('invalid op') ;
283        end
284        ytype = 'none' ;
285
286    case { 'real', 'imag', 'carg' }
287        if (~is_complex)
288            error ('invalid op') ;
289        end
290        if (isequal (optype, 'single complex'))
291            ztype = 'single' ;
292        else
293            ztype = 'double' ;
294        end
295        ytype = 'none' ;
296
297    %--------------------------------------------------------------------------
298    % binary positional ops
299    %--------------------------------------------------------------------------
300
301    case { 'firsti' , 'firsti1' , 'firstj' , 'firstj1', ...
302           'secondi', 'secondi1', 'secondj', 'secondj1' } ;
303        if (~(isequal (ztype, 'int64') || isequal (ztype, 'int32')))
304            error ('invalid op') ;
305        end
306        xtype = optype ;
307        ytype = optype ;
308
309    %--------------------------------------------------------------------------
310    % unary positional ops
311    %--------------------------------------------------------------------------
312
313    case { 'positioni', 'positioni1', 'positionj', 'positionj1' }
314        if (~(isequal (ztype, 'int64') || isequal (ztype, 'int32')))
315            error ('invalid op') ;
316        end
317        ytype = optype ;
318
319    otherwise
320        error ('unknown op') ;
321
322end
323
324