1 //------------------------------------------------------------------------------
2 // GB_bitmap_assign_M_accum: 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>(I,J) += A assign
10 // C(I,J)<M> += A subassign
11
12 // C<M,repl>(I,J) += A assign
13 // C(I,J)<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, row assign, col assign, or subassign
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(GrB_Matrix C,const bool C_replace,const GrB_Index * I,const int64_t nI,const int Ikind,const int64_t Icolon[3],const GrB_Index * J,const int64_t nJ,const int Jkind,const int64_t Jcolon[3],const GrB_Matrix M,const bool Mask_struct,const GrB_BinaryOp accum,const GrB_Matrix A,const void * scalar,const GrB_Type scalar_type,const int assign_kind,GB_Context Context)32 GrB_Info GB_bitmap_assign_M_accum
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_Index *I, // I index list
39 const int64_t nI,
40 const int Ikind,
41 const int64_t Icolon [3],
42 const GrB_Index *J, // J index list
43 const int64_t nJ,
44 const int Jkind,
45 const int64_t Jcolon [3],
46 const GrB_Matrix M, // mask matrix, which is not NULL here
47 // const bool Mask_comp, // false here
48 const bool Mask_struct, // true if M is structural, false if valued
49 const GrB_BinaryOp accum, // present here
50 const GrB_Matrix A, // input matrix, not transposed
51 const void *scalar, // input scalar
52 const GrB_Type scalar_type, // type of input scalar
53 const int assign_kind, // row assign, col assign, assign, or subassign
54 GB_Context Context
55 )
56 {
57
58 //--------------------------------------------------------------------------
59 // check inputs
60 //--------------------------------------------------------------------------
61
62 GBURBLE_BITMAP_ASSIGN ("bit3", M, false, accum,
63 Ikind, Jkind, assign_kind) ;
64 ASSERT (GB_IS_HYPERSPARSE (M) || GB_IS_SPARSE (M)) ;
65 ASSERT_MATRIX_OK (C, "C for bitmap assign, M, accum", GB0) ;
66 ASSERT_MATRIX_OK (M, "M for bitmap assign, M, accum", GB0) ;
67 ASSERT_MATRIX_OK_OR_NULL (A, "A for bitmap assign, M, accum", GB0) ;
68
69 //--------------------------------------------------------------------------
70 // get C, M, A, and accum
71 //--------------------------------------------------------------------------
72
73 GB_GET_C_BITMAP ; // C must be bitmap
74 GB_SLICE_M
75 GB_GET_A_AND_SCALAR
76 GB_GET_ACCUM_FOR_BITMAP
77
78 // if C FULL: if C_replace false, no deletion occurs
79 // if C_replace is true: convert C to bitmap first
80
81 //--------------------------------------------------------------------------
82 // do the assignment
83 //--------------------------------------------------------------------------
84
85 if (A == NULL && assign_kind == GB_SUBASSIGN)
86 {
87
88 //----------------------------------------------------------------------
89 // scalar subassignment: C(I,J)<M> += scalar
90 //----------------------------------------------------------------------
91
92 ASSERT (assign_kind == GB_SUBASSIGN) ;
93 int64_t keep = C_replace ? 3 : 1 ;
94
95 // for all entries in the mask M:
96 #undef GB_MASK_WORK
97 #define GB_MASK_WORK(pC) \
98 { \
99 int8_t cb = Cb [pC] ; \
100 /* keep this entry */ \
101 Cb [pC] = keep ; \
102 if (cb == 0) \
103 { \
104 /* Cx [pC] = scalar */ \
105 GB_ASSIGN_SCALAR (pC) ; \
106 task_cnvals++ ; \
107 } \
108 else /* (cb == 1) */ \
109 { \
110 /* Cx [pC] += scalar */ \
111 GB_ACCUM_SCALAR (pC) ; \
112 } \
113 }
114 #include "GB_bitmap_assign_M_sub_template.c"
115
116 if (C_replace)
117 {
118 // for all entries in IxJ
119 #undef GB_IXJ_WORK
120 #define GB_IXJ_WORK(pC,ignore) \
121 { \
122 int8_t cb = Cb [pC] ; \
123 Cb [pC] = (cb == 3) ; \
124 task_cnvals -= (cb == 1) ; \
125 }
126 #include "GB_bitmap_assign_IxJ_template.c"
127 }
128
129 }
130 else
131 {
132
133 //----------------------------------------------------------------------
134 // scatter M into C
135 //----------------------------------------------------------------------
136
137 // Cb [pC] += 2 for each entry M(i,j) in the mask
138 GB_bitmap_M_scatter (C, I, nI, Ikind, Icolon, J, nJ, Jkind, Jcolon,
139 M, Mask_struct, assign_kind, GB_BITMAP_M_SCATTER_PLUS_2,
140 M_ek_slicing, M_ntasks, M_nthreads, Context) ;
141 // the bitmap of C now contains:
142 // Cb (i,j) = 0: cij not present, mij zero
143 // Cb (i,j) = 1: cij present, mij zero
144 // Cb (i,j) = 2: cij not present, mij 1
145 // Cb (i,j) = 3: cij present, mij 1
146
147 if (A == NULL)
148 {
149
150 //------------------------------------------------------------------
151 // scalar assignment: C<M>(I,J) += scalar
152 //------------------------------------------------------------------
153
154 ASSERT (assign_kind == GB_ASSIGN) ;
155 // for all entries in IxJ
156 #undef GB_IXJ_WORK
157 #define GB_IXJ_WORK(pC,ignore) \
158 { \
159 int8_t cb = Cb [pC] ; \
160 if (cb == 2) \
161 { \
162 /* Cx [pC] = scalar */ \
163 GB_ASSIGN_SCALAR (pC) ; \
164 Cb [pC] = 3 ; \
165 task_cnvals++ ; \
166 } \
167 else if (cb == 3) \
168 { \
169 /* Cx [pC] += scalar */ \
170 GB_ACCUM_SCALAR (pC) ; \
171 } \
172 }
173 #include "GB_bitmap_assign_IxJ_template.c"
174
175 }
176 else
177 {
178
179 //------------------------------------------------------------------
180 // matrix assignment: C<M>(I,J) += A or C(I,J)<M> += A
181 //------------------------------------------------------------------
182
183 // for all entries aij in A (A hyper, sparse, bitmap, or full)
184 // if Cb(p) == 0 // do nothing
185 // if Cb(p) == 1 // do nothing
186 // if Cb(p) == 2:
187 // Cx(p) = aij
188 // Cb(p) = 3 // C(iC,jC) is now present, insert
189 // task_cnvals++
190 // if Cb(p) == 3:
191 // Cx(p) += aij // C(iC,jC) still present, updated
192 // Cb(p) still 3
193
194 #define GB_AIJ_WORK(pC,pA) \
195 { \
196 int8_t cb = Cb [pC] ; \
197 if (cb == 2) \
198 { \
199 /* Cx [pC] = Ax [pA] */ \
200 GB_ASSIGN_AIJ (pC, pA) ; \
201 Cb [pC] = 3 ; \
202 task_cnvals++ ; \
203 } \
204 else if (cb == 3) \
205 { \
206 /* Cx [pC] += Ax [pA] */ \
207 GB_ACCUM_AIJ (pC, pA) ; \
208 } \
209 }
210 #include "GB_bitmap_assign_A_template.c"
211 }
212
213 //----------------------------------------------------------------------
214 // final pass: clear M from C or handle C_replace
215 //----------------------------------------------------------------------
216
217 if (C_replace)
218 {
219 // scan all of C for the C_replace phase
220 // for row assign: for all entries in C(i,:)
221 // for col assign: for all entries in C(:,j)
222 // for assign: for all entries in C(:,:)
223 // for subassign: for all entries in C(I,J)
224 // 0 -> 0
225 // 1 -> 0 delete this entry
226 // 2 -> 0
227 // 3 -> 1: keep this entry. already counted above
228 #define GB_CIJ_WORK(pC) \
229 { \
230 int8_t cb = Cb [pC] ; \
231 Cb [pC] = (cb == 3) ; \
232 task_cnvals -= (cb == 1) ; \
233 }
234 #include "GB_bitmap_assign_C_template.c"
235 }
236 else
237 {
238 // clear M from C
239 // Cb [pC] -= 2 for each entry M(i,j) in the mask
240 GB_bitmap_M_scatter (C, I, nI, Ikind, Icolon, J, nJ, Jkind, Jcolon,
241 M, Mask_struct, assign_kind, GB_BITMAP_M_SCATTER_MINUS_2,
242 M_ek_slicing, M_ntasks, M_nthreads, Context) ;
243 }
244 }
245
246 //--------------------------------------------------------------------------
247 // free workspace and return result
248 //--------------------------------------------------------------------------
249
250 C->nvals = cnvals ;
251 GB_FREE_ALL ;
252 ASSERT_MATRIX_OK (C, "final C for bitmap assign, M, accum", GB0) ;
253 return (GrB_SUCCESS) ;
254 }
255
256