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