1 //------------------------------------------------------------------------------
2 // GB_new: create a new GraphBLAS matrix, but do not allocate A->{b,i,x}
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 // Creates a new matrix but does not allocate space for A->b, A->i, and A->x.
11 // See GB_new_bix instead.
12
13 // If the Ap_option is GB_Ap_calloc, the A->p and A->h are allocated and
14 // initialized, and A->magic is set to GB_MAGIC to denote a valid matrix.
15 // Otherwise, the matrix has not yet been completely initialized, and A->magic
16 // is set to GB_MAGIC2 to denote this. This case only occurs internally in
17 // GraphBLAS. The internal function that calls GB_new must then allocate or
18 // initialize A->p itself, and then set A->magic = GB_MAGIC when it does so.
19
20 // To allocate a full or bitmap matrix, the sparsity parameter
21 // is GxB_FULL or GxB_BITMAP. The Ap_option is ignored. For a full or
22 // bitmap matrix, only the header is allocated, if NULL on input.
23
24 // The GrB_Matrix object holds both a sparse vector and a sparse matrix. A
25 // vector is represented as an vlen-by-1 matrix, but it is sometimes treated
26 // differently in various methods. Vectors are never transposed via a
27 // descriptor, for example.
28
29 // The matrix may be created in an existing header, which case *Ahandle is
30 // non-NULL on input. If an out-of-memory condition occurs, (*Ahandle) is
31 // returned as NULL, and the existing header is freed as well, if non-NULL on
32 // input.
33
34 #include "GB.h"
35
36 GB_PUBLIC // accessed by the MATLAB tests in GraphBLAS/Test only
GB_new(GrB_Matrix * Ahandle,const bool A_static_header,const GrB_Type type,const int64_t vlen,const int64_t vdim,const GB_Ap_code Ap_option,const bool is_csc,const int sparsity,const float hyper_switch,const int64_t plen,GB_Context Context)37 GrB_Info GB_new // create matrix, except for indices & values
38 (
39 GrB_Matrix *Ahandle, // handle of matrix to create
40 const bool A_static_header, // true if Ahandle is statically allocated
41 const GrB_Type type, // matrix type
42 const int64_t vlen, // length of each vector
43 const int64_t vdim, // number of vectors
44 const GB_Ap_code Ap_option, // allocate A->p and A->h, or leave NULL
45 const bool is_csc, // true if CSC, false if CSR
46 const int sparsity, // hyper, sparse, bitmap, full, or auto
47 const float hyper_switch, // A->hyper_switch
48 const int64_t plen, // size of A->p and A->h, if A hypersparse.
49 // Ignored if A is not hypersparse.
50 GB_Context Context
51 )
52 {
53
54 //--------------------------------------------------------------------------
55 // check inputs
56 //--------------------------------------------------------------------------
57
58 ASSERT (Ahandle != NULL) ;
59 ASSERT_TYPE_OK (type, "type for GB_new", GB0) ;
60 ASSERT (vlen >= 0 && vlen <= GxB_INDEX_MAX)
61 ASSERT (vdim >= 0 && vdim <= GxB_INDEX_MAX) ;
62
63 //--------------------------------------------------------------------------
64 // allocate the matrix header, if not already allocated on input
65 //--------------------------------------------------------------------------
66
67 bool allocated_header = false ;
68 if ((*Ahandle) == NULL)
69 {
70 size_t header_size ;
71 (*Ahandle) = GB_MALLOC (1, struct GB_Matrix_opaque, &header_size) ;
72 if (*Ahandle == NULL)
73 {
74 // out of memory
75 return (GrB_OUT_OF_MEMORY) ;
76 }
77 allocated_header = true ;
78 (*Ahandle)->static_header = false ; // header of A has been malloc'd
79 (*Ahandle)->header_size = header_size ;
80 }
81 else
82 {
83 // the header of A has been provided on input. It may already be
84 // malloc'd, or it might be statically allocated in the caller.
85 (*Ahandle)->static_header = A_static_header ;
86 }
87
88 GrB_Matrix A = *Ahandle ;
89
90 //--------------------------------------------------------------------------
91 // initialize the matrix header
92 //--------------------------------------------------------------------------
93
94 // basic information
95 A->magic = GB_MAGIC2 ; // object is not yet valid
96 A->type = type ;
97 A->logger = NULL ; // no error logged yet
98 A->logger_size = 0 ;
99
100 // CSR/CSC format
101 A->is_csc = is_csc ;
102
103 // initial sparsity format
104 bool A_is_hyper ;
105 bool A_is_full_or_bitmap = false ;
106 A->hyper_switch = hyper_switch ;
107 A->bitmap_switch = GB_Global_bitmap_switch_matrix_get (vlen, vdim) ;
108 A->sparsity = GxB_AUTO_SPARSITY ;
109
110 if (sparsity == GxB_HYPERSPARSE)
111 {
112 A_is_hyper = true ; // force A to be hypersparse
113 }
114 else if (sparsity == GxB_SPARSE)
115 {
116 A_is_hyper = false ; // force A to be sparse
117 }
118 else if (sparsity == GxB_FULL || sparsity == GxB_BITMAP)
119 {
120 A_is_full_or_bitmap = true ; // force A to be full or bitmap
121 A_is_hyper = false ;
122 }
123 else // auto: sparse or hypersparse
124 {
125 // auto selection: sparse if one vector or less or
126 // if the global hyper_switch is negative; hypersparse otherwise.
127 // Never select A to be full or bitmap for this case.
128 A_is_hyper = !(vdim <= 1 || 0 > hyper_switch) ;
129 }
130
131 // matrix dimensions
132 A->vlen = vlen ;
133 A->vdim = vdim ;
134
135 // content that is freed or reset in GB_ph_free
136 if (A_is_full_or_bitmap)
137 {
138 // A is full or bitmap
139 A->plen = -1 ;
140 A->nvec = vdim ;
141 // all vectors present, unless matrix has a zero dimension
142 A->nvec_nonempty = (vlen > 0) ? vdim : 0 ;
143 }
144 else if (A_is_hyper)
145 {
146 // A is hypersparse
147 A->plen = GB_IMIN (plen, vdim) ;
148 A->nvec = 0 ; // no vectors present
149 A->nvec_nonempty = 0 ;
150 }
151 else
152 {
153 // A is sparse
154 A->plen = vdim ;
155 A->nvec = vdim ; // all vectors present
156 A->nvec_nonempty = 0 ;
157 }
158
159 // no content yet
160 A->p = NULL ; A->p_shallow = false ; A->p_size = 0 ;
161 A->h = NULL ; A->h_shallow = false ; A->h_size = 0 ;
162 A->b = NULL ; A->b_shallow = false ; A->b_size = 0 ;
163 A->i = NULL ; A->i_shallow = false ; A->i_size = 0 ;
164 A->x = NULL ; A->x_shallow = false ; A->x_size = 0 ;
165
166 A->nzmax = 0 ; // GB_NNZ(A) checks nzmax==0 before Ap[nvec]
167 A->nvals = 0 ; // for bitmapped matrices only
168 A->nzombies = 0 ;
169 A->jumbled = false ;
170 A->Pending = NULL ;
171
172 //--------------------------------------------------------------------------
173 // Allocate A->p and A->h if requested
174 //--------------------------------------------------------------------------
175
176 bool ok ;
177 if (A_is_full_or_bitmap || Ap_option == GB_Ap_null)
178 {
179 // A is not initialized yet; A->p and A->h are both NULL.
180 // sparse case: GB_NNZ(A) must check A->nzmax == 0 since A->p might not
181 // be allocated.
182 // full case: A->x not yet allocated. A->nzmax still zero
183 // bitmap case: A->b, A->x not yet allocated. A->nzmax still zero
184 A->magic = GB_MAGIC2 ;
185 A->p = NULL ;
186 A->h = NULL ;
187 ok = true ;
188 }
189 else if (Ap_option == GB_Ap_calloc)
190 {
191 // Sets the vector pointers to zero, which defines all vectors as empty
192 A->magic = GB_MAGIC ;
193 A->p = GB_CALLOC (A->plen+1, int64_t, &(A->p_size)) ;
194 ASSERT (A->p_size == GB_Global_memtable_size (A->p)) ;
195 ok = (A->p != NULL) ;
196 if (A_is_hyper)
197 {
198 // since nvec is zero, there is never any need to initialize A->h
199 A->h = GB_MALLOC (A->plen, int64_t, &(A->h_size)) ;
200 ok = ok && (A->h != NULL) ;
201 }
202 }
203 else // Ap_option == GB_Ap_malloc
204 {
205 // This is faster but can only be used internally by GraphBLAS since
206 // the matrix is allocated but not yet completely initialized. The
207 // caller must set A->p [0..plen] and then set A->magic to GB_MAGIC,
208 // before returning the matrix to the user application. GB_NNZ(A) must
209 // check A->nzmax == 0 since A->p [A->nvec] might be undefined.
210 A->magic = GB_MAGIC2 ;
211 A->p = GB_MALLOC (A->plen+1, int64_t, &(A->p_size)) ;
212 ASSERT (A->p_size == GB_Global_memtable_size (A->p)) ;
213 ok = (A->p != NULL) ;
214 if (A_is_hyper)
215 {
216 A->h = GB_MALLOC (A->plen, int64_t, &(A->h_size)) ;
217 ok = ok && (A->h != NULL) ;
218 }
219 }
220
221 if (!ok)
222 {
223 // out of memory
224 if (allocated_header)
225 {
226 // free all of A, including the header
227 GB_Matrix_free (Ahandle) ;
228 }
229 else
230 {
231 // the header was not allocated here; only free the content of A
232 GB_phbix_free (A) ;
233 }
234 return (GrB_OUT_OF_MEMORY) ;
235 }
236
237 //--------------------------------------------------------------------------
238 // return result
239 //--------------------------------------------------------------------------
240
241 // The vector pointers A->p are initialized only if Ap_calloc is true
242 if (A->magic == GB_MAGIC)
243 {
244 ASSERT_MATRIX_OK (A, "new matrix from GB_new", GB0) ;
245 }
246 return (GrB_SUCCESS) ;
247 }
248
249