Dune Core Modules (2.7.0)

aggregates.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_AMG_AGGREGATES_HH
4#define DUNE_AMG_AGGREGATES_HH
5
6
7#include "parameters.hh"
8#include "graph.hh"
9#include "properties.hh"
10#include "combinedfunctor.hh"
11
12#include <dune/common/timer.hh>
15#include <dune/common/sllist.hh>
16#include <dune/common/unused.hh>
19
20#include <utility>
21#include <set>
22#include <algorithm>
23#include <complex>
24#include <limits>
25#include <ostream>
26#include <tuple>
27
28namespace Dune
29{
30 namespace Amg
31 {
32
46 template<class T>
47 class AggregationCriterion : public T
48 {
49
50 public:
55
66 : T()
67 {}
68
70 : T(parms)
71 {}
81 void setDefaultValuesIsotropic(std::size_t dim, std::size_t diameter=2)
82 {
83 this->setMaxDistance(diameter-1);
84 std::size_t csize=1;
85
86 for(; dim>0; dim--) {
87 csize*=diameter;
88 this->setMaxDistance(this->maxDistance()+diameter-1);
89 }
90 this->setMinAggregateSize(csize);
91 this->setMaxAggregateSize(static_cast<std::size_t>(csize*1.5));
92 }
93
104 void setDefaultValuesAnisotropic(std::size_t dim,std::size_t diameter=2)
105 {
106 setDefaultValuesIsotropic(dim, diameter);
107 this->setMaxDistance(this->maxDistance()+dim-1);
108 }
109 };
110
111 template<class T>
112 std::ostream& operator<<(std::ostream& os, const AggregationCriterion<T>& criterion)
113 {
114 os<<"{ maxdistance="<<criterion.maxDistance()<<" minAggregateSize="
115 <<criterion.minAggregateSize()<< " maxAggregateSize="<<criterion.maxAggregateSize()
116 <<" connectivity="<<criterion.maxConnectivity()<<" debugLevel="<<criterion.debugLevel()<<"}";
117 return os;
118 }
119
131 template<class M, class N>
133 {
134 public:
138 typedef M Matrix;
139
143 typedef N Norm;
144
148 typedef typename Matrix::row_type Row;
149
154
155 void init(const Matrix* matrix);
156
157 void initRow(const Row& row, int index);
158
159 void examine(const ColIter& col);
160
161 template<class G>
162 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
163
164 bool isIsolated();
165
166
168 : Parameters(parms)
169 {}
171 : Parameters()
172 {}
173
174 protected:
179 typedef typename FieldTraits<field_type>::real_type real_type;
180 real_type maxValue_;
184 int row_;
186 real_type diagonal_;
187 std::vector<real_type> vals_;
188 typename std::vector<real_type>::iterator valIter_;
189
190 };
191
192
193 template<class M, class N>
194 inline void SymmetricMatrixDependency<M,N>::init(const Matrix* matrix)
195 {
196 matrix_ = matrix;
197 }
198
199 template<class M, class N>
200 inline void SymmetricMatrixDependency<M,N>::initRow(const Row& row, int index)
201 {
202 using std::min;
203 vals_.assign(row.size(), 0.0);
204 assert(vals_.size()==row.size());
205 valIter_=vals_.begin();
206
208 diagonal_=norm_(row[index]);
209 row_ = index;
210 }
211
212 template<class M, class N>
213 inline void SymmetricMatrixDependency<M,N>::examine(const ColIter& col)
214 {
215 using std::max;
216 // skip positive offdiagonals if norm preserves sign of them.
217 real_type eij = norm_(*col);
218 if(!N::is_sign_preserving || eij<0) // || eji<0)
219 {
220 *valIter_ = eij/diagonal_*eij/norm_(matrix_->operator[](col.index())[col.index()]);
221 maxValue_ = max(maxValue_, *valIter_);
222 }else
223 *valIter_ =0;
224 ++valIter_;
225 }
226
227 template<class M, class N>
228 template<class G>
229 inline void SymmetricMatrixDependency<M,N>::examine(G&, const typename G::EdgeIterator& edge, const ColIter&)
230 {
231 if(*valIter_ > alpha() * maxValue_) {
232 edge.properties().setDepends();
233 edge.properties().setInfluences();
234 }
235 ++valIter_;
236 }
237
238 template<class M, class N>
239 inline bool SymmetricMatrixDependency<M,N>::isIsolated()
240 {
241 if(diagonal_==0)
242 DUNE_THROW(Dune::ISTLError, "No diagonal entry for row "<<row_<<".");
243 valIter_=vals_.begin();
244 return maxValue_ < beta();
245 }
246
250 template<class M, class N>
251 class Dependency : public Parameters
252 {
253 public:
257 typedef M Matrix;
258
262 typedef N Norm;
263
267 typedef typename Matrix::row_type Row;
268
273
274 void init(const Matrix* matrix);
275
276 void initRow(const Row& row, int index);
277
278 void examine(const ColIter& col);
279
280 template<class G>
281 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
282
283 bool isIsolated();
284
285 Dependency(const Parameters& parms)
286 : Parameters(parms)
287 {}
288
289 Dependency()
290 : Parameters()
291 {}
292
293 protected:
298 typedef typename FieldTraits<field_type>::real_type real_type;
299 real_type maxValue_;
303 int row_;
305 real_type diagonal_;
306 };
307
311 template<class M, class N>
313 {
314 public:
318 typedef M Matrix;
319
323 typedef N Norm;
324
328 typedef typename Matrix::row_type Row;
329
334
335 void init(const Matrix* matrix);
336
337 void initRow(const Row& row, int index);
338
339 void examine(const ColIter& col);
340
341 template<class G>
342 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
343
344 bool isIsolated();
345
346
347 SymmetricDependency(const Parameters& parms)
348 : Parameters(parms)
349 {}
351 : Parameters()
352 {}
353
354 protected:
359 typedef typename FieldTraits<field_type>::real_type real_type;
360 real_type maxValue_;
364 int row_;
366 real_type diagonal_;
367 };
368
373 template<int N>
375 {
376 public:
377 enum { /* @brief We preserve the sign.*/
378 is_sign_preserving = true
379 };
380
385 template<class M>
386 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m,
387 typename std::enable_if_t<!Dune::IsNumber<M>::value>* sfinae = nullptr) const
388 {
389 typedef typename M::field_type field_type;
390 typedef typename FieldTraits<field_type>::real_type real_type;
391 static_assert( std::is_convertible<field_type, real_type >::value,
392 "use of diagonal norm in AMG not implemented for complex field_type");
393 return m[N][N];
394 // possible implementation for complex types: return signed_abs(m[N][N]);
395 }
396
401 template<class M>
402 auto operator()(const M& m,
403 typename std::enable_if_t<Dune::IsNumber<M>::value>* sfinae = nullptr) const
404 {
405 typedef typename FieldTraits<M>::real_type real_type;
406 static_assert( std::is_convertible<M, real_type >::value,
407 "use of diagonal norm in AMG not implemented for complex field_type");
408 return m;
409 // possible implementation for complex types: return signed_abs(m[N][N]);
410 }
411
412 private:
413
415 template<typename T>
416 static T signed_abs(const T & v)
417 {
418 return v;
419 }
420
422 template<typename T>
423 static T signed_abs(const std::complex<T> & v)
424 {
425 // return sign * abs_value
426 // in case of complex numbers this extends to using the csgn function to determine the sign
427 return csgn(v) * std::abs(v);
428 }
429
431 template<typename T>
432 static T csgn(const T & v)
433 {
434 return (T(0) < v) - (v < T(0));
435 }
436
438 template<typename T>
439 static T csgn(std::complex<T> a)
440 {
441 return csgn(a.real())+(a.real() == 0.0)*csgn(a.imag());
442 }
443
444 };
445
450 class FirstDiagonal : public Diagonal<0>
451 {};
452
458 struct RowSum
459 {
460
461 enum { /* @brief We preserve the sign.*/
462 is_sign_preserving = false
463 };
468 template<class M>
469 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
470 {
471 return m.infinity_norm();
472 }
473 };
474
475 struct FrobeniusNorm
476 {
477
478 enum { /* @brief We preserve the sign.*/
479 is_sign_preserving = false
480 };
485 template<class M>
486 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
487 {
488 return m.frobenius_norm();
489 }
490 };
491 struct AlwaysOneNorm
492 {
493
494 enum { /* @brief We preserve the sign.*/
495 is_sign_preserving = false
496 };
501 template<class M>
502 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
503 {
504 return 1;
505 }
506 };
513 template<class M, class Norm>
514 class SymmetricCriterion : public AggregationCriterion<SymmetricDependency<M,Norm> >
515 {
516 public:
517 SymmetricCriterion(const Parameters& parms)
519 {}
521 {}
522 };
523
524
533 template<class M, class Norm>
534 class UnSymmetricCriterion : public AggregationCriterion<Dependency<M,Norm> >
535 {
536 public:
537 UnSymmetricCriterion(const Parameters& parms)
539 {}
541 {}
542 };
543 // forward declaration
544 template<class G> class Aggregator;
545
546
554 template<class V>
556 {
557 public:
558
562 static const V UNAGGREGATED;
563
567 static const V ISOLATED;
572
577
583
589
594 {
595 public:
596 template<class EdgeIterator>
597 void operator()(const EdgeIterator& edge) const
598 {
600 }
601 };
602
603
608
615
620
632 template<class M, class G, class C>
633 std::tuple<int,int,int,int> buildAggregates(const M& matrix, G& graph, const C& criterion,
634 bool finestLevel);
635
653 template<bool reset, class G, class F, class VM>
654 std::size_t breadthFirstSearch(const VertexDescriptor& start,
655 const AggregateDescriptor& aggregate,
656 const G& graph,
657 F& aggregateVisitor,
658 VM& visitedMap) const;
659
683 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
684 std::size_t breadthFirstSearch(const VertexDescriptor& start,
685 const AggregateDescriptor& aggregate,
686 const G& graph, L& visited, F1& aggregateVisitor,
687 F2& nonAggregateVisitor,
688 VM& visitedMap) const;
689
695 void allocate(std::size_t noVertices);
696
700 std::size_t noVertices() const;
701
705 void free();
706
713
720
721 typedef const AggregateDescriptor* const_iterator;
722
723 const_iterator begin() const
724 {
725 return aggregates_;
726 }
727
728 const_iterator end() const
729 {
730 return aggregates_+noVertices();
731 }
732
733 typedef AggregateDescriptor* iterator;
734
735 iterator begin()
736 {
737 return aggregates_;
738 }
739
740 iterator end()
741 {
742 return aggregates_+noVertices();
743 }
744 private:
746 AggregatesMap(const AggregatesMap<V>&) = delete;
748 AggregatesMap<V>& operator=(const AggregatesMap<V>&) = delete;
749
753 AggregateDescriptor* aggregates_;
754
758 std::size_t noVertices_;
759 };
760
764 template<class G, class C>
765 void buildDependency(G& graph,
766 const typename C::Matrix& matrix,
767 C criterion,
768 bool finestLevel);
769
774 template<class G, class S>
776 {
777
778 public:
779
780 /***
781 * @brief The type of the matrix graph we work with.
782 */
783 typedef G MatrixGraph;
788
794
799 typedef S VertexSet;
800
802 typedef typename VertexSet::const_iterator const_iterator;
803
807 typedef std::size_t* SphereMap;
808
817 Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
818 VertexSet& connectivity, std::vector<Vertex>& front_);
819
820 void invalidate()
821 {
822 --id_;
823 }
824
832
836 void seed(const Vertex& vertex);
837
841 void add(const Vertex& vertex);
842
843 void add(std::vector<Vertex>& vertex);
847 void clear();
848
852 typename VertexSet::size_type size();
856 typename VertexSet::size_type connectSize();
857
861 int id();
862
865
868
869 private:
873 VertexSet vertices_;
874
879 int id_;
880
884 MatrixGraph& graph_;
885
889 AggregatesMap<Vertex>& aggregates_;
890
894 VertexSet& connected_;
895
899 std::vector<Vertex>& front_;
900 };
901
905 template<class G>
907 {
908 public:
909
913 typedef G MatrixGraph;
914
919
922
927
932
949 template<class M, class C>
950 std::tuple<int,int,int,int> build(const M& m, G& graph,
951 AggregatesMap<Vertex>& aggregates, const C& c,
952 bool finestLevel);
953 private:
959
964
968 typedef std::set<Vertex,std::less<Vertex>,Allocator> VertexSet;
969
973 typedef std::size_t* SphereMap;
974
978 MatrixGraph* graph_;
979
984
988 std::vector<Vertex> front_;
989
993 VertexSet connected_;
994
998 int size_;
999
1003 class Stack
1004 {
1005 public:
1006 static const Vertex NullEntry;
1007
1008 Stack(const MatrixGraph& graph,
1009 const Aggregator<G>& aggregatesBuilder,
1010 const AggregatesMap<Vertex>& aggregates);
1011 ~Stack();
1012 Vertex pop();
1013 private:
1014 enum { N = 1300000 };
1015
1017 const MatrixGraph& graph_;
1019 const Aggregator<G>& aggregatesBuilder_;
1021 const AggregatesMap<Vertex>& aggregates_;
1023 int size_;
1024 Vertex maxSize_;
1026 typename MatrixGraph::ConstVertexIterator begin_;
1028
1030 Vertex* vals_;
1031
1032 };
1033
1034 friend class Stack;
1035
1046 template<class V>
1047 void visitAggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate,
1048 const AggregatesMap<Vertex>& aggregates,
1049 V& visitor) const;
1050
1055 template<class V>
1056 class AggregateVisitor
1057 {
1058 public:
1062 typedef V Visitor;
1071 Visitor& visitor);
1072
1079 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1080
1081 private:
1083 const AggregatesMap<Vertex>& aggregates_;
1085 AggregateDescriptor aggregate_;
1087 Visitor* visitor_;
1088 };
1089
1093 class Counter
1094 {
1095 public:
1099 int value();
1100
1101 protected:
1106
1107 private:
1108 int count_;
1109 };
1110
1111
1116 class FrontNeighbourCounter : public Counter
1117 {
1118 public:
1124
1125 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1126
1127 private:
1128 const MatrixGraph& graph_;
1129 };
1130
1135 int noFrontNeighbours(const Vertex& vertex) const;
1136
1140 class TwoWayCounter : public Counter
1141 {
1142 public:
1143 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1144 };
1145
1157 int twoWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1158 const AggregatesMap<Vertex>& aggregates) const;
1159
1163 class OneWayCounter : public Counter
1164 {
1165 public:
1166 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1167 };
1168
1180 int oneWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1181 const AggregatesMap<Vertex>& aggregates) const;
1182
1189 class ConnectivityCounter : public Counter
1190 {
1191 public:
1198 ConnectivityCounter(const VertexSet& connected, const AggregatesMap<Vertex>& aggregates);
1199
1200 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1201
1202 private:
1204 const VertexSet& connected_;
1206 const AggregatesMap<Vertex>& aggregates_;
1207
1208 };
1209
1221 double connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1229 bool connected(const Vertex& vertex, const AggregateDescriptor& aggregate,
1230 const AggregatesMap<Vertex>& aggregates) const;
1231
1239 bool connected(const Vertex& vertex, const SLList<AggregateDescriptor>& aggregateList,
1240 const AggregatesMap<Vertex>& aggregates) const;
1241
1249 class DependencyCounter : public Counter
1250 {
1251 public:
1256
1257 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1258 };
1259
1266 class FrontMarker
1267 {
1268 public:
1275 FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph);
1276
1277 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1278
1279 private:
1281 std::vector<Vertex>& front_;
1283 MatrixGraph& graph_;
1284 };
1285
1289 void unmarkFront();
1290
1305 int unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1306
1320 std::pair<int,int> neighbours(const Vertex& vertex,
1321 const AggregateDescriptor& aggregate,
1322 const AggregatesMap<Vertex>& aggregates) const;
1339 int aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1340
1348 bool admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1349
1357 std::size_t distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates);
1358
1367 Vertex mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1368
1377 void nonisoNeighbourAggregate(const Vertex& vertex,
1378 const AggregatesMap<Vertex>& aggregates,
1379 SLList<Vertex>& neighbours) const;
1380
1388 template<class C>
1389 void growAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1390 template<class C>
1391 void growIsolatedAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1392 };
1393
1394#ifndef DOXYGEN
1395
1396 template<class M, class N>
1397 inline void SymmetricDependency<M,N>::init(const Matrix* matrix)
1398 {
1399 matrix_ = matrix;
1400 }
1401
1402 template<class M, class N>
1403 inline void SymmetricDependency<M,N>::initRow(const Row& row, int index)
1404 {
1405 using std::min;
1408 row_ = index;
1409 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1410 }
1411
1412 template<class M, class N>
1413 inline void SymmetricDependency<M,N>::examine(const ColIter& col)
1414 {
1415 using std::max;
1416 real_type eij = norm_(*col);
1417 typename Matrix::ConstColIterator opposite_entry =
1418 matrix_->operator[](col.index()).find(row_);
1419 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1420 {
1421 // Consider this a weak connection we disregard.
1422 return;
1423 }
1424 real_type eji = norm_(*opposite_entry);
1425
1426 // skip positive offdiagonals if norm preserves sign of them.
1427 if(!N::is_sign_preserving || eij<0 || eji<0)
1428 maxValue_ = max(maxValue_,
1429 eij /diagonal_ * eji/
1430 norm_(matrix_->operator[](col.index())[col.index()]));
1431 }
1432
1433 template<class M, class N>
1434 template<class G>
1435 inline void SymmetricDependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1436 {
1437 real_type eij = norm_(*col);
1438 typename Matrix::ConstColIterator opposite_entry =
1439 matrix_->operator[](col.index()).find(row_);
1440
1441 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1442 {
1443 // Consider this as a weak connection we disregard.
1444 return;
1445 }
1446 real_type eji = norm_(*opposite_entry);
1447 // skip positve offdiagonals if norm preserves sign of them.
1448 if(!N::is_sign_preserving || (eij<0 || eji<0))
1449 if(eji / norm_(matrix_->operator[](edge.target())[edge.target()]) *
1450 eij/ diagonal_ > alpha() * maxValue_) {
1451 edge.properties().setDepends();
1452 edge.properties().setInfluences();
1453 typename G::EdgeProperties& other = graph.getEdgeProperties(edge.target(), edge.source());
1454 other.setInfluences();
1455 other.setDepends();
1456 }
1457 }
1458
1459 template<class M, class N>
1460 inline bool SymmetricDependency<M,N>::isIsolated()
1461 {
1462 return maxValue_ < beta();
1463 }
1464
1465
1466 template<class M, class N>
1467 inline void Dependency<M,N>::init(const Matrix* matrix)
1468 {
1469 matrix_ = matrix;
1470 }
1471
1472 template<class M, class N>
1473 inline void Dependency<M,N>::initRow(const Row& row, int index)
1474 {
1475 using std::min;
1478 row_ = index;
1479 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1480 }
1481
1482 template<class M, class N>
1483 inline void Dependency<M,N>::examine(const ColIter& col)
1484 {
1485 using std::max;
1486 maxValue_ = max(maxValue_, -norm_(*col));
1487 }
1488
1489 template<class M, class N>
1490 template<class G>
1491 inline void Dependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1492 {
1493 if(-norm_(*col) >= maxValue_ * alpha()) {
1494 edge.properties().setDepends();
1495 typedef typename G::EdgeDescriptor ED;
1496 ED e= graph.findEdge(edge.target(), edge.source());
1498 {
1499 typename G::EdgeProperties& other = graph.getEdgeProperties(e);
1500 other.setInfluences();
1501 }
1502 }
1503 }
1504
1505 template<class M, class N>
1506 inline bool Dependency<M,N>::isIsolated()
1507 {
1508 return maxValue_ < beta() * diagonal_;
1509 }
1510
1511 template<class G,class S>
1512 Aggregate<G,S>::Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
1513 VertexSet& connected, std::vector<Vertex>& front)
1514 : vertices_(), id_(-1), graph_(graph), aggregates_(aggregates),
1515 connected_(connected), front_(front)
1516 {}
1517
1518 template<class G,class S>
1520 {
1521 /*
1522 vertices_.push_back(vertex);
1523 typedef typename VertexList::const_iterator iterator;
1524 iterator begin = vertices_.begin();
1525 iterator end = vertices_.end();*/
1526 throw "Not yet implemented";
1527
1528 // while(begin!=end){
1529 //for();
1530 // }
1531
1532 }
1533
1534 template<class G,class S>
1535 inline void Aggregate<G,S>::seed(const Vertex& vertex)
1536 {
1537 dvverb<<"Connected cleared"<<std::endl;
1538 connected_.clear();
1539 vertices_.clear();
1540 connected_.insert(vertex);
1541 dvverb << " Inserting "<<vertex<<" size="<<connected_.size();
1542 ++id_ ;
1543 add(vertex);
1544 }
1545
1546
1547 template<class G,class S>
1548 inline void Aggregate<G,S>::add(const Vertex& vertex)
1549 {
1550 vertices_.insert(vertex);
1551 aggregates_[vertex]=id_;
1552 if(front_.size())
1553 front_.erase(std::lower_bound(front_.begin(), front_.end(), vertex));
1554
1555
1556 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1557 const iterator end = graph_.endEdges(vertex);
1558 for(iterator edge = graph_.beginEdges(vertex); edge != end; ++edge) {
1559 dvverb << " Inserting "<<aggregates_[edge.target()];
1560 connected_.insert(aggregates_[edge.target()]);
1561 dvverb <<" size="<<connected_.size();
1562 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1563 !graph_.getVertexProperties(edge.target()).front())
1564 {
1565 front_.push_back(edge.target());
1566 graph_.getVertexProperties(edge.target()).setFront();
1567 }
1568 }
1569 dvverb <<std::endl;
1570 std::sort(front_.begin(), front_.end());
1571 }
1572
1573 template<class G,class S>
1574 inline void Aggregate<G,S>::add(std::vector<Vertex>& vertices)
1575 {
1576#ifndef NDEBUG
1577 std::size_t oldsize = vertices_.size();
1578#endif
1579 typedef typename std::vector<Vertex>::iterator Iterator;
1580
1581 typedef typename VertexSet::iterator SIterator;
1582
1583 SIterator pos=vertices_.begin();
1584 std::vector<Vertex> newFront;
1585 newFront.reserve(front_.capacity());
1586
1587 std::set_difference(front_.begin(), front_.end(), vertices.begin(), vertices.end(),
1588 std::back_inserter(newFront));
1589 front_=newFront;
1590
1591 for(Iterator vertex=vertices.begin(); vertex != vertices.end(); ++vertex)
1592 {
1593 pos=vertices_.insert(pos,*vertex);
1594 vertices_.insert(*vertex);
1595 graph_.getVertexProperties(*vertex).resetFront(); // Not a front node any more.
1596 aggregates_[*vertex]=id_;
1597
1598 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1599 const iterator end = graph_.endEdges(*vertex);
1600 for(iterator edge = graph_.beginEdges(*vertex); edge != end; ++edge) {
1601 dvverb << " Inserting "<<aggregates_[edge.target()];
1602 connected_.insert(aggregates_[edge.target()]);
1603 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1604 !graph_.getVertexProperties(edge.target()).front())
1605 {
1606 front_.push_back(edge.target());
1607 graph_.getVertexProperties(edge.target()).setFront();
1608 }
1609 dvverb <<" size="<<connected_.size();
1610 }
1611 dvverb <<std::endl;
1612 }
1613 std::sort(front_.begin(), front_.end());
1614 assert(oldsize+vertices.size()==vertices_.size());
1615 }
1616 template<class G,class S>
1617 inline void Aggregate<G,S>::clear()
1618 {
1619 vertices_.clear();
1620 connected_.clear();
1621 id_=-1;
1622 }
1623
1624 template<class G,class S>
1625 inline typename Aggregate<G,S>::VertexSet::size_type
1627 {
1628 return vertices_.size();
1629 }
1630
1631 template<class G,class S>
1632 inline typename Aggregate<G,S>::VertexSet::size_type
1634 {
1635 return connected_.size();
1636 }
1637
1638 template<class G,class S>
1639 inline int Aggregate<G,S>::id()
1640 {
1641 return id_;
1642 }
1643
1644 template<class G,class S>
1646 {
1647 return vertices_.begin();
1648 }
1649
1650 template<class G,class S>
1652 {
1653 return vertices_.end();
1654 }
1655
1656 template<class V>
1658
1659 template<class V>
1661
1662 template<class V>
1664 : aggregates_(0)
1665 {}
1666
1667 template<class V>
1669 {
1670 if(aggregates_!=0)
1671 delete[] aggregates_;
1672 }
1673
1674
1675 template<class V>
1676 inline AggregatesMap<V>::AggregatesMap(std::size_t noVertices)
1677 {
1678 allocate(noVertices);
1679 }
1680
1681 template<class V>
1682 inline std::size_t AggregatesMap<V>::noVertices() const
1683 {
1684 return noVertices_;
1685 }
1686
1687 template<class V>
1688 inline void AggregatesMap<V>::allocate(std::size_t noVertices)
1689 {
1690 aggregates_ = new AggregateDescriptor[noVertices];
1691 noVertices_ = noVertices;
1692
1693 for(std::size_t i=0; i < noVertices; i++)
1694 aggregates_[i]=UNAGGREGATED;
1695 }
1696
1697 template<class V>
1698 inline void AggregatesMap<V>::free()
1699 {
1700 assert(aggregates_ != 0);
1701 delete[] aggregates_;
1702 aggregates_=0;
1703 }
1704
1705 template<class V>
1707 AggregatesMap<V>::operator[](const VertexDescriptor& v)
1708 {
1709 return aggregates_[v];
1710 }
1711
1712 template<class V>
1713 inline const typename AggregatesMap<V>::AggregateDescriptor&
1714 AggregatesMap<V>::operator[](const VertexDescriptor& v) const
1715 {
1716 return aggregates_[v];
1717 }
1718
1719 template<class V>
1720 template<bool reset, class G, class F,class VM>
1721 inline std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1722 const AggregateDescriptor& aggregate,
1723 const G& graph, F& aggregateVisitor,
1724 VM& visitedMap) const
1725 {
1726 VertexList vlist;
1727
1728 DummyEdgeVisitor dummy;
1729 return breadthFirstSearch<true,reset>(start, aggregate, graph, vlist, aggregateVisitor, dummy, visitedMap);
1730 }
1731
1732 template<class V>
1733 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
1734 std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1735 const AggregateDescriptor& aggregate,
1736 const G& graph,
1737 L& visited,
1738 F1& aggregateVisitor,
1739 F2& nonAggregateVisitor,
1740 VM& visitedMap) const
1741 {
1742 typedef typename L::const_iterator ListIterator;
1743 int visitedSpheres = 0;
1744
1745 visited.push_back(start);
1746 put(visitedMap, start, true);
1747
1748 ListIterator current = visited.begin();
1749 ListIterator end = visited.end();
1750 std::size_t i=0, size=visited.size();
1751
1752 // visit the neighbours of all vertices of the
1753 // current sphere.
1754 while(current != end) {
1755
1756 for(; i<size; ++current, ++i) {
1757 typedef typename G::ConstEdgeIterator EdgeIterator;
1758 const EdgeIterator endEdge = graph.endEdges(*current);
1759
1760 for(EdgeIterator edge = graph.beginEdges(*current);
1761 edge != endEdge; ++edge) {
1762
1763 if(aggregates_[edge.target()]==aggregate) {
1764 if(!get(visitedMap, edge.target())) {
1765 put(visitedMap, edge.target(), true);
1766 visited.push_back(edge.target());
1767 aggregateVisitor(edge);
1768 }
1769 }else
1770 nonAggregateVisitor(edge);
1771 }
1772 }
1773 end = visited.end();
1774 size = visited.size();
1775 if(current != end)
1776 visitedSpheres++;
1777 }
1778
1779 if(reset)
1780 for(current = visited.begin(); current != end; ++current)
1781 put(visitedMap, *current, false);
1782
1783
1784 if(remove)
1785 visited.clear();
1786
1787 return visitedSpheres;
1788 }
1789
1790 template<class G>
1792 : graph_(0), aggregate_(0), front_(), connected_(), size_(-1)
1793 {}
1794
1795 template<class G>
1797 {
1798 size_=-1;
1799 }
1800
1801 template<class G, class C>
1802 void buildDependency(G& graph,
1803 const typename C::Matrix& matrix,
1804 C criterion, bool firstlevel)
1805 {
1806 // assert(graph.isBuilt());
1807 typedef typename C::Matrix Matrix;
1808 typedef typename G::VertexIterator VertexIterator;
1809
1810 criterion.init(&matrix);
1811
1812 for(VertexIterator vertex = graph.begin(); vertex != graph.end(); ++vertex) {
1813 typedef typename Matrix::row_type Row;
1814
1815 const Row& row = matrix[*vertex];
1816
1817 // Tell the criterion what row we will examine now
1818 // This might for example be used for calculating the
1819 // maximum offdiagonal value
1820 criterion.initRow(row, *vertex);
1821
1822 // On a first path all columns are examined. After this
1823 // the calculator should know whether the vertex is isolated.
1824 typedef typename Matrix::ConstColIterator ColIterator;
1825 ColIterator end = row.end();
1826 typename FieldTraits<typename Matrix::field_type>::real_type absoffdiag=0.;
1827
1828 using std::max;
1829 if(firstlevel) {
1830 for(ColIterator col = row.begin(); col != end; ++col)
1831 if(col.index()!=*vertex) {
1832 criterion.examine(col);
1833 absoffdiag = max(absoffdiag, Impl::asMatrix(*col).frobenius_norm());
1834 }
1835
1836 if(absoffdiag==0)
1837 vertex.properties().setExcludedBorder();
1838 }
1839 else
1840 for(ColIterator col = row.begin(); col != end; ++col)
1841 if(col.index()!=*vertex)
1842 criterion.examine(col);
1843
1844 // reset the vertex properties
1845 //vertex.properties().reset();
1846
1847 // Check whether the vertex is isolated.
1848 if(criterion.isIsolated()) {
1849 //std::cout<<"ISOLATED: "<<*vertex<<std::endl;
1850 vertex.properties().setIsolated();
1851 }else{
1852 // Examine all the edges beginning at this vertex.
1853 typedef typename G::EdgeIterator EdgeIterator;
1854 typedef typename Matrix::ConstColIterator ColIterator;
1855 EdgeIterator eEnd = vertex.end();
1856 ColIterator col = matrix[*vertex].begin();
1857
1858 for(EdgeIterator edge = vertex.begin(); edge!= eEnd; ++edge, ++col) {
1859 // Move to the right column.
1860 while(col.index()!=edge.target())
1861 ++col;
1862 criterion.examine(graph, edge, col);
1863 }
1864 }
1865
1866 }
1867 }
1868
1869
1870 template<class G>
1871 template<class V>
1872 inline Aggregator<G>::AggregateVisitor<V>::AggregateVisitor(const AggregatesMap<Vertex>& aggregates,
1873 const AggregateDescriptor& aggregate, V& visitor)
1874 : aggregates_(aggregates), aggregate_(aggregate), visitor_(&visitor)
1875 {}
1876
1877 template<class G>
1878 template<class V>
1879 inline void Aggregator<G>::AggregateVisitor<V>::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1880 {
1881 if(aggregates_[edge.target()]==aggregate_)
1882 visitor_->operator()(edge);
1883 }
1884
1885 template<class G>
1886 template<class V>
1887 inline void Aggregator<G>::visitAggregateNeighbours(const Vertex& vertex,
1888 const AggregateDescriptor& aggregate,
1889 const AggregatesMap<Vertex>& aggregates,
1890 V& visitor) const
1891 {
1892 // Only evaluates for edge pointing to the aggregate
1893 AggregateVisitor<V> v(aggregates, aggregate, visitor);
1894 visitNeighbours(*graph_, vertex, v);
1895 }
1896
1897
1898 template<class G>
1899 inline Aggregator<G>::Counter::Counter()
1900 : count_(0)
1901 {}
1902
1903 template<class G>
1904 inline void Aggregator<G>::Counter::increment()
1905 {
1906 ++count_;
1907 }
1908
1909 template<class G>
1910 inline void Aggregator<G>::Counter::decrement()
1911 {
1912 --count_;
1913 }
1914 template<class G>
1915 inline int Aggregator<G>::Counter::value()
1916 {
1917 return count_;
1918 }
1919
1920 template<class G>
1921 inline void Aggregator<G>::TwoWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1922 {
1923 if(edge.properties().isTwoWay())
1924 Counter::increment();
1925 }
1926
1927 template<class G>
1928 int Aggregator<G>::twoWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1929 const AggregatesMap<Vertex>& aggregates) const
1930 {
1931 TwoWayCounter counter;
1932 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1933 return counter.value();
1934 }
1935
1936 template<class G>
1937 int Aggregator<G>::oneWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1938 const AggregatesMap<Vertex>& aggregates) const
1939 {
1940 OneWayCounter counter;
1941 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1942 return counter.value();
1943 }
1944
1945 template<class G>
1946 inline void Aggregator<G>::OneWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1947 {
1948 if(edge.properties().isOneWay())
1949 Counter::increment();
1950 }
1951
1952 template<class G>
1953 inline Aggregator<G>::ConnectivityCounter::ConnectivityCounter(const VertexSet& connected,
1954 const AggregatesMap<Vertex>& aggregates)
1955 : Counter(), connected_(connected), aggregates_(aggregates)
1956 {}
1957
1958
1959 template<class G>
1960 inline void Aggregator<G>::ConnectivityCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1961 {
1962 if(connected_.find(aggregates_[edge.target()]) == connected_.end() || aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED)
1963 // Would be a new connection
1964 Counter::increment();
1965 else{
1966 Counter::increment();
1967 Counter::increment();
1968 }
1969 }
1970
1971 template<class G>
1972 inline double Aggregator<G>::connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
1973 {
1974 ConnectivityCounter counter(connected_, aggregates);
1975 double noNeighbours=visitNeighbours(*graph_, vertex, counter);
1976 return (double)counter.value()/noNeighbours;
1977 }
1978
1979 template<class G>
1980 inline Aggregator<G>::DependencyCounter::DependencyCounter()
1981 : Counter()
1982 {}
1983
1984 template<class G>
1985 inline void Aggregator<G>::DependencyCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1986 {
1987 if(edge.properties().depends())
1988 Counter::increment();
1989 if(edge.properties().influences())
1990 Counter::increment();
1991 }
1992
1993 template<class G>
1994 int Aggregator<G>::unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
1995 {
1996 return aggregateNeighbours(vertex, AggregatesMap<Vertex>::UNAGGREGATED, aggregates);
1997 }
1998
1999 template<class G>
2000 std::pair<int,int> Aggregator<G>::neighbours(const Vertex& vertex,
2001 const AggregateDescriptor& aggregate,
2002 const AggregatesMap<Vertex>& aggregates) const
2003 {
2004 DependencyCounter unused, aggregated;
2005 typedef AggregateVisitor<DependencyCounter> Counter;
2006 typedef std::tuple<Counter,Counter> CounterTuple;
2007 CombinedFunctor<CounterTuple> visitors(CounterTuple(Counter(aggregates, AggregatesMap<Vertex>::UNAGGREGATED, unused), Counter(aggregates, aggregate, aggregated)));
2008 visitNeighbours(*graph_, vertex, visitors);
2009 return std::make_pair(unused.value(), aggregated.value());
2010 }
2011
2012
2013 template<class G>
2014 int Aggregator<G>::aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2015 {
2016 DependencyCounter counter;
2017 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
2018 return counter.value();
2019 }
2020
2021 template<class G>
2022 std::size_t Aggregator<G>::distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates)
2023 {
2024 return 0;
2025 typename PropertyMapTypeSelector<VertexVisitedTag,G>::Type visitedMap = get(VertexVisitedTag(), *graph_);
2026 VertexList vlist;
2027 typename AggregatesMap<Vertex>::DummyEdgeVisitor dummy;
2028 return aggregates.template breadthFirstSearch<true,true>(vertex,
2029 aggregate_->id(), *graph_,
2030 vlist, dummy, dummy, visitedMap);
2031 }
2032
2033 template<class G>
2034 inline Aggregator<G>::FrontMarker::FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph)
2035 : front_(front), graph_(graph)
2036 {}
2037
2038 template<class G>
2039 inline void Aggregator<G>::FrontMarker::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2040 {
2041 Vertex target = edge.target();
2042
2043 if(!graph_.getVertexProperties(target).front()) {
2044 front_.push_back(target);
2045 graph_.getVertexProperties(target).setFront();
2046 }
2047 }
2048
2049 template<class G>
2050 inline bool Aggregator<G>::admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2051 {
2052 // Todo
2053 Dune::dvverb<<" Admissible not yet implemented!"<<std::endl;
2054 return true;
2055 //Situation 1: front node depends on two nodes. Then these
2056 // have to be strongly connected to each other
2057
2058 // Iterate over all all neighbours of front node
2059 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2060 Iterator vend = graph_->endEdges(vertex);
2061 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2062 // if(edge.properties().depends() && !edge.properties().influences()
2063 if(edge.properties().isStrong()
2064 && aggregates[edge.target()]==aggregate)
2065 {
2066 // Search for another link to the aggregate
2067 Iterator edge1 = edge;
2068 for(++edge1; edge1 != vend; ++edge1) {
2069 //if(edge1.properties().depends() && !edge1.properties().influences()
2070 if(edge1.properties().isStrong()
2071 && aggregates[edge.target()]==aggregate)
2072 {
2073 //Search for an edge connecting the two vertices that is
2074 //strong
2075 bool found=false;
2076 Iterator v2end = graph_->endEdges(edge.target());
2077 for(Iterator edge2 = graph_->beginEdges(edge.target()); edge2 != v2end; ++edge2) {
2078 if(edge2.target()==edge1.target() &&
2079 edge2.properties().isStrong()) {
2080 found =true;
2081 break;
2082 }
2083 }
2084 if(found)
2085 {
2086 return true;
2087 }
2088 }
2089 }
2090 }
2091 }
2092
2093 // Situation 2: cluster node depends on front node and other cluster node
2095 vend = graph_->endEdges(vertex);
2096 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2097 //if(!edge.properties().depends() && edge.properties().influences()
2098 if(edge.properties().isStrong()
2099 && aggregates[edge.target()]==aggregate)
2100 {
2101 // Search for a link from target that stays within the aggregate
2102 Iterator v1end = graph_->endEdges(edge.target());
2103
2104 for(Iterator edge1=graph_->beginEdges(edge.target()); edge1 != v1end; ++edge1) {
2105 //if(edge1.properties().depends() && !edge1.properties().influences()
2106 if(edge1.properties().isStrong()
2107 && aggregates[edge1.target()]==aggregate)
2108 {
2109 bool found=false;
2110 // Check if front node is also connected to this one
2111 Iterator v2end = graph_->endEdges(vertex);
2112 for(Iterator edge2 = graph_->beginEdges(vertex); edge2 != v2end; ++edge2) {
2113 if(edge2.target()==edge1.target()) {
2114 if(edge2.properties().isStrong())
2115 found=true;
2116 break;
2117 }
2118 }
2119 if(found)
2120 {
2121 return true;
2122 }
2123 }
2124 }
2125 }
2126 }
2127 return false;
2128 }
2129
2130 template<class G>
2131 void Aggregator<G>::unmarkFront()
2132 {
2133 typedef typename std::vector<Vertex>::const_iterator Iterator;
2134
2135 for(Iterator vertex=front_.begin(); vertex != front_.end(); ++vertex)
2136 graph_->getVertexProperties(*vertex).resetFront();
2137
2138 front_.clear();
2139 }
2140
2141 template<class G>
2142 inline void
2143 Aggregator<G>::nonisoNeighbourAggregate(const Vertex& vertex,
2144 const AggregatesMap<Vertex>& aggregates,
2145 SLList<Vertex>& neighbours) const
2146 {
2147 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2148 Iterator end=graph_->beginEdges(vertex);
2149 neighbours.clear();
2150
2151 for(Iterator edge=graph_->beginEdges(vertex); edge!=end; ++edge)
2152 {
2153 if(aggregates[edge.target()]!=AggregatesMap<Vertex>::UNAGGREGATED && graph_->getVertexProperties(edge.target()).isolated())
2154 neighbours.push_back(aggregates[edge.target()]);
2155 }
2156 }
2157
2158 template<class G>
2159 inline typename G::VertexDescriptor Aggregator<G>::mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2160 {
2161 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2162
2163 Iterator end = graph_->endEdges(vertex);
2164 for(Iterator edge = graph_->beginEdges(vertex); edge != end; ++edge) {
2165 if(aggregates[edge.target()] != AggregatesMap<Vertex>::UNAGGREGATED &&
2166 graph_->getVertexProperties(edge.target()).isolated() == graph_->getVertexProperties(edge.source()).isolated()) {
2167 if( graph_->getVertexProperties(vertex).isolated() ||
2168 ((edge.properties().depends() || edge.properties().influences())
2169 && admissible(vertex, aggregates[edge.target()], aggregates)))
2170 return edge.target();
2171 }
2172 }
2174 }
2175
2176 template<class G>
2177 Aggregator<G>::FrontNeighbourCounter::FrontNeighbourCounter(const MatrixGraph& graph)
2178 : Counter(), graph_(graph)
2179 {}
2180
2181 template<class G>
2182 void Aggregator<G>::FrontNeighbourCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2183 {
2184 if(graph_.getVertexProperties(edge.target()).front())
2185 Counter::increment();
2186 }
2187
2188 template<class G>
2189 int Aggregator<G>::noFrontNeighbours(const Vertex& vertex) const
2190 {
2191 FrontNeighbourCounter counter(*graph_);
2192 visitNeighbours(*graph_, vertex, counter);
2193 return counter.value();
2194 }
2195 template<class G>
2196 inline bool Aggregator<G>::connected(const Vertex& vertex,
2197 const AggregateDescriptor& aggregate,
2198 const AggregatesMap<Vertex>& aggregates) const
2199 {
2200 typedef typename G::ConstEdgeIterator iterator;
2201 const iterator end = graph_->endEdges(vertex);
2202 for(iterator edge = graph_->beginEdges(vertex); edge != end; ++edge)
2203 if(aggregates[edge.target()]==aggregate)
2204 return true;
2205 return false;
2206 }
2207 template<class G>
2208 inline bool Aggregator<G>::connected(const Vertex& vertex,
2209 const SLList<AggregateDescriptor>& aggregateList,
2210 const AggregatesMap<Vertex>& aggregates) const
2211 {
2212 typedef typename SLList<AggregateDescriptor>::const_iterator Iter;
2213 for(Iter i=aggregateList.begin(); i!=aggregateList.end(); ++i)
2214 if(connected(vertex, *i, aggregates))
2215 return true;
2216 return false;
2217 }
2218
2219 template<class G>
2220 template<class C>
2221 void Aggregator<G>::growIsolatedAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2222 {
2223 SLList<Vertex> connectedAggregates;
2224 nonisoNeighbourAggregate(seed, aggregates,connectedAggregates);
2225
2226 while(aggregate_->size()< c.minAggregateSize() && aggregate_->connectSize() < c.maxConnectivity()) {
2227 double maxCon=-1;
2228 std::size_t maxFrontNeighbours=0;
2229
2231
2232 typedef typename std::vector<Vertex>::const_iterator Iterator;
2233
2234 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2235 if(distance(*vertex, aggregates)>c.maxDistance())
2236 continue; // distance of proposes aggregate too big
2237
2238 if(connectedAggregates.size()>0) {
2239 // there is already a neighbour cluster
2240 // front node must be connected to same neighbour cluster
2241
2242 if(!connected(*vertex, connectedAggregates, aggregates))
2243 continue;
2244 }
2245
2246 double con = connectivity(*vertex, aggregates);
2247
2248 if(con == maxCon) {
2249 std::size_t frontNeighbours = noFrontNeighbours(*vertex);
2250
2251 if(frontNeighbours >= maxFrontNeighbours) {
2252 maxFrontNeighbours = frontNeighbours;
2253 candidate = *vertex;
2254 }
2255 }else if(con > maxCon) {
2256 maxCon = con;
2257 maxFrontNeighbours = noFrontNeighbours(*vertex);
2258 candidate = *vertex;
2259 }
2260 }
2261
2263 break;
2264
2265 aggregate_->add(candidate);
2266 }
2267 }
2268
2269 template<class G>
2270 template<class C>
2271 void Aggregator<G>::growAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2272 {
2273 using std::min;
2274
2275 std::size_t distance_ =0;
2276 while(aggregate_->size() < c.minAggregateSize()&& distance_<c.maxDistance()) {
2277 int maxTwoCons=0, maxOneCons=0, maxNeighbours=-1;
2278 double maxCon=-1;
2279
2280 std::vector<Vertex> candidates;
2281 candidates.reserve(30);
2282
2283 typedef typename std::vector<Vertex>::const_iterator Iterator;
2284
2285 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2286 // Only nonisolated nodes are considered
2287 if(graph_->getVertexProperties(*vertex).isolated())
2288 continue;
2289
2290 int twoWayCons = twoWayConnections(*vertex, aggregate_->id(), aggregates);
2291
2292 /* The case of two way connections. */
2293 if( maxTwoCons == twoWayCons && twoWayCons > 0) {
2294 double con = connectivity(*vertex, aggregates);
2295
2296 if(con == maxCon) {
2297 int neighbours = noFrontNeighbours(*vertex);
2298
2299 if(neighbours > maxNeighbours) {
2300 maxNeighbours = neighbours;
2301 candidates.clear();
2302 candidates.push_back(*vertex);
2303 }else{
2304 candidates.push_back(*vertex);
2305 }
2306 }else if( con > maxCon) {
2307 maxCon = con;
2308 maxNeighbours = noFrontNeighbours(*vertex);
2309 candidates.clear();
2310 candidates.push_back(*vertex);
2311 }
2312 }else if(twoWayCons > maxTwoCons) {
2313 maxTwoCons = twoWayCons;
2314 maxCon = connectivity(*vertex, aggregates);
2315 maxNeighbours = noFrontNeighbours(*vertex);
2316 candidates.clear();
2317 candidates.push_back(*vertex);
2318
2319 // two way connections precede
2320 maxOneCons = std::numeric_limits<int>::max();
2321 }
2322
2323 if(twoWayCons > 0)
2324 {
2325 continue; // THis is a two-way node, skip tests for one way nodes
2326 }
2327
2328 /* The one way case */
2329 int oneWayCons = oneWayConnections(*vertex, aggregate_->id(), aggregates);
2330
2331 if(oneWayCons==0)
2332 continue; // No strong connections, skip the tests.
2333
2334 if(!admissible(*vertex, aggregate_->id(), aggregates))
2335 continue;
2336
2337 if( maxOneCons == oneWayCons && oneWayCons > 0) {
2338 double con = connectivity(*vertex, aggregates);
2339
2340 if(con == maxCon) {
2341 int neighbours = noFrontNeighbours(*vertex);
2342
2343 if(neighbours > maxNeighbours) {
2344 maxNeighbours = neighbours;
2345 candidates.clear();
2346 candidates.push_back(*vertex);
2347 }else{
2348 if(neighbours==maxNeighbours)
2349 {
2350 candidates.push_back(*vertex);
2351 }
2352 }
2353 }else if( con > maxCon) {
2354 maxCon = con;
2355 maxNeighbours = noFrontNeighbours(*vertex);
2356 candidates.clear();
2357 candidates.push_back(*vertex);
2358 }
2359 }else if(oneWayCons > maxOneCons) {
2360 maxOneCons = oneWayCons;
2361 maxCon = connectivity(*vertex, aggregates);
2362 maxNeighbours = noFrontNeighbours(*vertex);
2363 candidates.clear();
2364 candidates.push_back(*vertex);
2365 }
2366 }
2367
2368
2369 if(!candidates.size())
2370 break; // No more candidates found
2371 distance_=distance(seed, aggregates);
2372 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2373 aggregate_->size()));
2374 aggregate_->add(candidates);
2375 }
2376 }
2377
2378 template<typename V>
2379 template<typename M, typename G, typename C>
2380 std::tuple<int,int,int,int> AggregatesMap<V>::buildAggregates(const M& matrix, G& graph, const C& criterion,
2381 bool finestLevel)
2382 {
2383 Aggregator<G> aggregator;
2384 return aggregator.build(matrix, graph, *this, criterion, finestLevel);
2385 }
2386
2387 template<class G>
2388 template<class M, class C>
2389 std::tuple<int,int,int,int> Aggregator<G>::build(const M& m, G& graph, AggregatesMap<Vertex>& aggregates, const C& c,
2390 bool finestLevel)
2391 {
2392 using std::max;
2393 using std::min;
2394 // Stack for fast vertex access
2395 Stack stack_(graph, *this, aggregates);
2396
2397 graph_ = &graph;
2398
2399 aggregate_ = new Aggregate<G,VertexSet>(graph, aggregates, connected_, front_);
2400
2401 Timer watch;
2402 watch.reset();
2403
2404 buildDependency(graph, m, c, finestLevel);
2405
2406 dverb<<"Build dependency took "<< watch.elapsed()<<" seconds."<<std::endl;
2407 int noAggregates, conAggregates, isoAggregates, oneAggregates;
2408 std::size_t maxA=0, minA=1000000, avg=0;
2409 int skippedAggregates;
2410 noAggregates = conAggregates = isoAggregates = oneAggregates =
2411 skippedAggregates = 0;
2412
2413 while(true) {
2414 Vertex seed = stack_.pop();
2415
2416 if(seed == Stack::NullEntry)
2417 // No more unaggregated vertices. We are finished!
2418 break;
2419
2420 // Debugging output
2421 if((noAggregates+1)%10000 == 0)
2422 Dune::dverb<<"c";
2423 unmarkFront();
2424
2425 if(graph.getVertexProperties(seed).excludedBorder()) {
2426 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2427 ++skippedAggregates;
2428 continue;
2429 }
2430
2431 if(graph.getVertexProperties(seed).isolated()) {
2432 if(c.skipIsolated()) {
2433 // isolated vertices are not aggregated but skipped on the coarser levels.
2434 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2435 ++skippedAggregates;
2436 // skip rest as no agglomeration is done.
2437 continue;
2438 }else{
2439 aggregate_->seed(seed);
2440 growIsolatedAggregate(seed, aggregates, c);
2441 }
2442 }else{
2443 aggregate_->seed(seed);
2444 growAggregate(seed, aggregates, c);
2445 }
2446
2447 /* The rounding step. */
2448 while(!(graph.getVertexProperties(seed).isolated()) && aggregate_->size() < c.maxAggregateSize()) {
2449
2450 std::vector<Vertex> candidates;
2451 candidates.reserve(30);
2452
2453 typedef typename std::vector<Vertex>::const_iterator Iterator;
2454
2455 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2456
2457 if(graph.getVertexProperties(*vertex).isolated())
2458 continue; // No isolated nodes here
2459
2460 if(twoWayConnections( *vertex, aggregate_->id(), aggregates) == 0 &&
2461 (oneWayConnections( *vertex, aggregate_->id(), aggregates) == 0 ||
2462 !admissible( *vertex, aggregate_->id(), aggregates) ))
2463 continue;
2464
2465 std::pair<int,int> neighbourPair=neighbours(*vertex, aggregate_->id(),
2466 aggregates);
2467
2468 //if(aggregateNeighbours(*vertex, aggregate_->id(), aggregates) <= unusedNeighbours(*vertex, aggregates))
2469 // continue;
2470
2471 if(neighbourPair.first >= neighbourPair.second)
2472 continue;
2473
2474 if(distance(*vertex, aggregates) > c.maxDistance())
2475 continue; // Distance too far
2476 candidates.push_back(*vertex);
2477 break;
2478 }
2479
2480 if(!candidates.size()) break; // no more candidates found.
2481
2482 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2483 aggregate_->size()));
2484 aggregate_->add(candidates);
2485
2486 }
2487
2488 // try to merge aggregates consisting of only one nonisolated vertex with other aggregates
2489 if(aggregate_->size()==1 && c.maxAggregateSize()>1) {
2490 if(!graph.getVertexProperties(seed).isolated()) {
2491 Vertex mergedNeighbour = mergeNeighbour(seed, aggregates);
2492
2493 if(mergedNeighbour != AggregatesMap<Vertex>::UNAGGREGATED) {
2494 // assign vertex to the neighbouring cluster
2495 aggregates[seed] = aggregates[mergedNeighbour];
2496 aggregate_->invalidate();
2497 }else{
2498 ++avg;
2499 minA=min(minA,static_cast<std::size_t>(1));
2500 maxA=max(maxA,static_cast<std::size_t>(1));
2501 ++oneAggregates;
2502 ++conAggregates;
2503 }
2504 }else{
2505 ++avg;
2506 minA=min(minA,static_cast<std::size_t>(1));
2507 maxA=max(maxA,static_cast<std::size_t>(1));
2508 ++oneAggregates;
2509 ++isoAggregates;
2510 }
2511 ++avg;
2512 }else{
2513 avg+=aggregate_->size();
2514 minA=min(minA,aggregate_->size());
2515 maxA=max(maxA,aggregate_->size());
2516 if(graph.getVertexProperties(seed).isolated())
2517 ++isoAggregates;
2518 else
2519 ++conAggregates;
2520 }
2521
2522 }
2523
2524 Dune::dinfo<<"connected aggregates: "<<conAggregates;
2525 Dune::dinfo<<" isolated aggregates: "<<isoAggregates;
2526 if(conAggregates+isoAggregates>0)
2527 Dune::dinfo<<" one node aggregates: "<<oneAggregates<<" min size="
2528 <<minA<<" max size="<<maxA
2529 <<" avg="<<avg/(conAggregates+isoAggregates)<<std::endl;
2530
2531 delete aggregate_;
2532 return std::make_tuple(conAggregates+isoAggregates,isoAggregates,
2533 oneAggregates,skippedAggregates);
2534 }
2535
2536
2537 template<class G>
2538 Aggregator<G>::Stack::Stack(const MatrixGraph& graph, const Aggregator<G>& aggregatesBuilder,
2539 const AggregatesMap<Vertex>& aggregates)
2540 : graph_(graph), aggregatesBuilder_(aggregatesBuilder), aggregates_(aggregates), begin_(graph.begin()), end_(graph.end())
2541 {
2542 //vals_ = new Vertex[N];
2543 }
2544
2545 template<class G>
2546 Aggregator<G>::Stack::~Stack()
2547 {
2548 //Dune::dverb << "Max stack size was "<<maxSize_<<" filled="<<filled_<<std::endl;
2549 //delete[] vals_;
2550 }
2551
2552 template<class G>
2553 const typename Aggregator<G>::Vertex Aggregator<G>::Stack::NullEntry
2555
2556 template<class G>
2557 inline typename G::VertexDescriptor Aggregator<G>::Stack::pop()
2558 {
2559 for(; begin_!=end_ && aggregates_[*begin_] != AggregatesMap<Vertex>::UNAGGREGATED; ++begin_) ;
2560
2561 if(begin_!=end_)
2562 {
2563 typename G::VertexDescriptor current=*begin_;
2564 ++begin_;
2565 return current;
2566 }else
2567 return NullEntry;
2568 }
2569
2570#endif // DOXYGEN
2571
2572 template<class V>
2573 void printAggregates2d(const AggregatesMap<V>& aggregates, int n, int m, std::ostream& os)
2574 {
2575 using std::max;
2576
2577 std::ios_base::fmtflags oldOpts=os.flags();
2578
2579 os.setf(std::ios_base::right, std::ios_base::adjustfield);
2580
2581 V maxVal=0;
2582 int width=1;
2583
2584 for(int i=0; i< n*m; i++)
2585 maxVal=max(maxVal, aggregates[i]);
2586
2587 for(int i=10; i < 1000000; i*=10)
2588 if(maxVal/i>0)
2589 width++;
2590 else
2591 break;
2592
2593 for(int j=0, entry=0; j < m; j++) {
2594 for(int i=0; i<n; i++, entry++) {
2595 os.width(width);
2596 os<<aggregates[entry]<<" ";
2597 }
2598
2599 os<<std::endl;
2600 }
2601 os<<std::endl;
2602 os.flags(oldOpts);
2603 }
2604
2605
2606 } // namespace Amg
2607
2608} // namespace Dune
2609
2610
2611#endif
A class for temporarily storing the vertices of an aggregate in.
Definition: aggregates.hh:776
A Dummy visitor that does nothing for each visited edge.
Definition: aggregates.hh:594
Class providing information about the mapping of the vertices onto aggregates.
Definition: aggregates.hh:556
Base class of all aggregation criterions.
Definition: aggregates.hh:48
Class for building the aggregates.
Definition: aggregates.hh:907
Dependency policy for symmetric matrices.
Definition: aggregates.hh:252
Norm that uses only the [N][N] entry of the block to determine couplings.
Definition: aggregates.hh:375
Norm that uses only the [0][0] entry of the block to determine couplings.
Definition: aggregates.hh:451
Iterator over all edges starting from a vertex.
Definition: graph.hh:93
The vertex iterator type of the graph.
Definition: graph.hh:207
The (undirected) graph of a matrix.
Definition: graph.hh:49
M::size_type VertexDescriptor
The vertex descriptor.
Definition: graph.hh:71
EdgeIteratorT< const MatrixGraph< Matrix > > ConstEdgeIterator
The constant edge iterator type.
Definition: graph.hh:296
All parameters for AMG.
Definition: parameters.hh:391
Criterion taking advantage of symmetric matrices.
Definition: aggregates.hh:515
Dependency policy for symmetric matrices.
Definition: aggregates.hh:313
Dependency policy for symmetric matrices.
Definition: aggregates.hh:133
Criterion suitable for unsymmetric matrices.
Definition: aggregates.hh:535
derive error class from the base class in common
Definition: istlexception.hh:16
A generic dynamic dense matrix.
Definition: matrix.hh:558
typename Imp::BlockTraits< T >::field_type field_type
Export the type representing the underlying field.
Definition: matrix.hh:562
row_type::const_iterator ConstColIterator
Const iterator for the entries of each row.
Definition: matrix.hh:586
MatrixImp::DenseMatrixBase< T, A >::window_type row_type
The type implementing a matrix row.
Definition: matrix.hh:571
An allocator managing a pool of objects for reuse.
Definition: poolallocator.hh:223
A single linked list.
Definition: sllist.hh:42
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:72
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:25
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
constexpr GeometryType vertex
GeometryType representing a vertex.
Definition: type.hh:797
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:272
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:153
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:582
int id()
Get the id identifying the aggregate.
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:301
MatrixGraph::VertexDescriptor Vertex
The vertex identifier.
Definition: aggregates.hh:918
AggregationCriterion()
Constructor.
Definition: aggregates.hh:65
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:356
auto operator()(const M &m, typename std::enable_if_t< Dune::IsNumber< M >::value > *sfinae=nullptr) const
Compute the norm of a scalar.
Definition: aggregates.hh:402
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:257
G MatrixGraph
The matrix graph type used.
Definition: aggregates.hh:913
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:362
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:318
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:186
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:262
int row_
index of the currently evaluated row.
Definition: aggregates.hh:184
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:328
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:295
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:333
~AggregatesMap()
Destructor.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:178
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:1062
std::size_t * SphereMap
Type of the mapping of aggregate members onto distance spheres.
Definition: aggregates.hh:807
Matrix::row_type Row
Constant Row iterator of the matrix.
Definition: aggregates.hh:267
VertexSet::size_type connectSize()
Get tne number of connections to other aggregates.
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:323
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:182
VertexSet::const_iterator const_iterator
Const iterator over a vertex list.
Definition: aggregates.hh:802
MatrixGraph::VertexDescriptor AggregateDescriptor
The type of the aggregate descriptor.
Definition: aggregates.hh:921
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:366
~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:54
Aggregator()
Constructor.
void operator()(const typename MatrixGraph::ConstEdgeIterator &edge)
Examine an edge.
FrontMarker(std::vector< Vertex > &front, MatrixGraph &graph)
Constructor.
FieldTraits< typenameM::field_type >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:502
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:81
V AggregateDescriptor
The aggregate descriptor type.
Definition: aggregates.hh:576
static const V ISOLATED
Identifier of isolated vertices.
Definition: aggregates.hh:567
int row_
index of the currently evaluated row.
Definition: aggregates.hh:364
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:305
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:104
AggregatesMap(std::size_t noVertices)
Constructs with allocating memory.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:358
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:588
ConnectivityCounter(const VertexSet &connected, const AggregatesMap< Vertex > &aggregates)
Constructor.
VertexSet::size_type size()
Get the size of the aggregate.
const_iterator end() const
get an iterator over the vertices of the aggregate.
int row_
index of the currently evaluated row.
Definition: aggregates.hh:303
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:138
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:176
S VertexSet
The type of a single linked list of vertex descriptors.
Definition: aggregates.hh:799
FieldTraits< typenameM::field_type >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:486
static const V UNAGGREGATED
Identifier of not yet aggregated vertices.
Definition: aggregates.hh:562
std::size_t breadthFirstSearch(const VertexDescriptor &start, const AggregateDescriptor &aggregate, const G &graph, F &aggregateVisitor, VM &visitedMap) const
Breadth first search within an aggregate.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:297
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:143
FieldTraits< typenameM::field_type >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:469
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:386
MatrixGraph::VertexDescriptor Vertex
The vertex descriptor type.
Definition: aggregates.hh:787
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:571
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:148
PoolAllocator< Vertex, 100 > Allocator
The allocator we use for our lists and the set.
Definition: aggregates.hh:793
auto min(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::min()
Definition: defaults.hh:87
auto max(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::max()
Definition: defaults.hh:79
DVVerbType dvverb(std::cout)
stream for very verbose output.
Definition: stdstreams.hh:93
DInfoType dinfo(std::cout)
Stream for informative output.
Definition: stdstreams.hh:138
DVerbType dverb(std::cout)
Singleton of verbose debug stream.
Definition: stdstreams.hh:114
constexpr Front front
PartitionSet for the front partition.
Definition: partitionset.hh:279
Dune namespace.
Definition: alignedallocator.hh:14
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:459
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition: typetraits.hh:163
A simple timing class.
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Oct 13, 22:30, 2024)