IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_SupportGraph.h
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
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 }; // class Ifpack_SupportGraph<T>
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   // Extract matrix dimensions                                                                  
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   // Assert square matrix                                                                       
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   // Rename for clarity                                                                         
00422   int num_verts = (int) rows;
00423 
00424   // Create data structures for the BGL code and temp data structures for extraction            
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   // Extract from the epetra matrix keeping only one edge per pair (assume symmetric)           
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               // Diagonal pertubation, only if requested
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                 // Add small random pertubation. 
00468                 weights[k] *= (1.0 + 1e-8 * drand48());
00469               }
00470 
00471           k++;
00472         }
00473     }
00474     }
00475   
00476   // Create BGL graph                                                                           
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   // Run Kruskal, actually maximal weight ST since edges are negative                           
00485   kruskal_minimum_spanning_tree(g, std::back_inserter(spanning_tree));
00486   
00487 
00488   std::vector<int> NumNz(num_verts,1);
00489 
00490   //Find the degree of all the vertices                                                         
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   // Create an stl vector of stl vectors to hold indices and values (neighbour edges)
00500   std::vector< std::vector< int > > Indices(num_verts);
00501   // TODO: Optimize for performance, may use arrays instead of vectors
00502   //std::vector<int> Indices[num_verts];
00503   //std::vector<double> Values[num_verts];
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   // Add each spanning forest (tree) to the support graph and 
00523   // remove it from original graph
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           // Assume standard Laplacian with constant row-sum.
00547           // Edge weights are negative, so subtract to make diagonal positive
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   // Set diagonal to weighted average of Laplacian preconditioner
00568   // and the original matrix
00569 
00570   // First compute the "diagonal surplus" (in the original input matrix)
00571   // If input is a (pure, Dirichlet) graph Laplacian , this will be 0
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   // Create the CrsMatrix for the support graph                                                 
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     // Fill in the matrix with the stl vectors for each row                                       
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     // Fill in the matrix with the stl vectors for each row                                       
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   // Diagonal pertubation parameters have weird names to be compatible with rest of Ifpack!
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   // store the flag -- it will be set in Initialize() if Inverse_ does not         
00695   // exist.   
00696   UseTranspose_ = UseTranspose_in;
00697 
00698   // If Inverse_ exists, pass it right now.                  
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()) // cannot compute right now
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
 All Classes Files Functions Variables Enumerations Friends