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