Commit 0796cf5e4c40ac03ad29f7d4cc5bfd6ae6f3a0e6
1 parent
c6e119fa
First implementation of sparse matrix class.
Showing
20 changed files
with
7337 additions
and
1404 deletions
src/GMatrix.cpp
| ... | ... | @@ -18,20 +18,51 @@ |
| 18 | 18 | using namespace std; |
| 19 | 19 | |
| 20 | 20 | |
| 21 | +/*========================================================================== | |
| 22 | + = = | |
| 23 | + = GMatrix constructors/destructors = | |
| 24 | + = = | |
| 25 | + ==========================================================================*/ | |
| 26 | + | |
| 27 | +/*************************************************************************** | |
| 28 | + * GMatrix private constructor (used for derived class initialization) * | |
| 29 | + ***************************************************************************/ | |
| 30 | +GMatrix::GMatrix(void) | |
| 31 | +{ | |
| 32 | + // Initialise private members for clean destruction | |
| 33 | + m_rows = 0; | |
| 34 | + m_cols = 0; | |
| 35 | + m_elements = 0; | |
| 36 | + m_num_rowsel = 0; | |
| 37 | + m_num_colsel = 0; | |
| 38 | + m_data = NULL; | |
| 39 | + m_colstart = NULL; | |
| 40 | + m_rowsel = NULL; | |
| 41 | + m_colsel = NULL; | |
| 42 | + | |
| 43 | + // Return | |
| 44 | + return; | |
| 45 | +} | |
| 46 | + | |
| 47 | + | |
| 21 | 48 | /*************************************************************************** |
| 22 | 49 | * GMatrix constructor * |
| 23 | 50 | ***************************************************************************/ |
| 24 | -GMatrix::GMatrix(unsigned rows, unsigned cols) | |
| 51 | +GMatrix::GMatrix(int rows, int cols) | |
| 25 | 52 | { |
| 26 | 53 | // Initialise private members for clean destruction |
| 27 | - m_rows = 0; | |
| 28 | - m_cols = 0; | |
| 29 | - m_elements = 0; | |
| 30 | - m_data = NULL; | |
| 31 | - m_colstart = NULL; | |
| 54 | + m_rows = 0; | |
| 55 | + m_cols = 0; | |
| 56 | + m_elements = 0; | |
| 57 | + m_num_rowsel = 0; | |
| 58 | + m_num_colsel = 0; | |
| 59 | + m_data = NULL; | |
| 60 | + m_colstart = NULL; | |
| 61 | + m_rowsel = NULL; | |
| 62 | + m_colsel = NULL; | |
| 32 | 63 | |
| 33 | 64 | // Determine number of physical elements in matrix |
| 34 | - unsigned elements = rows*cols; | |
| 65 | + int elements = rows*cols; | |
| 35 | 66 | |
| 36 | 67 | // Throw exception if requested matrix size is zero |
| 37 | 68 | if (elements == 0) |
| ... | ... | @@ -40,7 +71,7 @@ GMatrix::GMatrix(unsigned rows, unsigned cols) |
| 40 | 71 | // Allocate matrix array and column start index array. Throw an exception |
| 41 | 72 | // if allocation failed |
| 42 | 73 | m_data = new double[elements]; |
| 43 | - m_colstart = new unsigned[cols+1]; | |
| 74 | + m_colstart = new int[cols+1]; | |
| 44 | 75 | if (m_data == NULL || m_colstart == NULL) |
| 45 | 76 | throw mem_alloc("GMatrix constructor", elements); |
| 46 | 77 | |
| ... | ... | @@ -51,36 +82,80 @@ GMatrix::GMatrix(unsigned rows, unsigned cols) |
| 51 | 82 | |
| 52 | 83 | // Set-up column start indices |
| 53 | 84 | m_colstart[0] = 0; |
| 54 | - for (unsigned col = 1; col <= m_cols; ++col) | |
| 85 | + for (int col = 1; col <= m_cols; ++col) | |
| 55 | 86 | m_colstart[col] = m_colstart[col-1] + m_rows; |
| 56 | 87 | |
| 57 | 88 | // Initialise matrix elements to 0.0 |
| 58 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 89 | + for (int i = 0; i < m_elements; ++i) | |
| 59 | 90 | m_data[i] = 0.0; |
| 91 | + | |
| 92 | + // Return | |
| 93 | + return; | |
| 60 | 94 | } |
| 61 | 95 | |
| 62 | 96 | |
| 63 | 97 | /*************************************************************************** |
| 64 | - * GMatrix copy constructor * | |
| 98 | + * GMatrix copy constructor * | |
| 99 | + * ----------------------------------------------------------------------- * | |
| 100 | + * The copy constructor is sufficiently general to provide the base * | |
| 101 | + * constructor for all derived classes, including sparse matrices. * | |
| 65 | 102 | ***************************************************************************/ |
| 66 | 103 | GMatrix::GMatrix(const GMatrix& m) |
| 67 | 104 | { |
| 68 | - m_rows = 0; | |
| 69 | - m_cols = 0; | |
| 70 | - m_elements = 0; | |
| 71 | - m_data = NULL; | |
| 72 | - m_colstart = NULL; | |
| 73 | - m_data = new double[m.m_elements]; | |
| 74 | - m_colstart = new unsigned[m.m_cols+1]; | |
| 75 | - if (m_data == NULL || m_colstart == NULL) | |
| 76 | - throw mem_alloc("GMatrix copy constructor", m.m_elements); | |
| 105 | + // Initialise private members for clean destruction | |
| 106 | + m_rows = 0; | |
| 107 | + m_cols = 0; | |
| 108 | + m_elements = 0; | |
| 109 | + m_num_rowsel = 0; | |
| 110 | + m_num_colsel = 0; | |
| 111 | + m_data = NULL; | |
| 112 | + m_colstart = NULL; | |
| 113 | + m_rowsel = NULL; | |
| 114 | + m_colsel = NULL; | |
| 115 | + | |
| 116 | + // Allocate memory for column start array and copy content | |
| 117 | + m_colstart = new int[m.m_cols+1]; | |
| 118 | + if (m_colstart == NULL) | |
| 119 | + throw mem_alloc("GMatrix copy constructor", m.m_cols+1); | |
| 120 | + for (int i = 0; i <= m.m_cols; ++i) | |
| 121 | + m_colstart[i] = m.m_colstart[i]; | |
| 122 | + | |
| 123 | + // Allocate memory for elements and copy them (only if there are elements) | |
| 124 | + if (m.m_elements > 0) { | |
| 125 | + m_data = new double[m.m_elements]; | |
| 126 | + if (m_data == NULL) | |
| 127 | + throw mem_alloc("GMatrix copy constructor", m.m_elements); | |
| 128 | + for (int i = 0; i < m.m_elements; ++i) | |
| 129 | + m_data[i] = m.m_data[i]; | |
| 130 | + } | |
| 131 | + | |
| 132 | + // If there is a row selection then copy it | |
| 133 | + if (m.m_rowsel != NULL && m.m_num_rowsel > 0) { | |
| 134 | + m_rowsel = new int[m.m_num_rowsel]; | |
| 135 | + if (m_rowsel == NULL) | |
| 136 | + throw mem_alloc("GMatrix copy constructor", m.m_num_rowsel); | |
| 137 | + for (int i = 0; i < m.m_num_rowsel; ++i) | |
| 138 | + m_rowsel[i] = m.m_rowsel[i]; | |
| 139 | + m_num_rowsel = m.m_num_rowsel; | |
| 140 | + } | |
| 141 | + | |
| 142 | + // If there is a column selection then copy it | |
| 143 | + if (m.m_colsel != NULL && m.m_num_colsel > 0) { | |
| 144 | + m_colsel = new int[m.m_num_colsel]; | |
| 145 | + if (m_colsel == NULL) | |
| 146 | + throw mem_alloc("GMatrix copy constructor", m.m_num_colsel); | |
| 147 | + for (int i = 0; i < m.m_num_colsel; ++i) | |
| 148 | + m_colsel[i] = m.m_colsel[i]; | |
| 149 | + m_num_colsel = m.m_num_colsel; | |
| 150 | + } | |
| 151 | + | |
| 152 | + // Copy matrix attributes | |
| 77 | 153 | m_rows = m.m_rows; |
| 78 | 154 | m_cols = m.m_cols; |
| 79 | 155 | m_elements = m.m_elements; |
| 80 | - for (unsigned i = 0; i <= m_cols; ++i) | |
| 81 | - m_colstart[i] = m.m_colstart[i]; | |
| 82 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 83 | - m_data[i] = m.m_data[i]; | |
| 156 | + | |
| 157 | + // Return | |
| 158 | + return; | |
| 84 | 159 | } |
| 85 | 160 | |
| 86 | 161 | |
| ... | ... | @@ -90,104 +165,591 @@ GMatrix::GMatrix(const GMatrix& m) |
| 90 | 165 | GMatrix::~GMatrix() |
| 91 | 166 | { |
| 92 | 167 | // De-allocate only if memory has indeed been allocated |
| 93 | - if (m_colstart != NULL) delete[] m_colstart; | |
| 94 | - if (m_data != NULL) delete[] m_data; | |
| 168 | + if (m_colstart != NULL) delete [] m_colstart; | |
| 169 | + if (m_rowsel != NULL) delete [] m_rowsel; | |
| 170 | + if (m_colsel != NULL) delete [] m_colsel; | |
| 171 | + if (m_data != NULL) delete [] m_data; | |
| 172 | + | |
| 173 | + // Return | |
| 174 | + return; | |
| 95 | 175 | } |
| 96 | 176 | |
| 97 | 177 | |
| 178 | +/*========================================================================== | |
| 179 | + = = | |
| 180 | + = GMatrix operators = | |
| 181 | + = = | |
| 182 | + ==========================================================================*/ | |
| 183 | + | |
| 98 | 184 | /*************************************************************************** |
| 99 | 185 | * GMatrix assignment operator * |
| 100 | 186 | ***************************************************************************/ |
| 101 | 187 | GMatrix& GMatrix::operator= (const GMatrix& m) |
| 102 | 188 | { |
| 103 | - m_rows = 0; | |
| 104 | - m_cols = 0; | |
| 105 | - m_elements = 0; | |
| 106 | - m_data = NULL; | |
| 107 | - m_colstart = NULL; | |
| 108 | - m_data = new double[m.m_elements]; | |
| 109 | - m_colstart = new unsigned[m.m_cols+1]; | |
| 110 | - if (m_data == NULL || m_colstart == NULL) | |
| 111 | - throw mem_alloc("GMatrix assignment operator", m.m_elements); | |
| 112 | - m_rows = m.m_rows; | |
| 113 | - m_cols = m.m_cols; | |
| 114 | - m_elements = m.m_elements; | |
| 115 | - for (unsigned i = 0; i <= m_cols; ++i) | |
| 116 | - m_colstart[i] = m.m_colstart[i]; | |
| 117 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 118 | - m_data[i] = m.m_data[i]; | |
| 119 | - return *this; | |
| 120 | -} | |
| 189 | + // Execute only if object is not identical | |
| 190 | + if (this != &m) { | |
| 191 | + | |
| 192 | + // De-allocate memory if it has indeed been allocated | |
| 193 | + if (m_colstart != NULL) delete [] m_colstart; | |
| 194 | + if (m_rowsel != NULL) delete [] m_rowsel; | |
| 195 | + if (m_colsel != NULL) delete [] m_colsel; | |
| 196 | + if (m_data != NULL) delete [] m_data; | |
| 197 | + | |
| 198 | + // Initialise private members for clean destruction | |
| 199 | + m_rows = 0; | |
| 200 | + m_cols = 0; | |
| 201 | + m_elements = 0; | |
| 202 | + m_num_rowsel = 0; | |
| 203 | + m_num_colsel = 0; | |
| 204 | + m_data = NULL; | |
| 205 | + m_colstart = NULL; | |
| 206 | + m_rowsel = NULL; | |
| 207 | + m_colsel = NULL; | |
| 208 | + | |
| 209 | + // Allocate memory for column start array and copy content | |
| 210 | + m_colstart = new int[m.m_cols+1]; | |
| 211 | + if (m_colstart == NULL) | |
| 212 | + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_cols+1); | |
| 213 | + for (int i = 0; i <= m.m_cols; ++i) | |
| 214 | + m_colstart[i] = m.m_colstart[i]; | |
| 215 | + | |
| 216 | + // Allocate memory for elements and copy them (only if there are elements) | |
| 217 | + if (m.m_elements > 0) { | |
| 218 | + m_data = new double[m.m_elements]; | |
| 219 | + if (m_data == NULL) | |
| 220 | + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_elements); | |
| 221 | + for (int i = 0; i < m.m_elements; ++i) | |
| 222 | + m_data[i] = m.m_data[i]; | |
| 223 | + } | |
| 121 | 224 | |
| 225 | + // If there is a row selection then copy it | |
| 226 | + if (m.m_rowsel != NULL && m.m_num_rowsel > 0) { | |
| 227 | + m_rowsel = new int[m.m_num_rowsel]; | |
| 228 | + if (m_rowsel == NULL) | |
| 229 | + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_num_rowsel); | |
| 230 | + for (int i = 0; i < m.m_num_rowsel; ++i) | |
| 231 | + m_rowsel[i] = m.m_rowsel[i]; | |
| 232 | + m_num_rowsel = m.m_num_rowsel; | |
| 233 | + } | |
| 122 | 234 | |
| 123 | -/*************************************************************************** | |
| 124 | - * GMatrix output operator * | |
| 125 | - ***************************************************************************/ | |
| 126 | -ostream& operator<< (ostream& os, const GMatrix& m) | |
| 127 | -{ | |
| 128 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 129 | - for (unsigned col = 0; col < m.m_cols; ++col) { | |
| 130 | - os << m(row,col); | |
| 131 | - if (col != m.m_cols-1) | |
| 132 | - os << ", "; | |
| 133 | - } | |
| 134 | - if (row != m.m_rows-1) | |
| 135 | - os << endl; | |
| 136 | - } | |
| 137 | - return os; | |
| 235 | + // If there is a column selection then copy it | |
| 236 | + if (m.m_colsel != NULL && m.m_num_colsel > 0) { | |
| 237 | + m_colsel = new int[m.m_num_colsel]; | |
| 238 | + if (m_colsel == NULL) | |
| 239 | + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_num_colsel); | |
| 240 | + for (int i = 0; i < m.m_num_colsel; ++i) | |
| 241 | + m_colsel[i] = m.m_colsel[i]; | |
| 242 | + m_num_colsel = m.m_num_colsel; | |
| 243 | + } | |
| 244 | + | |
| 245 | + // Copy matrix attributes | |
| 246 | + m_rows = m.m_rows; | |
| 247 | + m_cols = m.m_cols; | |
| 248 | + m_elements = m.m_elements; | |
| 249 | + } // endif: object was not identical | |
| 250 | + | |
| 251 | + // Return this object | |
| 252 | + return *this; | |
| 138 | 253 | } |
| 139 | 254 | |
| 140 | 255 | |
| 141 | 256 | /*************************************************************************** |
| 142 | - * GMatrix * Gvector multiplication * | |
| 257 | + * Vector multiplication * | |
| 143 | 258 | ***************************************************************************/ |
| 144 | 259 | GVector GMatrix::operator* (const GVector& v) const |
| 145 | 260 | { |
| 146 | 261 | // Raise an exception if the matrix and vector dimensions are not compatible |
| 147 | 262 | if (m_cols != v.m_num) |
| 148 | - throw vec_mat_mismatch("GMatrix*GVector operator", v.m_num, m_rows, m_cols); | |
| 263 | + throw matrix_vector_mismatch("GMatrix::operator* (const GVector&)", | |
| 264 | + v.m_num, m_rows, m_cols); | |
| 149 | 265 | |
| 150 | 266 | // Perform vector multiplication |
| 151 | 267 | GVector result(m_rows); |
| 152 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 268 | + for (int row = 0; row < m_rows; ++row) { | |
| 153 | 269 | double sum = 0.0; |
| 154 | - for (unsigned col = 0; col < m_cols; ++col) | |
| 270 | + for (int col = 0; col < m_cols; ++col) | |
| 155 | 271 | sum += (*this)(row,col) * v(col); |
| 156 | 272 | result(row) = sum; |
| 157 | 273 | } |
| 274 | + | |
| 275 | + // Return result | |
| 276 | + return result; | |
| 277 | +} | |
| 278 | + | |
| 279 | + | |
| 280 | +/*************************************************************************** | |
| 281 | + * GMatrix comparison (equality operator) * | |
| 282 | + ***************************************************************************/ | |
| 283 | +int GMatrix::operator== (const GMatrix &m) const | |
| 284 | +{ | |
| 285 | + // Initalise the result to 'equal matrices' | |
| 286 | + int result = 1; | |
| 287 | + | |
| 288 | + // Perform comparison (only if matrix dimensions and number of physical | |
| 289 | + // elements are identical; otherwise set result to 'false') | |
| 290 | + if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { | |
| 291 | + for (int i = 0; i < m_elements; ++i) { | |
| 292 | + if (m_data[i] != m.m_data[i]) { | |
| 293 | + result = 0; | |
| 294 | + break; | |
| 295 | + } | |
| 296 | + } | |
| 297 | + } | |
| 298 | + else | |
| 299 | + result = 0; | |
| 300 | + | |
| 301 | + // Return result | |
| 302 | + return result; | |
| 303 | +} | |
| 304 | + | |
| 305 | + | |
| 306 | +/*************************************************************************** | |
| 307 | + * GMatrix comparison (non-equality operator) * | |
| 308 | + ***************************************************************************/ | |
| 309 | +int GMatrix::operator!= (const GMatrix &m) const | |
| 310 | +{ | |
| 311 | + // Initalise the result to 'equal matrices' | |
| 312 | + int result = 0; | |
| 313 | + | |
| 314 | + // Perform comparison (only if matrix dimensions and number of physical | |
| 315 | + // elements are identical; otherwise set result to 'true') | |
| 316 | + if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { | |
| 317 | + for (int i = 0; i < m_elements; ++i) { | |
| 318 | + if (m_data[i] != m.m_data[i]) { | |
| 319 | + result = 1; | |
| 320 | + break; | |
| 321 | + } | |
| 322 | + } | |
| 323 | + } | |
| 324 | + else | |
| 325 | + result = 1; | |
| 326 | + | |
| 327 | + // Return result | |
| 158 | 328 | return result; |
| 159 | 329 | } |
| 160 | 330 | |
| 161 | 331 | |
| 162 | 332 | /*************************************************************************** |
| 163 | - * GMatrix * GMatrix multiplication * | |
| 333 | + * GMatrix negation (unary minus operator) * | |
| 164 | 334 | ***************************************************************************/ |
| 165 | -GMatrix GMatrix::operator* (const GMatrix& m) const | |
| 335 | +GMatrix GMatrix::operator- ( ) const | |
| 336 | +{ | |
| 337 | + // Copy argument into result | |
| 338 | + GMatrix result = *this; | |
| 339 | + | |
| 340 | + // Negate result | |
| 341 | + for (int i = 0; i < m_elements; ++i) | |
| 342 | + result.m_data[i] = -result.m_data[i]; | |
| 343 | + | |
| 344 | + // Return result | |
| 345 | + return result; | |
| 346 | +} | |
| 347 | + | |
| 348 | + | |
| 349 | +/*************************************************************************** | |
| 350 | + * GMatrix addition (unary addition operator) * | |
| 351 | + ***************************************************************************/ | |
| 352 | +GMatrix& GMatrix::operator+= (const GMatrix& m) | |
| 353 | +{ | |
| 354 | + // Raise an exception if the matrix dimensions are not compatible | |
| 355 | + if (m_rows != m.m_rows || m_cols != m.m_cols) | |
| 356 | + throw matrix_mismatch("GMatrix::operator+= (const GMatrix&)", | |
| 357 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 358 | + | |
| 359 | + // Add matrices | |
| 360 | + for (int i = 0; i < m_elements; ++i) | |
| 361 | + m_data[i] += m.m_data[i]; | |
| 362 | + | |
| 363 | + // Return result | |
| 364 | + return *this; | |
| 365 | +} | |
| 366 | + | |
| 367 | + | |
| 368 | +/*************************************************************************** | |
| 369 | + * GMatrix subtraction (unary subtraction operator) * | |
| 370 | + ***************************************************************************/ | |
| 371 | +GMatrix& GMatrix::operator-= (const GMatrix& m) | |
| 372 | +{ | |
| 373 | + // Raise an exception if the matrix dimensions are not compatible | |
| 374 | + if (m_rows != m.m_rows || m_cols != m.m_cols) | |
| 375 | + throw matrix_mismatch("GMatrix::operator-= (const GMatrix&)", | |
| 376 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 377 | + | |
| 378 | + // Subtract matrices | |
| 379 | + for (int i = 0; i < m_elements; ++i) | |
| 380 | + m_data[i] -= m.m_data[i]; | |
| 381 | + | |
| 382 | + // Return result | |
| 383 | + return *this; | |
| 384 | +} | |
| 385 | + | |
| 386 | + | |
| 387 | +/*************************************************************************** | |
| 388 | + * Matrix multiplication (unary multiplication operator) * | |
| 389 | + * ----------------------------------------------------------------------- * | |
| 390 | + * In case of rectangular matrices the result matrix does not change and * | |
| 391 | + * the operations can be performed 'quasi' inplace (except of a vector). * | |
| 392 | + * For the general case the result matrix changes the size so for * | |
| 393 | + * simplicity a new matrix is allocated to hold the results. * | |
| 394 | + ***************************************************************************/ | |
| 395 | +GMatrix& GMatrix::operator*= (const GMatrix& m) | |
| 166 | 396 | { |
| 167 | 397 | // Raise an exception if the matrix dimensions are not compatible |
| 168 | 398 | if (m_cols != m.m_rows) |
| 169 | - throw GMatrix::dim_mult_mismatch("GMatrix multiplication", m_cols, m.m_rows); | |
| 170 | - | |
| 171 | - // Perform matrix multiplication | |
| 172 | - GMatrix result(m_rows,m.m_cols); | |
| 173 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 174 | - for (unsigned col = 0; col < m.m_cols; ++col) { | |
| 175 | - double sum = 0.0; | |
| 176 | - for (unsigned i = 0; i < m_cols; ++i) | |
| 177 | - sum += (*this)(row,i)*m(i,col); | |
| 178 | - result(row,col) = sum; | |
| 399 | + throw matrix_mismatch("GMatrix::operator*= (const GMatrix&)", | |
| 400 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 401 | + | |
| 402 | + // Case A: Matrices are rectangular, so perform 'inplace' multiplication | |
| 403 | + if (m_rows == m_cols) { | |
| 404 | + for (int row = 0; row < m_rows; ++row) { | |
| 405 | + GVector v_row = extract_row(row); | |
| 406 | + for (int col = 0; col < m_cols; ++col) { | |
| 407 | + double sum = 0.0; | |
| 408 | + for (int i = 0; i < m_cols; ++i) | |
| 409 | + sum += v_row(i) * m(i,col); | |
| 410 | + (*this)(row,col) = sum; | |
| 411 | + } | |
| 179 | 412 | } |
| 180 | 413 | } |
| 414 | + | |
| 415 | + // Case B: Matrices are not rectangular, so we cannot work inplace | |
| 416 | + else { | |
| 417 | + | |
| 418 | + // Allocate result matrix | |
| 419 | + GMatrix result(m_rows, m.m_cols); | |
| 420 | + | |
| 421 | + // Loop over all elements of result matrix | |
| 422 | + for (int row = 0; row < m_rows; ++row) { | |
| 423 | + for (int col = 0; col < m.m_cols; ++col) { | |
| 424 | + double sum = 0.0; | |
| 425 | + for (int i = 0; i < m_cols; ++i) | |
| 426 | + sum += (*this)(row,i) * m(i,col); | |
| 427 | + result(row,col) = sum; | |
| 428 | + } | |
| 429 | + } | |
| 430 | + | |
| 431 | + // Assign result | |
| 432 | + *this = result; | |
| 433 | + | |
| 434 | + } // endelse: matrices were not rectangular | |
| 435 | + | |
| 436 | + // Return result | |
| 437 | + return *this; | |
| 438 | +} | |
| 439 | + | |
| 440 | + | |
| 441 | +/*************************************************************************** | |
| 442 | + * GMatrix scalar multiplication (unary scalar multiplication operator) * | |
| 443 | + ***************************************************************************/ | |
| 444 | +GMatrix& GMatrix::operator*= (const double& d) | |
| 445 | +{ | |
| 446 | + // Case A: If multiplicator is 0.0 then set entire matrix to 0.0 | |
| 447 | + if (d == 0.0) { | |
| 448 | + for (int i = 0; i < m_elements; ++i) | |
| 449 | + m_data[i] = 0.0; | |
| 450 | + } | |
| 451 | + | |
| 452 | + // Case B: If multiplicator is not +/- 1.0 then perform multiplication | |
| 453 | + else if (fabs(d) != 1.0) { | |
| 454 | + for (int i = 0; i < m_elements; ++i) | |
| 455 | + m_data[i] *= d; | |
| 456 | + } | |
| 457 | + | |
| 458 | + // Case C: If multiplication is -1.0 then negate | |
| 459 | + else if (d == -1.0) { | |
| 460 | + for (int i = 0; i < m_elements; ++i) | |
| 461 | + m_data[i] = -m_data[i]; | |
| 462 | + } | |
| 463 | + | |
| 464 | + // Return result | |
| 465 | + return *this; | |
| 466 | +} | |
| 467 | + | |
| 468 | + | |
| 469 | +/*************************************************************************** | |
| 470 | + * Matrix scalar division (unary scalar division operator) * | |
| 471 | + ***************************************************************************/ | |
| 472 | +GMatrix& GMatrix::operator/= (const double& d) | |
| 473 | +{ | |
| 474 | + // Case A: If divider is not +/- 1.0 then perform division | |
| 475 | + if (fabs(d) != 1.0) { | |
| 476 | + for (int i = 0; i < m_elements; ++i) | |
| 477 | + m_data[i] /= d; | |
| 478 | + } | |
| 479 | + | |
| 480 | + // Case B: If divider is -1.0 then negate | |
| 481 | + else if (d == -1.0) { | |
| 482 | + for (int i = 0; i < m_elements; ++i) | |
| 483 | + m_data[i] = -m_data[i]; | |
| 484 | + } | |
| 485 | + | |
| 486 | + // Return result | |
| 487 | + return *this; | |
| 488 | +} | |
| 489 | + | |
| 490 | + | |
| 491 | +/*========================================================================== | |
| 492 | + = = | |
| 493 | + = GMatrix member functions = | |
| 494 | + = = | |
| 495 | + ==========================================================================*/ | |
| 496 | + | |
| 497 | +/*************************************************************************** | |
| 498 | + * Get minimum physical matrix element * | |
| 499 | + ***************************************************************************/ | |
| 500 | +double GMatrix::min() const | |
| 501 | +{ | |
| 502 | + // Initialise minimum with first element | |
| 503 | + double result = m_data[0]; | |
| 504 | + | |
| 505 | + // Search all elements for the smallest one | |
| 506 | + for (int i = 1; i < m_elements; ++i) { | |
| 507 | + if (m_data[i] < result) | |
| 508 | + result = m_data[i]; | |
| 509 | + } | |
| 510 | + | |
| 511 | + // Return result | |
| 512 | + return result; | |
| 513 | +} | |
| 514 | + | |
| 515 | + | |
| 516 | +/*************************************************************************** | |
| 517 | + * Get maximum physical matrix element * | |
| 518 | + ***************************************************************************/ | |
| 519 | +double GMatrix::max() const | |
| 520 | +{ | |
| 521 | + // Initialise minimum with first element | |
| 522 | + double result = m_data[0]; | |
| 523 | + | |
| 524 | + // Search all elements for the largest one | |
| 525 | + for (int i = 1; i < m_elements; ++i) { | |
| 526 | + if (m_data[i] > result) | |
| 527 | + result = m_data[i]; | |
| 528 | + } | |
| 529 | + | |
| 530 | + // Return result | |
| 531 | + return result; | |
| 532 | +} | |
| 533 | + | |
| 534 | + | |
| 535 | +/*************************************************************************** | |
| 536 | + * Get matrix sum * | |
| 537 | + ***************************************************************************/ | |
| 538 | +double GMatrix::sum() const | |
| 539 | +{ | |
| 540 | + // Initialise matrix sum | |
| 541 | + double result = 0.0; | |
| 542 | + | |
| 543 | + // Add all elements | |
| 544 | + for (int i = 0; i < m_elements; ++i) | |
| 545 | + result += m_data[i]; | |
| 546 | + | |
| 547 | + // Return result | |
| 548 | + return result; | |
| 549 | +} | |
| 550 | + | |
| 551 | + | |
| 552 | +/*************************************************************************** | |
| 553 | + * Inplace transpose of matrix * | |
| 554 | + * ----------------------------------------------------------------------- * | |
| 555 | + * The transpose operation exchanges the number of rows against the number * | |
| 556 | + * of columns. The element transformation is done inplace. * | |
| 557 | + ***************************************************************************/ | |
| 558 | +void GMatrix::transpose() | |
| 559 | +{ | |
| 560 | + // Case A: matrix is rectangular then simply swap the elements | |
| 561 | + if (m_rows == m_cols) { | |
| 562 | + double swap; | |
| 563 | + double* ptr_dst; | |
| 564 | + double* ptr_src; | |
| 565 | + for (int row = 0; row < m_rows; ++row) { | |
| 566 | + for (int col = row; col < m_cols; ++col) { | |
| 567 | + ptr_dst = m_data + m_cols*row + col; | |
| 568 | + ptr_src = m_data + m_rows*col + row; | |
| 569 | + swap = *ptr_dst; | |
| 570 | + *ptr_dst = *ptr_src; | |
| 571 | + *ptr_src = swap; | |
| 572 | + } | |
| 573 | + } | |
| 574 | + } | |
| 575 | + | |
| 576 | + // Case B: Dummy for non-rectangular transpose | |
| 577 | + else { | |
| 578 | + GMatrix result(m_cols, m_rows); | |
| 579 | + for (int row = 0; row < m_rows; ++row) { | |
| 580 | + for (int col = 0; col < m_cols; ++col) | |
| 581 | + result(col, row) = (*this)(row, col); | |
| 582 | + } | |
| 583 | + *this = result; | |
| 584 | + } | |
| 585 | + | |
| 586 | +} | |
| 587 | + | |
| 588 | + | |
| 589 | +/*************************************************************************** | |
| 590 | + * Extract row from matrix into vector * | |
| 591 | + ***************************************************************************/ | |
| 592 | +GVector GMatrix::extract_row(int row) const | |
| 593 | +{ | |
| 594 | + // Raise an exception if the row index is invalid | |
| 595 | + #if defined(G_RANGE_CHECK) | |
| 596 | + if (row >= m_rows) | |
| 597 | + throw out_of_range("GMatrix::extract_row(int)", | |
| 598 | + row, 0, m_rows, m_cols); | |
| 599 | + #endif | |
| 600 | + | |
| 601 | + // Create result vector | |
| 602 | + GVector result(m_cols); | |
| 603 | + | |
| 604 | + // Extract row into vector | |
| 605 | + for (int col = 0; col < m_cols; ++col) | |
| 606 | + result(col) = (*this)(row,col); | |
| 607 | + | |
| 608 | + // Return vector | |
| 181 | 609 | return result; |
| 610 | + | |
| 182 | 611 | } |
| 183 | 612 | |
| 184 | 613 | |
| 185 | 614 | /*************************************************************************** |
| 186 | - * Class exception handlers * | |
| 615 | + * Extract column from matrix into vector * | |
| 187 | 616 | ***************************************************************************/ |
| 188 | -// Matrix row or column out of range | |
| 189 | -GMatrix::out_of_range::out_of_range(string origin, unsigned row, unsigned col, | |
| 190 | - unsigned rows, unsigned cols) | |
| 617 | +GVector GMatrix::extract_col(int col) const | |
| 618 | +{ | |
| 619 | + // Raise an exception if the column index is invalid | |
| 620 | + #if defined(G_RANGE_CHECK) | |
| 621 | + if (col >= m_cols) | |
| 622 | + throw out_of_range("GMatrix::extract_col(int)", | |
| 623 | + 0, col, m_rows, m_cols); | |
| 624 | + #endif | |
| 625 | + | |
| 626 | + // Create result vector | |
| 627 | + GVector result(m_rows); | |
| 628 | + | |
| 629 | + // Extract column into vector | |
| 630 | + for (int row = 0; row < m_rows; ++row) | |
| 631 | + result(row) = (*this)(row,col); | |
| 632 | + | |
| 633 | + // Return vector | |
| 634 | + return result; | |
| 635 | + | |
| 636 | +} | |
| 637 | + | |
| 638 | + | |
| 639 | +/*========================================================================== | |
| 640 | + = = | |
| 641 | + = GMatrix private member functions = | |
| 642 | + = = | |
| 643 | + ==========================================================================*/ | |
| 644 | + | |
| 645 | +/*************************************************************************** | |
| 646 | + * select_non_zero * | |
| 647 | + * ----------------------------------------------------------------------- * | |
| 648 | + * Determines the non-zero rows and columns in matrix and set up index * | |
| 649 | + * arrays that points to these rows/columns. These arraya are used for * | |
| 650 | + * compressed matrix factorisations. * | |
| 651 | + ***************************************************************************/ | |
| 652 | +void GMatrix::select_non_zero(void) | |
| 653 | +{ | |
| 654 | + // Free existing selection arrays | |
| 655 | + if (m_rowsel != NULL) delete [] m_rowsel; | |
| 656 | + if (m_colsel != NULL) delete [] m_colsel; | |
| 657 | + | |
| 658 | + // Allocate selection arrays | |
| 659 | + m_rowsel = new int[m_rows]; | |
| 660 | + if (m_rowsel == NULL) | |
| 661 | + throw mem_alloc("GMatrix::select_non_zero()", m_rows); | |
| 662 | + m_colsel = new int[m_cols]; | |
| 663 | + if (m_colsel == NULL) | |
| 664 | + throw mem_alloc("GMatrix::select_non_zero()", m_cols); | |
| 665 | + | |
| 666 | + // Initialise non-zero row and column counters | |
| 667 | + m_num_rowsel = 0; | |
| 668 | + m_num_colsel = 0; | |
| 669 | + | |
| 670 | + // Declare loop variables | |
| 671 | + int row; | |
| 672 | + int col; | |
| 673 | + | |
| 674 | + // Find all non-zero rows | |
| 675 | + for (row = 0; row < m_rows; ++row) { | |
| 676 | + for (col = 0; col < m_cols; ++col) { | |
| 677 | + if ((*this)(row,col) != 0.0) | |
| 678 | + break; | |
| 679 | + } | |
| 680 | + if (col < m_cols) // found a non-zero element in row | |
| 681 | + m_rowsel[m_num_rowsel++] = row; | |
| 682 | + } | |
| 683 | + | |
| 684 | + // Find all non-zero columns | |
| 685 | + for (col = 0; col < m_cols; ++col) { | |
| 686 | + for (row = 0; row < m_rows; ++row) { | |
| 687 | + if ((*this)(row,col) != 0.0) | |
| 688 | + break; | |
| 689 | + } | |
| 690 | + if (row < m_rows) // found a non-zero element in column | |
| 691 | + m_colsel[m_num_colsel++] = col; | |
| 692 | + } | |
| 693 | + | |
| 694 | + // Return | |
| 695 | + return; | |
| 696 | +} | |
| 697 | + | |
| 698 | +/*========================================================================== | |
| 699 | + = = | |
| 700 | + = GMatrix friends = | |
| 701 | + = = | |
| 702 | + ==========================================================================*/ | |
| 703 | + | |
| 704 | +/*************************************************************************** | |
| 705 | + * Output operator * | |
| 706 | + ***************************************************************************/ | |
| 707 | +ostream& operator<< (ostream& os, const GMatrix& m) | |
| 708 | +{ | |
| 709 | + // Loop over all matrix elements | |
| 710 | + for (int row = 0; row < m.m_rows; ++row) { | |
| 711 | + for (int col = 0; col < m.m_cols; ++col) { | |
| 712 | + os << m(row,col); | |
| 713 | + if (col != m.m_cols-1) | |
| 714 | + os << ", "; | |
| 715 | + } | |
| 716 | + if (row != m.m_rows-1) | |
| 717 | + os << endl; | |
| 718 | + } | |
| 719 | + | |
| 720 | + // Return output stream | |
| 721 | + return os; | |
| 722 | +} | |
| 723 | + | |
| 724 | + | |
| 725 | +/*************************************************************************** | |
| 726 | + * Matrix absolute values * | |
| 727 | + ***************************************************************************/ | |
| 728 | +GMatrix fabs(const GMatrix& m) | |
| 729 | +{ | |
| 730 | + // Define result matrix | |
| 731 | + GMatrix result = m; | |
| 732 | + | |
| 733 | + // Convert all elements to absolute values | |
| 734 | + for (int i = 0; i < result.m_elements; ++i) | |
| 735 | + result.m_data[i] = fabs(result.m_data[i]); | |
| 736 | + | |
| 737 | + // Return result | |
| 738 | + return result; | |
| 739 | +} | |
| 740 | + | |
| 741 | + | |
| 742 | +/*========================================================================== | |
| 743 | + = = | |
| 744 | + = GMatrix exception classes = | |
| 745 | + = = | |
| 746 | + ==========================================================================*/ | |
| 747 | + | |
| 748 | +/*************************************************************************** | |
| 749 | + * Matrix row or column out of range * | |
| 750 | + ***************************************************************************/ | |
| 751 | +GMatrix::out_of_range::out_of_range(string origin, int row, int col, | |
| 752 | + int rows, int cols) | |
| 191 | 753 | { |
| 192 | 754 | m_origin = origin; |
| 193 | 755 | ostringstream s_row; |
| ... | ... | @@ -203,9 +765,12 @@ GMatrix::out_of_range::out_of_range(string origin, unsigned row, unsigned col, |
| 203 | 765 | s_cols.str() + "])"; |
| 204 | 766 | } |
| 205 | 767 | |
| 206 | -// Matrix - Vector mismatch | |
| 207 | -GMatrix::vec_mat_mismatch::vec_mat_mismatch(string origin, unsigned num, | |
| 208 | - unsigned rows, unsigned cols) | |
| 768 | + | |
| 769 | +/*************************************************************************** | |
| 770 | + * Mismatch between matrix and vector * | |
| 771 | + ***************************************************************************/ | |
| 772 | +GMatrix::matrix_vector_mismatch::matrix_vector_mismatch(string origin, | |
| 773 | + int num, int rows, int cols) | |
| 209 | 774 | { |
| 210 | 775 | m_origin = origin; |
| 211 | 776 | ostringstream s_num; |
| ... | ... | @@ -219,9 +784,12 @@ GMatrix::vec_mat_mismatch::vec_mat_mismatch(string origin, unsigned num, |
| 219 | 784 | s_rows.str() + "," + s_cols.str() + "]"; |
| 220 | 785 | } |
| 221 | 786 | |
| 222 | -// Matrix mismatch (additional etc.) | |
| 223 | -GMatrix::dim_add_mismatch::dim_add_mismatch(string origin, unsigned rows1, unsigned rows2, | |
| 224 | - unsigned cols1, unsigned cols2) | |
| 787 | + | |
| 788 | +/*************************************************************************** | |
| 789 | + * Matrix mismatch in operation * | |
| 790 | + ***************************************************************************/ | |
| 791 | +GMatrix::matrix_mismatch::matrix_mismatch(string origin, int rows1, | |
| 792 | + int cols1, int rows2, int cols2) | |
| 225 | 793 | { |
| 226 | 794 | m_origin = origin; |
| 227 | 795 | ostringstream s_rows1; |
| ... | ... | @@ -229,24 +797,84 @@ GMatrix::dim_add_mismatch::dim_add_mismatch(string origin, unsigned rows1, unsig |
| 229 | 797 | ostringstream s_cols1; |
| 230 | 798 | ostringstream s_cols2; |
| 231 | 799 | s_rows1 << rows1; |
| 800 | + s_cols1 << cols1; | |
| 232 | 801 | s_rows2 << rows2; |
| 802 | + s_cols2 << cols2; | |
| 803 | + m_message = "Matrix mismatch: M1(" + s_rows1.str() + "," + s_cols1.str() + | |
| 804 | + ") incompatible with M2(" + s_rows2.str() + "," + | |
| 805 | + s_cols2.str() + ")"; | |
| 806 | +} | |
| 807 | + | |
| 808 | + | |
| 809 | +/*************************************************************************** | |
| 810 | + * Matrix not rectangular * | |
| 811 | + ***************************************************************************/ | |
| 812 | +GMatrix::matrix_not_rect::matrix_not_rect(string origin, int rows1, | |
| 813 | + int cols1, int rows2, int cols2) | |
| 814 | +{ | |
| 815 | + m_origin = origin; | |
| 816 | + ostringstream s_rows1; | |
| 817 | + ostringstream s_rows2; | |
| 818 | + ostringstream s_cols1; | |
| 819 | + ostringstream s_cols2; | |
| 820 | + s_rows1 << rows1; | |
| 233 | 821 | s_cols1 << cols1; |
| 822 | + s_rows2 << rows2; | |
| 234 | 823 | s_cols2 << cols2; |
| 235 | - m_message = "Size [" + s_rows1.str() + "," + s_cols1.str() + | |
| 236 | - "] of first matrix is incompatible with size [" + | |
| 237 | - s_rows2.str() + "," + s_cols2.str() + | |
| 238 | - "] of second matrix"; | |
| 824 | + m_message = "Operation only valid for rectangular matrices: M[" + | |
| 825 | + s_rows1.str() + "," + s_cols1.str() + | |
| 826 | + "] *= M[" + s_rows2.str() + "," + s_cols2.str() + | |
| 827 | + "] not allowed"; | |
| 828 | +} | |
| 829 | + | |
| 830 | + | |
| 831 | +/*************************************************************************** | |
| 832 | + * Matrix is not positive definite * | |
| 833 | + ***************************************************************************/ | |
| 834 | +GMatrix::matrix_not_pos_definite::matrix_not_pos_definite(string origin, | |
| 835 | + int row, double sum) | |
| 836 | +{ | |
| 837 | + m_origin = origin; | |
| 838 | + ostringstream s_rows; | |
| 839 | + ostringstream s_sum; | |
| 840 | + s_rows << row; | |
| 841 | + s_sum << scientific << sum; | |
| 842 | + m_message = "Matrix is not positive definite (sum " + s_sum.str() + | |
| 843 | + " occured in row/column " + s_rows.str() + ")"; | |
| 239 | 844 | } |
| 240 | 845 | |
| 241 | -// Matrix mismatch (multiplication) | |
| 242 | -GMatrix::dim_mult_mismatch::dim_mult_mismatch(string origin, unsigned cols, unsigned rows) | |
| 846 | + | |
| 847 | +/*************************************************************************** | |
| 848 | + * Matrix is not symmetric * | |
| 849 | + ***************************************************************************/ | |
| 850 | +GMatrix::matrix_not_symmetric::matrix_not_symmetric(string origin, int cols, | |
| 851 | + int rows) | |
| 243 | 852 | { |
| 244 | 853 | m_origin = origin; |
| 245 | 854 | ostringstream s_rows; |
| 246 | 855 | ostringstream s_cols; |
| 247 | 856 | s_rows << rows; |
| 248 | 857 | s_cols << cols; |
| 249 | - m_message = "Number of columns [" + s_cols.str() + | |
| 250 | - "] in first matrix is incompatible with number of rows [" + | |
| 251 | - s_rows.str() + "] in second matrix"; | |
| 858 | + m_message = "Matrix is not symmetric [" + s_rows.str() + "," + | |
| 859 | + s_cols.str() + "]"; | |
| 860 | +} | |
| 861 | + | |
| 862 | + | |
| 863 | +/*************************************************************************** | |
| 864 | + * Matrix has not been factorised * | |
| 865 | + ***************************************************************************/ | |
| 866 | +GMatrix::matrix_not_factorised::matrix_not_factorised(string origin, string type) | |
| 867 | +{ | |
| 868 | + m_origin = origin; | |
| 869 | + m_message = "Matrix has not been factorised using " + type; | |
| 870 | +} | |
| 871 | + | |
| 872 | + | |
| 873 | +/*************************************************************************** | |
| 874 | + * All matrix elements are zero * | |
| 875 | + ***************************************************************************/ | |
| 876 | +GMatrix::matrix_zero::matrix_zero(string origin) | |
| 877 | +{ | |
| 878 | + m_origin = origin; | |
| 879 | + m_message = "All matrix elements are zero"; | |
| 252 | 880 | } | ... | ... |
src/GMatrix.hpp
| ... | ... | @@ -32,264 +32,131 @@ using namespace std; |
| 32 | 32 | * GMatrix class definition * |
| 33 | 33 | ***************************************************************************/ |
| 34 | 34 | class GMatrix { |
| 35 | - // Operator friends | |
| 36 | - friend GMatrix operator+ (const double& a, const GMatrix& b); | |
| 37 | - friend GMatrix operator- (const double& a, const GMatrix& b); | |
| 38 | - friend GMatrix operator* (const double& a, const GMatrix& b); | |
| 35 | + // Binary operator friends | |
| 36 | + friend GMatrix operator* (const double& a, const GMatrix& b); | |
| 37 | + friend GMatrix operator* (const GMatrix& a, const double& b); | |
| 38 | + friend GMatrix operator/ (const GMatrix& a, const double& b); | |
| 39 | 39 | |
| 40 | 40 | // I/O friends |
| 41 | - friend ostream& operator<< (ostream& os, const GMatrix& m); | |
| 41 | + friend ostream& operator<< (ostream& os, const GMatrix& m); | |
| 42 | 42 | |
| 43 | 43 | // Friend functions |
| 44 | 44 | friend GMatrix transpose(const GMatrix& m); |
| 45 | 45 | friend GMatrix fabs(const GMatrix& m); |
| 46 | + | |
| 46 | 47 | public: |
| 47 | 48 | // Constructors and destructors |
| 48 | - GMatrix(unsigned rows, unsigned cols); | |
| 49 | + GMatrix(int rows, int cols); | |
| 49 | 50 | GMatrix(const GMatrix& m); |
| 50 | 51 | virtual ~GMatrix(); |
| 51 | 52 | |
| 52 | 53 | // Matrix element access operators |
| 53 | - virtual double& operator() (unsigned row, unsigned col); | |
| 54 | - virtual const double& operator() (unsigned row, unsigned col) const; | |
| 54 | + virtual double& operator() (int row, int col); | |
| 55 | + virtual const double& operator() (int row, int col) const; | |
| 55 | 56 | |
| 56 | 57 | // Matrix assignment operators |
| 57 | - GMatrix& operator= (const GMatrix& m); | |
| 58 | - GMatrix& operator= (const double& d); | |
| 58 | + virtual GMatrix& operator= (const GMatrix& m); | |
| 59 | + | |
| 60 | + // Binary operators | |
| 61 | + virtual GMatrix operator+ (const GMatrix& m) const; | |
| 62 | + virtual GMatrix operator- (const GMatrix& m) const; | |
| 63 | + virtual GMatrix operator* (const GMatrix& m) const; | |
| 64 | + virtual GVector operator* (const GVector& v) const; | |
| 65 | + virtual int operator== (const GMatrix& m) const; | |
| 66 | + virtual int operator!= (const GMatrix& m) const; | |
| 59 | 67 | |
| 60 | - // Generic matrix operators (structure independent) | |
| 68 | + // Unary operators | |
| 69 | + GMatrix operator- () const; | |
| 61 | 70 | virtual GMatrix& operator+= (const GMatrix& m); |
| 62 | 71 | virtual GMatrix& operator-= (const GMatrix& m); |
| 63 | - virtual GMatrix& operator+= (const double& d); | |
| 64 | - virtual GMatrix& operator-= (const double& d); | |
| 72 | + virtual GMatrix& operator*= (const GMatrix& m); | |
| 65 | 73 | virtual GMatrix& operator*= (const double& d); |
| 66 | 74 | virtual GMatrix& operator/= (const double& d); |
| 67 | - virtual int operator== (const GMatrix& m) const; | |
| 68 | - virtual int operator!= (const GMatrix& m) const; | |
| 69 | - | |
| 70 | - // Specific matrix operators (structure dependent) | |
| 71 | - GMatrix operator+ (const GMatrix& m) const; | |
| 72 | - GMatrix operator- (const GMatrix& m) const; | |
| 73 | - GMatrix operator* (const GMatrix& m) const; | |
| 74 | - virtual GVector operator* (const GVector& v) const; | |
| 75 | - GMatrix operator+ (const double& d) const; | |
| 76 | - GMatrix operator- (const double& d) const; | |
| 77 | - GMatrix operator* (const double& d) const; | |
| 78 | - GMatrix operator/ (const double& d) const; | |
| 79 | - GMatrix operator- () const; | |
| 80 | - | |
| 81 | - // Generic matrix functions (structure independent) | |
| 82 | - virtual double min() const; // Minimum physical element | |
| 83 | - virtual double max() const; // Maximum physical element | |
| 84 | - virtual double sum() const; // Sum of matrix elements | |
| 85 | - virtual unsigned rows() const; // Return number of rows | |
| 86 | - virtual unsigned cols() const; // Return number of columns | |
| 87 | 75 | |
| 88 | - // Specific matrix functions (structure dependent) | |
| 89 | - virtual void transpose(); // Inplace transpose of matrix | |
| 76 | + // Matrix functions | |
| 77 | + virtual int rows() const { return m_rows; } | |
| 78 | + virtual int cols() const { return m_cols; } | |
| 79 | + virtual double min() const; | |
| 80 | + virtual double max() const; | |
| 81 | + virtual double sum() const; | |
| 82 | + virtual void transpose(); | |
| 83 | + virtual GVector extract_row(int row) const; | |
| 84 | + virtual GVector extract_col(int col) const; | |
| 90 | 85 | |
| 91 | 86 | // Exception: Matrix indices out of range |
| 92 | 87 | class out_of_range : public GException { |
| 93 | 88 | public: |
| 94 | - out_of_range(string origin, unsigned row, unsigned col, | |
| 95 | - unsigned rows, unsigned cols); | |
| 89 | + out_of_range(string origin, int row, int col, int rows, int cols); | |
| 96 | 90 | }; |
| 97 | 91 | |
| 98 | 92 | // Exception: Vector - Matrix mismatch |
| 99 | - class vec_mat_mismatch : public GException { | |
| 93 | + class matrix_vector_mismatch : public GException { | |
| 100 | 94 | public: |
| 101 | - vec_mat_mismatch(string origin, unsigned num, unsigned rows, unsigned cols); | |
| 95 | + matrix_vector_mismatch(string origin, int num, int rows, int cols); | |
| 102 | 96 | }; |
| 103 | 97 | |
| 104 | - // Exception: Matrix dimensions mismatch (addition, etc.) | |
| 105 | - class dim_add_mismatch : public GException { | |
| 98 | + // Exception: Matrix dimensions mismatch | |
| 99 | + class matrix_mismatch : public GException { | |
| 106 | 100 | public: |
| 107 | - dim_add_mismatch(string origin, unsigned rows1, unsigned rows2, | |
| 108 | - unsigned cols1, unsigned cols2); | |
| 101 | + matrix_mismatch(string origin, int rows1, int cols1, int cols1, int cols2); | |
| 109 | 102 | }; |
| 110 | 103 | |
| 111 | - // Exception: Matrix dimensions mismatch (multiplication) | |
| 112 | - class dim_mult_mismatch : public GException { | |
| 104 | + // Exception: Matrix not rectangular | |
| 105 | + class matrix_not_rect : public GException { | |
| 113 | 106 | public: |
| 114 | - dim_mult_mismatch(string origin, unsigned cols, unsigned rows); | |
| 107 | + matrix_not_rect(string origin, int rows1, int cols1, int cols1, int cols2); | |
| 115 | 108 | }; |
| 116 | 109 | |
| 117 | -protected: | |
| 118 | - // Void constructor to be used by derived classes which have own constructor | |
| 119 | - GMatrix() { } | |
| 120 | - | |
| 121 | - // Private data area | |
| 122 | - unsigned m_rows; // Number of rows | |
| 123 | - unsigned m_cols; // Number of columns | |
| 124 | - unsigned m_elements; // Number of (physical) elements in matrix | |
| 125 | - unsigned* m_colstart; // Column start indices (m_cols+1) | |
| 126 | - double* m_data; // Matrix data | |
| 127 | -}; | |
| 128 | - | |
| 129 | - | |
| 130 | -/*************************************************************************** | |
| 131 | - * Generic inline members (to be inherited) * | |
| 132 | - ***************************************************************************/ | |
| 133 | -// Matrix unary addition operator: GMatrix += GMatrix | |
| 134 | -inline | |
| 135 | -GMatrix& GMatrix::operator+= (const GMatrix& m) | |
| 136 | -{ | |
| 137 | - if (m_rows != m.m_rows || m_cols != m.m_cols) | |
| 138 | - throw dim_add_mismatch("GMatrix += operator", m_rows, m.m_rows, m_cols, m.m_cols); | |
| 139 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 140 | - m_data[i] += m.m_data[i]; | |
| 141 | - return *this; | |
| 142 | -} | |
| 143 | - | |
| 144 | -// Matrix unary subtraction operator: GMatrix -= GMatrix | |
| 145 | -inline | |
| 146 | -GMatrix& GMatrix::operator-= (const GMatrix& m) | |
| 147 | -{ | |
| 148 | - if (m_rows != m.m_rows || m_cols != m.m_cols) | |
| 149 | - throw dim_add_mismatch("GMatrix -= operator", m_rows, m.m_rows, m_cols, m.m_cols); | |
| 150 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 151 | - m_data[i] -= m.m_data[i]; | |
| 152 | - return *this; | |
| 153 | -} | |
| 154 | - | |
| 155 | -// Scalar unary addition operator: GMatrix += double | |
| 156 | -inline | |
| 157 | -GMatrix& GMatrix::operator+= (const double& d) | |
| 158 | -{ | |
| 159 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 160 | - m_data[i] += d; | |
| 161 | - return *this; | |
| 162 | -} | |
| 163 | - | |
| 164 | -// Scalar unary subtraction operator: GMatrix -= double | |
| 165 | -inline | |
| 166 | -GMatrix& GMatrix::operator-= (const double& d) | |
| 167 | -{ | |
| 168 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 169 | - m_data[i] -= d; | |
| 170 | - return *this; | |
| 171 | -} | |
| 172 | - | |
| 173 | -// Scalar unary multiplication operator: GMatrix *= double | |
| 174 | -inline | |
| 175 | -GMatrix& GMatrix::operator*= (const double& d) | |
| 176 | -{ | |
| 177 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 178 | - m_data[i] *= d; | |
| 179 | - return *this; | |
| 180 | -} | |
| 181 | - | |
| 182 | -// Scalar unary division operator: GMatrix /= double | |
| 183 | -inline | |
| 184 | -GMatrix& GMatrix::operator/= (const double& d) | |
| 185 | -{ | |
| 186 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 187 | - m_data[i] /= d; | |
| 188 | - return *this; | |
| 189 | -} | |
| 190 | - | |
| 191 | -// Equality operator: GMatrix == GMatrix | |
| 192 | -inline | |
| 193 | -int GMatrix::operator== (const GMatrix &m) const | |
| 194 | -{ | |
| 195 | - int result = 1; | |
| 196 | - if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { | |
| 197 | - for (unsigned i = 0; i < m_elements; ++i) { | |
| 198 | - if (m_data[i] != m.m_data[i]) { | |
| 199 | - result = 0; | |
| 200 | - break; | |
| 201 | - } | |
| 202 | - } | |
| 203 | - } | |
| 204 | - else | |
| 205 | - result = 0; | |
| 206 | - return result; | |
| 207 | -} | |
| 110 | + // Exception: Matrix not positive definite | |
| 111 | + class matrix_not_pos_definite : public GException { | |
| 112 | + public: | |
| 113 | + matrix_not_pos_definite(string origin, int row, double sum); | |
| 114 | + }; | |
| 208 | 115 | |
| 209 | -// Non equality operator: GMatrix != GMatrix | |
| 210 | -inline | |
| 211 | -int GMatrix::operator!= (const GMatrix &m) const | |
| 212 | -{ | |
| 213 | - int result = 0; | |
| 214 | - if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { | |
| 215 | - for (unsigned i = 0; i < m_elements; ++i) { | |
| 216 | - if (m_data[i] != m.m_data[i]) { | |
| 217 | - result = 1; | |
| 218 | - break; | |
| 219 | - } | |
| 220 | - } | |
| 221 | - } | |
| 222 | - else | |
| 223 | - result = 1; | |
| 224 | - return result; | |
| 225 | -} | |
| 116 | + // Exception: Matrix not symmetric | |
| 117 | + class matrix_not_symmetric : public GException { | |
| 118 | + public: | |
| 119 | + matrix_not_symmetric(string origin, int cols, int rows); | |
| 120 | + }; | |
| 226 | 121 | |
| 227 | -// Matrix minimum: GMatrix.min() | |
| 228 | -inline | |
| 229 | -double GMatrix::min() const | |
| 230 | -{ | |
| 231 | - double result = m_data[0]; | |
| 232 | - for (unsigned i = 1; i < m_elements; ++i) { | |
| 233 | - if (m_data[i] < result) | |
| 234 | - result = m_data[i]; | |
| 235 | - } | |
| 236 | - return result; | |
| 237 | -} | |
| 122 | + // Exception: Matrix not factorised | |
| 123 | + class matrix_not_factorised : public GException { | |
| 124 | + public: | |
| 125 | + matrix_not_factorised(string origin, string type); | |
| 126 | + }; | |
| 238 | 127 | |
| 239 | -// Matrix maximum: GMatrix.max() | |
| 240 | -inline | |
| 241 | -double GMatrix::max() const | |
| 242 | -{ | |
| 243 | - double result = m_data[0]; | |
| 244 | - for (unsigned i = 1; i < m_elements; ++i) { | |
| 245 | - if (m_data[i] > result) | |
| 246 | - result = m_data[i]; | |
| 247 | - } | |
| 248 | - return result; | |
| 249 | -} | |
| 128 | + // Exception: All matrix elements are zero | |
| 129 | + class matrix_zero : public GException { | |
| 130 | + public: | |
| 131 | + matrix_zero(string origin); | |
| 132 | + }; | |
| 250 | 133 | |
| 251 | -// Matrix sum: GMatrix.sum() | |
| 252 | -inline | |
| 253 | -double GMatrix::sum() const | |
| 254 | -{ | |
| 255 | - double result = 0.0; | |
| 256 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 257 | - for (unsigned col = 0; col < m_cols; ++col) | |
| 258 | - result += (*this)(row,col); | |
| 259 | - } | |
| 260 | - return result; | |
| 261 | -} | |
| 134 | +protected: | |
| 135 | + // Void constructor to be used by derived classes which have own constructor | |
| 136 | + GMatrix(); | |
| 262 | 137 | |
| 263 | -// Return number of rows: GMatrix.rows() | |
| 264 | -inline | |
| 265 | -unsigned GMatrix::rows() const | |
| 266 | -{ | |
| 267 | - return m_rows; | |
| 268 | -} | |
| 138 | + // Private member functions | |
| 139 | + void select_non_zero(void); | |
| 269 | 140 | |
| 270 | -// Return number of columns: GMatrix.cols() | |
| 271 | -inline | |
| 272 | -unsigned GMatrix::cols() const | |
| 273 | -{ | |
| 274 | - return m_cols; | |
| 275 | -} | |
| 141 | + // Private data area | |
| 142 | + int m_rows; // Number of rows | |
| 143 | + int m_cols; // Number of columns | |
| 144 | + int m_elements; // Number of (physical) elements in matrix | |
| 145 | + int m_num_rowsel; // Number of selected rows (for compressed decomposition) | |
| 146 | + int m_num_colsel; // Number of selected columns (for compressed decomposition) | |
| 147 | + int* m_colstart; // Column start indices (m_cols+1) | |
| 148 | + int* m_rowsel; // Row selection (for compressed decomposition) | |
| 149 | + int* m_colsel; // Column selection (for compressed decomposition) | |
| 150 | + double* m_data; // Matrix data | |
| 151 | +}; | |
| 276 | 152 | |
| 277 | 153 | |
| 278 | 154 | /*************************************************************************** |
| 279 | - * Specific inline members (may need specific function for derived class) * | |
| 155 | + * Inline member functions * | |
| 280 | 156 | ***************************************************************************/ |
| 281 | -// Scalar assignment operator: GMatrix = double | |
| 282 | -inline | |
| 283 | -GMatrix& GMatrix::operator= (const double& d) | |
| 284 | -{ | |
| 285 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 286 | - m_data[i] = d; | |
| 287 | - return *this; | |
| 288 | -} | |
| 289 | - | |
| 290 | -// Matrix element access operator: GMatrix(row,col) | |
| 157 | +// Matrix element access operator | |
| 291 | 158 | inline |
| 292 | -double& GMatrix::operator() (unsigned row, unsigned col) | |
| 159 | +double& GMatrix::operator() (int row, int col) | |
| 293 | 160 | { |
| 294 | 161 | #if defined(G_RANGE_CHECK) |
| 295 | 162 | if (row >= m_rows || col >= m_cols) |
| ... | ... | @@ -298,9 +165,9 @@ double& GMatrix::operator() (unsigned row, unsigned col) |
| 298 | 165 | return m_data[m_colstart[col]+row]; |
| 299 | 166 | } |
| 300 | 167 | |
| 301 | -// Matrix element access operator (const version): GMatrix(row,col) | |
| 168 | +// Matrix element access operator (const version) | |
| 302 | 169 | inline |
| 303 | -const double& GMatrix::operator() (unsigned row, unsigned col) const | |
| 170 | +const double& GMatrix::operator() (int row, int col) const | |
| 304 | 171 | { |
| 305 | 172 | #if defined(G_RANGE_CHECK) |
| 306 | 173 | if (row >= m_rows || col >= m_cols) |
| ... | ... | @@ -309,7 +176,7 @@ const double& GMatrix::operator() (unsigned row, unsigned col) const |
| 309 | 176 | return m_data[m_colstart[col]+row]; |
| 310 | 177 | } |
| 311 | 178 | |
| 312 | -// Matrix addition: GMatrix + GMatrix | |
| 179 | +// Binary matrix addition | |
| 313 | 180 | inline |
| 314 | 181 | GMatrix GMatrix::operator+ (const GMatrix& m) const |
| 315 | 182 | { |
| ... | ... | @@ -318,7 +185,7 @@ GMatrix GMatrix::operator+ (const GMatrix& m) const |
| 318 | 185 | return result; |
| 319 | 186 | } |
| 320 | 187 | |
| 321 | -// Matrix subtraction: GMatrix - GMatrix | |
| 188 | +// Binary matrix subtraction | |
| 322 | 189 | inline |
| 323 | 190 | GMatrix GMatrix::operator- (const GMatrix& m) const |
| 324 | 191 | { |
| ... | ... | @@ -327,91 +194,29 @@ GMatrix GMatrix::operator- (const GMatrix& m) const |
| 327 | 194 | return result; |
| 328 | 195 | } |
| 329 | 196 | |
| 330 | -// Matrix scaling: GMatrix + double | |
| 331 | -inline | |
| 332 | -GMatrix GMatrix::operator+ (const double& d) const | |
| 333 | -{ | |
| 334 | - GMatrix result = (*this); | |
| 335 | - result += d; | |
| 336 | - return result; | |
| 337 | -} | |
| 338 | - | |
| 339 | -// Matrix scaling: GMatrix - double | |
| 340 | -inline | |
| 341 | -GMatrix GMatrix::operator- (const double& d) const | |
| 342 | -{ | |
| 343 | - GMatrix result = (*this); | |
| 344 | - result -= d; | |
| 345 | - return result; | |
| 346 | -} | |
| 347 | - | |
| 348 | -// Matrix scaling: GMatrix * double | |
| 349 | -inline | |
| 350 | -GMatrix GMatrix::operator* (const double& d) const | |
| 351 | -{ | |
| 352 | - GMatrix result = (*this); | |
| 353 | - result *= d; | |
| 354 | - return result; | |
| 355 | -} | |
| 356 | - | |
| 357 | -// Matrix inverse scaling: GMatrix * double | |
| 358 | -inline | |
| 359 | -GMatrix GMatrix::operator/ (const double& d) const | |
| 360 | -{ | |
| 361 | - GMatrix result = (*this); | |
| 362 | - result /= d; | |
| 363 | - return result; | |
| 364 | -} | |
| 365 | - | |
| 366 | -// Unary minus operator: -GMatrix | |
| 197 | +// Binary matrix multiplication | |
| 367 | 198 | inline |
| 368 | -GMatrix GMatrix::operator- ( ) const | |
| 199 | +GMatrix GMatrix::operator* (const GMatrix& m) const | |
| 369 | 200 | { |
| 370 | 201 | GMatrix result = *this; |
| 371 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 372 | - result.m_data[i] = -result.m_data[i]; | |
| 202 | + result *= m; | |
| 373 | 203 | return result; |
| 374 | 204 | } |
| 375 | 205 | |
| 376 | -// Matrix transpose: GMatrix.transpose() | |
| 377 | -inline | |
| 378 | -void GMatrix::transpose() | |
| 379 | -{ | |
| 380 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 381 | - double* ptr0 = m_data + row; | |
| 382 | - double* ptr2 = m_data + m_colstart[row]+row+1; | |
| 383 | - for (unsigned col = row+1; col < m_cols; ++col) { | |
| 384 | - double* ptr1 = ptr0 + m_colstart[col]; | |
| 385 | - double swap = *ptr1; | |
| 386 | - *ptr1 = *ptr2; | |
| 387 | - *ptr2++ = swap; | |
| 388 | - } | |
| 389 | - } | |
| 390 | -} | |
| 391 | - | |
| 392 | 206 | |
| 393 | 207 | /*************************************************************************** |
| 394 | 208 | * Inline friends * |
| 395 | 209 | ***************************************************************************/ |
| 396 | -// Matrix addition: double + GMatrix | |
| 397 | -inline | |
| 398 | -GMatrix operator+ (const double& a, const GMatrix& b) | |
| 399 | -{ | |
| 400 | - GMatrix result = b; | |
| 401 | - result += a; | |
| 402 | - return result; | |
| 403 | -} | |
| 404 | - | |
| 405 | -// Matrix subtraction: double - GMatrix | |
| 406 | -inline | |
| 407 | -GMatrix operator- (const double& a, const GMatrix& b) | |
| 210 | +// Binary matrix scaling (matrix is left operand) | |
| 211 | +inline | |
| 212 | +GMatrix operator* (const GMatrix& a, const double& b) | |
| 408 | 213 | { |
| 409 | - GMatrix result = b; | |
| 410 | - result -= a; | |
| 214 | + GMatrix result = a; | |
| 215 | + result *= b; | |
| 411 | 216 | return result; |
| 412 | 217 | } |
| 413 | 218 | |
| 414 | -// Matrix scaling: double * GMatrix | |
| 219 | +// Binary matrix scaling (matrix is right operand) | |
| 415 | 220 | inline |
| 416 | 221 | GMatrix operator* (const double& a, const GMatrix& b) |
| 417 | 222 | { |
| ... | ... | @@ -420,22 +225,21 @@ GMatrix operator* (const double& a, const GMatrix& b) |
| 420 | 225 | return result; |
| 421 | 226 | } |
| 422 | 227 | |
| 423 | -// Matrix transpose: transpose(GMatrix) | |
| 424 | -inline | |
| 425 | -GMatrix transpose(const GMatrix& m) | |
| 228 | +// Binary matrix division (matrix is left operand) | |
| 229 | +inline | |
| 230 | +GMatrix operator/ (const GMatrix& a, const double& b) | |
| 426 | 231 | { |
| 427 | - GMatrix result = m; | |
| 428 | - result.transpose(); | |
| 232 | + GMatrix result = a; | |
| 233 | + result /= b; | |
| 429 | 234 | return result; |
| 430 | 235 | } |
| 431 | 236 | |
| 432 | -// Matrix absolute: fabs(GMatrix) | |
| 237 | +// Matrix transpose function | |
| 433 | 238 | inline |
| 434 | -GMatrix fabs(const GMatrix& m) | |
| 239 | +GMatrix transpose(const GMatrix& m) | |
| 435 | 240 | { |
| 436 | 241 | GMatrix result = m; |
| 437 | - for (unsigned i = 0; i < result.m_elements; ++i) | |
| 438 | - result.m_data[i] = fabs(result.m_data[i]); | |
| 242 | + result.transpose(); | |
| 439 | 243 | return result; |
| 440 | 244 | } |
| 441 | 245 | ... | ... |
src/GSparseMatrix.cpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * GSparseMatrix.cpp - sparse matrix class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + * ----------------------------------------------------------------------- * | |
| 13 | + * This class implements the compressed sparse column format. The * | |
| 14 | + * following arrays are allocated: * | |
| 15 | + * m_data : holds all 'elements' non-zero values, in column order (Ax) * | |
| 16 | + * m_colstart : holds the index of the first element of each column (Ap) * | |
| 17 | + * m_rowinx : holds the row indices for all elements (Ai) * | |
| 18 | + * Column 'col' covers therefore [m_colstart[j], ..., m_colstart[j+1]-1] * | |
| 19 | + * Note that 'm_colstart' has m_cols+1 elements. * | |
| 20 | +/*************************************************************************** | |
| 21 | + | |
| 22 | +/* __ Includes ___________________________________________________________ */ | |
| 23 | +#include "GSparseMatrix.hpp" | |
| 24 | +#include "GSparseSymbolic.hpp" | |
| 25 | +#include "GSparseNumeric.hpp" | |
| 26 | + | |
| 27 | +/* __ Namespaces _________________________________________________________ */ | |
| 28 | +using namespace std; | |
| 29 | + | |
| 30 | +/* __ Definitions ________________________________________________________ */ | |
| 31 | +//#define G_DEBUG_SPARSE_PENDING // Analyse pending values | |
| 32 | +//#define G_DEBUG_SPARSE_INSERTION // Analyse value insertion | |
| 33 | +//#define G_DEBUG_SPARSE_COMPRESSION // Analyse zero row/column compression | |
| 34 | + | |
| 35 | + | |
| 36 | +/*========================================================================== | |
| 37 | + = = | |
| 38 | + = GSparseMatrix constructors/destructors = | |
| 39 | + = = | |
| 40 | + ==========================================================================*/ | |
| 41 | + | |
| 42 | +/*************************************************************************** | |
| 43 | + * GSparseMatrix constructor * | |
| 44 | + ***************************************************************************/ | |
| 45 | +GSparseMatrix::GSparseMatrix(int rows, int cols, int elements) : GMatrix() | |
| 46 | +{ | |
| 47 | + // Initialise private members for clean destruction | |
| 48 | + m_rows = 0; | |
| 49 | + m_cols = 0; | |
| 50 | + m_elements = 0; | |
| 51 | + m_data = NULL; | |
| 52 | + m_colstart = NULL; | |
| 53 | + m_rowinx = NULL; | |
| 54 | + m_zero = 0.0; | |
| 55 | + m_fill_val = 0.0; | |
| 56 | + m_fill_row = 0; | |
| 57 | + m_fill_col = 0; | |
| 58 | + m_symbolic = NULL; | |
| 59 | + m_numeric = NULL; | |
| 60 | + | |
| 61 | + // Allocate column start array. This is the only array that we can | |
| 62 | + // allocate at this time. The other arrays can only be allocated during | |
| 63 | + // filling of the matrix | |
| 64 | + m_colstart = new int[cols+1]; | |
| 65 | + if (m_colstart == NULL) | |
| 66 | + throw mem_alloc("GSparseMatrix constructor", cols+1); | |
| 67 | + | |
| 68 | + // Store (logical) matrix size | |
| 69 | + m_rows = rows; | |
| 70 | + m_cols = cols; | |
| 71 | + | |
| 72 | + // Initialise column start indices to 0 | |
| 73 | + for (int col = 0; col <= m_cols; ++col) | |
| 74 | + m_colstart[col] = 0; | |
| 75 | + | |
| 76 | + // Optionally allocate elements | |
| 77 | + if (elements > 0) | |
| 78 | + alloc_elements(0, elements); | |
| 79 | + | |
| 80 | + // Return | |
| 81 | + return; | |
| 82 | +} | |
| 83 | + | |
| 84 | + | |
| 85 | +/*************************************************************************** | |
| 86 | + * GSparseMatrix copy constructor * | |
| 87 | + * ----------------------------------------------------------------------- * | |
| 88 | + * First invoques GMatrix copy constructor (which sets the logical matrix * | |
| 89 | + * dimensions and copies the elements and the column start array). It * | |
| 90 | + * remains then to this constructor to copy the row indices. * | |
| 91 | + * NOTE: The copy constructor does NOT fill a pending element. * | |
| 92 | + ***************************************************************************/ | |
| 93 | +GSparseMatrix::GSparseMatrix(const GSparseMatrix& m) : GMatrix(m) | |
| 94 | +{ | |
| 95 | + // Initialise private members for clean destruction | |
| 96 | + m_rowinx = NULL; | |
| 97 | + m_symbolic = NULL; | |
| 98 | + m_numeric = NULL; | |
| 99 | + | |
| 100 | + // Copy data members | |
| 101 | + m_zero = m.m_zero; | |
| 102 | + m_fill_val = m.m_fill_val; | |
| 103 | + m_fill_row = m.m_fill_row; | |
| 104 | + m_fill_col = m.m_fill_col; | |
| 105 | + | |
| 106 | + // Allocate memory for row indices and copy them (only if there are elements) | |
| 107 | + if (m_elements > 0) { | |
| 108 | + m_rowinx = new int[m_elements]; | |
| 109 | + if (m_rowinx == NULL) | |
| 110 | + throw mem_alloc("GSparseMatrix copy constructor", m_elements); | |
| 111 | + for (int i = 0; i < m_elements; ++i) | |
| 112 | + m_rowinx[i] = m.m_rowinx[i]; | |
| 113 | + } | |
| 114 | + | |
| 115 | + // If there is a symbolic decomposition then copy it | |
| 116 | + if (m.m_symbolic != NULL) { | |
| 117 | + GSparseSymbolic* symbolic = new GSparseSymbolic(); | |
| 118 | + if (symbolic == NULL) | |
| 119 | + throw mem_alloc("GSparseMatrix copy constructor", 1); | |
| 120 | + *symbolic = *((GSparseSymbolic*)m.m_symbolic); | |
| 121 | + m_symbolic = (void*)symbolic; | |
| 122 | + } | |
| 123 | + | |
| 124 | + // If there is a numeric decomposition then copy it | |
| 125 | + if (m.m_numeric != NULL) { | |
| 126 | + GSparseNumeric* numeric = new GSparseNumeric(); | |
| 127 | + if (numeric == NULL) | |
| 128 | + throw mem_alloc("GSparseMatrix copy constructor", 1); | |
| 129 | + *numeric = *((GSparseNumeric*)m.m_numeric); | |
| 130 | + m_numeric = (void*)numeric; | |
| 131 | + } | |
| 132 | + | |
| 133 | + // Return | |
| 134 | + return; | |
| 135 | +} | |
| 136 | + | |
| 137 | + | |
| 138 | +/*************************************************************************** | |
| 139 | + * GSparseMatrix destructor * | |
| 140 | + * ----------------------------------------------------------------------- * | |
| 141 | + * First invoques this destructor to de-allocate row indices, then invoque * | |
| 142 | + * ~GMatrix destructor to de-allocate the other arrays. * | |
| 143 | + ***************************************************************************/ | |
| 144 | +GSparseMatrix::~GSparseMatrix() | |
| 145 | +{ | |
| 146 | + // De-allocate only if memory has indeed been allocated by derived class | |
| 147 | + if (m_rowinx != NULL) delete [] m_rowinx; | |
| 148 | + if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; | |
| 149 | + if (m_numeric != NULL) delete (GSparseNumeric*)m_numeric; | |
| 150 | + | |
| 151 | + // Return | |
| 152 | + return; | |
| 153 | +} | |
| 154 | + | |
| 155 | + | |
| 156 | +/*========================================================================== | |
| 157 | + = = | |
| 158 | + = GSparseMatrix operators = | |
| 159 | + = = | |
| 160 | + ==========================================================================*/ | |
| 161 | + | |
| 162 | +/*************************************************************************** | |
| 163 | + * GSparseMatrix assignment operator * | |
| 164 | + ***************************************************************************/ | |
| 165 | +GSparseMatrix& GSparseMatrix::operator= (const GSparseMatrix& m) | |
| 166 | +{ | |
| 167 | + // Execute only if object is not identical | |
| 168 | + if (this != &m) { | |
| 169 | + | |
| 170 | + // Invoque base class assignment operator | |
| 171 | + this->GMatrix::operator=(m); | |
| 172 | + | |
| 173 | + // De-allocate memory if it has indeed been allocated | |
| 174 | + if (m_rowinx != NULL) delete [] m_rowinx; | |
| 175 | + if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; | |
| 176 | + if (m_numeric != NULL) delete (GSparseNumeric*)m_numeric; | |
| 177 | + | |
| 178 | + // Initialise private members for clean destruction | |
| 179 | + m_rowinx = NULL; | |
| 180 | + m_symbolic = NULL; | |
| 181 | + m_numeric = NULL; | |
| 182 | + | |
| 183 | + // Copy data members | |
| 184 | + m_zero = m.m_zero; | |
| 185 | + m_fill_val = m.m_fill_val; | |
| 186 | + m_fill_row = m.m_fill_row; | |
| 187 | + m_fill_col = m.m_fill_col; | |
| 188 | + | |
| 189 | + // Allocate memory for row indices and copy them (only if there are elements) | |
| 190 | + if (m_elements > 0) { | |
| 191 | + m_rowinx = new int[m_elements]; | |
| 192 | + if (m_rowinx == NULL) | |
| 193 | + throw mem_alloc("GSparseMatrix::operator= (const GSparseMatrix&)", | |
| 194 | + m_elements); | |
| 195 | + for (int i = 0; i < m_elements; ++i) | |
| 196 | + m_rowinx[i] = m.m_rowinx[i]; | |
| 197 | + } | |
| 198 | + | |
| 199 | + // If there is a symbolic decomposition then copy it | |
| 200 | + if (m.m_symbolic != NULL) { | |
| 201 | + GSparseSymbolic* symbolic = new GSparseSymbolic(); | |
| 202 | + if (symbolic == NULL) | |
| 203 | + throw mem_alloc("GSparseMatrix copy constructor", 1); | |
| 204 | + *symbolic = *((GSparseSymbolic*)m.m_symbolic); | |
| 205 | + m_symbolic = (void*)symbolic; | |
| 206 | + } | |
| 207 | + | |
| 208 | + // If there is a numeric decomposition then copy it | |
| 209 | + if (m.m_numeric != NULL) { | |
| 210 | + GSparseNumeric* numeric = new GSparseNumeric(); | |
| 211 | + if (numeric == NULL) | |
| 212 | + throw mem_alloc("GSparseMatrix copy constructor", 1); | |
| 213 | + *numeric = *((GSparseNumeric*)m.m_numeric); | |
| 214 | + m_numeric = (void*)numeric; | |
| 215 | + } | |
| 216 | + | |
| 217 | + } // endif: object was not identical | |
| 218 | + | |
| 219 | + // Return | |
| 220 | + return *this; | |
| 221 | +} | |
| 222 | + | |
| 223 | + | |
| 224 | +/*************************************************************************** | |
| 225 | + * Vector multiplication * | |
| 226 | + * ----------------------------------------------------------------------- * | |
| 227 | + * Performs sparse matrix*vector multiplication including an eventually * | |
| 228 | + * pending fill. * | |
| 229 | + ***************************************************************************/ | |
| 230 | +GVector GSparseMatrix::operator* (const GVector& v) const | |
| 231 | +{ | |
| 232 | + // Raise an exception if the matrix and vector dimensions are not compatible | |
| 233 | + if (m_cols != v.m_num) | |
| 234 | + throw matrix_vector_mismatch("GSparseMatrix::operator* (const GVector&)", | |
| 235 | + v.m_num, m_rows, m_cols); | |
| 236 | + | |
| 237 | + // Initialise result vector | |
| 238 | + GVector result(m_rows); | |
| 239 | + | |
| 240 | + // Multiply only if there are elements in matrix | |
| 241 | + if (m_elements > 0) { | |
| 242 | + | |
| 243 | + // Perform vector multiplication | |
| 244 | + for (int col = 0; col < m_cols; ++col) { | |
| 245 | + int i_start = m_colstart[col]; | |
| 246 | + int i_stop = m_colstart[col+1]; | |
| 247 | + double* ptr_data = m_data + i_start; | |
| 248 | + int* ptr_rowinx = m_rowinx + i_start; | |
| 249 | + for (int i = i_start; i < i_stop; ++i) | |
| 250 | + result(*ptr_rowinx++) += *ptr_data++ * v(col); | |
| 251 | + } | |
| 252 | + | |
| 253 | + // If fill is pending then add-in also this element into the product | |
| 254 | + if (m_fill_val != 0.0) { | |
| 255 | + result(m_fill_row) += m_fill_val * v(m_fill_col); | |
| 256 | + #if defined(G_DEBUG_SPARSE_PENDING) | |
| 257 | + cout << "GSparseMatrix::operator* (const GVector&) const: pending value " << | |
| 258 | + m_fill_val << " for location (" << m_fill_row << "," << m_fill_col << | |
| 259 | + ") has been used." << endl; | |
| 260 | + #endif | |
| 261 | + } | |
| 262 | + | |
| 263 | + } // endif: there were elements in matrix | |
| 264 | + | |
| 265 | + // Return result | |
| 266 | + return result; | |
| 267 | +} | |
| 268 | + | |
| 269 | + | |
| 270 | +/*************************************************************************** | |
| 271 | + * GSparseMatrix comparison (equality operator) * | |
| 272 | + ***************************************************************************/ | |
| 273 | +int GSparseMatrix::operator== (const GSparseMatrix &m) const | |
| 274 | +{ | |
| 275 | + // Initalise the result to 'equal matrices' | |
| 276 | + int result = 1; | |
| 277 | + | |
| 278 | + // Perform comparison (only if matrix dimensions are identical) | |
| 279 | + if (m_rows == m.m_rows && m_cols == m.m_cols) { | |
| 280 | + | |
| 281 | + // Loop over all matrix elements | |
| 282 | + for (int row = 0; row < m_rows; ++row) { | |
| 283 | + for (int col = 0; col < m_cols; ++col) { | |
| 284 | + if ((*this)(row,col) != m(row,col)) { | |
| 285 | + result = 0; | |
| 286 | + break; | |
| 287 | + } | |
| 288 | + } | |
| 289 | + if (!result) | |
| 290 | + break; | |
| 291 | + } | |
| 292 | + } | |
| 293 | + else | |
| 294 | + result = 0; | |
| 295 | + | |
| 296 | + // Return result | |
| 297 | + return result; | |
| 298 | +} | |
| 299 | + | |
| 300 | + | |
| 301 | +/*************************************************************************** | |
| 302 | + * GSparseMatrix comparison (non-equality operator) * | |
| 303 | + ***************************************************************************/ | |
| 304 | +int GSparseMatrix::operator!= (const GSparseMatrix &m) const | |
| 305 | +{ | |
| 306 | + // Initalise the result to 'equal matrices' | |
| 307 | + int result = 0; | |
| 308 | + | |
| 309 | + // Perform comparison (only if matrix dimensions are identical) | |
| 310 | + if (m_rows == m.m_rows && m_cols == m.m_cols) { | |
| 311 | + | |
| 312 | + // Loop over all matrix elements | |
| 313 | + for (int row = 0; row < m_rows; ++row) { | |
| 314 | + for (int col = 0; col < m_cols; ++col) { | |
| 315 | + if ((*this)(row,col) != m(row,col)) { | |
| 316 | + result = 1; | |
| 317 | + break; | |
| 318 | + } | |
| 319 | + } | |
| 320 | + if (!result) | |
| 321 | + break; | |
| 322 | + } | |
| 323 | + } | |
| 324 | + else | |
| 325 | + result = 1; | |
| 326 | + | |
| 327 | + // Return result | |
| 328 | + return result; | |
| 329 | +} | |
| 330 | + | |
| 331 | + | |
| 332 | +/*************************************************************************** | |
| 333 | + * GSparseMatrix negation (unary minus operator) * | |
| 334 | + ***************************************************************************/ | |
| 335 | +GSparseMatrix GSparseMatrix::operator- ( ) const | |
| 336 | +{ | |
| 337 | + // Copy argument into result | |
| 338 | + GSparseMatrix result = *this; | |
| 339 | + | |
| 340 | + // Fill pending matrix element | |
| 341 | + result.fill_pending(); | |
| 342 | + | |
| 343 | + // Negate result | |
| 344 | + for (int i = 0; i < result.m_elements; ++i) | |
| 345 | + result.m_data[i] = -result.m_data[i]; | |
| 346 | + | |
| 347 | + // Return result | |
| 348 | + return result; | |
| 349 | +} | |
| 350 | + | |
| 351 | + | |
| 352 | +/*************************************************************************** | |
| 353 | + * GSparseMatrix addition (unary addition operator) * | |
| 354 | + * ----------------------------------------------------------------------- * | |
| 355 | + * NOT YET IN PURE NATIVE CODE !!!!!! * | |
| 356 | + ***************************************************************************/ | |
| 357 | +GSparseMatrix& GSparseMatrix::operator+= (const GSparseMatrix& m) | |
| 358 | +{ | |
| 359 | + // Raise an exception if the matrix dimensions are not compatible | |
| 360 | + if (m_rows != m.m_rows || m_cols != m.m_cols) | |
| 361 | + throw matrix_mismatch("GSparseMatrix::operator+= (const GSparseMatrix&)", | |
| 362 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 363 | + | |
| 364 | + // Perform inplace matrix addition | |
| 365 | + for (int col = 0; col < m_cols; ++col) { | |
| 366 | + GVector v_result = extract_col(col); | |
| 367 | + GVector v_operand = m.extract_col(col); | |
| 368 | + v_result += v_operand; | |
| 369 | + insert_col(v_result, col); | |
| 370 | + } | |
| 371 | + | |
| 372 | + // Return result | |
| 373 | + return *this; | |
| 374 | +} | |
| 375 | + | |
| 376 | + | |
| 377 | +/*************************************************************************** | |
| 378 | + * GSparseMatrix subtraction (unary addition operator) * | |
| 379 | + * ----------------------------------------------------------------------- * | |
| 380 | + * NOT YET IN PURE NATIVE CODE !!!!!! * | |
| 381 | + ***************************************************************************/ | |
| 382 | +GSparseMatrix& GSparseMatrix::operator-= (const GSparseMatrix& m) | |
| 383 | +{ | |
| 384 | + // Raise an exception if the matrix dimensions are not compatible | |
| 385 | + if (m_rows != m.m_rows || m_cols != m.m_cols) | |
| 386 | + throw matrix_mismatch("GSparseMatrix::operator-= (const GSparseMatrix&)", | |
| 387 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 388 | + | |
| 389 | + // Perform inplace matrix subtraction | |
| 390 | + for (int col = 0; col < m_cols; ++col) { | |
| 391 | + GVector v_result = extract_col(col); | |
| 392 | + GVector v_operand = m.extract_col(col); | |
| 393 | + v_result -= v_operand; | |
| 394 | + insert_col(v_result, col); | |
| 395 | + } | |
| 396 | + | |
| 397 | + // Return result | |
| 398 | + return *this; | |
| 399 | +} | |
| 400 | + | |
| 401 | + | |
| 402 | +/*************************************************************************** | |
| 403 | + * Matrix multiplication (unary multiplication operator) * | |
| 404 | + * ----------------------------------------------------------------------- * | |
| 405 | + * NOT YET IN PURE NATIVE CODE !!!!!! * | |
| 406 | + ***************************************************************************/ | |
| 407 | +GSparseMatrix& GSparseMatrix::operator*= (const GSparseMatrix& m) | |
| 408 | +{ | |
| 409 | + // Raise an exception if the matrix dimensions are not compatible | |
| 410 | + if (m_cols != m.m_rows || m_rows != m.m_cols) | |
| 411 | + throw matrix_mismatch("GSparseMatrix::operator*= (const GSparseMatrix&)", | |
| 412 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 413 | + | |
| 414 | + // Allocate result matrix | |
| 415 | + GSparseMatrix result(m_rows, m.m_cols); | |
| 416 | + | |
| 417 | + // Multiply only if there are elements in both matrices | |
| 418 | + if (m_elements > 0 && m.m_elements > 0) { | |
| 419 | + | |
| 420 | + // Loop over all elements of result matrix | |
| 421 | + for (int row = 0; row < m_rows; ++row) { | |
| 422 | + for (int col = 0; col < m.m_cols; ++col) { | |
| 423 | + double sum = 0.0; | |
| 424 | + for (int i = 0; i < m_cols; ++i) | |
| 425 | + sum += (*this)(row,i) * m(i,col); | |
| 426 | + result(row,col) = sum; | |
| 427 | + } | |
| 428 | + } | |
| 429 | + | |
| 430 | + } | |
| 431 | + | |
| 432 | + // Assign result | |
| 433 | + *this = result; | |
| 434 | + | |
| 435 | + // Return result | |
| 436 | + return *this; | |
| 437 | +} | |
| 438 | + | |
| 439 | + | |
| 440 | +/*========================================================================== | |
| 441 | + = = | |
| 442 | + = GSparseMatrix member functions = | |
| 443 | + = = | |
| 444 | + ==========================================================================*/ | |
| 445 | + | |
| 446 | +/*************************************************************************** | |
| 447 | + * Get minimum matrix element * | |
| 448 | + ***************************************************************************/ | |
| 449 | +double GSparseMatrix::min() const | |
| 450 | +{ | |
| 451 | + // Initialise minimum with fill value | |
| 452 | + double result = m_fill_val; | |
| 453 | + | |
| 454 | + // Search all elements for the smallest one | |
| 455 | + for (int i = 0; i < m_elements; ++i) { | |
| 456 | + if (m_data[i] < result) | |
| 457 | + result = m_data[i]; | |
| 458 | + } | |
| 459 | + | |
| 460 | + // If minimum is > 0.0 and there are zero elements then set the minimum | |
| 461 | + // to 0.0 | |
| 462 | + if ((result > 0.0) && (m_elements < (m_rows*m_cols))) | |
| 463 | + result = 0.0; | |
| 464 | + | |
| 465 | + // Return result | |
| 466 | + return result; | |
| 467 | +} | |
| 468 | + | |
| 469 | + | |
| 470 | +/*************************************************************************** | |
| 471 | + * Get maximum matrix element * | |
| 472 | + ***************************************************************************/ | |
| 473 | +double GSparseMatrix::max() const | |
| 474 | +{ | |
| 475 | + // Initialise maximum with fill value | |
| 476 | + double result = m_fill_val; | |
| 477 | + | |
| 478 | + // Search all elements for the largest one | |
| 479 | + for (int i = 0; i < m_elements; ++i) { | |
| 480 | + if (m_data[i] > result) | |
| 481 | + result = m_data[i]; | |
| 482 | + } | |
| 483 | + | |
| 484 | + // If maximum is < 0.0 and there are zero elements then set the maximum | |
| 485 | + // to 0.0 | |
| 486 | + if ((result < 0.0) && (m_elements < (m_rows*m_cols))) | |
| 487 | + result = 0.0; | |
| 488 | + | |
| 489 | + // Return result | |
| 490 | + return result; | |
| 491 | +} | |
| 492 | + | |
| 493 | + | |
| 494 | +/*************************************************************************** | |
| 495 | + * Compute sum of non-zero elements * | |
| 496 | + ***************************************************************************/ | |
| 497 | +double GSparseMatrix::sum() const | |
| 498 | +{ | |
| 499 | + // Initialise matrix sum with fill value | |
| 500 | + double result = m_fill_val; | |
| 501 | + | |
| 502 | + // Add all elements | |
| 503 | + for (int i = 0; i < m_elements; ++i) | |
| 504 | + result += m_data[i]; | |
| 505 | + | |
| 506 | + // Return result | |
| 507 | + return result; | |
| 508 | +} | |
| 509 | + | |
| 510 | + | |
| 511 | +/*************************************************************************** | |
| 512 | + * Inplace transpose of matrix * | |
| 513 | + * ----------------------------------------------------------------------- * | |
| 514 | + * Call cs function * | |
| 515 | + ***************************************************************************/ | |
| 516 | +void GSparseMatrix::transpose() | |
| 517 | +{ | |
| 518 | + *this = cs_transpose(this, 1); | |
| 519 | +} | |
| 520 | + | |
| 521 | + | |
| 522 | +/*************************************************************************** | |
| 523 | + * Extract row from matrix into vector * | |
| 524 | + ***************************************************************************/ | |
| 525 | +GVector GSparseMatrix::extract_row(int row) const | |
| 526 | +{ | |
| 527 | + // Raise an exception if the row index is invalid | |
| 528 | + #if defined(G_RANGE_CHECK) | |
| 529 | + if (row >= m_rows) | |
| 530 | + throw out_of_range("GSparseMatrix::extract_row(int)", | |
| 531 | + row, 0, m_rows, m_cols); | |
| 532 | + #endif | |
| 533 | + | |
| 534 | + // Create result vector | |
| 535 | + GVector result(m_cols); | |
| 536 | + | |
| 537 | + // Loop over all columns to extract data | |
| 538 | + for (int col = 0; col < m_cols; ++col) { | |
| 539 | + | |
| 540 | + // Get the start and stop of the elements | |
| 541 | + int i_start = m_colstart[col]; | |
| 542 | + int i_stop = m_colstart[col+1]; | |
| 543 | + | |
| 544 | + // Search requested row in elements | |
| 545 | + int i; | |
| 546 | + for (i = i_start; i < i_stop; ++i) { | |
| 547 | + if (m_rowinx[i] == row) | |
| 548 | + break; | |
| 549 | + } | |
| 550 | + | |
| 551 | + // Copy element if we found one | |
| 552 | + if (i < i_stop) | |
| 553 | + result(col) = m_data[i]; | |
| 554 | + | |
| 555 | + } // endfor: looped over all columns | |
| 556 | + | |
| 557 | + // If there is a pending element then put it in the vector | |
| 558 | + if (m_fill_val != 0.0 && m_fill_row == row) | |
| 559 | + result(m_fill_col) = m_fill_val; | |
| 560 | + | |
| 561 | + // Return vector | |
| 562 | + return result; | |
| 563 | + | |
| 564 | +} | |
| 565 | + | |
| 566 | + | |
| 567 | +/*************************************************************************** | |
| 568 | + * Extract column from matrix into vector * | |
| 569 | + ***************************************************************************/ | |
| 570 | +GVector GSparseMatrix::extract_col(int col) const | |
| 571 | +{ | |
| 572 | + // Raise an exception if the column index is invalid | |
| 573 | + #if defined(G_RANGE_CHECK) | |
| 574 | + if (col >= m_cols) | |
| 575 | + throw out_of_range("GSparseMatrix::extract_col(int)", | |
| 576 | + 0, col, m_rows, m_cols); | |
| 577 | + #endif | |
| 578 | + | |
| 579 | + // Create result vector | |
| 580 | + GVector result(m_rows); | |
| 581 | + | |
| 582 | + // Get the start and stop of the elements | |
| 583 | + int i_start = m_colstart[col]; | |
| 584 | + int i_stop = m_colstart[col+1]; | |
| 585 | + | |
| 586 | + // Extract elements into vector | |
| 587 | + for (int i = i_start; i < i_stop; ++i) | |
| 588 | + result(m_rowinx[i]) = m_data[i]; | |
| 589 | + | |
| 590 | + // If there is a pending element then put it in the vector | |
| 591 | + if (m_fill_val != 0.0 && m_fill_col == col) | |
| 592 | + result(m_fill_row) = m_fill_val; | |
| 593 | + | |
| 594 | + // Return vector | |
| 595 | + return result; | |
| 596 | + | |
| 597 | +} | |
| 598 | + | |
| 599 | + | |
| 600 | +/*************************************************************************** | |
| 601 | + * Insert vector column into matrix * | |
| 602 | + ***************************************************************************/ | |
| 603 | +void GSparseMatrix::insert_col(const GVector& v, int col) | |
| 604 | +{ | |
| 605 | + // Debug header | |
| 606 | + #if defined(G_DEBUG_SPARSE_INSERTION) | |
| 607 | + cout << "GSparseMatrix::insert_col([" << v << "], " << col << "):" << endl; | |
| 608 | + cout << " In Data : "; | |
| 609 | + for (int i = 0; i < m_elements; ++i) | |
| 610 | + cout << m_data[i] << " "; | |
| 611 | + cout << endl << " In Row .: "; | |
| 612 | + for (int i = 0; i < m_elements; ++i) | |
| 613 | + cout << m_rowinx[i] << " "; | |
| 614 | + cout << endl << " In Col .: "; | |
| 615 | + for (int i = 0; i < m_cols+1; ++i) | |
| 616 | + cout << m_colstart[i] << " "; | |
| 617 | + cout << endl; | |
| 618 | + #endif | |
| 619 | + | |
| 620 | + // Raise an exception if the column index is invalid | |
| 621 | + #if defined(G_RANGE_CHECK) | |
| 622 | + if (col >= m_cols) | |
| 623 | + throw out_of_range("GSparseMatrix::insert_col(const GVector&, int)", | |
| 624 | + 0, col, m_rows, m_cols); | |
| 625 | + #endif | |
| 626 | + | |
| 627 | + // Raise an exception if the matrix and vector dimensions are not compatible | |
| 628 | + if (m_rows != v.m_num) | |
| 629 | + throw matrix_vector_mismatch("GSparseMatrix::insert_col(const GVector&, int)", | |
| 630 | + v.m_num, m_rows, m_cols); | |
| 631 | + | |
| 632 | + // If there is a pending element for this column then delete it since | |
| 633 | + // the vector overwrites this element | |
| 634 | + if (m_fill_val != 0.0 && m_fill_col == col) { | |
| 635 | + #if defined(G_DEBUG_SPARSE_PENDING) | |
| 636 | + cout << "GSparseMatrix::insert_col(const GVector, int): pending value " << | |
| 637 | + m_fill_val << " for location (" << m_fill_row << "," << m_fill_col << | |
| 638 | + ") became obsolete" << endl; | |
| 639 | + #endif | |
| 640 | + m_fill_val = 0.0; | |
| 641 | + m_fill_row = 0; | |
| 642 | + m_fill_col = 0; | |
| 643 | + } | |
| 644 | + | |
| 645 | + // Determine the number of non-zero elements in the vector | |
| 646 | + int n_vector = 0; | |
| 647 | + for (int row = 0; row < m_rows; ++row) { | |
| 648 | + if (v(row) != 0.0) | |
| 649 | + n_vector++; | |
| 650 | + } | |
| 651 | + | |
| 652 | + // Get the start and stop indices of the actual column and compute | |
| 653 | + // the number of exisiting elements in the column | |
| 654 | + int i_start = m_colstart[col]; | |
| 655 | + int i_stop = m_colstart[col+1]; | |
| 656 | + int n_exist = i_stop - i_start; | |
| 657 | + | |
| 658 | + // Compute the size difference for the new matrix. It is positive if | |
| 659 | + // the number of non-zero entries in the vector is larger than the | |
| 660 | + // number of non-zero entries in the matrix (in this case we have to | |
| 661 | + // increase the matrix size). | |
| 662 | + int n_diff = n_vector - n_exist; | |
| 663 | + | |
| 664 | + // If we need space then allocate it, if we have to much space the free it | |
| 665 | + if (n_diff > 0) { | |
| 666 | + alloc_elements(i_start, n_diff); | |
| 667 | + #if defined(G_DEBUG_SPARSE_INSERTION) | |
| 668 | + cout << " Insert .: " << n_diff << " elements at index " << i_start << endl; | |
| 669 | + #endif | |
| 670 | + } | |
| 671 | + else if (n_diff < 0) { | |
| 672 | + free_elements(i_start, -n_diff); | |
| 673 | + #if defined(G_DEBUG_SPARSE_INSERTION) | |
| 674 | + cout << " Remove .: " << -n_diff << " elements at index " << i_start << endl; | |
| 675 | + #endif | |
| 676 | + } | |
| 677 | + | |
| 678 | + // Insert the vector elements in the matrix | |
| 679 | + if (n_vector > 0) { | |
| 680 | + for (int row = 0, i = i_start; row < m_rows; ++row) { | |
| 681 | + if (v(row) != 0.0) { | |
| 682 | + m_data[i] = v(row); | |
| 683 | + m_rowinx[i] = row; | |
| 684 | + i++; | |
| 685 | + } | |
| 686 | + } | |
| 687 | + } | |
| 688 | + | |
| 689 | + // Update column start indices | |
| 690 | + for (int i = col+1; i <= m_cols; ++i) | |
| 691 | + m_colstart[i] += n_diff; | |
| 692 | + | |
| 693 | + // Debugging: show sparse matrix after insertion | |
| 694 | + #if defined(G_DEBUG_SPARSE_INSERTION) | |
| 695 | + cout << " Out Data: "; | |
| 696 | + for (int i = 0; i < m_elements; ++i) | |
| 697 | + cout << m_data[i] << " "; | |
| 698 | + cout << endl << " Out Row : "; | |
| 699 | + for (int i = 0; i < m_elements; ++i) | |
| 700 | + cout << m_rowinx[i] << " "; | |
| 701 | + cout << endl << " Out Col : "; | |
| 702 | + for (int i = 0; i < m_cols+1; ++i) | |
| 703 | + cout << m_colstart[i] << " "; | |
| 704 | + cout << endl; | |
| 705 | + #endif | |
| 706 | + | |
| 707 | + // Return | |
| 708 | + return; | |
| 709 | +} | |
| 710 | + | |
| 711 | + | |
| 712 | +/*************************************************************************** | |
| 713 | + * Add vector to matrix column * | |
| 714 | + ***************************************************************************/ | |
| 715 | +void GSparseMatrix::add_col(const GVector& v, int col) | |
| 716 | +{ | |
| 717 | + // Raise an exception if the column index is invalid | |
| 718 | + #if defined(G_RANGE_CHECK) | |
| 719 | + if (col >= m_cols) | |
| 720 | + throw out_of_range("GSparseMatrix::add_col(const GVector&, int)", | |
| 721 | + 0, col, m_rows, m_cols); | |
| 722 | + #endif | |
| 723 | + | |
| 724 | + // Raise an exception if the matrix and vector dimensions are incompatible | |
| 725 | + if (m_rows != v.m_num) | |
| 726 | + throw matrix_vector_mismatch("GSparseMatrix::add_col(const GVector&, int)", | |
| 727 | + v.m_num, m_rows, m_cols); | |
| 728 | + | |
| 729 | + // Extract vector for column, add elements, and re-insert vector | |
| 730 | + GVector column = extract_col(col); | |
| 731 | + column += v; | |
| 732 | + insert_col(column, col); | |
| 733 | + | |
| 734 | + // Return | |
| 735 | + return; | |
| 736 | +} | |
| 737 | + | |
| 738 | + | |
| 739 | +/*************************************************************************** | |
| 740 | + * Convert matrix into full matrix * | |
| 741 | + ***************************************************************************/ | |
| 742 | +GMatrix GSparseMatrix::convert_to_full() const | |
| 743 | +{ | |
| 744 | + // Define result matrix | |
| 745 | + GMatrix result(m_rows, m_cols); | |
| 746 | + | |
| 747 | + // Extract all elements | |
| 748 | + for (int row = 0; row < m_rows; ++row) { | |
| 749 | + for (int col = 0; col < m_cols; ++col) | |
| 750 | + result(row,col) = (*this)(row,col); | |
| 751 | + } | |
| 752 | + | |
| 753 | + // Return result | |
| 754 | + return result; | |
| 755 | +} | |
| 756 | + | |
| 757 | + | |
| 758 | +/*************************************************************************** | |
| 759 | + * GSparseMatrix Cholesky decomposition * | |
| 760 | + * ----------------------------------------------------------------------- * | |
| 761 | + * Cholesky decomposition of a sparse matrix. The decomposition is stored * | |
| 762 | + * within the GSparseMatrix without destroying the original matrix. * | |
| 763 | +***************************************************************************/ | |
| 764 | +void GSparseMatrix::cholesky_decompose(int compress) | |
| 765 | +{ | |
| 766 | + // Save original matrix size | |
| 767 | + int matrix_rows = m_rows; | |
| 768 | + int matrix_cols = m_cols; | |
| 769 | + | |
| 770 | + // Delete any existing symbolic analysis object | |
| 771 | + if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; | |
| 772 | + | |
| 773 | + // Allocate symbolic analysis object | |
| 774 | + GSparseSymbolic* symbolic = new GSparseSymbolic(); | |
| 775 | + if (symbolic == NULL) | |
| 776 | + throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", 1); | |
| 777 | + | |
| 778 | + // Declare numeric analysis object. We don't allocate one since we'll | |
| 779 | + // throw it away at the end of the function (the L matrix will be copied | |
| 780 | + // in this object) | |
| 781 | + GSparseNumeric numeric; | |
| 782 | + | |
| 783 | + // Fill pending element into matrix | |
| 784 | + fill_pending(); | |
| 785 | + | |
| 786 | + // Remove rows and columns containing only zeros if matrix compression | |
| 787 | + // has been selected | |
| 788 | + if (compress) | |
| 789 | + remove_zero_row_col(); | |
| 790 | + | |
| 791 | + // Ordering an symbolic analysis of matrix. This sets up an array 'pinv' | |
| 792 | + // which contains the fill-in reducing permutations | |
| 793 | + symbolic->cholesky_symbolic_analysis(1, *this); | |
| 794 | + | |
| 795 | + // Perform numeric Cholesky decomposition | |
| 796 | + numeric.cholesky_numeric_analysis(*this, *symbolic); | |
| 797 | + | |
| 798 | + // Insert zero rows and columns if they have been removed previously. | |
| 799 | + // Since no selection information is present in numeric.m_L we have to | |
| 800 | + // copy it from this in order to allow for insertion. | |
| 801 | + if (compress) { | |
| 802 | + | |
| 803 | + // If there is a row selection then copy it | |
| 804 | + if (m_rowsel != NULL && m_num_rowsel > 0) { | |
| 805 | + numeric.m_L->m_rowsel = new int[m_num_rowsel]; | |
| 806 | + if (numeric.m_L->m_rowsel == NULL) | |
| 807 | + throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", m_num_rowsel); | |
| 808 | + for (int i = 0; i < m_num_rowsel; ++i) | |
| 809 | + numeric.m_L->m_rowsel[i] = m_rowsel[i]; | |
| 810 | + numeric.m_L->m_num_rowsel = m_num_rowsel; | |
| 811 | + } | |
| 812 | + | |
| 813 | + // If there is a column selection then copy it | |
| 814 | + if (m_colsel != NULL && m_num_colsel > 0) { | |
| 815 | + numeric.m_L->m_colsel = new int[m_num_colsel]; | |
| 816 | + if (numeric.m_L->m_colsel == NULL) | |
| 817 | + throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", m_num_colsel); | |
| 818 | + for (int i = 0; i < m_num_colsel; ++i) | |
| 819 | + numeric.m_L->m_colsel[i] = m_colsel[i]; | |
| 820 | + numeric.m_L->m_num_colsel = m_num_colsel; | |
| 821 | + } | |
| 822 | + | |
| 823 | + // Now we can insert zero rows and columns | |
| 824 | + numeric.m_L->insert_zero_row_col(matrix_rows, matrix_cols); | |
| 825 | + } | |
| 826 | + | |
| 827 | + // Store Cholesky decomposition in matrix | |
| 828 | + *this = *(numeric.m_L); | |
| 829 | + | |
| 830 | + // Store symbolic pointer in sparse matrix object | |
| 831 | + m_symbolic = (void*)symbolic; | |
| 832 | + | |
| 833 | + // Return | |
| 834 | + return; | |
| 835 | +} | |
| 836 | + | |
| 837 | + | |
| 838 | +/*************************************************************************** | |
| 839 | + * GSparseMatrix Cholesky solver * | |
| 840 | + * ----------------------------------------------------------------------- * | |
| 841 | + * Solves the linear equation A*x=b using a Cholesky decomposition of A. * | |
| 842 | + * This function is to be applied on a GSparseMatrix matrix for which a * | |
| 843 | + * Choleksy factorization has been produced using 'cholesky_decompose'. * | |
| 844 | + ***************************************************************************/ | |
| 845 | +GVector GSparseMatrix::cholesky_solver(const GVector& v, int compress) | |
| 846 | +{ | |
| 847 | + // Declare loop variables | |
| 848 | + int row; | |
| 849 | + int col; | |
| 850 | + int c_row; | |
| 851 | + int c_col; | |
| 852 | + | |
| 853 | + // Dump header | |
| 854 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 855 | + cout << "GSparseMatrix::cholesky_solver" << endl; | |
| 856 | + cout << " Input vector .....: " << v << endl; | |
| 857 | + #endif | |
| 858 | + | |
| 859 | + // Raise an exception if the matrix and vector dimensions are incompatible | |
| 860 | + if (m_rows != v.m_num) | |
| 861 | + throw matrix_vector_mismatch( | |
| 862 | + "GSparseMatrix::cholesky_solver(const GVector&, int)", | |
| 863 | + v.m_num, m_rows, m_cols); | |
| 864 | + | |
| 865 | + // Raise an exception if there is no symbolic pointer | |
| 866 | + if (!m_symbolic) | |
| 867 | + throw matrix_not_factorised( | |
| 868 | + "GSparseMatrix::cholesky_solver(const GVector&, int)", | |
| 869 | + "Cholesky decomposition"); | |
| 870 | + | |
| 871 | + // Get symbolic pointer | |
| 872 | + GSparseSymbolic* symbolic = (GSparseSymbolic*)m_symbolic; | |
| 873 | + | |
| 874 | + // Raise an exception if there is no permutation | |
| 875 | + if (!symbolic->m_pinv) | |
| 876 | + throw matrix_not_factorised( | |
| 877 | + "GSparseMatrix::cholesky_solver(const GVector&, int)", | |
| 878 | + "Cholesky decomposition"); | |
| 879 | + | |
| 880 | + // Flag row and column compression | |
| 881 | + int row_compressed = (m_rowsel != NULL && m_num_rowsel < m_rows); | |
| 882 | + int col_compressed = (m_colsel != NULL && m_num_colsel < m_cols); | |
| 883 | + | |
| 884 | + // Decide if we need a compression algorithm or not | |
| 885 | + int no_zero = !(compress && (row_compressed || col_compressed)); | |
| 886 | + | |
| 887 | + // Allocate vector for permutation and result vector | |
| 888 | + GVector result(m_cols); | |
| 889 | + | |
| 890 | + // Setup pointers to L matrix and x vector | |
| 891 | + int* Lp = m_colstart; | |
| 892 | + int* Li = m_rowinx; | |
| 893 | + double* Lx = m_data; | |
| 894 | + | |
| 895 | + // Case A: no zero-row/col compression needed | |
| 896 | + if (no_zero) { | |
| 897 | + | |
| 898 | + // Declare working vector | |
| 899 | + GVector x(m_rows); | |
| 900 | + | |
| 901 | + // Perform inverse vector permutation | |
| 902 | + for (int i = 0; i < v.m_num; ++i) | |
| 903 | + x.m_data[symbolic->m_pinv[i]] = v.m_data[i]; | |
| 904 | + | |
| 905 | + // Inplace solve L\x=x | |
| 906 | + for (col = 0; col < m_cols; ++col) { // loop over columns | |
| 907 | + x.m_data[col] /= Lx[Lp[col]]; // divide by diag. | |
| 908 | + for (int p = Lp[col]+1; p < Lp[col+1]; p++) // loop over elements | |
| 909 | + x.m_data[Li[p]] -= Lx[p] * x.m_data[col]; | |
| 910 | + } | |
| 911 | + | |
| 912 | + // Inplace solve L'\x=x | |
| 913 | + for (col = m_cols-1; col >= 0; --col) { // loop over columns | |
| 914 | + for (int p = Lp[col]+1; p < Lp[col+1]; p++) // loop over elements | |
| 915 | + x.m_data[col] -= Lx[p] * x.m_data[Li[p]]; | |
| 916 | + x.m_data[col] /= Lx[Lp[col]]; | |
| 917 | + } | |
| 918 | + | |
| 919 | + // Perform vector permutation | |
| 920 | + for (int i = 0; i < m_cols; ++i) | |
| 921 | + result.m_data[i] = x.m_data[symbolic->m_pinv[i]]; | |
| 922 | + | |
| 923 | + } // endif: Case A | |
| 924 | + | |
| 925 | + // Case B: zero-row/column compression requested | |
| 926 | + else { | |
| 927 | + | |
| 928 | + // Allocate row and column mapping arrays | |
| 929 | + int* row_map = new int[m_rows]; | |
| 930 | + if (row_map == NULL) | |
| 931 | + throw mem_alloc("GSparseMatrix::cholesky_solver(const GVector&, int)", m_rows); | |
| 932 | + int* col_map = new int[m_cols]; | |
| 933 | + if (col_map == NULL) | |
| 934 | + throw mem_alloc("GSparseMatrix::cholesky_solver(const GVector&, int)", m_cols); | |
| 935 | + | |
| 936 | + // Setup row mapping array that maps original matrix rows into compressed | |
| 937 | + // matrix rows. An entry of -1 indicates that the row should be dropped. | |
| 938 | + // If no selection exists then setup an identity map. | |
| 939 | + if (row_compressed) { | |
| 940 | + for (row = 0; row < m_rows; ++row) | |
| 941 | + row_map[row] = -1; | |
| 942 | + for (c_row = 0; c_row < m_num_rowsel; ++c_row) | |
| 943 | + row_map[m_rowsel[c_row]] = c_row; | |
| 944 | + } | |
| 945 | + else { | |
| 946 | + for (row = 0; row < m_rows; ++row) | |
| 947 | + row_map[row] = row; | |
| 948 | + } | |
| 949 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 950 | + cout << " Row mapping ......:"; | |
| 951 | + for (row = 0; row < m_rows; ++row) | |
| 952 | + cout << " " << row_map[row]; | |
| 953 | + cout << endl; | |
| 954 | + #endif | |
| 955 | + | |
| 956 | + // Setup column mapping array that maps original matrix column into compressed | |
| 957 | + // matrix columns. An entry of -1 indicates that the column should be dropped | |
| 958 | + // If no selection exists then setup an identity map. | |
| 959 | + if (col_compressed) { | |
| 960 | + for (col = 0; col < m_cols; ++col) | |
| 961 | + col_map[col] = -1; | |
| 962 | + for (c_col = 0; c_col < m_num_colsel; ++c_col) | |
| 963 | + col_map[m_colsel[c_col]] = c_col; | |
| 964 | + } | |
| 965 | + else { | |
| 966 | + for (col = 0; col < m_cols; ++col) | |
| 967 | + col_map[col] = col; | |
| 968 | + } | |
| 969 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 970 | + cout << " Column mapping ...:"; | |
| 971 | + for (col = 0; col < m_cols; ++col) | |
| 972 | + cout << " " << col_map[col]; | |
| 973 | + cout << endl; | |
| 974 | + #endif | |
| 975 | + | |
| 976 | + // Declare working vector | |
| 977 | + GVector x(row_compressed ? m_num_rowsel : m_rows); | |
| 978 | + | |
| 979 | + // Compress input vector v -> c_v if required | |
| 980 | + if (m_rowsel != NULL && m_num_rowsel < m_rows) { | |
| 981 | + for (c_row = 0; c_row < m_num_rowsel; ++c_row) | |
| 982 | + x.m_data[c_row] = v.m_data[m_rowsel[c_row]]; | |
| 983 | + } | |
| 984 | + else | |
| 985 | + x = v; | |
| 986 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 987 | + cout << " Compressed vector : " << x << endl; | |
| 988 | + #endif | |
| 989 | + | |
| 990 | + // Perform inverse permutation | |
| 991 | + x = iperm(x, symbolic->m_pinv); | |
| 992 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 993 | + cout << " Permutated vector : " << x << endl; | |
| 994 | + #endif | |
| 995 | + | |
| 996 | + // Inplace solve L\x=x. The column and row maps are just use to see which | |
| 997 | + // columns or rows should be skipped in the calculations. | |
| 998 | + for (col = 0; col < m_cols; ++col) { // loop over columns | |
| 999 | + if ((c_col = col_map[col]) >= 0) { // use only non-zero cols | |
| 1000 | + x.m_data[c_col] /= Lx[Lp[col]]; // divide by diag. | |
| 1001 | + for (int p = Lp[col]+1; p < Lp[col+1]; p++) { // loop over elements | |
| 1002 | + if ((c_row = row_map[Li[p]]) >= 0) // use only non-zero rows | |
| 1003 | + x.m_data[c_row] -= Lx[p] * x.m_data[c_col]; | |
| 1004 | + } | |
| 1005 | + } | |
| 1006 | + } | |
| 1007 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1008 | + cout << " Solve Lx=x .......: " << x << endl; | |
| 1009 | + #endif | |
| 1010 | + | |
| 1011 | + // Inplace solve L'\x=x. The column and row maps are just use to see which | |
| 1012 | + // columns or rows should be skipped in the calculations. | |
| 1013 | + for (col = m_cols-1; col >= 0; --col) { // loop over columns | |
| 1014 | + if ((c_col = col_map[col]) >= 0) { // use only non-zero cols | |
| 1015 | + for (int p = Lp[col]+1; p < Lp[col+1]; p++) { // loop over elements | |
| 1016 | + if ((c_row = row_map[Li[p]]) >= 0) // use only non-zero rows | |
| 1017 | + x.m_data[c_col] -= Lx[p] * x.m_data[c_row]; | |
| 1018 | + } | |
| 1019 | + x.m_data[c_col] /= Lx[Lp[col]]; | |
| 1020 | + } | |
| 1021 | + } | |
| 1022 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1023 | + cout << " Solve L'x=x ......: " << x << endl; | |
| 1024 | + #endif | |
| 1025 | + | |
| 1026 | + // Perform vector permutation | |
| 1027 | + x = perm(x, symbolic->m_pinv); | |
| 1028 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1029 | + cout << " Permutated vector : " << x << endl; | |
| 1030 | + #endif | |
| 1031 | + | |
| 1032 | + // If column compression has been performed the expand the result vector | |
| 1033 | + // accordingly | |
| 1034 | + if (m_colsel != NULL && m_num_colsel < m_cols) { | |
| 1035 | + for (c_col = 0; c_col < m_num_colsel; ++c_col) | |
| 1036 | + result.m_data[m_colsel[c_col]] = x.m_data[c_col]; | |
| 1037 | + } | |
| 1038 | + else | |
| 1039 | + result = x; | |
| 1040 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1041 | + cout << " Restored vector ..: " << result << endl; | |
| 1042 | + #endif | |
| 1043 | + | |
| 1044 | + // Free mapping arrays | |
| 1045 | + delete [] row_map; | |
| 1046 | + delete [] col_map; | |
| 1047 | + | |
| 1048 | + } // endelse: Case B | |
| 1049 | + | |
| 1050 | + // Return result vector | |
| 1051 | + return result; | |
| 1052 | +} | |
| 1053 | + | |
| 1054 | + | |
| 1055 | +/*************************************************************************** | |
| 1056 | + * GSparseMatrix Cholesky invert * | |
| 1057 | + * ----------------------------------------------------------------------- * | |
| 1058 | + * Inplace matrix inversion using the Cholesky decomposition. * | |
| 1059 | + ***************************************************************************/ | |
| 1060 | +void GSparseMatrix::cholesky_invert(int compress) | |
| 1061 | +{ | |
| 1062 | + // Generate Cholesky decomposition of matrix | |
| 1063 | + cholesky_decompose(compress); | |
| 1064 | + | |
| 1065 | + // Allocate result matrix and unit vector | |
| 1066 | + GSparseMatrix result(m_rows, m_cols); | |
| 1067 | + GVector unit(m_rows); | |
| 1068 | + | |
| 1069 | + // Column-wise solving of the problem | |
| 1070 | + for (int col = 0; col < m_cols; ++col) { | |
| 1071 | + | |
| 1072 | + // Set unit vector | |
| 1073 | + unit.m_data[col] = 1.0; | |
| 1074 | + | |
| 1075 | + // Solve for column | |
| 1076 | + GVector x = cholesky_solver(unit, compress); | |
| 1077 | + | |
| 1078 | + // Insert column in matrix | |
| 1079 | + result.insert_col(x, col); | |
| 1080 | + | |
| 1081 | + // Clear unit vector for next round | |
| 1082 | + unit.m_data[col] = 0.0; | |
| 1083 | + | |
| 1084 | + } | |
| 1085 | + | |
| 1086 | + *this = result; | |
| 1087 | + | |
| 1088 | + // Return | |
| 1089 | + return; | |
| 1090 | +} | |
| 1091 | + | |
| 1092 | + | |
| 1093 | +/*========================================================================== | |
| 1094 | + = = | |
| 1095 | + = GSparseMatrix private functions = | |
| 1096 | + = = | |
| 1097 | + ==========================================================================*/ | |
| 1098 | + | |
| 1099 | +/*************************************************************************** | |
| 1100 | + * Determines element index for (row,col) * | |
| 1101 | + * ----------------------------------------------------------------------- * | |
| 1102 | + * Returns the index in the compressed array for (row,col). The following * | |
| 1103 | + * special results exist: * | |
| 1104 | + * -1: Requested index does not exist in the matrix * | |
| 1105 | + * m_elements: Requested index is the pending element * | |
| 1106 | + ***************************************************************************/ | |
| 1107 | +int GSparseMatrix::get_index(int row, int col) const | |
| 1108 | +{ | |
| 1109 | + // Initialise element to 'not found' | |
| 1110 | + int index = -1; | |
| 1111 | + | |
| 1112 | + // If we have a pending element then check if this element is requested | |
| 1113 | + if (m_fill_val != 0.0) { | |
| 1114 | + if (row == m_fill_row && col == m_fill_col) | |
| 1115 | + return m_elements; | |
| 1116 | + } | |
| 1117 | + | |
| 1118 | + // If requested element is not the pending element then check if it exists | |
| 1119 | + // in the matrix. Only if it is found its index is returned. Otherwise | |
| 1120 | + // the default index is -1, signalling that the element is absent. | |
| 1121 | + if (m_elements > 0) { | |
| 1122 | + int* ptr_colstart = m_colstart + col; | |
| 1123 | + int i_start = *ptr_colstart++; | |
| 1124 | + int i_stop = *ptr_colstart; | |
| 1125 | + int* ptr_rowinx = m_rowinx + i_start; | |
| 1126 | + for (int i = i_start; i < i_stop; ++i) { | |
| 1127 | + int row_test = *ptr_rowinx++; | |
| 1128 | + if (row_test == row) { | |
| 1129 | + index = i; | |
| 1130 | + break; | |
| 1131 | + } | |
| 1132 | + } | |
| 1133 | + } | |
| 1134 | + | |
| 1135 | + // Return index | |
| 1136 | + return index; | |
| 1137 | +} | |
| 1138 | + | |
| 1139 | + | |
| 1140 | +/*************************************************************************** | |
| 1141 | + * Fills pending matrix element * | |
| 1142 | + * ----------------------------------------------------------------------- * | |
| 1143 | + * If 'm_fill_val' is non-zero a pending matrix element exists that should * | |
| 1144 | + * be filled into (row,col)=(m_fill_row,m_fill_col). This routine performs * | |
| 1145 | + * the filling of the matrix with this element and resets 'm_fill_val' to * | |
| 1146 | + * zero. This routine allows for element-by-element filling of a sparse * | |
| 1147 | + * matrix. This is, of course, very time consuming and should in general * | |
| 1148 | + * be avoided. However, it allows to design a sparse matrix class that * | |
| 1149 | + * hides the matrix sparsity completely to the user. * | |
| 1150 | + ***************************************************************************/ | |
| 1151 | +void GSparseMatrix::fill_pending(void) | |
| 1152 | +{ | |
| 1153 | + // If we have a pending element then fill it into the matrix | |
| 1154 | + if (m_fill_val != 0.0) { | |
| 1155 | + | |
| 1156 | + // Debugging | |
| 1157 | + #if defined(G_DEBUG_SPARSE_PENDING) || defined(G_DEBUG_SPARSE_INSERTION) | |
| 1158 | + cout << "GSparseMatrix::fill_pending(): pending value " << | |
| 1159 | + m_fill_val << " will be filled in location (" << | |
| 1160 | + m_fill_row << "," << m_fill_col << ")" << endl; | |
| 1161 | + #endif | |
| 1162 | + | |
| 1163 | + // If there are so far no elements in the matrix then append element ... | |
| 1164 | + int inx_insert; | |
| 1165 | + if (m_elements == 0) | |
| 1166 | + inx_insert = 0; | |
| 1167 | + | |
| 1168 | + // ... otherwise search for index to insert | |
| 1169 | + else { | |
| 1170 | + int* ptr_colstart = m_colstart + m_fill_col; | |
| 1171 | + int i_start = *ptr_colstart++; | |
| 1172 | + int i_stop = *ptr_colstart; | |
| 1173 | + int* ptr_rowinx = m_rowinx + i_start; | |
| 1174 | + for (inx_insert = i_start; inx_insert < i_stop; ++inx_insert) { | |
| 1175 | + int row_test = *ptr_rowinx++; | |
| 1176 | + if (row_test > m_fill_row) { | |
| 1177 | + break; | |
| 1178 | + } | |
| 1179 | + } | |
| 1180 | + } | |
| 1181 | + | |
| 1182 | + // Allocate memory for new element | |
| 1183 | + alloc_elements(inx_insert, 1); | |
| 1184 | + | |
| 1185 | + // Insert element | |
| 1186 | + m_data[inx_insert] = m_fill_val; | |
| 1187 | + m_rowinx[inx_insert] = m_fill_row; | |
| 1188 | + | |
| 1189 | + // Update column start indices | |
| 1190 | + for (int col = m_fill_col+1; col <= m_cols; ++col) | |
| 1191 | + m_colstart[col] += 1; | |
| 1192 | + | |
| 1193 | + // Reset fill value | |
| 1194 | + m_fill_val = 0.0; | |
| 1195 | + m_fill_row = 0; | |
| 1196 | + m_fill_col = 0; | |
| 1197 | + | |
| 1198 | + // Debugging: show sparse matrix after filling | |
| 1199 | + #if defined(G_DEBUG_SPARSE_PENDING) || defined(G_DEBUG_SPARSE_INSERTION) | |
| 1200 | + cout << " Data: "; | |
| 1201 | + for (int i = 0; i < m_elements; ++i) | |
| 1202 | + cout << m_data[i] << " "; | |
| 1203 | + cout << endl << " Row.: "; | |
| 1204 | + for (int i = 0; i < m_elements; ++i) | |
| 1205 | + cout << m_rowinx[i] << " "; | |
| 1206 | + cout << endl << " Col.: "; | |
| 1207 | + for (int i = 0; i < m_cols+1; ++i) | |
| 1208 | + cout << m_colstart[i] << " "; | |
| 1209 | + cout << endl; | |
| 1210 | + #endif | |
| 1211 | + | |
| 1212 | + } // endif: a pending matrix element was found | |
| 1213 | + | |
| 1214 | +} | |
| 1215 | + | |
| 1216 | + | |
| 1217 | +/*************************************************************************** | |
| 1218 | + * Allocate memory for new matrix elements * | |
| 1219 | + * ----------------------------------------------------------------------- * | |
| 1220 | + * Inserts a memory allocation for 'num' elements at the index 'start'. * | |
| 1221 | + * The new elements are filled with 0.0 and the corresponding row indices * | |
| 1222 | + * are set to 0. * | |
| 1223 | + * NOTE: This routine does not take care of updating 'm_colstart'. This * | |
| 1224 | + * has to be done by the client. * | |
| 1225 | + ***************************************************************************/ | |
| 1226 | +void GSparseMatrix::alloc_elements(int start, int num) | |
| 1227 | +{ | |
| 1228 | + // Continue only if we need memory | |
| 1229 | + if (num > 0) { | |
| 1230 | + | |
| 1231 | + // If start is after the end the append memory | |
| 1232 | + if (start > m_elements) | |
| 1233 | + start = m_elements; | |
| 1234 | + | |
| 1235 | + // Allocate memory for new elements | |
| 1236 | + double* new_data = new double[m_elements+num]; | |
| 1237 | + int* new_rowinx = new int[m_elements+num]; | |
| 1238 | + if (new_data == NULL || new_rowinx == NULL) | |
| 1239 | + throw mem_alloc("GSparseMatrix::alloc_elements(int, int)", | |
| 1240 | + m_elements+num); | |
| 1241 | + | |
| 1242 | + // Copy all elements before index to insert | |
| 1243 | + for (int i = 0; i < start; ++i) { | |
| 1244 | + new_data[i] = m_data[i]; | |
| 1245 | + new_rowinx[i] = m_rowinx[i]; | |
| 1246 | + } | |
| 1247 | + | |
| 1248 | + // Clear new elements (zero content for row 0) | |
| 1249 | + for (int i = start; i < start+num; ++i) { | |
| 1250 | + new_data[i] = 0.0; | |
| 1251 | + new_rowinx[i] = 0; | |
| 1252 | + } | |
| 1253 | + | |
| 1254 | + // Copy all elements after index to insert | |
| 1255 | + for (int i = start; i < m_elements; ++i) { | |
| 1256 | + new_data[i+num] = m_data[i]; | |
| 1257 | + new_rowinx[i+num] = m_rowinx[i]; | |
| 1258 | + } | |
| 1259 | + | |
| 1260 | + // Delete old memory | |
| 1261 | + if (m_data != NULL) delete [] m_data; | |
| 1262 | + if (m_rowinx != NULL) delete [] m_rowinx; | |
| 1263 | + | |
| 1264 | + // Update pointers to new memory and update element counter | |
| 1265 | + m_data = new_data; | |
| 1266 | + m_rowinx = new_rowinx; | |
| 1267 | + m_elements += num; | |
| 1268 | + | |
| 1269 | + } // endif: needed new memory | |
| 1270 | + | |
| 1271 | +} | |
| 1272 | + | |
| 1273 | + | |
| 1274 | +/*************************************************************************** | |
| 1275 | + * Free memory for obsolete matrix elements * | |
| 1276 | + * ----------------------------------------------------------------------- * | |
| 1277 | + * Free memory for 'num' elements starting from index 'start'. * | |
| 1278 | + * NOTE: This routine does not take care of updating 'm_colstart'. This * | |
| 1279 | + * has to be done by the client. * | |
| 1280 | + ***************************************************************************/ | |
| 1281 | +void GSparseMatrix::free_elements(int start, int num) | |
| 1282 | +{ | |
| 1283 | + // Continue only if we need to free memory and if start is within the | |
| 1284 | + // range | |
| 1285 | + if (num > 0 && start < m_elements) { | |
| 1286 | + | |
| 1287 | + // Determine the new size of the matrix. If there are no elements then | |
| 1288 | + // simply delete all matrix elements ... | |
| 1289 | + int new_size = m_elements - num; | |
| 1290 | + if (new_size < 1) { | |
| 1291 | + if (m_data != NULL) delete [] m_data; | |
| 1292 | + if (m_rowinx != NULL) delete [] m_rowinx; | |
| 1293 | + m_data = NULL; | |
| 1294 | + m_rowinx = NULL; | |
| 1295 | + m_elements = 0; | |
| 1296 | + } | |
| 1297 | + | |
| 1298 | + // ... otherwise shrink the array | |
| 1299 | + else { | |
| 1300 | + | |
| 1301 | + // Allocate new memory | |
| 1302 | + double* new_data = new double[new_size]; | |
| 1303 | + int* new_rowinx = new int[new_size]; | |
| 1304 | + if (new_data == NULL || new_rowinx == NULL) | |
| 1305 | + throw mem_alloc("GSparseMatrix::free_elements(int, int)", | |
| 1306 | + new_size); | |
| 1307 | + | |
| 1308 | + // Copy all elements before the starting index | |
| 1309 | + for (int i = 0; i < start; ++i) { | |
| 1310 | + new_data[i] = m_data[i]; | |
| 1311 | + new_rowinx[i] = m_rowinx[i]; | |
| 1312 | + } | |
| 1313 | + | |
| 1314 | + // Copy all elements after the starting index | |
| 1315 | + for (int i = start; i < new_size; ++i) { | |
| 1316 | + new_data[i] = m_data[i+num]; | |
| 1317 | + new_rowinx[i] = m_rowinx[i+num]; | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + // Delete old memory | |
| 1321 | + if (m_data != NULL) delete [] m_data; | |
| 1322 | + if (m_rowinx != NULL) delete [] m_rowinx; | |
| 1323 | + | |
| 1324 | + // Update pointers to new memory and update element counter | |
| 1325 | + m_data = new_data; | |
| 1326 | + m_rowinx = new_rowinx; | |
| 1327 | + m_elements = new_size; | |
| 1328 | + | |
| 1329 | + } // endif: array shrinkage needed | |
| 1330 | + } // endif: needed new memory | |
| 1331 | + | |
| 1332 | +} | |
| 1333 | + | |
| 1334 | + | |
| 1335 | +/*************************************************************************** | |
| 1336 | + * remove_zero_row_col * | |
| 1337 | + * ----------------------------------------------------------------------- * | |
| 1338 | + * Remove all rows and columns that contain only zeros from matrix. This * | |
| 1339 | + * function is needed for compressed matrix factorisation. The resulting * | |
| 1340 | + * matrix has reduced size (# of rows and columns) and dimensions (# of * | |
| 1341 | + * elements). Note that the physical memory is not reduced by the routine. * | |
| 1342 | + ***************************************************************************/ | |
| 1343 | +void GSparseMatrix::remove_zero_row_col(void) | |
| 1344 | +{ | |
| 1345 | + // Dump header | |
| 1346 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1347 | + cout << "GSparseMatrix::remove_zero_row_col" << endl; | |
| 1348 | + #endif | |
| 1349 | + | |
| 1350 | + // Fill pending value in matrix | |
| 1351 | + fill_pending(); | |
| 1352 | + | |
| 1353 | + // Select non-zero rows and columns of matrix | |
| 1354 | + select_non_zero(); | |
| 1355 | + | |
| 1356 | + // Stop if there is no compression | |
| 1357 | + if (m_rows == m_num_rowsel && m_cols == m_num_colsel) | |
| 1358 | + return; | |
| 1359 | + | |
| 1360 | + // Raise exception if all matrix elements are zero | |
| 1361 | + if (m_num_rowsel < 1 || m_num_colsel < 1) | |
| 1362 | + throw matrix_zero("GSparseMatrix::remove_zero_row_col()"); | |
| 1363 | + | |
| 1364 | + // Allocate row mapping array | |
| 1365 | + int* row_map = new int[m_rows]; | |
| 1366 | + if (row_map == NULL) | |
| 1367 | + throw mem_alloc("GSparseMatrix::remove_zero_row_col()", m_rows); | |
| 1368 | + | |
| 1369 | + // Setup row mapping array that maps original matrix rows into compressed | |
| 1370 | + // matrix rows. An entry of -1 indicates that the row should be dropped | |
| 1371 | + for (int row = 0; row < m_rows; ++row) | |
| 1372 | + row_map[row] = -1; | |
| 1373 | + for (int c_row = 0; c_row < m_num_rowsel; ++c_row) | |
| 1374 | + row_map[m_rowsel[c_row]] = c_row; | |
| 1375 | + | |
| 1376 | + // Initialise pointers to compressed array | |
| 1377 | + double* d_data = m_data; | |
| 1378 | + int* d_rowinx = m_rowinx; | |
| 1379 | + | |
| 1380 | + // Initialise column start of first column to zero | |
| 1381 | + m_colstart[0] = 0; | |
| 1382 | + | |
| 1383 | + // Dump column start array | |
| 1384 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1385 | + cout << " before compression:"; | |
| 1386 | + for (int col = 0; col <= m_cols; ++col) | |
| 1387 | + cout << " " << m_colstart[col]; | |
| 1388 | + cout << endl; | |
| 1389 | + #endif | |
| 1390 | + | |
| 1391 | + // Loop over all columns of compressed matrix | |
| 1392 | + for (int c_col = 0; c_col < m_num_colsel; ++c_col) { | |
| 1393 | + | |
| 1394 | + // Get index range for elements in original matrix | |
| 1395 | + int i_start = m_colstart[m_colsel[c_col]]; | |
| 1396 | + int i_stop = m_colstart[m_colsel[c_col]+1]; | |
| 1397 | + | |
| 1398 | + // Initialise number of element counter for the compressed column | |
| 1399 | + int num = 0; | |
| 1400 | + | |
| 1401 | + // Loop over all elements in original column | |
| 1402 | + int c_row; | |
| 1403 | + for (int i = i_start; i < i_stop; ++i) { | |
| 1404 | + if ((c_row = row_map[m_rowinx[i]]) >= 0) { | |
| 1405 | + *d_data++ = m_data[i]; | |
| 1406 | + *d_rowinx++ = c_row; | |
| 1407 | + num++; | |
| 1408 | + } | |
| 1409 | + } | |
| 1410 | + | |
| 1411 | + // Update column stop | |
| 1412 | + m_colstart[c_col+1] = m_colstart[c_col] + num; | |
| 1413 | + | |
| 1414 | + } // endfor: looped over all columns of compressed matrix | |
| 1415 | + | |
| 1416 | + // Dump column start array | |
| 1417 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1418 | + cout << " after compression :"; | |
| 1419 | + for (int c_col = 0; c_col <= m_num_colsel; ++c_col) | |
| 1420 | + cout << " " << m_colstart[c_col]; | |
| 1421 | + cout << endl; | |
| 1422 | + #endif | |
| 1423 | + | |
| 1424 | + // Free row mapping array | |
| 1425 | + delete [] row_map; | |
| 1426 | + | |
| 1427 | + // Update matrix attributes | |
| 1428 | + m_rows = m_num_rowsel; | |
| 1429 | + m_cols = m_num_colsel; | |
| 1430 | + m_elements = m_colstart[m_num_colsel]; | |
| 1431 | + | |
| 1432 | + // Return | |
| 1433 | + return; | |
| 1434 | +} | |
| 1435 | + | |
| 1436 | + | |
| 1437 | +/*************************************************************************** | |
| 1438 | + * insert_zero_row_col * | |
| 1439 | + * ----------------------------------------------------------------------- * | |
| 1440 | + * Insert zero rows and columns into matrix. Since for a sparse matrix * | |
| 1441 | + * this does not require any allocation of additional memory, the data are * | |
| 1442 | + * not moved by this function, but the pointers are re-arranged. * | |
| 1443 | + ***************************************************************************/ | |
| 1444 | +void GSparseMatrix::insert_zero_row_col(int rows, int cols) | |
| 1445 | +{ | |
| 1446 | + // Dump header | |
| 1447 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1448 | + cout << "GSparseMatrix::insert_zero_row_col(" << rows << "," << cols << | |
| 1449 | + ")" << endl; | |
| 1450 | + #endif | |
| 1451 | + | |
| 1452 | + // Fill pending value in matrix | |
| 1453 | + fill_pending(); | |
| 1454 | + | |
| 1455 | + // Stop if there is no insertion | |
| 1456 | + if (m_rows == rows && m_cols == cols) | |
| 1457 | + return; | |
| 1458 | + | |
| 1459 | + // If row selection exists then restore row indices | |
| 1460 | + if (m_rowsel != NULL) { | |
| 1461 | + for (int i = 0; i < m_elements; ++i) | |
| 1462 | + m_rowinx[i] = m_rowsel[m_rowinx[i]]; | |
| 1463 | + } | |
| 1464 | + | |
| 1465 | + // Dump column start array | |
| 1466 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1467 | + cout << " before restoration:"; | |
| 1468 | + for (int c_col = 0; c_col <= m_num_colsel; ++c_col) | |
| 1469 | + cout << " " << m_colstart[c_col]; | |
| 1470 | + cout << endl; | |
| 1471 | + #endif | |
| 1472 | + | |
| 1473 | + // If column selection exists then restore column counters | |
| 1474 | + if (m_colsel != NULL) { | |
| 1475 | + int col_stop = cols - 1; | |
| 1476 | + for (int c_col = m_num_colsel-1; c_col > 0; --c_col) { | |
| 1477 | + int col_start = m_colsel[c_col-1] + 1; | |
| 1478 | + int col_value = m_colstart[c_col]; | |
| 1479 | + for (int col = col_start; col <= col_stop; ++col) | |
| 1480 | + m_colstart[col] = col_value; | |
| 1481 | + col_stop = col_start - 1; | |
| 1482 | + } | |
| 1483 | + m_colstart[cols] = m_elements; | |
| 1484 | + } | |
| 1485 | + | |
| 1486 | + // Dump column start array | |
| 1487 | + #if defined(G_DEBUG_SPARSE_COMPRESSION) | |
| 1488 | + cout << " after restoration :"; | |
| 1489 | + for (int col = 0; col <= cols; ++col) | |
| 1490 | + cout << " " << m_colstart[col]; | |
| 1491 | + cout << endl; | |
| 1492 | + #endif | |
| 1493 | + | |
| 1494 | + // Update matrix attributes | |
| 1495 | + m_rows = rows; | |
| 1496 | + m_cols = cols; | |
| 1497 | + | |
| 1498 | + // Return | |
| 1499 | + return; | |
| 1500 | +} | |
| 1501 | + | |
| 1502 | + | |
| 1503 | +/*************************************************************************** | |
| 1504 | + * cs_transpose * | |
| 1505 | + * ----------------------------------------------------------------------- * | |
| 1506 | + * Transpose matrix. The flag 'values' allows to avoid copying the actual * | |
| 1507 | + * data values. This allows to perform a logical matrix transposition, as * | |
| 1508 | + * needed by the symbolic matrix analysis class. * | |
| 1509 | + ***************************************************************************/ | |
| 1510 | +GSparseMatrix GSparseMatrix::cs_transpose(GSparseMatrix* m, int values) | |
| 1511 | +{ | |
| 1512 | + // Fill pending value in input matrix | |
| 1513 | + m->fill_pending(); | |
| 1514 | + | |
| 1515 | + // Declare and allocate result matrix | |
| 1516 | + GSparseMatrix result(m->m_cols, m->m_rows, m->m_elements); | |
| 1517 | + | |
| 1518 | + // Allocate and initialise workspace | |
| 1519 | + int wrk_size = m->m_rows; | |
| 1520 | + int* wrk_int = new int[wrk_size]; | |
| 1521 | + if (wrk_int == NULL) | |
| 1522 | + throw mem_alloc("GSparseMatrix::cs_transpose(GSparseMatrix*, int)", | |
| 1523 | + wrk_size); | |
| 1524 | + for (int i = 0; i < wrk_size; i++) | |
| 1525 | + wrk_int[i] = 0; | |
| 1526 | + | |
| 1527 | + // Setup the number of non-zero elements in each row | |
| 1528 | + for (int p = 0; p < m->m_elements; p++) | |
| 1529 | + wrk_int[m->m_rowinx[p]]++; | |
| 1530 | + | |
| 1531 | + // Set row pointers. To use a GSparseSymbolic function we have to | |
| 1532 | + // allocate and object (but this does not take memory) | |
| 1533 | + cs_cumsum(result.m_colstart, wrk_int, m->m_rows); | |
| 1534 | + | |
| 1535 | + // Case A: Normal transponse, including assignment of values | |
| 1536 | + if (values) { | |
| 1537 | + for (int col = 0; col < m->m_cols; col++) { | |
| 1538 | + for (int p = m->m_colstart[col] ; p < m->m_colstart[col+1] ; p++) { | |
| 1539 | + int i = wrk_int[m->m_rowinx[p]]++; | |
| 1540 | + result.m_rowinx[i] = col; | |
| 1541 | + result.m_data[i] = m->m_data[p] ; | |
| 1542 | + } | |
| 1543 | + } | |
| 1544 | + } | |
| 1545 | + | |
| 1546 | + // Case B: Logical transponse, no assignment of values is performed | |
| 1547 | + else { | |
| 1548 | + for (int col = 0; col < m->m_cols; col++) { | |
| 1549 | + for (int p = m->m_colstart[col] ; p < m->m_colstart[col+1] ; p++) | |
| 1550 | + result.m_rowinx[wrk_int[m->m_rowinx[p]]++] = col; | |
| 1551 | + } | |
| 1552 | + } | |
| 1553 | + | |
| 1554 | + // Return transponse matrix | |
| 1555 | + return result; | |
| 1556 | + | |
| 1557 | +} | |
| 1558 | + | |
| 1559 | + | |
| 1560 | +/*========================================================================== | |
| 1561 | + = = | |
| 1562 | + = GSparseMatrix friends = | |
| 1563 | + = = | |
| 1564 | + ==========================================================================*/ | |
| 1565 | + | |
| 1566 | +/*************************************************************************** | |
| 1567 | + * Output operator * | |
| 1568 | + ***************************************************************************/ | |
| 1569 | +ostream& operator<< (ostream& os, const GSparseMatrix& m) | |
| 1570 | +{ | |
| 1571 | + // Put header in stream | |
| 1572 | + os << "=== GSparseMatrix ===" << endl; | |
| 1573 | + if (m.m_rowsel != NULL) | |
| 1574 | + os << " Number of rows ............: " << m.m_rows << " (compressed " << | |
| 1575 | + m.m_num_rowsel << ")" << endl; | |
| 1576 | + else | |
| 1577 | + os << " Number of rows ............: " << m.m_rows << endl; | |
| 1578 | + if (m.m_colsel != NULL) | |
| 1579 | + os << " Number of columns .........: " << m.m_cols << " (compressed " << | |
| 1580 | + m.m_num_colsel << ")" << endl; | |
| 1581 | + else | |
| 1582 | + os << " Number of columns .........: " << m.m_cols << endl; | |
| 1583 | + os << " Number of non-zero elements: " << m.m_elements << endl; | |
| 1584 | + os << " Sparse matrix fill ........: " << m.fill() << endl; | |
| 1585 | + | |
| 1586 | + // Loop over all matrix elements and put them into the stream | |
| 1587 | + for (int row = 0; row < m.m_rows; ++row) { | |
| 1588 | + os << " "; | |
| 1589 | + for (int col = 0; col < m.m_cols; ++col) { | |
| 1590 | + os << m(row,col); | |
| 1591 | + if (col != m.m_cols-1) | |
| 1592 | + os << ", "; | |
| 1593 | + } | |
| 1594 | + if (row != m.m_rows-1) | |
| 1595 | + os << endl; | |
| 1596 | + } | |
| 1597 | + | |
| 1598 | + // If there is a row compression the show scheme | |
| 1599 | + if (m.m_rowsel != NULL) { | |
| 1600 | + os << endl << " Row selection ..:"; | |
| 1601 | + for (int row = 0; row < m.m_num_rowsel; ++row) | |
| 1602 | + os << " " << m.m_rowsel[row]; | |
| 1603 | + } | |
| 1604 | + | |
| 1605 | + // If there is a column compression the show scheme | |
| 1606 | + if (m.m_colsel != NULL) { | |
| 1607 | + os << endl << " Column selection:"; | |
| 1608 | + for (int col = 0; col < m.m_num_colsel; ++col) | |
| 1609 | + os << " " << m.m_colsel[col]; | |
| 1610 | + } | |
| 1611 | + | |
| 1612 | + // If there is a symbolic decomposition then put it also in the stream | |
| 1613 | + if (m.m_symbolic != NULL) { | |
| 1614 | + os << endl << *((GSparseSymbolic*)m.m_symbolic); | |
| 1615 | + } | |
| 1616 | + | |
| 1617 | + // If there is a numeric decomposition then put it also in the stream | |
| 1618 | + if (m.m_numeric != NULL) { | |
| 1619 | + os << endl << *((GSparseNumeric*)m.m_numeric); | |
| 1620 | + } | |
| 1621 | + | |
| 1622 | + // Return output stream | |
| 1623 | + return os; | |
| 1624 | +} | |
| 1625 | + | |
| 1626 | + | |
| 1627 | +/*************************************************************************** | |
| 1628 | + * Matrix absolute values * | |
| 1629 | + ***************************************************************************/ | |
| 1630 | +GSparseMatrix fabs(const GSparseMatrix& m) | |
| 1631 | +{ | |
| 1632 | + // Define result matrix | |
| 1633 | + GSparseMatrix result = m; | |
| 1634 | + | |
| 1635 | + // Fill pending element | |
| 1636 | + result.fill_pending(); | |
| 1637 | + | |
| 1638 | + // Convert all elements to absolute values | |
| 1639 | + for (int i = 0; i < result.m_elements; ++i) | |
| 1640 | + result.m_data[i] = fabs(result.m_data[i]); | |
| 1641 | + | |
| 1642 | + // Return result | |
| 1643 | + return result; | |
| 1644 | +} | |
| 1645 | + | |
| 1646 | + | |
| 1647 | +/*========================================================================== | |
| 1648 | + = = | |
| 1649 | + = GSparseMatrix exception classes = | |
| 1650 | + = = | |
| 1651 | + ==========================================================================*/ | |
| 1652 | + | |
| 1653 | + | |
| 1654 | +/*========================================================================== | |
| 1655 | + = = | |
| 1656 | + = Other functions used by GSparseMatrix = | |
| 1657 | + = = | |
| 1658 | + ==========================================================================*/ | |
| 1659 | + | |
| 1660 | +/*************************************************************************** | |
| 1661 | + * cs_cumsum * | |
| 1662 | + * ----------------------------------------------------------------------- * | |
| 1663 | + * Evaluate p[0..n] = cumulative sum of c[0..n-1] * | |
| 1664 | + * ----------------------------------------------------------------------- * | |
| 1665 | + * Input: c[0..n-1] integer array of n elements * | |
| 1666 | + * Output: nz2 cumulative sum of c[0..n-1] * | |
| 1667 | + * p[0..n] integer array of n+1 elements * | |
| 1668 | + * c[0..n-1] holds p[0..n-1] on output * | |
| 1669 | + ***************************************************************************/ | |
| 1670 | +double cs_cumsum(int* p, int* c, int n) | |
| 1671 | +{ | |
| 1672 | + // Signal error if one of the input pointers is NULL | |
| 1673 | + if (!p || !c) return (-1); | |
| 1674 | + | |
| 1675 | + // Initialise sums (integer and double) | |
| 1676 | + int nz = 0; | |
| 1677 | + double nz2 = 0.0; | |
| 1678 | + | |
| 1679 | + // Evaluate p[0..n] = cumulative sum of c[0..n-1] | |
| 1680 | + for (int i = 0; i < n; ++i) { | |
| 1681 | + p[i] = nz ; | |
| 1682 | + nz += c[i]; | |
| 1683 | + nz2 += c[i]; // also in double to avoid int overflow | |
| 1684 | + c[i] = p[i]; // also copy p[0..n-1] back into c[0..n-1] | |
| 1685 | + } | |
| 1686 | + p[n] = nz ; | |
| 1687 | + | |
| 1688 | + // Return cumulative sum of c[0..n-1] | |
| 1689 | + return nz2; | |
| 1690 | +} | |
| 1691 | + | ... | ... |
src/GSparseMatrix.hpp
| 1 | 1 | /*************************************************************************** |
| 2 | - * GSymMatrix.hpp - symmetric matrix class * | |
| 2 | + * GSparseMatrix.hpp - sparse matrix class * | |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | 4 | * copyright : (C) 2006 by Jurgen Knodlseder * |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| ... | ... | @@ -11,8 +11,8 @@ |
| 11 | 11 | * * |
| 12 | 12 | ***************************************************************************/ |
| 13 | 13 | |
| 14 | -#ifndef GSYMMATRIX_HPP | |
| 15 | -#define GSYMMATRIX_HPP | |
| 14 | +#ifndef GSPARSEMATRIX_HPP | |
| 15 | +#define GSPARSEMATRIX_HPP | |
| 16 | 16 | |
| 17 | 17 | /* __ Includes ___________________________________________________________ */ |
| 18 | 18 | #include "GException.hpp" |
| ... | ... | @@ -27,251 +27,248 @@ using namespace std; |
| 27 | 27 | /* __ Structures _________________________________________________________ */ |
| 28 | 28 | |
| 29 | 29 | /* __ Prototypes _________________________________________________________ */ |
| 30 | +double cs_cumsum(int* p, int* c, int n); | |
| 30 | 31 | |
| 31 | 32 | |
| 32 | 33 | /*************************************************************************** |
| 33 | - * GSymMatrix class definition * | |
| 34 | + * GSparseMatrix class definition * | |
| 34 | 35 | ***************************************************************************/ |
| 35 | -class GSymMatrix : public GMatrix { | |
| 36 | - // Operator friends | |
| 37 | - friend GSymMatrix operator* (const double &a, const GSymMatrix &b); | |
| 36 | +class GSparseMatrix : public GMatrix { | |
| 37 | + // Friend classes | |
| 38 | + friend class GSparseSymbolic; | |
| 39 | + friend class GSparseNumeric; | |
| 40 | + | |
| 41 | + // Binary operator friends | |
| 42 | + friend GSparseMatrix operator* (const double& a, const GSparseMatrix& b); | |
| 43 | + friend GSparseMatrix operator* (const GSparseMatrix& a, const double& b); | |
| 44 | + friend GSparseMatrix operator/ (const GSparseMatrix& a, const double& b); | |
| 38 | 45 | |
| 39 | 46 | // I/O friends |
| 40 | - // ... | |
| 41 | - | |
| 47 | + friend ostream& operator<< (ostream& os, const GSparseMatrix& m); | |
| 48 | + | |
| 42 | 49 | // Friend functions |
| 43 | - friend GSymMatrix transpose(const GSymMatrix &m); | |
| 44 | - friend GSymMatrix cholesky_decompose(const GSymMatrix &m); | |
| 45 | - friend GMatrix full(const GSymMatrix &m); | |
| 46 | - friend GMatrix lower_triangle(const GSymMatrix &m); | |
| 47 | - friend GMatrix upper_triangle(const GSymMatrix &m); | |
| 50 | + friend GSparseMatrix transpose(const GSparseMatrix& m); | |
| 51 | + friend GSparseMatrix fabs(const GSparseMatrix& m); | |
| 52 | + friend GSparseMatrix cholesky_decompose(const GSparseMatrix& m, int compress = 1); | |
| 53 | + friend GSparseMatrix cholesky_invert(const GSparseMatrix& m, int compress = 1); | |
| 54 | + | |
| 48 | 55 | public: |
| 49 | 56 | // Constructors and destructors (not inherited) |
| 50 | - GSymMatrix(unsigned rows, unsigned cols); | |
| 51 | - ~GSymMatrix() { } | |
| 57 | + GSparseMatrix(int rows, int cols, int elements = 0); | |
| 58 | + GSparseMatrix(const GSparseMatrix& m); | |
| 59 | + virtual ~GSparseMatrix(); | |
| 52 | 60 | |
| 53 | 61 | // Matrix element access operators |
| 54 | - double& operator() (unsigned row, unsigned col); | |
| 55 | - const double& operator() (unsigned row, unsigned col) const; | |
| 62 | + virtual double& operator() (int row, int col); | |
| 63 | + virtual const double& operator() (int row, int col) const; | |
| 56 | 64 | |
| 57 | 65 | // Matrix assignment operators (not inherited) |
| 58 | - GSymMatrix& operator= (const GSymMatrix& m); | |
| 59 | - GSymMatrix& operator= (const double& d); | |
| 60 | - | |
| 61 | - // Specific matrix operators (structure dependent) | |
| 62 | - GSymMatrix operator+ (const GSymMatrix& m) const; | |
| 63 | - GSymMatrix operator- (const GSymMatrix& m) const; | |
| 64 | - GSymMatrix operator* (const GSymMatrix& m) const; | |
| 65 | - GVector operator* (const GVector& v) const; | |
| 66 | - GSymMatrix operator* (const double& d) const; | |
| 67 | - GSymMatrix operator/ (const double& d) const; | |
| 68 | - GSymMatrix operator- () const; | |
| 69 | - | |
| 70 | - // Specific matrix functions | |
| 71 | - void transpose(); // Inplace transpose of matrix | |
| 72 | - void cholesky_decompose(); // Inplace Cholesky decomposition | |
| 73 | - | |
| 74 | - // Exception: Matrix not symmetric | |
| 75 | - class not_sym : public GException { | |
| 76 | - public: | |
| 77 | - not_sym(string origin, unsigned cols, unsigned rows); | |
| 78 | - }; | |
| 79 | - | |
| 80 | - // Exception: Matrix not positive definite | |
| 81 | - class not_pos_definite : public GException { | |
| 82 | - public: | |
| 83 | - not_pos_definite(string origin, unsigned row, double sum); | |
| 84 | - }; | |
| 66 | + virtual GSparseMatrix& operator= (const GSparseMatrix& m); | |
| 67 | + | |
| 68 | + // Binary operators | |
| 69 | + virtual GSparseMatrix operator+ (const GSparseMatrix& m) const; | |
| 70 | + virtual GSparseMatrix operator- (const GSparseMatrix& m) const; | |
| 71 | + virtual GSparseMatrix operator* (const GSparseMatrix& m) const; | |
| 72 | + virtual GVector operator* (const GVector& v) const; | |
| 73 | + virtual int operator== (const GSparseMatrix& m) const; | |
| 74 | + virtual int operator!= (const GSparseMatrix& m) const; | |
| 75 | + | |
| 76 | + // Unary operators | |
| 77 | + GSparseMatrix operator- () const; | |
| 78 | + virtual GSparseMatrix& operator+= (const GSparseMatrix& m); | |
| 79 | + virtual GSparseMatrix& operator-= (const GSparseMatrix& m); | |
| 80 | + virtual GSparseMatrix& operator*= (const GSparseMatrix& m); | |
| 81 | + virtual GSparseMatrix& operator*= (const double& d); | |
| 82 | + virtual GSparseMatrix& operator/= (const double& d); | |
| 83 | + | |
| 84 | + // Matrix functions | |
| 85 | + // USE_BASE: virtual int rows() const { return m_rows; } | |
| 86 | + // USE_BASE: virtual int cols() const { return m_cols; } | |
| 87 | + virtual double fill() const { return (double(m_elements)/double(m_rows*m_cols)); } | |
| 88 | + virtual double min() const; | |
| 89 | + virtual double max() const; | |
| 90 | + virtual double sum() const; | |
| 91 | + virtual void transpose(); | |
| 92 | + virtual GVector extract_row(int row) const; | |
| 93 | + virtual GVector extract_col(int col) const; | |
| 94 | + virtual void insert_col(const GVector& v, int col); | |
| 95 | + virtual void add_col(const GVector& v, int col); | |
| 96 | + virtual GMatrix convert_to_full() const; | |
| 97 | + //TBD virtual GMatrix extract_lower_triangle() const; | |
| 98 | + //TBD virtual GMatrix extract_upper_triangle() const; | |
| 99 | + virtual void cholesky_decompose(int compress = 1); | |
| 100 | + virtual GVector cholesky_solver(const GVector& v, int compress = 1); | |
| 101 | + virtual void cholesky_invert(int compress = 1); | |
| 102 | + | |
| 85 | 103 | private: |
| 104 | + // Private functions | |
| 105 | + int get_index(int row, int col) const; | |
| 106 | + void fill_pending(void); | |
| 107 | + void alloc_elements(int start, int num); | |
| 108 | + void free_elements(int start, int num); | |
| 109 | + void remove_zero_row_col(void); | |
| 110 | + void insert_zero_row_col(int rows, int cols); | |
| 111 | + GSparseMatrix cs_transpose(GSparseMatrix *m, int values); | |
| 112 | + | |
| 113 | + // Private data members | |
| 114 | + int* m_rowinx; // Row-indices of all elements | |
| 115 | + double m_zero; // The zero element (needed for data access) | |
| 116 | + double m_fill_val; // Element to be filled | |
| 117 | + int m_fill_row; // Row into which element needs to be filled | |
| 118 | + int m_fill_col; // Column into which element needs to be filled | |
| 119 | + void* m_symbolic; // Holds GSparseSymbolic object after decomposition | |
| 120 | + void* m_numeric; // Holds GSparseNumeric object after decomposition | |
| 86 | 121 | }; |
| 87 | 122 | |
| 88 | 123 | |
| 89 | 124 | /*************************************************************************** |
| 90 | 125 | * Inline members that override base class members * |
| 91 | 126 | ***************************************************************************/ |
| 92 | -// Matrix assignment operator: GSymMatrix = GSymMatrix | |
| 93 | -inline | |
| 94 | -GSymMatrix& GSymMatrix::operator= (const GSymMatrix& m) | |
| 95 | -{ | |
| 96 | - if (this != &m) | |
| 97 | - this->GMatrix::operator=(m); | |
| 98 | -} | |
| 99 | - | |
| 100 | -// Scalar assignment operator: GSymMatrix = double | |
| 127 | +// Matrix element access operator | |
| 101 | 128 | inline |
| 102 | -GSymMatrix& GSymMatrix::operator= (const double& d) | |
| 103 | -{ | |
| 104 | - this->GMatrix::operator=(d); | |
| 105 | -} | |
| 106 | - | |
| 107 | -// Matrix element access operator: GSymMatrix(row,col) | |
| 108 | -inline | |
| 109 | -double& GSymMatrix::operator() (unsigned row, unsigned col) | |
| 129 | +double& GSparseMatrix::operator() (int row, int col) | |
| 110 | 130 | { |
| 111 | - #if G_RANGE_CHECK | |
| 131 | + #if defined(G_RANGE_CHECK) | |
| 112 | 132 | if (row >= m_rows || col >= m_cols) |
| 113 | - throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); | |
| 133 | + throw out_of_range("GSparseMatrix access", row, col, m_rows, m_cols); | |
| 114 | 134 | #endif |
| 115 | - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); | |
| 116 | - return m_data[inx]; | |
| 135 | + fill_pending(); | |
| 136 | + int inx = get_index(row,col); | |
| 137 | + double* value; | |
| 138 | + if (inx < 0) { | |
| 139 | + value = &m_fill_val; | |
| 140 | + m_fill_row = row; | |
| 141 | + m_fill_col = col; | |
| 142 | + } | |
| 143 | + else | |
| 144 | + value = &(m_data[inx]); | |
| 145 | + return *value; | |
| 117 | 146 | } |
| 118 | 147 | |
| 119 | -// Matrix element access operator (const version): GSymMatrix(row,col) | |
| 148 | +// Matrix element access operator (const version) | |
| 149 | +// We need here the zero element to return also a pointer for 0.0 entry that is | |
| 150 | +// not stored. Since we have the const version we don't have to care about | |
| 151 | +// modification of this zero value. | |
| 120 | 152 | inline |
| 121 | -const double& GSymMatrix::operator() (unsigned row, unsigned col) const | |
| 153 | +const double& GSparseMatrix::operator() (int row, int col) const | |
| 122 | 154 | { |
| 123 | - #if G_RANGE_CHECK | |
| 155 | + #if defined(G_RANGE_CHECK) | |
| 124 | 156 | if (row >= m_rows || col >= m_cols) |
| 125 | - throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); | |
| 157 | + throw out_of_range("GSparseMatrix access", row, col, m_rows, m_cols); | |
| 126 | 158 | #endif |
| 127 | - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); | |
| 128 | - return m_data[inx]; | |
| 159 | + int inx = get_index(row,col); | |
| 160 | + double* value; | |
| 161 | + if (inx < 0) | |
| 162 | + value = (double*)&m_zero; | |
| 163 | + else if (inx == m_elements) | |
| 164 | + value = (double*)&m_fill_val; | |
| 165 | + else | |
| 166 | + value = (double*)&(m_data[inx]); | |
| 167 | + return *value; | |
| 129 | 168 | } |
| 130 | 169 | |
| 131 | -// Matrix addition: GSymMatrix + GSymMatrix | |
| 170 | +// Binary matrix addition | |
| 132 | 171 | inline |
| 133 | -GSymMatrix GSymMatrix::operator+ (const GSymMatrix& m) const | |
| 172 | +GSparseMatrix GSparseMatrix::operator+ (const GSparseMatrix& m) const | |
| 134 | 173 | { |
| 135 | - GSymMatrix result = *this; | |
| 174 | + GSparseMatrix result = *this; | |
| 136 | 175 | result += m; |
| 137 | 176 | return result; |
| 138 | 177 | } |
| 139 | 178 | |
| 140 | -// Matrix subtraction: GSymMatrix - GSymMatrix | |
| 179 | +// Binary matrix subtraction | |
| 141 | 180 | inline |
| 142 | -GSymMatrix GSymMatrix::operator- (const GSymMatrix& m) const | |
| 181 | +GSparseMatrix GSparseMatrix::operator- (const GSparseMatrix& m) const | |
| 143 | 182 | { |
| 144 | - GSymMatrix result = *this; | |
| 183 | + GSparseMatrix result = *this; | |
| 145 | 184 | result -= m; |
| 146 | 185 | return result; |
| 147 | 186 | } |
| 148 | 187 | |
| 149 | -// Matrix multiplication: GSymMatrix * GSymMatrix | |
| 150 | -inline | |
| 151 | -GSymMatrix GSymMatrix::operator* (const GSymMatrix& m) const | |
| 152 | -{ | |
| 153 | - #if G_RANGE_CHECK | |
| 154 | - if (m_cols != m.m_rows) | |
| 155 | - throw GMatrix::dim_mult_mismatch("GSymMatrix multiplication", m_cols, m.m_rows); | |
| 156 | - #endif | |
| 157 | - GSymMatrix result(m_rows,m.m_cols); | |
| 158 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 159 | - for (unsigned col = 0; col < m.m_cols; ++col) { | |
| 160 | - double sum = 0.0; | |
| 161 | - for (unsigned i = 0; i < m_cols; ++i) | |
| 162 | - sum += (*this)(row,i)*m(i,col); | |
| 163 | - result(row,col) = sum; | |
| 164 | - } | |
| 165 | - } | |
| 166 | - return result; | |
| 167 | -} | |
| 168 | - | |
| 169 | -// Matrix/Vector multiplication: GSymMatrix * GVector | |
| 188 | +// Binary matrix multiplication | |
| 170 | 189 | inline |
| 171 | -GVector GSymMatrix::operator* (const GVector& v) const | |
| 172 | -{ | |
| 173 | - return (this->GMatrix::operator*(v)); | |
| 174 | -} | |
| 175 | - | |
| 176 | -// Matrix scaling: GSymMatrix * double | |
| 177 | -inline | |
| 178 | -GSymMatrix GSymMatrix::operator* (const double &d) const | |
| 179 | -{ | |
| 180 | - GSymMatrix result = (*this); | |
| 181 | - result *= d; | |
| 182 | - return result; | |
| 183 | -} | |
| 184 | - | |
| 185 | -// Matrix inverse scaling: GSymMatrix * double | |
| 186 | -inline | |
| 187 | -GSymMatrix GSymMatrix::operator/ (const double &d) const | |
| 190 | +GSparseMatrix GSparseMatrix::operator* (const GSparseMatrix& m) const | |
| 188 | 191 | { |
| 189 | - GSymMatrix result = (*this); | |
| 190 | - result /= d; | |
| 192 | + GSparseMatrix result = *this; | |
| 193 | + result *= m; | |
| 191 | 194 | return result; |
| 192 | 195 | } |
| 193 | 196 | |
| 194 | -// Unary minus operator | |
| 197 | +// Unary scalar multiplication | |
| 195 | 198 | inline |
| 196 | -GSymMatrix GSymMatrix::operator- ( ) const | |
| 199 | +GSparseMatrix& GSparseMatrix::operator*= (const double& d) | |
| 197 | 200 | { |
| 198 | - GSymMatrix result = *this; | |
| 199 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 200 | - result.m_data[i] = -result.m_data[i]; | |
| 201 | - return result; | |
| 201 | + fill_pending(); | |
| 202 | + this->GMatrix::operator*=(d); | |
| 202 | 203 | } |
| 203 | 204 | |
| 204 | -// Matrix transpose | |
| 205 | +// Unary scalar division | |
| 205 | 206 | inline |
| 206 | -void GSymMatrix::transpose() | |
| 207 | +GSparseMatrix& GSparseMatrix::operator/= (const double& d) | |
| 207 | 208 | { |
| 208 | - return; | |
| 209 | + fill_pending(); | |
| 210 | + this->GMatrix::operator/=(d); | |
| 209 | 211 | } |
| 210 | 212 | |
| 211 | 213 | |
| 212 | - | |
| 213 | 214 | /*************************************************************************** |
| 214 | 215 | * Inline friends * |
| 215 | 216 | ***************************************************************************/ |
| 216 | -// Matrix scaling: double * GSymMatrix | |
| 217 | +// Binary matrix scaling (matrix is left operand) | |
| 217 | 218 | inline |
| 218 | -GSymMatrix operator* (const double& a, const GSymMatrix& b) | |
| 219 | +GSparseMatrix operator* (const GSparseMatrix& a, const double& b) | |
| 219 | 220 | { |
| 220 | - GSymMatrix result = b; | |
| 221 | - result *= a; | |
| 221 | + GSparseMatrix result = a; | |
| 222 | + result.fill_pending(); | |
| 223 | + result *= b; | |
| 222 | 224 | return result; |
| 223 | 225 | } |
| 224 | 226 | |
| 225 | -// Matrix transpose: transpose(GSymMatrix) | |
| 227 | +// Binary matrix scaling (matrix is right operand) | |
| 226 | 228 | inline |
| 227 | -GSymMatrix transpose(const GSymMatrix &m) | |
| 229 | +GSparseMatrix operator* (const double& a, const GSparseMatrix& b) | |
| 228 | 230 | { |
| 229 | - return m; | |
| 231 | + GSparseMatrix result = b; | |
| 232 | + result.fill_pending(); | |
| 233 | + result *= a; | |
| 234 | + return result; | |
| 230 | 235 | } |
| 231 | 236 | |
| 232 | -// Cholesky decomposition: cholesky_decompose(GSymMatrix) | |
| 237 | +// Binary matrix division (matrix is left operand) | |
| 233 | 238 | inline |
| 234 | -GSymMatrix cholesky_decompose(const GSymMatrix &m) | |
| 239 | +GSparseMatrix operator/ (const GSparseMatrix& a, const double& b) | |
| 235 | 240 | { |
| 236 | - GSymMatrix result = m; | |
| 237 | - result.cholesky_decompose(); | |
| 241 | + GSparseMatrix result = a; | |
| 242 | + result.fill_pending(); | |
| 243 | + result /= b; | |
| 238 | 244 | return result; |
| 239 | 245 | } |
| 240 | 246 | |
| 241 | -// Convert symmetric matrix into full matrix: full(GSymMatrix) | |
| 247 | +// Matrix transpose function | |
| 242 | 248 | inline |
| 243 | -GMatrix full(const GSymMatrix& m) | |
| 249 | +GSparseMatrix transpose(const GSparseMatrix& m) | |
| 244 | 250 | { |
| 245 | - GMatrix result(m.m_rows,m.m_cols); | |
| 246 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 247 | - for (unsigned col = 0; col < m.m_cols; ++col) | |
| 248 | - result(row,col) = m(row,col); | |
| 249 | - } | |
| 251 | + GSparseMatrix result = m; | |
| 252 | + result.transpose(); | |
| 250 | 253 | return result; |
| 251 | 254 | } |
| 252 | 255 | |
| 253 | -// Convert symmetric matrix into lower triangle full matrix: lower_triangle(GSymMatrix) | |
| 256 | +// Cholesky decomposition | |
| 254 | 257 | inline |
| 255 | -GMatrix lower_triangle(const GSymMatrix &m) | |
| 258 | +GSparseMatrix cholesky_decompose(const GSparseMatrix& m, int compress) | |
| 256 | 259 | { |
| 257 | - GMatrix result(m.m_rows,m.m_cols); | |
| 258 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 259 | - for (unsigned col = 0; col <= row; ++col) | |
| 260 | - result(row,col) = m.m_data[m.m_colstart[col]+(row-col)]; | |
| 261 | - } | |
| 260 | + GSparseMatrix result = m; | |
| 261 | + result.cholesky_decompose(compress); | |
| 262 | 262 | return result; |
| 263 | 263 | } |
| 264 | 264 | |
| 265 | -// Convert symmetric matrix into upper triangle full matrix: lower_triangle(GSymMatrix) | |
| 265 | +// Matrix inversion using Cholesky decomposition | |
| 266 | 266 | inline |
| 267 | -GMatrix upper_triangle(const GSymMatrix &m) | |
| 267 | +GSparseMatrix cholesky_invert(const GSparseMatrix& m, int compress) | |
| 268 | 268 | { |
| 269 | - GMatrix result(m.m_rows,m.m_cols); | |
| 270 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 271 | - for (unsigned col = row; col < m.m_cols; ++col) | |
| 272 | - result(row,col) = m.m_data[m.m_colstart[row]+(col-row)]; | |
| 273 | - } | |
| 269 | + GSparseMatrix result = m; | |
| 270 | + result.cholesky_invert(compress); | |
| 274 | 271 | return result; |
| 275 | 272 | } |
| 276 | 273 | |
| 277 | -#endif /* GSYMMATRIX_HPP */ | |
| 274 | +#endif /* GSPARSEMATRIX_HPP */ | ... | ... |
src/GSparseNumeric.cpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * GSparseNumeric.cpp - sparse matrix numeric analysis class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + ***************************************************************************/ | |
| 13 | + | |
| 14 | +/* __ Includes ___________________________________________________________ */ | |
| 15 | +#include "GSparseSymbolic.hpp" | |
| 16 | +#include "GSparseNumeric.hpp" | |
| 17 | + | |
| 18 | +/* __ Namespaces _________________________________________________________ */ | |
| 19 | +using namespace std; | |
| 20 | + | |
| 21 | +/* __ Macros _____________________________________________________________ */ | |
| 22 | +#define CS_FLIP(i) (-(i)-2) | |
| 23 | +#define CS_MARK(w,j) { w [j] = CS_FLIP (w [j]) ; } | |
| 24 | +#define CS_MARKED(w,j) (w [j] < 0) | |
| 25 | + | |
| 26 | + | |
| 27 | +/*========================================================================== | |
| 28 | + = = | |
| 29 | + = GSparseNumeric constructors/destructors = | |
| 30 | + = = | |
| 31 | + ==========================================================================*/ | |
| 32 | + | |
| 33 | +/*************************************************************************** | |
| 34 | + * GSparseNumeric constructor * | |
| 35 | + ***************************************************************************/ | |
| 36 | +GSparseNumeric::GSparseNumeric() | |
| 37 | +{ | |
| 38 | + // Initialise private members for clean destruction | |
| 39 | + m_L = NULL; | |
| 40 | + m_U = NULL; | |
| 41 | + m_pinv = NULL; | |
| 42 | + m_B = NULL; | |
| 43 | + m_n_pinv = 0; | |
| 44 | + m_n_B = 0; | |
| 45 | + | |
| 46 | + // Return | |
| 47 | + return; | |
| 48 | +} | |
| 49 | + | |
| 50 | + | |
| 51 | +/*************************************************************************** | |
| 52 | + * GSparseNumeric destructor * | |
| 53 | + ***************************************************************************/ | |
| 54 | +GSparseNumeric::~GSparseNumeric() | |
| 55 | +{ | |
| 56 | + // De-allocate only if memory has indeed been allocated | |
| 57 | + if (m_L != NULL) delete m_L; | |
| 58 | + if (m_U != NULL) delete m_U; | |
| 59 | + if (m_pinv != NULL) delete [] m_pinv; | |
| 60 | + if (m_B != NULL) delete [] m_B; | |
| 61 | + | |
| 62 | + // Return | |
| 63 | + return; | |
| 64 | +} | |
| 65 | + | |
| 66 | + | |
| 67 | +/*========================================================================== | |
| 68 | + = = | |
| 69 | + = GSparseNumeric operators = | |
| 70 | + = = | |
| 71 | + ==========================================================================*/ | |
| 72 | + | |
| 73 | +/*************************************************************************** | |
| 74 | + * GSparseNumeric assignment operator * | |
| 75 | + ***************************************************************************/ | |
| 76 | +GSparseNumeric& GSparseNumeric::operator= (const GSparseNumeric& n) | |
| 77 | +{ | |
| 78 | + // Execute only if object is not identical | |
| 79 | + if (this != &n) { | |
| 80 | + | |
| 81 | + // Initialise private members for clean destruction | |
| 82 | + m_L = NULL; | |
| 83 | + m_U = NULL; | |
| 84 | + m_pinv = NULL; | |
| 85 | + m_B = NULL; | |
| 86 | + m_n_pinv = 0; | |
| 87 | + m_n_B = 0; | |
| 88 | + | |
| 89 | + // Copy m_L if it exists | |
| 90 | + if (n.m_L != NULL) | |
| 91 | + m_L = new GSparseMatrix(*n.m_L); | |
| 92 | + | |
| 93 | + // Copy m_U if it exists | |
| 94 | + if (n.m_U != NULL) | |
| 95 | + m_U = new GSparseMatrix(*n.m_U); | |
| 96 | + | |
| 97 | + // Copy m_pinv array if it exists | |
| 98 | + if (n.m_pinv != NULL) { | |
| 99 | + m_pinv = new int[n.m_n_pinv]; | |
| 100 | + if (m_pinv == NULL) | |
| 101 | + throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)", | |
| 102 | + n.m_n_pinv); | |
| 103 | + for (int i = 0; i < n.m_n_pinv; ++i) | |
| 104 | + m_pinv[i] = n.m_pinv[i]; | |
| 105 | + m_n_pinv = n.m_n_pinv; | |
| 106 | + } | |
| 107 | + | |
| 108 | + // Copy m_B array if it exists | |
| 109 | + if (n.m_B != NULL) { | |
| 110 | + m_B = new double[n.m_n_B]; | |
| 111 | + if (m_B == NULL) | |
| 112 | + throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)", | |
| 113 | + n.m_n_B); | |
| 114 | + for (int i = 0; i < n.m_n_B; ++i) | |
| 115 | + m_B[i] = n.m_B[i]; | |
| 116 | + m_n_B = n.m_n_B; | |
| 117 | + } | |
| 118 | + | |
| 119 | + } // endif: object was not identical | |
| 120 | + | |
| 121 | + // Return | |
| 122 | + return *this; | |
| 123 | +} | |
| 124 | + | |
| 125 | + | |
| 126 | +/*========================================================================== | |
| 127 | + = = | |
| 128 | + = GSparseNumeric member functions = | |
| 129 | + = = | |
| 130 | + ==========================================================================*/ | |
| 131 | + | |
| 132 | +/*************************************************************************** | |
| 133 | + * cholesky_numeric_analysis * | |
| 134 | + * ----------------------------------------------------------------------- * | |
| 135 | + * L = chol (A, [pinv parent cp]), pinv is optional. This function * | |
| 136 | + * allocates the memory to hold the information. * | |
| 137 | + * ----------------------------------------------------------------------- * | |
| 138 | + * Input: A Sparse matrix * | |
| 139 | + * S Symbolic analysis of sparse matrix * | |
| 140 | + ***************************************************************************/ | |
| 141 | +void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix& A, | |
| 142 | + const GSparseSymbolic& S) | |
| 143 | +{ | |
| 144 | + // Return if arrays in the symbolic analysis have not been allocated | |
| 145 | + if (!S.m_cp || !S.m_parent) return; | |
| 146 | + | |
| 147 | + // Declare | |
| 148 | + double lki; | |
| 149 | + int top, i, p, k; | |
| 150 | + | |
| 151 | + // Assign input matrix attributes | |
| 152 | + int n = A.m_cols; | |
| 153 | + | |
| 154 | + // Allocate int workspace | |
| 155 | + int wrk_size = 2*n; | |
| 156 | + int* wrk_int = new int[wrk_size]; | |
| 157 | + if (wrk_int == NULL) | |
| 158 | + throw mem_alloc( | |
| 159 | + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", | |
| 160 | + wrk_size); | |
| 161 | + | |
| 162 | + // Allocate double workspace | |
| 163 | + wrk_size = n; | |
| 164 | + double* wrk_double = new double[wrk_size]; | |
| 165 | + if (wrk_double == NULL) | |
| 166 | + throw mem_alloc( | |
| 167 | + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", | |
| 168 | + wrk_size); | |
| 169 | + | |
| 170 | + // Assign pointers | |
| 171 | + int* cp = S.m_cp; | |
| 172 | + int* pinv = S.m_pinv; | |
| 173 | + int* parent = S.m_parent; | |
| 174 | + | |
| 175 | + // Assign C = A(p,p) where A and C are symmetric and the upper part stored | |
| 176 | + GSparseMatrix C = (pinv) ? S.cs_symperm(&A, pinv, 1) : (A); | |
| 177 | + | |
| 178 | + // Assign workspace pointer | |
| 179 | + int* c = wrk_int; | |
| 180 | + int* s = wrk_int + n; | |
| 181 | + double* x = wrk_double; | |
| 182 | + | |
| 183 | + // Assign C matrix pointers | |
| 184 | + int* Cp = C.m_colstart; | |
| 185 | + int* Ci = C.m_rowinx; | |
| 186 | + double* Cx = C.m_data; | |
| 187 | + | |
| 188 | + // Allocate L matrix | |
| 189 | + m_L = new GSparseMatrix(n,n,cp[n]); | |
| 190 | + if (m_L == NULL) | |
| 191 | + throw mem_alloc( | |
| 192 | + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", | |
| 193 | + 1); | |
| 194 | + | |
| 195 | + // Assign L matrix pointers | |
| 196 | + int* Lp = m_L->m_colstart; | |
| 197 | + int* Li = m_L->m_rowinx; | |
| 198 | + double* Lx = m_L->m_data; | |
| 199 | + | |
| 200 | + // Initialise column pointers of L and c | |
| 201 | + for (k = 0; k < n; ++k) | |
| 202 | + Lp[k] = c[k] = cp[k]; | |
| 203 | + | |
| 204 | + // Compute L(:,k) for L*L' = C | |
| 205 | + for (k = 0; k < n; k++) { | |
| 206 | + | |
| 207 | + // Nonzero pattern of L(k,:) | |
| 208 | + top = cs_ereach(&C, k, parent, s, c); // find pattern of L(k,:) | |
| 209 | + x[k] = 0; // x (0:k) is now zero | |
| 210 | + | |
| 211 | + // x = full(triu(C(:,k))) | |
| 212 | + for (p = Cp[k]; p < Cp[k+1]; p++) { | |
| 213 | + if (Ci[p] <= k) | |
| 214 | + x[Ci[p]] = Cx[p]; | |
| 215 | + } | |
| 216 | + | |
| 217 | + // d = C(k,k) | |
| 218 | + double d = x[k]; | |
| 219 | + | |
| 220 | + // Clear x for k+1st iteration | |
| 221 | + x[k] = 0; | |
| 222 | + | |
| 223 | + // Triangular solve: Solve L(0:k-1,0:k-1) * x = C(:,k) | |
| 224 | + for ( ; top < n; top++) { | |
| 225 | + i = s[top]; // s [top..n-1] is pattern of L(k,:) | |
| 226 | + lki = x[i]/Lx[Lp[i]]; // L(k,i) = x (i) / L(i,i) | |
| 227 | + x[i] = 0; // clear x for k+1st iteration | |
| 228 | + for (p = Lp[i]+1; p < c[i]; p++) | |
| 229 | + x[Li[p]] -= Lx[p] * lki; | |
| 230 | + d -= lki * lki; // d = d - L(k,i)*L(k,i) | |
| 231 | + p = c [i]++ ; | |
| 232 | + Li[p] = k; // store L(k,i) in column i | |
| 233 | + Lx[p] = lki; | |
| 234 | + } | |
| 235 | + | |
| 236 | + // Compute L(k,k) | |
| 237 | + if (d <= 0) | |
| 238 | + throw GSparseMatrix::matrix_not_pos_definite( | |
| 239 | + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", | |
| 240 | + k, d); | |
| 241 | + | |
| 242 | + // Store L(k,k) = sqrt (d) in column k | |
| 243 | + p = c[k]++; | |
| 244 | + Li[p] = k; | |
| 245 | + Lx[p] = sqrt(d); | |
| 246 | + } | |
| 247 | + | |
| 248 | + // Finalize L | |
| 249 | + Lp[n] = cp[n]; | |
| 250 | + | |
| 251 | + // Free workspace | |
| 252 | + delete [] wrk_int; | |
| 253 | + delete [] wrk_double; | |
| 254 | + | |
| 255 | + // Return void | |
| 256 | + return; | |
| 257 | +} | |
| 258 | + | |
| 259 | + | |
| 260 | +/*========================================================================== | |
| 261 | + = = | |
| 262 | + = GSparseNumeric private functions = | |
| 263 | + = = | |
| 264 | + ==========================================================================*/ | |
| 265 | + | |
| 266 | +/*************************************************************************** | |
| 267 | + * cs_ereach * | |
| 268 | + * ----------------------------------------------------------------------- * | |
| 269 | + * Find nonzero pattern of Cholesky L(k,1:k-1) using etree and * | |
| 270 | + * triu(A(:,k)) * | |
| 271 | + * ----------------------------------------------------------------------- * | |
| 272 | + * Input: A Sparse matrix * | |
| 273 | + * k Node * | |
| 274 | + * parent ... * | |
| 275 | + * s ... * | |
| 276 | + * w ... * | |
| 277 | + * Input: top Index, where s[top..n-1] contains pattern * | |
| 278 | + * of L(k,:); -1 if arrays have not been * | |
| 279 | + * allocated * | |
| 280 | + ***************************************************************************/ | |
| 281 | +int GSparseNumeric::cs_ereach(const GSparseMatrix* A, int k, | |
| 282 | + const int* parent, int* s, int* w) | |
| 283 | +{ | |
| 284 | + // Return -1 if arrays have not been allocated | |
| 285 | + if (!parent || !s || !w) return (-1); | |
| 286 | + | |
| 287 | + // Assign A matrix attributes and pointers | |
| 288 | + int n = A->m_cols; | |
| 289 | + int top = n; | |
| 290 | + int* Ap = A->m_colstart; | |
| 291 | + int* Ai = A->m_rowinx; | |
| 292 | + | |
| 293 | + // Mark node k as visited | |
| 294 | + CS_MARK(w, k); | |
| 295 | + | |
| 296 | + // Loop over elements of node | |
| 297 | + int i; | |
| 298 | + for (int p = Ap[k]; p < Ap[k+1]; ++p) { | |
| 299 | + i = Ai[p]; // A(i,k) is nonzero | |
| 300 | + if (i > k) continue; // only use upper triangular part of A | |
| 301 | + | |
| 302 | + // Traverse up etree | |
| 303 | + int len; | |
| 304 | + for (len = 0; !CS_MARKED(w,i); i = parent[i]) { | |
| 305 | + s[len++] = i; // L(k,i) is nonzero | |
| 306 | + CS_MARK(w, i); // mark i as visited | |
| 307 | + } | |
| 308 | + | |
| 309 | + // Push path onto stack | |
| 310 | + while (len > 0) | |
| 311 | + s[--top] = s[--len]; | |
| 312 | + } | |
| 313 | + | |
| 314 | + // Unmark all nodes | |
| 315 | + for (int p = top; p < n; ++p) | |
| 316 | + CS_MARK(w, s[p]); | |
| 317 | + | |
| 318 | + // Unmark node k | |
| 319 | + CS_MARK(w, k); | |
| 320 | + | |
| 321 | + // Return index top, where s[top..n-1] contains pattern of L(k,:) | |
| 322 | + return (top); | |
| 323 | +} | |
| 324 | + | |
| 325 | + | |
| 326 | +/*========================================================================== | |
| 327 | + = = | |
| 328 | + = GSparseNumeric static member functions = | |
| 329 | + = = | |
| 330 | + ==========================================================================*/ | |
| 331 | + | |
| 332 | +/*========================================================================== | |
| 333 | + = = | |
| 334 | + = GSparseNumeric friends = | |
| 335 | + = = | |
| 336 | + ==========================================================================*/ | |
| 337 | + | |
| 338 | +/*************************************************************************** | |
| 339 | + * Output operator * | |
| 340 | + ***************************************************************************/ | |
| 341 | +ostream& operator<< (ostream& os, const GSparseNumeric& n) | |
| 342 | +{ | |
| 343 | + // Put header is stream | |
| 344 | + os << "=== GSparseNumeric ==="; | |
| 345 | + | |
| 346 | + // Show L or V matrix | |
| 347 | + if (n.m_L != NULL) { | |
| 348 | + os << endl << | |
| 349 | + " === L or V "; | |
| 350 | + os << *n.m_L << endl; | |
| 351 | + } | |
| 352 | + | |
| 353 | + // Show U or R matrix | |
| 354 | + if (n.m_U != NULL) { | |
| 355 | + os << endl << | |
| 356 | + " === U or R matrix "; | |
| 357 | + os << *n.m_U << endl; | |
| 358 | + } | |
| 359 | + | |
| 360 | + // Show inverse permutation if it exists | |
| 361 | + if (n.m_pinv != NULL) { | |
| 362 | + os << endl << " Inverse permutation (of " << n.m_n_pinv << " elements)" << endl; | |
| 363 | + for (int i = 0; i < n.m_n_pinv; ++i) | |
| 364 | + os << " " << n.m_pinv[i]; | |
| 365 | + } | |
| 366 | + | |
| 367 | + // Show beta array if it exists | |
| 368 | + if (n.m_B != NULL) { | |
| 369 | + os << endl << " Beta[0.." << n.m_n_B << "]" << endl; | |
| 370 | + for (int i = 0; i < n.m_n_B; ++i) | |
| 371 | + os << " " << n.m_B[i]; | |
| 372 | + } | |
| 373 | + | |
| 374 | + // Return output stream | |
| 375 | + return os; | |
| 376 | +} | |
| 377 | + | |
| 378 | +/*========================================================================== | |
| 379 | + = = | |
| 380 | + = GSparseNumeric exception classes = | |
| 381 | + = = | |
| 382 | + ==========================================================================*/ | ... | ... |
src/GSparseNumeric.hpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * GSparseNumeric.hpp - sparse matrix numeric analysis class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + ***************************************************************************/ | |
| 13 | + | |
| 14 | +#ifndef GSPARSENUMERIC_HPP | |
| 15 | +#define GSPARSENUMERIC_HPP | |
| 16 | + | |
| 17 | +/* __ Includes ___________________________________________________________ */ | |
| 18 | +#include "GException.hpp" | |
| 19 | +#include "GVector.hpp" | |
| 20 | +#include "GMatrix.hpp" | |
| 21 | +#include "GSparseMatrix.hpp" | |
| 22 | + | |
| 23 | +/* __ Namespaces _________________________________________________________ */ | |
| 24 | +using namespace std; | |
| 25 | + | |
| 26 | +/* __ Definitions ________________________________________________________ */ | |
| 27 | + | |
| 28 | +/* __ Enumerators ________________________________________________________ */ | |
| 29 | + | |
| 30 | +/* __ Structures _________________________________________________________ */ | |
| 31 | + | |
| 32 | +/* __ Prototypes _________________________________________________________ */ | |
| 33 | + | |
| 34 | + | |
| 35 | +/*************************************************************************** | |
| 36 | + * GSparseNumeric class definition * | |
| 37 | + ***************************************************************************/ | |
| 38 | +class GSparseNumeric { | |
| 39 | + // Friend classes | |
| 40 | + friend class GSparseMatrix; | |
| 41 | + | |
| 42 | + // I/O friends | |
| 43 | + friend ostream& operator<< (ostream& os, const GSparseNumeric& n); | |
| 44 | + | |
| 45 | +public: | |
| 46 | + // Constructors and destructors | |
| 47 | + GSparseNumeric(); | |
| 48 | + ~GSparseNumeric(); | |
| 49 | + | |
| 50 | + // Assignment operator | |
| 51 | + GSparseNumeric& operator= (const GSparseNumeric& n); | |
| 52 | + | |
| 53 | + // Functions | |
| 54 | + void cholesky_numeric_analysis(GSparseMatrix& m, const GSparseSymbolic& s); | |
| 55 | + | |
| 56 | +private: | |
| 57 | + // Functions | |
| 58 | + int cs_ereach(const GSparseMatrix* A, int k, const int* parent, int* s, int* w); | |
| 59 | + | |
| 60 | + // Data | |
| 61 | + GSparseMatrix* m_L; // L for LU and Cholesky, V for QR | |
| 62 | + GSparseMatrix* m_U; // U for LU, R for QR, not used for Cholesky | |
| 63 | + int* m_pinv; // partial pivoting for LU | |
| 64 | + double* m_B; // beta [0..n-1] for QR | |
| 65 | + int m_n_pinv; // Number of elements in m_pinv | |
| 66 | + int m_n_B; // Number of elements in m_B | |
| 67 | +}; | |
| 68 | + | |
| 69 | + | |
| 70 | +/*************************************************************************** | |
| 71 | + * Inline members * | |
| 72 | + ***************************************************************************/ | |
| 73 | + | |
| 74 | + | |
| 75 | +/*************************************************************************** | |
| 76 | + * Inline friends * | |
| 77 | + ***************************************************************************/ | |
| 78 | + | |
| 79 | +#endif /* GSPARSENUMERIC_HPP */ | ... | ... |
src/GSparseSymbolic.cpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * GSparseSymbolic.cpp - sparse matrix symbolic analysis class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + ***************************************************************************/ | |
| 13 | + | |
| 14 | +/* __ Includes ___________________________________________________________ */ | |
| 15 | +#include "GSparseSymbolic.hpp" | |
| 16 | + | |
| 17 | +/* __ Namespaces _________________________________________________________ */ | |
| 18 | +using namespace std; | |
| 19 | + | |
| 20 | +/* __ Macros _____________________________________________________________ */ | |
| 21 | +#define CS_MIN(a,b) (((a) < (b)) ? (a) : (b)) | |
| 22 | +#define CS_MAX(a,b) (((a) > (b)) ? (a) : (b)) | |
| 23 | +#define CS_FLIP(i) (-(i)-2) | |
| 24 | + | |
| 25 | +/* __ Definitions ________________________________________________________ */ | |
| 26 | +//#define G_DEBUG_SPARSE_SYM_AMD_ORDERING // Debug AMD ordering | |
| 27 | + | |
| 28 | + | |
| 29 | +/*========================================================================== | |
| 30 | + = = | |
| 31 | + = GSparseSymbolic constructors/destructors = | |
| 32 | + = = | |
| 33 | + ==========================================================================*/ | |
| 34 | + | |
| 35 | +/*************************************************************************** | |
| 36 | + * GSparseSymbolic constructor * | |
| 37 | + ***************************************************************************/ | |
| 38 | +GSparseSymbolic::GSparseSymbolic() | |
| 39 | +{ | |
| 40 | + // Initialise private members for clean destruction | |
| 41 | + m_n_pinv = 0; | |
| 42 | + m_n_q = 0; | |
| 43 | + m_n_parent = 0; | |
| 44 | + m_n_cp = 0; | |
| 45 | + m_n_leftmost = 0; | |
| 46 | + m_pinv = NULL; | |
| 47 | + m_q = NULL; | |
| 48 | + m_parent = NULL; | |
| 49 | + m_cp = NULL; | |
| 50 | + m_leftmost = NULL; | |
| 51 | + m_m2 = 0; | |
| 52 | + m_lnz = 0.0; | |
| 53 | + m_unz = 0.0; | |
| 54 | + | |
| 55 | + // Return | |
| 56 | + return; | |
| 57 | +} | |
| 58 | + | |
| 59 | + | |
| 60 | +/*************************************************************************** | |
| 61 | + * GSparseSymbolic destructor * | |
| 62 | + ***************************************************************************/ | |
| 63 | +GSparseSymbolic::~GSparseSymbolic() | |
| 64 | +{ | |
| 65 | + // De-allocate only if memory has indeed been allocated | |
| 66 | + if (m_pinv != NULL) delete[] m_pinv; | |
| 67 | + if (m_q != NULL) delete[] m_q; | |
| 68 | + if (m_parent != NULL) delete[] m_parent; | |
| 69 | + if (m_cp != NULL) delete[] m_cp; | |
| 70 | + if (m_leftmost != NULL) delete[] m_leftmost; | |
| 71 | + | |
| 72 | + // Return | |
| 73 | + return; | |
| 74 | +} | |
| 75 | + | |
| 76 | + | |
| 77 | +/*========================================================================== | |
| 78 | + = = | |
| 79 | + = GSparseSymbolic operators = | |
| 80 | + = = | |
| 81 | + ==========================================================================*/ | |
| 82 | + | |
| 83 | +/*************************************************************************** | |
| 84 | + * GSparseSymbolic assignment operator * | |
| 85 | + ***************************************************************************/ | |
| 86 | +GSparseSymbolic& GSparseSymbolic::operator= (const GSparseSymbolic& s) | |
| 87 | +{ | |
| 88 | + // Execute only if object is not identical | |
| 89 | + if (this != &s) { | |
| 90 | + | |
| 91 | + // Initialise private members for clean destruction | |
| 92 | + m_n_pinv = 0; | |
| 93 | + m_n_q = 0; | |
| 94 | + m_n_parent = 0; | |
| 95 | + m_n_cp = 0; | |
| 96 | + m_n_leftmost = 0; | |
| 97 | + m_pinv = NULL; | |
| 98 | + m_q = NULL; | |
| 99 | + m_parent = NULL; | |
| 100 | + m_cp = NULL; | |
| 101 | + m_leftmost = NULL; | |
| 102 | + m_m2 = 0; | |
| 103 | + m_lnz = 0.0; | |
| 104 | + m_unz = 0.0; | |
| 105 | + | |
| 106 | + // Copy data members | |
| 107 | + m_m2 = s.m_m2; | |
| 108 | + m_lnz = s.m_lnz; | |
| 109 | + m_unz = s.m_unz; | |
| 110 | + | |
| 111 | + // Copy m_pinv array if it exists | |
| 112 | + if (s.m_pinv != NULL) { | |
| 113 | + m_pinv = new int[s.m_n_pinv]; | |
| 114 | + if (m_pinv == NULL) | |
| 115 | + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", | |
| 116 | + s.m_n_pinv); | |
| 117 | + for (int i = 0; i < s.m_n_pinv; ++i) | |
| 118 | + m_pinv[i] = s.m_pinv[i]; | |
| 119 | + m_n_pinv = s.m_n_pinv; | |
| 120 | + } | |
| 121 | + | |
| 122 | + // Copy m_q array if it exists | |
| 123 | + if (s.m_q != NULL) { | |
| 124 | + m_q = new int[s.m_n_q]; | |
| 125 | + if (m_q == NULL) | |
| 126 | + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", | |
| 127 | + s.m_n_q); | |
| 128 | + for (int i = 0; i < s.m_n_q; ++i) | |
| 129 | + m_q[i] = s.m_q[i]; | |
| 130 | + m_n_q = s.m_n_q; | |
| 131 | + } | |
| 132 | + | |
| 133 | + // Copy m_parent array if it exists | |
| 134 | + if (s.m_parent != NULL) { | |
| 135 | + m_parent = new int[s.m_n_parent]; | |
| 136 | + if (m_parent == NULL) | |
| 137 | + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", | |
| 138 | + s.m_n_parent); | |
| 139 | + for (int i = 0; i < s.m_n_parent; ++i) | |
| 140 | + m_parent[i] = s.m_parent[i]; | |
| 141 | + m_n_parent = s.m_n_parent; | |
| 142 | + } | |
| 143 | + | |
| 144 | + // Copy m_cp array if it exists | |
| 145 | + if (s.m_cp != NULL) { | |
| 146 | + m_cp = new int[s.m_n_cp]; | |
| 147 | + if (m_cp == NULL) | |
| 148 | + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", | |
| 149 | + s.m_n_cp); | |
| 150 | + for (int i = 0; i < s.m_n_cp; ++i) | |
| 151 | + m_cp[i] = s.m_cp[i]; | |
| 152 | + m_n_cp = s.m_n_cp; | |
| 153 | + } | |
| 154 | + | |
| 155 | + // Copy m_leftmost array if it exists | |
| 156 | + if (s.m_leftmost != NULL) { | |
| 157 | + m_leftmost = new int[s.m_n_leftmost]; | |
| 158 | + if (m_leftmost == NULL) | |
| 159 | + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", | |
| 160 | + s.m_n_leftmost); | |
| 161 | + for (int i = 0; i < s.m_n_leftmost; ++i) | |
| 162 | + m_leftmost[i] = s.m_leftmost[i]; | |
| 163 | + m_leftmost = s.m_leftmost; | |
| 164 | + } | |
| 165 | + | |
| 166 | + } // endif: object was not identical | |
| 167 | + | |
| 168 | + // Return | |
| 169 | + return (*this); | |
| 170 | +} | |
| 171 | + | |
| 172 | + | |
| 173 | +/*========================================================================== | |
| 174 | + = = | |
| 175 | + = GSparseSymbolic member functions = | |
| 176 | + = = | |
| 177 | + ==========================================================================*/ | |
| 178 | + | |
| 179 | +/*************************************************************************** | |
| 180 | + * cholesky_symbolic_analysis * | |
| 181 | + * ----------------------------------------------------------------------- * | |
| 182 | + * Ordering and symbolic analysis for a Cholesky factorization. This * | |
| 183 | + * function allocates the memory to hold the information. * | |
| 184 | + * ----------------------------------------------------------------------- * | |
| 185 | + * Input: order 0: natural * | |
| 186 | + * 1: Cholesky decomposition * | |
| 187 | + * m Sparse matrix * | |
| 188 | + ***************************************************************************/ | |
| 189 | +void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix& m) | |
| 190 | +{ | |
| 191 | + // Check if order type is valid | |
| 192 | + if (order < 0 || order > 1) | |
| 193 | + throw invalid_order("GSparseSymbolic::cholesky_symbolic_analysis(int, GSparseMatrix*)", | |
| 194 | + order, 0, 1); | |
| 195 | + | |
| 196 | + // Fill pending element | |
| 197 | + m.fill_pending(); | |
| 198 | + | |
| 199 | + // Assign input matrix attributes | |
| 200 | + int n = m.m_cols; | |
| 201 | + | |
| 202 | + // P = amd(A+A'), or natural | |
| 203 | + int* P = cs_amd(order, &m); | |
| 204 | + | |
| 205 | + // Find inverse permutation and store it in class member 'm_pinv' | |
| 206 | + m_pinv = cs_pinv(P, n); | |
| 207 | + m_n_pinv = n; | |
| 208 | + | |
| 209 | + // Delete workspace | |
| 210 | + delete [] P; | |
| 211 | + | |
| 212 | + // C = spones(triu(A(P,P))) | |
| 213 | + GSparseMatrix C = cs_symperm(&m, m_pinv, 0); | |
| 214 | + | |
| 215 | + // Find etree of C and store it in class member 'm_parent' | |
| 216 | + m_parent = cs_etree(&C, 0); | |
| 217 | + m_n_parent = n; | |
| 218 | + | |
| 219 | + // Post order the etree | |
| 220 | + int* post = cs_post(m_parent, n); | |
| 221 | + | |
| 222 | + // Find column counts of chol(C) | |
| 223 | + int* c = cs_counts(&C, m_parent, post, 0); | |
| 224 | + | |
| 225 | + // Delete workspace | |
| 226 | + delete [] post; | |
| 227 | + | |
| 228 | + // Allocate column pointers for Cholesky decomposition | |
| 229 | + m_n_cp = n+1; | |
| 230 | + m_cp = new int[m_n_cp]; | |
| 231 | + if (m_cp == NULL) | |
| 232 | + throw mem_alloc("GSparseSymbolic::cs_schol(int, GSparseMatrix*)", m_n_cp); | |
| 233 | + | |
| 234 | + // Find column pointers for L | |
| 235 | + m_unz = m_lnz = cs_cumsum(m_cp, c, n); | |
| 236 | + | |
| 237 | + // Delete workspace | |
| 238 | + delete [] c; | |
| 239 | + | |
| 240 | +// return ((S->lnz >= 0) ? S : cs_sfree (S)) ; | |
| 241 | +} | |
| 242 | + | |
| 243 | + | |
| 244 | +/*========================================================================== | |
| 245 | + = = | |
| 246 | + = GSparseSymbolic private functions = | |
| 247 | + = = | |
| 248 | + ==========================================================================*/ | |
| 249 | + | |
| 250 | +/*************************************************************************** | |
| 251 | + * cs_amd * | |
| 252 | + * ----------------------------------------------------------------------- * | |
| 253 | + * Applies an approximate minimum degree ordering algorithm to derive the * | |
| 254 | + * permutations that minimise the fill-in. * | |
| 255 | + * p = amd(A+A') if symmetric is true, or amd(A'A) otherwise * | |
| 256 | + * ----------------------------------------------------------------------- * | |
| 257 | + * Input: order 0: natural * | |
| 258 | + * 1: Cholesky decomposition * | |
| 259 | + * 2: LU decomposition * | |
| 260 | + * 3: QR decomposition * | |
| 261 | + * A Sparse matrix * | |
| 262 | + * Output: p[0..n] integer array of n+1 elements * | |
| 263 | + ***************************************************************************/ | |
| 264 | +int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) | |
| 265 | +{ | |
| 266 | + // Throw exception if order is not a decomposition | |
| 267 | + if (order < 0 || order > 3) | |
| 268 | + throw invalid_order("GSparseSymbolic::cs_amd(int, GSparseMatrix*)", | |
| 269 | + order, 0, 3); | |
| 270 | + | |
| 271 | + // Debug | |
| 272 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 273 | + cout << endl << "GSparseSymbolic::cs_amd entered" << endl; | |
| 274 | + cout << " order ......................: " << order << endl; | |
| 275 | + cout << " number of rows .............: " << A->m_rows << endl; | |
| 276 | + cout << " number of columns ..........: " << A->m_cols << endl; | |
| 277 | + cout << " number of non-zero elements : " << A->m_elements << endl; | |
| 278 | + #endif | |
| 279 | + | |
| 280 | + // Declare | |
| 281 | + int dense; | |
| 282 | + int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1, | |
| 283 | + k2, k3, jlast, ln, mindeg = 0, nvi, nvj, nvk, mark, wnvi, | |
| 284 | + ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q; | |
| 285 | + unsigned int h ; | |
| 286 | + | |
| 287 | + // Assign input matrix attributes | |
| 288 | + int m = A->m_rows; | |
| 289 | + int n = A->m_cols; | |
| 290 | + | |
| 291 | + | |
| 292 | + // ====================================================================== | |
| 293 | + // Step 1: Construct matrix C | |
| 294 | + // ====================================================================== | |
| 295 | + | |
| 296 | + // Debug | |
| 297 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 298 | + cout << " Step 1: Construct matrix C" << endl; | |
| 299 | + #endif | |
| 300 | + | |
| 301 | + // Initialise matrix C. We do not care at this point about the actual | |
| 302 | + // dimension since we attribute the matrix later anyways. It's just | |
| 303 | + // that there is no empty constructor of a matrix, so we have to put | |
| 304 | + // something by default ... | |
| 305 | + GSparseMatrix C(m,n); | |
| 306 | + | |
| 307 | + // Get (logical) transpose of A: AT = A' | |
| 308 | + GSparseMatrix AT = A->cs_transpose(A,0); | |
| 309 | + | |
| 310 | + // Find dense threshold | |
| 311 | + dense = (int)CS_MAX(16, 10 * sqrt((double)n)); | |
| 312 | + dense = CS_MIN(n-2, dense); | |
| 313 | + | |
| 314 | + // Case A: Cholesky decomposition of a symmetric matrix: C = A + A' | |
| 315 | + if (order == 1 && n == m) { | |
| 316 | +// C = cs_add (A, AT, 0, 0); | |
| 317 | + C = *A + AT; | |
| 318 | + } | |
| 319 | + | |
| 320 | + // Case B: LU decomposition: C = A' * A with no dense rows | |
| 321 | + else if (order == 2) { | |
| 322 | + | |
| 323 | + // Assign A' matrix attributes | |
| 324 | + int* ATp = AT.m_colstart; | |
| 325 | + int* ATi = AT.m_rowinx; | |
| 326 | + | |
| 327 | + // Drop dense columns from AT | |
| 328 | + for (p2 = 0, j = 0; j < m; j++) { | |
| 329 | + p = ATp[j]; // column j of AT starts here | |
| 330 | + ATp[j] = p2; // new column j starts here | |
| 331 | + if (ATp[j+1] - p > dense) continue; // skip dense col j | |
| 332 | + for ( ; p < ATp[j+1]; p++) | |
| 333 | + ATi[p2++] = ATi[p] ; | |
| 334 | + } | |
| 335 | + | |
| 336 | + // Finalise AT | |
| 337 | + ATp[m] = p2; | |
| 338 | + | |
| 339 | + // Get (logical) transpose of AT: A2 = AT' | |
| 340 | + GSparseMatrix A2 = AT.cs_transpose(&AT,0); | |
| 341 | + | |
| 342 | + // C = A' * A with no dense rows | |
| 343 | +// C = A2 ? cs_multiply(AT, A2) : NULL; | |
| 344 | + C = AT * A2; | |
| 345 | + } | |
| 346 | + | |
| 347 | + // Case C: QR decomposition: C = A' * A | |
| 348 | + else { | |
| 349 | +// C = cs_multiply(AT, A); | |
| 350 | + C = AT * *A; | |
| 351 | + } | |
| 352 | + | |
| 353 | + // Stop in case of an error | |
| 354 | +// if (!C) return (NULL) ; | |
| 355 | + | |
| 356 | + // Drop diagonal entries from C | |
| 357 | + cs_fkeep(&C, &cs_diag, NULL); | |
| 358 | + | |
| 359 | + // Assign C matrix attributes | |
| 360 | + int* Cp = C.m_colstart; | |
| 361 | + int cnz = Cp[n]; | |
| 362 | + | |
| 363 | + // Allocate result array | |
| 364 | + int* P = new int[n+1]; | |
| 365 | + if (P == NULL) | |
| 366 | + throw mem_alloc("GSparseSymbolic::cs_amd (int, GSparseMatrix*)", n+1); | |
| 367 | + | |
| 368 | + // Allocate workspace | |
| 369 | + int wrk_size = 8*(n+1); | |
| 370 | + int* wrk_int = new int[wrk_size]; | |
| 371 | + if (wrk_int == NULL) | |
| 372 | + throw mem_alloc("GSparseSymbolic::cs_amd (int, GSparseMatrix*)", wrk_size); | |
| 373 | + | |
| 374 | + // Add elbow room to C | |
| 375 | +// t = cnz + cnz/5 + 2*n; | |
| 376 | +// if (!P || !W || !cs_sprealloc (C, t)) return (cs_idone (P, C, W, 0)) ; | |
| 377 | + int t = cnz/5 + 2*n; | |
| 378 | + C.alloc_elements(cnz, t); | |
| 379 | + | |
| 380 | + // Set workspace pointers | |
| 381 | + int* len = wrk_int; | |
| 382 | + int* nv = wrk_int + (n+1); | |
| 383 | + int* next = wrk_int + 2*(n+1); | |
| 384 | + int* head = wrk_int + 3*(n+1); | |
| 385 | + int* elen = wrk_int + 4*(n+1); | |
| 386 | + int* degree = wrk_int + 5*(n+1); | |
| 387 | + int* w = wrk_int + 6*(n+1); | |
| 388 | + int* hhead = wrk_int + 7*(n+1); | |
| 389 | + int* last = P; // use P as workspace for last | |
| 390 | + | |
| 391 | + | |
| 392 | + // ====================================================================== | |
| 393 | + // Step 2: Initialize quotient graph | |
| 394 | + // ====================================================================== | |
| 395 | + | |
| 396 | + // Debug | |
| 397 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 398 | + cout << " Step 2: Initialize quotient graph" << endl; | |
| 399 | + #endif | |
| 400 | + | |
| 401 | + // (Re-)assign C matrix attributes | |
| 402 | + int nzmax = C.m_elements; // Maximum number of entries | |
| 403 | + Cp = C.m_colstart; | |
| 404 | + int* Ci = C.m_rowinx; | |
| 405 | + | |
| 406 | + // Setup array that contains for each column the number of non-zero elements | |
| 407 | + for (k = 0 ; k < n ; k++) | |
| 408 | + len[k] = Cp[k+1] - Cp[k]; | |
| 409 | + len[n] = 0; | |
| 410 | + | |
| 411 | + // Loop over all columns | |
| 412 | + for (i = 0 ; i <= n ; i++) { | |
| 413 | + head[i] = -1; // degree list i is empty | |
| 414 | + last[i] = -1; | |
| 415 | + next[i] = -1; | |
| 416 | + hhead[i] = -1; // hash list i is empty | |
| 417 | + nv[i] = 1; // node i is just one node | |
| 418 | + w[i] = 1; // node i is alive | |
| 419 | + elen[i] = 0; // Ek of node i is empty | |
| 420 | + degree[i] = len[i]; // degree of node i | |
| 421 | + } | |
| 422 | + | |
| 423 | + // Clear w | |
| 424 | + mark = cs_wclear(0, 0, w, n); | |
| 425 | + | |
| 426 | + // End-point initialisations | |
| 427 | + elen[n] = -2; // n is a dead element | |
| 428 | + Cp[n] = -1; // n is a root of assembly tree | |
| 429 | + w[n] = 0; // n is a dead element | |
| 430 | + | |
| 431 | + | |
| 432 | + // ====================================================================== | |
| 433 | + // Step 3: Initialize degree lists | |
| 434 | + // ====================================================================== | |
| 435 | + | |
| 436 | + // Debug | |
| 437 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 438 | + cout << " Step 3: Initialize degree lists" << endl; | |
| 439 | + #endif | |
| 440 | + | |
| 441 | + // Loop over all columns | |
| 442 | + for (i = 0 ; i < n ; i++) { | |
| 443 | + | |
| 444 | + // Get degree of node | |
| 445 | + d = degree[i]; | |
| 446 | + | |
| 447 | + // Case A: Node i is empty | |
| 448 | + if (d == 0) { | |
| 449 | + elen[i] = -2; // element i is dead | |
| 450 | + nel++ ; | |
| 451 | + Cp[i] = -1; // i is a root of assembly tree | |
| 452 | + w[i] = 0; // i is a dead element | |
| 453 | + } | |
| 454 | + | |
| 455 | + // Case B: Node is dense | |
| 456 | + else if (d > dense) { | |
| 457 | + nv[i] = 0; // absorb i into element n | |
| 458 | + elen[i] = -1; // node i is dead | |
| 459 | + nel++ ; | |
| 460 | + Cp[i] = CS_FLIP(n); | |
| 461 | + nv[n]++ ; | |
| 462 | + } | |
| 463 | + | |
| 464 | + // Case C: Node is sparse | |
| 465 | + else { | |
| 466 | + if (head[d] != -1) last[head[d]] = i; | |
| 467 | + next[i] = head[d]; // put node i in degree list d | |
| 468 | + head[d] = i; | |
| 469 | + } | |
| 470 | + } // endfor: looped over all columns | |
| 471 | + | |
| 472 | + | |
| 473 | + // ====================================================================== | |
| 474 | + // Step 4: Build permutations | |
| 475 | + // ====================================================================== | |
| 476 | + | |
| 477 | + // Debug | |
| 478 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 479 | + cout << " Step 4: Build permutations" << endl; | |
| 480 | + #endif | |
| 481 | + | |
| 482 | + // While (selecting pivots) do | |
| 483 | + while (nel < n) { | |
| 484 | + | |
| 485 | + // Select node of minimum approximate degree | |
| 486 | + for (k = -1; mindeg < n && (k = head [mindeg]) == -1; mindeg++) ; | |
| 487 | + if (next[k] != -1) last [next[k]] = -1; | |
| 488 | + head[mindeg] = next[k]; // remove k from degree list | |
| 489 | + elenk = elen[k]; // elenk = |Ek| | |
| 490 | + nvk = nv[k]; // # of nodes k represents | |
| 491 | + nel += nvk; // nv[k] nodes of A eliminated | |
| 492 | + | |
| 493 | + // Garbage collection | |
| 494 | + if (elenk > 0 && cnz + mindeg >= nzmax) { | |
| 495 | + | |
| 496 | + // Loop over all columns | |
| 497 | + for (j = 0 ; j < n ; j++) { | |
| 498 | + // If j is a live node or element, then ... | |
| 499 | + if ((p = Cp[j]) >= 0) { | |
| 500 | + Cp[j] = Ci[p]; // save first entry of object | |
| 501 | + Ci[p] = CS_FLIP(j); // first entry is now CS_FLIP(j) | |
| 502 | + } | |
| 503 | + } | |
| 504 | + | |
| 505 | + // Scan all memory | |
| 506 | + for (q = 0, p = 0; p < cnz ; ) { | |
| 507 | + // If we found object j, then ... | |
| 508 | + if ((j = CS_FLIP(Ci[p++])) >= 0) { | |
| 509 | + Ci[q] = Cp[j]; // restore first entry of object | |
| 510 | + Cp[j] = q++; // new pointer to object j | |
| 511 | + for (k3 = 0; k3 < len [j]-1; k3++) | |
| 512 | + Ci[q++] = Ci[p++]; | |
| 513 | + } | |
| 514 | + } | |
| 515 | + cnz = q; // Ci[cnz...nzmax-1] now free | |
| 516 | + | |
| 517 | + } // endif: garbage collection done | |
| 518 | + | |
| 519 | + // Construct new element ---------------------------------------- */ | |
| 520 | + dk = 0; | |
| 521 | + nv[k] = -nvk; // flag k as in Lk | |
| 522 | + p = Cp[k]; | |
| 523 | + pk1 = (elenk == 0) ? p : cnz; // do in place if elen[k] == 0 | |
| 524 | + pk2 = pk1; | |
| 525 | + for (k1 = 1; k1 <= elenk + 1; k1++) { | |
| 526 | + | |
| 527 | + // ... | |
| 528 | + if (k1 > elenk) { | |
| 529 | + e = k; // search the nodes in k | |
| 530 | + pj = p; // list of nodes starts at Ci[pj] | |
| 531 | + ln = len [k] - elenk; // length of list of nodes in k | |
| 532 | + } | |
| 533 | + else { | |
| 534 | + e = Ci[p++]; // search the nodes in e | |
| 535 | + pj = Cp[e]; | |
| 536 | + ln = len[e]; // length of list of nodes in e | |
| 537 | + } | |
| 538 | + | |
| 539 | + // ... | |
| 540 | + for (k2 = 1 ; k2 <= ln ; k2++) { | |
| 541 | + i = Ci[pj++]; | |
| 542 | + if ((nvi = nv [i]) <= 0) // Skip of node i is dead or seen | |
| 543 | + continue; | |
| 544 | + dk += nvi; // degree[Lk] += size of node i | |
| 545 | + nv[i] = -nvi; // negate nv[i] to denote i in Lk | |
| 546 | + Ci[pk2++] = i; // place i in Lk | |
| 547 | + if (next[i] != -1) | |
| 548 | + last[next[i]] = last[i]; | |
| 549 | + | |
| 550 | + // remove i from degree list | |
| 551 | + if (last[i] != -1) | |
| 552 | + next[last[i]] = next[i]; | |
| 553 | + else | |
| 554 | + head[degree[i]] = next[i]; | |
| 555 | + } // endfor: k2 | |
| 556 | + | |
| 557 | + // ... | |
| 558 | + if (e != k) { | |
| 559 | + Cp[e] = CS_FLIP (k); // absorb e into k | |
| 560 | + w[e] = 0; // e is now a dead element | |
| 561 | + } | |
| 562 | + } // endfor: k1 | |
| 563 | + | |
| 564 | + if (elenk != 0) cnz = pk2; // Ci [cnz...nzmax] is free | |
| 565 | + degree[k] = dk; // external degree of k - |Lk\i| | |
| 566 | + Cp[k] = pk1; // element k is in Ci[pk1..pk2-1] | |
| 567 | + len[k] = pk2 - pk1; | |
| 568 | + elen[k] = -2; // k is now an element | |
| 569 | + | |
| 570 | + // Clear w if necessary | |
| 571 | + mark = cs_wclear(mark, lemax, w, n); | |
| 572 | + | |
| 573 | + // Scan 1: Find set differences |Le\Lk| | |
| 574 | + for (pk = pk1 ; pk < pk2 ; pk++) { | |
| 575 | + i = Ci [pk]; | |
| 576 | + if ((eln = elen [i]) <= 0) // skip if elen[i] empty | |
| 577 | + continue; | |
| 578 | + nvi = -nv[i]; // nv [i] was negated | |
| 579 | + wnvi = mark - nvi; | |
| 580 | + | |
| 581 | + // Scan Ei | |
| 582 | + for (p = Cp[i]; p <= Cp[i] + eln - 1; p++) { | |
| 583 | + e = Ci [p] ; | |
| 584 | + if (w[e] >= mark) | |
| 585 | + w[e] -= nvi; // decrement |Le\Lk| | |
| 586 | + else if (w[e] != 0) // ensure e is a live element | |
| 587 | + w[e] = degree[e] + wnvi; // 1st time e seen in scan 1 | |
| 588 | + } | |
| 589 | + } // endfor: scan 1 finished | |
| 590 | + | |
| 591 | + // Scan 2: Degree update | |
| 592 | + for (pk = pk1; pk < pk2; pk++) { | |
| 593 | + i = Ci [pk] ; /* consider node i in Lk */ | |
| 594 | + p1 = Cp [i] ; | |
| 595 | + p2 = p1 + elen [i] - 1 ; | |
| 596 | + pn = p1 ; | |
| 597 | + | |
| 598 | + // Scan Ei | |
| 599 | + for (h = 0, d = 0, p = p1 ; p <= p2 ; p++) { | |
| 600 | + e = Ci [p] ; | |
| 601 | + // If e is an unabsorbed element, then ... | |
| 602 | + if (w [e] != 0) { | |
| 603 | + dext = w [e] - mark ; /* dext = |Le\Lk| */ | |
| 604 | + if (dext > 0) { | |
| 605 | + d += dext ; /* sum up the set differences */ | |
| 606 | + Ci [pn++] = e ; /* keep e in Ei */ | |
| 607 | + h += e ; /* compute the hash of node i */ | |
| 608 | + } | |
| 609 | + else { | |
| 610 | + Cp [e] = CS_FLIP (k) ; /* aggressive absorb. e->k */ | |
| 611 | + w [e] = 0 ; /* e is a dead element */ | |
| 612 | + } | |
| 613 | + } | |
| 614 | + } // endfor: scanned Ei | |
| 615 | + | |
| 616 | + // elen[i] = |Ei| | |
| 617 | + elen [i] = pn - p1 + 1 ; | |
| 618 | + p3 = pn ; | |
| 619 | + p4 = p1 + len [i] ; | |
| 620 | + | |
| 621 | + // Prune edges in Ai | |
| 622 | + for (p = p2 + 1 ; p < p4 ; p++) { | |
| 623 | + j = Ci [p] ; | |
| 624 | + if ((nvj = nv [j]) <= 0) continue ; /* node j dead or in Lk */ | |
| 625 | + d += nvj ; /* degree(i) += |j| */ | |
| 626 | + Ci [pn++] = j ; /* place j in node list of i */ | |
| 627 | + h += j ; /* compute hash for node i */ | |
| 628 | + } | |
| 629 | + | |
| 630 | + // Check for mass elimination | |
| 631 | + if (d == 0) { | |
| 632 | + Cp [i] = CS_FLIP (k) ; /* absorb i into k */ | |
| 633 | + nvi = -nv [i] ; | |
| 634 | + dk -= nvi ; /* |Lk| -= |i| */ | |
| 635 | + nvk += nvi ; /* |k| += nv[i] */ | |
| 636 | + nel += nvi ; | |
| 637 | + nv [i] = 0 ; | |
| 638 | + elen [i] = -1 ; /* node i is dead */ | |
| 639 | + } | |
| 640 | + else { | |
| 641 | + degree [i] = CS_MIN (degree [i], d) ; /* update degree(i) */ | |
| 642 | + Ci [pn] = Ci [p3] ; /* move first node to end */ | |
| 643 | + Ci [p3] = Ci [p1] ; /* move 1st el. to end of Ei */ | |
| 644 | + Ci [p1] = k ; /* add k as 1st element in of Ei */ | |
| 645 | + len [i] = pn - p1 + 1 ; /* new len of adj. list of node i */ | |
| 646 | + h %= n ; /* finalize hash of i */ | |
| 647 | + next [i] = hhead [h] ; /* place i in hash bucket */ | |
| 648 | + hhead [h] = i ; | |
| 649 | + last [i] = h ; /* save hash of i in last[i] */ | |
| 650 | + } | |
| 651 | + } // endfor: scan 2 is done | |
| 652 | + | |
| 653 | + // finalize |Lk| | |
| 654 | + degree[k] = dk ; | |
| 655 | + lemax = CS_MAX(lemax, dk); | |
| 656 | + | |
| 657 | + // Clear w | |
| 658 | + mark = cs_wclear(mark+lemax, lemax, w, n); | |
| 659 | + | |
| 660 | + // Supernode detection | |
| 661 | + for (pk = pk1 ; pk < pk2 ; pk++) { | |
| 662 | + i = Ci [pk] ; | |
| 663 | + if (nv [i] >= 0) continue ; /* skip if i is dead */ | |
| 664 | + h = last [i] ; /* scan hash bucket of node i */ | |
| 665 | + i = hhead [h] ; | |
| 666 | + hhead [h] = -1 ; /* hash bucket will be empty */ | |
| 667 | + | |
| 668 | + // ... | |
| 669 | + for ( ; i != -1 && next [i] != -1 ; i = next [i], mark++) { | |
| 670 | + ln = len [i] ; | |
| 671 | + eln = elen [i] ; | |
| 672 | + for (p = Cp [i]+1 ; p <= Cp [i] + ln-1 ; p++) w [Ci [p]] = mark; | |
| 673 | + jlast = i ; | |
| 674 | + | |
| 675 | + // Compare i with all j | |
| 676 | + for (j = next [i] ; j != -1 ; ) { | |
| 677 | + ok = (len [j] == ln) && (elen [j] == eln) ; | |
| 678 | + for (p = Cp [j] + 1 ; ok && p <= Cp [j] + ln - 1 ; p++) { | |
| 679 | + if (w [Ci [p]] != mark) ok = 0 ; /* compare i and j*/ | |
| 680 | + } | |
| 681 | + | |
| 682 | + // i and j are identical | |
| 683 | + if (ok) { | |
| 684 | + Cp[j] = CS_FLIP(i); /* absorb j into i */ | |
| 685 | + nv[i] += nv[j]; | |
| 686 | + nv[j] = 0; | |
| 687 | + elen[j] = -1; /* node j is dead */ | |
| 688 | + j = next[j]; /* delete j from hash bucket */ | |
| 689 | + next[jlast] = j; | |
| 690 | + } | |
| 691 | + // j and i are different | |
| 692 | + else { | |
| 693 | + jlast = j; | |
| 694 | + j = next[j]; | |
| 695 | + } | |
| 696 | + } // endfor: comparison of i with all j | |
| 697 | + } // | |
| 698 | + } // endfor: supernode detection | |
| 699 | + | |
| 700 | + // Finalize new element | |
| 701 | + for (p = pk1, pk = pk1 ; pk < pk2 ; pk++) /* finalize Lk */ | |
| 702 | + { | |
| 703 | + i = Ci [pk] ; | |
| 704 | + if ((nvi = -nv [i]) <= 0) continue ;/* skip if i is dead */ | |
| 705 | + nv [i] = nvi ; /* restore nv[i] */ | |
| 706 | + d = degree [i] + dk - nvi ; /* compute external degree(i) */ | |
| 707 | + d = CS_MIN (d, n - nel - nvi) ; | |
| 708 | + if (head [d] != -1) last [head [d]] = i ; | |
| 709 | + next [i] = head [d] ; /* put i back in degree list */ | |
| 710 | + last [i] = -1 ; | |
| 711 | + head [d] = i ; | |
| 712 | + mindeg = CS_MIN (mindeg, d) ; /* find new minimum degree */ | |
| 713 | + degree [i] = d ; | |
| 714 | + Ci [p++] = i ; /* place i in Lk */ | |
| 715 | + } | |
| 716 | + nv [k] = nvk ; /* # nodes absorbed into k */ | |
| 717 | + if ((len [k] = p-pk1) == 0) /* length of adj list of element k*/ | |
| 718 | + { | |
| 719 | + Cp [k] = -1 ; /* k is a root of the tree */ | |
| 720 | + w [k] = 0 ; /* k is now a dead element */ | |
| 721 | + } | |
| 722 | + if (elenk != 0) cnz = p ; /* free unused space in Lk */ | |
| 723 | + } | |
| 724 | + | |
| 725 | + // Postordering | |
| 726 | + for (i = 0 ; i < n ; i++) Cp [i] = CS_FLIP (Cp [i]) ;/* fix assembly tree */ | |
| 727 | + for (j = 0 ; j <= n ; j++) head [j] = -1 ; | |
| 728 | + for (j = n ; j >= 0 ; j--) /* place unordered nodes in lists */ | |
| 729 | + { | |
| 730 | + if (nv [j] > 0) continue ; /* skip if j is an element */ | |
| 731 | + next [j] = head [Cp [j]] ; /* place j in list of its parent */ | |
| 732 | + head [Cp [j]] = j ; | |
| 733 | + } | |
| 734 | + for (e = n ; e >= 0 ; e--) /* place elements in lists */ | |
| 735 | + { | |
| 736 | + if (nv [e] <= 0) continue ; /* skip unless e is an element */ | |
| 737 | + if (Cp [e] != -1) | |
| 738 | + { | |
| 739 | + next [e] = head [Cp [e]] ; /* place e in list of its parent */ | |
| 740 | + head [Cp [e]] = e ; | |
| 741 | + } | |
| 742 | + } | |
| 743 | + | |
| 744 | + // ====================================================================== | |
| 745 | + // Step 5: Postorder the assembly tree | |
| 746 | + // ====================================================================== | |
| 747 | + | |
| 748 | + // Debug | |
| 749 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 750 | + cout << " Step 5: Postorder the assembly tree" << endl; | |
| 751 | + #endif | |
| 752 | + | |
| 753 | + // Postorder the assembly tree | |
| 754 | + for (k = 0, i = 0 ; i <= n ; i++) { | |
| 755 | + if (Cp [i] == -1) | |
| 756 | + k = cs_tdfs(i, k, head, next, P, w); | |
| 757 | + } | |
| 758 | + | |
| 759 | + // Free workspace | |
| 760 | + delete [] wrk_int; | |
| 761 | + | |
| 762 | + // Debug | |
| 763 | + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) | |
| 764 | + cout << " Permutation:" << endl; | |
| 765 | + for (i = 0; i < n; ++i) | |
| 766 | + cout << " " << P[i]; | |
| 767 | + cout << endl; | |
| 768 | + cout << "GSparseSymbolic::cs_amd finished" << endl; | |
| 769 | + #endif | |
| 770 | + | |
| 771 | + // Return result | |
| 772 | + return (P); | |
| 773 | +} | |
| 774 | + | |
| 775 | + | |
| 776 | +/*************************************************************************** | |
| 777 | + * cs_counts * | |
| 778 | + * ----------------------------------------------------------------------- * | |
| 779 | + * Column counts of LL'=A or LL'=A'A, given parent & post ordering * | |
| 780 | + * ----------------------------------------------------------------------- * | |
| 781 | + * Input: A Sparse matrix A * | |
| 782 | + * parent[0..n-1] parent array * | |
| 783 | + * post[0..n-1] post ordering array * | |
| 784 | + * ata 0: count LL'=A, 1: count LL'=A'A * | |
| 785 | + * Output: p[0..n] integer array of n+1 elements * | |
| 786 | + ***************************************************************************/ | |
| 787 | +int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, | |
| 788 | + const int* post, int ata) | |
| 789 | +{ | |
| 790 | + // Declare loop variables | |
| 791 | + int i, j, k, J, p, q, jleaf; | |
| 792 | + | |
| 793 | + // Return NULL pointer if input arrays are NULL or sparse matrix is | |
| 794 | + // empty | |
| 795 | + if (!parent || !post) return (NULL); | |
| 796 | + | |
| 797 | + // Assign input matrix attributes | |
| 798 | + int m = A->m_rows; | |
| 799 | + int n = A->m_cols; | |
| 800 | + | |
| 801 | + // Allocate result | |
| 802 | + int* colcount = new int[n]; | |
| 803 | + if (colcount == NULL) | |
| 804 | + throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)", | |
| 805 | + n); | |
| 806 | + int* delta = colcount; | |
| 807 | + | |
| 808 | + // Allocate workspace | |
| 809 | + int wrk_size = 4*n + (ata ? (n+m+1) : 0); | |
| 810 | + int* wrk_int = new int[wrk_size]; | |
| 811 | + if (wrk_int == NULL) | |
| 812 | + throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)", | |
| 813 | + wrk_size); | |
| 814 | + | |
| 815 | + // Get transpose of A: AT = A' | |
| 816 | + GSparseMatrix AT = A->cs_transpose(A,0); | |
| 817 | + | |
| 818 | + // Set-up pointers to workspace | |
| 819 | + int* ancestor = wrk_int; | |
| 820 | + int* maxfirst = wrk_int + n; | |
| 821 | + int* prevleaf = wrk_int + 2*n; | |
| 822 | + int* first = wrk_int + 3*n; | |
| 823 | + | |
| 824 | + // Clear workspace | |
| 825 | + for (k = 0; k < wrk_size; k++) | |
| 826 | + wrk_int[k] = -1; | |
| 827 | + | |
| 828 | + // Find first j | |
| 829 | + for (k = 0; k < n; k++) { | |
| 830 | + j = post[k]; | |
| 831 | + delta[j] = (first[j] == -1) ? 1 : 0; // delta[j]=1 if j is a leaf | |
| 832 | + for ( ; j != -1 && first[j] == -1; j = parent[j]) first[j] = k; | |
| 833 | + } | |
| 834 | + | |
| 835 | + // Assign output matrix attributes | |
| 836 | + int* ATp = AT.m_colstart; | |
| 837 | + int* ATi = AT.m_rowinx; | |
| 838 | + | |
| 839 | + // Initialise | |
| 840 | + int* head = NULL; | |
| 841 | + int* next = NULL; | |
| 842 | + if (ata) init_ata(&AT, post, wrk_int, &head, &next); | |
| 843 | + | |
| 844 | + // Each node in its own set | |
| 845 | + for (i = 0; i < n; i++) ancestor[i] = i; | |
| 846 | + | |
| 847 | + // Loop over all columns of matrix A (or rows of matrix AT) | |
| 848 | + #define HEAD(k,j) (ata ? head [k] : j) | |
| 849 | + #define NEXT(J) (ata ? next [J] : -1) | |
| 850 | + for (k = 0; k < n; k++) { | |
| 851 | + j = post[k]; // j is the kth node in postordered etree | |
| 852 | + if (parent[j] != -1) delta[parent[j]]--; // j is not a root | |
| 853 | + for (J = HEAD(k,j); J != -1; J = NEXT(J)) { // J=j for LL'=A case | |
| 854 | + | |
| 855 | + // Loop over all non-zero elements in column J | |
| 856 | + for (p = ATp[J]; p < ATp[J+1]; p++) { | |
| 857 | + i = ATi [p] ; | |
| 858 | + q = cs_leaf(i, j, first, maxfirst, prevleaf, ancestor, &jleaf); | |
| 859 | + if (jleaf >= 1) delta [j]++ ; /* A(i,j) is in skeleton */ | |
| 860 | + if (jleaf == 2) delta [q]-- ; /* account for overlap in q */ | |
| 861 | + } | |
| 862 | + } | |
| 863 | + if (parent[j] != -1) ancestor[j] = parent[j]; | |
| 864 | + } | |
| 865 | + | |
| 866 | + // Sum up delta's of each child | |
| 867 | + for (j = 0; j < n; j++) { | |
| 868 | + if (parent[j] != -1) colcount[parent[j]] += colcount[j]; | |
| 869 | + } | |
| 870 | + | |
| 871 | + // Free workspace | |
| 872 | + delete [] wrk_int; | |
| 873 | + | |
| 874 | + // Return result | |
| 875 | + return (colcount); | |
| 876 | +} | |
| 877 | + | |
| 878 | + | |
| 879 | +/*************************************************************************** | |
| 880 | + * cs_etree * | |
| 881 | + * ----------------------------------------------------------------------- * | |
| 882 | + * Compute the etree of A using triu(A), or A'A without forming A'A * | |
| 883 | + * ----------------------------------------------------------------------- * | |
| 884 | + * Input: A Sparse matrix A * | |
| 885 | + * ata flag * | |
| 886 | + * Output: etree(A) Evaluation tree of matrix A * | |
| 887 | + ***************************************************************************/ | |
| 888 | +int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata) | |
| 889 | +{ | |
| 890 | + // Declare loop variables | |
| 891 | + int i, k, p; | |
| 892 | + | |
| 893 | + // Assign matrix attributes | |
| 894 | + int m = A->m_rows; | |
| 895 | + int n = A->m_cols; | |
| 896 | + | |
| 897 | + // Allocate result array | |
| 898 | + int* parent = new int[n]; | |
| 899 | + if (parent == NULL) | |
| 900 | + throw mem_alloc("GSparseSymbolic::cs_etree(GSparseMatrix*, int)", n); | |
| 901 | + | |
| 902 | + // Allocate workspace | |
| 903 | + int wrk_size = n + (ata ? m : 0); | |
| 904 | + int* wrk_int = new int[wrk_size]; | |
| 905 | + if (wrk_int == NULL) | |
| 906 | + throw mem_alloc("GSparseSymbolic::cs_etree(GSparseMatrix*, int)", wrk_size); | |
| 907 | + | |
| 908 | + // Set-up pointers to workspace. If 'ata=1' then we use also a prev array | |
| 909 | + int* ancestor = wrk_int; | |
| 910 | + int* prev = wrk_int + n; | |
| 911 | + | |
| 912 | + // If 'prev' is requested, initialise array with -1 | |
| 913 | + if (ata) for (i = 0; i < m ; ++i) prev[i] = -1; | |
| 914 | + | |
| 915 | + // Loop over all nodes (columns) | |
| 916 | + for (k = 0; k < n; ++k) { | |
| 917 | + | |
| 918 | + // Initialise node k to having no parent and no ancestor | |
| 919 | + parent[k] = -1; // node k has no parent yet | |
| 920 | + ancestor[k] = -1; // nor does k have an ancestor | |
| 921 | + | |
| 922 | + // Loop over all elements in column k | |
| 923 | + for (p = A->m_colstart[k]; p < A->m_colstart[k+1]; ++p) { | |
| 924 | + | |
| 925 | + // Get element index | |
| 926 | + i = ata ? (prev[A->m_rowinx[p]]) : (A->m_rowinx[p]); | |
| 927 | + | |
| 928 | + // Traverse from i to k | |
| 929 | + int inext; | |
| 930 | + for ( ; i != -1 && i < k; i = inext) { | |
| 931 | + inext = ancestor[i]; // inext = ancestor of i | |
| 932 | + ancestor[i] = k; // path compression | |
| 933 | + if (inext == -1) parent[i] = k; // no ancestor, parent is k | |
| 934 | + } | |
| 935 | + if (ata) prev[A->m_rowinx[p]] = k; | |
| 936 | + } | |
| 937 | + } | |
| 938 | + | |
| 939 | + // Free workspace | |
| 940 | + delete [] wrk_int; | |
| 941 | + | |
| 942 | + // Return result | |
| 943 | + return (parent); | |
| 944 | + | |
| 945 | +} | |
| 946 | + | |
| 947 | + | |
| 948 | +/*************************************************************************** | |
| 949 | + * cs_fkeep * | |
| 950 | + * ----------------------------------------------------------------------- * | |
| 951 | + * Drop entries for which fkeep(A(i,j)) is false. Return the number of * | |
| 952 | + * non-zero elements if ok, otherwise return -1. * | |
| 953 | + * ----------------------------------------------------------------------- * | |
| 954 | + * Input: A Sparse matrix * | |
| 955 | + * fkeep Screening function * | |
| 956 | + * other Other function * | |
| 957 | + * Output: result 0..n-1 if ok, -1 in case of error * | |
| 958 | + ***************************************************************************/ | |
| 959 | +int GSparseSymbolic::cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), | |
| 960 | + void* other) | |
| 961 | +{ | |
| 962 | + // Return error if some of the input pointers is invalid | |
| 963 | + if (!A || !fkeep) return (-1); | |
| 964 | + | |
| 965 | + // Declare | |
| 966 | + int j, p, nz = 0; | |
| 967 | + | |
| 968 | + // Assign matrix attributes | |
| 969 | + int n = A->m_cols; | |
| 970 | + int* Ap = A->m_colstart; | |
| 971 | + int* Ai = A->m_rowinx; | |
| 972 | + double* Ax = A->m_data; | |
| 973 | + | |
| 974 | + // Loop over all columns | |
| 975 | + for (j = 0; j < n; j++) { | |
| 976 | + p = Ap[j]; // get current location of col j | |
| 977 | + Ap[j] = nz; // record new location of col j | |
| 978 | + for ( ; p < Ap[j+1] ; p++) { | |
| 979 | + if (fkeep(Ai[p], j, Ax ? Ax[p] : 1, other)) { | |
| 980 | + if (Ax) Ax[nz] = Ax[p]; // keep A(i,j) | |
| 981 | + Ai[nz++] = Ai[p] ; | |
| 982 | + } | |
| 983 | + } | |
| 984 | + } | |
| 985 | + | |
| 986 | + // Finalise A | |
| 987 | + Ap[n] = nz; | |
| 988 | + | |
| 989 | + // Remove extra space from A | |
| 990 | +// cs_sprealloc (A, 0) ; /* remove extra space from A */ | |
| 991 | + | |
| 992 | + // Return number of non-zero elements | |
| 993 | + return (nz) ; | |
| 994 | +} | |
| 995 | + | |
| 996 | + | |
| 997 | +/*************************************************************************** | |
| 998 | + * cs_leaf * | |
| 999 | + * ----------------------------------------------------------------------- * | |
| 1000 | + * Consider A(i,j), node j in ith row subtree and return lca(jprev,j) * | |
| 1001 | + * ----------------------------------------------------------------------- * | |
| 1002 | + * Input: i row to consider * | |
| 1003 | + * j column to consider * | |
| 1004 | + * first[0..n-1] ... * | |
| 1005 | + * maxfirst[0..n-1] ... * | |
| 1006 | + * prevleaf[0..n-1] ... * | |
| 1007 | + * ancestor[0..n-1] ... * | |
| 1008 | + * Output: q ... * | |
| 1009 | + * jleaf ... * | |
| 1010 | + ***************************************************************************/ | |
| 1011 | +int GSparseSymbolic::cs_leaf(int i, int j, const int *first, int *maxfirst, | |
| 1012 | + int *prevleaf, int *ancestor, int *jleaf) | |
| 1013 | +{ | |
| 1014 | + // If one of the input pointers is invalid then return -1 | |
| 1015 | + if (!first || !maxfirst || !prevleaf || !ancestor || !jleaf) return (-1); | |
| 1016 | + | |
| 1017 | + // Declare loop variables | |
| 1018 | + int q, s, sparent; | |
| 1019 | + | |
| 1020 | + // ... | |
| 1021 | + *jleaf = 0 ; | |
| 1022 | + | |
| 1023 | + // If j is not a leaf then return -1 | |
| 1024 | + if (i <= j || first[j] <= maxfirst[i]) return (-1); | |
| 1025 | + | |
| 1026 | + // Update max first[j] seen so far | |
| 1027 | + maxfirst[i] = first[j]; | |
| 1028 | + | |
| 1029 | + // jprev = previous leaf of ith subtree | |
| 1030 | + int jprev = prevleaf[i]; | |
| 1031 | + prevleaf[i] = j; | |
| 1032 | + | |
| 1033 | + // j is first or subsequent leaf | |
| 1034 | + *jleaf = (jprev == -1) ? 1: 2; | |
| 1035 | + | |
| 1036 | + // If j is 1st leaf then q is the root of ith subtree | |
| 1037 | + if (*jleaf == 1) return (i); | |
| 1038 | + | |
| 1039 | + // ... | |
| 1040 | + for (q = jprev; q != ancestor[q]; q = ancestor[q]) ; | |
| 1041 | + | |
| 1042 | + // ... | |
| 1043 | + for (s = jprev; s != q; s = sparent) { | |
| 1044 | + sparent = ancestor[s]; // path compression | |
| 1045 | + ancestor[s] = q; | |
| 1046 | + } | |
| 1047 | + | |
| 1048 | + // Return least common ancester (jprev,j) | |
| 1049 | + return (q); | |
| 1050 | +} | |
| 1051 | + | |
| 1052 | + | |
| 1053 | +/*************************************************************************** | |
| 1054 | + * cs_pinv * | |
| 1055 | + * ----------------------------------------------------------------------- * | |
| 1056 | + * Inverts the permutation p[0..n-1] * | |
| 1057 | + * ----------------------------------------------------------------------- * | |
| 1058 | + * Input: p[0..n-1] integer array of n elements (NULL denotres ID) * | |
| 1059 | + * Output: pinv[0..n-1] pinv[0..n-1] = p[n-1..0] * | |
| 1060 | + ***************************************************************************/ | |
| 1061 | +int* GSparseSymbolic::cs_pinv(int const *p, int n) | |
| 1062 | +{ | |
| 1063 | + // Return NULL pointer if input pointer is NULL. This denotes identity | |
| 1064 | + if (!p || n < 1) return (NULL); | |
| 1065 | + | |
| 1066 | + // Allocate result array | |
| 1067 | + int* pinv = new int[n]; | |
| 1068 | + if (pinv == NULL) | |
| 1069 | + throw mem_alloc("GSparseSymbolic::cs_pinv", n); | |
| 1070 | + | |
| 1071 | + // Invert the permutation | |
| 1072 | + for (int k = 0; k < n; ++k) | |
| 1073 | + pinv[p[k]] = k; | |
| 1074 | + | |
| 1075 | + // Return result | |
| 1076 | + return (pinv); | |
| 1077 | +} | |
| 1078 | + | |
| 1079 | + | |
| 1080 | +/*************************************************************************** | |
| 1081 | + * cs_post * | |
| 1082 | + * ----------------------------------------------------------------------- * | |
| 1083 | + * Post order a forest * | |
| 1084 | + * ----------------------------------------------------------------------- * | |
| 1085 | + * Input: parent[0..n-1] integer array of n elements * | |
| 1086 | + * Output: post[0..n-1] ... * | |
| 1087 | + ***************************************************************************/ | |
| 1088 | +int* GSparseSymbolic::cs_post(const int* parent, int n) | |
| 1089 | +{ | |
| 1090 | + // Return NULL pointer if input pointer is NULL | |
| 1091 | + if (!parent || n < 1) return (NULL); | |
| 1092 | + | |
| 1093 | + // Allocate result array | |
| 1094 | + int* post = new int[n]; | |
| 1095 | + if (post == NULL) | |
| 1096 | + throw mem_alloc("GSparseSymbolic::cs_post(const int*, int)", n); | |
| 1097 | + | |
| 1098 | + // Allocate workspace | |
| 1099 | + int wrk_size = 3 * n; | |
| 1100 | + int* wrk_int = new int[wrk_size]; | |
| 1101 | + if (wrk_int == NULL) | |
| 1102 | + throw mem_alloc("GSparseSymbolic::cs_post(const int*, int)", wrk_size); | |
| 1103 | + | |
| 1104 | + // Set-up pointers to workspace | |
| 1105 | + int* head = wrk_int; | |
| 1106 | + int* next = wrk_int + n; | |
| 1107 | + int* stack = wrk_int + 2*n; // Working array for 'cs_tdfs' function | |
| 1108 | + | |
| 1109 | + // Declare and initialise loop variables | |
| 1110 | + int j, k = 0; | |
| 1111 | + | |
| 1112 | + // Empty linked list | |
| 1113 | + for (j = 0 ; j < n ; j++) head[j] = -1; | |
| 1114 | + | |
| 1115 | + // Traverse nodes in reverse order to build a linked list 'head' | |
| 1116 | + for (j = n-1; j >= 0; j--) { | |
| 1117 | + | |
| 1118 | + // Skip if j is a root | |
| 1119 | + if (parent[j] == -1) continue; | |
| 1120 | + | |
| 1121 | + // Add j to list of its parent | |
| 1122 | + next[j] = head[parent[j]]; | |
| 1123 | + head[parent[j]] = j; | |
| 1124 | + } | |
| 1125 | + | |
| 1126 | + // Traverse nodes | |
| 1127 | + for (j = 0 ; j < n ; j++) { | |
| 1128 | + | |
| 1129 | + // Skip if j is not a root | |
| 1130 | + if (parent[j] != -1) continue; | |
| 1131 | + | |
| 1132 | + // Depth-first search and postorder of a tree rooted at node j | |
| 1133 | + k = cs_tdfs(j, k, head, next, post, stack); | |
| 1134 | + } | |
| 1135 | + | |
| 1136 | + // Free workspace | |
| 1137 | + delete [] wrk_int; | |
| 1138 | + | |
| 1139 | + // Return result | |
| 1140 | + return (post); | |
| 1141 | + | |
| 1142 | +} | |
| 1143 | + | |
| 1144 | + | |
| 1145 | +/*************************************************************************** | |
| 1146 | + * cs_symperm * | |
| 1147 | + * ----------------------------------------------------------------------- * | |
| 1148 | + * C = A(p,p) where A and C are symmetric the upper part stored. * | |
| 1149 | + * pinv not p * | |
| 1150 | + * ----------------------------------------------------------------------- * | |
| 1151 | + * Input: A Sparse matrix * | |
| 1152 | + * pinv pinv[0..n-1] * | |
| 1153 | + * values =1 allocate memory for values (NOT USED) * | |
| 1154 | + * Output: C Sparse matrix * | |
| 1155 | + ***************************************************************************/ | |
| 1156 | +GSparseMatrix GSparseSymbolic::cs_symperm(GSparseMatrix* A, const int* pinv, | |
| 1157 | + int values) const | |
| 1158 | +{ | |
| 1159 | + // Declare loop variables | |
| 1160 | + int i, j, p, q, i2, j2; | |
| 1161 | + | |
| 1162 | + // Assign matrix attributes | |
| 1163 | + int n = A->m_cols; | |
| 1164 | + int* Ap = A->m_colstart; | |
| 1165 | + int* Ai = A->m_rowinx; | |
| 1166 | + double* Ax = A->m_data; | |
| 1167 | + | |
| 1168 | + // Allocate result matrix | |
| 1169 | + GSparseMatrix C(n, n, Ap[n]); | |
| 1170 | + | |
| 1171 | + // Allocate and initialise workspace | |
| 1172 | + int wrk_size = n; | |
| 1173 | + int* wrk_int = new int[wrk_size]; | |
| 1174 | + if (wrk_int == NULL) | |
| 1175 | + throw mem_alloc("GSparseSymbolic::cs_symperm(GSparseMatrix*, const int*, int", | |
| 1176 | + wrk_size); | |
| 1177 | + for (i = 0; i < wrk_size; ++i) | |
| 1178 | + wrk_int[i] = 0; | |
| 1179 | + | |
| 1180 | + // Assign result matriix attributes | |
| 1181 | + int* Cp = C.m_colstart; | |
| 1182 | + int* Ci = C.m_rowinx; | |
| 1183 | + double* Cx = C.m_data; | |
| 1184 | + | |
| 1185 | + // Count entries in each column of C | |
| 1186 | + for (j = 0; j < n; j++) { | |
| 1187 | + | |
| 1188 | + // Column j of A is column j2 of C | |
| 1189 | + j2 = pinv ? pinv[j] : j; | |
| 1190 | + | |
| 1191 | + // Loop over entries in column j | |
| 1192 | + for (p = Ap[j]; p < Ap[j+1]; p++) { | |
| 1193 | + i = Ai [p]; | |
| 1194 | + if (i > j) continue; // skip lower triangular part of A | |
| 1195 | + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C | |
| 1196 | + wrk_int[CS_MAX(i2, j2)]++; // column count of C | |
| 1197 | + } | |
| 1198 | + } | |
| 1199 | + | |
| 1200 | + // Compute column pointers of C | |
| 1201 | + cs_cumsum(Cp, wrk_int, n); | |
| 1202 | + | |
| 1203 | + // Loop over all columns of A | |
| 1204 | + for (j = 0 ; j < n ; j++) { | |
| 1205 | + | |
| 1206 | + // Column j of A is column j2 of C | |
| 1207 | + j2 = pinv ? pinv[j] : j; | |
| 1208 | + | |
| 1209 | + // Loop over entries in column j | |
| 1210 | + for (p = Ap[j]; p < Ap[j+1]; p++) { | |
| 1211 | + i = Ai [p] ; | |
| 1212 | + if (i > j) continue; // skip lower triangular part of A | |
| 1213 | + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C | |
| 1214 | + Ci[q = wrk_int[CS_MAX(i2,j2)]++] = CS_MIN(i2,j2); | |
| 1215 | + Cx[q] = Ax[p]; | |
| 1216 | + } | |
| 1217 | + } | |
| 1218 | + | |
| 1219 | + // Free workspace | |
| 1220 | + delete [] wrk_int; | |
| 1221 | + | |
| 1222 | + // Return result | |
| 1223 | + return (C); | |
| 1224 | + | |
| 1225 | +} | |
| 1226 | + | |
| 1227 | + | |
| 1228 | +/*************************************************************************** | |
| 1229 | + * cs_tdfs * | |
| 1230 | + * ----------------------------------------------------------------------- * | |
| 1231 | + * Depth-first search and postorder of a tree rooted at node j * | |
| 1232 | + * ----------------------------------------------------------------------- * | |
| 1233 | + * Input: j Node of tree root * | |
| 1234 | + * k ... * | |
| 1235 | + * head head[0..n-1] linked list (updated) * | |
| 1236 | + * next next[0..n-1] linked list info * | |
| 1237 | + * post post[0..n-1] array (updated) * | |
| 1238 | + * stack stack[0..n-1] working array (updated) * | |
| 1239 | + * Output: k Update of k * | |
| 1240 | + ***************************************************************************/ | |
| 1241 | +int GSparseSymbolic::cs_tdfs(int j, int k, int* head, const int* next, | |
| 1242 | + int* post, int* stack) | |
| 1243 | +{ | |
| 1244 | + // Return -1 if one of the array pointers is NULL | |
| 1245 | + if (!head || !next || !post || !stack) return (-1); | |
| 1246 | + | |
| 1247 | + // Decrare | |
| 1248 | + int i, p; | |
| 1249 | + | |
| 1250 | + // Place j on the first position of the stack | |
| 1251 | + stack[0] = j; | |
| 1252 | + | |
| 1253 | + // Loop while stack is not empty | |
| 1254 | + int top = 0; | |
| 1255 | + while (top >= 0) { | |
| 1256 | + p = stack[top]; // p = top of stack | |
| 1257 | + i = head[p]; // i = youngest child of p | |
| 1258 | + if (i == -1) { | |
| 1259 | + top--; // p has no unordered children left | |
| 1260 | + post[k++] = p; // node p is the kth postordered node | |
| 1261 | + } | |
| 1262 | + else { | |
| 1263 | + head[p] = next[i]; // remove i from children of p | |
| 1264 | + stack[++top] = i; // start depth-first search on child node i | |
| 1265 | + } | |
| 1266 | + } | |
| 1267 | + | |
| 1268 | + // Return result | |
| 1269 | + return (k) ; | |
| 1270 | +} | |
| 1271 | + | |
| 1272 | + | |
| 1273 | +/*========================================================================== | |
| 1274 | + = = | |
| 1275 | + = GSparseSymbolic static member functions = | |
| 1276 | + = = | |
| 1277 | + ==========================================================================*/ | |
| 1278 | + | |
| 1279 | +/*************************************************************************** | |
| 1280 | + * init_ata * | |
| 1281 | + * ----------------------------------------------------------------------- * | |
| 1282 | + * Initialise A'A. * | |
| 1283 | + * Note that the returned pointers 'head' and 'info' point into the * | |
| 1284 | + * 'wrk_int' workspace array. * | |
| 1285 | + * ----------------------------------------------------------------------- * | |
| 1286 | + * Input: AT Sparse matrix A' * | |
| 1287 | + * post ... * | |
| 1288 | + * wrk_int Workspace * | |
| 1289 | + * head pointer to head[0..n-1] linked list * | |
| 1290 | + * next pointer to next[0..n-1] linked list info * | |
| 1291 | + * Output: - - * | |
| 1292 | + ***************************************************************************/ | |
| 1293 | +void GSparseSymbolic::init_ata(GSparseMatrix* AT, const int* post, | |
| 1294 | + int* wrk_int, int** head, int** next) | |
| 1295 | +{ | |
| 1296 | + // Declare loop variables | |
| 1297 | + int i, k, p; | |
| 1298 | + | |
| 1299 | + // Assign matrix attributes | |
| 1300 | + int m = AT->m_cols; | |
| 1301 | + int n = AT->m_rows; | |
| 1302 | + int* ATp = AT->m_colstart; | |
| 1303 | + int* ATi = AT->m_rowinx; | |
| 1304 | + | |
| 1305 | + // Set-up pointers to workspace | |
| 1306 | + *head = wrk_int + 4*n; | |
| 1307 | + *next = wrk_int + 5*n+1; | |
| 1308 | + | |
| 1309 | + // Invert post | |
| 1310 | + for (k = 0 ; k < n ; k++) | |
| 1311 | + wrk_int[post[k]] = k; | |
| 1312 | + | |
| 1313 | + // Loop over columns of AT matrix | |
| 1314 | + for (i = 0 ; i < m ; i++) { | |
| 1315 | + | |
| 1316 | + // Loop over elements in column i of AT matrix | |
| 1317 | + for (k = n, p = ATp[i]; p < ATp[i+1]; p++) | |
| 1318 | + k = CS_MIN(k,wrk_int[ATi[p]]); | |
| 1319 | + | |
| 1320 | + // Place row i in linked list k | |
| 1321 | + (*next)[i] = (*head)[k]; | |
| 1322 | + (*head)[k] = i; | |
| 1323 | + } | |
| 1324 | +} | |
| 1325 | + | |
| 1326 | + | |
| 1327 | +/*************************************************************************** | |
| 1328 | + * cs_diag * | |
| 1329 | + * ----------------------------------------------------------------------- * | |
| 1330 | + * Keep off-diagonal entries and drop diagonal entries. * | |
| 1331 | + * ----------------------------------------------------------------------- * | |
| 1332 | + * Input: i Row index * | |
| 1333 | + * j Column index * | |
| 1334 | + * aij NOT USED * | |
| 1335 | + * other NOT USED * | |
| 1336 | + * Output: diag 0: off-diagonal, 1: diagonal element * | |
| 1337 | + ***************************************************************************/ | |
| 1338 | +int GSparseSymbolic::cs_diag(int i, int j, double aij, void* other) | |
| 1339 | +{ | |
| 1340 | + return (i != j); | |
| 1341 | +} | |
| 1342 | + | |
| 1343 | + | |
| 1344 | +/*************************************************************************** | |
| 1345 | + * cs_wclear * | |
| 1346 | + * ----------------------------------------------------------------------- * | |
| 1347 | + * Clear w array * | |
| 1348 | + * ----------------------------------------------------------------------- * | |
| 1349 | + * Input: mark ... * | |
| 1350 | + * lemax ... * | |
| 1351 | + * w w[0..n-1] working array * | |
| 1352 | + * n Size of the working array * | |
| 1353 | + * Output: mark Update of mark * | |
| 1354 | + * w Cleared w[0..n-1] working array * | |
| 1355 | + ***************************************************************************/ | |
| 1356 | +int GSparseSymbolic::cs_wclear(int mark, int lemax, int* w, int n) | |
| 1357 | +{ | |
| 1358 | + // Declare loop variables | |
| 1359 | + int k; | |
| 1360 | + | |
| 1361 | + // ... | |
| 1362 | + if (mark < 2 || (mark + lemax < 0)) { | |
| 1363 | + for (k = 0; k < n; k++) if (w[k] != 0) w[k] = 1; | |
| 1364 | + mark = 2; | |
| 1365 | + } | |
| 1366 | + | |
| 1367 | + // Return mark. At this point, w[0..n-1] < mark holds | |
| 1368 | + return (mark); | |
| 1369 | +} | |
| 1370 | + | |
| 1371 | + | |
| 1372 | +/*========================================================================== | |
| 1373 | + = = | |
| 1374 | + = GSparseSymbolic friends = | |
| 1375 | + = = | |
| 1376 | + ==========================================================================*/ | |
| 1377 | + | |
| 1378 | +/*************************************************************************** | |
| 1379 | + * Output operator * | |
| 1380 | + ***************************************************************************/ | |
| 1381 | +ostream& operator<< (ostream& os, const GSparseSymbolic& s) | |
| 1382 | +{ | |
| 1383 | + // Put header is stream | |
| 1384 | + os << "=== GSparseSymbolic ==="; | |
| 1385 | + | |
| 1386 | + // Show inverse permutation if it exists | |
| 1387 | + if (s.m_pinv != NULL) { | |
| 1388 | + os << endl << " Inverse permutation (of " << s.m_n_pinv << " elements)" << | |
| 1389 | + endl; | |
| 1390 | + for (int i = 0; i < s.m_n_pinv; ++i) | |
| 1391 | + os << " " << s.m_pinv[i]; | |
| 1392 | + } | |
| 1393 | + | |
| 1394 | + // Show fill reducing column permutation if it exists | |
| 1395 | + if (s.m_q != NULL) { | |
| 1396 | + os << endl << " Fill reducing column permutation (" << s.m_n_cp << | |
| 1397 | + " elements)" << endl; | |
| 1398 | + for (int i = 0; i < s.m_n_cp; ++i) | |
| 1399 | + os << " " << s.m_q[i]; | |
| 1400 | + } | |
| 1401 | + | |
| 1402 | + // Show elimination tree for Cholesky and QR if it exists | |
| 1403 | + if (s.m_parent != NULL) { | |
| 1404 | + os << endl << " Elimination tree (" << s.m_n_parent << " elements)" << | |
| 1405 | + endl; | |
| 1406 | + for (int i = 0; i < s.m_n_parent; ++i) | |
| 1407 | + os << " " << s.m_parent[i]; | |
| 1408 | + } | |
| 1409 | + | |
| 1410 | + // Show column pointers for Cholesky row counts for QR if it exists | |
| 1411 | + if (s.m_cp != NULL) { | |
| 1412 | + os << endl << " Cholesky column pointers/QR row counts (" << s.m_n_cp << | |
| 1413 | + " elements)" << endl; | |
| 1414 | + for (int i = 0; i < s.m_n_cp; ++i) | |
| 1415 | + os << " " << s.m_cp[i]; | |
| 1416 | + } | |
| 1417 | + | |
| 1418 | + // Show leftmost[i] = min(find(A(i,:))) if it exists | |
| 1419 | + if (s.m_leftmost != NULL) { | |
| 1420 | + os << endl << " leftmost[i] = min(find(A(i,:))) (" << s.m_n_leftmost << | |
| 1421 | + " elements)" << endl; | |
| 1422 | + for (int i = 0; i < s.m_n_leftmost; ++i) | |
| 1423 | + os << " " << s.m_leftmost[i]; | |
| 1424 | + } | |
| 1425 | + | |
| 1426 | + // Return output stream | |
| 1427 | + return os; | |
| 1428 | +} | |
| 1429 | + | |
| 1430 | + | |
| 1431 | +/*========================================================================== | |
| 1432 | + = = | |
| 1433 | + = GSparseSymbolic exception classes = | |
| 1434 | + = = | |
| 1435 | + ==========================================================================*/ | |
| 1436 | + | |
| 1437 | +/*************************************************************************** | |
| 1438 | + * Invalid ordering scheme requested * | |
| 1439 | + ***************************************************************************/ | |
| 1440 | +GSparseSymbolic::invalid_order::invalid_order(string origin, int order, | |
| 1441 | + int min_order, int max_order) | |
| 1442 | +{ | |
| 1443 | + m_origin = origin; | |
| 1444 | + ostringstream s_order; | |
| 1445 | + ostringstream s_min_order; | |
| 1446 | + ostringstream s_max_order; | |
| 1447 | + s_order << order; | |
| 1448 | + s_min_order << min_order; | |
| 1449 | + s_max_order << max_order; | |
| 1450 | + m_message = "Invalid ordering type " + s_order.str() + | |
| 1451 | + "requested; must be comprised in [" + s_min_order.str() + | |
| 1452 | + "," + s_max_order.str() + "]"; | |
| 1453 | +} | ... | ... |
src/GSparseSymbolic.hpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * GSparseSymbolic.hpp - sparse matrix symbolic analysis class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + ***************************************************************************/ | |
| 13 | + | |
| 14 | +#ifndef GSPARSESYMBOLIC_HPP | |
| 15 | +#define GSPARSESYMBOLIC_HPP | |
| 16 | + | |
| 17 | +/* __ Includes ___________________________________________________________ */ | |
| 18 | +#include "GException.hpp" | |
| 19 | +#include "GVector.hpp" | |
| 20 | +#include "GMatrix.hpp" | |
| 21 | +#include "GSparseMatrix.hpp" | |
| 22 | + | |
| 23 | +/* __ Namespaces _________________________________________________________ */ | |
| 24 | +using namespace std; | |
| 25 | + | |
| 26 | +/* __ Definitions ________________________________________________________ */ | |
| 27 | + | |
| 28 | +/* __ Enumerators ________________________________________________________ */ | |
| 29 | + | |
| 30 | +/* __ Structures _________________________________________________________ */ | |
| 31 | + | |
| 32 | +/* __ Prototypes _________________________________________________________ */ | |
| 33 | + | |
| 34 | + | |
| 35 | +/*************************************************************************** | |
| 36 | + * GSparseSymbolic class definition * | |
| 37 | + ***************************************************************************/ | |
| 38 | +class GSparseSymbolic { | |
| 39 | + // Friend classes | |
| 40 | + friend class GSparseMatrix; | |
| 41 | + friend class GSparseNumeric; | |
| 42 | + | |
| 43 | + // Binary operator friends | |
| 44 | + | |
| 45 | + // I/O friends | |
| 46 | + friend ostream& operator<< (ostream& os, const GSparseSymbolic& s); | |
| 47 | + | |
| 48 | + // Friend functions | |
| 49 | + | |
| 50 | +public: | |
| 51 | + // Constructors and destructors | |
| 52 | + GSparseSymbolic(); | |
| 53 | +// GSparseSymbolic(const GSparseSymbolic& s) { cout << "would sym to" << endl;} | |
| 54 | + ~GSparseSymbolic(); | |
| 55 | + | |
| 56 | + // Assignment operator | |
| 57 | + GSparseSymbolic& operator= (const GSparseSymbolic& s); | |
| 58 | + | |
| 59 | + // Binary operators | |
| 60 | + | |
| 61 | + // Unary operators | |
| 62 | + | |
| 63 | + // Functions | |
| 64 | + void cholesky_symbolic_analysis(int order, GSparseMatrix& m); | |
| 65 | + | |
| 66 | + // Exception: Invalid ordering scheme | |
| 67 | + class invalid_order : public GException { | |
| 68 | + public: | |
| 69 | + invalid_order(string origin, int order, int min_order, int max_order); | |
| 70 | + }; | |
| 71 | + | |
| 72 | +private: | |
| 73 | + // Functions | |
| 74 | + int* cs_amd (int order, GSparseMatrix* A); | |
| 75 | + int* cs_counts(GSparseMatrix* A, const int* parent, const int* post, int ata); | |
| 76 | + int* cs_etree(GSparseMatrix* A, int ata); | |
| 77 | + int cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), void* other); | |
| 78 | + int cs_leaf(int i, int j, const int* first, int* maxfirst, int* prevleaf, int* ancestor, int* jleaf); | |
| 79 | + int* cs_pinv(int const* p, int n); | |
| 80 | + int* cs_post(const int* parent, int n); | |
| 81 | + GSparseMatrix cs_symperm(GSparseMatrix* A, const int* pinv, int values) const; | |
| 82 | + int cs_tdfs(int j, int k, int* head, const int* next, int* post, int* stack); | |
| 83 | + static void init_ata(GSparseMatrix* AT, const int* post, int* wrk_int, int** head, int** next); | |
| 84 | + static int cs_diag(int i, int j, double aij, void* other); | |
| 85 | + static int cs_wclear(int mark, int lemax, int* w, int n); | |
| 86 | + | |
| 87 | + // Data | |
| 88 | + int* m_pinv; // Inverse row permutation for QR, fill reduce permutation for Cholesky | |
| 89 | + int* m_q; // Fill-reducing column permutation for LU and QR | |
| 90 | + int* m_parent; // elimination tree for Cholesky and QR | |
| 91 | + int* m_cp; // column pointers for Cholesky, row counts for QR | |
| 92 | + int* m_leftmost; // leftmost[i] = min(find(A(i,:))), for QR | |
| 93 | + int m_m2; // # of rows for QR, after adding fictitious rows | |
| 94 | + double m_lnz; // # entries in L for LU or Cholesky; in V for QR | |
| 95 | + double m_unz; // # entries in U for LU; in R for QR | |
| 96 | + int m_n_pinv; // Number of elements in m_pinv | |
| 97 | + int m_n_q; // Number of elements in m_q | |
| 98 | + int m_n_parent; // Number of elements in m_parent | |
| 99 | + int m_n_cp; // Number of elements in m_cp | |
| 100 | + int m_n_leftmost; // Number of elements in m_leftmost | |
| 101 | +}; | |
| 102 | + | |
| 103 | + | |
| 104 | +/*************************************************************************** | |
| 105 | + * Inline members * | |
| 106 | + ***************************************************************************/ | |
| 107 | + | |
| 108 | + | |
| 109 | +/*************************************************************************** | |
| 110 | + * Inline friends * | |
| 111 | + ***************************************************************************/ | |
| 112 | + | |
| 113 | +#endif /* GSPARSESYMBOLIC_HPP */ | ... | ... |
src/GSymMatrix.cpp
| ... | ... | @@ -18,26 +18,34 @@ |
| 18 | 18 | using namespace std; |
| 19 | 19 | |
| 20 | 20 | |
| 21 | +/*========================================================================== | |
| 22 | + = = | |
| 23 | + = GSymMatrix constructors/destructors = | |
| 24 | + = = | |
| 25 | + ==========================================================================*/ | |
| 26 | + | |
| 21 | 27 | /*************************************************************************** |
| 22 | - * GSymMatrix constructor * | |
| 28 | + * GSymMatrix constructor * | |
| 23 | 29 | ***************************************************************************/ |
| 24 | -GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() | |
| 30 | +GSymMatrix::GSymMatrix(int rows, int cols) : GMatrix() | |
| 25 | 31 | { |
| 26 | 32 | // Initialise private members for clean destruction |
| 27 | - m_rows = 0; | |
| 28 | - m_cols = 0; | |
| 29 | - m_elements = 0; | |
| 30 | - m_num_inx = 0; | |
| 31 | - m_data = NULL; | |
| 32 | - m_colstart = NULL; | |
| 33 | - m_inx = NULL; | |
| 33 | + m_rows = 0; | |
| 34 | + m_cols = 0; | |
| 35 | + m_elements = 0; | |
| 36 | + m_num_rowsel = 0; | |
| 37 | + m_num_colsel = 0; | |
| 38 | + m_data = NULL; | |
| 39 | + m_colstart = NULL; | |
| 40 | + m_rowsel = NULL; | |
| 41 | + m_colsel = NULL; | |
| 34 | 42 | |
| 35 | 43 | // Throw exception if number of rows and columns is not identical |
| 36 | 44 | if (rows != cols) |
| 37 | - throw not_sym("GSymMatrix constructor", rows, cols); | |
| 45 | + throw matrix_not_symmetric("GSymMatrix constructor", rows, cols); | |
| 38 | 46 | |
| 39 | 47 | // Determine number of physical elements in matrix |
| 40 | - unsigned elements = rows*(rows+1)/2; | |
| 48 | + int elements = rows*(rows+1)/2; | |
| 41 | 49 | |
| 42 | 50 | // Throw exception if requested matrix size is zero |
| 43 | 51 | if (elements == 0) |
| ... | ... | @@ -46,8 +54,8 @@ GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() |
| 46 | 54 | // Allocate matrix array and column start index array. Throw an exception |
| 47 | 55 | // if allocation failed |
| 48 | 56 | m_data = new double[elements]; |
| 49 | - m_colstart = new unsigned[cols+1]; | |
| 50 | - m_inx = new unsigned[cols]; | |
| 57 | + m_colstart = new int[cols+1]; | |
| 58 | + m_inx = new int[cols]; | |
| 51 | 59 | if (m_data == NULL || m_colstart == NULL || m_inx == NULL) |
| 52 | 60 | throw mem_alloc("GSymMatrix constructor", elements); |
| 53 | 61 | |
| ... | ... | @@ -58,13 +66,16 @@ GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() |
| 58 | 66 | |
| 59 | 67 | // Set-up column start indices |
| 60 | 68 | m_colstart[0] = 0; |
| 61 | - unsigned offset = rows; | |
| 62 | - for (unsigned col = 1; col <= m_cols; ++col) | |
| 69 | + int offset = rows; | |
| 70 | + for (int col = 1; col <= m_cols; ++col) | |
| 63 | 71 | m_colstart[col] = m_colstart[col-1] + offset--; |
| 64 | 72 | |
| 65 | 73 | // Initialise matrix elements to 0.0 |
| 66 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 74 | + for (int i = 0; i < m_elements; ++i) | |
| 67 | 75 | m_data[i] = 0.0; |
| 76 | + | |
| 77 | + // Return | |
| 78 | + return; | |
| 68 | 79 | } |
| 69 | 80 | |
| 70 | 81 | |
| ... | ... | @@ -75,12 +86,16 @@ GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() |
| 75 | 86 | ***************************************************************************/ |
| 76 | 87 | GSymMatrix::GSymMatrix(const GSymMatrix& m) : GMatrix(m) |
| 77 | 88 | { |
| 89 | + // Copy members | |
| 78 | 90 | m_num_inx = m.m_num_inx; |
| 79 | - m_inx = new unsigned[m_cols]; | |
| 91 | + m_inx = new int[m_cols]; | |
| 80 | 92 | if (m_inx == NULL) |
| 81 | 93 | throw mem_alloc("GSymMatrix copy constructor", m_cols); |
| 82 | - for (unsigned i = 0; i < m_cols; ++i) | |
| 94 | + for (int i = 0; i < m_cols; ++i) | |
| 83 | 95 | m_inx[i] = m.m_inx[i]; |
| 96 | + | |
| 97 | + // Return | |
| 98 | + return; | |
| 84 | 99 | } |
| 85 | 100 | |
| 86 | 101 | |
| ... | ... | @@ -92,46 +107,259 @@ GSymMatrix::GSymMatrix(const GSymMatrix& m) : GMatrix(m) |
| 92 | 107 | GSymMatrix::~GSymMatrix() |
| 93 | 108 | { |
| 94 | 109 | // De-allocate only if memory has indeed been allocated by derived class |
| 95 | - if (m_inx != NULL) delete[] m_inx; | |
| 110 | + if (m_inx != NULL) delete [] m_inx; | |
| 111 | + | |
| 112 | + // Return | |
| 113 | + return; | |
| 96 | 114 | } |
| 97 | 115 | |
| 98 | 116 | |
| 117 | +/*========================================================================== | |
| 118 | + = = | |
| 119 | + = GSymMatrix operators = | |
| 120 | + = = | |
| 121 | + ==========================================================================*/ | |
| 122 | + | |
| 99 | 123 | /*************************************************************************** |
| 100 | 124 | * GSymMatrix assignment operator * |
| 101 | 125 | ***************************************************************************/ |
| 102 | 126 | GSymMatrix& GSymMatrix::operator= (const GSymMatrix& m) |
| 103 | 127 | { |
| 128 | + // Execute only if object is not identical | |
| 104 | 129 | if (this != &m) { |
| 130 | + | |
| 131 | + // Invoque base class assignment operator | |
| 105 | 132 | this->GMatrix::operator=(m); |
| 133 | + | |
| 134 | + // De-allocate memory if it has indeed been allocated | |
| 135 | + if (m_inx != NULL) delete [] m_inx; | |
| 136 | + | |
| 137 | + // Copy data members | |
| 106 | 138 | m_num_inx = m.m_num_inx; |
| 107 | - m_inx = new unsigned[m_cols]; | |
| 139 | + | |
| 140 | + // Allocate memory for indices and copy them | |
| 141 | + m_inx = new int[m_cols]; | |
| 108 | 142 | if (m_inx == NULL) |
| 109 | 143 | throw mem_alloc("GSymMatrix assignment operator", m_cols); |
| 110 | - for (unsigned i = 0; i < m_cols; ++i) | |
| 144 | + for (int i = 0; i < m_cols; ++i) | |
| 111 | 145 | m_inx[i] = m.m_inx[i]; |
| 112 | 146 | } |
| 147 | + | |
| 148 | + // Return this object | |
| 149 | + return *this; | |
| 113 | 150 | } |
| 114 | 151 | |
| 115 | 152 | |
| 116 | 153 | /*************************************************************************** |
| 117 | - * GSymMatrix * GSymMatrix multiplication * | |
| 154 | + * Vector multiplication * | |
| 118 | 155 | ***************************************************************************/ |
| 119 | -GSymMatrix GSymMatrix::operator* (const GSymMatrix& m) const | |
| 156 | +GVector GSymMatrix::operator* (const GVector& v) const | |
| 157 | +{ | |
| 158 | + // Raise an exception if the matrix and vector dimensions are not compatible | |
| 159 | + if (m_cols != v.m_num) | |
| 160 | + throw matrix_vector_mismatch("GSymMatrix::operator* (const GVector&)", | |
| 161 | + v.m_num, m_rows, m_cols); | |
| 162 | + | |
| 163 | + // Perform vector multiplication | |
| 164 | + GVector result(m_rows); | |
| 165 | + for (int row = 0; row < m_rows; ++row) { | |
| 166 | + double sum = 0.0; | |
| 167 | + for (int col = 0; col < m_cols; ++col) | |
| 168 | + sum += (*this)(row,col) * v(col); | |
| 169 | + result(row) = sum; | |
| 170 | + } | |
| 171 | + | |
| 172 | + // Return result | |
| 173 | + return result; | |
| 174 | +} | |
| 175 | + | |
| 176 | + | |
| 177 | +/*************************************************************************** | |
| 178 | + * GSymMatrix negation (unary minus operator) * | |
| 179 | + ***************************************************************************/ | |
| 180 | +GSymMatrix GSymMatrix::operator- ( ) const | |
| 181 | +{ | |
| 182 | + // Copy argument into result | |
| 183 | + GSymMatrix result = *this; | |
| 184 | + | |
| 185 | + // Negate result | |
| 186 | + for (int i = 0; i < m_elements; ++i) | |
| 187 | + result.m_data[i] = -result.m_data[i]; | |
| 188 | + | |
| 189 | + // Return result | |
| 190 | + return result; | |
| 191 | +} | |
| 192 | + | |
| 193 | + | |
| 194 | +/*************************************************************************** | |
| 195 | + * Matrix multiplication (unary multiplication operator) * | |
| 196 | + * ----------------------------------------------------------------------- * | |
| 197 | + * Symmetric matrices must have the same dimensions to be multiplied. * | |
| 198 | + ***************************************************************************/ | |
| 199 | +GSymMatrix& GSymMatrix::operator*= (const GSymMatrix& m) | |
| 120 | 200 | { |
| 121 | 201 | // Raise an exception if the matrix dimensions are not compatible |
| 122 | - if (m_cols != m.m_rows) | |
| 123 | - throw GMatrix::dim_mult_mismatch("GSymMatrix multiplication", m_cols, m.m_rows); | |
| 202 | + if (m_cols != m.m_rows || m_rows != m.m_cols) | |
| 203 | + throw matrix_mismatch("GSymMatrix::operator*= (const GSymMatrix&)", | |
| 204 | + m_rows, m_cols, m.m_rows, m.m_cols); | |
| 124 | 205 | |
| 125 | - // Perform matrix multiplication | |
| 126 | - GSymMatrix result(m_rows,m.m_cols); | |
| 127 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 128 | - for (unsigned col = 0; col < m.m_cols; ++col) { | |
| 206 | + // Allocate result matrix | |
| 207 | + GSymMatrix result(m_rows, m.m_cols); | |
| 208 | + | |
| 209 | + // Loop over all elements of result matrix | |
| 210 | + for (int row = 0; row < m_rows; ++row) { | |
| 211 | + for (int col = 0; col < m.m_cols; ++col) { | |
| 129 | 212 | double sum = 0.0; |
| 130 | - for (unsigned i = 0; i < m_cols; ++i) | |
| 131 | - sum += (*this)(row,i)*m(i,col); | |
| 132 | - result(row,col) = sum; | |
| 133 | - } | |
| 213 | + for (int i = 0; i < m_cols; ++i) | |
| 214 | + sum += (*this)(row,i) * m(i,col); | |
| 215 | + result(row,col) = sum; | |
| 216 | + } | |
| 217 | + } | |
| 218 | + | |
| 219 | + // Assign result | |
| 220 | + *this = result; | |
| 221 | + | |
| 222 | + // Return result | |
| 223 | + return *this; | |
| 224 | +} | |
| 225 | + | |
| 226 | + | |
| 227 | +/*========================================================================== | |
| 228 | + = = | |
| 229 | + = GSymMatrix member functions = | |
| 230 | + = = | |
| 231 | + ==========================================================================*/ | |
| 232 | + | |
| 233 | +/*************************************************************************** | |
| 234 | + * Sum matrix elements * | |
| 235 | + ***************************************************************************/ | |
| 236 | +double GSymMatrix::sum() const | |
| 237 | +{ | |
| 238 | + // Initialise matrix sums (diagonal and off-diagonal) | |
| 239 | + double diag = 0.0; | |
| 240 | + double off_diag = 0.0; | |
| 241 | + | |
| 242 | + // Calulate sum over diagonal elements | |
| 243 | + for (int row = 0; row < m_rows; ++row) | |
| 244 | + diag += m_data[m_colstart[row]]; | |
| 245 | + | |
| 246 | + // Calulate sum over off-diagonal elements | |
| 247 | + for (int row = 0; row < m_rows; ++row) { | |
| 248 | + for (int col = row+1; col < m_cols; ++col) | |
| 249 | + off_diag += m_data[m_colstart[row]+(col-row)]; | |
| 250 | + } | |
| 251 | + | |
| 252 | + // Calculate total | |
| 253 | + double result = diag + 2.0 * off_diag; | |
| 254 | + | |
| 255 | + // Return result | |
| 256 | + return result; | |
| 257 | +} | |
| 258 | + | |
| 259 | + | |
| 260 | +/*************************************************************************** | |
| 261 | + * Extract row from matrix into vector * | |
| 262 | + ***************************************************************************/ | |
| 263 | +GVector GSymMatrix::extract_row(int row) const | |
| 264 | +{ | |
| 265 | + // Raise an exception if the row index is invalid | |
| 266 | + #if defined(G_RANGE_CHECK) | |
| 267 | + if (row >= m_rows) | |
| 268 | + throw out_of_range("GSymMatrix::extract_row(int)", | |
| 269 | + row, 0, m_rows, m_cols); | |
| 270 | + #endif | |
| 271 | + | |
| 272 | + // Create result vector | |
| 273 | + GVector result(m_cols); | |
| 274 | + | |
| 275 | + // Extract row into vector | |
| 276 | + for (int col = 0; col < m_cols; ++col) | |
| 277 | + result(col) = (*this)(row,col); | |
| 278 | + | |
| 279 | + // Return vector | |
| 280 | + return result; | |
| 281 | + | |
| 282 | +} | |
| 283 | + | |
| 284 | + | |
| 285 | +/*************************************************************************** | |
| 286 | + * Extract column from matrix into vector * | |
| 287 | + ***************************************************************************/ | |
| 288 | +GVector GSymMatrix::extract_col(int col) const | |
| 289 | +{ | |
| 290 | + // Raise an exception if the column index is invalid | |
| 291 | + #if defined(G_RANGE_CHECK) | |
| 292 | + if (col >= m_cols) | |
| 293 | + throw out_of_range("GSymMatrix::extract_col(int)", | |
| 294 | + 0, col, m_rows, m_cols); | |
| 295 | + #endif | |
| 296 | + | |
| 297 | + // Create result vector | |
| 298 | + GVector result(m_rows); | |
| 299 | + | |
| 300 | + // Extract column into vector | |
| 301 | + for (int row = 0; row < m_rows; ++row) | |
| 302 | + result(row) = (*this)(row,col); | |
| 303 | + | |
| 304 | + // Return vector | |
| 305 | + return result; | |
| 306 | + | |
| 307 | +} | |
| 308 | + | |
| 309 | + | |
| 310 | +/*************************************************************************** | |
| 311 | + * Convert symmetric matrix into full matrix * | |
| 312 | + ***************************************************************************/ | |
| 313 | +GMatrix GSymMatrix::convert_to_full() const | |
| 314 | +{ | |
| 315 | + // Define result matrix | |
| 316 | + GMatrix result(m_rows, m_cols); | |
| 317 | + | |
| 318 | + // Extract all elements | |
| 319 | + for (int row = 0; row < m_rows; ++row) { | |
| 320 | + for (int col = 0; col < m_cols; ++col) | |
| 321 | + result(row,col) = (*this)(row,col); | |
| 134 | 322 | } |
| 323 | + | |
| 324 | + // Return result | |
| 325 | + return result; | |
| 326 | +} | |
| 327 | + | |
| 328 | + | |
| 329 | +/*************************************************************************** | |
| 330 | + * Extract lower triangle of symmetric matrix into full matrix * | |
| 331 | + ***************************************************************************/ | |
| 332 | +GMatrix GSymMatrix::extract_lower_triangle() const | |
| 333 | +{ | |
| 334 | + // Define result matrix | |
| 335 | + GMatrix result(m_rows, m_cols); | |
| 336 | + | |
| 337 | + // Extract all elements | |
| 338 | + for (int row = 0; row < m_rows; ++row) { | |
| 339 | + for (int col = 0; col <= row; ++col) | |
| 340 | + result(row,col) = m_data[m_colstart[col]+(row-col)]; | |
| 341 | + } | |
| 342 | + | |
| 343 | + // Return result | |
| 344 | + return result; | |
| 345 | +} | |
| 346 | + | |
| 347 | + | |
| 348 | +/*************************************************************************** | |
| 349 | + * Extract upper triangle of symmetric matrix into full matrix * | |
| 350 | + ***************************************************************************/ | |
| 351 | +GMatrix GSymMatrix::extract_upper_triangle() const | |
| 352 | +{ | |
| 353 | + // Define result matrix | |
| 354 | + GMatrix result(m_rows, m_cols); | |
| 355 | + | |
| 356 | + // Extract all elements | |
| 357 | + for (int row = 0; row < m_rows; ++row) { | |
| 358 | + for (int col = row; col < m_cols; ++col) | |
| 359 | + result(row,col) = m_data[m_colstart[row]+(col-row)]; | |
| 360 | + } | |
| 361 | + | |
| 362 | + // Return result | |
| 135 | 363 | return result; |
| 136 | 364 | } |
| 137 | 365 | |
| ... | ... | @@ -159,18 +387,19 @@ void GSymMatrix::cholesky_decompose(int compress) |
| 159 | 387 | if (no_zeros) { |
| 160 | 388 | |
| 161 | 389 | // Loop over upper triangle (col >= row) |
| 162 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 390 | + for (int row = 0; row < m_rows; ++row) { | |
| 163 | 391 | double* ptr = m_data + m_colstart[row]; |
| 164 | - for (unsigned col = row; col < m_cols; ++col, ++ptr) { | |
| 392 | + for (int col = row; col < m_cols; ++col, ++ptr) { | |
| 165 | 393 | double sum = *ptr; // sum = M(row,col) |
| 166 | - for (unsigned k = 0; k < row; ++k) { | |
| 167 | - unsigned offset = m_colstart[k] - k; // is always positive | |
| 394 | + for (int k = 0; k < row; ++k) { | |
| 395 | + int offset = m_colstart[k] - k; // is always positive | |
| 168 | 396 | sum -= m_data[offset+row] * m_data[offset+col]; // sum -= M(row,k)*M(col,k) |
| 169 | 397 | } |
| 170 | 398 | double diag; |
| 171 | 399 | if (row == col) { |
| 172 | 400 | if (sum <= 0.0) |
| 173 | - throw not_pos_definite("GSymMatrix cholesky_decompose", row, sum); | |
| 401 | + throw matrix_not_pos_definite("GSymMatrix::cholesky_decompose(int)", | |
| 402 | + row, sum); | |
| 174 | 403 | *ptr = sqrt(sum); // M(row,row) = sqrt(sum) |
| 175 | 404 | diag = 1.0/(*ptr); |
| 176 | 405 | } |
| ... | ... | @@ -184,12 +413,12 @@ void GSymMatrix::cholesky_decompose(int compress) |
| 184 | 413 | else if (m_num_inx > 0) { |
| 185 | 414 | |
| 186 | 415 | // Allocate loop variables and pointers |
| 187 | - unsigned row; | |
| 188 | - unsigned col; | |
| 189 | - unsigned k; | |
| 190 | - unsigned* row_ptr; | |
| 191 | - unsigned* col_ptr; | |
| 192 | - unsigned* k_ptr; | |
| 416 | + int row; | |
| 417 | + int col; | |
| 418 | + int k; | |
| 419 | + int* row_ptr; | |
| 420 | + int* col_ptr; | |
| 421 | + int* k_ptr; | |
| 193 | 422 | |
| 194 | 423 | // Loop over upper triangle (col >= row) |
| 195 | 424 | for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) { |
| ... | ... | @@ -198,13 +427,14 @@ void GSymMatrix::cholesky_decompose(int compress) |
| 198 | 427 | double* ptr = ptr_0 + *col_ptr; |
| 199 | 428 | double sum = *ptr; // sum = M(row,col) |
| 200 | 429 | for (k = 0, k_ptr = m_inx; k < row; ++k, ++k_ptr) { |
| 201 | - unsigned offset = m_colstart[*k_ptr] - *k_ptr; // is always positive | |
| 430 | + int offset = m_colstart[*k_ptr] - *k_ptr; // is always positive | |
| 202 | 431 | sum -= m_data[offset+*row_ptr] * m_data[offset+*col_ptr]; // sum -= M(row,k)*M(col,k) |
| 203 | 432 | } |
| 204 | 433 | double diag; |
| 205 | 434 | if (*row_ptr == *col_ptr) { |
| 206 | 435 | if (sum <= 0.0) |
| 207 | - throw not_pos_definite("GSymMatrix cholesky_decompose", *row_ptr, sum); | |
| 436 | + throw matrix_not_pos_definite("GSymMatrix::cholesky_decompose(int)", | |
| 437 | + *row_ptr, sum); | |
| 208 | 438 | *ptr = sqrt(sum); // M(row,row) = sqrt(sum) |
| 209 | 439 | diag = 1.0/(*ptr); |
| 210 | 440 | } |
| ... | ... | @@ -216,7 +446,7 @@ void GSymMatrix::cholesky_decompose(int compress) |
| 216 | 446 | |
| 217 | 447 | // Case C: all matrix elements are zero |
| 218 | 448 | else |
| 219 | - throw all_zero("GSymMatrix cholesky_decompose"); | |
| 449 | + throw matrix_zero("GSymMatrix::cholesky_decompose(int)"); | |
| 220 | 450 | |
| 221 | 451 | } |
| 222 | 452 | |
| ... | ... | @@ -231,6 +461,12 @@ void GSymMatrix::cholesky_decompose(int compress) |
| 231 | 461 | ***************************************************************************/ |
| 232 | 462 | GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) |
| 233 | 463 | { |
| 464 | + // Raise an exception if the matrix and vector dimensions are not compatible | |
| 465 | + if (m_rows != v.m_num) | |
| 466 | + throw matrix_vector_mismatch( | |
| 467 | + "GSymMatrix::cholesky_solver(const GVector&, int)", | |
| 468 | + v.m_num, m_rows, m_cols); | |
| 469 | + | |
| 234 | 470 | // Allocate result vector |
| 235 | 471 | GVector x(m_rows); |
| 236 | 472 | |
| ... | ... | @@ -241,9 +477,9 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) |
| 241 | 477 | if (no_zeros) { |
| 242 | 478 | |
| 243 | 479 | // Solve L*y=b, storing y in x (row>k) |
| 244 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 480 | + for (int row = 0; row < m_rows; ++row) { | |
| 245 | 481 | double sum = v(row); |
| 246 | - for (unsigned k = 0; k < row; ++k) | |
| 482 | + for (int k = 0; k < row; ++k) | |
| 247 | 483 | sum -= m_data[m_colstart[k]+(row-k)] * x(k); // sum -= M(row,k) * x(k) |
| 248 | 484 | x(row) = sum/m_data[m_colstart[row]]; // x(row) = sum/M(row,row) |
| 249 | 485 | } |
| ... | ... | @@ -252,7 +488,7 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) |
| 252 | 488 | for (int row = m_rows-1; row >= 0; --row) { |
| 253 | 489 | double sum = x(row); |
| 254 | 490 | double* ptr = m_data + m_colstart[row] + 1; |
| 255 | - for (unsigned k = row+1; k < m_rows; ++k) | |
| 491 | + for (int k = row+1; k < m_rows; ++k) | |
| 256 | 492 | sum -= *ptr++ * x(k); // sum -= M(k,row) * x(k) |
| 257 | 493 | x(row) = sum/m_data[m_colstart[row]]; // x(row) = sum/M(row,row) |
| 258 | 494 | } |
| ... | ... | @@ -263,9 +499,9 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) |
| 263 | 499 | |
| 264 | 500 | // Allocate loop variables and pointers |
| 265 | 501 | int row; |
| 266 | - unsigned k; | |
| 267 | - unsigned* row_ptr; | |
| 268 | - unsigned* k_ptr; | |
| 502 | + int k; | |
| 503 | + int* row_ptr; | |
| 504 | + int* k_ptr; | |
| 269 | 505 | |
| 270 | 506 | // Solve L*y=b, storing y in x (row>k) |
| 271 | 507 | for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) { |
| ... | ... | @@ -289,7 +525,7 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) |
| 289 | 525 | |
| 290 | 526 | // Case C: all matrix elements are zero |
| 291 | 527 | else |
| 292 | - throw all_zero("GSymMatrix cholesky_solver"); | |
| 528 | + throw matrix_zero("GSymMatrix::cholesky_solver(const GVector&, int)"); | |
| 293 | 529 | |
| 294 | 530 | // Return result vector |
| 295 | 531 | return x; |
| ... | ... | @@ -315,27 +551,27 @@ void GSymMatrix::cholesky_invert(int compress) |
| 315 | 551 | if (no_zeros) { |
| 316 | 552 | |
| 317 | 553 | // Generate inverse of Cholesky decomposition (col>row) |
| 318 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 554 | + for (int row = 0; row < m_rows; ++row) { | |
| 319 | 555 | double* ptr = m_data + m_colstart[row]; |
| 320 | 556 | *ptr = 1.0/(*ptr); // M(row,row) = 1/M(row,row) |
| 321 | - for (unsigned col = row+1; col < m_cols; ++col) { | |
| 557 | + for (int col = row+1; col < m_cols; ++col) { | |
| 322 | 558 | double sum = 0.0; |
| 323 | 559 | double* ptr1 = m_data + col - row; |
| 324 | 560 | double* ptr2 = ptr; |
| 325 | - for (unsigned k = row; k < col; ++k) | |
| 561 | + for (int k = row; k < col; ++k) | |
| 326 | 562 | sum -= *(ptr1-- + m_colstart[k]) * *ptr2++; // sum -= M(col,k)*M(k,row) |
| 327 | 563 | *(ptr+col-row) = sum/m_data[m_colstart[col]]; // M(col,row) = sum/M(col,col) |
| 328 | 564 | } |
| 329 | 565 | } |
| 330 | 566 | |
| 331 | 567 | // Matrix multiplication (col>=row) |
| 332 | - for (unsigned row = 0; row < m_rows; ++row) { | |
| 568 | + for (int row = 0; row < m_rows; ++row) { | |
| 333 | 569 | double* ptr = m_data + m_colstart[row]; |
| 334 | - for (unsigned col = row; col < m_cols; ++col) { | |
| 570 | + for (int col = row; col < m_cols; ++col) { | |
| 335 | 571 | double sum = 0.0; |
| 336 | 572 | double* ptr1 = ptr + col - row; |
| 337 | 573 | double* ptr2 = m_data + m_colstart[col]; |
| 338 | - for (unsigned k = col; k < m_cols; ++k) | |
| 574 | + for (int k = col; k < m_cols; ++k) | |
| 339 | 575 | sum += *ptr1++ * *ptr2++; // sum += M(row,k)*M(k,col) |
| 340 | 576 | *(ptr+col-row) = sum; // M(row,col) = sum |
| 341 | 577 | } |
| ... | ... | @@ -346,12 +582,12 @@ void GSymMatrix::cholesky_invert(int compress) |
| 346 | 582 | else if (m_num_inx > 0) { |
| 347 | 583 | |
| 348 | 584 | // Allocate loop variables and pointers |
| 349 | - unsigned row; | |
| 350 | - unsigned col; | |
| 351 | - unsigned k; | |
| 352 | - unsigned* row_ptr; | |
| 353 | - unsigned* col_ptr; | |
| 354 | - unsigned* k_ptr; | |
| 585 | + int row; | |
| 586 | + int col; | |
| 587 | + int k; | |
| 588 | + int* row_ptr; | |
| 589 | + int* col_ptr; | |
| 590 | + int* k_ptr; | |
| 355 | 591 | |
| 356 | 592 | // Generate inverse of Cholesky decomposition (col>row) |
| 357 | 593 | for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) { |
| ... | ... | @@ -384,11 +620,17 @@ void GSymMatrix::cholesky_invert(int compress) |
| 384 | 620 | |
| 385 | 621 | // Case C: all matrix elements are zero |
| 386 | 622 | else |
| 387 | - throw all_zero("GSymMatrix cholesky_invert"); | |
| 623 | + throw matrix_zero("GSymMatrix::cholesky_invert(int)"); | |
| 388 | 624 | |
| 389 | 625 | } |
| 390 | 626 | |
| 391 | 627 | |
| 628 | +/*========================================================================== | |
| 629 | + = = | |
| 630 | + = GSymMatrix private functions = | |
| 631 | + = = | |
| 632 | + ==========================================================================*/ | |
| 633 | + | |
| 392 | 634 | /*************************************************************************** |
| 393 | 635 | * GSymMatrix set_inx * |
| 394 | 636 | * ----------------------------------------------------------------------- * |
| ... | ... | @@ -399,8 +641,8 @@ void GSymMatrix::cholesky_invert(int compress) |
| 399 | 641 | void GSymMatrix::set_inx(void) |
| 400 | 642 | { |
| 401 | 643 | // Allocate loop variables and pointers |
| 402 | - unsigned row; | |
| 403 | - unsigned col; | |
| 644 | + int row; | |
| 645 | + int col; | |
| 404 | 646 | |
| 405 | 647 | // Find all nonzero rows/cols |
| 406 | 648 | m_num_inx = 0; |
| ... | ... | @@ -430,37 +672,31 @@ void GSymMatrix::set_inx(void) |
| 430 | 672 | } |
| 431 | 673 | |
| 432 | 674 | |
| 675 | +/*========================================================================== | |
| 676 | + = = | |
| 677 | + = GSymMatrix friends = | |
| 678 | + = = | |
| 679 | + ==========================================================================*/ | |
| 680 | + | |
| 433 | 681 | /*************************************************************************** |
| 434 | - * Class exception handlers * | |
| 682 | + * Matrix absolute values * | |
| 435 | 683 | ***************************************************************************/ |
| 436 | -// Matrix not symmetric | |
| 437 | -GSymMatrix::not_sym::not_sym(string origin, unsigned cols, unsigned rows) | |
| 684 | +GSymMatrix fabs(const GSymMatrix& m) | |
| 438 | 685 | { |
| 439 | - m_origin = origin; | |
| 440 | - ostringstream s_rows; | |
| 441 | - ostringstream s_cols; | |
| 442 | - s_rows << rows; | |
| 443 | - s_cols << cols; | |
| 444 | - m_message = "Matrix is not symmetric [" + s_rows.str() + "," + | |
| 445 | - s_cols.str() + "]"; | |
| 686 | + // Define result matrix | |
| 687 | + GSymMatrix result(m.m_rows,m.m_cols); | |
| 688 | + | |
| 689 | + // Convert all elements to absolute values | |
| 690 | + for (int i = 0; i < m.m_elements; ++i) | |
| 691 | + result.m_data[i] = fabs(m.m_data[i]); | |
| 692 | + | |
| 693 | + // Return result | |
| 694 | + return result; | |
| 446 | 695 | } |
| 447 | 696 | |
| 448 | -// Matrix not positive definite | |
| 449 | -GSymMatrix::not_pos_definite::not_pos_definite(string origin, unsigned row, | |
| 450 | - double sum) | |
| 451 | -{ | |
| 452 | - m_origin = origin; | |
| 453 | - ostringstream s_rows; | |
| 454 | - ostringstream s_sum; | |
| 455 | - s_rows << row; | |
| 456 | - s_sum << scientific << sum; | |
| 457 | - m_message = "Matrix is not positive definite (sum " + s_sum.str() + | |
| 458 | - " occured in row " + s_rows.str() + ")"; | |
| 459 | -} | |
| 460 | 697 | |
| 461 | -// All matrix elements are zero | |
| 462 | -GSymMatrix::all_zero::all_zero(string origin) | |
| 463 | -{ | |
| 464 | - m_origin = origin; | |
| 465 | - m_message = "All matrix elements are zero"; | |
| 466 | -} | |
| 698 | +/*========================================================================== | |
| 699 | + = = | |
| 700 | + = GSymMatrix exception classes = | |
| 701 | + = = | |
| 702 | + ==========================================================================*/ | ... | ... |
src/GSymMatrix.hpp
| ... | ... | @@ -33,113 +33,106 @@ using namespace std; |
| 33 | 33 | * GSymMatrix class definition * |
| 34 | 34 | ***************************************************************************/ |
| 35 | 35 | class GSymMatrix : public GMatrix { |
| 36 | - // Operator friends | |
| 37 | - friend GSymMatrix operator+ (const double& a, const GSymMatrix& b); | |
| 38 | - friend GSymMatrix operator- (const double& a, const GSymMatrix& b); | |
| 39 | - friend GSymMatrix operator* (const double& a, const GSymMatrix& b); | |
| 36 | + // Binary operator friends | |
| 37 | + friend GSymMatrix operator* (const double& a, const GSymMatrix& b); | |
| 38 | + friend GSymMatrix operator* (const GSymMatrix& a, const double& b); | |
| 39 | + friend GSymMatrix operator/ (const GSymMatrix& a, const double& b); | |
| 40 | 40 | |
| 41 | 41 | // I/O friends |
| 42 | - // ... | |
| 43 | - | |
| 42 | + // USE_BASE: friend ostream& operator<< (ostream& os, const GSymMatrix& m); | |
| 43 | + | |
| 44 | 44 | // Friend functions |
| 45 | 45 | friend GSymMatrix transpose(const GSymMatrix& m); |
| 46 | 46 | friend GSymMatrix fabs(const GSymMatrix& m); |
| 47 | 47 | friend GSymMatrix cholesky_decompose(const GSymMatrix& m, int compress = 1); |
| 48 | 48 | friend GSymMatrix cholesky_invert(const GSymMatrix& m, int compress = 1); |
| 49 | - friend GMatrix full(const GSymMatrix& m); | |
| 50 | - friend GMatrix lower_triangle(const GSymMatrix& m); | |
| 51 | - friend GMatrix upper_triangle(const GSymMatrix& m); | |
| 49 | + | |
| 52 | 50 | public: |
| 53 | 51 | // Constructors and destructors (not inherited) |
| 54 | - GSymMatrix(unsigned rows, unsigned cols); | |
| 52 | + GSymMatrix(int rows, int cols); | |
| 55 | 53 | GSymMatrix(const GSymMatrix& m); |
| 56 | - ~GSymMatrix(); | |
| 54 | + virtual ~GSymMatrix(); | |
| 57 | 55 | |
| 58 | 56 | // Matrix element access operators |
| 59 | - double& operator() (unsigned row, unsigned col); | |
| 60 | - const double& operator() (unsigned row, unsigned col) const; | |
| 57 | + virtual double& operator() (int row, int col); | |
| 58 | + virtual const double& operator() (int row, int col) const; | |
| 61 | 59 | |
| 62 | 60 | // Matrix assignment operators (not inherited) |
| 63 | - GSymMatrix& operator= (const GSymMatrix& m); | |
| 64 | - GSymMatrix& operator= (const double& d); | |
| 65 | - | |
| 66 | - // Specific matrix operators (structure dependent) | |
| 67 | - GSymMatrix operator+ (const GSymMatrix& m) const; | |
| 68 | - GSymMatrix operator- (const GSymMatrix& m) const; | |
| 69 | - GSymMatrix operator* (const GSymMatrix& m) const; | |
| 70 | - GVector operator* (const GVector& v) const; | |
| 71 | - GSymMatrix operator+ (const double& d) const; | |
| 72 | - GSymMatrix operator- (const double& d) const; | |
| 73 | - GSymMatrix operator* (const double& d) const; | |
| 74 | - GSymMatrix operator/ (const double& d) const; | |
| 75 | - GSymMatrix operator- () const; | |
| 76 | - | |
| 77 | - // Specific matrix functions | |
| 78 | - void transpose(); // Inplace transpose of matrix | |
| 79 | - void cholesky_decompose(int compress = 1); // Inplace Cholesky decomposition | |
| 80 | - GVector cholesky_solver(const GVector& v, int compress = 1); // Cholesky solver | |
| 81 | - void cholesky_invert(int compress = 1); // Inplace Cholesky matrix inverter | |
| 82 | - | |
| 83 | - // Exception: Matrix not symmetric | |
| 84 | - class not_sym : public GException { | |
| 85 | - public: | |
| 86 | - not_sym(string origin, unsigned cols, unsigned rows); | |
| 87 | - }; | |
| 61 | + virtual GSymMatrix& operator= (const GSymMatrix& m); | |
| 88 | 62 | |
| 89 | - // Exception: Matrix not positive definite | |
| 90 | - class not_pos_definite : public GException { | |
| 91 | - public: | |
| 92 | - not_pos_definite(string origin, unsigned row, double sum); | |
| 93 | - }; | |
| 63 | + // Binary operators | |
| 64 | + virtual GSymMatrix operator+ (const GSymMatrix& m) const; | |
| 65 | + virtual GSymMatrix operator- (const GSymMatrix& m) const; | |
| 66 | + virtual GSymMatrix operator* (const GSymMatrix& m) const; | |
| 67 | + virtual GVector operator* (const GVector& v) const; | |
| 68 | + // USE_BASE: virtual int operator== (const GSymMatrix& m) const; | |
| 69 | + // USE_BASE: virtual int operator!= (const GSymMatrix& m) const; | |
| 94 | 70 | |
| 71 | + // Unary operators | |
| 72 | + GSymMatrix operator- () const; | |
| 73 | + // USE_BASE: virtual GSymMatrix& operator+= (const GSymMatrix& m); | |
| 74 | + // USE_BASE: virtual GSymMatrix& operator-= (const GSymMatrix& m); | |
| 75 | + virtual GSymMatrix& operator*= (const GSymMatrix& m); | |
| 76 | + virtual GSymMatrix& operator*= (const double& d); | |
| 77 | + virtual GSymMatrix& operator/= (const double& d); | |
| 78 | + | |
| 79 | + // Matrix functions | |
| 80 | + // USE_BASE: virtual int rows() const { return m_rows; } | |
| 81 | + // USE_BASE: virtual int cols() const { return m_cols; } | |
| 82 | + // USE_BASE: virtual double min() const; | |
| 83 | + // USE_BASE: virtual double max() const; | |
| 84 | + virtual double sum() const; | |
| 85 | + virtual void transpose() { return; } | |
| 86 | + virtual GVector extract_row(int row) const; | |
| 87 | + virtual GVector extract_col(int col) const; | |
| 88 | + virtual GMatrix convert_to_full() const; | |
| 89 | + virtual GMatrix extract_lower_triangle() const; | |
| 90 | + virtual GMatrix extract_upper_triangle() const; | |
| 91 | + virtual void cholesky_decompose(int compress = 1); | |
| 92 | + virtual GVector cholesky_solver(const GVector& v, int compress = 1); | |
| 93 | + virtual void cholesky_invert(int compress = 1); | |
| 94 | + | |
| 95 | 95 | // Exception: All matrix elements are zero |
| 96 | 96 | class all_zero : public GException { |
| 97 | 97 | public: |
| 98 | 98 | all_zero(string origin); |
| 99 | 99 | }; |
| 100 | + | |
| 100 | 101 | private: |
| 101 | - void set_inx(void); // Set indices of non-zero rows/columns | |
| 102 | - unsigned m_num_inx; // Number of non-zero rows/columns | |
| 103 | - unsigned* m_inx; // Indices of non-zero rows/columns | |
| 102 | + void set_inx(void); // Set indices of non-zero rows/columns | |
| 103 | + int m_num_inx; // Number of non-zero rows/columns | |
| 104 | + int* m_inx; // Indices of non-zero rows/columns | |
| 104 | 105 | }; |
| 105 | 106 | |
| 106 | 107 | |
| 107 | 108 | /*************************************************************************** |
| 108 | - * Inline members that override base class members * | |
| 109 | + * Inline member functions * | |
| 109 | 110 | ***************************************************************************/ |
| 110 | -// Scalar assignment operator: GSymMatrix = double | |
| 111 | +// Matrix element access operator | |
| 111 | 112 | inline |
| 112 | -GSymMatrix& GSymMatrix::operator= (const double& d) | |
| 113 | -{ | |
| 114 | - this->GMatrix::operator=(d); | |
| 115 | - return *this; | |
| 116 | -} | |
| 117 | - | |
| 118 | -// Matrix element access operator: GSymMatrix(row,col) | |
| 119 | -inline | |
| 120 | -double& GSymMatrix::operator() (unsigned row, unsigned col) | |
| 113 | +double& GSymMatrix::operator() (int row, int col) | |
| 121 | 114 | { |
| 122 | 115 | #if defined(G_RANGE_CHECK) |
| 123 | 116 | if (row >= m_rows || col >= m_cols) |
| 124 | 117 | throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); |
| 125 | 118 | #endif |
| 126 | - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); | |
| 119 | + int inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); | |
| 127 | 120 | return m_data[inx]; |
| 128 | 121 | } |
| 129 | 122 | |
| 130 | -// Matrix element access operator (const version): GSymMatrix(row,col) | |
| 123 | +// Matrix element access operator (const version) | |
| 131 | 124 | inline |
| 132 | -const double& GSymMatrix::operator() (unsigned row, unsigned col) const | |
| 125 | +const double& GSymMatrix::operator() (int row, int col) const | |
| 133 | 126 | { |
| 134 | 127 | #if defined(G_RANGE_CHECK) |
| 135 | 128 | if (row >= m_rows || col >= m_cols) |
| 136 | 129 | throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); |
| 137 | 130 | #endif |
| 138 | - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); | |
| 131 | + int inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); | |
| 139 | 132 | return m_data[inx]; |
| 140 | 133 | } |
| 141 | 134 | |
| 142 | -// Matrix addition: GSymMatrix + GSymMatrix | |
| 135 | +// Binary matrix addition | |
| 143 | 136 | inline |
| 144 | 137 | GSymMatrix GSymMatrix::operator+ (const GSymMatrix& m) const |
| 145 | 138 | { |
| ... | ... | @@ -148,7 +141,7 @@ GSymMatrix GSymMatrix::operator+ (const GSymMatrix& m) const |
| 148 | 141 | return result; |
| 149 | 142 | } |
| 150 | 143 | |
| 151 | -// Matrix subtraction: GSymMatrix - GSymMatrix | |
| 144 | +// Binary matrix subtraction | |
| 152 | 145 | inline |
| 153 | 146 | GSymMatrix GSymMatrix::operator- (const GSymMatrix& m) const |
| 154 | 147 | { |
| ... | ... | @@ -157,116 +150,68 @@ GSymMatrix GSymMatrix::operator- (const GSymMatrix& m) const |
| 157 | 150 | return result; |
| 158 | 151 | } |
| 159 | 152 | |
| 160 | -// Matrix/Vector multiplication: GSymMatrix * GVector | |
| 153 | +// Binary matrix multiplication | |
| 161 | 154 | inline |
| 162 | -GVector GSymMatrix::operator* (const GVector& v) const | |
| 163 | -{ | |
| 164 | - return (this->GMatrix::operator*(v)); | |
| 165 | -} | |
| 166 | - | |
| 167 | -// Matrix scaling: GSymMatrix + double | |
| 168 | -inline | |
| 169 | -GSymMatrix GSymMatrix::operator+ (const double& d) const | |
| 155 | +GSymMatrix GSymMatrix::operator* (const GSymMatrix& m) const | |
| 170 | 156 | { |
| 171 | - GSymMatrix result = (*this); | |
| 172 | - result += d; | |
| 173 | - return result; | |
| 174 | -} | |
| 175 | - | |
| 176 | -// Matrix scaling: GSymMatrix - double | |
| 177 | -inline | |
| 178 | -GSymMatrix GSymMatrix::operator- (const double& d) const | |
| 179 | -{ | |
| 180 | - GSymMatrix result = (*this); | |
| 181 | - result -= d; | |
| 182 | - return result; | |
| 183 | -} | |
| 184 | - | |
| 185 | -// Matrix scaling: GSymMatrix * double | |
| 186 | -inline | |
| 187 | -GSymMatrix GSymMatrix::operator* (const double& d) const | |
| 188 | -{ | |
| 189 | - GSymMatrix result = (*this); | |
| 190 | - result *= d; | |
| 191 | - return result; | |
| 192 | -} | |
| 193 | - | |
| 194 | -// Matrix inverse scaling: GSymMatrix * double | |
| 195 | -inline | |
| 196 | -GSymMatrix GSymMatrix::operator/ (const double& d) const | |
| 197 | -{ | |
| 198 | - GSymMatrix result = (*this); | |
| 199 | - result /= d; | |
| 157 | + GSymMatrix result = *this; | |
| 158 | + result *= m; | |
| 200 | 159 | return result; |
| 201 | 160 | } |
| 202 | 161 | |
| 203 | -// Unary minus operator | |
| 162 | +// Unary scalar multiplication | |
| 204 | 163 | inline |
| 205 | -GSymMatrix GSymMatrix::operator- ( ) const | |
| 164 | +GSymMatrix& GSymMatrix::operator*= (const double& d) | |
| 206 | 165 | { |
| 207 | - GSymMatrix result = *this; | |
| 208 | - for (unsigned i = 0; i < m_elements; ++i) | |
| 209 | - result.m_data[i] = -result.m_data[i]; | |
| 210 | - return result; | |
| 166 | + this->GMatrix::operator*=(d); | |
| 211 | 167 | } |
| 212 | 168 | |
| 213 | -// Matrix transpose | |
| 169 | +// Unary scalar division | |
| 214 | 170 | inline |
| 215 | -void GSymMatrix::transpose() | |
| 171 | +GSymMatrix& GSymMatrix::operator/= (const double& d) | |
| 216 | 172 | { |
| 217 | - return; | |
| 173 | + this->GMatrix::operator/=(d); | |
| 218 | 174 | } |
| 219 | 175 | |
| 220 | 176 | |
| 221 | - | |
| 222 | 177 | /*************************************************************************** |
| 223 | 178 | * Inline friends * |
| 224 | 179 | ***************************************************************************/ |
| 225 | -// Matrix addition: double + GSymMatrix | |
| 226 | -inline | |
| 227 | -GSymMatrix operator+ (const double& a, const GSymMatrix& b) | |
| 180 | +// Binary matrix scaling (matrix is left operand) | |
| 181 | +inline | |
| 182 | +GSymMatrix operator* (const GSymMatrix& a, const double& b) | |
| 228 | 183 | { |
| 229 | - GSymMatrix result = b; | |
| 230 | - result += a; | |
| 184 | + GSymMatrix result = a; | |
| 185 | + result *= b; | |
| 231 | 186 | return result; |
| 232 | 187 | } |
| 233 | 188 | |
| 234 | -// Matrix subtracxtion: double * GSymMatrix | |
| 189 | +// Binary matrix scaling (matrix is right operand) | |
| 235 | 190 | inline |
| 236 | -GSymMatrix operator- (const double& a, const GSymMatrix& b) | |
| 191 | +GSymMatrix operator* (const double& a, const GSymMatrix& b) | |
| 237 | 192 | { |
| 238 | 193 | GSymMatrix result = b; |
| 239 | - result -= a; | |
| 194 | + result *= a; | |
| 240 | 195 | return result; |
| 241 | 196 | } |
| 242 | 197 | |
| 243 | -// Matrix scaling: double * GSymMatrix | |
| 244 | -inline | |
| 245 | -GSymMatrix operator* (const double& a, const GSymMatrix& b) | |
| 198 | +// Binary matrix division (matrix is left operand) | |
| 199 | +inline | |
| 200 | +GSymMatrix operator/ (const GSymMatrix& a, const double& b) | |
| 246 | 201 | { |
| 247 | - GSymMatrix result = b; | |
| 248 | - result *= a; | |
| 202 | + GSymMatrix result = a; | |
| 203 | + result /= b; | |
| 249 | 204 | return result; |
| 250 | 205 | } |
| 251 | 206 | |
| 252 | -// Matrix transpose: transpose(GSymMatrix) | |
| 207 | +// Matrix transpose function | |
| 253 | 208 | inline |
| 254 | 209 | GSymMatrix transpose(const GSymMatrix& m) |
| 255 | 210 | { |
| 256 | 211 | return m; |
| 257 | 212 | } |
| 258 | 213 | |
| 259 | -// Matrix absolute: fabs(GSymMatrix) | |
| 260 | -inline | |
| 261 | -GSymMatrix fabs(const GSymMatrix& m) | |
| 262 | -{ | |
| 263 | - GSymMatrix result = m; | |
| 264 | - for (unsigned i = 0; i < result.m_elements; ++i) | |
| 265 | - result.m_data[i] = fabs(result.m_data[i]); | |
| 266 | - return result; | |
| 267 | -} | |
| 268 | - | |
| 269 | -// Cholesky decomposition: cholesky_decompose(GSymMatrix) | |
| 214 | +// Cholesky decomposition | |
| 270 | 215 | inline |
| 271 | 216 | GSymMatrix cholesky_decompose(const GSymMatrix& m, int compress) |
| 272 | 217 | { |
| ... | ... | @@ -275,7 +220,7 @@ GSymMatrix cholesky_decompose(const GSymMatrix& m, int compress) |
| 275 | 220 | return result; |
| 276 | 221 | } |
| 277 | 222 | |
| 278 | -// Inversion using Cholesky decomposition: cholesky_invert(GSymMatrix) | |
| 223 | +// Matrix inversion using Cholesky decomposition | |
| 279 | 224 | inline |
| 280 | 225 | GSymMatrix cholesky_invert(const GSymMatrix& m, int compress) |
| 281 | 226 | { |
| ... | ... | @@ -284,40 +229,4 @@ GSymMatrix cholesky_invert(const GSymMatrix& m, int compress) |
| 284 | 229 | return result; |
| 285 | 230 | } |
| 286 | 231 | |
| 287 | -// Convert symmetric matrix into full matrix: full(GSymMatrix) | |
| 288 | -inline | |
| 289 | -GMatrix full(const GSymMatrix& m) | |
| 290 | -{ | |
| 291 | - GMatrix result(m.m_rows,m.m_cols); | |
| 292 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 293 | - for (unsigned col = 0; col < m.m_cols; ++col) | |
| 294 | - result(row,col) = m(row,col); | |
| 295 | - } | |
| 296 | - return result; | |
| 297 | -} | |
| 298 | - | |
| 299 | -// Convert symmetric matrix into lower triangle full matrix: lower_triangle(GSymMatrix) | |
| 300 | -inline | |
| 301 | -GMatrix lower_triangle(const GSymMatrix& m) | |
| 302 | -{ | |
| 303 | - GMatrix result(m.m_rows,m.m_cols); | |
| 304 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 305 | - for (unsigned col = 0; col <= row; ++col) | |
| 306 | - result(row,col) = m.m_data[m.m_colstart[col]+(row-col)]; | |
| 307 | - } | |
| 308 | - return result; | |
| 309 | -} | |
| 310 | - | |
| 311 | -// Convert symmetric matrix into upper triangle full matrix: lower_triangle(GSymMatrix) | |
| 312 | -inline | |
| 313 | -GMatrix upper_triangle(const GSymMatrix& m) | |
| 314 | -{ | |
| 315 | - GMatrix result(m.m_rows,m.m_cols); | |
| 316 | - for (unsigned row = 0; row < m.m_rows; ++row) { | |
| 317 | - for (unsigned col = row; col < m.m_cols; ++col) | |
| 318 | - result(row,col) = m.m_data[m.m_colstart[row]+(col-row)]; | |
| 319 | - } | |
| 320 | - return result; | |
| 321 | -} | |
| 322 | - | |
| 323 | 232 | #endif /* GSYMMATRIX_HPP */ | ... | ... |
src/GVector.cpp
| ... | ... | @@ -15,10 +15,16 @@ |
| 15 | 15 | #include "GVector.hpp" |
| 16 | 16 | |
| 17 | 17 | |
| 18 | +/*========================================================================== | |
| 19 | + = = | |
| 20 | + = GVector constructors/destructors = | |
| 21 | + = = | |
| 22 | + ==========================================================================*/ | |
| 23 | + | |
| 18 | 24 | /*************************************************************************** |
| 19 | 25 | * GVector constructor * |
| 20 | 26 | ***************************************************************************/ |
| 21 | -GVector::GVector(unsigned num) | |
| 27 | +GVector::GVector(int num) | |
| 22 | 28 | { |
| 23 | 29 | // Throw exception if requested vector length is zero |
| 24 | 30 | if (num == 0) |
| ... | ... | @@ -31,8 +37,11 @@ GVector::GVector(unsigned num) |
| 31 | 37 | |
| 32 | 38 | // Store vector size and initialize elements to 0.0 |
| 33 | 39 | m_num = num; |
| 34 | - for (unsigned i = 0; i < m_num; ++i) | |
| 40 | + for (int i = 0; i < m_num; ++i) | |
| 35 | 41 | m_data[i] = 0.0; |
| 42 | + | |
| 43 | + // Return | |
| 44 | + return; | |
| 36 | 45 | } |
| 37 | 46 | |
| 38 | 47 | |
| ... | ... | @@ -46,15 +55,42 @@ GVector::~GVector() |
| 46 | 55 | m_num = 0; |
| 47 | 56 | delete[] m_data; |
| 48 | 57 | } |
| 58 | + | |
| 59 | + // Return | |
| 60 | + return; | |
| 49 | 61 | } |
| 50 | 62 | |
| 51 | 63 | |
| 64 | +/*========================================================================== | |
| 65 | + = = | |
| 66 | + = GVector operators = | |
| 67 | + = = | |
| 68 | + ==========================================================================*/ | |
| 69 | + | |
| 70 | +/*========================================================================== | |
| 71 | + = = | |
| 72 | + = GVector member functions = | |
| 73 | + = = | |
| 74 | + ==========================================================================*/ | |
| 75 | + | |
| 76 | +/*========================================================================== | |
| 77 | + = = | |
| 78 | + = GVector private functions = | |
| 79 | + = = | |
| 80 | + ==========================================================================*/ | |
| 81 | + | |
| 82 | +/*========================================================================== | |
| 83 | + = = | |
| 84 | + = GVector friends = | |
| 85 | + = = | |
| 86 | + ==========================================================================*/ | |
| 87 | + | |
| 52 | 88 | /*************************************************************************** |
| 53 | 89 | * GVector output operator * |
| 54 | 90 | ***************************************************************************/ |
| 55 | 91 | ostream& operator<< (ostream& os, const GVector& v) |
| 56 | 92 | { |
| 57 | - for (unsigned i = 0; i < v.m_num; ++i) { | |
| 93 | + for (int i = 0; i < v.m_num; ++i) { | |
| 58 | 94 | os << v(i); |
| 59 | 95 | if (i != v.m_num-1) |
| 60 | 96 | os << ", "; |
| ... | ... | @@ -80,12 +116,17 @@ GVector cross(const GVector &a, const GVector &b) |
| 80 | 116 | } |
| 81 | 117 | |
| 82 | 118 | |
| 119 | +/*========================================================================== | |
| 120 | + = = | |
| 121 | + = GSparseMatrix exception classes = | |
| 122 | + = = | |
| 123 | + ==========================================================================*/ | |
| 124 | + | |
| 83 | 125 | /*************************************************************************** |
| 84 | 126 | * Class exception handlers * |
| 85 | 127 | ***************************************************************************/ |
| 86 | 128 | // Vector index out of range |
| 87 | -GVector::out_of_range::out_of_range(string origin, unsigned inx, | |
| 88 | - unsigned elements) | |
| 129 | +GVector::out_of_range::out_of_range(string origin, int inx, int elements) | |
| 89 | 130 | { |
| 90 | 131 | m_origin = origin; |
| 91 | 132 | if (elements > 0) { |
| ... | ... | @@ -102,8 +143,7 @@ GVector::out_of_range::out_of_range(string origin, unsigned inx, |
| 102 | 143 | } |
| 103 | 144 | |
| 104 | 145 | // Vector dimensions differ |
| 105 | -GVector::dim_mismatch::dim_mismatch(string origin, unsigned size1, | |
| 106 | - unsigned size2) | |
| 146 | +GVector::dim_mismatch::dim_mismatch(string origin, int size1, int size2) | |
| 107 | 147 | { |
| 108 | 148 | m_origin = origin; |
| 109 | 149 | ostringstream s_size1; |
| ... | ... | @@ -115,7 +155,7 @@ GVector::dim_mismatch::dim_mismatch(string origin, unsigned size1, |
| 115 | 155 | } |
| 116 | 156 | |
| 117 | 157 | // Invalid vector dimension for cross product |
| 118 | -GVector::bad_cross_dim::bad_cross_dim(unsigned elements) | |
| 158 | +GVector::bad_cross_dim::bad_cross_dim(int elements) | |
| 119 | 159 | { |
| 120 | 160 | ostringstream s_elements; |
| 121 | 161 | s_elements << elements; | ... | ... |
src/GVector.hpp
| ... | ... | @@ -36,7 +36,8 @@ using namespace std; |
| 36 | 36 | class GVector { |
| 37 | 37 | // Friend classes |
| 38 | 38 | friend class GMatrix; |
| 39 | - friend class GMatrixSym; | |
| 39 | + friend class GSymMatrix; | |
| 40 | + friend class GSparseMatrix; | |
| 40 | 41 | |
| 41 | 42 | // Operator friends |
| 42 | 43 | friend GVector operator+ (const GVector &a, const GVector &b); |
| ... | ... | @@ -61,6 +62,8 @@ class GVector { |
| 61 | 62 | friend double min(const GVector &v); |
| 62 | 63 | friend double max(const GVector &v); |
| 63 | 64 | friend double sum(const GVector &v); |
| 65 | + friend GVector perm(const GVector &v, const int *p); | |
| 66 | + friend GVector iperm(const GVector &v, const int *p); | |
| 64 | 67 | friend GVector acos(const GVector &v); |
| 65 | 68 | friend GVector acosh(const GVector &v); |
| 66 | 69 | friend GVector asin(const GVector &v); |
| ... | ... | @@ -81,13 +84,13 @@ class GVector { |
| 81 | 84 | |
| 82 | 85 | public: |
| 83 | 86 | // Constructors and destructors |
| 84 | - explicit GVector(unsigned num); | |
| 87 | + explicit GVector(int num); | |
| 85 | 88 | GVector(const GVector& v); |
| 86 | 89 | ~GVector(); |
| 87 | 90 | |
| 88 | 91 | // Vector element access operators |
| 89 | - double& operator() (unsigned inx); | |
| 90 | - const double& operator() (unsigned inx) const; | |
| 92 | + double& operator() (int inx); | |
| 93 | + const double& operator() (int inx) const; | |
| 91 | 94 | |
| 92 | 95 | // Vector operators |
| 93 | 96 | GVector& operator= (const GVector& v); |
| ... | ... | @@ -101,28 +104,28 @@ public: |
| 101 | 104 | GVector operator- () const; |
| 102 | 105 | |
| 103 | 106 | // Vector functions |
| 104 | - unsigned size() const; // Return dimension of vector | |
| 107 | + int size() const; // Return dimension of vector | |
| 105 | 108 | |
| 106 | 109 | // Exception: Vector index out of range |
| 107 | 110 | class out_of_range : public GException { |
| 108 | 111 | public: |
| 109 | - out_of_range(string origin, unsigned inx, unsigned elements); | |
| 112 | + out_of_range(string origin, int inx, int elements); | |
| 110 | 113 | }; |
| 111 | 114 | |
| 112 | 115 | // Exception: Vector dimensions mismatch |
| 113 | 116 | class dim_mismatch : public GException { |
| 114 | 117 | public: |
| 115 | - dim_mismatch(string origin, unsigned size1, unsigned size2); | |
| 118 | + dim_mismatch(string origin, int size1, int size2); | |
| 116 | 119 | }; |
| 117 | 120 | |
| 118 | 121 | // Exception: Invalid vector dimension for cross product |
| 119 | 122 | class bad_cross_dim : public GException { |
| 120 | 123 | public: |
| 121 | - bad_cross_dim(unsigned elements); | |
| 124 | + bad_cross_dim(int elements); | |
| 122 | 125 | }; |
| 123 | 126 | private: |
| 124 | - unsigned m_num; | |
| 125 | - double* m_data; | |
| 127 | + int m_num; | |
| 128 | + double* m_data; | |
| 126 | 129 | }; |
| 127 | 130 | |
| 128 | 131 | |
| ... | ... | @@ -138,13 +141,13 @@ GVector::GVector(const GVector& v) |
| 138 | 141 | if (m_data == NULL) |
| 139 | 142 | throw mem_alloc("GVector copy constructor", v.m_num); |
| 140 | 143 | m_num = v.m_num; |
| 141 | - for (unsigned i = 0; i < m_num; ++i) | |
| 144 | + for (int i = 0; i < m_num; ++i) | |
| 142 | 145 | m_data[i] = v.m_data[i]; |
| 143 | 146 | } |
| 144 | 147 | |
| 145 | 148 | // Vector element access operator |
| 146 | 149 | inline |
| 147 | -double& GVector::operator() (unsigned inx) | |
| 150 | +double& GVector::operator() (int inx) | |
| 148 | 151 | { |
| 149 | 152 | #if defined(G_RANGE_CHECK) |
| 150 | 153 | if (inx >= m_num) |
| ... | ... | @@ -155,7 +158,7 @@ double& GVector::operator() (unsigned inx) |
| 155 | 158 | |
| 156 | 159 | // Vector element access operator (const version) |
| 157 | 160 | inline |
| 158 | -const double& GVector::operator() (unsigned inx) const | |
| 161 | +const double& GVector::operator() (int inx) const | |
| 159 | 162 | { |
| 160 | 163 | #if defined(G_RANGE_CHECK) |
| 161 | 164 | if (inx >= m_num) |
| ... | ... | @@ -168,12 +171,15 @@ const double& GVector::operator() (unsigned inx) const |
| 168 | 171 | inline |
| 169 | 172 | GVector& GVector::operator= (const GVector& v) |
| 170 | 173 | { |
| 171 | - m_data = new double[v.m_num]; | |
| 172 | - if (m_data == NULL) | |
| 173 | - throw mem_alloc("GVector assignment operator", v.m_num); | |
| 174 | - m_num = v.m_num; | |
| 175 | - for (unsigned i = 0; i < m_num; ++i) | |
| 176 | - m_data[i] = v.m_data[i]; | |
| 174 | + if (this != &v) { | |
| 175 | + if (m_data != NULL) delete [] m_data; | |
| 176 | + m_data = new double[v.m_num]; | |
| 177 | + if (m_data == NULL) | |
| 178 | + throw mem_alloc("GVector assignment operator", v.m_num); | |
| 179 | + m_num = v.m_num; | |
| 180 | + for (int i = 0; i < m_num; ++i) | |
| 181 | + m_data[i] = v.m_data[i]; | |
| 182 | + } | |
| 177 | 183 | return *this; |
| 178 | 184 | } |
| 179 | 185 | |
| ... | ... | @@ -183,7 +189,7 @@ GVector& GVector::operator+= (const GVector& v) |
| 183 | 189 | { |
| 184 | 190 | if (m_num != v.m_num) |
| 185 | 191 | throw dim_mismatch("GVector += operator", m_num, v.m_num); |
| 186 | - for (unsigned i = 0; i < m_num; ++i) | |
| 192 | + for (int i = 0; i < m_num; ++i) | |
| 187 | 193 | m_data[i] += v.m_data[i]; |
| 188 | 194 | return *this; |
| 189 | 195 | } |
| ... | ... | @@ -194,7 +200,7 @@ GVector& GVector::operator-= (const GVector& v) |
| 194 | 200 | { |
| 195 | 201 | if (m_num != v.m_num) |
| 196 | 202 | throw dim_mismatch("GVector -= operator", m_num, v.m_num); |
| 197 | - for (unsigned i = 0; i < m_num; ++i) | |
| 203 | + for (int i = 0; i < m_num; ++i) | |
| 198 | 204 | m_data[i] -= v.m_data[i]; |
| 199 | 205 | return *this; |
| 200 | 206 | } |
| ... | ... | @@ -203,7 +209,7 @@ GVector& GVector::operator-= (const GVector& v) |
| 203 | 209 | inline |
| 204 | 210 | GVector& GVector::operator= (const double& v) |
| 205 | 211 | { |
| 206 | - for (unsigned i = 0; i < m_num; ++i) | |
| 212 | + for (int i = 0; i < m_num; ++i) | |
| 207 | 213 | m_data[i] = v; |
| 208 | 214 | return *this; |
| 209 | 215 | } |
| ... | ... | @@ -212,7 +218,7 @@ GVector& GVector::operator= (const double& v) |
| 212 | 218 | inline |
| 213 | 219 | GVector& GVector::operator+= (const double& v) |
| 214 | 220 | { |
| 215 | - for (unsigned i = 0; i < m_num; ++i) | |
| 221 | + for (int i = 0; i < m_num; ++i) | |
| 216 | 222 | m_data[i] += v; |
| 217 | 223 | return *this; |
| 218 | 224 | } |
| ... | ... | @@ -221,7 +227,7 @@ GVector& GVector::operator+= (const double& v) |
| 221 | 227 | inline |
| 222 | 228 | GVector& GVector::operator-= (const double& v) |
| 223 | 229 | { |
| 224 | - for (unsigned i = 0; i < m_num; ++i) | |
| 230 | + for (int i = 0; i < m_num; ++i) | |
| 225 | 231 | m_data[i] -= v; |
| 226 | 232 | return *this; |
| 227 | 233 | } |
| ... | ... | @@ -230,7 +236,7 @@ GVector& GVector::operator-= (const double& v) |
| 230 | 236 | inline |
| 231 | 237 | GVector& GVector::operator*= (const double& v) |
| 232 | 238 | { |
| 233 | - for (unsigned i = 0; i < m_num; ++i) | |
| 239 | + for (int i = 0; i < m_num; ++i) | |
| 234 | 240 | m_data[i] *= v; |
| 235 | 241 | return *this; |
| 236 | 242 | } |
| ... | ... | @@ -239,7 +245,7 @@ GVector& GVector::operator*= (const double& v) |
| 239 | 245 | inline |
| 240 | 246 | GVector& GVector::operator/= (const double& v) |
| 241 | 247 | { |
| 242 | - for (unsigned i = 0; i < m_num; ++i) | |
| 248 | + for (int i = 0; i < m_num; ++i) | |
| 243 | 249 | m_data[i] /= v; |
| 244 | 250 | return *this; |
| 245 | 251 | } |
| ... | ... | @@ -249,14 +255,14 @@ inline |
| 249 | 255 | GVector GVector::operator- ( ) const |
| 250 | 256 | { |
| 251 | 257 | GVector result = *this; |
| 252 | - for (unsigned i = 0; i < m_num; ++i) | |
| 258 | + for (int i = 0; i < m_num; ++i) | |
| 253 | 259 | result.m_data[i] = -result.m_data[i]; |
| 254 | 260 | return result; |
| 255 | 261 | } |
| 256 | 262 | |
| 257 | 263 | // Return size of vector |
| 258 | 264 | inline |
| 259 | -unsigned GVector::size() const | |
| 265 | +int GVector::size() const | |
| 260 | 266 | { |
| 261 | 267 | return m_num; |
| 262 | 268 | } |
| ... | ... | @@ -326,7 +332,7 @@ double operator* (const GVector& a, const GVector& b) |
| 326 | 332 | if (a.m_num != b.m_num) |
| 327 | 333 | throw GVector::dim_mismatch("GVector scalar product", a.m_num, b.m_num); |
| 328 | 334 | double result = 0.0; |
| 329 | - for (unsigned i = 0; i < a.m_num; ++i) | |
| 335 | + for (int i = 0; i < a.m_num; ++i) | |
| 330 | 336 | result += (a.m_data[i] * b.m_data[i]); |
| 331 | 337 | return result; |
| 332 | 338 | } |
| ... | ... | @@ -363,7 +369,7 @@ inline |
| 363 | 369 | double norm(const GVector &v) |
| 364 | 370 | { |
| 365 | 371 | double result = 0.0; |
| 366 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 372 | + for (int i = 0; i < v.m_num; ++i) | |
| 367 | 373 | result += (v.m_data[i] * v.m_data[i]); |
| 368 | 374 | result = (result > 0.0) ? sqrt(result) : 0.0; |
| 369 | 375 | return result; |
| ... | ... | @@ -374,7 +380,7 @@ inline |
| 374 | 380 | double min(const GVector &v) |
| 375 | 381 | { |
| 376 | 382 | double result = v.m_data[0]; |
| 377 | - for (unsigned i = 1; i < v.m_num; ++i) { | |
| 383 | + for (int i = 1; i < v.m_num; ++i) { | |
| 378 | 384 | if (v.m_data[i] < result) |
| 379 | 385 | result = v.m_data[i]; |
| 380 | 386 | } |
| ... | ... | @@ -386,7 +392,7 @@ inline |
| 386 | 392 | double max(const GVector &v) |
| 387 | 393 | { |
| 388 | 394 | double result = v.m_data[0]; |
| 389 | - for (unsigned i = 1; i < v.m_num; ++i) { | |
| 395 | + for (int i = 1; i < v.m_num; ++i) { | |
| 390 | 396 | if (v.m_data[i] > result) |
| 391 | 397 | result = v.m_data[i]; |
| 392 | 398 | } |
| ... | ... | @@ -398,17 +404,45 @@ inline |
| 398 | 404 | double sum(const GVector &v) |
| 399 | 405 | { |
| 400 | 406 | double result = 0.0; |
| 401 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 407 | + for (int i = 0; i < v.m_num; ++i) | |
| 402 | 408 | result += v.m_data[i]; |
| 403 | 409 | return result; |
| 404 | 410 | } |
| 405 | 411 | |
| 412 | +// Vector permutation | |
| 413 | +inline | |
| 414 | +GVector perm(const GVector &v, const int *p) | |
| 415 | +{ | |
| 416 | + GVector result(v.m_num); | |
| 417 | + if (p == NULL) | |
| 418 | + result = v; | |
| 419 | + else { | |
| 420 | + for (int i = 0; i < v.m_num; ++i) | |
| 421 | + result.m_data[i] = v.m_data[p[i]]; | |
| 422 | + } | |
| 423 | + return result; | |
| 424 | +} | |
| 425 | + | |
| 426 | +// Inverse vector permutation | |
| 427 | +inline | |
| 428 | +GVector iperm(const GVector &v, const int *p) | |
| 429 | +{ | |
| 430 | + GVector result(v.m_num); | |
| 431 | + if (p == NULL) | |
| 432 | + result = v; | |
| 433 | + else { | |
| 434 | + for (int i = 0; i < v.m_num; ++i) | |
| 435 | + result.m_data[p[i]] = v.m_data[i]; | |
| 436 | + } | |
| 437 | + return result; | |
| 438 | +} | |
| 439 | + | |
| 406 | 440 | // Vector acos |
| 407 | 441 | inline |
| 408 | 442 | GVector acos(const GVector &v) |
| 409 | 443 | { |
| 410 | 444 | GVector result(v.m_num); |
| 411 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 445 | + for (int i = 0; i < v.m_num; ++i) | |
| 412 | 446 | result.m_data[i] = acos(v.m_data[i]); |
| 413 | 447 | return result; |
| 414 | 448 | } |
| ... | ... | @@ -418,7 +452,7 @@ inline |
| 418 | 452 | GVector acosh(const GVector &v) |
| 419 | 453 | { |
| 420 | 454 | GVector result(v.m_num); |
| 421 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 455 | + for (int i = 0; i < v.m_num; ++i) | |
| 422 | 456 | result.m_data[i] = acosh(v.m_data[i]); |
| 423 | 457 | return result; |
| 424 | 458 | } |
| ... | ... | @@ -428,7 +462,7 @@ inline |
| 428 | 462 | GVector asin(const GVector &v) |
| 429 | 463 | { |
| 430 | 464 | GVector result(v.m_num); |
| 431 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 465 | + for (int i = 0; i < v.m_num; ++i) | |
| 432 | 466 | result.m_data[i] = asin(v.m_data[i]); |
| 433 | 467 | return result; |
| 434 | 468 | } |
| ... | ... | @@ -438,7 +472,7 @@ inline |
| 438 | 472 | GVector asinh(const GVector &v) |
| 439 | 473 | { |
| 440 | 474 | GVector result(v.m_num); |
| 441 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 475 | + for (int i = 0; i < v.m_num; ++i) | |
| 442 | 476 | result.m_data[i] = asinh(v.m_data[i]); |
| 443 | 477 | return result; |
| 444 | 478 | } |
| ... | ... | @@ -448,7 +482,7 @@ inline |
| 448 | 482 | GVector atan(const GVector &v) |
| 449 | 483 | { |
| 450 | 484 | GVector result(v.m_num); |
| 451 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 485 | + for (int i = 0; i < v.m_num; ++i) | |
| 452 | 486 | result.m_data[i] = atan(v.m_data[i]); |
| 453 | 487 | return result; |
| 454 | 488 | } |
| ... | ... | @@ -458,7 +492,7 @@ inline |
| 458 | 492 | GVector atanh(const GVector &v) |
| 459 | 493 | { |
| 460 | 494 | GVector result(v.m_num); |
| 461 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 495 | + for (int i = 0; i < v.m_num; ++i) | |
| 462 | 496 | result.m_data[i] = atanh(v.m_data[i]); |
| 463 | 497 | return result; |
| 464 | 498 | } |
| ... | ... | @@ -468,7 +502,7 @@ inline |
| 468 | 502 | GVector cos(const GVector &v) |
| 469 | 503 | { |
| 470 | 504 | GVector result(v.m_num); |
| 471 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 505 | + for (int i = 0; i < v.m_num; ++i) | |
| 472 | 506 | result.m_data[i] = cos(v.m_data[i]); |
| 473 | 507 | return result; |
| 474 | 508 | } |
| ... | ... | @@ -478,7 +512,7 @@ inline |
| 478 | 512 | GVector cosh(const GVector &v) |
| 479 | 513 | { |
| 480 | 514 | GVector result(v.m_num); |
| 481 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 515 | + for (int i = 0; i < v.m_num; ++i) | |
| 482 | 516 | result.m_data[i] = cosh(v.m_data[i]); |
| 483 | 517 | return result; |
| 484 | 518 | } |
| ... | ... | @@ -488,7 +522,7 @@ inline |
| 488 | 522 | GVector exp(const GVector &v) |
| 489 | 523 | { |
| 490 | 524 | GVector result(v.m_num); |
| 491 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 525 | + for (int i = 0; i < v.m_num; ++i) | |
| 492 | 526 | result.m_data[i] = exp(v.m_data[i]); |
| 493 | 527 | return result; |
| 494 | 528 | } |
| ... | ... | @@ -498,7 +532,7 @@ inline |
| 498 | 532 | GVector fabs(const GVector &v) |
| 499 | 533 | { |
| 500 | 534 | GVector result(v.m_num); |
| 501 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 535 | + for (int i = 0; i < v.m_num; ++i) | |
| 502 | 536 | result.m_data[i] = fabs(v.m_data[i]); |
| 503 | 537 | return result; |
| 504 | 538 | } |
| ... | ... | @@ -508,7 +542,7 @@ inline |
| 508 | 542 | GVector log(const GVector &v) |
| 509 | 543 | { |
| 510 | 544 | GVector result(v.m_num); |
| 511 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 545 | + for (int i = 0; i < v.m_num; ++i) | |
| 512 | 546 | result.m_data[i] = log(v.m_data[i]); |
| 513 | 547 | return result; |
| 514 | 548 | } |
| ... | ... | @@ -518,7 +552,7 @@ inline |
| 518 | 552 | GVector log10(const GVector &v) |
| 519 | 553 | { |
| 520 | 554 | GVector result(v.m_num); |
| 521 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 555 | + for (int i = 0; i < v.m_num; ++i) | |
| 522 | 556 | result.m_data[i] = log10(v.m_data[i]); |
| 523 | 557 | return result; |
| 524 | 558 | } |
| ... | ... | @@ -528,7 +562,7 @@ inline |
| 528 | 562 | GVector sin(const GVector &v) |
| 529 | 563 | { |
| 530 | 564 | GVector result(v.m_num); |
| 531 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 565 | + for (int i = 0; i < v.m_num; ++i) | |
| 532 | 566 | result.m_data[i] = sin(v.m_data[i]); |
| 533 | 567 | return result; |
| 534 | 568 | } |
| ... | ... | @@ -538,7 +572,7 @@ inline |
| 538 | 572 | GVector sinh(const GVector &v) |
| 539 | 573 | { |
| 540 | 574 | GVector result(v.m_num); |
| 541 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 575 | + for (int i = 0; i < v.m_num; ++i) | |
| 542 | 576 | result.m_data[i] = sinh(v.m_data[i]); |
| 543 | 577 | return result; |
| 544 | 578 | } |
| ... | ... | @@ -548,7 +582,7 @@ inline |
| 548 | 582 | GVector sqrt(const GVector &v) |
| 549 | 583 | { |
| 550 | 584 | GVector result(v.m_num); |
| 551 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 585 | + for (int i = 0; i < v.m_num; ++i) | |
| 552 | 586 | result.m_data[i] = sqrt(v.m_data[i]); |
| 553 | 587 | return result; |
| 554 | 588 | } |
| ... | ... | @@ -558,7 +592,7 @@ inline |
| 558 | 592 | GVector tan(const GVector &v) |
| 559 | 593 | { |
| 560 | 594 | GVector result(v.m_num); |
| 561 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 595 | + for (int i = 0; i < v.m_num; ++i) | |
| 562 | 596 | result.m_data[i] = tan(v.m_data[i]); |
| 563 | 597 | return result; |
| 564 | 598 | } |
| ... | ... | @@ -568,7 +602,7 @@ inline |
| 568 | 602 | GVector tanh(const GVector &v) |
| 569 | 603 | { |
| 570 | 604 | GVector result(v.m_num); |
| 571 | - for (unsigned i = 0; i < v.m_num; ++i) | |
| 605 | + for (int i = 0; i < v.m_num; ++i) | |
| 572 | 606 | result.m_data[i] = tanh(v.m_data[i]); |
| 573 | 607 | return result; |
| 574 | 608 | } |
| ... | ... | @@ -579,7 +613,7 @@ int operator== (const GVector &a, const GVector &b) |
| 579 | 613 | { |
| 580 | 614 | int result = 1; |
| 581 | 615 | if (a.m_num == b.m_num) { |
| 582 | - for (unsigned i = 0; i < a.m_num; ++i) { | |
| 616 | + for (int i = 0; i < a.m_num; ++i) { | |
| 583 | 617 | if (a.m_data[i] != b.m_data[i]) { |
| 584 | 618 | result = 0; |
| 585 | 619 | break; |
| ... | ... | @@ -597,7 +631,7 @@ int operator!= (const GVector &a, const GVector &b) |
| 597 | 631 | { |
| 598 | 632 | int result = 0; |
| 599 | 633 | if (a.m_num == b.m_num) { |
| 600 | - for (unsigned i = 0; i < a.m_num; ++i) { | |
| 634 | + for (int i = 0; i < a.m_num; ++i) { | |
| 601 | 635 | if (a.m_data[i] != b.m_data[i]) { |
| 602 | 636 | result = 1; |
| 603 | 637 | break; | ... | ... |
src/Makefile.am
| ... | ... | @@ -3,7 +3,10 @@ |
| 3 | 3 | files = GException.hpp GException.cpp \ |
| 4 | 4 | GVector.hpp GVector.cpp \ |
| 5 | 5 | GMatrix.hpp GMatrix.cpp \ |
| 6 | - GSymMatrix.hpp GSymMatrix.cpp | |
| 6 | + GSymMatrix.hpp GSymMatrix.cpp \ | |
| 7 | + GSparseMatrix.hpp GSparseMatrix.cpp \ | |
| 8 | + GSparseSymbolic.hpp GSparseSymbolic.cpp \ | |
| 9 | + GSparseNumeric.hpp GSparseNumeric.cpp | |
| 7 | 10 | |
| 8 | 11 | lib_LTLIBRARIES = libgamma.la |
| 9 | 12 | libgamma_la_SOURCES = $(files) | ... | ... |
src/Makefile.in
| 1 | -# Makefile.in generated by automake 1.6.3 from Makefile.am. | |
| 1 | +# Makefile.in generated by automake 1.9.2 from Makefile.am. | |
| 2 | 2 | # @configure_input@ |
| 3 | 3 | |
| 4 | -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 | |
| 5 | -# Free Software Foundation, Inc. | |
| 4 | +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | |
| 5 | +# 2003, 2004 Free Software Foundation, Inc. | |
| 6 | 6 | # This Makefile.in is free software; the Free Software Foundation |
| 7 | 7 | # gives unlimited permission to copy and/or distribute it, |
| 8 | 8 | # with or without modifications, as long as this notice is preserved. |
| ... | ... | @@ -13,168 +13,234 @@ |
| 13 | 13 | # PARTICULAR PURPOSE. |
| 14 | 14 | |
| 15 | 15 | @SET_MAKE@ |
| 16 | -SHELL = @SHELL@ | |
| 16 | + | |
| 17 | +SOURCES = $(libgamma_la_SOURCES) | |
| 17 | 18 | |
| 18 | 19 | srcdir = @srcdir@ |
| 19 | 20 | top_srcdir = @top_srcdir@ |
| 20 | 21 | VPATH = @srcdir@ |
| 21 | -prefix = @prefix@ | |
| 22 | -exec_prefix = @exec_prefix@ | |
| 23 | - | |
| 24 | -bindir = @bindir@ | |
| 25 | -sbindir = @sbindir@ | |
| 26 | -libexecdir = @libexecdir@ | |
| 27 | -datadir = @datadir@ | |
| 28 | -sysconfdir = @sysconfdir@ | |
| 29 | -sharedstatedir = @sharedstatedir@ | |
| 30 | -localstatedir = @localstatedir@ | |
| 31 | -libdir = @libdir@ | |
| 32 | -infodir = @infodir@ | |
| 33 | -mandir = @mandir@ | |
| 34 | -includedir = @includedir@ | |
| 35 | -oldincludedir = /usr/include | |
| 36 | 22 | pkgdatadir = $(datadir)/@PACKAGE@ |
| 37 | 23 | pkglibdir = $(libdir)/@PACKAGE@ |
| 38 | 24 | pkgincludedir = $(includedir)/@PACKAGE@ |
| 39 | 25 | top_builddir = .. |
| 40 | - | |
| 41 | -ACLOCAL = @ACLOCAL@ | |
| 42 | -AUTOCONF = @AUTOCONF@ | |
| 43 | -AUTOMAKE = @AUTOMAKE@ | |
| 44 | -AUTOHEADER = @AUTOHEADER@ | |
| 45 | - | |
| 46 | 26 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd |
| 47 | 27 | INSTALL = @INSTALL@ |
| 48 | -INSTALL_PROGRAM = @INSTALL_PROGRAM@ | |
| 49 | -INSTALL_DATA = @INSTALL_DATA@ | |
| 50 | 28 | install_sh_DATA = $(install_sh) -c -m 644 |
| 51 | 29 | install_sh_PROGRAM = $(install_sh) -c |
| 52 | 30 | install_sh_SCRIPT = $(install_sh) -c |
| 53 | -INSTALL_SCRIPT = @INSTALL_SCRIPT@ | |
| 54 | 31 | INSTALL_HEADER = $(INSTALL_DATA) |
| 55 | -transform = @program_transform_name@ | |
| 32 | +transform = $(program_transform_name) | |
| 56 | 33 | NORMAL_INSTALL = : |
| 57 | 34 | PRE_INSTALL = : |
| 58 | 35 | POST_INSTALL = : |
| 59 | 36 | NORMAL_UNINSTALL = : |
| 60 | 37 | PRE_UNINSTALL = : |
| 61 | 38 | POST_UNINSTALL = : |
| 62 | -host_alias = @host_alias@ | |
| 39 | +build_triplet = @build@ | |
| 63 | 40 | host_triplet = @host@ |
| 64 | - | |
| 65 | -EXEEXT = @EXEEXT@ | |
| 66 | -OBJEXT = @OBJEXT@ | |
| 67 | -PATH_SEPARATOR = @PATH_SEPARATOR@ | |
| 41 | +subdir = src | |
| 42 | +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | |
| 43 | +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | |
| 44 | +am__aclocal_m4_deps = $(top_srcdir)/configure.ac | |
| 45 | +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ | |
| 46 | + $(ACLOCAL_M4) | |
| 47 | +mkinstalldirs = $(install_sh) -d | |
| 48 | +CONFIG_HEADER = $(top_builddir)/config.h | |
| 49 | +CONFIG_CLEAN_FILES = | |
| 50 | +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; | |
| 51 | +am__vpath_adj = case $$p in \ | |
| 52 | + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ | |
| 53 | + *) f=$$p;; \ | |
| 54 | + esac; | |
| 55 | +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; | |
| 56 | +am__installdirs = "$(DESTDIR)$(libdir)" | |
| 57 | +libLTLIBRARIES_INSTALL = $(INSTALL) | |
| 58 | +LTLIBRARIES = $(lib_LTLIBRARIES) | |
| 59 | +libgamma_la_LIBADD = | |
| 60 | +am__objects_1 = GException.lo GVector.lo GMatrix.lo GSymMatrix.lo \ | |
| 61 | + GSparseMatrix.lo GSparseSymbolic.lo GSparseNumeric.lo | |
| 62 | +am_libgamma_la_OBJECTS = $(am__objects_1) | |
| 63 | +libgamma_la_OBJECTS = $(am_libgamma_la_OBJECTS) | |
| 64 | +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) | |
| 65 | +depcomp = | |
| 66 | +am__depfiles_maybe = | |
| 67 | +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ | |
| 68 | + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 69 | +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ | |
| 70 | + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | |
| 71 | + $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 72 | +CXXLD = $(CXX) | |
| 73 | +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) \ | |
| 74 | + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
| 75 | +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ | |
| 76 | + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | |
| 77 | +LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \ | |
| 78 | + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | |
| 79 | + $(AM_CFLAGS) $(CFLAGS) | |
| 80 | +CCLD = $(CC) | |
| 81 | +LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ | |
| 82 | + $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
| 83 | +SOURCES = $(libgamma_la_SOURCES) | |
| 84 | +DIST_SOURCES = $(libgamma_la_SOURCES) | |
| 85 | +ETAGS = etags | |
| 86 | +CTAGS = ctags | |
| 87 | +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | |
| 88 | +ACLOCAL = @ACLOCAL@ | |
| 68 | 89 | AMTAR = @AMTAR@ |
| 69 | 90 | AR = @AR@ |
| 70 | -AS = @AS@ | |
| 91 | +AUTOCONF = @AUTOCONF@ | |
| 92 | +AUTOHEADER = @AUTOHEADER@ | |
| 93 | +AUTOMAKE = @AUTOMAKE@ | |
| 71 | 94 | AWK = @AWK@ |
| 72 | 95 | CC = @CC@ |
| 96 | +CFLAGS = @CFLAGS@ | |
| 97 | +CPP = @CPP@ | |
| 98 | +CPPFLAGS = @CPPFLAGS@ | |
| 73 | 99 | CXX = @CXX@ |
| 74 | 100 | CXXCPP = @CXXCPP@ |
| 75 | -DEPDIR = @DEPDIR@ | |
| 76 | -DLLTOOL = @DLLTOOL@ | |
| 101 | +CXXFLAGS = @CXXFLAGS@ | |
| 102 | +CYGPATH_W = @CYGPATH_W@ | |
| 103 | +DEFS = @DEFS@ | |
| 77 | 104 | ECHO = @ECHO@ |
| 105 | +ECHO_C = @ECHO_C@ | |
| 106 | +ECHO_N = @ECHO_N@ | |
| 107 | +ECHO_T = @ECHO_T@ | |
| 78 | 108 | EGREP = @EGREP@ |
| 109 | +EXEEXT = @EXEEXT@ | |
| 79 | 110 | F77 = @F77@ |
| 80 | -GCJ = @GCJ@ | |
| 81 | -GCJFLAGS = @GCJFLAGS@ | |
| 111 | +FFLAGS = @FFLAGS@ | |
| 112 | +INSTALL_DATA = @INSTALL_DATA@ | |
| 113 | +INSTALL_PROGRAM = @INSTALL_PROGRAM@ | |
| 114 | +INSTALL_SCRIPT = @INSTALL_SCRIPT@ | |
| 82 | 115 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ |
| 116 | +LDFLAGS = @LDFLAGS@ | |
| 117 | +LIBOBJS = @LIBOBJS@ | |
| 118 | +LIBS = @LIBS@ | |
| 83 | 119 | LIBTOOL = @LIBTOOL@ |
| 120 | +LIBTOOL_DEPS = @LIBTOOL_DEPS@ | |
| 84 | 121 | LN_S = @LN_S@ |
| 122 | +LTLIBOBJS = @LTLIBOBJS@ | |
| 85 | 123 | MAINT = @MAINT@ |
| 86 | -OBJDUMP = @OBJDUMP@ | |
| 124 | +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ | |
| 125 | +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ | |
| 126 | +MAKEINFO = @MAKEINFO@ | |
| 127 | +OBJEXT = @OBJEXT@ | |
| 87 | 128 | PACKAGE = @PACKAGE@ |
| 129 | +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | |
| 130 | +PACKAGE_NAME = @PACKAGE_NAME@ | |
| 131 | +PACKAGE_STRING = @PACKAGE_STRING@ | |
| 132 | +PACKAGE_TARNAME = @PACKAGE_TARNAME@ | |
| 133 | +PACKAGE_VERSION = @PACKAGE_VERSION@ | |
| 134 | +PATH_SEPARATOR = @PATH_SEPARATOR@ | |
| 88 | 135 | RANLIB = @RANLIB@ |
| 89 | -RC = @RC@ | |
| 136 | +SET_MAKE = @SET_MAKE@ | |
| 137 | +SHELL = @SHELL@ | |
| 90 | 138 | STRIP = @STRIP@ |
| 91 | 139 | VERSION = @VERSION@ |
| 92 | -am__include = @am__include@ | |
| 93 | -am__quote = @am__quote@ | |
| 140 | +ac_ct_AR = @ac_ct_AR@ | |
| 141 | +ac_ct_CC = @ac_ct_CC@ | |
| 142 | +ac_ct_CXX = @ac_ct_CXX@ | |
| 143 | +ac_ct_F77 = @ac_ct_F77@ | |
| 144 | +ac_ct_RANLIB = @ac_ct_RANLIB@ | |
| 145 | +ac_ct_STRIP = @ac_ct_STRIP@ | |
| 146 | +am__leading_dot = @am__leading_dot@ | |
| 147 | +am__tar = @am__tar@ | |
| 148 | +am__untar = @am__untar@ | |
| 149 | +bindir = @bindir@ | |
| 150 | +build = @build@ | |
| 151 | +build_alias = @build_alias@ | |
| 152 | +build_cpu = @build_cpu@ | |
| 153 | +build_os = @build_os@ | |
| 154 | +build_vendor = @build_vendor@ | |
| 155 | +datadir = @datadir@ | |
| 156 | +exec_prefix = @exec_prefix@ | |
| 157 | +host = @host@ | |
| 158 | +host_alias = @host_alias@ | |
| 159 | +host_cpu = @host_cpu@ | |
| 160 | +host_os = @host_os@ | |
| 161 | +host_vendor = @host_vendor@ | |
| 162 | +includedir = @includedir@ | |
| 163 | +infodir = @infodir@ | |
| 94 | 164 | install_sh = @install_sh@ |
| 95 | - | |
| 165 | +libdir = @libdir@ | |
| 166 | +libexecdir = @libexecdir@ | |
| 167 | +localstatedir = @localstatedir@ | |
| 168 | +mandir = @mandir@ | |
| 169 | +mkdir_p = @mkdir_p@ | |
| 170 | +oldincludedir = @oldincludedir@ | |
| 171 | +prefix = @prefix@ | |
| 172 | +program_transform_name = @program_transform_name@ | |
| 173 | +sbindir = @sbindir@ | |
| 174 | +sharedstatedir = @sharedstatedir@ | |
| 175 | +sysconfdir = @sysconfdir@ | |
| 176 | +target_alias = @target_alias@ | |
| 96 | 177 | files = GException.hpp GException.cpp \ |
| 97 | 178 | GVector.hpp GVector.cpp \ |
| 98 | 179 | GMatrix.hpp GMatrix.cpp \ |
| 99 | - GSymMatrix.hpp GSymMatrix.cpp | |
| 100 | - | |
| 180 | + GSymMatrix.hpp GSymMatrix.cpp \ | |
| 181 | + GSparseMatrix.hpp GSparseMatrix.cpp \ | |
| 182 | + GSparseSymbolic.hpp GSparseSymbolic.cpp \ | |
| 183 | + GSparseNumeric.hpp GSparseNumeric.cpp | |
| 101 | 184 | |
| 102 | 185 | lib_LTLIBRARIES = libgamma.la |
| 103 | 186 | libgamma_la_SOURCES = $(files) |
| 104 | -subdir = src | |
| 105 | -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs | |
| 106 | -CONFIG_HEADER = $(top_builddir)/config.h | |
| 107 | -CONFIG_CLEAN_FILES = | |
| 108 | -LTLIBRARIES = $(lib_LTLIBRARIES) | |
| 109 | - | |
| 110 | -libgamma_la_LDFLAGS = | |
| 111 | -libgamma_la_LIBADD = | |
| 112 | -am__objects_1 = GException.lo GVector.lo GMatrix.lo GSymMatrix.lo | |
| 113 | -am_libgamma_la_OBJECTS = $(am__objects_1) | |
| 114 | -libgamma_la_OBJECTS = $(am_libgamma_la_OBJECTS) | |
| 115 | - | |
| 116 | -DEFS = @DEFS@ | |
| 117 | -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) | |
| 118 | -CPPFLAGS = @CPPFLAGS@ | |
| 119 | -LDFLAGS = @LDFLAGS@ | |
| 120 | -LIBS = @LIBS@ | |
| 121 | -depcomp = | |
| 122 | -am__depfiles_maybe = | |
| 123 | -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ | |
| 124 | - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 125 | -LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ | |
| 126 | - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | |
| 127 | - $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 128 | -CXXLD = $(CXX) | |
| 129 | -CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ | |
| 130 | - $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
| 131 | -CXXFLAGS = @CXXFLAGS@ | |
| 132 | -CFLAGS = @CFLAGS@ | |
| 133 | -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ | |
| 134 | - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | |
| 135 | -LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ | |
| 136 | - $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | |
| 137 | -CCLD = $(CC) | |
| 138 | -LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ | |
| 139 | - $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
| 140 | -DIST_SOURCES = $(libgamma_la_SOURCES) | |
| 141 | -DIST_COMMON = Makefile.am Makefile.in | |
| 142 | -SOURCES = $(libgamma_la_SOURCES) | |
| 143 | - | |
| 144 | 187 | all: all-am |
| 145 | 188 | |
| 146 | 189 | .SUFFIXES: |
| 147 | 190 | .SUFFIXES: .cpp .lo .o .obj |
| 148 | -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) | |
| 191 | +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) | |
| 192 | + @for dep in $?; do \ | |
| 193 | + case '$(am__configure_deps)' in \ | |
| 194 | + *$$dep*) \ | |
| 195 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ | |
| 196 | + && exit 0; \ | |
| 197 | + exit 1;; \ | |
| 198 | + esac; \ | |
| 199 | + done; \ | |
| 200 | + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps src/Makefile'; \ | |
| 149 | 201 | cd $(top_srcdir) && \ |
| 150 | - $(AUTOMAKE) --gnu src/Makefile | |
| 151 | -Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status | |
| 152 | - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) | |
| 153 | -libLTLIBRARIES_INSTALL = $(INSTALL) | |
| 202 | + $(AUTOMAKE) --gnu --ignore-deps src/Makefile | |
| 203 | +.PRECIOUS: Makefile | |
| 204 | +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | |
| 205 | + @case '$?' in \ | |
| 206 | + *config.status*) \ | |
| 207 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ | |
| 208 | + *) \ | |
| 209 | + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | |
| 210 | + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | |
| 211 | + esac; | |
| 212 | + | |
| 213 | +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) | |
| 214 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
| 215 | + | |
| 216 | +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) | |
| 217 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
| 218 | +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) | |
| 219 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
| 154 | 220 | install-libLTLIBRARIES: $(lib_LTLIBRARIES) |
| 155 | 221 | @$(NORMAL_INSTALL) |
| 156 | - $(mkinstalldirs) $(DESTDIR)$(libdir) | |
| 222 | + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" | |
| 157 | 223 | @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ |
| 158 | 224 | if test -f $$p; then \ |
| 159 | - f="`echo $$p | sed -e 's|^.*/||'`"; \ | |
| 160 | - echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f"; \ | |
| 161 | - $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f; \ | |
| 225 | + f=$(am__strip_dir) \ | |
| 226 | + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ | |
| 227 | + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ | |
| 162 | 228 | else :; fi; \ |
| 163 | 229 | done |
| 164 | 230 | |
| 165 | 231 | uninstall-libLTLIBRARIES: |
| 166 | 232 | @$(NORMAL_UNINSTALL) |
| 167 | - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ | |
| 168 | - p="`echo $$p | sed -e 's|^.*/||'`"; \ | |
| 169 | - echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \ | |
| 170 | - $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ | |
| 233 | + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ | |
| 234 | + p=$(am__strip_dir) \ | |
| 235 | + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ | |
| 236 | + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ | |
| 171 | 237 | done |
| 172 | 238 | |
| 173 | 239 | clean-libLTLIBRARIES: |
| 174 | 240 | -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) |
| 175 | 241 | @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ |
| 176 | 242 | dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ |
| 177 | - test -z "$dir" && dir=.; \ | |
| 243 | + test "$$dir" != "$$p" || dir=.; \ | |
| 178 | 244 | echo "rm -f \"$${dir}/so_locations\""; \ |
| 179 | 245 | rm -f "$${dir}/so_locations"; \ |
| 180 | 246 | done |
| ... | ... | @@ -182,19 +248,19 @@ libgamma.la: $(libgamma_la_OBJECTS) $(libgamma_la_DEPENDENCIES) |
| 182 | 248 | $(CXXLINK) -rpath $(libdir) $(libgamma_la_LDFLAGS) $(libgamma_la_OBJECTS) $(libgamma_la_LIBADD) $(LIBS) |
| 183 | 249 | |
| 184 | 250 | mostlyclean-compile: |
| 185 | - -rm -f *.$(OBJEXT) core *.core | |
| 251 | + -rm -f *.$(OBJEXT) | |
| 186 | 252 | |
| 187 | 253 | distclean-compile: |
| 188 | 254 | -rm -f *.tab.c |
| 189 | 255 | |
| 190 | 256 | .cpp.o: |
| 191 | - $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< | |
| 257 | + $(CXXCOMPILE) -c -o $@ $< | |
| 192 | 258 | |
| 193 | 259 | .cpp.obj: |
| 194 | - $(CXXCOMPILE) -c -o $@ `cygpath -w $<` | |
| 260 | + $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` | |
| 195 | 261 | |
| 196 | 262 | .cpp.lo: |
| 197 | - $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< | |
| 263 | + $(LTCXXCOMPILE) -c -o $@ $< | |
| 198 | 264 | |
| 199 | 265 | mostlyclean-libtool: |
| 200 | 266 | -rm -f *.lo |
| ... | ... | @@ -206,11 +272,6 @@ distclean-libtool: |
| 206 | 272 | -rm -f libtool |
| 207 | 273 | uninstall-info-am: |
| 208 | 274 | |
| 209 | -ETAGS = etags | |
| 210 | -ETAGSFLAGS = | |
| 211 | - | |
| 212 | -tags: TAGS | |
| 213 | - | |
| 214 | 275 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) |
| 215 | 276 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ |
| 216 | 277 | unique=`for i in $$list; do \ |
| ... | ... | @@ -219,6 +280,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) |
| 219 | 280 | $(AWK) ' { files[$$0] = 1; } \ |
| 220 | 281 | END { for (i in files) print i; }'`; \ |
| 221 | 282 | mkid -fID $$unique |
| 283 | +tags: TAGS | |
| 222 | 284 | |
| 223 | 285 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ |
| 224 | 286 | $(TAGS_FILES) $(LISP) |
| ... | ... | @@ -230,8 +292,24 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ |
| 230 | 292 | done | \ |
| 231 | 293 | $(AWK) ' { files[$$0] = 1; } \ |
| 232 | 294 | END { for (i in files) print i; }'`; \ |
| 233 | - test -z "$(ETAGS_ARGS)$$tags$$unique" \ | |
| 234 | - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | |
| 295 | + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ | |
| 296 | + test -n "$$unique" || unique=$$empty_fix; \ | |
| 297 | + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | |
| 298 | + $$tags $$unique; \ | |
| 299 | + fi | |
| 300 | +ctags: CTAGS | |
| 301 | +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | |
| 302 | + $(TAGS_FILES) $(LISP) | |
| 303 | + tags=; \ | |
| 304 | + here=`pwd`; \ | |
| 305 | + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | |
| 306 | + unique=`for i in $$list; do \ | |
| 307 | + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | |
| 308 | + done | \ | |
| 309 | + $(AWK) ' { files[$$0] = 1; } \ | |
| 310 | + END { for (i in files) print i; }'`; \ | |
| 311 | + test -z "$(CTAGS_ARGS)$$tags$$unique" \ | |
| 312 | + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ | |
| 235 | 313 | $$tags $$unique |
| 236 | 314 | |
| 237 | 315 | GTAGS: |
| ... | ... | @@ -240,19 +318,21 @@ GTAGS: |
| 240 | 318 | && gtags -i $(GTAGS_ARGS) $$here |
| 241 | 319 | |
| 242 | 320 | distclean-tags: |
| 243 | - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH | |
| 244 | -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | |
| 245 | - | |
| 246 | -top_distdir = .. | |
| 247 | -distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) | |
| 321 | + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags | |
| 248 | 322 | |
| 249 | 323 | distdir: $(DISTFILES) |
| 250 | - @list='$(DISTFILES)'; for file in $$list; do \ | |
| 324 | + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ | |
| 325 | + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ | |
| 326 | + list='$(DISTFILES)'; for file in $$list; do \ | |
| 327 | + case $$file in \ | |
| 328 | + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ | |
| 329 | + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ | |
| 330 | + esac; \ | |
| 251 | 331 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ |
| 252 | 332 | dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ |
| 253 | 333 | if test "$$dir" != "$$file" && test "$$dir" != "."; then \ |
| 254 | 334 | dir="/$$dir"; \ |
| 255 | - $(mkinstalldirs) "$(distdir)$$dir"; \ | |
| 335 | + $(mkdir_p) "$(distdir)$$dir"; \ | |
| 256 | 336 | else \ |
| 257 | 337 | dir=''; \ |
| 258 | 338 | fi; \ |
| ... | ... | @@ -270,10 +350,10 @@ distdir: $(DISTFILES) |
| 270 | 350 | check-am: all-am |
| 271 | 351 | check: check-am |
| 272 | 352 | all-am: Makefile $(LTLIBRARIES) |
| 273 | - | |
| 274 | 353 | installdirs: |
| 275 | - $(mkinstalldirs) $(DESTDIR)$(libdir) | |
| 276 | - | |
| 354 | + for dir in "$(DESTDIR)$(libdir)"; do \ | |
| 355 | + test -z "$$dir" || $(mkdir_p) "$$dir"; \ | |
| 356 | + done | |
| 277 | 357 | install: install-am |
| 278 | 358 | install-exec: install-exec-am |
| 279 | 359 | install-data: install-data-am |
| ... | ... | @@ -285,7 +365,7 @@ install-am: all-am |
| 285 | 365 | installcheck: installcheck-am |
| 286 | 366 | install-strip: |
| 287 | 367 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ |
| 288 | - INSTALL_STRIP_FLAG=-s \ | |
| 368 | + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | |
| 289 | 369 | `test -z '$(STRIP)' || \ |
| 290 | 370 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install |
| 291 | 371 | mostlyclean-generic: |
| ... | ... | @@ -293,7 +373,7 @@ mostlyclean-generic: |
| 293 | 373 | clean-generic: |
| 294 | 374 | |
| 295 | 375 | distclean-generic: |
| 296 | - -rm -f Makefile $(CONFIG_CLEAN_FILES) | |
| 376 | + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) | |
| 297 | 377 | |
| 298 | 378 | maintainer-clean-generic: |
| 299 | 379 | @echo "This command is intended for maintainers to use" |
| ... | ... | @@ -304,7 +384,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ |
| 304 | 384 | mostlyclean-am |
| 305 | 385 | |
| 306 | 386 | distclean: distclean-am |
| 307 | - | |
| 387 | + -rm -f Makefile | |
| 308 | 388 | distclean-am: clean-am distclean-compile distclean-generic \ |
| 309 | 389 | distclean-libtool distclean-tags |
| 310 | 390 | |
| ... | ... | @@ -312,6 +392,8 @@ dvi: dvi-am |
| 312 | 392 | |
| 313 | 393 | dvi-am: |
| 314 | 394 | |
| 395 | +html: html-am | |
| 396 | + | |
| 315 | 397 | info: info-am |
| 316 | 398 | |
| 317 | 399 | info-am: |
| ... | ... | @@ -327,7 +409,7 @@ install-man: |
| 327 | 409 | installcheck-am: |
| 328 | 410 | |
| 329 | 411 | maintainer-clean: maintainer-clean-am |
| 330 | - | |
| 412 | + -rm -f Makefile | |
| 331 | 413 | maintainer-clean-am: distclean-am maintainer-clean-generic |
| 332 | 414 | |
| 333 | 415 | mostlyclean: mostlyclean-am |
| ... | ... | @@ -335,17 +417,26 @@ mostlyclean: mostlyclean-am |
| 335 | 417 | mostlyclean-am: mostlyclean-compile mostlyclean-generic \ |
| 336 | 418 | mostlyclean-libtool |
| 337 | 419 | |
| 420 | +pdf: pdf-am | |
| 421 | + | |
| 422 | +pdf-am: | |
| 423 | + | |
| 424 | +ps: ps-am | |
| 425 | + | |
| 426 | +ps-am: | |
| 427 | + | |
| 338 | 428 | uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES |
| 339 | 429 | |
| 340 | -.PHONY: GTAGS all all-am check check-am clean clean-generic \ | |
| 341 | - clean-libLTLIBRARIES clean-libtool distclean distclean-compile \ | |
| 342 | - distclean-generic distclean-libtool distclean-tags distdir dvi \ | |
| 343 | - dvi-am info info-am install install-am install-data \ | |
| 344 | - install-data-am install-exec install-exec-am install-info \ | |
| 345 | - install-info-am install-libLTLIBRARIES install-man \ | |
| 346 | - install-strip installcheck installcheck-am installdirs \ | |
| 347 | - maintainer-clean maintainer-clean-generic mostlyclean \ | |
| 348 | - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ | |
| 430 | +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ | |
| 431 | + clean-libLTLIBRARIES clean-libtool ctags distclean \ | |
| 432 | + distclean-compile distclean-generic distclean-libtool \ | |
| 433 | + distclean-tags distdir dvi dvi-am html html-am info info-am \ | |
| 434 | + install install-am install-data install-data-am install-exec \ | |
| 435 | + install-exec-am install-info install-info-am \ | |
| 436 | + install-libLTLIBRARIES install-man install-strip installcheck \ | |
| 437 | + installcheck-am installdirs maintainer-clean \ | |
| 438 | + maintainer-clean-generic mostlyclean mostlyclean-compile \ | |
| 439 | + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ | |
| 349 | 440 | tags uninstall uninstall-am uninstall-info-am \ |
| 350 | 441 | uninstall-libLTLIBRARIES |
| 351 | 442 | ... | ... |
test/Makefile.am
| 1 | 1 | ## Process this file with automake to produce Makefile.in |
| 2 | 2 | |
| 3 | -check_PROGRAMS = test_GVector test_GMatrix test_GSymMatrix | |
| 4 | -TESTS = test_GVector test_GMatrix test_GSymMatrix | |
| 3 | +check_PROGRAMS = test_GVector \ | |
| 4 | + test_GMatrix \ | |
| 5 | + test_GSymMatrix \ | |
| 6 | + test_GSparseMatrix | |
| 7 | +TESTS = test_GVector \ | |
| 8 | + test_GMatrix \ | |
| 9 | + test_GSymMatrix \ | |
| 10 | + test_GSparseMatrix | |
| 5 | 11 | test_GVector_SOURCES = test_GVector.cpp |
| 6 | 12 | test_GVector_LDADD = ../src/libgamma.la |
| 7 | 13 | test_GMatrix_SOURCES = test_GMatrix.cpp |
| 8 | 14 | test_GMatrix_LDADD = ../src/libgamma.la |
| 9 | 15 | test_GSymMatrix_SOURCES = test_GSymMatrix.cpp |
| 10 | 16 | test_GSymMatrix_LDADD = ../src/libgamma.la |
| 17 | +test_GSparseMatrix_SOURCES = test_GSparseMatrix.cpp | |
| 18 | +test_GSparseMatrix_LDADD = ../src/libgamma.la | ... | ... |
test/Makefile.in
| 1 | -# Makefile.in generated by automake 1.6.3 from Makefile.am. | |
| 1 | +# Makefile.in generated by automake 1.9.2 from Makefile.am. | |
| 2 | 2 | # @configure_input@ |
| 3 | 3 | |
| 4 | -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 | |
| 5 | -# Free Software Foundation, Inc. | |
| 4 | +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | |
| 5 | +# 2003, 2004 Free Software Foundation, Inc. | |
| 6 | 6 | # This Makefile.in is free software; the Free Software Foundation |
| 7 | 7 | # gives unlimited permission to copy and/or distribute it, |
| 8 | 8 | # with or without modifications, as long as this notice is preserved. |
| ... | ... | @@ -13,143 +13,206 @@ |
| 13 | 13 | # PARTICULAR PURPOSE. |
| 14 | 14 | |
| 15 | 15 | @SET_MAKE@ |
| 16 | -SHELL = @SHELL@ | |
| 16 | +SOURCES = $(test_GMatrix_SOURCES) $(test_GSparseMatrix_SOURCES) $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) | |
| 17 | 17 | |
| 18 | 18 | srcdir = @srcdir@ |
| 19 | 19 | top_srcdir = @top_srcdir@ |
| 20 | 20 | VPATH = @srcdir@ |
| 21 | -prefix = @prefix@ | |
| 22 | -exec_prefix = @exec_prefix@ | |
| 23 | - | |
| 24 | -bindir = @bindir@ | |
| 25 | -sbindir = @sbindir@ | |
| 26 | -libexecdir = @libexecdir@ | |
| 27 | -datadir = @datadir@ | |
| 28 | -sysconfdir = @sysconfdir@ | |
| 29 | -sharedstatedir = @sharedstatedir@ | |
| 30 | -localstatedir = @localstatedir@ | |
| 31 | -libdir = @libdir@ | |
| 32 | -infodir = @infodir@ | |
| 33 | -mandir = @mandir@ | |
| 34 | -includedir = @includedir@ | |
| 35 | -oldincludedir = /usr/include | |
| 36 | 21 | pkgdatadir = $(datadir)/@PACKAGE@ |
| 37 | 22 | pkglibdir = $(libdir)/@PACKAGE@ |
| 38 | 23 | pkgincludedir = $(includedir)/@PACKAGE@ |
| 39 | 24 | top_builddir = .. |
| 40 | - | |
| 41 | -ACLOCAL = @ACLOCAL@ | |
| 42 | -AUTOCONF = @AUTOCONF@ | |
| 43 | -AUTOMAKE = @AUTOMAKE@ | |
| 44 | -AUTOHEADER = @AUTOHEADER@ | |
| 45 | - | |
| 46 | 25 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd |
| 47 | 26 | INSTALL = @INSTALL@ |
| 48 | -INSTALL_PROGRAM = @INSTALL_PROGRAM@ | |
| 49 | -INSTALL_DATA = @INSTALL_DATA@ | |
| 50 | 27 | install_sh_DATA = $(install_sh) -c -m 644 |
| 51 | 28 | install_sh_PROGRAM = $(install_sh) -c |
| 52 | 29 | install_sh_SCRIPT = $(install_sh) -c |
| 53 | -INSTALL_SCRIPT = @INSTALL_SCRIPT@ | |
| 54 | 30 | INSTALL_HEADER = $(INSTALL_DATA) |
| 55 | -transform = @program_transform_name@ | |
| 31 | +transform = $(program_transform_name) | |
| 56 | 32 | NORMAL_INSTALL = : |
| 57 | 33 | PRE_INSTALL = : |
| 58 | 34 | POST_INSTALL = : |
| 59 | 35 | NORMAL_UNINSTALL = : |
| 60 | 36 | PRE_UNINSTALL = : |
| 61 | 37 | POST_UNINSTALL = : |
| 62 | -host_alias = @host_alias@ | |
| 38 | +build_triplet = @build@ | |
| 63 | 39 | host_triplet = @host@ |
| 64 | - | |
| 65 | -EXEEXT = @EXEEXT@ | |
| 66 | -OBJEXT = @OBJEXT@ | |
| 67 | -PATH_SEPARATOR = @PATH_SEPARATOR@ | |
| 40 | +check_PROGRAMS = test_GVector$(EXEEXT) test_GMatrix$(EXEEXT) \ | |
| 41 | + test_GSymMatrix$(EXEEXT) test_GSparseMatrix$(EXEEXT) | |
| 42 | +subdir = test | |
| 43 | +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | |
| 44 | +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | |
| 45 | +am__aclocal_m4_deps = $(top_srcdir)/configure.ac | |
| 46 | +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ | |
| 47 | + $(ACLOCAL_M4) | |
| 48 | +mkinstalldirs = $(install_sh) -d | |
| 49 | +CONFIG_HEADER = $(top_builddir)/config.h | |
| 50 | +CONFIG_CLEAN_FILES = | |
| 51 | +am_test_GMatrix_OBJECTS = test_GMatrix.$(OBJEXT) | |
| 52 | +test_GMatrix_OBJECTS = $(am_test_GMatrix_OBJECTS) | |
| 53 | +test_GMatrix_DEPENDENCIES = ../src/libgamma.la | |
| 54 | +am_test_GSparseMatrix_OBJECTS = test_GSparseMatrix.$(OBJEXT) | |
| 55 | +test_GSparseMatrix_OBJECTS = $(am_test_GSparseMatrix_OBJECTS) | |
| 56 | +test_GSparseMatrix_DEPENDENCIES = ../src/libgamma.la | |
| 57 | +am_test_GSymMatrix_OBJECTS = test_GSymMatrix.$(OBJEXT) | |
| 58 | +test_GSymMatrix_OBJECTS = $(am_test_GSymMatrix_OBJECTS) | |
| 59 | +test_GSymMatrix_DEPENDENCIES = ../src/libgamma.la | |
| 60 | +am_test_GVector_OBJECTS = test_GVector.$(OBJEXT) | |
| 61 | +test_GVector_OBJECTS = $(am_test_GVector_OBJECTS) | |
| 62 | +test_GVector_DEPENDENCIES = ../src/libgamma.la | |
| 63 | +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) | |
| 64 | +depcomp = | |
| 65 | +am__depfiles_maybe = | |
| 66 | +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ | |
| 67 | + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 68 | +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ | |
| 69 | + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | |
| 70 | + $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 71 | +CXXLD = $(CXX) | |
| 72 | +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) \ | |
| 73 | + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
| 74 | +SOURCES = $(test_GMatrix_SOURCES) $(test_GSparseMatrix_SOURCES) \ | |
| 75 | + $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) | |
| 76 | +DIST_SOURCES = $(test_GMatrix_SOURCES) $(test_GSparseMatrix_SOURCES) \ | |
| 77 | + $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) | |
| 78 | +ETAGS = etags | |
| 79 | +CTAGS = ctags | |
| 80 | +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | |
| 81 | +ACLOCAL = @ACLOCAL@ | |
| 68 | 82 | AMTAR = @AMTAR@ |
| 69 | 83 | AR = @AR@ |
| 70 | -AS = @AS@ | |
| 84 | +AUTOCONF = @AUTOCONF@ | |
| 85 | +AUTOHEADER = @AUTOHEADER@ | |
| 86 | +AUTOMAKE = @AUTOMAKE@ | |
| 71 | 87 | AWK = @AWK@ |
| 72 | 88 | CC = @CC@ |
| 89 | +CFLAGS = @CFLAGS@ | |
| 90 | +CPP = @CPP@ | |
| 91 | +CPPFLAGS = @CPPFLAGS@ | |
| 73 | 92 | CXX = @CXX@ |
| 74 | 93 | CXXCPP = @CXXCPP@ |
| 75 | -DEPDIR = @DEPDIR@ | |
| 76 | -DLLTOOL = @DLLTOOL@ | |
| 94 | +CXXFLAGS = @CXXFLAGS@ | |
| 95 | +CYGPATH_W = @CYGPATH_W@ | |
| 96 | +DEFS = @DEFS@ | |
| 77 | 97 | ECHO = @ECHO@ |
| 98 | +ECHO_C = @ECHO_C@ | |
| 99 | +ECHO_N = @ECHO_N@ | |
| 100 | +ECHO_T = @ECHO_T@ | |
| 78 | 101 | EGREP = @EGREP@ |
| 102 | +EXEEXT = @EXEEXT@ | |
| 79 | 103 | F77 = @F77@ |
| 80 | -GCJ = @GCJ@ | |
| 81 | -GCJFLAGS = @GCJFLAGS@ | |
| 104 | +FFLAGS = @FFLAGS@ | |
| 105 | +INSTALL_DATA = @INSTALL_DATA@ | |
| 106 | +INSTALL_PROGRAM = @INSTALL_PROGRAM@ | |
| 107 | +INSTALL_SCRIPT = @INSTALL_SCRIPT@ | |
| 82 | 108 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ |
| 109 | +LDFLAGS = @LDFLAGS@ | |
| 110 | +LIBOBJS = @LIBOBJS@ | |
| 111 | +LIBS = @LIBS@ | |
| 83 | 112 | LIBTOOL = @LIBTOOL@ |
| 113 | +LIBTOOL_DEPS = @LIBTOOL_DEPS@ | |
| 84 | 114 | LN_S = @LN_S@ |
| 115 | +LTLIBOBJS = @LTLIBOBJS@ | |
| 85 | 116 | MAINT = @MAINT@ |
| 86 | -OBJDUMP = @OBJDUMP@ | |
| 117 | +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ | |
| 118 | +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ | |
| 119 | +MAKEINFO = @MAKEINFO@ | |
| 120 | +OBJEXT = @OBJEXT@ | |
| 87 | 121 | PACKAGE = @PACKAGE@ |
| 122 | +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | |
| 123 | +PACKAGE_NAME = @PACKAGE_NAME@ | |
| 124 | +PACKAGE_STRING = @PACKAGE_STRING@ | |
| 125 | +PACKAGE_TARNAME = @PACKAGE_TARNAME@ | |
| 126 | +PACKAGE_VERSION = @PACKAGE_VERSION@ | |
| 127 | +PATH_SEPARATOR = @PATH_SEPARATOR@ | |
| 88 | 128 | RANLIB = @RANLIB@ |
| 89 | -RC = @RC@ | |
| 129 | +SET_MAKE = @SET_MAKE@ | |
| 130 | +SHELL = @SHELL@ | |
| 90 | 131 | STRIP = @STRIP@ |
| 91 | 132 | VERSION = @VERSION@ |
| 92 | -am__include = @am__include@ | |
| 93 | -am__quote = @am__quote@ | |
| 133 | +ac_ct_AR = @ac_ct_AR@ | |
| 134 | +ac_ct_CC = @ac_ct_CC@ | |
| 135 | +ac_ct_CXX = @ac_ct_CXX@ | |
| 136 | +ac_ct_F77 = @ac_ct_F77@ | |
| 137 | +ac_ct_RANLIB = @ac_ct_RANLIB@ | |
| 138 | +ac_ct_STRIP = @ac_ct_STRIP@ | |
| 139 | +am__leading_dot = @am__leading_dot@ | |
| 140 | +am__tar = @am__tar@ | |
| 141 | +am__untar = @am__untar@ | |
| 142 | +bindir = @bindir@ | |
| 143 | +build = @build@ | |
| 144 | +build_alias = @build_alias@ | |
| 145 | +build_cpu = @build_cpu@ | |
| 146 | +build_os = @build_os@ | |
| 147 | +build_vendor = @build_vendor@ | |
| 148 | +datadir = @datadir@ | |
| 149 | +exec_prefix = @exec_prefix@ | |
| 150 | +host = @host@ | |
| 151 | +host_alias = @host_alias@ | |
| 152 | +host_cpu = @host_cpu@ | |
| 153 | +host_os = @host_os@ | |
| 154 | +host_vendor = @host_vendor@ | |
| 155 | +includedir = @includedir@ | |
| 156 | +infodir = @infodir@ | |
| 94 | 157 | install_sh = @install_sh@ |
| 158 | +libdir = @libdir@ | |
| 159 | +libexecdir = @libexecdir@ | |
| 160 | +localstatedir = @localstatedir@ | |
| 161 | +mandir = @mandir@ | |
| 162 | +mkdir_p = @mkdir_p@ | |
| 163 | +oldincludedir = @oldincludedir@ | |
| 164 | +prefix = @prefix@ | |
| 165 | +program_transform_name = @program_transform_name@ | |
| 166 | +sbindir = @sbindir@ | |
| 167 | +sharedstatedir = @sharedstatedir@ | |
| 168 | +sysconfdir = @sysconfdir@ | |
| 169 | +target_alias = @target_alias@ | |
| 170 | +TESTS = test_GVector \ | |
| 171 | + test_GMatrix \ | |
| 172 | + test_GSymMatrix \ | |
| 173 | + test_GSparseMatrix | |
| 95 | 174 | |
| 96 | -check_PROGRAMS = test_GVector test_GMatrix test_GSymMatrix | |
| 97 | -TESTS = test_GVector test_GMatrix test_GSymMatrix | |
| 98 | 175 | test_GVector_SOURCES = test_GVector.cpp |
| 99 | 176 | test_GVector_LDADD = ../src/libgamma.la |
| 100 | 177 | test_GMatrix_SOURCES = test_GMatrix.cpp |
| 101 | 178 | test_GMatrix_LDADD = ../src/libgamma.la |
| 102 | 179 | test_GSymMatrix_SOURCES = test_GSymMatrix.cpp |
| 103 | 180 | test_GSymMatrix_LDADD = ../src/libgamma.la |
| 104 | -subdir = test | |
| 105 | -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs | |
| 106 | -CONFIG_HEADER = $(top_builddir)/config.h | |
| 107 | -CONFIG_CLEAN_FILES = | |
| 108 | -check_PROGRAMS = test_GVector$(EXEEXT) test_GMatrix$(EXEEXT) \ | |
| 109 | - test_GSymMatrix$(EXEEXT) | |
| 110 | -am_test_GMatrix_OBJECTS = test_GMatrix.$(OBJEXT) | |
| 111 | -test_GMatrix_OBJECTS = $(am_test_GMatrix_OBJECTS) | |
| 112 | -test_GMatrix_DEPENDENCIES = ../src/libgamma.la | |
| 113 | -test_GMatrix_LDFLAGS = | |
| 114 | -am_test_GSymMatrix_OBJECTS = test_GSymMatrix.$(OBJEXT) | |
| 115 | -test_GSymMatrix_OBJECTS = $(am_test_GSymMatrix_OBJECTS) | |
| 116 | -test_GSymMatrix_DEPENDENCIES = ../src/libgamma.la | |
| 117 | -test_GSymMatrix_LDFLAGS = | |
| 118 | -am_test_GVector_OBJECTS = test_GVector.$(OBJEXT) | |
| 119 | -test_GVector_OBJECTS = $(am_test_GVector_OBJECTS) | |
| 120 | -test_GVector_DEPENDENCIES = ../src/libgamma.la | |
| 121 | -test_GVector_LDFLAGS = | |
| 122 | - | |
| 123 | -DEFS = @DEFS@ | |
| 124 | -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) | |
| 125 | -CPPFLAGS = @CPPFLAGS@ | |
| 126 | -LDFLAGS = @LDFLAGS@ | |
| 127 | -LIBS = @LIBS@ | |
| 128 | -depcomp = | |
| 129 | -am__depfiles_maybe = | |
| 130 | -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ | |
| 131 | - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 132 | -LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ | |
| 133 | - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | |
| 134 | - $(AM_CXXFLAGS) $(CXXFLAGS) | |
| 135 | -CXXLD = $(CXX) | |
| 136 | -CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ | |
| 137 | - $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
| 138 | -CXXFLAGS = @CXXFLAGS@ | |
| 139 | -DIST_SOURCES = $(test_GMatrix_SOURCES) $(test_GSymMatrix_SOURCES) \ | |
| 140 | - $(test_GVector_SOURCES) | |
| 141 | -DIST_COMMON = Makefile.am Makefile.in | |
| 142 | -SOURCES = $(test_GMatrix_SOURCES) $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) | |
| 143 | - | |
| 181 | +test_GSparseMatrix_SOURCES = test_GSparseMatrix.cpp | |
| 182 | +test_GSparseMatrix_LDADD = ../src/libgamma.la | |
| 144 | 183 | all: all-am |
| 145 | 184 | |
| 146 | 185 | .SUFFIXES: |
| 147 | 186 | .SUFFIXES: .cpp .lo .o .obj |
| 148 | -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) | |
| 187 | +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) | |
| 188 | + @for dep in $?; do \ | |
| 189 | + case '$(am__configure_deps)' in \ | |
| 190 | + *$$dep*) \ | |
| 191 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ | |
| 192 | + && exit 0; \ | |
| 193 | + exit 1;; \ | |
| 194 | + esac; \ | |
| 195 | + done; \ | |
| 196 | + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps test/Makefile'; \ | |
| 149 | 197 | cd $(top_srcdir) && \ |
| 150 | - $(AUTOMAKE) --gnu test/Makefile | |
| 151 | -Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status | |
| 152 | - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) | |
| 198 | + $(AUTOMAKE) --gnu --ignore-deps test/Makefile | |
| 199 | +.PRECIOUS: Makefile | |
| 200 | +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | |
| 201 | + @case '$?' in \ | |
| 202 | + *config.status*) \ | |
| 203 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ | |
| 204 | + *) \ | |
| 205 | + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | |
| 206 | + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | |
| 207 | + esac; | |
| 208 | + | |
| 209 | +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) | |
| 210 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
| 211 | + | |
| 212 | +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) | |
| 213 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
| 214 | +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) | |
| 215 | + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
| 153 | 216 | |
| 154 | 217 | clean-checkPROGRAMS: |
| 155 | 218 | @list='$(check_PROGRAMS)'; for p in $$list; do \ |
| ... | ... | @@ -160,6 +223,9 @@ clean-checkPROGRAMS: |
| 160 | 223 | test_GMatrix$(EXEEXT): $(test_GMatrix_OBJECTS) $(test_GMatrix_DEPENDENCIES) |
| 161 | 224 | @rm -f test_GMatrix$(EXEEXT) |
| 162 | 225 | $(CXXLINK) $(test_GMatrix_LDFLAGS) $(test_GMatrix_OBJECTS) $(test_GMatrix_LDADD) $(LIBS) |
| 226 | +test_GSparseMatrix$(EXEEXT): $(test_GSparseMatrix_OBJECTS) $(test_GSparseMatrix_DEPENDENCIES) | |
| 227 | + @rm -f test_GSparseMatrix$(EXEEXT) | |
| 228 | + $(CXXLINK) $(test_GSparseMatrix_LDFLAGS) $(test_GSparseMatrix_OBJECTS) $(test_GSparseMatrix_LDADD) $(LIBS) | |
| 163 | 229 | test_GSymMatrix$(EXEEXT): $(test_GSymMatrix_OBJECTS) $(test_GSymMatrix_DEPENDENCIES) |
| 164 | 230 | @rm -f test_GSymMatrix$(EXEEXT) |
| 165 | 231 | $(CXXLINK) $(test_GSymMatrix_LDFLAGS) $(test_GSymMatrix_OBJECTS) $(test_GSymMatrix_LDADD) $(LIBS) |
| ... | ... | @@ -168,19 +234,19 @@ test_GVector$(EXEEXT): $(test_GVector_OBJECTS) $(test_GVector_DEPENDENCIES) |
| 168 | 234 | $(CXXLINK) $(test_GVector_LDFLAGS) $(test_GVector_OBJECTS) $(test_GVector_LDADD) $(LIBS) |
| 169 | 235 | |
| 170 | 236 | mostlyclean-compile: |
| 171 | - -rm -f *.$(OBJEXT) core *.core | |
| 237 | + -rm -f *.$(OBJEXT) | |
| 172 | 238 | |
| 173 | 239 | distclean-compile: |
| 174 | 240 | -rm -f *.tab.c |
| 175 | 241 | |
| 176 | 242 | .cpp.o: |
| 177 | - $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< | |
| 243 | + $(CXXCOMPILE) -c -o $@ $< | |
| 178 | 244 | |
| 179 | 245 | .cpp.obj: |
| 180 | - $(CXXCOMPILE) -c -o $@ `cygpath -w $<` | |
| 246 | + $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` | |
| 181 | 247 | |
| 182 | 248 | .cpp.lo: |
| 183 | - $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< | |
| 249 | + $(LTCXXCOMPILE) -c -o $@ $< | |
| 184 | 250 | |
| 185 | 251 | mostlyclean-libtool: |
| 186 | 252 | -rm -f *.lo |
| ... | ... | @@ -192,11 +258,6 @@ distclean-libtool: |
| 192 | 258 | -rm -f libtool |
| 193 | 259 | uninstall-info-am: |
| 194 | 260 | |
| 195 | -ETAGS = etags | |
| 196 | -ETAGSFLAGS = | |
| 197 | - | |
| 198 | -tags: TAGS | |
| 199 | - | |
| 200 | 261 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) |
| 201 | 262 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ |
| 202 | 263 | unique=`for i in $$list; do \ |
| ... | ... | @@ -205,6 +266,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) |
| 205 | 266 | $(AWK) ' { files[$$0] = 1; } \ |
| 206 | 267 | END { for (i in files) print i; }'`; \ |
| 207 | 268 | mkid -fID $$unique |
| 269 | +tags: TAGS | |
| 208 | 270 | |
| 209 | 271 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ |
| 210 | 272 | $(TAGS_FILES) $(LISP) |
| ... | ... | @@ -216,8 +278,24 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ |
| 216 | 278 | done | \ |
| 217 | 279 | $(AWK) ' { files[$$0] = 1; } \ |
| 218 | 280 | END { for (i in files) print i; }'`; \ |
| 219 | - test -z "$(ETAGS_ARGS)$$tags$$unique" \ | |
| 220 | - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | |
| 281 | + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ | |
| 282 | + test -n "$$unique" || unique=$$empty_fix; \ | |
| 283 | + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | |
| 284 | + $$tags $$unique; \ | |
| 285 | + fi | |
| 286 | +ctags: CTAGS | |
| 287 | +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | |
| 288 | + $(TAGS_FILES) $(LISP) | |
| 289 | + tags=; \ | |
| 290 | + here=`pwd`; \ | |
| 291 | + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | |
| 292 | + unique=`for i in $$list; do \ | |
| 293 | + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | |
| 294 | + done | \ | |
| 295 | + $(AWK) ' { files[$$0] = 1; } \ | |
| 296 | + END { for (i in files) print i; }'`; \ | |
| 297 | + test -z "$(CTAGS_ARGS)$$tags$$unique" \ | |
| 298 | + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ | |
| 221 | 299 | $$tags $$unique |
| 222 | 300 | |
| 223 | 301 | GTAGS: |
| ... | ... | @@ -226,10 +304,10 @@ GTAGS: |
| 226 | 304 | && gtags -i $(GTAGS_ARGS) $$here |
| 227 | 305 | |
| 228 | 306 | distclean-tags: |
| 229 | - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH | |
| 307 | + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags | |
| 230 | 308 | |
| 231 | 309 | check-TESTS: $(TESTS) |
| 232 | - @failed=0; all=0; xfail=0; xpass=0; \ | |
| 310 | + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ | |
| 233 | 311 | srcdir=$(srcdir); export srcdir; \ |
| 234 | 312 | list='$(TESTS)'; \ |
| 235 | 313 | if test -n "$$list"; then \ |
| ... | ... | @@ -241,26 +319,29 @@ check-TESTS: $(TESTS) |
| 241 | 319 | all=`expr $$all + 1`; \ |
| 242 | 320 | case " $(XFAIL_TESTS) " in \ |
| 243 | 321 | *" $$tst "*) \ |
| 244 | - xpass=`expr $$xpass + 1`; \ | |
| 245 | - failed=`expr $$failed + 1`; \ | |
| 246 | - echo "XPASS: $$tst"; \ | |
| 322 | + xpass=`expr $$xpass + 1`; \ | |
| 323 | + failed=`expr $$failed + 1`; \ | |
| 324 | + echo "XPASS: $$tst"; \ | |
| 247 | 325 | ;; \ |
| 248 | 326 | *) \ |
| 249 | - echo "PASS: $$tst"; \ | |
| 327 | + echo "PASS: $$tst"; \ | |
| 250 | 328 | ;; \ |
| 251 | 329 | esac; \ |
| 252 | 330 | elif test $$? -ne 77; then \ |
| 253 | 331 | all=`expr $$all + 1`; \ |
| 254 | 332 | case " $(XFAIL_TESTS) " in \ |
| 255 | 333 | *" $$tst "*) \ |
| 256 | - xfail=`expr $$xfail + 1`; \ | |
| 257 | - echo "XFAIL: $$tst"; \ | |
| 334 | + xfail=`expr $$xfail + 1`; \ | |
| 335 | + echo "XFAIL: $$tst"; \ | |
| 258 | 336 | ;; \ |
| 259 | 337 | *) \ |
| 260 | - failed=`expr $$failed + 1`; \ | |
| 261 | - echo "FAIL: $$tst"; \ | |
| 338 | + failed=`expr $$failed + 1`; \ | |
| 339 | + echo "FAIL: $$tst"; \ | |
| 262 | 340 | ;; \ |
| 263 | 341 | esac; \ |
| 342 | + else \ | |
| 343 | + skip=`expr $$skip + 1`; \ | |
| 344 | + echo "SKIP: $$tst"; \ | |
| 264 | 345 | fi; \ |
| 265 | 346 | done; \ |
| 266 | 347 | if test "$$failed" -eq 0; then \ |
| ... | ... | @@ -276,24 +357,41 @@ check-TESTS: $(TESTS) |
| 276 | 357 | banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ |
| 277 | 358 | fi; \ |
| 278 | 359 | fi; \ |
| 279 | - dashes=`echo "$$banner" | sed s/./=/g`; \ | |
| 360 | + dashes="$$banner"; \ | |
| 361 | + skipped=""; \ | |
| 362 | + if test "$$skip" -ne 0; then \ | |
| 363 | + skipped="($$skip tests were not run)"; \ | |
| 364 | + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ | |
| 365 | + dashes="$$skipped"; \ | |
| 366 | + fi; \ | |
| 367 | + report=""; \ | |
| 368 | + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ | |
| 369 | + report="Please report to $(PACKAGE_BUGREPORT)"; \ | |
| 370 | + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ | |
| 371 | + dashes="$$report"; \ | |
| 372 | + fi; \ | |
| 373 | + dashes=`echo "$$dashes" | sed s/./=/g`; \ | |
| 280 | 374 | echo "$$dashes"; \ |
| 281 | 375 | echo "$$banner"; \ |
| 376 | + test -z "$$skipped" || echo "$$skipped"; \ | |
| 377 | + test -z "$$report" || echo "$$report"; \ | |
| 282 | 378 | echo "$$dashes"; \ |
| 283 | 379 | test "$$failed" -eq 0; \ |
| 284 | 380 | else :; fi |
| 285 | -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | |
| 286 | - | |
| 287 | -top_distdir = .. | |
| 288 | -distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) | |
| 289 | 381 | |
| 290 | 382 | distdir: $(DISTFILES) |
| 291 | - @list='$(DISTFILES)'; for file in $$list; do \ | |
| 383 | + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ | |
| 384 | + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ | |
| 385 | + list='$(DISTFILES)'; for file in $$list; do \ | |
| 386 | + case $$file in \ | |
| 387 | + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ | |
| 388 | + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ | |
| 389 | + esac; \ | |
| 292 | 390 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ |
| 293 | 391 | dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ |
| 294 | 392 | if test "$$dir" != "$$file" && test "$$dir" != "."; then \ |
| 295 | 393 | dir="/$$dir"; \ |
| 296 | - $(mkinstalldirs) "$(distdir)$$dir"; \ | |
| 394 | + $(mkdir_p) "$(distdir)$$dir"; \ | |
| 297 | 395 | else \ |
| 298 | 396 | dir=''; \ |
| 299 | 397 | fi; \ |
| ... | ... | @@ -313,9 +411,7 @@ check-am: all-am |
| 313 | 411 | $(MAKE) $(AM_MAKEFLAGS) check-TESTS |
| 314 | 412 | check: check-am |
| 315 | 413 | all-am: Makefile |
| 316 | - | |
| 317 | 414 | installdirs: |
| 318 | - | |
| 319 | 415 | install: install-am |
| 320 | 416 | install-exec: install-exec-am |
| 321 | 417 | install-data: install-data-am |
| ... | ... | @@ -327,7 +423,7 @@ install-am: all-am |
| 327 | 423 | installcheck: installcheck-am |
| 328 | 424 | install-strip: |
| 329 | 425 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ |
| 330 | - INSTALL_STRIP_FLAG=-s \ | |
| 426 | + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | |
| 331 | 427 | `test -z '$(STRIP)' || \ |
| 332 | 428 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install |
| 333 | 429 | mostlyclean-generic: |
| ... | ... | @@ -335,17 +431,18 @@ mostlyclean-generic: |
| 335 | 431 | clean-generic: |
| 336 | 432 | |
| 337 | 433 | distclean-generic: |
| 338 | - -rm -f Makefile $(CONFIG_CLEAN_FILES) | |
| 434 | + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) | |
| 339 | 435 | |
| 340 | 436 | maintainer-clean-generic: |
| 341 | 437 | @echo "This command is intended for maintainers to use" |
| 342 | 438 | @echo "it deletes files that may require special tools to rebuild." |
| 343 | 439 | clean: clean-am |
| 344 | 440 | |
| 345 | -clean-am: clean-checkPROGRAMS clean-generic clean-libtool mostlyclean-am | |
| 441 | +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ | |
| 442 | + mostlyclean-am | |
| 346 | 443 | |
| 347 | 444 | distclean: distclean-am |
| 348 | - | |
| 445 | + -rm -f Makefile | |
| 349 | 446 | distclean-am: clean-am distclean-compile distclean-generic \ |
| 350 | 447 | distclean-libtool distclean-tags |
| 351 | 448 | |
| ... | ... | @@ -353,6 +450,8 @@ dvi: dvi-am |
| 353 | 450 | |
| 354 | 451 | dvi-am: |
| 355 | 452 | |
| 453 | +html: html-am | |
| 454 | + | |
| 356 | 455 | info: info-am |
| 357 | 456 | |
| 358 | 457 | info-am: |
| ... | ... | @@ -368,7 +467,7 @@ install-man: |
| 368 | 467 | installcheck-am: |
| 369 | 468 | |
| 370 | 469 | maintainer-clean: maintainer-clean-am |
| 371 | - | |
| 470 | + -rm -f Makefile | |
| 372 | 471 | maintainer-clean-am: distclean-am maintainer-clean-generic |
| 373 | 472 | |
| 374 | 473 | mostlyclean: mostlyclean-am |
| ... | ... | @@ -376,17 +475,26 @@ mostlyclean: mostlyclean-am |
| 376 | 475 | mostlyclean-am: mostlyclean-compile mostlyclean-generic \ |
| 377 | 476 | mostlyclean-libtool |
| 378 | 477 | |
| 478 | +pdf: pdf-am | |
| 479 | + | |
| 480 | +pdf-am: | |
| 481 | + | |
| 482 | +ps: ps-am | |
| 483 | + | |
| 484 | +ps-am: | |
| 485 | + | |
| 379 | 486 | uninstall-am: uninstall-info-am |
| 380 | 487 | |
| 381 | -.PHONY: GTAGS all all-am check check-TESTS check-am clean \ | |
| 382 | - clean-checkPROGRAMS clean-generic clean-libtool distclean \ | |
| 383 | - distclean-compile distclean-generic distclean-libtool \ | |
| 384 | - distclean-tags distdir dvi dvi-am info info-am install \ | |
| 385 | - install-am install-data install-data-am install-exec \ | |
| 386 | - install-exec-am install-info install-info-am install-man \ | |
| 387 | - install-strip installcheck installcheck-am installdirs \ | |
| 388 | - maintainer-clean maintainer-clean-generic mostlyclean \ | |
| 389 | - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ | |
| 488 | +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ | |
| 489 | + clean-checkPROGRAMS clean-generic clean-libtool ctags \ | |
| 490 | + distclean distclean-compile distclean-generic \ | |
| 491 | + distclean-libtool distclean-tags distdir dvi dvi-am html \ | |
| 492 | + html-am info info-am install install-am install-data \ | |
| 493 | + install-data-am install-exec install-exec-am install-info \ | |
| 494 | + install-info-am install-man install-strip installcheck \ | |
| 495 | + installcheck-am installdirs maintainer-clean \ | |
| 496 | + maintainer-clean-generic mostlyclean mostlyclean-compile \ | |
| 497 | + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ | |
| 390 | 498 | tags uninstall uninstall-am uninstall-info-am |
| 391 | 499 | |
| 392 | 500 | # Tell versions [3.59,3.63) of GNU make to not export all variables. | ... | ... |
test/test_GMatrix.cpp
| ... | ... | @@ -18,10 +18,12 @@ |
| 18 | 18 | using namespace std; |
| 19 | 19 | |
| 20 | 20 | /* __ Globals ____________________________________________________________ */ |
| 21 | -double g_matrix[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; | |
| 22 | -double g_vector[] = {1.0, 2.0, 3.0}; | |
| 21 | +double g_matrix[] = {1.0, 2.0, 3.0, 4.0, | |
| 22 | + 5.0, 6.0, 7.0, 8.0, | |
| 23 | + 9.0, 10., 11., 12.}; | |
| 24 | +double g_vector[] = {1.0, 2.0, 3.0, 4.0}; | |
| 23 | 25 | unsigned g_rows = 3; |
| 24 | -unsigned g_cols = 3; | |
| 26 | +unsigned g_cols = 4; | |
| 25 | 27 | |
| 26 | 28 | |
| 27 | 29 | /*************************************************************************** |
| ... | ... | @@ -72,7 +74,32 @@ int check_matrix(const GMatrix& m, const double scale, const double add) |
| 72 | 74 | for (unsigned row = 0; row < g_rows; ++row) { |
| 73 | 75 | for (unsigned col = 0; col < g_cols; ++col) { |
| 74 | 76 | double value = g_matrix[col+row*g_cols] * scale + add; |
| 75 | - if (m(row,col) != value) { | |
| 77 | + if (fabs(m(row,col)-value) > 1.0e-15) { | |
| 78 | + result = 0; | |
| 79 | + break; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + } | |
| 83 | + } | |
| 84 | + catch (exception &e) { | |
| 85 | + cout << "TEST ERROR: Unable to check test matrix." << endl; | |
| 86 | + throw; | |
| 87 | + } | |
| 88 | + return result; | |
| 89 | +} | |
| 90 | + | |
| 91 | + | |
| 92 | +/*************************************************************************** | |
| 93 | + * Check transposed test matrix * | |
| 94 | + ***************************************************************************/ | |
| 95 | +int check_transpose_matrix(const GMatrix& m, const double scale, const double add) | |
| 96 | +{ | |
| 97 | + int result = 1; | |
| 98 | + try { | |
| 99 | + for (unsigned row = 0; row < g_rows; ++row) { | |
| 100 | + for (unsigned col = 0; col < g_cols; ++col) { | |
| 101 | + double value = g_matrix[col+row*g_cols] * scale + add; | |
| 102 | + if (m(col,row) != value) { | |
| 76 | 103 | result = 0; |
| 77 | 104 | break; |
| 78 | 105 | } |
| ... | ... | @@ -167,15 +194,15 @@ int check_matrix_vector(const GVector& v) |
| 167 | 194 | ***************************************************************************/ |
| 168 | 195 | int check_matrix_matrix(const GMatrix& m) |
| 169 | 196 | { |
| 170 | - if (m.rows() != g_rows || m.cols() != g_cols) | |
| 197 | + if (m.rows() != g_rows || m.cols() != g_rows) | |
| 171 | 198 | return 0; |
| 172 | 199 | int result = 1; |
| 173 | 200 | try { |
| 174 | - for (unsigned row = 0; row < g_rows; ++row) { | |
| 175 | - for (unsigned col = 0; col < g_cols; ++col) { | |
| 201 | + for (unsigned row = 0; row < m.rows(); ++row) { | |
| 202 | + for (unsigned col = 0; col < m.cols(); ++col) { | |
| 176 | 203 | double value = 0.0; |
| 177 | 204 | for (unsigned i = 0; i < g_cols; ++i) |
| 178 | - value += g_matrix[i+row*g_cols] * g_matrix[row+i*g_cols]; | |
| 205 | + value += g_matrix[i+row*g_cols] * g_matrix[i+col*g_cols]; | |
| 179 | 206 | if (m(row,col) != value) { |
| 180 | 207 | result = 0; |
| 181 | 208 | break; |
| ... | ... | @@ -323,7 +350,7 @@ int main(void) |
| 323 | 350 | cout << "GMatrix - Test 4: Define matrix using copy constructor: "; |
| 324 | 351 | // |
| 325 | 352 | GMatrix test4 = m_test; |
| 326 | - if (!check_matrix(test4, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 353 | + if (!check_matrix(test4, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 327 | 354 | cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; |
| 328 | 355 | cout << test4 << endl; |
| 329 | 356 | throw; |
| ... | ... | @@ -341,8 +368,8 @@ int main(void) |
| 341 | 368 | // |
| 342 | 369 | // GMatrix = GMatrix |
| 343 | 370 | result = m_test; |
| 344 | - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 345 | - cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; | |
| 371 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 372 | + cout << endl << "TEST ERROR: Corrupt assignment." << endl; | |
| 346 | 373 | cout << result << endl; |
| 347 | 374 | throw; |
| 348 | 375 | } |
| ... | ... | @@ -356,14 +383,41 @@ int main(void) |
| 356 | 383 | } |
| 357 | 384 | cout << "ok." << endl; |
| 358 | 385 | |
| 359 | - // Test 6: Matrix*Vector multiplication | |
| 386 | + // Test 6: Transposition | |
| 360 | 387 | try { |
| 361 | - cout << "GMatrix - Test 6: Matrix*Vector multiplication: "; | |
| 388 | + cout << "GMatrix - Test 6: Transposition: "; | |
| 362 | 389 | // |
| 363 | - GVector v_test6 = m_test*v_test; | |
| 364 | - if (!check_matrix_vector(v_test6) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 390 | + // transpose(GMatrix) | |
| 391 | + result = transpose(m_test); | |
| 392 | + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 393 | + cout << endl << "TEST ERROR: Corrupt transpose(GMatrix) function." << endl; | |
| 394 | + cout << result << endl; | |
| 395 | + throw; | |
| 396 | + } | |
| 397 | + // | |
| 398 | + // GMatrix.transpose() | |
| 399 | + result = m_test; | |
| 400 | + result.transpose(); | |
| 401 | + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 402 | + cout << endl << "TEST ERROR: Corrupt GMatrix.transpose() function." << endl; | |
| 403 | + cout << result << endl; | |
| 404 | + throw; | |
| 405 | + } | |
| 406 | + } | |
| 407 | + catch (exception &e) { | |
| 408 | + cout << e.what() << endl; | |
| 409 | + throw; | |
| 410 | + } | |
| 411 | + cout << "ok." << endl; | |
| 412 | + | |
| 413 | + // Test 7: Matrix*Vector multiplication | |
| 414 | + try { | |
| 415 | + cout << "GMatrix - Test 7: Matrix*Vector multiplication: "; | |
| 416 | + // | |
| 417 | + GVector v_test7 = m_test*v_test; | |
| 418 | + if (!check_matrix_vector(v_test7) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 365 | 419 | cout << endl << "TEST ERROR: Corrupt Matrix*Vector multiplication." << endl; |
| 366 | - cout << v_test6 << endl; | |
| 420 | + cout << v_test7 << endl; | |
| 367 | 421 | throw; |
| 368 | 422 | } |
| 369 | 423 | } |
| ... | ... | @@ -372,9 +426,9 @@ int main(void) |
| 372 | 426 | throw; |
| 373 | 427 | } |
| 374 | 428 | try { |
| 375 | - GVector v_test6 = bigger*v_test; | |
| 429 | + GVector v_test7 = bigger*v_test; | |
| 376 | 430 | } |
| 377 | - catch (GMatrix::vec_mat_mismatch &e) { | |
| 431 | + catch (GMatrix::matrix_vector_mismatch &e) { | |
| 378 | 432 | } |
| 379 | 433 | catch (exception &e) { |
| 380 | 434 | cout << e.what() << endl; |
| ... | ... | @@ -382,14 +436,14 @@ int main(void) |
| 382 | 436 | } |
| 383 | 437 | cout << "ok." << endl; |
| 384 | 438 | |
| 385 | - // Test 7: Matrix*Matrix multiplication | |
| 439 | + // Test 8: Matrix*Matrix multiplication | |
| 386 | 440 | try { |
| 387 | - cout << "GMatrix - Test 7: Matrix*Matrix multiplication: "; | |
| 441 | + cout << "GMatrix - Test 8: Matrix*Matrix multiplication: "; | |
| 388 | 442 | // |
| 389 | - GMatrix m_test7 = m_test*m_test; | |
| 390 | - if (!check_matrix_matrix(m_test7) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 443 | + GMatrix m_test8 = m_test * transpose(m_test); | |
| 444 | + if (!check_matrix_matrix(m_test8) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 391 | 445 | cout << endl << "TEST ERROR: Corrupt Matrix*Matrix multiplication." << endl; |
| 392 | - cout << m_test7 << endl; | |
| 446 | + cout << m_test8 << endl; | |
| 393 | 447 | throw; |
| 394 | 448 | } |
| 395 | 449 | } |
| ... | ... | @@ -398,18 +452,18 @@ int main(void) |
| 398 | 452 | throw; |
| 399 | 453 | } |
| 400 | 454 | try { |
| 401 | - GMatrix m_test7 = m_test*bigger; | |
| 455 | + GMatrix m_test8 = m_test*bigger; | |
| 402 | 456 | } |
| 403 | - catch (GMatrix::dim_mult_mismatch &e) { | |
| 457 | + catch (GMatrix::matrix_mismatch &e) { | |
| 404 | 458 | } |
| 405 | 459 | catch (exception &e) { |
| 406 | 460 | cout << e.what() << endl; |
| 407 | 461 | throw; |
| 408 | 462 | } |
| 409 | 463 | try { |
| 410 | - GMatrix m_test7 = bigger*m_test; | |
| 464 | + GMatrix m_test8 = bigger*m_test; | |
| 411 | 465 | } |
| 412 | - catch (GMatrix::dim_mult_mismatch &e) { | |
| 466 | + catch (GMatrix::matrix_mismatch &e) { | |
| 413 | 467 | } |
| 414 | 468 | catch (exception &e) { |
| 415 | 469 | cout << e.what() << endl; |
| ... | ... | @@ -417,67 +471,40 @@ int main(void) |
| 417 | 471 | } |
| 418 | 472 | cout << "ok." << endl; |
| 419 | 473 | |
| 420 | - // Test 8: Assignment and arithmetics | |
| 474 | + // Test 9: Assignment and arithmetics | |
| 421 | 475 | try { |
| 422 | - cout << "GMatrix - Test 8: Assignment and arithmetics: "; | |
| 476 | + cout << "GMatrix - Test 9: Assignment and arithmetics: "; | |
| 423 | 477 | // |
| 424 | 478 | // -GMatrix |
| 425 | 479 | result = -m_test; |
| 426 | - if (!check_matrix(result, -1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 480 | + if (!check_matrix(result, -1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 427 | 481 | cout << endl << "TEST ERROR: Corrupt -GMatrix operator." << endl; |
| 428 | 482 | cout << result << endl; |
| 429 | 483 | throw; |
| 430 | 484 | } |
| 431 | 485 | // |
| 432 | - // GMatrix = 3.0 | |
| 433 | - result = m_test; | |
| 434 | - result = 3.0; | |
| 435 | - if (!check_matrix(result, 0.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 436 | - cout << endl << "TEST ERROR: Corrupt GMatrix = double operator." << endl; | |
| 437 | - cout << result << endl; | |
| 438 | - throw; | |
| 439 | - } | |
| 440 | - // | |
| 441 | 486 | // GMatrix += GMatrix |
| 442 | 487 | result = m_test; |
| 443 | 488 | result += m_test; |
| 444 | - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 489 | + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 445 | 490 | cout << endl << "TEST ERROR: Corrupt GMatrix += GMatrix operator." << endl; |
| 446 | 491 | cout << result << endl; |
| 447 | 492 | throw; |
| 448 | 493 | } |
| 449 | 494 | // |
| 450 | - // GMatrix += 3.0 | |
| 451 | - result = m_test; | |
| 452 | - result += 3.0; | |
| 453 | - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 454 | - cout << endl << "TEST ERROR: Corrupt GMatrix += double operator." << endl; | |
| 455 | - cout << result << endl; | |
| 456 | - throw; | |
| 457 | - } | |
| 458 | - // | |
| 459 | 495 | // GMatrix -= GMatrix |
| 460 | 496 | result = m_test; |
| 461 | 497 | result -= m_test; |
| 462 | - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 498 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 463 | 499 | cout << endl << "TEST ERROR: Corrupt GMatrix -= GMatrix operator." << endl; |
| 464 | 500 | cout << result << endl; |
| 465 | 501 | throw; |
| 466 | 502 | } |
| 467 | 503 | // |
| 468 | - // GMatrix -= 3.0 | |
| 469 | - result = m_test; | |
| 470 | - result -= 3.0; | |
| 471 | - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 472 | - cout << endl << "TEST ERROR: Corrupt GMatrix -= double operator." << endl; | |
| 473 | - cout << result << endl; | |
| 474 | - throw; | |
| 475 | - } | |
| 476 | - // | |
| 477 | 504 | // GMatrix *= 3.0 |
| 478 | 505 | result = m_test; |
| 479 | 506 | result *= 3.0; |
| 480 | - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 507 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 481 | 508 | cout << endl << "TEST ERROR: Corrupt GMatrix *= double operator." << endl; |
| 482 | 509 | cout << result << endl; |
| 483 | 510 | throw; |
| ... | ... | @@ -486,7 +513,7 @@ int main(void) |
| 486 | 513 | // GMatrix /= 3.0 |
| 487 | 514 | result = m_test; |
| 488 | 515 | result /= 3.0; |
| 489 | - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 516 | + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 490 | 517 | cout << endl << "TEST ERROR: Corrupt GMatrix /= double operator." << endl; |
| 491 | 518 | cout << result << endl; |
| 492 | 519 | throw; |
| ... | ... | @@ -494,7 +521,7 @@ int main(void) |
| 494 | 521 | // |
| 495 | 522 | // GMatrix + GMatrix |
| 496 | 523 | result = m_test + m_test; |
| 497 | - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 524 | + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 498 | 525 | cout << endl << "TEST ERROR: Corrupt GMatrix + GMatrix operator." << endl; |
| 499 | 526 | cout << result << endl; |
| 500 | 527 | throw; |
| ... | ... | @@ -502,7 +529,7 @@ int main(void) |
| 502 | 529 | // |
| 503 | 530 | // GMatrix - GMatrix |
| 504 | 531 | result = m_test - m_test; |
| 505 | - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 532 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 506 | 533 | cout << endl << "TEST ERROR: Corrupt GMatrix - GMatrix operator." << endl; |
| 507 | 534 | cout << result << endl; |
| 508 | 535 | throw; |
| ... | ... | @@ -510,47 +537,15 @@ int main(void) |
| 510 | 537 | // |
| 511 | 538 | // GMatrix - GMatrix |
| 512 | 539 | result = m_test - m_test; |
| 513 | - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 540 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 514 | 541 | cout << endl << "TEST ERROR: Corrupt GMatrix - GMatrix operator." << endl; |
| 515 | 542 | cout << result << endl; |
| 516 | 543 | throw; |
| 517 | 544 | } |
| 518 | 545 | // |
| 519 | - // GMatrix + 3.0 | |
| 520 | - result = m_test + 3.0; | |
| 521 | - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 522 | - cout << endl << "TEST ERROR: Corrupt GMatrix + double operator." << endl; | |
| 523 | - cout << result << endl; | |
| 524 | - throw; | |
| 525 | - } | |
| 526 | - // | |
| 527 | - // 3.0 + GMatrix | |
| 528 | - result = 3.0 + m_test; | |
| 529 | - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 530 | - cout << endl << "TEST ERROR: Corrupt double + GMatrix operator." << endl; | |
| 531 | - cout << result << endl; | |
| 532 | - throw; | |
| 533 | - } | |
| 534 | - // | |
| 535 | - // GMatrix - 3.0 | |
| 536 | - result = m_test - 3.0; | |
| 537 | - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 538 | - cout << endl << "TEST ERROR: Corrupt GMatrix - double operator." << endl; | |
| 539 | - cout << result << endl; | |
| 540 | - throw; | |
| 541 | - } | |
| 542 | - // | |
| 543 | - // 3.0 - GMatrix | |
| 544 | - result = 3.0 - m_test; | |
| 545 | - if (!check_matrix(result, -1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 546 | - cout << endl << "TEST ERROR: Corrupt double - GMatrix operator." << endl; | |
| 547 | - cout << result << endl; | |
| 548 | - throw; | |
| 549 | - } | |
| 550 | - // | |
| 551 | 546 | // GMatrix * 3.0 |
| 552 | 547 | result = m_test * 3.0; |
| 553 | - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 548 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 554 | 549 | cout << endl << "TEST ERROR: Corrupt GMatrix * double operator." << endl; |
| 555 | 550 | cout << result << endl; |
| 556 | 551 | throw; |
| ... | ... | @@ -558,7 +553,7 @@ int main(void) |
| 558 | 553 | // |
| 559 | 554 | // 3.0 * GMatrix |
| 560 | 555 | result = 3.0 * m_test; |
| 561 | - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 556 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 562 | 557 | cout << endl << "TEST ERROR: Corrupt double * GMatrix operator." << endl; |
| 563 | 558 | cout << result << endl; |
| 564 | 559 | throw; |
| ... | ... | @@ -566,7 +561,7 @@ int main(void) |
| 566 | 561 | // |
| 567 | 562 | // GMatrix / 3.0 |
| 568 | 563 | result = m_test / 3.0; |
| 569 | - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 564 | + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 570 | 565 | cout << endl << "TEST ERROR: Corrupt GMatrix / double operator." << endl; |
| 571 | 566 | cout << result << endl; |
| 572 | 567 | throw; |
| ... | ... | @@ -580,7 +575,7 @@ int main(void) |
| 580 | 575 | result = m_test; |
| 581 | 576 | result += bigger; |
| 582 | 577 | } |
| 583 | - catch (GMatrix::dim_add_mismatch) { | |
| 578 | + catch (GMatrix::matrix_mismatch) { | |
| 584 | 579 | } |
| 585 | 580 | catch (exception &e) { |
| 586 | 581 | cout << e.what() << endl; |
| ... | ... | @@ -588,9 +583,9 @@ int main(void) |
| 588 | 583 | } |
| 589 | 584 | cout << "ok." << endl; |
| 590 | 585 | |
| 591 | - // Test 9: Matrix functions | |
| 586 | + // Test 10: Matrix functions | |
| 592 | 587 | try { |
| 593 | - cout << "GMatrix - Test 9: Matrix functions: "; | |
| 588 | + cout << "GMatrix - Test 10: Matrix functions: "; | |
| 594 | 589 | // |
| 595 | 590 | double min = m_test.min(); |
| 596 | 591 | if (!check_matrix_min(min)) { |
| ... | ... | @@ -618,9 +613,9 @@ int main(void) |
| 618 | 613 | } |
| 619 | 614 | cout << "ok." << endl; |
| 620 | 615 | |
| 621 | - // Test 10: Matrix comparison | |
| 616 | + // Test 11: Matrix comparison | |
| 622 | 617 | try { |
| 623 | - cout << "GMatrix - Test 10: Comparison: "; | |
| 618 | + cout << "GMatrix - Test 11: Comparison: "; | |
| 624 | 619 | // |
| 625 | 620 | if ((m_test == m_test) != 1) { |
| 626 | 621 | cout << endl << "TEST ERROR: Corrupt GMatrix == GMatrix operator." << endl; |
| ... | ... | @@ -659,49 +654,4 @@ int main(void) |
| 659 | 654 | } |
| 660 | 655 | cout << "ok." << endl; |
| 661 | 656 | |
| 662 | - // Test 11: Transformations | |
| 663 | - try { | |
| 664 | - cout << "GMatrix - Test 11: Transformations: "; | |
| 665 | - // | |
| 666 | - // transpose(GMatrix) | |
| 667 | - result = transpose(m_test); | |
| 668 | - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 669 | - cout << endl << "TEST ERROR: Corrupt transpose(GMatrix) function." << endl; | |
| 670 | - cout << result << endl; | |
| 671 | - throw; | |
| 672 | - } | |
| 673 | - // | |
| 674 | - // GMatrix.transpose() | |
| 675 | - result = m_test; | |
| 676 | - result.transpose(); | |
| 677 | - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 678 | - cout << endl << "TEST ERROR: Corrupt GMatrix.transpose() function." << endl; | |
| 679 | - cout << result << endl; | |
| 680 | - throw; | |
| 681 | - } | |
| 682 | -/* | |
| 683 | - // | |
| 684 | - // lower_triangle(GMatrix) | |
| 685 | - m_test11 = lower_triangle(m_test); | |
| 686 | - if (!check_matrix_lt(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 687 | - cout << endl << "TEST ERROR: Corrupt lower_triangle(GMatrix) function." << endl; | |
| 688 | - cout << m_test11 << endl; | |
| 689 | - throw; | |
| 690 | - } | |
| 691 | - // | |
| 692 | - // upper_triangle(GMatrix) | |
| 693 | - m_test11 = upper_triangle(m_test); | |
| 694 | - if (!check_matrix_ut(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 695 | - cout << endl << "TEST ERROR: Corrupt upper_triangle(GMatrix) function." << endl; | |
| 696 | - cout << m_test11 << endl; | |
| 697 | - throw; | |
| 698 | - } | |
| 699 | -*/ | |
| 700 | - } | |
| 701 | - catch (exception &e) { | |
| 702 | - cout << e.what() << endl; | |
| 703 | - throw; | |
| 704 | - } | |
| 705 | - cout << "ok." << endl; | |
| 706 | - | |
| 707 | -} | |
| 708 | 657 | \ No newline at end of file |
| 658 | +} | ... | ... |
test/test_GSparseMatrix.cpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * test_GSparseMatrix.cpp - test GSparseMatrix class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + ***************************************************************************/ | |
| 13 | + | |
| 14 | +/* __ Includes ___________________________________________________________ */ | |
| 15 | +#include "test_GSparseMatrix.hpp" | |
| 16 | + | |
| 17 | +/* __ Namespaces _________________________________________________________ */ | |
| 18 | +using namespace std; | |
| 19 | + | |
| 20 | +/* __ Definitions ________________________________________________________ */ | |
| 21 | +//#define DUMP_RESIDUALS // Dump residuals | |
| 22 | +#define DUMP_TIMING // Dump timing | |
| 23 | + | |
| 24 | +/* __ Globals ____________________________________________________________ */ | |
| 25 | +double g_matrix[] = {1.0, 7.0, 3.0, 2.0, 4.0, 8.0, 5.0, 6.0, 9.0}; | |
| 26 | +unsigned g_row[] = { 0, 0, 1, 2, 2, 2, 3, 3, 3}; | |
| 27 | +unsigned g_col[] = { 0, 4, 1, 0, 2, 4, 2, 3, 4}; | |
| 28 | +double g_vector[] = {1.0, 2.0, 3.0, 4.0, 5.0}; | |
| 29 | +unsigned g_elements = 9; | |
| 30 | +unsigned g_rows = 4; | |
| 31 | +unsigned g_cols = 5; | |
| 32 | + | |
| 33 | + | |
| 34 | +/*************************************************************************** | |
| 35 | + * Set test matrix * | |
| 36 | + ***************************************************************************/ | |
| 37 | +GSparseMatrix set_matrix(void) | |
| 38 | +{ | |
| 39 | + try { | |
| 40 | + GSparseMatrix matrix(g_rows,g_cols); | |
| 41 | + for (unsigned i = 0; i < g_elements; ++i) | |
| 42 | + matrix(g_row[i],g_col[i]) = g_matrix[i]; | |
| 43 | + return matrix; | |
| 44 | + } | |
| 45 | + catch (exception &e) { | |
| 46 | + cout << "TEST ERROR: Unable to set test matrix." << endl; | |
| 47 | + throw; | |
| 48 | + } | |
| 49 | +} | |
| 50 | + | |
| 51 | + | |
| 52 | +/*************************************************************************** | |
| 53 | + * Set test vector * | |
| 54 | + ***************************************************************************/ | |
| 55 | +GVector set_vector(void) | |
| 56 | +{ | |
| 57 | + try { | |
| 58 | + GVector vector(g_cols); | |
| 59 | + for (unsigned col = 0; col < g_cols; ++col) | |
| 60 | + vector(col) = g_vector[col]; | |
| 61 | + return vector; | |
| 62 | + } | |
| 63 | + catch (exception &e) { | |
| 64 | + cout << "TEST ERROR: Unable to set test vector." << endl; | |
| 65 | + throw; | |
| 66 | + } | |
| 67 | +} | |
| 68 | + | |
| 69 | + | |
| 70 | +/*************************************************************************** | |
| 71 | + * Check test matrix * | |
| 72 | + ***************************************************************************/ | |
| 73 | +int check_matrix(const GSparseMatrix& m, const double scale, const double add) | |
| 74 | +{ | |
| 75 | + int result = 1; | |
| 76 | + try { | |
| 77 | + for (unsigned row = 0; row < g_rows; ++row) { | |
| 78 | + for (unsigned col = 0; col < g_cols; ++col) { | |
| 79 | + unsigned i; | |
| 80 | + double ref_value = add; | |
| 81 | + for (i = 0; i < g_elements; ++i) { | |
| 82 | + if (g_row[i] == row && g_col[i] == col) { | |
| 83 | + ref_value = g_matrix[i] * scale + add; | |
| 84 | + break; | |
| 85 | + } | |
| 86 | + } | |
| 87 | + if (fabs(m(row,col)-ref_value) > 1.0e-15) { | |
| 88 | +//cout << row << "," << col << ": " << fabs(m(row,col)-ref_value) << endl; | |
| 89 | + result = 0; | |
| 90 | + break; | |
| 91 | + } | |
| 92 | + } | |
| 93 | + } | |
| 94 | + } | |
| 95 | + catch (exception &e) { | |
| 96 | + cout << "TEST ERROR: Unable to check test matrix." << endl; | |
| 97 | + throw; | |
| 98 | + } | |
| 99 | + return result; | |
| 100 | +} | |
| 101 | + | |
| 102 | + | |
| 103 | +/*************************************************************************** | |
| 104 | + * Check matrix*vector * | |
| 105 | + ***************************************************************************/ | |
| 106 | +int check_matrix_vector(const GVector& v) | |
| 107 | +{ | |
| 108 | + int result = 1; | |
| 109 | + try { | |
| 110 | + for (unsigned row = 0; row < v.size(); ++row) { | |
| 111 | + double value = 0.0; | |
| 112 | + for (unsigned col = 0; col < g_cols; ++col) { | |
| 113 | + unsigned i; | |
| 114 | + double ref_value = 0.0; | |
| 115 | + for (i = 0; i < g_elements; ++i) { | |
| 116 | + if (g_row[i] == row && g_col[i] == col) { | |
| 117 | + ref_value = g_matrix[i]; | |
| 118 | + break; | |
| 119 | + } | |
| 120 | + } | |
| 121 | + value += ref_value * g_vector[col]; | |
| 122 | + } | |
| 123 | + if (v(row) != value) { | |
| 124 | + result = 0; | |
| 125 | + break; | |
| 126 | + } | |
| 127 | + } | |
| 128 | + } | |
| 129 | + catch (exception &e) { | |
| 130 | + cout << "TEST ERROR: Unable to check matrix*vector product." << endl; | |
| 131 | + throw; | |
| 132 | + } | |
| 133 | + return result; | |
| 134 | +} | |
| 135 | + | |
| 136 | + | |
| 137 | +/*************************************************************************** | |
| 138 | + * Check matrix*matrix * | |
| 139 | + ***************************************************************************/ | |
| 140 | +int check_matrix_matrix(const GSparseMatrix& m) | |
| 141 | +{ | |
| 142 | + if (m.rows() != g_rows || m.cols() != g_rows) | |
| 143 | + return 0; | |
| 144 | + int result = 1; | |
| 145 | + try { | |
| 146 | + for (unsigned row = 0; row < m.rows(); ++row) { | |
| 147 | + for (unsigned col = 0; col < m.cols(); ++col) { | |
| 148 | + double value = 0.0; | |
| 149 | + for (unsigned i = 0; i < g_cols; ++i) { | |
| 150 | + unsigned k; | |
| 151 | + double ref_value_1 = 0.0; | |
| 152 | + double ref_value_2 = 0.0; | |
| 153 | + for (k = 0; k < g_elements; ++k) { | |
| 154 | + if (g_row[k] == row && g_col[k] == i) { | |
| 155 | + ref_value_1 = g_matrix[k]; | |
| 156 | + break; | |
| 157 | + } | |
| 158 | + } | |
| 159 | + for (k = 0; k < g_elements; ++k) { | |
| 160 | + if (g_row[k] == col && g_col[k] == i) { | |
| 161 | + ref_value_2 = g_matrix[k]; | |
| 162 | + break; | |
| 163 | + } | |
| 164 | + } | |
| 165 | + value += ref_value_1 * ref_value_2; | |
| 166 | + } | |
| 167 | +//cout << row << "," << col << ": " << fabs(m(row,col)-value) << endl; | |
| 168 | + if (m(row,col) != value) { | |
| 169 | + result = 0; | |
| 170 | + break; | |
| 171 | + } | |
| 172 | + } | |
| 173 | + } | |
| 174 | + } | |
| 175 | + catch (exception &e) { | |
| 176 | + cout << "TEST ERROR: Unable to check matrix*matrix product." << endl; | |
| 177 | + throw; | |
| 178 | + } | |
| 179 | + return result; | |
| 180 | +} | |
| 181 | + | |
| 182 | + | |
| 183 | +/*************************************************************************** | |
| 184 | + * Check transposed test matrix * | |
| 185 | + ***************************************************************************/ | |
| 186 | +int check_transpose_matrix(const GSparseMatrix& m, const double scale, const double add) | |
| 187 | +{ | |
| 188 | + int result = 1; | |
| 189 | + try { | |
| 190 | + for (unsigned row = 0; row < g_rows; ++row) { | |
| 191 | + for (unsigned col = 0; col < g_cols; ++col) { | |
| 192 | + unsigned i; | |
| 193 | + double ref_value = 0.0; | |
| 194 | + for (i = 0; i < g_elements; ++i) { | |
| 195 | + if (g_row[i] == row && g_col[i] == col) { | |
| 196 | + ref_value = g_matrix[i] * scale + add; | |
| 197 | + break; | |
| 198 | + } | |
| 199 | + } | |
| 200 | + if (fabs(m(col,row)-ref_value) > 1.0e-15) { | |
| 201 | + result = 0; | |
| 202 | + break; | |
| 203 | + } | |
| 204 | + } | |
| 205 | + } | |
| 206 | + } | |
| 207 | + catch (exception &e) { | |
| 208 | + cout << "TEST ERROR: Unable to check test matrix." << endl; | |
| 209 | + throw; | |
| 210 | + } | |
| 211 | + return result; | |
| 212 | +} | |
| 213 | + | |
| 214 | + | |
| 215 | +/*************************************************************************** | |
| 216 | + * Check matrix min * | |
| 217 | + ***************************************************************************/ | |
| 218 | +int check_matrix_min(const double min) | |
| 219 | +{ | |
| 220 | + double value = g_matrix[0]; | |
| 221 | + for (unsigned i = 0; i < g_elements; ++i) { | |
| 222 | + if (g_matrix[i] < value) | |
| 223 | + value = g_matrix[i]; | |
| 224 | + } | |
| 225 | +// return (min == value); | |
| 226 | + return (min == 0.0); | |
| 227 | +} | |
| 228 | + | |
| 229 | + | |
| 230 | +/*************************************************************************** | |
| 231 | + * Check matrix max * | |
| 232 | + ***************************************************************************/ | |
| 233 | +int check_matrix_max(const double max) | |
| 234 | +{ | |
| 235 | + double value = g_matrix[0]; | |
| 236 | + for (unsigned i = 0; i < g_elements; ++i) { | |
| 237 | + if (g_matrix[i] > value) | |
| 238 | + value = g_matrix[i]; | |
| 239 | + } | |
| 240 | + return (max == value); | |
| 241 | +} | |
| 242 | + | |
| 243 | + | |
| 244 | +/*************************************************************************** | |
| 245 | + * Check matrix sum * | |
| 246 | + ***************************************************************************/ | |
| 247 | +int check_matrix_sum(const double sum) | |
| 248 | +{ | |
| 249 | + double value = 0.0; | |
| 250 | + for (unsigned i = 0; i < g_elements; ++i) | |
| 251 | + value += g_matrix[i]; | |
| 252 | + return (sum == value); | |
| 253 | +} | |
| 254 | + | |
| 255 | + | |
| 256 | +/*************************************************************************** | |
| 257 | + * Test: Output * | |
| 258 | + ***************************************************************************/ | |
| 259 | +void test_output(const GSparseMatrix& m_test) | |
| 260 | +{ | |
| 261 | + cout << "Test GSparseMatrix: Output test matrix: " << endl; | |
| 262 | + try { | |
| 263 | + cout << m_test << endl; | |
| 264 | + } | |
| 265 | + catch (exception &e) { | |
| 266 | + cout << endl << "TEST ERROR: Unable to output matrix." << endl; | |
| 267 | + cout << e.what() << endl; | |
| 268 | + throw; | |
| 269 | + } | |
| 270 | +} | |
| 271 | + | |
| 272 | + | |
| 273 | +/*************************************************************************** | |
| 274 | + * Test: Allocate zero matrix * | |
| 275 | + ***************************************************************************/ | |
| 276 | +void test_allocate(void) | |
| 277 | +{ | |
| 278 | + cout << "Test GSparseMatrix: Allocate zero matrix: "; | |
| 279 | + try { | |
| 280 | + GSparseMatrix test(0,0); | |
| 281 | + } | |
| 282 | + catch (empty &e) { | |
| 283 | + cout << ". ok." << endl; | |
| 284 | + } | |
| 285 | + catch (exception &e) { | |
| 286 | + cout << endl << "TEST ERROR: Did not signal zero matrix allocation." << endl; | |
| 287 | + cout << e.what() << endl; | |
| 288 | + throw; | |
| 289 | + } | |
| 290 | + cout << ". ok." << endl; | |
| 291 | +} | |
| 292 | + | |
| 293 | + | |
| 294 | +/*************************************************************************** | |
| 295 | + * Test: Assign values * | |
| 296 | + ***************************************************************************/ | |
| 297 | +void test_assign_values(const GSparseMatrix& m_test) | |
| 298 | +{ | |
| 299 | + cout << "Test GSparseMatrix: Assign matrix values: "; | |
| 300 | + try { | |
| 301 | + // | |
| 302 | + GSparseMatrix test(3,3); | |
| 303 | + test(1,1) = 1.0; | |
| 304 | + if (test(0,0) != 0.0 || test(1,0) != 0.0 || test(2,0) != 0.0 || | |
| 305 | + test(0,1) != 0.0 || test(1,1) != 1.0 || test(2,1) != 0.0 || | |
| 306 | + test(0,2) != 0.0 || test(1,2) != 0.0 || test(2,2) != 0.0) { | |
| 307 | + cout << endl << "TEST ERROR: Unable to set matrix values." << endl; | |
| 308 | + cout << test << endl; | |
| 309 | + throw; | |
| 310 | + } | |
| 311 | + cout << "."; | |
| 312 | + // | |
| 313 | + GSparseMatrix result = m_test; | |
| 314 | + result(0,0) = 0.0; | |
| 315 | + result(0,0) = 1.0; | |
| 316 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 317 | + cout << endl << "TEST ERROR: Bad M(row,col) assignment." << endl; | |
| 318 | + cout << "result:" << endl << result << endl; | |
| 319 | + cout << "m_test:" << endl << m_test << endl; | |
| 320 | + throw; | |
| 321 | + } | |
| 322 | + cout << "."; | |
| 323 | + // | |
| 324 | + result = m_test; | |
| 325 | + result(0,0) = 0.0; | |
| 326 | + result(0,4) = 0.0; | |
| 327 | + result(0,0) = 1.0; | |
| 328 | + result(0,4) = 0.0; | |
| 329 | + result(0,4) = 7.0; | |
| 330 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 331 | + cout << endl << "TEST ERROR: Bad M(row,col) assignment." << endl; | |
| 332 | + cout << "result:" << endl << result << endl; | |
| 333 | + cout << "m_test:" << endl << m_test << endl; | |
| 334 | + throw; | |
| 335 | + } | |
| 336 | + cout << "."; | |
| 337 | + // | |
| 338 | + result = m_test; | |
| 339 | + result(0,1) = 2.0; | |
| 340 | + result(0,2) = 2.0; | |
| 341 | + result(0,3) = 2.0; | |
| 342 | + result(0,1) = 0.0; | |
| 343 | + result(0,2) = 0.0; | |
| 344 | + result(0,3) = 0.0; | |
| 345 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 346 | + cout << endl << "TEST ERROR: Bad M(row,col) assignment." << endl; | |
| 347 | + cout << "result:" << endl << result << endl; | |
| 348 | + cout << "m_test:" << endl << m_test << endl; | |
| 349 | + throw; | |
| 350 | + } | |
| 351 | + cout << "."; | |
| 352 | + } | |
| 353 | + catch (exception &e) { | |
| 354 | + cout << e.what() << endl; | |
| 355 | + throw; | |
| 356 | + } | |
| 357 | + #if defined(G_RANGE_CHECK) | |
| 358 | + try { | |
| 359 | + GSparseMatrix test(3,3); | |
| 360 | + test(3,3) = 1.0; | |
| 361 | + } | |
| 362 | + catch (GMatrix::out_of_range &e) { | |
| 363 | + } | |
| 364 | + catch (exception &e) { | |
| 365 | + cout << e.what() << endl; | |
| 366 | + throw; | |
| 367 | + } | |
| 368 | + cout << "."; | |
| 369 | + #endif | |
| 370 | + cout << " ok." << endl; | |
| 371 | +} | |
| 372 | + | |
| 373 | + | |
| 374 | +/*************************************************************************** | |
| 375 | + * Test: Matrix copy constructor * | |
| 376 | + ***************************************************************************/ | |
| 377 | +void test_copy_constructor(const GSparseMatrix& m_test) | |
| 378 | +{ | |
| 379 | + cout << "Test GSparseMatrix: Define matrix using copy constructor: "; | |
| 380 | + try { | |
| 381 | + // | |
| 382 | + GSparseMatrix test = m_test; | |
| 383 | + if (!check_matrix(test, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 384 | + cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; | |
| 385 | + cout << test << endl; | |
| 386 | + throw; | |
| 387 | + } | |
| 388 | + } | |
| 389 | + catch (exception &e) { | |
| 390 | + cout << e.what() << endl; | |
| 391 | + throw; | |
| 392 | + } | |
| 393 | + cout << ". ok." << endl; | |
| 394 | +} | |
| 395 | + | |
| 396 | + | |
| 397 | +/*************************************************************************** | |
| 398 | + * Test: Matrix assignment * | |
| 399 | + ***************************************************************************/ | |
| 400 | +void test_assign_matrix(const GSparseMatrix& m_test) | |
| 401 | +{ | |
| 402 | + cout << "Test GSparseMatrix: Matrix assignment: "; | |
| 403 | + try { | |
| 404 | + // | |
| 405 | + // GSparseMatrix = GSparseMatrix | |
| 406 | + GSparseMatrix result(1,1); | |
| 407 | + result = m_test; | |
| 408 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 409 | + cout << endl << "TEST ERROR: Corrupt assignment." << endl; | |
| 410 | + cout << result << endl; | |
| 411 | + throw; | |
| 412 | + } | |
| 413 | + cout << "."; | |
| 414 | + // | |
| 415 | + // GSparseMatrix = GSparseMatrix (bigger matrix) | |
| 416 | + GSparseMatrix bigger(1000,1000); | |
| 417 | + for (int i = 0; i < 1000; ++i) | |
| 418 | + bigger(i,i) = (i+1)*1.1; | |
| 419 | + result = bigger; | |
| 420 | + cout << "."; | |
| 421 | + } | |
| 422 | + catch (exception &e) { | |
| 423 | + cout << e.what() << endl; | |
| 424 | + throw; | |
| 425 | + } | |
| 426 | + cout << " ok." << endl; | |
| 427 | +} | |
| 428 | + | |
| 429 | + | |
| 430 | +/*************************************************************************** | |
| 431 | + * Test: Matrix transpose * | |
| 432 | + ***************************************************************************/ | |
| 433 | +void test_transpose(const GSparseMatrix& m_test) | |
| 434 | +{ | |
| 435 | + cout << "Test GSparseMatrix: Matrix transpose: "; | |
| 436 | + try { | |
| 437 | + // | |
| 438 | + // transpose(GSparseMatrix) | |
| 439 | + GSparseMatrix result(1,1); | |
| 440 | + result = transpose(m_test); | |
| 441 | + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 442 | + cout << endl << "TEST ERROR: Corrupt transpose(GSparseMatrix) function." << endl; | |
| 443 | + cout << result << endl; | |
| 444 | + throw; | |
| 445 | + } | |
| 446 | + cout << "."; | |
| 447 | + // | |
| 448 | + // GSparseMatrix.transpose() | |
| 449 | + result = m_test; | |
| 450 | + result.transpose(); | |
| 451 | + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 452 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.transpose() function." << endl; | |
| 453 | + cout << result << endl; | |
| 454 | + throw; | |
| 455 | + } | |
| 456 | + cout << "."; | |
| 457 | + } | |
| 458 | + catch (exception &e) { | |
| 459 | + cout << e.what() << endl; | |
| 460 | + throw; | |
| 461 | + } | |
| 462 | + cout << " ok." << endl; | |
| 463 | +} | |
| 464 | + | |
| 465 | + | |
| 466 | +/*************************************************************************** | |
| 467 | + * Test: Matrix*Vector multiplication * | |
| 468 | + ***************************************************************************/ | |
| 469 | +void test_matrix_vector(const GSparseMatrix& m_test, const GVector& v_test) | |
| 470 | +{ | |
| 471 | + cout << "Test GSparseMatrix: Matrix*Vector multiplication: "; | |
| 472 | + try { | |
| 473 | + // | |
| 474 | + GVector test = m_test*v_test; | |
| 475 | + if (!check_matrix_vector(test) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 476 | + cout << endl << "TEST ERROR: Corrupt Matrix*Vector multiplication." << endl; | |
| 477 | + cout << test << endl; | |
| 478 | + throw; | |
| 479 | + } | |
| 480 | + } | |
| 481 | + catch (exception &e) { | |
| 482 | + cout << e.what() << endl; | |
| 483 | + throw; | |
| 484 | + } | |
| 485 | + cout << "."; | |
| 486 | + try { | |
| 487 | + GSparseMatrix bigger(1000,1000); | |
| 488 | + for (int i = 0; i < 1000; ++i) | |
| 489 | + bigger(i,i) = (i+1)*1.1; | |
| 490 | + GVector test = bigger*v_test; | |
| 491 | + } | |
| 492 | + catch (GMatrix::matrix_vector_mismatch &e) { | |
| 493 | + } | |
| 494 | + catch (exception &e) { | |
| 495 | + cout << e.what() << endl; | |
| 496 | + throw; | |
| 497 | + } | |
| 498 | + cout << ". ok." << endl; | |
| 499 | +} | |
| 500 | + | |
| 501 | + | |
| 502 | +/*************************************************************************** | |
| 503 | + * Test: Matrix*Vector multiplication * | |
| 504 | + ***************************************************************************/ | |
| 505 | +void test_matrix_matrix(const GSparseMatrix& m_test) | |
| 506 | +{ | |
| 507 | + cout << "Test GSparseMatrix: Matrix*Matrix multiplication: "; | |
| 508 | + try { | |
| 509 | + // | |
| 510 | + GSparseMatrix test = m_test * transpose(m_test); | |
| 511 | + if (!check_matrix_matrix(test) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 512 | + cout << endl << "TEST ERROR: Corrupt Matrix*Matrix multiplication." << endl; | |
| 513 | + cout << "test:" << endl << test << endl; | |
| 514 | + cout << "m_test:" << endl << m_test << endl; | |
| 515 | + throw; | |
| 516 | + } | |
| 517 | + cout << "."; | |
| 518 | + // | |
| 519 | + GSparseMatrix bigger(1000,1000); | |
| 520 | + for (int i = 0; i < 1000; ++i) | |
| 521 | + bigger(i,i) = (i+1)*1.1; | |
| 522 | + try { | |
| 523 | + GSparseMatrix test = m_test * bigger; | |
| 524 | + } | |
| 525 | + catch (GMatrix::matrix_mismatch &e) { | |
| 526 | + cout << "."; | |
| 527 | + } | |
| 528 | + catch (exception &e) { | |
| 529 | + cout << e.what() << endl; | |
| 530 | + throw; | |
| 531 | + } | |
| 532 | + // | |
| 533 | + try { | |
| 534 | + GSparseMatrix test7 = bigger * m_test; | |
| 535 | + } | |
| 536 | + catch (GMatrix::matrix_mismatch &e) { | |
| 537 | + cout << "."; | |
| 538 | + } | |
| 539 | + catch (exception &e) { | |
| 540 | + cout << e.what() << endl; | |
| 541 | + throw; | |
| 542 | + } | |
| 543 | + } | |
| 544 | + catch (exception &e) { | |
| 545 | + cout << e.what() << endl; | |
| 546 | + throw; | |
| 547 | + } | |
| 548 | + cout << " ok." << endl; | |
| 549 | +} | |
| 550 | + | |
| 551 | + | |
| 552 | +/*************************************************************************** | |
| 553 | + * Test: Arithmetics * | |
| 554 | + ***************************************************************************/ | |
| 555 | +void test_arithmetics(const GSparseMatrix& m_test) | |
| 556 | +{ | |
| 557 | + cout << "Test GSparseMatrix: Arithmetics: "; | |
| 558 | + try { | |
| 559 | + // | |
| 560 | + // -GSparseMatrix | |
| 561 | + GSparseMatrix result(1,1); | |
| 562 | + result = -m_test; | |
| 563 | + if (!check_matrix(result, -1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 564 | + cout << endl << "TEST ERROR: Corrupt -GSparseMatrix operator." << endl; | |
| 565 | + cout << "result " << result << endl; | |
| 566 | + cout << "m_test " << m_test << endl; | |
| 567 | + throw; | |
| 568 | + } | |
| 569 | + cout << "."; | |
| 570 | + // | |
| 571 | + // fabs(GSparseMatrix) | |
| 572 | + result = fabs(m_test); | |
| 573 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 574 | + cout << endl << "TEST ERROR: Corrupt fabs(GSparseMatrix) function." << endl; | |
| 575 | + cout << "result " << result << endl; | |
| 576 | + cout << "m_test " << m_test << endl; | |
| 577 | + throw; | |
| 578 | + } | |
| 579 | + cout << "."; | |
| 580 | + // | |
| 581 | + // GSparseMatrix += GSparseMatrix | |
| 582 | + result = m_test; | |
| 583 | + result += m_test; | |
| 584 | + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 585 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix += GSparseMatrix operator." << endl; | |
| 586 | + cout << "result " << result << endl; | |
| 587 | + cout << "m_test " << m_test << endl; | |
| 588 | + throw; | |
| 589 | + } | |
| 590 | + cout << "."; | |
| 591 | + // | |
| 592 | + // GSparseMatrix -= GSparseMatrix | |
| 593 | + result = m_test; | |
| 594 | + result -= m_test; | |
| 595 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 596 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix -= GSparseMatrix operator." << endl; | |
| 597 | + cout << "result " << result << endl; | |
| 598 | + cout << "m_test " << m_test << endl; | |
| 599 | + throw; | |
| 600 | + } | |
| 601 | + cout << "."; | |
| 602 | + // | |
| 603 | + // GSparseMatrix *= 3.0 | |
| 604 | + result = m_test; | |
| 605 | + result *= 3.0; | |
| 606 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 607 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix *= double operator." << endl; | |
| 608 | + cout << "result " << result << endl; | |
| 609 | + cout << "m_test " << m_test << endl; | |
| 610 | + throw; | |
| 611 | + } | |
| 612 | + cout << "."; | |
| 613 | + // | |
| 614 | + // GSparseMatrix /= 3.0 | |
| 615 | + result = m_test; | |
| 616 | + result /= 3.0; | |
| 617 | + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 618 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix /= double operator." << endl; | |
| 619 | + cout << "result " << result << endl; | |
| 620 | + cout << "m_test " << m_test << endl; | |
| 621 | + throw; | |
| 622 | + } | |
| 623 | + cout << "."; | |
| 624 | + // | |
| 625 | + // GSparseMatrix + GSparseMatrix | |
| 626 | + result = m_test + m_test; | |
| 627 | + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 628 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix + GSparseMatrix operator." << endl; | |
| 629 | + cout << "result " << result << endl; | |
| 630 | + cout << "m_test " << m_test << endl; | |
| 631 | + throw; | |
| 632 | + } | |
| 633 | + cout << "."; | |
| 634 | + // | |
| 635 | + // GSparseMatrix - GSparseMatrix | |
| 636 | + result = m_test - m_test; | |
| 637 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 638 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix - GSparseMatrix operator." << endl; | |
| 639 | + cout << "result " << result << endl; | |
| 640 | + cout << "m_test " << m_test << endl; | |
| 641 | + throw; | |
| 642 | + } | |
| 643 | + cout << "."; | |
| 644 | + // | |
| 645 | + // GSparseMatrix - GSparseMatrix | |
| 646 | + result = m_test - m_test; | |
| 647 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 648 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix - GSparseMatrix operator." << endl; | |
| 649 | + cout << "result " << result << endl; | |
| 650 | + cout << "m_test " << m_test << endl; | |
| 651 | + throw; | |
| 652 | + } | |
| 653 | + cout << "."; | |
| 654 | + // | |
| 655 | + // GSparseMatrix * 3.0 | |
| 656 | + result = m_test * 3.0; | |
| 657 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 658 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix * double operator." << endl; | |
| 659 | + cout << "result " << result << endl; | |
| 660 | + cout << "m_test " << m_test << endl; | |
| 661 | + throw; | |
| 662 | + } | |
| 663 | + cout << "."; | |
| 664 | + // | |
| 665 | + // GSparseMatrix * -7.12 | |
| 666 | + result = m_test * -7.12; | |
| 667 | + if (!check_matrix(result, -7.12, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 668 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix * double operator." << endl; | |
| 669 | + cout << "result " << result << endl; | |
| 670 | + cout << "m_test " << m_test << endl; | |
| 671 | + throw; | |
| 672 | + } | |
| 673 | + cout << "."; | |
| 674 | + // | |
| 675 | + // 3.0 * GSparseMatrix | |
| 676 | + result = 3.0 * m_test; | |
| 677 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 678 | + cout << endl << "TEST ERROR: Corrupt double * GSparseMatrix operator." << endl; | |
| 679 | + cout << "result " << result << endl; | |
| 680 | + cout << "m_test " << m_test << endl; | |
| 681 | + throw; | |
| 682 | + } | |
| 683 | + cout << "."; | |
| 684 | + // | |
| 685 | + // GSparseMatrix / 3.0 | |
| 686 | + result = m_test / 3.0; | |
| 687 | + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 688 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix / double operator." << endl; | |
| 689 | + cout << "result " << result << endl; | |
| 690 | + cout << "m_test " << m_test << endl; | |
| 691 | + throw; | |
| 692 | + } | |
| 693 | + cout << "."; | |
| 694 | + // | |
| 695 | + // GSparseMatrix / 0.0 | |
| 696 | + double zero = 0.0; | |
| 697 | + result = m_test / zero; | |
| 698 | + if (!check_matrix(result, 1.0/zero, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 699 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix / 0.0." << endl; | |
| 700 | + cout << "result " << result << endl; | |
| 701 | + cout << "m_test " << m_test << endl; | |
| 702 | + throw; | |
| 703 | + cout << "."; | |
| 704 | + } | |
| 705 | + // | |
| 706 | + // GSparseMatrix.add_col() | |
| 707 | + result = m_test; | |
| 708 | + GVector v_add(g_rows); | |
| 709 | + for (int i = 0; i < g_rows; ++i) | |
| 710 | + v_add(i) = 7.0; | |
| 711 | + for (int col = 0; col < g_cols; ++col) | |
| 712 | + result.add_col(v_add, col); | |
| 713 | + if (!check_matrix(result, 1.0, 7.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 714 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.add_col(+v)." << endl; | |
| 715 | + cout << "result " << result << endl; | |
| 716 | + cout << "m_test " << m_test << endl; | |
| 717 | + throw; | |
| 718 | + } | |
| 719 | + cout << "."; | |
| 720 | + // | |
| 721 | + // GSparseMatrix.add_col() | |
| 722 | + for (int col = 0; col < g_cols; ++col) | |
| 723 | + result.add_col(-v_add, col); | |
| 724 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 725 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.add_col(-v)." << endl; | |
| 726 | + cout << "result " << result << endl; | |
| 727 | + cout << "m_test " << m_test << endl; | |
| 728 | + throw; | |
| 729 | + } | |
| 730 | + cout << "."; | |
| 731 | + } | |
| 732 | + catch (exception &e) { | |
| 733 | + cout << e.what() << endl; | |
| 734 | + throw; | |
| 735 | + } | |
| 736 | + try { | |
| 737 | + GSparseMatrix bigger(1000,1000); | |
| 738 | + GSparseMatrix result(1,1); | |
| 739 | + for (int i = 0; i < 1000; ++i) | |
| 740 | + bigger(i,i) = (i+1)*1.1; | |
| 741 | + result = m_test; | |
| 742 | + result += bigger; | |
| 743 | + } | |
| 744 | + catch (GMatrix::matrix_mismatch) { | |
| 745 | + cout << "."; | |
| 746 | + } | |
| 747 | + catch (exception &e) { | |
| 748 | + cout << e.what() << endl; | |
| 749 | + throw; | |
| 750 | + } | |
| 751 | + cout << " ok." << endl; | |
| 752 | +} | |
| 753 | + | |
| 754 | + | |
| 755 | +/*************************************************************************** | |
| 756 | + * Test: Matrix functions * | |
| 757 | + ***************************************************************************/ | |
| 758 | +void test_functions(const GSparseMatrix& m_test) | |
| 759 | +{ | |
| 760 | + cout << "Test GSparseMatrix: Matrix functions: "; | |
| 761 | + try { | |
| 762 | + // | |
| 763 | + double min = m_test.min(); | |
| 764 | + if (!check_matrix_min(min)) { | |
| 765 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.min() function." << endl; | |
| 766 | + cout << "min:" << min << endl; | |
| 767 | + throw; | |
| 768 | + } | |
| 769 | + cout << "."; | |
| 770 | + // | |
| 771 | + double max = m_test.max(); | |
| 772 | + if (!check_matrix_max(max)) { | |
| 773 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.max() function." << endl; | |
| 774 | + cout << "max:" << max << endl; | |
| 775 | + throw; | |
| 776 | + } | |
| 777 | + cout << "."; | |
| 778 | + // | |
| 779 | + double sum = m_test.sum(); | |
| 780 | + if (!check_matrix_sum(sum)) { | |
| 781 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.sum() function." << endl; | |
| 782 | + cout << "sum:" << sum << endl; | |
| 783 | + throw; | |
| 784 | + } | |
| 785 | + cout << "."; | |
| 786 | + } | |
| 787 | + catch (exception &e) { | |
| 788 | + cout << e.what() << endl; | |
| 789 | + } | |
| 790 | + cout << " ok." << endl; | |
| 791 | +} | |
| 792 | + | |
| 793 | + | |
| 794 | +/*************************************************************************** | |
| 795 | + * Test: Matrix comparison * | |
| 796 | + ***************************************************************************/ | |
| 797 | +void test_comparison(const GSparseMatrix& m_test) | |
| 798 | +{ | |
| 799 | + cout << "Test GSparseMatrix: Comparison: "; | |
| 800 | + try { | |
| 801 | + GSparseMatrix bigger(1000,1000); | |
| 802 | + for (int i = 0; i < 1000; ++i) | |
| 803 | + bigger(i,i) = (i+1)*1.1; | |
| 804 | + // | |
| 805 | + if ((m_test == m_test) != 1) { | |
| 806 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix == GSparseMatrix operator." << endl; | |
| 807 | + throw; | |
| 808 | + } | |
| 809 | + cout << "."; | |
| 810 | + // | |
| 811 | + GSparseMatrix test(g_rows,g_cols); | |
| 812 | + if ((m_test == test) != 0) { | |
| 813 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix == GSparseMatrix operator." << endl; | |
| 814 | + throw; | |
| 815 | + } | |
| 816 | + cout << "."; | |
| 817 | + // | |
| 818 | + if ((m_test == bigger) != 0) { | |
| 819 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix == GSparseMatrix operator." << endl; | |
| 820 | + throw; | |
| 821 | + } | |
| 822 | + cout << "."; | |
| 823 | + // | |
| 824 | + if ((m_test != m_test) != 0) { | |
| 825 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix != GSparseMatrix operator." << endl; | |
| 826 | + throw; | |
| 827 | + } | |
| 828 | + cout << "."; | |
| 829 | + // | |
| 830 | + if ((m_test != test) != 1) { | |
| 831 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix != GSparseMatrix operator." << endl; | |
| 832 | + throw; | |
| 833 | + } | |
| 834 | + cout << "."; | |
| 835 | + // | |
| 836 | + if ((m_test != bigger) != 1) { | |
| 837 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix != GSparseMatrix operator." << endl; | |
| 838 | + throw; | |
| 839 | + } | |
| 840 | + cout << "."; | |
| 841 | + } | |
| 842 | + catch (exception &e) { | |
| 843 | + cout << e.what() << endl; | |
| 844 | + throw; | |
| 845 | + } | |
| 846 | + cout << " ok." << endl; | |
| 847 | +} | |
| 848 | + | |
| 849 | + | |
| 850 | +/*************************************************************************** | |
| 851 | + * Test: Matrix conversions * | |
| 852 | + ***************************************************************************/ | |
| 853 | +void test_conversion(const GSparseMatrix& m_test) | |
| 854 | +{ | |
| 855 | + cout << "Test GSparseMatrix: Conversions: "; | |
| 856 | + cout << " ok." << endl; | |
| 857 | +} | |
| 858 | + | |
| 859 | + | |
| 860 | +/*************************************************************************** | |
| 861 | + * Test: Cholesky factorisation * | |
| 862 | + ***************************************************************************/ | |
| 863 | +void test_cholesky(void) | |
| 864 | +{ | |
| 865 | + cout << "Test GSparseMatrix: Cholesky decomposition, solver and inverter: "; | |
| 866 | + try { | |
| 867 | + // | |
| 868 | + // Setup matrix for Cholesky decomposition | |
| 869 | + GSparseMatrix m_chol_test(5,5); | |
| 870 | + m_chol_test(0,0) = 1.0; | |
| 871 | + m_chol_test(0,1) = 0.2; | |
| 872 | + m_chol_test(0,2) = 0.2; | |
| 873 | + m_chol_test(0,3) = 0.2; | |
| 874 | + m_chol_test(0,4) = 0.2; | |
| 875 | + m_chol_test(1,0) = 0.2; | |
| 876 | + m_chol_test(2,0) = 0.2; | |
| 877 | + m_chol_test(3,0) = 0.2; | |
| 878 | + m_chol_test(4,0) = 0.2; | |
| 879 | + m_chol_test(1,1) = 1.0; | |
| 880 | + m_chol_test(2,2) = 1.0; | |
| 881 | + m_chol_test(3,3) = 1.0; | |
| 882 | + m_chol_test(4,4) = 1.0; | |
| 883 | + // | |
| 884 | + // Try to solve now (should not work) | |
| 885 | + try { | |
| 886 | + GVector v_test12(5); | |
| 887 | + v_test12 = m_chol_test.cholesky_solver(v_test12); | |
| 888 | + } | |
| 889 | + catch (GMatrix::matrix_not_factorised) { | |
| 890 | + cout << "."; | |
| 891 | + } | |
| 892 | + catch (exception &e) { | |
| 893 | + cout << e.what() << endl; | |
| 894 | + throw; | |
| 895 | + } | |
| 896 | + // | |
| 897 | + // Test Cholesky decomposition | |
| 898 | + GSparseMatrix cd = cholesky_decompose(m_chol_test); | |
| 899 | + cout << "."; | |
| 900 | + // | |
| 901 | + // Test inplace Cholesky decomposition | |
| 902 | + cd = m_chol_test; | |
| 903 | + cd.cholesky_decompose(); | |
| 904 | + cout << "."; | |
| 905 | + // | |
| 906 | + // Test Cholesky solver | |
| 907 | + GVector e0(5); | |
| 908 | + GVector a0(5); | |
| 909 | + e0(0) = 1.0; | |
| 910 | + a0(0) = 1.0; | |
| 911 | + a0(1) = 0.2; | |
| 912 | + a0(2) = 0.2; | |
| 913 | + a0(3) = 0.2; | |
| 914 | + a0(4) = 0.2; | |
| 915 | + GVector s0 = cd.cholesky_solver(a0); | |
| 916 | + double res = max(fabs(s0-e0)); | |
| 917 | + if (res < 1.0e-15) | |
| 918 | + #if defined(DUMP_RESIDUALS) | |
| 919 | + cout << " Res(S0)=" << res << " "; | |
| 920 | + #else | |
| 921 | + cout << "."; | |
| 922 | + #endif | |
| 923 | + else { | |
| 924 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 925 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 926 | + cout << s0 << endl; | |
| 927 | + throw; | |
| 928 | + } | |
| 929 | + // | |
| 930 | + e0(0) = 0.0; | |
| 931 | + e0(1) = 1.0; | |
| 932 | + a0(0) = 0.2; | |
| 933 | + a0(1) = 1.0; | |
| 934 | + a0(2) = 0.0; | |
| 935 | + a0(3) = 0.0; | |
| 936 | + a0(4) = 0.0; | |
| 937 | + s0 = cd.cholesky_solver(a0); | |
| 938 | + res = max(fabs(s0-e0)); | |
| 939 | + if (res < 1.0e-15) | |
| 940 | + #if defined(DUMP_RESIDUALS) | |
| 941 | + cout << "Res(S1)=" << res << " "; | |
| 942 | + #else | |
| 943 | + cout << "."; | |
| 944 | + #endif | |
| 945 | + else { | |
| 946 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 947 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 948 | + cout << s0 << endl; | |
| 949 | + throw; | |
| 950 | + } | |
| 951 | + // | |
| 952 | + e0(1) = 0.0; | |
| 953 | + e0(2) = 1.0; | |
| 954 | + a0(1) = 0.0; | |
| 955 | + a0(2) = 1.0; | |
| 956 | + s0 = cd.cholesky_solver(a0); | |
| 957 | + res = max(fabs(s0-e0)); | |
| 958 | + if (res < 1.0e-15) | |
| 959 | + #if defined(DUMP_RESIDUALS) | |
| 960 | + cout << "Res(S2)=" << res << " "; | |
| 961 | + #else | |
| 962 | + cout << "."; | |
| 963 | + #endif | |
| 964 | + else { | |
| 965 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 966 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 967 | + cout << s0 << endl; | |
| 968 | + throw; | |
| 969 | + } | |
| 970 | + // | |
| 971 | + e0(2) = 0.0; | |
| 972 | + e0(3) = 1.0; | |
| 973 | + a0(2) = 0.0; | |
| 974 | + a0(3) = 1.0; | |
| 975 | + s0 = cd.cholesky_solver(a0); | |
| 976 | + res = max(fabs(s0-e0)); | |
| 977 | + if (res < 1.0e-15) | |
| 978 | + #if defined(DUMP_RESIDUALS) | |
| 979 | + cout << "Res(S3)=" << res << " "; | |
| 980 | + #else | |
| 981 | + cout << "."; | |
| 982 | + #endif | |
| 983 | + else { | |
| 984 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 985 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 986 | + cout << s0 << endl; | |
| 987 | + throw; | |
| 988 | + } | |
| 989 | + // | |
| 990 | + e0(3) = 0.0; | |
| 991 | + e0(4) = 1.0; | |
| 992 | + a0(3) = 0.0; | |
| 993 | + a0(4) = 1.0; | |
| 994 | + s0 = cd.cholesky_solver(a0); | |
| 995 | + res = max(fabs(s0-e0)); | |
| 996 | + if (res < 1.0e-15) | |
| 997 | + #if defined(DUMP_RESIDUALS) | |
| 998 | + cout << "Res(S4)=" << res << " "; | |
| 999 | + #else | |
| 1000 | + cout << "."; | |
| 1001 | + #endif | |
| 1002 | + else { | |
| 1003 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1004 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1005 | + cout << s0 << endl; | |
| 1006 | + throw; | |
| 1007 | + } | |
| 1008 | + // | |
| 1009 | + // Setup matrix for Cholesky decomposition with zero row/col | |
| 1010 | + GSparseMatrix m_chol_test_zero(6,6); | |
| 1011 | + m_chol_test_zero(0,0) = 1.0; | |
| 1012 | + m_chol_test_zero(0,1) = 0.2; | |
| 1013 | + m_chol_test_zero(0,2) = 0.2; | |
| 1014 | + m_chol_test_zero(0,4) = 0.2; | |
| 1015 | + m_chol_test_zero(0,5) = 0.2; | |
| 1016 | + m_chol_test_zero(1,0) = 0.2; | |
| 1017 | + m_chol_test_zero(2,0) = 0.2; | |
| 1018 | + m_chol_test_zero(4,0) = 0.2; | |
| 1019 | + m_chol_test_zero(5,0) = 0.2; | |
| 1020 | + m_chol_test_zero(1,1) = 1.0; | |
| 1021 | + m_chol_test_zero(2,2) = 1.0; | |
| 1022 | + m_chol_test_zero(4,4) = 1.0; | |
| 1023 | + m_chol_test_zero(5,5) = 1.0; | |
| 1024 | + // | |
| 1025 | + // Test compressed Cholesky decomposition | |
| 1026 | + GSparseMatrix cd_zero = m_chol_test_zero; | |
| 1027 | + cd_zero.cholesky_decompose(); | |
| 1028 | + // | |
| 1029 | + // Test compressed Cholesky solver | |
| 1030 | + e0 = GVector(6); | |
| 1031 | + a0 = GVector(6); | |
| 1032 | + e0(0) = 1.0; | |
| 1033 | + a0(0) = 1.0; | |
| 1034 | + a0(1) = 0.2; | |
| 1035 | + a0(2) = 0.2; | |
| 1036 | + a0(4) = 0.2; | |
| 1037 | + a0(5) = 0.2; | |
| 1038 | + s0 = cd_zero.cholesky_solver(a0); | |
| 1039 | + res = max(fabs(s0-e0)); | |
| 1040 | + if (res < 1.0e-15) | |
| 1041 | + #if defined(DUMP_RESIDUALS) | |
| 1042 | + cout << "Res(S0Z)=" << res << " "; | |
| 1043 | + #else | |
| 1044 | + cout << "."; | |
| 1045 | + #endif | |
| 1046 | + else { | |
| 1047 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1048 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1049 | + cout << s0 << endl; | |
| 1050 | + throw; | |
| 1051 | + } | |
| 1052 | + // | |
| 1053 | + e0(0) = 0.0; | |
| 1054 | + e0(1) = 1.0; | |
| 1055 | + a0(0) = 0.2; | |
| 1056 | + a0(1) = 1.0; | |
| 1057 | + a0(2) = 0.0; | |
| 1058 | + a0(4) = 0.0; | |
| 1059 | + a0(5) = 0.0; | |
| 1060 | + s0 = cd_zero.cholesky_solver(a0); | |
| 1061 | + res = max(fabs(s0-e0)); | |
| 1062 | + if (res < 1.0e-15) | |
| 1063 | + #if defined(DUMP_RESIDUALS) | |
| 1064 | + cout << "Res(S1Z)=" << res << " "; | |
| 1065 | + #else | |
| 1066 | + cout << "."; | |
| 1067 | + #endif | |
| 1068 | + else { | |
| 1069 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1070 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1071 | + cout << s0 << endl; | |
| 1072 | + throw; | |
| 1073 | + } | |
| 1074 | + // | |
| 1075 | + e0(1) = 0.0; | |
| 1076 | + e0(2) = 1.0; | |
| 1077 | + a0(1) = 0.0; | |
| 1078 | + a0(2) = 1.0; | |
| 1079 | + s0 = cd_zero.cholesky_solver(a0); | |
| 1080 | + res = max(fabs(s0-e0)); | |
| 1081 | + if (res < 1.0e-15) | |
| 1082 | + #if defined(DUMP_RESIDUALS) | |
| 1083 | + cout << "Res(S2Z)=" << res << " "; | |
| 1084 | + #else | |
| 1085 | + cout << "."; | |
| 1086 | + #endif | |
| 1087 | + else { | |
| 1088 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1089 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1090 | + cout << s0 << endl; | |
| 1091 | + throw; | |
| 1092 | + } | |
| 1093 | + // | |
| 1094 | + e0(2) = 0.0; | |
| 1095 | + e0(4) = 1.0; | |
| 1096 | + a0(2) = 0.0; | |
| 1097 | + a0(4) = 1.0; | |
| 1098 | + s0 = cd_zero.cholesky_solver(a0); | |
| 1099 | + res = max(fabs(s0-e0)); | |
| 1100 | + if (res < 1.0e-15) | |
| 1101 | + #if defined(DUMP_RESIDUALS) | |
| 1102 | + cout << "Res(S3Z)=" << res << " "; | |
| 1103 | + #else | |
| 1104 | + cout << "."; | |
| 1105 | + #endif | |
| 1106 | + else { | |
| 1107 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1108 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1109 | + cout << s0 << endl; | |
| 1110 | + throw; | |
| 1111 | + } | |
| 1112 | + // | |
| 1113 | + e0(4) = 0.0; | |
| 1114 | + e0(5) = 1.0; | |
| 1115 | + a0(4) = 0.0; | |
| 1116 | + a0(5) = 1.0; | |
| 1117 | + s0 = cd_zero.cholesky_solver(a0); | |
| 1118 | + res = max(fabs(s0-e0)); | |
| 1119 | + if (res < 1.0e-15) | |
| 1120 | + #if defined(DUMP_RESIDUALS) | |
| 1121 | + cout << "Res(S4Z)=" << res << " "; | |
| 1122 | + #else | |
| 1123 | + cout << "."; | |
| 1124 | + #endif | |
| 1125 | + else { | |
| 1126 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1127 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1128 | + cout << s0 << endl; | |
| 1129 | + throw; | |
| 1130 | + } | |
| 1131 | + // | |
| 1132 | + // Setup matrix for Cholesky decomposition with zero row/col (unsymmetric case) | |
| 1133 | + GSparseMatrix m_chol_test_zero2(6,5); | |
| 1134 | + m_chol_test_zero2(0,0) = 1.0; | |
| 1135 | + m_chol_test_zero2(0,1) = 0.2; | |
| 1136 | + m_chol_test_zero2(0,2) = 0.2; | |
| 1137 | + m_chol_test_zero2(0,3) = 0.2; | |
| 1138 | + m_chol_test_zero2(0,4) = 0.2; | |
| 1139 | + m_chol_test_zero2(1,0) = 0.2; | |
| 1140 | + m_chol_test_zero2(2,0) = 0.2; | |
| 1141 | + m_chol_test_zero2(4,0) = 0.2; | |
| 1142 | + m_chol_test_zero2(5,0) = 0.2; | |
| 1143 | + m_chol_test_zero2(1,1) = 1.0; | |
| 1144 | + m_chol_test_zero2(2,2) = 1.0; | |
| 1145 | + m_chol_test_zero2(4,3) = 1.0; | |
| 1146 | + m_chol_test_zero2(5,4) = 1.0; | |
| 1147 | + // | |
| 1148 | + // Test compressed Cholesky decomposition (unsymmetric case) | |
| 1149 | + GSparseMatrix cd_zero2 = m_chol_test_zero2; | |
| 1150 | + cd_zero2.cholesky_decompose(); | |
| 1151 | + // | |
| 1152 | + // Test compressed Cholesky solver (unsymmetric case) | |
| 1153 | + e0 = GVector(5); | |
| 1154 | + a0 = GVector(6); | |
| 1155 | + e0(0) = 1.0; | |
| 1156 | + a0(0) = 1.0; | |
| 1157 | + a0(1) = 0.2; | |
| 1158 | + a0(2) = 0.2; | |
| 1159 | + a0(4) = 0.2; | |
| 1160 | + a0(5) = 0.2; | |
| 1161 | + s0 = cd_zero2.cholesky_solver(a0); | |
| 1162 | + res = max(fabs(s0-e0)); | |
| 1163 | + if (res < 1.0e-15) | |
| 1164 | + #if defined(DUMP_RESIDUALS) | |
| 1165 | + cout << "Res(S0ZU)=" << res << " "; | |
| 1166 | + #else | |
| 1167 | + cout << "."; | |
| 1168 | + #endif | |
| 1169 | + else { | |
| 1170 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1171 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1172 | + cout << s0 << endl; | |
| 1173 | + throw; | |
| 1174 | + } | |
| 1175 | + // | |
| 1176 | + e0(0) = 0.0; | |
| 1177 | + e0(1) = 1.0; | |
| 1178 | + a0(0) = 0.2; | |
| 1179 | + a0(1) = 1.0; | |
| 1180 | + a0(2) = 0.0; | |
| 1181 | + a0(4) = 0.0; | |
| 1182 | + a0(5) = 0.0; | |
| 1183 | + s0 = cd_zero2.cholesky_solver(a0); | |
| 1184 | + res = max(fabs(s0-e0)); | |
| 1185 | + if (res < 1.0e-15) | |
| 1186 | + #if defined(DUMP_RESIDUALS) | |
| 1187 | + cout << "Res(S1ZU)=" << res << " "; | |
| 1188 | + #else | |
| 1189 | + cout << "."; | |
| 1190 | + #endif | |
| 1191 | + else { | |
| 1192 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1193 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1194 | + cout << s0 << endl; | |
| 1195 | + throw; | |
| 1196 | + } | |
| 1197 | + // | |
| 1198 | + e0(1) = 0.0; | |
| 1199 | + e0(2) = 1.0; | |
| 1200 | + a0(1) = 0.0; | |
| 1201 | + a0(2) = 1.0; | |
| 1202 | + s0 = cd_zero2.cholesky_solver(a0); | |
| 1203 | + res = max(fabs(s0-e0)); | |
| 1204 | + if (res < 1.0e-15) | |
| 1205 | + #if defined(DUMP_RESIDUALS) | |
| 1206 | + cout << "Res(S2ZU)=" << res << " "; | |
| 1207 | + #else | |
| 1208 | + cout << "."; | |
| 1209 | + #endif | |
| 1210 | + else { | |
| 1211 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1212 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1213 | + cout << s0 << endl; | |
| 1214 | + throw; | |
| 1215 | + } | |
| 1216 | + // | |
| 1217 | + e0(2) = 0.0; | |
| 1218 | + e0(3) = 1.0; | |
| 1219 | + a0(2) = 0.0; | |
| 1220 | + a0(4) = 1.0; | |
| 1221 | + s0 = cd_zero2.cholesky_solver(a0); | |
| 1222 | + res = max(fabs(s0-e0)); | |
| 1223 | + if (res < 1.0e-15) | |
| 1224 | + #if defined(DUMP_RESIDUALS) | |
| 1225 | + cout << "Res(S3ZU)=" << res << " "; | |
| 1226 | + #else | |
| 1227 | + cout << "."; | |
| 1228 | + #endif | |
| 1229 | + else { | |
| 1230 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1231 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1232 | + cout << s0 << endl; | |
| 1233 | + throw; | |
| 1234 | + } | |
| 1235 | + // | |
| 1236 | + e0(3) = 0.0; | |
| 1237 | + e0(4) = 1.0; | |
| 1238 | + a0(4) = 0.0; | |
| 1239 | + a0(5) = 1.0; | |
| 1240 | + s0 = cd_zero2.cholesky_solver(a0); | |
| 1241 | + res = max(fabs(s0-e0)); | |
| 1242 | + if (res < 1.0e-15) | |
| 1243 | + #if defined(DUMP_RESIDUALS) | |
| 1244 | + cout << "Res(S4ZU)=" << res << " "; | |
| 1245 | + #else | |
| 1246 | + cout << "."; | |
| 1247 | + #endif | |
| 1248 | + else { | |
| 1249 | + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; | |
| 1250 | + cout << "Residual vector (all elements should be zero):" << endl; | |
| 1251 | + cout << s0 << endl; | |
| 1252 | + throw; | |
| 1253 | + } | |
| 1254 | + // | |
| 1255 | + // Test Cholesky inverter (inplace) | |
| 1256 | + GSparseMatrix unit(5,5); | |
| 1257 | + unit(0,0) = 1.0; | |
| 1258 | + unit(1,1) = 1.0; | |
| 1259 | + unit(2,2) = 1.0; | |
| 1260 | + unit(3,3) = 1.0; | |
| 1261 | + unit(4,4) = 1.0; | |
| 1262 | + GSparseMatrix m_chol_test_inv = m_chol_test; | |
| 1263 | + m_chol_test_inv.cholesky_invert(); | |
| 1264 | + GSparseMatrix ci_product = m_chol_test * m_chol_test_inv; | |
| 1265 | + GSparseMatrix ci_residuals = ci_product - unit; | |
| 1266 | + res = (fabs(ci_residuals)).max(); | |
| 1267 | + if (res < 1.0e-15) | |
| 1268 | + #if defined(DUMP_RESIDUALS) | |
| 1269 | + cout << "Res(CI)=" << res << " "; | |
| 1270 | + #else | |
| 1271 | + cout << "."; | |
| 1272 | + #endif | |
| 1273 | + else { | |
| 1274 | + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.cholesky_invert() function." << endl; | |
| 1275 | + cout << "Residual matrix (all elements should be zero):" << endl; | |
| 1276 | + cout << ci_residuals << endl; | |
| 1277 | + throw; | |
| 1278 | + } | |
| 1279 | + // | |
| 1280 | + // Test Cholesky inverter | |
| 1281 | + m_chol_test_inv = cholesky_invert(m_chol_test); | |
| 1282 | + ci_product = m_chol_test * m_chol_test_inv; | |
| 1283 | + ci_residuals = ci_product - unit; | |
| 1284 | + res = (fabs(ci_residuals)).max(); | |
| 1285 | + if (res < 1.0e-15) | |
| 1286 | + #if defined(DUMP_RESIDUALS) | |
| 1287 | + cout << "Res(CI2)=" << res << " "; | |
| 1288 | + #else | |
| 1289 | + cout << "."; | |
| 1290 | + #endif | |
| 1291 | + else { | |
| 1292 | + cout << endl << "TEST ERROR: Corrupt cholesky_invert(GSparseMatrix) function." << endl; | |
| 1293 | + cout << "Residual matrix (all elements should be zero):" << endl; | |
| 1294 | + cout << ci_residuals << endl; | |
| 1295 | + throw; | |
| 1296 | + } | |
| 1297 | + // | |
| 1298 | + // Test Cholesky inverter for compressed matrix | |
| 1299 | + unit = GSparseMatrix(6,6); | |
| 1300 | + unit(0,0) = 1.0; | |
| 1301 | + unit(1,1) = 1.0; | |
| 1302 | + unit(2,2) = 1.0; | |
| 1303 | + unit(4,4) = 1.0; | |
| 1304 | + unit(5,5) = 1.0; | |
| 1305 | + GSparseMatrix m_chol_test_zero_inv = m_chol_test_zero; | |
| 1306 | + m_chol_test_zero_inv.cholesky_invert(); | |
| 1307 | + GSparseMatrix ciz_product = m_chol_test_zero * m_chol_test_zero_inv; | |
| 1308 | + GSparseMatrix ciz_residuals = ciz_product - unit; | |
| 1309 | + res = (fabs(ciz_residuals)).max(); | |
| 1310 | + if (res < 1.0e-15) | |
| 1311 | + #if defined(DUMP_RESIDUALS) | |
| 1312 | + cout << "Res(CIZ)=" << res << " "; | |
| 1313 | + #else | |
| 1314 | + cout << "."; | |
| 1315 | + #endif | |
| 1316 | + else { | |
| 1317 | + cout << endl << "TEST ERROR: Corrupt compressed GSparseMatrix.cholesky_invert() function." << endl; | |
| 1318 | + cout << "Residual matrix (all elements should be zero):" << endl; | |
| 1319 | + cout << ciz_residuals << endl; | |
| 1320 | + throw; | |
| 1321 | + } | |
| 1322 | + } | |
| 1323 | + catch (exception &e) { | |
| 1324 | + cout << e.what() << endl; | |
| 1325 | + throw; | |
| 1326 | + } | |
| 1327 | + cout << "ok." << endl; | |
| 1328 | +} | |
| 1329 | + | |
| 1330 | + | |
| 1331 | +/*************************************************************************** | |
| 1332 | + * Test: Heavy calculus * | |
| 1333 | + ***************************************************************************/ | |
| 1334 | +void test_heavy() | |
| 1335 | +{ | |
| 1336 | + // Allocate some variables | |
| 1337 | + clock_t t_start; | |
| 1338 | + double t_elapse; | |
| 1339 | + int number; | |
| 1340 | + | |
| 1341 | + // Perform test | |
| 1342 | + cout << "Test GSparseMatrix: Heavy calculus: "; | |
| 1343 | + try { | |
| 1344 | + // | |
| 1345 | + // Fill 10000 x 10000 matrix with 10000 values | |
| 1346 | + number = 10000; | |
| 1347 | + t_start = clock(); | |
| 1348 | + GSparseMatrix large(number,number); | |
| 1349 | + for (int i = 0; i < number; ++i) | |
| 1350 | + large(i,i) = (i+1)*3.14; | |
| 1351 | + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); | |
| 1352 | + #if defined(DUMP_TIMING) | |
| 1353 | + cout << endl << " - Fill of 10000 values needed " << t_elapse << | |
| 1354 | + " sec (reference ~ 1.9 sec)"; | |
| 1355 | + #endif | |
| 1356 | + // | |
| 1357 | + // Modify 10000 x 10000 matrix with 10000 (exisiting) values | |
| 1358 | + t_start = clock(); | |
| 1359 | + for (int i = 0; i < number; ++i) | |
| 1360 | + large(i,i) = (i+1)*1.0; | |
| 1361 | + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); | |
| 1362 | + #if defined(DUMP_TIMING) | |
| 1363 | + cout << endl << " - Modification of 10000 values needed " << t_elapse << | |
| 1364 | + " sec (reference ~ 0 sec)"; | |
| 1365 | + #endif | |
| 1366 | + // | |
| 1367 | + // Subsequent addition and subtractions | |
| 1368 | + number = 300; | |
| 1369 | + t_start = clock(); | |
| 1370 | + GSparseMatrix sum(number,number); | |
| 1371 | + GSparseMatrix add(number,number); | |
| 1372 | + GSparseMatrix sub(number,number); | |
| 1373 | + for (int i = 0; i < number; ++i) { | |
| 1374 | + add(i,number-i-1) = (i*i+1)*0.01; | |
| 1375 | + sum += add; | |
| 1376 | + sub(i,i) = (i+1)*1.0; | |
| 1377 | + sum -= sub; | |
| 1378 | + } | |
| 1379 | + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); | |
| 1380 | + #if defined(DUMP_TIMING) | |
| 1381 | + cout << endl << " - Matrix adding and subtraction 300 times " << t_elapse << | |
| 1382 | + " sec (reference ~ 1.5 sec)"; | |
| 1383 | + #endif | |
| 1384 | + // | |
| 1385 | + // Subsequent multiplications | |
| 1386 | + t_start = clock(); | |
| 1387 | + GSparseMatrix fac(number,number); | |
| 1388 | + for (int i = 0; i < 1; ++i) { | |
| 1389 | + for (int j = 0; j < number; ++j) | |
| 1390 | + fac(j,j) = (i+1)*1.0; | |
| 1391 | + sum *= fac; | |
| 1392 | + } | |
| 1393 | + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); | |
| 1394 | + #if defined(DUMP_TIMING) | |
| 1395 | + cout << endl << " - Matrix multiplication 1 times " << t_elapse << | |
| 1396 | + " sec (reference ~ 3.5 sec)"; | |
| 1397 | + #endif | |
| 1398 | + } | |
| 1399 | + catch (exception &e) { | |
| 1400 | + cout << e.what() << endl; | |
| 1401 | + throw; | |
| 1402 | + } | |
| 1403 | + #if defined(DUMP_TIMING) | |
| 1404 | + cout << endl; | |
| 1405 | + #endif | |
| 1406 | + cout << "ok." << endl; | |
| 1407 | +} | |
| 1408 | + | |
| 1409 | + | |
| 1410 | +/*************************************************************************** | |
| 1411 | + * Main test function * | |
| 1412 | + ***************************************************************************/ | |
| 1413 | +int main(void) | |
| 1414 | +{ | |
| 1415 | + // Dump header | |
| 1416 | + cout << endl; | |
| 1417 | + cout << "*******************************" << endl; | |
| 1418 | + cout << "* GSparseMatrix class testing *" << endl; | |
| 1419 | + cout << "*******************************" << endl; | |
| 1420 | + | |
| 1421 | + // Set test matrix and vector | |
| 1422 | + GSparseMatrix m_test = set_matrix(); | |
| 1423 | + GVector v_test = set_vector(); | |
| 1424 | + | |
| 1425 | + // Execute the tests | |
| 1426 | + test_output(m_test); | |
| 1427 | + test_allocate(); | |
| 1428 | + test_assign_values(m_test); | |
| 1429 | + test_copy_constructor(m_test); | |
| 1430 | + test_assign_matrix(m_test); | |
| 1431 | + test_transpose(m_test); | |
| 1432 | + test_matrix_vector(m_test, v_test); | |
| 1433 | + test_matrix_matrix(m_test); | |
| 1434 | + test_arithmetics(m_test); | |
| 1435 | + test_functions(m_test); | |
| 1436 | + test_comparison(m_test); | |
| 1437 | + test_conversion(m_test); | |
| 1438 | + test_cholesky(); | |
| 1439 | + test_heavy(); | |
| 1440 | + | |
| 1441 | + // Return | |
| 1442 | + return 0; | |
| 1443 | +} | ... | ... |
test/test_GSparseMatrix.hpp
0 โ 100644
| 1 | +/*************************************************************************** | |
| 2 | + * test_GSparseMatrix.hpp - test GSparseMatrix class * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright : (C) 2006 by Jurgen Knodlseder * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software; you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation; either version 2 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + ***************************************************************************/ | |
| 13 | + | |
| 14 | +#ifndef TEST_GSPARSEMATRIX_HPP | |
| 15 | +#define TEST_GSPARSEMATRIX_HPP | |
| 16 | + | |
| 17 | +/* __ Includes ___________________________________________________________ */ | |
| 18 | +#include "../src/GSparseMatrix.hpp" | |
| 19 | +#include <iostream> // cout, cerr | |
| 20 | +#include <stdexcept> // std::exception | |
| 21 | +#include <math.h> | |
| 22 | + | |
| 23 | +#endif /* TEST_GSPARSEMATRIX_HPP */ | ... | ... |
test/test_GSymMatrix.cpp
| ... | ... | @@ -99,7 +99,7 @@ int check_matrix(const GSymMatrix& m, const double scale, const double add) |
| 99 | 99 | for (unsigned row = 0; row < g_rows; ++row) { |
| 100 | 100 | for (unsigned col = 0; col < g_cols; ++col) { |
| 101 | 101 | double value = g_matrix[col+row*g_cols] * scale + add; |
| 102 | - if (m(row,col) != value) { | |
| 102 | + if (fabs(m(row,col)-value) > 1.0e-15) { | |
| 103 | 103 | result = 0; |
| 104 | 104 | break; |
| 105 | 105 | } |
| ... | ... | @@ -219,15 +219,15 @@ int check_matrix_vector(const GVector& v) |
| 219 | 219 | ***************************************************************************/ |
| 220 | 220 | int check_matrix_matrix(const GSymMatrix& m) |
| 221 | 221 | { |
| 222 | - if (m.rows() != g_rows || m.cols() != g_cols) | |
| 222 | + if (m.rows() != g_rows || m.cols() != g_rows) | |
| 223 | 223 | return 0; |
| 224 | 224 | int result = 1; |
| 225 | 225 | try { |
| 226 | - for (unsigned row = 0; row < g_rows; ++row) { | |
| 227 | - for (unsigned col = 0; col < g_cols; ++col) { | |
| 226 | + for (unsigned row = 0; row < m.rows(); ++row) { | |
| 227 | + for (unsigned col = 0; col < m.cols(); ++col) { | |
| 228 | 228 | double value = 0.0; |
| 229 | 229 | for (unsigned i = 0; i < g_cols; ++i) |
| 230 | - value += g_matrix[i+row*g_cols] * g_matrix[row+i*g_cols]; | |
| 230 | + value += g_matrix[i+row*g_cols] * g_matrix[i+col*g_cols]; | |
| 231 | 231 | if (m(row,col) != value) { |
| 232 | 232 | result = 0; |
| 233 | 233 | break; |
| ... | ... | @@ -375,7 +375,7 @@ int main(void) |
| 375 | 375 | cout << "GSymMatrix - Test 4: Define matrix using copy constructor: "; |
| 376 | 376 | // |
| 377 | 377 | GSymMatrix test4 = m_test; |
| 378 | - if (!check_matrix(test4, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 378 | + if (!check_matrix(test4, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 379 | 379 | cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; |
| 380 | 380 | cout << test4 << endl; |
| 381 | 381 | throw; |
| ... | ... | @@ -393,8 +393,8 @@ int main(void) |
| 393 | 393 | // |
| 394 | 394 | // GSymMatrix = GSymMatrix |
| 395 | 395 | result = m_test; |
| 396 | - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 397 | - cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; | |
| 396 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 397 | + cout << endl << "TEST ERROR: Corrupt assignment." << endl; | |
| 398 | 398 | cout << result << endl; |
| 399 | 399 | throw; |
| 400 | 400 | } |
| ... | ... | @@ -413,7 +413,7 @@ int main(void) |
| 413 | 413 | cout << "GSymMatrix - Test 6: Matrix*Vector multiplication: "; |
| 414 | 414 | // |
| 415 | 415 | GVector v_test6 = m_test*v_test; |
| 416 | - if (!check_matrix_vector(v_test6) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 416 | + if (!check_matrix_vector(v_test6) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 417 | 417 | cout << endl << "TEST ERROR: Corrupt Matrix*Vector multiplication." << endl; |
| 418 | 418 | cout << v_test6 << endl; |
| 419 | 419 | throw; |
| ... | ... | @@ -426,7 +426,7 @@ int main(void) |
| 426 | 426 | try { |
| 427 | 427 | GVector v_test6 = bigger*v_test; |
| 428 | 428 | } |
| 429 | - catch (GMatrix::vec_mat_mismatch &e) { | |
| 429 | + catch (GMatrix::matrix_vector_mismatch &e) { | |
| 430 | 430 | } |
| 431 | 431 | catch (exception &e) { |
| 432 | 432 | cout << e.what() << endl; |
| ... | ... | @@ -439,7 +439,7 @@ int main(void) |
| 439 | 439 | cout << "GSymMatrix - Test 7: Matrix*Matrix multiplication: "; |
| 440 | 440 | // |
| 441 | 441 | GSymMatrix m_test7 = m_test*m_test; |
| 442 | - if (!check_matrix_matrix(m_test7) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 442 | + if (!check_matrix_matrix(m_test7) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 443 | 443 | cout << endl << "TEST ERROR: Corrupt Matrix*Matrix multiplication." << endl; |
| 444 | 444 | cout << m_test7 << endl; |
| 445 | 445 | throw; |
| ... | ... | @@ -452,7 +452,7 @@ int main(void) |
| 452 | 452 | try { |
| 453 | 453 | GSymMatrix m_test7 = m_test*bigger; |
| 454 | 454 | } |
| 455 | - catch (GMatrix::dim_mult_mismatch &e) { | |
| 455 | + catch (GMatrix::matrix_mismatch &e) { | |
| 456 | 456 | } |
| 457 | 457 | catch (exception &e) { |
| 458 | 458 | cout << e.what() << endl; |
| ... | ... | @@ -461,7 +461,7 @@ int main(void) |
| 461 | 461 | try { |
| 462 | 462 | GSymMatrix m_test7 = bigger*m_test; |
| 463 | 463 | } |
| 464 | - catch (GMatrix::dim_mult_mismatch &e) { | |
| 464 | + catch (GMatrix::matrix_mismatch &e) { | |
| 465 | 465 | } |
| 466 | 466 | catch (exception &e) { |
| 467 | 467 | cout << e.what() << endl; |
| ... | ... | @@ -475,61 +475,34 @@ int main(void) |
| 475 | 475 | // |
| 476 | 476 | // -GSymMatrix |
| 477 | 477 | result = -m_test; |
| 478 | - if (!check_matrix(result, -1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 478 | + if (!check_matrix(result, -1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 479 | 479 | cout << endl << "TEST ERROR: Corrupt -GSymMatrix operator." << endl; |
| 480 | 480 | cout << result << endl; |
| 481 | 481 | throw; |
| 482 | 482 | } |
| 483 | 483 | // |
| 484 | - // GSymMatrix = 3.0 | |
| 485 | - result = m_test; | |
| 486 | - result = 3.0; | |
| 487 | - if (!check_matrix(result, 0.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 488 | - cout << endl << "TEST ERROR: Corrupt GSymMatrix = double operator." << endl; | |
| 489 | - cout << result << endl; | |
| 490 | - throw; | |
| 491 | - } | |
| 492 | - // | |
| 493 | 484 | // GSymMatrix += GSymMatrix |
| 494 | 485 | result = m_test; |
| 495 | 486 | result += m_test; |
| 496 | - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 487 | + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 497 | 488 | cout << endl << "TEST ERROR: Corrupt GSymMatrix += GSymMatrix operator." << endl; |
| 498 | 489 | cout << result << endl; |
| 499 | 490 | throw; |
| 500 | 491 | } |
| 501 | 492 | // |
| 502 | - // GSymMatrix += 3.0 | |
| 503 | - result = m_test; | |
| 504 | - result += 3.0; | |
| 505 | - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 506 | - cout << endl << "TEST ERROR: Corrupt GSymMatrix += double operator." << endl; | |
| 507 | - cout << result << endl; | |
| 508 | - throw; | |
| 509 | - } | |
| 510 | - // | |
| 511 | 493 | // GSymMatrix -= GSymMatrix |
| 512 | 494 | result = m_test; |
| 513 | 495 | result -= m_test; |
| 514 | - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 496 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 515 | 497 | cout << endl << "TEST ERROR: Corrupt GSymMatrix -= GSymMatrix operator." << endl; |
| 516 | 498 | cout << result << endl; |
| 517 | 499 | throw; |
| 518 | 500 | } |
| 519 | 501 | // |
| 520 | - // GSymMatrix -= 3.0 | |
| 521 | - result = m_test; | |
| 522 | - result -= 3.0; | |
| 523 | - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 524 | - cout << endl << "TEST ERROR: Corrupt GSymMatrix -= double operator." << endl; | |
| 525 | - cout << result << endl; | |
| 526 | - throw; | |
| 527 | - } | |
| 528 | - // | |
| 529 | 502 | // GSymMatrix *= 3.0 |
| 530 | 503 | result = m_test; |
| 531 | 504 | result *= 3.0; |
| 532 | - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 505 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 533 | 506 | cout << endl << "TEST ERROR: Corrupt GSymMatrix *= double operator." << endl; |
| 534 | 507 | cout << result << endl; |
| 535 | 508 | throw; |
| ... | ... | @@ -538,7 +511,7 @@ int main(void) |
| 538 | 511 | // GSymMatrix /= 3.0 |
| 539 | 512 | result = m_test; |
| 540 | 513 | result /= 3.0; |
| 541 | - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 514 | + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 542 | 515 | cout << endl << "TEST ERROR: Corrupt GSymMatrix /= double operator." << endl; |
| 543 | 516 | cout << result << endl; |
| 544 | 517 | throw; |
| ... | ... | @@ -546,7 +519,7 @@ int main(void) |
| 546 | 519 | // |
| 547 | 520 | // GSymMatrix + GSymMatrix |
| 548 | 521 | result = m_test + m_test; |
| 549 | - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 522 | + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 550 | 523 | cout << endl << "TEST ERROR: Corrupt GSymMatrix + GSymMatrix operator." << endl; |
| 551 | 524 | cout << result << endl; |
| 552 | 525 | throw; |
| ... | ... | @@ -554,7 +527,7 @@ int main(void) |
| 554 | 527 | // |
| 555 | 528 | // GSymMatrix - GSymMatrix |
| 556 | 529 | result = m_test - m_test; |
| 557 | - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 530 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 558 | 531 | cout << endl << "TEST ERROR: Corrupt GSymMatrix - GSymMatrix operator." << endl; |
| 559 | 532 | cout << result << endl; |
| 560 | 533 | throw; |
| ... | ... | @@ -562,47 +535,15 @@ int main(void) |
| 562 | 535 | // |
| 563 | 536 | // GSymMatrix - GSymMatrix |
| 564 | 537 | result = m_test - m_test; |
| 565 | - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 538 | + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 566 | 539 | cout << endl << "TEST ERROR: Corrupt GSymMatrix - GSymMatrix operator." << endl; |
| 567 | 540 | cout << result << endl; |
| 568 | 541 | throw; |
| 569 | 542 | } |
| 570 | 543 | // |
| 571 | - // GSymMatrix + 3.0 | |
| 572 | - result = m_test + 3.0; | |
| 573 | - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 574 | - cout << endl << "TEST ERROR: Corrupt GSymMatrix + double operator." << endl; | |
| 575 | - cout << result << endl; | |
| 576 | - throw; | |
| 577 | - } | |
| 578 | - // | |
| 579 | - // 3.0 + GSymMatrix | |
| 580 | - result = 3.0 + m_test; | |
| 581 | - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 582 | - cout << endl << "TEST ERROR: Corrupt double + GSymMatrix operator." << endl; | |
| 583 | - cout << result << endl; | |
| 584 | - throw; | |
| 585 | - } | |
| 586 | - // | |
| 587 | - // GSymMatrix - 3.0 | |
| 588 | - result = m_test - 3.0; | |
| 589 | - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 590 | - cout << endl << "TEST ERROR: Corrupt GSymMatrix - double operator." << endl; | |
| 591 | - cout << result << endl; | |
| 592 | - throw; | |
| 593 | - } | |
| 594 | - // | |
| 595 | - // 3.0 - GSymMatrix | |
| 596 | - result = 3.0 - m_test; | |
| 597 | - if (!check_matrix(result, -1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 598 | - cout << endl << "TEST ERROR: Corrupt double - GSymMatrix operator." << endl; | |
| 599 | - cout << result << endl; | |
| 600 | - throw; | |
| 601 | - } | |
| 602 | - // | |
| 603 | 544 | // GSymMatrix * 3.0 |
| 604 | 545 | result = m_test * 3.0; |
| 605 | - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 546 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 606 | 547 | cout << endl << "TEST ERROR: Corrupt GSymMatrix * double operator." << endl; |
| 607 | 548 | cout << result << endl; |
| 608 | 549 | throw; |
| ... | ... | @@ -610,7 +551,7 @@ int main(void) |
| 610 | 551 | // |
| 611 | 552 | // 3.0 * GSymMatrix |
| 612 | 553 | result = 3.0 * m_test; |
| 613 | - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 554 | + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 614 | 555 | cout << endl << "TEST ERROR: Corrupt double * GSymMatrix operator." << endl; |
| 615 | 556 | cout << result << endl; |
| 616 | 557 | throw; |
| ... | ... | @@ -618,7 +559,7 @@ int main(void) |
| 618 | 559 | // |
| 619 | 560 | // GSymMatrix / 3.0 |
| 620 | 561 | result = m_test / 3.0; |
| 621 | - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 562 | + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 622 | 563 | cout << endl << "TEST ERROR: Corrupt GSymMatrix / double operator." << endl; |
| 623 | 564 | cout << result << endl; |
| 624 | 565 | throw; |
| ... | ... | @@ -632,7 +573,7 @@ int main(void) |
| 632 | 573 | result = m_test; |
| 633 | 574 | result += bigger; |
| 634 | 575 | } |
| 635 | - catch (GMatrix::dim_add_mismatch) { | |
| 576 | + catch (GMatrix::matrix_mismatch) { | |
| 636 | 577 | } |
| 637 | 578 | catch (exception &e) { |
| 638 | 579 | cout << e.what() << endl; |
| ... | ... | @@ -717,7 +658,7 @@ int main(void) |
| 717 | 658 | // |
| 718 | 659 | // transpose(GSymMatrix) |
| 719 | 660 | result = transpose(m_test); |
| 720 | - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 661 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 721 | 662 | cout << endl << "TEST ERROR: Corrupt transpose(GSymMatrix) function." << endl; |
| 722 | 663 | cout << result << endl; |
| 723 | 664 | throw; |
| ... | ... | @@ -726,32 +667,32 @@ int main(void) |
| 726 | 667 | // GSymMatrix.transpose() |
| 727 | 668 | result = m_test; |
| 728 | 669 | result.transpose(); |
| 729 | - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 670 | + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 730 | 671 | cout << endl << "TEST ERROR: Corrupt GSymMatrix.transpose() function." << endl; |
| 731 | 672 | cout << result << endl; |
| 732 | 673 | throw; |
| 733 | 674 | } |
| 734 | 675 | // |
| 735 | - // full(GSymMatrix) | |
| 736 | - GMatrix m_test11 = full(m_test); | |
| 737 | - if (!check_matrix(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 738 | - cout << endl << "TEST ERROR: Corrupt full(GSymMatrix) operator." << endl; | |
| 676 | + // convert_to_full() | |
| 677 | + GMatrix m_test11 = m_test.convert_to_full(); | |
| 678 | + if (!check_matrix(m_test11, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 679 | + cout << endl << "TEST ERROR: Corrupt convert_to_full() operator." << endl; | |
| 739 | 680 | cout << m_test11 << endl; |
| 740 | 681 | throw; |
| 741 | 682 | } |
| 742 | 683 | // |
| 743 | - // lower_triangle(GSymMatrix) | |
| 744 | - m_test11 = lower_triangle(m_test); | |
| 745 | - if (!check_matrix_lt(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 746 | - cout << endl << "TEST ERROR: Corrupt lower_triangle(GSymMatrix) function." << endl; | |
| 684 | + // extract_lower_triangle() | |
| 685 | + m_test11 = m_test.extract_lower_triangle(); | |
| 686 | + if (!check_matrix_lt(m_test11, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 687 | + cout << endl << "TEST ERROR: Corrupt extract_lower_triangle() function." << endl; | |
| 747 | 688 | cout << m_test11 << endl; |
| 748 | 689 | throw; |
| 749 | 690 | } |
| 750 | 691 | // |
| 751 | - // upper_triangle(GSymMatrix) | |
| 752 | - m_test11 = upper_triangle(m_test); | |
| 753 | - if (!check_matrix_ut(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { | |
| 754 | - cout << endl << "TEST ERROR: Corrupt upper_triangle(GSymMatrix) function." << endl; | |
| 692 | + // extract_upper_triangle() | |
| 693 | + m_test11 = m_test.extract_upper_triangle(); | |
| 694 | + if (!check_matrix_ut(m_test11, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { | |
| 695 | + cout << endl << "TEST ERROR: Corrupt extract_upper_triangle() function." << endl; | |
| 755 | 696 | cout << m_test11 << endl; |
| 756 | 697 | throw; |
| 757 | 698 | } |
| ... | ... | @@ -768,10 +709,10 @@ int main(void) |
| 768 | 709 | // |
| 769 | 710 | // Test Cholesky decomposition |
| 770 | 711 | GSymMatrix cd = cholesky_decompose(m_test); |
| 771 | - GMatrix cd_lower = lower_triangle(cd); | |
| 712 | + GMatrix cd_lower = cd.extract_lower_triangle(); | |
| 772 | 713 | GMatrix cd_upper = transpose(cd_lower); |
| 773 | 714 | GMatrix cd_product = cd_lower * cd_upper; |
| 774 | - GMatrix cd_residuals = full(m_test) - cd_product; | |
| 715 | + GMatrix cd_residuals = m_test.convert_to_full() - cd_product; | |
| 775 | 716 | // |
| 776 | 717 | double res = (fabs(cd_residuals)).max(); |
| 777 | 718 | if (res < 1.0e-15) |
| ... | ... | @@ -786,10 +727,10 @@ int main(void) |
| 786 | 727 | // Test compressed Cholesky decomposition |
| 787 | 728 | GSymMatrix m_test_zero = set_matrix_zero(); |
| 788 | 729 | GSymMatrix cd_zero = cholesky_decompose(m_test_zero); |
| 789 | - GMatrix cd_zero_lower = lower_triangle(cd_zero); | |
| 730 | + GMatrix cd_zero_lower = cd_zero.extract_lower_triangle(); | |
| 790 | 731 | GMatrix cd_zero_upper = transpose(cd_zero_lower); |
| 791 | 732 | GMatrix cd_zero_product = cd_zero_lower * cd_zero_upper; |
| 792 | - GMatrix cd_zero_residuals = full(m_test_zero) - cd_zero_product; | |
| 733 | + GMatrix cd_zero_residuals = m_test_zero.convert_to_full() - cd_zero_product; | |
| 793 | 734 | // |
| 794 | 735 | res = (fabs(cd_zero_residuals)).max(); |
| 795 | 736 | if (res < 1.0e-15) |
| ... | ... | @@ -804,7 +745,7 @@ int main(void) |
| 804 | 745 | // Test Cholesky inplace decomposition |
| 805 | 746 | GSymMatrix m_test12 = m_test; |
| 806 | 747 | m_test12.cholesky_decompose(); |
| 807 | - GMatrix cd_lower2 = lower_triangle(m_test12); | |
| 748 | + GMatrix cd_lower2 = m_test12.extract_lower_triangle(); | |
| 808 | 749 | if (cd_lower2 != cd_lower) { |
| 809 | 750 | cout << endl << "TEST ERROR: Corrupt GSymMatrix.cholesky_decompose() function." << endl; |
| 810 | 751 | cout << cd_lower2 << endl; |
| ... | ... | @@ -967,4 +908,4 @@ int main(void) |
| 967 | 908 | } |
| 968 | 909 | cout << "ok." << endl; |
| 969 | 910 | |
| 970 | -} | |
| 971 | 911 | \ No newline at end of file |
| 912 | +} | ... | ... |