1 //------------------------------------------------------------------------------
2 // GB_subref_phase2: C=A(I,J)
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 // This function either frees Cp and Ch, or transplants then into C, as C->p
11 // and C->h.  Either way, the caller must not free them.
12 
13 #include "GB_subref.h"
14 #include "GB_sort.h"
15 
GB_subref_phase2(GrB_Matrix C,int64_t ** Cp_handle,size_t Cp_size,const int64_t Cnvec_nonempty,const GB_task_struct * restrict TaskList,const int ntasks,const int nthreads,const bool post_sort,const int64_t * Mark,const int64_t * Inext,const int64_t nduplicates,int64_t ** Ch_handle,size_t Ch_size,const int64_t * restrict Ap_start,const int64_t * restrict Ap_end,const int64_t Cnvec,const bool need_qsort,const int Ikind,const int64_t nI,const int64_t Icolon[3],const int64_t nJ,const bool C_is_csc,const GrB_Matrix A,const GrB_Index * I,const bool symbolic,GB_Context Context)16 GrB_Info GB_subref_phase2   // C=A(I,J)
17 (
18     GrB_Matrix C,               // output matrix, static header
19     // from phase1:
20     int64_t **Cp_handle,        // vector pointers for C
21     size_t Cp_size,
22     const int64_t Cnvec_nonempty,       // # of non-empty vectors in C
23     // from phase0b:
24     const GB_task_struct *restrict TaskList,    // array of structs
25     const int ntasks,                           // # of tasks
26     const int nthreads,                         // # of threads to use
27     const bool post_sort,               // true if post-sort needed
28     const int64_t *Mark,                // for I inverse buckets, size A->vlen
29     const int64_t *Inext,               // for I inverse buckets, size nI
30     const int64_t nduplicates,          // # of duplicates, if I inverted
31     // from phase0:
32     int64_t **Ch_handle,
33     size_t Ch_size,
34     const int64_t *restrict Ap_start,
35     const int64_t *restrict Ap_end,
36     const int64_t Cnvec,
37     const bool need_qsort,
38     const int Ikind,
39     const int64_t nI,
40     const int64_t Icolon [3],
41     const int64_t nJ,
42     // original input:
43     const bool C_is_csc,        // format of output matrix C
44     const GrB_Matrix A,
45     const GrB_Index *I,
46     const bool symbolic,
47     GB_Context Context
48 )
49 {
50 
51     //--------------------------------------------------------------------------
52     // check inputs
53     //--------------------------------------------------------------------------
54 
55     ASSERT (C != NULL && C->static_header) ;
56     ASSERT (Cp_handle != NULL) ;
57     ASSERT (Ch_handle != NULL) ;
58     const int64_t *restrict Ch = (*Ch_handle) ;
59     const int64_t *restrict Cp = (*Cp_handle) ;
60     ASSERT (Cp != NULL) ;
61     ASSERT_MATRIX_OK (A, "A for subref phase2", GB0) ;
62     ASSERT (!GB_IS_BITMAP (A)) ;    // GB_bitmap_subref is used instead
63 
64     //--------------------------------------------------------------------------
65     // allocate the output matrix C
66     //--------------------------------------------------------------------------
67 
68     int64_t cnz = Cp [Cnvec] ;
69 
70     bool C_is_hyper = (Ch != NULL) ;
71 
72     GrB_Type ctype = (symbolic) ? GrB_INT64 : A->type ;
73 
74     // allocate the result C (but do not allocate C->p or C->h)
75     int sparsity = C_is_hyper ? GxB_HYPERSPARSE : GxB_SPARSE ;
76     GrB_Info info = GB_new_bix (&C, true, // sparse or hyper, static header
77         ctype, nI, nJ, GB_Ap_null, C_is_csc,
78         sparsity, true, A->hyper_switch, Cnvec, cnz, true, Context) ;
79     if (info != GrB_SUCCESS)
80     {
81         // out of memory
82         GB_FREE (Cp_handle, Cp_size) ;
83         GB_FREE (Ch_handle, Ch_size) ;
84         return (info) ;
85     }
86 
87     // add Cp as the vector pointers for C, from GB_subref_phase1
88     C->p = (int64_t *) Cp ; C->p_size = Cp_size ;
89     (*Cp_handle) = NULL ;
90 
91     // add Ch as the hypersparse list for C, from GB_subref_phase0
92     if (C_is_hyper)
93     {
94         // transplant Ch into C
95         C->h = (int64_t *) Ch ; C->h_size = Ch_size ;
96         (*Ch_handle) = NULL ;
97         C->nvec = Cnvec ;
98     }
99 
100     // now Cp and Ch have been transplanted into C, so they must not be freed.
101     ASSERT ((*Cp_handle) == NULL) ;
102     ASSERT ((*Ch_handle) == NULL) ;
103     C->nvec_nonempty = Cnvec_nonempty ;
104     C->magic = GB_MAGIC ;
105 
106     //--------------------------------------------------------------------------
107     // phase2: C = A(I,J)
108     //--------------------------------------------------------------------------
109 
110     #define GB_PHASE_2_OF_2
111     if (symbolic)
112     {
113         #define GB_SYMBOLIC
114         #include "GB_subref_template.c"
115         #undef  GB_SYMBOLIC
116     }
117     else
118     {
119         #define GB_NUMERIC
120         #include "GB_subref_template.c"
121         #undef  GB_NUMERIC
122     }
123 
124     //--------------------------------------------------------------------------
125     // remove empty vectors from C, if hypersparse
126     //--------------------------------------------------------------------------
127 
128     info = GB_hypermatrix_prune (C, Context) ;
129     if (info != GrB_SUCCESS)
130     {
131         // out of memory
132         GB_phbix_free (C) ;
133         return (info) ;
134     }
135 
136     //--------------------------------------------------------------------------
137     // return result
138     //--------------------------------------------------------------------------
139 
140     // caller must not free Cp or Ch
141     ASSERT_MATRIX_OK (C, "C output for subref phase2", GB0) ;
142     return (GrB_SUCCESS) ;
143 }
144 
145