function codegen_axb_method (addop, multop, add, addfunc, mult, ztype, ... xytype, identity, terminal, omp_atomic, omp_microsoft_atomic) %CODEGEN_AXB_METHOD create a function to compute C=A*B over a semiring % % codegen_axb_method (addop, multop, add, addfunc, mult, ztype, xytype, identity, terminal, omp_atomic, omp_microsoft_atomic) % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. % SPDX-License-Identifier: Apache-2.0 if (isempty (mult)) return end f = fopen ('control.m4', 'w') ; is_first = false ; is_second = false ; is_pair = false ; is_positional = false ; switch (multop) case { 'firsti', 'firsti1', 'firstj', 'firstj1', 'secondj', 'secondj1' } is_positional = true ; case { 'first' } is_first = true ; case { 'second' } is_second = true ; case { 'pair' } is_pair = true ; end is_any = isequal (addop, 'any') ; is_max = isequal (addop, 'max') ; is_min = isequal (addop, 'min') ; is_eq = isequal (addop, 'eq') ; is_any_pair = is_any && isequal (multop, 'pair') ; ztype_is_real = ~contains (ztype, 'FC') ; is_any_complex = is_any && ~ztype_is_real ; is_plus_pair_real = isequal (addop, 'plus') && isequal (multop, 'pair') ... && ztype_is_real ; t_is_simple = isequal (multop, 'pair') || contains (multop, 'first') || contains (multop, 'second') ; t_is_nonnan = isequal (multop (1:2), 'is') || (multop (1) == 'l') ; switch (ztype) case { 'bool' } ztype_is_float = false ; ztype_ignore_overflow = false ; nbits = 8 ; bits = '0x1L' ; case { 'int8_t', 'uint8_t' } ztype_is_float = false ; ztype_ignore_overflow = false ; nbits = 8 ; bits = '0xffL' ; xbits = '0xFF' ; case { 'int16_t', 'uint16_t' } ztype_is_float = false ; ztype_ignore_overflow = false ; nbits = 16 ; bits = '0xffffL' ; xbits = '0xFFFF' ; case { 'int32_t', 'uint32_t' } ztype_is_float = false ; ztype_ignore_overflow = false ; nbits = 32 ; bits = '0xffffffffL' ; xbits = '0xFFFFFFFF' ; case { 'int64_t', 'uint64_t' } ztype_is_float = false ; ztype_ignore_overflow = true ; nbits = 64 ; bits = '0' ; xbits = '0xFFFFFFFFFFFFFFFFL' ; case { 'float' } ztype_is_float = true ; ztype_ignore_overflow = true ; nbits = 32 ; bits = '0' ; case { 'double', 'GxB_FC32_t' } ztype_is_float = true ; ztype_ignore_overflow = true ; nbits = 64 ; bits = '0' ; case { 'GxB_FC64_t' } ztype_is_float = true ; ztype_ignore_overflow = true ; nbits = 128 ; bits = '0' ; otherwise error ('unknown type') ; end % bits: special cases for the PAIR multiplier fprintf (f, 'define(`GB_ctype_bits'', `%s'')\n', bits) ; % nbits: # of bits in the type, needed for the atomic compare-exchange: fprintf (f, 'define(`GB_atomic_compare_exchange'', `GB_ATOMIC_COMPARE_EXCHANGE_%d'')\n', nbits) ; if (is_pair) % these semirings are renamed to any_pair, and not thus created if (isequal (addop, 'land') || isequal (addop, 'eq' ) || ... isequal (addop, 'lor' ) || isequal (addop, 'max' ) || ... isequal (addop, 'min' ) || isequal (addop, 'times')) return end end [fname, unsigned, bits] = codegen_type (xytype) ; [zname, ~, ~] = codegen_type (ztype) ; name = sprintf ('%s_%s_%s', addop, multop, fname) ; % function names fprintf (f, 'define(`_Adot2B'', `_Adot2B__%s'')\n', name) ; fprintf (f, 'define(`_Adot3B'', `_Adot3B__%s'')\n', name) ; fprintf (f, 'define(`_Adot4B'', `_Adot4B__%s'')\n', name) ; fprintf (f, 'define(`_Asaxpy3B'', `_Asaxpy3B__%s'')\n', name) ; fprintf (f, 'define(`_Asaxpy3B_M'', `_Asaxpy3B_M__%s'')\n', name) ; fprintf (f, 'define(`_Asaxpy3B_noM'', `_Asaxpy3B_noM__%s'')\n', name) ; fprintf (f, 'define(`_Asaxpy3B_notM'', `_Asaxpy3B_notM__%s'')\n', name) ; fprintf (f, 'define(`_AsaxbitB'', `_AsaxbitB__%s'')\n', name) ; fprintf (f, 'define(`GB_AxB_defs'', `GB_AxB_defs__%s'')\n', name) ; fprintf (f, 'define(`GB_AxB_defs_include'', `#include "GB_AxB_defs__%s.h"'')\n', name) ; % type of C, A, and B fprintf (f, 'define(`GB_ctype'', `%s'')\n', ztype) ; fprintf (f, 'define(`GB_atype'', `%s'')\n', xytype) ; fprintf (f, 'define(`GB_btype'', `%s'')\n', xytype) ; % flag if ztype can ignore overflow in some computations fprintf (f, 'define(`GB_ctype_ignore_overflow'', `%d'')\n', ztype_ignore_overflow) ; % simple typecast from 1 (or 2) real scalars to any other type switch (ztype) case { 'GxB_FC32_t' } fprintf (f, 'define(`GB_ctype_cast'', `GxB_CMPLXF (((float) $1), ((float) $2))'')\n') ; case { 'GxB_FC64_t' } fprintf (f, 'define(`GB_ctype_cast'', `GxB_CMPLX (((double) $1), ((double) $2))'')\n') ; otherwise fprintf (f, 'define(`GB_ctype_cast'', `((GB_ctype) $1)'')\n') ; end % simple typecast from 1 (or 2) real scalars to any other type switch (xytype) case { 'GxB_FC32_t' } fprintf (f, 'define(`GB_atype_cast'', `GxB_CMPLXF (((float) $1), ((float) $2))'')\n') ; case { 'GxB_FC64_t' } fprintf (f, 'define(`GB_atype_cast'', `GxB_CMPLX (((double) $1), ((double) $2))'')\n') ; otherwise fprintf (f, 'define(`GB_atype_cast'', `((GB_atype) $1)'')\n') ; end % identity and terminal values for the monoid fprintf (f, 'define(`GB_identity'', `%s'')\n', identity) ; if (is_any_pair) fprintf (f, 'define(`GB_is_any_pair_semiring'', `1'')\n') ; else fprintf (f, 'define(`GB_is_any_pair_semiring'', `0'')\n') ; end if (is_plus_pair_real) fprintf (f, 'define(`GB_is_plus_pair_real_semiring'', `1'')\n') ; else fprintf (f, 'define(`GB_is_plus_pair_real_semiring'', `0'')\n') ; end if (is_pair) fprintf (f, 'define(`GB_is_pair_multiplier'', `1'')\n') ; else fprintf (f, 'define(`GB_is_pair_multiplier'', `0'')\n') ; end if (is_eq) fprintf (f, 'define(`GB_is_eq_monoid'', `1'')\n') ; else fprintf (f, 'define(`GB_is_eq_monoid'', `0'')\n') ; end % for the conventional semirings in MATLAB, which get extra optimization % if (isequal (addop, 'plus') && isequal (multop, 'times') && ztype_is_float) % fprintf (f, 'define(`GB_is_performance_critical_semiring'', `1'')\n') ; % else % fprintf (f, 'define(`GB_is_performance_critical_semiring'', `0'')\n') ; % end if (is_any) % the ANY monoid terminates on the first entry seen fprintf (f, 'define(`GB_is_any_monoid'', `1'')\n') ; fprintf (f, 'define(`GB_terminal'', `break ;'')\n') ; fprintf (f, 'define(`GB_dot_simd_vectorize'', `;'')\n') ; elseif (~isempty (terminal)) % terminal monoids terminate when cij equals the terminal value fprintf (f, 'define(`GB_is_any_monoid'', `0'')\n') ; fprintf (f, 'define(`GB_terminal'', `if (cij == %s) { break ; }'')\n', ... terminal) ; fprintf (f, 'define(`GB_dot_simd_vectorize'', `;'')\n') ; else % non-terminal monoids fprintf (f, 'define(`GB_is_any_monoid'', `0'')\n') ; fprintf (f, 'define(`GB_terminal'', `;'')\n') ; op = '' ; if (ztype_is_real) switch (addop) case { 'plus' } op = '+' ; case { 'times' } op = '*' ; case { 'lor' } op = '||' ; case { 'land' } op = '&&' ; case { 'lxor' } op = '^' ; case { 'bor' } op = '|' ; case { 'band' } op = '&' ; case { 'bxor' } op = '^' ; otherwise op = '' ; end end if (isempty (op)) fprintf (f, 'define(`GB_dot_simd_vectorize'', `;'')\n') ; else pragma = sprintf ('GB_PRAGMA_SIMD_REDUCTION (%s,$1)', op) ; fprintf (f, 'define(`GB_dot_simd_vectorize'', `%s'')\n', pragma) ; end end if (ztype_is_real) if (omp_atomic || is_any) % on x86: all built-in real monoids are atomic. % The ANY monoid is atomic on any architecture. % MIN, MAX, EQ, XNOR are implemented with atomic compare/exchange. fprintf (f, 'define(`GB_has_atomic'', `1'')\n') ; else %% % no built-in OpenMP atomic pragma for this monoid. %% % Do not use atomic compare/exchange unless on the x86. %% fprintf (f, 'define(`GB_has_atomic'', `GB_X86_64'')\n') ; fprintf (f, 'define(`GB_has_atomic'', `1'')\n') ; end else % complex monoids are not atomic, except for 'plus' if (isequal (addop, 'plus')) fprintf (f, 'define(`GB_has_atomic'', `1'')\n') ; else fprintf (f, 'define(`GB_has_atomic'', `0'')\n') ; end end % firsti multiply operator if (contains (multop, 'firsti')) fprintf (f, 'define(`GB_is_firsti_multiplier'', `1'')\n') ; else fprintf (f, 'define(`GB_is_firsti_multiplier'', `0'')\n') ; end % firstj multiply operator if (contains (multop, 'firstj')) fprintf (f, 'define(`GB_is_firstj_multiplier'', `1'')\n') ; else fprintf (f, 'define(`GB_is_firstj_multiplier'', `0'')\n') ; end % secondj multiply operator if (contains (multop, 'secondj')) fprintf (f, 'define(`GB_is_secondj_multiplier'', `1'')\n') ; else fprintf (f, 'define(`GB_is_secondj_multiplier'', `0'')\n') ; end % plus_fc32 monoid: if (isequal (addop, 'plus') && isequal (ztype, 'GxB_FC32_t')) fprintf (f, 'define(`GB_is_plus_fc32_monoid'', `1'')\n') ; else fprintf (f, 'define(`GB_is_plus_fc32_monoid'', `0'')\n') ; end % plus_fc64 monoid: if (isequal (addop, 'plus') && isequal (ztype, 'GxB_FC64_t')) fprintf (f, 'define(`GB_is_plus_fc64_monoid'', `1'')\n') ; else fprintf (f, 'define(`GB_is_plus_fc64_monoid'', `0'')\n') ; end % any_fc32 monoid: if (isequal (addop, 'any') && isequal (ztype, 'GxB_FC32_t')) fprintf (f, 'define(`GB_is_any_fc32_monoid'', `1'')\n') ; else fprintf (f, 'define(`GB_is_any_fc32_monoid'', `0'')\n') ; end % any_fc64 monoid: if (isequal (addop, 'any') && isequal (ztype, 'GxB_FC64_t')) fprintf (f, 'define(`GB_is_any_fc64_monoid'', `1'')\n') ; else fprintf (f, 'define(`GB_is_any_fc64_monoid'', `0'')\n') ; end % min monoids: if (is_min) if (contains (ztype, 'int')) % min monoid for signed or unsigned integers fprintf (f, 'define(`GB_is_imin_monoid'', `1'')\n') ; fprintf (f, 'define(`GB_is_fmin_monoid'', `0'')\n') ; else % min monoid for float or double fprintf (f, 'define(`GB_is_imin_monoid'', `0'')\n') ; fprintf (f, 'define(`GB_is_fmin_monoid'', `1'')\n') ; end else % not a min monoid fprintf (f, 'define(`GB_is_imin_monoid'', `0'')\n') ; fprintf (f, 'define(`GB_is_fmin_monoid'', `0'')\n') ; end % max monoids: if (is_max) if (contains (ztype, 'int')) % max monoid for signed or unsigned integers fprintf (f, 'define(`GB_is_imax_monoid'', `1'')\n') ; fprintf (f, 'define(`GB_is_fmax_monoid'', `0'')\n') ; else % max monoid for float or double fprintf (f, 'define(`GB_is_imax_monoid'', `0'')\n') ; fprintf (f, 'define(`GB_is_fmax_monoid'', `1'')\n') ; end else % not a max monoid fprintf (f, 'define(`GB_is_imax_monoid'', `0'')\n') ; fprintf (f, 'define(`GB_is_fmax_monoid'', `0'')\n') ; end % only PLUS, TIMES, LOR, LAND, and LXOR can be done with OpenMP atomics % in gcc and icc. However, only PLUS and TIMES work with OpenMP atomics % in Microsoft Visual Studio; the LOR, LAND, and LXOR atomics don't compile. fprintf (f, 'define(`GB_has_omp_atomic'', `%d'')\n', omp_atomic) ; fprintf (f, 'define(`GB_microsoft_has_omp_atomic'', `%d'')\n', omp_microsoft_atomic) ; % to get an entry from A if (is_second || is_pair || is_positional) % value of A is ignored for the SECOND and PAIR operators fprintf (f, 'define(`GB_a_is_pattern'', `1'')\n') ; fprintf (f, 'define(`GB_geta'', `;'')\n') ; else fprintf (f, 'define(`GB_a_is_pattern'', `0'')\n') ; fprintf (f, 'define(`GB_geta'', `%s $1 = $2 [$3]'')\n', xytype) ; end % to get an entry from B if (is_first || is_pair || is_positional) % value of B is ignored for the FIRST and PAIR operators fprintf (f, 'define(`GB_b_is_pattern'', `1'')\n') ; fprintf (f, 'define(`GB_getb'', `;'')\n') ; fprintf (f, 'define(`GB_loadb'', `;'')\n') ; else fprintf (f, 'define(`GB_b_is_pattern'', `0'')\n') ; fprintf (f, 'define(`GB_getb'', `%s $1 = $2 [$3]'')\n', xytype) ; fprintf (f, 'define(`GB_loadb'', `$1 [$2] = $3 [$4]'')\n', xytype) ; end % type-specific IDIV if (~isempty (strfind (mult, 'IDIV'))) if (unsigned) mult = strrep (mult, 'IDIV', 'IDIV_UNSIGNED') ; else mult = strrep (mult, 'IDIV', 'IDIV_SIGNED') ; end mult = strrep (mult, ')', sprintf (', %d)', bits)) ; end % create the multiply operator (assignment) mult2 = strrep (mult, 'xarg', '`$2''') ; mult2 = strrep (mult2, 'yarg', '`$3''') ; fprintf (f, 'define(`GB_multiply'', `$1 = %s'')\n', mult2) ; % create the add update, of the form w += t if (is_min) if (contains (ztype, 'int')) % min monoid for signed or unsigned integers add2 = 'if ($1 > $2) { $1 = $2 ; }' ; else % min monoid for float or double, with omitnan property if (t_is_nonnan) add2 = 'if (!islessequal ($1, $2)) { $1 = $2 ; }' ; else add2 = 'if (!isnan ($2) && !islessequal ($1, $2)) { $1 = $2 ; }' ; end end elseif (is_max) if (contains (ztype, 'int')) % max monoid for signed or unsigned integers add2 = 'if ($1 < $2) { $1 = $2 ; }' ; else % max monoid for float or double, with omitnan property if (t_is_nonnan) add2 = 'if (!isgreaterequal ($1, $2)) { $1 = $2 ; }' ; else add2 = 'if (!isnan ($2) && !isgreaterequal ($1, $2)) { $1 = $2 ; }'; end end else % use the add function as given add2 = strrep (add, 'w', '`$1''') ; add2 = strrep (add2, 't', '`$2''') ; end fprintf (f, 'define(`GB_add_update'', `%s'')\n', add2) ; % create the add function, of the form w + t add2 = strrep (addfunc, 'w', '`$1''') ; add2 = strrep (add2, 't', '`$2''') ; fprintf (f, 'define(`GB_add_function'', `%s'')\n', add2) ; % create the multiply-add operator is_imin_or_imax = (isequal (addop, 'min') || isequal (addop, 'max')) && contains (ztype, 'int') ; if (~is_imin_or_imax && ... (isequal (ztype, 'float') || isequal (ztype, 'double') || ... isequal (ztype, 'bool') || is_first || is_second || is_pair || is_positional)) % float and double do not get promoted. % bool is OK since promotion of the result (0 or 1) to int is safe. % first and second are OK since no promotion occurs. % is* operators are OK too. multadd = strrep (add, 't', mult) ; multadd = strrep (multadd, 'w', '`$1''') ; multadd = strrep (multadd, 'xarg', '`$2''') ; multadd = strrep (multadd, 'yarg', '`$3''') ; fprintf (f, 'define(`GB_multiply_add'', `%s'')\n', multadd) ; need_mult_typecast = false ; else % use explicit typecasting to avoid ANSI C integer promotion. add2 = strrep (add, 'w', '`$1''') ; add2 = strrep (add2, 't', 'x_op_y') ; fprintf (f, 'define(`GB_multiply_add'', `%s x_op_y = %s ; %s'')\n', ... ztype, mult2, add2) ; need_mult_typecast = true ; end % create the bitmap multiply-add statement: % The bitmap_multadd (cb,cx,exists,ax,bx) macro computes does the following. % The value of cx has been initialized to the identity value of the monoid, so % cx += ax*bx can always be used (except for the ANY monoid). % % if (exists) % if (cb == 0) % cx = ax * bx % cb = 1 % else % cx += ax * bx mult2 = strrep (mult, 'xarg', 'ax') ; mult2 = strrep (mult2, 'yarg', 'bx') ; xinit = ';' ; xload = ';' ; idbyte = '' ; if (need_mult_typecast) % the result of the multiplier must be explicitly typcasted mult2 = sprintf ('((%s) (%s))', ztype, mult2) ; else mult2 = sprintf ('(%s)', mult2) ; end switch (addop) % any monoid case { 'any' } if (isequal (multop, 'pair')) s = ' ' ; else s = sprintf ('if (exists && !cb) { cx = %s ; }', mult2) ; end % boolean monoids (except eq / lxnor) case { 'lor' } % TODO: should this be: cx ||= exists && %s ? s = sprintf ('cx |= exists & %s', mult2) ; idbyte = '0' ; case { 'land' } % TODO: should this be: cx &&= !exists || %s ? s = sprintf ('cx &= ~exists | %s', mult2) ; idbyte = '1' ; case { 'lxor' } if (isequal (multop, 'pair')) s = sprintf ('cx ^= exists') ; else % TODO: should this be: cx ^= exists && %s ? s = sprintf ('cx ^= exists & %s', mult2) ; end idbyte = '0' ; % min/max monoids: case { 'min' } if (contains (ztype, 'int')) % min for signed or unsigned integers if (t_is_simple) s = sprintf ('if (exists && cx > %s) { cx = %s ; }', ... mult2, mult2) ; else s = sprintf (... '%s t = %s ; if (exists && cx > t) { cx = t ; }', ... ztype, mult2) ; end else % min for float or double, with omitnan property if (t_is_simple) s = sprintf ( ... 'if (exists && !isnan (%s) && !islessequal (cx, %s)) { cx = %s ; }', ... mult2, mult2, mult2) ; elseif (t_is_nonnan) s = sprintf ('%s t = %s ; if (exists && !islessequal (cx, t)) { cx = t ; } ', ... ztype, mult2) ; else s = sprintf ('%s t = %s ; if (exists && !isnan (t) && !islessequal (cx, t)) { cx = t ; }', ... ztype, mult2) ; end end if (contains (ztype, 'uint')) idbyte = '0xFF' ; end case { 'max' } if (contains (ztype, 'int')) % max for signed or unsigned integers if (t_is_simple) s = sprintf ('if (exists && cx < %s) { cx = %s ; }', ... mult2, mult2) ; else s = sprintf ('%s t = %s ; if (exists && cx < t) { cx = t ; }', ... ztype, mult2) ; end else % max for float or double, with omitnan property if (t_is_simple) s = sprintf (... 'if (exists && !isnan (%s) && !isgreaterequal (cx, %s)) { cx = %s ; }', ... mult2, mult2, mult2) ; elseif (t_is_nonnan) s = sprintf (... '%s t = %s ; if (exists && !isgreaterequal (cx, t)) { cx = t ; }', ... ztype, mult2) ; else s = sprintf (... '%s t = %s ; if (exists && !isnan (t) && !isgreaterequal (cx, t)) { cx = t ; }', ... ztype, mult2) ; end end if (contains (ztype, 'uint')) idbyte = '0' ; end % plus monoid: special cases for some multipliers case { 'plus' } idbyte = '0' ; if (ztype_is_real) if (isequal (multop, 'times')) % X = {0,bx} xinit = sprintf ('%s X [2] = {0,0}', ztype) ; xload = 'X [1] = bx' ; if (need_mult_typecast) s = sprintf ('cx += (%s) (ax * X [exists])', ztype) ; else s = 'cx += ax * X [exists]' ; end elseif (isequal (multop, 'pair')) s = 'cx += exists' ; else % X = {0,1} xinit = sprintf ('%s X [2] = {0,1}', ztype) ; if (need_mult_typecast) s = sprintf ('cx += (%s) (%s * X [exists])', ztype, mult2) ; else s = sprintf ('cx += %s * X [exists]', mult2) ; end end else % plus monoids for complex types s = '' ; end % bitwise monoids (except bxnor) case { 'bor' } % X = {all zeros, all ones} xinit = sprintf ('%s X [2] = {0,%s}', ztype, xbits) ; s = sprintf ('cx |= X [exists] & %s', mult2) ; idbyte = '0' ; case { 'band' } % X = {all ones, all zeros} xinit = sprintf ('%s X [2] = {%s,0}', ztype, xbits) ; s = sprintf ('cx &= X [exists] | %s', mult2) ; idbyte = '0xFF' ; case { 'bxor' } % X = {all zeros, all ones} xinit = sprintf ('%s X [2] = {0,%s}', ztype, xbits) ; s = sprintf ('cx ^= X [exists] & %s', mult2) ; idbyte = '0' ; % these monoids do not have a concise bitmap multiply-add case { 'eq' } s = '' ; idbyte = '1' ; % eq monoid: identity byte for memset case { 'times' } s = '' ; idbyte = '' ; case {'bxnor' } s = '' ; idbyte = '0xFF' ; % bxnor monoid: identity byte for memset end if (isempty (idbyte)) fprintf (f, 'define(`GB_has_identity_byte'', `0'')\n') ; fprintf (f, 'define(`GB_identity_byte'', `(none)'')\n') ; else fprintf (f, 'define(`GB_has_identity_byte'', `1'')\n') ; fprintf (f, 'define(`GB_identity_byte'', `%s'')\n', idbyte) ; end % disable the bitmap multadd when using div or rdiv and any floating-point % type, to avoid divide-by-zero when operating on entries not in the bitmap. if (contains (multop, 'div') && ztype_is_float) s = '' ; end if (isempty (s)) fprintf (f, 'define(`GB_has_bitmap_multadd'', `0'')\n') ; fprintf (f, 'define(`GB_bitmap_multadd'', `(none)'')\n') ; else if (length (s) > 1) s = [s ' ; cb |= exists'] ; else s = ['cb |= exists'] ; end s = strrep (s, 'cb', '$1') ; s = strrep (s, 'cx', '$2') ; s = strrep (s, 'exists', '$3') ; s = strrep (s, 'ax', '$4') ; s = strrep (s, 'bx', '$5') ; fprintf (f, 'define(`GB_has_bitmap_multadd'', `1'')\n') ; fprintf (f, 'define(`GB_bitmap_multadd'', `%s'')\n', s) ; end xload = strrep (xload, 'bx', '$1') ; fprintf (f, 'define(`GB_xload'', `%s'')\n', xload) ; fprintf (f, 'define(`GB_xinit'', `%s'')\n', xinit) ; % fprintf ('(%5s %-8s %10s): { %s } { %s } { %s }\n', addop, multop, ztype, xinit, xload, s) ; % create the disable flag disable = sprintf ('GxB_NO_%s', upper (addop)) ; if (~isequal (addop, multop)) disable = [disable (sprintf (' || GxB_NO_%s', upper (multop)))] ; end disable = [disable (sprintf (' || GxB_NO_%s', upper (fname)))] ; disable = [disable (sprintf (' || GxB_NO_%s_%s', upper (addop), upper (zname)))] ; if (~ (isequal (addop, multop) && isequal (zname, fname))) disable = [disable (sprintf (' || GxB_NO_%s_%s', upper (multop), upper (fname)))] ; end disable = [disable (sprintf (' || GxB_NO_%s_%s_%s', ... upper (addop), upper (multop), upper (fname))) ] ; fprintf (f, 'define(`GB_disable'', `(%s)'')\n', disable) ; fclose (f) ; nprune = 57 ; % construct the *.c and *.h files for the semiring fmt = 'cat control.m4 Generator/%s.%s | m4 | tail -n +%d > Generated/%s__%s.%s' ; base = { 'GB_Adot2B', 'GB_Adot3B', 'GB_Adot4B', 'GB_AsaxbitB', ... 'GB_Asaxpy3B', 'GB_Asaxpy3B_noM', 'GB_Asaxpy3B_M', 'GB_Asaxpy3B_notM', ... 'GB_AxB_defs' } ; suffix = { 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'h' } ; for k = 1:length (base) cmd = sprintf (fmt, base {k}, suffix {k}, nprune, base {k}, name, suffix {k}) ; system (cmd) ; end fprintf ('.') ; % append to the *.h file cmd = sprintf (... 'cat control.m4 Generator/GB_AxB.h | m4 | tail -n +%d >> Generated/GB_AxB__include.h', nprune) ; system (cmd) ; delete ('control.m4') ;