computation/solver/preconditioner/IlutPreconditioning.cxx

00001 // Copyright (C) 2010 Marc Duruflé
00002 //
00003 // This file is part of the linear-algebra library Seldon,
00004 // http://seldon.sourceforge.net/.
00005 //
00006 // Seldon is free software; you can redistribute it and/or modify it under the
00007 // terms of the GNU Lesser General Public License as published by the Free
00008 // Software Foundation; either version 2.1 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public License
00017 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00018 
00019 
00020 #ifndef SELDON_FILE_ILUT_PRECONDITIONING_CXX
00021 
00022 #include "SymmetricIlutPreconditioning.cxx"
00023 
00024 namespace Seldon
00025 {
00026 
00027   template<class real, class cplx, class Allocator>
00028   IlutPreconditioning<real, cplx, Allocator>::IlutPreconditioning()
00029   {
00030     print_level = 0;
00031     symmetric_algorithm = false;
00032     type_ilu = ILUT;
00033     fill_level = 1000000;
00034     additional_fill = 1000000;
00035     mbloc = 1000000;
00036     alpha = 1.0;
00037     droptol = 0.01;
00038     permtol = 0.1;
00039   }
00040 
00041 
00042   template<class real, class cplx, class Allocator>
00043   void IlutPreconditioning<real, cplx, Allocator>::Clear()
00044   {
00045     permutation_row.Clear();
00046     mat_sym.Clear();
00047     mat_unsym.Clear();
00048     xtmp.Clear();
00049   }
00050 
00051 
00052   template<class real, class cplx, class Allocator>
00053   int IlutPreconditioning<real, cplx, Allocator>::GetFactorisationType() const
00054   {
00055     return type_ilu;
00056   }
00057 
00058 
00059   template<class real, class cplx, class Allocator>
00060   int IlutPreconditioning<real, cplx, Allocator>::GetFillLevel() const
00061   {
00062     return fill_level;
00063   }
00064 
00065 
00066   template<class real, class cplx, class Allocator>
00067   int IlutPreconditioning<real, cplx, Allocator>::GetAdditionalFillNumber()
00068     const
00069   {
00070     return additional_fill;
00071   }
00072 
00073 
00074   template<class real, class cplx, class Allocator>
00075   int IlutPreconditioning<real, cplx, Allocator>::GetPrintLevel() const
00076   {
00077     return print_level;
00078   }
00079 
00080 
00081   template<class real, class cplx, class Allocator>
00082   int IlutPreconditioning<real, cplx, Allocator>::GetPivotBlockInteger() const
00083   {
00084     return mbloc;
00085   }
00086 
00087 
00088   template<class real, class cplx, class Allocator>
00089   void IlutPreconditioning<real, cplx, Allocator>
00090   ::SetFactorisationType(int type)
00091   {
00092     type_ilu = type;
00093   }
00094 
00095 
00096   template<class real, class cplx, class Allocator>
00097   void IlutPreconditioning<real, cplx, Allocator>::SetFillLevel(int level)
00098   {
00099     fill_level = level;
00100   }
00101 
00102 
00103   template<class real, class cplx, class Allocator>
00104   void IlutPreconditioning<real, cplx, Allocator>
00105   ::SetAdditionalFillNumber(int level)
00106   {
00107     additional_fill = level;
00108   }
00109 
00110 
00111   template<class real, class cplx, class Allocator>
00112   void IlutPreconditioning<real, cplx, Allocator>::SetPrintLevel(int level)
00113   {
00114     print_level = level;
00115   }
00116 
00117 
00118   template<class real, class cplx, class Allocator>
00119   void IlutPreconditioning<real, cplx, Allocator>::SetPivotBlockInteger(int i)
00120   {
00121     mbloc = i;
00122   }
00123 
00124 
00125   template<class real, class cplx, class Allocator>
00126   real IlutPreconditioning<real, cplx, Allocator>
00127   ::GetDroppingThreshold() const
00128   {
00129     return droptol;
00130   }
00131 
00132 
00133   template<class real, class cplx, class Allocator>
00134   real IlutPreconditioning<real, cplx, Allocator>
00135   ::GetDiagonalCoefficient() const
00136   {
00137     return alpha;
00138   }
00139 
00140 
00141   template<class real, class cplx, class Allocator>
00142   real IlutPreconditioning<real, cplx, Allocator>::GetPivotThreshold() const
00143   {
00144     return permtol;
00145   }
00146 
00147 
00148   template<class real, class cplx, class Allocator>
00149   void IlutPreconditioning<real, cplx, Allocator>
00150   ::SetDroppingThreshold(real tol)
00151   {
00152     droptol = tol;
00153   }
00154 
00155 
00156   template<class real, class cplx, class Allocator>
00157   void IlutPreconditioning<real, cplx, Allocator>
00158   ::SetDiagonalCoefficient(real beta)
00159   {
00160     alpha = beta;
00161   }
00162 
00163 
00164   template<class real, class cplx, class Allocator>
00165   void IlutPreconditioning<real, cplx, Allocator>::SetPivotThreshold(real tol)
00166   {
00167     permtol = tol;
00168   }
00169 
00170 
00171   template<class real, class cplx, class Allocator>
00172   void IlutPreconditioning<real, cplx, Allocator>::SetSymmetricAlgorithm()
00173   {
00174     symmetric_algorithm = true;
00175   }
00176 
00177 
00178   template<class real, class cplx, class Allocator>
00179   void IlutPreconditioning<real, cplx, Allocator>::SetUnsymmetricAlgorithm()
00180   {
00181     symmetric_algorithm = false;
00182   }
00183 
00184 
00185   template<class real, class cplx, class Allocator>
00186   template<class T0, class Storage0, class Allocator0>
00187   void IlutPreconditioning<real, cplx, Allocator>::
00188   FactorizeMatrix(const IVect& perm,
00189                   Matrix<T0, General, Storage0, Allocator0>& mat,
00190                   bool keep_matrix)
00191   {
00192     if (symmetric_algorithm)
00193       {
00194         cout << "Conversion to symmetric matrices not implemented." << endl;
00195         abort();
00196       }
00197     else
00198       FactorizeUnsymMatrix(perm, mat, keep_matrix);
00199   }
00200 
00201 
00202   template<class real, class cplx, class Allocator>
00203   template<class T0, class Storage0, class Allocator0>
00204   void IlutPreconditioning<real, cplx, Allocator>::
00205   FactorizeMatrix(const IVect& perm,
00206                   Matrix<T0, Symmetric, Storage0, Allocator0>& mat,
00207                   bool keep_matrix)
00208   {
00209     if (symmetric_algorithm)
00210       FactorizeSymMatrix(perm, mat, keep_matrix);
00211     else
00212       FactorizeUnsymMatrix(perm, mat, keep_matrix);
00213   }
00214 
00215 
00216   template<class real, class cplx, class Allocator>
00217   template<class MatrixSparse>
00218   void IlutPreconditioning<real, cplx, Allocator>::
00219   FactorizeSymMatrix(const IVect& perm, MatrixSparse& mat, bool keep_matrix)
00220   {
00221     IVect inv_permutation;
00222 
00223     // We convert matrix to symmetric format.
00224     Copy(mat, mat_sym);
00225 
00226     // Old matrix is erased if needed.
00227     if (!keep_matrix)
00228       mat.Clear();
00229 
00230     // We keep permutation array in memory, and check it.
00231     int n = mat_sym.GetM();
00232     if (perm.GetM() != n)
00233       {
00234         cout << "Numbering array should have the same size as matrix.";
00235         cout << endl;
00236         abort();
00237       }
00238 
00239     permutation_row.Reallocate(n);
00240     inv_permutation.Reallocate(n);
00241     inv_permutation.Fill(-1);
00242     for (int i = 0; i < n; i++)
00243       {
00244         permutation_row(i) = perm(i);
00245         inv_permutation(perm(i)) = i;
00246       }
00247 
00248     for (int i = 0; i < n; i++)
00249       if (inv_permutation(i) == -1)
00250         {
00251           cout << "Error in the numbering array." << endl;
00252           abort();
00253         }
00254 
00255     // Matrix is permuted.
00256     ApplyInversePermutation(mat_sym, perm, perm);
00257 
00258     // Temporary vector used for solving.
00259     xtmp.Reallocate(n);
00260 
00261     // Factorization is performed.
00262     GetIlut(*this, mat_sym);
00263   }
00264 
00265 
00266   template<class real, class cplx, class Allocator>
00267   template<class MatrixSparse>
00268   void IlutPreconditioning<real, cplx, Allocator>::
00269   FactorizeUnsymMatrix(const IVect& perm, MatrixSparse& mat, bool keep_matrix)
00270   {
00271     IVect inv_permutation;
00272 
00273     // We convert matrix to unsymmetric format.
00274     Copy(mat, mat_unsym);
00275 
00276     // Old matrix is erased if needed.
00277     if (!keep_matrix)
00278       mat.Clear();
00279 
00280     // We keep permutation array in memory, and check it.
00281     int n = mat_unsym.GetM();
00282     if (perm.GetM() != n)
00283       {
00284         cout << "Numbering array should have the same size as matrix.";
00285         cout << endl;
00286         abort();
00287       }
00288 
00289     permutation_row.Reallocate(n);
00290     permutation_col.Reallocate(n);
00291     inv_permutation.Reallocate(n);
00292     inv_permutation.Fill(-1);
00293     for (int i = 0; i < n; i++)
00294       {
00295         permutation_row(i) = i;
00296         permutation_col(i) = i;
00297         inv_permutation(perm(i)) = i;
00298       }
00299 
00300     for (int i = 0; i < n; i++)
00301       if (inv_permutation(i) == -1)
00302         {
00303           cout << "Error in the numbering array." << endl;
00304           abort();
00305         }
00306 
00307     IVect iperm = inv_permutation;
00308 
00309     // Rows of matrix are permuted.
00310     ApplyInversePermutation(mat_unsym, perm, perm);
00311 
00312     // Temporary vector used for solving.
00313     xtmp.Reallocate(n);
00314 
00315     // Factorization is performed.
00316     // Columns are permuted during the factorization.
00317     inv_permutation.Fill();
00318     GetIlut(*this, mat_unsym, permutation_col, inv_permutation);
00319 
00320     // Combining permutations.
00321     IVect itmp = permutation_col;
00322     for (int i = 0; i < n; i++)
00323       permutation_col(i) = iperm(itmp(i));
00324 
00325     permutation_row = perm;
00326   }
00327 
00328 
00329   template<class real, class cplx, class Allocator>
00330   template<class Matrix1, class Vector1>
00331   void IlutPreconditioning<real, cplx, Allocator>::
00332   Solve(const Matrix1& A, const Vector1& r, Vector1& z)
00333   {
00334     if (symmetric_algorithm)
00335       {
00336         for (int i = 0; i < r.GetM(); i++)
00337           xtmp(permutation_row(i)) = r(i);
00338 
00339         SolveLU(mat_sym, xtmp);
00340 
00341         for (int i = 0; i < r.GetM(); i++)
00342           z(i) = xtmp(permutation_row(i));
00343       }
00344     else
00345       {
00346         for (int i = 0; i < r.GetM(); i++)
00347           xtmp(permutation_row(i)) = r(i);
00348 
00349         SolveLU(mat_unsym, xtmp);
00350 
00351         for (int i = 0; i < r.GetM(); i++)
00352           z(permutation_col(i)) = xtmp(i);
00353       }
00354   }
00355 
00356 
00357   template<class real, class cplx, class Allocator>
00358   template<class Matrix1, class Vector1>
00359   void IlutPreconditioning<real, cplx, Allocator>::
00360   TransSolve(const Matrix1& A, const Vector1& r, Vector1& z)
00361   {
00362     if (symmetric_algorithm)
00363       Solve(A, r, z);
00364     else
00365       {
00366         for (int i = 0; i < r.GetM(); i++)
00367           xtmp(i) = r(permutation_col(i));
00368 
00369         SolveLU(SeldonTrans, mat_unsym, xtmp);
00370 
00371         for (int i = 0; i < r.GetM(); i++)
00372           z(i) = xtmp(permutation_row(i));
00373       }
00374   }
00375 
00376 
00377   template<class real, class cplx, class Allocator>
00378   template<class Vector1>
00379   void IlutPreconditioning<real, cplx, Allocator>::Solve(Vector1& z)
00380   {
00381     if (symmetric_algorithm)
00382       {
00383         for (int i = 0; i < z.GetM(); i++)
00384           xtmp(permutation_row(i)) = z(i);
00385 
00386         SolveLU(mat_sym, xtmp);
00387 
00388         for (int i = 0; i < z.GetM(); i++)
00389           z(i) = xtmp(permutation_row(i));
00390       }
00391     else
00392       {
00393         for (int i = 0; i < z.GetM(); i++)
00394           xtmp(permutation_row(i)) = z(i);
00395 
00396         SolveLU(mat_unsym, xtmp);
00397 
00398         for (int i = 0; i < z.GetM(); i++)
00399           z(permutation_col(i)) = xtmp(i);
00400       }
00401   }
00402 
00403 
00404   template<class real, class cplx, class Allocator>
00405   template<class Vector1>
00406   void IlutPreconditioning<real, cplx, Allocator>::TransSolve(Vector1& z)
00407   {
00408     if (symmetric_algorithm)
00409       Solve(z);
00410     else
00411       {
00412         for (int i = 0; i < z.GetM(); i++)
00413           xtmp(i) = z(permutation_col(i));
00414 
00415         SolveLU(SeldonTrans, mat_unsym, xtmp);
00416 
00417         for (int i = 0; i < z.GetM(); i++)
00418           z(i) = xtmp(permutation_row(i));
00419       }
00420   }
00421 
00422 
00423   template<class real, class cplx, class Storage, class Allocator>
00424   void qsplit_ilut(Vector<cplx, Storage, Allocator>& a, IVect& ind, int first,
00425                    int n, int ncut, const real& abs_ncut)
00426   {
00427     //-----------------------------------------------------------------------
00428     //     does a quick-sort split of a real array.
00429     //     on input a(1:n). is a real array
00430     //     on output a(1:n) is permuted such that its elements satisfy:
00431     //
00432     //     abs(a(i)) .ge. abs(a(ncut)) for i .lt. ncut and
00433     //     abs(a(i)) .le. abs(a(ncut)) for i .gt. ncut
00434     //
00435     //     ind is an integer array which permuted in the same way as a
00436     //-----------------------------------------------------------------------
00437     int last = n-1;
00438     int ncut_ = ncut-1;
00439     int first_ = first;
00440 
00441     if ((ncut_ < first_) || (ncut_ > last))
00442       return;
00443 
00444     cplx tmp; real abskey;
00445     int mid, itmp;
00446     bool test_loop = true;
00447 
00448     //     outer loop -- while mid .ne. ncut do
00449     while (test_loop)
00450       {
00451         mid = first_;
00452         abskey = abs(a(mid));
00453         for (int j = (first_+1); j <= last; j++)
00454           {
00455             if (abs(a(j)) > abskey)
00456               {
00457                 mid++;
00458                 // Interchange.
00459                 tmp = a(mid);
00460                 itmp = ind(mid);
00461                 a(mid) = a(j);
00462                 ind(mid) = ind(j);
00463                 a(j)  = tmp;
00464                 ind(j) = itmp;
00465               }
00466           }
00467 
00468         // Interchange.
00469         tmp = a(mid);
00470         a(mid) = a(first_);
00471         a(first_)  = tmp;
00472 
00473         itmp = ind(mid);
00474         ind(mid) = ind(first_);
00475         ind(first_) = itmp;
00476 
00477         // Test for while loop.
00478         if (mid == ncut_)
00479           return;
00480 
00481         if (mid > ncut_)
00482           last = mid-1;
00483         else
00484           first_ = mid+1;
00485       }
00486   }
00487 
00488 
00490   template<class real, class cplx, class Allocator1, class Allocator2>
00491   void GetIlut(const IlutPreconditioning<real, cplx, Allocator1>& param,
00492                Matrix<cplx, General, ArrayRowSparse, Allocator2>& A,
00493                IVect& iperm, IVect& rperm)
00494   {
00495     int size_row;
00496     int n = A.GetN();
00497     int type_factorisation = param.GetFactorisationType();
00498     int lfil = param.GetFillLevel();
00499     real zero(0);
00500     real droptol = param.GetDroppingThreshold();
00501     real alpha = param.GetDiagonalCoefficient();
00502     bool variable_fill = false;
00503     bool standard_dropping = true;
00504     int additional_fill = param.GetAdditionalFillNumber();
00505     int mbloc = param.GetPivotBlockInteger();
00506     real permtol = param.GetPivotThreshold();
00507     int print_level = param.GetPrintLevel();
00508 
00509     if (type_factorisation == param.ILUT)
00510       standard_dropping = false;
00511     else if (type_factorisation == param.ILU_D)
00512       standard_dropping = true;
00513     else if (type_factorisation == param.ILUT_K)
00514       {
00515         variable_fill = true;   // We use a variable lfil
00516         standard_dropping = false;
00517       }
00518     else if (type_factorisation == param.ILU_0)
00519       {
00520         GetIlu0(A);
00521         return;
00522       }
00523     else if (type_factorisation == param.MILU_0)
00524       {
00525         GetMilu0(A);
00526         return;
00527       }
00528     else if (type_factorisation == param.ILU_K)
00529       {
00530         GetIluk(lfil, A);
00531         return;
00532       }
00533 
00534     cplx fact, s, t;
00535     real tnorm;
00536     int length_lower, length_upper, jpos, jrow, i_row, j_col;
00537     int i, j, k, index_lu, length;
00538 
00539 
00540     if (lfil < 0)
00541       {
00542         cout << "Incorrect fill level." << endl;
00543         abort();
00544       }
00545 
00546     cplx czero, cone;
00547     SetComplexZero(czero);
00548     SetComplexOne(cone);
00549     typedef Vector<cplx, VectFull, Allocator2> VectCplx;
00550     VectCplx Row_Val(n);
00551     IVect Index(n), Row_Ind(n), Index_Diag(n);
00552     Row_Val.Fill(czero);
00553     Row_Ind.Fill(-1);
00554     Index_Diag.Fill(-1);
00555 
00556     Index.Fill(-1);
00557 
00558     bool element_dropped; cplx dropsum;
00559 
00560     // main loop
00561     int new_percent = 0, old_percent = 0;
00562     for (i_row = 0; i_row < n; i_row++)
00563       {
00564         // Progress bar if print level is high enough.
00565         if (print_level > 0)
00566           {
00567             new_percent = int(double(i_row)/(n-1)*80);
00568             for (int percent = old_percent; percent < new_percent; percent++)
00569               {
00570                 cout << "#"; cout.flush();
00571               }
00572 
00573             old_percent = new_percent;
00574           }
00575 
00576         size_row = A.GetRowSize(i_row);
00577         tnorm = zero;
00578 
00579         dropsum = czero;
00580         for (k = 0 ; k < size_row; k++)
00581           if (A.Value(i_row, k) != czero)
00582             tnorm += abs(A.Value(i_row, k));
00583 
00584         if (tnorm == zero)
00585           {
00586             cout << "Structurally singular matrix." << endl;
00587             cout << "Norm of row " << i_row << " is equal to 0." << endl;
00588             abort();
00589           }
00590 
00591         // tnorm is the sum of absolute value of coefficients of row i_row.
00592         tnorm /= real(size_row);
00593         if (variable_fill)
00594           lfil = size_row + additional_fill;
00595 
00596         // Unpack L-part and U-part of row of A.
00597         length_upper = 1;
00598         length_lower = 0;
00599         Row_Ind(i_row) = i_row;
00600         Row_Val(i_row) = czero;
00601         Index(i_row) = i_row;
00602 
00603         for (j = 0; j < size_row; j++)
00604           {
00605             k = rperm(A.Index(i_row, j));
00606 
00607             t = A.Value(i_row,j);
00608             if (k < i_row)
00609               {
00610                 Row_Ind(length_lower) = k;
00611                 Row_Val(length_lower) = t;
00612                 Index(k) = length_lower;
00613                 ++length_lower;
00614               }
00615             else if (k == i_row)
00616               {
00617                 Row_Val(i_row) = t;
00618               }
00619             else
00620               {
00621                 jpos = i_row + length_upper;
00622                 Row_Ind(jpos) = k;
00623                 Row_Val(jpos) = t;
00624                 Index(k) = jpos;
00625                 length_upper++;
00626               }
00627           }
00628 
00629         j_col = 0;
00630         length = 0;
00631 
00632         // Eliminates previous rows.
00633         while (j_col < length_lower)
00634           {
00635             // In order to do the elimination in the correct order, we must
00636             // select the smallest column index.
00637             jrow = Row_Ind(j_col);
00638             k = j_col;
00639 
00640             // Determine smallest column index.
00641             for (j = j_col + 1; j < length_lower; j++)
00642               {
00643                 if (Row_Ind(j) < jrow)
00644                   {
00645                     jrow = Row_Ind(j);
00646                     k = j;
00647                   }
00648               }
00649 
00650             if (k != j_col)
00651               {
00652                 // Exchanging column coefficients.
00653                 j = Row_Ind(j_col);
00654                 Row_Ind(j_col) = Row_Ind(k);
00655                 Row_Ind(k) = j;
00656 
00657                 Index(jrow) = j_col;
00658                 Index(j) = k;
00659 
00660                 s = Row_Val(j_col);
00661                 Row_Val(j_col) = Row_Val(k);
00662                 Row_Val(k) = s;
00663               }
00664 
00665             // Zero out element in row.
00666             Index(jrow) = -1;
00667 
00668             element_dropped = false;
00669             if (standard_dropping)
00670               if (abs(Row_Val(j_col)) <= droptol*tnorm)
00671                 {
00672                   dropsum += Row_Val(j_col);
00673                   element_dropped = true;
00674                 }
00675 
00676             // Gets the multiplier for row to be eliminated (jrow).
00677             if (!element_dropped)
00678               {
00679                 // first_index_upper points now on the diagonal coefficient.
00680                 fact = Row_Val(j_col) * A.Value(jrow, Index_Diag(jrow));
00681 
00682                 if (!standard_dropping)
00683                   {
00684                     if (abs(fact) <= droptol)
00685                       element_dropped = true;
00686                   }
00687               }
00688 
00689             if (!element_dropped)
00690               {
00691                 // Combines current row and row jrow.
00692                 for (k = (Index_Diag(jrow)+1); k < A.GetRowSize(jrow); k++)
00693                   {
00694                     s = fact * A.Value(jrow,k);
00695                     j = rperm(A.Index(jrow,k));
00696 
00697                     jpos = Index(j);
00698 
00699                     if (j >= i_row)
00700                       {
00701 
00702                         // Dealing with upper part.
00703                         if (jpos == -1)
00704                           {
00705                             // This is a fill-in element.
00706                             i = i_row + length_upper;
00707                             Row_Ind(i) = j;
00708                             Index(j) = i;
00709                             Row_Val(i) = -s;
00710                             ++length_upper;
00711                           }
00712                         else
00713                           {
00714                             // This is not a fill-in element.
00715                             Row_Val(jpos) -= s;
00716                           }
00717                       }
00718                     else
00719                       {
00720                         // Dealing  with lower part.
00721                         if (jpos == -1)
00722                           {
00723                             // this is a fill-in element
00724                             Row_Ind(length_lower) = j;
00725                             Index(j) = length_lower;
00726                             Row_Val(length_lower) = -s;
00727                             ++length_lower;
00728                           }
00729                         else
00730                           {
00731                             // This is not a fill-in element.
00732                             Row_Val(jpos) -= s;
00733                           }
00734                       }
00735                   }
00736 
00737                 // Stores this pivot element from left to right -- no danger
00738                 // of overlap with the working elements in L (pivots).
00739                 Row_Val(length) = fact;
00740                 Row_Ind(length) = jrow;
00741                 ++length;
00742               }
00743 
00744             j_col++;
00745           }
00746 
00747         // Resets double-pointer to zero (U-part).
00748         for (k = 0; k < length_upper; k++)
00749           Index(Row_Ind(i_row+k )) = -1;
00750 
00751         // Updates L-matrix.
00752         if (!standard_dropping)
00753           {
00754             length_lower = length;
00755             length = min(length_lower,lfil);
00756 
00757             // Sorts by quick-split.
00758             qsplit_ilut(Row_Val, Row_Ind, 0, length_lower, length,tnorm);
00759           }
00760 
00761         size_row = length;
00762         A.ReallocateRow(i_row,size_row);
00763 
00764         // store L-part
00765         index_lu = 0;
00766         for (k = 0 ; k < length ; k++)
00767           {
00768             A.Value(i_row,index_lu) = Row_Val(k);
00769             A.Index(i_row,index_lu) = iperm(Row_Ind(k));
00770             ++index_lu;
00771           }
00772 
00773         // Saves pointer to beginning of row i_row of U.
00774         Index_Diag(i_row) = index_lu;
00775 
00776         // Updates. U-matrix -- first apply dropping strategy.
00777         length = 0;
00778         for (k = 1; k <= (length_upper-1); k++)
00779           {
00780             if (abs(Row_Val(i_row+k)) > droptol * tnorm)
00781               {
00782                 ++length;
00783                 Row_Val(i_row+length) = Row_Val(i_row+k);
00784                 Row_Ind(i_row+length) = Row_Ind(i_row+k);
00785               }
00786             else
00787               dropsum += Row_Val(i_row+k);
00788           }
00789 
00790         if (!standard_dropping)
00791           {
00792             length_upper = length + 1;
00793             length = min(length_upper,lfil);
00794 
00795             qsplit_ilut(Row_Val, Row_Ind, i_row+1,
00796                         i_row+length_upper, i_row+length+1, tnorm);
00797           }
00798         else
00799           length++;
00800 
00801         // Determines next pivot.
00802         int imax = i_row;
00803         real xmax = abs(Row_Val(imax));
00804         real xmax0 = xmax;
00805         int icut = i_row + mbloc - 1 - i_row%mbloc;
00806         for ( k = i_row + 1; k <= i_row + length - 1; k++)
00807           {
00808             tnorm = abs(Row_Val(k));
00809             if ((tnorm > xmax) && (tnorm*permtol > xmax0)
00810                 && (Row_Ind(k)<= icut))
00811               {
00812                 imax = k;
00813                 xmax = tnorm;
00814               }
00815           }
00816 
00817         // Exchanges Row_Val.
00818         s = Row_Val(i_row);
00819         Row_Val(i_row) = Row_Val(imax);
00820         Row_Val(imax) = s;
00821 
00822         // Updates iperm and reverses iperm.
00823         j = Row_Ind(imax);
00824         i = iperm(i_row);
00825         iperm(i_row) = iperm(j);
00826         iperm(j) = i;
00827 
00828         // Reverses iperm.
00829         rperm(iperm(i_row)) = i_row;
00830         rperm(iperm(j)) = j;
00831 
00832         // Copies U-part in original coordinates.
00833         int index_diag = index_lu;
00834         A.ResizeRow(i_row, size_row+length);
00835 
00836         for (k = i_row ; k <= i_row + length - 1; k++)
00837           {
00838             A.Index(i_row,index_lu) = iperm(Row_Ind(k));
00839             A.Value(i_row,index_lu) = Row_Val(k);
00840             ++index_lu;
00841           }
00842 
00843         // Stores inverse of diagonal element of u.
00844         if (standard_dropping)
00845           Row_Val(i_row) += alpha*dropsum;
00846 
00847         if (Row_Val(i_row) == czero)
00848           Row_Val(i_row) = (droptol + 1e-4) * tnorm;
00849 
00850         A.Value(i_row, index_diag) = cone / Row_Val(i_row);
00851 
00852       } // end main loop
00853 
00854     if (print_level > 0)
00855       cout << endl;
00856 
00857     if (print_level > 0)
00858       cout << "The matrix takes " <<
00859         int((A.GetDataSize()*(sizeof(cplx)+4))/(1024*1024)) << " MB" << endl;
00860 
00861     for (i = 0; i < n; i++ )
00862       for (j = 0; j < A.GetRowSize(i); j++)
00863         A.Index(i,j) = rperm(A.Index(i,j));
00864   }
00865 
00866 
00867   template<class cplx, class Allocator>
00868   void GetIluk(int lfil, Matrix<cplx, General, ArrayRowSparse, Allocator>& A)
00869   {
00870     int n = A.GetM();
00871     Vector<cplx, VectFull, CallocAlloc<cplx> > w;
00872     w.Reallocate(n+1);
00873     IVect jw(3*n), Index_Diag(n);
00874     Vector<IVect, VectFull, NewAlloc<IVect> > levs(n);
00875 
00876     cplx czero, cone;
00877     SetComplexZero(czero);
00878     SetComplexOne(cone);
00879 
00880     // Local variables
00881     cplx fact, s, t;
00882     int length_lower,length_upper, jpos, jrow, i_row, j_col;
00883     int i, j, k, index_lu, length;
00884     bool element_dropped;
00885 
00886     int n2 = 2*n, jlev, k_, size_upper;
00887     jw.Fill(-1);
00888 
00889     // Main loop.
00890     for (i_row = 0; i_row < n; i_row++)
00891       {
00892         int size_row = A.GetRowSize(i_row);
00893 
00894         // Unpacks L-part and U-part of row of A in arrays w, jw.
00895         length_upper = 1;
00896         length_lower = 0;
00897         jw(i_row) = i_row;
00898         w(i_row) = 0.0;
00899         jw(n + i_row) = i_row;
00900 
00901         for (j = 0; j < size_row; j++)
00902           {
00903             k = A.Index(i_row,j);
00904             t = A.Value(i_row,j);
00905             if (k < i_row)
00906               {
00907                 jw(length_lower) = k;
00908                 w(length_lower) = t;
00909                 jw(n + k) = length_lower;
00910                 jw(n2+length_lower) = -1;
00911                 ++length_lower;
00912               }
00913             else if (k == i_row)
00914               {
00915                 w(i_row) = t;
00916                 jw(n2+length_lower) = -1;
00917               }
00918             else
00919               {
00920                 jpos = i_row + length_upper;
00921                 jw(jpos) = k;
00922                 w(jpos) = t;
00923                 jw(n + k) = jpos;
00924                 length_upper++;
00925               }
00926           }
00927 
00928         j_col = 0;
00929         length = 0;
00930 
00931 
00932         // Eliminates previous rows.
00933         while (j_col <length_lower)
00934           {
00935             // In order to do the elimination in the correct order, we must
00936             // select the smallest column index among jw(k); k = j_col + 1,
00937             // ..., length_lower.
00938             jrow = jw(j_col);
00939             k = j_col;
00940 
00941             // Determines smallest column index.
00942             for (j = (j_col+1) ; j < length_lower; j++)
00943               {
00944                 if (jw(j) < jrow)
00945                   {
00946                     jrow = jw(j);
00947                     k = j;
00948                   }
00949               }
00950 
00951             if (k != j_col)
00952               {
00953                 // Exchanges in jw.
00954                 j = jw(j_col);
00955                 jw(j_col) = jw(k);
00956                 jw(k) = j;
00957 
00958                 // Exchanges in jw(n+  (pointers/ nonzero indicator).
00959                 jw(n+jrow) = j_col;
00960                 jw(n+j) = k;
00961 
00962                 // Exchanges in jw(n2+  (levels).
00963                 j = jw(n2+j_col);
00964                 jw(n2+j_col)  = jw(n2+k);
00965                 jw(n2+k) = j;
00966 
00967                 // Exchanges in w.
00968                 s = w(j_col);
00969                 w(j_col) = w(k);
00970                 w(k) = s;
00971               }
00972 
00973             // Zero out element in row by setting jw(n+jrow) to zero.
00974             jw(n + jrow) = -1;
00975 
00976             element_dropped = false;
00977 
00978             // Gets the multiplier for row to be eliminated (jrow).
00979             fact = w(j_col) * A.Value(jrow,Index_Diag(jrow));
00980 
00981             jlev = jw(n2+j_col) + 1;
00982             if (jlev > lfil)
00983               element_dropped = true;
00984 
00985             if (!element_dropped)
00986               {
00987                 // Combines current row and row jrow.
00988                 k_ = 0;
00989                 for (k = (Index_Diag(jrow)+1); k < A.GetRowSize(jrow) ; k++)
00990                   {
00991                     s = fact * A.Value(jrow,k);
00992                     j = A.Index(jrow,k);
00993 
00994                     jpos = jw(n + j);
00995                     if (j >= i_row)
00996                       {
00997                         // Dealing with upper part.
00998                         if (jpos == -1)
00999                           {
01000                             // This is a fill-in element.
01001                             i = i_row + length_upper;
01002                             jw(i) = j;
01003                             jw(n + j) = i;
01004                             w(i) = -s;
01005 
01006                             jw(n2+i) = jlev + levs(jrow)(k_) + 1;
01007                             ++length_upper;
01008                           }
01009                         else
01010                           {
01011                             // This is not a fill-in element.
01012                             w(jpos) -= s;
01013                             jw(n2+jpos) = min(jw(n2+jpos),
01014                                               jlev + levs(jrow)(k_)+1);
01015                           }
01016                       }
01017                     else
01018                       {
01019                         // Dealing  with lower part.
01020                         if (jpos == -1)
01021                           {
01022                             // This is a fill-in element.
01023                             jw(length_lower) = j;
01024                             jw(n + j) = length_lower;
01025                             w(length_lower) = -s;
01026                             jw(n2+length_lower) = jlev + levs(jrow)(k_) + 1;
01027                             ++length_lower;
01028                           }
01029                         else
01030                           {
01031                             // This is not a fill-in element.
01032                             w(jpos) -= s;
01033                             jw(n2+jpos) = min(jw(n2 + jpos),
01034                                               jlev + levs(jrow)(k_) + 1);
01035                           }
01036                       }
01037 
01038                     k_++;
01039                   }
01040 
01041               }
01042 
01043             // Stores this pivot element from left to right -- no danger of
01044             // overlap with the working elements in L (pivots).
01045             w(j_col) = fact;
01046             jw(j_col) = jrow;
01047 
01048             j_col++;
01049           }
01050 
01051         // Resets double-pointer to zero (U-part).
01052         for (k = 0; k < length_upper; k++)
01053           jw(n + jw(i_row + k )) = -1;
01054 
01055         // Updates L-matrix.
01056         size_row = 1; // we have the diagonal value.
01057         // Size of L-matrix.
01058         for (k = 0; k < length_lower; k++)
01059           if (jw(n2+k) < lfil)
01060             size_row++;
01061 
01062         // Size of U-matrix.
01063         size_upper = 0;
01064         for (k = (i_row+1) ; k <= (i_row+length_upper-1) ; k++)
01065           if (jw(n2+k) < lfil)
01066             size_upper++;
01067 
01068         size_row += size_upper;
01069         A.ReallocateRow(i_row,size_row);
01070         levs(i_row).Reallocate(size_upper);
01071 
01072         index_lu = 0;
01073         for (k = 0; k < length_lower; k++)
01074           {
01075             if (jw(n2+k) < lfil)
01076               {
01077                 A.Value(i_row,index_lu) = w(k);
01078                 A.Index(i_row,index_lu) = jw(k);
01079                 ++index_lu;
01080               }
01081           }
01082 
01083         // Saves pointer to beginning of row i_row of U.
01084         Index_Diag(i_row) = index_lu;
01085         A.Value(i_row,index_lu) = cone / w(i_row);
01086         A.Index(i_row,index_lu++) = i_row;
01087 
01088         for (k = (i_row+1) ; k <= (i_row+length_upper-1) ; k++)
01089           {
01090             if (jw(n2+k) < lfil)
01091               {
01092                 A.Index(i_row,index_lu) = jw(k);
01093                 A.Value(i_row,index_lu) = w(k);
01094                 levs(i_row)(index_lu-Index_Diag(i_row)-1) = jw(n2+k);
01095                 ++index_lu;
01096               }
01097           }
01098       }
01099   }
01100 
01101 
01102   template<class cplx, class Allocator>
01103   void GetIlu0(Matrix<cplx, General, ArrayRowSparse, Allocator>& A)
01104   {
01105     int j_col, jrow, jw, n = A.GetM();
01106     IVect Index(n), ju(n);
01107 
01108     cplx czero, cone;
01109     SetComplexZero(czero);
01110     SetComplexOne(cone);
01111 
01112     // Initializes work vector to zero's.
01113     Index.Fill(-1); ju.Fill(-1);
01114     cplx tl;
01115 
01116     // Main loop.
01117     for (int i_row = 0 ; i_row < n ; i_row++)
01118       {
01119         // Generating row number i_row of L and U.
01120         for (int j = 0 ; j < A.GetRowSize(i_row) ; j++ )
01121           {
01122             j_col = A.Index(i_row, j);
01123             if (j_col == i_row)
01124               ju(i_row) = j;
01125 
01126             Index(j_col) = j;
01127           }
01128 
01129         int jm = ju(i_row)-1;
01130 
01131         // Exit if diagonal element is reached.
01132         for (int j = 0; j <= jm; j++)
01133           {
01134             jrow = A.Index(i_row, j);
01135             tl = A.Value(i_row, j)*A.Value(jrow, ju(jrow));
01136             A.Value(i_row, j) = tl;
01137 
01138             // Performs linear combination.
01139             for ( j_col = (ju(jrow)+1); j_col < A.GetRowSize(jrow); j_col++)
01140               {
01141                 jw = Index(A.Index(jrow,j_col));
01142                 if (jw != -1)
01143                   A.Value(i_row, jw) -= tl*A.Value(jrow, j_col);
01144               }
01145           }
01146 
01147 
01148         // Inverts and stores diagonal element.
01149         if (A.Value(i_row, ju(i_row)) == czero)
01150           {
01151             cout << "Factorization fails because we found a null coefficient"
01152                  << " on diagonal " << i_row << endl;
01153             abort();
01154           }
01155 
01156         A.Value(i_row,ju(i_row)) = cone / A.Value(i_row,ju(i_row));
01157 
01158         // Resets pointer Index to zero.
01159         Index(i_row) = -1;
01160         for (int i = 0; i < A.GetRowSize(i_row); i++)
01161           Index(A.Index(i_row, i)) = -1;
01162       }
01163 
01164   }
01165 
01166 
01167   template<class cplx, class Allocator>
01168   void GetMilu0(Matrix<cplx, General, ArrayRowSparse, Allocator>& A)
01169   {
01170     int j_col, jrow, jw, n = A.GetM();
01171     IVect Index(n), ju(n);
01172 
01173     cplx czero, cone;
01174     SetComplexZero(czero);
01175     SetComplexOne(cone);
01176 
01177     // Initializes work vector to zero's.
01178     Index.Fill(-1); ju.Fill(-1);
01179     cplx tl;
01180 
01181     // Main loop.
01182     for (int i_row = 0 ; i_row < n ; i_row++)
01183       {
01184         // Generating row number i_row of L and U.
01185         for (int j = 0; j < A.GetRowSize(i_row); j++ )
01186           {
01187             j_col = A.Index(i_row, j);
01188             if (j_col == i_row)
01189               ju(i_row) = j;
01190 
01191             Index(j_col) = j;
01192           }
01193 
01194         int jm = ju(i_row)-1;
01195         // Exit if diagonal element is reached.
01196         // s accumulates fill-in values.
01197         cplx s(0);
01198         for (int j = 0; j <= jm; j++)
01199           {
01200             jrow = A.Index(i_row, j);
01201             tl = A.Value(i_row, j)*A.Value(jrow, ju(jrow));
01202             A.Value(i_row, j) = tl;
01203 
01204             // Performs linear combination.
01205             for ( j_col = (ju(jrow)+1); j_col < A.GetRowSize(jrow); j_col++ )
01206               {
01207                 jw = Index(A.Index(jrow, j_col));
01208                 if (jw != -1)
01209                   A.Value(i_row, jw) -= tl*A.Value(jrow, j_col);
01210                 else
01211                   s += tl*A.Value(jrow, j_col);
01212               }
01213           }
01214 
01215         // Inverts and stores diagonal element.
01216         A.Value(i_row, ju(i_row)) -= s;
01217         if (A.Value(i_row, ju(i_row)) == czero)
01218           {
01219             cout << "Factorization fails because we found a null coefficient"
01220                  << " on diagonal " << i_row << endl;
01221             abort();
01222           }
01223 
01224         A.Value(i_row, ju(i_row)) = cone /A.Value(i_row, ju(i_row));
01225 
01226         // Resets pointer Index to zero.
01227         Index(i_row) = -1;
01228         for (int i = 0; i < A.GetRowSize(i_row); i++)
01229           Index(A.Index(i_row, i)) = -1;
01230       }
01231   }
01232 
01233 
01235 
01238   template<class real, class cplx, class Allocator,
01239            class Storage2, class Allocator2>
01240   void SolveLU(const Matrix<real, General, ArrayRowSparse, Allocator>& A,
01241                Vector<cplx, Storage2, Allocator2>& x)
01242   {
01243     int i, k, n, k_;
01244     real inv_diag;
01245     n = A.GetM();
01246 
01247     // Forward solve.
01248     for (i = 0; i < n; i++)
01249       {
01250         k_ = 0; k = A.Index(i,k_);
01251         while ( k < i)
01252           {
01253             x(i) -= A.Value(i,k_)*x(k);
01254             k_++;
01255             k = A.Index(i,k_);
01256           }
01257       }
01258 
01259     // Backward solve.
01260     for (i = n-1; i >= 0; i--)
01261       {
01262         k_ = 0; k = A.Index(i,k_);
01263         while ( k < i)
01264           {
01265             k_++;
01266             k = A.Index(i,k_);
01267           }
01268 
01269         inv_diag = A.Value(i,k_);
01270         for ( k = (k_+1); k < A.GetRowSize(i) ; k++)
01271           x(i) -= A.Value(i,k) * x(A.Index(i,k));
01272 
01273         x(i) *= inv_diag;
01274       }
01275   }
01276 
01277 
01278   template<class cplx, class Allocator, class Storage2, class Allocator2>
01279   void SolveLU(const class_SeldonTrans& transA,
01280                const Matrix<cplx, General, ArrayRowSparse, Allocator>& A,
01281                Vector<cplx,Storage2,Allocator2>& x)
01282   {
01283     int i, k, n, k_;
01284     n = A.GetM();
01285 
01286     // Forward solve (with U^T).
01287     for (i = 0 ; i < n ; i++)
01288       {
01289         k_ = 0; k = A.Index(i,k_);
01290         while ( k < i)
01291           {
01292             k_++;
01293             k = A.Index(i,k_);
01294           }
01295 
01296         x(i) *= A.Value(i,k_);
01297         for ( k = (k_+1); k < A.GetRowSize(i) ; k++)
01298           {
01299             x(A.Index(i,k)) -= A.Value(i,k) * x(i);
01300           }
01301       }
01302 
01303     // Backward solve (with L^T).
01304     for (i = n-1 ; i>=0  ; i--)
01305       {
01306         k_ = 0; k = A.Index(i,k_);
01307         while ( k < i)
01308           {
01309             x(k) -= A.Value(i,k_)*x(i);
01310             k_++;
01311             k = A.Index(i,k_);
01312           }
01313       }
01314   }
01315 
01316 }
01317 
01318 #define SELDON_FILE_ILUT_PRECONDITIONING_CXX
01319 #endif