1 //------------------------------------------------------------------------------
2 // GB_masker: R = masker (C, M, Z) constructs R for C<M>=Z
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 // GB_masker (R, C, M, Z), does R=C ; R<M>=Z.  No typecasting is performed.
11 // The operation is similar to both R=C+Z via GB_add and R=C.*Z via GB_emult,
12 // depending on the value of the mask.
13 
14 // GB_masker is only called by GB_mask, which itself is only called by
15 // GB_accum_mask.
16 
17 // Let R be the result of the mask.  In the caller, R is written back into the
18 // final C matrix, but in GB_masker, C is a read-only matrix.  Consider the
19 // following table, where "add" is the result of C+Z, an "emult" is the result
20 // of C.*Z.
21 
22 //                                      R = masker (C,M,Z)
23 
24 // C(i,j)   Z(i,j)  add     emult       M(i,j)=1    M(i,j)=0
25 
26 // ------   ------  ------  ------      --------    --------
27 
28 //  cij     zij     cij+zij cij*zij     zij         cij
29 
30 //   -      zij     zij     -           zij         -
31 
32 //  cij     -       cij     -           -           cij
33 
34 //   -      -       -       -           -           -
35 
36 // As a result, GB_masker is very similar to GB_add and GB_emult.  The
37 // vectors that appear in R are bounded by the set union of C and Z, just
38 // like GB_add when the mask is *not* present.  The pattern of R is bounded
39 // by the pattern of C+Z, also ignoring the mask.
40 
41 // C is always sparse or hypersparse; if C is bitmap or full, GB_subassign is
42 // used instead, since C(:,:)<M>=Z can directly modify C in that case, without
43 // creating zombies or pending tuples, in GB_bitmap_assign.
44 
45 // M and Z can have any sparsity structure: sparse, hypersparse, bitmap, or
46 // full.  R is constructed as sparse, hypersparse, or bitmap, depending on
47 // the sparsity of M and Z, as determined by GB_masker_sparsity.
48 
49 #include "GB_mask.h"
50 #include "GB_add.h"
51 #define GB_FREE_ALL ;
52 
GB_masker(GrB_Matrix R,const bool R_is_csc,const GrB_Matrix M,const bool Mask_comp,const bool Mask_struct,const GrB_Matrix C,const GrB_Matrix Z,GB_Context Context)53 GrB_Info GB_masker          // R = masker (C, M, Z)
54 (
55     GrB_Matrix R,           // output matrix, static header
56     const bool R_is_csc,    // format of output matrix R
57     const GrB_Matrix M,     // required input mask
58     const bool Mask_comp,   // descriptor for M
59     const bool Mask_struct, // if true, use the only structure of M
60     const GrB_Matrix C,     // input C matrix
61     const GrB_Matrix Z,     // input Z matrix
62     GB_Context Context
63 )
64 {
65 
66     //--------------------------------------------------------------------------
67     // check inputs
68     //--------------------------------------------------------------------------
69 
70     GrB_Info info ;
71 
72     ASSERT (R != NULL && R->static_header) ;
73 
74     ASSERT_MATRIX_OK (M, "M for masker", GB0) ;
75     ASSERT (!GB_PENDING (M)) ;
76     ASSERT (!GB_JUMBLED (M)) ;
77     ASSERT (!GB_ZOMBIES (M)) ;
78 
79     ASSERT_MATRIX_OK (C, "C for masker", GB0) ;
80     ASSERT (!GB_PENDING (C)) ;
81     ASSERT (!GB_JUMBLED (C)) ;
82     ASSERT (!GB_ZOMBIES (C)) ;
83 
84     ASSERT_MATRIX_OK (Z, "Z for masker", GB0) ;
85     ASSERT (!GB_PENDING (Z)) ;
86     ASSERT (!GB_JUMBLED (Z)) ;
87     ASSERT (!GB_ZOMBIES (Z)) ;
88 
89     ASSERT (!GB_IS_BITMAP (C)) ;    // GB_masker not used if C is bitmap
90     ASSERT (!GB_IS_FULL (C)) ;      // GB_masker not used if C is full
91 
92     ASSERT (C->vdim == Z->vdim && C->vlen == Z->vlen) ;
93     ASSERT (C->vdim == M->vdim && C->vlen == M->vlen) ;
94 
95     //--------------------------------------------------------------------------
96     // determine the sparsity of R
97     //--------------------------------------------------------------------------
98 
99     int R_sparsity = GB_masker_sparsity (C, M, Mask_comp, Z) ;
100 
101     //--------------------------------------------------------------------------
102     // initializations
103     //--------------------------------------------------------------------------
104 
105     int64_t Rnvec, Rnvec_nonempty ;
106     int64_t *Rp     = NULL ; size_t Rp_size = 0 ;
107     int64_t *Rh     = NULL ; size_t Rh_size = 0 ;
108     int64_t *R_to_M = NULL ; size_t R_to_M_size = 0 ;
109     int64_t *R_to_C = NULL ; size_t R_to_C_size = 0 ;
110     int64_t *R_to_Z = NULL ; size_t R_to_Z_size = 0 ;
111     int R_ntasks = 0, R_nthreads ;
112     size_t TaskList_size = 0 ;
113     GB_task_struct *TaskList = NULL ;
114 
115     //--------------------------------------------------------------------------
116     // phase0: finalize the sparsity structure of R and the vectors of R
117     //--------------------------------------------------------------------------
118 
119     // This phase is identical to phase0 of GB_add, except that Ch is never a
120     // deep or shallow copy of Mh.
121 
122     info = GB_add_phase0 (
123         // computed by by phase0:
124         &Rnvec, &Rh, &Rh_size,
125         &R_to_M, &R_to_M_size,
126         &R_to_C, &R_to_C_size,
127         &R_to_Z, &R_to_Z_size, NULL, &R_sparsity,
128         // original input:
129         M, C, Z, Context) ;
130     if (info != GrB_SUCCESS)
131     {
132         // out of memory
133         return (info) ;
134     }
135 
136     GBURBLE ("masker:(%s:%s%s%s%s%s=%s) ",
137         GB_sparsity_char (R_sparsity),
138         GB_sparsity_char_matrix (C),
139         Mask_struct ? "{" : "<",
140         Mask_comp ? "!" : "",
141         GB_sparsity_char_matrix (M),
142         Mask_struct ? "}" : ">",
143         GB_sparsity_char_matrix (Z)) ;
144 
145     //--------------------------------------------------------------------------
146     // phase1: split R into tasks, and count entries in each vector of R
147     //--------------------------------------------------------------------------
148 
149     if (R_sparsity == GxB_SPARSE || R_sparsity == GxB_HYPERSPARSE)
150     {
151 
152         //----------------------------------------------------------------------
153         // R is sparse or hypersparse: slice and analyze the R matrix
154         //----------------------------------------------------------------------
155 
156         // phase1a: split R into tasks
157         info = GB_ewise_slice (
158             // computed by phase1a
159             &TaskList, &TaskList_size, &R_ntasks, &R_nthreads,
160             // computed by phase0:
161             Rnvec, Rh, R_to_M, R_to_C, R_to_Z, false,
162             // original input:
163             M, C, Z, Context) ;
164         if (info != GrB_SUCCESS)
165         {
166             // out of memory; free everything allocated by GB_add_phase0
167             GB_FREE (&Rh, Rh_size) ;
168             GB_FREE_WERK (&R_to_M, R_to_M_size) ;
169             GB_FREE_WERK (&R_to_C, R_to_C_size) ;
170             GB_FREE_WERK (&R_to_Z, R_to_Z_size) ;
171             return (info) ;
172         }
173 
174         // count the number of entries in each vector of R
175         info = GB_masker_phase1 (
176             // computed or used by phase1:
177             &Rp, &Rp_size, &Rnvec_nonempty,
178             // from phase1a:
179             TaskList, R_ntasks, R_nthreads,
180             // from phase0:
181             Rnvec, Rh, R_to_M, R_to_C, R_to_Z,
182             // original input:
183             M, Mask_comp, Mask_struct, C, Z, Context) ;
184         if (info != GrB_SUCCESS)
185         {
186             // out of memory; free everything allocated by GB_add_phase0
187             GB_FREE_WERK (&TaskList, TaskList_size) ;
188             GB_FREE (&Rh, Rh_size) ;
189             GB_FREE_WERK (&R_to_M, R_to_M_size) ;
190             GB_FREE_WERK (&R_to_C, R_to_C_size) ;
191             GB_FREE_WERK (&R_to_Z, R_to_Z_size) ;
192             return (info) ;
193         }
194 
195     }
196     else
197     {
198 
199         //----------------------------------------------------------------------
200         // R is bitmap or full: only determine how many threads to use
201         //----------------------------------------------------------------------
202 
203         GB_GET_NTHREADS_MAX (nthreads_max, chunk, Context) ;
204         R_nthreads = GB_nthreads (M->vlen * M->vdim, chunk, nthreads_max) ;
205     }
206 
207     //--------------------------------------------------------------------------
208     // phase2: compute the entries (indices and values) in each vector of R
209     //--------------------------------------------------------------------------
210 
211     // Rp and Rh are either freed by phase2, or transplanted into R.
212     // Either way, they are not freed here.
213 
214     info = GB_masker_phase2 (
215         // computed or used by phase2:
216         R, R_is_csc,
217         // from phase1:
218         &Rp, Rp_size, Rnvec_nonempty,
219         // from phase1a:
220         TaskList, R_ntasks, R_nthreads,
221         // from phase0:
222         Rnvec, &Rh, Rh_size, R_to_M, R_to_C, R_to_Z, R_sparsity,
223         // original input:
224         M, Mask_comp, Mask_struct, C, Z, Context) ;
225 
226     // if successful, Rh and Rp must not be freed; they are now R->h and R->p
227 
228     // free workspace
229     GB_FREE_WERK (&TaskList, TaskList_size) ;
230     GB_FREE_WERK (&R_to_M, R_to_M_size) ;
231     GB_FREE_WERK (&R_to_C, R_to_C_size) ;
232     GB_FREE_WERK (&R_to_Z, R_to_Z_size) ;
233 
234     if (info != GrB_SUCCESS)
235     {
236         // out of memory; note that Rp and Rh are already freed
237         return (info) ;
238     }
239 
240     //--------------------------------------------------------------------------
241     // return result
242     //--------------------------------------------------------------------------
243 
244     ASSERT_MATRIX_OK (R, "R output for masker", GB0) ;
245     return (GrB_SUCCESS) ;
246 }
247 
248