1 //------------------------------------------------------------------------------
2 // GB_shallow_op:  create a shallow copy and apply a unary operator to a matrix
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 // C = op (A)
11 
12 // Create a shallow copy of a matrix, applying an operator to the entries.
13 
14 // The CSR/CSC format of C and A can differ, but they have they same vlen and
15 // vdim.  This function is CSR/CSC agnostic, except that C_is_csc is used to
16 // set the C->is_csc state in C.
17 
18 // The values are typically not a shallow copy, unless no typecasting is needed
19 // and the operator is an identity operator.
20 
21 // The pattern is always a shallow copy.  No errors are checked except for
22 // out-of-memory conditions.  This function is not user-callable.  Shallow
23 // matrices are never passed back to the user.
24 
25 // Compare this function with GB_shallow_copy.c
26 
27 #include "GB_apply.h"
28 
29 GB_PUBLIC   // accessed by the MATLAB tests in GraphBLAS/Test only
GB_shallow_op(GrB_Matrix C,const bool C_is_csc,const GrB_UnaryOp op1,const GrB_BinaryOp op2,const GxB_Scalar scalar,bool binop_bind1st,const GrB_Matrix A,GB_Context Context)30 GrB_Info GB_shallow_op      // create shallow matrix and apply operator
31 (
32     GrB_Matrix C,           // output C, of type op*->ztype, static header
33     const bool C_is_csc,    // desired CSR/CSC format of C
34         const GrB_UnaryOp op1,          // unary operator to apply
35         const GrB_BinaryOp op2,         // binary operator to apply
36         const GxB_Scalar scalar,        // scalar to bind to binary operator
37         bool binop_bind1st,             // if true, binop(x,A) else binop(A,y)
38     const GrB_Matrix A,     // input matrix to typecast
39     GB_Context Context
40 )
41 {
42 
43     //--------------------------------------------------------------------------
44     // check inputs
45     //--------------------------------------------------------------------------
46 
47     ASSERT (C != NULL && C->static_header) ;
48     ASSERT_MATRIX_OK (A, "A for shallow_op", GB0) ;
49     ASSERT (!GB_ZOMBIES (A)) ;
50     ASSERT (GB_JUMBLED_OK (A)) ;
51     ASSERT (!GB_PENDING (A)) ;
52 
53     GrB_Type ztype, op_intype = NULL ;
54     GB_Opcode opcode = (op1 != NULL) ? op1->opcode : op2->opcode ;
55     bool op_is_positional = GB_OPCODE_IS_POSITIONAL (opcode) ;
56     if (op1 != NULL)
57     {
58         ASSERT_UNARYOP_OK (op1, "unop for shallow_op", GB0) ;
59         if (!op_is_positional)
60         {
61             ASSERT (GB_Type_compatible (op1->xtype, A->type)) ;
62             op_intype = op1->xtype ;
63         }
64         ztype = op1->ztype ;
65     }
66     else // op2 != NULL
67     {
68         ASSERT_BINARYOP_OK (op2, "binop for shallow_op", GB0) ;
69         if (!op_is_positional)
70         {
71             op_intype = (binop_bind1st) ? op2->xtype : op2->ytype ;
72             ASSERT (GB_Type_compatible (op_intype, A->type)) ;
73         }
74         ztype = op2->ztype ;
75     }
76 
77     //--------------------------------------------------------------------------
78     // construct a shallow copy of A for the pattern of C
79     //--------------------------------------------------------------------------
80 
81     // initialized the header for C, but do not allocate C->{p,h,b,i,x}
82     // C has the exact same sparsity structure as A.
83     GrB_Info info ;
84     info = GB_new (&C, true, // any sparsity, static header
85         ztype, A->vlen, A->vdim, GB_Ap_null, C_is_csc,
86         GB_sparsity (A), A->hyper_switch, 0, Context) ;
87     ASSERT (info == GrB_SUCCESS) ;
88 
89     //--------------------------------------------------------------------------
90     // make a shallow copy of the vector pointers
91     //--------------------------------------------------------------------------
92 
93     C->p_shallow = (A->p != NULL) ;     // C->p not freed when freeing C
94     C->h_shallow = (A->h != NULL) ;     // C->h not freed when freeing C
95     C->p = A->p ;                       // C->p is of size A->plen + 1
96     C->h = A->h ;                       // C->h is of size A->plen
97     C->plen = A->plen ;                 // C and A have the same hyperlist sizes
98     C->nvec = A->nvec ;
99     C->nvec_nonempty = A->nvec_nonempty ;
100     C->jumbled = A->jumbled ;           // C is jumbled if A is jumbled
101     C->nvals = A->nvals ;               // if A bitmap
102     C->magic = GB_MAGIC ;
103 
104     //--------------------------------------------------------------------------
105     // check for empty matrix
106     //--------------------------------------------------------------------------
107 
108     if (A->nzmax == 0)
109     {
110         // C->p and C->h are shallow but the rest is empty
111         C->nzmax = 0 ;
112         C->b = NULL ;
113         C->i = NULL ;
114         C->x = NULL ;
115         C->b_shallow = false ;
116         C->i_shallow = false ;
117         C->x_shallow = false ;
118         C->jumbled = false ;
119         ASSERT_MATRIX_OK (C, "C = quick copy of empty A", GB0) ;
120         return (GrB_SUCCESS) ;
121     }
122 
123     //--------------------------------------------------------------------------
124     // make a shallow copy of the pattern
125     //--------------------------------------------------------------------------
126 
127     C->b = A->b ;               // of size A->nzmax
128     C->b_shallow = (A->b != NULL) ;  // C->b will not be freed when freeing C
129 
130     C->i = A->i ;               // of size A->nzmax
131     C->i_shallow = (A->i != NULL) ; // C->i will not be freed when freeing C
132 
133     //--------------------------------------------------------------------------
134     // make a shallow copy of the values, if possible
135     //--------------------------------------------------------------------------
136 
137     // If the identity operator, first(A,y), second(x,A), any(A,y), or any(x,A)
138     // are used with no typecasting, C->x becomes a shallow copy of A->x, and
139     // no work is done.
140 
141     int64_t anz = GB_NNZ_HELD (A) ;
142     ASSERT (A->nzmax >= GB_IMAX (anz, 1)) ;
143 
144     if (A->type == op_intype &&
145         ((opcode == GB_IDENTITY_opcode) || (opcode == GB_ANY_opcode) ||
146          (opcode == GB_FIRST_opcode  && !binop_bind1st) ||
147          (opcode == GB_SECOND_opcode &&  binop_bind1st)))
148     {
149         // no work is done at all.  C is a pure shallow copy
150         GBURBLE ("(pure shallow) ") ;
151         C->nzmax = A->nzmax ;
152         C->x = A->x ;
153         C->x_shallow = true ;       // C->x will not be freed when freeing C
154         ASSERT (C->x_size == 0) ;
155         ASSERT_MATRIX_OK (C, "C = pure shallow (A)", GB0) ;
156         return (GrB_SUCCESS) ;
157     }
158 
159     //--------------------------------------------------------------------------
160     // apply the operator to the numerical values
161     //--------------------------------------------------------------------------
162 
163     // allocate new space for the numerical values of C
164     C->nzmax = GB_IMAX (anz, 1) ;
165     C->x = GB_MALLOC (C->nzmax * C->type->size, GB_void, &(C->x_size)) ;
166     C->x_shallow = false ;          // free C->x when freeing C
167     if (C->x == NULL)
168     {
169         // out of memory
170         GB_phbix_free (C) ;
171         return (GrB_OUT_OF_MEMORY) ;
172     }
173 
174     GB_void *Cx = (GB_void *) C->x ;
175     info = GB_apply_op (Cx, op1,    // op1 is never identity of same types
176         op2, scalar, binop_bind1st, A, Context) ;
177     if (info != GrB_SUCCESS)
178     {
179         // out of memory
180         GB_phbix_free (C) ;
181         return (GrB_OUT_OF_MEMORY) ;
182     }
183 
184     //--------------------------------------------------------------------------
185     // return the result
186     //--------------------------------------------------------------------------
187 
188     ASSERT_MATRIX_OK (C, "C = shallow (op (A))", GB0) ;
189     return (GrB_SUCCESS) ;
190 }
191 
192