1 //------------------------------------------------------------------------------
2 // GB_mex_setElement: MATLAB interface for A(i,j) = x
3 //------------------------------------------------------------------------------
4
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7
8 //------------------------------------------------------------------------------
9
10 // x = A (i,j), where i and j are zero-based. If i and j arrays, then
11 // x (k) = A (i (k), j (k)) is done for all k.
12
13 // I and J and zero-based
14
15 #include "GB_mex.h"
16
17 #define USAGE "A = GB_mex_setElement (A, I, J, X, debug_wait)"
18
19 bool debug_wait = false ;
20
21 #define FREE_ALL \
22 { \
23 GrB_Matrix_free_(&A) ; \
24 GB_mx_put_global (true) ; \
25 }
26
27 #if defined ( __GNUC__ )
28 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
29 #endif
30
31 // set all elements of a matrix and return if an error is encountered
32 #define setEl(prefix,name,type) \
33 GrB_Info set_ ## name \
34 (GrB_Matrix A, type *X, GrB_Index *I, GrB_Index *J, GrB_Index ni) \
35 { \
36 for (int64_t k = 0 ; k < ni ; k++) \
37 { \
38 GrB_Info info = prefix ## Matrix_setElement_ ## name \
39 (A, AMPERSAND (X [k]), I [k], J [k]) ; \
40 if (info != GrB_SUCCESS) return (info) ; \
41 } \
42 if (debug_wait) \
43 { \
44 return (GB_Matrix_wait (A, "A", NULL)) ; \
45 } \
46 return (GrB_SUCCESS) ; \
47 }
48
49 // create all the local set_TYPE functions
50 #define AMPERSAND(x) x
51 setEl (GrB_, BOOL , bool ) ;
52 setEl (GrB_, INT8 , int8_t ) ;
53 setEl (GrB_, UINT8 , uint8_t ) ;
54 setEl (GrB_, INT16 , int16_t ) ;
55 setEl (GrB_, UINT16 , uint16_t ) ;
56 setEl (GrB_, INT32 , int32_t ) ;
57 setEl (GrB_, UINT32 , uint32_t ) ;
58 setEl (GrB_, INT64 , int64_t ) ;
59 setEl (GrB_, UINT64 , uint64_t ) ;
60 setEl (GrB_, FP32 , float ) ;
61 setEl (GrB_, FP64 , double ) ;
62 setEl (GxB_, FC32 , GxB_FC32_t ) ;
63 setEl (GxB_, FC64 , GxB_FC64_t ) ;
64 #undef AMPERSAND
65 #define AMPERSAND(x) &x
66 setEl (GrB_, UDT , GxB_FC64_t) ;
67 #undef AMPERSAND
68
69
70 // set all elements of a vector and return if an error is encountered
71 #define vsetEl(prefix,name,type) \
72 GrB_Info vset_ ## name \
73 (GrB_Matrix A, type *X, GrB_Index *I, GrB_Index ni) \
74 { \
75 GrB_Vector w = (GrB_Vector) A ; \
76 for (int64_t k = 0 ; k < ni ; k++) \
77 { \
78 GrB_Info info = prefix ## Vector_setElement_ ## name \
79 (w, AMPERSAND (X [k]), I [k]) ; \
80 if (info != GrB_SUCCESS) return (info) ; \
81 } \
82 if (debug_wait) \
83 { \
84 return (GB_Matrix_wait (A, "A", NULL)) ; \
85 } \
86 return (GrB_SUCCESS) ; \
87 }
88
89 // create all the local set_TYPE functions
90 #define AMPERSAND(x) x
91 vsetEl (GrB_, BOOL , bool ) ;
92 vsetEl (GrB_, INT8 , int8_t ) ;
93 vsetEl (GrB_, UINT8 , uint8_t ) ;
94 vsetEl (GrB_, INT16 , int16_t ) ;
95 vsetEl (GrB_, UINT16 , uint16_t ) ;
96 vsetEl (GrB_, INT32 , int32_t ) ;
97 vsetEl (GrB_, UINT32 , uint32_t ) ;
98 vsetEl (GrB_, INT64 , int64_t ) ;
99 vsetEl (GrB_, UINT64 , uint64_t ) ;
100 vsetEl (GrB_, FP32 , float ) ;
101 vsetEl (GrB_, FP64 , double ) ;
102 vsetEl (GxB_, FC32 , GxB_FC32_t ) ;
103 vsetEl (GxB_, FC64 , GxB_FC64_t ) ;
104 #undef AMPERSAND
105 #define AMPERSAND(x) &x
106 vsetEl (GrB_, UDT , GxB_FC64_t) ;
107 #undef AMPERSAND
108
mexFunction(int nargout,mxArray * pargout[],int nargin,const mxArray * pargin[])109 void mexFunction
110 (
111 int nargout,
112 mxArray *pargout [ ],
113 int nargin,
114 const mxArray *pargin [ ]
115 )
116 {
117
118 bool malloc_debug = GB_mx_get_global (true) ;
119
120 GrB_Matrix A = NULL ;
121 GB_void *Y ;
122 GrB_Type xtype ;
123 GrB_Index *I = NULL, ni = 0, I_range [3] ;
124 GrB_Index *J = NULL, nj = 0, J_range [3] ;
125 bool is_list ;
126
127 // check inputs
128 if (nargout > 1 || nargin < 4 || nargin > 5)
129 {
130 mexErrMsgTxt ("Usage: " USAGE) ;
131 }
132
133 // get A (deep copy)
134 #define GET_DEEP_COPY \
135 A = GB_mx_mxArray_to_Matrix (pargin [0], "A input", true, true) ;
136 #define FREE_DEEP_COPY GrB_Matrix_free_(&A) ;
137 GET_DEEP_COPY ;
138 if (A == NULL)
139 {
140 FREE_ALL ;
141 mexErrMsgTxt ("A failed") ;
142 }
143
144 // get I
145 if (!GB_mx_mxArray_to_indices (&I, pargin [1], &ni, I_range, &is_list))
146 {
147 FREE_ALL ;
148 mexErrMsgTxt ("I failed") ;
149 }
150 if (!is_list)
151 {
152 mexErrMsgTxt ("I is invalid; must be a list") ;
153 }
154
155 // get J
156 if (!GB_mx_mxArray_to_indices (&J, pargin [2], &nj, J_range, &is_list))
157 {
158 FREE_ALL ;
159 mexErrMsgTxt ("J failed") ;
160 }
161 if (!is_list)
162 {
163 mexErrMsgTxt ("J is invalid; must be a list") ;
164 }
165
166 if (ni != nj)
167 {
168 FREE_ALL ;
169 mexErrMsgTxt ("I and J must be the same size") ;
170 }
171
172 // get X
173 if (ni != mxGetNumberOfElements (pargin [3]))
174 {
175 FREE_ALL ;
176 mexErrMsgTxt ("I and X must be the same size") ;
177 }
178 if (!(mxIsNumeric (pargin [3]) || mxIsLogical (pargin [3])))
179 {
180 FREE_ALL ;
181 mexErrMsgTxt ("X must be a numeric or logical array") ;
182 }
183 if (mxIsSparse (pargin [3]))
184 {
185 FREE_ALL ;
186 mexErrMsgTxt ("X cannot be sparse") ;
187 }
188
189 // get debug_wait (if true, to GB_Matrix_wait after setElements)
190 GET_SCALAR (4, bool, debug_wait, false) ;
191
192 if (mxIsComplex (pargin [3]))
193 {
194 xtype = Complex ;
195 Y = mxGetComplexDoubles (pargin [3]) ;
196 }
197 else
198 {
199 Y = mxGetData (pargin [3]) ;
200 xtype = GB_mx_Type (pargin [3]) ;
201 if (xtype == NULL)
202 {
203 FREE_ALL ;
204 mexErrMsgTxt ("X must be numeric") ;
205 }
206 }
207
208 size_t s = 2 * sizeof (double) ;
209
210 // A (i,j) = x, for a list of elements
211
212 // the METHOD (...) macro is not used on each call to setElement, but
213 // to all of them. Thus, if any failure occurs, the computation is rolled
214 // back to the very beginning, and another fresh, deep, copy of A is made,
215 // and the sequence of setElements is tried again. If a setElement fails
216 // by running out of memory, it clears to whole matrix, so recovery cannot
217 // be made.
218
219 if (A->vdim == 1)
220 {
221 // test GrB_Vector_setElement
222 switch (xtype->code)
223 {
224 case GB_BOOL_code : METHOD (vset_BOOL (A, (bool *) Y, I, ni)) ; break ;
225 case GB_INT8_code : METHOD (vset_INT8 (A, (int8_t *) Y, I, ni)) ; break ;
226 case GB_INT16_code : METHOD (vset_INT16 (A, (int16_t *) Y, I, ni)) ; break ;
227 case GB_INT32_code : METHOD (vset_INT32 (A, (int32_t *) Y, I, ni)) ; break ;
228 case GB_INT64_code : METHOD (vset_INT64 (A, (int64_t *) Y, I, ni)) ; break ;
229 case GB_UINT8_code : METHOD (vset_UINT8 (A, (uint8_t *) Y, I, ni)) ; break ;
230 case GB_UINT16_code : METHOD (vset_UINT16 (A, (uint16_t *) Y, I, ni)) ; break ;
231 case GB_UINT32_code : METHOD (vset_UINT32 (A, (uint32_t *) Y, I, ni)) ; break ;
232 case GB_UINT64_code : METHOD (vset_UINT64 (A, (uint64_t *) Y, I, ni)) ; break ;
233 case GB_FP32_code : METHOD (vset_FP32 (A, (float *) Y, I, ni)) ; break ;
234 case GB_FP64_code : METHOD (vset_FP64 (A, (double *) Y, I, ni)) ; break ;
235 case GB_FC32_code : METHOD (vset_FC32 (A, (GxB_FC32_t *) Y, I, ni)) ; break ;
236 case GB_FC64_code : METHOD (vset_FC64 (A, (GxB_FC64_t *) Y, I, ni)) ; break ;
237 case GB_UDT_code : METHOD (vset_UDT (A, (void *) Y, I, ni)) ; break ;
238 default:
239 FREE_ALL ;
240 mexErrMsgTxt ("unsupported type") ;
241 }
242 }
243 else
244 {
245 // test GrB_Matrix_setElement
246 switch (xtype->code)
247 {
248 case GB_BOOL_code : METHOD (set_BOOL (A, (bool *) Y, I, J, ni)) ; break ;
249 case GB_INT8_code : METHOD (set_INT8 (A, (int8_t *) Y, I, J, ni)) ; break ;
250 case GB_INT16_code : METHOD (set_INT16 (A, (int16_t *) Y, I, J, ni)) ; break ;
251 case GB_INT32_code : METHOD (set_INT32 (A, (int32_t *) Y, I, J, ni)) ; break ;
252 case GB_INT64_code : METHOD (set_INT64 (A, (int64_t *) Y, I, J, ni)) ; break ;
253 case GB_UINT8_code : METHOD (set_UINT8 (A, (uint8_t *) Y, I, J, ni)) ; break ;
254 case GB_UINT16_code : METHOD (set_UINT16 (A, (uint16_t *) Y, I, J, ni)) ; break ;
255 case GB_UINT32_code : METHOD (set_UINT32 (A, (uint32_t *) Y, I, J, ni)) ; break ;
256 case GB_UINT64_code : METHOD (set_UINT64 (A, (uint64_t *) Y, I, J, ni)) ; break ;
257 case GB_FP32_code : METHOD (set_FP32 (A, (float *) Y, I, J, ni)) ; break ;
258 case GB_FP64_code : METHOD (set_FP64 (A, (double *) Y, I, J, ni)) ; break ;
259 case GB_FC32_code : METHOD (set_FC32 (A, (GxB_FC32_t *) Y, I, J, ni)) ; break ;
260 case GB_FC64_code : METHOD (set_FC64 (A, (GxB_FC64_t *) Y, I, J, ni)) ; break ;
261 case GB_UDT_code : METHOD (set_UDT (A, (void *) Y, I, J, ni)) ; break ;
262 default:
263 FREE_ALL ;
264 mexErrMsgTxt ("unsupported type") ;
265 }
266 }
267
268 // only do debug checks after adding lots of tuples
269 if (ni > 1000) { ASSERT_MATRIX_OK (A, "A added pending tuples", GB0) ; }
270
271 // return A to MATLAB as a struct and free the GraphBLAS A
272 pargout [0] = GB_mx_Matrix_to_mxArray (&A, "A output", true) ;
273
274 FREE_ALL ;
275 }
276
277