bpp-core  2.1.0
MatrixTools.h
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Friends