1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
//------------------------------------------------------------------------------
// GB_Vector_diag: extract a diagonal from a matrix, as a vector
//------------------------------------------------------------------------------
// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//------------------------------------------------------------------------------
#define GB_FREE_WORKSPACE \
{ \
GB_Matrix_free (&T) ; \
}
#define GB_FREE_ALL \
{ \
GB_FREE_WORKSPACE ; \
GB_phybix_free (V) ; \
}
#include "GB_diag.h"
#include "GB_select.h"
GrB_Info GB_Vector_diag // extract a diagonal from a matrix, as a vector
(
GrB_Matrix V, // output vector (as an n-by-1 matrix)
const GrB_Matrix A, // input matrix
int64_t k,
GB_Context Context
)
{
//--------------------------------------------------------------------------
// check inputs
//--------------------------------------------------------------------------
GrB_Info info ;
ASSERT_MATRIX_OK (A, "A input for GB_Vector_diag", GB0) ;
ASSERT_MATRIX_OK (V, "V input for GB_Vector_diag", GB0) ;
ASSERT (GB_VECTOR_OK (V)) ; // V is a vector on input
ASSERT (!GB_aliased (A, V)) ; // A and V cannot be aliased
ASSERT (!GB_IS_HYPERSPARSE (V)) ; // vectors cannot be hypersparse
struct GB_Matrix_opaque T_header ;
GrB_Matrix T = NULL ;
GrB_Type atype = A->type ;
GrB_Type vtype = V->type ;
int64_t nrows = GB_NROWS (A) ;
int64_t ncols = GB_NCOLS (A) ;
int64_t n ;
if (k >= ncols || k <= -nrows)
{
// output vector V must have zero length
n = 0 ;
}
else if (k >= 0)
{
// if k is in range 0 to n-1, V must have length min (m,n-k)
n = GB_IMIN (nrows, ncols - k) ;
}
else
{
// if k is in range -1 to -m+1, V must have length min (m+k,n)
n = GB_IMIN (nrows + k, ncols) ;
}
if (n != V->vlen)
{
GB_ERROR (GrB_DIMENSION_MISMATCH,
"Input vector must have size " GBd "\n", n) ;
}
if (!GB_Type_compatible (atype, vtype))
{
GB_ERROR (GrB_DOMAIN_MISMATCH, "Input matrix of type [%s] "
"cannot be typecast to output of type [%s]\n",
atype->name, vtype->name) ;
}
//--------------------------------------------------------------------------
// finish any pending work in A and clear the output vector V
//--------------------------------------------------------------------------
GB_MATRIX_WAIT (A) ;
GB_phybix_free (V) ;
//--------------------------------------------------------------------------
// handle the CSR/CSC format of A
//--------------------------------------------------------------------------
bool csc = A->is_csc ;
if (!csc)
{
// The kth diagonal of a CSC matrix is the same as the (-k)th diagonal
// of the CSR format, so if A is CSR, negate the value of k. Then
// treat A as if it were CSC in the rest of this method.
k = -k ;
}
//--------------------------------------------------------------------------
// extract the kth diagonal of A into the temporary hypersparse matrix T
//--------------------------------------------------------------------------
GB_CLEAR_STATIC_HEADER (T, &T_header) ;
GB_OK (GB_selector (
T, // output matrix
GB_DIAG_selop_code, // just use the DIAG opcode
NULL, // do not use the GB_Operator
false, // flipij is false
A, // input matrix
k, // ithunk = k
NULL, // no GrB_Scalar Thunk
Context)) ;
GB_OK (GB_convert_any_to_hyper (T, Context)) ;
GB_MATRIX_WAIT (T) ;
ASSERT_MATRIX_OK (T, "T = diag (A,k)", GB0) ;
//--------------------------------------------------------------------------
// transplant the pattern of T into the sparse vector V
//--------------------------------------------------------------------------
int64_t vnz = GB_nnz (T) ;
float bitmap_switch = V->bitmap_switch ;
int sparsity_control = V->sparsity_control ;
GB_OK (GB_new (&V, // existing header
vtype, n, 1, GB_Ap_malloc, true, GxB_SPARSE,
GxB_NEVER_HYPER, 1, Context)) ;
V->sparsity_control = sparsity_control ;
V->bitmap_switch = bitmap_switch ;
V->iso = T->iso ; // OK
if (V->iso)
{
GBURBLE ("(iso diag) ") ;
}
V->p [0] = 0 ;
V->p [1] = vnz ;
V->nvals = vnz ;
if (k >= 0)
{
// transplant T->i into V->i
V->i = T->i ;
V->i_size = T->i_size ;
T->i = NULL ;
}
else
{
// transplant T->h into V->i
V->i = T->h ;
V->i_size = T->h_size ;
T->h = NULL ;
}
//--------------------------------------------------------------------------
// transplant or typecast the values from T to V
//--------------------------------------------------------------------------
GB_Type_code vcode = vtype->code ;
GB_Type_code acode = atype->code ;
if (vcode == acode)
{
// transplant T->x into V->x
V->x = T->x ;
V->x_size = T->x_size ;
T->x = NULL ;
}
else
{
// V->x = (vtype) T->x
// V is sparse so malloc is OK
V->x = GB_XALLOC (false, V->iso, vnz, vtype->size, &(V->x_size)) ;
if (V->x == NULL)
{
// out of memory
GB_FREE_ALL ;
return (GrB_OUT_OF_MEMORY) ;
}
GB_cast_matrix (V, T, Context) ;
}
//--------------------------------------------------------------------------
// finalize the vector V
//--------------------------------------------------------------------------
V->jumbled = T->jumbled ;
V->nvec_nonempty = (vnz == 0) ? 0 : 1 ;
V->magic = GB_MAGIC ;
//--------------------------------------------------------------------------
// free workspace, conform V to its desired format, and return result
//--------------------------------------------------------------------------
GB_FREE_WORKSPACE ;
ASSERT_MATRIX_OK (V, "V before conform for GB_Vector_diag", GB0) ;
GB_OK (GB_conform (V, Context)) ;
ASSERT_MATRIX_OK (V, "V output for GB_Vector_diag", GB0) ;
return (GrB_SUCCESS) ;
}
|