1 //------------------------------------------------------------------------------
2 // GB_mex_edit: add/remove entries from 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 #include "GB_mex.h"
11 
12 #define USAGE "C = GB_mex_edit (C, I, J, X, Action)"
13 
14 #define FREE_ALL                        \
15 {                                       \
16     GrB_Matrix_free_(&C) ;              \
17     GB_mx_put_global (true) ;           \
18 }
19 
20 #define OK(method)                      \
21 {                                       \
22     info = method ;                     \
23     if (info != GrB_SUCCESS)            \
24     {                                   \
25         mexErrMsgTxt ("fail") ;         \
26     }                                   \
27 }
28 
mexFunction(int nargout,mxArray * pargout[],int nargin,const mxArray * pargin[])29 void mexFunction
30 (
31     int nargout,
32     mxArray *pargout [ ],
33     int nargin,
34     const mxArray *pargin [ ]
35 )
36 {
37 
38     GrB_Matrix C = NULL ;
39     GrB_Index *I = NULL, ni = 0, I_range [3] ;
40     GrB_Index *J = NULL, nj = 0, J_range [3] ;
41     bool ignore ;
42     bool malloc_debug = false ;
43     GrB_Info info = GrB_SUCCESS ;
44     int64_t nwork = 0 ;
45 
46     //--------------------------------------------------------------------------
47     // check inputs
48     //--------------------------------------------------------------------------
49 
50     malloc_debug = GB_mx_get_global (true) ;
51     C = NULL ;
52 
53     // check inputs
54     if (nargout > 1 || nargin != 5)
55     {
56         mexErrMsgTxt ("Usage: " USAGE) ;
57     }
58 
59     //--------------------------------------------------------------------------
60     // get C (make a deep copy)
61     //--------------------------------------------------------------------------
62 
63     C = GB_mx_mxArray_to_Matrix (pargin [0], "C input", true, true) ;
64     if (C == NULL)
65     {
66         FREE_ALL ;
67         mexErrMsgTxt ("C failed") ;
68     }
69 
70     GrB_Index ncols ;
71     GxB_Format_Value fmt ;
72     bool is_hyper ;
73     OK (GrB_Matrix_ncols (&ncols, C)) ;
74     OK (GxB_Matrix_Option_get (C, GxB_FORMAT, &fmt)) ;
75     OK (GxB_Matrix_Option_get (C, GxB_IS_HYPER, &is_hyper)) ;   // historical
76     bool is_vector = (fmt == GxB_BY_COL && !is_hyper && ncols == 1) ;
77 
78     // get I
79     if (!GB_mx_mxArray_to_indices (&I, pargin [1], &ni, I_range, &ignore))
80     {
81         FREE_ALL ;
82         mexErrMsgTxt ("I failed") ;
83     }
84 
85     // get J
86     if (!GB_mx_mxArray_to_indices (&J, pargin [2], &nj, J_range, &ignore))
87     {
88         FREE_ALL ;
89         mexErrMsgTxt ("J failed") ;
90     }
91 
92     // get X; must be double
93     double *X = mxGetDoubles (pargin [3]) ;
94 
95     // get Action: must be double
96     double *Action = mxGetDoubles (pargin [4]) ;
97 
98     nwork = ni ;
99     if (nwork != nj ||
100         nwork != mxGetNumberOfElements (pargin [3]) ||
101         nwork != mxGetNumberOfElements (pargin [4]) ||
102         mxGetClassID (pargin [3]) != mxDOUBLE_CLASS ||
103         mxGetClassID (pargin [4]) != mxDOUBLE_CLASS)
104     {
105         mexErrMsgTxt ("Usage: " USAGE) ;
106     }
107 
108     //--------------------------------------------------------------------------
109     // turn off malloc debugging
110     //--------------------------------------------------------------------------
111 
112     bool save = GB_Global_malloc_debug_get ( ) ;
113     GB_Global_malloc_debug_set (false) ;
114 
115     //--------------------------------------------------------------------------
116     // edit the matrix
117     //--------------------------------------------------------------------------
118 
119     for (int64_t k = 0 ; k < nwork ; k++)
120     {
121         int64_t i = I [k] - 1 ;
122         int64_t j = J [k] - 1 ;
123         double x = X [k] ;
124         double action = Action [k] ;
125         if (action == 0)
126         {
127             // remove the (i,j) entry
128             if (is_vector)
129             {
130                 OK (GrB_Vector_removeElement ((GrB_Vector) C, i)) ;
131             }
132             else
133             {
134                 OK (GrB_Matrix_removeElement (C, i, j)) ;
135             }
136         }
137         else
138         {
139             // add the (i,j) entry
140             if (is_vector)
141             {
142                 OK (GrB_Vector_setElement_FP64_ ((GrB_Vector) C, x, i)) ;
143             }
144             else
145             {
146                 OK (GrB_Matrix_setElement_FP64_ (C, x, i, j)) ;
147             }
148         }
149     }
150 
151     //--------------------------------------------------------------------------
152     // restore malloc debugging to test the method
153     //--------------------------------------------------------------------------
154 
155     GB_Global_malloc_debug_set (save) ;
156 
157     //--------------------------------------------------------------------------
158     // return C to MATLAB as a MATLAB sparse matrix
159     //--------------------------------------------------------------------------
160 
161     pargout [0] = GB_mx_Matrix_to_mxArray (&C, "C mex_edit result", false) ;
162     FREE_ALL ;
163 }
164 
165