1 //------------------------------------------------------------------------------
2 // GB_convert.h: converting between sparsity structures
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 #ifndef GB_CONVERT_H
11 #define GB_CONVERT_H
12 
13 // these parameters define the hyper_switch needed to ensure matrix stays
14 // either always hypersparse, or never hypersparse.
15 #define GB_ALWAYS_HYPER (1.0)
16 #define GB_NEVER_HYPER  (-1.0)
17 
18 // true if A is bitmap
19 #define GB_IS_BITMAP(A) ((A) != NULL && ((A)->b != NULL))
20 
21 // true if A is full (but not bitmap)
22 #define GB_IS_FULL(A) \
23     ((A) != NULL && (A)->h == NULL && (A)->p == NULL && (A)->i == NULL \
24         && (A)->b == NULL)
25 
26 // true if A is hypersparse
27 #define GB_IS_HYPERSPARSE(A) ((A) != NULL && ((A)->h != NULL))
28 
29 // true if A is sparse (but not hypersparse)
30 #define GB_IS_SPARSE(A) ((A) != NULL && ((A)->h == NULL) && (A)->p != NULL)
31 
32 // determine the sparsity control for a matrix
33 int GB_sparsity_control     // revised sparsity
34 (
35     int sparsity,           // sparsity control
36     int64_t vdim            // A->vdim, or -1 to ignore this condition
37 ) ;
38 
39 // GB_sparsity: determine the current sparsity status of a matrix
GB_sparsity(GrB_Matrix A)40 static inline int GB_sparsity (GrB_Matrix A)
41 {
42     if (A == NULL)
43     {
44         // if A is NULL, pretend it is sparse
45         return (GxB_SPARSE) ;
46     }
47     else if (GB_IS_HYPERSPARSE (A))
48     {
49         return (GxB_HYPERSPARSE) ;
50     }
51     else if (GB_IS_FULL (A))
52     {
53         return (GxB_FULL) ;
54     }
55     else if (GB_IS_BITMAP (A))
56     {
57         return (GxB_BITMAP) ;
58     }
59     else
60     {
61         return (GxB_SPARSE) ;
62     }
63 }
64 
65 GB_PUBLIC   // accessed by the MATLAB tests in GraphBLAS/Test only
66 GrB_Info GB_convert_hyper_to_sparse // convert hypersparse to sparse
67 (
68     GrB_Matrix A,           // matrix to convert from hypersparse to sparse
69     GB_Context Context
70 ) ;
71 
72 GB_PUBLIC   // accessed by the MATLAB tests in GraphBLAS/Test only
73 GrB_Info GB_convert_sparse_to_hyper // convert from sparse to hypersparse
74 (
75     GrB_Matrix A,           // matrix to convert to hypersparse
76     GB_Context Context
77 ) ;
78 
79 bool GB_convert_hyper_to_sparse_test    // test for hypersparse to sparse
80 (
81     float hyper_switch,     // A->hyper_switch
82     int64_t k,              // # of non-empty vectors of A (an estimate is OK)
83     int64_t vdim            // A->vdim
84 ) ;
85 
86 bool GB_convert_sparse_to_hyper_test  // test sparse to hypersparse conversion
87 (
88     float hyper_switch,     // A->hyper_switch
89     int64_t k,              // # of non-empty vectors of A (an estimate is OK)
90     int64_t vdim            // A->vdim
91 ) ;
92 
93 bool GB_convert_bitmap_to_sparse_test    // test for hyper/sparse to bitmap
94 (
95     float bitmap_switch,    // A->bitmap_switch
96     int64_t anz,            // # of entries in A = GB_NNZ (A)
97     int64_t vlen,           // A->vlen
98     int64_t vdim            // A->vdim
99 ) ;
100 
101 bool GB_convert_sparse_to_bitmap_test    // test for hyper/sparse to bitmap
102 (
103     float bitmap_switch,    // A->bitmap_switch
104     int64_t anz,            // # of entries in A = GB_NNZ (A)
105     int64_t vlen,           // A->vlen
106     int64_t vdim            // A->vdim
107 ) ;
108 
109 GrB_Info GB_convert_full_to_sparse      // convert matrix from full to sparse
110 (
111     GrB_Matrix A,               // matrix to convert from full to sparse
112     GB_Context Context
113 ) ;
114 
115 GrB_Info GB_convert_full_to_bitmap      // convert matrix from full to bitmap
116 (
117     GrB_Matrix A,               // matrix to convert from full to bitmap
118     GB_Context Context
119 ) ;
120 
121 GrB_Info GB_convert_sparse_to_bitmap    // convert sparse/hypersparse to bitmap
122 (
123     GrB_Matrix A,               // matrix to convert from sparse to bitmap
124     GB_Context Context
125 ) ;
126 
127 GrB_Info GB_convert_bitmap_to_sparse    // convert matrix from bitmap to sparse
128 (
129     GrB_Matrix A,               // matrix to convert from bitmap to sparse
130     GB_Context Context
131 ) ;
132 
133 GrB_Info GB_convert_bitmap_worker   // extract CSC/CSR or triplets from bitmap
134 (
135     // outputs:
136     int64_t *restrict Ap,        // vector pointers for CSC/CSR form
137     int64_t *restrict Ai,        // indices for CSC/CSR or triplet form
138     int64_t *restrict Aj,        // vector indices for triplet form
139     GB_void *restrict Ax_new,    // values for CSC/CSR or triplet form
140     int64_t *anvec_nonempty,        // # of non-empty vectors
141     // inputs: not modified
142     const GrB_Matrix A,             // matrix to extract; not modified
143     GB_Context Context
144 ) ;
145 
146 GrB_Info GB_convert_to_full     // convert matrix to full; delete prior values
147 (
148     GrB_Matrix A                // matrix to convert to full
149 ) ;
150 
151 GrB_Info GB_convert_any_to_bitmap   // convert to bitmap
152 (
153     GrB_Matrix A,           // matrix to convert to bitmap
154     GB_Context Context
155 ) ;
156 
157 GB_PUBLIC                       // used by MATLAB interface
158 void GB_convert_any_to_full     // convert any matrix to full
159 (
160     GrB_Matrix A                // matrix to convert to full
161 ) ;
162 
163 GrB_Info GB_convert_any_to_hyper // convert to hypersparse
164 (
165     GrB_Matrix A,           // matrix to convert to hypersparse
166     GB_Context Context
167 ) ;
168 
169 GrB_Info GB_convert_any_to_sparse // convert to sparse
170 (
171     GrB_Matrix A,           // matrix to convert to sparse
172     GB_Context Context
173 ) ;
174 
175 GrB_Info GB_convert_to_nonfull      // ensure a matrix is not full
176 (
177     GrB_Matrix A,
178     GB_Context Context
179 ) ;
180 
181 /* ensure C is sparse or hypersparse */
182 #define GB_ENSURE_SPARSE(C)                                 \
183 {                                                           \
184     if (GB_IS_BITMAP (C))                                   \
185     {                                                       \
186         /* convert C from bitmap to sparse */               \
187         GB_OK (GB_convert_bitmap_to_sparse (C, Context)) ;  \
188     }                                                       \
189     else if (GB_IS_FULL (C))                                \
190     {                                                       \
191         /* convert C from full to sparse */                 \
192         GB_OK (GB_convert_full_to_sparse (C, Context)) ;    \
193     }                                                       \
194 }
195 
196 #define GB_ENSURE_FULL(C)                                       \
197 {                                                               \
198     ASSERT (GB_is_dense (C)) ;                                  \
199     if (GB_sparsity_control (C->sparsity, C->vdim) & GxB_FULL)  \
200     {                                                           \
201         /* convert C from any structure to full, */             \
202         /* if permitted by C->sparsity */                       \
203         GB_convert_any_to_full (C) ;                            \
204     }                                                           \
205 }
206 
207 //------------------------------------------------------------------------------
208 // GB_is_dense
209 //------------------------------------------------------------------------------
210 
GB_is_dense(const GrB_Matrix A)211 static inline bool GB_is_dense
212 (
213     const GrB_Matrix A
214 )
215 {
216     // check if A is competely dense:  all entries present.
217     // zombies, pending tuples, and jumbled status are not considered.
218     // A can have any sparsity structure: hyper, sparse, bitmap, or full.
219     // It can be converted to full, if zombies/tuples/jumbled are discarded.
220     if (A == NULL)
221     {
222         return (false) ;
223     }
224     if (GB_IS_FULL (A))
225     {
226         // A is full; the pattern is not present
227         return (true) ;
228     }
229     // A is sparse, hyper, or bitmap: check if all entries present
230     GrB_Index anzmax ;
231     bool ok = GB_Index_multiply (&anzmax, A->vlen, A->vdim) ;
232     return (ok && (anzmax == GB_NNZ (A))) ;
233 }
234 
235 //------------------------------------------------------------------------------
236 // GB_as_if_full
237 //------------------------------------------------------------------------------
238 
GB_as_if_full(const GrB_Matrix A)239 static inline bool GB_as_if_full
240 (
241     const GrB_Matrix A
242 )
243 {
244     // check if A is competely dense:  all entries present.
245     // zombies, pending tuples, and jumbled status are checked.
246     // A can have any sparsity structure: hyper, sparse, bitmap, or full.
247     // It can be converted to full.
248     if (A == NULL)
249     {
250         return (false) ;
251     }
252     if (GB_IS_FULL (A))
253     {
254         // A is full; the pattern is not present
255         return (true) ;
256     }
257     if (GB_ANY_PENDING_WORK (A))
258     {
259         // A has pending work and so cannot be treated as if full.
260         return (false) ;
261     }
262     // A is sparse, hyper, or bitmap: check if all entries present
263     GrB_Index anzmax ;
264     bool ok = GB_Index_multiply (&anzmax, A->vlen, A->vdim) ;
265     return (ok && (anzmax == GB_NNZ (A))) ;
266 }
267 
268 //------------------------------------------------------------------------------
269 // GB_is_packed
270 //------------------------------------------------------------------------------
271 
GB_is_packed(const GrB_Matrix A)272 static inline bool GB_is_packed
273 (
274     const GrB_Matrix A
275 )
276 {
277     // check if A is a packed matrix.  A is packed if it is bitmap or full.  If
278     // A is hypersparse or sparse, it is packed if it is not jumbled, all
279     // entries are present, and it has no zombies or pending tuples.
280     // If A is sparse or hypersparse, it can be converted to full via
281     // GB_convert_any_to_full, by deleting A->p, A->h, and A->i.  If bitmap,
282     // it cannot be converted to full unless GB_is_dense (A) is also true
283     // (it must have all entries present).
284 
285     return (GB_IS_BITMAP (A) || GB_as_if_full (A)) ;
286 }
287 
288 //------------------------------------------------------------------------------
289 
290 GrB_Info GB_conform     // conform a matrix to its desired sparsity structure
291 (
292     GrB_Matrix A,       // matrix to conform
293     GB_Context Context
294 ) ;
295 
GB_sparsity_char(int sparsity)296 static inline char *GB_sparsity_char (int sparsity)
297 {
298     switch (sparsity)
299     {
300         case GxB_HYPERSPARSE: return ("H") ;
301         case GxB_SPARSE:      return ("S") ;
302         case GxB_BITMAP:      return ("B") ;
303         case GxB_FULL:        return ("F") ;
304         default: ASSERT (0) ; return ("?") ;
305     }
306 }
307 
GB_sparsity_char_matrix(GrB_Matrix A)308 static inline const char *GB_sparsity_char_matrix (GrB_Matrix A)
309 {
310     bool A_as_if_full = GB_as_if_full (A) ;
311     if (A == NULL)             return (".") ;
312     if (GB_IS_HYPERSPARSE (A)) return (A_as_if_full ? "Hf" : "H") ;
313     if (GB_IS_SPARSE (A))      return (A_as_if_full ? "Sf" : "S") ;
314     if (GB_IS_BITMAP (A))      return (A_as_if_full ? "Bf" : "B") ;
315     if (GB_IS_FULL (A))        return ("F") ;
316     ASSERT (0) ;               return ("?") ;
317 }
318 
319 GrB_Matrix GB_hyper_pack            // return C
320 (
321     GrB_Matrix C,                   // output matrix
322     const GrB_Matrix A              // input matrix
323 ) ;
324 
325 #endif
326 
327