1 //------------------------------------------------------------------------------
2 // GB_extract: C<M> = accum(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 // Not user-callable.  Implements the user-callable GrB_*_extract functions.
11 
12 // C<M> = accum (C, A (Rows,Cols)) or
13 
14 // C<M> = accum (C, AT(Rows,Cols)) where AT = A'
15 
16 // equivalently:
17 
18 // C<M> = accum (C, A(Rows,Cols) )
19 
20 // C<M> = accum (C, A(Cols,Rows)')
21 
22 #include "GB_extract.h"
23 #include "GB_subref.h"
24 #include "GB_accum_mask.h"
25 
26 #define GB_FREE_ALL ;
27 
GB_extract(GrB_Matrix C,const bool C_replace,const GrB_Matrix M,const bool Mask_comp,const bool Mask_struct,const GrB_BinaryOp accum,const GrB_Matrix A,const bool A_transpose,const GrB_Index * Rows,const GrB_Index nRows_in,const GrB_Index * Cols,const GrB_Index nCols_in,GB_Context Context)28 GrB_Info GB_extract                 // C<M> = accum (C, A(I,J))
29 (
30     GrB_Matrix C,                   // input/output matrix for results
31     const bool C_replace,           // C matrix descriptor
32     const GrB_Matrix M,             // optional mask for C, unused if NULL
33     const bool Mask_comp,           // mask descriptor
34     const bool Mask_struct,         // if true, use the only structure of M
35     const GrB_BinaryOp accum,       // optional accum for Z=accum(C,T)
36     const GrB_Matrix A,             // input matrix
37     const bool A_transpose,         // A matrix descriptor
38     const GrB_Index *Rows,          // row indices
39     const GrB_Index nRows_in,       // number of row indices
40     const GrB_Index *Cols,          // column indices
41     const GrB_Index nCols_in,       // number of column indices
42     GB_Context Context
43 )
44 {
45 
46     //--------------------------------------------------------------------------
47     // check inputs
48     //--------------------------------------------------------------------------
49 
50     // C may be aliased with M and/or A
51 
52     GrB_Info info ;
53     GB_RETURN_IF_NULL (Rows) ;
54     GB_RETURN_IF_NULL (Cols) ;
55     GB_RETURN_IF_FAULTY_OR_POSITIONAL (accum) ;
56 
57     ASSERT_MATRIX_OK (C, "C input for GB_Matrix_extract", GB0) ;
58     ASSERT_MATRIX_OK_OR_NULL (M, "M for GB_Matrix_extract", GB0) ;
59     ASSERT_BINARYOP_OK_OR_NULL (accum, "accum for GB_Matrix_extract", GB0) ;
60     ASSERT_MATRIX_OK (A, "A input for GB_Matrix_extract", GB0) ;
61 
62     // check domains and dimensions for C<M> = accum (C,T)
63     GB_OK (GB_compatible (C->type, C, M, Mask_struct, accum, A->type,
64         Context)) ;
65 
66     // check the dimensions of C
67     int64_t cnrows = GB_NROWS (C) ;
68     int64_t cncols = GB_NCOLS (C) ;
69 
70     int64_t nRows, nCols, RowColon [3], ColColon [3] ;
71     int rkind, ckind ;
72 
73     if (!A_transpose)
74     {
75         // T = A(Rows,Cols)
76         GB_ijlength (Rows, nRows_in, GB_NROWS (A), &nRows, &rkind, RowColon) ;
77         GB_ijlength (Cols, nCols_in, GB_NCOLS (A), &nCols, &ckind, ColColon) ;
78     }
79     else
80     {
81         // T = A(Cols,Rows)
82         GB_ijlength (Rows, nRows_in, GB_NCOLS (A), &nRows, &rkind, RowColon) ;
83         GB_ijlength (Cols, nCols_in, GB_NROWS (A), &nCols, &ckind, ColColon) ;
84     }
85 
86     if (cnrows != nRows || cncols != nCols)
87     {
88         GB_ERROR (GrB_DIMENSION_MISMATCH,
89             "Dimensions not compatible:\n"
90             "required size of output is " GBd "-by-" GBd "\n"
91             "but actual size output is  " GBd "-by-" GBd "\n",
92             nRows, nCols, cnrows, cncols) ;
93     }
94 
95     // quick return if an empty mask is complemented
96     GB_RETURN_IF_QUICK_MASK (C, C_replace, M, Mask_comp, Mask_struct) ;
97 
98     // delete any lingering zombies and assemble any pending tuples
99     GB_MATRIX_WAIT (M) ;        // cannot be jumbled
100     GB_MATRIX_WAIT (A) ;        // cannot be jumbled
101 
102     GB_BURBLE_DENSE (C, "(C %s) ") ;
103     GB_BURBLE_DENSE (M, "(M %s) ") ;
104     GB_BURBLE_DENSE (A, "(A %s) ") ;
105 
106     //--------------------------------------------------------------------------
107     // handle the CSR/CSC format and transpose; T = A (I,J) or T = A (J,I)
108     //--------------------------------------------------------------------------
109 
110     const GrB_Index *I, *J ;
111     int64_t ni, nj ;
112     bool T_is_csc ;
113 
114     if (A->is_csc)
115     {
116         if (!A_transpose)
117         {
118             // T = A(Rows,Cols) where both A and T are in CSC format
119             I = Rows ; ni = nRows_in ;  // indices into the vectors
120             J = Cols ; nj = nCols_in ;  // vectors
121             T_is_csc = true ;           // return T in CSC format
122         }
123         else
124         {
125             // T = A(Cols,Rows) where A is CSC and T is returned as CSR format
126             I = Cols ; ni = nCols_in ;  // indices into the vectors
127             J = Rows ; nj = nRows_in ;  // vectors
128             T_is_csc = false ;          // return T in CSR format
129         }
130     }
131     else
132     {
133         if (!A_transpose)
134         {
135             // T = A(Rows,Cols) where both A and T are in CSR format
136             I = Cols ; ni = nCols_in ;  // indices into the vectors
137             J = Rows ; nj = nRows_in ;  // vectors
138             T_is_csc = false ;          // return T in CSR format
139         }
140         else
141         {
142             // T = A(Cols,Rows) where A is CSR but T is returned as CSC format
143             I = Rows ; ni = nRows_in ;  // indices into the vectors
144             J = Cols ; nj = nCols_in ;  // vectors
145             T_is_csc = true ;           // return T in CSC format
146         }
147     }
148 
149     // T has T->vdim = |J|, each vector of length T->vlen = |J|, regardless of
150     // its CSR/CSC format.
151 
152     // J is a list of length |J| of vectors in the range 0:A->vdim-1
153     // I is a list of length |I| of indices in the range 0:A->vlen-1
154 
155     // |I| and |J| are either nRows or nCols, depending on the 4 cases above.
156 
157     // T has the same hypersparsity as A.
158 
159     //--------------------------------------------------------------------------
160     // T = A (I,J)
161     //--------------------------------------------------------------------------
162 
163     struct GB_Matrix_opaque T_header ;
164     GrB_Matrix T = GB_clear_static_header (&T_header) ;
165     GB_OK (GB_subref (T, T_is_csc, A, I, ni, J, nj, false, Context)) ;
166     ASSERT_MATRIX_OK (T, "T extracted", GB0) ;
167     ASSERT (GB_JUMBLED_OK (T)) ;
168 
169     //--------------------------------------------------------------------------
170     // C<M> = accum (C,T): accumulate the results into C via the mask M
171     //--------------------------------------------------------------------------
172 
173     return (GB_accum_mask (C, M, NULL, accum, &T, C_replace, Mask_comp,
174         Mask_struct, Context)) ;
175 }
176 
177