00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MTL_COMPRESSED2D_INCLUDE
00013 #define MTL_COMPRESSED2D_INCLUDE
00014
00015 #include <algorithm>
00016 #include <vector>
00017 #include <map>
00018 #include <cmath>
00019 #include <boost/tuple/tuple.hpp>
00020 #include <boost/type_traits.hpp>
00021 #include <boost/mpl/if.hpp>
00022
00023 #include <boost/numeric/linear_algebra/identity.hpp>
00024
00025 #include <boost/numeric/mtl/mtl_fwd.hpp>
00026 #include <boost/numeric/mtl/config.hpp>
00027 #include <boost/numeric/mtl/utility/common_include.hpp>
00028 #include <boost/numeric/mtl/utility/maybe.hpp>
00029 #include <boost/numeric/mtl/utility/zipped_sort.hpp>
00030 #include <boost/numeric/mtl/utility/shrink_stl_vector.hpp>
00031 #include <boost/numeric/mtl/detail/base_cursor.hpp>
00032 #include <boost/numeric/mtl/operation/update.hpp>
00033 #include <boost/numeric/mtl/operation/shift_block.hpp>
00034 #include <boost/numeric/mtl/matrix/crtp_base_matrix.hpp>
00035 #include <boost/numeric/mtl/matrix/mat_expr.hpp>
00036 #include <boost/numeric/mtl/matrix/element_matrix.hpp>
00037 #include <boost/numeric/mtl/matrix/element_array.hpp>
00038 #include <boost/numeric/mtl/vector/dense_vector.hpp>
00039 #include <boost/numeric/mtl/operation/compute_factors.hpp>
00040 #include <boost/numeric/mtl/operation/size.hpp>
00041 #include <boost/numeric/mtl/operation/num_rows.hpp>
00042 #include <boost/numeric/mtl/operation/num_cols.hpp>
00043
00044 namespace mtl { namespace matrix {
00045
00046
00047 struct compressed_key
00048 {
00049 typedef std::size_t size_t;
00050 typedef compressed_key self;
00051
00052 template <typename Elt, typename Parameters>
00053 explicit compressed_key(compressed2D<Elt, Parameters> const& matrix, size_t offset) : offset(offset)
00054 {
00055 std::size_t my_major= matrix.indexer.find_major(matrix, offset);
00056 major= my_major;
00057 }
00058
00059 template <typename Elt, typename Parameters>
00060 explicit compressed_key(compressed2D<Elt, Parameters> const& matrix, size_t r, size_t c)
00061 {
00062 offset= matrix.indexer(matrix, r, c);
00063 major= matrix.indexer.major_minor_c(matrix, r, c).first;
00064 }
00065
00066 compressed_key(compressed_key const& other) { offset= other.offset; major= other.major; }
00067
00068 self& operator= (self const& other)
00069 {
00070 offset= other.offset; major= other.major;
00071 return *this;
00072 }
00073
00074 bool operator== (compressed_key const& other) const
00075 {
00076
00077
00078
00079
00080 return offset == other.offset;
00081 }
00082
00083 bool operator!= (compressed_key const& other) const { return !(*this == other); }
00084
00085 size_t major;
00086 size_t offset;
00087 };
00088
00089
00090
00091 template <typename Elt, typename Parameters>
00092 struct compressed_el_cursor
00093 : public compressed_key
00094 {
00095 typedef Elt value_type;
00096 typedef compressed_key base;
00097 typedef compressed_el_cursor self;
00098 typedef std::size_t size_t;
00099
00100 explicit compressed_el_cursor(compressed2D<Elt, Parameters> const& matrix, size_t r, size_t c)
00101 : base(matrix, r, c), matrix(matrix) {}
00102
00103 explicit compressed_el_cursor(compressed2D<Elt, Parameters> const& matrix, size_t offset)
00104 : base(matrix, offset), matrix(matrix) {}
00105
00106 compressed_el_cursor(const compressed_el_cursor<Elt, Parameters>& other)
00107 : base(other), matrix(other.matrix) {}
00108
00109 self& operator= (self const& other) { base::operator=(other); return *this; }
00110
00111 self& operator++ ()
00112 {
00113 ++offset;
00114 MTL_DEBUG_THROW_IF(matrix.starts[major+1] < offset, runtime_error("Inconsistent incrementation!"));
00115 while (major < matrix.starts.size()-1 && matrix.starts[major+1] == offset)
00116 ++major;
00117 return *this;
00118 }
00119
00120 base& operator* () { return *this; }
00121 const base& operator* () const { return *this; }
00122
00123 compressed2D<Elt, Parameters> const& matrix;
00124 };
00125
00126
00127
00128 template <typename Elt, typename Parameters>
00129 struct compressed_minor_cursor
00130 : public compressed_key
00131 {
00132 typedef Elt value_type;
00133 typedef compressed_key base;
00134 typedef compressed_minor_cursor self;
00135 typedef std::size_t size_t;
00136
00137 explicit compressed_minor_cursor(mtl::compressed2D<Elt, Parameters> const& matrix, size_t r, size_t c)
00138 : base(matrix, r, c), matrix(matrix)
00139 {}
00140
00141 explicit compressed_minor_cursor(mtl::compressed2D<Elt, Parameters> const& matrix, size_t offset)
00142 : base(matrix, offset), matrix(matrix)
00143 {}
00144
00145 compressed_minor_cursor(self const& other) : base(other), matrix(other.matrix) {}
00146
00147 self& operator= (self const& other)
00148 { base::operator=(other); return *this; }
00149
00150 self& operator++() { ++offset; return *this; }
00151 self& operator+=(size_t inc) { offset+= inc; return *this; }
00152 self operator+(size_t inc) const { self tmp(*this); tmp+= inc; return tmp; }
00153
00154 self& operator--() { --offset; return *this; }
00155 base& operator* () { return *this; }
00156 const base& operator* () const { return *this; }
00157
00158 mtl::compressed2D<Elt, Parameters> const& matrix;
00159 };
00160
00161
00162
00163
00164
00165 struct compressed2D_indexer
00166 {
00167 typedef std::size_t size_t;
00168 typedef size_t size_type;
00169 typedef std::pair<size_type, size_type> size_pair;
00170 private:
00171
00172 template <class Matrix>
00173 utilities::maybe<size_t> offset(const Matrix& ma, size_t major, size_t minor) const
00174 {
00175 typedef utilities::maybe<size_t> result_type;
00176 assert(ma.starts[major] <= ma.starts[major+1]);
00177 assert(ma.starts[major+1] <= ma.my_nnz);
00178
00179
00180
00181 if (ma.indices.empty())
00182 return result_type(0, false);
00183
00184 const size_t *first = &ma.indices[0] + ma.starts[major],
00185 *last = &ma.indices[0] + ma.starts[major+1];
00186
00187 if (first == last)
00188 return result_type(first - &ma.indices[0], false);
00189
00190 const size_t *index= first;
00191 if (last - index <= int(compressed_linear_search_limit))
00192 while (index != last && *index < minor) ++index;
00193 else
00194 index = std::lower_bound(first, last, minor);
00195 return result_type(index - &ma.indices[0], index != last && *index == minor);
00196 }
00197
00198 public:
00199
00200 template <class Matrix>
00201 size_pair major_minor_c(const Matrix& ma, size_t row, size_t col) const
00202 {
00203 using std::make_pair;
00204
00205 typename Matrix::index_type my_index;
00206 size_t my_row= index::change_from(my_index, row),
00207 my_col= index::change_from(my_index, col);
00208 return make_pair(ma.major_(my_row, my_col), ma.minor_(my_row, my_col));
00209 }
00210
00211
00212
00213 template <class Matrix>
00214 utilities::maybe<size_t> operator() (const Matrix& ma, size_t row, size_t col) const
00215 {
00216 size_t major, minor;
00217 boost::tie(major, minor) = major_minor_c(ma, row, col);
00218 return offset(ma, major, minor);
00219 }
00220
00221
00222 template <class Matrix>
00223 utilities::maybe<size_t> operator() (const Matrix& ma, size_pair major_minor) const
00224 {
00225 return offset(ma, major_minor.first, major_minor.second);
00226 }
00227
00228
00229
00230 template <class Matrix>
00231 size_t find_major(const Matrix& ma, size_t offset) const
00232 {
00233 MTL_DEBUG_THROW_IF(ma.starts.empty(), logic_error("Major vector can't be empty"));
00234 size_t my_major= std::upper_bound(ma.starts.begin(), ma.starts.end(), offset) - ma.starts.begin();
00235 return --my_major;
00236 }
00237
00238 template <class Matrix>
00239 size_t minor_from_offset(const Matrix& ma, size_t offset) const
00240 {
00241 typedef typename Matrix::index_type my_index;
00242 return index::change_to(my_index(), ma.indices[offset]);
00243 }
00244
00245 };
00246
00247
00249
00250 template <typename Elt, typename Parameters = matrix::parameters<> >
00251 class compressed2D
00252 : public base_matrix<Elt, Parameters>,
00253 public const_crtp_base_matrix< compressed2D<Elt, Parameters>, Elt, std::size_t >,
00254 public crtp_matrix_assign< compressed2D<Elt, Parameters>, Elt, std::size_t >,
00255 public mat_expr< compressed2D<Elt, Parameters> >
00256 {
00257 typedef std::size_t size_t;
00258 typedef base_matrix<Elt, Parameters> super;
00259 typedef compressed2D self;
00260 typedef mat_expr< compressed2D<Elt, Parameters> > expr_base;
00261 typedef crtp_matrix_assign< self, Elt, std::size_t > assign_base;
00262
00263
00264 void allocate(size_t new_nnz)
00265 {
00266 if (new_nnz) {
00267 this->my_nnz = new_nnz;
00268 data.resize(this->my_nnz);
00269 indices.resize(this->my_nnz, 0);
00270 }
00271 }
00272
00273 public:
00274 typedef Parameters parameters;
00275 typedef typename Parameters::orientation orientation;
00276 typedef typename Parameters::index index_type;
00277 typedef typename Parameters::dimensions dimensions;
00278 typedef Elt value_type;
00279 typedef compressed_key key_type;
00280
00281 typedef value_type const_reference;
00282
00283 typedef size_t size_type;
00284 typedef compressed2D_indexer indexer_type;
00285
00286 void check() const { MTL_DEBUG_THROW_IF(inserting, access_during_insertion()); }
00287
00289 void make_empty()
00290 {
00291 check();
00292 this->my_nnz = 0;
00293 data.resize(0);
00294 indices.resize(0);
00295 std::fill(starts.begin(), starts.end(), 0);
00296 }
00297
00299 void change_dim(size_type r, size_type c)
00300 {
00301 check();
00302 if (this->num_rows() != r || this->num_cols() != c) {
00303 super::change_dim(r, c);
00304 starts.resize(this->dim1()+1);
00305 make_empty();
00306 }
00307 }
00308
00309
00311 explicit compressed2D () : super(), inserting(false)
00312 {
00313 if (super::dim_type::is_static) starts.resize(super::dim1() + 1);
00314 }
00315
00317 explicit compressed2D (mtl::non_fixed::dimensions d, size_t nnz = 0) : super(d), inserting(false)
00318 {
00319 starts.resize(super::dim1() + 1, 0);
00320 allocate(nnz);
00321 }
00322
00324 explicit compressed2D (size_type num_rows, size_type num_cols, size_t nnz = 0)
00325 : super(non_fixed::dimensions(num_rows, num_cols)), inserting(false)
00326 {
00327 starts.resize(super::dim1() + 1, 0);
00328 allocate(nnz);
00329 }
00330
00332 compressed2D(const self& src) : super(non_fixed::dimensions(src.num_rows(), src.num_cols())), inserting(false)
00333 {
00334 starts.resize(super::dim1() + 1, 0);
00335 matrix_copy(src, *this);
00336 }
00337
00339 template <typename MatrixSrc>
00340 explicit compressed2D (const MatrixSrc& src) : super(), inserting(false)
00341 {
00342 if (super::dim_type::is_static) starts.resize(super::dim1() + 1);
00343 *this= src;
00344 }
00345
00346
00348 self& operator=(self src)
00349 {
00350 assert(this != &src);
00351
00352 check(); check_dim(src.num_rows(), src.num_cols());
00353 swap(*this, src);
00354 return *this;
00355 }
00356
00357 using assign_base::operator=;
00358
00359
00360
00361
00362 template <typename ValueIterator, typename StartIterator, typename IndexIterator>
00363 void raw_copy(ValueIterator first_value, ValueIterator last_value,
00364 StartIterator first_start, IndexIterator first_index)
00365 {
00366 using std::copy;
00367
00368
00369 allocate(last_value - first_value);
00370
00371
00372 copy(first_value, last_value, data.begin());
00373 copy(first_start, first_start + this->dim1() + 1, starts.begin());
00374 copy(first_index, first_index + this->nnz(), indices.begin());
00375 }
00376
00378 const_reference operator() (size_type row, size_type col) const
00379 {
00380 using math::zero;
00381 check(); MTL_DEBUG_THROW_IF(row < 0 || row >= this->num_rows() || col < 0 || col >= this->num_cols(), index_out_of_range());
00382 utilities::maybe<size_type> pos = indexer(*this, row, col);
00383 return pos ? data[pos] : zero(value_type());
00384 }
00385
00387
00388 value_type& lvalue(size_type row, size_type col)
00389 {
00390 utilities::maybe<size_type> pos = indexer(*this, row, col);
00391 check(); MTL_DEBUG_THROW_IF(!pos, logic_error("This entry does not exist in the matrix"));
00392 return data[pos];
00393 }
00394
00395
00396 const value_type& value_from_offset(size_type offset) const
00397 {
00398 check(); MTL_DEBUG_THROW_IF(offset >= this->my_nnz, index_out_of_range("Offset larger than matrix"));
00399 return data[offset];
00400 }
00401
00402 value_type& value_from_offset(size_type offset)
00403 {
00404 check(); MTL_DEBUG_THROW_IF(offset >= this->my_nnz, index_out_of_range("Offset larger than matrix"));
00405 return data[offset];
00406 }
00407
00409 friend void swap(self& matrix1, self& matrix2)
00410 {
00411 using std::swap;
00412 swap(static_cast<super&>(matrix1), static_cast<super&>(matrix2));
00413
00414 swap(matrix1.data, matrix2.data);
00415 swap(matrix1.starts, matrix2.starts);
00416 swap(matrix1.indices, matrix2.indices);
00417 swap(matrix1.inserting, matrix2.inserting);
00418 }
00419
00421 void crop()
00422 {
00423 check();
00424 if (data.empty()) return;
00425
00426 using math::zero;
00427 value_type z= zero(data[0]);
00428 size_type nzi= 0;
00429
00430 std::vector<size_type> new_starts(this->dim1() + 1);
00431 new_starts[0] = 0;
00432
00433 for (size_type i = 0; i < this->dim1(); i++) {
00434 for (size_type j= starts[i], end= starts[i+1]; j != end; ++j)
00435 if (data[j] != z)
00436 indices[nzi]= indices[j], data[nzi++]= data[j];
00437 new_starts[i+1]= nzi;
00438 }
00439 this->my_nnz= nzi;
00440 data.resize(nzi);
00441 indices.resize(nzi);
00442 swap(starts, new_starts);
00443 }
00444
00445
00447 size_type* address_major() { check(); return &starts[0]; }
00448 const size_type* address_major() const { check(); return &starts[0]; }
00450 size_type* address_minor() { check(); return &indices[0]; }
00451 const size_type* address_minor() const { check(); return &indices[0]; }
00453 value_type* address_data() { check(); return &data[0]; }
00454 const value_type* address_data() const { check(); return &data[0]; }
00455
00457 void shrink()
00458 {
00459 shrink_stl_vector(data);
00460 shrink_stl_vector(starts);
00461 shrink_stl_vector(indices);
00462 }
00463
00464 friend struct compressed2D_indexer;
00465 template <typename, typename, typename> friend struct compressed2D_inserter;
00466 template <typename, typename> friend struct compressed_el_cursor;
00467 template <typename, typename> friend struct compressed_minor_cursor;
00468
00469 indexer_type indexer;
00470 std::vector<value_type> data;
00471 protected:
00472 std::vector<size_type> starts;
00473 std::vector<size_type> indices;
00474 bool inserting;
00475 };
00476
00477
00478
00479
00480
00481
00482
00483
00484 template <typename Elt, typename Parameters, typename Updater = mtl::operations::update_store<Elt> >
00485 struct compressed2D_inserter
00486 {
00487 typedef compressed2D_inserter self;
00488 typedef compressed2D<Elt, Parameters> matrix_type;
00489 typedef typename matrix_type::size_type size_type;
00490 typedef typename matrix_type::value_type value_type;
00491 typedef std::pair<size_type, size_type> size_pair;
00492 typedef std::map<size_pair, value_type> map_type;
00493 typedef operations::update_proxy<self, size_type> proxy_type;
00494
00495 private:
00496
00497 void stretch();
00498
00499 struct bracket_proxy
00500 {
00501 bracket_proxy(self& ref, size_type row) : ref(ref), row(row) {}
00502
00503 proxy_type operator[](size_type col) { return proxy_type(ref, row, col); }
00504
00505 self& ref;
00506 size_type row;
00507 };
00508
00509 public:
00510 explicit compressed2D_inserter(matrix_type& matrix, size_type slot_size = 5)
00511 : matrix(matrix), elements(matrix.data), starts(matrix.starts), indices(matrix.indices),
00512 slot_size(std::min(slot_size, matrix.dim2())), slot_ends(matrix.dim1()+1)
00513 {
00514 MTL_THROW_IF(matrix.inserting, runtime_error("Two inserters on same matrix"));
00515 matrix.inserting = true;
00516 stretch();
00517 }
00518
00519 ~compressed2D_inserter()
00520 {
00521 final_place();
00522 insert_spare();
00523 matrix.inserting = false;
00524 }
00525
00526 bracket_proxy operator[] (size_type row)
00527 {
00528 return bracket_proxy(*this, row);
00529 }
00530
00531 proxy_type operator() (size_type row, size_type col)
00532 {
00533 return proxy_type(*this, row, col);
00534 }
00535
00536 template <typename Modifier>
00537 void modify(size_type row, size_type col, value_type val);
00538
00539 void update(size_type row, size_type col, value_type val)
00540 {
00541 using math::zero;
00542 modify<Updater>(row, col, val);
00543 }
00544
00545
00546 void print() const
00547 {
00548 for (size_type j= 0; j < matrix.dim1(); j++)
00549 print(j);
00550 }
00551
00552
00553 void print(size_type i) const
00554 {
00555 std::cout << "in slot " << i << ": ";
00556 for (size_type j= starts[i]; j < slot_ends[i]; ++j)
00557 std::cout << "[" << indices[j] << ": " << elements[j] << "]";
00558 std::cout << "\n";
00559 }
00560
00561
00562
00563 void make_empty(size_type i)
00564 {
00565 slot_ends[i]= starts[i];
00566 }
00567
00568 template <typename Matrix, typename Rows, typename Cols>
00569 self& sorted_block_insertion(const element_matrix_t<Matrix, Rows, Cols>& elements);
00570
00571 template <typename Matrix, typename Rows, typename Cols>
00572 self& operator<< (const element_matrix_t<Matrix, Rows, Cols>& elements)
00573 {
00574 using mtl::size;
00575 #if 0 // shouldn't be slower now
00576 if (size(elements.cols) > sorted_block_insertion_limit
00577 && boost::is_same<typename Parameters::orientation, row_major>::value)
00578 return sorted_block_insertion(elements);
00579 #endif
00580
00581 for (unsigned ri= 0; ri < size(elements.rows); ri++)
00582 for (unsigned ci= 0; ci < size(elements.cols); ci++)
00583 update (elements.rows[ri], elements.cols[ci], elements.matrix[ri][ci]);
00584 return *this;
00585 }
00586
00587
00588 template <typename Matrix, typename Rows, typename Cols>
00589 self& operator<< (const element_array_t<Matrix, Rows, Cols>& elements)
00590 {
00591 return *this << element_matrix_t<Matrix, Rows, Cols>(elements.array, elements.rows, elements.cols);
00592 }
00593
00594 private:
00595 utilities::maybe<typename self::size_type> matrix_offset(size_pair);
00596 void final_place();
00597 void insert_spare();
00598
00599
00600 void display(size_type i)
00601 {
00602 std::cout << "slot " << i << " is [";
00603 for (size_type j= starts[i]; j < slot_ends[i]; ++j)
00604 std::cout << '(' << indices[j] << ": " << elements[j] << ")"
00605 << (j < slot_ends[i] - 1 ? ", " : "");
00606 std::cout << "]\n";
00607 }
00608
00609
00610
00611 void reduce_slot(size_type i)
00612 {
00613 size_type tgt= starts[i], src= tgt + 1, end= slot_ends[i];
00614 for (; src < end;) {
00615 while (src < end && indices[tgt] == indices[src])
00616 Updater()(elements[tgt], elements[src++]);
00617 ++tgt;
00618 if (tgt == src)
00619 ++src;
00620 else if (src < end && indices[tgt] != indices[src]) {
00621 indices[tgt]= indices[src];
00622 elements[tgt]= elements[src++];
00623 if (src >= end) ++tgt;
00624 }
00625 }
00626 slot_ends[i]= tgt;
00627 }
00628
00629 protected:
00630 compressed2D<Elt, Parameters>& matrix;
00631 std::vector<value_type>& elements;
00632 std::vector<size_type>& starts;
00633 std::vector<size_type>& indices;
00634 size_type slot_size;
00635 std::vector<size_type> slot_ends;
00636 map_type spare;
00637 };
00638
00639 template <typename Elt, typename Parameters, typename Updater>
00640 void compressed2D_inserter<Elt, Parameters, Updater>::stretch()
00641 {
00642 using std::copy;
00643 using std::copy_backward;
00644 using std::swap;
00645
00646
00647 if (elements.empty()) {
00648 for (size_type i= 0, s= 0; i <= matrix.dim1(); i++, s+= slot_size)
00649 slot_ends[i]= starts[i]= s;
00650 size_type new_total= (slot_ends[matrix.dim1()]= starts[matrix.dim1()]) + slot_size;
00651 elements.resize(new_total); indices.resize(new_total);
00652 return;
00653 }
00654
00655
00656 if (elements.size() + matrix.dim1()/2 > slot_size * matrix.dim1()) {
00657
00658 copy(starts.begin() + 1, starts.end(), slot_ends.begin());
00659 slot_ends[matrix.dim1()]= starts[matrix.dim1()];
00660 return;
00661 }
00662
00663 std::vector<size_type> new_starts(matrix.dim1() + 1);
00664 new_starts[0] = 0;
00665 for (size_type i = 0; i < matrix.dim1(); i++) {
00666 size_type entries = starts[i+1] - starts[i];
00667 slot_ends[i] = new_starts[i] + entries;
00668 new_starts[i+1] = new_starts[i] + std::max(entries, slot_size);
00669 }
00670
00671 size_type new_total= (slot_ends[matrix.dim1()]= new_starts[matrix.dim1()]) + slot_size;
00672 elements.resize(new_total);
00673 indices.resize(new_total);
00674
00675
00676
00677
00678
00679 for (size_type i = matrix.dim1(); i > 0; i--)
00680 if (starts[i] <= new_starts[i-1]) {
00681
00682 copy(&elements[0] + starts[i-1], &elements[0] + starts[i], &elements[0] + new_starts[i-1]);
00683 copy(&indices[0] + starts[i-1], &indices[0] + starts[i], &indices[0] + new_starts[i-1]);
00684 } else {
00685
00686 copy_backward(&elements[0] + starts[i-1], &elements[0] + starts[i], &elements[0] + slot_ends[i-1]);
00687 copy_backward(&indices[0] + starts[i-1], &indices[0] + starts[i], &indices[0] + slot_ends[i-1]);
00688 }
00689 swap(starts, new_starts);
00690 }
00691
00692 template <typename Elt, typename Parameters, typename Updater>
00693 inline utilities::maybe<typename compressed2D_inserter<Elt, Parameters, Updater>::size_type>
00694 compressed2D_inserter<Elt, Parameters, Updater>::matrix_offset(size_pair mm)
00695 {
00696 size_type major, minor;
00697 boost::tie(major, minor) = mm;
00698
00699 if (indices.empty())
00700 return utilities::maybe<size_t> (0, false);
00701
00702
00703 const size_t *first = &indices[0] + starts[major],
00704 *last = &indices[0] + slot_ends[major];
00705 if (first == last)
00706 return utilities::maybe<size_t> (first - &indices[0], false);
00707
00708 const size_t *index= first;
00709 if (last - index < 10)
00710 while (index != last && *index < minor) ++index;
00711 else
00712 index = std::lower_bound(first, last, minor);
00713 return utilities::maybe<size_t>(index - &indices[0], index != last && *index == minor);
00714 }
00715
00716
00717 template <typename Elt, typename Parameters, typename Updater>
00718 template <typename Modifier>
00719 inline void compressed2D_inserter<Elt, Parameters, Updater>::modify(size_type row, size_type col, value_type val)
00720 {
00721 using std::copy_backward;
00722 MTL_DEBUG_THROW_IF(row < 0 || row >= num_rows(matrix) || col < 0 || col >= num_cols(matrix), index_out_of_range());
00723
00724 Modifier modifier;
00725 compressed2D_indexer indexer;
00726 size_pair mm = indexer.major_minor_c(matrix, row, col);
00727 size_type major, minor;
00728 boost::tie(major, minor) = mm;
00729
00730 utilities::maybe<size_type> pos = matrix_offset(mm);
00731
00732 if (pos)
00733 modifier (elements[pos], val);
00734 else {
00735 size_type& my_end = slot_ends[major];
00736
00737 if (my_end != starts[major+1]) {
00738 if (pos.value() != my_end) {
00739 copy_backward(&elements[0] + pos.value(), &elements[0] + my_end, &elements[0] + (my_end+1));
00740 copy_backward(&indices[0] + pos.value(), &indices[0] + my_end, &indices[0] + (my_end+1));
00741 }
00742 elements[pos] = modifier.init(val); indices[pos] = minor;
00743 my_end++;
00744 matrix.my_nnz++;
00745 } else {
00746 typename map_type::iterator it = spare.find(mm);
00747
00748 if (it == spare.end()) {
00749 spare.insert(std::make_pair(mm, modifier.init(val)));
00750 matrix.my_nnz++;
00751 } else
00752 modifier(it->second, val);
00753 }
00754 }
00755
00756 }
00757
00758 namespace detail {
00759
00760 struct cmp_first
00761 {
00762 template <typename F, typename S>
00763 bool operator()(const std::pair<F, S>& x, const std::pair<F, S>& y) const
00764 {
00765 return x.first < y.first;
00766 }
00767 };
00768 }
00769
00770 template <typename Elt, typename Parameters, typename Updater>
00771 template <typename Matrix, typename Rows, typename Cols>
00772 compressed2D_inserter<Elt, Parameters, Updater>&
00773 compressed2D_inserter<Elt, Parameters, Updater>::sorted_block_insertion(const element_matrix_t<Matrix, Rows, Cols>& iblock)
00774 {
00775 using std::copy; using std::copy_backward; using std::min;
00776 using mtl::size; using mtl::num_rows; using mtl::num_cols;
00777 using namespace mtl::utility;
00778 typedef zip_it<size_type, value_type> it_type;
00779
00780 size_type m= size(iblock.rows), n= size(iblock.cols);
00781 MTL_THROW_IF(m != num_rows(iblock.matrix) || n != num_cols(iblock.matrix), incompatible_size());
00782 MTL_THROW_IF(&iblock.matrix[0][1] - &iblock.matrix[0][0] != 1, logic_error("Rows must be consecutive"));
00783
00784 size_type rmax= matrix.dim1(), &index_max0= indices[starts[rmax]];
00785 value_type& value_max0= elements[starts[rmax]];
00786 for (size_type i= 0; i < m; i++) {
00787 size_type r= iblock.rows[i], &index_0= indices[starts[r]];
00788 value_type& value_0= elements[starts[r]];
00789 if (slot_ends[r] == starts[r]) {
00790 size_type to_copy= min(starts[r+1] - starts[r], n);
00791 copy(&iblock.cols[0], &iblock.cols[0]+to_copy, &index_0);
00792 copy(&iblock.matrix[i][0], &iblock.matrix[i][0]+to_copy, &value_0);
00793 slot_ends[r]= starts[r] + to_copy;
00794 std::sort(it_type(&index_0, &value_0, 0), it_type(&index_0, &value_0, to_copy), less_0());
00795 reduce_slot(r);
00796
00797 matrix.my_nnz+= slot_ends[r] - starts[r];
00798 for (size_type j= to_copy; j < n; ++j)
00799 update(r, iblock.cols[j], iblock.matrix[i][j]);
00800 } else {
00801 size_type to_copy= min(slot_size, n);
00802 copy(&iblock.cols[0], &iblock.cols[0]+to_copy, &index_max0);
00803 copy(&iblock.matrix[i][0], &iblock.matrix[i][0]+to_copy, &value_max0);
00804 slot_ends[rmax]= starts[rmax] + to_copy;
00805 std::sort(it_type(&index_max0, &value_max0, 0), it_type(&index_max0, &value_max0, to_copy), less_0());
00806 size_type tgt= starts[r], tend= slot_ends[r], later= starts[rmax], src= later, end= slot_ends[rmax];
00807 for (; src < end; ) {
00808
00809 while (tgt < tend && indices[src] > indices[tgt]) ++tgt;
00810
00811 if (tgt < tend)
00812 while (src < end && indices[src] == indices[tgt])
00813 Updater()(elements[tgt], elements[src++]);
00814 else {
00815 for (; src < end && tgt < starts[r+1]; ++src) {
00816 indices[tgt]= indices[src];
00817 elements[tgt]= elements[src];
00818 slot_ends[r]= ++tgt;
00819 ++matrix.my_nnz;
00820 }
00821 for (; src < end; ++src)
00822 update(r, indices[src], elements[src]);
00823 later= starts[rmax];
00824 }
00825
00826 while (src < end && indices[src] < indices[tgt]) {
00827 if (later != src) {
00828 indices[later]= indices[src];
00829 elements[later]= elements[src];
00830 }
00831 ++src; ++later;
00832 }
00833 }
00834 for (size_type j= starts[rmax]; j < later; ++j)
00835 update(r, indices[j], elements[j]);
00836 }
00837 }
00838 return *this;
00839 }
00840
00841
00842 template <typename Elt, typename Parameters, typename Updater>
00843 void compressed2D_inserter<Elt, Parameters, Updater>::final_place()
00844 {
00845 using std::swap;
00846
00847 size_type dim1 = matrix.dim1();
00848 std::vector<size_type> new_starts(dim1 + 1);
00849 new_starts[0] = 0;
00850
00851 if (spare.empty()) {
00852
00853 if (slot_ends[dim1-1] == matrix.my_nnz) {
00854 starts[dim1]= slot_ends[dim1-1];
00855 if (matrix.my_nnz < elements.size())
00856 elements.resize(matrix.my_nnz),
00857 indices.resize(matrix.my_nnz);
00858 return;
00859 }
00860 size_type pos= 0;
00861 for (size_type i= 0; i < dim1; ++i) {
00862 new_starts[i]= pos;
00863 for (size_type j= starts[i], je= slot_ends[i]; j < je; ++j, ++pos) {
00864 elements[pos]= elements[j];
00865 indices[pos]= indices[j];
00866 }
00867 }
00868 new_starts[dim1]= pos;
00869 swap(new_starts, starts);
00870 if (matrix.my_nnz < elements.size())
00871 elements.resize(matrix.my_nnz),
00872 indices.resize(matrix.my_nnz);
00873 return;
00874 }
00875
00876 typename map_type::iterator it = spare.begin();
00877 for (size_type i = 0; i < dim1; i++) {
00878 size_type entries = slot_ends[i] - starts[i];
00879 while (it != spare.end() && it->first.first == i)
00880 entries++, it++;
00881 new_starts[i+1] = new_starts[i] + entries;
00882 }
00883
00884 size_type new_total = new_starts[dim1], old_total = starts[dim1];
00885 if (new_total > old_total) {
00886 elements.resize(new_total);
00887 indices.resize(new_total); }
00888
00889 operations::shift_blocks(dim1, starts, new_starts, slot_ends, elements);
00890 operations::shift_blocks(dim1, starts, new_starts, slot_ends, indices);
00891
00892 if (new_total < elements.size()) {
00893 elements.resize(new_total);
00894 indices.resize(new_total); }
00895
00896 for (size_type i = 0; i < dim1; i++)
00897 slot_ends[i] = new_starts[i] + slot_ends[i] - starts[i];
00898
00899 swap(starts, new_starts);
00900 }
00901
00902 template <typename Elt, typename Parameters, typename Updater>
00903 void compressed2D_inserter<Elt, Parameters, Updater>::insert_spare()
00904 {
00905 using std::copy_backward;
00906
00907 for (typename map_type::iterator it = spare.begin(); it != spare.end(); ++it) {
00908 size_pair mm = it->first;
00909 size_type major = mm.first, minor = mm.second;
00910 utilities::maybe<size_type> pos = matrix_offset(mm);
00911 size_type& my_end = slot_ends[major];
00912
00913
00914 copy_backward(&elements[0] + pos.value(), &elements[0] + my_end, &elements[0] + (my_end+1));
00915 copy_backward(&indices[0] + pos.value(), &indices[0] + my_end, &indices[0] + (my_end+1));
00916 elements[pos] = it->second; indices[pos] = minor;
00917 my_end++;
00918 }
00919 }
00920
00921
00922
00923
00924
00925 template <typename Value, typename Parameters>
00926 typename compressed2D<Value, Parameters>::size_type
00927 inline num_rows(const compressed2D<Value, Parameters>& matrix)
00928 {
00929 return matrix.num_rows();
00930 }
00931
00932 template <typename Value, typename Parameters>
00933 typename compressed2D<Value, Parameters>::size_type
00934 inline num_cols(const compressed2D<Value, Parameters>& matrix)
00935 {
00936 return matrix.num_cols();
00937 }
00938
00939 template <typename Value, typename Parameters>
00940 typename compressed2D<Value, Parameters>::size_type
00941 inline size(const compressed2D<Value, Parameters>& matrix)
00942 {
00943 return matrix.num_cols() * matrix.num_rows();
00944 }
00945
00946
00947 }}
00948
00949
00950
00951
00952
00953
00954
00955
00956 namespace mtl { namespace traits {
00957
00958
00959 using mtl::matrix::compressed2D;
00960 using mtl::matrix::compressed_el_cursor;
00961 using mtl::matrix::compressed_minor_cursor;
00962
00963
00964
00965
00966
00967 template <class Elt, class Parameters>
00968 struct range_generator<glas::tag::nz, compressed2D<Elt, Parameters> >
00969 : detail::all_offsets_range_generator<compressed2D<Elt, Parameters>,
00970 compressed_el_cursor<Elt, Parameters>,
00971 complexity_classes::linear_cached>
00972 {};
00973
00974
00975
00976 template <typename Elt, typename Parameters>
00977 struct range_generator<glas::tag::row, compressed2D<Elt, Parameters> >
00978 : boost::mpl::if_<
00979 boost::is_same<typename Parameters::orientation, row_major>
00980 , detail::all_rows_range_generator<compressed2D<Elt, Parameters>, complexity_classes::linear_cached>
00981 , range_generator<tag::unsupported, compressed2D<Elt, Parameters> >
00982 >::type {};
00983
00984
00985 template <class Elt, class Parameters>
00986 struct range_generator<glas::tag::nz,
00987 detail::sub_matrix_cursor<compressed2D<Elt, Parameters>, glas::tag::row, 2> >
00988 {
00989 typedef typename Collection<compressed2D<Elt, Parameters> >::size_type size_type;
00990 typedef detail::sub_matrix_cursor<compressed2D<Elt, Parameters>, glas::tag::row, 2> cursor_type;
00991 typedef complexity_classes::linear_cached complexity;
00992 typedef compressed_minor_cursor<Elt, Parameters> type;
00993 static int const level = 1;
00994
00995 type begin(cursor_type const& cursor) const
00996 {
00997 return type(cursor.ref, cursor.key, cursor.ref.begin_col());
00998 }
00999 type end(cursor_type const& cursor) const
01000 {
01001 return type(cursor.ref, cursor.key, cursor.ref.end_col());
01002 }
01003 type lower_bound(cursor_type const& cursor, size_type position) const
01004 {
01005 return type(cursor.ref, cursor.key, std::min(position, cursor.ref.end_col()));
01006 }
01007 };
01008
01009
01010
01011 template <typename Elt, typename Parameters>
01012 struct range_generator<glas::tag::col, compressed2D<Elt, Parameters> >
01013 : boost::mpl::if_<
01014 boost::is_same<typename Parameters::orientation, col_major>
01015 , detail::all_cols_range_generator<compressed2D<Elt, Parameters>, complexity_classes::linear_cached>
01016 , range_generator<tag::unsupported, compressed2D<Elt, Parameters> >
01017 >::type {};
01018
01019
01020 template <class Elt, class Parameters>
01021 struct range_generator<glas::tag::nz,
01022 detail::sub_matrix_cursor<compressed2D<Elt, Parameters>, glas::tag::col, 2> >
01023 {
01024 typedef typename Collection<compressed2D<Elt, Parameters> >::size_type size_type;
01025 typedef detail::sub_matrix_cursor<compressed2D<Elt, Parameters>, glas::tag::col, 2> cursor_type;
01026 typedef complexity_classes::linear_cached complexity;
01027 typedef compressed_minor_cursor<Elt, Parameters> type;
01028 static int const level = 1;
01029
01030 type begin(cursor_type const& cursor) const
01031 {
01032 return type(cursor.ref, cursor.ref.begin_row(), cursor.key);
01033 }
01034 type end(cursor_type const& cursor) const
01035 {
01036 return type(cursor.ref, cursor.ref.end_row(), cursor.key);
01037 }
01038 type lower_bound(cursor_type const& cursor, size_type position) const
01039 {
01040 return type(cursor.ref, std::min(position, cursor.ref.end_row()), cursor.key);
01041 }
01042 };
01043
01044
01045 template <typename Elt, typename Parameters>
01046 struct range_generator<glas::tag::major, compressed2D<Elt, Parameters> >
01047 : boost::mpl::if_<
01048 boost::is_same<typename Parameters::orientation, row_major>
01049 , range_generator<glas::tag::row, compressed2D<Elt, Parameters> >
01050 , range_generator<glas::tag::col, compressed2D<Elt, Parameters> >
01051 >::type {};
01052
01053
01054
01055
01056
01057
01058
01059 template <class Elt, class Parameters>
01060 struct range_generator<tag::const_iter::nz,
01061 detail::sub_matrix_cursor<compressed2D<Elt, Parameters>, glas::tag::row, 2> >
01062 {
01063 typedef compressed2D<Elt, Parameters> matrix_type;
01064 typedef typename matrix_type::size_type size_type;
01065 typedef typename matrix_type::value_type value_type;
01066 typedef detail::sub_matrix_cursor<matrix_type, glas::tag::row, 2> cursor;
01067
01068 typedef complexity_classes::linear_cached complexity;
01069 static int const level = 1;
01070 typedef const value_type* type;
01071
01072 type begin(cursor const& c)
01073 {
01074 const matrix_type& matrix= c.ref;
01075 size_type offset= matrix.indexer(matrix, c.key, matrix.begin_col());
01076 return &matrix.data[0] + offset;
01077 }
01078
01079
01080 type end(cursor const& c)
01081 {
01082 const matrix_type& matrix= c.ref;
01083 size_type offset= matrix.indexer(matrix, c.key, matrix.end_col());
01084 return &matrix.data[0] + offset;
01085 }
01086 };
01087
01088
01089 template <class Elt, class Parameters>
01090 struct range_generator<tag::const_iter::nz,
01091 detail::sub_matrix_cursor<compressed2D<Elt, Parameters>, glas::tag::col, 2> >
01092 {
01093 typedef compressed2D<Elt, Parameters> matrix_type;
01094 typedef typename matrix_type::size_type size_type;
01095 typedef typename matrix_type::value_type value_type;
01096 typedef detail::sub_matrix_cursor<matrix_type, glas::tag::col, 2> cursor;
01097
01098 typedef complexity_classes::linear_cached complexity;
01099 static int const level = 1;
01100 typedef const value_type* type;
01101
01102 type begin(cursor const& c)
01103 {
01104 const matrix_type& matrix= c.ref;
01105 size_type offset= matrix.indexer(matrix, matrix.begin_row(), c.key);
01106 return &matrix.data[0] + offset;
01107 }
01108
01109
01110 type end(cursor const& c)
01111 {
01112 const matrix_type& matrix= c.ref;
01113 size_type offset= matrix.indexer(matrix, matrix.end_row(), c.key);
01114 return &matrix.data[0] + offset;
01115 }
01116 };
01117
01118
01119 }}
01120
01121
01122
01123 #endif // MTL_COMPRESSED2D_INCLUDE