1 //------------------------------------------------------------------------------
2 // GB_extractTuples: extract all the tuples from a matrix
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 // Extracts all tuples from a matrix, like [I,J,X] = find (A). If any
11 // parameter I, J and/or X is NULL, then that component is not extracted. The
12 // size of the I, J, and X arrays (those that are not NULL) is given by nvals,
13 // which must be at least as large as GrB_nvals (&nvals, A). The values in the
14 // matrix are typecasted to the type of X, as needed.
15
16 // This function does the work for the user-callable GrB_*_extractTuples
17 // functions.
18
19 #include "GB.h"
20
21 #define GB_FREE_ALL \
22 { \
23 GB_FREE_WERK (&Ap, Ap_size) ; \
24 GB_FREE_WERK (&X_bitmap, X_bitmap_size) ; \
25 }
26
GB_extractTuples(GrB_Index * I_out,GrB_Index * J_out,void * X,GrB_Index * p_nvals,const GB_Type_code xcode,const GrB_Matrix A,GB_Context Context)27 GrB_Info GB_extractTuples // extract all tuples from a matrix
28 (
29 GrB_Index *I_out, // array for returning row indices of tuples
30 GrB_Index *J_out, // array for returning col indices of tuples
31 void *X, // array for returning values of tuples
32 GrB_Index *p_nvals, // I,J,X size on input; # tuples on output
33 const GB_Type_code xcode, // type of array X
34 const GrB_Matrix A, // matrix to extract tuples from
35 GB_Context Context
36 )
37 {
38
39 //--------------------------------------------------------------------------
40 // check inputs
41 //--------------------------------------------------------------------------
42
43 GrB_Info info ;
44 GB_void *restrict X_bitmap = NULL ; size_t X_bitmap_size = 0 ;
45 int64_t *restrict Ap = NULL ; size_t Ap_size = 0 ;
46
47 ASSERT_MATRIX_OK (A, "A to extract", GB0) ;
48 ASSERT (p_nvals != NULL) ;
49
50 // delete any lingering zombies and assemble any pending tuples;
51 // allow A to remain jumbled
52 GB_MATRIX_WAIT_IF_PENDING_OR_ZOMBIES (A) ;
53
54 GB_BURBLE_DENSE (A, "(A %s) ") ;
55 ASSERT (xcode <= GB_UDT_code) ;
56 const GB_Type_code acode = A->type->code ;
57
58 // xcode and A must be compatible
59 if (!GB_code_compatible (xcode, acode))
60 {
61 return (GrB_DOMAIN_MISMATCH) ;
62 }
63
64 const int64_t anz = GB_NNZ (A) ;
65 if (anz == 0)
66 {
67 // no work to do
68 (*p_nvals) = 0 ;
69 return (GrB_SUCCESS) ;
70 }
71
72 int64_t nvals = *p_nvals ; // size of I,J,X on input
73
74 if (nvals < anz && (I_out != NULL || J_out != NULL || X != NULL))
75 {
76 // output arrays are not big enough
77 return (GrB_INSUFFICIENT_SPACE) ;
78 }
79
80 const size_t asize = A->type->size ;
81
82 //-------------------------------------------------------------------------
83 // determine the number of threads to use
84 //-------------------------------------------------------------------------
85
86 GB_GET_NTHREADS_MAX (nthreads_max, chunk, Context) ;
87 int nthreads = GB_nthreads (anz + A->nvec, chunk, nthreads_max) ;
88
89 //-------------------------------------------------------------------------
90 // handle the CSR/CSC format
91 //--------------------------------------------------------------------------
92
93 GrB_Index *I, *J ;
94 if (A->is_csc)
95 {
96 I = I_out ;
97 J = J_out ;
98 }
99 else
100 {
101 I = J_out ;
102 J = I_out ;
103 }
104
105 //--------------------------------------------------------------------------
106 // bitmap case
107 //--------------------------------------------------------------------------
108
109 if (GB_IS_BITMAP (A))
110 {
111
112 //----------------------------------------------------------------------
113 // allocate workspace
114 //----------------------------------------------------------------------
115
116 bool need_typecast = (X != NULL) && (xcode != acode) ;
117 if (need_typecast)
118 {
119 // X must be typecasted
120 int64_t anzmax = GB_IMAX (anz, 1) ;
121 X_bitmap = GB_MALLOC_WERK (anzmax*asize, GB_void, &X_bitmap_size) ;
122 }
123 Ap = GB_MALLOC_WERK (A->vdim+1, int64_t, &Ap_size) ;
124 if (Ap == NULL || (need_typecast && X_bitmap == NULL))
125 {
126 // out of memory
127 GB_FREE_ALL ;
128 return (GrB_OUT_OF_MEMORY) ;
129 }
130
131 //----------------------------------------------------------------------
132 // extract the tuples
133 //----------------------------------------------------------------------
134
135 // TODO: pass xcode to GB_convert_bitmap_worker and let it do the
136 // typecasting. This works for now, however.
137
138 GB_OK (GB_convert_bitmap_worker (Ap, (int64_t *) I, (int64_t *) J,
139 (GB_void *) (need_typecast ? X_bitmap : X), NULL, A, Context)) ;
140
141 //----------------------------------------------------------------------
142 // typecast the result if needed
143 //----------------------------------------------------------------------
144
145 if (need_typecast)
146 {
147 // typecast the values from X_bitmap into X
148 GB_cast_array ((GB_void *) X, xcode, X_bitmap,
149 acode, NULL, asize, anz, nthreads) ;
150 }
151
152 }
153 else
154 {
155
156 //----------------------------------------------------------------------
157 // sparse, hypersparse, or full case
158 //----------------------------------------------------------------------
159
160 //----------------------------------------------------------------------
161 // extract the row indices
162 //----------------------------------------------------------------------
163
164 if (I != NULL)
165 {
166 if (A->i == NULL)
167 {
168 // A is full; construct the row indices
169 int64_t avlen = A->vlen ;
170 int64_t p ;
171 #pragma omp parallel for num_threads(nthreads) schedule(static)
172 for (p = 0 ; p < anz ; p++)
173 {
174 I [p] = (p % avlen) ;
175 }
176 }
177 else
178 {
179 GB_memcpy (I, A->i, anz * sizeof (int64_t), nthreads) ;
180 }
181 }
182
183 //----------------------------------------------------------------------
184 // extract the column indices
185 //----------------------------------------------------------------------
186
187 if (J != NULL)
188 {
189 GB_OK (GB_extract_vector_list ((int64_t *) J, A, Context)) ;
190 }
191
192 //----------------------------------------------------------------------
193 // extract the values
194 //----------------------------------------------------------------------
195
196 if (X != NULL)
197 {
198 // typecast or copy the values from A into X
199 GB_cast_array ((GB_void *) X, xcode, (GB_void *) A->x,
200 acode, NULL, asize, anz, nthreads) ;
201 }
202 }
203
204 //--------------------------------------------------------------------------
205 // free workspace and return result
206 //--------------------------------------------------------------------------
207
208 *p_nvals = anz ; // number of tuples extracted
209 GB_FREE_ALL ;
210 return (GrB_SUCCESS) ;
211 }
212
213