1function [S,p] = GB_spec_build (I, J, X, nrows, ncols, op, order, sclass) 2%GB_SPEC_BUILD a MATLAB version of GrB_Matrix_build and GrB_vector_build 3% 4% Usage: 5% [S p] = GB_spec_build (I, J, X, nrows, ncols, op, order) 6% 7% GB_spec_build builds a full matrix S, mimicing GB_mex_Matrix_build but in 8% almost pure MATLAB. This function is very slow since it creates a dense 9% matrix instead of a sparse one. It is meant only as an executable version of 10% the GraphBLAS spec. It cannot operate purely in MATLAB, however, because the 11% casting and operator rules in MATLAB differ from the C-style casting and 12% operator rules GraphBLAS. In MATLAB, adding two int8 values 120 + 30 results 13% in 127; since 150 is larger than the max int8 value of 127, the result is 14% that max value. In C, the result wraps around, modulo 256, to be -106. 15% 16% S is returned as a struct, with S.matrix being the matrix, S.class the class, 17% and S.pattern the nonzero pattern of S. 18% 19% I: row indices. Indices are zero-based, just like GB_mex_Matrix_build. 20% 21% optional arguments: 22% J: column indices. Default J is a vector of all zeros, for building a column 23% vector. 24% X: numerical values, with MATLAB class logical, any integer, single, or 25% double. I, J, and X must have the same number of entries. 26% Default X is a logical vector of all true. 27% nrows: number of rows of S. Default is nrows = max (I) + 1 ; 28% ncols: number of cols of S. Default is ncols = max (J) + 1 ; 29% op: binary operator z=f(x,y) for assembling duplicates. See 30% GB_spec_operator. The GraphBLAS spec requires op to be associative 31% (min, max, plus, or times) but any binary operator with x,y,z 32% types the same will work; see the 'order' parameter. 33% order: 'natural', or 'random'. Default is 'natural'. 34% The GraphBLAS spec does not state what order the duplicates are 35% assembled. It only guarantees the result if op is associative. The 36% 'natural' order sums them up in the order they appear in [I,J,X], and 37% this is what GB_mex_Matrix_build does. To check the results against 38% any possible order, use 'random', which sums them up in a random 39% order. The results of 'natural' and 'random' will differ if op is not 40% associative. With floating-point values, roundoff may vary slightly, 41% which should be acceptable. If the results differ greatly then the 42% problem is very ill-conditioned. The output p returns the ordering 43% used to assemble the entries, a permutation of 1:length(X). 44% 45% Use an empty value ([ ] or '') to obtain the default value for optional 46% parameters, or pass fewer inputs. For exampe S = GB_spec_build (I, J, X, 47% nrows, ncols) uses defaults for op, and order, but not X, nrows and ncols. 48 49% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. 50% SPDX-License-Identifier: Apache-2.0 51 52%------------------------------------------------------------------------------- 53% get inputs 54%------------------------------------------------------------------------------- 55 56if (nargout > 2 || nargin < 1 || nargin > 8) 57 error ('usage: [S p] = GB_spec_build (I, J, X, nrows, ncols, op, order, sclass)') ; 58end 59 60% get I 61nnz = length (I) ; 62 63% get J 64if (nargin < 2) 65 J = [ ] ; 66end 67if (isempty (J)) 68 J = zeros (nnz, 1) ; 69end 70if (nnz ~= length (J)) 71 error ('I and J must have the same size') ; 72end 73 74% get X 75if (nargin < 3) 76 X = [ ] ; 77end 78if (isempty (X)) 79 X = ones (nnz, 1, 'logical') ; 80end 81if (nnz ~= length (X)) 82 error ('I and X must have the same size') ; 83end 84 85% get the number of rows 86if (nargin < 4) 87 nrows = [ ] ; 88end 89if (isempty (nrows)) 90 nrows = max (I) + 1 ; 91end 92 93% get the number of cols 94if (nargin < 5) 95 ncols = [ ] 96end 97if (isempty (ncols)) 98 ncols = max (J) + 1 ; 99end 100 101% get the op 102if (nargin < 6) 103 op = [ ] ; 104end 105if (isempty (op)) 106 op = 'plus' ; 107end 108[opname optype ztype xtype ytype] = GB_spec_operator (op, GB_spec_type (X)) ; 109 110if (GB_spec_is_positional (opname)) 111 error ('dup operator cannot be positional') ; 112end 113 114assert (isequal (ztype, xtype)) ; 115assert (isequal (ztype, ytype)) ; 116 117% get the ordering 118if (nargin < 7) 119 order = '' ; 120end 121 122%------------------------------------------------------------------------------- 123% do the work via a clean MATLAB interpretation of the entire GraphBLAS spec 124%------------------------------------------------------------------------------- 125 126% sort or randomize the tuples 127if (isequal (order, 'random')) 128 % the GraphBLAS spec allows for any ordering 129 p = randperm (nnz) ; 130else 131 % the 'natural' ordering is used in this implementation of GrB_Matrix_build 132 [~, p] = sortrows ([J I (1:nnz)']) ; 133end 134I = I (p) ; 135J = J (p) ; 136X = X (p) ; 137 138% initialize the matrix S and its pattern 139S.matrix = GB_spec_zeros ([nrows ncols], optype) ; 140S.pattern = false (nrows, ncols) ; 141S.class = optype ; 142 143% assemble the tuples into S 144for t = 1:nnz 145 i = 1 + I (t) ; % convert from 0-based GraphBLAS to 1-based MATLAB 146 j = 1 + J (t) ; 147 if (~S.pattern (i,j)) 148 % first time S(i,j) is modified: cast x into S 149 S.matrix (i,j) = GB_mex_cast (X (t), optype) ; 150 S.pattern (i,j) = true ; 151 else 152 % a duplicate entry to be assembled with the operator op 153 % cast x into the class of S and the operator 154 x = GB_mex_cast (X (t), optype) ; 155 % apply the operator, result is of class optype 156 S.matrix (i,j) = GB_spec_op (op, S.matrix (i,j), x) ; 157 end 158end 159 160% get the sclass 161if (nargin < 8) 162 sclass = optype ; % default is optype 163end 164 165% typecast S into the desired class 166if (~isequal (optype, sclass)) 167 S.matrix = GB_mex_cast (S.matrix, sclass) ; 168 S.class = sclass ; 169end 170 171