1 //------------------------------------------------------------------------------
2 // GB_masker_phase2: phase2 for R = masker (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_phase2 computes R = masker (C,M,Z). It is preceded first by
11 // GB_add_phase0, which computes the list of vectors of R to compute (Rh) and
12 // their location in C and Z (R_to_[CZ]). Next, GB_masker_phase1 counts the
13 // entries in each vector R(:,j) and computes Rp.
14
15 // GB_masker_phase2 computes the pattern and values of each vector of R(:,j),
16 // entirely in parallel.
17
18 // R, M, C, and Z can be standard sparse or hypersparse, as determined by
19 // GB_add_phase0. All cases of the mask M are handled: present and not
20 // complemented, and present and complemented. The mask is always present.
21
22 // This function either frees Rp and Rh, or transplants then into R, as R->p
23 // and R->h. Either way, the caller must not free them.
24
25 #include "GB_mask.h"
26 #include "GB_ek_slice.h"
27 #include "GB_unused.h"
28
29 #undef GB_FREE_WORK
30 #define GB_FREE_WORK \
31 { \
32 GB_WERK_POP (M_ek_slicing, int64_t) ; \
33 GB_WERK_POP (C_ek_slicing, int64_t) ; \
34 }
35
36 #undef GB_FREE_ALL
37 #define GB_FREE_ALL \
38 { \
39 GB_FREE_WORK ; \
40 GB_phbix_free (R) ; \
41 }
42
GB_masker_phase2(GrB_Matrix R,const bool R_is_csc,int64_t ** Rp_handle,size_t Rp_size,const int64_t Rnvec_nonempty,const GB_task_struct * restrict TaskList,const int R_ntasks,const int R_nthreads,const int64_t Rnvec,int64_t ** Rh_handle,size_t Rh_size,const int64_t * restrict R_to_M,const int64_t * restrict R_to_C,const int64_t * restrict R_to_Z,const int R_sparsity,const GrB_Matrix M,const bool Mask_comp,const bool Mask_struct,const GrB_Matrix C,const GrB_Matrix Z,GB_Context Context)43 GrB_Info GB_masker_phase2 // phase2 for R = masker (C,M,Z)
44 (
45 GrB_Matrix R, // output matrix, static header
46 const bool R_is_csc, // format of output matrix R
47 // from phase1:
48 int64_t **Rp_handle, // vector pointers for R
49 size_t Rp_size,
50 const int64_t Rnvec_nonempty, // # of non-empty vectors in R
51 // tasks from phase1a:
52 const GB_task_struct *restrict TaskList, // array of structs
53 const int R_ntasks, // # of tasks
54 const int R_nthreads, // # of threads to use
55 // analysis from phase0:
56 const int64_t Rnvec,
57 int64_t **Rh_handle,
58 size_t Rh_size,
59 const int64_t *restrict R_to_M,
60 const int64_t *restrict R_to_C,
61 const int64_t *restrict R_to_Z,
62 const int R_sparsity,
63 // original input:
64 const GrB_Matrix M, // required mask
65 const bool Mask_comp, // if true, then M is complemented
66 const bool Mask_struct, // if true, use the only structure of M
67 const GrB_Matrix C,
68 const GrB_Matrix Z,
69 GB_Context Context
70 )
71 {
72
73 //--------------------------------------------------------------------------
74 // check inputs
75 //--------------------------------------------------------------------------
76
77 ASSERT_MATRIX_OK (M, "M for mask phase2", GB0) ;
78 ASSERT (!GB_ZOMBIES (M)) ;
79 ASSERT (!GB_JUMBLED (M)) ;
80 ASSERT (!GB_PENDING (M)) ;
81
82 ASSERT_MATRIX_OK (C, "C for mask phase2", GB0) ;
83 ASSERT (!GB_ZOMBIES (C)) ;
84 ASSERT (!GB_JUMBLED (C)) ;
85 ASSERT (!GB_PENDING (C)) ;
86
87 ASSERT_MATRIX_OK (Z, "Z for mask phase2", GB0) ;
88 ASSERT (!GB_ZOMBIES (Z)) ;
89 ASSERT (!GB_JUMBLED (Z)) ;
90 ASSERT (!GB_PENDING (Z)) ;
91
92 ASSERT (!GB_IS_BITMAP (C)) ; // not used if C is bitmap
93
94 ASSERT (C->vdim == Z->vdim && C->vlen == Z->vlen) ;
95 ASSERT (C->vdim == M->vdim && C->vlen == M->vlen) ;
96 ASSERT (C->type == Z->type) ;
97
98 ASSERT (R != NULL && R->static_header) ;
99
100 GB_WERK_DECLARE (C_ek_slicing, int64_t) ;
101 GB_WERK_DECLARE (M_ek_slicing, int64_t) ;
102
103 ASSERT (Rp_handle != NULL) ;
104 ASSERT (Rh_handle != NULL) ;
105 int64_t *Rp = (*Rp_handle) ;
106 int64_t *Rh = (*Rh_handle) ;
107
108 //--------------------------------------------------------------------------
109 // allocate the output matrix R
110 //--------------------------------------------------------------------------
111
112 bool R_is_hyper = (R_sparsity == GxB_HYPERSPARSE) ;
113 bool R_is_sparse_or_hyper = (R_sparsity == GxB_SPARSE) || R_is_hyper ;
114 ASSERT (R_is_sparse_or_hyper == (Rp != NULL)) ;
115 ASSERT (R_is_hyper == (Rh != NULL)) ;
116
117 int64_t rnz = (R_is_sparse_or_hyper) ? Rp [Rnvec] : C->vlen*C->vdim ;
118
119 // allocate the result R (but do not allocate R->p or R->h)
120 GrB_Info info = GB_new_bix (&R, true, // any sparsity, static header
121 C->type, C->vlen, C->vdim, GB_Ap_null, R_is_csc,
122 R_sparsity, true, C->hyper_switch, Rnvec, rnz, true, Context) ;
123 if (info != GrB_SUCCESS)
124 {
125 // out of memory; caller must free R_to_M, R_to_C, R_to_Z
126 GB_FREE (Rp_handle, Rp_size) ;
127 GB_FREE (Rh_handle, Rh_size) ;
128 return (info) ;
129 }
130
131 // add Rp as the vector pointers for R, from GB_masker_phase1
132 if (R_is_sparse_or_hyper)
133 {
134 R->nvec_nonempty = Rnvec_nonempty ;
135 R->p = (int64_t *) Rp ; R->p_size = Rp_size ;
136 (*Rp_handle) = NULL ;
137 }
138
139 // add Rh as the hypersparse list for R, from GB_add_phase0
140 if (R_is_hyper)
141 {
142 R->h = (int64_t *) Rh ; R->h_size = Rh_size ;
143 R->nvec = Rnvec ;
144 (*Rh_handle) = NULL ;
145 }
146
147 // now Rp and Rh have been transplanted into R, so they must not be freed.
148 ASSERT ((*Rp_handle) == NULL) ;
149 ASSERT ((*Rh_handle) == NULL) ;
150 R->magic = GB_MAGIC ;
151
152 //--------------------------------------------------------------------------
153 // generic worker
154 //--------------------------------------------------------------------------
155
156 #define GB_PHASE_2_OF_2
157 #include "GB_masker_template.c"
158
159 //--------------------------------------------------------------------------
160 // prune empty vectors from Rh
161 //--------------------------------------------------------------------------
162
163 GB_OK (GB_hypermatrix_prune (R, Context)) ;
164
165 //--------------------------------------------------------------------------
166 // free workspace and return result
167 //--------------------------------------------------------------------------
168
169 // caller must free R_to_M, R_to_C, and R_to_Z, but not Rp or Rh
170 GB_FREE_WORK ;
171 ASSERT_MATRIX_OK (R, "R output for mask phase2", GB0) ;
172 ASSERT (!GB_ZOMBIES (R)) ;
173 ASSERT (!GB_JUMBLED (R)) ;
174 ASSERT (!GB_PENDING (R)) ;
175 return (GrB_SUCCESS) ;
176 }
177
178