DUNE-FEM (unstable)

aggregates.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4// vi: set et ts=4 sw=2 sts=2:
5#ifndef DUNE_AMG_AGGREGATES_HH
6#define DUNE_AMG_AGGREGATES_HH
7
8
9#include "parameters.hh"
10#include "graph.hh"
11#include "properties.hh"
12#include "combinedfunctor.hh"
13
14#include <dune/common/timer.hh>
17#include <dune/common/sllist.hh>
20
21#include <utility>
22#include <set>
23#include <algorithm>
24#include <complex>
25#include <limits>
26#include <ostream>
27#include <tuple>
28
29namespace Dune
30{
31 namespace Amg
32 {
33
47 template<class T>
48 class AggregationCriterion : public T
49 {
50
51 public:
56
67 : T()
68 {}
69
71 : T(parms)
72 {}
82 void setDefaultValuesIsotropic(std::size_t dim, std::size_t diameter=2)
83 {
84 this->setMaxDistance(diameter-1);
85 std::size_t csize=1;
86
87 for(; dim>0; dim--) {
88 csize*=diameter;
89 this->setMaxDistance(this->maxDistance()+diameter-1);
90 }
91 this->setMinAggregateSize(csize);
92 this->setMaxAggregateSize(static_cast<std::size_t>(csize*1.5));
93 }
94
105 void setDefaultValuesAnisotropic(std::size_t dim,std::size_t diameter=2)
106 {
107 setDefaultValuesIsotropic(dim, diameter);
108 this->setMaxDistance(this->maxDistance()+dim-1);
109 }
110 };
111
112 template<class T>
113 std::ostream& operator<<(std::ostream& os, const AggregationCriterion<T>& criterion)
114 {
115 os<<"{ maxdistance="<<criterion.maxDistance()<<" minAggregateSize="
116 <<criterion.minAggregateSize()<< " maxAggregateSize="<<criterion.maxAggregateSize()
117 <<" connectivity="<<criterion.maxConnectivity()<<" debugLevel="<<criterion.debugLevel()<<"}";
118 return os;
119 }
120
132 template<class M, class N>
134 {
135 public:
139 typedef M Matrix;
140
144 typedef N Norm;
145
149 typedef typename Matrix::row_type Row;
150
155
156 void init(const Matrix* matrix);
157
158 void initRow(const Row& row, int index);
159
160 void examine(const ColIter& col);
161
162 template<class G>
163 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
164
165 bool isIsolated();
166
167
169 : Parameters(parms)
170 {}
172 : Parameters()
173 {}
174
175 protected:
180 typedef typename FieldTraits<field_type>::real_type real_type;
181 real_type maxValue_;
185 int row_;
187 real_type diagonal_;
188 std::vector<real_type> vals_;
189 typename std::vector<real_type>::iterator valIter_;
190
191 };
192
193
194 template<class M, class N>
195 inline void SymmetricMatrixDependency<M,N>::init(const Matrix* matrix)
196 {
197 matrix_ = matrix;
198 }
199
200 template<class M, class N>
201 inline void SymmetricMatrixDependency<M,N>::initRow(const Row& row, int index)
202 {
203 using std::min;
204 vals_.assign(row.size(), 0.0);
205 assert(vals_.size()==row.size());
206 valIter_=vals_.begin();
207
209 diagonal_=norm_(row[index]);
210 row_ = index;
211 }
212
213 template<class M, class N>
214 inline void SymmetricMatrixDependency<M,N>::examine(const ColIter& col)
215 {
216 using std::max;
217 // skip positive offdiagonals if norm preserves sign of them.
218 real_type eij = norm_(*col);
219 if(!N::is_sign_preserving || eij<0) // || eji<0)
220 {
221 *valIter_ = eij/diagonal_*eij/norm_(matrix_->operator[](col.index())[col.index()]);
222 maxValue_ = max(maxValue_, *valIter_);
223 }else
224 *valIter_ =0;
225 ++valIter_;
226 }
227
228 template<class M, class N>
229 template<class G>
230 inline void SymmetricMatrixDependency<M,N>::examine(G&, const typename G::EdgeIterator& edge, const ColIter&)
231 {
232 if(*valIter_ > alpha() * maxValue_) {
233 edge.properties().setDepends();
234 edge.properties().setInfluences();
235 }
236 ++valIter_;
237 }
238
239 template<class M, class N>
240 inline bool SymmetricMatrixDependency<M,N>::isIsolated()
241 {
242 if(diagonal_==0)
243 DUNE_THROW(Dune::ISTLError, "No diagonal entry for row "<<row_<<".");
244 valIter_=vals_.begin();
245 return maxValue_ < beta();
246 }
247
251 template<class M, class N>
252 class Dependency : public Parameters
253 {
254 public:
258 typedef M Matrix;
259
263 typedef N Norm;
264
268 typedef typename Matrix::row_type Row;
269
274
275 void init(const Matrix* matrix);
276
277 void initRow(const Row& row, int index);
278
279 void examine(const ColIter& col);
280
281 template<class G>
282 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
283
284 bool isIsolated();
285
286 Dependency(const Parameters& parms)
287 : Parameters(parms)
288 {}
289
290 Dependency()
291 : Parameters()
292 {}
293
294 protected:
299 typedef typename FieldTraits<field_type>::real_type real_type;
300 real_type maxValue_;
304 int row_;
306 real_type diagonal_;
307 };
308
312 template<class M, class N>
314 {
315 public:
319 typedef M Matrix;
320
324 typedef N Norm;
325
329 typedef typename Matrix::row_type Row;
330
335
336 void init(const Matrix* matrix);
337
338 void initRow(const Row& row, int index);
339
340 void examine(const ColIter& col);
341
342 template<class G>
343 void examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col);
344
345 bool isIsolated();
346
347
348 SymmetricDependency(const Parameters& parms)
349 : Parameters(parms)
350 {}
352 : Parameters()
353 {}
354
355 protected:
360 typedef typename FieldTraits<field_type>::real_type real_type;
361 real_type maxValue_;
365 int row_;
367 real_type diagonal_;
368 private:
369 void initRow(const Row& row, int index, const std::true_type&);
370 void initRow(const Row& row, int index, const std::false_type&);
371 };
372
377 template<int N>
379 {
380 public:
381 enum { /* @brief We preserve the sign.*/
382 is_sign_preserving = true
383 };
384
389 template<class M>
390 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m,
391 [[maybe_unused]] typename std::enable_if_t<!Dune::IsNumber<M>::value>* sfinae = nullptr) const
392 {
393 typedef typename M::field_type field_type;
394 typedef typename FieldTraits<field_type>::real_type real_type;
395 static_assert( std::is_convertible<field_type, real_type >::value,
396 "use of diagonal norm in AMG not implemented for complex field_type");
397 return m[N][N];
398 // possible implementation for complex types: return signed_abs(m[N][N]);
399 }
400
405 template<class M>
406 auto operator()(const M& m,
407 typename std::enable_if_t<Dune::IsNumber<M>::value>* sfinae = nullptr) const
408 {
409 typedef typename FieldTraits<M>::real_type real_type;
410 static_assert( std::is_convertible<M, real_type >::value,
411 "use of diagonal norm in AMG not implemented for complex field_type");
412 return m;
413 // possible implementation for complex types: return signed_abs(m[N][N]);
414 }
415
416 private:
417
419 template<typename T>
420 static T signed_abs(const T & v)
421 {
422 return v;
423 }
424
426 template<typename T>
427 static T signed_abs(const std::complex<T> & v)
428 {
429 // return sign * abs_value
430 // in case of complex numbers this extends to using the csgn function to determine the sign
431 return csgn(v) * std::abs(v);
432 }
433
435 template<typename T>
436 static T csgn(const T & v)
437 {
438 return (T(0) < v) - (v < T(0));
439 }
440
442 template<typename T>
443 static T csgn(std::complex<T> a)
444 {
445 return csgn(a.real())+(a.real() == 0.0)*csgn(a.imag());
446 }
447
448 };
449
454 class FirstDiagonal : public Diagonal<0>
455 {};
456
462 struct RowSum
463 {
464
465 enum { /* @brief We preserve the sign.*/
466 is_sign_preserving = false
467 };
472 template<class M>
473 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
474 {
475 return m.infinity_norm();
476 }
477 };
478
479 struct FrobeniusNorm
480 {
481
482 enum { /* @brief We preserve the sign.*/
483 is_sign_preserving = false
484 };
489 template<class M>
490 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
491 {
492 return m.frobenius_norm();
493 }
494 };
495 struct AlwaysOneNorm
496 {
497
498 enum { /* @brief We preserve the sign.*/
499 is_sign_preserving = false
500 };
505 template<class M>
506 typename FieldTraits<typename M::field_type>::real_type operator()(const M& m) const
507 {
508 return 1;
509 }
510 };
517 template<class M, class Norm>
518 class SymmetricCriterion : public AggregationCriterion<SymmetricDependency<M,Norm> >
519 {
520 public:
521 SymmetricCriterion(const Parameters& parms)
523 {}
525 {}
526 };
527
528
537 template<class M, class Norm>
538 class UnSymmetricCriterion : public AggregationCriterion<Dependency<M,Norm> >
539 {
540 public:
541 UnSymmetricCriterion(const Parameters& parms)
543 {}
545 {}
546 };
547 // forward declaration
548 template<class G> class Aggregator;
549
550
558 template<class V>
560 {
561 public:
562
566 static const V UNAGGREGATED;
567
571 static const V ISOLATED;
576
581
587
593
598 {
599 public:
600 template<class EdgeIterator>
601 void operator()([[maybe_unused]] const EdgeIterator& edge) const
602 {}
603 };
604
605
610
617
622
634 template<class M, class G, class C>
635 std::tuple<int,int,int,int> buildAggregates(const M& matrix, G& graph, const C& criterion,
636 bool finestLevel);
637
655 template<bool reset, class G, class F, class VM>
656 std::size_t breadthFirstSearch(const VertexDescriptor& start,
657 const AggregateDescriptor& aggregate,
658 const G& graph,
659 F& aggregateVisitor,
660 VM& visitedMap) const;
661
685 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
686 std::size_t breadthFirstSearch(const VertexDescriptor& start,
687 const AggregateDescriptor& aggregate,
688 const G& graph, L& visited, F1& aggregateVisitor,
689 F2& nonAggregateVisitor,
690 VM& visitedMap) const;
691
697 void allocate(std::size_t noVertices);
698
702 std::size_t noVertices() const;
703
707 void free();
708
715
722
723 typedef const AggregateDescriptor* const_iterator;
724
725 const_iterator begin() const
726 {
727 return aggregates_;
728 }
729
730 const_iterator end() const
731 {
732 return aggregates_+noVertices();
733 }
734
735 typedef AggregateDescriptor* iterator;
736
737 iterator begin()
738 {
739 return aggregates_;
740 }
741
742 iterator end()
743 {
744 return aggregates_+noVertices();
745 }
746 private:
748 AggregatesMap(const AggregatesMap<V>&) = delete;
750 AggregatesMap<V>& operator=(const AggregatesMap<V>&) = delete;
751
755 AggregateDescriptor* aggregates_;
756
760 std::size_t noVertices_;
761 };
762
766 template<class G, class C>
767 void buildDependency(G& graph,
768 const typename C::Matrix& matrix,
769 C criterion,
770 bool finestLevel);
771
776 template<class G, class S>
778 {
779
780 public:
781
782 /***
783 * @brief The type of the matrix graph we work with.
784 */
785 typedef G MatrixGraph;
790
796
801 typedef S VertexSet;
802
804 typedef typename VertexSet::const_iterator const_iterator;
805
809 typedef std::size_t* SphereMap;
810
819 Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
820 VertexSet& connectivity, std::vector<Vertex>& front_);
821
822 void invalidate()
823 {
824 --id_;
825 }
826
834
838 void seed(const Vertex& vertex);
839
843 void add(const Vertex& vertex);
844
845 void add(std::vector<Vertex>& vertex);
849 void clear();
850
854 typename VertexSet::size_type size();
858 typename VertexSet::size_type connectSize();
859
863 int id();
864
867
870
871 private:
875 VertexSet vertices_;
876
881 int id_;
882
886 MatrixGraph& graph_;
887
891 AggregatesMap<Vertex>& aggregates_;
892
896 VertexSet& connected_;
897
901 std::vector<Vertex>& front_;
902 };
903
907 template<class G>
909 {
910 public:
911
915 typedef G MatrixGraph;
916
921
924
929
934
951 template<class M, class C>
952 std::tuple<int,int,int,int> build(const M& m, G& graph,
953 AggregatesMap<Vertex>& aggregates, const C& c,
954 bool finestLevel);
955 private:
961
966
970 typedef std::set<Vertex,std::less<Vertex>,Allocator> VertexSet;
971
975 typedef std::size_t* SphereMap;
976
980 MatrixGraph* graph_;
981
986
990 std::vector<Vertex> front_;
991
995 VertexSet connected_;
996
1000 int size_;
1001
1005 class Stack
1006 {
1007 public:
1008 static const Vertex NullEntry;
1009
1010 Stack(const MatrixGraph& graph,
1011 const Aggregator<G>& aggregatesBuilder,
1012 const AggregatesMap<Vertex>& aggregates);
1013 ~Stack();
1014 Vertex pop();
1015 private:
1016 enum { N = 1300000 };
1017
1019 const MatrixGraph& graph_;
1021 const Aggregator<G>& aggregatesBuilder_;
1023 const AggregatesMap<Vertex>& aggregates_;
1025 int size_;
1026 Vertex maxSize_;
1028 typename MatrixGraph::ConstVertexIterator begin_;
1030
1032 Vertex* vals_;
1033
1034 };
1035
1036 friend class Stack;
1037
1048 template<class V>
1049 void visitAggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate,
1050 const AggregatesMap<Vertex>& aggregates,
1051 V& visitor) const;
1052
1057 template<class V>
1058 class AggregateVisitor
1059 {
1060 public:
1064 typedef V Visitor;
1073 Visitor& visitor);
1074
1081 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1082
1083 private:
1085 const AggregatesMap<Vertex>& aggregates_;
1087 AggregateDescriptor aggregate_;
1089 Visitor* visitor_;
1090 };
1091
1095 class Counter
1096 {
1097 public:
1101 int value();
1102
1103 protected:
1108
1109 private:
1110 int count_;
1111 };
1112
1113
1118 class FrontNeighbourCounter : public Counter
1119 {
1120 public:
1126
1127 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1128
1129 private:
1130 const MatrixGraph& graph_;
1131 };
1132
1137 int noFrontNeighbours(const Vertex& vertex) const;
1138
1142 class TwoWayCounter : public Counter
1143 {
1144 public:
1145 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1146 };
1147
1159 int twoWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1160 const AggregatesMap<Vertex>& aggregates) const;
1161
1165 class OneWayCounter : public Counter
1166 {
1167 public:
1168 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1169 };
1170
1182 int oneWayConnections(const Vertex&, const AggregateDescriptor& aggregate,
1183 const AggregatesMap<Vertex>& aggregates) const;
1184
1191 class ConnectivityCounter : public Counter
1192 {
1193 public:
1200 ConnectivityCounter(const VertexSet& connected, const AggregatesMap<Vertex>& aggregates);
1201
1202 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1203
1204 private:
1206 const VertexSet& connected_;
1208 const AggregatesMap<Vertex>& aggregates_;
1209
1210 };
1211
1223 double connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1231 bool connected(const Vertex& vertex, const AggregateDescriptor& aggregate,
1232 const AggregatesMap<Vertex>& aggregates) const;
1233
1241 bool connected(const Vertex& vertex, const SLList<AggregateDescriptor>& aggregateList,
1242 const AggregatesMap<Vertex>& aggregates) const;
1243
1251 class DependencyCounter : public Counter
1252 {
1253 public:
1258
1259 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1260 };
1261
1268 class FrontMarker
1269 {
1270 public:
1277 FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph);
1278
1279 void operator()(const typename MatrixGraph::ConstEdgeIterator& edge);
1280
1281 private:
1283 std::vector<Vertex>& front_;
1285 MatrixGraph& graph_;
1286 };
1287
1291 void unmarkFront();
1292
1307 int unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1308
1322 std::pair<int,int> neighbours(const Vertex& vertex,
1323 const AggregateDescriptor& aggregate,
1324 const AggregatesMap<Vertex>& aggregates) const;
1341 int aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1342
1350 bool admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const;
1351
1359 std::size_t distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates);
1360
1369 Vertex mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const;
1370
1379 void nonisoNeighbourAggregate(const Vertex& vertex,
1380 const AggregatesMap<Vertex>& aggregates,
1381 SLList<Vertex>& neighbours) const;
1382
1390 template<class C>
1391 void growAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1392 template<class C>
1393 void growIsolatedAggregate(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates, const C& c);
1394 };
1395
1396#ifndef DOXYGEN
1397
1398 template<class M, class N>
1399 inline void SymmetricDependency<M,N>::init(const Matrix* matrix)
1400 {
1401 matrix_ = matrix;
1402 }
1403
1404 template<class M, class N>
1405 inline void SymmetricDependency<M,N>::initRow(const Row& row, int index)
1406 {
1407 initRow(row, index, std::is_convertible<field_type, real_type>());
1408 }
1409
1410 template<class M, class N>
1411 inline void SymmetricDependency<M,N>::initRow(const Row& row, int index, const std::false_type&)
1412 {
1413 DUNE_THROW(InvalidStateException, "field_type needs to convertible to real_type");
1414 }
1415
1416 template<class M, class N>
1417 inline void SymmetricDependency<M,N>::initRow([[maybe_unused]] const Row& row, int index, const std::true_type&)
1418 {
1419 using std::min;
1421 row_ = index;
1422 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1423 }
1424
1425 template<class M, class N>
1426 inline void SymmetricDependency<M,N>::examine(const ColIter& col)
1427 {
1428 using std::max;
1429 real_type eij = norm_(*col);
1430 typename Matrix::ConstColIterator opposite_entry =
1431 matrix_->operator[](col.index()).find(row_);
1432 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1433 {
1434 // Consider this a weak connection we disregard.
1435 return;
1436 }
1437 real_type eji = norm_(*opposite_entry);
1438
1439 // skip positive offdiagonals if norm preserves sign of them.
1440 if(!N::is_sign_preserving || eij<0 || eji<0)
1441 maxValue_ = max(maxValue_,
1442 eij /diagonal_ * eji/
1443 norm_(matrix_->operator[](col.index())[col.index()]));
1444 }
1445
1446 template<class M, class N>
1447 template<class G>
1448 inline void SymmetricDependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1449 {
1450 real_type eij = norm_(*col);
1451 typename Matrix::ConstColIterator opposite_entry =
1452 matrix_->operator[](col.index()).find(row_);
1453
1454 if ( opposite_entry == matrix_->operator[](col.index()).end() )
1455 {
1456 // Consider this as a weak connection we disregard.
1457 return;
1458 }
1459 real_type eji = norm_(*opposite_entry);
1460 // skip positive offdiagonals if norm preserves sign of them.
1461 if(!N::is_sign_preserving || (eij<0 || eji<0))
1462 if(eji / norm_(matrix_->operator[](edge.target())[edge.target()]) *
1463 eij/ diagonal_ > alpha() * maxValue_) {
1464 edge.properties().setDepends();
1465 edge.properties().setInfluences();
1466 typename G::EdgeProperties& other = graph.getEdgeProperties(edge.target(), edge.source());
1467 other.setInfluences();
1468 other.setDepends();
1469 }
1470 }
1471
1472 template<class M, class N>
1473 inline bool SymmetricDependency<M,N>::isIsolated()
1474 {
1475 return maxValue_ < beta();
1476 }
1477
1478
1479 template<class M, class N>
1480 inline void Dependency<M,N>::init(const Matrix* matrix)
1481 {
1482 matrix_ = matrix;
1483 }
1484
1485 template<class M, class N>
1486 inline void Dependency<M,N>::initRow([[maybe_unused]] const Row& row, int index)
1487 {
1488 using std::min;
1490 row_ = index;
1491 diagonal_ = norm_(matrix_->operator[](row_)[row_]);
1492 }
1493
1494 template<class M, class N>
1495 inline void Dependency<M,N>::examine(const ColIter& col)
1496 {
1497 using std::max;
1498 maxValue_ = max(maxValue_, -norm_(*col));
1499 }
1500
1501 template<class M, class N>
1502 template<class G>
1503 inline void Dependency<M,N>::examine(G& graph, const typename G::EdgeIterator& edge, const ColIter& col)
1504 {
1505 if(-norm_(*col) >= maxValue_ * alpha()) {
1506 edge.properties().setDepends();
1507 typedef typename G::EdgeDescriptor ED;
1508 ED e= graph.findEdge(edge.target(), edge.source());
1510 {
1511 typename G::EdgeProperties& other = graph.getEdgeProperties(e);
1512 other.setInfluences();
1513 }
1514 }
1515 }
1516
1517 template<class M, class N>
1518 inline bool Dependency<M,N>::isIsolated()
1519 {
1520 return maxValue_ < beta() * diagonal_;
1521 }
1522
1523 template<class G,class S>
1524 Aggregate<G,S>::Aggregate(MatrixGraph& graph, AggregatesMap<Vertex>& aggregates,
1525 VertexSet& connected, std::vector<Vertex>& front)
1526 : vertices_(), id_(-1), graph_(graph), aggregates_(aggregates),
1527 connected_(connected), front_(front)
1528 {}
1529
1530 template<class G,class S>
1532 {
1533 /*
1534 vertices_.push_back(vertex);
1535 typedef typename VertexList::const_iterator iterator;
1536 iterator begin = vertices_.begin();
1537 iterator end = vertices_.end();*/
1538 throw "Not yet implemented";
1539
1540 // while(begin!=end){
1541 //for();
1542 // }
1543
1544 }
1545
1546 template<class G,class S>
1547 inline void Aggregate<G,S>::seed(const Vertex& vertex)
1548 {
1549 dvverb<<"Connected cleared"<<std::endl;
1550 connected_.clear();
1551 vertices_.clear();
1552 connected_.insert(vertex);
1553 dvverb << " Inserting "<<vertex<<" size="<<connected_.size();
1554 ++id_ ;
1555 add(vertex);
1556 }
1557
1558
1559 template<class G,class S>
1560 inline void Aggregate<G,S>::add(const Vertex& vertex)
1561 {
1562 vertices_.insert(vertex);
1563 aggregates_[vertex]=id_;
1564 if(front_.size())
1565 front_.erase(std::lower_bound(front_.begin(), front_.end(), vertex));
1566
1567
1568 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1569 const iterator end = graph_.endEdges(vertex);
1570 for(iterator edge = graph_.beginEdges(vertex); edge != end; ++edge) {
1571 dvverb << " Inserting "<<aggregates_[edge.target()];
1572 connected_.insert(aggregates_[edge.target()]);
1573 dvverb <<" size="<<connected_.size();
1574 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1575 !graph_.getVertexProperties(edge.target()).front())
1576 {
1577 front_.push_back(edge.target());
1578 graph_.getVertexProperties(edge.target()).setFront();
1579 }
1580 }
1581 dvverb <<std::endl;
1582 std::sort(front_.begin(), front_.end());
1583 }
1584
1585 template<class G,class S>
1586 inline void Aggregate<G,S>::add(std::vector<Vertex>& vertices)
1587 {
1588#ifndef NDEBUG
1589 std::size_t oldsize = vertices_.size();
1590#endif
1591 typedef typename std::vector<Vertex>::iterator Iterator;
1592
1593 typedef typename VertexSet::iterator SIterator;
1594
1595 SIterator pos=vertices_.begin();
1596 std::vector<Vertex> newFront;
1597 newFront.reserve(front_.capacity());
1598
1599 std::set_difference(front_.begin(), front_.end(), vertices.begin(), vertices.end(),
1600 std::back_inserter(newFront));
1601 front_=newFront;
1602
1603 for(Iterator vertex=vertices.begin(); vertex != vertices.end(); ++vertex)
1604 {
1605 pos=vertices_.insert(pos,*vertex);
1606 vertices_.insert(*vertex);
1607 graph_.getVertexProperties(*vertex).resetFront(); // Not a front node any more.
1608 aggregates_[*vertex]=id_;
1609
1610 typedef typename MatrixGraph::ConstEdgeIterator iterator;
1611 const iterator end = graph_.endEdges(*vertex);
1612 for(iterator edge = graph_.beginEdges(*vertex); edge != end; ++edge) {
1613 dvverb << " Inserting "<<aggregates_[edge.target()];
1614 connected_.insert(aggregates_[edge.target()]);
1615 if(aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED &&
1616 !graph_.getVertexProperties(edge.target()).front())
1617 {
1618 front_.push_back(edge.target());
1619 graph_.getVertexProperties(edge.target()).setFront();
1620 }
1621 dvverb <<" size="<<connected_.size();
1622 }
1623 dvverb <<std::endl;
1624 }
1625 std::sort(front_.begin(), front_.end());
1626 assert(oldsize+vertices.size()==vertices_.size());
1627 }
1628 template<class G,class S>
1629 inline void Aggregate<G,S>::clear()
1630 {
1631 vertices_.clear();
1632 connected_.clear();
1633 id_=-1;
1634 }
1635
1636 template<class G,class S>
1637 inline typename Aggregate<G,S>::VertexSet::size_type
1639 {
1640 return vertices_.size();
1641 }
1642
1643 template<class G,class S>
1644 inline typename Aggregate<G,S>::VertexSet::size_type
1646 {
1647 return connected_.size();
1648 }
1649
1650 template<class G,class S>
1651 inline int Aggregate<G,S>::id()
1652 {
1653 return id_;
1654 }
1655
1656 template<class G,class S>
1658 {
1659 return vertices_.begin();
1660 }
1661
1662 template<class G,class S>
1664 {
1665 return vertices_.end();
1666 }
1667
1668 template<class V>
1670
1671 template<class V>
1673
1674 template<class V>
1676 : aggregates_(0)
1677 {}
1678
1679 template<class V>
1681 {
1682 if(aggregates_!=0)
1683 delete[] aggregates_;
1684 }
1685
1686
1687 template<class V>
1688 inline AggregatesMap<V>::AggregatesMap(std::size_t noVertices)
1689 {
1690 allocate(noVertices);
1691 }
1692
1693 template<class V>
1694 inline std::size_t AggregatesMap<V>::noVertices() const
1695 {
1696 return noVertices_;
1697 }
1698
1699 template<class V>
1700 inline void AggregatesMap<V>::allocate(std::size_t noVertices)
1701 {
1702 aggregates_ = new AggregateDescriptor[noVertices];
1703 noVertices_ = noVertices;
1704
1705 for(std::size_t i=0; i < noVertices; i++)
1706 aggregates_[i]=UNAGGREGATED;
1707 }
1708
1709 template<class V>
1710 inline void AggregatesMap<V>::free()
1711 {
1712 assert(aggregates_ != 0);
1713 delete[] aggregates_;
1714 aggregates_=0;
1715 }
1716
1717 template<class V>
1719 AggregatesMap<V>::operator[](const VertexDescriptor& v)
1720 {
1721 return aggregates_[v];
1722 }
1723
1724 template<class V>
1725 inline const typename AggregatesMap<V>::AggregateDescriptor&
1726 AggregatesMap<V>::operator[](const VertexDescriptor& v) const
1727 {
1728 return aggregates_[v];
1729 }
1730
1731 template<class V>
1732 template<bool reset, class G, class F,class VM>
1733 inline std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1734 const AggregateDescriptor& aggregate,
1735 const G& graph, F& aggregateVisitor,
1736 VM& visitedMap) const
1737 {
1738 VertexList vlist;
1739
1740 DummyEdgeVisitor dummy;
1741 return breadthFirstSearch<true,reset>(start, aggregate, graph, vlist, aggregateVisitor, dummy, visitedMap);
1742 }
1743
1744 template<class V>
1745 template<bool remove, bool reset, class G, class L, class F1, class F2, class VM>
1746 std::size_t AggregatesMap<V>::breadthFirstSearch(const V& start,
1747 const AggregateDescriptor& aggregate,
1748 const G& graph,
1749 L& visited,
1750 F1& aggregateVisitor,
1751 F2& nonAggregateVisitor,
1752 VM& visitedMap) const
1753 {
1754 typedef typename L::const_iterator ListIterator;
1755 int visitedSpheres = 0;
1756
1757 visited.push_back(start);
1758 put(visitedMap, start, true);
1759
1760 ListIterator current = visited.begin();
1761 ListIterator end = visited.end();
1762 std::size_t i=0, size=visited.size();
1763
1764 // visit the neighbours of all vertices of the
1765 // current sphere.
1766 while(current != end) {
1767
1768 for(; i<size; ++current, ++i) {
1769 typedef typename G::ConstEdgeIterator EdgeIterator;
1770 const EdgeIterator endEdge = graph.endEdges(*current);
1771
1772 for(EdgeIterator edge = graph.beginEdges(*current);
1773 edge != endEdge; ++edge) {
1774
1775 if(aggregates_[edge.target()]==aggregate) {
1776 if(!get(visitedMap, edge.target())) {
1777 put(visitedMap, edge.target(), true);
1778 visited.push_back(edge.target());
1779 aggregateVisitor(edge);
1780 }
1781 }else
1782 nonAggregateVisitor(edge);
1783 }
1784 }
1785 end = visited.end();
1786 size = visited.size();
1787 if(current != end)
1788 visitedSpheres++;
1789 }
1790
1791 if(reset)
1792 for(current = visited.begin(); current != end; ++current)
1793 put(visitedMap, *current, false);
1794
1795
1796 if(remove)
1797 visited.clear();
1798
1799 return visitedSpheres;
1800 }
1801
1802 template<class G>
1804 : graph_(0), aggregate_(0), front_(), connected_(), size_(-1)
1805 {}
1806
1807 template<class G>
1809 {
1810 size_=-1;
1811 }
1812
1813 template<class G, class C>
1814 void buildDependency(G& graph,
1815 const typename C::Matrix& matrix,
1816 C criterion, bool firstlevel)
1817 {
1818 // assert(graph.isBuilt());
1819 typedef typename C::Matrix Matrix;
1820 typedef typename G::VertexIterator VertexIterator;
1821
1822 criterion.init(&matrix);
1823
1824 for(VertexIterator vertex = graph.begin(); vertex != graph.end(); ++vertex) {
1825 typedef typename Matrix::row_type Row;
1826
1827 const Row& row = matrix[*vertex];
1828
1829 // Tell the criterion what row we will examine now
1830 // This might for example be used for calculating the
1831 // maximum offdiagonal value
1832 criterion.initRow(row, *vertex);
1833
1834 // On a first path all columns are examined. After this
1835 // the calculator should know whether the vertex is isolated.
1836 typedef typename Matrix::ConstColIterator ColIterator;
1837 ColIterator end = row.end();
1838 typename FieldTraits<typename Matrix::field_type>::real_type absoffdiag=0.;
1839
1840 using std::max;
1841 if(firstlevel) {
1842 for(ColIterator col = row.begin(); col != end; ++col)
1843 if(col.index()!=*vertex) {
1844 criterion.examine(col);
1845 absoffdiag = max(absoffdiag, Impl::asMatrix(*col).frobenius_norm());
1846 }
1847
1848 if(absoffdiag==0)
1849 vertex.properties().setExcludedBorder();
1850 }
1851 else
1852 for(ColIterator col = row.begin(); col != end; ++col)
1853 if(col.index()!=*vertex)
1854 criterion.examine(col);
1855
1856 // reset the vertex properties
1857 //vertex.properties().reset();
1858
1859 // Check whether the vertex is isolated.
1860 if(criterion.isIsolated()) {
1861 //std::cout<<"ISOLATED: "<<*vertex<<std::endl;
1862 vertex.properties().setIsolated();
1863 }else{
1864 // Examine all the edges beginning at this vertex.
1865 auto eEnd = vertex.end();
1866 auto col = matrix[*vertex].begin();
1867
1868 for(auto edge = vertex.begin(); edge!= eEnd; ++edge, ++col) {
1869 // Move to the right column.
1870 while(col.index()!=edge.target())
1871 ++col;
1872 criterion.examine(graph, edge, col);
1873 }
1874 }
1875
1876 }
1877 }
1878
1879
1880 template<class G>
1881 template<class V>
1882 inline Aggregator<G>::AggregateVisitor<V>::AggregateVisitor(const AggregatesMap<Vertex>& aggregates,
1883 const AggregateDescriptor& aggregate, V& visitor)
1884 : aggregates_(aggregates), aggregate_(aggregate), visitor_(&visitor)
1885 {}
1886
1887 template<class G>
1888 template<class V>
1889 inline void Aggregator<G>::AggregateVisitor<V>::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1890 {
1891 if(aggregates_[edge.target()]==aggregate_)
1892 visitor_->operator()(edge);
1893 }
1894
1895 template<class G>
1896 template<class V>
1897 inline void Aggregator<G>::visitAggregateNeighbours(const Vertex& vertex,
1898 const AggregateDescriptor& aggregate,
1899 const AggregatesMap<Vertex>& aggregates,
1900 V& visitor) const
1901 {
1902 // Only evaluates for edge pointing to the aggregate
1903 AggregateVisitor<V> v(aggregates, aggregate, visitor);
1904 visitNeighbours(*graph_, vertex, v);
1905 }
1906
1907
1908 template<class G>
1909 inline Aggregator<G>::Counter::Counter()
1910 : count_(0)
1911 {}
1912
1913 template<class G>
1914 inline void Aggregator<G>::Counter::increment()
1915 {
1916 ++count_;
1917 }
1918
1919 template<class G>
1920 inline void Aggregator<G>::Counter::decrement()
1921 {
1922 --count_;
1923 }
1924 template<class G>
1925 inline int Aggregator<G>::Counter::value()
1926 {
1927 return count_;
1928 }
1929
1930 template<class G>
1931 inline void Aggregator<G>::TwoWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1932 {
1933 if(edge.properties().isTwoWay())
1934 Counter::increment();
1935 }
1936
1937 template<class G>
1938 int Aggregator<G>::twoWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1939 const AggregatesMap<Vertex>& aggregates) const
1940 {
1941 TwoWayCounter counter;
1942 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1943 return counter.value();
1944 }
1945
1946 template<class G>
1947 int Aggregator<G>::oneWayConnections(const Vertex& vertex, const AggregateDescriptor& aggregate,
1948 const AggregatesMap<Vertex>& aggregates) const
1949 {
1950 OneWayCounter counter;
1951 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
1952 return counter.value();
1953 }
1954
1955 template<class G>
1956 inline void Aggregator<G>::OneWayCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1957 {
1958 if(edge.properties().isOneWay())
1959 Counter::increment();
1960 }
1961
1962 template<class G>
1963 inline Aggregator<G>::ConnectivityCounter::ConnectivityCounter(const VertexSet& connected,
1964 const AggregatesMap<Vertex>& aggregates)
1965 : Counter(), connected_(connected), aggregates_(aggregates)
1966 {}
1967
1968
1969 template<class G>
1970 inline void Aggregator<G>::ConnectivityCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1971 {
1972 if(connected_.find(aggregates_[edge.target()]) == connected_.end() || aggregates_[edge.target()]==AggregatesMap<Vertex>::UNAGGREGATED)
1973 // Would be a new connection
1974 Counter::increment();
1975 else{
1976 Counter::increment();
1977 Counter::increment();
1978 }
1979 }
1980
1981 template<class G>
1982 inline double Aggregator<G>::connectivity(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
1983 {
1984 ConnectivityCounter counter(connected_, aggregates);
1985 double noNeighbours=visitNeighbours(*graph_, vertex, counter);
1986 return (double)counter.value()/noNeighbours;
1987 }
1988
1989 template<class G>
1990 inline Aggregator<G>::DependencyCounter::DependencyCounter()
1991 : Counter()
1992 {}
1993
1994 template<class G>
1995 inline void Aggregator<G>::DependencyCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
1996 {
1997 if(edge.properties().depends())
1998 Counter::increment();
1999 if(edge.properties().influences())
2000 Counter::increment();
2001 }
2002
2003 template<class G>
2004 int Aggregator<G>::unusedNeighbours(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2005 {
2006 return aggregateNeighbours(vertex, AggregatesMap<Vertex>::UNAGGREGATED, aggregates);
2007 }
2008
2009 template<class G>
2010 std::pair<int,int> Aggregator<G>::neighbours(const Vertex& vertex,
2011 const AggregateDescriptor& aggregate,
2012 const AggregatesMap<Vertex>& aggregates) const
2013 {
2014 DependencyCounter unused, aggregated;
2015 typedef AggregateVisitor<DependencyCounter> CounterT;
2016 typedef std::tuple<CounterT,CounterT> CounterTuple;
2017 CombinedFunctor<CounterTuple> visitors(CounterTuple(CounterT(aggregates, AggregatesMap<Vertex>::UNAGGREGATED, unused), CounterT(aggregates, aggregate, aggregated)));
2018 visitNeighbours(*graph_, vertex, visitors);
2019 return std::make_pair(unused.value(), aggregated.value());
2020 }
2021
2022
2023 template<class G>
2024 int Aggregator<G>::aggregateNeighbours(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2025 {
2026 DependencyCounter counter;
2027 visitAggregateNeighbours(vertex, aggregate, aggregates, counter);
2028 return counter.value();
2029 }
2030
2031 template<class G>
2032 std::size_t Aggregator<G>::distance(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates)
2033 {
2034 return 0;
2035 typename PropertyMapTypeSelector<VertexVisitedTag,G>::Type visitedMap = get(VertexVisitedTag(), *graph_);
2036 VertexList vlist;
2037 typename AggregatesMap<Vertex>::DummyEdgeVisitor dummy;
2038 return aggregates.template breadthFirstSearch<true,true>(vertex,
2039 aggregate_->id(), *graph_,
2040 vlist, dummy, dummy, visitedMap);
2041 }
2042
2043 template<class G>
2044 inline Aggregator<G>::FrontMarker::FrontMarker(std::vector<Vertex>& front, MatrixGraph& graph)
2045 : front_(front), graph_(graph)
2046 {}
2047
2048 template<class G>
2049 inline void Aggregator<G>::FrontMarker::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2050 {
2051 Vertex target = edge.target();
2052
2053 if(!graph_.getVertexProperties(target).front()) {
2054 front_.push_back(target);
2055 graph_.getVertexProperties(target).setFront();
2056 }
2057 }
2058
2059 template<class G>
2060 inline bool Aggregator<G>::admissible(const Vertex& vertex, const AggregateDescriptor& aggregate, const AggregatesMap<Vertex>& aggregates) const
2061 {
2062 // Todo
2063 Dune::dvverb<<" Admissible not yet implemented!"<<std::endl;
2064 return true;
2065 //Situation 1: front node depends on two nodes. Then these
2066 // have to be strongly connected to each other
2067
2068 // Iterate over all all neighbours of front node
2069 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2070 Iterator vend = graph_->endEdges(vertex);
2071 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2072 // if(edge.properties().depends() && !edge.properties().influences()
2073 if(edge.properties().isStrong()
2074 && aggregates[edge.target()]==aggregate)
2075 {
2076 // Search for another link to the aggregate
2077 Iterator edge1 = edge;
2078 for(++edge1; edge1 != vend; ++edge1) {
2079 //if(edge1.properties().depends() && !edge1.properties().influences()
2080 if(edge1.properties().isStrong()
2081 && aggregates[edge.target()]==aggregate)
2082 {
2083 //Search for an edge connecting the two vertices that is
2084 //strong
2085 bool found=false;
2086 Iterator v2end = graph_->endEdges(edge.target());
2087 for(Iterator edge2 = graph_->beginEdges(edge.target()); edge2 != v2end; ++edge2) {
2088 if(edge2.target()==edge1.target() &&
2089 edge2.properties().isStrong()) {
2090 found =true;
2091 break;
2092 }
2093 }
2094 if(found)
2095 {
2096 return true;
2097 }
2098 }
2099 }
2100 }
2101 }
2102
2103 // Situation 2: cluster node depends on front node and other cluster node
2105 vend = graph_->endEdges(vertex);
2106 for(Iterator edge = graph_->beginEdges(vertex); edge != vend; ++edge) {
2107 //if(!edge.properties().depends() && edge.properties().influences()
2108 if(edge.properties().isStrong()
2109 && aggregates[edge.target()]==aggregate)
2110 {
2111 // Search for a link from target that stays within the aggregate
2112 Iterator v1end = graph_->endEdges(edge.target());
2113
2114 for(Iterator edge1=graph_->beginEdges(edge.target()); edge1 != v1end; ++edge1) {
2115 //if(edge1.properties().depends() && !edge1.properties().influences()
2116 if(edge1.properties().isStrong()
2117 && aggregates[edge1.target()]==aggregate)
2118 {
2119 bool found=false;
2120 // Check if front node is also connected to this one
2121 Iterator v2end = graph_->endEdges(vertex);
2122 for(Iterator edge2 = graph_->beginEdges(vertex); edge2 != v2end; ++edge2) {
2123 if(edge2.target()==edge1.target()) {
2124 if(edge2.properties().isStrong())
2125 found=true;
2126 break;
2127 }
2128 }
2129 if(found)
2130 {
2131 return true;
2132 }
2133 }
2134 }
2135 }
2136 }
2137 return false;
2138 }
2139
2140 template<class G>
2141 void Aggregator<G>::unmarkFront()
2142 {
2143 typedef typename std::vector<Vertex>::const_iterator Iterator;
2144
2145 for(Iterator vertex=front_.begin(); vertex != front_.end(); ++vertex)
2146 graph_->getVertexProperties(*vertex).resetFront();
2147
2148 front_.clear();
2149 }
2150
2151 template<class G>
2152 inline void
2153 Aggregator<G>::nonisoNeighbourAggregate(const Vertex& vertex,
2154 const AggregatesMap<Vertex>& aggregates,
2155 SLList<Vertex>& neighbours) const
2156 {
2157 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2158 Iterator end=graph_->beginEdges(vertex);
2159 neighbours.clear();
2160
2161 for(Iterator edge=graph_->beginEdges(vertex); edge!=end; ++edge)
2162 {
2163 if(aggregates[edge.target()]!=AggregatesMap<Vertex>::UNAGGREGATED && graph_->getVertexProperties(edge.target()).isolated())
2164 neighbours.push_back(aggregates[edge.target()]);
2165 }
2166 }
2167
2168 template<class G>
2169 inline typename G::VertexDescriptor Aggregator<G>::mergeNeighbour(const Vertex& vertex, const AggregatesMap<Vertex>& aggregates) const
2170 {
2171 typedef typename MatrixGraph::ConstEdgeIterator Iterator;
2172
2173 Iterator end = graph_->endEdges(vertex);
2174 for(Iterator edge = graph_->beginEdges(vertex); edge != end; ++edge) {
2175 if(aggregates[edge.target()] != AggregatesMap<Vertex>::UNAGGREGATED &&
2176 graph_->getVertexProperties(edge.target()).isolated() == graph_->getVertexProperties(edge.source()).isolated()) {
2177 if( graph_->getVertexProperties(vertex).isolated() ||
2178 ((edge.properties().depends() || edge.properties().influences())
2179 && admissible(vertex, aggregates[edge.target()], aggregates)))
2180 return edge.target();
2181 }
2182 }
2184 }
2185
2186 template<class G>
2187 Aggregator<G>::FrontNeighbourCounter::FrontNeighbourCounter(const MatrixGraph& graph)
2188 : Counter(), graph_(graph)
2189 {}
2190
2191 template<class G>
2192 void Aggregator<G>::FrontNeighbourCounter::operator()(const typename MatrixGraph::ConstEdgeIterator& edge)
2193 {
2194 if(graph_.getVertexProperties(edge.target()).front())
2195 Counter::increment();
2196 }
2197
2198 template<class G>
2199 int Aggregator<G>::noFrontNeighbours(const Vertex& vertex) const
2200 {
2201 FrontNeighbourCounter counter(*graph_);
2202 visitNeighbours(*graph_, vertex, counter);
2203 return counter.value();
2204 }
2205 template<class G>
2206 inline bool Aggregator<G>::connected(const Vertex& vertex,
2207 const AggregateDescriptor& aggregate,
2208 const AggregatesMap<Vertex>& aggregates) const
2209 {
2210 typedef typename G::ConstEdgeIterator iterator;
2211 const iterator end = graph_->endEdges(vertex);
2212 for(iterator edge = graph_->beginEdges(vertex); edge != end; ++edge)
2213 if(aggregates[edge.target()]==aggregate)
2214 return true;
2215 return false;
2216 }
2217 template<class G>
2218 inline bool Aggregator<G>::connected(const Vertex& vertex,
2219 const SLList<AggregateDescriptor>& aggregateList,
2220 const AggregatesMap<Vertex>& aggregates) const
2221 {
2222 typedef typename SLList<AggregateDescriptor>::const_iterator Iter;
2223 for(Iter i=aggregateList.begin(); i!=aggregateList.end(); ++i)
2224 if(connected(vertex, *i, aggregates))
2225 return true;
2226 return false;
2227 }
2228
2229 template<class G>
2230 template<class C>
2231 void Aggregator<G>::growIsolatedAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2232 {
2233 SLList<Vertex> connectedAggregates;
2234 nonisoNeighbourAggregate(seed, aggregates,connectedAggregates);
2235
2236 while(aggregate_->size()< c.minAggregateSize() && aggregate_->connectSize() < c.maxConnectivity()) {
2237 double maxCon=-1;
2238 std::size_t maxFrontNeighbours=0;
2239
2241
2242 typedef typename std::vector<Vertex>::const_iterator Iterator;
2243
2244 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2245 if(distance(*vertex, aggregates)>c.maxDistance())
2246 continue; // distance of proposes aggregate too big
2247
2248 if(connectedAggregates.size()>0) {
2249 // there is already a neighbour cluster
2250 // front node must be connected to same neighbour cluster
2251
2252 if(!connected(*vertex, connectedAggregates, aggregates))
2253 continue;
2254 }
2255
2256 double con = connectivity(*vertex, aggregates);
2257
2258 if(con == maxCon) {
2259 std::size_t frontNeighbours = noFrontNeighbours(*vertex);
2260
2261 if(frontNeighbours >= maxFrontNeighbours) {
2262 maxFrontNeighbours = frontNeighbours;
2263 candidate = *vertex;
2264 }
2265 }else if(con > maxCon) {
2266 maxCon = con;
2267 maxFrontNeighbours = noFrontNeighbours(*vertex);
2268 candidate = *vertex;
2269 }
2270 }
2271
2273 break;
2274
2275 aggregate_->add(candidate);
2276 }
2277 }
2278
2279 template<class G>
2280 template<class C>
2281 void Aggregator<G>::growAggregate(const Vertex& seed, const AggregatesMap<Vertex>& aggregates, const C& c)
2282 {
2283 using std::min;
2284
2285 std::size_t distance_ =0;
2286 while(aggregate_->size() < c.minAggregateSize()&& distance_<c.maxDistance()) {
2287 int maxTwoCons=0, maxOneCons=0, maxNeighbours=-1;
2288 double maxCon=-1;
2289
2290 std::vector<Vertex> candidates;
2291 candidates.reserve(30);
2292
2293 typedef typename std::vector<Vertex>::const_iterator Iterator;
2294
2295 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2296 // Only nonisolated nodes are considered
2297 if(graph_->getVertexProperties(*vertex).isolated())
2298 continue;
2299
2300 int twoWayCons = twoWayConnections(*vertex, aggregate_->id(), aggregates);
2301
2302 /* The case of two way connections. */
2303 if( maxTwoCons == twoWayCons && twoWayCons > 0) {
2304 double con = connectivity(*vertex, aggregates);
2305
2306 if(con == maxCon) {
2307 int neighbours = noFrontNeighbours(*vertex);
2308
2309 if(neighbours > maxNeighbours) {
2310 maxNeighbours = neighbours;
2311 candidates.clear();
2312 candidates.push_back(*vertex);
2313 }else{
2314 candidates.push_back(*vertex);
2315 }
2316 }else if( con > maxCon) {
2317 maxCon = con;
2318 maxNeighbours = noFrontNeighbours(*vertex);
2319 candidates.clear();
2320 candidates.push_back(*vertex);
2321 }
2322 }else if(twoWayCons > maxTwoCons) {
2323 maxTwoCons = twoWayCons;
2324 maxCon = connectivity(*vertex, aggregates);
2325 maxNeighbours = noFrontNeighbours(*vertex);
2326 candidates.clear();
2327 candidates.push_back(*vertex);
2328
2329 // two way connections precede
2330 maxOneCons = std::numeric_limits<int>::max();
2331 }
2332
2333 if(twoWayCons > 0)
2334 {
2335 continue; // THis is a two-way node, skip tests for one way nodes
2336 }
2337
2338 /* The one way case */
2339 int oneWayCons = oneWayConnections(*vertex, aggregate_->id(), aggregates);
2340
2341 if(oneWayCons==0)
2342 continue; // No strong connections, skip the tests.
2343
2344 if(!admissible(*vertex, aggregate_->id(), aggregates))
2345 continue;
2346
2347 if( maxOneCons == oneWayCons && oneWayCons > 0) {
2348 double con = connectivity(*vertex, aggregates);
2349
2350 if(con == maxCon) {
2351 int neighbours = noFrontNeighbours(*vertex);
2352
2353 if(neighbours > maxNeighbours) {
2354 maxNeighbours = neighbours;
2355 candidates.clear();
2356 candidates.push_back(*vertex);
2357 }else{
2358 if(neighbours==maxNeighbours)
2359 {
2360 candidates.push_back(*vertex);
2361 }
2362 }
2363 }else if( con > maxCon) {
2364 maxCon = con;
2365 maxNeighbours = noFrontNeighbours(*vertex);
2366 candidates.clear();
2367 candidates.push_back(*vertex);
2368 }
2369 }else if(oneWayCons > maxOneCons) {
2370 maxOneCons = oneWayCons;
2371 maxCon = connectivity(*vertex, aggregates);
2372 maxNeighbours = noFrontNeighbours(*vertex);
2373 candidates.clear();
2374 candidates.push_back(*vertex);
2375 }
2376 }
2377
2378
2379 if(!candidates.size())
2380 break; // No more candidates found
2381 distance_=distance(seed, aggregates);
2382 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2383 aggregate_->size()));
2384 aggregate_->add(candidates);
2385 }
2386 }
2387
2388 template<typename V>
2389 template<typename M, typename G, typename C>
2390 std::tuple<int,int,int,int> AggregatesMap<V>::buildAggregates(const M& matrix, G& graph, const C& criterion,
2391 bool finestLevel)
2392 {
2393 Aggregator<G> aggregator;
2394 return aggregator.build(matrix, graph, *this, criterion, finestLevel);
2395 }
2396
2397 template<class G>
2398 template<class M, class C>
2399 std::tuple<int,int,int,int> Aggregator<G>::build(const M& m, G& graph, AggregatesMap<Vertex>& aggregates, const C& c,
2400 bool finestLevel)
2401 {
2402 using std::max;
2403 using std::min;
2404 // Stack for fast vertex access
2405 Stack stack_(graph, *this, aggregates);
2406
2407 graph_ = &graph;
2408
2409 aggregate_ = new Aggregate<G,VertexSet>(graph, aggregates, connected_, front_);
2410
2411 Timer watch;
2412 watch.reset();
2413
2414 buildDependency(graph, m, c, finestLevel);
2415
2416 dverb<<"Build dependency took "<< watch.elapsed()<<" seconds."<<std::endl;
2417 int noAggregates, conAggregates, isoAggregates, oneAggregates;
2418 std::size_t maxA=0, minA=1000000, avg=0;
2419 int skippedAggregates;
2420 noAggregates = conAggregates = isoAggregates = oneAggregates =
2421 skippedAggregates = 0;
2422
2423 while(true) {
2424 Vertex seed = stack_.pop();
2425
2426 if(seed == Stack::NullEntry)
2427 // No more unaggregated vertices. We are finished!
2428 break;
2429
2430 // Debugging output
2431 if((noAggregates+1)%10000 == 0)
2432 Dune::dverb<<"c";
2433 unmarkFront();
2434
2435 if(graph.getVertexProperties(seed).excludedBorder()) {
2436 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2437 ++skippedAggregates;
2438 continue;
2439 }
2440
2441 if(graph.getVertexProperties(seed).isolated()) {
2442 if(c.skipIsolated()) {
2443 // isolated vertices are not aggregated but skipped on the coarser levels.
2444 aggregates[seed]=AggregatesMap<Vertex>::ISOLATED;
2445 ++skippedAggregates;
2446 // skip rest as no agglomeration is done.
2447 continue;
2448 }else{
2449 aggregate_->seed(seed);
2450 growIsolatedAggregate(seed, aggregates, c);
2451 }
2452 }else{
2453 aggregate_->seed(seed);
2454 growAggregate(seed, aggregates, c);
2455 }
2456
2457 /* The rounding step. */
2458 while(!(graph.getVertexProperties(seed).isolated()) && aggregate_->size() < c.maxAggregateSize()) {
2459
2460 std::vector<Vertex> candidates;
2461 candidates.reserve(30);
2462
2463 typedef typename std::vector<Vertex>::const_iterator Iterator;
2464
2465 for(Iterator vertex = front_.begin(); vertex != front_.end(); ++vertex) {
2466
2467 if(graph.getVertexProperties(*vertex).isolated())
2468 continue; // No isolated nodes here
2469
2470 if(twoWayConnections( *vertex, aggregate_->id(), aggregates) == 0 &&
2471 (oneWayConnections( *vertex, aggregate_->id(), aggregates) == 0 ||
2472 !admissible( *vertex, aggregate_->id(), aggregates) ))
2473 continue;
2474
2475 std::pair<int,int> neighbourPair=neighbours(*vertex, aggregate_->id(),
2476 aggregates);
2477
2478 //if(aggregateNeighbours(*vertex, aggregate_->id(), aggregates) <= unusedNeighbours(*vertex, aggregates))
2479 // continue;
2480
2481 if(neighbourPair.first >= neighbourPair.second)
2482 continue;
2483
2484 if(distance(*vertex, aggregates) > c.maxDistance())
2485 continue; // Distance too far
2486 candidates.push_back(*vertex);
2487 break;
2488 }
2489
2490 if(!candidates.size()) break; // no more candidates found.
2491
2492 candidates.resize(min(candidates.size(), c.maxAggregateSize()-
2493 aggregate_->size()));
2494 aggregate_->add(candidates);
2495
2496 }
2497
2498 // try to merge aggregates consisting of only one nonisolated vertex with other aggregates
2499 if(aggregate_->size()==1 && c.maxAggregateSize()>1) {
2500 if(!graph.getVertexProperties(seed).isolated()) {
2501 Vertex mergedNeighbour = mergeNeighbour(seed, aggregates);
2502
2503 if(mergedNeighbour != AggregatesMap<Vertex>::UNAGGREGATED) {
2504 // assign vertex to the neighbouring cluster
2505 aggregates[seed] = aggregates[mergedNeighbour];
2506 aggregate_->invalidate();
2507 }else{
2508 ++avg;
2509 minA=min(minA,static_cast<std::size_t>(1));
2510 maxA=max(maxA,static_cast<std::size_t>(1));
2511 ++oneAggregates;
2512 ++conAggregates;
2513 }
2514 }else{
2515 ++avg;
2516 minA=min(minA,static_cast<std::size_t>(1));
2517 maxA=max(maxA,static_cast<std::size_t>(1));
2518 ++oneAggregates;
2519 ++isoAggregates;
2520 }
2521 ++avg;
2522 }else{
2523 avg+=aggregate_->size();
2524 minA=min(minA,aggregate_->size());
2525 maxA=max(maxA,aggregate_->size());
2526 if(graph.getVertexProperties(seed).isolated())
2527 ++isoAggregates;
2528 else
2529 ++conAggregates;
2530 }
2531
2532 }
2533
2534 Dune::dinfo<<"connected aggregates: "<<conAggregates;
2535 Dune::dinfo<<" isolated aggregates: "<<isoAggregates;
2536 if(conAggregates+isoAggregates>0)
2537 Dune::dinfo<<" one node aggregates: "<<oneAggregates<<" min size="
2538 <<minA<<" max size="<<maxA
2539 <<" avg="<<avg/(conAggregates+isoAggregates)<<std::endl;
2540
2541 delete aggregate_;
2542 return std::make_tuple(conAggregates+isoAggregates,isoAggregates,
2543 oneAggregates,skippedAggregates);
2544 }
2545
2546
2547 template<class G>
2548 Aggregator<G>::Stack::Stack(const MatrixGraph& graph, const Aggregator<G>& aggregatesBuilder,
2549 const AggregatesMap<Vertex>& aggregates)
2550 : graph_(graph), aggregatesBuilder_(aggregatesBuilder), aggregates_(aggregates), begin_(graph.begin()), end_(graph.end())
2551 {
2552 //vals_ = new Vertex[N];
2553 }
2554
2555 template<class G>
2556 Aggregator<G>::Stack::~Stack()
2557 {
2558 //Dune::dverb << "Max stack size was "<<maxSize_<<" filled="<<filled_<<std::endl;
2559 //delete[] vals_;
2560 }
2561
2562 template<class G>
2563 const typename Aggregator<G>::Vertex Aggregator<G>::Stack::NullEntry
2565
2566 template<class G>
2567 inline typename G::VertexDescriptor Aggregator<G>::Stack::pop()
2568 {
2569 for(; begin_!=end_ && aggregates_[*begin_] != AggregatesMap<Vertex>::UNAGGREGATED; ++begin_) ;
2570
2571 if(begin_!=end_)
2572 {
2573 typename G::VertexDescriptor current=*begin_;
2574 ++begin_;
2575 return current;
2576 }else
2577 return NullEntry;
2578 }
2579
2580#endif // DOXYGEN
2581
2582 template<class V>
2583 void printAggregates2d(const AggregatesMap<V>& aggregates, int n, int m, std::ostream& os)
2584 {
2585 using std::max;
2586
2587 std::ios_base::fmtflags oldOpts=os.flags();
2588
2589 os.setf(std::ios_base::right, std::ios_base::adjustfield);
2590
2591 V maxVal=0;
2592 int width=1;
2593
2594 for(int i=0; i< n*m; i++)
2595 maxVal=max(maxVal, aggregates[i]);
2596
2597 for(int i=10; i < 1000000; i*=10)
2598 if(maxVal/i>0)
2599 width++;
2600 else
2601 break;
2602
2603 for(int j=0, entry=0; j < m; j++) {
2604 for(int i=0; i<n; i++, entry++) {
2605 os.width(width);
2606 os<<aggregates[entry]<<" ";
2607 }
2608
2609 os<<std::endl;
2610 }
2611 os<<std::endl;
2612 os.flags(oldOpts);
2613 }
2614
2615
2616 } // namespace Amg
2617
2618} // namespace Dune
2619
2620
2621#endif
A class for temporarily storing the vertices of an aggregate in.
Definition: aggregates.hh:778
A Dummy visitor that does nothing for each visited edge.
Definition: aggregates.hh:598
Class providing information about the mapping of the vertices onto aggregates.
Definition: aggregates.hh:560
Base class of all aggregation criterions.
Definition: aggregates.hh:49
Class for building the aggregates.
Definition: aggregates.hh:909
Dependency policy for symmetric matrices.
Definition: aggregates.hh:253
Norm that uses only the [N][N] entry of the block to determine couplings.
Definition: aggregates.hh:379
Norm that uses only the [0][0] entry of the block to determine couplings.
Definition: aggregates.hh:455
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:519
Dependency policy for symmetric matrices.
Definition: aggregates.hh:314
Dependency policy for symmetric matrices.
Definition: aggregates.hh:134
Criterion suitable for unsymmetric matrices.
Definition: aggregates.hh:539
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, m)
Definition: exceptions.hh:218
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:484
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:506
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:273
Matrix::ConstColIterator ColIter
Constant column iterator of the matrix.
Definition: aggregates.hh:154
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:586
int id()
Get the id identifying the aggregate.
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:302
MatrixGraph::VertexDescriptor Vertex
The vertex identifier.
Definition: aggregates.hh:920
AggregationCriterion()
Constructor.
Definition: aggregates.hh:66
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:357
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:406
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:258
G MatrixGraph
The matrix graph type used.
Definition: aggregates.hh:915
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:363
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:319
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:187
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:263
int row_
index of the currently evaluated row.
Definition: aggregates.hh:185
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:329
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:296
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:334
~AggregatesMap()
Destructor.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:179
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:1064
std::size_t * SphereMap
Type of the mapping of aggregate members onto distance spheres.
Definition: aggregates.hh:809
Matrix::row_type Row
Constant Row iterator of the matrix.
Definition: aggregates.hh:268
VertexSet::size_type connectSize()
Get the number of connections to other aggregates.
N Norm
The norm to use for examining the matrix entries.
Definition: aggregates.hh:324
Norm norm_
The functor for calculating the norm.
Definition: aggregates.hh:183
VertexSet::const_iterator const_iterator
Const iterator over a vertex list.
Definition: aggregates.hh:804
MatrixGraph::VertexDescriptor AggregateDescriptor
The type of the aggregate descriptor.
Definition: aggregates.hh:923
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:367
~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:55
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:506
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:82
V AggregateDescriptor
The aggregate descriptor type.
Definition: aggregates.hh:580
static const V ISOLATED
Identifier of isolated vertices.
Definition: aggregates.hh:571
int row_
index of the currently evaluated row.
Definition: aggregates.hh:365
real_type diagonal_
The norm of the current diagonal.
Definition: aggregates.hh:306
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:105
AggregatesMap(std::size_t noVertices)
Constructs with allocating memory.
Matrix::field_type field_type
The current max value.
Definition: aggregates.hh:359
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:592
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:304
M Matrix
The matrix type we build the dependency of.
Definition: aggregates.hh:139
const Matrix * matrix_
The matrix we work on.
Definition: aggregates.hh:177
S VertexSet
The type of a single linked list of vertex descriptors.
Definition: aggregates.hh:801
FieldTraits< typenameM::field_type >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:490
static const V UNAGGREGATED
Identifier of not yet aggregated vertices.
Definition: aggregates.hh:566
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:298
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:144
FieldTraits< typenameM::field_type >::real_type operator()(const M &m) const
compute the norm of a matrix.
Definition: aggregates.hh:473
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:390
MatrixGraph::VertexDescriptor Vertex
The vertex descriptor type.
Definition: aggregates.hh:789
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:575
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:149
PoolAllocator< Vertex, 100 > Allocator
The allocator we use for our lists and the set.
Definition: aggregates.hh:795
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 std::integral_constant< T, I0 > front(std::integer_sequence< T, I0, II... >)
Return the first entry of the sequence.
Definition: integersequence.hh:39
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:463
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition: typetraits.hh:194
A simple timing class.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 21, 23:30, 2024)