sparse.hpp
Go to the documentation of this file.
1/*!
2 * \brief Classes used for vector proxies
3 *
4 * \author O. Krause
5 * \date 2016
6 *
7 *
8 * \par Copyright 1995-2015 Shark Development Team
9 *
10 * <BR><HR>
11 * This file is part of Shark.
12 * <http://image.diku.dk/shark/>
13 *
14 * Shark is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published
16 * by the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Shark is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28 #ifndef REMORA_SPARSE_HPP
29#define REMORA_SPARSE_HPP
30
31
32#include "detail/storage.hpp"
33#include "detail/traits.hpp"
34#include "cpu/sparse.hpp"
35#include "cpu/sparse_matrix.hpp"
36#include "expression_types.hpp"
37#include "assignment.hpp"
38
39
40namespace remora{
41
42template<class T, class I = std::size_t> class compressed_vector;
43template<class T, class I = std::size_t> class compressed_vector_adaptor;
44template<class T, class I = std::size_t, class Orientation = row_major> class compressed_matrix;
45
46
47/** \brief Compressed array based sparse vector
48 *
49 * a sparse vector of values of type T of variable size. The non zero values are stored as
50 * two seperate arrays: an index array and a value array. The index array is always sorted
51 * and there is at most one entry for each index. Inserting an element can be time consuming.
52 * If the vector has a very high dimension with a few non-zero values, then this vector is
53 * very time and memory efficient.
54 *
55 * For a \f$n\f$-dimensional compressed vector and \f$0 \leq i < n\f$ the non-zero elements
56 * \f$v_i\f$ are mapped to consecutive elements of the index and value container, i.e. for
57 * elements \f$k = v_{i_1}\f$ and \f$k + 1 = v_{i_2}\f$ of these containers holds \f$i_1 < i_2\f$.
58 *
59 * \tparam T the type of object stored in the vector (like double, float, complex, etc...)
60 * \tparam I the indices stored in the vector
61 */
62template<class T, class I>
63class compressed_vector
64:public vector_container<compressed_vector<T, I>, cpu_tag >
65,public detail::BaseSparseVector<detail::VectorStorage<T,I > >{
66public:
67 typedef T value_type;
68 typedef I size_type;
69 typedef T const& const_reference;
70 typedef T& reference;
71
72 typedef detail::compressed_vector_reference<compressed_vector const> const_closure_type;
73 typedef detail::compressed_vector_reference<compressed_vector> closure_type;
74 typedef sparse_vector_storage<T,I> storage_type;
75 typedef sparse_vector_storage<T const,I const> const_storage_type;
76 typedef elementwise<sparse_tag> evaluation_category;
77
78 // Construction and destruction
79 compressed_vector()
80 : detail::BaseSparseVector<detail::VectorStorage<T,I> >(
81 detail::VectorStorage<T, I>(),0,0
82 ){}
83 explicit compressed_vector(size_type size, size_type non_zeros = 0)
84 : detail::BaseSparseVector<detail::VectorStorage<T,I> >(
85 detail::VectorStorage<T, I>(),size,non_zeros
86 ){}
87 template<class E>
88 compressed_vector(vector_expression<E, cpu_tag> const& e, size_type non_zeros = 0)
89 : detail::BaseSparseVector<detail::VectorStorage<T,I> >(
90 detail::VectorStorage<T, I>(),e().size(),non_zeros
91 ){
92 assign(*this,e);
93 }
94
95 void resize(size_type size, bool keep = false){
96 this->do_resize(size, keep);
97 }
98
99 ///\brief Returns the underlying storage structure for low level access
100 storage_type raw_storage(){
101 return this->m_manager.m_storage;
102 }
103
104 ///\brief Returns the underlying storage structure for low level access
105 const_storage_type raw_storage() const{
106 return this->m_manager.m_storage;
107 }
108
109 typename device_traits<cpu_tag>::queue_type& queue() const{
110 return device_traits<cpu_tag>::default_queue();
111 }
112
113 friend void swap(compressed_vector& v1, compressed_vector& v2){
114 std::swap(v1.m_size, v2.m_size);
115 v1.m_indices.swap(v2.m_indices);
116 v1.m_values.swap(v2.m_values);
117 v1.m_storage.swap(v2.m_storage);
118 }
119
120 // Assignment
121 compressed_vector& operator = (compressed_vector const& v) = default;
122 template<class C> // Container assignment without temporary
123 compressed_vector& operator = (vector_container<C, cpu_tag> const& v) {
124 this->resize(v().size(), false);
125 assign(*this, v);
126 return *this;
127 }
128 template<class AE>
129 compressed_vector& operator = (vector_expression<AE, cpu_tag> const& ae) {
130 compressed_vector temporary(ae, this->nnz_capacity());
131 swap(temporary);
132 return *this;
133 }
134
135 // Serialization
136 template<class Archive>
137 void serialize(Archive& ar, const unsigned int /* file_version */) {
138 ar & static_cast< detail::BaseSparseVector<detail::VectorStorage<T,I > >& >(*this);
139 }
140};
141
142
143/** \brief Wraps external memory compatible to the format of a compressed vector
144 *
145 * For a \f$n\f$-dimensional compressed vector and \f$0 \leq i < n\f$ the non-zero elements
146 * \f$v_i\f$ are mapped to consecutive elements of the index and value container, i.e. for
147 * elements \f$k = v_{i_1}\f$ and \f$k + 1 = v_{i_2}\f$ of these containers holds \f$i_1 < i_2\f$.
148 *
149 * There are 4 values needed: the address of the arrays of indices and values, the number of nonzero elements
150 * and the size of the arrays (which can be larger than the number of noznero elements to allow for insertion).
151 *
152 * \tparam T the type of object stored in the vector (like double, float, complex, etc...)
153 * \tparam I the indices stored in the vector
154 */
155template<class T, class I>
156class compressed_vector_adaptor
157: public vector_expression<compressed_vector_adaptor<T, I>, cpu_tag>
158,public detail::BaseSparseVector<detail::VectorStorageReference<T,I > >{
159public:
160 typedef typename std::remove_const<T>::type value_type;
161 typedef typename std::remove_const<I>::type size_type;
162 typedef T const& const_reference;
163 typedef T& reference;
164
165 typedef detail::compressed_vector_reference<compressed_vector_adaptor const> const_closure_type;
166 typedef detail::compressed_vector_reference<compressed_vector_adaptor> closure_type;
167 typedef sparse_vector_storage<T,I> storage_type;
168 typedef sparse_vector_storage<T const,I const> const_storage_type;
169 typedef elementwise<sparse_tag> evaluation_category;
170
171 // Construction and destruction
172
173 /// \brief Constructs the adaptor from external storage
174 explicit compressed_vector_adaptor(size_type size, storage_type storage)
175 : detail::BaseSparseVector<detail::VectorStorageReference<T,I> >(
176 detail::VectorStorageReference<T,I>(storage), size, storage.nnz
177 ){}
178
179 /// \brief Covnerts an expression into an adaptor
180 template<class E>
181 compressed_vector_adaptor(vector_expression<E, cpu_tag> const& e)
182 : detail::BaseSparseVector<detail::VectorStorageReference<T,I> >(
183 detail::VectorStorageReference<T,I>(e().raw_storage()), e().size(), e().raw_storage().nnz
184 ){}
185
186 ///\brief Returns the underlying storage structure for low level access
187 storage_type raw_storage(){
188 return this->m_manager.m_storage;
189 }
190
191 ///\brief Returns the underlying storage structure for low level access
192 const_storage_type raw_storage() const{
193 return this->m_manager.m_storage;
194 }
195
196 typename device_traits<cpu_tag>::queue_type& queue() const{
197 return device_traits<cpu_tag>::default_queue();
198 }
199
200 // Assignment
201 compressed_vector_adaptor& operator = (compressed_vector_adaptor const& v) {
202 kernels::assign(*this, typename vector_temporary<compressed_vector_adaptor>::type(v));
203 return *this;
204 }
205 template<class AE>
206 compressed_vector_adaptor& operator = (vector_expression<AE, cpu_tag> const& ae) {
207 kernels::assign(*this, typename vector_temporary<AE>::type(ae));
208 return *this;
209 }
210};
211
212template<class T, class I, class Orientation>
213class compressed_matrix:public matrix_container<compressed_matrix<T, I, Orientation>, cpu_tag >{
214public:
215 typedef I size_type;
216 typedef T value_type;
217 typedef T const& const_reference;
218 typedef T& reference;
219
220 typedef detail::compressed_matrix_proxy<compressed_matrix<T, I, Orientation> const, Orientation> const_closure_type;
221 typedef detail::compressed_matrix_proxy<compressed_matrix<T, I, Orientation>, Orientation> closure_type;
222 typedef sparse_matrix_storage<T, I> storage_type;
223 typedef sparse_matrix_storage<T const, I const> const_storage_type;
224 typedef elementwise<sparse_tag> evaluation_category;
225 typedef Orientation orientation;
226
227 compressed_matrix():m_impl(detail::MatrixStorage<T,I>(0,0)){}
228
229 compressed_matrix(size_type rows, size_type cols, size_type non_zeros = 0)
230 :m_impl(detail::MatrixStorage<T,I>(orientation::index_M(rows,cols),orientation::index_m(rows,cols)),non_zeros){}
231
232 template<class E>
233 compressed_matrix(matrix_expression<E, cpu_tag> const& m, size_type non_zeros = 0)
234 :m_impl(
235 detail::MatrixStorage<T,I>(orientation::index_M(m().size1(),m().size2()),orientation::index_m(m().size1(),m().size2())),
236 non_zeros
237 ){
238 assign(*this,m);
239 }
240
241 template<class E>
242 compressed_matrix operator=(matrix_container<E, cpu_tag> const& m){
243 resize(m.size1(),m.size2());
244 return assign(*this,m);
245 }
246 template<class E>
247 compressed_matrix& operator=(matrix_expression<E, cpu_tag> const& m){
248 compressed_matrix temporary(m);
249 m_impl = std::move(temporary.m_impl);
250 return *this;
251 }
252
253 ///\brief Number of rows of the matrix
254 size_type size1() const {
255 return orientation::index_M(m_impl.major_size(), m_impl.minor_size());
256 }
257
258 ///\brief Number of columns of the matrix
259 size_type size2() const {
260 return orientation::index_m(m_impl.major_size(), m_impl.minor_size());
261 }
262
263 /// \brief Number of nonzeros this matrix can maximally store before requiring new memory
264 std::size_t nnz_capacity() const{
265 return m_impl.nnz_capacity();
266 }
267 /// \brief Number of reserved elements in the matrix (> number of nonzeros stored)
268 std::size_t nnz_reserved() const {
269 return m_impl.nnz_reserved();
270 }
271 /// \brief Number of nonzeros the major index (a row or column depending on orientation) can maximally store before a resize
272 std::size_t major_capacity(size_type i)const{
273 return m_impl.major_capacity(i);
274 }
275 /// \brief Number of nonzeros the major index (a row or column depending on orientation) currently stores
276 std::size_t major_nnz(size_type i) const {
277 return m_impl.major_nnz(i);
278 }
279
280 /// \brief Set the total number of nonzeros stored by the matrix
281 void set_nnz(std::size_t non_zeros) {
282 m_impl.set_nnz(non_zeros);
283 }
284 /// \brief Set the number of nonzeros stored in the major index (a row or column depending on orientation)
285 void set_major_nnz(size_type i,std::size_t non_zeros) {
286 m_impl.set_major_nnz(i,non_zeros);
287 }
288
289 const_storage_type raw_storage()const{
290 return m_impl.raw_storage();
291 }
292 storage_type raw_storage(){
293 return m_impl.raw_storage();
294 }
295
296 typename device_traits<cpu_tag>::queue_type& queue() const{
297 return device_traits<cpu_tag>::default_queue();
298 }
299
300 void reserve(std::size_t non_zeros) {
301 m_impl.reserve(non_zeros);
302 }
303
304 void major_reserve(size_type i, std::size_t non_zeros, bool exact_size = false) {
305 m_impl.major_reserve(i, non_zeros, exact_size);
306 }
307
308 void resize(size_type rows, size_type columns){
309 m_impl.resize(orientation::index_M(rows,columns),orientation::index_m(rows,columns));
310 }
311
312 typedef typename detail::compressed_matrix_impl<detail::MatrixStorage<T,I> >::const_major_iterator const_major_iterator;
313 typedef typename detail::compressed_matrix_impl<detail::MatrixStorage<T,I> >::major_iterator major_iterator;
314
315 const_major_iterator major_begin(size_type i) const {
316 return m_impl.cmajor_begin(i);
317 }
318
319 const_major_iterator major_end(size_type i) const{
320 return m_impl.cmajor_end(i);
321 }
322
323 major_iterator major_begin(size_type i) {
324 return m_impl.major_begin(i);
325 }
326
327 major_iterator major_end(size_type i) {
328 return m_impl.major_end(i);
329 }
330
331 major_iterator set_element(major_iterator pos, size_type index, value_type value){
332 return m_impl.set_element(pos, index, value);
333 }
334
335 major_iterator clear_range(major_iterator start, major_iterator end) {
336 return m_impl.clear_range(start,end);
337 }
338
339 void clear() {
340 for(std::size_t i = 0; i != m_impl.major_size(); ++i){
341 clear_range(major_begin(i),major_end(i));
342 }
343 }
344 // Serialization
345 template<class Archive>
346 void serialize(Archive &ar, const unsigned int /* file_version */) {
347 ar & m_impl;
348 }
349
350private:
351 detail::compressed_matrix_impl<detail::MatrixStorage<T,I> > m_impl;
352};
353
354
355
356//~ ///\brief Wraps externally provided storage into a sparse matrix interface
357//~ ///
358//~ /// Note that for this class, storage is limited and if an insertion operation takes more space than available, it will throw an exception
359//~ template<class T, class I, class Orientation>
360//~ class compressed_matrix_adaptor:public matrix_container<compressed_matrix_adaptor<T, I, Orientation>, cpu_tag >{
361//~ public:
362 //~ typedef I size_type;
363 //~ typedef T value_type;
364 //~ typedef T const& const_reference;
365 //~ typedef T& reference;
366
367 //~ typedef detail::compressed_matrix_proxy<compressed_matrix<T, I, Orientation> const, Orientation> const_closure_type;
368 //~ typedef detail::compressed_matrix_proxy<compressed_matrix<T, I, Orientation>, Orientation> closure_type;
369 //~ typedef sparse_matrix_storage<T, I> storage_type;
370 //~ typedef sparse_matrix_storage<T const, I const> const_storage_type;
371 //~ typedef elementwise<sparse_tag> evaluation_category;
372 //~ typedef Orientation orientation;
373
374 //~ compressed_matrix_adaptor(size_type rows, size_type cols, storage_type storage)
375 //~ :m_impl(detail::MatrixStorageAdaptor<T,I>(orientation::index_M(rows,cols),orientation::index_m(rows,cols)),storage){}
376
377 //~ template<class E>
378 //~ compressed_matrix operator=(matrix_container<E, cpu_tag> const& m){
379 //~ return assign(*this,m);
380 //~ }
381 //~ template<class E>
382 //~ compressed_matrix& operator=(matrix_expression<E, cpu_tag> const& m){
383 //~ compressed_matrix temporary(m);
384 //~ swap(*this,temporary);
385 //~ return *this;
386 //~ }
387
388 //~ ///\brief Number of rows of the matrix
389 //~ size_type size1() const {
390 //~ return orientation::index_M(m_impl.major_size(), m_impl.minor_size());
391 //~ }
392
393 //~ ///\brief Number of columns of the matrix
394 //~ size_type size2() const {
395 //~ return orientation::index_m(m_impl.major_size(), m_impl.minor_size());
396 //~ }
397
398 //~ /// \brief Number of nonzeros this matrix can maximally store before memory is exhausted
399 //~ std::size_t nnz_capacity() const{
400 //~ return m_impl.nnz_capacity();
401 //~ }
402 //~ /// \brief Number of reserved elements in the matrix (> number of nonzeros stored, < nnz_capacity)
403 //~ std::size_t nnz_reserved() const {
404 //~ return m_impl.nnz_reserved();
405 //~ }
406 //~ /// \brief Number of nonzeros the major index (a row or column depending on orientation) can maximally store before a resize
407 //~ std::size_t major_capacity(size_type i)const{
408 //~ return m_impl.major_capacity(i);
409 //~ }
410 //~ /// \brief Number of nonzeros the major index (a row or column depending on orientation) currently stores
411 //~ std::size_t major_nnz(size_type i) const {
412 //~ return m_impl.major_nnz(i);
413 //~ }
414
415 //~ /// \brief Set the total number of nonzeros stored by the matrix
416 //~ void set_nnz(std::size_t non_zeros) {
417 //~ m_impl.set_nnz(non_zeros);
418 //~ }
419 //~ /// \brief Set the number of nonzeros stored in the major index (a row or column depending on orientation)
420 //~ void set_major_nnz(size_type i,std::size_t non_zeros) {
421 //~ m_impl.set_major_nnz(i,non_zeros);
422 //~ }
423
424 //~ const_storage_type raw_storage()const{
425 //~ return m_impl.raw_storage();
426 //~ }
427 //~ storage_type raw_storage(){
428 //~ return m_impl.raw_storage();
429 //~ }
430
431 //~ typename device_traits<cpu_tag>::queue_type& queue() const{
432 //~ return device_traits<cpu_tag>::default_queue();
433 //~ }
434
435 //~ void reserve(std::size_t non_zeros) {
436 //~ m_impl.reserve(non_zeros);
437 //~ }
438
439 //~ void major_reserve(size_type i, std::size_t non_zeros) {
440 //~ m_impl.major_reserve(i, non_zeros, true);
441 //~ }
442
443 //~ typedef typename detail::compressed_matrix_impl<detail::MatrixStorage<T,I> >::const_major_iterator const_major_iterator;
444 //~ typedef typename detail::compressed_matrix_impl<detail::MatrixStorage<T,I> >::major_iterator major_iterator;
445
446 //~ const_major_iterator major_begin(size_type i) const {
447 //~ return m_impl.cmajor_begin(i);
448 //~ }
449
450 //~ const_major_iterator major_end(size_type i) const{
451 //~ return m_impl.cmajor_end(i);
452 //~ }
453
454 //~ major_iterator major_begin(size_type i) {
455 //~ return m_impl.major_begin(i);
456 //~ }
457
458 //~ major_iterator major_end(size_type i) {
459 //~ return m_impl.major_end(i);
460 //~ }
461
462 //~ major_iterator set_element(major_iterator pos, size_type index, value_type value){
463 //~ return m_impl.set_element(pos, index, value);
464 //~ }
465
466 //~ major_iterator clear_range(major_iterator start, major_iterator end) {
467 //~ return m_impl.clear_range(start,end);
468 //~ }
469
470 //~ void clear() {
471 //~ for(std::size_t i = 0; i != m_impl.major_size(); ++i){
472 //~ clear_range(major_begin(i),major_end(i));
473 //~ }
474 //~ }
475//~ private:
476 //~ detail::compressed_matrix_impl<detail::MatrixStorage<T,I> > m_impl;
477//~ };
478
479namespace detail{
480////////////////////////MATRIX ROW//////////////////////
481template<class M>
482struct matrix_row_optimizer<detail::compressed_matrix_proxy<M, row_major> >{
483 typedef compressed_matrix_row<detail::compressed_matrix_proxy<M, row_major> > type;
484
485 static type create(detail::compressed_matrix_proxy<M, row_major> const& m, std::size_t i){
486 //create vector reference
487 return type(m,i);
488 }
489};
490
491
492////////////////////////MATRIX TRANSPOSE//////////////////////
493template<class M, class Orientation>
494struct matrix_transpose_optimizer<detail::compressed_matrix_proxy<M, Orientation> >{
495 typedef detail::compressed_matrix_proxy<M, typename Orientation::transposed_orientation> type;
496
497 static type create(detail::compressed_matrix_proxy<M, Orientation> const& m){
498 return type(m.matrix(), m.start(), m.end());
499 }
500};
501
502////////////////////////MATRIX ROWS//////////////////////
503template<class M>
504struct matrix_rows_optimizer<detail::compressed_matrix_proxy<M, row_major> >{
505 typedef detail::compressed_matrix_proxy<M, row_major> type;
506
507 static type create(detail::compressed_matrix_proxy<M, row_major> const& m,
508 std::size_t start, std::size_t end
509 ){
510 return type(m.matrix(), start + m.start(), end+m.start());
511 }
512};
513}
514
515template<class T, class O>
516struct matrix_temporary_type<T,O,sparse_tag, cpu_tag> {
517 typedef compressed_matrix<T,std::size_t, O> type;
518};
519
520template<class T>
521struct vector_temporary_type<T,sparse_tag, cpu_tag>{
522 typedef compressed_vector<T> type;
523};
524
525}
526#endif