ug4
lu.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt
3  * Author: Martin Rupp
4  *
5  * This file is part of UG4.
6  *
7  * UG4 is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License version 3 (as published by the
9  * Free Software Foundation) with the following additional attribution
10  * requirements (according to LGPL/GPL v3 §7):
11  *
12  * (1) The following notice must be displayed in the Appropriate Legal Notices
13  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14  *
15  * (2) The following notice must be displayed at a prominent place in the
16  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17  *
18  * (3) The following bibliography is recommended for citation and must be
19  * preserved in all covered files:
20  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21  * parallel geometric multigrid solver on hierarchically distributed grids.
22  * Computing and visualization in science 16, 4 (2013), 151-164"
23  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24  * flexible software system for simulating pde based models on high performance
25  * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU Lesser General Public License for more details.
31  */
32 
33 #ifndef __H__LIB_ALGEBRA__LAPACK_LU_OPERATOR__
34 #define __H__LIB_ALGEBRA__LAPACK_LU_OPERATOR__
35 #include <iostream>
36 #include <sstream>
37 
38 #include "common/common.h"
40 
41 #ifdef UG_PARALLEL
43 #endif
44 #include "../preconditioner/ilut_scalar.h"
45 #include "../interface/preconditioned_linear_operator_inverse.h"
46 #include "linear_solver.h"
47 
49 
50 #include "../operator_util.h"
51 namespace ug{
52 
53 template <typename TAlgebra>
54 class LU
55  : public IMatrixOperatorInverse<typename TAlgebra::matrix_type,
56  typename TAlgebra::vector_type>
57 {
58  public:
60  typedef TAlgebra algebra_type;
61 
63  typedef typename TAlgebra::vector_type vector_type;
64 
66  typedef typename TAlgebra::matrix_type matrix_type;
67 
70 
71  using base_type::init;
72 
73  protected:
75 
76  public:
78  LU() : m_spOperator(NULL), m_mat(), m_bSortSparse(true), m_bInfo(false), m_bShowProgress(true)
79  {
80 #ifdef LAPACK_AVAILABLE
81  m_iMinimumForSparse = 4000;
82 #else
83  m_iMinimumForSparse = 1000;
84 #endif
85  };
86 
88  virtual bool supports_parallel() const {return false;}
89 
91  void set_minimum_for_sparse(size_t N)
92  {
94  }
95 
96  void set_sort_sparse(bool b)
97  {
98  m_bSortSparse = b;
99  }
100 
101  void set_info(bool b)
102  {
103  m_bInfo = b;
104  }
105 
106  void set_show_progress(bool b)
107  {
108  m_bShowProgress = b;
109  }
110 
111  virtual const char* name() const {return "LU";}
112 
113  private:
114 
115  void print_info(const matrix_type &A)
116  {
118  UG_LOG("Matrix " << A.num_rows() << " x " << A.num_rows() << " with " << blockSize << " x " << blockSize << " blocks");
119  }
120 
122  bool init_dense(const matrix_type &A)
123  {
124  PROFILE_FUNC();
125  m_bDense = true;
126 
127  if(m_bInfo)
128  {
129  UG_LOG("LU, using DenseLU on ");
130  print_info(A);
131  UG_LOG("\n DenseLU needs " << GetBytesSizeString(m_size*m_size*sizeof(double)) << " of memory.\n");
132  }
133 
135 
136  if(m_mat.invert() == false)
137  {
138  UG_THROW("ERROR in Matrix is singular");
139  return false;
140  }
141  else
142  return true;
143  }
144 
145  void init_var(const matrix_type &A)
146  {
147  UG_ASSERT(0, "not yet tested");
148  /*m_size = 0;
149  std::vector<size_t> blockbegin(A.num_rows()+1);
150 
151  for(size_t i=0; i<A.num_rows(); i++)
152  {
153  bool bFound;
154  typename matrix_type::const_row_iterator it = A.get_connection(i,i, bFound);
155  UG_ASSERT(bFound, "Matrix has to have entry A(" << i << ", " << i << ")");
156  size_t s = GetRows(it.value());
157  UG_ASSERT(s == GetCols(it.value()), "diagonal elements have to be square");
158  if(i == 0)
159  blockbegin[i] = m_size;
160  m_size += s;
161  }
162  blockbegin[A.num_rows()] = m_size;
163 
164  m_mat.resize(m_size);
165 
166  for(size_t r=0; r<A.num_rows(); r++)
167  for(typename matrix_type::const_row_iterator it = A.begin_row(r); it != A.end_row(r); ++it)
168  {
169  size_t c = it.index();
170  const typename matrix_type::value_type &val = it.value();
171  UG_ASSERT(blockbegin[r]+GetRows(val) == blockbegin[r+1], "blocksizes in matrix inconsistent");
172  UG_ASSERT(blockbegin[c]+GetCols(val) == blockbegin[c+1], "blocksizes in matrix inconsistent");
173  for(size_t r2=0; r2 < GetRows(val); r2++)
174  for(size_t c2=0; c2 < GetCols(val); c2++)
175  m_mat(blockbegin[r] + r2, blockbegin[c]+c2) = BlockRef(val, r2, c2);
176  }
177 */
178  }
179 
180 
181  bool init_sparse(const matrix_type &A)
182  {
183  try{
184  PROFILE_FUNC();
185  m_bDense = false;
186 
187  if(m_bInfo)
188  {
189  UG_LOG("LU using Sparse LU on ");
190  print_info(A);
191  UG_LOG("\n");
192  }
194  ilut_scalar->set_sort(m_bSortSparse);
195  ilut_scalar->set_info(m_bInfo);
196  ilut_scalar->set_show_progress(m_bShowProgress);
197  ilut_scalar->preprocess(A);
198 
199  }UG_CATCH_THROW("LU::" << __FUNCTION__ << " failed")
200  return true;
201  }
202 
204  {
205  try{
206  PROFILE_FUNC();
207  x = b;
208  m_tmp.resize(m_size);
209  for(size_t i=0, k=0; i<b.size(); i++)
210  {
211  for(size_t j=0; j<GetSize(b[i]); j++)
212  m_tmp[k++] = BlockRef(b[i],j);
213  }
214  m_mat.apply(m_tmp);
215 
216 
217  for(size_t i=0, k=0; i<b.size(); i++)
218  {
219  for(size_t j=0; j<GetSize(b[i]); j++)
220  BlockRef(x[i],j) = m_tmp[k++];
221  }
222 
223  }UG_CATCH_THROW("LU::" << __FUNCTION__ << " failed")
224  return true;
225  }
226 
228  {
229  PROFILE_FUNC();
230  ilut_scalar->solve(x, b);
231  return true;
232  }
233 
234  public:
236  bool init_lu(const matrix_type *pA)
237  {
238  try{
239  // get matrix of Operator
240  m_pMatrix = pA;
241  if(m_pMatrix->num_rows() == 0) return true;
242 
243  // check that matrix exist
244  if(m_pMatrix == NULL)
245  {
246  UG_LOG("ERROR in 'LU::init': No Matrix given.\n");
247  return false;
248  }
249 
250  const matrix_type &A = *pA;
251 
252  PROFILE_FUNC();
253  PROFILE_BEGIN_GROUP(LU_init_lu, "algebra lu");
255  {
257  UG_ASSERT(nrOfRows == block_traits<typename matrix_type::value_type>::static_num_cols, "only square matrices supported");
258  m_size = A.num_rows() * nrOfRows;
259 
261  init_sparse(A);
262  else
263  init_dense(A);
264  }
265  else
266  init_var(A);
267  }UG_CATCH_THROW("LU::" << __FUNCTION__ << " failed")
268  return true;
269  }
270 
271  bool apply_lu(vector_type &x, const vector_type &b)
272  {
273  if(m_pMatrix->num_rows() == 0) return true;
274  try{
275  PROFILE_BEGIN_GROUP(LU_apply_lu, "algebra lu");
276 #ifndef NDEBUG
278  {
280  UG_ASSERT(m_size == b.size() * static_size && m_size == x.size() * static_size,
281  " wrong size! has to be " << m_size << ", but is " << b << " and " << x);
282  }
283  else
284  {
285  size_t b_size = 0;
286  for(size_t i=0; i<b.size(); i++)
287  {
288  UG_ASSERT(GetSize(b[i]) == GetSize(x[i]), "wrong size! Sizes of b and x must be the same, but is "
289  << GetSize(b[i]) << " and " << GetSize(x[i]) << "!");
290  b_size += GetSize(b[i]);
291  }
292  UG_ASSERT(m_size == b_size, " wrong size! has to be " << m_size << ", but is " << b_size << "!");
293  }
294 #endif
295 
296  if(m_bDense)
297  return solve_dense(x, b);
298  else
299  return solve_sparse(x, b);
300 
301  }UG_CATCH_THROW("LU::" << __FUNCTION__ << " failed")
302  }
303 
306  {
307  // remember operator
308  m_spOperator = Op;
309 
310  // init LU operator
311  if(!init_lu(&m_spOperator->get_matrix()))
312  {
313  UG_LOG("ERROR in 'LU::init': Cannot init LU Decomposition.\n");
314  return false;
315  }
316 
317  // we're done
318  return true;
319  }
320 
322  virtual bool apply(vector_type& u, const vector_type& f)
323  {
324  PROFILE_FUNC();
325  convergence_check()->set_symbol('%');
326  convergence_check()->set_name("LU Solver");
327 
328 #ifdef UG_PARALLEL
329  if(!f.has_storage_type(PST_ADDITIVE))
330  {
331  UG_LOG("ERROR: In 'LU::apply': "
332  "Inadequate storage format of Vector f.\n");
333  return false;
334  }
335  if(!u.has_storage_type(PST_CONSISTENT))
336  {
337  UG_LOG("ERROR: In 'LU::apply': "
338  "Inadequate storage format of Vector u.\n");
339  return false;
340  }
341 #endif
342  UG_ASSERT(f.size() == m_pMatrix->num_rows(), "Vector ["<<f.size()<<"] and Row "<<m_pMatrix->num_rows()<<" size mismatch");
343  UG_ASSERT(u.size() == m_pMatrix->num_cols(), "Vector ["<<u.size()<<"] and Col "<<m_pMatrix->num_cols()<<" size mismatch");
344  UG_ASSERT(f.size() == u.size(), "Vector sizes have to match!");
345 
346  if(!apply_lu(u, f))
347  {
348  UG_LOG("ERROR in 'LU::apply': "
349  "Cannot apply LU decomposition.\n");
350  return false;
351  }
352 
353 #ifdef UG_PARALLEL
354  // todo: we set solution to consistent here, but that is only true for
355  // serial case. Handle parallel case.
356  u.set_storage_type(PST_CONSISTENT);
357 #endif
358 
359  // we're done
360  return true;
361  }
362 
365  {
366  PROFILE_BEGIN_GROUP(LU_apply_return_defect, "algebra lu");
367  // solve u
368  if(!apply(u, f)) return false;
369 
370  // update defect
371  if(!m_pMatrix->matmul_minus(f, u))
372  {
373  UG_LOG("ERROR in 'LU::apply_return_defect': "
374  "Cannot apply matmul_minus.\n");
375  return false;
376  }
377 
378  // we're done
379  return true;
380  }
381 
382  virtual std::string config_string() const
383  {
384  std::stringstream ss;
385  ss << "LU Decomposition: Direct Solver for Linear Equation Systems.\n";
386  ss << " Minimum Entries for Sparse LU: " << m_iMinimumForSparse;
387  if(m_iMinimumForSparse==0)
388  ss << " (= always Sparse LU)";
389  return ss.str();
390  }
391 
392 
394  virtual ~LU() {};
395 
396  protected:
399 
402 
408  size_t m_size;
409 
410  bool m_bDense;
414 };
415 
416 } // end namespace ug
417 
418 #endif /* __H__LIB_ALGEBRA__LAPACK_LU_OPERATOR__ */
Definition: smart_pointer.h:108
Definition: lapack_densematrix_inverse.h:51
Definition: densevector.h:101
Definition: ilut_scalar.h:53
ConstSmartPtr< IConvergenceCheck< X > > convergence_check() const
returns the convergence check
Definition: linear_operator_inverse.h:202
describes an inverse linear mapping X->Y based on a matrix
Definition: matrix_operator_inverse.h:64
virtual bool init(SmartPtr< MatrixOperator< M, Y, X > > A)=0
initializes this inverse operator for a matrix-based operator
Definition: lu.h:57
DenseVector< VariableArray1< double > > m_tmp
Definition: lu.h:405
bool solve_dense(vector_type &x, const vector_type &b)
Definition: lu.h:203
virtual bool apply_return_defect(vector_type &u, vector_type &f)
Compute u = L^{-1} * f AND return defect f := f - L*u.
Definition: lu.h:364
bool init_lu(const matrix_type *pA)
initializes the solver for a matrix A
Definition: lu.h:236
bool init_sparse(const matrix_type &A)
Definition: lu.h:181
size_t m_size
Definition: lu.h:408
TAlgebra::matrix_type matrix_type
Matrix type.
Definition: lu.h:66
bool m_bDense
Definition: lu.h:410
virtual bool supports_parallel() const
returns if parallel solving is supported
Definition: lu.h:88
void set_info(bool b)
Definition: lu.h:101
bool init_dense(const matrix_type &A)
returns name of solver
Definition: lu.h:122
LU()
constructor
Definition: lu.h:78
CPUAlgebra::vector_type m_u
Definition: lu.h:406
bool m_bSortSparse
Definition: lu.h:413
size_t m_iMinimumForSparse
Definition: lu.h:412
SmartPtr< MatrixOperator< matrix_type, vector_type > > m_spOperator
Operator to invert.
Definition: lu.h:394
void set_show_progress(bool b)
Definition: lu.h:106
virtual bool apply(vector_type &u, const vector_type &f)
Compute u = L^{-1} * f.
Definition: lu.h:322
virtual std::string config_string() const
returns information about configuration parameters
Definition: lu.h:382
void print_info(const matrix_type &A)
Definition: lu.h:115
SmartPtr< ILUTScalarPreconditioner< algebra_type > > ilut_scalar
Definition: lu.h:411
virtual ~LU()
Destructor.
Definition: lu.h:394
void set_sort_sparse(bool b)
Definition: lu.h:96
IMatrixOperatorInverse< matrix_type, vector_type > base_type
Base type.
Definition: lu.h:69
virtual const char * name() const
returns the name of the operator inverse
Definition: lu.h:111
bool m_bShowProgress
Definition: lu.h:413
TAlgebra algebra_type
Algebra type.
Definition: lu.h:60
bool apply_lu(vector_type &x, const vector_type &b)
Definition: lu.h:271
bool m_bInfo
Definition: lu.h:413
bool solve_sparse(vector_type &x, const vector_type &b)
Definition: lu.h:227
DenseMatrixInverse< DenseMatrix< VariableArray2< double > > > m_mat
inverse
Definition: lu.h:404
void set_minimum_for_sparse(size_t N)
Definition: lu.h:91
virtual bool init(SmartPtr< MatrixOperator< matrix_type, vector_type > > Op)
set operator L, that will be inverted
Definition: lu.h:305
void init_var(const matrix_type &A)
Definition: lu.h:145
CPUAlgebra::vector_type m_b
Definition: lu.h:407
TAlgebra::vector_type vector_type
Vector type.
Definition: lu.h:63
const matrix_type * m_pMatrix
matrix to invert
Definition: lu.h:401
Definition: matrix_operator.h:49
@ PST_CONSISTENT
Definition: parallel_storage_type.h:68
@ PST_ADDITIVE
Definition: parallel_storage_type.h:69
size_t GetDenseDoubleFromSparse(TDenseType &A, const TSparseMatrix &S)
Definition: sparsematrix_util.h:1207
#define UG_ASSERT(expr, msg)
Definition: assert.h:70
#define UG_CATCH_THROW(msg)
Definition: error.h:64
#define UG_THROW(msg)
Definition: error.h:57
#define UG_LOG(msg)
Definition: log.h:367
the ug namespace
double & BlockRef(T &vec, size_t i)
Definition: blocks.h:66
string GetBytesSizeString(size_t s, int length)
Definition: string_util.cpp:489
size_t GetSize(const T &t)
#define PROFILE_BEGIN_GROUP(name, groups)
Definition: profiler.h:255
#define PROFILE_FUNC()
Definition: profiler.h:257
SmartPtr< T, FreePolicy > make_sp(T *inst)
returns a SmartPtr for the passed raw pointer
Definition: smart_pointer.h:836
Definition: communication_policies.h:58