1 //------------------------------------------------------------------------------
2 // GB_mex_reduce_to_scalar: c = accum(c,reduce_to_scalar(A))
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 // Reduce a matrix or vector to a scalar
11
12 #include "GB_mex.h"
13
14 #define USAGE "c = GB_mex_reduce_to_scalar (c, accum, reduce, A)"
15
16 #define FREE_ALL \
17 { \
18 GrB_Matrix_free_(&A) ; \
19 if (reduce_monoid_allocated) \
20 { \
21 GrB_Monoid_free_(&reduce) ; \
22 } \
23 GB_mx_put_global (true) ; \
24 }
25
mexFunction(int nargout,mxArray * pargout[],int nargin,const mxArray * pargin[])26 void mexFunction
27 (
28 int nargout,
29 mxArray *pargout [ ],
30 int nargin,
31 const mxArray *pargin [ ]
32 )
33 {
34
35 bool malloc_debug = GB_mx_get_global (true) ;
36 GrB_Matrix A = NULL ;
37 GrB_Monoid reduce = NULL ;
38 bool reduce_is_complex = false ;
39 bool reduce_monoid_allocated = false ;
40
41 // check inputs
42 if (nargout > 1 || nargin != 4)
43 {
44 mexErrMsgTxt ("Usage: " USAGE) ;
45 }
46
47 #define GET_DEEP_COPY ;
48 #define FREE_DEEP_COPY ;
49
50 // get the scalar c
51 GB_void *c ;
52 int64_t cnrows, cncols ;
53 GrB_Type ctype ;
54
55 GB_mx_mxArray_to_array (pargin [0], &c, &cnrows, &cncols, &ctype) ;
56 if (cnrows != 1 || cncols != 1)
57 {
58 mexErrMsgTxt ("c must be a scalar") ;
59 }
60 if (ctype == NULL)
61 {
62 mexErrMsgTxt ("c must be numeric") ;
63 }
64
65 // get A (shallow copy)
66 A = GB_mx_mxArray_to_Matrix (pargin [3], "A input", false, true) ;
67 if (A == NULL)
68 {
69 FREE_ALL ;
70 mexErrMsgTxt ("A failed") ;
71 }
72
73 // get reduce
74 bool user_complex = (Complex != GxB_FC64) && (ctype == Complex) ;
75 GrB_BinaryOp reduceop ;
76 if (!GB_mx_mxArray_to_BinaryOp (&reduceop, pargin [2], "reduceop",
77 ctype, user_complex) || reduceop == NULL)
78 {
79 FREE_ALL ;
80 mexErrMsgTxt ("reduceop failed") ;
81 }
82
83 // get the reduce monoid
84 if (user_complex)
85 {
86 if (reduceop == Complex_plus)
87 {
88 reduce = Complex_plus_monoid ;
89 }
90 else if (reduceop == Complex_times)
91 {
92 reduce = Complex_times_monoid ;
93 }
94 else
95 {
96 FREE_ALL ;
97 mexErrMsgTxt ("reduce failed") ;
98 }
99 }
100 else
101 {
102 // create the reduce monoid
103 if (!GB_mx_Monoid (&reduce, reduceop, malloc_debug))
104 {
105 FREE_ALL ;
106 mexErrMsgTxt ("reduce failed") ;
107 }
108 reduce_monoid_allocated = true ;
109 }
110
111 // get accum, if present
112 GrB_BinaryOp accum ;
113 if (!GB_mx_mxArray_to_BinaryOp (&accum, pargin [1], "accum",
114 ctype, user_complex))
115 {
116 FREE_ALL ;
117 mexErrMsgTxt ("accum failed") ;
118 }
119
120 // c = accum(C,A*B)
121
122 // test both Vector and Matrix methods. The typecast is not necessary,
123 // just to test.
124
125 if (user_complex)
126 {
127 if (A->vdim == 1)
128 {
129 GrB_Vector V ;
130 V = (GrB_Vector) A ;
131 METHOD (GrB_Vector_reduce_UDT (c, accum, reduce, V, NULL)) ;
132 }
133 else
134 {
135 METHOD (GrB_Matrix_reduce_UDT (c, accum, reduce, A, NULL)) ;
136 }
137 }
138 else
139 {
140
141 #define REDUCE(prefix,suffix,type) \
142 if (A->vdim == 1) \
143 { \
144 GrB_Vector V ; \
145 V = (GrB_Vector) A ; \
146 METHOD (prefix ## Vector_reduce ## suffix \
147 ((type *) c, accum, reduce, V, NULL)) ; \
148 } \
149 else \
150 { \
151 METHOD (prefix ## Matrix_reduce ## suffix \
152 ((type *) c, accum, reduce, A, NULL)) ; \
153 }
154
155 switch (ctype->code)
156 {
157 case GB_BOOL_code : REDUCE (GrB_, _BOOL, bool ) ; break ;
158 case GB_INT8_code : REDUCE (GrB_, _INT8, int8_t ) ; break ;
159 case GB_INT16_code : REDUCE (GrB_, _INT16, int16_t ) ; break ;
160 case GB_INT32_code : REDUCE (GrB_, _INT32, int32_t ) ; break ;
161 case GB_INT64_code : REDUCE (GrB_, _INT64, int64_t ) ; break ;
162 case GB_UINT8_code : REDUCE (GrB_, _UINT8, uint8_t ) ; break ;
163 case GB_UINT16_code : REDUCE (GrB_, _UINT16, uint16_t) ; break ;
164 case GB_UINT32_code : REDUCE (GrB_, _UINT32, uint32_t) ; break ;
165 case GB_UINT64_code : REDUCE (GrB_, _UINT64, uint64_t) ; break ;
166 case GB_FP32_code : REDUCE (GrB_, _FP32, float ) ; break ;
167 case GB_FP64_code : REDUCE (GrB_, _FP64, double ) ; break ;
168 case GB_FC32_code : REDUCE (GxB_, _FC32, GxB_FC32_t) ; break ;
169 case GB_FC64_code : REDUCE (GxB_, _FC64, GxB_FC64_t) ; break ;
170 default :
171 FREE_ALL ;
172 mexErrMsgTxt ("unknown type: reduce to scalar") ;
173 }
174 }
175
176 // return C to MATLAB as a scalar
177 pargout [0] = GB_mx_create_full (1, 1, ctype) ;
178 GB_void *p = mxGetData (pargout [0]) ;
179 memcpy (p, c, ctype->size) ;
180 FREE_ALL ;
181 }
182
183