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