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