1 //------------------------------------------------------------------------------
2 // GB_jappend.h: definitions of GB_jappend, and GB_jwrapup
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 // These methods are now only used by GB_Matrix_wait.
11 
12 #ifndef GB_JAPPEND_H
13 #define GB_JAPPEND_H
14 #include "GB.h"
15 
16 //------------------------------------------------------------------------------
17 // GB_jappend:  append a new vector to the end of a matrix
18 //------------------------------------------------------------------------------
19 
20 // Append a new vector to the end of a matrix C.
21 
22 // If C->h != NULL, C is in hypersparse form with
23 // C->nvec <= C->plen <= C->vdim.  C->h has size C->plen.
24 
25 // If C->h == NULL, C is in non-hypersparse form with
26 // C->nvec == C->plen == C->vdim.  C->h is NULL.
27 // In both cases, C->p has size C->plen+1.
28 
GB_jappend(GrB_Matrix C,int64_t j,int64_t * jlast,int64_t cnz,int64_t * cnz_last,GB_Context Context)29 static inline GrB_Info GB_jappend
30 (
31     GrB_Matrix C,           // matrix to append vector j to
32     int64_t j,              // new vector to append
33     int64_t *jlast,         // last vector appended, -1 if none
34     int64_t cnz,            // nnz(C) after adding this vector j
35     int64_t *cnz_last,      // nnz(C) before adding this vector j
36     GB_Context Context
37 )
38 {
39 
40     //--------------------------------------------------------------------------
41     // check inputs
42     //--------------------------------------------------------------------------
43 
44     ASSERT (C != NULL) ;
45     ASSERT (!C->p_shallow) ;
46     ASSERT (!C->h_shallow) ;
47     ASSERT (C->p != NULL) ;
48     ASSERT (!GB_IS_FULL (C)) ;
49 
50     if (cnz <= (*cnz_last))
51     {
52         // nothing to do
53         return (GrB_SUCCESS) ;
54     }
55 
56     // one more non-empty vector
57     C->nvec_nonempty++ ;
58 
59     if (C->h != NULL)
60     {
61 
62         //----------------------------------------------------------------------
63         // C is hypersparse; make sure space exists in the hyperlist
64         //----------------------------------------------------------------------
65 
66         ASSERT (C->p [C->nvec] == (*cnz_last)) ;
67         ASSERT (C->h != NULL) ;
68 
69         // check if space exists
70         if (C->nvec == C->plen)
71         {
72             // double the size of C->h and C->p
73             GrB_Info info ;
74             info = GB_hyper_realloc (C, GB_IMIN (C->vdim, 2*(C->plen+1)),
75                 Context) ;
76             if (info != GrB_SUCCESS)
77             {
78                 // out of memory
79                 return (info) ;
80             }
81         }
82 
83         ASSERT (C->nvec >= 0) ;
84         ASSERT (C->nvec < C->plen) ;
85         ASSERT (C->plen <= C->vdim) ;
86         ASSERT (C->p [C->nvec] == (*cnz_last)) ;
87 
88         // add j to the hyperlist
89         C->h [C->nvec] = j ;
90 
91         // mark the end of C(:,j)
92         C->p [C->nvec+1] = cnz ;
93         C->nvec++ ;                     // one more vector in the hyperlist
94 
95     }
96     else
97     {
98 
99         //----------------------------------------------------------------------
100         // C is non-hypersparse
101         //----------------------------------------------------------------------
102 
103         int64_t *restrict Cp = C->p ;
104 
105         ASSERT (C->nvec == C->plen && C->plen == C->vdim) ;
106         ASSERT (C->h == NULL) ;
107         ASSERT (Cp [(*jlast)+1] == (*cnz_last)) ;
108 
109         // Even if C is non-hypersparse, the iteration that uses this function
110         // may iterate over a hypersparse input matrix, so not every vector j
111         // will be traversed.  So when j is seen, the end of vectors jlast+1 to
112         // j must logged in Cp.
113 
114         for (int64_t jprior = (*jlast)+1 ; jprior < j ; jprior++)
115         {
116             // mark the end of C(:,jprior)
117             Cp [jprior+1] = (*cnz_last) ;
118         }
119         // mark the end of C(:,j)
120         Cp [j+1] = cnz ;
121     }
122 
123     // record the last vector added to C
124     (*cnz_last) = cnz ;
125     (*jlast) = j ;
126 
127     return (GrB_SUCCESS) ;
128 }
129 
130 //------------------------------------------------------------------------------
131 // GB_jwrapup:  finish contructing a new matrix
132 //------------------------------------------------------------------------------
133 
134 // Log the end of any vectors in C that are not yet terminated.  Nothing
135 // happens if C is hypersparse (except for setting C->magic).
136 
GB_jwrapup(GrB_Matrix C,int64_t jlast,int64_t cnz)137 static inline void GB_jwrapup
138 (
139     GrB_Matrix C,           // matrix to finish
140     int64_t jlast,          // last vector appended, -1 if none
141     int64_t cnz             // final nnz(C)
142 )
143 {
144 
145     if (C->h == NULL)
146     {
147 
148         //----------------------------------------------------------------------
149         // C is non-hypersparse
150         //----------------------------------------------------------------------
151 
152         // log the end of C(:,jlast+1) to C(:,n-1), in case the last vector
153         // j=n-1 has not yet been seen, or has been seen but was empty.
154 
155         int64_t *restrict Cp = C->p ;
156         int64_t j = C->vdim - 1 ;
157 
158         for (int64_t jprior = jlast+1 ; jprior <= j ; jprior++)
159         {
160             // mark the end of C(:,jprior)
161             Cp [jprior+1] = cnz ;
162         }
163     }
164 
165     // C->p and C->h are now valid
166     C->magic = GB_MAGIC ;
167 }
168 
169 #endif
170 
171