sparse.hpp
Go to the documentation of this file.
1/*!
2 * \brief Implementation of the sparse matrix class
3 *
4 * \author O. Krause
5 * \date 2017
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_CPU_SPARSE_HPP
29#define REMORA_CPU_SPARSE_HPP
30
31#include "iterator.hpp"
32
33#include <vector>
34
35#include <boost/serialization/collection_size_type.hpp>
36#include <boost/serialization/nvp.hpp>
37#include <boost/serialization/vector.hpp>
38
39namespace remora{ namespace detail{
40
41template<class T, class I>
42struct VectorStorageReference{
43 typedef sparse_vector_storage<T,I> storage_type;
44 typedef I size_type;
45 typedef T value_type;
46
47 std::size_t max_capacity() const{
48 return m_storage.capacity;
49 }
50
51 void reserve(size_type non_zeros){
52 assert(non_zeros <= max_capacity());
53 }
54
55 VectorStorageReference(storage_type const& storage)
56 : m_storage(storage){}
57
58 storage_type m_storage;
59};
60
61
62template<class T, class I>
63struct VectorStorage{
64 typedef sparse_vector_storage<T,I> storage_type;
65 typedef I size_type;
66 typedef T value_type;
67
68 std::size_t max_capacity() const{
69 return std::numeric_limits<std::size_t>::max()/sizeof(T);
70 }
71
72 void reserve(size_type non_zeros){
73 if(non_zeros > m_storage.capacity){
74 m_indices.resize(non_zeros);
75 m_values.resize(non_zeros);
76 }
77 m_storage.values = m_values.data();
78 m_storage.indices = m_indices.data();
79 m_storage.capacity = non_zeros;
80 }
81
82 VectorStorage(): m_storage({nullptr,nullptr,0,0}){}
83
84 template<class Archive>
85 void serialize(Archive& ar, const unsigned int /* file_version */) {
86 ar & boost::serialization::make_nvp("nnz", m_storage.nnz);
87 ar & boost::serialization::make_nvp("capacity", m_storage.capacity);
88 ar & boost::serialization::make_nvp("indices", m_indices);
89 ar & boost::serialization::make_nvp("values", m_values);
90 m_storage.values = m_values.data();
91 m_storage.indices = m_indices.data();
92 }
93 storage_type m_storage;
94private:
95 std::vector<T> m_values;
96 std::vector<I> m_indices;
97};
98
99template<class StorageManager>
100struct BaseSparseVector{
101 typedef typename StorageManager::storage_type storage_type;
102 typedef typename StorageManager::size_type size_type;
103 typedef typename StorageManager::value_type value_type;
104
105 BaseSparseVector(StorageManager const& manager, std::size_t size, std::size_t nnz)
106 : m_manager(manager)
107 , m_size(size){};
108
109 /// \brief Return the size of the vector
110 size_type size() const {
111 return m_size;
112 }
113
114 /// \brief number of non-zeros currently stored in the vector
115 size_type nnz() const {
116 return m_manager.m_storage.nnz;
117 }
118
119 /// \brief number of nnz that can be stored before more memory needs to be allocated
120 size_type nnz_capacity() const{
121 return m_manager.m_storage.capacity;
122 }
123
124 /// \brief upper bound for nnz capacity
125 size_type max_nnz_capacity() const{
126 return std::min(size(), m_manager.max_capacity());
127 }
128
129 /// \brief reserve space for more non-zero elements
130 void reserve(size_type non_zeros) {
131 if(non_zeros <= nnz_capacity()) return;
132 m_manager.reserve(non_zeros);
133 }
134
135
136 // --------------
137 // ITERATORS
138 // --------------
139
140 typedef iterators::compressed_storage_iterator<value_type, size_type> iterator;
141 typedef iterators::compressed_storage_iterator<value_type const, size_type const> const_iterator;
142
143 /// \brief return an iterator behind the last non-zero element of the vector
144 const_iterator begin() const {
145 return const_iterator(m_manager.m_storage.values, m_manager.m_storage.indices, 0);
146 }
147
148 /// \brief return an iterator behind the last non-zero element of the vector
149 const_iterator end() const {
150 return const_iterator(m_manager.m_storage.values, m_manager.m_storage.indices, nnz());
151 }
152
153 /// \brief return an iterator behind the last non-zero element of the vector
154 iterator begin() {
155 return iterator(m_manager.m_storage.values, m_manager.m_storage.indices, 0);
156 }
157
158 /// \brief return an iterator behind the last non-zero element of the vector
159 iterator end() {
160 return iterator(m_manager.m_storage.values, m_manager.m_storage.indices, nnz());
161 }
162
163 iterator set_element(iterator pos, size_type index, value_type value) {
164 REMORA_RANGE_CHECK(size_type(pos - begin()) <=m_size);
165
166 if(pos != end() && pos.index() == index){
167 *pos = value;
168 return pos + 1;
169 }
170 //get position of the new element in the array.
171 std::ptrdiff_t arrayPos = pos - begin();
172 if(nnz() == nnz_capacity())//reserve more space if needed, this invalidates pos.
173 reserve(std::min(std::max<size_type>(5,2 * nnz_capacity()),max_nnz_capacity()));
174
175 //copy the remaining elements to make space for the new ones
176 auto values = m_manager.m_storage.values;
177 auto indices = m_manager.m_storage.indices;
178 std::copy_backward(values + arrayPos, values + nnz() , values + nnz() +1);
179 std::copy_backward(indices + arrayPos, indices + nnz(), indices + nnz() +1);
180 //insert new element
181 values[arrayPos] = value;
182 indices[arrayPos] = index;
183 m_manager.m_storage.nnz += 1;
184
185 //return new iterator to the next element.
186 return iterator(values,indices,arrayPos+1);
187 }
188
189 iterator clear_range(iterator start, iterator end) {
190 //get position of the elements in the array.
191 std::ptrdiff_t startPos = start - begin();
192 std::ptrdiff_t endPos = end - begin();
193
194 //remove the elements in the range
195 auto values = m_manager.m_storage.values;
196 auto indices = m_manager.m_storage.indices;
197 std::copy(values + endPos, values + nnz(), values + startPos);
198 std::copy(indices + endPos, indices + nnz() , indices + startPos);
199 m_manager.m_storage.nnz -= endPos - startPos;
200 //return new iterator to the next element
201 return iterator(values, indices, startPos);
202 }
203
204 iterator clear_element(iterator pos){
205 auto end = pos + 1;
206 return clear_range(pos, end);
207 }
208
209 void clear(){
210 clear_range(begin(),end());
211 }
212protected:
213 StorageManager m_manager;
214 std::size_t m_size;
215
216 void do_resize(size_type size, bool keep){
217 //delete all elements which have indices larger than the new size
218 if(size < m_size){
219 auto pos = keep? end() : begin();
220 auto start = begin();
221 while(pos != start){
222 auto new_pos = pos-1;
223 if(pos.index() < size)
224 break;
225 pos = new_pos;
226 }
227 clear_range(pos,end());
228 }
229 m_size = size;
230 }
231};
232
233template<class V>
234class compressed_vector_reference: public vector_expression<compressed_vector_reference<V>, cpu_tag >{
235private:
236 template<class> friend class compressed_vector_reference;
237public:
238 typedef typename V::size_type size_type;
239 typedef typename V::value_type value_type;
240 typedef typename V::const_reference const_reference;
241 typedef typename remora::reference<V>::type reference;
242
243 typedef compressed_vector_reference<V const> const_closure_type;
244 typedef compressed_vector_reference closure_type;
245 typedef typename remora::storage<V>::type storage_type;
246 typedef typename V::const_storage_type const_storage_type;
247 typedef elementwise<sparse_tag> evaluation_category;
248
249 // Construction
250 compressed_vector_reference(V& v):m_vector(&v){}
251 //copy or conversion ctor non-const ->const proxy
252 compressed_vector_reference(compressed_vector_reference<typename std::remove_const<V>::type > const& ref):m_vector(ref.m_vector){}
253
254 //assignment from different expression
255 template<class E>
256 compressed_vector_reference& operator=(matrix_expression<E, cpu_tag> const& e){
257 return assign(*this, typename vector_temporary<E>::type(e));
258 }
259
260 compressed_vector_reference& operator=(compressed_vector_reference const& e){
261 return assign(*this, typename vector_temporary<V>::type(e));
262 }
263
264 ///\brief Returns the underlying storage structure for low level access
265 storage_type raw_storage(){
266 return m_vector->raw_storage();
267 }
268
269 ///\brief Returns the underlying storage structure for low level access
270 const_storage_type raw_storage() const{
271 return m_vector->raw_storage();
272 }
273
274 /// \brief Return the size of the vector
275 size_type size() const {
276 return m_vector->size();
277 }
278
279 size_type nnz() const {
280 return m_vector->nnz();
281 }
282
283 size_type nnz_capacity() const {
284 return m_vector->nnz_capacity();
285 }
286
287 void reserve(size_type non_zeros) {
288 m_vector->reserve(non_zeros);
289 }
290
291 typename device_traits<cpu_tag>::queue_type& queue(){
292 return device_traits<cpu_tag>::default_queue();
293 }
294
295 // --------------
296 // ITERATORS
297 // --------------
298
299 typedef typename std::conditional<
300 std::is_const<V>::value,
301 typename V::const_iterator,
302 typename V::iterator
303 >::type iterator;
304 typedef iterator const_iterator;
305
306 /// \brief return an iterator tp the first non-zero element of the vector
307 iterator begin() const {
308 return m_vector->begin();
309 }
310
311 /// \brief return an iterator behind the last non-zero element of the vector
312 iterator end() const {
313 return m_vector->end();
314 }
315
316 iterator set_element(iterator pos, size_type index, value_type value) {
317 return m_vector->set_element(pos,index,value);
318 }
319
320 iterator clear_range(iterator start, iterator end) {
321 m_vector->clear_range(start,end);
322 }
323
324 iterator clear_element(iterator pos){
325 m_vector->clear_element(pos);
326 }
327
328 void clear(){
329 m_vector->clear();
330 }
331private:
332 V* m_vector;
333};
334
335}}
336#endif