DUNE PDELab (unstable)

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