1 //------------------------------------------------------------------------------
2 // gb_get_shallow: create a shallow copy of a MATLAB sparse matrix
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 // A = gb_get_shallow (X) constructs a shallow GrB_Matrix from a MATLAB
11 // mxArray, which can either be a MATLAB sparse matrix (double, complex, or
12 // logical) or a MATLAB struct that contains a GraphBLAS matrix.
13
14 // X must not be NULL, but it can be an empty matrix, as X = [ ] or even X = ''
15 // (the empty string). In this case, A is returned as NULL. This is not an
16 // error here, since the caller might be getting an optional input matrix, such
17 // as Cin or the Mask.
18
19 // For v4, is_uniform is false, and the s component has length 9.
20 // For v5, is_uniform may be true, and the s component has length 10.
21
22 #include "gb_matlab.h"
23
24 #define IF(error,message) \
25 CHECK_ERROR (error, "invalid GraphBLAS struct (" message ")" ) ;
26
gb_get_shallow(const mxArray * X)27 GrB_Matrix gb_get_shallow // return a shallow copy of MATLAB sparse matrix
28 (
29 const mxArray *X
30 )
31 {
32
33 //--------------------------------------------------------------------------
34 // check inputs
35 //--------------------------------------------------------------------------
36
37 CHECK_ERROR (X == NULL, "matrix missing") ;
38
39 //--------------------------------------------------------------------------
40 // construct the shallow GrB_Matrix
41 //--------------------------------------------------------------------------
42
43 GrB_Matrix A = NULL ;
44
45 if (gb_mxarray_is_empty (X))
46 {
47
48 //----------------------------------------------------------------------
49 // matrix is empty
50 //----------------------------------------------------------------------
51
52 // X is a 0-by-0 MATLAB matrix. Create a new 0-by-0 matrix of the same
53 // type as X, with the default format.
54 OK (GrB_Matrix_new (&A, gb_mxarray_type (X), 0, 0)) ;
55
56 }
57 else if (mxIsStruct (X))
58 {
59
60 //----------------------------------------------------------------------
61 // construct a shallow GrB_Matrix copy from a MATLAB struct
62 //----------------------------------------------------------------------
63
64 bool GraphBLASv4 = false ;
65 bool GraphBLASv3 = false ;
66
67 // get the type
68 mxArray *mx_type = mxGetField (X, 0, "GraphBLASv5") ;
69 if (mx_type == NULL)
70 {
71 // check if it is a GraphBLASv4 struct
72 mx_type = mxGetField (X, 0, "GraphBLASv4") ;
73 GraphBLASv4 = true ;
74 }
75 if (mx_type == NULL)
76 {
77 // check if it is a GraphBLASv3 struct
78 mx_type = mxGetField (X, 0, "GraphBLAS") ;
79 GraphBLASv3 = true ;
80 }
81 CHECK_ERROR (mx_type == NULL, "not a GraphBLAS struct") ;
82
83 GrB_Type type = gb_mxstring_to_type (mx_type) ;
84 size_t type_size ;
85 OK (GxB_Type_size (&type_size, type)) ;
86
87 // get the scalar info
88 mxArray *opaque = mxGetField (X, 0, "s") ;
89 IF (opaque == NULL, ".s missing") ;
90 IF (mxGetM (opaque) != 1, ".s wrong size") ;
91 size_t s_size = mxGetN (opaque) ;
92 if (GraphBLASv3)
93 {
94 IF (s_size != 8, ".s wrong size") ;
95 }
96 else if (GraphBLASv4)
97 {
98 IF (s_size != 9, ".s wrong size") ;
99 }
100 else
101 {
102 IF (s_size != 10, ".s wrong size") ;
103 }
104 int64_t *s = mxGetInt64s (opaque) ;
105 int64_t plen = s [0] ;
106 int64_t vlen = s [1] ;
107 int64_t vdim = s [2] ;
108 int64_t nvec = s [3] ;
109 int64_t nvec_nonempty = s [4] ;
110 bool by_col = (bool) (s [6]) ;
111 int64_t nzmax = s [7] ;
112
113 int sparsity_status, sparsity_control ;
114 int64_t nvals ;
115 bool is_uniform ;
116 if (GraphBLASv3)
117 {
118 // GraphBLASv3 struct: sparse or hypersparse only
119 sparsity_control = GxB_AUTO_SPARSITY ;
120 nvals = 0 ;
121 is_uniform = false ;
122 }
123 else
124 {
125 // GraphBLASv4 or v5 struct: sparse, hypersparse, bitmap, or full
126 sparsity_control = (int) (s [5]) ;
127 nvals = s [8] ;
128 if (GraphBLASv4)
129 {
130 // GraphBLASv4: is_uniform is always false
131 is_uniform = false ;
132 }
133 else
134 {
135 // GraphBLASv5: is_uniform is present as s [9]
136 is_uniform = (bool) s [9] ;
137 }
138 }
139
140 int nfields = mxGetNumberOfFields (X) ;
141 switch (nfields)
142 {
143 case 3 :
144 // A is full, with 3 fields: GraphBLAS*, s, x
145 sparsity_status = GxB_FULL ;
146 break ;
147
148 case 5 :
149 // A is sparse, with 5 fields: GraphBLAS*, s, x, p, i
150 sparsity_status = GxB_SPARSE ;
151 break ;
152
153 case 6 :
154 // A is hypersparse, with 6 fields: GraphBLAS*, s, x, p, i, h
155 sparsity_status = GxB_HYPERSPARSE ;
156 break ;
157
158 case 4 :
159 // A is bitmap, with 4 fields: GraphBLAS*, s, x, b
160 sparsity_status = GxB_BITMAP ;
161 break ;
162
163 default : ERROR ("invalid GraphBLAS struct") ;
164 }
165
166 // each component
167 int64_t *Ap = NULL, *Ai = NULL, *Ah = NULL ;
168 int8_t *Ab = NULL ;
169 void *Ax = NULL ;
170
171 // size of each component
172 size_t Ap_size = 0 ;
173 size_t Ah_size = 0 ;
174 size_t Ab_size = 0 ;
175 size_t Ai_size = 0 ;
176 size_t Ax_size = 0 ;
177
178 if (sparsity_status == GxB_HYPERSPARSE || sparsity_status == GxB_SPARSE)
179 {
180 // A is hypersparse or sparse
181
182 // get Ap
183 mxArray *Ap_mx = mxGetField (X, 0, "p") ;
184 IF (Ap_mx == NULL, ".p missing") ;
185 IF (mxGetM (Ap_mx) != 1, ".p wrong size") ;
186 Ap = mxGetInt64s (Ap_mx) ;
187 IF (Ap == NULL, ".p wrong type") ;
188 Ap_size = mxGetN (Ap_mx) * sizeof (int64_t) ;
189
190 // get Ai
191 mxArray *Ai_mx = mxGetField (X, 0, "i") ;
192 IF (Ai_mx == NULL, ".i missing") ;
193 IF (mxGetM (Ai_mx) != 1, ".i wrong size") ;
194 Ai_size = mxGetN (Ai_mx) * sizeof (int64_t) ;
195 Ai = (Ai_size == 0) ? NULL : mxGetInt64s (Ai_mx) ;
196 IF (Ai == NULL && Ai_size > 0, ".i wrong type") ;
197 }
198
199 // get the values
200 mxArray *Ax_mx = mxGetField (X, 0, "x") ;
201 IF (Ax_mx == NULL, ".x missing") ;
202 IF (mxGetM (Ax_mx) != 1, ".x wrong size") ;
203 Ax_size = mxGetN (Ax_mx) ;
204 Ax = (Ax_size == 0) ? NULL : ((void *) mxGetUint8s (Ax_mx)) ;
205 IF (Ax == NULL && Ax_size > 0, ".x wrong type") ;
206
207 if (sparsity_status == GxB_HYPERSPARSE)
208 {
209 // A is hypersparse
210 // get the hyperlist
211 mxArray *Ah_mx = mxGetField (X, 0, "h") ;
212 IF (Ah_mx == NULL, ".h missing") ;
213 IF (mxGetM (Ah_mx) != 1, ".h wrong size") ;
214 Ah_size = mxGetN (Ah_mx) * sizeof (int64_t) ;
215 Ah = (Ah_size == 0) ? NULL : ((int64_t *) mxGetInt64s (Ah_mx)) ;
216 IF (Ah == NULL && Ah_size > 0, ".h wrong type") ;
217 }
218
219 if (sparsity_status == GxB_BITMAP)
220 {
221 // A is bitmap
222 // get the bitmap
223 mxArray *Ab_mx = mxGetField (X, 0, "b") ;
224 IF (Ab_mx == NULL, ".b missing") ;
225 IF (mxGetM (Ab_mx) != 1, ".b wrong size") ;
226 Ab_size = mxGetN (Ab_mx) ;
227 Ab = (Ab_size == 0) ? NULL : ((int8_t *) mxGetInt8s (Ab_mx)) ;
228 IF (Ab == NULL && Ab_size > 0, ".b wrong type") ;
229 }
230
231 //----------------------------------------------------------------------
232 // import the matrix
233 //----------------------------------------------------------------------
234
235 int64_t nrows = (by_col) ? vlen : vdim ;
236 int64_t ncols = (by_col) ? vdim : vlen ;
237
238 switch (sparsity_status)
239 {
240 case GxB_FULL :
241 if (by_col)
242 {
243 OK (GxB_Matrix_import_FullC (&A, type, nrows, ncols,
244 &Ax, Ax_size, is_uniform, NULL)) ;
245 }
246 else
247 {
248 OK (GxB_Matrix_import_FullR (&A, type, nrows, ncols,
249 &Ax, Ax_size, is_uniform, NULL)) ;
250 }
251 break ;
252
253 case GxB_SPARSE :
254 if (by_col)
255 {
256 OK (GxB_Matrix_import_CSC (&A, type, nrows, ncols,
257 &Ap, &Ai, &Ax, Ap_size, Ai_size, Ax_size, is_uniform,
258 false, NULL)) ;
259 }
260 else
261 {
262 OK (GxB_Matrix_import_CSR (&A, type, nrows, ncols,
263 &Ap, &Ai, &Ax, Ap_size, Ai_size, Ax_size, is_uniform,
264 false, NULL)) ;
265 }
266 break ;
267
268 case GxB_HYPERSPARSE :
269 if (by_col)
270 {
271 OK (GxB_Matrix_import_HyperCSC (&A, type, nrows, ncols,
272 &Ap, &Ah, &Ai, &Ax,
273 Ap_size, Ah_size, Ai_size, Ax_size, is_uniform,
274 nvec, false, NULL)) ;
275 }
276 else
277 {
278 OK (GxB_Matrix_import_HyperCSR (&A, type, nrows, ncols,
279 &Ap, &Ah, &Ai, &Ax,
280 Ap_size, Ah_size, Ai_size, Ax_size, is_uniform,
281 nvec, false, NULL)) ;
282 }
283 break ;
284
285 case GxB_BITMAP :
286 if (by_col)
287 {
288 OK (GxB_Matrix_import_BitmapC (&A, type, nrows, ncols,
289 &Ab, &Ax, Ab_size, Ax_size, is_uniform, nvals, NULL)) ;
290 }
291 else
292 {
293 OK (GxB_Matrix_import_BitmapR (&A, type, nrows, ncols,
294 &Ab, &Ax, Ab_size, Ax_size, is_uniform, nvals, NULL)) ;
295 }
296 break ;
297
298 default: ;
299 }
300
301 }
302 else
303 {
304
305 //----------------------------------------------------------------------
306 // construct a shallow GrB_Matrix copy of a MATLAB matrix
307 //----------------------------------------------------------------------
308
309 // get the type and dimensions
310 bool X_is_sparse = mxIsSparse (X) ;
311
312 GrB_Type type = gb_mxarray_type (X) ;
313 GrB_Index nrows = (GrB_Index) mxGetM (X) ;
314 GrB_Index ncols = (GrB_Index) mxGetN (X) ;
315
316 // get Xp, Xi, nzmax, or create them
317 GrB_Index *Xp, *Xi, nzmax ;
318 if (X_is_sparse)
319 {
320 // get the nzmax, Xp, and Xi from the MATLAB sparse matrix X
321 nzmax = (GrB_Index) mxGetNzmax (X) ;
322 Xp = (GrB_Index *) mxGetJc (X) ;
323 Xi = (GrB_Index *) mxGetIr (X) ;
324 }
325 else
326 {
327 // X is a MATLAB full matrix; so is the GrB_Matrix
328 nzmax = nrows * ncols ;
329 Xp = NULL ;
330 Xi = NULL ;
331 }
332
333 // get the numeric data
334 void *Xx = NULL ;
335 size_t type_size = 0 ;
336 if (type == GrB_FP64)
337 {
338 // MATLAB sparse or full double matrix
339 Xx = mxGetDoubles (X) ;
340 type_size = sizeof (double) ;
341 }
342 else if (type == GxB_FC64)
343 {
344 // MATLAB sparse or full double complex matrix
345 Xx = mxGetComplexDoubles (X) ;
346 type_size = 2 * sizeof (double) ;
347 }
348 else if (type == GrB_BOOL)
349 {
350 // MATLAB sparse or full logical matrix
351 Xx = mxGetData (X) ;
352 type_size = sizeof (bool) ;
353 }
354 else if (X_is_sparse)
355 {
356 // MATLAB does not support any other kinds of sparse matrices
357 ERROR ("unsupported type") ;
358 }
359 else if (type == GrB_INT8)
360 {
361 // full int8 matrix
362 Xx = mxGetInt8s (X) ;
363 type_size = sizeof (int8_t) ;
364 }
365 else if (type == GrB_INT16)
366 {
367 // full int16 matrix
368 Xx = mxGetInt16s (X) ;
369 type_size = sizeof (int16_t) ;
370 }
371 else if (type == GrB_INT32)
372 {
373 // full int32 matrix
374 Xx = mxGetInt32s (X) ;
375 type_size = sizeof (int32_t) ;
376 }
377 else if (type == GrB_INT64)
378 {
379 // full int64 matrix
380 Xx = mxGetInt64s (X) ;
381 type_size = sizeof (int64_t) ;
382 }
383 else if (type == GrB_UINT8)
384 {
385 // full uint8 matrix
386 Xx = mxGetUint8s (X) ;
387 type_size = sizeof (uint8_t) ;
388 }
389 else if (type == GrB_UINT16)
390 {
391 // full uint16 matrix
392 Xx = mxGetUint16s (X) ;
393 type_size = sizeof (uint16_t) ;
394 }
395 else if (type == GrB_UINT32)
396 {
397 // full uint32 matrix
398 Xx = mxGetUint32s (X) ;
399 type_size = sizeof (uint32_t) ;
400 }
401 else if (type == GrB_UINT64)
402 {
403 // full uint64 matrix
404 Xx = mxGetUint64s (X) ;
405 type_size = sizeof (uint64_t) ;
406 }
407 else if (type == GrB_FP32)
408 {
409 // full single matrix
410 Xx = mxGetSingles (X) ;
411 type_size = sizeof (float) ;
412 }
413 else if (type == GxB_FC32)
414 {
415 // full single complex matrix
416 Xx = mxGetComplexSingles (X) ;
417 type_size = 2 * sizeof (float) ;
418 }
419 else
420 {
421 ERROR ("unsupported type") ;
422 }
423
424 if (X_is_sparse)
425 {
426 // import the matrix in CSC format. This sets Xp, Xi, and Xx to
427 // NULL, but it does not change the MATLAB matrix they came from.
428 OK (GxB_Matrix_import_CSC (&A, type, nrows, ncols, &Xp, &Xi, &Xx,
429 (ncols+1) * sizeof (int64_t),
430 nzmax * sizeof (int64_t),
431 nzmax * type_size, false, false, NULL)) ;
432 }
433 else
434 {
435 // import a full matrix
436 OK (GxB_Matrix_import_FullC (&A, type, nrows, ncols, &Xx,
437 nzmax * type_size, false, NULL)) ;
438 }
439 }
440
441 //-------------------------------------------------------------------------
442 // tell GraphBLAS the matrix is shallow
443 //-------------------------------------------------------------------------
444
445 // TODO need a shallow import
446 A->p_shallow = (A->p != NULL) ;
447 A->h_shallow = (A->h != NULL) ;
448 A->b_shallow = (A->b != NULL) ;
449 A->i_shallow = (A->i != NULL) ;
450 A->x_shallow = (A->x != NULL) ;
451 #ifdef GB_DEBUG
452 if (A->p != NULL) GB_Global_memtable_remove (A->p) ;
453 if (A->h != NULL) GB_Global_memtable_remove (A->h) ;
454 if (A->b != NULL) GB_Global_memtable_remove (A->b) ;
455 if (A->i != NULL) GB_Global_memtable_remove (A->i) ;
456 if (A->x != NULL) GB_Global_memtable_remove (A->x) ;
457 #endif
458
459 //--------------------------------------------------------------------------
460 // return the result
461 //--------------------------------------------------------------------------
462
463 return (A) ;
464 }
465
466