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