libMesh
Loading...
Searching...
No Matches
coupling_matrix.h
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20#ifndef LIBMESH_COUPLING_MATRIX_H
21#define LIBMESH_COUPLING_MATRIX_H
22
23// Local Includes
24#include "libmesh/libmesh_common.h"
25
26// C++ includes
27#include <algorithm>
28#include <limits>
29#include <utility> // std::pair
30#include <vector>
31
32namespace libMesh
33{
34
35// Forward declarations
36class ConstCouplingAccessor;
37class CouplingAccessor;
38
39class ConstCouplingRow;
40
41class ConstCouplingRowConstIterator;
42
55{
56public:
57
61 explicit
62 CouplingMatrix (const std::size_t n=0);
63
67 bool operator() (const std::size_t i,
68 const std::size_t j) const;
69
74 CouplingAccessor operator() (const std::size_t i,
75 const std::size_t j);
76
81 std::size_t size() const;
82
87 void resize(const std::size_t n);
88
92 void clear();
93
97 bool empty() const;
98
100
101private:
102
104 friend class CouplingAccessor;
105 friend class ConstCouplingRow;
107
119 typedef std::pair<std::size_t, std::size_t> range_type;
120 typedef std::vector<range_type> rc_type;
122
126 std::size_t _size;
127};
128
129
130
135{
136public:
137 ConstCouplingAccessor(std::size_t loc_in,
138 const CouplingMatrix & mat_in) :
139 _location(loc_in), _mat(mat_in)
140 {
141 libmesh_assert_less(_location, _mat.size() * _mat.size());
142 }
143
144 operator bool() const
145 {
146 const std::size_t max_size = std::numeric_limits<std::size_t>::max();
147
148 // Find the range that might contain i,j
149 // lower_bound isn't *quite* what we want
150 CouplingMatrix::rc_type::const_iterator lb = std::upper_bound
151 (_mat._ranges.begin(), _mat._ranges.end(),
152 std::make_pair(_location, max_size));
153 if (lb!=_mat._ranges.begin())
154 --lb;
155 else
156 lb=_mat._ranges.end();
157
158 // If no range might contain i,j then it's 0
159 if (lb == _mat._ranges.end())
160 return false;
161
162 const std::size_t lastloc = lb->second;
163
164#ifdef DEBUG
165 const std::size_t firstloc = lb->first;
166 libmesh_assert_less_equal(firstloc, lastloc);
167 libmesh_assert_less_equal(firstloc, _location);
168
169 CouplingMatrix::rc_type::const_iterator next = lb;
170 next++;
171 if (next != _mat._ranges.end())
172 {
173 // Ranges should be sorted and should not touch
174 libmesh_assert_greater(next->first, lastloc+1);
175 }
176#endif
177
178 return (lastloc >= _location);
179 }
180
181protected:
182
183 std::size_t _location;
185};
186
187
192{
193public:
194 CouplingAccessor(std::size_t loc_in,
195 CouplingMatrix & mat_in) :
196 ConstCouplingAccessor(loc_in, mat_in), _my_mat(mat_in) {}
197
198 template <typename T>
200 {
201 // For backwards compatibility we take integer arguments,
202 // but coupling matrix entries are really all zero or one.
203 const bool as_bool = new_value;
204 libmesh_assert_equal_to(new_value, as_bool);
205
206 *this = as_bool;
207 return *this;
208 }
209
211 {
212 const std::size_t max_size = std::numeric_limits<std::size_t>::max();
213
214 // Find the range that might contain i,j
215 // lower_bound isn't *quite* what we want
216 CouplingMatrix::rc_type::iterator lb =
217 std::upper_bound (_my_mat._ranges.begin(), _my_mat._ranges.end(),
218 std::make_pair(_location, max_size));
219 if (lb!=_my_mat._ranges.begin())
220 --lb;
221 else
222 lb=_my_mat._ranges.end();
223
224 // If no range might contain i,j then we might need to make a new
225 // one.
226 if (lb == _my_mat._ranges.end())
227 {
228 if (new_value == true)
229 _my_mat._ranges.emplace
231 }
232 else
233 {
234 const std::size_t firstloc = lb->first;
235 const std::size_t lastloc = lb->second;
236 libmesh_assert_less_equal(firstloc, lastloc);
237 libmesh_assert_less_equal(firstloc, _location);
238
239#ifdef DEBUG
240 {
241 CouplingMatrix::rc_type::const_iterator next = lb;
242 next++;
243 if (next != _my_mat._ranges.end())
244 {
245 // Ranges should be sorted and should not touch
246 libmesh_assert_greater(next->first, lastloc+1);
247 }
248 }
249#endif
250
251 // If we're in this range, we might need to shorten or remove
252 // or split it
253 if (new_value == false)
254 {
255 if (_location == firstloc)
256 {
257 if (_location == lastloc)
258 {
259 _my_mat._ranges.erase(lb);
260 }
261 else
262 {
263 libmesh_assert_less (lb->first, lastloc);
264 lb->first++;
265 }
266 }
267 else if (_location == lastloc)
268 {
269 libmesh_assert_less (firstloc, lb->second);
270
271 lb->second--;
272 }
273 else if (_location < lastloc)
274 {
275 libmesh_assert_less_equal(_location+1, lastloc);
276
277 lb->first = _location+1;
278
279 libmesh_assert_less_equal(firstloc, _location-1);
280
281 _my_mat._ranges.emplace(lb, firstloc, _location-1);
282 }
283 }
284
285 // If we're not in this range, we might need to extend it or
286 // join it with its neighbor or add a new one.
287 else // new_value == true
288 {
289 CouplingMatrix::rc_type::iterator next = lb;
290 next++;
291 const std::size_t nextloc =
292 (next == _my_mat._ranges.end()) ?
293 std::numeric_limits<std::size_t>::max() :
294 next->first;
295
296 // Ranges should be sorted and should not touch
297 libmesh_assert_greater(nextloc, lastloc+1);
298
299 if (_location > lastloc)
300 {
301 if (_location == lastloc + 1)
302 {
303 if (_location == nextloc - 1)
304 {
305 next->first = firstloc;
306 _my_mat._ranges.erase(lb);
307 }
308 else
309 lb->second++;
310 }
311 else
312 {
313 if (_location == nextloc - 1)
314 next->first--;
315 else
316 _my_mat._ranges.emplace(next, _location, _location);
317 }
318 }
319 }
320 }
321
322 return *this;
323 }
324
325private:
326
328};
329
330
331
337{
338public:
339 ConstCouplingRow(std::size_t row_in,
340 const CouplingMatrix & mat_in) :
341 _row_i(row_in), _mat(mat_in),
342 _end_location(_row_i*_mat.size()+_mat.size()-1)
343 {
344 libmesh_assert_less(_row_i, _mat.size());
345
346 // Location for i,N, where we'll start looking for our beginning
347 // range
349
350 const std::size_t max_size = std::numeric_limits<std::size_t>::max();
351
352 // Find the range that might contain i,N
353 // lower_bound isn't *quite* what we want
354 _begin_it = std::upper_bound
355 (_mat._ranges.begin(), _mat._ranges.end(),
356 std::make_pair(_begin_location, max_size));
357 if (_begin_it !=_mat._ranges.begin())
358 --_begin_it;
359 else
360 _begin_it=_mat._ranges.end();
361
362 // If that range doesn't exist then we're an empty row
363 if (_begin_it == _mat._ranges.end())
364 _begin_location = max_size;
365 else
366 {
367 const std::size_t lastloc = _begin_it->second;
368#ifdef DEBUG
369 const std::size_t firstloc = _begin_it->first;
370 libmesh_assert_less_equal(firstloc, lastloc);
371#endif
372
373 // If that range ends before i,0 then we're an empty row
374 std::size_t zero_location = _row_i*_mat.size();
375 if (zero_location > lastloc)
376 {
377 _begin_location = max_size;
378 _begin_it = _mat._ranges.end();
379 }
380 else
381 // We have *some* entry(s) in this row, we just need to find
382 // the earliest
383 {
384 while (_begin_it != _mat._ranges.begin())
385 {
386 CouplingMatrix::rc_type::const_iterator prev =
387 _begin_it;
388 --prev;
389
390 if (prev->second < zero_location)
391 break;
392
393 _begin_it = prev;
394 }
395 if (_begin_it->first < zero_location)
396 _begin_location = zero_location;
397 else
398 _begin_location = _begin_it->first;
399 }
400 }
401 }
402
403 /*
404 * A forward iterator type for looping over indices in this row
405 */
407
408 /*
409 * An iterator to the first index in this row, or to end() for an
410 * empty row
411 */
412 const_iterator begin() const;
413
414 /*
415 * An iterator representing past-the-end of this row
416 */
417 const_iterator end() const;
418
419 bool operator== (const ConstCouplingRow & other) const
420 {
421 // Thinking that rows from different matrix objects are equal is
422 // not even wrong
423 libmesh_assert(&_mat == &other._mat);
424
425 return ((_begin_location == other._begin_location) &&
426 (_begin_it == other._begin_it));
427 }
428
429 bool operator!= (const ConstCouplingRow & other) const
430 {
431 return !(*this == other);
432 }
433protected:
434
436
437 std::size_t _row_i;
439
440 // The location (i*size+j) corresponding to the first entry in this
441 // row, or numeric_limits<size_t>::max() for an empty row.
442 std::size_t _begin_location;
443
444 // The location (i*size+j) corresponding to the end of this row
445 // (regardless of whether that end falls within a range). Cached
446 // because every ++iterator call needs to use it.
447 const std::size_t _end_location;
448
449 // Iterator to the range containing the first row element, or
450 // _row._mat._ranges.end() if no CouplingMatrix values are true for
451 // this row
452 CouplingMatrix::rc_type::const_iterator _begin_it;
453};
454
455
456
458{
459public:
461 std::size_t loc_in,
462 CouplingMatrix::rc_type::const_iterator it_in) :
463 _location(loc_in),
464 _row(row_in),
465 _it(it_in)
466 {
467#ifndef NDEBUG
468 if (_it != _row._mat._ranges.end())
469 {
470 libmesh_assert_less_equal(_it->first, _location);
471 libmesh_assert_less_equal(_location, _it->second);
472 }
473 else
474 {
475 libmesh_assert_equal_to
476 (_location, std::numeric_limits<size_t>::max());
477 }
478#endif
479 }
480
481 std::size_t operator* ()
482 {
483 libmesh_assert_not_equal_to
484 (_location, std::numeric_limits<std::size_t>::max());
485 return _location % _row._mat.size();
486 }
487
489 {
490 libmesh_assert_not_equal_to
491 (_location, std::numeric_limits<std::size_t>::max());
493 (_it != _row._mat._ranges.end());
494
495 if (_location >= _it->second)
496 {
497 ++_it;
498
499 // Are we past the end of the matrix?
500 if (_it == _row._mat._ranges.end())
501 _location = std::numeric_limits<std::size_t>::max();
502 else
503 {
504 _location = _it->first;
505 // Is the new range past the end of the row?
507 _location = std::numeric_limits<std::size_t>::max();
508 }
509 }
510 // Would incrementing put us past the end of the row?
511 else if (_location >= _row._end_location)
512 _location = std::numeric_limits<std::size_t>::max();
513 else
514 ++_location;
515
516 return *this;
517 }
518
520 {
521 // Thinking that iterators from different row objects are equal
522 // is not even wrong
523 libmesh_assert(_row == other._row);
524
525 return (_location == other._location);
526 // Testing for equality of _it is either redundant (for a
527 // dereferenceable iterator, where _it is defined to be the range
528 // which includes _location) or wrong (for an end iterator, where
529 // we don't always bother to set _it)
530 // && (_it == other._it);
531 }
532
534 {
535 return !(*this == other);
536 }
537
538private:
539 // The location (i*size+j) corresponding to this iterator, or
540 // numeric_limits<size_t>::max() to signify end()
541 std::size_t _location;
543 // The range containing this iterator location, or
544 // _row._mat._ranges.end() if no range contains this location
545 CouplingMatrix::rc_type::const_iterator _it;
546};
547
548
549
550//--------------------------------------------------
551// ConstCouplingRow inline methods
552inline
557
558inline
560{
561 return const_iterator
562 (*this, std::numeric_limits<std::size_t>::max(),
563 _mat._ranges.end());
564}
565
566
567
568//--------------------------------------------------
569// CouplingMatrix inline methods
570inline
571CouplingMatrix::CouplingMatrix (const std::size_t n) :
572 _ranges(), _size(n)
573{
574 this->resize(n);
575}
576
577
578
579inline
580bool CouplingMatrix::operator() (const std::size_t i,
581 const std::size_t j) const
582{
583 libmesh_assert_less (i, _size);
584 libmesh_assert_less (j, _size);
585
586 const std::size_t location = std::size_t(i)*_size + j;
587
588 return bool(ConstCouplingAccessor(location, *this));
589}
590
591
592
593
594inline
596 const std::size_t j)
597{
598 const std::size_t location = std::size_t(i)*_size + j;
599
600 return CouplingAccessor(location, *this);
601}
602
603
604
605inline
606std::size_t CouplingMatrix::size() const
607{
608 return _size;
609}
610
611
612
613inline
614void CouplingMatrix::resize(const std::size_t n)
615{
616 _size = n;
617
618 _ranges.clear();
619}
620
621
622
623inline
625{
626 this->resize(0);
627}
628
629
630
631inline
633{
634 return (_size == 0);
635}
636
637
638} // namespace libMesh
639
640
641#endif // LIBMESH_COUPLING_MATRIX_H
This accessor class allows simple access to CouplingMatrix values.
ConstCouplingAccessor(std::size_t loc_in, const CouplingMatrix &mat_in)
const CouplingMatrix & _mat
ConstCouplingRowConstIterator & operator++()
ConstCouplingRowConstIterator(const ConstCouplingRow &row_in, std::size_t loc_in, CouplingMatrix::rc_type::const_iterator it_in)
CouplingMatrix::rc_type::const_iterator _it
bool operator==(const ConstCouplingRowConstIterator &other) const
bool operator!=(const ConstCouplingRowConstIterator &other) const
This proxy class acts like a container of indices from a single coupling row.
bool operator==(const ConstCouplingRow &other) const
const std::size_t _end_location
const_iterator end() const
CouplingMatrix::rc_type::const_iterator _begin_it
ConstCouplingRow(std::size_t row_in, const CouplingMatrix &mat_in)
bool operator!=(const ConstCouplingRow &other) const
const CouplingMatrix & _mat
const_iterator begin() const
ConstCouplingRowConstIterator const_iterator
This accessor class allows simple setting of CouplingMatrix values.
CouplingAccessor(std::size_t loc_in, CouplingMatrix &mat_in)
CouplingAccessor & operator=(T new_value)
This class defines a coupling matrix.
std::size_t _size
The size of the matrix.
CouplingMatrix(const std::size_t n=0)
Constructor.
std::size_t size() const
CouplingMatrix & operator&=(const CouplingMatrix &other)
std::vector< range_type > rc_type
friend class ConstCouplingAccessor
bool operator()(const std::size_t i, const std::size_t j) const
std::pair< std::size_t, std::size_t > range_type
Coupling matrices are typically either full or very sparse, and all values are only zero or one.
void resize(const std::size_t n)
Resizes the matrix and initializes all entries to be 0.
void clear()
Clears the matrix.
The libMesh namespace provides an interface to certain functionality in the library.
libmesh_assert(ctx)