Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * include/stxxl/bits/containers/matrix.h 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2010-2011 Raoul Steffen <R-Steffen@gmx.de> 00007 * 00008 * Distributed under the Boost Software License, Version 1.0. 00009 * (See accompanying file LICENSE_1_0.txt or copy at 00010 * http://www.boost.org/LICENSE_1_0.txt) 00011 **************************************************************************/ 00012 00013 #ifndef STXXL_MATRIX_HEADER 00014 #define STXXL_MATRIX_HEADER 00015 00016 #include <stxxl/bits/containers/vector.h> 00017 #include <stxxl/bits/common/shared_object.h> 00018 #include <stxxl/bits/mng/block_scheduler.h> 00019 #include <stxxl/bits/containers/matrix_arithmetic.h> 00020 00021 __STXXL_BEGIN_NAMESPACE 00022 00023 /* index-variable naming convention: 00024 * [MODIFIER_][UNIT_]DIMENSION[_in_[MODIFIER_]ENVIRONMENT] 00025 * 00026 * e.g.: 00027 * block_row = number of row measured in rows consisting of blocks 00028 * element_row_in_block = number of row measured in rows consisting of elements in the (row of) block(s) 00029 * 00030 * size-variable naming convention: 00031 * [MODIFIER_][ENVIRONMENT_]DIMENSION[_in_UNITs] 00032 * 00033 * e.g. 00034 * height_in_blocks 00035 */ 00036 00037 //forward declaration 00038 template <typename ValueType, unsigned BlockSideLength> 00039 class matrix; 00040 00041 //! \brief external column-vector container for matrix multiplication 00042 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00043 template <typename ValueType> 00044 class column_vector : public vector<ValueType> 00045 { 00046 public: 00047 typedef vector<ValueType> vector_type; 00048 typedef typename vector_type::size_type size_type; 00049 00050 using vector_type::size; 00051 00052 //! \param n number of elements 00053 column_vector(size_type n = 0) 00054 : vector_type(n) {} 00055 00056 column_vector operator + (const column_vector & right) const 00057 { 00058 assert(size() == right.size()); 00059 column_vector res(size()); 00060 for (size_type i = 0; i < size(); ++i) 00061 res[i] = (*this)[i] + right[i]; 00062 return res; 00063 } 00064 00065 column_vector operator - (const column_vector & right) const 00066 { 00067 assert(size() == right.size()); 00068 column_vector res(size()); 00069 for (size_type i = 0; i < size(); ++i) 00070 res[i] = (*this)[i] - right[i]; 00071 return res; 00072 } 00073 00074 column_vector operator * (const ValueType scalar) const 00075 { 00076 column_vector res(size()); 00077 for (size_type i = 0; i < size(); ++i) 00078 res[i] = (*this)[i] * scalar; 00079 return res; 00080 } 00081 00082 column_vector & operator += (const column_vector & right) 00083 { 00084 assert(size() == right.size()); 00085 for (size_type i = 0; i < size(); ++i) 00086 (*this)[i] += right[i]; 00087 return *this; 00088 } 00089 00090 column_vector & operator -= (const column_vector & right) 00091 { 00092 assert(size() == right.size()); 00093 for (size_type i = 0; i < size(); ++i) 00094 (*this)[i] -= right[i]; 00095 return *this; 00096 } 00097 00098 column_vector & operator *= (const ValueType scalar) 00099 { 00100 for (size_type i = 0; i < size(); ++i) 00101 (*this)[i] *= scalar; 00102 return *this; 00103 } 00104 00105 void set_zero() 00106 { 00107 for (typename vector_type::iterator it = vector_type::begin(); it != vector_type::end(); ++it) 00108 *it = 0; 00109 } 00110 }; 00111 00112 //! \brief external row-vector container for matrix multiplication 00113 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00114 template <typename ValueType> 00115 class row_vector : public vector<ValueType> 00116 { 00117 public: 00118 typedef vector<ValueType> vector_type; 00119 typedef typename vector_type::size_type size_type; 00120 00121 using vector_type::size; 00122 00123 //! \param n number of elements 00124 row_vector(size_type n = 0) 00125 : vector_type(n) {} 00126 00127 row_vector operator + (const row_vector & right) const 00128 { 00129 assert(size() == right.size()); 00130 row_vector res(size()); 00131 for (size_type i = 0; i < size(); ++i) 00132 res[i] = (*this)[i] + right[i]; 00133 return res; 00134 } 00135 00136 row_vector operator - (const row_vector & right) const 00137 { 00138 assert(size() == right.size()); 00139 row_vector res(size()); 00140 for (size_type i = 0; i < size(); ++i) 00141 res[i] = (*this)[i] - right[i]; 00142 return res; 00143 } 00144 00145 row_vector operator * (const ValueType scalar) const 00146 { 00147 row_vector res(size()); 00148 for (size_type i = 0; i < size(); ++i) 00149 res[i] = (*this)[i] * scalar; 00150 return res; 00151 } 00152 00153 template <unsigned BlockSideLength> 00154 row_vector operator * (const matrix<ValueType, BlockSideLength> & right) const 00155 { return right.multiply_from_left(*this); } 00156 00157 ValueType operator * (const column_vector<ValueType> & right) const 00158 { 00159 ValueType res = 0; 00160 for (size_type i = 0; i < size(); ++i) 00161 res += (*this)[i] * right[i]; 00162 return res; 00163 } 00164 00165 row_vector & operator += (const row_vector & right) 00166 { 00167 assert(size() == right.size()); 00168 for (size_type i = 0; i < size(); ++i) 00169 (*this)[i] += right[i]; 00170 return *this; 00171 } 00172 00173 row_vector & operator -= (const row_vector & right) 00174 { 00175 assert(size() == right.size()); 00176 for (size_type i = 0; i < size(); ++i) 00177 (*this)[i] -= right[i]; 00178 return *this; 00179 } 00180 00181 row_vector & operator *= (const ValueType scalar) 00182 { 00183 for (size_type i = 0; i < size(); ++i) 00184 (*this)[i] *= scalar; 00185 return *this; 00186 } 00187 00188 void set_zero() 00189 { 00190 for (typename vector_type::iterator it = vector_type::begin(); it != vector_type::end(); ++it) 00191 *it = 0; 00192 } 00193 }; 00194 00195 //! \brief Specialized swappable_block that interprets uninitialized as containing zeros. 00196 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00197 //! \tparam BlockSideLength side length of a matrix block 00198 //! 00199 //! When initializing, all values are set to zero. 00200 template <typename ValueType, unsigned BlockSideLength> 00201 class matrix_swappable_block : public swappable_block<ValueType, BlockSideLength * BlockSideLength> 00202 { 00203 public: 00204 typedef typename swappable_block<ValueType, BlockSideLength * BlockSideLength>::internal_block_type internal_block_type; 00205 00206 using swappable_block<ValueType, BlockSideLength * BlockSideLength>::get_internal_block; 00207 00208 void fill_default() 00209 { 00210 // get_internal_block checks acquired 00211 internal_block_type & data = get_internal_block(); 00212 #if STXXL_PARALLEL 00213 #pragma omp parallel for 00214 #endif 00215 for (int_type row = 0; row < int_type(BlockSideLength); ++row) 00216 for (int_type col = 0; col < int_type(BlockSideLength); ++col) 00217 data[row * BlockSideLength + col] = 0; 00218 } 00219 }; 00220 00221 //! \brief External container for a (sub)matrix. Not intended for direct use. 00222 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00223 //! \tparam BlockSideLength side length of a matrix block 00224 //! 00225 //! Stores blocks only, so all measures (height, width, row, col) are in blocks. 00226 template <typename ValueType, unsigned BlockSideLength> 00227 class swappable_block_matrix : public shared_object 00228 { 00229 public: 00230 typedef int_type size_type; 00231 typedef int_type elem_size_type; 00232 typedef block_scheduler< matrix_swappable_block<ValueType, BlockSideLength> > block_scheduler_type; 00233 typedef typename block_scheduler_type::swappable_block_identifier_type swappable_block_identifier_type; 00234 typedef std::vector<swappable_block_identifier_type> blocks_type; 00235 typedef matrix_operations<ValueType, BlockSideLength> Ops; 00236 00237 block_scheduler_type & bs; 00238 00239 private: 00240 // assigning is not allowed 00241 swappable_block_matrix & operator = (const swappable_block_matrix & other); 00242 00243 protected: 00244 //! \brief height of the matrix in blocks 00245 size_type height, 00246 //! \brief width of the matrix in blocks 00247 width, 00248 //! \brief height copied from supermatrix in blocks 00249 height_from_supermatrix, 00250 //! \brief width copied from supermatrix in blocks 00251 width_from_supermatrix; 00252 //! \brief the matrice's blocks in row-major 00253 blocks_type blocks; 00254 //! \brief if the elements in each block are in col-major instead of row-major 00255 bool elements_in_blocks_transposed; 00256 //! \brief get identifier of the block at (row, col) 00257 swappable_block_identifier_type & bl(const size_type row, const size_type col) 00258 { return blocks[row * width + col]; } 00259 00260 public: 00261 //! \brief Create an empty swappable_block_matrix of given dimensions. 00262 swappable_block_matrix(block_scheduler_type & bs, const size_type height_in_blocks, const size_type width_in_blocks, const bool transposed = false) 00263 : bs(bs), 00264 height(height_in_blocks), 00265 width(width_in_blocks), 00266 height_from_supermatrix(0), 00267 width_from_supermatrix(0), 00268 blocks(height * width), 00269 elements_in_blocks_transposed(transposed) 00270 { 00271 for (size_type row = 0; row < height; ++row) 00272 for (size_type col = 0; col < width; ++col) 00273 bl(row, col) = bs.allocate_swappable_block(); 00274 } 00275 00276 //! \brief Create swappable_block_matrix of given dimensions that 00277 //! represents the submatrix of supermatrix starting at (from_row_in_blocks, from_col_in_blocks). 00278 //! 00279 //! If supermatrix is not large enough, the submatrix is padded with empty blocks. 00280 //! The supermatrix must not be destructed or transposed before the submatrix is destructed. 00281 swappable_block_matrix(const swappable_block_matrix & supermatrix, 00282 const size_type height_in_blocks, const size_type width_in_blocks, 00283 const size_type from_row_in_blocks, const size_type from_col_in_blocks) 00284 : bs(supermatrix.bs), 00285 height(height_in_blocks), 00286 width(width_in_blocks), 00287 height_from_supermatrix(std::min(supermatrix.height - from_row_in_blocks, height)), 00288 width_from_supermatrix(std::min(supermatrix.width - from_col_in_blocks, width)), 00289 blocks(height * width), 00290 elements_in_blocks_transposed(supermatrix.elements_in_blocks_transposed) 00291 { 00292 for (size_type row = 0; row < height_from_supermatrix; ++row) 00293 { 00294 for (size_type col = 0; col < width_from_supermatrix; ++col) 00295 bl(row, col) = supermatrix.block(row + from_row_in_blocks, col + from_col_in_blocks); 00296 for (size_type col = width_from_supermatrix; col < width; ++col) 00297 bl(row, col) = bs.allocate_swappable_block(); 00298 } 00299 for (size_type row = height_from_supermatrix; row < height; ++row) 00300 for (size_type col = 0; col < width; ++col) 00301 bl(row, col) = bs.allocate_swappable_block(); 00302 } 00303 00304 //! \brief Create swappable_block_matrix that represents the combination matrix ul ur 00305 //! dl dr 00306 //! 00307 //! The submatrices are assumed to be of fitting dimensions and equal transposition. 00308 //! The submatrices must not be destructed or transposed before the matrix is destructed. 00309 swappable_block_matrix(const swappable_block_matrix & ul, const swappable_block_matrix & ur, 00310 const swappable_block_matrix & dl, const swappable_block_matrix & dr) 00311 : bs(ul.bs), 00312 height(ul.height + dl.height), 00313 width(ul.width + ur.width), 00314 height_from_supermatrix(height), 00315 width_from_supermatrix(width), 00316 blocks(height * width), 00317 elements_in_blocks_transposed(ul.elements_in_blocks_transposed) 00318 { 00319 for (size_type row = 0; row < ul.height; ++row) 00320 { 00321 for (size_type col = 0; col < ul.width; ++col) 00322 bl(row, col) = ul.block(row, col); 00323 for (size_type col = ul.width; col < width; ++col) 00324 bl(row, col) = ur.block(row, col - ul.width); 00325 } 00326 for (size_type row = ul.height; row < height; ++row) 00327 { 00328 for (size_type col = 0; col < ul.width; ++col) 00329 bl(row, col) = dl.block(row - ul.height, col); 00330 for (size_type col = ul.width; col < width; ++col) 00331 bl(row, col) = dr.block(row - ul.height, col - ul.width); 00332 } 00333 } 00334 00335 swappable_block_matrix(const swappable_block_matrix & other) 00336 : shared_object(other), 00337 bs(other.bs), 00338 height(other.height), 00339 width(other.width), 00340 height_from_supermatrix(0), 00341 width_from_supermatrix(0), 00342 blocks(height * width), 00343 elements_in_blocks_transposed(false) 00344 { 00345 for (size_type row = 0; row < height; ++row) 00346 for (size_type col = 0; col < width; ++col) 00347 bl(row, col) = bs.allocate_swappable_block(); 00348 // 0 + other is copying 00349 Ops::element_op(*this, other, typename Ops::addition()); 00350 } 00351 00352 ~swappable_block_matrix() 00353 { 00354 for (size_type row = 0; row < height_from_supermatrix; ++row) 00355 { 00356 for (size_type col = width_from_supermatrix; col < width; ++col) 00357 bs.free_swappable_block(bl(row, col)); 00358 } 00359 for (size_type row = height_from_supermatrix; row < height; ++row) 00360 for (size_type col = 0; col < width; ++col) 00361 bs.free_swappable_block(bl(row, col)); 00362 } 00363 00364 static size_type block_index_from_elem(elem_size_type index) 00365 { return index / BlockSideLength; } 00366 00367 static int_type elem_index_in_block_from_elem(elem_size_type index) 00368 { return index % BlockSideLength; } 00369 00370 // regards transposed 00371 int_type elem_index_in_block_from_elem(elem_size_type row, elem_size_type col) const 00372 { 00373 return (is_transposed()) 00374 ? row % BlockSideLength + col % BlockSideLength * BlockSideLength 00375 : row % BlockSideLength * BlockSideLength + col % BlockSideLength; 00376 } 00377 00378 swappable_block_identifier_type block(const size_type row, const size_type col) const 00379 { return blocks[row * width + col]; } 00380 00381 swappable_block_identifier_type operator () (const size_type row, const size_type col) const 00382 { return block(row, col); } 00383 00384 const size_type & get_height() const 00385 { return height; } 00386 00387 const size_type & get_width() const 00388 { return width; } 00389 00390 //! \brief if the elements inside the blocks are in transposed order i.e. column-major 00391 const bool & is_transposed() const 00392 { return elements_in_blocks_transposed; } 00393 00394 void transpose() 00395 { 00396 // transpose matrix of blocks 00397 blocks_type bl(blocks.size()); 00398 for (size_type row = 1; row < height; ++row) 00399 for (size_type col = 0; col < row; ++col) 00400 bl[col * height + row] = bl(row,col); 00401 bl.swap(blocks); 00402 // swap dimensions 00403 std::swap(height, width); 00404 std::swap(height_from_supermatrix, width_from_supermatrix); 00405 elements_in_blocks_transposed = ! elements_in_blocks_transposed; 00406 } 00407 00408 void set_zero() 00409 { 00410 for (typename blocks_type::iterator it = blocks.begin(); it != blocks.end(); ++it) 00411 bs.deinitialize(*it); 00412 } 00413 }; 00414 00415 //! \brief general iterator type that points to single elements inside a matrix 00416 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00417 //! \tparam BlockSideLength side length of a matrix block 00418 template <typename ValueType, unsigned BlockSideLength> 00419 class matrix_iterator 00420 { 00421 protected: 00422 typedef matrix<ValueType, BlockSideLength> matrix_type; 00423 typedef typename matrix_type::swappable_block_matrix_type swappable_block_matrix_type; 00424 typedef typename matrix_type::block_scheduler_type block_scheduler_type; 00425 typedef typename block_scheduler_type::internal_block_type internal_block_type; 00426 typedef typename matrix_type::elem_size_type elem_size_type; 00427 typedef typename matrix_type::block_size_type block_size_type; 00428 00429 template <typename VT, unsigned BSL> friend class matrix; 00430 template <typename VT, unsigned BSL> friend class const_matrix_iterator; 00431 00432 matrix_type * m; 00433 elem_size_type current_row, // \ both indices == -1 <=> empty iterator 00434 current_col; // / 00435 block_size_type current_block_row, 00436 current_block_col; 00437 internal_block_type * current_iblock; // NULL if block is not acquired 00438 00439 void acquire_current_iblock() 00440 { 00441 if (! current_iblock) 00442 current_iblock = & m->data->bs.acquire(m->data->block(current_block_row, current_block_col)); 00443 } 00444 00445 void release_current_iblock() 00446 { 00447 if (current_iblock) 00448 { 00449 m->data->bs.release(m->data->block(current_block_row, current_block_col), true); 00450 current_iblock = 0; 00451 } 00452 } 00453 00454 //! \brief create iterator pointing to given row and col 00455 matrix_iterator(matrix_type & matrix, const elem_size_type start_row, const elem_size_type start_col) 00456 : m(&matrix), 00457 current_row(start_row), 00458 current_col(start_col), 00459 current_block_row(m->data->block_index_from_elem(start_row)), 00460 current_block_col(m->data->block_index_from_elem(start_col)), 00461 current_iblock(0) {} 00462 00463 //! \brief create empty iterator 00464 matrix_iterator(matrix_type & matrix) 00465 : m(&matrix), 00466 current_row(-1), // empty iterator 00467 current_col(-1), 00468 current_block_row(-1), 00469 current_block_col(-1), 00470 current_iblock(0) {} 00471 00472 void set_empty() 00473 { 00474 release_current_iblock(); 00475 current_row = -1; 00476 current_col = -1; 00477 current_block_row = -1; 00478 current_block_col = -1; 00479 } 00480 00481 public: 00482 matrix_iterator(const matrix_iterator & other) 00483 : m(other.m), 00484 current_row(other.current_row), 00485 current_col(other.current_col), 00486 current_block_row(other.current_block_row), 00487 current_block_col(other.current_block_col), 00488 current_iblock(0) 00489 { 00490 if (other.current_iblock) 00491 acquire_current_iblock(); 00492 } 00493 00494 matrix_iterator & operator = (const matrix_iterator & other) 00495 { 00496 set_pos(other.current_row, other.current_col); 00497 m = other.m; 00498 if (other.current_iblock) 00499 acquire_current_iblock(); 00500 return *this; 00501 } 00502 00503 ~matrix_iterator() 00504 { release_current_iblock(); } 00505 00506 void set_row(const elem_size_type new_row) 00507 { 00508 const block_size_type new_block_row = m->data->block_index_from_elem(new_row); 00509 if (new_block_row != current_block_row) 00510 { 00511 release_current_iblock(); 00512 current_block_row = new_block_row; 00513 } 00514 current_row = new_row; 00515 } 00516 00517 void set_col(const elem_size_type new_col) 00518 { 00519 const block_size_type new_block_col = m->data->block_index_from_elem(new_col); 00520 if (new_block_col != current_block_col) 00521 { 00522 release_current_iblock(); 00523 current_block_col = new_block_col; 00524 } 00525 current_col = new_col; 00526 } 00527 00528 void set_pos(const elem_size_type new_row, const elem_size_type new_col) 00529 { 00530 const block_size_type new_block_row = m->data->block_index_from_elem(new_row), 00531 new_block_col = m->data->block_index_from_elem(new_col); 00532 if (new_block_col != current_block_col || new_block_row != current_block_row) 00533 { 00534 release_current_iblock(); 00535 current_block_row = new_block_row; 00536 current_block_col = new_block_col; 00537 } 00538 current_row = new_row; 00539 current_col = new_col; 00540 } 00541 00542 void set_pos(const std::pair<elem_size_type, elem_size_type> new_pos) 00543 { set_pos(new_pos.first, new_pos.second); } 00544 00545 const elem_size_type & get_row() const 00546 { return current_row; } 00547 00548 const elem_size_type & get_col() const 00549 { return current_col; } 00550 00551 std::pair<elem_size_type, elem_size_type> get_pos() const 00552 { return std::make_pair(current_row, current_col); } 00553 00554 bool empty() const 00555 { return current_row == -1 && current_col == -1; } 00556 00557 operator bool () const 00558 { return ! empty(); } 00559 00560 bool operator == (const matrix_iterator & other) const 00561 { 00562 return current_row == other.current_row && current_col == other.current_col && m == other.m; 00563 } 00564 00565 //! \brief Returns reference access to the element referenced by the iterator. 00566 //! The reference is only valid so long as the iterator is not moved. 00567 ValueType & operator * () 00568 { 00569 acquire_current_iblock(); 00570 return (*current_iblock)[m->data->elem_index_in_block_from_elem(current_row, current_col)]; 00571 } 00572 }; 00573 00574 //! \brief row-major iterator that points to single elements inside a matrix 00575 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00576 //! \tparam BlockSideLength side length of a matrix block 00577 template <typename ValueType, unsigned BlockSideLength> 00578 class matrix_row_major_iterator : public matrix_iterator<ValueType, BlockSideLength> 00579 { 00580 protected: 00581 typedef matrix_iterator<ValueType, BlockSideLength> matrix_iterator_type; 00582 typedef typename matrix_iterator_type::matrix_type matrix_type; 00583 typedef typename matrix_iterator_type::elem_size_type elem_size_type; 00584 00585 template <typename VT, unsigned BSL> friend class matrix; 00586 00587 using matrix_iterator_type::m; 00588 using matrix_iterator_type::set_empty; 00589 00590 //! \brief create iterator pointing to given row and col 00591 matrix_row_major_iterator(matrix_type & matrix, const elem_size_type start_row, const elem_size_type start_col) 00592 : matrix_iterator_type(matrix, start_row, start_col) {} 00593 00594 //! \brief create empty iterator 00595 matrix_row_major_iterator(matrix_type & matrix) 00596 : matrix_iterator_type(matrix) {} 00597 00598 public: 00599 //! \brief convert from matrix_iterator 00600 matrix_row_major_iterator(const matrix_iterator_type & matrix_iterator) 00601 : matrix_iterator_type(matrix_iterator) {} 00602 00603 // Has to be not empty, else behavior is undefined. 00604 matrix_row_major_iterator & operator ++ () 00605 { 00606 if (get_col() + 1 < m->get_width()) 00607 // => not matrix_row_major_iterator the end of row, move right 00608 set_col(get_col() + 1); 00609 else if (get_row() + 1 < m->get_height()) 00610 // => at end of row but not last row, move to beginning of next row 00611 set_pos(get_row() + 1, 0); 00612 else 00613 // => at end of matrix, set to empty-state 00614 set_empty(); 00615 return *this; 00616 } 00617 00618 // Has to be not empty, else behavior is undefined. 00619 matrix_row_major_iterator & operator -- () 00620 { 00621 if (get_col() - 1 >= 0) 00622 // => not at the beginning of row, move left 00623 set_col(get_col() - 1); 00624 else if (get_row() - 1 >= 0) 00625 // => at beginning of row but not first row, move to end of previous row 00626 set_pos(get_row() - 1, m.get_width() - 1); 00627 else 00628 // => at beginning of matrix, set to empty-state 00629 set_empty(); 00630 return *this; 00631 } 00632 00633 using matrix_iterator_type::get_row; 00634 using matrix_iterator_type::get_col; 00635 using matrix_iterator_type::set_col; 00636 using matrix_iterator_type::set_pos; 00637 }; 00638 00639 //! \brief column-major iterator that points to single elements inside a matrix 00640 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00641 //! \tparam BlockSideLength side length of a matrix block 00642 template <typename ValueType, unsigned BlockSideLength> 00643 class matrix_col_major_iterator : public matrix_iterator<ValueType, BlockSideLength> 00644 { 00645 protected: 00646 typedef matrix_iterator<ValueType, BlockSideLength> matrix_iterator_type; 00647 typedef typename matrix_iterator_type::matrix_type matrix_type; 00648 typedef typename matrix_iterator_type::elem_size_type elem_size_type; 00649 00650 template <typename VT, unsigned BSL> friend class matrix; 00651 00652 using matrix_iterator_type::m; 00653 using matrix_iterator_type::set_empty; 00654 00655 //! \brief create iterator pointing to given row and col 00656 matrix_col_major_iterator(matrix_type & matrix, const elem_size_type start_row, const elem_size_type start_col) 00657 : matrix_iterator_type(matrix, start_row, start_col) {} 00658 00659 //! \brief create empty iterator 00660 matrix_col_major_iterator(matrix_type & matrix) 00661 : matrix_iterator_type(matrix) {} 00662 00663 public: 00664 //! \brief convert from matrix_iterator 00665 matrix_col_major_iterator(const matrix_iterator_type & matrix_iterator) 00666 : matrix_iterator_type(matrix_iterator) {} 00667 00668 // Has to be not empty, else behavior is undefined. 00669 matrix_col_major_iterator & operator ++ () 00670 { 00671 if (get_row() + 1 < m->get_height()) 00672 // => not at the end of col, move down 00673 set_row(get_row() + 1); 00674 else if (get_col() + 1 < m->get_width()) 00675 // => at end of col but not last col, move to beginning of next col 00676 set_pos(0, get_col() + 1); 00677 else 00678 // => at end of matrix, set to empty-state 00679 set_empty(); 00680 return *this; 00681 } 00682 00683 // Has to be not empty, else behavior is undefined. 00684 matrix_col_major_iterator & operator -- () 00685 { 00686 if (get_row() - 1 >= 0) 00687 // => not at the beginning of col, move up 00688 set_row(get_row() - 1); 00689 else if (get_col() - 1 >= 0) 00690 // => at beginning of col but not first col, move to end of previous col 00691 set_pos(m->get_height() - 1, get_col() - 1); 00692 else 00693 // => at beginning of matrix, set to empty-state 00694 set_empty(); 00695 return *this; 00696 } 00697 00698 using matrix_iterator_type::get_row; 00699 using matrix_iterator_type::get_col; 00700 using matrix_iterator_type::set_row; 00701 using matrix_iterator_type::set_pos; 00702 }; 00703 00704 //! \brief general const_iterator type that points to single elements inside a matrix 00705 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00706 //! \tparam BlockSideLength side length of a matrix block 00707 template <typename ValueType, unsigned BlockSideLength> 00708 class const_matrix_iterator 00709 { 00710 protected: 00711 typedef matrix<ValueType, BlockSideLength> matrix_type; 00712 typedef typename matrix_type::swappable_block_matrix_type swappable_block_matrix_type; 00713 typedef typename matrix_type::block_scheduler_type block_scheduler_type; 00714 typedef typename block_scheduler_type::internal_block_type internal_block_type; 00715 typedef typename matrix_type::elem_size_type elem_size_type; 00716 typedef typename matrix_type::block_size_type block_size_type; 00717 00718 template <typename VT, unsigned BSL> friend class matrix; 00719 00720 const matrix_type * m; 00721 elem_size_type current_row, // \ both indices == -1 <=> empty iterator 00722 current_col; // / 00723 block_size_type current_block_row, 00724 current_block_col; 00725 internal_block_type * current_iblock; // NULL if block is not acquired 00726 00727 void acquire_current_iblock() 00728 { 00729 if (! current_iblock) 00730 current_iblock = & m->data->bs.acquire(m->data->block(current_block_row, current_block_col)); 00731 } 00732 00733 void release_current_iblock() 00734 { 00735 if (current_iblock) 00736 { 00737 m->data->bs.release(m->data->block(current_block_row, current_block_col), false); 00738 current_iblock = 0; 00739 } 00740 } 00741 00742 //! \brief create iterator pointing to given row and col 00743 const_matrix_iterator(const matrix_type & matrix, const elem_size_type start_row, const elem_size_type start_col) 00744 : m(&matrix), 00745 current_row(start_row), 00746 current_col(start_col), 00747 current_block_row(m->data->block_index_from_elem(start_row)), 00748 current_block_col(m->data->block_index_from_elem(start_col)), 00749 current_iblock(0) {} 00750 00751 //! \brief create empty iterator 00752 const_matrix_iterator(const matrix_type & matrix) 00753 : m(&matrix), 00754 current_row(-1), // empty iterator 00755 current_col(-1), 00756 current_block_row(-1), 00757 current_block_col(-1), 00758 current_iblock(0) {} 00759 00760 void set_empty() 00761 { 00762 release_current_iblock(); 00763 current_row = -1; 00764 current_col = -1; 00765 current_block_row = -1; 00766 current_block_col = -1; 00767 } 00768 public: 00769 const_matrix_iterator(const matrix_iterator<ValueType, BlockSideLength> & other) 00770 : m(other.m), 00771 current_row(other.current_row), 00772 current_col(other.current_col), 00773 current_block_row(other.current_block_row), 00774 current_block_col(other.current_block_col), 00775 current_iblock(0) 00776 { 00777 if (other.current_iblock) 00778 acquire_current_iblock(); 00779 } 00780 00781 const_matrix_iterator(const const_matrix_iterator & other) 00782 : m(other.m), 00783 current_row(other.current_row), 00784 current_col(other.current_col), 00785 current_block_row(other.current_block_row), 00786 current_block_col(other.current_block_col), 00787 current_iblock(0) 00788 { 00789 if (other.current_iblock) 00790 acquire_current_iblock(); 00791 } 00792 00793 const_matrix_iterator & operator = (const const_matrix_iterator & other) 00794 { 00795 set_pos(other.current_row, other.current_col); 00796 m = other.m; 00797 if (other.current_iblock) 00798 acquire_current_iblock(); 00799 return *this; 00800 } 00801 00802 ~const_matrix_iterator() 00803 { release_current_iblock(); } 00804 00805 void set_row(const elem_size_type new_row) 00806 { 00807 const block_size_type new_block_row = m->data->block_index_from_elem(new_row); 00808 if (new_block_row != current_block_row) 00809 { 00810 release_current_iblock(); 00811 current_block_row = new_block_row; 00812 } 00813 current_row = new_row; 00814 } 00815 00816 void set_col(const elem_size_type new_col) 00817 { 00818 const block_size_type new_block_col = m->data->block_index_from_elem(new_col); 00819 if (new_block_col != current_block_col) 00820 { 00821 release_current_iblock(); 00822 current_block_col = new_block_col; 00823 } 00824 current_col = new_col; 00825 } 00826 00827 void set_pos(const elem_size_type new_row, const elem_size_type new_col) 00828 { 00829 const block_size_type new_block_row = m->data->block_index_from_elem(new_row), 00830 new_block_col = m->data->block_index_from_elem(new_col); 00831 if (new_block_col != current_block_col || new_block_row != current_block_row) 00832 { 00833 release_current_iblock(); 00834 current_block_row = new_block_row; 00835 current_block_col = new_block_col; 00836 } 00837 current_row = new_row; 00838 current_col = new_col; 00839 } 00840 00841 void set_pos(const std::pair<elem_size_type, elem_size_type> new_pos) 00842 { set_pos(new_pos.first, new_pos.second); } 00843 00844 const elem_size_type & get_row() const 00845 { return current_row; } 00846 00847 const elem_size_type & get_col() const 00848 { return current_col; } 00849 00850 std::pair<elem_size_type, elem_size_type> get_pos() const 00851 { return std::make_pair(current_row, current_col); } 00852 00853 bool empty() const 00854 { return current_row == -1 && current_col == -1; } 00855 00856 operator bool () const 00857 { return ! empty(); } 00858 00859 bool operator == (const const_matrix_iterator & other) const 00860 { 00861 return current_row == other.current_row && current_col == other.current_col && m == other.m; 00862 } 00863 00864 //! \brief Returns reference access to the element referenced by the iterator. 00865 //! The reference is only valid so long as the iterator is not moved. 00866 const ValueType & operator * () 00867 { 00868 acquire_current_iblock(); 00869 return (*current_iblock)[m->data->elem_index_in_block_from_elem(current_row, current_col)]; 00870 } 00871 }; 00872 00873 //! \brief row-major const_iterator that points to single elements inside a matrix 00874 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00875 //! \tparam BlockSideLength side length of a matrix block 00876 template <typename ValueType, unsigned BlockSideLength> 00877 class const_matrix_row_major_iterator : public const_matrix_iterator<ValueType, BlockSideLength> 00878 { 00879 protected: 00880 typedef const_matrix_iterator<ValueType, BlockSideLength> const_matrix_iterator_type; 00881 typedef typename const_matrix_iterator_type::matrix_type matrix_type; 00882 typedef typename const_matrix_iterator_type::elem_size_type elem_size_type; 00883 00884 template <typename VT, unsigned BSL> friend class matrix; 00885 00886 using const_matrix_iterator_type::m; 00887 using const_matrix_iterator_type::set_empty; 00888 00889 //! \brief create iterator pointing to given row and col 00890 const_matrix_row_major_iterator(const matrix_type & matrix, const elem_size_type start_row, const elem_size_type start_col) 00891 : const_matrix_iterator_type(matrix, start_row, start_col) {} 00892 00893 //! \brief create empty iterator 00894 const_matrix_row_major_iterator(const matrix_type & matrix) 00895 : const_matrix_iterator_type(matrix) {} 00896 00897 public: 00898 //! \brief convert from matrix_iterator 00899 const_matrix_row_major_iterator(const const_matrix_row_major_iterator & matrix_iterator) 00900 : const_matrix_iterator_type(matrix_iterator) {} 00901 00902 //! \brief convert from matrix_iterator 00903 const_matrix_row_major_iterator(const const_matrix_iterator_type & matrix_iterator) 00904 : const_matrix_iterator_type(matrix_iterator) {} 00905 00906 // Has to be not empty, else behavior is undefined. 00907 const_matrix_row_major_iterator & operator ++ () 00908 { 00909 if (get_col() + 1 < m->get_width()) 00910 // => not matrix_row_major_iterator the end of row, move right 00911 set_col(get_col() + 1); 00912 else if (get_row() + 1 < m->get_height()) 00913 // => at end of row but not last row, move to beginning of next row 00914 set_pos(get_row() + 1, 0); 00915 else 00916 // => at end of matrix, set to empty-state 00917 set_empty(); 00918 return *this; 00919 } 00920 00921 // Has to be not empty, else behavior is undefined. 00922 const_matrix_row_major_iterator & operator -- () 00923 { 00924 if (get_col() - 1 >= 0) 00925 // => not at the beginning of row, move left 00926 set_col(get_col() - 1); 00927 else if (get_row() - 1 >= 0) 00928 // => at beginning of row but not first row, move to end of previous row 00929 set_pos(get_row() - 1, m.get_width() - 1); 00930 else 00931 // => at beginning of matrix, set to empty-state 00932 set_empty(); 00933 return *this; 00934 } 00935 00936 using const_matrix_iterator_type::get_row; 00937 using const_matrix_iterator_type::get_col; 00938 using const_matrix_iterator_type::set_col; 00939 using const_matrix_iterator_type::set_pos; 00940 }; 00941 00942 //! \brief column-major const_iterator that points to single elements inside a matrix 00943 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 00944 //! \tparam BlockSideLength side length of a matrix block 00945 template <typename ValueType, unsigned BlockSideLength> 00946 class const_matrix_col_major_iterator : public const_matrix_iterator<ValueType, BlockSideLength> 00947 { 00948 protected: 00949 typedef const_matrix_iterator<ValueType, BlockSideLength> const_matrix_iterator_type; 00950 typedef typename const_matrix_iterator_type::matrix_type matrix_type; 00951 typedef typename const_matrix_iterator_type::elem_size_type elem_size_type; 00952 00953 template <typename VT, unsigned BSL> friend class matrix; 00954 00955 using const_matrix_iterator_type::m; 00956 using const_matrix_iterator_type::set_empty; 00957 00958 //! \brief create iterator pointing to given row and col 00959 const_matrix_col_major_iterator(const matrix_type & matrix, const elem_size_type start_row, const elem_size_type start_col) 00960 : const_matrix_iterator_type(matrix, start_row, start_col) {} 00961 00962 //! \brief create empty iterator 00963 const_matrix_col_major_iterator(const matrix_type & matrix) 00964 : const_matrix_iterator_type(matrix) {} 00965 00966 public: 00967 //! \brief convert from matrix_iterator 00968 const_matrix_col_major_iterator(const matrix_iterator<ValueType, BlockSideLength> & matrix_iterator) 00969 : const_matrix_iterator_type(matrix_iterator) {} 00970 00971 //! \brief convert from matrix_iterator 00972 const_matrix_col_major_iterator(const const_matrix_iterator_type & matrix_iterator) 00973 : const_matrix_iterator_type(matrix_iterator) {} 00974 00975 // Has to be not empty, else behavior is undefined. 00976 const_matrix_col_major_iterator & operator ++ () 00977 { 00978 if (get_row() + 1 < m->get_height()) 00979 // => not at the end of col, move down 00980 set_row(get_row() + 1); 00981 else if (get_col() + 1 < m->get_width()) 00982 // => at end of col but not last col, move to beginning of next col 00983 set_pos(0, get_col() + 1); 00984 else 00985 // => at end of matrix, set to empty-state 00986 set_empty(); 00987 return *this; 00988 } 00989 00990 // Has to be not empty, else behavior is undefined. 00991 const_matrix_col_major_iterator & operator -- () 00992 { 00993 if (get_row() - 1 >= 0) 00994 // => not at the beginning of col, move up 00995 set_row(get_row() - 1); 00996 else if (get_col() - 1 >= 0) 00997 // => at beginning of col but not first col, move to end of previous col 00998 set_pos(m->get_height() - 1, get_col() - 1); 00999 else 01000 // => at beginning of matrix, set to empty-state 01001 set_empty(); 01002 return *this; 01003 } 01004 01005 using const_matrix_iterator_type::get_row; 01006 using const_matrix_iterator_type::get_col; 01007 using const_matrix_iterator_type::set_row; 01008 using const_matrix_iterator_type::set_pos; 01009 }; 01010 01011 //! \brief External matrix container. 01012 //! \tparam ValueType type of contained objects (POD with no references to internal memory) 01013 //! \tparam BlockSideLength side length of a matrix block 01014 //! 01015 //! Divides the matrix in square submatrices (blocks). 01016 //! Blocks can be swapped individually to and from external memory. 01017 //! They are only swapped if necessary to minimize I/O. 01018 template <typename ValueType, unsigned BlockSideLength> 01019 class matrix 01020 { 01021 protected: 01022 typedef matrix<ValueType, BlockSideLength> matrix_type; 01023 typedef swappable_block_matrix<ValueType, BlockSideLength> swappable_block_matrix_type; 01024 typedef shared_object_pointer<swappable_block_matrix_type> swappable_block_matrix_pointer_type; 01025 typedef typename swappable_block_matrix_type::block_scheduler_type block_scheduler_type; 01026 typedef typename swappable_block_matrix_type::size_type block_size_type; 01027 typedef typename swappable_block_matrix_type::elem_size_type elem_size_type; 01028 typedef matrix_operations<ValueType, BlockSideLength> Ops; 01029 typedef matrix_swappable_block<ValueType, BlockSideLength> swappable_block_type; 01030 01031 public: 01032 typedef matrix_iterator<ValueType, BlockSideLength> iterator; 01033 typedef const_matrix_iterator<ValueType, BlockSideLength> const_iterator; 01034 typedef matrix_row_major_iterator<ValueType, BlockSideLength> row_major_iterator; 01035 typedef matrix_col_major_iterator<ValueType, BlockSideLength> col_major_iterator; 01036 typedef const_matrix_row_major_iterator<ValueType, BlockSideLength> const_row_major_iterator; 01037 typedef const_matrix_col_major_iterator<ValueType, BlockSideLength> const_col_major_iterator; 01038 typedef column_vector<ValueType> column_vector_type; 01039 typedef row_vector<ValueType> row_vector_type; 01040 01041 protected: 01042 template <typename VT, unsigned BSL> friend class matrix_iterator; 01043 template <typename VT, unsigned BSL> friend class const_matrix_iterator; 01044 01045 elem_size_type height, 01046 width; 01047 swappable_block_matrix_pointer_type data; 01048 01049 public: 01050 //! \brief Creates a new matrix of given dimensions. Elements' values are set to zero. 01051 //! \param height height of the created matrix 01052 //! \param width width of the created matrix 01053 matrix(block_scheduler_type & bs, const elem_size_type height, const elem_size_type width) 01054 : height(height), 01055 width(width), 01056 data(new swappable_block_matrix_type 01057 (bs, div_ceil(height, BlockSideLength), div_ceil(width, BlockSideLength))) 01058 {} 01059 01060 matrix(block_scheduler_type & bs, const column_vector_type & left, const row_vector_type & right) 01061 : height(left.size()), 01062 width(right.size()), 01063 data(new swappable_block_matrix_type 01064 (bs, div_ceil(height, BlockSideLength), div_ceil(width, BlockSideLength))) 01065 { Ops::recursive_matrix_from_vectors(*data, left, right); } 01066 01067 ~matrix() {} 01068 01069 const elem_size_type & get_height() const 01070 { return height; } 01071 01072 const elem_size_type & get_width() const 01073 { return width; } 01074 01075 iterator begin() 01076 { 01077 data.unify(); 01078 return iterator(*this, 0, 0); 01079 } 01080 const_iterator begin() const 01081 { return const_iterator(*this, 0, 0); } 01082 const_iterator cbegin() const 01083 { return const_iterator(*this, 0, 0); } 01084 01085 iterator end() 01086 { 01087 data.unify(); 01088 return iterator(*this); 01089 } 01090 const_iterator end() const 01091 { return const_iterator(*this); } 01092 const_iterator cend() const 01093 { return const_iterator(*this); } 01094 01095 const_iterator operator () (const elem_size_type row, const elem_size_type col) const 01096 { return const_iterator(*this, row, col); } 01097 01098 iterator operator () (const elem_size_type row, const elem_size_type col) 01099 { 01100 data.unify(); 01101 return iterator(*this, row, col); 01102 } 01103 01104 void transpose() 01105 { 01106 data.unify(); 01107 data->transpose(); 01108 std::swap(height, width); 01109 } 01110 01111 void set_zero() 01112 { 01113 if (data.unique()) 01114 data->set_zero(); 01115 else 01116 data = new swappable_block_matrix_type 01117 (data->bs, div_ceil(height, BlockSideLength), div_ceil(width, BlockSideLength)); 01118 } 01119 01120 matrix_type operator + (const matrix_type & right) const 01121 { 01122 assert(height == right.height && width == right.width); 01123 matrix_type res(data->bs, height, width); 01124 Ops::element_op(*res.data, *data, *right.data, typename Ops::addition()); // more efficient than copying this and then adding right 01125 return res; 01126 } 01127 01128 matrix_type operator - (const matrix_type & right) const 01129 { 01130 assert(height == right.height && width == right.width); 01131 matrix_type res(data->bs, height, width); 01132 Ops::element_op(*res.data, *data, *right.data, typename Ops::subtraction()); // more efficient than copying this and then subtracting right 01133 return res; 01134 } 01135 01136 matrix_type operator * (const matrix_type & right) const 01137 { return multiply(right); } 01138 01139 matrix_type operator * (const ValueType scalar) const 01140 { 01141 matrix_type res(data->bs, height, width); 01142 Ops::element_op(*res.data, *data, typename Ops::scalar_multiplication(scalar)); 01143 return res; 01144 } 01145 01146 matrix_type & operator += (const matrix_type & right) 01147 { 01148 assert(height == right.height && width == right.width); 01149 data.unify(); 01150 Ops::element_op(*data, *right.data, typename Ops::addition()); 01151 return *this; 01152 } 01153 01154 matrix_type & operator -= (const matrix_type & right) 01155 { 01156 assert(height == right.height && width == right.width); 01157 data.unify(); 01158 Ops::element_op(*data, *right.data, typename Ops::subtraction()); 01159 return *this; 01160 } 01161 01162 matrix_type & operator *= (const matrix_type & right) 01163 { return *this = operator * (right); } // implicitly unifies by constructing a result-matrix 01164 01165 matrix_type & operator *= (const ValueType scalar) 01166 { 01167 data.unify(); 01168 Ops::element_op(*data, typename Ops::scalar_multiplication(scalar)); 01169 return *this; 01170 } 01171 01172 column_vector_type operator * (const column_vector_type & right) const 01173 { 01174 assert(elem_size_type(right.size()) == width); 01175 column_vector_type res(height); 01176 res.set_zero(); 01177 Ops::recursive_matrix_col_vector_multiply_and_add(*data, right, res); 01178 return res; 01179 } 01180 01181 row_vector_type multiply_from_left(const row_vector_type & left) const 01182 { 01183 assert(elem_size_type(left.size()) == height); 01184 row_vector_type res(width); 01185 res.set_zero(); 01186 Ops::recursive_matrix_row_vector_multiply_and_add(left, *data, res); 01187 return res; 01188 } 01189 01190 //! \brief multiply with another matrix 01191 //! \param multiplication_algorithm allows to choose the applied algorithm 01192 //! \param scheduling_algorithm allows to choose the applied algorithm 01193 //! 01194 //! Available algorithms are: \n 01195 //! 0: naive_multiply_and_add (I/O inefficient, slow) \n 01196 //! 1: recursive_multiply_and_add (recommended, default, stable time and I/O complexity) \n 01197 //! 2: strassen_winograd_multiply_and_add (sometimes fast but unstable time and I/O complexity) \n 01198 //! 3: multi_level_strassen_winograd_multiply_and_add (sometimes fast but unstable time and I/O complexity) \n 01199 //! 4: strassen_winograd_multiply, optimized pre- and postadditions (sometimes fast but unstable time and I/O complexity) \n 01200 //! 5: strassen_winograd_multiply_and_add_interleaved, optimized preadditions (sometimes fast but unstable time and I/O complexity) \n 01201 //! 6: multi_level_strassen_winograd_multiply_and_add_block_grained (sometimes fast but unstable time and I/O complexity) 01202 matrix_type multiply (const matrix_type & right, const int_type multiplication_algorithm = 1, const int_type scheduling_algorithm = 2) const 01203 { 01204 assert(width == right.height); 01205 assert(& data->bs == & right.data->bs); 01206 matrix_type res(data->bs, height, right.width); 01207 01208 if (scheduling_algorithm > 0) 01209 { 01210 // all offline algos need a simulation-run 01211 delete data->bs.switch_algorithm_to(new 01212 block_scheduler_algorithm_simulation<swappable_block_type>(data->bs)); 01213 switch (multiplication_algorithm) 01214 { 01215 case 0: 01216 Ops::naive_multiply_and_add(*data, *right.data, *res.data); 01217 break; 01218 case 1: 01219 Ops::recursive_multiply_and_add(*data, *right.data, *res.data); 01220 break; 01221 case 2: 01222 Ops::strassen_winograd_multiply_and_add(*data, *right.data, *res.data); 01223 break; 01224 case 3: 01225 Ops::multi_level_strassen_winograd_multiply_and_add(*data, *right.data, *res.data); 01226 break; 01227 case 4: 01228 Ops::strassen_winograd_multiply(*data, *right.data, *res.data); 01229 break; 01230 case 5: 01231 Ops::strassen_winograd_multiply_and_add_interleaved(*data, *right.data, *res.data); 01232 break; 01233 case 6: 01234 Ops::multi_level_strassen_winograd_multiply_and_add_block_grained(*data, *right.data, *res.data); 01235 break; 01236 default: 01237 STXXL_ERRMSG("invalid multiplication-algorithm number"); 01238 break; 01239 } 01240 } 01241 switch (scheduling_algorithm) 01242 { 01243 case 0: 01244 delete data->bs.switch_algorithm_to(new 01245 block_scheduler_algorithm_online_lru<swappable_block_type>(data->bs)); 01246 break; 01247 case 1: 01248 delete data->bs.switch_algorithm_to(new 01249 block_scheduler_algorithm_offline_lfd<swappable_block_type>(data->bs)); 01250 break; 01251 case 2: 01252 delete data->bs.switch_algorithm_to(new 01253 block_scheduler_algorithm_offline_lru_prefetching<swappable_block_type>(data->bs)); 01254 break; 01255 default: 01256 STXXL_ERRMSG("invalid scheduling-algorithm number"); 01257 } 01258 switch (multiplication_algorithm) 01259 { 01260 case 0: 01261 Ops::naive_multiply_and_add(*data, *right.data, *res.data); 01262 break; 01263 case 1: 01264 Ops::recursive_multiply_and_add(*data, *right.data, *res.data); 01265 break; 01266 case 2: 01267 Ops::strassen_winograd_multiply_and_add(*data, *right.data, *res.data); 01268 break; 01269 case 3: 01270 Ops::multi_level_strassen_winograd_multiply_and_add(*data, *right.data, *res.data); 01271 break; 01272 case 4: 01273 Ops::strassen_winograd_multiply(*data, *right.data, *res.data); 01274 break; 01275 case 5: 01276 Ops::strassen_winograd_multiply_and_add_interleaved(*data, *right.data, *res.data); 01277 break; 01278 case 6: 01279 Ops::multi_level_strassen_winograd_multiply_and_add_block_grained(*data, *right.data, *res.data); 01280 break; 01281 default: 01282 STXXL_ERRMSG("invalid multiplication-algorithm number"); 01283 break; 01284 } 01285 delete data->bs.switch_algorithm_to(new 01286 block_scheduler_algorithm_online_lru<swappable_block_type>(data->bs)); 01287 return res; 01288 } 01289 01290 //! \brief Use internal memory multiplication. Designated for testing. May exceed memory limitations. 01291 matrix_type multiply_internal (const matrix_type & right, const int_type scheduling_algorithm = 2) const 01292 { 01293 assert(width == right.height); 01294 assert(& data->bs == & right.data->bs); 01295 matrix_type res(data->bs, height, right.width); 01296 01297 if (scheduling_algorithm > 0) 01298 { 01299 // all offline algos need a simulation-run 01300 delete data->bs.switch_algorithm_to(new 01301 block_scheduler_algorithm_simulation<swappable_block_type>(data->bs)); 01302 multiply_internal(right, res); 01303 } 01304 switch (scheduling_algorithm) 01305 { 01306 case 0: 01307 delete data->bs.switch_algorithm_to(new 01308 block_scheduler_algorithm_online_lru<swappable_block_type>(data->bs)); 01309 break; 01310 case 1: 01311 delete data->bs.switch_algorithm_to(new 01312 block_scheduler_algorithm_offline_lfd<swappable_block_type>(data->bs)); 01313 break; 01314 case 2: 01315 delete data->bs.switch_algorithm_to(new 01316 block_scheduler_algorithm_offline_lru_prefetching<swappable_block_type>(data->bs)); 01317 break; 01318 default: 01319 STXXL_ERRMSG("invalid scheduling-algorithm number"); 01320 } 01321 multiply_internal(right, res); 01322 delete data->bs.switch_algorithm_to(new 01323 block_scheduler_algorithm_online_lru<swappable_block_type>(data->bs)); 01324 return res; 01325 } 01326 01327 protected: 01328 void multiply_internal(const matrix_type & right, matrix_type & res) const 01329 { 01330 ValueType * A = new ValueType[height * width]; 01331 ValueType * B = new ValueType[right.height * right.width]; 01332 ValueType * C = new ValueType[res.height * res.width]; 01333 ValueType * vit; 01334 vit = A; 01335 for(const_row_major_iterator mit = cbegin(); mit != cend(); ++mit, ++vit) 01336 *vit = *mit; 01337 vit = B; 01338 for(const_row_major_iterator mit = right.cbegin(); mit != right.cend(); ++mit, ++vit) 01339 *vit = *mit; 01340 if (! res.data->bs.is_simulating()) 01341 #if STXXL_BLAS 01342 gemm_wrapper(height, width, res.width, 01343 ValueType(1), false, A, 01344 false, B, 01345 ValueType(0), false, C); 01346 #else 01347 assert(false /* internal multiplication is only available for testing with blas */); 01348 #endif 01349 vit = C; 01350 for(row_major_iterator mit = res.begin(); mit != res.end(); ++mit, ++vit) 01351 *mit = *vit; 01352 delete A; 01353 delete B; 01354 delete C; 01355 } 01356 }; 01357 01358 __STXXL_END_NAMESPACE 01359 01360 #endif /* STXXL_MATRIX_HEADER */ 01361 // vim: et:ts=4:sw=4