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