Commit 65c1aac005cfcc806e62502c6eabc4ec83352fc8
1 parent
c495d065
fixed memory leaks in stim::matrix
Showing
1 changed file
with
150 additions
and
34 deletions
Show diff stats
stim/math/matrix.h
@@ -17,42 +17,79 @@ class matrix { | @@ -17,42 +17,79 @@ class matrix { | ||
17 | size_t R; //number of rows | 17 | size_t R; //number of rows |
18 | size_t C; //number of colums | 18 | size_t C; //number of colums |
19 | 19 | ||
20 | - void init(size_t rows, size_t cols){ | 20 | + /*void init(size_t rows, size_t cols){ |
21 | R = rows; | 21 | R = rows; |
22 | C = cols; | 22 | C = cols; |
23 | - M = (T*) malloc (R * C * sizeof(T)); //allocate space for the matrix | 23 | + if (R == 0 || C == 0) M = NULL; |
24 | + else | ||
25 | + M = (T*)malloc(R * C * sizeof(T)); //allocate space for the matrix | ||
26 | + }*/ | ||
27 | + | ||
28 | + T get(const size_t row, const size_t col) const { | ||
29 | + if (row >= R || col >= C) { | ||
30 | + std::cout << "ERROR: row or column out of range." << std::endl; | ||
31 | + exit(1); | ||
32 | + } | ||
33 | + return M[col * R + row]; | ||
24 | } | 34 | } |
25 | 35 | ||
26 | T& at(size_t row, size_t col){ | 36 | T& at(size_t row, size_t col){ |
37 | + if (row >= R || col >= C) { | ||
38 | + std::cout << "ERROR: row or column out of range." << std::endl; | ||
39 | + exit(1); | ||
40 | + } | ||
27 | return M[col * R + row]; | 41 | return M[col * R + row]; |
28 | } | 42 | } |
29 | 43 | ||
30 | public: | 44 | public: |
31 | - | 45 | + matrix() { |
46 | + R = 0; | ||
47 | + C = 0; | ||
48 | + M = NULL; | ||
49 | + } | ||
50 | + | ||
32 | matrix(size_t rows, size_t cols) { | 51 | matrix(size_t rows, size_t cols) { |
33 | - init(rows, cols); //initialize memory | 52 | + R = rows; |
53 | + C = cols; | ||
54 | + if (R * C == 0) | ||
55 | + M = NULL; | ||
56 | + else | ||
57 | + M = new T[R * C]; | ||
34 | } | 58 | } |
35 | 59 | ||
36 | matrix(size_t rows, size_t cols, T* data) { | 60 | matrix(size_t rows, size_t cols, T* data) { |
37 | - init(rows, cols); | 61 | + R = rows; |
62 | + C = cols; | ||
63 | + if (R * C == 0) | ||
64 | + M = NULL; | ||
65 | + else | ||
66 | + M = new T[R * C]; | ||
38 | memcpy(M, data, R * C * sizeof(T)); | 67 | memcpy(M, data, R * C * sizeof(T)); |
39 | } | 68 | } |
40 | 69 | ||
41 | matrix(const matrix<T>& cpy){ | 70 | matrix(const matrix<T>& cpy){ |
42 | - init(cpy.R, cpy.C); | ||
43 | - memcpy(M, cpy.M, R * C * sizeof(T)); | 71 | + |
72 | + if (cpy.R * cpy.C == 0) | ||
73 | + M = NULL; | ||
74 | + else | ||
75 | + M = new T[cpy.R * cpy.C]; | ||
76 | + memcpy(M, cpy.M, cpy.R * cpy.C * sizeof(T)); | ||
77 | + | ||
78 | + R = cpy.R; | ||
79 | + C = cpy.C; | ||
44 | } | 80 | } |
45 | 81 | ||
46 | ~matrix() { | 82 | ~matrix() { |
47 | - R = C = 0; | ||
48 | if(M) free(M); | 83 | if(M) free(M); |
84 | + M = NULL; | ||
85 | + R = C = 0; | ||
49 | } | 86 | } |
50 | 87 | ||
51 | - size_t rows(){ | 88 | + size_t rows() const { |
52 | return R; | 89 | return R; |
53 | } | 90 | } |
54 | 91 | ||
55 | - size_t cols(){ | 92 | + size_t cols() const { |
56 | return C; | 93 | return C; |
57 | } | 94 | } |
58 | 95 | ||
@@ -60,10 +97,8 @@ public: | @@ -60,10 +97,8 @@ public: | ||
60 | return at(row, col); | 97 | return at(row, col); |
61 | } | 98 | } |
62 | 99 | ||
63 | - matrix<T> operator=(T rhs) { | ||
64 | - if (&rhs == this) | ||
65 | - return *this; | ||
66 | - init(R, C); | 100 | + matrix<T>& operator=(const T rhs) { |
101 | + //init(R, C); | ||
67 | size_t N = R * C; | 102 | size_t N = R * C; |
68 | for(size_t n=0; n<N; n++) | 103 | for(size_t n=0; n<N; n++) |
69 | M[n] = rhs; | 104 | M[n] = rhs; |
@@ -71,14 +106,21 @@ public: | @@ -71,14 +106,21 @@ public: | ||
71 | return *this; | 106 | return *this; |
72 | } | 107 | } |
73 | 108 | ||
74 | - matrix<T>& operator=(matrix<T> rhs){ | ||
75 | - init(rhs.R, rhs.C); | ||
76 | - memcpy(M, rhs.M, R * C * sizeof(T)); | 109 | + matrix<T>& operator=(const matrix<T>& rhs){ |
110 | + if (this != &rhs) { //if the matrix isn't self-assigned | ||
111 | + T* new_matrix = new T[rhs.R * rhs.C]; //allocate new resources | ||
112 | + memcpy(new_matrix, rhs.M, rhs.R * rhs.C * sizeof(T)); //copy the matrix | ||
113 | + | ||
114 | + delete[] M; //delete the previous array | ||
115 | + M = new_matrix; | ||
116 | + R = rhs.R; | ||
117 | + C = rhs.C; | ||
118 | + } | ||
77 | return *this; | 119 | return *this; |
78 | } | 120 | } |
79 | 121 | ||
80 | //element-wise operations | 122 | //element-wise operations |
81 | - matrix<T> operator+(T rhs) { | 123 | + matrix<T> operator+(const T rhs) const { |
82 | matrix<T> result(R, C); //create a result matrix | 124 | matrix<T> result(R, C); //create a result matrix |
83 | size_t N = R * C; | 125 | size_t N = R * C; |
84 | 126 | ||
@@ -88,11 +130,39 @@ public: | @@ -88,11 +130,39 @@ public: | ||
88 | return result; | 130 | return result; |
89 | } | 131 | } |
90 | 132 | ||
91 | - matrix<T> operator-(T rhs) { | 133 | + matrix<T> operator+(const matrix<T> rhs) const { |
134 | + if (R != rhs.R || C != rhs.C) { | ||
135 | + std::cout << "ERROR: addition is only defined for matrices that are the same size." << std::endl; | ||
136 | + exit(1); | ||
137 | + } | ||
138 | + matrix<T> result(R, C); //create a result matrix | ||
139 | + size_t N = R * C; | ||
140 | + | ||
141 | + for (int i = 0; i < N; i++) | ||
142 | + result.M[i] = M[i] + rhs.M[i]; //calculate the operation and assign to result | ||
143 | + | ||
144 | + return result; | ||
145 | + } | ||
146 | + | ||
147 | + matrix<T> operator-(const T rhs) const { | ||
92 | return operator+(-rhs); //add the negative of rhs | 148 | return operator+(-rhs); //add the negative of rhs |
93 | } | 149 | } |
94 | 150 | ||
95 | - matrix<T> operator*(T rhs) { | 151 | + matrix<T> operator-(const matrix<T> rhs) const { |
152 | + return operator+(-rhs); | ||
153 | + } | ||
154 | + | ||
155 | + matrix<T> operator-() const { | ||
156 | + matrix<T> result(R, C); //create a result matrix | ||
157 | + size_t N = R * C; | ||
158 | + | ||
159 | + for (int i = 0; i < N; i++) | ||
160 | + result.M[i] = -M[i]; //calculate the operation and assign to result | ||
161 | + | ||
162 | + return result; | ||
163 | + } | ||
164 | + | ||
165 | + matrix<T> operator*(const T rhs) const { | ||
96 | matrix<T> result(R, C); //create a result matrix | 166 | matrix<T> result(R, C); //create a result matrix |
97 | size_t N = R * C; | 167 | size_t N = R * C; |
98 | 168 | ||
@@ -102,7 +172,7 @@ public: | @@ -102,7 +172,7 @@ public: | ||
102 | return result; | 172 | return result; |
103 | } | 173 | } |
104 | 174 | ||
105 | - matrix<T> operator/(T rhs) { | 175 | + matrix<T> operator/(const T rhs) const { |
106 | matrix<T> result(R, C); //create a result matrix | 176 | matrix<T> result(R, C); //create a result matrix |
107 | size_t N = R * C; | 177 | size_t N = R * C; |
108 | 178 | ||
@@ -113,7 +183,7 @@ public: | @@ -113,7 +183,7 @@ public: | ||
113 | } | 183 | } |
114 | 184 | ||
115 | //matrix multiplication | 185 | //matrix multiplication |
116 | - matrix<T> operator*(matrix<T> rhs){ | 186 | + matrix<T> operator*(const matrix<T> rhs) const { |
117 | if(C != rhs.R){ | 187 | if(C != rhs.R){ |
118 | std::cout<<"ERROR: matrix multiplication is undefined for matrices of size "; | 188 | std::cout<<"ERROR: matrix multiplication is undefined for matrices of size "; |
119 | std::cout<<"[ "<<R<<" x "<<C<<" ] and [ "<<rhs.R<<" x "<<rhs.C<<"]"<<std::endl; | 189 | std::cout<<"[ "<<R<<" x "<<C<<" ] and [ "<<rhs.R<<" x "<<rhs.C<<"]"<<std::endl; |
@@ -127,7 +197,7 @@ public: | @@ -127,7 +197,7 @@ public: | ||
127 | for(r = 0; r < R; r++){ | 197 | for(r = 0; r < R; r++){ |
128 | inner = (T)0; | 198 | inner = (T)0; |
129 | for(i = 0; i < C; i++){ | 199 | for(i = 0; i < C; i++){ |
130 | - inner += at(r, i) * rhs.at(i, c); | 200 | + inner += get(r, i) * rhs.get(i, c); |
131 | } | 201 | } |
132 | result.M[c * R + r] = inner; | 202 | result.M[c * R + r] = inner; |
133 | } | 203 | } |
@@ -141,7 +211,7 @@ public: | @@ -141,7 +211,7 @@ public: | ||
141 | } | 211 | } |
142 | 212 | ||
143 | //return a transposed matrix | 213 | //return a transposed matrix |
144 | - matrix<T> transpose(){ | 214 | + matrix<T> transpose() const { |
145 | matrix<T> result(C, R); | 215 | matrix<T> result(C, R); |
146 | size_t c, r; | 216 | size_t c, r; |
147 | for(c = 0; c < C; c++){ | 217 | for(c = 0; c < C; c++){ |
@@ -152,8 +222,31 @@ public: | @@ -152,8 +222,31 @@ public: | ||
152 | return result; | 222 | return result; |
153 | } | 223 | } |
154 | 224 | ||
225 | + ///Calculate and return the determinant of the matrix | ||
226 | + T det() const { | ||
227 | + if (R != C) { | ||
228 | + std::cout << "ERROR: a determinant can only be calculated for a square matrix." << std::endl; | ||
229 | + exit(1); | ||
230 | + } | ||
231 | + if (R == 1) return M[0]; //if the matrix only contains one value, return it | ||
232 | + | ||
233 | + int r, c, ri, cia, cib; | ||
234 | + T a = 0; | ||
235 | + T b = 0; | ||
236 | + for (c = 0; c < C; c++) { | ||
237 | + for (r = 0; r < R; r++) { | ||
238 | + ri = r; | ||
239 | + cia = (r + c) % C; | ||
240 | + cib = (C - 1 - r) % C; | ||
241 | + a += get(ri, cia); | ||
242 | + b += get(ri, cib); | ||
243 | + } | ||
244 | + } | ||
245 | + return a - b; | ||
246 | + } | ||
247 | + | ||
155 | /// Sort rows of the matrix by the specified indices | 248 | /// Sort rows of the matrix by the specified indices |
156 | - matrix<T> sort_rows(size_t* idx) { | 249 | + matrix<T> sort_rows(size_t* idx) const { |
157 | matrix<T> result(C, R); //create the output matrix | 250 | matrix<T> result(C, R); //create the output matrix |
158 | size_t r, c; | 251 | size_t r, c; |
159 | for (c = 0; c < C; c++) { //for each column | 252 | for (c = 0; c < C; c++) { //for each column |
@@ -165,7 +258,7 @@ public: | @@ -165,7 +258,7 @@ public: | ||
165 | } | 258 | } |
166 | 259 | ||
167 | /// Sort columns of the matrix by the specified indices | 260 | /// Sort columns of the matrix by the specified indices |
168 | - matrix<T> sort_cols(size_t* idx) { | 261 | + matrix<T> sort_cols(size_t* idx) const { |
169 | matrix<T> result(C, R); | 262 | matrix<T> result(C, R); |
170 | size_t c; | 263 | size_t c; |
171 | for (c = 0; c < C; c++) { //for each column | 264 | for (c = 0; c < C; c++) { //for each column |
@@ -174,7 +267,7 @@ public: | @@ -174,7 +267,7 @@ public: | ||
174 | return result; | 267 | return result; |
175 | } | 268 | } |
176 | 269 | ||
177 | - std::string toStr() { | 270 | + std::string toStr() const { |
178 | std::stringstream ss; | 271 | std::stringstream ss; |
179 | 272 | ||
180 | for(int r = 0; r < R; r++) { | 273 | for(int r = 0; r < R; r++) { |
@@ -187,25 +280,35 @@ public: | @@ -187,25 +280,35 @@ public: | ||
187 | return ss.str(); | 280 | return ss.str(); |
188 | } | 281 | } |
189 | 282 | ||
190 | - std::string csv() { | ||
191 | - std::stringstream csvss; | 283 | + void csv(std::ostream& out) const { |
284 | + //std::stringstream csvss; | ||
192 | for (size_t i = 0; i < R; i++) { | 285 | for (size_t i = 0; i < R; i++) { |
193 | - csvss << M[i]; | ||
194 | - for (size_t j = 0; j < C; j++) csvss << ", " << M[j * R + i]; | ||
195 | - csvss << std::endl; | 286 | + out << std::fixed << M[i]; |
287 | + for (size_t j = 1; j < C; j++) | ||
288 | + out << ", " << std::fixed << M[j * R + i]; | ||
289 | + out << std::endl; | ||
196 | } | 290 | } |
291 | + //return csvss.str(); | ||
292 | + } | ||
293 | + | ||
294 | + std::string csv() const { | ||
295 | + std::stringstream csvss; | ||
296 | + int digits = std::numeric_limits<double>::max_digits10; | ||
297 | + csvss.precision(digits); | ||
298 | + csv(csvss); | ||
197 | return csvss.str(); | 299 | return csvss.str(); |
198 | } | 300 | } |
199 | 301 | ||
302 | + | ||
303 | + | ||
200 | //save the data as a CSV file | 304 | //save the data as a CSV file |
201 | - void csv(std::string filename) { | 305 | + void csv(std::string filename) const { |
202 | ofstream basisfile(filename.c_str()); | 306 | ofstream basisfile(filename.c_str()); |
203 | basisfile << csv(); | 307 | basisfile << csv(); |
204 | basisfile.close(); | 308 | basisfile.close(); |
205 | } | 309 | } |
206 | 310 | ||
207 | static matrix<T> I(size_t N) { | 311 | static matrix<T> I(size_t N) { |
208 | - | ||
209 | matrix<T> result(N, N); //create the identity matrix | 312 | matrix<T> result(N, N); //create the identity matrix |
210 | memset(result.M, 0, N * N * sizeof(T)); //set the entire matrix to zero | 313 | memset(result.M, 0, N * N * sizeof(T)); //set the entire matrix to zero |
211 | for (size_t n = 0; n < N; n++) { | 314 | for (size_t n = 0; n < N; n++) { |
@@ -214,6 +317,19 @@ public: | @@ -214,6 +317,19 @@ public: | ||
214 | return result; | 317 | return result; |
215 | } | 318 | } |
216 | 319 | ||
320 | + //loads a matrix from a stream in CSV format | ||
321 | + void csv(std::istream& in) { | ||
322 | + size_t c, r; | ||
323 | + T v; | ||
324 | + for (r = 0; r < R; r++) { | ||
325 | + for (c = 0; c < C; c++) { | ||
326 | + in >> v; | ||
327 | + if (in.peek() == ',') in.seekg(1, std::ios::cur); | ||
328 | + at(r, c) = v;; | ||
329 | + } | ||
330 | + } | ||
331 | + } | ||
332 | + | ||
217 | }; | 333 | }; |
218 | 334 | ||
219 | } //end namespace rts | 335 | } //end namespace rts |