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