Dune Core Modules (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 typename FieldTraits<M>::real_type 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<M>::real_type operator()(const M& m) const
497 {
498 using std::abs;
499 if constexpr(Dune::IsNumber<M>::value)
500 return abs(m);
501 else
502 return m.frobenius_norm();
503 }
504 };
505 struct AlwaysOneNorm
506 {
507
508 enum { /* @brief We preserve the sign.*/
509 is_sign_preserving = false
510 };
515 template<class M>
516 typename FieldTraits<M>::real_type operator()(const M& /*m*/) const
517 {
518 return 1;
519 }
520 };
527 template<class M, class Norm>
528 class SymmetricCriterion : public AggregationCriterion<SymmetricDependency<M,Norm> >
529 {
530 public:
531 SymmetricCriterion(const Parameters& parms)
533 {}
535 {}
536 };
537
538
547 template<class M, class Norm>
548 class UnSymmetricCriterion : public AggregationCriterion<Dependency<M,Norm> >
549 {
550 public:
551 UnSymmetricCriterion(const Parameters& parms)
553 {}
555 {}
556 };
557 // forward declaration
558 template<class G> class Aggregator;
559
560
568 template<class V>
570 {
571 public:
572
576 static const V UNAGGREGATED;
577
581 static const V ISOLATED;
586
591
597
603
608 {
609 public:
610 template<class EdgeIterator>
611 void operator()([[maybe_unused]] const EdgeIterator& edge) const
612 {}
613 };
614
615
620
627
632
644 template<class M, class G, class C>
645 std::tuple<int,int,int,int> buildAggregates(const M& matrix, G& graph, const C& criterion,
646 bool finestLevel);
647
665 template<bool reset, class G, class F, class VM>
666 std::size_t breadthFirstSearch(const VertexDescriptor& start,
667 const AggregateDescriptor& aggregate,
668 const G& graph,
669 F& aggregateVisitor,
670 VM& visitedMap) const;
671
695 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
696 std::size_t breadthFirstSearch(const VertexDescriptor& start,
697 const AggregateDescriptor& aggregate,
698 const G& graph, L& visited, F1& aggregateVisitor,
699 F2& nonAggregateVisitor,
700 VM& visitedMap) const;
701
707 void allocate(std::size_t noVertices);
708
712 std::size_t noVertices() const;
713
717 void free();
718
725
732
733 typedef const AggregateDescriptor* const_iterator;
734
735 const_iterator begin() const
736 {
737 return aggregates_;
738 }
739
740 const_iterator end() const
741 {
742 return aggregates_+noVertices();
743 }
744
745 typedef AggregateDescriptor* iterator;
746
747 iterator begin()
748 {
749 return aggregates_;
750 }
751
752 iterator end()
753 {
754 return aggregates_+noVertices();
755 }
756 private:
758 AggregatesMap(const AggregatesMap<V>&) = delete;
760 AggregatesMap<V>& operator=(const AggregatesMap<V>&) = delete;
761
765 AggregateDescriptor* aggregates_;
766
770 std::size_t noVertices_;
771 };
772
776 template<class G, class C>
777 void buildDependency(G& graph,
778 const typename C::Matrix& matrix,
779 C criterion,
780 bool finestLevel);
781
786 template<class G, class S>
788 {
789
790 public:
791
792 /***
793 * @brief The type of the matrix graph we work with.
794 */
795 typedef G MatrixGraph;
800
806
811 typedef S VertexSet;
812
816 using size_type = typename VertexSet::size_type;
817
819 typedef typename VertexSet::const_iterator const_iterator;
820
824 typedef std::size_t* SphereMap;
825
834 Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
835 VertexSet& connectivity, std::vector<Vertex>& front_);
836
837 void invalidate()
838 {
839 --id_;
840 }
841
849
853 void seed(const Vertex& vertex);
854
858 void add(const Vertex& vertex);
859
860 void add(std::vector<Vertex>& vertex);
864 void clear();
865
874
878 int id();
879
882
885
886 private:
890 VertexSet vertices_;
891
896 int id_;
897
901 MatrixGraph& graph_;
902
906 AggregatesMap<Vertex>& aggregates_;
907
911 VertexSet& connected_;
912
916 std::vector<Vertex>& front_;
917 };
918
922 template<class G>
924 {
925 public:
926
930 typedef G MatrixGraph;
931
936
939
944
949
966 template<class M, class C>
967 std::tuple<int,int,int,int> build(const M& m, G& graph,
968 AggregatesMap<Vertex>& aggregates, const C& c,
969 bool finestLevel);
970 private:
976
981
985 typedef std::set<Vertex,std::less<Vertex>,Allocator> VertexSet;
986
990 typedef std::size_t* SphereMap;
991
995 MatrixGraph* graph_;
996
1001
1005 std::vector<Vertex> front_;
1006
1010 VertexSet connected_;
1011
1015 int size_;
1016
1020 class Stack
1021 {
1022 public:
1023 static const Vertex NullEntry;
1024
1025 Stack(const MatrixGraph& graph,
1026 const Aggregator<G>& aggregatesBuilder,
1027 const AggregatesMap<Vertex>& aggregates);
1028 ~Stack();
1029 Vertex pop();
1030 private:
1031 enum { N = 1300000 };
1032
1034 const MatrixGraph& graph_;
1036 const Aggregator<G>& aggregatesBuilder_;
1038 const AggregatesMap<Vertex>& aggregates_;
1040 int size_;
1041 Vertex maxSize_;
1043 typename MatrixGraph::ConstVertexIterator begin_;
1045
1047 Vertex* vals_;
1048
1049 };
1050
1051 friend class Stack;
1052
1063 template<class V>
1064 void visitAggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate,
1065 const AggregatesMap<Vertex>& aggregates,
1066 V& visitor) const;
1067
1072 template<class V>
1073 class AggregateVisitor
1074 {
1075 public:
1079 typedef V Visitor;
1088 Visitor& visitor);
1089
1096 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1097
1098 private:
1100 const AggregatesMap<Vertex>& aggregates_;
1102 AggregateDescriptor aggregate_;
1104 Visitor* visitor_;
1105 };
1106
1110 class Counter
1111 {
1112 public:
1116 int value();
1117
1118 protected:
1123
1124 private:
1125 int count_;
1126 };
1127
1128
1133 class FrontNeighbourCounter : public Counter
1134 {
1135 public:
1141
1142 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1143
1144 private:
1145 const MatrixGraph& graph_;
1146 };
1147
1152 int noFrontNeighbours(const Vertex& vertex) const;
1153
1157 class TwoWayCounter : public Counter
1158 {
1159 public:
1160 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1161 };
1162
1174 int twoWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1175 const AggregatesMap<Vertex>& aggregates) const;
1176
1180 class OneWayCounter : public Counter
1181 {
1182 public:
1183 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1184 };
1185
1197 int oneWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1198 const AggregatesMap<Vertex>& aggregates) const;
1199
1206 class ConnectivityCounter : public Counter
1207 {
1208 public:
1214 ConnectivityCounter(const VertexSet& connected, const AggregatesMap<Vertex>& aggregates);
1215
1216 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1217
1218 private:
1220 const VertexSet& connected_;
1222 const AggregatesMap<Vertex>& aggregates_;
1223
1224 };
1225
1237 double connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1245 bool connected(const Vertex& vertex, const AggregateDescriptor& aggregate,
1246 const AggregatesMap<Vertex>& aggregates) const;
1247
1255 bool connected(const Vertex& vertex, const SLList<AggregateDescriptor>& aggregateList,
1256 const AggregatesMap<Vertex>& aggregates) const;
1257
1265 class DependencyCounter : public Counter
1266 {
1267 public:
1272
1273 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1274 };
1275
1282 class FrontMarker
1283 {
1284 public:
1291 FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph);
1292
1293 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1294
1295 private:
1297 std::vector<Vertex>& front_;
1299 MatrixGraph& graph_;
1300 };
1301
1305 void unmarkFront();
1306
1321 int unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1322
1336 std::pair<int,int> neighbours(const Vertex& vertex,
1337 const AggregateDescriptor& aggregate,
1338 const AggregatesMap<Vertex>& aggregates) const;
1355 int aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1356
1364 bool admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1365
1373 std::size_t distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates);
1374
1383 Vertex mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1384
1393 void nonisoNeighbourAggregate(const Vertex& vertex,
1394 const AggregatesMap<Vertex>& aggregates,
1395 SLList<Vertex>& neighbours) const;
1396
1404 template<class C>
1405 void growAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1406 template<class C>
1407 void growIsolatedAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1408 };
1409
1410#ifndef DOXYGEN
1411
1412 template<class M, class N>
1413 inline void SymmetricDependency<M,N>::init(const Matrix* matrix)
1414 {
1415 matrix_ = matrix;
1416 }
1417
1418 template<class M, class N>
1419 inline void SymmetricDependency<M,N>::initRow(const Row& row, int index)
1420 {
1421 initRow(row, index, std::is_convertible<field_type, real_type>());
1422 }
1423
1424 template<class M, class N>
1425 inline void SymmetricDependency<M,N>::initRow(const Row& /*row*/, int /*index*/, const std::false_type&)
1426 {
1427 DUNE_THROW(InvalidStateException, "field_type needs to convertible to real_type");
1428 }
1429
1430 template<class M, class N>
1431 inline void SymmetricDependency<M,N>::initRow(const Row& /*row*/, int index, const std::true_type&)
1432 {
1433 using std::min;
1435 row_ = index;
1436 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1437 }
1438
1439 template<class M, class N>
1440 inline void SymmetricDependency<M,N>::examine(const ColIter& col)
1441 {
1442 using std::max;
1443 real_type eij = norm_(*col);
1444 typename Matrix::ConstColIterator opposite_entry =
1445 matrix_->operator[](col.index()).find(row_);
1446 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1447 {
1448 // Consider this a weak connection we disregard.
1449 return;
1450 }
1451 real_type eji = norm_(*opposite_entry);
1452
1453 // skip positive offdiagonals if norm preserves sign of them.
1454 if(!N::is_sign_preserving || eij<0 || eji<0)
1455 maxValue_ = max(maxValue_,
1456 eij /diagonal_ * eji/
1457 norm_(matrix_->operator[](col.index())[col.index()]));
1458 }
1459
1460 template<class M, class N>
1461 template<class G>
1462 inline void SymmetricDependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1463 {
1464 real_type eij = norm_(*col);
1465 typename Matrix::ConstColIterator opposite_entry =
1466 matrix_->operator[](col.index()).find(row_);
1467
1468 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1469 {
1470 // Consider this as a weak connection we disregard.
1471 return;
1472 }
1473 real_type eji = norm_(*opposite_entry);
1474 // skip positive offdiagonals if norm preserves sign of them.
1475 if(!N::is_sign_preserving || (eij<0 || eji<0))
1476 if(eji / norm_(matrix_->operator[](edge.target())[edge.target()]) *
1477 eij/ diagonal_ > alpha() * maxValue_) {
1478 edge.properties().setDepends();
1479 edge.properties().setInfluences();
1480 typename G::EdgeProperties& other = graph.getEdgeProperties(edge.target(), edge.source());
1481 other.setInfluences();
1482 other.setDepends();
1483 }
1484 }
1485
1486 template<class M, class N>
1487 inline bool SymmetricDependency<M,N>::isIsolated()
1488 {
1489 return maxValue_ < beta();
1490 }
1491
1492
1493 template<class M, class N>
1494 inline void Dependency<M,N>::init(const Matrix* matrix)
1495 {
1496 matrix_ = matrix;
1497 }
1498
1499 template<class M, class N>
1500 inline void Dependency<M,N>::initRow([[maybe_unused]] const Row& row, int index)
1501 {
1502 using std::min;
1504 row_ = index;
1505 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1506 }
1507
1508 template<class M, class N>
1509 inline void Dependency<M,N>::examine(const ColIter& col)
1510 {
1511 using std::max;
1512 maxValue_ = max(maxValue_, -norm_(*col));
1513 }
1514
1515 template<class M, class N>
1516 template<class G>
1517 inline void Dependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1518 {
1519 if(-norm_(*col) >= maxValue_ * alpha()) {
1520 edge.properties().setDepends();
1521 typedef typename G::EdgeDescriptor ED;
1522 ED e= graph.findEdge(edge.target(), edge.source());
1524 {
1525 typename G::EdgeProperties& other = graph.getEdgeProperties(e);
1526 other.setInfluences();
1527 }
1528 }
1529 }
1530
1531 template<class M, class N>
1532 inline bool Dependency<M,N>::isIsolated()
1533 {
1534 return maxValue_ < beta() * diagonal_;
1535 }
1536
1537 template<class G,class S>
1538 Aggregate<G,S>::Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
1539 VertexSet& connected, std::vector<Vertex>& front)
1540 : vertices_(), id_(-1), graph_(graph), aggregates_(aggregates),
1541 connected_(connected), front_(front)
1542 {}
1543
1544 template<class G,class S>
1545 void Aggregate<G,S>::reconstruct(const Vertex& /*vertex*/)
1546 {
1547 /*
1548 vertices_.push_back(vertex);
1549 typedef typename VertexList::const_iterator iterator;
1550 iterator begin = vertices_.begin();
1551 iterator end = vertices_.end();*/
1552 throw "Not yet implemented";
1553
1554 // while(begin!=end){
1555 //for();
1556 // }
1557
1558 }
1559
1560 template<class G,class S>
1561 inline void Aggregate<G,S>::seed(const Vertex& vertex)
1562 {
1563 dvverb<<"Connected cleared"<<std::endl;
1564 connected_.clear();
1565 vertices_.clear();
1566 connected_.insert(vertex);
1567 dvverb << " Inserting "<<vertex<<" size="<<connected_.size();
1568 ++id_ ;
1569 add(vertex);
1570 }
1571
1572
1573 template<class G,class S>
1574 inline void Aggregate<G,S>::add(const Vertex& vertex)
1575 {
1576 vertices_.insert(vertex);
1577 aggregates_[vertex]=id_;
1578 if(front_.size())
1579 front_.erase(std::lower_bound(front_.begin(), front_.end(), vertex));
1580
1581
1582 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1583 const iterator end = graph_.endEdges(vertex);
1584 for(iterator edge = graph_.beginEdges(vertex); edge != end; ++edge) {
1585 dvverb << " Inserting "<<aggregates_[edge.target()];
1586 connected_.insert(aggregates_[edge.target()]);
1587 dvverb <<" size="<<connected_.size();
1588 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1589 !graph_.getVertexProperties(edge.target()).front())
1590 {
1591 front_.push_back(edge.target());
1592 graph_.getVertexProperties(edge.target()).setFront();
1593 }
1594 }
1595 dvverb <<std::endl;
1596 std::sort(front_.begin(), front_.end());
1597 }
1598
1599 template<class G,class S>
1600 inline void Aggregate<G,S>::add(std::vector<Vertex>& vertices)
1601 {
1602#ifndef NDEBUG
1603 std::size_t oldsize = vertices_.size();
1604#endif
1605 typedef typename std::vector<Vertex>::iterator Iterator;
1606
1607 typedef typename VertexSet::iterator SIterator;
1608
1609 SIterator pos=vertices_.begin();
1610 std::vector<Vertex> newFront;
1611 newFront.reserve(front_.capacity());
1612
1613 std::set_difference(front_.begin(), front_.end(), vertices.begin(), vertices.end(),
1614 std::back_inserter(newFront));
1615 front_=newFront;
1616
1617 for(Iterator vertex=vertices.begin(); vertex != vertices.end(); ++vertex)
1618 {
1619 pos=vertices_.insert(pos,*vertex);
1620 vertices_.insert(*vertex);
1621 graph_.getVertexProperties(*vertex).resetFront(); // Not a front node any more.
1622 aggregates_[*vertex]=id_;
1623
1624 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1625 const iterator end = graph_.endEdges(*vertex);
1626 for(iterator edge = graph_.beginEdges(*vertex); edge != end; ++edge) {
1627 dvverb << " Inserting "<<aggregates_[edge.target()];
1628 connected_.insert(aggregates_[edge.target()]);
1629 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1630 !graph_.getVertexProperties(edge.target()).front())
1631 {
1632 front_.push_back(edge.target());
1633 graph_.getVertexProperties(edge.target()).setFront();
1634 }
1635 dvverb <<" size="<<connected_.size();
1636 }
1637 dvverb <<std::endl;
1638 }
1639 std::sort(front_.begin(), front_.end());
1640 assert(oldsize+vertices.size()==vertices_.size());
1641 }
1642 template<class G,class S>
1643 inline void Aggregate<G,S>::clear()
1644 {
1645 vertices_.clear();
1646 connected_.clear();
1647 id_=-1;
1648 }
1649
1650 template<class G,class S>
1651 inline typename Aggregate<G,S>::size_type
1653 {
1654 return vertices_.size();
1655 }
1656
1657 template<class G,class S>
1658 inline typename Aggregate<G,S>::size_type
1660 {
1661 return connected_.size();
1662 }
1663
1664 template<class G,class S>
1665 inline int Aggregate<G,S>::id()
1666 {
1667 return id_;
1668 }
1669
1670 template<class G,class S>
1672 {
1673 return vertices_.begin();
1674 }
1675
1676 template<class G,class S>
1678 {
1679 return vertices_.end();
1680 }
1681
1682 template<class V>
1684
1685 template<class V>
1687
1688 template<class V>
1690 : aggregates_(0)
1691 {}
1692
1693 template<class V>
1695 {
1696 if(aggregates_!=0)
1697 delete[] aggregates_;
1698 }
1699
1700
1701 template<class V>
1702 inline AggregatesMap<V>::AggregatesMap(std::size_t noVertices)
1703 {
1704 allocate(noVertices);
1705 }
1706
1707 template<class V>
1708 inline std::size_t AggregatesMap<V>::noVertices() const
1709 {
1710 return noVertices_;
1711 }
1712
1713 template<class V>
1714 inline void AggregatesMap<V>::allocate(std::size_t noVertices)
1715 {
1716 aggregates_ = new AggregateDescriptor[noVertices];
1717 noVertices_ = noVertices;
1718
1719 for(std::size_t i=0; i < noVertices; i++)
1720 aggregates_[i]=UNAGGREGATED;
1721 }
1722
1723 template<class V>
1724 inline void AggregatesMap<V>::free()
1725 {
1726 assert(aggregates_ != 0);
1727 delete[] aggregates_;
1728 aggregates_=0;
1729 }
1730
1731 template<class V>
1733 AggregatesMap<V>::operator[](const VertexDescriptor& v)
1734 {
1735 return aggregates_[v];
1736 }
1737
1738 template<class V>
1739 inline const typename AggregatesMap<V>::AggregateDescriptor&
1740 AggregatesMap<V>::operator[](const VertexDescriptor& v) const
1741 {
1742 return aggregates_[v];
1743 }
1744
1745 template<class V>
1746 template<bool reset, class G, class F,class VM>
1747 inline std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1748 const AggregateDescriptor& aggregate,
1749 const G& graph, F& aggregateVisitor,
1750 VM& visitedMap) const
1751 {
1752 VertexList vlist;
1753
1754 DummyEdgeVisitor dummy;
1755 return breadthFirstSearch<true,reset>(start, aggregate, graph, vlist, aggregateVisitor, dummy, visitedMap);
1756 }
1757
1758 template<class V>
1759 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
1760 std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1761 const AggregateDescriptor& aggregate,
1762 const G& graph,
1763 L& visited,
1764 F1& aggregateVisitor,
1765 F2& nonAggregateVisitor,
1766 VM& visitedMap) const
1767 {
1768 typedef typename L::const_iterator ListIterator;
1769 int visitedSpheres = 0;
1770
1771 visited.push_back(start);
1772 put(visitedMap, start, true);
1773
1774 ListIterator current = visited.begin();
1775 ListIterator end = visited.end();
1776 std::size_t i=0, size=visited.size();
1777
1778 // visit the neighbours of all vertices of the
1779 // current sphere.
1780 while(current != end) {
1781
1782 for(; i<size; ++current, ++i) {
1783 typedef typename G::ConstEdgeIterator EdgeIterator;
1784 const EdgeIterator endEdge = graph.endEdges(*current);
1785
1786 for(EdgeIterator edge = graph.beginEdges(*current);
1787 edge != endEdge; ++edge) {
1788
1789 if(aggregates_[edge.target()]==aggregate) {
1790 if(!get(visitedMap, edge.target())) {
1791 put(visitedMap, edge.target(), true);
1792 visited.push_back(edge.target());
1793 aggregateVisitor(edge);
1794 }
1795 }else
1796 nonAggregateVisitor(edge);
1797 }
1798 }
1799 end = visited.end();
1800 size = visited.size();
1801 if(current != end)
1802 visitedSpheres++;
1803 }
1804
1805 if(reset)
1806 for(current = visited.begin(); current != end; ++current)
1807 put(visitedMap, *current, false);
1808
1809
1810 if(remove)
1811 visited.clear();
1812
1813 return visitedSpheres;
1814 }
1815
1816 template<class G>
1818 : graph_(0), aggregate_(0), front_(), connected_(), size_(-1)
1819 {}
1820
1821 template<class G>
1823 {
1824 size_=-1;
1825 }
1826
1827 template<class G, class C>
1828 void buildDependency(G& graph,
1829 const typename C::Matrix& matrix,
1830 C criterion, bool firstlevel)
1831 {
1832 // assert(graph.isBuilt());
1833 typedef typename C::Matrix Matrix;
1834 typedef typename G::VertexIterator VertexIterator;
1835
1836 criterion.init(&matrix);
1837
1838 for(VertexIterator vertex = graph.begin(); vertex != graph.end(); ++vertex) {
1839 typedef typename Matrix::row_type Row;
1840
1841 const Row& row = matrix[*vertex];
1842
1843 // Tell the criterion what row we will examine now
1844 // This might for example be used for calculating the
1845 // maximum offdiagonal value
1846 criterion.initRow(row, *vertex);
1847
1848 // On a first path all columns are examined. After this
1849 // the calculator should know whether the vertex is isolated.
1850 typedef typename Matrix::ConstColIterator ColIterator;
1851 ColIterator end = row.end();
1852 typename FieldTraits<typename Matrix::field_type>::real_type absoffdiag=0.;
1853
1854 using std::max;
1855 if(firstlevel) {
1856 for(ColIterator col = row.begin(); col != end; ++col)
1857 if(col.index()!=*vertex) {
1858 criterion.examine(col);
1859 absoffdiag = max(absoffdiag, Impl::asMatrix(*col).frobenius_norm());
1860 }
1861
1862 if(absoffdiag==0)
1863 vertex.properties().setExcludedBorder();
1864 }
1865 else
1866 for(ColIterator col = row.begin(); col != end; ++col)
1867 if(col.index()!=*vertex)
1868 criterion.examine(col);
1869
1870 // reset the vertex properties
1871 //vertex.properties().reset();
1872
1873 // Check whether the vertex is isolated.
1874 if(criterion.isIsolated()) {
1875 //std::cout<<"ISOLATED: "<<*vertex<<std::endl;
1876 vertex.properties().setIsolated();
1877 }else{
1878 // Examine all the edges beginning at this vertex.
1879 auto eEnd = vertex.end();
1880 auto col = matrix[*vertex].begin();
1881
1882 for(auto edge = vertex.begin(); edge!= eEnd; ++edge, ++col) {
1883 // Move to the right column.
1884 while(col.index()!=edge.target())
1885 ++col;
1886 criterion.examine(graph, edge, col);
1887 }
1888 }
1889
1890 }
1891 }
1892
1893
1894 template<class G>
1895 template<class V>
1896 inline Aggregator<G>::AggregateVisitor<V>::AggregateVisitor(const AggregatesMap<Vertex>& aggregates,
1897 const AggregateDescriptor& aggregate, V& visitor)
1898 : aggregates_(aggregates), aggregate_(aggregate), visitor_(&visitor)
1899 {}
1900
1901 template<class G>
1902 template<class V>
1903 inline void Aggregator<G>::AggregateVisitor<V>::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1904 {
1905 if(aggregates_[edge.target()]==aggregate_)
1906 visitor_->operator()(edge);
1907 }
1908
1909 template<class G>
1910 template<class V>
1911 inline void Aggregator<G>::visitAggregateNeighbours(const Vertex& vertex,
1912 const AggregateDescriptor& aggregate,
1913 const AggregatesMap<Vertex>& aggregates,
1914 V& visitor) const
1915 {
1916 // Only evaluates for edge pointing to the aggregate
1917 AggregateVisitor<V> v(aggregates, aggregate, visitor);
1918 visitNeighbours(*graph_, vertex, v);
1919 }
1920
1921
1922 template<class G>
1923 inline Aggregator<G>::Counter::Counter()
1924 : count_(0)
1925 {}
1926
1927 template<class G>
1928 inline void Aggregator<G>::Counter::increment()
1929 {
1930 ++count_;
1931 }
1932
1933 template<class G>
1934 inline void Aggregator<G>::Counter::decrement()
1935 {
1936 --count_;
1937 }
1938 template<class G>
1939 inline int Aggregator<G>::Counter::value()
1940 {
1941 return count_;
1942 }
1943
1944 template<class G>
1945 inline void Aggregator<G>::TwoWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1946 {
1947 if(edge.properties().isTwoWay())
1948 Counter::increment();
1949 }
1950
1951 template<class G>
1952 int Aggregator<G>::twoWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1953 const AggregatesMap<Vertex>& aggregates) const
1954 {
1955 TwoWayCounter counter;
1956 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1957 return counter.value();
1958 }
1959
1960 template<class G>
1961 int Aggregator<G>::oneWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1962 const AggregatesMap<Vertex>& aggregates) const
1963 {
1964 OneWayCounter counter;
1965 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1966 return counter.value();
1967 }
1968
1969 template<class G>
1970 inline void Aggregator<G>::OneWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1971 {
1972 if(edge.properties().isOneWay())
1973 Counter::increment();
1974 }
1975
1976 template<class G>
1977 inline Aggregator<G>::ConnectivityCounter::ConnectivityCounter(const VertexSet& connected,
1978 const AggregatesMap<Vertex>& aggregates)
1979 : Counter(), connected_(connected), aggregates_(aggregates)
1980 {}
1981
1982
1983 template<class G>
1984 inline void Aggregator<G>::ConnectivityCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1985 {
1986 if(connected_.find(aggregates_[edge.target()]) == connected_.end() || aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED)
1987 // Would be a new connection
1988 Counter::increment();
1989 else{
1990 Counter::increment();
1991 Counter::increment();
1992 }
1993 }
1994
1995 template<class G>
1996 inline double Aggregator<G>::connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
1997 {
1998 ConnectivityCounter counter(connected_, aggregates);
1999 double noNeighbours=visitNeighbours(*graph_, vertex, counter);
2000 return (double)counter.value()/noNeighbours;
2001 }
2002
2003 template<class G>
2004 inline Aggregator<G>::DependencyCounter::DependencyCounter()
2005 : Counter()
2006 {}
2007
2008 template<class G>
2009 inline void Aggregator<G>::DependencyCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2010 {
2011 if(edge.properties().depends())
2012 Counter::increment();
2013 if(edge.properties().influences())
2014 Counter::increment();
2015 }
2016
2017 template<class G>
2018 int Aggregator<G>::unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2019 {
2020 return aggregateNeighbours(vertex, AggregatesMap<Vertex>::UNAGGREGATED, aggregates);
2021 }
2022
2023 template<class G>
2024 std::pair<int,int> Aggregator<G>::neighbours(const Vertex& vertex,
2025 const AggregateDescriptor& aggregate,
2026 const AggregatesMap<Vertex>& aggregates) const
2027 {
2028 DependencyCounter unused, aggregated;
2029 typedef AggregateVisitor<DependencyCounter> CounterT;
2030 typedef std::tuple<CounterT,CounterT> CounterTuple;
2031 CombinedFunctor<CounterTuple> visitors(CounterTuple(CounterT(aggregates, AggregatesMap<Vertex>::UNAGGREGATED, unused), CounterT(aggregates, aggregate, aggregated)));
2032 visitNeighbours(*graph_, vertex, visitors);
2033 return std::make_pair(unused.value(), aggregated.value());
2034 }
2035
2036
2037 template<class G>
2038 int Aggregator<G>::aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2039 {
2040 DependencyCounter counter;
2041 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
2042 return counter.value();
2043 }
2044
2045 template<class G>
2046 std::size_t Aggregator<G>::distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates)
2047 {
2048 return 0;
2049 typename PropertyMapTypeSelector<VertexVisitedTag,G>::Type visitedMap = get(VertexVisitedTag(), *graph_);
2050 VertexList vlist;
2051 typename AggregatesMap<Vertex>::DummyEdgeVisitor dummy;
2052 return aggregates.template breadthFirstSearch<true,true>(vertex,
2053 aggregate_->id(), *graph_,
2054 vlist, dummy, dummy, visitedMap);
2055 }
2056
2057 template<class G>
2058 inline Aggregator<G>::FrontMarker::FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph)
2059 : front_(front), graph_(graph)
2060 {}
2061
2062 template<class G>
2063 inline void Aggregator<G>::FrontMarker::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2064 {
2065 Vertex target = edge.target();
2066
2067 if(!graph_.getVertexProperties(target).front()) {
2068 front_.push_back(target);
2069 graph_.getVertexProperties(target).setFront();
2070 }
2071 }
2072
2073 template<class G>
2074 inline bool Aggregator<G>::admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2075 {
2076 // Todo
2077 Dune::dvverb<<" Admissible not yet implemented!"<<std::endl;
2078 return true;
2079 //Situation 1: front node depends on two nodes. Then these
2080 // have to be strongly connected to each other
2081
2082 // Iterate over all all neighbours of front node
2083 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2084 Iterator vend = graph_->endEdges(vertex);
2085 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2086 // if(edge.properties().depends() && !edge.properties().influences()
2087 if(edge.properties().isStrong()
2088 && aggregates[edge.target()]==aggregate)
2089 {
2090 // Search for another link to the aggregate
2091 Iterator edge1 = edge;
2092 for(++edge1; edge1 != vend; ++edge1) {
2093 //if(edge1.properties().depends() && !edge1.properties().influences()
2094 if(edge1.properties().isStrong()
2095 && aggregates[edge.target()]==aggregate)
2096 {
2097 //Search for an edge connecting the two vertices that is
2098 //strong
2099 bool found=false;
2100 Iterator v2end = graph_->endEdges(edge.target());
2101 for(Iterator edge2 = graph_->beginEdges(edge.target()); edge2 != v2end; ++edge2) {
2102 if(edge2.target()==edge1.target() &&
2103 edge2.properties().isStrong()) {
2104 found =true;
2105 break;
2106 }
2107 }
2108 if(found)
2109 {
2110 return true;
2111 }
2112 }
2113 }
2114 }
2115 }
2116
2117 // Situation 2: cluster node depends on front node and other cluster node
2119 vend = graph_->endEdges(vertex);
2120 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2121 //if(!edge.properties().depends() && edge.properties().influences()
2122 if(edge.properties().isStrong()
2123 && aggregates[edge.target()]==aggregate)
2124 {
2125 // Search for a link from target that stays within the aggregate
2126 Iterator v1end = graph_->endEdges(edge.target());
2127
2128 for(Iterator edge1=graph_->beginEdges(edge.target()); edge1 != v1end; ++edge1) {
2129 //if(edge1.properties().depends() && !edge1.properties().influences()
2130 if(edge1.properties().isStrong()
2131 && aggregates[edge1.target()]==aggregate)
2132 {
2133 bool found=false;
2134 // Check if front node is also connected to this one
2135 Iterator v2end = graph_->endEdges(vertex);
2136 for(Iterator edge2 = graph_->beginEdges(vertex); edge2 != v2end; ++edge2) {
2137 if(edge2.target()==edge1.target()) {
2138 if(edge2.properties().isStrong())
2139 found=true;
2140 break;
2141 }
2142 }
2143 if(found)
2144 {
2145 return true;
2146 }
2147 }
2148 }
2149 }
2150 }
2151 return false;
2152 }
2153
2154 template<class G>
2155 void Aggregator<G>::unmarkFront()
2156 {
2157 typedef typename std::vector<Vertex>::const_iterator Iterator;
2158
2159 for(Iterator vertex=front_.begin(); vertex != front_.end(); ++vertex)
2160 graph_->getVertexProperties(*vertex).resetFront();
2161
2162 front_.clear();
2163 }
2164
2165 template<class G>
2166 inline void
2167 Aggregator<G>::nonisoNeighbourAggregate(const Vertex& vertex,
2168 const AggregatesMap<Vertex>& aggregates,
2169 SLList<Vertex>& neighbours) const
2170 {
2171 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2172 Iterator end=graph_->beginEdges(vertex);
2173 neighbours.clear();
2174
2175 for(Iterator edge=graph_->beginEdges(vertex); edge!=end; ++edge)
2176 {
2177 if(aggregates[edge.target()]!=AggregatesMap<Vertex>::UNAGGREGATED && graph_->getVertexProperties(edge.target()).isolated())
2178 neighbours.push_back(aggregates[edge.target()]);
2179 }
2180 }
2181
2182 template<class G>
2183 inline typename G::VertexDescriptor Aggregator<G>::mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2184 {
2185 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2186
2187 Iterator end = graph_->endEdges(vertex);
2188 for(Iterator edge = graph_->beginEdges(vertex); edge != end; ++edge) {
2189 if(aggregates[edge.target()] != AggregatesMap<Vertex>::UNAGGREGATED &&
2190 graph_->getVertexProperties(edge.target()).isolated() == graph_->getVertexProperties(edge.source()).isolated()) {
2191 if( graph_->getVertexProperties(vertex).isolated() ||
2192 ((edge.properties().depends() || edge.properties().influences())
2193 && admissible(vertex, aggregates[edge.target()], aggregates)))
2194 return edge.target();
2195 }
2196 }
2198 }
2199
2200 template<class G>
2201 Aggregator<G>::FrontNeighbourCounter::FrontNeighbourCounter(const MatrixGraph& graph)
2202 : Counter(), graph_(graph)
2203 {}
2204
2205 template<class G>
2206 void Aggregator<G>::FrontNeighbourCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2207 {
2208 if(graph_.getVertexProperties(edge.target()).front())
2209 Counter::increment();
2210 }
2211
2212 template<class G>
2213 int Aggregator<G>::noFrontNeighbours(const Vertex& vertex) const
2214 {
2215 FrontNeighbourCounter counter(*graph_);
2216 visitNeighbours(*graph_, vertex, counter);
2217 return counter.value();
2218 }
2219 template<class G>
2220 inline bool Aggregator<G>::connected(const Vertex& vertex,
2221 const AggregateDescriptor& aggregate,
2222 const AggregatesMap<Vertex>& aggregates) const
2223 {
2224 typedef typename G::ConstEdgeIterator iterator;
2225 const iterator end = graph_->endEdges(vertex);
2226 for(iterator edge = graph_->beginEdges(vertex); edge != end; ++edge)
2227 if(aggregates[edge.target()]==aggregate)
2228 return true;
2229 return false;
2230 }
2231 template<class G>
2232 inline bool Aggregator<G>::connected(const Vertex& vertex,
2233 const SLList<AggregateDescriptor>& aggregateList,
2234 const AggregatesMap<Vertex>& aggregates) const
2235 {
2236 typedef typename SLList<AggregateDescriptor>::const_iterator Iter;
2237 for(Iter i=aggregateList.begin(); i!=aggregateList.end(); ++i)
2238 if(connected(vertex, *i, aggregates))
2239 return true;
2240 return false;
2241 }
2242
2243 template<class G>
2244 template<class C>
2245 void Aggregator<G>::growIsolatedAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2246 {
2247 SLList<Vertex> connectedAggregates;
2248 nonisoNeighbourAggregate(seed, aggregates,connectedAggregates);
2249
2250 while(aggregate_->size()< c.minAggregateSize() && aggregate_->connectSize() < c.maxConnectivity()) {
2251 double maxCon=-1;
2252 std::size_t maxFrontNeighbours=0;
2253
2255
2256 typedef typename std::vector<Vertex>::const_iterator Iterator;
2257
2258 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2259 if(distance(*vertex, aggregates)>c.maxDistance())
2260 continue; // distance of proposes aggregate too big
2261
2262 if(connectedAggregates.size()>0) {
2263 // there is already a neighbour cluster
2264 // front node must be connected to same neighbour cluster
2265
2266 if(!connected(*vertex, connectedAggregates, aggregates))
2267 continue;
2268 }
2269
2270 double con = connectivity(*vertex, aggregates);
2271
2272 if(con == maxCon) {
2273 std::size_t frontNeighbours = noFrontNeighbours(*vertex);
2274
2275 if(frontNeighbours >= maxFrontNeighbours) {
2276 maxFrontNeighbours = frontNeighbours;
2277 candidate = *vertex;
2278 }
2279 }else if(con > maxCon) {
2280 maxCon = con;
2281 maxFrontNeighbours = noFrontNeighbours(*vertex);
2282 candidate = *vertex;
2283 }
2284 }
2285
2287 break;
2288
2289 aggregate_->add(candidate);
2290 }
2291 }
2292
2293 template<class G>
2294 template<class C>
2295 void Aggregator<G>::growAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2296 {
2297 using std::min;
2298
2299 std::size_t distance_ =0;
2300 while(aggregate_->size() < c.minAggregateSize()&& distance_<c.maxDistance()) {
2301 int maxTwoCons=0, maxOneCons=0, maxNeighbours=-1;
2302 double maxCon=-1;
2303
2304 std::vector<Vertex> candidates;
2305 candidates.reserve(30);
2306
2307 typedef typename std::vector<Vertex>::const_iterator Iterator;
2308
2309 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2310 // Only nonisolated nodes are considered
2311 if(graph_->getVertexProperties(*vertex).isolated())
2312 continue;
2313
2314 int twoWayCons = twoWayConnections(*vertex, aggregate_->id(), aggregates);
2315
2316 /* The case of two way connections. */
2317 if( maxTwoCons == twoWayCons && twoWayCons > 0) {
2318 double con = connectivity(*vertex, aggregates);
2319
2320 if(con == maxCon) {
2321 int neighbours = noFrontNeighbours(*vertex);
2322
2323 if(neighbours > maxNeighbours) {
2324 maxNeighbours = neighbours;
2325 candidates.clear();
2326 candidates.push_back(*vertex);
2327 }else{
2328 candidates.push_back(*vertex);
2329 }
2330 }else if( con > maxCon) {
2331 maxCon = con;
2332 maxNeighbours = noFrontNeighbours(*vertex);
2333 candidates.clear();
2334 candidates.push_back(*vertex);
2335 }
2336 }else if(twoWayCons > maxTwoCons) {
2337 maxTwoCons = twoWayCons;
2338 maxCon = connectivity(*vertex, aggregates);
2339 maxNeighbours = noFrontNeighbours(*vertex);
2340 candidates.clear();
2341 candidates.push_back(*vertex);
2342
2343 // two way connections precede
2344 maxOneCons = std::numeric_limits<int>::max();
2345 }
2346
2347 if(twoWayCons > 0)
2348 {
2349 continue; // THis is a two-way node, skip tests for one way nodes
2350 }
2351
2352 /* The one way case */
2353 int oneWayCons = oneWayConnections(*vertex, aggregate_->id(), aggregates);
2354
2355 if(oneWayCons==0)
2356 continue; // No strong connections, skip the tests.
2357
2358 if(!admissible(*vertex, aggregate_->id(), aggregates))
2359 continue;
2360
2361 if( maxOneCons == oneWayCons && oneWayCons > 0) {
2362 double con = connectivity(*vertex, aggregates);
2363
2364 if(con == maxCon) {
2365 int neighbours = noFrontNeighbours(*vertex);
2366
2367 if(neighbours > maxNeighbours) {
2368 maxNeighbours = neighbours;
2369 candidates.clear();
2370 candidates.push_back(*vertex);
2371 }else{
2372 if(neighbours==maxNeighbours)
2373 {
2374 candidates.push_back(*vertex);
2375 }
2376 }
2377 }else if( con > maxCon) {
2378 maxCon = con;
2379 maxNeighbours = noFrontNeighbours(*vertex);
2380 candidates.clear();
2381 candidates.push_back(*vertex);
2382 }
2383 }else if(oneWayCons > maxOneCons) {
2384 maxOneCons = oneWayCons;
2385 maxCon = connectivity(*vertex, aggregates);
2386 maxNeighbours = noFrontNeighbours(*vertex);
2387 candidates.clear();
2388 candidates.push_back(*vertex);
2389 }
2390 }
2391
2392
2393 if(!candidates.size())
2394 break; // No more candidates found
2395 distance_=distance(seed, aggregates);
2396 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2397 aggregate_->size()));
2398 aggregate_->add(candidates);
2399 }
2400 }
2401
2402 template<typename V>
2403 template<typename M, typename G, typename C>
2404 std::tuple<int,int,int,int> AggregatesMap<V>::buildAggregates(const M& matrix, G& graph, const C& criterion,
2405 bool finestLevel)
2406 {
2407 Aggregator<G> aggregator;
2408 return aggregator.build(matrix, graph, *this, criterion, finestLevel);
2409 }
2410
2411 template<class G>
2412 template<class M, class C>
2413 std::tuple<int,int,int,int> Aggregator<G>::build(const M& m, G& graph, AggregatesMap<Vertex>& aggregates, const C& c,
2414 bool finestLevel)
2415 {
2416 using std::max;
2417 using std::min;
2418 // Stack for fast vertex access
2419 Stack stack_(graph, *this, aggregates);
2420
2421 graph_ = &graph;
2422
2423 aggregate_ = new Aggregate<G,VertexSet>(graph, aggregates, connected_, front_);
2424
2425 Timer watch;
2426 watch.reset();
2427
2428 buildDependency(graph, m, c, finestLevel);
2429
2430 dverb<<"Build dependency took "<< watch.elapsed()<<" seconds."<<std::endl;
2431 int noAggregates, conAggregates, isoAggregates, oneAggregates;
2432 std::size_t maxA=0, minA=1000000, avg=0;
2433 int skippedAggregates;
2434 noAggregates = conAggregates = isoAggregates = oneAggregates =
2435 skippedAggregates = 0;
2436
2437 while(true) {
2438 Vertex seed = stack_.pop();
2439
2440 if(seed == Stack::NullEntry)
2441 // No more unaggregated vertices. We are finished!
2442 break;
2443
2444 // Debugging output
2445 if((noAggregates+1)%10000 == 0)
2446 Dune::dverb<<"c";
2447 unmarkFront();
2448
2449 if(graph.getVertexProperties(seed).excludedBorder()) {
2450 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2451 ++skippedAggregates;
2452 continue;
2453 }
2454
2455 if(graph.getVertexProperties(seed).isolated()) {
2456 if(c.skipIsolated()) {
2457 // isolated vertices are not aggregated but skipped on the coarser levels.
2458 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2459 ++skippedAggregates;
2460 // skip rest as no agglomeration is done.
2461 continue;
2462 }else{
2463 aggregate_->seed(seed);
2464 growIsolatedAggregate(seed, aggregates, c);
2465 }
2466 }else{
2467 aggregate_->seed(seed);
2468 growAggregate(seed, aggregates, c);
2469 }
2470
2471 /* The rounding step. */
2472 while(!(graph.getVertexProperties(seed).isolated()) && aggregate_->size() < c.maxAggregateSize()) {
2473
2474 std::vector<Vertex> candidates;
2475 candidates.reserve(30);
2476
2477 typedef typename std::vector<Vertex>::const_iterator Iterator;
2478
2479 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2480
2481 if(graph.getVertexProperties(*vertex).isolated())
2482 continue; // No isolated nodes here
2483
2484 if(twoWayConnections( *vertex, aggregate_->id(), aggregates) == 0 &&
2485 (oneWayConnections( *vertex, aggregate_->id(), aggregates) == 0 ||
2486 !admissible( *vertex, aggregate_->id(), aggregates) ))
2487 continue;
2488
2489 std::pair<int,int> neighbourPair=neighbours(*vertex, aggregate_->id(),
2490 aggregates);
2491
2492 //if(aggregateNeighbours(*vertex, aggregate_->id(), aggregates) <= unusedNeighbours(*vertex, aggregates))
2493 // continue;
2494
2495 if(neighbourPair.first >= neighbourPair.second)
2496 continue;
2497
2498 if(distance(*vertex, aggregates) > c.maxDistance())
2499 continue; // Distance too far
2500 candidates.push_back(*vertex);
2501 break;
2502 }
2503
2504 if(!candidates.size()) break; // no more candidates found.
2505
2506 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2507 aggregate_->size()));
2508 aggregate_->add(candidates);
2509
2510 }
2511
2512 // try to merge aggregates consisting of only one nonisolated vertex with other aggregates
2513 if(aggregate_->size()==1 && c.maxAggregateSize()>1) {
2514 if(!graph.getVertexProperties(seed).isolated()) {
2515 Vertex mergedNeighbour = mergeNeighbour(seed, aggregates);
2516
2517 if(mergedNeighbour != AggregatesMap<Vertex>::UNAGGREGATED) {
2518 // assign vertex to the neighbouring cluster
2519 aggregates[seed] = aggregates[mergedNeighbour];
2520 aggregate_->invalidate();
2521 }else{
2522 ++avg;
2523 minA=min(minA,static_cast<std::size_t>(1));
2524 maxA=max(maxA,static_cast<std::size_t>(1));
2525 ++oneAggregates;
2526 ++conAggregates;
2527 }
2528 }else{
2529 ++avg;
2530 minA=min(minA,static_cast<std::size_t>(1));
2531 maxA=max(maxA,static_cast<std::size_t>(1));
2532 ++oneAggregates;
2533 ++isoAggregates;
2534 }
2535 ++avg;
2536 }else{
2537 avg+=aggregate_->size();
2538 minA=min(minA,aggregate_->size());
2539 maxA=max(maxA,aggregate_->size());
2540 if(graph.getVertexProperties(seed).isolated())
2541 ++isoAggregates;
2542 else
2543 ++conAggregates;
2544 }
2545
2546 }
2547
2548 Dune::dinfo<<"connected aggregates: "<<conAggregates;
2549 Dune::dinfo<<" isolated aggregates: "<<isoAggregates;
2550 if(conAggregates+isoAggregates>0)
2551 Dune::dinfo<<" one node aggregates: "<<oneAggregates<<" min size="
2552 <<minA<<" max size="<<maxA
2553 <<" avg="<<avg/(conAggregates+isoAggregates)<<std::endl;
2554
2555 delete aggregate_;
2556 return std::make_tuple(conAggregates+isoAggregates,isoAggregates,
2557 oneAggregates,skippedAggregates);
2558 }
2559
2560
2561 template<class G>
2562 Aggregator<G>::Stack::Stack(const MatrixGraph& graph, const Aggregator<G>& aggregatesBuilder,
2563 const AggregatesMap<Vertex>& aggregates)
2564 : graph_(graph), aggregatesBuilder_(aggregatesBuilder), aggregates_(aggregates), begin_(graph.begin()), end_(graph.end())
2565 {
2566 //vals_ = new Vertex[N];
2567 }
2568
2569 template<class G>
2570 Aggregator<G>::Stack::~Stack()
2571 {
2572 //Dune::dverb << "Max stack size was "<<maxSize_<<" filled="<<filled_<<std::endl;
2573 //delete[] vals_;
2574 }
2575
2576 template<class G>
2577 const typename Aggregator<G>::Vertex Aggregator<G>::Stack::NullEntry
2579
2580 template<class G>
2581 inline typename G::VertexDescriptor Aggregator<G>::Stack::pop()
2582 {
2583 for(; begin_!=end_ && aggregates_[*begin_] != AggregatesMap<Vertex>::UNAGGREGATED; ++begin_) ;
2584
2585 if(begin_!=end_)
2586 {
2587 typename G::VertexDescriptor current=*begin_;
2588 ++begin_;
2589 return current;
2590 }else
2591 return NullEntry;
2592 }
2593
2594#endif // DOXYGEN
2595
2596 template<class V>
2597 void printAggregates2d(const AggregatesMap<V>& aggregates, int n, int m, std::ostream& os)
2598 {
2599 using std::max;
2600
2601 std::ios_base::fmtflags oldOpts=os.flags();
2602
2603 os.setf(std::ios_base::right, std::ios_base::adjustfield);
2604
2605 V maxVal=0;
2606 int width=1;
2607
2608 for(int i=0; i< n*m; i++)
2609 maxVal=max(maxVal, aggregates[i]);
2610
2611 for(int i=10; i < 1000000; i*=10)
2612 if(maxVal/i>0)
2613 width++;
2614 else
2615 break;
2616
2617 for(int j=0, entry=0; j < m; j++) {
2618 for(int i=0; i<n; i++, entry++) {
2619 os.width(width);
2620 os<<aggregates[entry]<<" ";
2621 }
2622
2623 os<<std::endl;
2624 }
2625 os<<std::endl;
2626 os.flags(oldOpts);
2627 }
2628
2629
2630 } // namespace Amg
2631
2632} // namespace Dune
2633
2634
2635#endif
A class for temporarily storing the vertices of an aggregate in.
Definition: aggregates.hh:788
A Dummy visitor that does nothing for each visited edge.
Definition: aggregates.hh:608
Class providing information about the mapping of the vertices onto aggregates.
Definition: aggregates.hh:570
Base class of all aggregation criterions.
Definition: aggregates.hh:51
Class for building the aggregates.
Definition: aggregates.hh:924
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:529
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:549
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:596
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:935
AggregationCriterion()
Constructor.
Definition: aggregates.hh:68
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:359
FieldTraits< M >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:496
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:260
G MatrixGraph
The matrix graph type used.
Definition: aggregates.hh:930
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:365
FieldTraits< M >::real_type operator()(const M &) const
compute the norm of a matrix.
Definition: aggregates.hh:516
typename VertexSet::size_type size_type
Type of size used by allocator of sllist.
Definition: aggregates.hh:816
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
~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:1079
std::size_t * SphereMap
Type of the mapping of aggregate members onto distance spheres.
Definition: aggregates.hh:824
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:819
MatrixGraph::VertexDescriptor AggregateDescriptor
The type of the aggregate descriptor.
Definition: aggregates.hh:938
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
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:590
static const V ISOLATED
Identifier of isolated vertices.
Definition: aggregates.hh:581
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:602
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:811
static const V UNAGGREGATED
Identifier of not yet aggregated vertices.
Definition: aggregates.hh:576
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:799
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:585
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
FieldTraits< M >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:475
PoolAllocator< Vertex, 100 > Allocator
The allocator we use for our lists and the set.
Definition: aggregates.hh:805
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:217
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 (Mar 14, 23:39, 2026)