IlutPreconditioning.cxx
1 // Copyright (C) 2010 Marc DuruflĂ©
2 //
3 // This file is part of the linear-algebra library Seldon,
4 // http://seldon.sourceforge.net/.
5 //
6 // Seldon is free software; you can redistribute it and/or modify it under the
7 // terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 2.1 of the License, or (at your option)
9 // any later version.
10 //
11 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
14 // more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with Seldon. If not, see http://www.gnu.org/licenses/.
18 
19 
20 #ifndef SELDON_FILE_ILUT_PRECONDITIONING_CXX
21 
22 #include "SymmetricIlutPreconditioning.cxx"
23 
24 namespace Seldon
25 {
26 
27  template<class cplx, class Allocator>
28  IlutPreconditioning<cplx, Allocator>::IlutPreconditioning()
29  {
30  print_level = 0;
31  symmetric_algorithm = false;
32  type_ilu = ILUT;
33  fill_level = 1000000;
34  additional_fill = 1000000;
35  mbloc = 1000000;
36  alpha = 1.0;
37  droptol = 0.01;
38  permtol = 0.1;
39  }
40 
41 
42  template<class cplx, class Allocator>
43  void IlutPreconditioning<cplx, Allocator>::Clear()
44  {
45  permutation_row.Clear();
46  mat_sym.Clear();
47  mat_unsym.Clear();
48  }
49 
50 
51  template<class cplx, class Allocator>
52  bool IlutPreconditioning<cplx, Allocator>::UseInteger8() const
53  {
54  return false;
55  }
56 
57 
58  template<class cplx, class Allocator>
59  void IlutPreconditioning<cplx, Allocator>::HideMessages()
60  {
61  print_level = 0;
62  }
63 
64 
65  template<class cplx, class Allocator>
66  void IlutPreconditioning<cplx, Allocator>::ShowMessages()
67  {
68  print_level = 1;
69  }
70 
71 
72  template<class cplx, class Allocator>
73  int IlutPreconditioning<cplx, Allocator>::GetFactorisationType() const
74  {
75  return type_ilu;
76  }
77 
78 
79  template<class cplx, class Allocator>
80  int IlutPreconditioning<cplx, Allocator>::GetFillLevel() const
81  {
82  return fill_level;
83  }
84 
85 
86  template<class cplx, class Allocator>
87  int IlutPreconditioning<cplx, Allocator>::GetAdditionalFillNumber()
88  const
89  {
90  return additional_fill;
91  }
92 
93 
94  template<class cplx, class Allocator>
95  int IlutPreconditioning<cplx, Allocator>::GetPrintLevel() const
96  {
97  return print_level;
98  }
99 
100 
101  template<class cplx, class Allocator>
102  int IlutPreconditioning<cplx, Allocator>::GetPivotBlockInteger() const
103  {
104  return mbloc;
105  }
106 
107 
108  template<class cplx, class Allocator>
109  size_t IlutPreconditioning<cplx, Allocator>::GetMemorySize() const
110  {
111  size_t taille = sizeof(int)*(permutation_row.GetM() + permutation_col.GetM());
112  taille += mat_sym.GetMemorySize() + mat_unsym.GetMemorySize();
113  return taille;
114  }
115 
116 
117  template<class T, class Allocator>
118  inline int IlutPreconditioning<T, Allocator>::GetInfoFactorization() const
119  {
120  return 0;
121  }
122 
123 
124  template<class cplx, class Allocator>
125  void IlutPreconditioning<cplx, Allocator>
126  ::SetFactorisationType(int type)
127  {
128  type_ilu = type;
129  }
130 
131 
132  template<class cplx, class Allocator>
133  void IlutPreconditioning<cplx, Allocator>::SetFillLevel(int level)
134  {
135  fill_level = level;
136  }
137 
138 
139  template<class cplx, class Allocator>
140  void IlutPreconditioning<cplx, Allocator>
141  ::SetAdditionalFillNumber(int level)
142  {
143  additional_fill = level;
144  }
145 
146 
147  template<class cplx, class Allocator>
148  void IlutPreconditioning<cplx, Allocator>::SetPrintLevel(int level)
149  {
150  print_level = level;
151  }
152 
153 
154  template<class cplx, class Allocator>
155  void IlutPreconditioning<cplx, Allocator>::SetPivotBlockInteger(int i)
156  {
157  mbloc = i;
158  }
159 
160 
161  template<class cplx, class Allocator>
162  typename ClassComplexType<cplx>::Treal IlutPreconditioning<cplx, Allocator>
163  ::GetDroppingThreshold() const
164  {
165  return droptol;
166  }
167 
168 
169  template<class cplx, class Allocator>
170  typename ClassComplexType<cplx>::Treal IlutPreconditioning<cplx, Allocator>
171  ::GetDiagonalCoefficient() const
172  {
173  return alpha;
174  }
175 
176 
177  template<class cplx, class Allocator>
178  typename ClassComplexType<cplx>::Treal IlutPreconditioning<cplx, Allocator>
179  ::GetPivotThreshold() const
180  {
181  return permtol;
182  }
183 
184 
185  template<class cplx, class Allocator>
186  void IlutPreconditioning<cplx, Allocator>
187  ::SetDroppingThreshold(typename ClassComplexType<cplx>::Treal tol)
188  {
189  droptol = tol;
190  }
191 
192 
193  template<class cplx, class Allocator>
194  void IlutPreconditioning<cplx, Allocator>
195  ::SetDiagonalCoefficient(typename ClassComplexType<cplx>::Treal beta)
196  {
197  alpha = beta;
198  }
199 
200 
201  template<class cplx, class Allocator>
204  {
205  permtol = tol;
206  }
207 
208 
209  template<class cplx, class Allocator>
211  {
212  symmetric_algorithm = true;
213  }
214 
215 
216  template<class cplx, class Allocator>
217  void IlutPreconditioning<cplx, Allocator>::SetUnsymmetricAlgorithm()
218  {
219  symmetric_algorithm = false;
220  }
221 
222 
223  template<class cplx, class Allocator>
224  template<class T0, class Storage0, class Allocator0>
225  void IlutPreconditioning<cplx, Allocator>::
226  FactorizeMatrix(const IVect& perm,
227  Matrix<T0, General, Storage0, Allocator0>& mat,
228  bool keep_matrix)
229  {
230  if (symmetric_algorithm)
231  {
232  cout << "Conversion to symmetric matrices not implemented." << endl;
233  abort();
234  }
235  else
236  FactorizeUnsymMatrix(perm, mat, keep_matrix);
237  }
238 
239 
240  template<class cplx, class Allocator>
241  template<class T0, class Storage0, class Allocator0>
242  void IlutPreconditioning<cplx, Allocator>::
243  FactorizeMatrix(const IVect& perm,
244  Matrix<T0, Symmetric, Storage0, Allocator0>& mat,
245  bool keep_matrix)
246  {
247  if (symmetric_algorithm)
248  FactorizeSymMatrix(perm, mat, keep_matrix);
249  else
250  FactorizeUnsymMatrix(perm, mat, keep_matrix);
251  }
252 
253 
254  template<class cplx, class Allocator>
255  template<class MatrixSparse>
256  void IlutPreconditioning<cplx, Allocator>::
257  FactorizeSymMatrix(const IVect& perm, MatrixSparse& mat, bool keep_matrix)
258  {
259  IVect inv_permutation;
260 
261  // We convert matrix to symmetric format.
262  Copy(mat, mat_sym);
263 
264  // Old matrix is erased if needed.
265  if (!keep_matrix)
266  mat.Clear();
267 
268  // We keep permutation array in memory, and check it.
269  int n = mat_sym.GetM();
270  if (perm.GetM() != n)
271  {
272  cout << "Numbering array should have the same size as matrix.";
273  cout << endl;
274  abort();
275  }
276 
277  permutation_row.Reallocate(n);
278  inv_permutation.Reallocate(n);
279  inv_permutation.Fill(-1);
280  for (int i = 0; i < n; i++)
281  {
282  permutation_row(i) = perm(i);
283  inv_permutation(perm(i)) = i;
284  }
285 
286  for (int i = 0; i < n; i++)
287  if (inv_permutation(i) == -1)
288  {
289  cout << "Error in the numbering array." << endl;
290  abort();
291  }
292 
293  // Matrix is permuted.
294  ApplyInversePermutation(mat_sym, perm, perm);
295 
296  // Factorization is performed.
297  GetIlut(*this, mat_sym);
298  }
299 
300 
301  template<class cplx, class Allocator>
302  template<class MatrixSparse>
303  void IlutPreconditioning<cplx, Allocator>::
304  FactorizeUnsymMatrix(const IVect& perm, MatrixSparse& mat, bool keep_matrix)
305  {
306  IVect inv_permutation;
307 
308  // We convert matrix to unsymmetric format.
309  Copy(mat, mat_unsym);
310 
311  // Old matrix is erased if needed.
312  if (!keep_matrix)
313  mat.Clear();
314 
315  // We keep permutation array in memory, and check it.
316  int n = mat_unsym.GetM();
317  if (perm.GetM() != n)
318  {
319  cout << "Numbering array should have the same size as matrix.";
320  cout << endl;
321  abort();
322  }
323 
324  permutation_row.Reallocate(n);
325  permutation_col.Reallocate(n);
326  inv_permutation.Reallocate(n);
327  inv_permutation.Fill(-1);
328  for (int i = 0; i < n; i++)
329  {
330  permutation_row(i) = i;
331  permutation_col(i) = i;
332  inv_permutation(perm(i)) = i;
333  }
334 
335  for (int i = 0; i < n; i++)
336  if (inv_permutation(i) == -1)
337  {
338  cout << "Error in the numbering array." << endl;
339  abort();
340  }
341 
342  IVect iperm = inv_permutation;
343 
344  // Rows of matrix are permuted.
345  ApplyInversePermutation(mat_unsym, perm, perm);
346 
347  // Factorization is performed.
348  // Columns are permuted during the factorization.
349  inv_permutation.Fill();
350  GetIlut(*this, mat_unsym, permutation_col, inv_permutation);
351 
352  // Combining permutations.
353  IVect itmp = permutation_col;
354  for (int i = 0; i < n; i++)
355  permutation_col(i) = iperm(itmp(i));
356 
357  permutation_row = perm;
358  }
359 
360 
361 #ifdef SELDON_WITH_VIRTUAL
362  template<class T, class Allocator>
365  ::Solve(const VirtualMatrix<T>&, const Vector<T>& r, Vector<T>& z)
366  {
367  if (symmetric_algorithm)
368  {
369  Vector<T> xtmp(z);
370  for (int i = 0; i < r.GetM(); i++)
371  xtmp(permutation_row(i)) = r(i);
372 
373  SolveLU(mat_sym, xtmp);
374 
375  for (int i = 0; i < r.GetM(); i++)
376  z(i) = xtmp(permutation_row(i));
377  }
378  else
379  {
380  Vector<T> xtmp(z);
381  for (int i = 0; i < r.GetM(); i++)
382  xtmp(permutation_row(i)) = r(i);
383 
384  SolveLU(mat_unsym, xtmp);
385 
386  for (int i = 0; i < r.GetM(); i++)
387  z(permutation_col(i)) = xtmp(i);
388  }
389  }
390 
391 
393  template<class T, class Allocator>
395  ::TransSolve(const VirtualMatrix<T>& A, const Vector<T>& r, Vector<T>& z)
396  {
397  if (symmetric_algorithm)
398  Solve(A, r, z);
399  else
400  {
401  Vector<T> xtmp(z);
402  for (int i = 0; i < r.GetM(); i++)
403  xtmp(i) = r(permutation_col(i));
404 
405  SolveLU(SeldonTrans, mat_unsym, xtmp);
406 
407  for (int i = 0; i < r.GetM(); i++)
408  z(i) = xtmp(permutation_row(i));
409  }
410  }
411 
412 #else
413 
415  template<class cplx, class Allocator>
416  template<class Matrix1, class Vector1>
418  ::Solve(const Matrix1& A, const Vector1& r, Vector1& z)
419  {
420  if (symmetric_algorithm)
421  {
422  Vector1 xtmp(z);
423  for (int i = 0; i < r.GetM(); i++)
424  xtmp(permutation_row(i)) = r(i);
425 
426  SolveLU(mat_sym, xtmp);
427 
428  for (int i = 0; i < r.GetM(); i++)
429  z(i) = xtmp(permutation_row(i));
430  }
431  else
432  {
433  Vector1 xtmp(z);
434  for (int i = 0; i < r.GetM(); i++)
435  xtmp(permutation_row(i)) = r(i);
436 
437  SolveLU(mat_unsym, xtmp);
438 
439  for (int i = 0; i < r.GetM(); i++)
440  z(permutation_col(i)) = xtmp(i);
441  }
442  }
443 
444 
446  template<class cplx, class Allocator>
447  template<class Matrix1, class Vector1>
449  ::TransSolve(const Matrix1& A, const Vector1& r, Vector1& z)
450  {
451  if (symmetric_algorithm)
452  Solve(A, r, z);
453  else
454  {
455  Vector1 xtmp(z);
456  for (int i = 0; i < r.GetM(); i++)
457  xtmp(i) = r(permutation_col(i));
458 
459  SolveLU(SeldonTrans, mat_unsym, xtmp);
460 
461  for (int i = 0; i < r.GetM(); i++)
462  z(i) = xtmp(permutation_row(i));
463  }
464  }
465 #endif
466 
467 
468  template<class cplx, class Allocator>
469  template<class Vector1>
471  {
472  if (symmetric_algorithm)
473  {
474  Vector1 xtmp(z);
475  for (int i = 0; i < z.GetM(); i++)
476  xtmp(permutation_row(i)) = z(i);
477 
478  SolveLU(mat_sym, xtmp);
479 
480  for (int i = 0; i < z.GetM(); i++)
481  z(i) = xtmp(permutation_row(i));
482  }
483  else
484  {
485  Vector1 xtmp(z);
486  for (int i = 0; i < z.GetM(); i++)
487  xtmp(permutation_row(i)) = z(i);
488 
489  SolveLU(mat_unsym, xtmp);
490 
491  for (int i = 0; i < z.GetM(); i++)
492  z(permutation_col(i)) = xtmp(i);
493  }
494  }
495 
496 
497  template<class cplx, class Allocator>
498  template<class Vector1>
500  {
501  if (symmetric_algorithm)
502  Solve(z);
503  else
504  {
505  Vector1 xtmp(z);
506  for (int i = 0; i < z.GetM(); i++)
507  xtmp(i) = z(permutation_col(i));
508 
509  SolveLU(SeldonTrans, mat_unsym, xtmp);
510 
511  for (int i = 0; i < z.GetM(); i++)
512  z(i) = xtmp(permutation_row(i));
513  }
514  }
515 
516 
517  template<class cplx, class Allocator> template<class Vector1>
519  ::Solve(const SeldonTranspose& transA, Vector1& z)
520  {
521  if (transA.Trans())
522  TransSolve(z);
523  else
524  Solve(z);
525  }
526 
527 
528  template<class cplx, class Allocator>
530  ::Solve(const SeldonTranspose& TransA, cplx* x_ptr, int nrhs)
531  {
532  Vector<cplx> x;
533  int n = permutation_row.GetM();
534  for (int k = 0; k < nrhs; k++)
535  {
536  x.SetData(n, &x_ptr[k*n]);
537  Solve(TransA, x);
538  x.Nullify();
539  }
540  }
541 
542 
543  template<class real, class cplx, class Storage, class Allocator>
544  void qsplit_ilut(Vector<cplx, Storage, Allocator>& a, IVect& ind, int first,
545  int n, int ncut, const real& abs_ncut)
546  {
547  //-----------------------------------------------------------------------
548  // does a quick-sort split of a real array.
549  // on input a(1:n). is a real array
550  // on output a(1:n) is permuted such that its elements satisfy:
551  //
552  // abs(a(i)) .ge. abs(a(ncut)) for i .lt. ncut and
553  // abs(a(i)) .le. abs(a(ncut)) for i .gt. ncut
554  //
555  // ind is an integer array which permuted in the same way as a
556  //-----------------------------------------------------------------------
557  int last = n-1;
558  int ncut_ = ncut-1;
559  int first_ = first;
560 
561  if ((ncut_ < first_) || (ncut_ > last))
562  return;
563 
564  cplx tmp; real abskey;
565  int mid, itmp;
566  bool test_loop = true;
567 
568  // outer loop -- while mid .ne. ncut do
569  while (test_loop)
570  {
571  mid = first_;
572  abskey = abs(a(mid));
573  for (int j = (first_+1); j <= last; j++)
574  {
575  if (abs(a(j)) > abskey)
576  {
577  mid++;
578  // Interchange.
579  tmp = a(mid);
580  itmp = ind(mid);
581  a(mid) = a(j);
582  ind(mid) = ind(j);
583  a(j) = tmp;
584  ind(j) = itmp;
585  }
586  }
587 
588  // Interchange.
589  tmp = a(mid);
590  a(mid) = a(first_);
591  a(first_) = tmp;
592 
593  itmp = ind(mid);
594  ind(mid) = ind(first_);
595  ind(first_) = itmp;
596 
597  // Test for while loop.
598  if (mid == ncut_)
599  return;
600 
601  if (mid > ncut_)
602  last = mid-1;
603  else
604  first_ = mid+1;
605  }
606  }
607 
608 
610  template<class cplx, class Allocator1, class Allocator2>
613  IVect& iperm, IVect& rperm)
614  {
615  int size_row;
616  int n = A.GetN();
617  int type_factorization = param.GetFactorisationType();
618  int lfil = param.GetFillLevel();
619  typename ClassComplexType<cplx>::Treal zero(0);
620  typename ClassComplexType<cplx>::Treal droptol = param.GetDroppingThreshold();
621  typename ClassComplexType<cplx>::Treal alpha = param.GetDiagonalCoefficient();
622  bool variable_fill = false;
623  bool standard_dropping = true;
624  int additional_fill = param.GetAdditionalFillNumber();
625  int mbloc = param.GetPivotBlockInteger();
626  typename ClassComplexType<cplx>::Treal permtol = param.GetPivotThreshold();
627  int print_level = param.GetPrintLevel();
628 
629  if (type_factorization == param.ILUT)
630  standard_dropping = false;
631  else if (type_factorization == param.ILU_D)
632  standard_dropping = true;
633  else if (type_factorization == param.ILUT_K)
634  {
635  variable_fill = true; // We use a variable lfil
636  standard_dropping = false;
637  }
638  else if (type_factorization == param.ILU_0)
639  {
640  GetIlu0(A);
641  return;
642  }
643  else if (type_factorization == param.MILU_0)
644  {
645  GetMilu0(A);
646  return;
647  }
648  else if (type_factorization == param.ILU_K)
649  {
650  GetIluk(lfil, A);
651  return;
652  }
653 
654  cplx fact, s, t;
655  typename ClassComplexType<cplx>::Treal tnorm;
656  int length_lower, length_upper, jpos, jrow, i_row, j_col;
657  int i, j, k, index_lu, length;
658 
659 
660  if (lfil < 0)
661  {
662  cout << "Incorrect fill level." << endl;
663  abort();
664  }
665 
666  cplx czero, cone;
667  SetComplexZero(czero);
668  SetComplexOne(cone);
669  typedef Vector<cplx, VectFull, Allocator2> VectCplx;
670  VectCplx Row_Val(n);
671  IVect Index(n), Row_Ind(n), Index_Diag(n);
672  Row_Val.Fill(czero);
673  Row_Ind.Fill(-1);
674  Index_Diag.Fill(-1);
675 
676  Index.Fill(-1);
677 
678  bool element_dropped; cplx dropsum;
679 
680  // main loop
681  int new_percent = 0, old_percent = 0;
682  for (i_row = 0; i_row < n; i_row++)
683  {
684  // Progress bar if print level is high enough.
685  if (print_level > 0)
686  {
687  new_percent = int(double(i_row)/(n-1)*80);
688  for (int percent = old_percent; percent < new_percent; percent++)
689  {
690  cout << "#"; cout.flush();
691  }
692 
693  old_percent = new_percent;
694  }
695 
696  size_row = A.GetRowSize(i_row);
697  tnorm = zero;
698 
699  dropsum = czero;
700  for (k = 0 ; k < size_row; k++)
701  if (A.Value(i_row, k) != czero)
702  tnorm += abs(A.Value(i_row, k));
703 
704  if (tnorm == zero)
705  {
706  cout << "Structurally singular matrix." << endl;
707  cout << "Norm of row " << i_row << " is equal to 0." << endl;
708  abort();
709  }
710 
711  // tnorm is the sum of absolute value of coefficients of row i_row.
712  tnorm /= typename ClassComplexType<cplx>::Treal(size_row);
713  if (variable_fill)
714  lfil = size_row + additional_fill;
715 
716  // Unpack L-part and U-part of row of A.
717  length_upper = 1;
718  length_lower = 0;
719  Row_Ind(i_row) = i_row;
720  Row_Val(i_row) = czero;
721  Index(i_row) = i_row;
722 
723  for (j = 0; j < size_row; j++)
724  {
725  k = rperm(A.Index(i_row, j));
726 
727  t = A.Value(i_row,j);
728  if (k < i_row)
729  {
730  Row_Ind(length_lower) = k;
731  Row_Val(length_lower) = t;
732  Index(k) = length_lower;
733  ++length_lower;
734  }
735  else if (k == i_row)
736  {
737  Row_Val(i_row) = t;
738  }
739  else
740  {
741  jpos = i_row + length_upper;
742  Row_Ind(jpos) = k;
743  Row_Val(jpos) = t;
744  Index(k) = jpos;
745  length_upper++;
746  }
747  }
748 
749  j_col = 0;
750  length = 0;
751 
752  // Eliminates previous rows.
753  while (j_col < length_lower)
754  {
755  // In order to do the elimination in the correct order, we must
756  // select the smallest column index.
757  jrow = Row_Ind(j_col);
758  k = j_col;
759 
760  // Determine smallest column index.
761  for (j = j_col + 1; j < length_lower; j++)
762  {
763  if (Row_Ind(j) < jrow)
764  {
765  jrow = Row_Ind(j);
766  k = j;
767  }
768  }
769 
770  if (k != j_col)
771  {
772  // Exchanging column coefficients.
773  j = Row_Ind(j_col);
774  Row_Ind(j_col) = Row_Ind(k);
775  Row_Ind(k) = j;
776 
777  Index(jrow) = j_col;
778  Index(j) = k;
779 
780  s = Row_Val(j_col);
781  Row_Val(j_col) = Row_Val(k);
782  Row_Val(k) = s;
783  }
784 
785  // Zero out element in row.
786  Index(jrow) = -1;
787 
788  element_dropped = false;
789  if (standard_dropping)
790  if (abs(Row_Val(j_col)) <= droptol*tnorm)
791  {
792  dropsum += Row_Val(j_col);
793  element_dropped = true;
794  }
795 
796  // Gets the multiplier for row to be eliminated (jrow).
797  if (!element_dropped)
798  {
799  // first_index_upper points now on the diagonal coefficient.
800  fact = Row_Val(j_col) * A.Value(jrow, Index_Diag(jrow));
801 
802  if (!standard_dropping)
803  {
804  if (abs(fact) <= droptol)
805  element_dropped = true;
806  }
807  }
808 
809  if (!element_dropped)
810  {
811  // Combines current row and row jrow.
812  for (k = (Index_Diag(jrow)+1); k < A.GetRowSize(jrow); k++)
813  {
814  s = fact * A.Value(jrow,k);
815  j = rperm(A.Index(jrow,k));
816 
817  jpos = Index(j);
818 
819  if (j >= i_row)
820  {
821 
822  // Dealing with upper part.
823  if (jpos == -1)
824  {
825  // This is a fill-in element.
826  i = i_row + length_upper;
827  Row_Ind(i) = j;
828  Index(j) = i;
829  Row_Val(i) = -s;
830  ++length_upper;
831  }
832  else
833  {
834  // This is not a fill-in element.
835  Row_Val(jpos) -= s;
836  }
837  }
838  else
839  {
840  // Dealing with lower part.
841  if (jpos == -1)
842  {
843  // this is a fill-in element
844  Row_Ind(length_lower) = j;
845  Index(j) = length_lower;
846  Row_Val(length_lower) = -s;
847  ++length_lower;
848  }
849  else
850  {
851  // This is not a fill-in element.
852  Row_Val(jpos) -= s;
853  }
854  }
855  }
856 
857  // Stores this pivot element from left to right -- no danger
858  // of overlap with the working elements in L (pivots).
859  Row_Val(length) = fact;
860  Row_Ind(length) = jrow;
861  ++length;
862  }
863 
864  j_col++;
865  }
866 
867  // Resets double-pointer to zero (U-part).
868  for (k = 0; k < length_upper; k++)
869  Index(Row_Ind(i_row+k )) = -1;
870 
871  // Updates L-matrix.
872  if (!standard_dropping)
873  {
874  length_lower = length;
875  length = min(length_lower,lfil);
876 
877  // Sorts by quick-split.
878  qsplit_ilut(Row_Val, Row_Ind, 0, length_lower, length,tnorm);
879  }
880 
881  size_row = length;
882  A.ReallocateRow(i_row,size_row);
883 
884  // store L-part
885  index_lu = 0;
886  for (k = 0 ; k < length ; k++)
887  {
888  A.Value(i_row,index_lu) = Row_Val(k);
889  A.Index(i_row,index_lu) = iperm(Row_Ind(k));
890  ++index_lu;
891  }
892 
893  // Saves pointer to beginning of row i_row of U.
894  Index_Diag(i_row) = index_lu;
895 
896  // Updates. U-matrix -- first apply dropping strategy.
897  length = 0;
898  for (k = 1; k <= (length_upper-1); k++)
899  {
900  if (abs(Row_Val(i_row+k)) > droptol * tnorm)
901  {
902  ++length;
903  Row_Val(i_row+length) = Row_Val(i_row+k);
904  Row_Ind(i_row+length) = Row_Ind(i_row+k);
905  }
906  else
907  dropsum += Row_Val(i_row+k);
908  }
909 
910  if (!standard_dropping)
911  {
912  length_upper = length + 1;
913  length = min(length_upper,lfil);
914 
915  qsplit_ilut(Row_Val, Row_Ind, i_row+1,
916  i_row+length_upper, i_row+length+1, tnorm);
917  }
918  else
919  length++;
920 
921  // Determines next pivot.
922  int imax = i_row;
923  typename ClassComplexType<cplx>::Treal xmax = abs(Row_Val(imax));
924  typename ClassComplexType<cplx>::Treal xmax0 = xmax;
925  int icut = i_row + mbloc - 1 - i_row%mbloc;
926  for ( k = i_row + 1; k <= i_row + length - 1; k++)
927  {
928  tnorm = abs(Row_Val(k));
929  if ((tnorm > xmax) && (tnorm*permtol > xmax0)
930  && (Row_Ind(k)<= icut))
931  {
932  imax = k;
933  xmax = tnorm;
934  }
935  }
936 
937  // Exchanges Row_Val.
938  s = Row_Val(i_row);
939  Row_Val(i_row) = Row_Val(imax);
940  Row_Val(imax) = s;
941 
942  // Updates iperm and reverses iperm.
943  j = Row_Ind(imax);
944  i = iperm(i_row);
945  iperm(i_row) = iperm(j);
946  iperm(j) = i;
947 
948  // Reverses iperm.
949  rperm(iperm(i_row)) = i_row;
950  rperm(iperm(j)) = j;
951 
952  // Copies U-part in original coordinates.
953  int index_diag = index_lu;
954  A.ResizeRow(i_row, size_row+length);
955 
956  for (k = i_row ; k <= i_row + length - 1; k++)
957  {
958  A.Index(i_row,index_lu) = iperm(Row_Ind(k));
959  A.Value(i_row,index_lu) = Row_Val(k);
960  ++index_lu;
961  }
962 
963  // Stores inverse of diagonal element of u.
964  if (standard_dropping)
965  Row_Val(i_row) += alpha*dropsum;
966 
967  if (Row_Val(i_row) == czero)
968  Row_Val(i_row) = (droptol + typename
969  ClassComplexType<cplx>::Treal(1e-4)) * tnorm;
970 
971  A.Value(i_row, index_diag) = cone / Row_Val(i_row);
972 
973  } // end main loop
974 
975  if (print_level > 0)
976  cout << endl;
977 
978  if (print_level > 0)
979  cout << "The matrix takes " <<
980  int((A.GetDataSize()*(sizeof(cplx)+4))/(1024*1024)) << " MB" << endl;
981 
982  for (i = 0; i < n; i++ )
983  for (j = 0; j < A.GetRowSize(i); j++)
984  A.Index(i,j) = rperm(A.Index(i,j));
985  }
986 
987 
988  template<class cplx, class Allocator>
989  void GetIluk(int lfil, Matrix<cplx, General, ArrayRowSparse, Allocator>& A)
990  {
991  int n = A.GetM();
992  Vector<cplx> w;
993  w.Reallocate(n+1);
994  IVect jw(3*n), Index_Diag(n);
995  Vector<IVect, VectFull, NewAlloc<IVect> > levs(n);
996 
997  cplx czero, cone;
998  SetComplexZero(czero);
999  SetComplexOne(cone);
1000 
1001  // Local variables
1002  cplx fact, s, t;
1003  int length_lower,length_upper, jpos, jrow, i_row, j_col;
1004  int i, j, k, index_lu;
1005  bool element_dropped;
1006 
1007  int n2 = 2*n, jlev, k_, size_upper;
1008  jw.Fill(-1);
1009 
1010  // Main loop.
1011  for (i_row = 0; i_row < n; i_row++)
1012  {
1013  int size_row = A.GetRowSize(i_row);
1014 
1015  // Unpacks L-part and U-part of row of A in arrays w, jw.
1016  length_upper = 1;
1017  length_lower = 0;
1018  jw(i_row) = i_row;
1019  w(i_row) = 0.0;
1020  jw(n + i_row) = i_row;
1021 
1022  for (j = 0; j < size_row; j++)
1023  {
1024  k = A.Index(i_row,j);
1025  t = A.Value(i_row,j);
1026  if (k < i_row)
1027  {
1028  jw(length_lower) = k;
1029  w(length_lower) = t;
1030  jw(n + k) = length_lower;
1031  jw(n2+length_lower) = -1;
1032  ++length_lower;
1033  }
1034  else if (k == i_row)
1035  {
1036  w(i_row) = t;
1037  jw(n2+length_lower) = -1;
1038  }
1039  else
1040  {
1041  jpos = i_row + length_upper;
1042  jw(jpos) = k;
1043  w(jpos) = t;
1044  jw(n + k) = jpos;
1045  length_upper++;
1046  }
1047  }
1048 
1049  j_col = 0;
1050 
1051  // Eliminates previous rows.
1052  while (j_col <length_lower)
1053  {
1054  // In order to do the elimination in the correct order, we must
1055  // select the smallest column index among jw(k); k = j_col + 1,
1056  // ..., length_lower.
1057  jrow = jw(j_col);
1058  k = j_col;
1059 
1060  // Determines smallest column index.
1061  for (j = (j_col+1) ; j < length_lower; j++)
1062  {
1063  if (jw(j) < jrow)
1064  {
1065  jrow = jw(j);
1066  k = j;
1067  }
1068  }
1069 
1070  if (k != j_col)
1071  {
1072  // Exchanges in jw.
1073  j = jw(j_col);
1074  jw(j_col) = jw(k);
1075  jw(k) = j;
1076 
1077  // Exchanges in jw(n+ (pointers/ nonzero indicator).
1078  jw(n+jrow) = j_col;
1079  jw(n+j) = k;
1080 
1081  // Exchanges in jw(n2+ (levels).
1082  j = jw(n2+j_col);
1083  jw(n2+j_col) = jw(n2+k);
1084  jw(n2+k) = j;
1085 
1086  // Exchanges in w.
1087  s = w(j_col);
1088  w(j_col) = w(k);
1089  w(k) = s;
1090  }
1091 
1092  // Zero out element in row by setting jw(n+jrow) to zero.
1093  jw(n + jrow) = -1;
1094 
1095  element_dropped = false;
1096 
1097  // Gets the multiplier for row to be eliminated (jrow).
1098  fact = w(j_col) * A.Value(jrow,Index_Diag(jrow));
1099 
1100  jlev = jw(n2+j_col) + 1;
1101  if (jlev > lfil)
1102  element_dropped = true;
1103 
1104  if (!element_dropped)
1105  {
1106  // Combines current row and row jrow.
1107  k_ = 0;
1108  for (k = (Index_Diag(jrow)+1); k < A.GetRowSize(jrow) ; k++)
1109  {
1110  s = fact * A.Value(jrow,k);
1111  j = A.Index(jrow,k);
1112 
1113  jpos = jw(n + j);
1114  if (j >= i_row)
1115  {
1116  // Dealing with upper part.
1117  if (jpos == -1)
1118  {
1119  // This is a fill-in element.
1120  i = i_row + length_upper;
1121  jw(i) = j;
1122  jw(n + j) = i;
1123  w(i) = -s;
1124 
1125  jw(n2+i) = jlev + levs(jrow)(k_) + 1;
1126  ++length_upper;
1127  }
1128  else
1129  {
1130  // This is not a fill-in element.
1131  w(jpos) -= s;
1132  jw(n2+jpos) = min(jw(n2+jpos),
1133  jlev + levs(jrow)(k_)+1);
1134  }
1135  }
1136  else
1137  {
1138  // Dealing with lower part.
1139  if (jpos == -1)
1140  {
1141  // This is a fill-in element.
1142  jw(length_lower) = j;
1143  jw(n + j) = length_lower;
1144  w(length_lower) = -s;
1145  jw(n2+length_lower) = jlev + levs(jrow)(k_) + 1;
1146  ++length_lower;
1147  }
1148  else
1149  {
1150  // This is not a fill-in element.
1151  w(jpos) -= s;
1152  jw(n2+jpos) = min(jw(n2 + jpos),
1153  jlev + levs(jrow)(k_) + 1);
1154  }
1155  }
1156 
1157  k_++;
1158  }
1159 
1160  }
1161 
1162  // Stores this pivot element from left to right -- no danger of
1163  // overlap with the working elements in L (pivots).
1164  w(j_col) = fact;
1165  jw(j_col) = jrow;
1166 
1167  j_col++;
1168  }
1169 
1170  // Resets double-pointer to zero (U-part).
1171  for (k = 0; k < length_upper; k++)
1172  jw(n + jw(i_row + k )) = -1;
1173 
1174  // Updates L-matrix.
1175  size_row = 1; // we have the diagonal value.
1176  // Size of L-matrix.
1177  for (k = 0; k < length_lower; k++)
1178  if (jw(n2+k) < lfil)
1179  size_row++;
1180 
1181  // Size of U-matrix.
1182  size_upper = 0;
1183  for (k = (i_row+1) ; k <= (i_row+length_upper-1) ; k++)
1184  if (jw(n2+k) < lfil)
1185  size_upper++;
1186 
1187  size_row += size_upper;
1188  A.ReallocateRow(i_row,size_row);
1189  levs(i_row).Reallocate(size_upper);
1190 
1191  index_lu = 0;
1192  for (k = 0; k < length_lower; k++)
1193  {
1194  if (jw(n2+k) < lfil)
1195  {
1196  A.Value(i_row,index_lu) = w(k);
1197  A.Index(i_row,index_lu) = jw(k);
1198  ++index_lu;
1199  }
1200  }
1201 
1202  // Saves pointer to beginning of row i_row of U.
1203  Index_Diag(i_row) = index_lu;
1204  A.Value(i_row,index_lu) = cone / w(i_row);
1205  A.Index(i_row,index_lu++) = i_row;
1206 
1207  for (k = (i_row+1) ; k <= (i_row+length_upper-1) ; k++)
1208  {
1209  if (jw(n2+k) < lfil)
1210  {
1211  A.Index(i_row,index_lu) = jw(k);
1212  A.Value(i_row,index_lu) = w(k);
1213  levs(i_row)(index_lu-Index_Diag(i_row)-1) = jw(n2+k);
1214  ++index_lu;
1215  }
1216  }
1217  }
1218  }
1219 
1220 
1221  template<class cplx, class Allocator>
1222  void GetIlu0(Matrix<cplx, General, ArrayRowSparse, Allocator>& A)
1223  {
1224  int j_col, jrow, jw, n = A.GetM();
1225  IVect Index(n), ju(n);
1226 
1227  cplx czero, cone;
1228  SetComplexZero(czero);
1229  SetComplexOne(cone);
1230 
1231  // Initializes work vector to zero's.
1232  Index.Fill(-1); ju.Fill(-1);
1233  cplx tl;
1234 
1235  // Main loop.
1236  for (int i_row = 0 ; i_row < n ; i_row++)
1237  {
1238  // Generating row number i_row of L and U.
1239  for (int j = 0 ; j < A.GetRowSize(i_row) ; j++ )
1240  {
1241  j_col = A.Index(i_row, j);
1242  if (j_col == i_row)
1243  ju(i_row) = j;
1244 
1245  Index(j_col) = j;
1246  }
1247 
1248  int jm = ju(i_row)-1;
1249 
1250  // Exit if diagonal element is reached.
1251  for (int j = 0; j <= jm; j++)
1252  {
1253  jrow = A.Index(i_row, j);
1254  tl = A.Value(i_row, j)*A.Value(jrow, ju(jrow));
1255  A.Value(i_row, j) = tl;
1256 
1257  // Performs linear combination.
1258  for ( j_col = (ju(jrow)+1); j_col < A.GetRowSize(jrow); j_col++)
1259  {
1260  jw = Index(A.Index(jrow,j_col));
1261  if (jw != -1)
1262  A.Value(i_row, jw) -= tl*A.Value(jrow, j_col);
1263  }
1264  }
1265 
1266 
1267  // Inverts and stores diagonal element.
1268  if (A.Value(i_row, ju(i_row)) == czero)
1269  {
1270  cout << "Factorization fails because we found a null coefficient"
1271  << " on diagonal " << i_row << endl;
1272  abort();
1273  }
1274 
1275  A.Value(i_row,ju(i_row)) = cone / A.Value(i_row,ju(i_row));
1276 
1277  // Resets pointer Index to zero.
1278  Index(i_row) = -1;
1279  for (int i = 0; i < A.GetRowSize(i_row); i++)
1280  Index(A.Index(i_row, i)) = -1;
1281  }
1282 
1283  }
1284 
1285 
1286  template<class cplx, class Allocator>
1287  void GetMilu0(Matrix<cplx, General, ArrayRowSparse, Allocator>& A)
1288  {
1289  int j_col, jrow, jw, n = A.GetM();
1290  IVect Index(n), ju(n);
1291 
1292  cplx czero, cone;
1293  SetComplexZero(czero);
1294  SetComplexOne(cone);
1295 
1296  // Initializes work vector to zero's.
1297  Index.Fill(-1); ju.Fill(-1);
1298  cplx tl;
1299 
1300  // Main loop.
1301  for (int i_row = 0 ; i_row < n ; i_row++)
1302  {
1303  // Generating row number i_row of L and U.
1304  for (int j = 0; j < A.GetRowSize(i_row); j++ )
1305  {
1306  j_col = A.Index(i_row, j);
1307  if (j_col == i_row)
1308  ju(i_row) = j;
1309 
1310  Index(j_col) = j;
1311  }
1312 
1313  int jm = ju(i_row)-1;
1314  // Exit if diagonal element is reached.
1315  // s accumulates fill-in values.
1316  cplx s; SetComplexZero(s);
1317  for (int j = 0; j <= jm; j++)
1318  {
1319  jrow = A.Index(i_row, j);
1320  tl = A.Value(i_row, j)*A.Value(jrow, ju(jrow));
1321  A.Value(i_row, j) = tl;
1322 
1323  // Performs linear combination.
1324  for ( j_col = (ju(jrow)+1); j_col < A.GetRowSize(jrow); j_col++ )
1325  {
1326  jw = Index(A.Index(jrow, j_col));
1327  if (jw != -1)
1328  A.Value(i_row, jw) -= tl*A.Value(jrow, j_col);
1329  else
1330  s += tl*A.Value(jrow, j_col);
1331  }
1332  }
1333 
1334  // Inverts and stores diagonal element.
1335  A.Value(i_row, ju(i_row)) -= s;
1336  if (A.Value(i_row, ju(i_row)) == czero)
1337  {
1338  cout << "Factorization fails because we found a null coefficient"
1339  << " on diagonal " << i_row << endl;
1340  abort();
1341  }
1342 
1343  A.Value(i_row, ju(i_row)) = cone /A.Value(i_row, ju(i_row));
1344 
1345  // Resets pointer Index to zero.
1346  Index(i_row) = -1;
1347  for (int i = 0; i < A.GetRowSize(i_row); i++)
1348  Index(A.Index(i_row, i)) = -1;
1349  }
1350  }
1351 
1352 
1353  template<class MatrixSparse, class T, class Alloc2>
1354  void GetLU(MatrixSparse& A, IlutPreconditioning<T, Alloc2>& mat_lu,
1355  IVect& permut, bool keep_matrix, T& x)
1356  {
1357  mat_lu.FactorizeMatrix(permut, A, keep_matrix);
1358  }
1359 
1360 
1361  template<class MatrixSparse, class T, class Alloc2>
1362  void GetLU(MatrixSparse& A, IlutPreconditioning<T, Alloc2>& mat_lu,
1363  IVect& permut, bool keep_matrix, complex<T>& x)
1364  {
1365  throw WrongArgument(string("GetLU(Matrix<complex<T> >& A, ") +
1366  "IlutPreconditioning<T>& mat_lu, bool)",
1367  "The LU matrix must be complex");
1368  }
1369 
1370 
1371  template<class MatrixSparse, class T, class Alloc2>
1372  void GetLU(MatrixSparse& A, IlutPreconditioning<complex<T>, Alloc2>& mat_lu,
1373  IVect& permut, bool keep_matrix, T& x)
1374  {
1375  throw WrongArgument(string("GetLU(Matrix<T>& A, ")+
1376  "IlutPreconditioning<complex<T> >& mat_lu, bool)",
1377  "The sparse matrix must be complex");
1378  }
1379 
1380 
1381  template<class T0, class Prop, class Storage, class Allocator,
1382  class T, class Alloc2>
1383  void GetLU(Matrix<T0, Prop, Storage, Allocator>& A,
1384  IlutPreconditioning<T, Alloc2>& mat_lu,
1385  IVect& permut, bool keep_matrix)
1386  {
1387  typename Matrix<T0, Prop, Storage, Allocator>::entry_type x;
1388  GetLU(A, mat_lu, permut, keep_matrix, x);
1389  }
1390 
1391 }
1392 
1393 #define SELDON_FILE_ILUT_PRECONDITIONING_CXX
1394 #endif
Seldon::Vector< int, VectFull >
Seldon::IlutPreconditioning::Solve
void Solve(const Matrix1 &A, const Vector1 &r, Vector1 &z)
Applies ilut preconditioning.
Definition: IlutPreconditioning.cxx:418
Seldon::Matrix
Definition: SeldonHeader.hxx:226
Seldon::IlutPreconditioning::SetPivotThreshold
void SetPivotThreshold(double)
Sets the threshold for pivot.
Definition: IlutPreconditioning.cxx:203
Seldon::GetIlut
void GetIlut(const IlutPreconditioning< cplx, Allocator1 > &param, Matrix< cplx, General, ArrayRowSparse, Allocator2 > &A, IVect &iperm, IVect &rperm)
Incomplete factorization with pivot for unsymmetric matrix.
Definition: IlutPreconditioning.cxx:611
Seldon::GetLU
void GetLU(Matrix< T0, Prop0, Storage0, Allocator0 > &A)
Returns the LU factorization of a matrix.
Definition: Functions_Matrix.cxx:2073
Seldon::IlutPreconditioning
Definition: IlutPreconditioning.hxx:27
Seldon
Seldon namespace.
Definition: Array.cxx:24
Seldon::IlutPreconditioning::TransSolve
void TransSolve(const Matrix1 &A, const Vector1 &r, Vector1 &z)
Applies transpose of ilut preconditioning.
Definition: IlutPreconditioning.cxx:449