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