Skylark (Sketching Library)
0.1
|
00001 #ifndef SKYLARK_SPARSE_MATRIX_HPP 00002 #define SKYLARK_SPARSE_MATRIX_HPP 00003 00004 #include <set> 00005 #include <vector> 00006 #include <boost/tuple/tuple.hpp> 00007 #include <boost/unordered_map.hpp> 00008 00009 namespace skylark { namespace base { 00010 00019 template<typename ValueType=double> 00020 struct sparse_matrix_t { 00021 00022 typedef int index_type; 00023 typedef ValueType value_type; 00024 00025 typedef boost::tuple<index_type, index_type, value_type> coord_tuple_t; 00026 typedef std::vector<coord_tuple_t> coords_t; 00027 00028 sparse_matrix_t() 00029 : _ownindptr(false), _ownindices(false), _ownvalues(false), 00030 _dirty_struct(false), _height(0), _width(0), _nnz(0), 00031 _indptr(nullptr), _indices(nullptr), _values(nullptr) 00032 {} 00033 00034 // The following relies on C++11 00035 sparse_matrix_t(sparse_matrix_t<ValueType>&& A) : 00036 _ownindptr(A._ownindptr), _ownindices(A._ownindices), 00037 _ownvalues(A._ownvalues), _dirty_struct(A._dirty_struct), 00038 _height(A._height), _width(A._width), _nnz(A._nnz), 00039 _indptr(A._indptr), _indices(A._indices), _values(A._values) 00040 { 00041 A._ownindptr = false; 00042 A._ownindices = false; 00043 A._ownvalues = false; 00044 } 00045 00046 ~sparse_matrix_t() { 00047 _free_data(); 00048 } 00049 00050 bool struct_updated() const { return _dirty_struct; } 00051 void reset_update_flag() { _dirty_struct = false; } 00052 00056 template<typename IdxType, typename ValType> 00057 void detach(IdxType *indptr, IdxType *indices, ValType *values) const { 00058 00059 for(size_t i = 0; i <= _width; ++i) 00060 indptr[i] = static_cast<IdxType>(_indptr[i]); 00061 00062 for(size_t i = 0; i < _nnz; ++i) { 00063 indices[i] = static_cast<IdxType>(_indices[i]); 00064 values[i] = static_cast<ValType>(_values[i]); 00065 } 00066 } 00067 00071 void attach(const index_type *indptr, const index_type *indices, double *values, 00072 int nnz, int n_rows, int n_cols, bool _own = false) { 00073 attach(indptr, indices, values, nnz, n_rows, n_cols, _own, _own, _own); 00074 } 00075 00079 void attach(const index_type *indptr, const index_type *indices, double *values, 00080 int nnz, int n_rows, int n_cols, 00081 bool ownindptr, bool ownindices, bool ownvalues) { 00082 _free_data(); 00083 00084 _indptr = indptr; 00085 _indices = indices; 00086 _values = values; 00087 _nnz = nnz; 00088 _width = n_cols; 00089 _height = n_rows; 00090 00091 _ownindptr = ownindptr; 00092 _ownindices = ownindices; 00093 _ownvalues = ownvalues; 00094 00095 _dirty_struct = true; 00096 } 00097 00098 00099 // attaching a coordinate structure facilitates going from distributed 00100 // input to local output. 00101 void set(coords_t coords, int n_rows = 0, int n_cols = 0) { 00102 00103 sort(coords.begin(), coords.end(), &sparse_matrix_t::_sort_coords); 00104 00105 n_cols = std::max(n_cols, boost::get<1>(coords.back()) + 1); 00106 index_type *indptr = new index_type[n_cols + 1]; 00107 00108 // Count non-zeros 00109 int nnz = 0; 00110 for(size_t i = 0; i < coords.size(); ++i) { 00111 nnz++; 00112 index_type cur_row = boost::get<0>(coords[i]); 00113 index_type cur_col = boost::get<1>(coords[i]); 00114 while(i + 1 < coords.size() && 00115 cur_row == boost::get<0>(coords[i + 1]) && 00116 cur_col == boost::get<1>(coords[i + 1])) 00117 i++; 00118 } 00119 00120 index_type *indices = new index_type[nnz]; 00121 value_type *values = new value_type[nnz]; 00122 00123 nnz = 0; 00124 int indptr_idx = 0; 00125 indptr[indptr_idx] = 0; 00126 for(size_t i = 0; i < coords.size(); ++i) { 00127 index_type cur_row = boost::get<0>(coords[i]); 00128 index_type cur_col = boost::get<1>(coords[i]); 00129 value_type cur_val = boost::get<2>(coords[i]); 00130 00131 for(; indptr_idx < cur_col; ++indptr_idx) 00132 indptr[indptr_idx + 1] = nnz; 00133 nnz++; 00134 00135 // sum duplicates 00136 while(i + 1 < coords.size() && 00137 cur_row == boost::get<0>(coords[i + 1]) && 00138 cur_col == boost::get<1>(coords[i + 1])) { 00139 00140 cur_val += boost::get<2>(coords[i + 1]); 00141 i++; 00142 } 00143 00144 indices[nnz - 1] = cur_row; 00145 values[nnz - 1] = cur_val; 00146 00147 n_rows = std::max(cur_row + 1, n_rows); 00148 } 00149 00150 for(; indptr_idx < n_cols; ++indptr_idx) 00151 indptr[indptr_idx + 1] = nnz; 00152 00153 attach(indptr, indices, values, nnz, n_rows, n_cols, true); 00154 } 00155 00156 int height() const { 00157 return _height; 00158 } 00159 00160 int width() const { 00161 return _width; 00162 } 00163 00164 int nonzeros() const { 00165 return _nnz; 00166 } 00167 00168 const index_type* indptr() const { 00169 return _indptr; 00170 } 00171 00172 const index_type* indices() const { 00173 return _indices; 00174 } 00175 00176 value_type* values() { 00177 return _values; 00178 } 00179 00180 const value_type* locked_values() const { 00181 return _values; 00182 } 00183 00184 bool operator==(const sparse_matrix_t &rhs) const { 00185 00186 // column pointer arrays have to be exactly the same 00187 if (std::vector<int>(_indptr, _indptr+_width) != 00188 std::vector<int>(rhs._indptr, rhs._indptr + rhs._width)) 00189 return false; 00190 00191 // check more carefully for unordered row indices 00192 const int* indptr = _indptr; 00193 const int* indices = _indices; 00194 const double* values = _values; 00195 00196 const int* indices_rhs = rhs.indices(); 00197 const double* values_rhs = rhs.locked_values(); 00198 00199 for(int col = 0; col < width(); col++) { 00200 00201 boost::unordered_map<int, double> col_values; 00202 00203 for(int idx = indptr[col]; idx < indptr[col + 1]; idx++) 00204 col_values.insert(std::make_pair(indices[idx], values[idx])); 00205 00206 for(int idx = indptr[col]; idx < indptr[col + 1]; idx++) { 00207 if(col_values[indices_rhs[idx]] != values_rhs[idx]) 00208 return false; 00209 } 00210 } 00211 00212 return true; 00213 } 00214 00215 private: 00216 bool _ownindptr; 00217 bool _ownindices; 00218 bool _ownvalues; 00219 00220 bool _dirty_struct; 00221 00222 int _height; 00223 int _width; 00224 int _nnz; 00225 00226 const index_type* _indptr; 00227 const index_type* _indices; 00228 value_type* _values; 00229 00230 // TODO add the following 00231 sparse_matrix_t(const sparse_matrix_t&); 00232 void operator=(const sparse_matrix_t&); 00233 00234 void _free_data() { 00235 if (_ownindptr) 00236 delete[] _indptr; 00237 if (_ownindices) 00238 delete[] _indices; 00239 if (_ownvalues) 00240 delete[] _values; 00241 } 00242 00243 static bool _sort_coords(coord_tuple_t lhs, coord_tuple_t rhs) { 00244 if(boost::get<1>(lhs) != boost::get<1>(rhs)) 00245 return boost::get<1>(lhs) < boost::get<1>(rhs); 00246 else 00247 return boost::get<0>(lhs) < boost::get<0>(rhs); 00248 } 00249 }; 00250 00251 template<typename T> 00252 void Transpose(const sparse_matrix_t<T>& A, sparse_matrix_t<T>& B) { 00253 const int* aindptr = A.indptr(); 00254 const int* aindices = A.indices(); 00255 const double* avalues = A.locked_values(); 00256 00257 int m = A.width(); 00258 int n = A.height(); 00259 int nnz = A.nonzeros(); 00260 00261 int *indptr = new int[n + 1]; 00262 int *indices = new int[nnz]; 00263 double *values = new double[nnz]; 00264 00265 // Count nonzeros in each row 00266 int *nzrow = new int[n]; 00267 std::fill(nzrow, nzrow + n, 0); 00268 for(int col = 0; col < m; col++) 00269 for(int idx = aindptr[col]; idx < aindptr[col + 1]; idx++) 00270 nzrow[aindices[idx]]++; 00271 00272 // Set indptr 00273 indptr[0] = 0; 00274 for(int col = 1; col <= n; col++) 00275 indptr[col] = indptr[col - 1] + nzrow[col - 1]; 00276 00277 // Fill values 00278 std::fill(nzrow, nzrow + n, 0); 00279 for(int col = 0; col < m; col++) 00280 for(int idx = aindptr[col]; idx < aindptr[col + 1]; idx++) { 00281 int row = aindices[idx]; 00282 double val = avalues[idx]; 00283 indices[indptr[row] + nzrow[row]] = col; 00284 values[indptr[row] + nzrow[row]] = val; 00285 nzrow[row]++; 00286 } 00287 00288 delete[] nzrow; 00289 00290 B.attach(indptr, indices, values, nnz, m, n, true); 00291 } 00292 00293 } } 00294 00295 #endif