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 204 205
|
//------------------------------------------------------------------------------
// GB_shallow_op: create a shallow copy and apply a unary operator to a matrix
//------------------------------------------------------------------------------
// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//------------------------------------------------------------------------------
// C = op (A), called only by GB_apply.
// Create a shallow copy of a matrix, applying an operator to the entries.
// The CSR/CSC format of C and A can differ, but they have they same vlen and
// vdim. This function is CSR/CSC agnostic, except that C_is_csc is used to
// set the C->is_csc state in C.
// The values are typically not a shallow copy, unless no typecasting is needed
// and the operator is an identity operator.
// The pattern is always a shallow copy. No errors are checked except for
// out-of-memory conditions. This function is not user-callable. Shallow
// matrices are never passed back to the user.
// Compare this function with GB_shallow_copy.c.
#include "GB_apply.h"
#define GB_FREE_ALL GB_phybix_free (C) ;
GB_PUBLIC
GrB_Info GB_shallow_op // create shallow matrix and apply operator
(
GrB_Matrix C, // output C, of type op*->ztype, static header
const bool C_is_csc, // desired CSR/CSC format of C
const GB_Operator op, // unary/index-unary/binop to apply
const GrB_Scalar scalar, // scalar to bind to binary operator
bool binop_bind1st, // if true, binop(x,A) else binop(A,y)
bool flipij, // if true, flip i,j for user idxunop
const GrB_Matrix A, // input matrix to typecast
GB_Context Context
)
{
//--------------------------------------------------------------------------
// check inputs
//--------------------------------------------------------------------------
ASSERT (C != NULL && (C->static_header || GBNSTATIC)) ;
ASSERT_MATRIX_OK (A, "A for shallow_op", GB0) ;
ASSERT_OP_OK (op, "unop/binop for shallow_op", GB0) ;
ASSERT (!GB_ZOMBIES (A)) ;
ASSERT (GB_JUMBLED_OK (A)) ;
ASSERT (!GB_PENDING (A)) ;
GrB_Type ztype = op->ztype ;
GrB_Type op_intype = NULL ;
GB_Opcode opcode = op->opcode ;
bool op_is_positional = GB_OPCODE_IS_POSITIONAL (opcode) ;
if (GB_IS_UNARYOP_CODE (opcode))
{
ASSERT_UNARYOP_OK (op, "unop for shallow_op", GB0) ;
if (!op_is_positional)
{
ASSERT (GB_Type_compatible (op->xtype, A->type)) ;
op_intype = op->xtype ;
}
}
else if (GB_IS_BINARYOP_CODE (opcode))
{
ASSERT_BINARYOP_OK (op, "binop for shallow_op", GB0) ;
if (!op_is_positional)
{
op_intype = (binop_bind1st) ? op->xtype : op->ytype ;
ASSERT (GB_Type_compatible (op_intype, A->type)) ;
}
}
else // GB_IS_INDEXUNARYOP_CODE (opcode)
{
ASSERT_INDEXUNARYOP_OK (op, "ixdunop for shallow_op", GB0) ;
op_intype = op->xtype ;
ASSERT (GB_Type_compatible (op_intype, A->type)) ;
}
//--------------------------------------------------------------------------
// construct a shallow copy of A for the pattern of C
//--------------------------------------------------------------------------
GB_iso_code C_code_iso = GB_iso_unop_code (A, op, binop_bind1st) ;
bool C_iso = (C_code_iso != GB_NON_ISO) ;
// initialized the header for C, but do not allocate C->{p,h,b,i,x}
// C has the exact same sparsity structure as A.
GrB_Info info ;
info = GB_new (&C, // any sparsity, existing header
ztype, A->vlen, A->vdim, GB_Ap_null, C_is_csc,
GB_sparsity (A), A->hyper_switch, 0, Context) ;
ASSERT (info == GrB_SUCCESS) ;
//--------------------------------------------------------------------------
// make a shallow copy of the vector pointers
//--------------------------------------------------------------------------
C->p_shallow = (A->p != NULL) ; // C->p not freed when freeing C
C->h_shallow = (A->h != NULL) ; // C->h not freed when freeing C
C->p = A->p ; // C->p is of size A->plen + 1
C->h = A->h ; // C->h is of size A->plen
C->p_size = A->p_size ;
C->h_size = A->h_size ;
C->plen = A->plen ; // C and A have the same hyperlist sizes
C->nvec = A->nvec ;
C->nvec_nonempty = A->nvec_nonempty ;
C->jumbled = A->jumbled ; // C is jumbled if A is jumbled
C->nvals = A->nvals ;
C->magic = GB_MAGIC ;
C->iso = C_iso ; // OK
if (C_iso)
{
GB_BURBLE_MATRIX (A, "(iso apply) ") ;
}
//--------------------------------------------------------------------------
// make a shallow copy of the A->Y hyper_hash
//--------------------------------------------------------------------------
C->Y = A->Y ;
C->Y_shallow = (A->Y != NULL) ;
//--------------------------------------------------------------------------
// check for empty matrix
//--------------------------------------------------------------------------
if (GB_nnz_max (A) == 0)
{
// C->p and C->h are shallow but the rest is empty
C->b = NULL ;
C->i = NULL ;
C->x = NULL ;
C->b_shallow = false ;
C->i_shallow = false ;
C->x_shallow = false ;
C->jumbled = false ;
C->iso = false ;
ASSERT_MATRIX_OK (C, "C = quick copy of empty A", GB0) ;
return (GrB_SUCCESS) ;
}
//--------------------------------------------------------------------------
// make a shallow copy of the pattern
//--------------------------------------------------------------------------
C->b = A->b ; C->b_shallow = (A->b != NULL) ; C->b_size = A->b_size ;
C->i = A->i ; C->i_shallow = (A->i != NULL) ; C->i_size = A->i_size ;
//--------------------------------------------------------------------------
// make a shallow copy of the values, if possible
//--------------------------------------------------------------------------
// If the identity operator, first(A,y), or second(x,A) are used with no
// typecasting, C->x becomes a shallow copy of A->x, and no work is done.
int64_t anz = GB_nnz_held (A) ;
if ((A->type == op_intype) &&
((opcode == GB_IDENTITY_unop_code) ||
(opcode == GB_FIRST_binop_code && !binop_bind1st) ||
(opcode == GB_SECOND_binop_code && binop_bind1st)))
{
// no work is done at all. C is a pure shallow copy
GBURBLE ("(pure shallow) ") ;
C->x = A->x ;
C->x_shallow = true ; // C->x will not be freed when freeing C
C->x_size = A->x_size ;
C->iso = A->iso ; // C has the same iso property as A
ASSERT_MATRIX_OK (C, "C = pure shallow (A)", GB0) ;
return (GrB_SUCCESS) ;
}
//--------------------------------------------------------------------------
// apply the operator to the numerical values
//--------------------------------------------------------------------------
// allocate new space for the numerical values of C; use calloc if bitmap
C->x = GB_XALLOC (GB_IS_BITMAP (C), C_iso, anz, // x:OK
C->type->size, &(C->x_size)) ;
C->x_shallow = false ; // free C->x when freeing C
if (C->x == NULL)
{
// out of memory
GB_FREE_ALL ;
return (GrB_OUT_OF_MEMORY) ;
}
GB_OK (GB_apply_op ((GB_void *) C->x, C->type, C_code_iso, op,
scalar, binop_bind1st, flipij, A, Context)) ;
//--------------------------------------------------------------------------
// return the result
//--------------------------------------------------------------------------
ASSERT_MATRIX_OK (C, "C = shallow (op (A))", GB0) ;
return (GrB_SUCCESS) ;
}
|