DUNE-FEM (unstable)

aggregates.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4// vi: set et ts=4 sw=2 sts=2:
5#ifndef DUNE_AMG_AGGREGATES_HH
6#define DUNE_AMG_AGGREGATES_HH
7
8
9#include "parameters.hh"
10#include "graph.hh"
11#include "properties.hh"
12#include "combinedfunctor.hh"
13
14#include <dune/common/timer.hh>
17#include <dune/common/sllist.hh>
21
22#include <utility>
23#include <set>
24#include <algorithm>
25#include <complex>
26#include <limits>
27#include <ostream>
28#include <tuple>
29#include <cmath>
30
31namespace Dune
32{
33 namespace Amg
34 {
35
49 template<class T>
50 class AggregationCriterion : public T
51 {
52
53 public:
58
69 : T()
70 {}
71
73 : T(parms)
74 {}
84 void setDefaultValuesIsotropic(std::size_t dim, std::size_t diameter=2)
85 {
86 this->setMaxDistance(diameter-1);
87 std::size_t csize=1;
88
89 for(; dim>0; dim--) {
90 csize*=diameter;
91 this->setMaxDistance(this->maxDistance()+diameter-1);
92 }
93 this->setMinAggregateSize(csize);
94 this->setMaxAggregateSize(static_cast<std::size_t>(csize*1.5));
95 }
96
107 void setDefaultValuesAnisotropic(std::size_t dim,std::size_t diameter=2)
108 {
109 setDefaultValuesIsotropic(dim, diameter);
110 this->setMaxDistance(this->maxDistance()+dim-1);
111 }
112 };
113
114 template<class T>
115 std::ostream& operator<<(std::ostream& os, const AggregationCriterion<T>& criterion)
116 {
117 os<<"{ maxdistance="<<criterion.maxDistance()<<" minAggregateSize="
118 <<criterion.minAggregateSize()<< " maxAggregateSize="<<criterion.maxAggregateSize()
119 <<" connectivity="<<criterion.maxConnectivity()<<" debugLevel="<<criterion.debugLevel()<<"}";
120 return os;
121 }
122
134 template<class M, class N>
136 {
137 public:
141 typedef M Matrix;
142
146 typedef N Norm;
147
151 typedef typename Matrix::row_type Row;
152
157
158 void init(const Matrix* matrix);
159
160 void initRow(const Row& row, int index);
161
162 void examine(const ColIter& col);
163
164 template<class G>
165 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
166
167 bool isIsolated();
168
169
171 : Parameters(parms)
172 {}
174 : Parameters()
175 {}
176
177 protected:
182 typedef typename FieldTraits<field_type>::real_type real_type;
183 real_type maxValue_;
187 int row_;
189 real_type diagonal_;
190 std::vector<real_type> vals_;
191 typename std::vector<real_type>::iterator valIter_;
192
193 };
194
195
196 template<class M, class N>
197 inline void SymmetricMatrixDependency<M,N>::init(const Matrix* matrix)
198 {
199 matrix_ = matrix;
200 }
201
202 template<class M, class N>
203 inline void SymmetricMatrixDependency<M,N>::initRow(const Row& row, int index)
204 {
205 using std::min;
206 vals_.assign(row.size(), 0.0);
207 assert(vals_.size()==row.size());
208 valIter_=vals_.begin();
209
211 diagonal_=norm_(row[index]);
212 row_ = index;
213 }
214
215 template<class M, class N>
216 inline void SymmetricMatrixDependency<M,N>::examine(const ColIter& col)
217 {
218 using std::max;
219 // skip positive offdiagonals if norm preserves sign of them.
220 real_type eij = norm_(*col);
221 if(!N::is_sign_preserving || eij<0) // || eji<0)
222 {
223 *valIter_ = eij/diagonal_*eij/norm_(matrix_->operator[](col.index())[col.index()]);
224 maxValue_ = max(maxValue_, *valIter_);
225 }else
226 *valIter_ =0;
227 ++valIter_;
228 }
229
230 template<class M, class N>
231 template<class G>
232 inline void SymmetricMatrixDependency<M,N>::examine(G&, const typename G::EdgeIterator& edge, const ColIter&)
233 {
234 if(*valIter_ > alpha() * maxValue_) {
235 edge.properties().setDepends();
236 edge.properties().setInfluences();
237 }
238 ++valIter_;
239 }
240
241 template<class M, class N>
242 inline bool SymmetricMatrixDependency<M,N>::isIsolated()
243 {
244 if(diagonal_==0)
245 DUNE_THROW(Dune::ISTLError, "No diagonal entry for row "<<row_<<".");
246 valIter_=vals_.begin();
247 return maxValue_ < beta();
248 }
249
253 template<class M, class N>
254 class Dependency : public Parameters
255 {
256 public:
260 typedef M Matrix;
261
265 typedef N Norm;
266
270 typedef typename Matrix::row_type Row;
271
276
277 void init(const Matrix* matrix);
278
279 void initRow(const Row& row, int index);
280
281 void examine(const ColIter& col);
282
283 template<class G>
284 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
285
286 bool isIsolated();
287
288 Dependency(const Parameters& parms)
289 : Parameters(parms)
290 {}
291
292 Dependency()
293 : Parameters()
294 {}
295
296 protected:
301 typedef typename FieldTraits<field_type>::real_type real_type;
302 real_type maxValue_;
306 int row_;
308 real_type diagonal_;
309 };
310
314 template<class M, class N>
316 {
317 public:
321 typedef M Matrix;
322
326 typedef N Norm;
327
331 typedef typename Matrix::row_type Row;
332
337
338 void init(const Matrix* matrix);
339
340 void initRow(const Row& row, int index);
341
342 void examine(const ColIter& col);
343
344 template<class G>
345 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
346
347 bool isIsolated();
348
349
350 SymmetricDependency(const Parameters& parms)
351 : Parameters(parms)
352 {}
354 : Parameters()
355 {}
356
357 protected:
362 typedef typename FieldTraits<field_type>::real_type real_type;
363 real_type maxValue_;
367 int row_;
369 real_type diagonal_;
370 private:
371 void initRow(const Row& row, int index, const std::true_type&);
372 void initRow(const Row& row, int index, const std::false_type&);
373 };
374
379 template<int N>
381 {
382 public:
383 enum { /* @brief We preserve the sign.*/
384 is_sign_preserving = true
385 };
386
391 template<class M>
392 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m,
393 [[maybe_unused]] typename std::enable_if_t<!Dune::IsNumber<M>::value>* sfinae = nullptr) const
394 {
395 typedef typename M::field_type field_type;
396 typedef typename FieldTraits<field_type>::real_type real_type;
397 static_assert( std::is_convertible<field_type, real_type >::value,
398 "use of diagonal norm in AMG not implemented for complex field_type");
399 return m[N][N];
400 // possible implementation for complex types: return signed_abs(m[N][N]);
401 }
402
407 template<class M>
408 auto operator()(const M& m,
409 typename std::enable_if_t<Dune::IsNumber<M>::value>* /*sfinae*/ = nullptr) const
410 {
411 typedef typename FieldTraits<M>::real_type real_type;
412 static_assert( std::is_convertible<M, real_type >::value,
413 "use of diagonal norm in AMG not implemented for complex field_type");
414 return m;
415 // possible implementation for complex types: return signed_abs(m[N][N]);
416 }
417
418 private:
419
421 template<typename T>
422 static T signed_abs(const T & v)
423 {
424 return v;
425 }
426
428 template<typename T>
429 static T signed_abs(const std::complex<T> & v)
430 {
431 // return sign * abs_value
432 // in case of complex numbers this extends to using the csgn function to determine the sign
433 return csgn(v) * std::abs(v);
434 }
435
437 template<typename T>
438 static T csgn(const T & v)
439 {
440 return (T(0) < v) - (v < T(0));
441 }
442
444 template<typename T>
445 static T csgn(std::complex<T> a)
446 {
447 return csgn(a.real())+(a.real() == 0.0)*csgn(a.imag());
448 }
449
450 };
451
456 class FirstDiagonal : public Diagonal<0>
457 {};
458
464 struct RowSum
465 {
466
467 enum { /* @brief We preserve the sign.*/
468 is_sign_preserving = false
469 };
474 template<class M>
475 auto operator()(const M& m) const
476 {
477 using std::abs;
478 if constexpr(Dune::IsNumber<M>::value)
479 return abs(m);
480 else
481 return m.infinity_norm();
482 }
483 };
484
485 struct FrobeniusNorm
486 {
487
488 enum { /* @brief We preserve the sign.*/
489 is_sign_preserving = false
490 };
495 template<class M>
496 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
497 {
498 return m.frobenius_norm();
499 }
500 };
501 struct AlwaysOneNorm
502 {
503
504 enum { /* @brief We preserve the sign.*/
505 is_sign_preserving = false
506 };
511 template<class M>
512 typename FieldTraits<typename M::field_type>::real_type operator()(const M& /*m*/) const
513 {
514 return 1;
515 }
516 };
523 template<class M, class Norm>
524 class SymmetricCriterion : public AggregationCriterion<SymmetricDependency<M,Norm> >
525 {
526 public:
527 SymmetricCriterion(const Parameters& parms)
529 {}
531 {}
532 };
533
534
543 template<class M, class Norm>
544 class UnSymmetricCriterion : public AggregationCriterion<Dependency<M,Norm> >
545 {
546 public:
547 UnSymmetricCriterion(const Parameters& parms)
549 {}
551 {}
552 };
553 // forward declaration
554 template<class G> class Aggregator;
555
556
564 template<class V>
566 {
567 public:
568
572 static const V UNAGGREGATED;
573
577 static const V ISOLATED;
582
587
593
599
604 {
605 public:
606 template<class EdgeIterator>
607 void operator()([[maybe_unused]] const EdgeIterator& edge) const
608 {}
609 };
610
611
616
623
628
640 template<class M, class G, class C>
641 std::tuple<int,int,int,int> buildAggregates(const M& matrix, G& graph, const C& criterion,
642 bool finestLevel);
643
661 template<bool reset, class G, class F, class VM>
662 std::size_t breadthFirstSearch(const VertexDescriptor& start,
663 const AggregateDescriptor& aggregate,
664 const G& graph,
665 F& aggregateVisitor,
666 VM& visitedMap) const;
667
691 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
692 std::size_t breadthFirstSearch(const VertexDescriptor& start,
693 const AggregateDescriptor& aggregate,
694 const G& graph, L& visited, F1& aggregateVisitor,
695 F2& nonAggregateVisitor,
696 VM& visitedMap) const;
697
703 void allocate(std::size_t noVertices);
704
708 std::size_t noVertices() const;
709
713 void free();
714
721
728
729 typedef const AggregateDescriptor* const_iterator;
730
731 const_iterator begin() const
732 {
733 return aggregates_;
734 }
735
736 const_iterator end() const
737 {
738 return aggregates_+noVertices();
739 }
740
741 typedef AggregateDescriptor* iterator;
742
743 iterator begin()
744 {
745 return aggregates_;
746 }
747
748 iterator end()
749 {
750 return aggregates_+noVertices();
751 }
752 private:
754 AggregatesMap(const AggregatesMap<V>&) = delete;
756 AggregatesMap<V>& operator=(const AggregatesMap<V>&) = delete;
757
761 AggregateDescriptor* aggregates_;
762
766 std::size_t noVertices_;
767 };
768
772 template<class G, class C>
773 void buildDependency(G& graph,
774 const typename C::Matrix& matrix,
775 C criterion,
776 bool finestLevel);
777
782 template<class G, class S>
784 {
785
786 public:
787
788 /***
789 * @brief The type of the matrix graph we work with.
790 */
791 typedef G MatrixGraph;
796
802
807 typedef S VertexSet;
808
812 using size_type = typename VertexSet::size_type;
813
815 typedef typename VertexSet::const_iterator const_iterator;
816
820 typedef std::size_t* SphereMap;
821
830 Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
831 VertexSet& connectivity, std::vector<Vertex>& front_);
832
833 void invalidate()
834 {
835 --id_;
836 }
837
845
849 void seed(const Vertex& vertex);
850
854 void add(const Vertex& vertex);
855
856 void add(std::vector<Vertex>& vertex);
860 void clear();
861
870
874 int id();
875
878
881
882 private:
886 VertexSet vertices_;
887
892 int id_;
893
897 MatrixGraph& graph_;
898
902 AggregatesMap<Vertex>& aggregates_;
903
907 VertexSet& connected_;
908
912 std::vector<Vertex>& front_;
913 };
914
918 template<class G>
920 {
921 public:
922
926 typedef G MatrixGraph;
927
932
935
940
945
962 template<class M, class C>
963 std::tuple<int,int,int,int> build(const M& m, G& graph,
964 AggregatesMap<Vertex>& aggregates, const C& c,
965 bool finestLevel);
966 private:
972
977
981 typedef std::set<Vertex,std::less<Vertex>,Allocator> VertexSet;
982
986 typedef std::size_t* SphereMap;
987
991 MatrixGraph* graph_;
992
997
1001 std::vector<Vertex> front_;
1002
1006 VertexSet connected_;
1007
1011 int size_;
1012
1016 class Stack
1017 {
1018 public:
1019 static const Vertex NullEntry;
1020
1021 Stack(const MatrixGraph& graph,
1022 const Aggregator<G>& aggregatesBuilder,
1023 const AggregatesMap<Vertex>& aggregates);
1024 ~Stack();
1025 Vertex pop();
1026 private:
1027 enum { N = 1300000 };
1028
1030 const MatrixGraph& graph_;
1032 const Aggregator<G>& aggregatesBuilder_;
1034 const AggregatesMap<Vertex>& aggregates_;
1036 int size_;
1037 Vertex maxSize_;
1039 typename MatrixGraph::ConstVertexIterator begin_;
1041
1043 Vertex* vals_;
1044
1045 };
1046
1047 friend class Stack;
1048
1059 template<class V>
1060 void visitAggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate,
1061 const AggregatesMap<Vertex>& aggregates,
1062 V& visitor) const;
1063
1068 template<class V>
1069 class AggregateVisitor
1070 {
1071 public:
1075 typedef V Visitor;
1084 Visitor& visitor);
1085
1092 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1093
1094 private:
1096 const AggregatesMap<Vertex>& aggregates_;
1098 AggregateDescriptor aggregate_;
1100 Visitor* visitor_;
1101 };
1102
1106 class Counter
1107 {
1108 public:
1112 int value();
1113
1114 protected:
1119
1120 private:
1121 int count_;
1122 };
1123
1124
1129 class FrontNeighbourCounter : public Counter
1130 {
1131 public:
1137
1138 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1139
1140 private:
1141 const MatrixGraph& graph_;
1142 };
1143
1148 int noFrontNeighbours(const Vertex& vertex) const;
1149
1153 class TwoWayCounter : public Counter
1154 {
1155 public:
1156 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1157 };
1158
1170 int twoWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1171 const AggregatesMap<Vertex>& aggregates) const;
1172
1176 class OneWayCounter : public Counter
1177 {
1178 public:
1179 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1180 };
1181
1193 int oneWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1194 const AggregatesMap<Vertex>& aggregates) const;
1195
1202 class ConnectivityCounter : public Counter
1203 {
1204 public:
1210 ConnectivityCounter(const VertexSet& connected, const AggregatesMap<Vertex>& aggregates);
1211
1212 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1213
1214 private:
1216 const VertexSet& connected_;
1218 const AggregatesMap<Vertex>& aggregates_;
1219
1220 };
1221
1233 double connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1241 bool connected(const Vertex& vertex, const AggregateDescriptor& aggregate,
1242 const AggregatesMap<Vertex>& aggregates) const;
1243
1251 bool connected(const Vertex& vertex, const SLList<AggregateDescriptor>& aggregateList,
1252 const AggregatesMap<Vertex>& aggregates) const;
1253
1261 class DependencyCounter : public Counter
1262 {
1263 public:
1268
1269 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1270 };
1271
1278 class FrontMarker
1279 {
1280 public:
1287 FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph);
1288
1289 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1290
1291 private:
1293 std::vector<Vertex>& front_;
1295 MatrixGraph& graph_;
1296 };
1297
1301 void unmarkFront();
1302
1317 int unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1318
1332 std::pair<int,int> neighbours(const Vertex& vertex,
1333 const AggregateDescriptor& aggregate,
1334 const AggregatesMap<Vertex>& aggregates) const;
1351 int aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1352
1360 bool admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1361
1369 std::size_t distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates);
1370
1379 Vertex mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1380
1389 void nonisoNeighbourAggregate(const Vertex& vertex,
1390 const AggregatesMap<Vertex>& aggregates,
1391 SLList<Vertex>& neighbours) const;
1392
1400 template<class C>
1401 void growAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1402 template<class C>
1403 void growIsolatedAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1404 };
1405
1406#ifndef DOXYGEN
1407
1408 template<class M, class N>
1409 inline void SymmetricDependency<M,N>::init(const Matrix* matrix)
1410 {
1411 matrix_ = matrix;
1412 }
1413
1414 template<class M, class N>
1415 inline void SymmetricDependency<M,N>::initRow(const Row& row, int index)
1416 {
1417 initRow(row, index, std::is_convertible<field_type, real_type>());
1418 }
1419
1420 template<class M, class N>
1421 inline void SymmetricDependency<M,N>::initRow(const Row& /*row*/, int /*index*/, const std::false_type&)
1422 {
1423 DUNE_THROW(InvalidStateException, "field_type needs to convertible to real_type");
1424 }
1425
1426 template<class M, class N>
1427 inline void SymmetricDependency<M,N>::initRow(const Row& /*row*/, int index, const std::true_type&)
1428 {
1429 using std::min;
1431 row_ = index;
1432 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1433 }
1434
1435 template<class M, class N>
1436 inline void SymmetricDependency<M,N>::examine(const ColIter& col)
1437 {
1438 using std::max;
1439 real_type eij = norm_(*col);
1440 typename Matrix::ConstColIterator opposite_entry =
1441 matrix_->operator[](col.index()).find(row_);
1442 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1443 {
1444 // Consider this a weak connection we disregard.
1445 return;
1446 }
1447 real_type eji = norm_(*opposite_entry);
1448
1449 // skip positive offdiagonals if norm preserves sign of them.
1450 if(!N::is_sign_preserving || eij<0 || eji<0)
1451 maxValue_ = max(maxValue_,
1452 eij /diagonal_ * eji/
1453 norm_(matrix_->operator[](col.index())[col.index()]));
1454 }
1455
1456 template<class M, class N>
1457 template<class G>
1458 inline void SymmetricDependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1459 {
1460 real_type eij = norm_(*col);
1461 typename Matrix::ConstColIterator opposite_entry =
1462 matrix_->operator[](col.index()).find(row_);
1463
1464 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1465 {
1466 // Consider this as a weak connection we disregard.
1467 return;
1468 }
1469 real_type eji = norm_(*opposite_entry);
1470 // skip positive offdiagonals if norm preserves sign of them.
1471 if(!N::is_sign_preserving || (eij<0 || eji<0))
1472 if(eji / norm_(matrix_->operator[](edge.target())[edge.target()]) *
1473 eij/ diagonal_ > alpha() * maxValue_) {
1474 edge.properties().setDepends();
1475 edge.properties().setInfluences();
1476 typename G::EdgeProperties& other = graph.getEdgeProperties(edge.target(), edge.source());
1477 other.setInfluences();
1478 other.setDepends();
1479 }
1480 }
1481
1482 template<class M, class N>
1483 inline bool SymmetricDependency<M,N>::isIsolated()
1484 {
1485 return maxValue_ < beta();
1486 }
1487
1488
1489 template<class M, class N>
1490 inline void Dependency<M,N>::init(const Matrix* matrix)
1491 {
1492 matrix_ = matrix;
1493 }
1494
1495 template<class M, class N>
1496 inline void Dependency<M,N>::initRow([[maybe_unused]] const Row& row, int index)
1497 {
1498 using std::min;
1500 row_ = index;
1501 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1502 }
1503
1504 template<class M, class N>
1505 inline void Dependency<M,N>::examine(const ColIter& col)
1506 {
1507 using std::max;
1508 maxValue_ = max(maxValue_, -norm_(*col));
1509 }
1510
1511 template<class M, class N>
1512 template<class G>
1513 inline void Dependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1514 {
1515 if(-norm_(*col) >= maxValue_ * alpha()) {
1516 edge.properties().setDepends();
1517 typedef typename G::EdgeDescriptor ED;
1518 ED e= graph.findEdge(edge.target(), edge.source());
1520 {
1521 typename G::EdgeProperties& other = graph.getEdgeProperties(e);
1522 other.setInfluences();
1523 }
1524 }
1525 }
1526
1527 template<class M, class N>
1528 inline bool Dependency<M,N>::isIsolated()
1529 {
1530 return maxValue_ < beta() * diagonal_;
1531 }
1532
1533 template<class G,class S>
1534 Aggregate<G,S>::Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
1535 VertexSet& connected, std::vector<Vertex>& front)
1536 : vertices_(), id_(-1), graph_(graph), aggregates_(aggregates),
1537 connected_(connected), front_(front)
1538 {}
1539
1540 template<class G,class S>
1541 void Aggregate<G,S>::reconstruct(const Vertex& /*vertex*/)
1542 {
1543 /*
1544 vertices_.push_back(vertex);
1545 typedef typename VertexList::const_iterator iterator;
1546 iterator begin = vertices_.begin();
1547 iterator end = vertices_.end();*/
1548 throw "Not yet implemented";
1549
1550 // while(begin!=end){
1551 //for();
1552 // }
1553
1554 }
1555
1556 template<class G,class S>
1557 inline void Aggregate<G,S>::seed(const Vertex& vertex)
1558 {
1559 dvverb<<"Connected cleared"<<std::endl;
1560 connected_.clear();
1561 vertices_.clear();
1562 connected_.insert(vertex);
1563 dvverb << " Inserting "<<vertex<<" size="<<connected_.size();
1564 ++id_ ;
1565 add(vertex);
1566 }
1567
1568
1569 template<class G,class S>
1570 inline void Aggregate<G,S>::add(const Vertex& vertex)
1571 {
1572 vertices_.insert(vertex);
1573 aggregates_[vertex]=id_;
1574 if(front_.size())
1575 front_.erase(std::lower_bound(front_.begin(), front_.end(), vertex));
1576
1577
1578 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1579 const iterator end = graph_.endEdges(vertex);
1580 for(iterator edge = graph_.beginEdges(vertex); edge != end; ++edge) {
1581 dvverb << " Inserting "<<aggregates_[edge.target()];
1582 connected_.insert(aggregates_[edge.target()]);
1583 dvverb <<" size="<<connected_.size();
1584 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1585 !graph_.getVertexProperties(edge.target()).front())
1586 {
1587 front_.push_back(edge.target());
1588 graph_.getVertexProperties(edge.target()).setFront();
1589 }
1590 }
1591 dvverb <<std::endl;
1592 std::sort(front_.begin(), front_.end());
1593 }
1594
1595 template<class G,class S>
1596 inline void Aggregate<G,S>::add(std::vector<Vertex>& vertices)
1597 {
1598#ifndef NDEBUG
1599 std::size_t oldsize = vertices_.size();
1600#endif
1601 typedef typename std::vector<Vertex>::iterator Iterator;
1602
1603 typedef typename VertexSet::iterator SIterator;
1604
1605 SIterator pos=vertices_.begin();
1606 std::vector<Vertex> newFront;
1607 newFront.reserve(front_.capacity());
1608
1609 std::set_difference(front_.begin(), front_.end(), vertices.begin(), vertices.end(),
1610 std::back_inserter(newFront));
1611 front_=newFront;
1612
1613 for(Iterator vertex=vertices.begin(); vertex != vertices.end(); ++vertex)
1614 {
1615 pos=vertices_.insert(pos,*vertex);
1616 vertices_.insert(*vertex);
1617 graph_.getVertexProperties(*vertex).resetFront(); // Not a front node any more.
1618 aggregates_[*vertex]=id_;
1619
1620 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1621 const iterator end = graph_.endEdges(*vertex);
1622 for(iterator edge = graph_.beginEdges(*vertex); edge != end; ++edge) {
1623 dvverb << " Inserting "<<aggregates_[edge.target()];
1624 connected_.insert(aggregates_[edge.target()]);
1625 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1626 !graph_.getVertexProperties(edge.target()).front())
1627 {
1628 front_.push_back(edge.target());
1629 graph_.getVertexProperties(edge.target()).setFront();
1630 }
1631 dvverb <<" size="<<connected_.size();
1632 }
1633 dvverb <<std::endl;
1634 }
1635 std::sort(front_.begin(), front_.end());
1636 assert(oldsize+vertices.size()==vertices_.size());
1637 }
1638 template<class G,class S>
1639 inline void Aggregate<G,S>::clear()
1640 {
1641 vertices_.clear();
1642 connected_.clear();
1643 id_=-1;
1644 }
1645
1646 template<class G,class S>
1647 inline typename Aggregate<G,S>::size_type
1649 {
1650 return vertices_.size();
1651 }
1652
1653 template<class G,class S>
1654 inline typename Aggregate<G,S>::size_type
1656 {
1657 return connected_.size();
1658 }
1659
1660 template<class G,class S>
1661 inline int Aggregate<G,S>::id()
1662 {
1663 return id_;
1664 }
1665
1666 template<class G,class S>
1668 {
1669 return vertices_.begin();
1670 }
1671
1672 template<class G,class S>
1674 {
1675 return vertices_.end();
1676 }
1677
1678 template<class V>
1680
1681 template<class V>
1683
1684 template<class V>
1686 : aggregates_(0)
1687 {}
1688
1689 template<class V>
1691 {
1692 if(aggregates_!=0)
1693 delete[] aggregates_;
1694 }
1695
1696
1697 template<class V>
1698 inline AggregatesMap<V>::AggregatesMap(std::size_t noVertices)
1699 {
1700 allocate(noVertices);
1701 }
1702
1703 template<class V>
1704 inline std::size_t AggregatesMap<V>::noVertices() const
1705 {
1706 return noVertices_;
1707 }
1708
1709 template<class V>
1710 inline void AggregatesMap<V>::allocate(std::size_t noVertices)
1711 {
1712 aggregates_ = new AggregateDescriptor[noVertices];
1713 noVertices_ = noVertices;
1714
1715 for(std::size_t i=0; i < noVertices; i++)
1716 aggregates_[i]=UNAGGREGATED;
1717 }
1718
1719 template<class V>
1720 inline void AggregatesMap<V>::free()
1721 {
1722 assert(aggregates_ != 0);
1723 delete[] aggregates_;
1724 aggregates_=0;
1725 }
1726
1727 template<class V>
1729 AggregatesMap<V>::operator[](const VertexDescriptor& v)
1730 {
1731 return aggregates_[v];
1732 }
1733
1734 template<class V>
1735 inline const typename AggregatesMap<V>::AggregateDescriptor&
1736 AggregatesMap<V>::operator[](const VertexDescriptor& v) const
1737 {
1738 return aggregates_[v];
1739 }
1740
1741 template<class V>
1742 template<bool reset, class G, class F,class VM>
1743 inline std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1744 const AggregateDescriptor& aggregate,
1745 const G& graph, F& aggregateVisitor,
1746 VM& visitedMap) const
1747 {
1748 VertexList vlist;
1749
1750 DummyEdgeVisitor dummy;
1751 return breadthFirstSearch<true,reset>(start, aggregate, graph, vlist, aggregateVisitor, dummy, visitedMap);
1752 }
1753
1754 template<class V>
1755 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
1756 std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1757 const AggregateDescriptor& aggregate,
1758 const G& graph,
1759 L& visited,
1760 F1& aggregateVisitor,
1761 F2& nonAggregateVisitor,
1762 VM& visitedMap) const
1763 {
1764 typedef typename L::const_iterator ListIterator;
1765 int visitedSpheres = 0;
1766
1767 visited.push_back(start);
1768 put(visitedMap, start, true);
1769
1770 ListIterator current = visited.begin();
1771 ListIterator end = visited.end();
1772 std::size_t i=0, size=visited.size();
1773
1774 // visit the neighbours of all vertices of the
1775 // current sphere.
1776 while(current != end) {
1777
1778 for(; i<size; ++current, ++i) {
1779 typedef typename G::ConstEdgeIterator EdgeIterator;
1780 const EdgeIterator endEdge = graph.endEdges(*current);
1781
1782 for(EdgeIterator edge = graph.beginEdges(*current);
1783 edge != endEdge; ++edge) {
1784
1785 if(aggregates_[edge.target()]==aggregate) {
1786 if(!get(visitedMap, edge.target())) {
1787 put(visitedMap, edge.target(), true);
1788 visited.push_back(edge.target());
1789 aggregateVisitor(edge);
1790 }
1791 }else
1792 nonAggregateVisitor(edge);
1793 }
1794 }
1795 end = visited.end();
1796 size = visited.size();
1797 if(current != end)
1798 visitedSpheres++;
1799 }
1800
1801 if(reset)
1802 for(current = visited.begin(); current != end; ++current)
1803 put(visitedMap, *current, false);
1804
1805
1806 if(remove)
1807 visited.clear();
1808
1809 return visitedSpheres;
1810 }
1811
1812 template<class G>
1814 : graph_(0), aggregate_(0), front_(), connected_(), size_(-1)
1815 {}
1816
1817 template<class G>
1819 {
1820 size_=-1;
1821 }
1822
1823 template<class G, class C>
1824 void buildDependency(G& graph,
1825 const typename C::Matrix& matrix,
1826 C criterion, bool firstlevel)
1827 {
1828 // assert(graph.isBuilt());
1829 typedef typename C::Matrix Matrix;
1830 typedef typename G::VertexIterator VertexIterator;
1831
1832 criterion.init(&matrix);
1833
1834 for(VertexIterator vertex = graph.begin(); vertex != graph.end(); ++vertex) {
1835 typedef typename Matrix::row_type Row;
1836
1837 const Row& row = matrix[*vertex];
1838
1839 // Tell the criterion what row we will examine now
1840 // This might for example be used for calculating the
1841 // maximum offdiagonal value
1842 criterion.initRow(row, *vertex);
1843
1844 // On a first path all columns are examined. After this
1845 // the calculator should know whether the vertex is isolated.
1846 typedef typename Matrix::ConstColIterator ColIterator;
1847 ColIterator end = row.end();
1848 typename FieldTraits<typename Matrix::field_type>::real_type absoffdiag=0.;
1849
1850 using std::max;
1851 if(firstlevel) {
1852 for(ColIterator col = row.begin(); col != end; ++col)
1853 if(col.index()!=*vertex) {
1854 criterion.examine(col);
1855 absoffdiag = max(absoffdiag, Impl::asMatrix(*col).frobenius_norm());
1856 }
1857
1858 if(absoffdiag==0)
1859 vertex.properties().setExcludedBorder();
1860 }
1861 else
1862 for(ColIterator col = row.begin(); col != end; ++col)
1863 if(col.index()!=*vertex)
1864 criterion.examine(col);
1865
1866 // reset the vertex properties
1867 //vertex.properties().reset();
1868
1869 // Check whether the vertex is isolated.
1870 if(criterion.isIsolated()) {
1871 //std::cout<<"ISOLATED: "<<*vertex<<std::endl;
1872 vertex.properties().setIsolated();
1873 }else{
1874 // Examine all the edges beginning at this vertex.
1875 auto eEnd = vertex.end();
1876 auto col = matrix[*vertex].begin();
1877
1878 for(auto edge = vertex.begin(); edge!= eEnd; ++edge, ++col) {
1879 // Move to the right column.
1880 while(col.index()!=edge.target())
1881 ++col;
1882 criterion.examine(graph, edge, col);
1883 }
1884 }
1885
1886 }
1887 }
1888
1889
1890 template<class G>
1891 template<class V>
1892 inline Aggregator<G>::AggregateVisitor<V>::AggregateVisitor(const AggregatesMap<Vertex>& aggregates,
1893 const AggregateDescriptor& aggregate, V& visitor)
1894 : aggregates_(aggregates), aggregate_(aggregate), visitor_(&visitor)
1895 {}
1896
1897 template<class G>
1898 template<class V>
1899 inline void Aggregator<G>::AggregateVisitor<V>::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1900 {
1901 if(aggregates_[edge.target()]==aggregate_)
1902 visitor_->operator()(edge);
1903 }
1904
1905 template<class G>
1906 template<class V>
1907 inline void Aggregator<G>::visitAggregateNeighbours(const Vertex& vertex,
1908 const AggregateDescriptor& aggregate,
1909 const AggregatesMap<Vertex>& aggregates,
1910 V& visitor) const
1911 {
1912 // Only evaluates for edge pointing to the aggregate
1913 AggregateVisitor<V> v(aggregates, aggregate, visitor);
1914 visitNeighbours(*graph_, vertex, v);
1915 }
1916
1917
1918 template<class G>
1919 inline Aggregator<G>::Counter::Counter()
1920 : count_(0)
1921 {}
1922
1923 template<class G>
1924 inline void Aggregator<G>::Counter::increment()
1925 {
1926 ++count_;
1927 }
1928
1929 template<class G>
1930 inline void Aggregator<G>::Counter::decrement()
1931 {
1932 --count_;
1933 }
1934 template<class G>
1935 inline int Aggregator<G>::Counter::value()
1936 {
1937 return count_;
1938 }
1939
1940 template<class G>
1941 inline void Aggregator<G>::TwoWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1942 {
1943 if(edge.properties().isTwoWay())
1944 Counter::increment();
1945 }
1946
1947 template<class G>
1948 int Aggregator<G>::twoWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1949 const AggregatesMap<Vertex>& aggregates) const
1950 {
1951 TwoWayCounter counter;
1952 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1953 return counter.value();
1954 }
1955
1956 template<class G>
1957 int Aggregator<G>::oneWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1958 const AggregatesMap<Vertex>& aggregates) const
1959 {
1960 OneWayCounter counter;
1961 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1962 return counter.value();
1963 }
1964
1965 template<class G>
1966 inline void Aggregator<G>::OneWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1967 {
1968 if(edge.properties().isOneWay())
1969 Counter::increment();
1970 }
1971
1972 template<class G>
1973 inline Aggregator<G>::ConnectivityCounter::ConnectivityCounter(const VertexSet& connected,
1974 const AggregatesMap<Vertex>& aggregates)
1975 : Counter(), connected_(connected), aggregates_(aggregates)
1976 {}
1977
1978
1979 template<class G>
1980 inline void Aggregator<G>::ConnectivityCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1981 {
1982 if(connected_.find(aggregates_[edge.target()]) == connected_.end() || aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED)
1983 // Would be a new connection
1984 Counter::increment();
1985 else{
1986 Counter::increment();
1987 Counter::increment();
1988 }
1989 }
1990
1991 template<class G>
1992 inline double Aggregator<G>::connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
1993 {
1994 ConnectivityCounter counter(connected_, aggregates);
1995 double noNeighbours=visitNeighbours(*graph_, vertex, counter);
1996 return (double)counter.value()/noNeighbours;
1997 }
1998
1999 template<class G>
2000 inline Aggregator<G>::DependencyCounter::DependencyCounter()
2001 : Counter()
2002 {}
2003
2004 template<class G>
2005 inline void Aggregator<G>::DependencyCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2006 {
2007 if(edge.properties().depends())
2008 Counter::increment();
2009 if(edge.properties().influences())
2010 Counter::increment();
2011 }
2012
2013 template<class G>
2014 int Aggregator<G>::unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2015 {
2016 return aggregateNeighbours(vertex, AggregatesMap<Vertex>::UNAGGREGATED, aggregates);
2017 }
2018
2019 template<class G>
2020 std::pair<int,int> Aggregator<G>::neighbours(const Vertex& vertex,
2021 const AggregateDescriptor& aggregate,
2022 const AggregatesMap<Vertex>& aggregates) const
2023 {
2024 DependencyCounter unused, aggregated;
2025 typedef AggregateVisitor<DependencyCounter> CounterT;
2026 typedef std::tuple<CounterT,CounterT> CounterTuple;
2027 CombinedFunctor<CounterTuple> visitors(CounterTuple(CounterT(aggregates, AggregatesMap<Vertex>::UNAGGREGATED, unused), CounterT(aggregates, aggregate, aggregated)));
2028 visitNeighbours(*graph_, vertex, visitors);
2029 return std::make_pair(unused.value(), aggregated.value());
2030 }
2031
2032
2033 template<class G>
2034 int Aggregator<G>::aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2035 {
2036 DependencyCounter counter;
2037 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
2038 return counter.value();
2039 }
2040
2041 template<class G>
2042 std::size_t Aggregator<G>::distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates)
2043 {
2044 return 0;
2045 typename PropertyMapTypeSelector<VertexVisitedTag,G>::Type visitedMap = get(VertexVisitedTag(), *graph_);
2046 VertexList vlist;
2047 typename AggregatesMap<Vertex>::DummyEdgeVisitor dummy;
2048 return aggregates.template breadthFirstSearch<true,true>(vertex,
2049 aggregate_->id(), *graph_,
2050 vlist, dummy, dummy, visitedMap);
2051 }
2052
2053 template<class G>
2054 inline Aggregator<G>::FrontMarker::FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph)
2055 : front_(front), graph_(graph)
2056 {}
2057
2058 template<class G>
2059 inline void Aggregator<G>::FrontMarker::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2060 {
2061 Vertex target = edge.target();
2062
2063 if(!graph_.getVertexProperties(target).front()) {
2064 front_.push_back(target);
2065 graph_.getVertexProperties(target).setFront();
2066 }
2067 }
2068
2069 template<class G>
2070 inline bool Aggregator<G>::admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2071 {
2072 // Todo
2073 Dune::dvverb<<" Admissible not yet implemented!"<<std::endl;
2074 return true;
2075 //Situation 1: front node depends on two nodes. Then these
2076 // have to be strongly connected to each other
2077
2078 // Iterate over all all neighbours of front node
2079 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2080 Iterator vend = graph_->endEdges(vertex);
2081 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2082 // if(edge.properties().depends() && !edge.properties().influences()
2083 if(edge.properties().isStrong()
2084 && aggregates[edge.target()]==aggregate)
2085 {
2086 // Search for another link to the aggregate
2087 Iterator edge1 = edge;
2088 for(++edge1; edge1 != vend; ++edge1) {
2089 //if(edge1.properties().depends() && !edge1.properties().influences()
2090 if(edge1.properties().isStrong()
2091 && aggregates[edge.target()]==aggregate)
2092 {
2093 //Search for an edge connecting the two vertices that is
2094 //strong
2095 bool found=false;
2096 Iterator v2end = graph_->endEdges(edge.target());
2097 for(Iterator edge2 = graph_->beginEdges(edge.target()); edge2 != v2end; ++edge2) {
2098 if(edge2.target()==edge1.target() &&
2099 edge2.properties().isStrong()) {
2100 found =true;
2101 break;
2102 }
2103 }
2104 if(found)
2105 {
2106 return true;
2107 }
2108 }
2109 }
2110 }
2111 }
2112
2113 // Situation 2: cluster node depends on front node and other cluster node
2115 vend = graph_->endEdges(vertex);
2116 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2117 //if(!edge.properties().depends() && edge.properties().influences()
2118 if(edge.properties().isStrong()
2119 && aggregates[edge.target()]==aggregate)
2120 {
2121 // Search for a link from target that stays within the aggregate
2122 Iterator v1end = graph_->endEdges(edge.target());
2123
2124 for(Iterator edge1=graph_->beginEdges(edge.target()); edge1 != v1end; ++edge1) {
2125 //if(edge1.properties().depends() && !edge1.properties().influences()
2126 if(edge1.properties().isStrong()
2127 && aggregates[edge1.target()]==aggregate)
2128 {
2129 bool found=false;
2130 // Check if front node is also connected to this one
2131 Iterator v2end = graph_->endEdges(vertex);
2132 for(Iterator edge2 = graph_->beginEdges(vertex); edge2 != v2end; ++edge2) {
2133 if(edge2.target()==edge1.target()) {
2134 if(edge2.properties().isStrong())
2135 found=true;
2136 break;
2137 }
2138 }
2139 if(found)
2140 {
2141 return true;
2142 }
2143 }
2144 }
2145 }
2146 }
2147 return false;
2148 }
2149
2150 template<class G>
2151 void Aggregator<G>::unmarkFront()
2152 {
2153 typedef typename std::vector<Vertex>::const_iterator Iterator;
2154
2155 for(Iterator vertex=front_.begin(); vertex != front_.end(); ++vertex)
2156 graph_->getVertexProperties(*vertex).resetFront();
2157
2158 front_.clear();
2159 }
2160
2161 template<class G>
2162 inline void
2163 Aggregator<G>::nonisoNeighbourAggregate(const Vertex& vertex,
2164 const AggregatesMap<Vertex>& aggregates,
2165 SLList<Vertex>& neighbours) const
2166 {
2167 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2168 Iterator end=graph_->beginEdges(vertex);
2169 neighbours.clear();
2170
2171 for(Iterator edge=graph_->beginEdges(vertex); edge!=end; ++edge)
2172 {
2173 if(aggregates[edge.target()]!=AggregatesMap<Vertex>::UNAGGREGATED && graph_->getVertexProperties(edge.target()).isolated())
2174 neighbours.push_back(aggregates[edge.target()]);
2175 }
2176 }
2177
2178 template<class G>
2179 inline typename G::VertexDescriptor Aggregator<G>::mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2180 {
2181 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2182
2183 Iterator end = graph_->endEdges(vertex);
2184 for(Iterator edge = graph_->beginEdges(vertex); edge != end; ++edge) {
2185 if(aggregates[edge.target()] != AggregatesMap<Vertex>::UNAGGREGATED &&
2186 graph_->getVertexProperties(edge.target()).isolated() == graph_->getVertexProperties(edge.source()).isolated()) {
2187 if( graph_->getVertexProperties(vertex).isolated() ||
2188 ((edge.properties().depends() || edge.properties().influences())
2189 && admissible(vertex, aggregates[edge.target()], aggregates)))
2190 return edge.target();
2191 }
2192 }
2194 }
2195
2196 template<class G>
2197 Aggregator<G>::FrontNeighbourCounter::FrontNeighbourCounter(const MatrixGraph& graph)
2198 : Counter(), graph_(graph)
2199 {}
2200
2201 template<class G>
2202 void Aggregator<G>::FrontNeighbourCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2203 {
2204 if(graph_.getVertexProperties(edge.target()).front())
2205 Counter::increment();
2206 }
2207
2208 template<class G>
2209 int Aggregator<G>::noFrontNeighbours(const Vertex& vertex) const
2210 {
2211 FrontNeighbourCounter counter(*graph_);
2212 visitNeighbours(*graph_, vertex, counter);
2213 return counter.value();
2214 }
2215 template<class G>
2216 inline bool Aggregator<G>::connected(const Vertex& vertex,
2217 const AggregateDescriptor& aggregate,
2218 const AggregatesMap<Vertex>& aggregates) const
2219 {
2220 typedef typename G::ConstEdgeIterator iterator;
2221 const iterator end = graph_->endEdges(vertex);
2222 for(iterator edge = graph_->beginEdges(vertex); edge != end; ++edge)
2223 if(aggregates[edge.target()]==aggregate)
2224 return true;
2225 return false;
2226 }
2227 template<class G>
2228 inline bool Aggregator<G>::connected(const Vertex& vertex,
2229 const SLList<AggregateDescriptor>& aggregateList,
2230 const AggregatesMap<Vertex>& aggregates) const
2231 {
2232 typedef typename SLList<AggregateDescriptor>::const_iterator Iter;
2233 for(Iter i=aggregateList.begin(); i!=aggregateList.end(); ++i)
2234 if(connected(vertex, *i, aggregates))
2235 return true;
2236 return false;
2237 }
2238
2239 template<class G>
2240 template<class C>
2241 void Aggregator<G>::growIsolatedAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2242 {
2243 SLList<Vertex> connectedAggregates;
2244 nonisoNeighbourAggregate(seed, aggregates,connectedAggregates);
2245
2246 while(aggregate_->size()< c.minAggregateSize() && aggregate_->connectSize() < c.maxConnectivity()) {
2247 double maxCon=-1;
2248 std::size_t maxFrontNeighbours=0;
2249
2251
2252 typedef typename std::vector<Vertex>::const_iterator Iterator;
2253
2254 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2255 if(distance(*vertex, aggregates)>c.maxDistance())
2256 continue; // distance of proposes aggregate too big
2257
2258 if(connectedAggregates.size()>0) {
2259 // there is already a neighbour cluster
2260 // front node must be connected to same neighbour cluster
2261
2262 if(!connected(*vertex, connectedAggregates, aggregates))
2263 continue;
2264 }
2265
2266 double con = connectivity(*vertex, aggregates);
2267
2268 if(con == maxCon) {
2269 std::size_t frontNeighbours = noFrontNeighbours(*vertex);
2270
2271 if(frontNeighbours >= maxFrontNeighbours) {
2272 maxFrontNeighbours = frontNeighbours;
2273 candidate = *vertex;
2274 }
2275 }else if(con > maxCon) {
2276 maxCon = con;
2277 maxFrontNeighbours = noFrontNeighbours(*vertex);
2278 candidate = *vertex;
2279 }
2280 }
2281
2283 break;
2284
2285 aggregate_->add(candidate);
2286 }
2287 }
2288
2289 template<class G>
2290 template<class C>
2291 void Aggregator<G>::growAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2292 {
2293 using std::min;
2294
2295 std::size_t distance_ =0;
2296 while(aggregate_->size() < c.minAggregateSize()&& distance_<c.maxDistance()) {
2297 int maxTwoCons=0, maxOneCons=0, maxNeighbours=-1;
2298 double maxCon=-1;
2299
2300 std::vector<Vertex> candidates;
2301 candidates.reserve(30);
2302
2303 typedef typename std::vector<Vertex>::const_iterator Iterator;
2304
2305 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2306 // Only nonisolated nodes are considered
2307 if(graph_->getVertexProperties(*vertex).isolated())
2308 continue;
2309
2310 int twoWayCons = twoWayConnections(*vertex, aggregate_->id(), aggregates);
2311
2312 /* The case of two way connections. */
2313 if( maxTwoCons == twoWayCons && twoWayCons > 0) {
2314 double con = connectivity(*vertex, aggregates);
2315
2316 if(con == maxCon) {
2317 int neighbours = noFrontNeighbours(*vertex);
2318
2319 if(neighbours > maxNeighbours) {
2320 maxNeighbours = neighbours;
2321 candidates.clear();
2322 candidates.push_back(*vertex);
2323 }else{
2324 candidates.push_back(*vertex);
2325 }
2326 }else if( con > maxCon) {
2327 maxCon = con;
2328 maxNeighbours = noFrontNeighbours(*vertex);
2329 candidates.clear();
2330 candidates.push_back(*vertex);
2331 }
2332 }else if(twoWayCons > maxTwoCons) {
2333 maxTwoCons = twoWayCons;
2334 maxCon = connectivity(*vertex, aggregates);
2335 maxNeighbours = noFrontNeighbours(*vertex);
2336 candidates.clear();
2337 candidates.push_back(*vertex);
2338
2339 // two way connections precede
2340 maxOneCons = std::numeric_limits<int>::max();
2341 }
2342
2343 if(twoWayCons > 0)
2344 {
2345 continue; // THis is a two-way node, skip tests for one way nodes
2346 }
2347
2348 /* The one way case */
2349 int oneWayCons = oneWayConnections(*vertex, aggregate_->id(), aggregates);
2350
2351 if(oneWayCons==0)
2352 continue; // No strong connections, skip the tests.
2353
2354 if(!admissible(*vertex, aggregate_->id(), aggregates))
2355 continue;
2356
2357 if( maxOneCons == oneWayCons && oneWayCons > 0) {
2358 double con = connectivity(*vertex, aggregates);
2359
2360 if(con == maxCon) {
2361 int neighbours = noFrontNeighbours(*vertex);
2362
2363 if(neighbours > maxNeighbours) {
2364 maxNeighbours = neighbours;
2365 candidates.clear();
2366 candidates.push_back(*vertex);
2367 }else{
2368 if(neighbours==maxNeighbours)
2369 {
2370 candidates.push_back(*vertex);
2371 }
2372 }
2373 }else if( con > maxCon) {
2374 maxCon = con;
2375 maxNeighbours = noFrontNeighbours(*vertex);
2376 candidates.clear();
2377 candidates.push_back(*vertex);
2378 }
2379 }else if(oneWayCons > maxOneCons) {
2380 maxOneCons = oneWayCons;
2381 maxCon = connectivity(*vertex, aggregates);
2382 maxNeighbours = noFrontNeighbours(*vertex);
2383 candidates.clear();
2384 candidates.push_back(*vertex);
2385 }
2386 }
2387
2388
2389 if(!candidates.size())
2390 break; // No more candidates found
2391 distance_=distance(seed, aggregates);
2392 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2393 aggregate_->size()));
2394 aggregate_->add(candidates);
2395 }
2396 }
2397
2398 template<typename V>
2399 template<typename M, typename G, typename C>
2400 std::tuple<int,int,int,int> AggregatesMap<V>::buildAggregates(const M& matrix, G& graph, const C& criterion,
2401 bool finestLevel)
2402 {
2403 Aggregator<G> aggregator;
2404 return aggregator.build(matrix, graph, *this, criterion, finestLevel);
2405 }
2406
2407 template<class G>
2408 template<class M, class C>
2409 std::tuple<int,int,int,int> Aggregator<G>::build(const M& m, G& graph, AggregatesMap<Vertex>& aggregates, const C& c,
2410 bool finestLevel)
2411 {
2412 using std::max;
2413 using std::min;
2414 // Stack for fast vertex access
2415 Stack stack_(graph, *this, aggregates);
2416
2417 graph_ = &graph;
2418
2419 aggregate_ = new Aggregate<G,VertexSet>(graph, aggregates, connected_, front_);
2420
2421 Timer watch;
2422 watch.reset();
2423
2424 buildDependency(graph, m, c, finestLevel);
2425
2426 dverb<<"Build dependency took "<< watch.elapsed()<<" seconds."<<std::endl;
2427 int noAggregates, conAggregates, isoAggregates, oneAggregates;
2428 std::size_t maxA=0, minA=1000000, avg=0;
2429 int skippedAggregates;
2430 noAggregates = conAggregates = isoAggregates = oneAggregates =
2431 skippedAggregates = 0;
2432
2433 while(true) {
2434 Vertex seed = stack_.pop();
2435
2436 if(seed == Stack::NullEntry)
2437 // No more unaggregated vertices. We are finished!
2438 break;
2439
2440 // Debugging output
2441 if((noAggregates+1)%10000 == 0)
2442 Dune::dverb<<"c";
2443 unmarkFront();
2444
2445 if(graph.getVertexProperties(seed).excludedBorder()) {
2446 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2447 ++skippedAggregates;
2448 continue;
2449 }
2450
2451 if(graph.getVertexProperties(seed).isolated()) {
2452 if(c.skipIsolated()) {
2453 // isolated vertices are not aggregated but skipped on the coarser levels.
2454 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2455 ++skippedAggregates;
2456 // skip rest as no agglomeration is done.
2457 continue;
2458 }else{
2459 aggregate_->seed(seed);
2460 growIsolatedAggregate(seed, aggregates, c);
2461 }
2462 }else{
2463 aggregate_->seed(seed);
2464 growAggregate(seed, aggregates, c);
2465 }
2466
2467 /* The rounding step. */
2468 while(!(graph.getVertexProperties(seed).isolated()) && aggregate_->size() < c.maxAggregateSize()) {
2469
2470 std::vector<Vertex> candidates;
2471 candidates.reserve(30);
2472
2473 typedef typename std::vector<Vertex>::const_iterator Iterator;
2474
2475 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2476
2477 if(graph.getVertexProperties(*vertex).isolated())
2478 continue; // No isolated nodes here
2479
2480 if(twoWayConnections( *vertex, aggregate_->id(), aggregates) == 0 &&
2481 (oneWayConnections( *vertex, aggregate_->id(), aggregates) == 0 ||
2482 !admissible( *vertex, aggregate_->id(), aggregates) ))
2483 continue;
2484
2485 std::pair<int,int> neighbourPair=neighbours(*vertex, aggregate_->id(),
2486 aggregates);
2487
2488 //if(aggregateNeighbours(*vertex, aggregate_->id(), aggregates) <= unusedNeighbours(*vertex, aggregates))
2489 // continue;
2490
2491 if(neighbourPair.first >= neighbourPair.second)
2492 continue;
2493
2494 if(distance(*vertex, aggregates) > c.maxDistance())
2495 continue; // Distance too far
2496 candidates.push_back(*vertex);
2497 break;
2498 }
2499
2500 if(!candidates.size()) break; // no more candidates found.
2501
2502 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2503 aggregate_->size()));
2504 aggregate_->add(candidates);
2505
2506 }
2507
2508 // try to merge aggregates consisting of only one nonisolated vertex with other aggregates
2509 if(aggregate_->size()==1 && c.maxAggregateSize()>1) {
2510 if(!graph.getVertexProperties(seed).isolated()) {
2511 Vertex mergedNeighbour = mergeNeighbour(seed, aggregates);
2512
2513 if(mergedNeighbour != AggregatesMap<Vertex>::UNAGGREGATED) {
2514 // assign vertex to the neighbouring cluster
2515 aggregates[seed] = aggregates[mergedNeighbour];
2516 aggregate_->invalidate();
2517 }else{
2518 ++avg;
2519 minA=min(minA,static_cast<std::size_t>(1));
2520 maxA=max(maxA,static_cast<std::size_t>(1));
2521 ++oneAggregates;
2522 ++conAggregates;
2523 }
2524 }else{
2525 ++avg;
2526 minA=min(minA,static_cast<std::size_t>(1));
2527 maxA=max(maxA,static_cast<std::size_t>(1));
2528 ++oneAggregates;
2529 ++isoAggregates;
2530 }
2531 ++avg;
2532 }else{
2533 avg+=aggregate_->size();
2534 minA=min(minA,aggregate_->size());
2535 maxA=max(maxA,aggregate_->size());
2536 if(graph.getVertexProperties(seed).isolated())
2537 ++isoAggregates;
2538 else
2539 ++conAggregates;
2540 }
2541
2542 }
2543
2544 Dune::dinfo<<"connected aggregates: "<<conAggregates;
2545 Dune::dinfo<<" isolated aggregates: "<<isoAggregates;
2546 if(conAggregates+isoAggregates>0)
2547 Dune::dinfo<<" one node aggregates: "<<oneAggregates<<" min size="
2548 <<minA<<" max size="<<maxA
2549 <<" avg="<<avg/(conAggregates+isoAggregates)<<std::endl;
2550
2551 delete aggregate_;
2552 return std::make_tuple(conAggregates+isoAggregates,isoAggregates,
2553 oneAggregates,skippedAggregates);
2554 }
2555
2556
2557 template<class G>
2558 Aggregator<G>::Stack::Stack(const MatrixGraph& graph, const Aggregator<G>& aggregatesBuilder,
2559 const AggregatesMap<Vertex>& aggregates)
2560 : graph_(graph), aggregatesBuilder_(aggregatesBuilder), aggregates_(aggregates), begin_(graph.begin()), end_(graph.end())
2561 {
2562 //vals_ = new Vertex[N];
2563 }
2564
2565 template<class G>
2566 Aggregator<G>::Stack::~Stack()
2567 {
2568 //Dune::dverb << "Max stack size was "<<maxSize_<<" filled="<<filled_<<std::endl;
2569 //delete[] vals_;
2570 }
2571
2572 template<class G>
2573 const typename Aggregator<G>::Vertex Aggregator<G>::Stack::NullEntry
2575
2576 template<class G>
2577 inline typename G::VertexDescriptor Aggregator<G>::Stack::pop()
2578 {
2579 for(; begin_!=end_ && aggregates_[*begin_] != AggregatesMap<Vertex>::UNAGGREGATED; ++begin_) ;
2580
2581 if(begin_!=end_)
2582 {
2583 typename G::VertexDescriptor current=*begin_;
2584 ++begin_;
2585 return current;
2586 }else
2587 return NullEntry;
2588 }
2589
2590#endif // DOXYGEN
2591
2592 template<class V>
2593 void printAggregates2d(const AggregatesMap<V>& aggregates, int n, int m, std::ostream& os)
2594 {
2595 using std::max;
2596
2597 std::ios_base::fmtflags oldOpts=os.flags();
2598
2599 os.setf(std::ios_base::right, std::ios_base::adjustfield);
2600
2601 V maxVal=0;
2602 int width=1;
2603
2604 for(int i=0; i< n*m; i++)
2605 maxVal=max(maxVal, aggregates[i]);
2606
2607 for(int i=10; i < 1000000; i*=10)
2608 if(maxVal/i>0)
2609 width++;
2610 else
2611 break;
2612
2613 for(int j=0, entry=0; j < m; j++) {
2614 for(int i=0; i<n; i++, entry++) {
2615 os.width(width);
2616 os<<aggregates[entry]<<" ";
2617 }
2618
2619 os<<std::endl;
2620 }
2621 os<<std::endl;
2622 os.flags(oldOpts);
2623 }
2624
2625
2626 } // namespace Amg
2627
2628} // namespace Dune
2629
2630
2631#endif
A class for temporarily storing the vertices of an aggregate in.
Definition: aggregates.hh:784
A Dummy visitor that does nothing for each visited edge.
Definition: aggregates.hh:604
Class providing information about the mapping of the vertices onto aggregates.
Definition: aggregates.hh:566
Base class of all aggregation criterions.
Definition: aggregates.hh:51
Class for building the aggregates.
Definition: aggregates.hh:920
Dependency policy for symmetric matrices.
Definition: aggregates.hh:255
Norm that uses only the [N][N] entry of the block to determine couplings.
Definition: aggregates.hh:381
Norm that uses only the [0][0] entry of the block to determine couplings.
Definition: aggregates.hh:457
Iterator over all edges starting from a vertex.
Definition: graph.hh:95
The vertex iterator type of the graph.
Definition: graph.hh:209
The (undirected) graph of a matrix.
Definition: graph.hh:51
M::size_type VertexDescriptor
The vertex descriptor.
Definition: graph.hh:73
EdgeIteratorT< const MatrixGraph< Matrix > > ConstEdgeIterator
The constant edge iterator type.
Definition: graph.hh:298
All parameters for AMG.
Definition: parameters.hh:416
Criterion taking advantage of symmetric matrices.
Definition: aggregates.hh:525
Dependency policy for symmetric matrices.
Definition: aggregates.hh:316
Dependency policy for symmetric matrices.
Definition: aggregates.hh:136
Criterion suitable for unsymmetric matrices.
Definition: aggregates.hh:545
derive error class from the base class in common
Definition: istlexception.hh:19
A generic dynamic dense matrix.
Definition: matrix.hh:561
typename Imp::BlockTraits< T >::field_type field_type
Export the type representing the underlying field.
Definition: matrix.hh:565
row_type::const_iterator ConstColIterator
Const iterator for the entries of each row.
Definition: matrix.hh:589
MatrixImp::DenseMatrixBase< T, A >::window_type row_type
The type implementing a matrix row.
Definition: matrix.hh:574
An allocator managing a pool of objects for reuse.
Definition: poolallocator.hh:223
A single linked list.
Definition: sllist.hh:44
Type traits to determine the type of reals (when working with complex numbers)
Provides classes for building the matrix graph.
SLListConstIterator< T, A > const_iterator
The constant iterator of the list.
Definition: sllist.hh:74
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
constexpr GeometryType vertex
GeometryType representing a vertex.
Definition: type.hh:492
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:511
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:275
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:156
std::size_t breadthFirstSearch(const VertexDescriptor &start, const AggregateDescriptor &aggregate, const G &graph, L &visited, F1 &aggregateVisitor, F2 &nonAggregateVisitor, VM &visitedMap) const
Breadth first search within an aggregate.
PoolAllocator< VertexDescriptor, 100 > Allocator
The allocator we use for our lists and the set.
Definition: aggregates.hh:592
int id()
Get the id identifying the aggregate.
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:304
size_type size()
Get the size of the aggregate.
MatrixGraph::VertexDescriptor Vertex
The vertex identifier.
Definition: aggregates.hh:931
AggregationCriterion()
Constructor.
Definition: aggregates.hh:68
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:359
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:260
G MatrixGraph
The matrix graph type used.
Definition: aggregates.hh:926
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:365
typename VertexSet::size_type size_type
Type of size used by allocator of sllist.
Definition: aggregates.hh:812
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:321
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:189
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:265
int row_
index of the currently evaluated row.
Definition: aggregates.hh:187
std::tuple< int, int, int, int > build(const M &m, G &graph, AggregatesMap< Vertex > &aggregates, const C &c, bool finestLevel)
Build the aggregates.
FrontNeighbourCounter(const MatrixGraph &front)
Constructor.
Matrix::row_type Row
Constant Row iterator of the matrix.
Definition: aggregates.hh:331
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:298
size_type connectSize()
Get the number of connections to other aggregates.
const AggregateDescriptor & operator[](const VertexDescriptor &v) const
Get the aggregate a vertex belongs to.
AggregateVisitor(const AggregatesMap< Vertex > &aggregates, const AggregateDescriptor &aggregate, Visitor &visitor)
Constructor.
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:336
FieldTraits< typenameM::field_type >::real_type operator()(const M &) const
compute the norm of a matrix.
Definition: aggregates.hh:512
~AggregatesMap()
Destructor.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:181
void decrement()
Decrement counter.
Aggregate(MatrixGraph &graph, AggregatesMap< Vertex > &aggregates, VertexSet &connectivity, std::vector< Vertex > &front_)
Constructor.
V Visitor
The type of the adapted visitor.
Definition: aggregates.hh:1075
std::size_t * SphereMap
Type of the mapping of aggregate members onto distance spheres.
Definition: aggregates.hh:820
Matrix::row_type Row
Constant Row iterator of the matrix.
Definition: aggregates.hh:270
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:326
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:185
VertexSet::const_iterator const_iterator
Const iterator over a vertex list.
Definition: aggregates.hh:815
MatrixGraph::VertexDescriptor AggregateDescriptor
The type of the aggregate descriptor.
Definition: aggregates.hh:934
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:369
~Aggregator()
Destructor.
void add(const Vertex &vertex)
Add a vertex to the aggregate.
T DependencyPolicy
The policy for calculating the dependency graph.
Definition: aggregates.hh:57
auto operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:475
Aggregator()
Constructor.
void operator()(const typename MatrixGraph::ConstEdgeIterator &edge)
Examine an edge.
FrontMarker(std::vector< Vertex > &front, MatrixGraph &graph)
Constructor.
int visitNeighbours(const G &graph, const typename G::VertexDescriptor &vertex, V &visitor)
Visit all neighbour vertices of a vertex in a graph.
void setDefaultValuesIsotropic(std::size_t dim, std::size_t diameter=2)
Sets reasonable default values for an isotropic problem.
Definition: aggregates.hh:84
V AggregateDescriptor
The aggregate descriptor type.
Definition: aggregates.hh:586
static const V ISOLATED
Identifier of isolated vertices.
Definition: aggregates.hh:577
int row_
index of the currently evaluated row.
Definition: aggregates.hh:367
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:308
std::size_t noVertices() const
Get the number of vertices.
void setDefaultValuesAnisotropic(std::size_t dim, std::size_t diameter=2)
Sets reasonable default values for an aisotropic problem.
Definition: aggregates.hh:107
AggregatesMap(std::size_t noVertices)
Constructs with allocating memory.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:361
AggregateDescriptor & operator[](const VertexDescriptor &v)
Get the aggregate a vertex belongs to.
AggregatesMap()
Constructs without allocating memory.
int value()
Access the current count.
SLList< VertexDescriptor, Allocator > VertexList
The type of a single linked list of vertex descriptors.
Definition: aggregates.hh:598
ConnectivityCounter(const VertexSet &connected, const AggregatesMap< Vertex > &aggregates)
Constructor.
const_iterator end() const
get an iterator over the vertices of the aggregate.
int row_
index of the currently evaluated row.
Definition: aggregates.hh:306
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:141
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:179
S VertexSet
The type of a single linked list of vertex descriptors.
Definition: aggregates.hh:807
FieldTraits< typenameM::field_type >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:496
static const V UNAGGREGATED
Identifier of not yet aggregated vertices.
Definition: aggregates.hh:572
std::size_t breadthFirstSearch(const VertexDescriptor &start, const AggregateDescriptor &aggregate, const G &graph, F &aggregateVisitor, VM &visitedMap) const
Breadth first search within an aggregate.
auto operator()(const M &m, typename std::enable_if_t< Dune::IsNumber< M >::value > *=nullptr) const
Compute the norm of a scalar.
Definition: aggregates.hh:408
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:300
void allocate(std::size_t noVertices)
Allocate memory for holding the information.
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:146
void reconstruct(const Vertex &vertex)
Reconstruct the aggregat from an seed node.
const_iterator begin() const
get an iterator over the vertices of the aggregate.
FieldTraits< typenameM::field_type >::real_type operator()(const M &m, typename std::enable_if_t<!Dune::IsNumber< M >::value > *sfinae=nullptr) const
compute the norm of a matrix.
Definition: aggregates.hh:392
MatrixGraph::VertexDescriptor Vertex
The vertex descriptor type.
Definition: aggregates.hh:795
void seed(const Vertex &vertex)
Initialize the aggregate with one vertex.
void clear()
Clear the aggregate.
void free()
Free the allocated memory.
void increment()
Increment counter.
void buildDependency(G &graph, const typename C::Matrix &matrix, C criterion, bool finestLevel)
Build the dependency of the matrix graph.
V VertexDescriptor
The vertex descriptor type.
Definition: aggregates.hh:581
std::tuple< int, int, int, int > buildAggregates(const M &matrix, G &graph, const C &criterion, bool finestLevel)
Build the aggregates.
Matrix::row_type Row
Constant Row iterator of the matrix.
Definition: aggregates.hh:151
PoolAllocator< Vertex, 100 > Allocator
The allocator we use for our lists and the set.
Definition: aggregates.hh:801
DVVerbType dvverb(std::cout)
stream for very verbose output.
Definition: stdstreams.hh:96
DInfoType dinfo(std::cout)
Stream for informative output.
Definition: stdstreams.hh:141
DVerbType dverb(std::cout)
Singleton of verbose debug stream.
Definition: stdstreams.hh:117
Dune namespace
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
constexpr auto front(const HybridMultiIndex< T... > &tp) -> decltype(tp.front())
Returns a copy of the first element of the HybridMultiIndex.
Definition: hybridmultiindex.hh:238
constexpr auto get(std::integer_sequence< T, II... >, std::integral_constant< std::size_t, pos >={})
Return the entry at position pos of the given sequence.
Definition: integersequence.hh:22
Parameter classes for customizing AMG.
An stl-compliant pool allocator.
Provides classes for handling internal properties in a graph.
Implements a scalar matrix view wrapper around an existing scalar.
Implements a singly linked list together with the necessary iterators.
Standard Dune debug streams.
Functor using the row sum (infinity) norm to determine strong couplings.
Definition: aggregates.hh:465
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition: typetraits.hh:194
A simple timing class.
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jan 9, 23:34, 2026)