1 //------------------------------------------------------------------------------
2 // GB_bitmap_assign_M_accum_whole: assign to C bitmap
3 //------------------------------------------------------------------------------
4
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7
8 //------------------------------------------------------------------------------
9 // C<M> += A assign
10 // C<M> += A subassign
11
12 // C<M,repl> += A assign
13 // C<M,repl> += A subassign
14 //------------------------------------------------------------------------------
15
16 // C: bitmap
17 // M: present, hypersparse or sparse (not bitmap or full)
18 // Mask_comp: false
19 // Mask_struct: true or false
20 // C_replace: true or false
21 // accum: present
22 // A: matrix (hyper, sparse, bitmap, or full), or scalar
23 // kind: assign or subassign (same action)
24
25 #include "GB_bitmap_assign_methods.h"
26
27 #define GB_FREE_ALL \
28 { \
29 GB_WERK_POP (M_ek_slicing, int64_t) ; \
30 }
31
GB_bitmap_assign_M_accum_whole(GrB_Matrix C,const bool C_replace,const GrB_Matrix M,const bool Mask_struct,const GrB_BinaryOp accum,const GrB_Matrix A,const void * scalar,const GrB_Type scalar_type,GB_Context Context)32 GrB_Info GB_bitmap_assign_M_accum_whole
33 (
34 // input/output:
35 GrB_Matrix C, // input/output matrix in bitmap format
36 // inputs:
37 const bool C_replace, // descriptor for C
38 const GrB_Matrix M, // mask matrix, which is not NULL here
39 // const bool Mask_comp, // false here
40 const bool Mask_struct, // true if M is structural, false if valued
41 const GrB_BinaryOp accum, // present here
42 const GrB_Matrix A, // input matrix, not transposed
43 const void *scalar, // input scalar
44 const GrB_Type scalar_type, // type of input scalar
45 GB_Context Context
46 )
47 {
48
49 //--------------------------------------------------------------------------
50 // check inputs
51 //--------------------------------------------------------------------------
52
53 GBURBLE_BITMAP_ASSIGN ("bit3:whole", M, false, accum,
54 GB_ALL, GB_ALL, GB_ASSIGN) ;
55 ASSERT (GB_IS_HYPERSPARSE (M) || GB_IS_SPARSE (M)) ;
56 ASSERT (GB_JUMBLED_OK (M)) ;
57 ASSERT_MATRIX_OK (C, "C for bitmap assign, M, accum", GB0) ;
58 ASSERT_MATRIX_OK (M, "M for bitmap assign, M, accum", GB0) ;
59 ASSERT_MATRIX_OK_OR_NULL (A, "A for bitmap assign, M, accum", GB0) ;
60
61 //--------------------------------------------------------------------------
62 // get C, M, A, and accum
63 //--------------------------------------------------------------------------
64
65 GB_GET_C_BITMAP ; // C must be bitmap
66 GB_SLICE_M
67 GB_GET_A_AND_SCALAR
68 GB_GET_ACCUM_FOR_BITMAP
69
70 //--------------------------------------------------------------------------
71 // do the assignment
72 //--------------------------------------------------------------------------
73
74 if (A == NULL)
75 {
76
77 //----------------------------------------------------------------------
78 // scalar assignment: C<M, replace or !replace> += scalar
79 //----------------------------------------------------------------------
80
81 if (C_replace)
82 {
83
84 //------------------------------------------------------------------
85 // C<M,replace> += scalar
86 //------------------------------------------------------------------
87
88 // Cb [pC] += 2 for each entry M(i,j) in the mask
89 GB_bitmap_M_scatter_whole (C,
90 M, Mask_struct, GB_BITMAP_M_SCATTER_PLUS_2,
91 M_ek_slicing, M_ntasks, M_nthreads, Context) ;
92 // the bitmap of C now contains:
93 // Cb (i,j) = 0: cij not present, mij zero
94 // Cb (i,j) = 1: cij present, mij zero
95 // Cb (i,j) = 2: cij not present, mij 1
96 // Cb (i,j) = 3: cij present, mij 1
97
98 #undef GB_CIJ_WORK
99 #define GB_CIJ_WORK(pC) \
100 { \
101 switch (Cb [pC]) \
102 { \
103 case 1: /* C(i,j) present, M(i,j) = 0 */ \
104 /* delete this entry */ \
105 Cb [pC] = 0 ; \
106 task_cnvals-- ; \
107 break ; \
108 case 2: /* C(i,j) not present, M(i,j) = 1 */ \
109 /* Cx [pC] = scalar */ \
110 GB_ASSIGN_SCALAR (pC) ; \
111 Cb [pC] = 1 ; \
112 task_cnvals++ ; \
113 break ; \
114 case 3: /* C(i,j) present, M(i,j) = 1 */ \
115 /* Cx [pC] += scalar */ \
116 GB_ACCUM_SCALAR (pC) ; \
117 Cb [pC] = 1 ; \
118 break ; \
119 default: ; \
120 } \
121 }
122 #include "GB_bitmap_assign_C_whole_template.c"
123
124 }
125 else
126 {
127
128 //------------------------------------------------------------------
129 // C<M> += scalar
130 //------------------------------------------------------------------
131
132 #undef GB_MASK_WORK
133 #define GB_MASK_WORK(pC) \
134 { \
135 if (Cb [pC]) \
136 { \
137 /* C(i,j) present, M(i,j) = 1 */ \
138 /* Cx [pC] += scalar */ \
139 GB_ACCUM_SCALAR (pC) ; \
140 } \
141 else \
142 { \
143 /* C(i,j) not present, M(i,j) = 1 */ \
144 /* Cx [pC] = scalar */ \
145 GB_ASSIGN_SCALAR (pC) ; \
146 Cb [pC] = 1 ; \
147 task_cnvals++ ; \
148 } \
149 }
150 #include "GB_bitmap_assign_M_all_template.c"
151 }
152
153 }
154 else
155 {
156
157 //----------------------------------------------------------------------
158 // matrix assignment: C<M, replace or !replace> += A
159 //----------------------------------------------------------------------
160
161 if (GB_IS_BITMAP (A) || GB_IS_FULL (A))
162 {
163
164 //------------------------------------------------------------------
165 // C<M, replace or !replace> += A where A is bitmap or full
166 //------------------------------------------------------------------
167
168 if (C_replace)
169 {
170
171 //--------------------------------------------------------------
172 // C<M, replace> += A where A is bitmap or full
173 //--------------------------------------------------------------
174
175 // Cb [pC] += 2 for each entry M(i,j) in the mask
176 GB_bitmap_M_scatter_whole (C,
177 M, Mask_struct, GB_BITMAP_M_SCATTER_PLUS_2,
178 M_ek_slicing, M_ntasks, M_nthreads, Context) ;
179 // the bitmap of C now contains:
180 // Cb (i,j) = 0: cij not present, mij zero
181 // Cb (i,j) = 1: cij present, mij zero
182 // Cb (i,j) = 2: cij not present, mij 1
183 // Cb (i,j) = 3: cij present, mij 1
184
185 #undef GB_CIJ_WORK
186 #define GB_CIJ_WORK(pC) \
187 { \
188 switch (Cb [pC]) \
189 { \
190 case 1: /* C(i,j) present, M(i,j) = 0 */ \
191 /* delete this entry */ \
192 Cb [pC] = 0 ; \
193 task_cnvals-- ; \
194 break ; \
195 case 2: /* C(i,j) not present, M(i,j) = 1 */ \
196 if (GBB (Ab, pC)) \
197 { \
198 /* Cx [pC] = Ax [pC] */ \
199 GB_ASSIGN_AIJ (pC, pC) ; \
200 Cb [pC] = 1 ; \
201 task_cnvals++ ; \
202 } \
203 else \
204 { \
205 /* clear the mask from C */ \
206 Cb [pC] = 0 ; \
207 } \
208 break ; \
209 case 3: /* C(i,j) present, M(i,j) = 1 */ \
210 if (GBB (Ab, pC)) \
211 { \
212 /* Cx [pC] += Ax [pC] */ \
213 GB_ACCUM_AIJ (pC, pC) ; \
214 } \
215 Cb [pC] = 1 ; \
216 break ; \
217 default: ; \
218 } \
219 }
220 #include "GB_bitmap_assign_C_whole_template.c"
221
222 }
223 else
224 {
225
226 //--------------------------------------------------------------
227 // C<M> += A where A is bitmap or full
228 //--------------------------------------------------------------
229
230 #undef GB_MASK_WORK
231 #define GB_MASK_WORK(pC) \
232 { \
233 if (GBB (Ab, pC)) \
234 { \
235 /* A(i,j) is present */ \
236 if (Cb [pC]) \
237 { \
238 /* C(i,j) present, M(i,j) = 1 */ \
239 /* Cx [pC] += Ax [pC] */ \
240 GB_ACCUM_AIJ (pC, pC) ; \
241 } \
242 else \
243 { \
244 /* C(i,j) not present, M(i,j) = 1 */ \
245 /* Cx [pC] = Ax [pC] */ \
246 GB_ASSIGN_AIJ (pC, pC) ; \
247 Cb [pC] = 1 ; \
248 task_cnvals++ ; \
249 } \
250 } \
251 }
252 #include "GB_bitmap_assign_M_all_template.c"
253
254 }
255 }
256 else
257 {
258
259 //------------------------------------------------------------------
260 // C<M, replace or !replace> += A where A is sparse or hyper
261 //------------------------------------------------------------------
262
263 // Cb [pC] += 2 for each entry M(i,j) in the mask
264 GB_bitmap_M_scatter_whole (C,
265 M, Mask_struct, GB_BITMAP_M_SCATTER_PLUS_2,
266 M_ek_slicing, M_ntasks, M_nthreads, Context) ;
267 // the bitmap of C now contains:
268 // Cb (i,j) = 0: cij not present, mij zero
269 // Cb (i,j) = 1: cij present, mij zero
270 // Cb (i,j) = 2: cij not present, mij 1
271 // Cb (i,j) = 3: cij present, mij 1
272
273 // assign or accumulate entries from A into C
274 #undef GB_AIJ_WORK
275 #define GB_AIJ_WORK(pC,pA) \
276 { \
277 /* A(i,j) is present */ \
278 int8_t cb = Cb [pC] ; \
279 if (cb == 2) \
280 { \
281 /* C(i,j) not present, M(i,j) = 1 */ \
282 /* Cx [pC] = Ax [pA] */ \
283 GB_ASSIGN_AIJ (pC, pA) ; \
284 Cb [pC] = 3 ; \
285 task_cnvals++ ; \
286 } \
287 else if (cb == 3) \
288 { \
289 /* C(i,j) present, M(i,j) = 1 */ \
290 /* Cx [pC] += Ax [pA] */ \
291 GB_ACCUM_AIJ (pC, pA) ; \
292 } \
293 }
294 #include "GB_bitmap_assign_A_whole_template.c"
295
296 if (C_replace)
297 {
298 // clear the mask and delete entries not assigned
299 #undef GB_CIJ_WORK
300 #define GB_CIJ_WORK(pC) \
301 { \
302 int8_t cb = Cb [pC] ; \
303 Cb [pC] = (cb == 3) ; \
304 task_cnvals -= (cb == 1) ; \
305 }
306 #include "GB_bitmap_assign_C_whole_template.c"
307 }
308 else
309 {
310 // clear the mask
311 // Cb [pC] -= 2 for each entry M(i,j) in the mask
312 GB_bitmap_M_scatter_whole (C,
313 M, Mask_struct, GB_BITMAP_M_SCATTER_MINUS_2,
314 M_ek_slicing, M_ntasks, M_nthreads, Context) ;
315 }
316 }
317 }
318
319 //--------------------------------------------------------------------------
320 // free workspace and return result
321 //--------------------------------------------------------------------------
322
323 C->nvals = cnvals ;
324 GB_FREE_ALL ;
325 ASSERT_MATRIX_OK (C, "final C for bitmap assign, M, accum, whole", GB0) ;
326 return (GrB_SUCCESS) ;
327 }
328
329