PolyFEM
Loading...
Searching...
No Matches
MatrixCache.cpp
Go to the documentation of this file.
1#include "MatrixCache.hpp"
2
5
6namespace polyfem::utils
7{
9 {
10 init(size);
11 }
12
13 SparseMatrixCache::SparseMatrixCache(const size_t rows, const size_t cols)
14 {
15 init(rows, cols);
16 }
17
19 {
20 init(other);
21 }
22
24 const SparseMatrixCache &other, const bool copy_main_cache_ptr)
25 {
26 init(other, copy_main_cache_ptr);
27 }
28
29 void SparseMatrixCache::init(const size_t size)
30 {
31 assert(mapping().empty() || size_ == size);
32
33 size_ = size;
34 tmp_.resize(size_, size_);
35 mat_.resize(size_, size_);
36 mat_.setZero();
37 }
38
39 void SparseMatrixCache::init(const size_t rows, const size_t cols)
40 {
41 assert(mapping().empty());
42
43 size_ = rows == cols ? rows : 0;
44 tmp_.resize(rows, cols);
45 mat_.resize(rows, cols);
46 mat_.setZero();
47 }
48
50 {
51 assert(this != &other);
52 assert(&other == &dynamic_cast<const SparseMatrixCache &>(other));
53 init(dynamic_cast<const SparseMatrixCache &>(other));
54 }
55
57 const SparseMatrixCache &other, const bool copy_main_cache_ptr)
58 {
59 assert(this != &other);
60 if (copy_main_cache_ptr)
61 {
63 }
64 else if (main_cache_ == nullptr)
65 {
66 main_cache_ = other.main_cache();
67 // Only one level of cache
68 assert(main_cache_ != this && main_cache_ != nullptr && main_cache_->main_cache_ == nullptr);
69 }
70 size_ = other.size_;
71
72 values_.resize(other.values_.size());
73
74 tmp_.resize(other.mat_.rows(), other.mat_.cols());
75 mat_.resize(other.mat_.rows(), other.mat_.cols());
76 mat_.setZero();
77 std::fill(values_.begin(), values_.end(), 0);
78 }
79
81 {
82 tmp_.setZero();
83 mat_.setZero();
84
85 std::fill(values_.begin(), values_.end(), 0);
86 }
87
88 void SparseMatrixCache::add_value(const int e, const int i, const int j, const double value)
89 {
90 // caches have yet to be constructed (likely because the matrix has yet to be fully assembled)
91 if (mapping().empty())
92 {
93 // save entry so it can be added to the matrix later
94 entries_.emplace_back(i, j, value);
95
96 // save the index information so the cache can be built later
97 if (second_cache_entries_.size() <= e)
98 second_cache_entries_.resize(e + 1);
99 second_cache_entries_[e].emplace_back(i, j);
100 }
101 else
102 {
103 if (e != current_e_)
104 {
105 current_e_ = e;
107 }
108
109 // save entry directly to value buffer at the proper index
110 values_[second_cache()[e][current_e_index_]] += value;
112 }
113 }
114
116 {
117 // caches have yet to be constructed (likely because the matrix has yet to be fully assembled)
118 if (mapping().empty())
119 {
120 tmp_.setFromTriplets(entries_.begin(), entries_.end());
121 tmp_.makeCompressed();
122 mat_ += tmp_;
123
124 tmp_.setZero();
125 tmp_.data().squeeze();
126 mat_.makeCompressed();
127
128 entries_.clear();
129
130 mat_.makeCompressed();
131 }
132 }
133
135 {
136 prune();
137
138 // caches have yet to be constructed (likely because the matrix has yet to be fully assembled)
139 if (mapping().empty())
140 {
141 if (compute_mapping && size_ > 0)
142 {
143 assert(main_cache_ == nullptr);
144
145 values_.resize(mat_.nonZeros());
146 inner_index_.resize(mat_.nonZeros());
147 outer_index_.resize(mat_.rows() + 1);
148 mapping_.resize(mat_.rows());
149
150 // note: mat_ is column major
151 const auto inn_ptr = mat_.innerIndexPtr();
152 const auto out_ptr = mat_.outerIndexPtr();
153 inner_index_.assign(inn_ptr, inn_ptr + inner_index_.size());
154 outer_index_.assign(out_ptr, out_ptr + outer_index_.size());
155
156 size_t index = 0;
157 // loop over columns of the matrix
158 for (size_t i = 0; i < mat_.cols(); ++i)
159 {
160 const auto start = outer_index_[i];
161 const auto end = outer_index_[i + 1];
162
163 // loop over the nonzero elements of the given column
164 for (size_t ii = start; ii < end; ++ii)
165 {
166 // pick out current row
167 const auto j = inner_index_[ii];
168 auto &map = mapping_[j];
169 map.emplace_back(i, index);
170 ++index;
171 }
172 }
173
174 logger().trace("Cache computed");
175
176 second_cache_.clear();
178 // loop over each element
179 for (int e = 0; e < second_cache_entries_.size(); ++e)
180 {
181 // loop over each global index affected by the given element
182 for (const auto &p : second_cache_entries_[e])
183 {
184 const int i = p.first;
185 const int j = p.second;
186
187 // pick out column/sparse matrix index pairs for the given column
188 const auto &map = mapping()[i];
189 int index = -1;
190
191 // loop over column/sparse matrix index pairs
192 for (const auto &p : map)
193 {
194 // match columns
195 if (p.first == j)
196 {
197 assert(p.second < values_.size());
198 index = p.second;
199 break;
200 }
201 }
202 assert(index >= 0);
203
204 // save the sparse matrix index used by this element
205 second_cache_[e].emplace_back(index);
206 }
207 }
208
209 second_cache_entries_.resize(0);
210
211 logger().trace("Second cache computed");
212 }
213 }
214 else
215 {
216 assert(size_ > 0);
217 const auto &outer_index = main_cache()->outer_index_;
218 const auto &inner_index = main_cache()->inner_index_;
219 // directly write the values to the matrix
220 mat_ = Eigen::Map<const StiffnessMatrix>(
221 size_, size_, values_.size(), &outer_index[0], &inner_index[0], &values_[0]);
222
223 current_e_ = -1;
224 current_e_index_ = -1;
225 }
226 std::fill(values_.begin(), values_.end(), 0);
227 return mat_;
228 }
229
230 std::shared_ptr<MatrixCache> SparseMatrixCache::operator+(const MatrixCache &a) const
231 {
232 assert(&a == &dynamic_cast<const SparseMatrixCache &>(a));
233 return *this + dynamic_cast<const SparseMatrixCache &>(a);
234 }
235
236 std::shared_ptr<MatrixCache> SparseMatrixCache::operator+(const SparseMatrixCache &a) const
237 {
238 std::shared_ptr<SparseMatrixCache> out = std::make_shared<SparseMatrixCache>(a);
239
240 if (a.mapping().empty() || mapping().empty())
241 {
242 out->mat_ = a.mat_ + mat_;
243 const size_t this_e_size = second_cache_entries_.size();
244 const size_t a_e_size = a.second_cache_entries_.size();
245
246 out->second_cache_entries_.resize(std::max(this_e_size, a_e_size));
247 for (int e = 0; e < std::min(this_e_size, a_e_size); ++e)
248 {
249 assert(second_cache_entries_[e].size() == 0 || a.second_cache_entries_[e].size() == 0);
250 out->second_cache_entries_[e].insert(out->second_cache_entries_[e].end(), second_cache_entries_[e].begin(), second_cache_entries_[e].end());
251 out->second_cache_entries_[e].insert(out->second_cache_entries_[e].end(), a.second_cache_entries_[e].begin(), a.second_cache_entries_[e].end());
252 }
253
254 for (int e = std::min(this_e_size, a_e_size); e < std::max(this_e_size, a_e_size); ++e)
255 {
256 if (second_cache_entries_.size() < e)
257 out->second_cache_entries_[e].insert(out->second_cache_entries_[e].end(), second_cache_entries_[e].begin(), second_cache_entries_[e].end());
258 else
259 out->second_cache_entries_[e].insert(out->second_cache_entries_[e].end(), a.second_cache_entries_[e].begin(), a.second_cache_entries_[e].end());
260 }
261 }
262 else
263 {
264 const auto &outer_index = main_cache()->outer_index_;
265 const auto &inner_index = main_cache()->inner_index_;
266 const auto &aouter_index = a.main_cache()->outer_index_;
267 const auto &ainner_index = a.main_cache()->inner_index_;
268 assert(ainner_index.size() == inner_index.size());
269 assert(aouter_index.size() == outer_index.size());
270 assert(a.values_.size() == values_.size());
271
272 maybe_parallel_for(a.values_.size(), [&](int start, int end, int thread_id) {
273 for (int i = start; i < end; ++i)
274 {
275 out->values_[i] = a.values_[i] + values_[i];
276 }
277 });
278 }
279
280 return out;
281 }
282
284 {
285 assert(&o == &dynamic_cast<const SparseMatrixCache &>(o));
286 *this += dynamic_cast<const SparseMatrixCache &>(o);
287 }
288
290 {
291 if (mapping().empty() || o.mapping().empty())
292 {
293 mat_ += o.mat_;
294
295 const size_t this_e_size = second_cache_entries_.size();
296 const size_t o_e_size = o.second_cache_entries_.size();
297
298 second_cache_entries_.resize(std::max(this_e_size, o_e_size));
299 for (int e = 0; e < o_e_size; ++e)
300 {
301 assert(second_cache_entries_[e].size() == 0 || o.second_cache_entries_[e].size() == 0);
303 }
304 }
305 else
306 {
307 const auto &outer_index = main_cache()->outer_index_;
308 const auto &inner_index = main_cache()->inner_index_;
309 const auto &oouter_index = o.main_cache()->outer_index_;
310 const auto &oinner_index = o.main_cache()->inner_index_;
311 assert(inner_index.size() == oinner_index.size());
312 assert(outer_index.size() == oouter_index.size());
313 assert(values_.size() == o.values_.size());
314
315 maybe_parallel_for(o.values_.size(), [&](int start, int end, int thread_id) {
316 for (int i = start; i < end; ++i)
317 {
318 values_[i] += o.values_[i];
319 }
320 });
321 }
322 }
323
324 // ========================================================================
325
327 {
328 mat_.setZero(size, size);
329 }
330
331 DenseMatrixCache::DenseMatrixCache(const size_t rows, const size_t cols)
332 {
333 mat_.setZero(rows, cols);
334 }
335
337 {
338 init(other);
339 }
340
342 {
343 init(other);
344 }
345
346 void DenseMatrixCache::init(const size_t size)
347 {
348 mat_.setZero(size, size);
349 }
350
351 void DenseMatrixCache::init(const size_t rows, const size_t cols)
352 {
353 mat_.setZero(rows, cols);
354 }
355
357 {
358 init(dynamic_cast<const DenseMatrixCache &>(other));
359 }
360
362 {
363 mat_.setZero(other.mat_.rows(), other.mat_.cols());
364 }
365
367 {
368 mat_.setZero();
369 }
370
371 void DenseMatrixCache::add_value(const int e, const int i, const int j, const double value)
372 {
373 mat_(i, j) += value;
374 }
375
377
379 {
380 return mat_.sparseView();
381 }
382
383 std::shared_ptr<MatrixCache> DenseMatrixCache::operator+(const MatrixCache &a) const
384 {
385 return *this + dynamic_cast<const DenseMatrixCache &>(a);
386 }
387
388 std::shared_ptr<MatrixCache> DenseMatrixCache::operator+(const DenseMatrixCache &a) const
389 {
390 std::shared_ptr<DenseMatrixCache> out = std::make_shared<DenseMatrixCache>(a);
391 out->mat_ += mat_;
392 return out;
393 }
394
396 {
397 *this += dynamic_cast<const DenseMatrixCache &>(o);
398 }
399
401 {
402 mat_ += o.mat_;
403 }
404
405} // namespace polyfem::utils
std::shared_ptr< MatrixCache > operator+(const MatrixCache &a) const override
void init(const size_t size) override
StiffnessMatrix get_matrix(const bool compute_mapping=true) override
void add_value(const int e, const int i, const int j, const double value) override
void operator+=(const MatrixCache &o) override
abstract class used for caching
void operator+=(const MatrixCache &o) override
void add_value(const int e, const int i, const int j, const double value) override
e = element_index, i = global row_index, j = global column_index, value = value to add to matrix if t...
void set_zero() override
set matrix values to zero modifies tmp_, mat_, and values (setting all to zero)
std::vector< int > outer_index_
saves inner/outer indices for sparse matrix
void prune() override
if caches have yet to be constructed, add the saved triplets to mat_ modifies tmp_ and mat_,...
const SparseMatrixCache * main_cache_
std::shared_ptr< MatrixCache > operator+(const MatrixCache &a) const override
const std::vector< std::vector< std::pair< int, size_t > > > & mapping() const
std::vector< std::vector< std::pair< int, int > > > second_cache_entries_
maps element indices to global matrix indices
const SparseMatrixCache * main_cache() const
std::vector< double > values_
buffer for values (corresponds to inner/outer_index_ structure for sparse matrix)
const std::vector< std::vector< int > > & second_cache() const
std::vector< Eigen::Triplet< double > > entries_
contains global matrix indices and corresponding value
StiffnessMatrix get_matrix(const bool compute_mapping=true) override
if the cache is yet to be constructed, save the cached (ordered) indices in inner_index_ and outer_in...
void init(const size_t size) override
set matrix to be size x size
std::vector< std::vector< int > > second_cache_
maps element index to local index
std::vector< std::vector< std::pair< int, size_t > > > mapping_
maps row indices to column index/local index pairs
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24