SparseSolver.cxx
1 // Copyright (C) 2011 Marc DuruflĂ©
2 // Copyright (C) 2010-2011 Vivien Mallet
3 //
4 // This file is part of the linear-algebra library Seldon,
5 // http://seldon.sourceforge.net/.
6 //
7 // Seldon is free software; you can redistribute it and/or modify it under the
8 // terms of the GNU Lesser General Public License as published by the Free
9 // Software Foundation; either version 2.1 of the License, or (at your option)
10 // any later version.
11 //
12 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 // more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with Seldon. If not, see http://www.gnu.org/licenses/.
19 
20 
21 #ifndef SELDON_FILE_COMPUTATION_SPARSESOLVER_CXX
22 
23 #include "SparseSolverInline.cxx"
24 
25 namespace Seldon
26 {
27 
28  /*****************************************
29  * Virtual interface with direct solvers *
30  *****************************************/
31 
32 
34  template<class T>
36  {
37  }
38 
39 
41  template<class T>
43  {
44  // default method : no pivoting
45  }
46 
47 
49  template<class T>
51  {
52  }
53 
54 
56  template<class T>
58  {
59  }
60 
61 
63  template<class T>
65  {
66  }
67 
68 
70  template<class T>
73  {
74  }
75 
76 
78  template<class T>
81  {
82  }
83 
84 
86  template<class T>
88  {
89  }
90 
91 
93  template<class T>
95  {
96  }
97 
98 
100  template<class T>
102  {
103  }
104 
105 
107  template<class T>
109  {
110  }
111 
112 
113 #ifdef SELDON_WITH_MPI
114  template<class T>
117  ::FactorizeDistributedMatrix(MPI_Comm& comm_facto, Vector<long>& Ptr,
118  Vector<int>& IndRow, Vector<T>& Val,
119  const Vector<int>& glob_number,
120  bool sym, bool keep_matrix)
121  {
122  // if this method is not overloaded, the computation is stopped
123  cout << "FactorizeDistributedMatrix (32 bits) not present " << endl;
124  cout << "Is it implemented in the chosen solver ?" << endl;
125  cout << "Or the 64 bits version should be called ?" << endl;
126  abort();
127  }
128 
129 
131  template<class T>
132  void VirtualSparseDirectSolver<T>
133  ::FactorizeDistributedMatrix(MPI_Comm& comm_facto, Vector<int64_t>& Ptr,
134  Vector<int64_t>& IndRow, Vector<T>& Val,
135  const Vector<int>& glob_number,
136  bool sym, bool keep_matrix)
137  {
138  // if this method is not overloaded, the computation is stopped
139  cout << "FactorizeDistributedMatrix (64 bits) not present " << endl;
140  cout << "Is it implemented in the chosen solver ?" << endl;
141  cout << "Or the 32 bits version should be called ?" << endl;
142  abort();
143  }
144 
145 
147  template<class T>
148  void VirtualSparseDirectSolver<T>
149  ::PerformAnalysisDistributed(MPI_Comm& comm_facto, Vector<long>& Ptr,
150  Vector<int>& IndRow, Vector<T>& Val,
151  const Vector<int>& glob_number,
152  bool sym, bool keep_matrix)
153  {
154  // if this method is not overloaded, the computation is stopped
155  cout << "PerformAnalysisDistributed (32 bits) not present " << endl;
156  cout << "Is it implemented in the chosen solver ?" << endl;
157  cout << "Or the 64 bits version should be called ?" << endl;
158  abort();
159  }
160 
161 
163  template<class T>
164  void VirtualSparseDirectSolver<T>
165  ::PerformAnalysisDistributed(MPI_Comm& comm_facto, Vector<int64_t>& Ptr,
166  Vector<int64_t>& IndRow, Vector<T>& Val,
167  const Vector<int>& glob_number,
168  bool sym, bool keep_matrix)
169  {
170  // if this method is not overloaded, the computation is stopped
171  cout << "PerformAnalysisDistributed (64 bits) not present " << endl;
172  cout << "Is it implemented in the chosen solver ?" << endl;
173  cout << "Or the 32 bits version should be called ?" << endl;
174  abort();
175  }
176 
177 
179  template<class T>
180  void VirtualSparseDirectSolver<T>
181  ::PerformFactorizationDistributed(MPI_Comm& comm_facto, Vector<long>& Ptr,
182  Vector<int>& IndRow, Vector<T>& Val,
183  const Vector<int>& glob_number,
184  bool sym, bool keep_matrix)
185  {
186  // if this method is not overloaded, the computation is stopped
187  cout << "PerformAnalysisDistributed (32 bits) not present " << endl;
188  cout << "Is it implemented in the chosen solver ?" << endl;
189  cout << "Or the 64 bits version should be called ?" << endl;
190  abort();
191  }
192 
193 
195  template<class T>
196  void VirtualSparseDirectSolver<T>
197  ::PerformFactorizationDistributed(MPI_Comm& comm_facto, Vector<int64_t>& Ptr,
198  Vector<int64_t>& IndRow, Vector<T>& Val,
199  const Vector<int>& glob_number,
200  bool sym, bool keep_matrix)
201  {
202  // if this method is not overloaded, the computation is stopped
203  cout << "PerformAnalysisDistributed (64 bits) not present " << endl;
204  cout << "Is it implemented in the chosen solver ?" << endl;
205  cout << "Or the 32 bits version should be called ?" << endl;
206  abort();
207  }
208 
209 
212  template<class T>
213  void VirtualSparseDirectSolver<T>
214  ::SolveDistributed(MPI_Comm& comm_facto, const SeldonTranspose& TransA,
215  T* x_ptr, int nrhs, const IVect& glob_num)
216  {
217  cout << "SolveDistributed is not present" << endl;
218  cout << "Is it implemented in the chosen solver ?" << endl;
219  abort();
220  }
221 #endif
222 
223  /*************************
224  * Default Seldon solver *
225  *************************/
226 
227 
229  template<class T, class Allocator>
231  {
232  size_t taille = mat_sym.GetMemorySize() + mat_unsym.GetMemorySize();
233  taille += permutation_row.GetMemorySize() + permutation_col.GetMemorySize();
234  return taille;
235  }
236 
237 
239 
244  template<class T, class Allocator>
245  template<class T0, class Storage0, class Allocator0>
249  bool keep_matrix)
250  {
251  IVect inv_permutation;
252 
253  // We convert matrix to unsymmetric format.
254  Copy(mat, mat_unsym);
255 
256  // Old matrix is erased if needed.
257  if (!keep_matrix)
258  mat.Clear();
259 
260  // We keep permutation array in memory, and check it.
261  int n = mat_unsym.GetM();
262  if (perm.GetM() != n)
263  throw WrongArgument("FactorizeMatrix(IVect&, Matrix&, bool)",
264  "Numbering array is of size "
265  + to_str(perm.GetM())
266  + " while the matrix is of size "
267  + to_str(mat.GetM()) + " x "
268  + to_str(mat.GetN()) + ".");
269 
270  permutation_row.Reallocate(n);
271  permutation_col.Reallocate(n);
272  inv_permutation.Reallocate(n);
273  inv_permutation.Fill(-1);
274  for (int i = 0; i < n; i++)
275  {
276  permutation_row(i) = i;
277  permutation_col(i) = i;
278  inv_permutation(perm(i)) = i;
279  }
280 
281  for (int i = 0; i < n; i++)
282  if (inv_permutation(i) == -1)
283  throw WrongArgument("FactorizeMatrix(IVect&, Matrix&, bool)",
284  "The numbering array is invalid.");
285 
286  IVect iperm = inv_permutation;
287 
288  // Rows of matrix are permuted.
289  ApplyInversePermutation(mat_unsym, perm, perm);
290 
291  // Factorization is performed.
292  // Columns are permuted during the factorization.
293  symmetric_matrix = false;
294  inv_permutation.Fill();
295  GetLU(mat_unsym, permutation_col, inv_permutation, permtol, print_level);
296 
297  // Combining permutations.
298  IVect itmp = permutation_col;
299  for (int i = 0; i < n; i++)
300  permutation_col(i) = iperm(itmp(i));
301 
302  permutation_row = perm;
303 
304  }
305 
306 
308 
313  template<class T, class Allocator>
314  template<class T0, class Storage0, class Allocator0>
318  bool keep_matrix)
319  {
320  IVect inv_permutation;
321 
322  // We convert matrix to symmetric format.
323  Copy(mat, mat_sym);
324 
325  // Old matrix is erased if needed.
326  if (!keep_matrix)
327  mat.Clear();
328 
329  // We keep permutation array in memory, and check it.
330  int n = mat_sym.GetM();
331  if (perm.GetM() != n)
332  throw WrongArgument("FactorizeMatrix(IVect&, Matrix&, bool)",
333  "Numbering array is of size "
334  + to_str(perm.GetM())
335  + " while the matrix is of size "
336  + to_str(mat.GetM()) + " x "
337  + to_str(mat.GetN()) + ".");
338 
339  permutation_row.Reallocate(n);
340  inv_permutation.Reallocate(n);
341  inv_permutation.Fill(-1);
342  for (int i = 0; i < n; i++)
343  {
344  permutation_row(i) = perm(i);
345  inv_permutation(perm(i)) = i;
346  }
347 
348  for (int i = 0; i < n; i++)
349  if (inv_permutation(i) == -1)
350  throw WrongArgument("FactorizeMatrix(IVect&, Matrix&, bool)",
351  "The numbering array is invalid.");
352 
353  // Matrix is permuted.
354  ApplyInversePermutation(mat_sym, perm, perm);
355 
356  // Factorization is performed.
357  symmetric_matrix = true;
358  GetLU(mat_sym, print_level);
359  }
360 
361 
362  template<class T, class Allocator> template<class T1>
364  {
365  Vector<T1> xtmp(z);
366 
367  if (symmetric_matrix)
368  {
369  for (int i = 0; i < z.GetM(); i++)
370  xtmp(permutation_row(i)) = z(i);
371 
372  SolveLU(mat_sym, xtmp);
373 
374  for (int i = 0; i < z.GetM(); i++)
375  z(i) = xtmp(permutation_row(i));
376  }
377  else
378  {
379  for (int i = 0; i < z.GetM(); i++)
380  xtmp(permutation_row(i)) = z(i);
381 
382  SolveLU(mat_unsym, xtmp);
383 
384  for (int i = 0; i < z.GetM(); i++)
385  z(permutation_col(i)) = xtmp(i);
386  }
387  }
388 
389 
390  template<class T, class Allocator> template<class T1>
391  void SparseSeldonSolver<T, Allocator>
392  ::Solve(const SeldonTranspose& TransA, Vector<T1>& z)
393  {
394  if (symmetric_matrix)
395  Solve(z);
396  else
397  {
398  Vector<T1> xtmp(z);
399  if (TransA.Trans())
400  {
401  for (int i = 0; i < z.GetM(); i++)
402  xtmp(i) = z(permutation_col(i));
403 
404  SolveLU(SeldonTrans, mat_unsym, xtmp);
405 
406  for (int i = 0; i < z.GetM(); i++)
407  z(i) = xtmp(permutation_row(i));
408  }
409  else
410  Solve(z);
411  }
412  }
413 
414 
415  template<class T, class Allocator>
416  void SparseSeldonSolver<T, Allocator>
417  ::Solve(const SeldonTranspose& TransA, T* x_ptr, int nrhs)
418  {
419  Vector<T> x;
420  int n = permutation_row.GetM();
421  for (int k = 0; k < nrhs; k++)
422  {
423  x.SetData(n, &x_ptr[k*n]);
424  Solve(TransA, x);
425  x.Nullify();
426  }
427  }
428 
429 
430  /************************************************
431  * GetLU and SolveLU used by SeldonSparseSolver *
432  ************************************************/
433 
434 
436  template<class T, class Allocator>
438  IVect& iperm, IVect& rperm,
439  const double& permtol, int print_level)
440  {
441  int n = A.GetN();
442 
443  T fact, s, t;
444  typedef typename ClassComplexType<T>::Treal Treal;
445  Treal tnorm, zero = 0.0;
446  int length_lower, length_upper, jpos, jrow, i_row, j_col;
447  int i, j, k, length, size_row, index_lu;
448 
449  T czero, cone;
450  SetComplexZero(czero);
451  SetComplexOne(cone);
453  IVect Index(n), Row_Ind(n), Index_Diag(n);
454  Row_Val.Fill(czero);
455  Row_Ind.Fill(-1);
456  Index_Diag.Fill(-1);
457 
458  Index.Fill(-1);
459  // main loop
460  int new_percent = 0, old_percent = 0;
461  for (i_row = 0; i_row < n; i_row++)
462  {
463  // Progress bar if print level is high enough.
464  if (print_level > 0)
465  {
466  new_percent = int(double(i_row) / double(n-1) * 78.);
467  for (int percent = old_percent; percent < new_percent; percent++)
468  {
469  cout << "#";
470  cout.flush();
471  }
472 
473  old_percent = new_percent;
474  }
475 
476  size_row = A.GetRowSize(i_row);
477  tnorm = zero;
478 
479  // tnorm is the sum of absolute value of coefficients of row i_row.
480  for (k = 0 ; k < size_row; k++)
481  if (A.Value(i_row, k) != czero)
482  tnorm += abs(A.Value(i_row, k));
483 
484  if (tnorm == zero)
485  throw WrongArgument("GetLU(Matrix<ArrayRowSparse>&, IVect&, "
486  "IVect&, double, int)",
487  "The matrix is structurally singular. "
488  "The norm of row " + to_str(i_row)
489  + " is equal to 0.");
490 
491  // Unpack L-part and U-part of row of A.
492  length_upper = 1;
493  length_lower = 0;
494  Row_Ind(i_row) = i_row;
495  Row_Val(i_row) = czero;
496  Index(i_row) = i_row;
497 
498  for (j = 0; j < size_row; j++)
499  {
500  k = rperm(A.Index(i_row, j));
501 
502  t = A.Value(i_row,j);
503  if (k < i_row)
504  {
505  Row_Ind(length_lower) = k;
506  Row_Val(length_lower) = t;
507  Index(k) = length_lower;
508  ++length_lower;
509  }
510  else if (k == i_row)
511  {
512  Row_Val(i_row) = t;
513  }
514  else
515  {
516  jpos = i_row + length_upper;
517  Row_Ind(jpos) = k;
518  Row_Val(jpos) = t;
519  Index(k) = jpos;
520  length_upper++;
521  }
522  }
523 
524  j_col = 0;
525  length = 0;
526 
527  // Eliminates previous rows.
528  while (j_col < length_lower)
529  {
530  // In order to do the elimination in the correct order, we must
531  // select the smallest column index.
532  jrow = Row_Ind(j_col);
533  k = j_col;
534 
535  // Determine smallest column index.
536  for (j = j_col + 1; j < length_lower; j++)
537  if (Row_Ind(j) < jrow)
538  {
539  jrow = Row_Ind(j);
540  k = j;
541  }
542 
543  if (k != j_col)
544  {
545  // Exchanging column coefficients.
546  j = Row_Ind(j_col);
547  Row_Ind(j_col) = Row_Ind(k);
548  Row_Ind(k) = j;
549 
550  Index(jrow) = j_col;
551  Index(j) = k;
552 
553  s = Row_Val(j_col);
554  Row_Val(j_col) = Row_Val(k);
555  Row_Val(k) = s;
556  }
557 
558  // Zero out element in row.
559  Index(jrow) = -1;
560 
561  // Gets the multiplier for row to be eliminated (jrow).
562  // first_index_upper points now on the diagonal coefficient.
563  fact = Row_Val(j_col) * A.Value(jrow, Index_Diag(jrow));
564 
565  // Combines current row and row jrow.
566  for (k = (Index_Diag(jrow)+1); k < A.GetRowSize(jrow); k++)
567  {
568  s = fact * A.Value(jrow,k);
569  j = rperm(A.Index(jrow,k));
570 
571  jpos = Index(j);
572 
573  if (j >= i_row)
574  // Dealing with upper part.
575  if (jpos == -1)
576  {
577  // This is a fill-in element.
578  i = i_row + length_upper;
579  Row_Ind(i) = j;
580  Index(j) = i;
581  Row_Val(i) = -s;
582  ++length_upper;
583  }
584  else
585  // This is not a fill-in element.
586  Row_Val(jpos) -= s;
587  else
588  // Dealing with lower part.
589  if (jpos == -1)
590  {
591  // this is a fill-in element
592  Row_Ind(length_lower) = j;
593  Index(j) = length_lower;
594  Row_Val(length_lower) = -s;
595  ++length_lower;
596  }
597  else
598  // This is not a fill-in element.
599  Row_Val(jpos) -= s;
600  }
601 
602  // Stores this pivot element from left to right -- no danger
603  // of overlap with the working elements in L (pivots).
604  Row_Val(length) = fact;
605  Row_Ind(length) = jrow;
606  ++length;
607  j_col++;
608  }
609 
610  // Resets double-pointer to zero (U-part).
611  for (k = 0; k < length_upper; k++)
612  Index(Row_Ind(i_row + k)) = -1;
613 
614  size_row = length;
615  A.ReallocateRow(i_row,size_row);
616 
617  // store L-part
618  index_lu = 0;
619  for (k = 0 ; k < length ; k++)
620  {
621  A.Value(i_row,index_lu) = Row_Val(k);
622  A.Index(i_row,index_lu) = iperm(Row_Ind(k));
623  ++index_lu;
624  }
625 
626  // Saves pointer to beginning of row i_row of U.
627  Index_Diag(i_row) = index_lu;
628 
629  // Updates. U-matrix -- first apply dropping strategy.
630  length = 0;
631  for (k = 1; k <= (length_upper-1); k++)
632  {
633  ++length;
634  Row_Val(i_row+length) = Row_Val(i_row+k);
635  Row_Ind(i_row+length) = Row_Ind(i_row+k);
636  }
637 
638  length++;
639 
640  // Determines next pivot.
641  int imax = i_row;
642  Treal xmax = abs(Row_Val(imax));
643  Treal xmax0 = xmax;
644  for (k = i_row + 1; k <= i_row + length - 1; k++)
645  {
646  tnorm = abs(Row_Val(k));
647  if (tnorm > xmax && tnorm * permtol > xmax0)
648  {
649  imax = k;
650  xmax = tnorm;
651  }
652  }
653 
654  // Exchanges Row_Val.
655  s = Row_Val(i_row);
656  Row_Val(i_row) = Row_Val(imax);
657  Row_Val(imax) = s;
658 
659  // Updates iperm and reverses iperm.
660  j = Row_Ind(imax);
661  i = iperm(i_row);
662  iperm(i_row) = iperm(j);
663  iperm(j) = i;
664 
665  // Reverses iperm.
666  rperm(iperm(i_row)) = i_row;
667  rperm(iperm(j)) = j;
668 
669  // Copies U-part in original coordinates.
670  int index_diag = index_lu;
671  A.ResizeRow(i_row, size_row+length);
672 
673  for (k = i_row ; k <= i_row + length - 1; k++)
674  {
675  A.Index(i_row,index_lu) = iperm(Row_Ind(k));
676  A.Value(i_row,index_lu) = Row_Val(k);
677  ++index_lu;
678  }
679 
680  // Stores inverse of diagonal element of u.
681  A.Value(i_row, index_diag) = cone / Row_Val(i_row);
682 
683  } // end main loop
684 
685  if (print_level > 0)
686  cout << endl;
687 
688  if (print_level > 0)
689  cout << "The matrix takes " <<
690  int((A.GetDataSize() * (sizeof(T) + 4)) / (1024. * 1024.))
691  << " MB" << endl;
692 
693  for (i = 0; i < n; i++ )
694  for (j = 0; j < A.GetRowSize(i); j++)
695  A.Index(i,j) = rperm(A.Index(i,j));
696 
697  }
698 
699 
700  template<class T1, class Allocator1,
701  class T2, class Storage2, class Allocator2>
702  void SolveLuVector(const Matrix<T1, General, ArrayRowSparse, Allocator1>& A,
703  Vector<T2, Storage2, Allocator2>& x)
704  {
705  SolveLuVector(SeldonNoTrans, A, x);
706  }
707 
708 
710 
713  template<class T1, class Allocator1,
714  class T2, class Storage2, class Allocator2>
715  void SolveLuVector(const SeldonTranspose& transA,
718  {
719  int i, k, n, k_;
720  T1 inv_diag;
721  n = A.GetM();
722 
723  if (transA.Trans())
724  {
725  // Forward solve (with U^T).
726  for (i = 0 ; i < n ; i++)
727  {
728  k_ = 0; k = A.Index(i,k_);
729  while (k < i)
730  {
731  k_++;
732  k = A.Index(i,k_);
733  }
734 
735  x(i) *= A.Value(i,k_);
736  for (k = k_ + 1; k < A.GetRowSize(i) ; k++)
737  x(A.Index(i,k)) -= A.Value(i,k) * x(i);
738  }
739 
740  // Backward solve (with L^T).
741  for (i = n-1 ; i>=0 ; i--)
742  {
743  k_ = 0; k = A.Index(i, k_);
744  while (k < i)
745  {
746  x(k) -= A.Value(i, k_)*x(i);
747  k_++;
748  k = A.Index(i, k_);
749  }
750  }
751  }
752  else
753  {
754  // Forward solve.
755  for (i = 0; i < n; i++)
756  {
757  k_ = 0;
758  k = A.Index(i, k_);
759  while (k < i)
760  {
761  x(i) -= A.Value(i, k_) * x(k);
762  k_++;
763  k = A.Index(i, k_);
764  }
765  }
766 
767  // Backward solve.
768  for (i = n-1; i >= 0; i--)
769  {
770  k_ = 0;
771  k = A.Index(i, k_);
772  while (k < i)
773  {
774  k_++;
775  k = A.Index(i, k_);
776  }
777 
778  inv_diag = A.Value(i, k_);
779  for (k = k_ + 1; k < A.GetRowSize(i); k++)
780  x(i) -= A.Value(i, k) * x(A.Index(i, k));
781 
782  x(i) *= inv_diag;
783  }
784  }
785  }
786 
787 
789  template<class T, class Allocator>
791  int print_level)
792  {
793  int size_row;
794  int n = A.GetN();
795  typename ClassComplexType<T>::Treal zero(0), tnorm, one(1);
796 
797  T fact, s, t;
798  int length_lower, length_upper, jpos, jrow;
799  int i_row, j_col, index_lu, length;
800  int i, j, k;
801 
803  IVect Index(n), Row_Ind(n);
804  Row_Val.Zero();
805  Row_Ind.Fill(-1);
806  Index.Fill(-1);
807 
808  // We convert A into an unsymmetric matrix.
810  Seldon::Copy(A, B);
811 
812  A.Clear();
813  A.Reallocate(n, n);
814 
815  // Main loop.
816  int new_percent = 0, old_percent = 0;
817  for (i_row = 0; i_row < n; i_row++)
818  {
819  // Progress bar if print level is high enough.
820  if (print_level > 0)
821  {
822  new_percent = int(double(i_row) / double(n-1) * 78.);
823  for (int percent = old_percent; percent < new_percent; percent++)
824  {
825  cout << "#";
826  cout.flush();
827  }
828  old_percent = new_percent;
829  }
830 
831  // 1-norm of the row of initial matrix.
832  size_row = B.GetRowSize(i_row);
833  tnorm = zero;
834  for (k = 0 ; k < size_row; k++)
835  tnorm += abs(B.Value(i_row, k));
836 
837  if (tnorm == zero)
838  throw WrongArgument("GetLU(Matrix<ArrayRowSymSparse>&, int)",
839  "The matrix is structurally singular. "
840  "The norm of row " + to_str(i_row)
841  + " is equal to 0.");
842 
843  // Separating lower part from upper part for this row.
844  length_upper = 1;
845  length_lower = 0;
846  Row_Ind(i_row) = i_row;
847  SetComplexZero(Row_Val(i_row));
848  Index(i_row) = i_row;
849 
850  for (j = 0; j < size_row; j++)
851  {
852  k = B.Index(i_row,j);
853  t = B.Value(i_row,j);
854  if (k < i_row)
855  {
856  Row_Ind(length_lower) = k;
857  Row_Val(length_lower) = t;
858  Index(k) = length_lower;
859  ++length_lower;
860  }
861  else if (k == i_row)
862  {
863  Row_Val(i_row) = t;
864  }
865  else
866  {
867  jpos = i_row + length_upper;
868  Row_Ind(jpos) = k;
869  Row_Val(jpos) = t;
870  Index(k) = jpos;
871  length_upper++;
872  }
873  }
874 
875  // This row of B is cleared.
876  B.ClearRow(i_row);
877 
878  j_col = 0;
879  length = 0;
880 
881  // We eliminate previous rows.
882  while (j_col <length_lower)
883  {
884  // In order to do the elimination in the correct order, we must
885  // select the smallest column index.
886  jrow = Row_Ind(j_col);
887  k = j_col;
888 
889  // We determine smallest column index.
890  for (j = (j_col+1) ; j < length_lower; j++)
891  {
892  if (Row_Ind(j) < jrow)
893  {
894  jrow = Row_Ind(j);
895  k = j;
896  }
897  }
898 
899  // If needed, we exchange positions of this element in
900  // Row_Ind/Row_Val so that it appears first.
901  if (k != j_col)
902  {
903 
904  j = Row_Ind(j_col);
905  Row_Ind(j_col) = Row_Ind(k);
906  Row_Ind(k) = j;
907 
908  Index(jrow) = j_col;
909  Index(j) = k;
910 
911  s = Row_Val(j_col);
912  Row_Val(j_col) = Row_Val(k);
913  Row_Val(k) = s;
914  }
915 
916  // Zero out element in row by setting Index to -1.
917  Index(jrow) = -1;
918 
919  // Gets the multiplier for row to be eliminated.
920  fact = Row_Val(j_col) * A.Value(jrow, 0);
921 
922  // Combines current row and row jrow.
923  for (k = 1; k < A.GetRowSize(jrow); k++)
924  {
925  s = fact * A.Value(jrow, k);
926  j = A.Index(jrow, k);
927 
928  jpos = Index(j);
929  if (j >= i_row)
930  {
931 
932  // Dealing with upper part.
933  if (jpos == -1)
934  {
935  // This is a fill-in element.
936  i = i_row + length_upper;
937  Row_Ind(i) = j;
938  Index(j) = i;
939  Row_Val(i) = -s;
940  ++length_upper;
941  }
942  else
943  {
944  // This is not a fill-in element.
945  Row_Val(jpos) -= s;
946  }
947  }
948  else
949  {
950  // Dealing with lower part.
951  if (jpos == -1)
952  {
953  // This is a fill-in element.
954  Row_Ind(length_lower) = j;
955  Index(j) = length_lower;
956  Row_Val(length_lower) = -s;
957  ++length_lower;
958  }
959  else
960  {
961  // This is not a fill-in element.
962  Row_Val(jpos) -= s;
963  }
964  }
965  }
966 
967  // We store this pivot element (from left to right -- no
968  // danger of overlap with the working elements in L (pivots).
969  Row_Val(length) = fact;
970  Row_Ind(length) = jrow;
971  ++length;
972  j_col++;
973  }
974 
975  // Resets double-pointer to zero (U-part).
976  for (k = 0; k < length_upper; k++)
977  Index(Row_Ind(i_row + k)) = -1;
978 
979  // Updating U-matrix
980  length = 0;
981  for (k = 1; k <= length_upper - 1; k++)
982  {
983  ++length;
984  Row_Val(i_row + length) = Row_Val(i_row + k);
985  Row_Ind(i_row + length) = Row_Ind(i_row + k);
986  }
987 
988  length++;
989 
990  // Copies U-part in matrix A.
991  A.ReallocateRow(i_row, length);
992  index_lu = 1;
993  for (k = i_row + 1 ; k <= i_row + length - 1 ; k++)
994  {
995  A.Index(i_row, index_lu) = Row_Ind(k);
996  A.Value(i_row, index_lu) = Row_Val(k);
997  ++index_lu;
998  }
999 
1000  // Stores the inverse of the diagonal element of u.
1001  A.Value(i_row,0) = one / Row_Val(i_row);
1002 
1003  } // end main loop.
1004 
1005  if (print_level > 0)
1006  cout << endl;
1007 
1008  // for each row of A, we divide by diagonal value
1009  for (int i = 0; i < n; i++)
1010  for (int j = 1; j < A.GetRowSize(i); j++)
1011  A.Value(i, j) *= A.Value(i, 0);
1012 
1013  if (print_level > 0)
1014  cout << "The matrix takes " <<
1015  int((A.GetDataSize() * (sizeof(T) + 4)) / (1024. * 1024.))
1016  << " MB" << endl;
1017 
1018  }
1019 
1020 
1021  template<class T1, class Allocator1,
1022  class T2, class Storage2, class Allocator2>
1023  void SolveLuVector(const Matrix<T1, Symmetric, ArrayRowSymSparse, Allocator1>& A,
1024  Vector<T2, Storage2, Allocator2>& x)
1025  {
1026  SolveLuVector(SeldonNoTrans, A, x);
1027  }
1028 
1029 
1031 
1034  template<class T1, class Allocator1,
1035  class T2, class Storage2, class Allocator2>
1036  void SolveLuVector(const SeldonTranspose& transA,
1039  {
1040  int n = A.GetM(), j_row;
1041  T2 tmp;
1042 
1043  // We solve first L y = b.
1044  for (int i_col = 0; i_col < n ; i_col++)
1045  {
1046  for (int k = 1; k < A.GetRowSize(i_col) ; k++)
1047  {
1048  j_row = A.Index(i_col, k);
1049  x(j_row) -= A.Value(i_col, k)*x(i_col);
1050  }
1051  }
1052 
1053  // Inverting by diagonal D.
1054  for (int i_col = 0; i_col < n ; i_col++)
1055  x(i_col) *= A.Value(i_col, 0);
1056 
1057  // Then we solve L^t x = y.
1058  for (int i_col = n-1; i_col >=0 ; i_col--)
1059  {
1060  tmp = x(i_col);
1061  for (int k = 1; k < A.GetRowSize(i_col) ; k++)
1062  {
1063  j_row = A.Index(i_col, k);
1064  tmp -= A.Value(i_col, k)*x(j_row);
1065  }
1066 
1067  x(i_col) = tmp;
1068  }
1069  }
1070 
1071 
1072  /********************************************
1073  * GetLU and SolveLU for SeldonSparseSolver *
1074  ********************************************/
1075 
1076 
1078  template<class MatrixSparse, class T, class Alloc2>
1079  void GetLU(MatrixSparse& A, SparseSeldonSolver<T, Alloc2>& mat_lu,
1080  bool keep_matrix, T& x)
1081  {
1082  // identity ordering
1083  IVect perm(A.GetM());
1084  perm.Fill();
1085 
1086  // factorisation
1087  mat_lu.FactorizeMatrix(perm, A, keep_matrix);
1088  }
1089 
1090 
1092  template<class MatrixSparse, class T, class Alloc2>
1093  void GetLU(MatrixSparse& A, SparseSeldonSolver<T, Alloc2>& mat_lu,
1094  bool keep_matrix, complex<T>& x)
1095  {
1096  throw WrongArgument("GetLU(Matrix<complex<T> >& A, "
1097  + string("SparseSeldonSolver<T>& mat_lu, bool)"),
1098  "The LU matrix must be complex");
1099  }
1100 
1101 
1103  template<class MatrixSparse, class T, class Alloc2>
1104  void GetLU(MatrixSparse& A, SparseSeldonSolver<complex<T>, Alloc2>& mat_lu,
1105  bool keep_matrix, T& x)
1106  {
1107  throw WrongArgument("GetLU(Matrix<T>& A, " +
1108  string("SparseSeldonSolver<complex<T> >& mat_lu, bool)"),
1109  "The sparse matrix must be complex");
1110  }
1111 
1112 
1114  template<class T0, class Prop, class Storage, class Allocator,
1115  class T, class Alloc2>
1117  SparseSeldonSolver<T, Alloc2>& mat_lu, bool keep_matrix)
1118  {
1120  GetLU(A, mat_lu, keep_matrix, x);
1121  }
1122 
1123 
1125  template<class MatrixSparse, class T, class Alloc2>
1126  void GetLU(MatrixSparse& A, SparseSeldonSolver<T, Alloc2>& mat_lu,
1127  IVect& permut, bool keep_matrix, T& x)
1128  {
1129  mat_lu.FactorizeMatrix(permut, A, keep_matrix);
1130  }
1131 
1132 
1134  template<class MatrixSparse, class T, class Alloc2>
1135  void GetLU(MatrixSparse& A, SparseSeldonSolver<T, Alloc2>& mat_lu,
1136  IVect& permut, bool keep_matrix, complex<T>& x)
1137  {
1138  throw WrongArgument(string("GetLU(Matrix<complex<T> >& A, ")
1139  + "SparseSeldonSolver<T>& mat_lu, bool)",
1140  "The LU matrix must be complex");
1141  }
1142 
1143 
1145  template<class MatrixSparse, class T, class Alloc2>
1146  void GetLU(MatrixSparse& A, SparseSeldonSolver<complex<T>, Alloc2>& mat_lu,
1147  IVect& permut, bool keep_matrix, T& x)
1148  {
1149  throw WrongArgument(string("GetLU(Matrix<T>& A, ") +
1150  "SparseSeldonSolver<complex<T> >& mat_lu, bool)",
1151  "The sparse matrix must be complex");
1152  }
1153 
1154 
1156  template<class T0, class Prop, class Storage, class Allocator,
1157  class T, class Alloc2>
1160  IVect& permut, bool keep_matrix)
1161  {
1163  GetLU(A, mat_lu, permut, keep_matrix, x);
1164  }
1165 
1166 
1167  template<class T, class Alloc2, class T1, class Allocator>
1168  void SolveLU(SparseSeldonSolver<T, Alloc2>& mat_lu,
1169  Vector<T1, VectFull, Allocator>& x)
1170  {
1171  mat_lu.Solve(x);
1172  }
1173 
1174 
1175  template<class T, class Alloc2, class T1, class Allocator>
1176  void SolveLU(const SeldonTranspose& TransA,
1177  SparseSeldonSolver<T, Alloc2>& mat_lu,
1178  Vector<T1, VectFull, Allocator>& x)
1179  {
1180  mat_lu.Solve(TransA, x);
1181  }
1182 
1183 
1184 } // namespace Seldon.
1185 
1186 
1187 #define SELDON_FILE_COMPUTATION_SPARSESOLVER_CXX
1188 #endif
Seldon::SeldonTranspose
Definition: MatrixFlag.hxx:32
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::to_str
std::string to_str(const T &input)
Converts most types to string.
Definition: CommonInline.cxx:137
Seldon::Vector< int >
Seldon::VirtualSparseDirectSolver::SelectParallelOrdering
virtual void SelectParallelOrdering(int)
selects ordering to use in parallel for the interfaced solver
Definition: SparseSolver.cxx:94
Seldon::Matrix
Definition: SeldonHeader.hxx:226
Seldon::VirtualSparseDirectSolver::SetPivotThreshold
virtual void SetPivotThreshold(double)
Sets the threshold for pivot.
Definition: SparseSolver.cxx:42
Seldon::VirtualSparseDirectSolver::~VirtualSparseDirectSolver
virtual ~VirtualSparseDirectSolver()
Destructor.
Definition: SparseSolver.cxx:35
Seldon::VirtualSparseDirectSolver::SetIncreaseCoefficientEstimationNeededMemory
virtual void SetIncreaseCoefficientEstimationNeededMemory(double coef)
Method overloaded in Mumps solver.
Definition: SparseSolver.cxx:80
Seldon::SparseSeldonSolver::FactorizeMatrix
void FactorizeMatrix(const IVect &perm, Matrix< T0, General, Storage0, Allocator0 > &mat, bool keep_matrix=false)
performs LU factorisation of matrix mat
Definition: SparseSolver.cxx:247
Seldon::VirtualSparseDirectSolver::SelectOrdering
virtual void SelectOrdering(int)
selects ordering to use in the interfaced solver
Definition: SparseSolver.cxx:87
Seldon::Vector< T, VectFull, Allocator >::Zero
void Zero()
Sets all elements to zero.
Definition: VectorInline.cxx:727
Seldon::Vector< T, VectFull, Allocator >
Full vector class.
Definition: Vector.hxx:88
Seldon::GetLU
void GetLU(Matrix< T0, Prop0, Storage0, Allocator0 > &A)
Returns the LU factorization of a matrix.
Definition: Functions_Matrix.cxx:2073
Seldon::VirtualSparseDirectSolver
Base class for an interface with a direct solver.
Definition: SparseSolver.hxx:30
Seldon::SolveLuVector
void SolveLuVector(const Matrix< T0, Prop0, Storage0, Allocator0 > &M, Vector< T1, Storage1, Allocator1 > &Y)
Solves a linear system whose matrix has been LU-factorized.
Definition: Functions_MatVect.cxx:1782
Seldon::SparseSeldonSolver
Default solver in Seldon.
Definition: SparseSolver.hxx:111
Seldon::SparseSeldonSolver::GetMemorySize
size_t GetMemorySize() const
returns memory used by the object in bytes
Definition: SparseSolver.cxx:230
Seldon::WrongArgument
Definition: Errors.hxx:76
Seldon::VirtualSparseDirectSolver::RefineSolution
virtual void RefineSolution()
Tells to the direct solver that refinement is required.
Definition: SparseSolver.cxx:50
Seldon::VirtualSparseDirectSolver::SetPermutation
virtual void SetPermutation(const Vector< int > &)
gives the ordering array to the interface solver
Definition: SparseSolver.cxx:101
Seldon
Seldon namespace.
Definition: Array.cxx:24
Seldon::VirtualSparseDirectSolver::SetCoefficientEstimationNeededMemory
virtual void SetCoefficientEstimationNeededMemory(double coef)
Method overloaded in Mumps solver.
Definition: SparseSolver.cxx:64
Seldon::VirtualSparseDirectSolver::SetMaximumCoefficientEstimationNeededMemory
virtual void SetMaximumCoefficientEstimationNeededMemory(double coef)
Method overloaded in Mumps solver.
Definition: SparseSolver.cxx:72
Seldon::VirtualSparseDirectSolver::SetNumberOfThreadPerNode
virtual void SetNumberOfThreadPerNode(int n)
Sets the number of threads per mpi process.
Definition: SparseSolver.cxx:108
Seldon::Vector< T, VectFull, Allocator >::Fill
void Fill()
Fills the vector with 0, 1, 2, ...
Definition: VectorInline.cxx:736
Seldon::VirtualSparseDirectSolver::DoNotRefineSolution
virtual void DoNotRefineSolution()
Tells to the direct solver that no refinement is required.
Definition: SparseSolver.cxx:57