|
bpp-core
2.1.0
|
00001 // 00002 // File: MatrixTools.h 00003 // Created by: Julien Dutheil 00004 // Created on: Mon Jan 19 16:42:25 2004 00005 // 00006 00007 /* 00008 Copyright or © or Copr. Bio++ Development Team, (November 17, 2004) 00009 00010 This software is a computer program whose purpose is to provide classes 00011 for numerical calculus. This file is part of the Bio++ project. 00012 00013 This software is governed by the CeCILL license under French law and 00014 abiding by the rules of distribution of free software. You can use, 00015 modify and/ or redistribute the software under the terms of the CeCILL 00016 license as circulated by CEA, CNRS and INRIA at the following URL 00017 "http://www.cecill.info". 00018 00019 As a counterpart to the access to the source code and rights to copy, 00020 modify and redistribute granted by the license, users are provided only 00021 with a limited warranty and the software's author, the holder of the 00022 economic rights, and the successive licensors have only limited 00023 liability. 00024 00025 In this respect, the user's attention is drawn to the risks associated 00026 with loading, using, modifying and/or developing or reproducing the 00027 software by the user in light of its specific status of free software, 00028 that may mean that it is complicated to manipulate, and that also 00029 therefore means that it is reserved for developers and experienced 00030 professionals having in-depth computer knowledge. Users are therefore 00031 encouraged to load and test the software's suitability as regards their 00032 requirements in conditions enabling the security of their systems and/or 00033 data to be ensured and, more generally, to use and operate it in the 00034 same conditions as regards security. 00035 00036 The fact that you are presently reading this means that you have had 00037 knowledge of the CeCILL license and that you accept its terms. 00038 */ 00039 00040 #ifndef _MATRIXTOOLS_H_ 00041 #define _MATRIXTOOLS_H_ 00042 00043 #include "../VectorTools.h" 00044 #include "Matrix.h" 00045 #include "LUDecomposition.h" 00046 #include "EigenValue.h" 00047 00048 #include <cstdio> 00049 #include <iostream> 00050 00051 namespace bpp 00052 { 00056 class MatrixTools 00057 { 00058 public: 00059 MatrixTools() {} 00060 ~MatrixTools() {} 00061 00062 public: 00069 template<class MatrixA, class MatrixO> 00070 static void copy(const MatrixA& A, MatrixO& O) 00071 { 00072 O.resize(A.getNumberOfRows(), A.getNumberOfColumns()); 00073 for (size_t i = 0; i < A.getNumberOfRows(); i++) 00074 { 00075 for (size_t j = 0; j < A.getNumberOfColumns(); j++) 00076 { 00077 O(i, j) = A(i, j); 00078 } 00079 } 00080 } 00081 00088 template<class Matrix> 00089 static void getId(size_t n, Matrix& O) 00090 { 00091 O.resize(n, n); 00092 for (size_t i = 0; i < n; i++) 00093 { 00094 for (size_t j = 0; j < n; j++) { 00095 O(i, j) = (i == j) ? 1 : 0; 00096 } 00097 } 00098 } 00099 00104 template<class Scalar> 00105 static void diag(const std::vector<Scalar>& D, Matrix<Scalar>& O) 00106 { 00107 size_t n = D.size(); 00108 O.resize(n, n); 00109 for (size_t i = 0; i < n; i++) 00110 { 00111 for (size_t j = 0; j < n; j++) { O(i, j) = (i == j) ? D[i] : 0;} 00112 } 00113 } 00114 00120 template<class Scalar> 00121 static void diag(const Scalar x, size_t n, Matrix<Scalar>& O) 00122 { 00123 O.resize(n, n); 00124 for (size_t i = 0; i < n; i++) 00125 { 00126 for (size_t j = 0; j < n; j++) { O(i, j) = (i == j) ? x : 0;} 00127 } 00128 } 00129 00135 template<class Scalar> 00136 static void diag(const Matrix<Scalar>& M, std::vector<Scalar>& O) throw (DimensionException) 00137 { 00138 size_t nc = M.getNumberOfColumns(); 00139 size_t nr = M.getNumberOfRows(); 00140 if (nc != nr) throw DimensionException("MatrixTools::diag(). M must be a square matrix.", nr, nc); 00141 O.resize(nc); 00142 for (size_t i = 0; i < nc; i++) { O[i] = M(i, i);} 00143 } 00144 00150 template<class Matrix, class Scalar> 00151 static void fill(Matrix& M, Scalar x) 00152 { 00153 for (size_t i = 0; i < M.getNumberOfRows(); i++) 00154 { 00155 for (size_t j = 0; j < M.getNumberOfColumns(); j++) 00156 { 00157 M(i, j) = x; 00158 } 00159 } 00160 } 00161 00171 template<class Matrix, class Scalar> 00172 static void scale(Matrix& A, Scalar a, Scalar b = 0) 00173 { 00174 for (size_t i = 0; i < A.getNumberOfRows(); i++) 00175 { 00176 for (size_t j = 0; j < A.getNumberOfColumns(); j++) 00177 { 00178 A(i, j) = a * A(i, j) + b; 00179 } 00180 } 00181 } 00182 00188 template<class Scalar> 00189 static void mult(const Matrix<Scalar>& A, const Matrix<Scalar>& B, Matrix<Scalar>& O) throw (DimensionException) 00190 { 00191 size_t ncA = A.getNumberOfColumns(); 00192 size_t nrA = A.getNumberOfRows(); 00193 size_t nrB = B.getNumberOfRows(); 00194 size_t ncB = B.getNumberOfColumns(); 00195 if (ncA != nrB) throw DimensionException("MatrixTools::mult(). nrows B != ncols A.", nrB, ncA); 00196 O.resize(nrA, ncB); 00197 for (size_t i = 0; i < nrA; i++) 00198 { 00199 for (size_t j = 0; j < ncB; j++) 00200 { 00201 O(i, j) = 0; 00202 for (size_t k = 0; k < ncA; k++) 00203 { 00204 O(i, j) += A(i, k) * B(k, j); 00205 } 00206 } 00207 } 00208 } 00209 00222 template<class Scalar> 00223 static void mult(const Matrix<Scalar>& A, const std::vector<Scalar>& D, const Matrix<Scalar>& B, Matrix<Scalar>& O) throw (DimensionException) 00224 { 00225 size_t ncA = A.getNumberOfColumns(); 00226 size_t nrA = A.getNumberOfRows(); 00227 size_t nrB = B.getNumberOfRows(); 00228 size_t ncB = B.getNumberOfColumns(); 00229 if (ncA != nrB) throw DimensionException("MatrixTools::mult(). nrows B != ncols A.", nrB, ncA); 00230 if (ncA != D.size()) throw DimensionException("MatrixTools::mult(). Vector size is not equal to matrix size.", D.size(), ncA); 00231 O.resize(nrA, ncB); 00232 for (size_t i = 0; i < nrA; i++) 00233 { 00234 for (size_t j = 0; j < ncB; j++) 00235 { 00236 O(i, j) = 0; 00237 for (size_t k = 0; k < ncA; k++) 00238 { 00239 O(i, j) += A(i, k) * B(k, j) * D[k]; 00240 } 00241 } 00242 } 00243 } 00244 00261 template<class Scalar> 00262 static void mult(const Matrix<Scalar>& A, const std::vector<Scalar>& D, const std::vector<Scalar>& U, const std::vector<Scalar>& L, const Matrix<Scalar>& B, Matrix<Scalar>& O) throw (DimensionException) 00263 { 00264 size_t ncA = A.getNumberOfColumns(); 00265 size_t nrA = A.getNumberOfRows(); 00266 size_t nrB = B.getNumberOfRows(); 00267 size_t ncB = B.getNumberOfColumns(); 00268 if (ncA != nrB) throw DimensionException("MatrixTools::mult(). nrows B != ncols A.", nrB, ncA); 00269 if (ncA != D.size()) throw DimensionException("MatrixTools::mult(). Vector size is not equal to matrix size.", D.size(), ncA); 00270 if (ncA != U.size()+1) throw DimensionException("MatrixTools::mult(). Vector size is not equal to matrix size-1.", U.size(), ncA); 00271 if (ncA != L.size()+1) throw DimensionException("MatrixTools::mult(). Vector size is not equal to matrix size-1.", L.size(), ncA); 00272 O.resize(nrA, ncB); 00273 for (size_t i = 0; i < nrA; i++) 00274 { 00275 for (size_t j = 0; j < ncB; j++) 00276 { 00277 O(i, j) = A(i, 0) * D[0] * B(0, j); 00278 if (nrB>1) 00279 O(i, j) += A(i,0) * U[0] * B(1,j); 00280 for (size_t k = 1; k < ncA-1; k++) 00281 { 00282 O(i, j) += A(i, k) * (L[k-1] * B(k-1, j) + D[k] * B(k, j) + U[k] * B(k+1,j)); 00283 } 00284 if (ncA>=2) 00285 O(i, j) += A(i, ncA-1) * L[ncA-2] * B(ncA-2, j); 00286 O(i,j) += A(i, ncA-1) * D[ncA-1] * B(ncA-1, j); 00287 } 00288 } 00289 } 00290 00298 template<class MatrixA, class MatrixB> 00299 static void add(MatrixA& A, const MatrixB& B) throw (DimensionException) 00300 { 00301 size_t ncA = A.getNumberOfColumns(); 00302 size_t nrA = A.getNumberOfRows(); 00303 size_t nrB = B.getNumberOfRows(); 00304 size_t ncB = B.getNumberOfColumns(); 00305 if (ncA != ncB) throw DimensionException("MatrixTools::operator+(). A and B must have the same number of colums.", ncB, ncA); 00306 if (nrA != nrB) throw DimensionException("MatrixTools::operator+(). A and B must have the same number of rows.", nrB, nrA); 00307 for (size_t i = 0; i < A.getNumberOfRows(); i++) 00308 { 00309 for (size_t j = 0; j < A.getNumberOfColumns(); j++) 00310 { 00311 A(i, j) += B(i, j); 00312 } 00313 } 00314 } 00315 00324 template<class MatrixA, class MatrixB, class Scalar> 00325 static void add(MatrixA& A, Scalar& x, const MatrixB& B) throw (DimensionException) 00326 { 00327 size_t ncA = A.getNumberOfColumns(); 00328 size_t nrA = A.getNumberOfRows(); 00329 size_t nrB = B.getNumberOfRows(); 00330 size_t ncB = B.getNumberOfColumns(); 00331 if (ncA != ncB) throw DimensionException("MatrixTools::operator+(). A and B must have the same number of colums.", ncB, ncA); 00332 if (nrA != nrB) throw DimensionException("MatrixTools::operator+(). A and B must have the same number of rows.", nrB, nrA); 00333 for (size_t i = 0; i < A.getNumberOfRows(); i++) 00334 { 00335 for (size_t j = 0; j < A.getNumberOfColumns(); j++) 00336 { 00337 A(i, j) += x*B(i, j); 00338 } 00339 } 00340 } 00341 00353 template<class Matrix> 00354 static void pow(const Matrix& A, size_t p, Matrix& O) throw (DimensionException) 00355 { 00356 size_t n = A.getNumberOfRows(); 00357 if (n != A.getNumberOfColumns()) throw DimensionException("MatrixTools::pow(). nrows != ncols.", A.getNumberOfColumns(), A.getNumberOfRows()); 00358 switch(p){ 00359 case 0: 00360 getId<Matrix>(n, O); 00361 break; 00362 case 1: 00363 copy(A,O); 00364 break; 00365 case 2: 00366 mult(A,A,O); 00367 break; 00368 default: 00369 Matrix tmp; 00370 if (p%2){ 00371 pow(A,p/2,tmp); 00372 pow(tmp,2,O); 00373 } 00374 else{ 00375 pow(A,(p-1)/2,tmp); 00376 pow(tmp,2,O); 00377 mult(A,O,tmp); 00378 copy(tmp,O); 00379 } 00380 } 00381 } 00382 00392 template<class Scalar> 00393 static void pow(const Matrix<Scalar>& A, double p, Matrix<Scalar>& O) throw (DimensionException) 00394 { 00395 size_t n = A.getNumberOfRows(); 00396 if (n != A.getNumberOfColumns()) throw DimensionException("MatrixTools::pow(). nrows != ncols.", A.getNumberOfColumns(), A.getNumberOfRows()); 00397 EigenValue<Scalar> eigen(A); 00398 RowMatrix<Scalar> rightEV, leftEV; 00399 rightEV = eigen.getV(); 00400 inv(rightEV, leftEV); 00401 mult(rightEV, VectorTools::pow(eigen.getRealEigenValues(), p), leftEV, O); 00402 } 00403 00414 template<class Scalar> 00415 static void exp(const Matrix<Scalar>& A, Matrix<Scalar>& O) throw (DimensionException) 00416 { 00417 size_t n = A.getNumberOfRows(); 00418 if (n != A.getNumberOfColumns()) throw DimensionException("MatrixTools::exp(). nrows != ncols.", A.getNumberOfColumns(), A.getNumberOfRows()); 00419 EigenValue<Scalar> eigen(A); 00420 RowMatrix<Scalar> rightEV, leftEV; 00421 rightEV = eigen.getV(); 00422 inv(rightEV, leftEV); 00423 mult(rightEV, VectorTools::exp(eigen.getRealEigenValues()), leftEV, O); 00424 } 00425 00436 template<class Matrix, class Scalar> 00437 static void Taylor(const Matrix& A, size_t p, std::vector< RowMatrix<Scalar> > & vO) throw (DimensionException) 00438 { 00439 size_t n = A.getNumberOfRows(); 00440 if (n != A.getNumberOfColumns()) 00441 throw DimensionException("MatrixTools::pow(). nrows != ncols.", A.getNumberOfColumns(), A.getNumberOfRows()); 00442 vO.resize(p+1); 00443 getId<Matrix>(n, vO[0]); 00444 copy(A,vO[1]); 00445 00446 for (size_t i = 1; i < p; i++) 00447 { 00448 mult(vO[i], A, vO[i+1]); 00449 } 00450 } 00451 00456 template<class Matrix> 00457 static std::vector<size_t> whichMax(const Matrix& m) 00458 { 00459 size_t nrows = m.getNumberOfRows(); 00460 size_t ncols = m.getNumberOfColumns(); 00461 std::vector<size_t> pos(2); 00462 size_t imax = 0; 00463 size_t jmax = 0; 00464 double currentMax = log(0.); 00465 for (size_t i = 0; i < nrows; i++) 00466 { 00467 for (size_t j = 0; j < ncols; j++) 00468 { 00469 double currentValue = m(i, j); 00470 // cout << currentValue << "\t" << (currentValue > currentMax) << endl; 00471 if (currentValue > currentMax) 00472 { 00473 imax = i; 00474 jmax = j; 00475 currentMax = currentValue; 00476 } 00477 } 00478 } 00479 pos[0] = imax; 00480 pos[1] = jmax; 00481 return pos; 00482 } 00483 00488 template<class Matrix> 00489 static std::vector<size_t> whichMin(const Matrix& m) 00490 { 00491 size_t nrows = m.getNumberOfRows(); 00492 size_t ncols = m.getNumberOfColumns(); 00493 std::vector<size_t> pos(2); 00494 size_t imin = 0; 00495 size_t jmin = 0; 00496 double currentMin = -log(0.); 00497 for (size_t i = 0; i < nrows; i++) 00498 { 00499 for (size_t j = 0; j < ncols; j++) 00500 { 00501 double currentValue = m(i, j); 00502 if (currentValue < currentMin) 00503 { 00504 imin = i; 00505 jmin = j; 00506 currentMin = currentValue; 00507 } 00508 } 00509 } 00510 pos[0] = imin; 00511 pos[1] = jmin; 00512 return pos; 00513 } 00514 00519 template<class Real> 00520 static Real max(const Matrix<Real>& m) 00521 { 00522 size_t nrows = m.getNumberOfRows(); 00523 size_t ncols = m.getNumberOfColumns(); 00524 Real currentMax = log(0.); 00525 for (size_t i = 0; i < nrows; i++) 00526 { 00527 for (size_t j = 0; j < ncols; j++) 00528 { 00529 Real currentValue = m(i, j); 00530 // cout << currentValue << "\t" << (currentValue > currentMax) << endl; 00531 if (currentValue > currentMax) 00532 { 00533 currentMax = currentValue; 00534 } 00535 } 00536 } 00537 return currentMax; 00538 } 00539 00540 00545 template<class Real> 00546 static Real min(const Matrix<Real>& m) 00547 { 00548 size_t nrows = m.getNumberOfRows(); 00549 size_t ncols = m.getNumberOfColumns(); 00550 Real currentMin = -log(0.); 00551 for (size_t i = 0; i < nrows; i++) 00552 { 00553 for (size_t j = 0; j < ncols; j++) 00554 { 00555 Real currentValue = m(i, j); 00556 if (currentValue < currentMin) 00557 { 00558 currentMin = currentValue; 00559 } 00560 } 00561 } 00562 return currentMin; 00563 } 00564 00571 template<class Matrix> 00572 static void print(const Matrix& m, std::ostream& out = std::cout) 00573 { 00574 out << m.getNumberOfRows() << "x" << m.getNumberOfColumns() << std::endl; 00575 out << "[" << std::endl; 00576 for (size_t i = 0; i < m.getNumberOfRows(); i++) 00577 { 00578 out << "["; 00579 for (size_t j = 0; j < m.getNumberOfColumns() - 1; j++) 00580 { 00581 out << m(i, j) << ", "; 00582 } 00583 if (m.getNumberOfColumns() > 0) out << m(i, m.getNumberOfColumns() - 1) << "]" << std::endl; 00584 } 00585 out << "]" << std::endl; 00586 } 00587 00595 template<class Matrix> 00596 static void printForR(const Matrix& m, const std::string& variableName = "x", std::ostream& out = std::cout) 00597 { 00598 out.precision(12); 00599 out << variableName << "<-matrix(c("; 00600 for (size_t i = 0; i < m.getNumberOfRows(); i++) 00601 { 00602 for (size_t j = 0; j < m.getNumberOfColumns(); j++) 00603 { 00604 if (i > 0 || j > 0) 00605 out << ", "; 00606 out << m(i, j); 00607 } 00608 } 00609 out << "), nrow=" << m.getNumberOfRows() << ", byrow=TRUE)" << std::endl; 00610 } 00611 00612 00619 template<class Real> 00620 static void print(const std::vector<Real>& v, std::ostream& out = std::cout) 00621 { 00622 out << v.size() << std::endl; 00623 out << "["; 00624 for (size_t i = 0; i < v.size() - 1; i++) 00625 { 00626 out << v[i] << ", "; 00627 } 00628 if (v.size() > 0) out << v[v.size() - 1]; 00629 out << "]" << std::endl; 00630 } 00631 00636 template<class Matrix> 00637 static bool isSquare(const Matrix& A) { return A.getNumberOfRows() == A.getNumberOfColumns(); } 00638 00645 template<class Scalar> 00646 static Scalar inv(const Matrix<Scalar>& A, Matrix<Scalar>& O) throw (DimensionException, ZeroDivisionException) 00647 { 00648 if (!isSquare(A)) throw DimensionException("MatrixTools::inv(). Matrix A is not a square matrix.", A.getNumberOfRows(), A.getNumberOfColumns()); 00649 LUDecomposition<Scalar> lu(A); 00650 RowMatrix<Scalar> I; 00651 getId(A.getNumberOfRows(), I); 00652 return lu.solve(I, O); 00653 } 00654 00664 template<class Scalar> 00665 static double det(const Matrix<Scalar>& A) throw (DimensionException) 00666 { 00667 if (!isSquare(A)) throw DimensionException("MatrixTools::det(). Matrix A is not a square matrix.", A.getNumberOfRows(), A.getNumberOfColumns()); 00668 LUDecomposition<Scalar> lu(A); 00669 return lu.det(); 00670 } 00671 00676 template<class MatrixA, class MatrixO> 00677 static void transpose(const MatrixA& A, MatrixO& O) 00678 { 00679 O.resize(A.getNumberOfColumns(), A.getNumberOfRows()); 00680 for (size_t i = 0; i < A.getNumberOfColumns(); i++) 00681 { 00682 for (size_t j = 0; j < A.getNumberOfRows(); j++) 00683 { 00684 O(i, j) = A(j, i); 00685 } 00686 } 00687 } 00688 00701 template<class Scalar> 00702 static void covar(const Matrix<Scalar>& A, Matrix<Scalar>& O) 00703 { 00704 size_t r = A.getNumberOfRows(); 00705 size_t n = A.getNumberOfColumns(); 00706 O.resize(r, r); 00707 RowMatrix<Scalar> tA; 00708 transpose(A, tA); 00709 mult(A, tA, O); 00710 scale(O, 1. / static_cast<double>(n)); 00711 RowMatrix<Scalar> mean(r, 1); 00712 for (size_t i = 0; i < r; i++) 00713 { 00714 for (size_t j = 0; j < n; j++) 00715 { 00716 mean(i, 0) += A(i, j); 00717 } 00718 mean(i, 0) /= static_cast<double>(n); 00719 } 00720 RowMatrix<Scalar> tMean; 00721 transpose(mean, tMean); 00722 RowMatrix<Scalar> meanMat; 00723 mult(mean, tMean, meanMat); 00724 scale(meanMat, -1.); 00725 add(O, meanMat); 00726 } 00727 00735 template<class Scalar> 00736 static void kroneckerMult(const Matrix<Scalar>& A, const Matrix<Scalar>& B, Matrix<Scalar>& O) 00737 { 00738 size_t ncA = A.getNumberOfColumns(); 00739 size_t nrA = A.getNumberOfRows(); 00740 size_t nrB = B.getNumberOfRows(); 00741 size_t ncB = B.getNumberOfColumns(); 00742 O.resize(nrA * nrB, ncA * ncB); 00743 for (size_t ia = 0; ia < nrA; ia++) 00744 { 00745 for (size_t ja = 0; ja < ncA; ja++) 00746 { 00747 Scalar aij = A(ia, ja); 00748 for (size_t ib = 0; ib < nrB; ib++) 00749 { 00750 for (size_t jb = 0; jb < ncB; jb++) 00751 { 00752 O(ia * nrB + ib, ja * ncB + jb) = aij * B(ib, jb); 00753 } 00754 } 00755 } 00756 } 00757 } 00758 00766 template<class Scalar> 00767 static void hadamardMult(const Matrix<Scalar>& A, const Matrix<Scalar>& B, Matrix<Scalar>& O) 00768 { 00769 size_t ncA = A.getNumberOfColumns(); 00770 size_t nrA = A.getNumberOfRows(); 00771 size_t nrB = B.getNumberOfRows(); 00772 size_t ncB = B.getNumberOfColumns(); 00773 if (nrA != nrB) throw DimensionException("MatrixTools::hadamardMult(). nrows A != nrows B.", nrA, nrB); 00774 if (ncA != ncB) throw DimensionException("MatrixTools::hadamardMult(). ncols A != ncols B.", ncA, ncB); 00775 O.resize(nrA, ncA); 00776 for (size_t i = 0; i < nrA; i++) 00777 { 00778 for (size_t j = 0; j < ncA; j++) 00779 { 00780 O(i, j) = A(i, j) * B(i, j); 00781 } 00782 } 00783 } 00784 00793 template<class Scalar> 00794 static void hadamardMult(const Matrix<Scalar>& A, const std::vector<Scalar>& B, Matrix<Scalar>& O, bool row = true) 00795 { 00796 size_t ncA = A.getNumberOfColumns(); 00797 size_t nrA = A.getNumberOfRows(); 00798 size_t sB = B.size(); 00799 if (row == true && nrA != sB) throw DimensionException("MatrixTools::hadamardMult(). nrows A != size of B.", nrA, sB); 00800 if (row == false && ncA != sB) throw DimensionException("MatrixTools::hadamardMult(). ncols A != size of B.", ncA, sB); 00801 O.resize(nrA, ncA); 00802 if (row) 00803 { 00804 for (size_t i = 0; i < nrA; i++) 00805 { 00806 for (size_t j = 0; j < ncA; j++) 00807 { 00808 O(i, j) = A(i, j) * B[i]; 00809 } 00810 } 00811 } 00812 else 00813 { 00814 for (size_t i = 0; i < nrA; i++) 00815 { 00816 for (size_t j = 0; j < ncA; j++) 00817 { 00818 O(i, j) = A(i, j) * B[j]; 00819 } 00820 } 00821 } 00822 } 00823 00831 template<class Scalar> 00832 static void kroneckerSum(const Matrix<Scalar>& A, const Matrix<Scalar>& B, Matrix<Scalar>& O) 00833 { 00834 size_t ncA = A.getNumberOfColumns(); 00835 size_t nrA = A.getNumberOfRows(); 00836 size_t nrB = B.getNumberOfRows(); 00837 size_t ncB = B.getNumberOfColumns(); 00838 O.resize(nrA + nrB, ncA + ncB); 00839 for (size_t ia = 0; ia < nrA; ia++) 00840 { 00841 for (size_t ja = 0; ja < ncA; ja++) 00842 { 00843 O(ia, ja) = A(ia, ja); 00844 } 00845 } 00846 for (size_t ib = 0; ib < nrB; ib++) 00847 { 00848 for (size_t jb = 0; jb < nrB; jb++) 00849 { 00850 O(nrA + ib, ncA + jb) = B(ib, jb); 00851 } 00852 } 00853 } 00854 00861 template<class Scalar> 00862 static void kroneckerSum(const std::vector< Matrix<Scalar>*>& vA, Matrix<Scalar>& O) 00863 { 00864 size_t nr = 0; 00865 size_t nc = 0; 00866 for (size_t k = 0; k < vA.size(); k++) 00867 { 00868 nr += vA[k]->getNumberOfRows(); 00869 nc += vA[k]->getNumberOfColumns(); 00870 } 00871 O.resize(nr, nc); 00872 size_t rk = 0; // Row counter 00873 size_t ck = 0; // Col counter 00874 for (size_t k = 0; k < vA.size(); k++) 00875 { 00876 const Matrix<Scalar>* Ak = vA[k]; 00877 for (size_t i = 0; i < Ak->getNumberOfRows(); i++) 00878 { 00879 for (size_t j = 0; j < Ak->getNumberOfColumns(); j++) 00880 { 00881 O(rk + i, ck + j) = (*Ak)(i, j); 00882 } 00883 } 00884 rk += Ak->getNumberOfRows(); 00885 ck += Ak->getNumberOfColumns(); 00886 } 00887 } 00888 00895 template<class Scalar> 00896 static void toVVdouble(const Matrix<Scalar>& M, std::vector< std::vector<Scalar> >& vO) 00897 { 00898 size_t n = M.getNumberOfRows(); 00899 size_t m = M.getNumberOfColumns(); 00900 vO.resize(n); 00901 for (size_t i = 0; i < n; i++) 00902 { 00903 vO[i].resize(m); 00904 for (size_t j = 0; j < m; j++) 00905 { 00906 vO[i][j] = M(i, j); 00907 } 00908 } 00909 } 00910 00916 template<class Scalar> 00917 static Scalar sumElements(const Matrix<Scalar>& M) 00918 { 00919 Scalar sum = 0; 00920 for (size_t i = 0; i < M.getNumberOfRows(); i++) 00921 { 00922 for (size_t j = 0; j < M.getNumberOfColumns(); j++) 00923 { 00924 sum += M(i, j); 00925 } 00926 } 00927 return sum; 00928 } 00929 00930 00931 00946 template<class Scalar> 00947 static Scalar lap(Matrix<Scalar>& assignCost, 00948 std::vector<int> &rowSol, 00949 std::vector<int> &colSol, 00950 std::vector<Scalar> &u, 00951 std::vector<Scalar> &v) throw (Exception) 00952 { 00953 size_t dim = assignCost.getNumberOfRows(); 00954 if (assignCost.getNumberOfColumns() != dim) 00955 throw Exception("MatrixTools::lap. Cost matrix should be scare."); 00956 00957 bool unassignedFound; 00958 size_t i, iMin; 00959 size_t numFree = 0, previousNumFree, f, i0, k, freeRow; 00960 std::vector<size_t> free(dim); // list of unassigned rows. 00961 std::vector<size_t> pred(dim); // row-predecessor of column in augmenting/alternating path. 00962 size_t j, j1, j2, endOfPath, last, low, up; 00963 std::vector<size_t> colList(dim); // list of columns to be scanned in various ways. 00964 std::vector<short int> matches(dim, 0); // counts how many times a row could be assigned. 00965 Scalar min; 00966 Scalar h; 00967 size_t uMin, uSubMin; 00968 Scalar v2; 00969 std::vector<Scalar> d(dim); // 'cost-distance' in augmenting path calculation. 00970 00971 // Column reduction 00972 for (j = dim; j > 0; j--) // reverse order gives better results. 00973 { 00974 // find minimum cost over rows. 00975 min = assignCost(0, j - 1); 00976 iMin = 0; 00977 for (i = 1; i < dim; ++i) { 00978 if (assignCost(i, j - 1) < min) 00979 { 00980 min = assignCost(i, j - 1); 00981 iMin = i; 00982 } 00983 } 00984 v[j - 1] = min; 00985 00986 if (++matches[iMin] == 1) 00987 { 00988 // init assignment if minimum row assigned for first time. 00989 rowSol[iMin] = j - 1; 00990 colSol[j - 1] = iMin; 00991 } 00992 else 00993 colSol[j - 1] = -1; // row already assigned, column not assigned. 00994 } 00995 00996 // Reduction tranfer 00997 for (i = 0; i < dim; i++) { 00998 if (matches[i] == 0) // fill list of unassigned 'free' rows. 00999 free[numFree++] = i; 01000 else { 01001 if (matches[i] == 1) // transfer reduction from rows that are assigned once. 01002 { 01003 j1 = rowSol[i]; 01004 min = -log(0); 01005 for (j = 0; j < dim; j++) 01006 if (j != j1) 01007 if (assignCost(i, j - 1) - v[j] < min) 01008 min = assignCost(i, j - 1) - v[j - 1]; 01009 v[j1] = v[j1] - min; 01010 } 01011 } 01012 } 01013 01014 // Augmenting row reduction 01015 short loopcnt = 0; // do-loop to be done twice. 01016 do 01017 { 01018 loopcnt++; 01019 01020 // scan all free rows. 01021 // in some cases, a free row may be replaced with another one to be scanned next. 01022 k = 0; 01023 previousNumFree = numFree; 01024 numFree = 0; // start list of rows still free after augmenting row reduction. 01025 while (k < previousNumFree) 01026 { 01027 i = free[k]; 01028 k++; 01029 01030 // find minimum and second minimum reduced cost over columns. 01031 uMin = assignCost(i, 0) - v[0]; 01032 j1 = 0; 01033 uSubMin = -log(0); 01034 for (j = 1; j < dim; j++) 01035 { 01036 h = assignCost(i, j) - v[j]; 01037 if (h < uSubMin) { 01038 if (h >= uMin) 01039 { 01040 uSubMin = h; 01041 j2 = j; 01042 } 01043 else 01044 { 01045 uSubMin = uMin; 01046 uMin = h; 01047 j2 = j1; 01048 j1 = j; 01049 } 01050 } 01051 } 01052 01053 i0 = colSol[j1]; 01054 if (uMin < uSubMin) { 01055 // change the reduction of the minimum column to increase the minimum 01056 // reduced cost in the row to the subminimum. 01057 v[j1] = v[j1] - (uSubMin - uMin); 01058 } else { // minimum and subminimum equal. 01059 if (i0 >= 0) // minimum column j1 is assigned. 01060 { 01061 // swap columns j1 and j2, as j2 may be unassigned. 01062 j1 = j2; 01063 i0 = colSol[j2]; 01064 } 01065 } 01066 01067 // (re-)assign i to j1, possibly de-assigning an i0. 01068 rowSol[i] = j1; 01069 colSol[j1] = i; 01070 01071 if (i0 >= 0) { // minimum column j1 assigned earlier. 01072 if (uMin < uSubMin) { 01073 // put in current k, and go back to that k. 01074 // continue augmenting path i - j1 with i0. 01075 free[--k] = i0; 01076 } else { 01077 // no further augmenting reduction possible. 01078 // store i0 in list of free rows for next phase. 01079 free[numFree++] = i0; 01080 } 01081 } 01082 } 01083 } 01084 while (loopcnt < 2); // repeat once. 01085 01086 // Augment solution for each free row. 01087 for (f = 0; f < numFree; f++) 01088 { 01089 freeRow = free[f]; // start row of augmenting path. 01090 01091 // Dijkstra shortest path algorithm. 01092 // runs until unassigned column added to shortest path tree. 01093 for (j = 0; j < dim; j++) 01094 { 01095 d[j] = assignCost(freeRow, j) - v[j]; 01096 pred[j] = freeRow; 01097 colList[j] = j; // init column list. 01098 } 01099 01100 low = 0; // columns in 0..low-1 are ready, now none. 01101 up = 0; // columns in low..up-1 are to be scanned for current minimum, now none. 01102 // columns in up..dim-1 are to be considered later to find new minimum, 01103 // at this stage the list simply contains all columns 01104 unassignedFound = false; 01105 do 01106 { 01107 if (up == low) // no more columns to be scanned for current minimum. 01108 { 01109 last = low - 1; 01110 01111 // scan columns for up..dim-1 to find all indices for which new minimum occurs. 01112 // store these indices between low..up-1 (increasing up). 01113 min = d[colList[up++]]; 01114 for (k = up; k < dim; k++) 01115 { 01116 j = colList[k]; 01117 h = d[j]; 01118 if (h <= min) 01119 { 01120 if (h < min) // new minimum. 01121 { 01122 up = low; // restart list at index low. 01123 min = h; 01124 } 01125 // new index with same minimum, put on undex up, and extend list. 01126 colList[k] = colList[up]; 01127 colList[up++] = j; 01128 } 01129 } 01130 01131 // check if any of the minimum columns happens to be unassigned. 01132 // if so, we have an augmenting path right away. 01133 for (k = low; k < up; k++) { 01134 if (colSol[colList[k]] < 0) 01135 { 01136 endOfPath = colList[k]; 01137 unassignedFound = true; 01138 break; 01139 } 01140 } 01141 } 01142 01143 if (!unassignedFound) 01144 { 01145 // update 'distances' between freerow and all unscanned columns, via next scanned column. 01146 j1 = colList[low]; 01147 low++; 01148 i = colSol[j1]; 01149 h = assignCost(i, j1) - v[j1] - min; 01150 01151 for (k = up; k < dim; k++) 01152 { 01153 j = colList[k]; 01154 v2 = assignCost(i, j) - v[j] - h; 01155 if (v2 < d[j]) 01156 { 01157 pred[j] = i; 01158 if (v2 == min) { // new column found at same minimum value 01159 if (colSol[j] < 0) 01160 { 01161 // if unassigned, shortest augmenting path is complete. 01162 endOfPath = j; 01163 unassignedFound = true; 01164 break; 01165 } 01166 // else add to list to be scanned right away. 01167 else 01168 { 01169 colList[k] = colList[up]; 01170 colList[up++] = j; 01171 } 01172 } 01173 d[j] = v2; 01174 } 01175 } 01176 } 01177 } 01178 while (!unassignedFound); 01179 01180 // update column prices. 01181 for (k = 0; k <= last; k++) 01182 { 01183 j1 = colList[k]; 01184 v[j1] = v[j1] + d[j1] - min; 01185 } 01186 01187 // reset row and column assignments along the alternating path. 01188 do 01189 { 01190 i = pred[endOfPath]; 01191 colSol[endOfPath] = i; 01192 j1 = endOfPath; 01193 endOfPath = rowSol[i]; 01194 rowSol[i] = j1; 01195 } 01196 while (i != freeRow); 01197 } 01198 01199 // calculate optimal cost. 01200 Scalar lapCost = 0; 01201 for (i = 0; i < dim; i++) 01202 { 01203 j = rowSol[i]; 01204 u[i] = assignCost(i, j) - v[j]; 01205 lapCost = lapCost + assignCost(i, j); 01206 } 01207 01208 return lapCost; 01209 } 01210 01211 }; 01212 01213 /* DEPRECATED 01214 namespace MatrixOperators { 01215 01216 MatrixB operator*(const MatrixA & A, const MatrixB & B) throw (DimensionException) 01217 { 01218 return MatrixTools::mult<MatrixA, MatrixB>(A, B); 01219 } 01220 01221 template<class MatrixA, class MatrixB> 01222 MatrixA operator+(const MatrixA & A, const MatrixB & B) throw (DimensionException) 01223 { 01224 MatrixA C = A; 01225 MatrixTools::add<MatrixA, MatrixB>(C, B); 01226 return C; 01227 } 01228 01229 template<class MatrixA, class MatrixB> 01230 MatrixA operator+=(MatrixA & A, const MatrixB & B) throw (DimensionException) 01231 { 01232 MatrixTools::add<MatrixA, MatrixB>(A, B); 01233 return A; 01234 } 01235 01236 template<class Matrix> 01237 Matrix operator-(const Matrix A) 01238 { 01239 Matrix B(A.getNumberOfRows(), A.getNumberOfColumns()); 01240 for(size_t i = 0; i < B.getNumberOfRows(); i++) { 01241 for(size_t j = 0; j < B.getNumberOfColumns(); j++) { 01242 B(i, j) = -A(i, j); 01243 } 01244 } 01245 return B; 01246 } 01247 01248 template<class MatrixA, class MatrixB> 01249 MatrixA operator-(const MatrixA & A, const MatrixB & B) throw (DimensionException) 01250 { 01251 // size_t ncA = A.getNumberOfColumns(); 01252 // size_t nrA = A.getNumberOfRows(); 01253 // size_t nrB = B.getNumberOfRows(); 01254 // size_t ncB = B.getNumberOfColumns(); 01255 // if(ncA != ncB) throw DimensionException("MatrixTools::operator-(). A and B must have the same number of colums.", ncB, ncA); 01256 // if(nrA != nrB) throw DimensionException("MatrixTools::operator-(). A and B must have the same number of rows.", nrB, nrA); 01257 // MatrixB C(A.getNumberOfRows(), A.getNumberOfColumns()); 01258 // for(size_t i = 0; i < A.getNumberOfRows(); i++) { 01259 // for(size_t j = 0; j < A.getNumberOfColumns(); j++) { 01260 // C(i, j) = A(i, j) - B(i, j); 01261 // } 01262 // } 01263 // return C; 01264 MatrixA C = A; 01265 MatrixTools::add<MatrixA, MatrixB>(C, -B); 01266 return C; 01267 } 01268 01269 template<class MatrixA, class MatrixB> 01270 MatrixA operator-=(MatrixA & A, const MatrixB & B) throw (DimensionException) 01271 { 01272 MatrixTools::add<MatrixA, MatrixB>(A, -B); 01273 return A; 01274 } 01275 01276 }; 01277 */ 01278 } // end of namespace bpp. 01279 01280 #endif // _MATRIXTOOLS_H_