bpp-core3  3.0.0
LUDecomposition.h
Go to the documentation of this file.
1 //
2 // File: LUDecomposition.h
3 // Authors:
4 // Julien Dutheil
5 // Created: 2004-04-07 16:24:00
6 //
7 
8 /*
9  Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
10 
11  This software is a computer program whose purpose is to provide classes
12  for numerical calculus.
13 
14  This software is governed by the CeCILL license under French law and
15  abiding by the rules of distribution of free software. You can use,
16  modify and/ or redistribute the software under the terms of the CeCILL
17  license as circulated by CEA, CNRS and INRIA at the following URL
18  "http://www.cecill.info".
19 
20  As a counterpart to the access to the source code and rights to copy,
21  modify and redistribute granted by the license, users are provided only
22  with a limited warranty and the software's author, the holder of the
23  economic rights, and the successive licensors have only limited
24  liability.
25 
26  In this respect, the user's attention is drawn to the risks associated
27  with loading, using, modifying and/or developing or reproducing the
28  software by the user in light of its specific status of free software,
29  that may mean that it is complicated to manipulate, and that also
30  therefore means that it is reserved for developers and experienced
31  professionals having in-depth computer knowledge. Users are therefore
32  encouraged to load and test the software's suitability as regards their
33  requirements in conditions enabling the security of their systems and/or
34  data to be ensured and, more generally, to use and operate it in the
35  same conditions as regards security.
36 
37  The fact that you are presently reading this means that you have had
38  knowledge of the CeCILL license and that you accept its terms.
39 */
40 
41 #ifndef BPP_NUMERIC_MATRIX_LUDECOMPOSITION_H
42 #define BPP_NUMERIC_MATRIX_LUDECOMPOSITION_H
43 
44 
45 #include "../../Exceptions.h"
46 #include "../NumTools.h"
47 #include "Matrix.h"
48 
49 // From the STL:
50 #include <algorithm>
51 #include <vector>
52 // for min(), max() below
53 
54 namespace bpp
55 {
71 template<class Real>
73 {
74 private:
75  /* Array for internal storage of decomposition. */
79  size_t m, n;
80  int pivsign;
81  std::vector<size_t> piv;
82 
83 private:
84  static void permuteCopy(const Matrix<Real>& A, const std::vector<size_t>& piv, size_t j0, size_t j1, Matrix<Real>& X)
85  {
86  size_t piv_length = piv.size();
87 
88  X.resize(piv_length, j1 - j0 + 1);
89 
90  for (size_t i = 0; i < piv_length; i++)
91  {
92  for (size_t j = j0; j <= j1; j++)
93  {
94  X(i, j - j0) = A(piv[i], j);
95  }
96  }
97  }
98 
99  static void permuteCopy(const std::vector<Real>& A, const std::vector<size_t>& piv, std::vector<Real>& X)
100  {
101  size_t piv_length = piv.size();
102  if (piv_length != A.size())
103  X.clean();
104 
105  X.resize(piv_length);
106 
107  for (size_t i = 0; i < piv_length; i++)
108  {
109  X[i] = A[piv[i]];
110  }
111  }
112 
113 public:
121  // This is the constructor in JAMA C++ port. However, it seems to have some bug...
122  // We use the original JAMA's 'experimental' port, which gives good results instead.
123  /* LUDecomposition (const Matrix<Real> &A) : LU(A), m(A.getNumberOfRows()), n(A.getNumberOfColumns()), piv(A.getNumberOfRows())
124  {
125 
126  // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
127 
128 
129  for (size_t i = 0; i < m; i++) {
130  piv[i] = i;
131  }
132  pivsign = 1;
133  //Real *LUrowi = 0;;
134  vector<Real> LUrowi;
135  vector<Real> LUcolj;
136 
137  // Outer loop.
138 
139  for (size_t j = 0; j < n; j++) {
140 
141  // Make a copy of the j-th column to localize references.
142 
143  LUcolj = LU.col(j);
144  //for (size_t i = 0; i < m; i++) {
145  // LUcolj[i] = LU(i,j);
146  //}
147 
148  // Apply previous transformations.
149 
150  for (size_t i = 0; i < m; i++) {
151  //LUrowi = LU[i];
152  LUrowi = LU.row(i);
153 
154  // Most of the time is spent in the following dot product.
155 
156  size_t kmax = NumTools::min<size_t>(i,j);
157  double s = 0.0;
158  for (size_t k = 0; k < kmax; k++) {
159  s += LUrowi[k] * LUcolj[k];
160  }
161 
162  LUrowi[j] = LUcolj[i] -= s;
163  }
164 
165  // Find pivot and exchange if necessary.
166 
167  size_t p = j;
168  for (size_t i = j+1; i < m; i++) {
169  if (NumTools::abs<Real>(LUcolj[i]) > NumTools::abs<Real>(LUcolj[p])) {
170  p = i;
171  }
172  }
173  if (p != j) {
174  size_t k=0;
175  for (k = 0; k < n; k++) {
176  double t = LU(p,k);
177  LU(p,k) = LU(j,k);
178  LU(j,k) = t;
179  }
180  k = piv[p];
181  piv[p] = piv[j];
182  piv[j] = k;
183  pivsign = -pivsign;
184  }
185 
186  // Compute multipliers.
187 
188  if ((j < m) && (LU(j,j) != 0.0)) {
189  for (size_t i = j+1; i < m; i++) {
190  LU(i,j) /= LU(j,j);
191  }
192  }
193  }
194  }
195  */
196 
198  LU(A),
199  L_(A.getNumberOfRows(), A.getNumberOfColumns()),
200  U_(A.getNumberOfColumns(), A.getNumberOfColumns()),
201  m(A.getNumberOfRows()),
202  n(A.getNumberOfColumns()),
203  pivsign(1),
204  piv(A.getNumberOfRows())
205  {
206  for (size_t i = 0; i < m; i++)
207  {
208  piv[i] = i;
209  }
210  // Main loop.
211  for (size_t k = 0; k < n; k++)
212  {
213  // Find pivot.
214  size_t p = k;
215  for (size_t i = k + 1; i < m; i++)
216  {
217  if (NumTools::abs<Real>(LU(i, k)) > NumTools::abs<Real>(LU(p, k)))
218  {
219  p = i;
220  }
221  }
222  // Exchange if necessary.
223  if (p != k)
224  {
225  for (size_t j = 0; j < n; j++)
226  {
227  double t = LU(p, j); LU(p, j) = LU(k, j); LU(k, j) = t;
228  }
229  size_t t = piv[p]; piv[p] = piv[k]; piv[k] = t;
230  pivsign = -pivsign;
231  }
232  // Compute multipliers and eliminate k-th column.
233  if (LU(k, k) != 0.0)
234  {
235  for (size_t i = k + 1; i < m; i++)
236  {
237  LU(i, k) /= LU(k, k);
238  for (size_t j = k + 1; j < n; j++)
239  {
240  LU(i, j) -= LU(i, k) * LU(k, j);
241  }
242  }
243  }
244  }
245  }
246 
253  {
254  for (size_t i = 0; i < m; i++)
255  {
256  for (size_t j = 0; j < n; j++)
257  {
258  if (i > j)
259  {
260  L_(i, j) = LU(i, j);
261  }
262  else if (i == j)
263  {
264  L_(i, j) = 1.0;
265  }
266  else
267  {
268  L_(i, j) = 0.0;
269  }
270  }
271  }
272  return L_;
273  }
274 
281  {
282  for (size_t i = 0; i < n; i++)
283  {
284  for (size_t j = 0; j < n; j++)
285  {
286  if (i <= j)
287  {
288  U_(i, j) = LU(i, j);
289  }
290  else
291  {
292  U_(i, j) = 0.0;
293  }
294  }
295  }
296  return U_;
297  }
298 
304  std::vector<size_t> getPivot () const
305  {
306  return piv;
307  }
308 
309 
315  Real det() const
316  {
317  if (m != n)
318  {
319  return Real(0);
320  }
321  Real d = Real(pivsign);
322  for (size_t j = 0; j < n; j++)
323  {
324  d *= LU(j, j);
325  }
326  return d;
327  }
328 
340  Real solve (const Matrix<Real>& B, Matrix<Real>& X) const
341  {
342  /* Dimensions: A is mxn, X is nxk, B is mxk */
343 
344  if (B.getNumberOfRows() != m)
345  {
346  throw BadIntegerException("Wrong dimension in LU::solve", static_cast<int>(B.getNumberOfRows()));
347  }
348 
349  Real minD = NumTools::abs<Real>(LU(0, 0));
350  for (size_t i = 1; i < m; i++)
351  {
352  Real currentValue = NumTools::abs<Real>(LU(i, i));
353  if (currentValue < minD)
354  minD = currentValue;
355  }
356 
357  if (minD < NumConstants::SMALL())
358  {
359  throw ZeroDivisionException("Singular matrix in LU::solve.");
360  }
361 
362  // Copy right hand side with pivoting
363  size_t nx = B.getNumberOfColumns();
364 
365  permuteCopy(B, piv, 0, nx - 1, X);
366 
367  // Solve L*Y = B(piv,:)
368  for (size_t k = 0; k < n; k++)
369  {
370  for (size_t i = k + 1; i < n; i++)
371  {
372  for (size_t j = 0; j < nx; j++)
373  {
374  X(i, j) -= X(k, j) * LU(i, k);
375  }
376  }
377  }
378  // Solve U*X = Y;
379  // !!! Do not use unsigned int with -- loop!!!
380  // for (int k = n-1; k >= 0; k--) {
381  size_t k = n;
382 
383  do
384  {
385  k--;
386  for (size_t j = 0; j < nx; j++)
387  {
388  X(k, j) /= LU(k, k);
389  }
390  for (size_t i = 0; i < k; i++)
391  {
392  for (size_t j = 0; j < nx; j++)
393  {
394  X(i, j) -= X(k, j) * LU(i, k);
395  }
396  }
397  }
398  while (k > 0);
399 
400  return minD;
401  }
402 
403 
414  Real solve (const std::vector<Real>& b, std::vector<Real>& x) const
415  {
416  /* Dimensions: A is mxn, X is nxk, B is mxk */
417 
418  if (b.dim1() != m)
419  {
420  throw BadIntegerException("Wrong dimension in LU::solve", b.dim1());
421  }
422 
423  Real minD = NumTools::abs<Real>(LU(0, 0));
424  for (size_t i = 1; i < m; i++)
425  {
426  Real currentValue = NumTools::abs<Real>(LU(i, i));
427  if (currentValue < minD)
428  minD = currentValue;
429  }
430 
431  if (minD < NumConstants::SMALL())
432  {
433  throw ZeroDivisionException("Singular matrix in LU::solve.");
434  }
435 
436  permuteCopy(b, piv, x);
437 
438  // Solve L*Y = B(piv)
439  for (size_t k = 0; k < n; k++)
440  {
441  for (size_t i = k + 1; i < n; i++)
442  {
443  x[i] -= x[k] * LU(i, k);
444  }
445  }
446 
447  // Solve U*X = Y;
448  // for (size_t k = n-1; k >= 0; k--) {
449  size_t k = n;
450  do
451  {
452  k--;
453  x[k] /= LU(k, k);
454  for (size_t i = 0; i < k; i++)
455  {
456  x[i] -= x[k] * LU(i, k);
457  }
458  }
459  while (k > 0);
460 
461  return minD;
462  }
463 }; /* class LU */
464 } // end of namespace bpp.
465 #endif // BPP_NUMERIC_MATRIX_LUDECOMPOSITION_H
Number exception: integers.
Definition: Exceptions.h:116
LU Decomposition.
const RowMatrix< Real > & getU()
Return upper triangular factor.
RowMatrix< Real > LU
Real det() const
Compute determinant using LU factors.
LUDecomposition(const Matrix< Real > &A)
LU Decomposition.
std::vector< size_t > getPivot() const
Return pivot permutation vector.
std::vector< size_t > piv
Real solve(const std::vector< Real > &b, std::vector< Real > &x) const
Solve A*x = b, where x and b are vectors of length equal to the number of rows in A.
Real solve(const Matrix< Real > &B, Matrix< Real > &X) const
Solve A*X = B.
const RowMatrix< Real > & getL()
Return lower triangular factor.
static void permuteCopy(const Matrix< Real > &A, const std::vector< size_t > &piv, size_t j0, size_t j1, Matrix< Real > &X)
RowMatrix< Real > L_
static void permuteCopy(const std::vector< Real > &A, const std::vector< size_t > &piv, std::vector< Real > &X)
RowMatrix< Real > U_
The matrix template interface.
Definition: Matrix.h:61
virtual size_t getNumberOfColumns() const =0
virtual void resize(size_t nRows, size_t nCols)=0
Resize the matrix.
virtual size_t getNumberOfRows() const =0
static double SMALL()
Definition: NumConstants.h:81
The base class exception for zero division error.
Definition: Exceptions.h:106