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