Stxxl  1.4.0
include/stxxl/bits/containers/matrix.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines