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