1 //------------------------------------------------------------------------------
2 // GB_subref.h: definitions for GB_subref_* functions
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_SUBREF_H
11 #define GB_SUBREF_H
12 #include "GB_ij.h"
13 
14 GB_PUBLIC   // accessed by the MATLAB tests in GraphBLAS/Test only
15 GrB_Info GB_subref              // C = A(I,J): either symbolic or numeric
16 (
17     // output
18     GrB_Matrix C,               // output matrix, static header
19     // input, not modified
20     const bool C_is_csc,        // requested format of C
21     const GrB_Matrix A,
22     const GrB_Index *I,         // index list for C = A(I,J), or GrB_ALL, etc.
23     const int64_t ni,           // length of I, or special
24     const GrB_Index *J,         // index list for C = A(I,J), or GrB_ALL, etc.
25     const int64_t nj,           // length of J, or special
26     const bool symbolic,        // if true, construct Cx as symbolic
27 //  const bool must_sort,       // if true, must return C sorted
28     GB_Context Context
29 ) ;
30 
31 GrB_Info GB_subref_phase0
32 (
33     // output
34     int64_t *restrict *p_Ch,         // Ch = C->h hyperlist, or NULL standard
35     size_t *p_Ch_size,
36     int64_t *restrict *p_Ap_start,   // A(:,kA) starts at Ap_start [kC]
37     size_t *p_Ap_start_size,
38     int64_t *restrict *p_Ap_end,     // ... and ends at Ap_end [kC] - 1
39     size_t *p_Ap_end_size,
40     int64_t *p_Cnvec,       // # of vectors in C
41     bool *p_need_qsort,     // true if C must be sorted
42     int *p_Ikind,           // kind of I
43     int64_t *p_nI,          // length of I
44     int64_t Icolon [3],     // for GB_RANGE, GB_STRIDE
45     int64_t *p_nJ,          // length of J
46     // input, not modified
47     const GrB_Matrix A,
48     const GrB_Index *I,     // index list for C = A(I,J), or GrB_ALL, etc.
49     const int64_t ni,       // length of I, or special
50     const GrB_Index *J,     // index list for C = A(I,J), or GrB_ALL, etc.
51     const int64_t nj,       // length of J, or special
52 //  const bool must_sort,   // true if C must be returned sorted
53     GB_Context Context
54 ) ;
55 
56 GrB_Info GB_subref_slice
57 (
58     // output:
59     GB_task_struct **p_TaskList,    // array of structs
60     size_t *p_TaskList_size,        // size of TaskList
61     int *p_ntasks,                  // # of tasks constructed
62     int *p_nthreads,                // # of threads for subref operation
63     bool *p_post_sort,              // true if a final post-sort is needed
64     int64_t *restrict *p_Mark,      // for I inverse, if needed; size avlen
65     size_t *p_Mark_size,
66     int64_t *restrict *p_Inext,     // for I inverse, if needed; size nI
67     size_t *p_Inext_size,
68     int64_t *p_nduplicates,         // # of duplicates, if I inverse computed
69     // from phase0:
70     const int64_t *restrict Ap_start,   // location of A(imin:imax,kA)
71     const int64_t *restrict Ap_end,
72     const int64_t Cnvec,            // # of vectors of C
73     const bool need_qsort,          // true if C must be sorted
74     const int Ikind,                // GB_ALL, GB_RANGE, GB_STRIDE or GB_LIST
75     const int64_t nI,               // length of I
76     const int64_t Icolon [3],       // for GB_RANGE and GB_STRIDE
77     // original input:
78     const int64_t avlen,            // A->vlen
79     const int64_t anz,              // nnz (A)
80     const GrB_Index *I,
81     GB_Context Context
82 ) ;
83 
84 GrB_Info GB_subref_phase1               // count nnz in each C(:,j)
85 (
86     // computed by phase1:
87     int64_t **Cp_handle,                // output of size Cnvec+1
88     size_t *Cp_size_handle,
89     int64_t *Cnvec_nonempty,            // # of non-empty vectors in C
90     // tasks from phase0b:
91     GB_task_struct *restrict TaskList,  // array of structs
92     const int ntasks,                   // # of tasks
93     const int nthreads,                 // # of threads to use
94     const int64_t *Mark,                // for I inverse buckets, size A->vlen
95     const int64_t *Inext,               // for I inverse buckets, size nI
96     const int64_t nduplicates,          // # of duplicates, if I inverted
97     // analysis from phase0:
98     const int64_t *restrict Ap_start,
99     const int64_t *restrict Ap_end,
100     const int64_t Cnvec,
101     const bool need_qsort,
102     const int Ikind,
103     const int64_t nI,
104     const int64_t Icolon [3],
105     // original input:
106     const GrB_Matrix A,
107     const GrB_Index *I,         // index list for C = A(I,J), or GrB_ALL, etc.
108     const bool symbolic,
109     GB_Context Context
110 ) ;
111 
112 GrB_Info GB_subref_phase2   // C=A(I,J)
113 (
114     GrB_Matrix C,               // output matrix, static header
115     // from phase1:
116     int64_t **Cp_handle,        // vector pointers for C
117     size_t Cp_size,
118     const int64_t Cnvec_nonempty,       // # of non-empty vectors in C
119     // from phase0b:
120     const GB_task_struct *restrict TaskList,    // array of structs
121     const int ntasks,                           // # of tasks
122     const int nthreads,                         // # of threads to use
123     const bool post_sort,               // true if post-sort needed
124     const int64_t *Mark,                // for I inverse buckets, size A->vlen
125     const int64_t *Inext,               // for I inverse buckets, size nI
126     const int64_t nduplicates,          // # of duplicates, if I inverted
127     // from phase0:
128     int64_t **Ch_handle,
129     size_t Ch_size,
130     const int64_t *restrict Ap_start,
131     const int64_t *restrict Ap_end,
132     const int64_t Cnvec,
133     const bool need_qsort,
134     const int Ikind,
135     const int64_t nI,
136     const int64_t Icolon [3],
137     const int64_t nJ,
138     // original input:
139     const bool C_is_csc,        // format of output matrix C
140     const GrB_Matrix A,
141     const GrB_Index *I,
142     const bool symbolic,
143     GB_Context Context
144 ) ;
145 
146 GrB_Info GB_I_inverse           // invert the I list for C=A(I,:)
147 (
148     const GrB_Index *I,         // list of indices, duplicates OK
149     int64_t nI,                 // length of I
150     int64_t avlen,              // length of the vectors of A
151     // outputs:
152     int64_t *restrict *p_Mark,  // head pointers for buckets, size avlen
153     size_t *p_Mark_size,
154     int64_t *restrict *p_Inext, // next pointers for buckets, size nI
155     size_t *p_Inext_size,
156     int64_t *p_ndupl,           // number of duplicate entries in I
157     GB_Context Context
158 ) ;
159 
160 //------------------------------------------------------------------------------
161 // GB_subref_method: select a method for C(:,kC) = A(I,kA), for one vector of C
162 //------------------------------------------------------------------------------
163 
164 // Determines the method used for to construct C(:,kC) = A(I,kA) for a
165 // single vector of C and A.
166 
GB_subref_method(int64_t * p_work,bool * p_this_needs_I_inverse,const int64_t ajnz,const int64_t avlen,const int Ikind,const int64_t nI,const bool I_inverse_ok,const bool need_qsort,const int64_t iinc,const int64_t nduplicates)167 static inline int GB_subref_method  // return the method to use (1 to 12)
168 (
169     // output
170     int64_t *p_work,                // work required
171     bool *p_this_needs_I_inverse,   // true if I needs to be inverted
172     // input:
173     const int64_t ajnz,             // nnz (A (:,j))
174     const int64_t avlen,            // A->vlen
175     const int Ikind,                // GB_ALL, GB_RANGE, GB_STRIDE, or GB_LIST
176     const int64_t nI,               // length of I
177     const bool I_inverse_ok,        // true if I is invertable
178     const bool need_qsort,          // true if C(:,k) requires sorting
179     const int64_t iinc,             // increment for GB_STRIDE
180     const int64_t nduplicates       // # of duplicates in I (zero if not known)
181 )
182 {
183 
184     //--------------------------------------------------------------------------
185     // initialize return values
186     //--------------------------------------------------------------------------
187 
188     int method ;            // determined below
189     bool this_needs_I_inverse = false ; // most methods do not need I inverse
190     int64_t work ;          // most methods require O(nnz(A(:,j))) work
191 
192     //--------------------------------------------------------------------------
193     // determine the method to use for C(:,j) = A (I,j)
194     //--------------------------------------------------------------------------
195 
196     if (ajnz == avlen)
197     {
198         // A(:,j) is dense
199         if (Ikind == GB_ALL)
200         {
201             // Case 1: C(:,k) = A(:,j) are both dense
202             method = 1 ;
203             work = nI ;   // ajnz == avlen == nI
204         }
205         else
206         {
207             // Case 2: C(:,k) = A(I,j), where A(:,j) is dense,
208             // for Ikind == GB_RANGE, GB_STRIDE, or GB_LIST
209             method = 2 ;
210             work = nI ;
211         }
212     }
213     else if (nI == 1)
214     {
215         // Case 3: one index
216         method = 3 ;
217         work = 1 ;
218     }
219     else if (Ikind == GB_ALL)
220     {
221         // Case 4: I is ":"
222         method = 4 ;
223         work = ajnz ;
224     }
225     else if (Ikind == GB_RANGE)
226     {
227         // Case 5: C (:,k) = A (ibegin:iend,j)
228         method = 5 ;
229         work = ajnz ;
230     }
231     else if ((Ikind == GB_LIST && !I_inverse_ok) ||  // must do Case 6
232         (64 * nI < ajnz))    // Case 6 faster
233     {
234         // Case 6: nI not large; binary search of A(:,j) for each i in I
235         method = 6 ;
236         work = nI * 64 ;
237     }
238     else if (Ikind == GB_STRIDE)
239     {
240         if (iinc >= 0)
241         {
242             // Case 7: I = ibegin:iinc:iend with iinc >= 0
243             method = 7 ;
244             work = ajnz ;
245         }
246         else if (iinc < -1)
247         {
248             // Case 8: I = ibegin:iinc:iend with iinc < =1
249             method = 8 ;
250             work = ajnz ;
251         }
252         else // iinc == -1
253         {
254             // Case 9: I = ibegin:(-1):iend
255             method = 9 ;
256             work = ajnz ;
257         }
258     }
259     else // Ikind == GB_LIST, and I inverse buckets will be used
260     {
261         // construct the I inverse buckets
262         this_needs_I_inverse = true ;
263         if (need_qsort)
264         {
265             // Case 10: nI large, need qsort
266             // duplicates are possible so cjnz > ajnz can hold.  If fine tasks
267             // use this method, a post sort is needed when all tasks are done.
268             method = 10 ;
269             work = ajnz * 32 ;
270         }
271         else if (nduplicates > 0)
272         {
273             // Case 11: nI large, no qsort, with duplicates
274             // duplicates are possible so cjnz > ajnz can hold.  Note that the
275             // # of duplicates is only known after I is inverted, which might
276             // not yet be done.  In that case, nuplicates is assumed to be
277             // zero, and Case 11 is assumed to be used instead.  This is
278             // revised after I is inverted.
279             method = 11 ;
280             work = ajnz * 2 ;
281         }
282         else
283         {
284             // Case 12: nI large, no qsort, no dupl
285             method = 12 ;
286             work = ajnz ;
287         }
288     }
289 
290     //--------------------------------------------------------------------------
291     // return result
292     //--------------------------------------------------------------------------
293 
294     if (p_work != NULL)
295     {
296         (*p_work) = work ;
297     }
298     if (p_this_needs_I_inverse != NULL)
299     {
300         (*p_this_needs_I_inverse) = this_needs_I_inverse ;
301     }
302     return (method) ;
303 }
304 
305 GrB_Info GB_bitmap_subref       // C = A(I,J): either symbolic or numeric
306 (
307     // output
308     GrB_Matrix C,               // output matrix, static header
309     // input, not modified
310     const bool C_is_csc,        // requested format of C
311     const GrB_Matrix A,
312     const GrB_Index *I,         // index list for C = A(I,J), or GrB_ALL, etc.
313     const int64_t ni,           // length of I, or special
314     const GrB_Index *J,         // index list for C = A(I,J), or GrB_ALL, etc.
315     const int64_t nj,           // length of J, or special
316     const bool symbolic,        // if true, construct C as symbolic
317     GB_Context Context
318 ) ;
319 
320 #endif
321 
322