├── .gitignore ├── Makefile ├── README.md ├── src └── SparseMatrix │ ├── SparseMatrix.cpp │ ├── SparseMatrix.h │ └── exceptions.h └── tests ├── cases ├── addition.cpp ├── constructor.cpp ├── crs-format.cpp ├── custom-type.cpp ├── multiplication.cpp ├── output.cpp ├── subtraction.cpp └── values.cpp ├── inc ├── SparseMatrixMock.h ├── helpers.h └── testslib.h └── run.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SparseMatrix Makefile 2 | 3 | all: test 4 | 5 | build: 6 | g++ -Wall -pedantic tests/run.cpp -o tests/SparseMatrix-tests 7 | 8 | test: build 9 | ./tests/SparseMatrix-tests.exe 10 | 11 | debug: 12 | g++ -Wall -pedantic -g tests/run.cpp -o tests/SparseMatrix-tests-gdb 13 | gdb tests/SparseMatrix-tests-gdb.exe 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sparse Matrix 2 | 3 | C++ implementation of sparse matrix using [CRS format](http://netlib.org/linalg/html_templates/node91.html#SECTION00931100000000000000). 4 | 5 | [![Buy me a Coffee](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KWQJ7VTXZMZLS) 6 | 7 | 8 | ## Usage 9 | 10 | ### Creation 11 | 12 | SparseMatrix comes as a template class, so we have to specify the element type. 13 | 14 | ```cpp 15 | SparseMatrix::SparseMatrix matrix(3); // 3×3 matrix of integers 16 | SparseMatrix::SparseMatrix matrix2(4, 5); // 4×5 matrix - 4 rows, 5 columns 17 | 18 | SparseMatrix::SparseMatrix matrix3(matrix); // copy constructor 19 | SparseMatrix::SparseMatrix matrix4 = matrix2; // deep copy assignment 20 | ``` 21 | 22 | All values are now equal to `()`, which for type `int` is `0`. 23 | 24 | ### Values 25 | 26 | To set or get value, use methods `set()` and `get()`: 27 | 28 | ```cpp 29 | int val; 30 | matrix.set(-5, 2, 3); // sets -5 on 2nd row and 3rd column 31 | val = matrix.get(2, 3); // val = -5 32 | val = matrix.get(1, 1); // val = 0 33 | ``` 34 | 35 | When accessing invalid coordinates, `InvalidCoordinatesException` is thrown. Please note that **rows and columns are indexed from 1**. 36 | 37 | ### Operations 38 | 39 | SparseMatrix is implemented as an immutable object - all operations create new matrix instead of changing the matrix the operation is called on. 40 | 41 | #### Matrix-Vector multiplication 42 | 43 | Number of columns in the matrix has to be the same as the size of the vector, otherwise `InvalidDimensionsException` is thrown. 44 | 45 | ```cpp 46 | SparseMatrix::SparseMatrix mat(4, 5); 47 | std::vector vec(5, 2); 48 | 49 | std::vector result; 50 | result = mat.multiply(vec); // method 51 | result = mat * vec; // operator 52 | ``` 53 | 54 | #### Matrix-Matrix multiplication 55 | 56 | Number of columns in the left matrix must be same as number of rows in the right matrix, otherwise `InvalidDimensionsException` is thrown. 57 | 58 | ```cpp 59 | SparseMatrix::SparseMatrix matrixA(2, 3); 60 | SparseMatrix::SparseMatrix matrixB(3, 4); 61 | 62 | SparseMatrix::SparseMatrix product; // will be of size 2×4 63 | product = matrixA.multiply(matrixB); // method 64 | product = matrixA * matrixB; // operator 65 | ``` 66 | 67 | #### Matrix-Matrix addition / subtraction 68 | 69 | You can also add and subtract matrices together. Both matrices has to have same dimentions, otherwise `InvalidDimensionsException` is thrown. 70 | 71 | ```cpp 72 | SparseMatrix::SparseMatrix matrixA(4, 7); 73 | SparseMatrix::SparseMatrix matrixB(4, 7); 74 | 75 | SparseMatrix::SparseMatrix sum; 76 | sum = matrixA.add(matrixB); // method 77 | sum = matrixA + matrixB; // operator 78 | 79 | SparseMatrix::SparseMatrix diff; 80 | diff = matrixA.subtract(matrixB); // method 81 | diff = matrixA - matrixB; // operator 82 | ``` 83 | 84 | #### Matrix-Matrix comparison 85 | 86 | ```cpp 87 | SparseMatrix::SparseMatrix matrixA(3); 88 | SparseMatrix::SparseMatrix matrixB(3); 89 | 90 | bool areSame = matrixA == matrixB; // true 91 | ``` 92 | 93 | #### Dimensions 94 | 95 | To access matrix dimensions use simple getters: 96 | 97 | ```cpp 98 | int rows = matrix.getRowCount(); 99 | int cols = matrix.getColumnCount(); 100 | ``` 101 | 102 | #### Printing matrix 103 | 104 | Basic output streaming is implemented. Note that output operator must be implemented for the element type as well. 105 | 106 | ```cpp 107 | SparseMatrix::SparseMatrix matrix(3, 4); 108 | matrix.set(2, 1, 1); 109 | matrix.set(7, 1, 3); 110 | matrix.set(4, 2, 2); 111 | matrix.set(1, 3, 4); 112 | 113 | std::cout << matrix << std::endl; 114 | 115 | /* 116 | 2 0 7 0 117 | 0 4 0 0 118 | 0 0 0 1 119 | */ 120 | ``` 121 | 122 | ### Custom element type 123 | 124 | If integers/floats are not enough, you can always use your own element type. 125 | 126 | Make sure your type implements: 127 | 128 | * empty constructor (which represents the zero value) 129 | * copying constructor 130 | * comparison `operator ==` so that it is possible to tell whether a value is zero-ish 131 | * adding `operator +` 132 | * subtracting `operator -` 133 | * product `operator *` 134 | * output `operator <<` to be able to nicely output the matrix 135 | 136 | You can see a simple custom element example in [the tests](tests/cases/custom-type.cpp). 137 | 138 | 139 | ----------- 140 | 141 | Any questions / issues / pull requests / [donations](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KWQJ7VTXZMZLS) are very welcome! :-) 142 | -------------------------------------------------------------------------------- /src/SparseMatrix/SparseMatrix.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include 10 | #include 11 | #include "exceptions.h" 12 | #include "SparseMatrix.h" 13 | 14 | 15 | namespace SparseMatrix 16 | { 17 | 18 | // === CREATION ============================================== 19 | 20 | template 21 | SparseMatrix::SparseMatrix(int n) 22 | { 23 | this->construct(n, n); 24 | } 25 | 26 | 27 | template 28 | SparseMatrix::SparseMatrix(int rows, int columns) 29 | { 30 | this->construct(rows, columns); 31 | } 32 | 33 | 34 | template 35 | SparseMatrix::SparseMatrix(const SparseMatrix & matrix) 36 | { 37 | this->deepCopy(matrix); 38 | } 39 | 40 | 41 | template 42 | SparseMatrix & SparseMatrix::operator = (const SparseMatrix & matrix) 43 | { 44 | if (&matrix != this) { 45 | this->destruct(); 46 | this->deepCopy(matrix); 47 | } 48 | 49 | return *this; 50 | } 51 | 52 | 53 | template 54 | void SparseMatrix::deepCopy(const SparseMatrix & matrix) 55 | { 56 | this->m = matrix.m; 57 | this->n = matrix.n; 58 | this->rows = new std::vector(*(matrix.rows)); 59 | 60 | if (matrix.vals != NULL) { 61 | this->cols = new std::vector(*(matrix.cols)); 62 | this->vals = new std::vector(*(matrix.vals)); 63 | } 64 | } 65 | 66 | 67 | template 68 | SparseMatrix::~SparseMatrix(void) 69 | { 70 | this->destruct(); 71 | } 72 | 73 | 74 | template 75 | void SparseMatrix::construct(int rows, int columns) 76 | { 77 | if (rows < 1 || columns < 1) { 78 | throw InvalidDimensionsException("Matrix dimensions cannot be zero or negative."); 79 | } 80 | 81 | this->m = rows; 82 | this->n = columns; 83 | 84 | this->vals = NULL; 85 | this->cols = NULL; 86 | this->rows = new std::vector(rows + 1, 1); 87 | } 88 | 89 | 90 | template 91 | void SparseMatrix::destruct(void) 92 | { 93 | if (this->vals != NULL) { 94 | delete this->vals; 95 | delete this->cols; 96 | } 97 | 98 | delete this->rows; 99 | } 100 | 101 | 102 | // === GETTERS / SETTERS ============================================== 103 | 104 | template 105 | int SparseMatrix::getRowCount(void) const 106 | { 107 | return this->m; 108 | } 109 | 110 | 111 | template 112 | int SparseMatrix::getColumnCount(void) const 113 | { 114 | return this->n; 115 | } 116 | 117 | 118 | // === VALUES ============================================== 119 | 120 | template 121 | T SparseMatrix::get(int row, int col) const 122 | { 123 | this->validateCoordinates(row, col); 124 | 125 | int currCol; 126 | 127 | for (int pos = (*(this->rows))[row - 1] - 1; pos < (*(this->rows))[row] - 1; ++pos) { 128 | currCol = (*(this->cols))[pos]; 129 | 130 | if (currCol == col) { 131 | return (*(this->vals))[pos]; 132 | 133 | } else if (currCol > col) { 134 | break; 135 | } 136 | } 137 | 138 | return T(); 139 | } 140 | 141 | 142 | template 143 | SparseMatrix & SparseMatrix::set(T val, int row, int col) 144 | { 145 | this->validateCoordinates(row, col); 146 | 147 | int pos = (*(this->rows))[row - 1] - 1; 148 | int currCol = 0; 149 | 150 | for (; pos < (*(this->rows))[row] - 1; pos++) { 151 | currCol = (*(this->cols))[pos]; 152 | 153 | if (currCol >= col) { 154 | break; 155 | } 156 | } 157 | 158 | if (currCol != col) { 159 | if (!(val == T())) { 160 | this->insert(pos, row, col, val); 161 | } 162 | 163 | } else if (val == T()) { 164 | this->remove(pos, row); 165 | 166 | } else { 167 | (*(this->vals))[pos] = val; 168 | } 169 | 170 | return *this; 171 | } 172 | 173 | 174 | // === OPERATIONS ============================================== 175 | 176 | template 177 | std::vector SparseMatrix::multiply(const std::vector & x) const 178 | { 179 | if (this->n != (int) x.size()) { 180 | throw InvalidDimensionsException("Cannot multiply: Matrix column count and vector size don't match."); 181 | } 182 | 183 | std::vector result(this->m, T()); 184 | 185 | if (this->vals != NULL) { // only if any value set 186 | for (int i = 0; i < this->m; i++) { 187 | T sum = T(); 188 | for (int j = (*(this->rows))[i]; j < (*(this->rows))[i + 1]; j++) { 189 | sum = sum + (*(this->vals))[j - 1] * x[(*(this->cols))[j - 1] - 1]; 190 | } 191 | 192 | result[i] = sum; 193 | } 194 | } 195 | 196 | return result; 197 | } 198 | 199 | 200 | template 201 | std::vector SparseMatrix::operator * (const std::vector & x) const 202 | { 203 | return this->multiply(x); 204 | } 205 | 206 | 207 | template 208 | SparseMatrix SparseMatrix::multiply(const SparseMatrix & m) const 209 | { 210 | if (this->n != m.m) { 211 | throw InvalidDimensionsException("Cannot multiply: Left matrix column count and right matrix row count don't match."); 212 | } 213 | 214 | SparseMatrix result(this->m, m.n); 215 | 216 | T a; 217 | 218 | // TODO: more efficient? 219 | // @see http://www.math.tamu.edu/~srobertp/Courses/Math639_2014_Sp/CRSDescription/CRSStuff.pdf 220 | 221 | for (int i = 1; i <= this->m; i++) { 222 | for (int j = 1; j <= m.n; j++) { 223 | a = T(); 224 | 225 | for (int k = 1; k <= this->n; k++) { 226 | a = a + this->get(i, k) * m.get(k, j); 227 | } 228 | 229 | result.set(a, i, j); 230 | } 231 | } 232 | 233 | return result; 234 | } 235 | 236 | 237 | template 238 | SparseMatrix SparseMatrix::operator * (const SparseMatrix & m) const 239 | { 240 | return this->multiply(m); 241 | } 242 | 243 | 244 | template 245 | SparseMatrix SparseMatrix::add(const SparseMatrix & m) const 246 | { 247 | if (this->m != m.m || this->n != m.n) { 248 | throw InvalidDimensionsException("Cannot add: matrices dimensions don't match."); 249 | } 250 | 251 | SparseMatrix result(this->m, this->n); 252 | 253 | // TODO: more efficient? 254 | // @see http://www.math.tamu.edu/~srobertp/Courses/Math639_2014_Sp/CRSDescription/CRSStuff.pdf 255 | 256 | for (int i = 1; i <= this->m; i++) { 257 | for (int j = 1; j <= this->n; j++) { 258 | result.set(this->get(i, j) + m.get(i, j), i, j); 259 | } 260 | } 261 | 262 | return result; 263 | } 264 | 265 | 266 | template 267 | SparseMatrix SparseMatrix::operator + (const SparseMatrix & m) const 268 | { 269 | return this->add(m); 270 | } 271 | 272 | 273 | template 274 | SparseMatrix SparseMatrix::subtract(const SparseMatrix & m) const 275 | { 276 | if (this->m != m.m || this->n != m.n) { 277 | throw InvalidDimensionsException("Cannot subtract: matrices dimensions don't match."); 278 | } 279 | 280 | SparseMatrix result(this->m, this->n); 281 | 282 | // TODO: more efficient? 283 | // @see http://www.math.tamu.edu/~srobertp/Courses/Math639_2014_Sp/CRSDescription/CRSStuff.pdf 284 | 285 | for (int i = 1; i <= this->m; i++) { 286 | for (int j = 1; j <= this->n; j++) { 287 | result.set(this->get(i, j) - m.get(i, j), i, j); 288 | } 289 | } 290 | 291 | return result; 292 | } 293 | 294 | 295 | template 296 | SparseMatrix SparseMatrix::operator - (const SparseMatrix & m) const 297 | { 298 | return this->subtract(m); 299 | } 300 | 301 | 302 | // === HELPERS / VALIDATORS ============================================== 303 | 304 | template 305 | void SparseMatrix::validateCoordinates(int row, int col) const 306 | { 307 | if (row < 1 || col < 1 || row > this->m || col > this->n) { 308 | throw InvalidCoordinatesException("Coordinates out of range."); 309 | } 310 | } 311 | 312 | 313 | template 314 | void SparseMatrix::insert(int index, int row, int col, T val) 315 | { 316 | if (this->vals == NULL) { 317 | this->vals = new std::vector(1, val); 318 | this->cols = new std::vector(1, col); 319 | 320 | } else { 321 | this->vals->insert(this->vals->begin() + index, val); 322 | this->cols->insert(this->cols->begin() + index, col); 323 | } 324 | 325 | for (int i = row; i <= this->m; i++) { 326 | (*(this->rows))[i] += 1; 327 | } 328 | } 329 | 330 | 331 | template 332 | void SparseMatrix::remove(int index, int row) 333 | { 334 | this->vals->erase(this->vals->begin() + index); 335 | this->cols->erase(this->cols->begin() + index); 336 | 337 | for (int i = row; i <= this->m; i++) { 338 | (*(this->rows))[i] -= 1; 339 | } 340 | } 341 | 342 | 343 | // === FRIEND FUNCTIONS ========================================= 344 | 345 | template 346 | bool operator == (const SparseMatrix & a, const SparseMatrix & b) 347 | { 348 | return ((a.vals == NULL && b.vals == NULL) 349 | || (a.vals != NULL && b.vals != NULL && *(a.vals) == *(b.vals))) 350 | && ((a.cols == NULL && b.cols == NULL) 351 | || (a.cols != NULL && b.cols != NULL && *(a.cols) == *(b.cols))) 352 | && *(a.rows) == *(b.rows); 353 | } 354 | 355 | 356 | template 357 | bool operator != (const SparseMatrix & a, const SparseMatrix & b) 358 | { 359 | return !(a == b); 360 | } 361 | 362 | 363 | template 364 | std::ostream & operator << (std::ostream & os, const SparseMatrix & matrix) 365 | { 366 | for (int i = 1; i <= matrix.m; i++) { 367 | for (int j = 1; j <= matrix.n; j++) { 368 | if (j != 1) { 369 | os << " "; 370 | } 371 | 372 | os << matrix.get(i, j); 373 | } 374 | 375 | if (i < matrix.m) { 376 | os << std::endl; 377 | } 378 | } 379 | 380 | return os; 381 | } 382 | 383 | } 384 | -------------------------------------------------------------------------------- /src/SparseMatrix/SparseMatrix.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #ifndef __SPARSEMATRIX_H__ 10 | 11 | #define __SPARSEMATRIX_H__ 12 | 13 | #include 14 | #include 15 | 16 | 17 | namespace SparseMatrix 18 | { 19 | 20 | template 21 | class SparseMatrix 22 | { 23 | 24 | public: 25 | 26 | // === CREATION ============================================== 27 | 28 | SparseMatrix(int n); // square matrix n×n 29 | SparseMatrix(int rows, int columns); // general matrix 30 | 31 | SparseMatrix(const SparseMatrix & m); // copy constructor 32 | SparseMatrix & operator = (const SparseMatrix & m); 33 | 34 | ~SparseMatrix(void); 35 | 36 | 37 | // === GETTERS / SETTERS ============================================== 38 | 39 | int getRowCount(void) const; 40 | int getColumnCount(void) const; 41 | 42 | 43 | // === VALUES ============================================== 44 | 45 | T get(int row, int col) const; 46 | SparseMatrix & set(T val, int row, int col); 47 | 48 | 49 | // === OPERATIONS ============================================== 50 | 51 | std::vector multiply(const std::vector & x) const; 52 | std::vector operator * (const std::vector & x) const; 53 | 54 | SparseMatrix multiply(const SparseMatrix & m) const; 55 | SparseMatrix operator * (const SparseMatrix & m) const; 56 | 57 | SparseMatrix add(const SparseMatrix & m) const; 58 | SparseMatrix operator + (const SparseMatrix & m) const; 59 | 60 | SparseMatrix subtract(const SparseMatrix & m) const; 61 | SparseMatrix operator - (const SparseMatrix & m) const; 62 | 63 | 64 | // === FRIEND FUNCTIONS ========================================= 65 | 66 | template 67 | friend bool operator == (const SparseMatrix & a, const SparseMatrix & b); 68 | 69 | template 70 | friend bool operator != (const SparseMatrix & a, const SparseMatrix & b); 71 | 72 | template 73 | friend std::ostream & operator << (std::ostream & os, const SparseMatrix & matrix); 74 | 75 | 76 | protected: 77 | 78 | int m, n; 79 | 80 | std::vector * vals; 81 | std::vector * rows, * cols; 82 | 83 | 84 | // === HELPERS / VALIDATORS ============================================== 85 | 86 | void construct(int m, int n); 87 | void destruct(void); 88 | void deepCopy(const SparseMatrix & m); 89 | void validateCoordinates(int row, int col) const; 90 | void insert(int index, int row, int col, T val); 91 | void remove(int index, int row); 92 | 93 | }; 94 | 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/SparseMatrix/exceptions.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #ifndef __SPARSEMATRIX_EXCEPTIONS_H__ 10 | 11 | #define __SPARSEMATRIX_EXCEPTIONS_H__ 12 | 13 | #include 14 | 15 | 16 | namespace SparseMatrix 17 | { 18 | 19 | class Exception : public std::exception 20 | { 21 | 22 | public: 23 | 24 | explicit Exception(const std::string & message) : exception(), message(message) 25 | {} 26 | 27 | 28 | virtual ~Exception(void) throw () 29 | {} 30 | 31 | 32 | inline std::string getMessage(void) const 33 | { 34 | return this->message; 35 | } 36 | 37 | 38 | protected: 39 | 40 | std::string message; 41 | 42 | }; 43 | 44 | 45 | class InvalidDimensionsException : public Exception 46 | { 47 | 48 | public: 49 | 50 | InvalidDimensionsException(const std::string & message) : Exception(message) 51 | {} 52 | 53 | }; 54 | 55 | 56 | class InvalidCoordinatesException : public Exception 57 | { 58 | 59 | public: 60 | 61 | InvalidCoordinatesException(const std::string & message) : Exception(message) 62 | {} 63 | 64 | }; 65 | 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /tests/cases/addition.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void _additionFail1(void) 14 | { 15 | SparseMatrix::SparseMatrix a(3, 4), b(3, 5); 16 | a.add(b); 17 | } 18 | 19 | 20 | void testAdditionFail1(void) 21 | { 22 | std::cout << "add() fail #1..." << std::flush; 23 | assertException("InvalidDimensionsException", _additionFail1); 24 | std::cout << " OK" << std::endl; 25 | } 26 | 27 | 28 | void _additionFail2(void) 29 | { 30 | SparseMatrix::SparseMatrix a(3, 4), b(4, 4); 31 | a.add(b); 32 | } 33 | 34 | 35 | void testAdditionFail2(void) 36 | { 37 | std::cout << "add() fail #2..." << std::flush; 38 | assertException("InvalidDimensionsException", _additionFail2); 39 | std::cout << " OK" << std::endl; 40 | } 41 | 42 | 43 | void _additionFail3(void) 44 | { 45 | SparseMatrix::SparseMatrix a(3, 4), b(4, 5); 46 | a.add(b); 47 | } 48 | 49 | 50 | void testAdditionFail3(void) 51 | { 52 | std::cout << "add() fail #3..." << std::flush; 53 | assertException("InvalidDimensionsException", _additionFail3); 54 | std::cout << " OK" << std::endl; 55 | } 56 | 57 | 58 | void testAddition(void) 59 | { 60 | for (int N = 0; N < 5e3; N++) { 61 | std::cout << "\rmatrices addition... #" << N + 1 << std::flush; 62 | 63 | // generate random matrices 64 | int rows = rand() % 16 + 1; 65 | int cols = rand() % 16 + 1; 66 | 67 | std::vector > classicMatrixA = generateRandomMatrix(rows, cols); 68 | SparseMatrixMock sparseMatrixA = SparseMatrixMock::fromVectors(classicMatrixA); 69 | 70 | std::vector > classicMatrixB = generateRandomMatrix(rows, cols); 71 | SparseMatrixMock sparseMatrixB = SparseMatrixMock::fromVectors(classicMatrixB); 72 | 73 | // calculate result manually 74 | std::vector > manualResult = addMatrices(classicMatrixA, classicMatrixB); 75 | 76 | // method 77 | assertEquals, std::vector > >( 78 | sparseMatrixA.add(sparseMatrixB), 79 | manualResult, 80 | "Incorrect matrices addition" 81 | ); 82 | 83 | // operator 84 | assertEquals, std::vector > >( 85 | sparseMatrixA + sparseMatrixB, 86 | manualResult, 87 | "Incorrect matrices addition (operator +)" 88 | ); 89 | } 90 | 91 | std::cout << " OK" << std::endl; 92 | } 93 | -------------------------------------------------------------------------------- /tests/cases/constructor.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void _constructorFail1(void) 14 | { 15 | SparseMatrix::SparseMatrix(0); 16 | } 17 | 18 | 19 | void testConstructorFail1(void) 20 | { 21 | std::cout << "constructor fail #1..." << std::flush; 22 | assertException("InvalidDimensionsException", _constructorFail1); 23 | std::cout << " OK" << std::endl; 24 | } 25 | 26 | 27 | void _constructorFail2(void) 28 | { 29 | SparseMatrix::SparseMatrix(0, 1); 30 | } 31 | 32 | 33 | void testConstructorFail2(void) 34 | { 35 | std::cout << "constructor fail #2..." << std::flush; 36 | assertException("InvalidDimensionsException", _constructorFail2); 37 | std::cout << " OK" << std::endl; 38 | } 39 | 40 | 41 | void _constructorFail3(void) 42 | { 43 | SparseMatrix::SparseMatrix(1, 0); 44 | } 45 | 46 | 47 | void testConstructorFail3(void) 48 | { 49 | std::cout << "constructor fail #3..." << std::flush; 50 | assertException("InvalidDimensionsException", _constructorFail3); 51 | std::cout << " OK" << std::endl; 52 | } 53 | 54 | 55 | void _constructorFail4(void) 56 | { 57 | SparseMatrix::SparseMatrix(0, 0); 58 | } 59 | 60 | 61 | void testConstructorFail4(void) 62 | { 63 | std::cout << "constructor fail #4..." << std::flush; 64 | assertException("InvalidDimensionsException", _constructorFail4); 65 | std::cout << " OK" << std::endl; 66 | } 67 | -------------------------------------------------------------------------------- /tests/cases/crs-format.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void testInternalStorage(void) 14 | { 15 | std::cout << "internal storage..." << std::flush; 16 | 17 | /* 18 | "Standard" matrix 19 | [ 1 0 4 5 ] 20 | [ 2 -1 0 0 ] 21 | [ 0 0 3 2 ] 22 | 23 | should be stored as 24 | rows: [ 1, 4, 6, 8 ] 25 | columns: [ 1, 3, 4, 1, 2, 3, 4 ] 26 | values: [ 1, 4, 5, 2, -1, 3, 2 ] 27 | */ 28 | 29 | SparseMatrixMock m1(3, 4); 30 | m1.set(1, 1, 1) 31 | .set(4, 1, 3) 32 | .set(5, 1, 4) 33 | .set(2, 2, 1) 34 | .set(-1, 2, 2) 35 | .set(3, 3, 3) 36 | .set(2, 3, 4); 37 | 38 | std::vector rowPointers1; 39 | rowPointers1.push_back(1); 40 | rowPointers1.push_back(4); 41 | rowPointers1.push_back(6); 42 | rowPointers1.push_back(8); 43 | assertEquals >(rowPointers1, *(m1.getRowPointers()), "Incorrect internal row pointers"); 44 | 45 | std::vector columnPointers1; 46 | columnPointers1.push_back(1); 47 | columnPointers1.push_back(3); 48 | columnPointers1.push_back(4); 49 | columnPointers1.push_back(1); 50 | columnPointers1.push_back(2); 51 | columnPointers1.push_back(3); 52 | columnPointers1.push_back(4); 53 | assertEquals >(columnPointers1, *(m1.getColumnPointers()), "Incorrect internal column pointers"); 54 | 55 | std::vector values1; 56 | values1.push_back(1); 57 | values1.push_back(4); 58 | values1.push_back(5); 59 | values1.push_back(2); 60 | values1.push_back(-1); 61 | values1.push_back(3); 62 | values1.push_back(2); 63 | assertEquals >(values1, *(m1.getValues()), "Incorrect internal values storage"); 64 | 65 | 66 | /* 67 | Matrix with empty row 68 | [ 10 0 0 2 ] 69 | [ 0 0 0 0 ] 70 | [ 3 1 0 4 ] 71 | 72 | should be stored as 73 | rows: [ 1, 3, 3, 6 ] 74 | columns: [ 1, 4, 1, 2, 4 ] 75 | values: [ 10, 2, 3, 1, 4 ] 76 | */ 77 | 78 | SparseMatrixMock m2(3, 4); 79 | m2.set(10, 1, 1) 80 | . set(2, 1, 4) 81 | . set(3, 3, 1) 82 | . set(1, 3, 2) 83 | . set(4, 3, 4); 84 | 85 | std::vector rowPointers2; 86 | rowPointers2.push_back(1); 87 | rowPointers2.push_back(3); 88 | rowPointers2.push_back(3); 89 | rowPointers2.push_back(6); 90 | assertEquals >(rowPointers2, *(m2.getRowPointers()), "Incorrect internal row pointers"); 91 | 92 | std::vector columnPointers2; 93 | columnPointers2.push_back(1); 94 | columnPointers2.push_back(4); 95 | columnPointers2.push_back(1); 96 | columnPointers2.push_back(2); 97 | columnPointers2.push_back(4); 98 | assertEquals >(columnPointers2, *(m2.getColumnPointers()), "Incorrect internal column pointers"); 99 | 100 | std::vector values2; 101 | values2.push_back(10); 102 | values2.push_back(2); 103 | values2.push_back(3); 104 | values2.push_back(1); 105 | values2.push_back(4); 106 | assertEquals >(values2, *(m2.getValues()), "Incorrect internal values storage"); 107 | 108 | 109 | /* 110 | Previous matrix after adding non-zero element to empty row 111 | 112 | should be stored as 113 | rows: [ 1, 3, 4, 7 ] 114 | columns: [ 1, 4, 2, 1, 2, 4 ] 115 | values: [ 10, 2, 5, 3, 1, 4 ] 116 | */ 117 | 118 | SparseMatrixMock m3 = m2; 119 | m3.set(5, 2, 2); 120 | 121 | std::vector rowPointers3; 122 | rowPointers3.push_back(1); 123 | rowPointers3.push_back(3); 124 | rowPointers3.push_back(4); 125 | rowPointers3.push_back(7); 126 | assertEquals >(rowPointers3, *(m3.getRowPointers()), "Incorrect internal row pointers"); 127 | 128 | std::vector columnPointers3; 129 | columnPointers3.push_back(1); 130 | columnPointers3.push_back(4); 131 | columnPointers3.push_back(2); 132 | columnPointers3.push_back(1); 133 | columnPointers3.push_back(2); 134 | columnPointers3.push_back(4); 135 | assertEquals >(columnPointers3, *(m3.getColumnPointers()), "Incorrect internal column pointers"); 136 | 137 | std::vector values3; 138 | values3.push_back(10); 139 | values3.push_back(2); 140 | values3.push_back(5); 141 | values3.push_back(3); 142 | values3.push_back(1); 143 | values3.push_back(4); 144 | assertEquals >(values3, *(m3.getValues()), "Incorrect internal values storage"); 145 | 146 | /* 147 | Previous matrix with removed the only non-zero element on 2nd row (should be equal to 2nd matrix) 148 | 149 | should be stored as 150 | rows: [ 1, 3, 3, 6 ] 151 | columns: [ 1, 4, 1, 2, 4 ] 152 | values: [ 10, 2, 3, 1, 4 ] 153 | */ 154 | 155 | SparseMatrixMock m4 = m3; 156 | m4.set(0, 2, 2); 157 | 158 | assertEquals >(rowPointers2, *(m4.getRowPointers()), "Incorrect internal row pointers"); 159 | assertEquals >(columnPointers2, *(m4.getColumnPointers()), "Incorrect internal column pointers"); 160 | assertEquals >(values2, *(m4.getValues()), "Incorrect internal values storage"); 161 | 162 | std::cout << " OK" << std::endl; 163 | } 164 | -------------------------------------------------------------------------------- /tests/cases/custom-type.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "../inc/testslib.h" 13 | #include "../inc/SparseMatrixMock.h" 14 | 15 | 16 | std::string joinStrings(const std::string & a, const std::string & b) 17 | { 18 | std::string c = a; 19 | 20 | if (a.length() && b.length()) { 21 | c += " "; 22 | } 23 | 24 | c += b; 25 | return c; 26 | } 27 | 28 | 29 | struct person 30 | { 31 | 32 | person(void) : firstname(""), lastname("") 33 | {} 34 | 35 | 36 | person(const person & p) : firstname(p.firstname), lastname(p.lastname) 37 | {} 38 | 39 | 40 | person(const std::string & f, const std::string & l) : firstname(f), lastname(l) 41 | {} 42 | 43 | 44 | bool operator == (const person & p) const 45 | { 46 | return this->firstname == p.firstname && this->lastname == p.lastname; 47 | } 48 | 49 | 50 | person operator + (const person & p) const 51 | { 52 | return person(joinStrings(this->firstname, p.firstname), joinStrings(this->lastname, p.lastname)); 53 | } 54 | 55 | 56 | person operator - (const person & p) const 57 | { 58 | return person(p.lastname, this->lastname); 59 | } 60 | 61 | 62 | person operator * (const person & p) const 63 | { 64 | if (*this == person() || p == person()) { 65 | return person(); 66 | } 67 | 68 | return person(joinStrings(this->firstname, p.lastname), joinStrings(this->lastname, p.firstname)); 69 | } 70 | 71 | 72 | std::string firstname, lastname; 73 | 74 | }; 75 | 76 | 77 | std::ostream & operator << (std::ostream & os, const person & p) 78 | { 79 | os << p.firstname << ", " << p.lastname; 80 | return os; 81 | } 82 | 83 | 84 | void testElementTypes(void) 85 | { 86 | std::cout << "custom element types..." << std::flush; 87 | 88 | // addition 89 | 90 | SparseMatrix::SparseMatrix a(4, 5); 91 | a.set(person("John", "Doe"), 3, 2); 92 | 93 | SparseMatrix::SparseMatrix b(4, 5); 94 | b.set(person("Foo", "Bar"), 3, 2); 95 | 96 | SparseMatrix::SparseMatrix sum = a.add(b); 97 | assertEquals(person("John Foo", "Doe Bar"), sum.get(3, 2)); 98 | 99 | 100 | // subtraction 101 | 102 | SparseMatrix::SparseMatrix diff = a.subtract(b); 103 | assertEquals(person("Bar", "Doe"), diff.get(3, 2)); 104 | 105 | 106 | // matrix-matrix multiplication 107 | 108 | SparseMatrix::SparseMatrix c(5, 3); 109 | c.set(person("Foo", "Bar"), 2, 3); 110 | 111 | SparseMatrix::SparseMatrix product = a.multiply(c); 112 | 113 | for (int i = 1, rows = product.getRowCount(); i <= rows; i++) { 114 | for (int j = 1, cols = product.getColumnCount(); j <= cols; j++) { 115 | person value = product.get(i, j); 116 | 117 | if (i == 3 && j == 3) { 118 | assertEquals(person("John Bar", "Doe Foo"), value); 119 | 120 | } else { 121 | assertEquals(person(), value); 122 | } 123 | } 124 | } 125 | 126 | 127 | // vector-matrix multiplication 128 | 129 | std::vector people; 130 | people.push_back(person("John", "Doe")); 131 | people.push_back(person("Foo", "Bar")); 132 | people.push_back(person("Willy", "Wonka")); 133 | people.push_back(person("Jon", "Snow")); 134 | people.push_back(person("Bridget", "Johnes")); 135 | 136 | std::vector result = a.multiply(people); 137 | assertEquals(person(), result[0]); 138 | assertEquals(person(), result[1]); 139 | assertEquals(person("John Bar", "Doe Foo"), result[2]); 140 | assertEquals(person(), result[3]); 141 | 142 | std::cout << " OK" << std::endl; 143 | } 144 | -------------------------------------------------------------------------------- /tests/cases/multiplication.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void _multiplicationFail1(void) 14 | { 15 | SparseMatrix::SparseMatrix m(3, 4); 16 | std::vector x(3, 1); 17 | m.multiply(x); 18 | } 19 | 20 | 21 | void testMultiplicationFail1(void) 22 | { 23 | std::cout << "multiply() fail #1..." << std::flush; 24 | assertException("InvalidDimensionsException", _multiplicationFail1); 25 | std::cout << " OK" << std::endl; 26 | } 27 | 28 | 29 | void _multiplicationFail2(void) 30 | { 31 | SparseMatrix::SparseMatrix a(3, 4), b(5, 6); 32 | a.multiply(b); 33 | } 34 | 35 | 36 | void testMultiplicationFail2(void) 37 | { 38 | std::cout << "multiply() fail #2..." << std::flush; 39 | assertException("InvalidDimensionsException", _multiplicationFail2); 40 | std::cout << " OK" << std::endl; 41 | } 42 | 43 | 44 | void testVectorMultiplication(void) 45 | { 46 | for (int N = 0; N < 5e3; N++) { 47 | std::cout << "\rvector multiplication... #" << N + 1 << std::flush; 48 | 49 | // generate random vector and matrix 50 | int rows = rand() % 16 + 1; 51 | int cols = rand() % 16 + 1; 52 | 53 | std::vector vec = generateRandomVector(cols); 54 | 55 | std::vector > classicMatrix = generateRandomMatrix(rows, cols); 56 | SparseMatrixMock sparseMatrix = SparseMatrixMock::fromVectors(classicMatrix); 57 | 58 | // calculate result manually 59 | std::vector manualResult = multiplyMatrixByVector(classicMatrix, vec); 60 | 61 | // method 62 | assertEquals >(manualResult, sparseMatrix.multiply(vec), "Incorrect vector multiplication"); 63 | 64 | // operator 65 | assertEquals >(manualResult, sparseMatrix * vec, "Incorrect vector multiplication (operator *)"); 66 | } 67 | 68 | std::cout << " OK" << std::endl; 69 | } 70 | 71 | 72 | void testMatricesMultiplication(void) 73 | { 74 | for (int N = 0; N < 5e3; N++) { 75 | std::cout << "\rmatrices multiplication... #" << N + 1 << std::flush; 76 | 77 | // generate random matrices 78 | int rowsA = rand() % 16 + 1; 79 | int colsArowsB = rand() % 16 + 1; 80 | int colsB = rand() % 16 + 1; 81 | 82 | std::vector > classicMatrixA = generateRandomMatrix(rowsA, colsArowsB); 83 | SparseMatrixMock sparseMatrixA = SparseMatrixMock::fromVectors(classicMatrixA); 84 | 85 | std::vector > classicMatrixB = generateRandomMatrix(colsArowsB, colsB); 86 | SparseMatrixMock sparseMatrixB = SparseMatrixMock::fromVectors(classicMatrixB); 87 | 88 | // calculate result manually 89 | std::vector > manualResult = multiplyMatrices(classicMatrixA, classicMatrixB); 90 | 91 | // method 92 | assertEquals, std::vector > >( 93 | sparseMatrixA.multiply(sparseMatrixB), 94 | manualResult, 95 | "Incorrect matrices multiplication" 96 | ); 97 | 98 | // operator 99 | assertEquals, std::vector > >( 100 | sparseMatrixA * sparseMatrixB, 101 | manualResult, 102 | "Incorrect matrices multiplication (operator *)" 103 | ); 104 | } 105 | 106 | std::cout << " OK" << std::endl; 107 | } 108 | -------------------------------------------------------------------------------- /tests/cases/output.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void testOutput(void) 14 | { 15 | std::cout << "output..." << std::flush; 16 | 17 | std::ostringstream oss; 18 | std::string output; 19 | 20 | SparseMatrix::SparseMatrix m(3, 3); 21 | oss << m; 22 | assertEquals("0 0 0\n0 0 0\n0 0 0", oss.str()); 23 | 24 | m.set(7, 1, 3) 25 | .set(5, 2, 2) 26 | .set(3, 3, 1); 27 | 28 | oss.str(""); 29 | oss << m; 30 | assertEquals("0 0 7\n0 5 0\n3 0 0", oss.str()); 31 | 32 | std::cout << " OK" << std::endl; 33 | } 34 | -------------------------------------------------------------------------------- /tests/cases/subtraction.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void _subtractionFail1(void) 14 | { 15 | SparseMatrix::SparseMatrix a(3, 4), b(3, 5); 16 | a.subtract(b); 17 | } 18 | 19 | 20 | void testSubtractionFail1(void) 21 | { 22 | std::cout << "subtract() fail #1..." << std::flush; 23 | assertException("InvalidDimensionsException", _subtractionFail1); 24 | std::cout << " OK" << std::endl; 25 | } 26 | 27 | 28 | void _subtractionFail2(void) 29 | { 30 | SparseMatrix::SparseMatrix a(3, 4), b(4, 4); 31 | a.subtract(b); 32 | } 33 | 34 | 35 | void testSubtractionFail2(void) 36 | { 37 | std::cout << "subtract() fail #2..." << std::flush; 38 | assertException("InvalidDimensionsException", _subtractionFail2); 39 | std::cout << " OK" << std::endl; 40 | } 41 | 42 | 43 | void _subtractionFail3(void) 44 | { 45 | SparseMatrix::SparseMatrix a(3, 4), b(4, 5); 46 | a.subtract(b); 47 | } 48 | 49 | 50 | void testSubtractionFail3(void) 51 | { 52 | std::cout << "subtract() fail #3..." << std::flush; 53 | assertException("InvalidDimensionsException", _subtractionFail3); 54 | std::cout << " OK" << std::endl; 55 | } 56 | 57 | 58 | void testSubtraction(void) 59 | { 60 | for (int N = 0; N < 5e3; N++) { 61 | std::cout << "\rmatrices subtraction... #" << N + 1 << std::flush; 62 | 63 | // generate random matrices 64 | int rows = rand() % 16 + 1; 65 | int cols = rand() % 16 + 1; 66 | 67 | std::vector > classicMatrixA = generateRandomMatrix(rows, cols); 68 | SparseMatrixMock sparseMatrixA = SparseMatrixMock::fromVectors(classicMatrixA); 69 | 70 | std::vector > classicMatrixB = generateRandomMatrix(rows, cols); 71 | SparseMatrixMock sparseMatrixB = SparseMatrixMock::fromVectors(classicMatrixB); 72 | 73 | // calculate result manually 74 | std::vector > manualResult = subtractMatrices(classicMatrixA, classicMatrixB); 75 | 76 | // method 77 | assertEquals, std::vector > >( 78 | sparseMatrixA.subtract(sparseMatrixB), 79 | manualResult, 80 | "Incorrect matrices subtract" 81 | ); 82 | 83 | // operator 84 | assertEquals, std::vector > >( 85 | sparseMatrixA - sparseMatrixB, 86 | manualResult, 87 | "Incorrect matrices subtract (operator -)" 88 | ); 89 | } 90 | 91 | std::cout << " OK" << std::endl; 92 | } 93 | -------------------------------------------------------------------------------- /tests/cases/values.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include "../inc/testslib.h" 10 | #include "../inc/SparseMatrixMock.h" 11 | 12 | 13 | void _getFail(void) 14 | { 15 | SparseMatrix::SparseMatrix m(1, 1); 16 | m.get(2, 1); 17 | } 18 | 19 | 20 | void testGetFail(void) 21 | { 22 | std::cout << "get() fail..." << std::flush; 23 | assertException("InvalidCoordinatesException", _getFail); 24 | std::cout << " OK" << std::endl; 25 | } 26 | 27 | 28 | void _setFail(void) 29 | { 30 | SparseMatrix::SparseMatrix m(3, 4); 31 | m.set(-1, 4, 0); 32 | } 33 | 34 | 35 | void testSetFail(void) 36 | { 37 | std::cout << "set() fail..." << std::flush; 38 | assertException("InvalidCoordinatesException", _setFail); 39 | std::cout << " OK" << std::endl; 40 | } 41 | 42 | 43 | void testGettersAndSetters(void) 44 | { 45 | std::cout << "getters/setters..." << std::flush; 46 | 47 | SparseMatrix::SparseMatrix m(3); 48 | for (int i = 1; i <= 3; i++) { 49 | for (int j = 1; j <= 3; j++) { 50 | assertEquals(0, m.get(i, j)); 51 | } 52 | } 53 | 54 | m.set(-4, 1, 3); 55 | assertEquals(-4, m.get(1, 3)); 56 | 57 | std::cout << " OK" << std::endl; 58 | } 59 | -------------------------------------------------------------------------------- /tests/inc/SparseMatrixMock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #ifndef __SPARSEMATRIX_MOCK_H__ 10 | 11 | #define __SPARSEMATRIX_MOCK_H__ 12 | 13 | #include 14 | #include "../../src/SparseMatrix/SparseMatrix.h" 15 | 16 | 17 | /** 18 | * This class is used only for testing purposes 19 | * 20 | * @internal 21 | */ 22 | template 23 | class SparseMatrixMock : public SparseMatrix::SparseMatrix 24 | { 25 | 26 | public: 27 | 28 | SparseMatrixMock(int n) : SparseMatrix::SparseMatrix(n) 29 | {} 30 | 31 | 32 | SparseMatrixMock(int rows, int columns) : SparseMatrix::SparseMatrix(rows, columns) 33 | {} 34 | 35 | 36 | /** @return Non-empty values in the matrix */ 37 | std::vector * getValues(void) 38 | { 39 | return this->vals; 40 | } 41 | 42 | 43 | /** @return Column pointers */ 44 | std::vector * getColumnPointers(void) 45 | { 46 | return this->cols; 47 | } 48 | 49 | 50 | /** @return Row pointers */ 51 | std::vector * getRowPointers(void) 52 | { 53 | return this->rows; 54 | } 55 | 56 | 57 | /** 58 | * Sends internal storage info to given output stream 59 | * 60 | * @param os output stream 61 | * @return void 62 | */ 63 | void printInfo(std::ostream & os) const 64 | { 65 | std::vector::iterator intIt; 66 | 67 | os << "rows (" << this->rows->size() << "): ["; 68 | 69 | for (intIt = this->rows->begin(); intIt < this->rows->end(); intIt++) { 70 | if (intIt > this->rows->begin()) { 71 | os << ", "; 72 | } 73 | 74 | os << *intIt; 75 | } 76 | 77 | os << "]"; 78 | 79 | os << std::endl << "cols"; 80 | if (this->cols == NULL) { 81 | os << ": NULL"; 82 | 83 | } else { 84 | os << " (" << this->cols->size() << "): ["; 85 | 86 | for (intIt = this->cols->begin(); intIt < this->cols->end(); intIt++) { 87 | if (intIt > this->cols->begin()) { 88 | os << ", "; 89 | } 90 | 91 | os << *intIt; 92 | } 93 | 94 | os << "]"; 95 | } 96 | 97 | os << std::endl << "vals"; 98 | if (this->vals == NULL) { 99 | os << ": NULL"; 100 | 101 | } else { 102 | typename std::vector::iterator valIt; 103 | 104 | os << " (" << this->vals->size() << "): ["; 105 | 106 | for (valIt = this->vals->begin(); valIt < this->vals->end(); valIt++) { 107 | if (valIt > this->vals->begin()) { 108 | os << ", "; 109 | } 110 | 111 | os << *valIt; 112 | } 113 | 114 | os << "]"; 115 | } 116 | } 117 | 118 | 119 | /** @return Constructed SparseMatrix */ 120 | static SparseMatrixMock fromVectors(std::vector > vec) 121 | { 122 | SparseMatrixMock matrix(vec.size(), vec[0].size()); 123 | 124 | for (int i = 0, len = vec.size(); i < len; i++) { 125 | for (int j = 0, len = vec[i].size(); j < len; j++) { 126 | matrix.set(vec[i][j], i + 1, j + 1); 127 | } 128 | } 129 | 130 | return matrix; 131 | } 132 | 133 | }; 134 | 135 | 136 | template 137 | bool operator == (const SparseMatrix::SparseMatrix & sparse, const std::vector > & classical) 138 | { 139 | for (int i = 0, rows = classical.size(); i < rows; i++) { 140 | for (int j = 0, cols = classical[i].size(); j < cols; j++) { 141 | if (sparse.get(i + 1, j + 1) != classical[i][j]) { 142 | return false; 143 | } 144 | } 145 | } 146 | 147 | return true; 148 | } 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /tests/inc/helpers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #ifndef __HELPERS_H__ 10 | 11 | #define __HELPERS_H__ 12 | 13 | #include 14 | #include 15 | 16 | 17 | // === GENERATORS ========================================= 18 | 19 | template 20 | std::vector generateRandomVector(int size) 21 | { 22 | std::vector vector(size, 0); 23 | 24 | for (int i = 0; i < size; i++) { 25 | vector[i] = rand() % 101; 26 | } 27 | 28 | return vector; 29 | } 30 | 31 | 32 | template 33 | std::vector > generateRandomMatrix(int rows, int columns) 34 | { 35 | std::vector > matrix(rows, std::vector(columns, 0)); 36 | 37 | for (int i = 0; i < rows; i++) { 38 | for (int j = 0; j < columns; j++) { 39 | matrix[i][j] = rand() % 101; 40 | } 41 | } 42 | 43 | return matrix; 44 | } 45 | 46 | 47 | // === STANDARD OPERATIONS ========================================= 48 | 49 | template 50 | std::vector > addMatrices(const std::vector > & a, const std::vector > & b) 51 | { 52 | int rows = a.size(); 53 | int cols = a.front().size(); 54 | 55 | std::vector > result(rows, std::vector(cols, 0)); 56 | 57 | for (int i = 0; i < rows; i++) { 58 | for (int j = 0; j < cols; j++) { 59 | result[i][j] = a[i][j] + b[i][j]; 60 | } 61 | } 62 | 63 | return result; 64 | } 65 | 66 | 67 | template 68 | std::vector > subtractMatrices(const std::vector > & a, const std::vector > & b) 69 | { 70 | int rows = a.size(); 71 | int cols = a.front().size(); 72 | 73 | std::vector > result(rows, std::vector(cols, 0)); 74 | 75 | for (int i = 0; i < rows; i++) { 76 | for (int j = 0; j < cols; j++) { 77 | result[i][j] = a[i][j] - b[i][j]; 78 | } 79 | } 80 | 81 | return result; 82 | } 83 | 84 | 85 | template 86 | std::vector multiplyMatrixByVector(const std::vector > & m, const std::vector & v) 87 | { 88 | int rows = m.size(); 89 | int cols = v.size(); 90 | 91 | std::vector result(rows, 0); 92 | 93 | for (int i = 0; i < rows; i++) { 94 | for (int j = 0; j < cols; j++) { 95 | result[i] += m[i][j] * v[j]; 96 | } 97 | } 98 | 99 | return result; 100 | } 101 | 102 | 103 | template 104 | std::vector > multiplyMatrices(const std::vector > & a, const std::vector > & b) 105 | { 106 | int rowsA = a.size(); 107 | int colsA = a.front().size(); 108 | int colsB = b.front().size(); 109 | 110 | std::vector > result(rowsA, std::vector(colsB, 0)); 111 | 112 | for (int i = 0; i < rowsA; i++) { 113 | for (int j = 0; j < colsB; j++) { 114 | result[i][j] = 0; 115 | 116 | for (int k = 0; k < colsA; k++) { 117 | result[i][j] += a[i][k] * b[k][j]; 118 | } 119 | } 120 | } 121 | 122 | return result; 123 | } 124 | 125 | 126 | // === OUTPUT HELPERS ========================================= 127 | 128 | template 129 | std::ostream & operator << (std::ostream & os, const std::vector & v) 130 | { 131 | os << "["; 132 | 133 | for (int i = 0, len = v.size(); i < len; i++) { 134 | if (i != 0) { 135 | os << ", "; 136 | } 137 | 138 | os << v[i]; 139 | } 140 | 141 | os << "]"; 142 | 143 | return os; 144 | } 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /tests/inc/testslib.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #ifndef __TESTSLIB_H__ 10 | 11 | #define __TESTSLIB_H__ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | class FailureException : public std::exception 23 | { 24 | 25 | public: 26 | 27 | FailureException(const std::string & message) : std::exception(), message(message) 28 | {} 29 | 30 | 31 | virtual ~FailureException(void) throw () 32 | {} 33 | 34 | 35 | inline std::string getMessage(void) const 36 | { 37 | return this->message; 38 | } 39 | 40 | 41 | protected: 42 | 43 | std::string message; 44 | 45 | }; 46 | 47 | 48 | void assertException(const char * exceptionClass, void (*callback)(void)) 49 | { 50 | try { 51 | callback(); 52 | 53 | } catch (const std::exception & e) { 54 | std::string actualClass(typeid(e).name()); 55 | 56 | if (strstr(actualClass.c_str(), exceptionClass) == NULL) { 57 | std::ostringstream oss; 58 | oss << "Exception class '" << exceptionClass << "' expected, but '" << actualClass << "' thrown."; 59 | 60 | throw FailureException(oss.str()); 61 | } 62 | 63 | return ; 64 | } 65 | 66 | throw FailureException("Exception expected but none thrown."); 67 | } 68 | 69 | 70 | template 71 | void assertEquals(const T & a, const T & b, const char * message = NULL) 72 | { 73 | if (!(a == b)) { 74 | std::ostringstream oss; 75 | if (message == NULL) { 76 | oss << "Objects not equal when they should be." << std::endl; 77 | 78 | } else { 79 | oss << message << std::endl; 80 | } 81 | 82 | oss << a << std::endl << "expected, but" << std::endl << b << " given"; 83 | throw FailureException(oss.str()); 84 | } 85 | } 86 | 87 | 88 | template 89 | void assertEquals(const X & a, const Y & b, const char * message = NULL) 90 | { 91 | if (!(a == b)) { 92 | std::ostringstream oss; 93 | if (message == NULL) { 94 | oss << "Objects not equal when they should be." << std::endl; 95 | 96 | } else { 97 | oss << message << std::endl; 98 | } 99 | 100 | oss << a << std::endl << "expected, but" << std::endl << b << " given"; 101 | throw FailureException(oss.str()); 102 | } 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /tests/run.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the SparseMatrix library 3 | * 4 | * @license MIT 5 | * @author Petr Kessler (https://kesspess.cz) 6 | * @link https://github.com/uestla/Sparse-Matrix 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "inc/testslib.h" 13 | #include "inc/helpers.h" 14 | 15 | #include "../src/SparseMatrix/SparseMatrix.cpp" 16 | #include "cases/constructor.cpp" 17 | #include "cases/values.cpp" 18 | #include "cases/multiplication.cpp" 19 | #include "cases/addition.cpp" 20 | #include "cases/subtraction.cpp" 21 | #include "cases/crs-format.cpp" 22 | #include "cases/output.cpp" 23 | #include "cases/custom-type.cpp" 24 | 25 | 26 | int main(int argc, char ** argv) 27 | { 28 | srand(time(NULL)); // used at random matrices / vectors generating 29 | 30 | try { 31 | 32 | testConstructorFail1(); 33 | testConstructorFail2(); 34 | testConstructorFail3(); 35 | testConstructorFail4(); 36 | testGetFail(); 37 | testSetFail(); 38 | testMultiplicationFail1(); 39 | testMultiplicationFail2(); 40 | testAdditionFail1(); 41 | testAdditionFail2(); 42 | testAdditionFail3(); 43 | testSubtractionFail1(); 44 | testSubtractionFail2(); 45 | testSubtractionFail3(); 46 | testGettersAndSetters(); 47 | testInternalStorage(); 48 | testOutput(); 49 | testVectorMultiplication(); 50 | testMatricesMultiplication(); 51 | testAddition(); 52 | testSubtraction(); 53 | testElementTypes(); 54 | 55 | } catch (const FailureException & e) { 56 | std::cout << " - FAIL: '" << e.getMessage() << "'" << std::endl; 57 | return 1; 58 | } 59 | 60 | return 0; 61 | } 62 | --------------------------------------------------------------------------------