1 //------------------------------------------------------------------------------
2 // GB_mex_transpose: transpose a sparse matrix and return it to MATLAB
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<M> = accum (C,A') or accum (C,A)
11
12 #include "GB_mex.h"
13
14 #define USAGE "C = GB_mex_transpose (C, M, accum, A, desc, test)"
15
16 #define FREE_ALL \
17 { \
18 bool A_is_M = (A == M) ; \
19 bool A_is_C = (A == C) ; \
20 bool C_is_M = (C == M) ; \
21 GrB_Matrix_free_(&A) ; \
22 if (A_is_C) C = NULL ; \
23 if (A_is_M) M = NULL ; \
24 GrB_Matrix_free_(&C) ; \
25 if (C_is_M) M = NULL ; \
26 GrB_Matrix_free_(&M) ; \
27 GrB_Descriptor_free_(&desc) ; \
28 GB_mx_put_global (true) ; \
29 }
30
mexFunction(int nargout,mxArray * pargout[],int nargin,const mxArray * pargin[])31 void mexFunction
32 (
33 int nargout,
34 mxArray *pargout [ ],
35 int nargin,
36 const mxArray *pargin [ ]
37 )
38 {
39
40 bool malloc_debug = GB_mx_get_global (true) ;
41 GrB_Matrix A = NULL ;
42 GrB_Matrix C = NULL ;
43 GrB_Matrix M = NULL ;
44 GrB_Descriptor desc = NULL ;
45
46 // check inputs
47 if (nargout > 1 || nargin < 4 || nargin > 6)
48 {
49 mexErrMsgTxt ("Usage: " USAGE) ;
50 }
51
52 // get M (shallow copy)
53 if (!mxIsChar (pargin [1]))
54 {
55 M = GB_mx_mxArray_to_Matrix (pargin [1], "M", false, false) ;
56 if (M == NULL && !mxIsEmpty (pargin [1]))
57 {
58 FREE_ALL ;
59 mexErrMsgTxt ("M failed") ;
60 }
61 }
62
63 // get A (shallow copy)
64 if (!mxIsChar (pargin [3]))
65 {
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
74 // get C (make a deep copy) and get any aliases for M and A
75 #define GET_DEEP_COPY \
76 { \
77 C = GB_mx_mxArray_to_Matrix (pargin [0], "C input", true, true) ; \
78 if (nargin > 5 && C != NULL) \
79 { \
80 C->nvec_nonempty = -1 ; /* for testing */ \
81 } \
82 if (mxIsChar (pargin [1])) \
83 { \
84 M = GB_mx_alias ("M", pargin [1], "C", C, "A", A) ; \
85 } \
86 if (mxIsChar (pargin [3])) \
87 { \
88 A = GB_mx_alias ("A", pargin [3], "C", C, "M", M) ; \
89 } \
90 }
91
92 #define FREE_DEEP_COPY \
93 { \
94 if (A == C) A = NULL ; \
95 if (M == C) M = NULL ; \
96 GrB_Matrix_free_(&C) ; \
97 }
98
99 GET_DEEP_COPY ;
100 if (C == NULL)
101 {
102 FREE_ALL ;
103 mexErrMsgTxt ("C failed") ;
104 }
105
106 // get accum; default: NOP, default is C->type
107 bool user_complex = (Complex != GxB_FC64)
108 && (C->type == Complex || A->type == Complex) ;
109 GrB_BinaryOp accum ;
110 if (!GB_mx_mxArray_to_BinaryOp (&accum, pargin [2], "accum",
111 C->type, user_complex))
112 {
113 FREE_ALL ;
114 mexErrMsgTxt ("accum failed") ;
115 }
116
117 // get desc
118 if (!GB_mx_mxArray_to_Descriptor (&desc, PARGIN (4), "desc"))
119 {
120 FREE_ALL ;
121 mexErrMsgTxt ("desc failed") ;
122 }
123
124 // just for testing
125 if (nargin > 5)
126 {
127 if (M != NULL) M->nvec_nonempty = -1 ;
128 A->nvec_nonempty = -1 ;
129 C->nvec_nonempty = -1 ;
130 }
131
132 // C<M> = op(C,A') or op(C,A)
133 METHOD (GrB_transpose (C, M, accum, A, desc)) ;
134
135 // return C to MATLAB as a struct and free the GraphBLAS C
136 if (C == A) A = NULL ; // do not free A if it is aliased to C
137 if (C == M) M = NULL ; // do not free M if it is aliased to C
138 pargout [0] = GB_mx_Matrix_to_mxArray (&C, "C output", true) ;
139 // C is now NULL
140
141 FREE_ALL ;
142 }
143
144