00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #ifndef IFPACK_SUPPORTGRAPH_H
00044 #define IFPACK_SUPPORTGRAPH_H
00045
00046 #include "Ifpack_ConfigDefs.h"
00047 #include "Ifpack_Condest.h"
00048 #include "Ifpack_Preconditioner.h"
00049 #include "Ifpack_Amesos.h"
00050 #include "Ifpack_Condest.h"
00051 #include "Epetra_Map.h"
00052 #include "Epetra_Comm.h"
00053 #include "Epetra_Time.h"
00054 #include "Epetra_Vector.h"
00055 #include "Epetra_MultiVector.h"
00056 #include "Epetra_LinearProblem.h"
00057 #include "Epetra_RowMatrix.h"
00058 #include "Epetra_CrsMatrix.h"
00059
00060 #include "Teuchos_ParameterList.hpp"
00061 #include "Teuchos_RefCountPtr.hpp"
00062
00063 #include <boost/graph/adjacency_list.hpp>
00064 #include <boost/graph/kruskal_min_spanning_tree.hpp>
00065 #include <boost/graph/prim_minimum_spanning_tree.hpp>
00066 #include <boost/config.hpp>
00067
00068 using Teuchos::RefCountPtr;
00069 using Teuchos::rcp;
00070 typedef std::pair<int, int> E;
00071 using namespace boost;
00072
00073 typedef adjacency_list < vecS, vecS, undirectedS,
00074 no_property, property < edge_weight_t, double > > Graph;
00075 typedef graph_traits < Graph >::edge_descriptor Edge;
00076 typedef graph_traits < Graph >::vertex_descriptor Vertex;
00077
00078
00079
00080 template<typename T=Ifpack_Amesos> class Ifpack_SupportGraph :
00081 public virtual Ifpack_Preconditioner
00082 {
00083
00084 public:
00085
00087
00089 Ifpack_SupportGraph(Epetra_RowMatrix* Matrix_in);
00090
00092
00093
00095
00096
00105 virtual int SetUseTranspose(bool UseTranspose_in);
00106
00108
00109
00111
00113
00121 virtual int Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const;
00122
00124
00135 virtual int ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const;
00136
00138 virtual double NormInf() const {return(0.0);}
00139
00141
00142
00144
00146 virtual const char * Label() const;
00147
00149 virtual bool UseTranspose() const {return(UseTranspose_);};
00150
00152 virtual bool HasNormInf() const {return(false);};
00153
00155 virtual const Epetra_Comm & Comm() const {return(Matrix_->Comm());};
00156
00158 virtual const Epetra_Map & OperatorDomainMap() const {return(Matrix_->OperatorDomainMap());};
00159
00161 virtual const Epetra_Map & OperatorRangeMap() const {return(Matrix_->OperatorRangeMap());};
00162
00164
00165
00167
00169 virtual bool IsInitialized() const
00170 {
00171 return(IsInitialized_);
00172 }
00173
00175 virtual bool IsComputed() const
00176 {
00177 return(IsComputed_);
00178 }
00179
00181
00193 virtual int SetParameters(Teuchos::ParameterList& List);
00194
00196
00199 virtual int Initialize();
00201
00204 virtual int Compute();
00205
00207
00208
00210
00211
00213
00216 virtual double Condest(const Ifpack_CondestType CT = Ifpack_Cheap,
00217 const int MaxIters = 1550,
00218 const double Tol = 1e-9,
00219 Epetra_RowMatrix* Matrix_in = 0);
00220
00222 virtual double Condest() const
00223 {
00224 return(Condest_);
00225 }
00226
00228 virtual const Epetra_RowMatrix& Matrix() const
00229 {
00230 return(*Matrix_);
00231 }
00232
00234 virtual std::ostream& Print(std::ostream&) const;
00235
00237 virtual int NumInitialize() const
00238 {
00239 return(NumInitialize_);
00240 }
00241
00243 virtual int NumCompute() const
00244 {
00245 return(NumCompute_);
00246 }
00247
00249 virtual int NumApplyInverse() const
00250 {
00251 return(NumApplyInverse_);
00252 }
00253
00255 virtual double InitializeTime() const
00256 {
00257 return(InitializeTime_);
00258 }
00259
00261 virtual double ComputeTime() const
00262 {
00263 return(ComputeTime_);
00264 }
00265
00267 virtual double ApplyInverseTime() const
00268 {
00269 return(ApplyInverseTime_);
00270 }
00271
00273 virtual double InitializeFlops() const
00274 {
00275 return(InitializeFlops_);
00276 }
00277
00279 virtual double ComputeFlops() const
00280 {
00281 return(ComputeFlops_);
00282 }
00283
00285 virtual double ApplyInverseFlops() const
00286 {
00287 return(ApplyInverseFlops_);
00288 }
00289
00290
00292
00293 protected:
00294
00296 int FindSupport();
00297
00299 Teuchos::RefCountPtr<const Epetra_RowMatrix> Matrix_;
00300
00302 Teuchos::RefCountPtr<Epetra_CrsMatrix> Support_;
00303
00305 string Label_;
00306
00308 bool IsInitialized_;
00309
00311 bool IsComputed_;
00312
00314 bool UseTranspose_;
00315
00317 Teuchos::ParameterList List_;
00318
00320 double Condest_;
00321
00323 int NumInitialize_;
00324
00326 int NumCompute_;
00327
00329 mutable int NumApplyInverse_;
00330
00332 double InitializeTime_;
00333
00335 double ComputeTime_;
00336
00338 mutable double ApplyInverseTime_;
00339
00341 double InitializeFlops_;
00342
00344 double ComputeFlops_;
00345
00347 mutable double ApplyInverseFlops_;
00348
00350 Teuchos::RefCountPtr<Epetra_Time> Time_;
00351
00353 Teuchos::RefCountPtr<T> Inverse_;
00354
00356 int NumForests_;
00357
00359 double DiagPertRel_;
00360
00362 double DiagPertAbs_;
00363
00365 double KeepDiag_;
00366
00368 int Randomize_;
00369
00370 };
00371
00372
00373
00374
00375 template<typename T>
00376 Ifpack_SupportGraph<T>::Ifpack_SupportGraph(Epetra_RowMatrix* Matrix_in):
00377 Matrix_(rcp(Matrix_in,false)),
00378 IsInitialized_(false),
00379 IsComputed_(false),
00380 UseTranspose_(false),
00381 Condest_(-1.0),
00382 NumInitialize_(0),
00383 NumCompute_(0),
00384 NumApplyInverse_(0),
00385 InitializeTime_(0.0),
00386 ComputeTime_(0.0),
00387 ApplyInverseTime_(0.0),
00388 InitializeFlops_(0.0),
00389 ComputeFlops_(0.0),
00390 ApplyInverseFlops_(0.0),
00391 NumForests_(1),
00392 DiagPertRel_(1.0),
00393 DiagPertAbs_(0.0),
00394 KeepDiag_(1.0),
00395 Randomize_(0)
00396 {
00397
00398 Teuchos::ParameterList List_in;
00399 SetParameters(List_in);
00400 }
00401
00402 template<typename T>
00403 int Ifpack_SupportGraph<T>::FindSupport()
00404 {
00405
00406
00407 long long rows = (*Matrix_).NumGlobalRows64();
00408 long long cols = (*Matrix_).NumGlobalCols64();
00409 int num_edges = ((*Matrix_).NumMyNonzeros() - (*Matrix_).NumMyDiagonals())/2;
00410 std::cout << "global num rows " << rows << std::endl;
00411
00412
00413 IFPACK_CHK_ERR((rows == cols));
00414
00415 if(rows > std::numeric_limits<int>::max())
00416 {
00417 std::cerr << "Ifpack_SupportGraph<T>::FindSupport: global num rows won't fit an int. " << rows << std::endl;
00418 IFPACK_CHK_ERR(1);
00419 }
00420
00421
00422 int num_verts = (int) rows;
00423
00424
00425 E *edge_array = new E[num_edges];
00426 double *weights = new double[num_edges];
00427
00428 int num_entries;
00429 int max_num_entries = (*Matrix_).MaxNumEntries();
00430 double *values = new double[max_num_entries];
00431 int *indices = new int[max_num_entries];
00432
00433 double * diagonal = new double[num_verts];
00434
00435
00436 for(int i = 0; i < max_num_entries; i++)
00437 {
00438 values[i]=0;
00439 indices[i]=0;
00440 }
00441
00442
00443 int k = 0;
00444 for(int i = 0; i < num_verts; i++)
00445 {
00446 (*Matrix_).ExtractMyRowCopy(i,max_num_entries,num_entries,values,indices);
00447
00448 for(int j = 0; j < num_entries; j++)
00449 {
00450
00451 if(i == indices[j])
00452 {
00453 diagonal[i] = values[j];
00454
00455 if (DiagPertRel_)
00456 diagonal[i] *= DiagPertRel_;
00457 if (DiagPertAbs_)
00458 diagonal[i] += DiagPertAbs_;
00459 }
00460
00461 if(i < indices[j])
00462 {
00463 edge_array[k] = E(i,indices[j]);
00464 weights[k] = values[j];
00465 if (Randomize_)
00466 {
00467
00468 weights[k] *= (1.0 + 1e-8 * drand48());
00469 }
00470
00471 k++;
00472 }
00473 }
00474 }
00475
00476
00477 Graph g(edge_array, edge_array + num_edges, weights, num_verts);
00478
00479
00480 property_map < Graph, edge_weight_t >::type weight = get(edge_weight, g);
00481
00482 std::vector < Edge > spanning_tree;
00483
00484
00485 kruskal_minimum_spanning_tree(g, std::back_inserter(spanning_tree));
00486
00487
00488 std::vector<int> NumNz(num_verts,1);
00489
00490
00491 for (std::vector < Edge >::iterator ei = spanning_tree.begin();
00492 ei != spanning_tree.end(); ++ei)
00493 {
00494 NumNz[source(*ei,g)] = NumNz[source(*ei,g)] + 1;
00495 NumNz[target(*ei,g)] = NumNz[target(*ei,g)] + 1;
00496 }
00497
00498
00499
00500 std::vector< std::vector< int > > Indices(num_verts);
00501
00502
00503
00504
00505 std::vector< std::vector< double > > Values(num_verts);
00506
00507 for(int i = 0; i < num_verts; i++)
00508 {
00509 std::vector<int> temp(NumNz[i],0);
00510 std::vector<double> temp2(NumNz[i],0);
00511 Indices[i] = temp;
00512 Values[i] = temp2;
00513 }
00514
00515 int *l = new int[num_verts];
00516 for(int i = 0; i < num_verts; i++)
00517 {
00518 Indices[i][0] = i;
00519 l[i] = 1;
00520 }
00521
00522
00523
00524 for(int i = 0; i < NumForests_; i++)
00525 {
00526 if(i > 0)
00527 {
00528 spanning_tree.clear();
00529 kruskal_minimum_spanning_tree(g,std::back_inserter(spanning_tree));
00530 for(std::vector < Edge >::iterator ei = spanning_tree.begin();
00531 ei != spanning_tree.end(); ++ei)
00532 {
00533 NumNz[source(*ei,g)] = NumNz[source(*ei,g)] + 1;
00534 NumNz[target(*ei,g)] = NumNz[target(*ei,g)] + 1;
00535 }
00536 for(int i = 0; i < num_verts; i++)
00537 {
00538 Indices[i].resize(NumNz[i]);
00539 Values[i].resize(NumNz[i]);
00540 }
00541 }
00542
00543 for (std::vector < Edge >::iterator ei = spanning_tree.begin();
00544 ei != spanning_tree.end(); ++ei)
00545 {
00546
00547
00548 Indices[source(*ei,g)][0] = source(*ei,g);
00549 Values[source(*ei,g)][0] = Values[source(*ei,g)][0] - weight[*ei];
00550 Indices[target(*ei,g)][0] = target(*ei,g);
00551 Values[target(*ei,g)][0] = Values[target(*ei,g)][0] - weight[*ei];
00552
00553 Indices[source(*ei,g)][l[source(*ei,g)]] = target(*ei,g);
00554 Values[source(*ei,g)][l[source(*ei,g)]] = weight[*ei];
00555 l[source(*ei,g)] = l[source(*ei,g)] + 1;
00556
00557 Indices[target(*ei,g)][l[target(*ei,g)]] = source(*ei,g);
00558 Values[target(*ei,g)][l[target(*ei,g)]] = weight[*ei];
00559 l[target(*ei,g)] = l[target(*ei,g)] + 1;
00560
00561 remove_edge(*ei,g);
00562 }
00563
00564 }
00565
00566
00567
00568
00569
00570
00571
00572 Epetra_Vector ones(Matrix_->OperatorDomainMap());
00573 Epetra_Vector surplus(Matrix_->OperatorRangeMap());
00574
00575 ones.PutScalar(1.0);
00576 Matrix_->Multiply(false, ones, surplus);
00577
00578 for(int i = 0; i < num_verts; i++)
00579 {
00580 Values[i][0] += surplus[i];
00581 Values[i][0] = KeepDiag_*diagonal[i] +
00582 (1.-KeepDiag_) * Values[i][0];
00583 }
00584
00585
00586 Support_ = rcp(new Epetra_CrsMatrix(Copy, Matrix().RowMatrixRowMap(),l, false));
00587
00588 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00589 if((*Matrix_).RowMatrixRowMap().GlobalIndicesLongLong())
00590 {
00591
00592 for(int i = 0; i < num_verts; i++)
00593 {
00594 std::vector<long long> IndicesLL(l[i]);
00595 for(int k = 0; k < l[i]; ++k)
00596 IndicesLL[k] = Indices[i][k];
00597
00598 (*Support_).InsertGlobalValues(i,l[i],&Values[i][0],&IndicesLL[0]);
00599 }
00600 }
00601 else
00602 #endif
00603 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00604 if((*Matrix_).RowMatrixRowMap().GlobalIndicesInt())
00605 {
00606
00607 for(int i = 0; i < num_verts; i++)
00608 {
00609 (*Support_).InsertGlobalValues(i,l[i],&Values[i][0],&Indices[i][0]);
00610 }
00611 }
00612 else
00613 #endif
00614 throw "Ifpack_SupportGraph::FindSupport: GlobalIndices unknown.";;
00615
00616 (*Support_).FillComplete();
00617
00618 delete edge_array;
00619 delete weights;
00620 delete values;
00621 delete indices;
00622 delete l;
00623 delete diagonal;
00624
00625 return(0);
00626 }
00627
00628 template<typename T>
00629 int Ifpack_SupportGraph<T>::SetParameters(Teuchos::ParameterList& List_in)
00630 {
00631 List_ = List_in;
00632 NumForests_ = List_in.get("MST: forest number", NumForests_);
00633 KeepDiag_ = List_in.get("MST: keep diagonal", KeepDiag_);
00634 Randomize_ = List_in.get("MST: randomize", Randomize_);
00635
00636 DiagPertRel_ = List_in.get("fact: relative threshold", DiagPertRel_);
00637 DiagPertAbs_ = List_in.get("fact: absolute threshold", DiagPertAbs_);
00638
00639 return(0);
00640 }
00641
00642 template<typename T>
00643 int Ifpack_SupportGraph<T>::Initialize()
00644 {
00645 IsInitialized_ = false;
00646 IsComputed_ = false;
00647
00648
00649 if (Time_ == Teuchos::null)
00650 {
00651 Time_ = Teuchos::rcp( new Epetra_Time(Comm()) );
00652 }
00653
00654
00655 Time_->ResetStartTime();
00656
00657 FindSupport();
00658
00659 Inverse_ = Teuchos::rcp(new T(Support_.get()));
00660
00661 IFPACK_CHK_ERR(Inverse_->Initialize());
00662
00663 IsInitialized_ = true;
00664 ++NumInitialize_;
00665 InitializeTime_ += Time_->ElapsedTime();
00666
00667 return(0);
00668
00669 }
00670
00671 template<typename T>
00672 int Ifpack_SupportGraph<T>::Compute()
00673 {
00674 if (IsInitialized() == false)
00675 IFPACK_CHK_ERR(Initialize());
00676
00677 Time_->ResetStartTime();
00678 IsComputed_ = false;
00679 Condest_ = -1.0;
00680
00681 IFPACK_CHK_ERR(Inverse_->Compute());
00682
00683 IsComputed_ = true;
00684 ++NumCompute_;
00685 ComputeTime_ += Time_->ElapsedTime();
00686
00687
00688 return(0);
00689 }
00690
00691 template<typename T>
00692 int Ifpack_SupportGraph<T>::SetUseTranspose(bool UseTranspose_in)
00693 {
00694
00695
00696 UseTranspose_ = UseTranspose_in;
00697
00698
00699 if (Inverse_!=Teuchos::null)
00700 IFPACK_CHK_ERR(Inverse_->SetUseTranspose(UseTranspose_in));
00701
00702 return(0);
00703 }
00704
00705 template<typename T>
00706 int Ifpack_SupportGraph<T>::
00707 Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00708 {
00709 IFPACK_CHK_ERR(Matrix_->Apply(X,Y));
00710 return(0);
00711 }
00712
00713 template<typename T>
00714 const char * Ifpack_SupportGraph<T>::Label() const
00715 {
00716 return(Label_.c_str());
00717 }
00718
00719 template<typename T>
00720 int Ifpack_SupportGraph<T>::
00721 ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00722 {
00723 if (!IsComputed())
00724 IFPACK_CHK_ERR(-3);
00725
00726 Time_->ResetStartTime();
00727
00728
00729 Inverse_->ApplyInverse(X,Y);
00730
00731 ++NumApplyInverse_;
00732 ApplyInverseTime_ += Time_->ElapsedTime();
00733
00734 return(0);
00735 }
00736
00737 template<typename T>
00738 std::ostream& Ifpack_SupportGraph<T>::
00739 Print(std::ostream& os) const
00740 {
00741 os << "================================================================================" << std::endl;
00742 os << "Ifpack_SupportGraph: " << Label () << endl << endl;
00743 os << "Condition number estimate = " << Condest() << endl;
00744 os << "Global number of rows = " << Matrix_->NumGlobalRows64() << endl;
00745 os << "Number of edges in support graph = " << (Support_->NumGlobalNonzeros64()-Support_->NumGlobalDiagonals64())/2 << endl;
00746 os << "Fraction of off diagonals of support graph/off diagonals of original = "
00747 << ((double)Support_->NumGlobalNonzeros64()-Support_->NumGlobalDiagonals64())/(Matrix_->NumGlobalNonzeros64()-Matrix_->NumGlobalDiagonals64());
00748 os << endl;
00749 os << "Phase # calls Total Time (s) Total MFlops MFlops/s" << endl;
00750 os << "----- ------- -------------- ------------ --------" << endl;
00751 os << "Initialize() " << std::setw(10) << NumInitialize_
00752 << " " << std::setw(15) << InitializeTime_
00753 << " 0.0 0.0" << endl;
00754 os << "Compute() " << std::setw(10) << NumCompute_
00755 << " " << std::setw(22) << ComputeTime_
00756 << " " << std::setw(15) << 1.0e-6 * ComputeFlops_;
00757 if (ComputeTime_ != 0.0)
00758 os << " " << std::setw(15) << 1.0e-6 * ComputeFlops_ / ComputeTime_ << endl;
00759 else
00760 os << " " << std::setw(15) << 0.0 << endl;
00761 os << "ApplyInverse() " << std::setw(10) << NumApplyInverse_
00762 << " " << std::setw(22) << ApplyInverseTime_
00763 << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops_;
00764 if (ApplyInverseTime_ != 0.0)
00765 os << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops_ / ApplyInverseTime_ << endl;
00766 else
00767 os << " " << std::setw(15) << 0.0 << endl;
00768
00769 os << std::endl << std::endl;
00770 os << "Now calling the underlying preconditioner's print()" << std::endl;
00771
00772 Inverse_->Print(os);
00773
00774 return os;
00775 }
00776
00777 template<typename T>
00778 double Ifpack_SupportGraph<T>::
00779 Condest(const Ifpack_CondestType CT, const int MaxIters,
00780 const double Tol, Epetra_RowMatrix* Matrix_in)
00781 {
00782 if (!IsComputed())
00783 {
00784 return(-1.0);
00785 }
00786
00787 Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00788
00789 return(Condest_);
00790 }
00791
00792 #endif // IFPACK_SUPPORTGRAPH_H