MOOCHO (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AbstractLinAlgPack_SuperLUSolver.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization
5 // Copyright (2003) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifdef SPARSE_SOLVER_PACK_USE_SUPERLU
43 
44 #include <assert.h>
45 #include <valarray>
46 #include <stdexcept>
47 
49 #include "Teuchos_dyn_cast.hpp"
50 #include "Teuchos_Workspace.hpp"
51 #include "Teuchos_Assert.hpp"
52 
53 // SuperLU
54 #include "dsp_defs.h"
55 #include "util.h"
56 
57 namespace {
58 
59 // Static SuperLU stuff
60 
61 int local_panel_size = 0;
62 int local_relax = 0;
63 
64 class StaticSuperLUInit {
65 public:
66  StaticSuperLUInit()
67  {
68  local_panel_size = sp_ienv(1);
69  local_relax = sp_ienv(2);
70  StatInit(local_panel_size,local_relax);
71  }
72  ~StaticSuperLUInit()
73  {
74  StatFree();
75  }
76 };
77 
78 StaticSuperLUInit static_super_lu_init; // Will be created early and destroyed late!
79 
80 // ToDo: RAB: 2002/10/14: We must find a better way to work with
81 // SuperLU than this. It should not be too hard
82 // to do better in the future.
83 
84 // A cast to const is needed because the standard does not return a reference from
85 // valarray<>::operator[]() const.
86 template <class T>
87 std::valarray<T>& cva(const std::valarray<T>& va )
88 {
89  return const_cast<std::valarray<T>&>(va);
90 }
91 
92 } // end namespace
93 
94 namespace SuperLUPack {
95 
96 class SuperLUSolverImpl;
97 
102 class SuperLUSolverImpl : public SuperLUSolver {
103 public:
104 
107 
109  class FactorizationStructureImpl : public FactorizationStructure {
110  public:
111  friend class SuperLUSolverImpl;
112  private:
113  int rank_; // For square basis
114  int nz_; // ...
115  std::valarray<int> perm_r_; // ...
116  std::valarray<int> perm_c_; // ...
117  std::valarray<int> etree_; // ...
118  int m_orig_; // For original rectangular matrix
119  int n_orig_; // ...
120  int nz_orig_; // ...
121  std::valarray<int> perm_r_orig_; // ...
122  std::valarray<int> perm_c_orig_; // ...
123  };
124 
126  class FactorizationNonzerosImpl : public FactorizationNonzeros {
127  public:
128  friend class SuperLUSolverImpl;
129  private:
130  SuperMatrix L_;
131  SuperMatrix U_;
132  };
133 
135 
138 
140  void analyze_and_factor(
141  int m
142  ,int n
143  ,int nz
144  ,const double a_val[]
145  ,const int a_row_i[]
146  ,const int a_col_ptr[]
147  ,FactorizationStructure *fact_struct
148  ,FactorizationNonzeros *fact_nonzeros
149  ,int row_perm[]
150  ,int col_perm[]
151  ,int *rank
152  );
154  void factor(
155  int m
156  ,int n
157  ,int nz
158  ,const double a_val[]
159  ,const int a_row_i[]
160  ,const int a_col_ptr[]
161  ,const FactorizationStructure &fact_struct
162  ,FactorizationNonzeros *fact_nonzeros
163  );
165  void solve(
166  const FactorizationStructure &fact_struct
167  ,const FactorizationNonzeros &fact_nonzeros
168  ,bool transp
169  ,int n
170  ,int nrhs
171  ,double rhs[]
172  ,int ldrhs
173  ) const;
174 
176 
177 private:
178 
180  void copy_basis_nonzeros(
181  int m_orig
182  ,int n_orig
183  ,int nz_orig
184  ,const double a_orig_val[]
185  ,const int a_orig_row_i[]
186  ,const int a_orig_col_ptr[]
187  ,const int a_orig_perm_r[]
188  ,const int a_orig_perm_c[]
189  ,const int rank
190  ,double b_val[]
191  ,int b_row_i[]
192  ,int b_col_ptr[]
193  ,int *b_nz
194  ) const;
195 
196 }; // end class SuperLUSolver
197 
198 //
199 // SuperLUSolver
200 //
201 
203 SuperLUSolver::create_solver()
204 {
205  return Teuchos::rcp(new SuperLUSolverImpl());
206 }
207 
209 SuperLUSolver::create_fact_struct()
210 {
211  return Teuchos::rcp(new SuperLUSolverImpl::FactorizationStructureImpl());
212 }
213 
215 SuperLUSolver::create_fact_nonzeros()
216 {
217  return Teuchos::rcp(new SuperLUSolverImpl::FactorizationNonzerosImpl());
218 }
219 
220 //
221 // SuperLUSolverImp
222 //
223 
224 // Overridden from SuperLUSolver
225 
226 void SuperLUSolverImpl::analyze_and_factor(
227  int m
228  ,int n
229  ,int nz
230  ,const double a_val[]
231  ,const int a_row_i[]
232  ,const int a_col_ptr[]
233  ,FactorizationStructure *fact_struct
234  ,FactorizationNonzeros *fact_nonzeros
235  ,int perm_r[]
236  ,int perm_c[]
237  ,int *rank
238  )
239 {
240  using Teuchos::dyn_cast;
241  using Teuchos::Workspace;
243 
244  FactorizationStructureImpl
245  &fs = dyn_cast<FactorizationStructureImpl>(*fact_struct);
246  FactorizationNonzerosImpl
247  &fn = dyn_cast<FactorizationNonzerosImpl>(*fact_nonzeros);
248 
249  char refact[] = "N";
250 
251  // Resize storage.
252  // Note: if this function was called recursively for m>n on the last call
253  // then m_orig, n_orig etc. will already be set and should not be
254  // disturbed.
255  fs.rank_ = n; // Assume this for now
256  fs.nz_ = nz;
257  fs.perm_r_.resize(m);
258  fs.perm_c_.resize(n);
259  fs.etree_.resize(n);
260 
261  // Create matrix A in the format expected by SuperLU
262  SuperMatrix A;
263  dCreate_CompCol_Matrix(
264  &A, m, n, nz
265  ,const_cast<double*>(a_val)
266  ,const_cast<int*>(a_row_i)
267  ,const_cast<int*>(a_col_ptr)
268  ,NC, D_, GE
269  );
270 
271  // Get the columm permutations
272  int permc_spec = 0; // ToDo: Make this an external parameter
273  get_perm_c(permc_spec, &A, &fs.perm_c_[0]);
274 
275  // Permute the columns of the matrix
276  SuperMatrix AC;
277  sp_preorder(refact,&A,&fs.perm_c_[0],&fs.etree_[0],&AC);
278 
279  int info = -1;
280  dgstrf(
281  refact
282  ,&AC
283  ,1.0 /* diag_pivot_thresh */
284  ,0.0 /* drop_tol */
285  ,local_relax
286  ,local_panel_size
287  ,&fs.etree_[0]
288  ,NULL /* work */
289  ,0 /* lwork */
290  ,&fs.perm_r_[0]
291  ,&fs.perm_c_[0]
292  ,&fn.L_
293  ,&fn.U_
294  ,&info
295  );
296 
298  info != 0, std::runtime_error
299  ,"SuperLUSolverImpl::analyze_and_factor(...): Error, dgstrf(...) returned info = " << info
300  );
301 
302  std::copy( &fs.perm_r_[0], &fs.perm_r_[0] + m, perm_r );
303  std::copy( &fs.perm_c_[0], &fs.perm_c_[0] + n, perm_c );
304  *rank = n; // We must assume this until I can figure out a way to do better!
305 
306  if(m > n) {
307  // Now we must refactor the basis by only passing in the elements for the basis
308  // determined by SuperLU. This is wasteful but it is the easiest thing to do
309  // for now.
310  fs.rank_ = *rank;
311  fs.m_orig_ = m;
312  fs.n_orig_ = n;
313  fs.nz_orig_ = nz;
314  fs.perm_r_orig_ = fs.perm_r_;
315  fs.perm_c_orig_ = fs.perm_c_;
316  // Copy the nonzeros for the sqare factor into new storage
317  Workspace<double> b_val(wss,nz);
318  Workspace<int> b_row_i(wss,nz);
319  Workspace<int> b_col_ptr(wss,n+1);
320  copy_basis_nonzeros(
321  m,n,nz,a_val,a_row_i,a_col_ptr
322  ,&fs.perm_r_orig_[0],&fs.perm_c_orig_[0],fs.rank_
323  ,&b_val[0],&b_row_i[0],&b_col_ptr[0]
324  ,&fs.nz_
325  );
326  // Analyze and factor the new matrix
327  int b_rank = -1;
328  analyze_and_factor(
329  fs.rank_, fs.rank_, fs.nz_, &b_val[0], &b_row_i[0], &b_col_ptr[0]
330  ,fact_struct, fact_nonzeros
331  ,&fs.perm_r_[0], &fs.perm_c_[0], &b_rank
332  );
334  (b_rank != *rank), std::runtime_error
335  ,"SuperLUSolverImpl::analyze_and_factor(...): Error, the rank determined by "
336  "the factorization of the rectangular " << m << " x " << n << " matrix of "
337  << (*rank) << " is not the same as the refactorization of the basis returned as "
338  << b_rank << "!"
339  );
340  }
341  else {
342  fs.m_orig_ = m;
343  fs.n_orig_ = n;
344  fs.nz_orig_ = nz;
345  }
346 }
347 
348 void SuperLUSolverImpl::factor(
349  int m
350  ,int n
351  ,int nz
352  ,const double a_val[]
353  ,const int a_row_i[]
354  ,const int a_col_ptr[]
355  ,const FactorizationStructure &fact_struct
356  ,FactorizationNonzeros *fact_nonzeros
357  )
358 {
359  using Teuchos::dyn_cast;
360  using Teuchos::Workspace;
362 
363  const FactorizationStructureImpl
364  &fs = dyn_cast<const FactorizationStructureImpl>(fact_struct);
365  FactorizationNonzerosImpl
366  &fn = dyn_cast<FactorizationNonzerosImpl>(*fact_nonzeros);
367 
368  char refact[] = "Y";
369 
370  // Copy the nonzeros for the sqare factor into new storage
371  Workspace<double> b_val(wss,fs.nz_);
372  Workspace<int> b_row_i(wss,fs.nz_);
373  Workspace<int> b_col_ptr(wss,fs.rank_+1);
374  if(fs.m_orig_ > fs.n_orig_) {
375  int b_nz = -1;
376  copy_basis_nonzeros(
377  m,n,nz,a_val,a_row_i,a_col_ptr
378  ,&cva(fs.perm_r_orig_)[0],&cva(fs.perm_c_orig_)[0],fs.rank_
379  ,&b_val[0],&b_row_i[0],&b_col_ptr[0]
380  ,&b_nz
381  );
383  (b_nz != fs.nz_), std::runtime_error
384  ,"SuperLUSolverImpl::factor(...): Error!"
385  );
386  }
387  else {
388  std::copy( a_val, a_val + nz, &b_val[0] );
389  std::copy( a_row_i, a_row_i + nz, &b_row_i[0] );
390  std::copy( a_col_ptr, a_col_ptr + n+1, &b_col_ptr[0] );
391  }
392 
393  // Create matrix A in the format expected by SuperLU
394  SuperMatrix A;
395  dCreate_CompCol_Matrix(
396  &A, fs.rank_, fs.rank_, fs.nz_
397  ,&b_val[0]
398  ,&b_row_i[0]
399  ,&b_col_ptr[0]
400  ,NC, D_, GE
401  );
402 
403  // Permute the columns
404  SuperMatrix AC;
405  sp_preorder(
406  refact,&A
407  ,&cva(fs.perm_c_)[0]
408  ,&cva(fs.etree_)[0]
409  ,&AC
410  );
411 
412  int info = -1;
413  dgstrf(
414  refact
415  ,&AC
416  ,1.0 /* diag_pivot_thresh */
417  ,0.0 /* drop_tol */
418  ,local_relax
419  ,local_panel_size
420  ,const_cast<int*>(&cva(fs.etree_)[0])
421  ,NULL /* work */
422  ,0 /* lwork */
423  ,&cva(fs.perm_r_)[0]
424  ,&cva(fs.perm_c_)[0]
425  ,&fn.L_
426  ,&fn.U_
427  ,&info
428  );
429 
431  info != 0, std::runtime_error
432  ,"SuperLUSolverImpl::factor(...): Error, dgstrf(...) returned info = " << info
433  );
434 
435 }
436 
437 void SuperLUSolverImpl::solve(
438  const FactorizationStructure &fact_struct
439  ,const FactorizationNonzeros &fact_nonzeros
440  ,bool transp
441  ,int n
442  ,int nrhs
443  ,double rhs[]
444  ,int ldrhs
445  ) const
446 {
447 
448  using Teuchos::dyn_cast;
449 
450  const FactorizationStructureImpl
451  &fs = dyn_cast<const FactorizationStructureImpl>(fact_struct);
452  const FactorizationNonzerosImpl
453  &fn = dyn_cast<const FactorizationNonzerosImpl>(fact_nonzeros);
454 
456  n != fs.rank_, std::runtime_error
457  ,"SuperLUSolverImpl::solve(...): Error, the dimmensions n = " << n << " and fs.rank = " << fs.rank_
458  << " do not match up!"
459  );
460 
461  SuperMatrix B;
462  dCreate_Dense_Matrix(&B, n, nrhs, rhs, ldrhs, DN, D_, GE);
463 
464  char transc[1];
465  transc[0] = ( transp ? 'T' : 'N' );
466 
467  int info = -1;
468  dgstrs(
469  transc
470  ,const_cast<SuperMatrix*>(&fn.L_)
471  ,const_cast<SuperMatrix*>(&fn.U_)
472  ,&cva(fs.perm_r_)[0]
473  ,&cva(fs.perm_c_)[0]
474  ,&B, &info
475  );
476 
478  info != 0, std::runtime_error
479  ,"SuperLUSolverImpl::solve(...): Error, dgssv(...) returned info = " << info
480  );
481 
482 }
483 
484 // private
485 
486 void SuperLUSolverImpl::copy_basis_nonzeros(
487  int m_orig
488  ,int n_orig
489  ,int nz_orig
490  ,const double a_orig_val[]
491  ,const int a_orig_row_i[]
492  ,const int a_orig_col_ptr[]
493  ,const int a_orig_perm_r[]
494  ,const int a_orig_perm_c[]
495  ,const int rank
496  ,double b_val[]
497  ,int b_row_i[]
498  ,int b_col_ptr[]
499  ,int *b_nz
500  ) const
501 {
502  *b_nz = 0;
503  b_col_ptr[0] = *b_nz;
504  for( int j = 0; j < rank; ++j ) {
505  const int col_start_k = a_orig_col_ptr[j];
506  const int col_end_k = a_orig_col_ptr[j+1];
507  for( int k = col_start_k; k < col_end_k; ++k ) {
508  const int i_orig = a_orig_row_i[k];
509  if(i_orig < rank) {
510  b_val[*b_nz] = a_orig_val[k];
511  b_row_i[*b_nz] = a_orig_row_i[k];
512  ++(*b_nz);
513  }
514  }
515  b_col_ptr[j+1] = *b_nz;
516  }
517 }
518 
519 } // end namespace SuperLUPack
520 
521 #endif // SPARSE_SOLVER_PACK_USE_SUPERLU
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
const LAPACK_C_Decl::f_int LAPACK_C_Decl::f_dbl_prec * A
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void copy(const f_int &N, const f_dbl_prec *X, const f_int &INCX, f_dbl_prec *Y, const f_int &INCY)
T_To & dyn_cast(T_From &from)
const LAPACK_C_Decl::f_int const LAPACK_C_Decl::f_int const LAPACK_C_Decl::f_dbl_prec const LAPACK_C_Decl::f_int const LAPACK_C_Decl::f_int LAPACK_C_Decl::f_dbl_prec B[]
const f_dbl_prec const f_int const f_int const f_int f_dbl_prec rhs[]
TEUCHOSCORE_LIB_DLL_EXPORT Teuchos::RCP< WorkspaceStore > get_default_workspace_store()