1 //------------------------------------------------------------------------------
2 // gbdegree: number of entries in each vector of a GraphBLAS matrix struct
3 //------------------------------------------------------------------------------
4 
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: GPL-3.0-or-later
7 
8 //------------------------------------------------------------------------------
9 
10 // The input may be either a GraphBLAS matrix struct or a standard MATLAB
11 // sparse matrix.
12 
13 //  gbdegree (X, 'row')     row degree
14 //  gbdegree (X, 'col')     column degree
15 //  gbdegree (X, true)      native (get degree of each vector):
16 //                          row degree if X is held by row,
17 //                          col degree if X is held by col.
18 //  gbdegree (X, false)     non-native (sum across vectors):
19 //                          col degree if X is held by row,
20 //                          row degree if X is held by col.
21 
22 #include "gb_matlab.h"
23 
24 #define USAGE "usage: degree = gbdegree (X, dim)"
25 
mexFunction(int nargout,mxArray * pargout[],int nargin,const mxArray * pargin[])26 void mexFunction
27 (
28     int nargout,
29     mxArray *pargout [ ],
30     int nargin,
31     const mxArray *pargin [ ]
32 )
33 {
34 
35     //--------------------------------------------------------------------------
36     // check inputs
37     //--------------------------------------------------------------------------
38 
39     gb_usage (nargin == 2 && nargout <= 1, USAGE) ;
40 
41     //--------------------------------------------------------------------------
42     // get the inputs
43     //--------------------------------------------------------------------------
44 
45     int64_t *degree = NULL ;
46     GrB_Index *list = NULL, nvec = 0 ;
47     size_t degree_size = 0 ;
48     size_t list_size = 0 ;
49     GrB_Vector d = NULL ;
50     GrB_Vector y = NULL ;
51     GrB_Matrix T = NULL ;
52     GrB_Matrix Z = NULL ;
53     GrB_Descriptor desc = NULL ;
54 
55     GrB_Matrix X = gb_get_shallow (pargin [0]) ;
56     GxB_Format_Value fmt ;
57     OK (GxB_Matrix_Option_get (X, GxB_FORMAT, &fmt)) ;
58 
59     bool native ;
60     if (mxIsChar (pargin [1]))
61     {
62         #define LEN 256
63         char dim_string [LEN+2] ;
64         gb_mxstring_to_string (dim_string, LEN, pargin [1], "dim") ;
65         if (MATCH (dim_string, "row"))
66         {
67             native = (fmt == GxB_BY_ROW) ;
68         }
69         else // if (MATCH (dim_string, "col"))
70         {
71             native = (fmt == GxB_BY_COL) ;
72         }
73     }
74     else
75     {
76         native = (mxGetScalar (pargin [1]) != 0) ;
77     }
78 
79     //--------------------------------------------------------------------------
80     // if X is bitmap: create a copy of X and convert it to sparse
81     //--------------------------------------------------------------------------
82 
83     int sparsity ;
84     OK (GxB_Matrix_Option_get (X, GxB_SPARSITY_STATUS, &sparsity)) ;
85     if (sparsity == GxB_BITMAP)
86     {
87         // Z = deep copy of the shallow matrix X
88         OK (GrB_Matrix_dup (&Z, X)) ;
89         // convert Z to sparse
90         OK (GxB_Matrix_Option_set (Z, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ;
91         // free the shallow X and replace it with Z
92         OK (GrB_Matrix_free (&X)) ;
93         X = Z ;
94     }
95 
96     //--------------------------------------------------------------------------
97     // get the degree of each row or column of X
98     //--------------------------------------------------------------------------
99 
100     GrB_Index nvals, nrows, ncols ;
101     OK (GrB_Matrix_nvals (&nvals, X)) ;
102     OK (GrB_Matrix_nrows (&nrows, X)) ;
103     OK (GrB_Matrix_ncols (&ncols, X)) ;
104 
105     if (native)
106     {
107 
108         //----------------------------------------------------------------------
109         // get the degree of each vector of X, where X is sparse or hypersparse
110         //----------------------------------------------------------------------
111 
112         if (!GB_matlab_helper9 (X, &degree, &degree_size,
113             &list, &list_size, &nvec))
114         {
115             ERROR ("out of memory") ;
116         }
117         // TODO do not use X->vdim
118         OK (GxB_Vector_import_CSC (&d, GrB_INT64, X->vdim, &list, &degree,
119             list_size, degree_size, false, nvec, false, NULL)) ;
120 
121     }
122     else
123     {
124 
125         //----------------------------------------------------------------------
126         // get the degree of each index of X, where X is sparse or hypersparse
127         //----------------------------------------------------------------------
128 
129         // ensure the descriptor is present, and set GxB_SORT to true
130         OK (GrB_Descriptor_new (&desc)) ;
131         OK (GxB_Desc_set (desc, GxB_SORT, true)) ;
132 
133         if (fmt == GxB_BY_COL)
134         {
135 
136             //------------------------------------------------------------------
137             // compute the degree of each row of X, where X is held by column
138             //------------------------------------------------------------------
139 
140             if (nvals < ncols / 16 && ncols > 256)
141             {
142 
143                 // X is hypersparse, or might as well be, and held by column,
144                 // so compute the degree of each vector of T = GrB(X,'by row')
145                 // instead.
146 
147                 OK (GrB_Matrix_new (&T, GrB_BOOL, nrows, ncols)) ;
148                 OK (GxB_Matrix_Option_set (T, GxB_FORMAT, GxB_BY_ROW)) ;
149                 OK1 (T, GrB_Matrix_apply (T, NULL, NULL, GxB_ONE_BOOL, X,
150                     NULL)) ;
151 
152                 // get the degree of nonempty rows of T
153                 if (!GB_matlab_helper9 (T, &degree, &degree_size,
154                     &list, &list_size, &nvec))
155                 {
156                     ERROR ("out of memory") ;
157                 }
158                 OK (GxB_Vector_import_CSC (&d, GrB_INT64, nrows, &list, &degree,
159                     list_size, degree_size, false, nvec, false, NULL)) ;
160 
161             }
162             else
163             {
164 
165                 // y = full vector of size ncols-by-1; value is not relevant
166                 OK (GrB_Vector_new (&y, GrB_BOOL, ncols)) ;
167                 OK (GrB_Vector_assign_BOOL (y, NULL, NULL, false, GrB_ALL,
168                     ncols, NULL)) ;
169 
170                 // d = X*y using the PLUS_PAIR semiring
171                 OK (GrB_Vector_new (&d, GrB_INT64, nrows)) ;
172                 OK (GrB_mxv (d, NULL, NULL, GxB_PLUS_PAIR_INT64, X, y, desc)) ;
173             }
174 
175         }
176         else
177         {
178 
179             //------------------------------------------------------------------
180             // compute the degree of each column of X, where X is held by row
181             //------------------------------------------------------------------
182 
183             if (nvals < nrows / 16 && nrows > 256)
184             {
185 
186                 // X is hypersparse, or might as well be, and held by row,
187                 // so compute the degree of each vector of T = GrB(X,'by col')
188                 // instead.
189 
190                 OK (GrB_Matrix_new (&T, GrB_BOOL, nrows, ncols)) ;
191                 OK (GxB_Matrix_Option_set (T, GxB_FORMAT, GxB_BY_COL)) ;
192                 OK1 (T, GrB_Matrix_apply (T, NULL, NULL, GxB_ONE_BOOL, X,
193                     NULL)) ;
194 
195                 // get the degree of nonempty columns of T
196                 if (!GB_matlab_helper9 (T, &degree, &degree_size,
197                     &list, &list_size, &nvec))
198                 {
199                     ERROR ("out of memory") ;
200                 }
201                 OK (GxB_Vector_import_CSC (&d, GrB_INT64, ncols, &list, &degree,
202                     list_size, degree_size, false, nvec, false, NULL)) ;
203 
204             }
205             else
206             {
207 
208                 // y = full vector of size nrows-by-1; value is not relevant
209                 OK (GrB_Vector_new (&y, GrB_BOOL, nrows)) ;
210                 OK (GrB_Vector_assign_BOOL (y, NULL, NULL, false, GrB_ALL,
211                     nrows, NULL)) ;
212 
213                 // d = y*X using the PLUS_PAIR semiring
214                 OK (GrB_Vector_new (&d, GrB_INT64, ncols)) ;
215                 OK (GrB_vxm (d, NULL, NULL, GxB_PLUS_PAIR_INT64, y, X, desc)) ;
216             }
217         }
218     }
219 
220     //--------------------------------------------------------------------------
221     // free workspace and export d to MATLAB as a GraphBLAS matrix
222     //--------------------------------------------------------------------------
223 
224     OK (GrB_Vector_free (&y)) ;
225     OK (GrB_Matrix_free (&T)) ;
226     OK (GrB_Matrix_free (&X)) ;
227     OK (GrB_Descriptor_free (&desc)) ;
228     pargout [0] = gb_export ((GrB_Matrix *) &d, KIND_GRB) ;
229     GB_WRAPUP ;
230 }
231 
232