SymmetricIlutPreconditioning.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_SYMMETRIC_ILUT_PRECONDITIONING_CXX
21 
22 namespace Seldon
23 {
24 
26  template<class cplx, class Allocator1, class Allocator2>
29  {
30  int size_row;
31  int n = A.GetN();
32  int lfil = param.GetFillLevel();
33  typename ClassComplexType<cplx>::Treal zero = 0.0;
34  typename ClassComplexType<cplx>::Treal droptol = param.GetDroppingThreshold();
35  typename ClassComplexType<cplx>::Treal alpha = param.GetDiagonalCoefficient();
36  bool variable_fill = false;
37  bool standard_dropping = true;
38  int type_factorization = param.GetFactorisationType();
39  int additional_fill = param.GetAdditionalFillNumber();
40  int print_level = param.GetPrintLevel();
41  if (type_factorization == param.ILUT)
42  standard_dropping = false;
43  else if (type_factorization == param.ILU_D)
44  standard_dropping = true;
45  else if (type_factorization == param.ILUT_K)
46  {
47  variable_fill = true;
48  standard_dropping = false;
49  }
50  else if (type_factorization == param.ILU_0)
51  {
52  GetIlu0(A);
53  return;
54  }
55  else if (type_factorization == param.MILU_0)
56  {
57  GetMilu0(A);
58  return;
59  }
60  else if (type_factorization == param.ILU_K)
61  {
62  GetIluk(lfil, print_level, A);
63  return;
64  }
65 
66  cplx fact, s, t;
67  typename ClassComplexType<cplx>::Treal tnorm, one(1);
68  int length_lower, length_upper, jpos, jrow;
69  int i_row, j_col, index_lu, length;
70  int i, j, k;
71 
72  lfil = n;
73  typedef Vector<cplx, VectFull, Allocator2> VectCplx;
74  VectCplx Row_Val(n);
75  IVect Index(n), Row_Ind(n);
76  Row_Val.Fill(0); Row_Ind.Fill(-1);
77 
78  Index.Fill(-1);
79 
80  bool element_dropped; cplx dropsum, czero;
81  SetComplexZero(czero);
82 
83  // We convert A into an unsymmetric matrix.
85  Seldon::Copy(A, B);
86 
87  A.Clear();
88  A.Reallocate(n, n);
89 
90  // Main loop.
91  int new_percent = 0, old_percent = 0;
92  for (i_row = 0; i_row < n; i_row++)
93  {
94  // Progress bar if print level is high enough.
95  if (print_level > 0)
96  {
97  new_percent = int(double(i_row)/(n-1)*80);
98  for (int percent = old_percent; percent < new_percent; percent++)
99  {
100  cout << "#"; cout.flush();
101  }
102 
103  old_percent = new_percent;
104  }
105 
106  // 1-norm of the row of initial matrix.
107  size_row = B.GetRowSize(i_row);
108  tnorm = zero;
109  dropsum = czero;
110  for (k = 0 ; k < size_row; k++)
111  tnorm += abs(B.Value(i_row, k));
112 
113  if (tnorm == zero)
114  {
115  cout << "Structurally singular matrix." << endl;
116  cout << "Norm of row " << i_row << " is equal to 0." << endl;
117  abort();
118  }
119 
120  // tnorm is the sum of absolute value of coefficients of row i_row
121  tnorm /= typename ClassComplexType<cplx>::Treal(size_row);
122  if (variable_fill)
123  lfil = size_row + additional_fill;
124 
125 
126  // Separating lower part from upper part for this row.
127  length_upper = 1;
128  length_lower = 0;
129  Row_Ind(i_row) = i_row;
130  Row_Val(i_row) = czero;
131  Index(i_row) = i_row;
132 
133  for (j = 0; j < size_row; j++)
134  {
135  k = B.Index(i_row,j);
136  t = B.Value(i_row,j);
137  if (k < i_row)
138  {
139  Row_Ind(length_lower) = k;
140  Row_Val(length_lower) = t;
141  Index(k) = length_lower;
142  ++length_lower;
143  }
144  else if (k == i_row)
145  {
146  Row_Val(i_row) = t;
147  }
148  else
149  {
150  jpos = i_row + length_upper;
151  Row_Ind(jpos) = k;
152  Row_Val(jpos) = t;
153  Index(k) = jpos;
154  length_upper++;
155  }
156  }
157 
158  // This row of B is cleared.
159  B.ClearRow(i_row);
160 
161  j_col = 0;
162  length = 0;
163 
164  // We eliminate previous rows.
165  while (j_col <length_lower)
166  {
167  // In order to do the elimination in the correct order, we must
168  // select the smallest column index.
169  jrow = Row_Ind(j_col);
170  k = j_col;
171 
172  // We determine smallest column index.
173  for (j = (j_col+1) ; j < length_lower; j++)
174  {
175  if (Row_Ind(j) < jrow)
176  {
177  jrow = Row_Ind(j);
178  k = j;
179  }
180  }
181 
182  // If needed, we exchange positions of this element in
183  // Row_Ind/Row_Val so that it appears first.
184  if (k != j_col)
185  {
186 
187  j = Row_Ind(j_col);
188  Row_Ind(j_col) = Row_Ind(k);
189  Row_Ind(k) = j;
190 
191  Index(jrow) = j_col;
192  Index(j) = k;
193 
194  s = Row_Val(j_col);
195  Row_Val(j_col) = Row_Val(k);
196  Row_Val(k) = s;
197  }
198 
199  // Zero out element in row by setting Index to -1.
200  Index(jrow) = -1;
201 
202  element_dropped = false;
203  if (standard_dropping)
204  if (abs(Row_Val(j_col)) <= droptol*tnorm)
205  {
206  dropsum += Row_Val(j_col);
207  element_dropped = true;
208  }
209 
210  // Gets the multiplier for row to be eliminated.
211  if (!element_dropped)
212  {
213  fact = Row_Val(j_col) * A.Value(jrow, 0);
214 
215  if (!standard_dropping)
216  {
217  if (abs(fact) <= droptol)
218  element_dropped = true;
219  }
220  }
221 
222  if (!element_dropped)
223  {
224  // Combines current row and row jrow.
225  for (k = 1; k < A.GetRowSize(jrow); k++)
226  {
227  s = fact * A.Value(jrow,k);
228  j = A.Index(jrow,k);
229 
230  jpos = Index(j);
231  if (j >= i_row)
232  {
233 
234  // Dealing with upper part.
235  if (jpos == -1)
236  {
237 
238  // This is a fill-in element.
239  i = i_row + length_upper;
240  Row_Ind(i) = j;
241  Index(j) = i;
242  Row_Val(i) = -s;
243  ++length_upper;
244  }
245  else
246  {
247  // This is not a fill-in element.
248  Row_Val(jpos) -= s;
249  }
250  }
251  else
252  {
253  // Dealing with lower part.
254  if (jpos == -1)
255  {
256  // This is a fill-in element.
257  Row_Ind(length_lower) = j;
258  Index(j) = length_lower;
259  Row_Val(length_lower) = -s;
260  ++length_lower;
261  }
262  else
263  {
264  // This is not a fill-in element.
265  Row_Val(jpos) -= s;
266  }
267  }
268  }
269 
270  // We store this pivot element (from left to right -- no
271  // danger of overlap with the working elements in L (pivots).
272  Row_Val(length) = fact;
273  Row_Ind(length) = jrow;
274  ++length;
275  }
276 
277  j_col++;
278  }
279 
280  // Resets double-pointer to zero (U-part).
281  for (k = 0; k < length_upper; k++)
282  Index(Row_Ind(i_row + k)) = -1;
283 
284  // Updating U-matrix -- first apply dropping strategy.
285  length = 0;
286  for (k = 1; k <= (length_upper-1); k++)
287  {
288  if (abs(Row_Val(i_row+k)) > droptol * tnorm)
289  {
290  ++length;
291  Row_Val(i_row+length) = Row_Val(i_row+k);
292  Row_Ind(i_row+length) = Row_Ind(i_row+k);
293  }
294  else
295  dropsum += Row_Val(i_row+k);
296  }
297 
298 
299  if (!standard_dropping)
300  {
301  length_upper = length + 1;
302  length = min(length_upper, lfil);
303 
304  qsplit_ilut(Row_Val, Row_Ind, i_row+1,
305  i_row+length_upper, i_row+length+1, tnorm);
306  }
307  else
308  length++;
309 
310  // Copies U-part in matrix A.
311  A.ReallocateRow(i_row, length);
312  index_lu = 1;
313  // sorting column numbers
314  Sort(i_row+1, i_row + length - 1, Row_Ind, Row_Val);
315  for (k = (i_row+1) ; k <= (i_row+length-1) ; k++)
316  {
317  A.Index(i_row,index_lu) = Row_Ind(k);
318  A.Value(i_row,index_lu) = Row_Val(k);
319  ++index_lu;
320  }
321 
322  // Stores the inverse of the diagonal element of u.
323  if (standard_dropping)
324  Row_Val(i_row) += alpha*dropsum;
325 
326  if (Row_Val(i_row) == czero)
327  Row_Val(i_row) = (droptol + 1e-4) * tnorm;
328 
329  A.Value(i_row,0) = one / Row_Val(i_row);
330 
331  } // end main loop.
332 
333  if (print_level > 0)
334  cout<<endl;
335 
336  // for each row of A, we divide by diagonal value
337  for (int i = 0; i < n; i++)
338  for (int j = 1; j < A.GetRowSize(i); j++)
339  A.Value(i,j) *= A.Value(i,0);
340 
341  if (print_level > 0)
342  cout << "The matrix takes " <<
343  int((A.GetDataSize()*(sizeof(cplx)+4))/(1024*1024)) << " MB" << endl;
344 
345  }
346 
347 
349 
354  template<class cplx, class Allocator>
355  void GetIluk(int lfil, int print_level,
357  {
358  int n = A.GetM();
359  cplx fact, s, t;
360  int length_lower, length_upper, jpos, jrow;
361  int i_row, j_col, index_lu, length;
362  int i, j, k;
363  typename ClassComplexType<cplx>::Treal tnorm, one(1);
364 
365  if (lfil < 0)
366  {
367  cout << "Incorrect fill level." << endl;
368  abort();
369  }
370 
371  typedef Vector<cplx, VectFull, Allocator> VectCplx;
372  VectCplx Row_Val(n);
373  IVect Index(n), Row_Ind(n), Row_Level(n);
374  Row_Val.Fill(0); Row_Ind.Fill(-1);
375  Row_Level.Fill(-1);
376  Index.Fill(-1);
377 
378  bool element_dropped;
379 
380  // We convert A into an unsymmetric matrix.
382  Seldon::Copy(A, B);
383 
384  A.Clear();
385  A.Reallocate(n, n);
387 
388  // Main loop.
389  int new_percent = 0, old_percent = 0;
390  for (i_row = 0; i_row < n; i_row++)
391  {
392  // Progress bar if print level is high enough.
393  if (print_level > 0)
394  {
395  new_percent = int(double(i_row)/(n-1)*80);
396  for (int percent = old_percent; percent < new_percent; percent++)
397  {
398  cout << "#"; cout.flush();
399  }
400 
401  old_percent = new_percent;
402  }
403 
404  // 1-norm of the row of initial matrix.
405  int size_row = B.GetRowSize(i_row);
406  tnorm = 0.0;
407  for (k = 0 ; k < size_row; k++)
408  tnorm += abs(B.Value(i_row, k));
409 
410  if (tnorm == 0.0)
411  {
412  cout << "Structurally singular matrix." << endl;
413  cout << "Norm of row " << i_row << " is equal to 0." << endl;
414  abort();
415  }
416 
417  // current row will be stored in arrays Row_Val, Row_Ind
418  // (respectively values and column indexes)
419  // the array Index returns for global column index
420  // the local column index used in Row_Ind
421  // (Index is the reciprocal array of Row_Ind)
422 
423  // Row_Level will store the level associated with each
424  // column index (-1 for an entry in the original matrix,
425  // 0 for an entry appearing because of a single combination,
426  // 1 for an entry appearing because of at least two combinations, etc)
427 
428  // Separating lower part from upper part for this row.
429  length_upper = 1;
430  length_lower = 0;
431 
432  Row_Ind(i_row) = i_row;
433  Row_Val(i_row) = 0.0;
434  Index(i_row) = i_row;
435 
436  for (j = 0; j < size_row; j++)
437  {
438  k = B.Index(i_row, j);
439  t = B.Value(i_row, j);
440  if (k < i_row)
441  {
442  // part in L
443  Row_Ind(length_lower) = k;
444  Row_Val(length_lower) = t;
445  Index(k) = length_lower;
446  Row_Level(length_lower) = -1;
447  ++length_lower;
448  }
449  else if (k == i_row)
450  {
451  // diagonal part
452  Row_Val(i_row) = t;
453  Row_Level(i_row) = -1;
454  }
455  else
456  {
457  // part in U
458  jpos = i_row + length_upper;
459  Row_Ind(jpos) = k;
460  Row_Val(jpos) = t;
461  Row_Level(jpos) = -1;
462  Index(k) = jpos;
463  length_upper++;
464  }
465  }
466 
467  // This row of B is cleared (since already stored in Row_Ind/Row_Val)
468  B.ClearRow(i_row);
469 
470  j_col = 0;
471  length = 0;
472 
473  // We eliminate previous rows.
474  while (j_col < length_lower)
475  {
476  // In order to do the elimination in the correct order, we must
477  // select the smallest column index.
478  jrow = Row_Ind(j_col);
479  k = j_col;
480 
481  // We determine smallest column index.
482  for (j = (j_col+1) ; j < length_lower; j++)
483  {
484  if (Row_Ind(j) < jrow)
485  {
486  jrow = Row_Ind(j);
487  k = j;
488  }
489  }
490 
491  // If needed, we exchange positions of this element in
492  // Row_Ind/Row_Val so that it appears first.
493  if (k != j_col)
494  {
495 
496  j = Row_Ind(j_col);
497  Row_Ind(j_col) = Row_Ind(k);
498  Row_Ind(k) = j;
499 
500  Index(jrow) = j_col;
501  Index(j) = k;
502 
503  j = Row_Level(j_col);
504  Row_Level(j_col) = Row_Level(k);
505  Row_Level(k) = j;
506 
507  s = Row_Val(j_col);
508  Row_Val(j_col) = Row_Val(k);
509  Row_Val(k) = s;
510  }
511 
512  // Zero out element in row by setting Index to -1.
513  Index(jrow) = -1;
514 
515  element_dropped = false;
516  fact = Row_Val(j_col) * A.Value(jrow, 0);
517 
518  int jlev = Row_Level(j_col) + 1;
519  if (jlev > lfil)
520  element_dropped = true;
521 
522  if (!element_dropped)
523  {
524  // Combines current row and row jrow.
525  for (k = 1; k < A.GetRowSize(jrow); k++)
526  {
527  s = fact * A.Value(jrow, k);
528  j = A.Index(jrow, k);
529 
530  jpos = Index(j);
531  if (j >= i_row)
532  {
533  // Dealing with upper part.
534  if (jpos == -1)
535  {
536  // This is a fill-in element.
537  i = i_row + length_upper;
538  Row_Ind(i) = j;
539  Index(j) = i;
540  Row_Val(i) = -s;
541  Row_Level(i) = jlev + levs(jrow)(k) + 1;
542  ++length_upper;
543  }
544  else
545  {
546  // This is not a fill-in element.
547  Row_Val(jpos) -= s;
548  Row_Level(jpos) = min(Row_Level(jpos),
549  jlev + levs(jrow)(k)+1);
550  }
551  }
552  else
553  {
554  // Dealing with lower part.
555  if (jpos == -1)
556  {
557  // This is a fill-in element.
558  Row_Ind(length_lower) = j;
559  Index(j) = length_lower;
560  Row_Val(length_lower) = -s;
561  Row_Level(length_lower) = jlev + levs(jrow)(k) + 1;
562  ++length_lower;
563  }
564  else
565  {
566  // This is not a fill-in element.
567  Row_Val(jpos) -= s;
568  Row_Level(jpos) = min(Row_Level(jpos),
569  jlev + levs(jrow)(k)+1);
570  }
571  }
572  }
573 
574  // We store this pivot element (from left to right -- no
575  // danger of overlap with the working elements in L (pivots).
576  Row_Val(length) = fact;
577  Row_Ind(length) = jrow;
578  ++length;
579  }
580 
581  j_col++;
582  }
583 
584  // Resets double-pointer to zero (U-part).
585  for (k = 0; k < length_upper; k++)
586  Index(Row_Ind(i_row+k )) = -1;
587 
588  // couting size of upper part after dropping
589  length = 1;
590  for (k = 1; k <= (length_upper-1); k++)
591  if (Row_Level(i_row+k) < lfil)
592  length++;
593 
594  // sorting column indexes in U
595  Sort(i_row+1, i_row+length_upper-1, Row_Ind, Row_Val, Row_Level);
596 
597  // Copies U-part in matrix A.
598  // L-part is not stored since A is symmetric
599  A.ReallocateRow(i_row, length);
600  levs(i_row).Reallocate(length);
601 
602  // diagonal element
603  A.Index(i_row, 0) = i_row;
604  A.Value(i_row, 0) = one / Row_Val(i_row);
605  levs(i_row)(0) = -1;
606 
607  // extra-diagonal elements
608  index_lu = 1;
609  for (k = (i_row+1) ; k <= (i_row+length_upper-1) ; k++)
610  if (Row_Level(k) < lfil)
611  {
612  A.Index(i_row, index_lu) = Row_Ind(k);
613  A.Value(i_row, index_lu) = Row_Val(k);
614  levs(i_row)(index_lu) = Row_Level(k);
615  ++index_lu;
616  }
617 
618  } // end main loop.
619 
620  if (print_level > 0)
621  cout<<endl;
622 
623  // for each row of A, we divide by diagonal value
624  for (int i = 0; i < n; i++)
625  for (int j = 1; j < A.GetRowSize(i); j++)
626  A.Value(i,j) *= A.Value(i,0);
627 
628  if (print_level > 0)
629  cout << "The matrix takes " <<
630  int((A.GetDataSize()*(sizeof(cplx)+4))/(1024*1024)) << " MB" << endl;
631 
632  }
633 
634 
635  template<class cplx, class Allocator>
636  void GetIlu0(Matrix<cplx, Symmetric, ArrayRowSymSparse, Allocator>& A)
637  {
638  int n = A.GetM();
639  cplx one, invDiag, fact, zero;
640  SetComplexOne(one);
641  SetComplexZero(zero);
642  IVect Index(n);
643  Index.Fill(-1);
644  // loop on rows
645  for (int i = 0; i < n; i++)
646  {
647  if (A.GetRowSize(i) == 0)
648  {
649  cout << "Empty row " << i << endl;
650  cout << "Factorisation cannot be completed" << endl;
651  abort();
652  }
653 
654  if (A.Index(i, 0) != i)
655  {
656  cout << "No diagonal element on row " << i << endl;
657  cout << "ILU(0) needs one" << endl;
658  abort();
659  }
660 
661  if (A.Value(i, 0) == zero)
662  {
663  cout << "Factorization fails because we found a null coefficient"
664  << " on diagonal " << i << endl;
665  abort();
666  }
667 
668  // updating Index, Index(j) will be the local position of column j
669  // in the row i (-1 if there is no non-zero entry (i, j))
670  for (int jloc = 1; jloc < A.GetRowSize(i); jloc++)
671  Index(A.Index(i, jloc)) = jloc;
672 
673  invDiag = one / A.Value(i, 0);
674  // loop on each extra-diagonal element of the row
675  for (int jloc = 1; jloc < A.GetRowSize(i); jloc++)
676  {
677  int j = A.Index(i, jloc);
678  // combination Lj <- Lj - a_ji / a_ii L_i
679  // for upper part of the row Lj
680  fact = A.Value(i, jloc) * invDiag;
681 
682  for (int kloc = 0; kloc < A.GetRowSize(j); kloc++)
683  {
684  // ILU(0) -> combination performed only if a non-zero entry
685  // exists at position (j, k)
686  int k = A.Index(j, kloc);
687  if (Index(k) >= 0)
688  A.Value(j, kloc) -= fact * A.Value(i, Index(k));
689  }
690  }
691 
692  // storing inverse of diagonal
693  A.Value(i, 0) = invDiag;
694 
695  // reverting Index to -1
696  for (int jloc = 1; jloc < A.GetRowSize(i); jloc++)
697  Index(A.Index(i, jloc)) = -1;
698 
699  }
700 
701  // for each row of A, we divide by diagonal value
702  for (int i = 0; i < n; i++)
703  for (int j = 1; j < A.GetRowSize(i); j++)
704  A.Value(i, j) *= A.Value(i, 0);
705  }
706 
707 
708  template<class cplx, class Allocator>
709  void GetMilu0(Matrix<cplx, Symmetric, ArrayRowSymSparse, Allocator>& A)
710  {
711  int n = A.GetM();
712  cplx one, invDiag, fact, zero;
713  SetComplexOne(one);
714  SetComplexZero(zero);
715  Vector<cplx> SumRow(n);
716  SumRow.Fill(zero);
717  // loop on rows
718  for (int i = 0; i < n; i++)
719  {
720  if (A.GetRowSize(i) == 0)
721  {
722  cout << "Empty row " << i << endl;
723  cout << "Factorisation cannot be completed" << endl;
724  abort();
725  }
726 
727  if (A.Index(i, 0) != i)
728  {
729  cout << "No diagonal element on row " << i << endl;
730  cout << "ILU(0) needs one" << endl;
731  abort();
732  }
733 
734  // adding fill-in values to the diagonal
735  A.Value(i, 0) += SumRow(i);
736  if (A.Value(i, 0) == zero)
737  {
738  cout << "Factorization fails because we found a null coefficient"
739  << " on diagonal " << i << endl;
740  abort();
741  }
742 
743  invDiag = one / A.Value(i, 0);
744  // loop on each extra-diagonal element of the row
745  for (int jloc = 1; jloc < A.GetRowSize(i); jloc++)
746  {
747  int j = A.Index(i, jloc);
748  // combination Lj <- Lj - a_ji / a_ii L_i
749  // for upper part of the row Lj
750  fact = A.Value(i, jloc) * invDiag;
751 
752  int k2 = 0;
753  while ((k2 < A.GetRowSize(i)) && (A.Index(i, k2) < j))
754  k2++;
755 
756  for (int kloc = 0; kloc < A.GetRowSize(j); kloc++)
757  {
758  int k = A.Index(j, kloc);
759  // MILU(0) -> combination performed only if a non-zero entry
760  // exists at position (j, k)
761  // Fill-in elements are summed and reported to the diagonal
762  while ((k2 < A.GetRowSize(i)) && (A.Index(i, k2) < k))
763  SumRow(j) -= fact * A.Value(i, k2++);
764 
765  if ((k2 < A.GetRowSize(i)) && (A.Index(i, k2) == k))
766  A.Value(j, kloc) -= fact * A.Value(i, k2++);
767  }
768 
769  while (k2 < A.GetRowSize(i))
770  SumRow(j) -= fact * A.Value(i, k2++);
771  }
772 
773  // storing inverse of diagonal
774  A.Value(i, 0) = invDiag;
775  }
776 
777  // for each row of A, we divide by diagonal value
778  for (int i = 0; i < n; i++)
779  for (int j = 1; j < A.GetRowSize(i); j++)
780  A.Value(i, j) *= A.Value(i, 0);
781  }
782 
783 
784 } // end namespace
785 
786 #define SELDON_FILE_SYMMETRIC_ILUT_PRECONDITIONING_CXX
787 #endif
Seldon::Copy
void Copy(const DistributedMatrix< complex< T >, Prop1, Storage1, Allocator1 > &A, DistributedMatrix< T, Prop2, Storage2, Allocator2 > &B)
converts a distributed matrix to another one
Definition: DistributedMatrixInline.cxx:344
Seldon::Vector
Definition: SeldonHeader.hxx:207
Seldon::Matrix
Definition: SeldonHeader.hxx:226
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::IlutPreconditioning
Definition: IlutPreconditioning.hxx:27
Seldon
Seldon namespace.
Definition: Array.cxx:24