File: GB_spec_matrix.m

package info (click to toggle)
suitesparse-graphblas 7.4.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 67,112 kB
  • sloc: ansic: 1,072,243; cpp: 8,081; sh: 512; makefile: 506; asm: 369; python: 125; awk: 10
file content (167 lines) | stat: -rw-r--r-- 6,441 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
function Cout = GB_spec_matrix (Cin, identity)
%GB_SPEC_MATRIX a mimic that conforms a matrix to the GraphBLAS spec
%
% Cout = GB_spec_matrix (Cin)
% Cout = GB_spec_matrix (Cin, identity)
%
% Conforms an input matrix to the GraphBLAS spec, for use in GB_spec_* only.
%
% The identity argument is the addititive identity of the semiring that will be
% used on the matrix (default is zero).  It represents the value of the
% implicit 'zeros' that are not present in a sparse matrix.
%
% The input Cin is either a matrix or a struct.
%
% If Cin is a struct, it must have a field Cin.matrix, and it can have two
% optional fields, Cin.pattern and Cin.class.  Let X = Cin.matrix.  The type
% of X is given by Cin.class, if present, or type(X) otherwise.  For a dense
% X, type(X) and Cin.class, if present, must match.  If present, the pattern
% of X is given by Cin.pattern; otherwise the pattern for a sparse X is
% GB_spones_mex(X) and entries outside the pattern are assumed to be equal to
% identity.  For a dense X, with no Cin.pattern present the pattern of X is
% all true.
%
% If Cin is a matrix, then its type is given by GB_spec_type (Cin).  If the
% matrix is sparse, its pattern is GB_spones_mex(Cin) and entries not in the
% pattern are assumed equal to identity.  Otherwise the pattern of Cin is
% all true.
%
% The output Cout is a struct with all three fields present (matrix, pattern,
% and type).  Cout.matrix is dense, and it has been typecast into the type
% given by Cout.class.  Entries not in the pattern of X are explicitly set to
% identity.
%
% The matrix is typecast to Cout.class using the typecasting GraphBLAS
% typecasting rules.
%
% Converting a matrix from sparse to full is not part of the GraphBLAS spec, of
% course.  Neither is the identity value a part of the matrix structure in
% GraphBLAS.  A matrix in GraphBLAS is always sparse, and entries not in the
% pattern are always implicitly equal to whatever semiring is used on the
% sparse matrix.  As a result, GraphBLAS never needs to know what the identity
% value is until it operates on the matrix, and the identity is not part of the
% matrix itself.  Using a different semiring immediately changes the value of
% the implicit zero, with a change to the GraphBLAS data structure for the
% matrix.
%
% However, built-in methods only support logical, double, and double complex
% sparse matrices, so to the mimic functions GB_spec_* operate only on dense
% matrices.  When a built-in sparse matrix is converted into a dense matrix,
% the entries not in the pattern must be set to an explicit value: the
% addititive identity.
%
% The mimic routines, GB_spec_* are written almost purely in M, and
% do not call GraphBLAS functions (with the exception of typecasting and
% operators).  They always return a stuct C with a dense C.matrix, a
% pattern C.pattern and type C.class.
%
% GraphBLAS GB_mex_* functions are direct interfaces to the C functions in
% GraphBLAS, and they always return a sparse struct; otherwise large problems
% could not be solved.  The struct contains just C.matrix and C.class.  The
% pattern of C.matrix is GB_spones_mex(C.matrix).  To compare the output C0 of
% a GB_mex_* function with C1 of a GrapBLAS_spec_* function, the struct C0
% must first be passed to this function, C0=GB_spec_matrix(C0,identity) and
% then C0 and C1 should be identical.

% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
% SPDX-License-Identifier: Apache-2.0

% get the semiring addititive identity, if present
if (nargin < 2)
    identity = 0 ;      % default is zero
end

% get the matrix
if (isstruct (Cin))
    X = Cin.matrix ;
else
    X = Cin ;
end

% get the type
if (isstruct (Cin))
    if (isfield (Cin, 'class'))
        % get the type of X from Cin.class
        xtype = Cin.class ;
        if (~issparse (X) && ~isequal (xtype, GB_spec_type (X)))
            % for a dense X, GB_spec_type (X) and Cin.class must match
            X = GB_mex_cast (X, xtype) ;
        end
    else
        % no Cin.class present, so get the type from X itself
        xtype = GB_spec_type (X) ;
    end
else
    % Cin is a matrix, so get the type from X itself
    xtype = GB_spec_type (X) ;
end

% get the pattern
if (isstruct (Cin) && isfield (Cin, 'pattern'))
    xpattern = Cin.pattern ;
else
    % must be done before typecasting since it can introduce zeros
    if (issparse (X))
        % For a sparse matrix, use the actual pattern.  Entries not in the
        % the pattern are assumed to be equal to the addititve identity.
        xpattern = GB_mex_cast (full (GB_spones_mex (X)), 'logical') ;
    else
        xpattern = true (size (X)) ;
        % xpattern = (X ~= identity) ;
    end
end

% get the uncasted values, if present
if (isstruct (Cin) && isfield (Cin, 'values') &&  ...
    (isequal (xtype, 'int64') || isequal (xtype, 'uint64')))
    % Cin.matrix is sparse, either double or logical.  But it was typecasted
    % from a GraphBLAS matrix that was not double or logical.  Typecasting
    % to int64 or uint64 can lead to loss of precision.  So in this case,
    % use Cin.values instead.
    X = GB_spec_zeros (size (Cin.matrix), xtype) ;
    [I, J, ~] = find (xpattern) ;
    Cx = Cin.values ;
    assert (length (I) == length (Cx)) ;
    for k = 1:length (Cin.values)
        X (I (k), J (k)) = Cx (k) ;
    end
else
    % typecast X to the requested type and make it dense
    X = GB_mex_cast (full (X), xtype) ;
end

% in the dense X, entries not in the xpattern must be set to the identity
X (~xpattern) = GB_mex_cast (identity, xtype) ;

if (~isequal (xtype, GB_spec_type (X)))
    % if X is complex, it may have been downgraded to real, if
    % its imaginary part is zero
    X = GB_mex_cast (X, xtype) ;
end

% return the output struct
Cout.matrix = X ;
Cout.pattern = xpattern ;
Cout.class = xtype ;

% The output is now a struct with all 3 fields present, and Cout.matrix
% is always dense.  Cout.class always matches type(Cout.matrix).
assert (isstruct (Cout)) ;
assert (~issparse (Cout.matrix)) ;

% handle the iso case
if (isstruct (Cin) && isfield (Cin, 'iso'))
    iso = Cin.iso ;
    if (iso)
        % get the first entry in the pattern
        [I,J] = ind2sub (size (xpattern), find (xpattern)) ;
        if (isempty (I))
            xiso = 0 ;
        else
            xiso = X (I (1), J (1)) ;
        end
        Cout.matrix (xpattern) = xiso ;
    end
    Cout.iso = iso ;
end