1 //------------------------------------------------------------------------------
2 // GB_concat_full: concatenate an array of matrices into a full matrix
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 #define GB_FREE_WORK        \
11     GB_phbix_free (T) ;
12 
13 #define GB_FREE_ALL         \
14     GB_FREE_WORK ;          \
15     GB_phbix_free (C) ;
16 
17 #include "GB_concat.h"
18 
GB_concat_full(GrB_Matrix C,const GrB_Matrix * Tiles,const GrB_Index m,const GrB_Index n,const int64_t * restrict Tile_rows,const int64_t * restrict Tile_cols,GB_Context Context)19 GrB_Info GB_concat_full             // concatenate into a full matrix
20 (
21     GrB_Matrix C,                   // input/output matrix for results
22     const GrB_Matrix *Tiles,        // 2D row-major array of size m-by-n,
23     const GrB_Index m,
24     const GrB_Index n,
25     const int64_t *restrict Tile_rows,  // size m+1
26     const int64_t *restrict Tile_cols,  // size n+1
27     GB_Context Context
28 )
29 {
30 
31     //--------------------------------------------------------------------------
32     // allocate C as a full matrix
33     //--------------------------------------------------------------------------
34 
35     GrB_Info info ;
36     GrB_Matrix A = NULL ;
37     struct GB_Matrix_opaque T_header ;
38     GrB_Matrix T = GB_clear_static_header (&T_header) ;
39 
40     GrB_Type ctype = C->type ;
41     int64_t cvlen = C->vlen ;
42     int64_t cvdim = C->vdim ;
43     bool csc = C->is_csc ;
44     size_t csize = ctype->size ;
45     GB_Type_code ccode = ctype->code ;
46     if (!GB_IS_FULL (C))
47     {
48         GB_phbix_free (C) ;
49         GB_OK (GB_bix_alloc (C, cvlen * cvdim, false, false, false, true,
50             Context)) ;
51         C->plen = -1 ;
52         C->nvec = cvdim ;
53         C->nvec_nonempty = (cvlen > 0) ? cvdim : 0 ;
54     }
55     ASSERT (GB_IS_FULL (C)) ;
56     GB_GET_NTHREADS_MAX (nthreads_max, chunk, Context) ;
57 
58     int64_t nouter = csc ? n : m ;
59     int64_t ninner = csc ? m : n ;
60 
61     //--------------------------------------------------------------------------
62     // concatenate all matrices into C
63     //--------------------------------------------------------------------------
64 
65     for (int64_t outer = 0 ; outer < nouter ; outer++)
66     {
67         for (int64_t inner = 0 ; inner < ninner ; inner++)
68         {
69 
70             //------------------------------------------------------------------
71             // get the tile A; transpose and typecast, if needed
72             //------------------------------------------------------------------
73 
74             A = csc ? GB_TILE (Tiles, inner, outer)
75                     : GB_TILE (Tiles, outer, inner) ;
76             if (csc != A->is_csc)
77             {
78                 // T = (ctype) A', not in-place
79                 GB_OK (GB_transpose (&T, ctype, csc, A,
80                     NULL, NULL, NULL, false, Context)) ;
81                 A = T ;
82                 GB_MATRIX_WAIT (A) ;
83             }
84             ASSERT (C->is_csc == A->is_csc) ;
85             ASSERT (GB_is_dense (A)) ;
86             ASSERT (!GB_ANY_PENDING_WORK (A)) ;
87             GB_Type_code acode = A->type->code ;
88 
89             //------------------------------------------------------------------
90             // determine where to place the tile in C
91             //------------------------------------------------------------------
92 
93             // The tile A appears in vectors cvstart:cvend-1 of C, and indices
94             // cistart:ciend-1.
95 
96             int64_t cvstart, cvend, cistart, ciend ;
97             if (csc)
98             {
99                 // C and A are held by column
100                 // Tiles is row-major and accessed in column order
101                 cvstart = Tile_cols [outer] ;
102                 cvend   = Tile_cols [outer+1] ;
103                 cistart = Tile_rows [inner] ;
104                 ciend   = Tile_rows [inner+1] ;
105             }
106             else
107             {
108                 // C and A are held by row
109                 // Tiles is row-major and accessed in row order
110                 cvstart = Tile_rows [outer] ;
111                 cvend   = Tile_rows [outer+1] ;
112                 cistart = Tile_cols [inner] ;
113                 ciend   = Tile_cols [inner+1] ;
114             }
115 
116             int64_t avdim = cvend - cvstart ;
117             int64_t avlen = ciend - cistart ;
118             ASSERT (avdim == A->vdim) ;
119             ASSERT (avlen == A->vlen) ;
120             int64_t anz = avdim * avlen ;
121             int A_nthreads = GB_nthreads (anz, chunk, nthreads_max) ;
122 
123             //------------------------------------------------------------------
124             // copy the tile A into C
125             //------------------------------------------------------------------
126 
127             bool done = false ;
128 
129             #ifndef GBCOMPACT
130                 if (ccode == acode)
131                 {
132                     // no typecasting needed
133                     switch (csize)
134                     {
135                         #define GB_COPY(pC,pA) Cx [pC] = Ax [pA]
136 
137                         case 1 : // uint8, int8, bool, or 1-byte user-defined
138                             #define GB_CTYPE uint8_t
139                             #include "GB_concat_full_template.c"
140                             break ;
141 
142                         case 2 : // uint16, int16, or 2-byte user-defined
143                             #define GB_CTYPE uint16_t
144                             #include "GB_concat_full_template.c"
145                             break ;
146 
147                         case 4 : // uint32, int32, float, or 4-byte user-defined
148                             #define GB_CTYPE uint32_t
149                             #include "GB_concat_full_template.c"
150                             break ;
151 
152                         case 8 : // uint64, int64, double, float complex,
153                                  // or 8-byte user defined
154                             #define GB_CTYPE uint64_t
155                             #include "GB_concat_full_template.c"
156                             break ;
157 
158                         case 16 : // double complex or 16-byte user-defined
159                             #define GB_CTYPE uint64_t
160                             #undef  GB_COPY
161                             #define GB_COPY(pC,pA)                      \
162                                 Cx [2*pC  ] = Ax [2*pA  ] ;             \
163                                 Cx [2*pC+1] = Ax [2*pA+1] ;
164                             #include "GB_concat_full_template.c"
165                             break ;
166 
167                         default:;
168                     }
169                 }
170             #endif
171 
172             if (!done)
173             {
174                 // with typecasting or user-defined types
175                 GB_cast_function cast_A_to_C = GB_cast_factory (ccode, acode) ;
176                 size_t asize = A->type->size ;
177                 #define GB_CTYPE GB_void
178                 #undef  GB_COPY
179                 #define GB_COPY(pC,pA)  \
180                     cast_A_to_C (Cx + (pC)*csize, Ax + (pA)*asize, asize) ;
181                 #include "GB_concat_full_template.c"
182             }
183 
184             GB_FREE_WORK ;
185         }
186     }
187 
188     C->magic = GB_MAGIC ;
189     return (GrB_SUCCESS) ;
190 }
191 
192