Chi-Tech
chi_math_sparse_matrix.cc
Go to the documentation of this file.
2
3#include "chi_runtime.h"
4#include "chi_log.h"
5
6#include <iomanip>
7#include <algorithm>
8
9//###################################################################
10/**Constructor with number of rows and columns constructor.*/
11chi_math::SparseMatrix::SparseMatrix(size_t num_rows, size_t num_cols) :
12 row_size_(num_rows),
13 col_size_(num_cols)
14{
15 rowI_values_.resize(num_rows, std::vector<double>());
16 rowI_indices_.resize(num_rows, std::vector<size_t>());
17}
18
19//###################################################################
20/**Copy constructor.*/
22 SparseMatrix(const chi_math::SparseMatrix& in_matrix) :
23 row_size_(in_matrix.NumRows()),
24 col_size_(in_matrix.NumCols())
25{
26 rowI_values_.resize(row_size_, std::vector<double>());
27 rowI_indices_.resize(row_size_, std::vector<size_t>());
28
29 for (size_t i=0; i<in_matrix.rowI_values_.size(); i++)
30 {
31 rowI_values_[i] = (in_matrix.rowI_values_[i]);
32 rowI_indices_[i] = (in_matrix.rowI_indices_[i]);
33 }
34}
35
36//###################################################################
37/**Inserts a value into the matrix.*/
38void chi_math::SparseMatrix::Insert(size_t i, size_t j, double value)
39{
40 CheckInitialized();
41
42 if ((i<0) || (i >= row_size_) || (j < 0) || (j >= col_size_))
43 {
45 << "SparseMatrix::Insert encountered out of bounds,"
46 << " i=" << i << " j=" << j
47 << " bounds(" << row_size_ << "," << col_size_ << ")";
48 Chi::Exit(EXIT_FAILURE);
49 }
50
51 auto relative_location = std::find(rowI_indices_[i].begin(),
52 rowI_indices_[i].end(), j);
53 bool already_there = (relative_location != rowI_indices_[i].end());
54
55 if (already_there)
56 {
57 size_t jr = relative_location - rowI_indices_[i].begin();
58 rowI_values_[i][jr] = value;
59 }
60 else
61 {
62 rowI_values_[i].push_back(value);
63 rowI_indices_[i].push_back(j);
64 }
65}
66
67//###################################################################
68/**Inserts-Adds a value into the matrix with duplicate check.*/
69void chi_math::SparseMatrix::InsertAdd(size_t i, size_t j, double value)
70{
71 CheckInitialized();
72
73 if ((i<0) || (i >= row_size_) || (j < 0) || (j >= col_size_))
74 {
76 << "SparseMatrix::Insert encountered out of bounds,"
77 << " i=" << i << " j=" << j
78 << " bounds(" << row_size_ << "," << col_size_ << ")";
79 Chi::Exit(EXIT_FAILURE);
80 }
81
82 auto relative_location = std::find(rowI_indices_[i].begin(),
83 rowI_indices_[i].end(), j);
84 bool already_there = (relative_location != rowI_indices_[i].end());
85
86 if (already_there)
87 {
88 size_t jr = relative_location - rowI_indices_[i].begin();
89 rowI_values_[i][jr] += value;
90 }
91 else
92 {
93 rowI_values_[i].push_back(value);
94 rowI_indices_[i].push_back(j);
95 }
96}
97
98//###################################################################
99/**Sets the diagonal of the matrix using a vector.*/
100void chi_math::SparseMatrix::SetDiagonal(const std::vector<double>& diag)
101{
102 CheckInitialized();
103
104 size_t num_rows = rowI_values_.size();
105 //============================================= Check size
106 if (diag.size() != rowI_values_.size())
107 {
109 << "Incompatible matrix-vector size encountered "
110 << "in call to SparseMatrix::SetDiagonal.";
111 Chi::Exit(EXIT_FAILURE);
112 }
113
114 //============================================= Assign values
115 for (size_t i=0; i<num_rows; i++)
116 {
117 auto relative_location = std::find(rowI_indices_[i].begin(),
118 rowI_indices_[i].end(), i);
119 bool already_there = (relative_location != rowI_indices_[i].end());
120
121 if (already_there)
122 {
123 size_t jr = relative_location - rowI_indices_[i].begin();
124 rowI_values_[i][jr] = diag[i];
125 }
126 else
127 {
128 rowI_values_[i].push_back(diag[i]);
129 rowI_indices_[i].push_back(i);
130 }
131 }//for i
132}
133
134//###################################################################
135/**Returns the value in the matrix at the given location. This
136 * is a rather inefficient routine. Use the columns and values
137 * rather than directly this function.*/
138double chi_math::SparseMatrix::ValueIJ(size_t i, size_t j) const
139{
140 double retval = 0.0;
141 if ((i<0) || (i >= rowI_indices_.size()))
142 {
144 << "Index i out of bounds"
145 << " in call to SparseMatrix::ValueIJ"
146 << " i=" << i;
147 Chi::Exit(EXIT_FAILURE);
148 }
149
150 if (not rowI_indices_[i].empty())
151 {
152 auto relative_location = std::find(rowI_indices_[i].begin(),
153 rowI_indices_[i].end(), j);
154 bool non_zero = (relative_location != rowI_indices_[i].end());
155 if (non_zero)
156 {
157 size_t jr = relative_location - rowI_indices_[i].begin();
158 retval = rowI_values_[i][jr];
159 }
160 }
161 return retval;
162}
163
164//###################################################################
165/**Sorts the column indices of each row for faster lookup.*/
167{
168 for (size_t i=0; i < rowI_indices_.size(); ++i)
169 {
170 auto& indices = rowI_indices_[i];
171 auto& values = rowI_values_[i];
172
173 //====================================== Copy row indexes and values into
174 // vector of pairs
175 std::vector<std::pair<size_t,double>> target;
176 target.reserve(indices.size());
177
178 auto index = indices.begin();
179 auto value = values.begin();
180 for (;index!=indices.end(); ++index, ++value)
181 {
182 target.emplace_back(*index,*value);
183 }
184
185 //====================================== Define compare operator
186 struct
187 {
188 bool operator()(std::pair<size_t,double> a, std::pair<size_t,double> b)
189 {
190 return a.first < b.first;
191 }
192 }compare_index;
193
194 //Sort
195 std::stable_sort(target.begin(), target.end(), compare_index);
196
197 //====================================== Copy back
198 indices.clear();
199 values.clear();
200 for (auto& iv_pair : target)
201 {
202 indices.push_back(iv_pair.first);
203 values.push_back(iv_pair.second);
204 }
205 }
206
207}
208
209//###################################################################
210/**Prints the sparse matrix to string.*/
212{
213 std::stringstream out;
214
215
216 for (size_t i=0; i < row_size_; i++)
217 {
218 for (size_t j=0; j < col_size_; j++)
219 {
220 auto relative_location = std::find(rowI_indices_[i].begin(),
221 rowI_indices_[i].end(), j);
222 bool non_zero = (relative_location != rowI_indices_[i].end());
223
224 if (non_zero)
225 {
226 size_t jr = relative_location - rowI_indices_[i].begin();
227 out
228 << std::setprecision(2)
229 << std::scientific
230 << std::setw(9)
231 << rowI_values_[i][jr] << " ";
232 }
233 else
234 {
235 out
236 << std::setprecision(0)
237 << std::fixed
238 << std::setw(9)
239 << 0.0 << " ";
240 }
241 }
242 out << "\n";
243 }
244
245 return out.str();
246}
247
248//###################################################################
249/**Constructor with number of rows constructor.*/
251{
252 if (rowI_values_.empty())
253 {
255 << "Illegal call to unitialized SparseMatrix matrix.";
256 Chi::Exit(EXIT_FAILURE);
257 }
258}
259
260//###################################################################
261// Iterator routines
262namespace chi_math
263{
265 {return {*this, row_id};}
266
268 {return {*this, row_id};}
269
271 {
272 //Find first non-empty row
273 size_t nerow = row_size_; //nerow = non-empty row
274 for (size_t r=0; r < row_size_; ++r)
275 if (not rowI_indices_[r].empty())
276 { nerow = r;break;}
277
278 return EntriesIterator(*this, nerow);
279 }
280
282 {return EntriesIterator(*this, row_size_);}
283}
284
285
286
static void Exit(int error_code)
Definition: chi_runtime.cc:342
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream LogAllError()
Definition: chi_log.h:239
void Insert(size_t i, size_t j, double value)
SparseMatrix(size_t num_rows, size_t num_cols)
RowIteratorContext Row(size_t row_id)
std::vector< std::vector< double > > rowI_values_
void InsertAdd(size_t i, size_t j, double value)
double ValueIJ(size_t i, size_t j) const
std::vector< std::vector< size_t > > rowI_indices_
size_t row_size_
Maximum number of rows for this matrix.
void SetDiagonal(const std::vector< double > &diag)