1 //------------------------------------------------------------------------------
2 // GB_bitmap_subref: C = A(I,J) where A is bitmap or full
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 // C=A(I,J), where A is bitmap or full, symbolic and numeric.
11 // See GB_subref for details.
12 
13 #include "GB_subref.h"
14 #include "GB_subassign_IxJ_slice.h"
15 
16 #define GB_FREE_ALL             \
17 {                               \
18     GB_phbix_free (C) ;       \
19 }
20 
GB_bitmap_subref(GrB_Matrix C,const bool C_is_csc,const GrB_Matrix A,const GrB_Index * I,const int64_t ni,const GrB_Index * J,const int64_t nj,const bool symbolic,GB_Context Context)21 GrB_Info GB_bitmap_subref       // C = A(I,J): either symbolic or numeric
22 (
23     // output
24     GrB_Matrix C,               // output matrix, static header
25     // input, not modified
26     const bool C_is_csc,        // requested format of C
27     const GrB_Matrix A,
28     const GrB_Index *I,         // index list for C = A(I,J), or GrB_ALL, etc.
29     const int64_t ni,           // length of I, or special
30     const GrB_Index *J,         // index list for C = A(I,J), or GrB_ALL, etc.
31     const int64_t nj,           // length of J, or special
32     const bool symbolic,        // if true, construct C as symbolic
33     GB_Context Context
34 )
35 {
36 
37     //--------------------------------------------------------------------------
38     // check inputs
39     //--------------------------------------------------------------------------
40 
41     GrB_Info info ;
42     ASSERT (C != NULL && C->static_header) ;
43     ASSERT_MATRIX_OK (A, "A for C=A(I,J) bitmap subref", GB0) ;
44     ASSERT (GB_IS_BITMAP (A) || GB_IS_FULL (A)) ;
45     ASSERT (!GB_IS_SPARSE (A)) ;
46     ASSERT (!GB_IS_HYPERSPARSE (A)) ;
47     ASSERT (!GB_ZOMBIES (A)) ;
48     ASSERT (!GB_JUMBLED (A)) ;
49     ASSERT (!GB_PENDING (A)) ;
50 
51     //--------------------------------------------------------------------------
52     // get A
53     //--------------------------------------------------------------------------
54 
55     const int8_t  *restrict Ab = A->b ;
56     const GB_void *restrict Ax = (GB_void *) A->x ;
57     const int64_t avlen = A->vlen ;
58     const int64_t avdim = A->vdim ;
59     const size_t asize = A->type->size ;
60 
61     //--------------------------------------------------------------------------
62     // check the properties of I and J
63     //--------------------------------------------------------------------------
64 
65     // C = A(I,J) so I is in range 0:avlen-1 and J is in range 0:avdim-1
66     int64_t nI, nJ, Icolon [3], Jcolon [3] ;
67     int Ikind, Jkind ;
68     GB_ijlength (I, ni, avlen, &nI, &Ikind, Icolon) ;
69     GB_ijlength (J, nj, avdim, &nJ, &Jkind, Jcolon) ;
70 
71     bool I_unsorted, I_has_dupl, I_contig, J_unsorted, J_has_dupl, J_contig ;
72     int64_t imin, imax, jmin, jmax ;
73 
74     info = GB_ijproperties (I, ni, nI, avlen, &Ikind, Icolon,
75         &I_unsorted, &I_has_dupl, &I_contig, &imin, &imax, Context) ;
76     if (info != GrB_SUCCESS)
77     {
78         // I invalid
79         return (info) ;
80     }
81 
82     info = GB_ijproperties (J, nj, nJ, avdim, &Jkind, Jcolon,
83         &J_unsorted, &J_has_dupl, &J_contig, &jmin, &jmax, Context) ;
84     if (info != GrB_SUCCESS)
85     {
86         // J invalid
87         return (info) ;
88     }
89 
90     //--------------------------------------------------------------------------
91     // allocate C
92     //--------------------------------------------------------------------------
93 
94     int64_t cnzmax ;
95     bool ok = GB_Index_multiply ((GrB_Index *) (&cnzmax), nI, nJ) ;
96     if (!ok)
97     {
98         // problem too large
99         return (GrB_OUT_OF_MEMORY) ;
100     }
101     GrB_Type ctype = symbolic ? GrB_INT64 : A->type ;
102     int sparsity = GB_IS_BITMAP (A) ? GxB_BITMAP : GxB_FULL ;
103     GB_OK (GB_new_bix (&C, true, // bitmap or full, static header
104         ctype, nI, nJ, GB_Ap_null, C_is_csc,
105         sparsity, true, A->hyper_switch, -1, cnzmax, true, Context)) ;
106 
107     //--------------------------------------------------------------------------
108     // get C
109     //--------------------------------------------------------------------------
110 
111     int8_t *restrict Cb = C->b ;
112 
113     // In GB_bitmap_assign_IxJ_template, vlen is the vector length of the
114     // submatrix C(I,J), but here the template is used to access A(I,J), and so
115     // the vector length is A->vlen, not C->vlen.  The pointers pA and pC are
116     // swapped in the macros below, since C=A(I,J) is being computed, instead
117     // of C(I,J)=A for the bitmap assignment.
118 
119     int64_t vlen = avlen ;
120 
121     //--------------------------------------------------------------------------
122     // C = A(I,J)
123     //--------------------------------------------------------------------------
124 
125     int64_t cnvals = 0 ;
126 
127     if (sparsity == GxB_BITMAP)
128     {
129 
130         //----------------------------------------------------------------------
131         // C = A (I,J) where A and C are both bitmap
132         //----------------------------------------------------------------------
133 
134         // symbolic subref is only used by GB_subassign_symbolic, which only
135         // operates on a matrix that is hypersparse, sparse, or full, but not
136         // bitmap.  As a result, the symbolic subref C=A(I,J) where both A and
137         // C are bitmap is not needed.  The code is left here in case it is
138         // needed in the future.
139 
140         ASSERT (!symbolic) ;
141 
142 #if 0
143         if (symbolic)
144         {
145             // C=A(I,J) symbolic with A and C bitmap
146             ASSERT (GB_DEAD_CODE) ;
147             int64_t *restrict Cx = (int64_t *) C->x ;
148             #undef  GB_IXJ_WORK
149             #define GB_IXJ_WORK(pA,pC)                                      \
150             {                                                               \
151                 int8_t ab = Ab [pA] ;                                       \
152                 Cb [pC] = ab ;                                              \
153                 Cx [pC] = pA ;                                              \
154                 task_cnvals += ab ;                                         \
155             }
156             #include "GB_bitmap_assign_IxJ_template.c"
157         }
158         else
159 #endif
160         {
161             // C=A(I,J) numeric with A and C bitmap
162             GB_void *restrict Cx = (GB_void *) C->x ;
163             #undef  GB_IXJ_WORK
164             #define GB_IXJ_WORK(pA,pC)                                      \
165             {                                                               \
166                 int8_t ab = Ab [pA] ;                                       \
167                 Cb [pC] = ab ;                                              \
168                 if (ab)                                                     \
169                 {                                                           \
170                     /* Cx [pC] = Ax [pA] */                                 \
171                     memcpy (Cx +((pC)*asize), Ax +((pA)*asize), asize) ;    \
172                     task_cnvals++ ;                                         \
173                 }                                                           \
174             }
175             #include "GB_bitmap_assign_IxJ_template.c"
176         }
177         C->nvals = cnvals ;
178 
179     }
180     else
181     {
182 
183         //----------------------------------------------------------------------
184         // C = A (I,J) where A and C are both full
185         //----------------------------------------------------------------------
186 
187         if (symbolic)
188         {
189             // C=A(I,J) symbolic with A and C full (from GB_subassign_symbolic)
190             int64_t *restrict Cx = (int64_t *) C->x ;
191             #undef  GB_IXJ_WORK
192             #define GB_IXJ_WORK(pA,pC)                                      \
193             {                                                               \
194                 Cx [pC] = pA ;                                              \
195             }
196             #include "GB_bitmap_assign_IxJ_template.c"
197         }
198         else
199         {
200             // C=A(I,J) numeric with A and C full
201             GB_void *restrict Cx = (GB_void *) C->x ;
202             #undef  GB_IXJ_WORK
203             #define GB_IXJ_WORK(pA,pC)                                      \
204             {                                                               \
205                 /* Cx [pC] = Ax [pA] */                                     \
206                 memcpy (Cx +((pC)*asize), Ax +((pA)*asize), asize) ;        \
207             }
208             #include "GB_bitmap_assign_IxJ_template.c"
209         }
210     }
211 
212     //--------------------------------------------------------------------------
213     // return result
214     //--------------------------------------------------------------------------
215 
216     C->magic = GB_MAGIC ;
217     ASSERT_MATRIX_OK (C, "C output for bitmap subref C=A(I,J)", GB0) ;
218     return (GrB_SUCCESS) ;
219 }
220 
221