123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829 |
- /**
- * @file KernelData.cpp
- * @brief caching some kernel data
- * @author Erik Rodner
- * @date 01/19/2010
- */
- #include <iostream>
- #include "KernelData.h"
- #include "core/algebra/CholeskyRobustAuto.h"
- #include "core/algebra/CholeskyRobust.h"
- #include "core/vector/Algorithms.h"
- #ifdef NICE_USELIB_OPENMP
- #include <omp.h> //for parallel processing
- #endif
- #include "vector"
- using namespace std;
- using namespace NICE;
- using namespace OBJREC;
- KernelData::KernelData()
- {
- // empty config
- Config conf;
- initFromConfig ( &conf, "DONTCARE" );
- }
- KernelData::KernelData ( const KernelData & src )
- {
- kernelMatrix = src.kernelMatrix;
- inverseKernelMatrix = src.inverseKernelMatrix;
- choleskyMatrix = src.choleskyMatrix;
- for ( map<int, NICE::Matrix *>::const_iterator i = src.cachedMatrices.begin();
- i != src.cachedMatrices.end(); i++ )
- {
- Matrix *M = new Matrix ( * ( i->second ) );
- cachedMatrices.insert ( pair<int, NICE::Matrix *> ( i->first, M ) );
- }
- logdet = src.logdet;
- verbose = src.verbose;
- cr = src.cr->clone();
- }
- KernelData::KernelData ( const Config *conf, const Matrix & kernelMatrix, const string & section )
- {
- initFromConfig ( conf, section );
- this->kernelMatrix = kernelMatrix;
- updateCholeskyFactorization();
- }
- KernelData::KernelData ( const Config *conf, const string & section )
- {
- initFromConfig ( conf, section );
- }
- void KernelData::initFromConfig ( const Config *conf, const string & section )
- {
- verbose = conf->gB ( section, "verbose", false );
- string inv_method = conf->gS ( section, "robust_cholesky", "auto" );
- double noiseStep = conf->gD ( section, "rchol_noise_variance", 1e-7 );
- double minimumLogDet = conf->gD ( section, "rchol_minimum_logdet", - std::numeric_limits<double>::max() );
- bool useCuda = conf->gB ( section, "rchol_cuda", true );
- if ( verbose && useCuda )
- std::cerr << "KernelData: using the cuda implementation of cholesky decomposition (might be inaccurate)" << std::endl;
- if ( inv_method == "auto" )
- {
- if ( verbose )
- std::cerr << "KernelData: using the cholesky method with automatic regularization" << std::endl;
- cr = new CholeskyRobustAuto ( verbose, noiseStep, minimumLogDet, useCuda );
- } else {
- if ( verbose )
- std::cerr << "KernelData: using the cholesky method with static regularization" << std::endl;
- cr = new CholeskyRobust ( verbose, noiseStep, useCuda );
- }
- }
- KernelData::~KernelData()
- {
- delete cr;
- }
- void KernelData::updateCholeskyFactorization ()
- {
- if ( verbose )
- std::cerr << "KernelData: kernel: " << kernelMatrix.rows() << " " << kernelMatrix.cols() << std::endl;
- if ( ( kernelMatrix.rows() <= 0 ) || ( kernelMatrix.cols() <= 0 ) )
- fthrow ( Exception, "KernelData: no kernel matrix available !" );
- if ( kernelMatrix.containsNaN() )
- {
- if ( verbose )
- std::cerr << "KernelData: kernel matrix contains NaNs (setting inverse to identity)" << std::endl;
- logdet = numeric_limits<double>::max();
- choleskyMatrix.resize ( kernelMatrix.rows(), kernelMatrix.cols() );
- choleskyMatrix.setIdentity();
- } else {
- if ( verbose )
- std::cerr << "KernelData: calculating cholesky decomposition" << std::endl;
- cr->robustChol ( kernelMatrix, choleskyMatrix );
- logdet = cr->getLastLogDet();
- if ( !finite ( logdet ) )
- {
- choleskyMatrix.resize ( kernelMatrix.rows(), kernelMatrix.cols() );
- choleskyMatrix.setIdentity();
- logdet = numeric_limits<double>::max();
- }
- }
- }
- void KernelData::updateInverseKernelMatrix ()
- {
- if ( ! hasCholeskyFactorization() )
- updateCholeskyFactorization();
- inverseKernelMatrix.resize ( choleskyMatrix.rows(), choleskyMatrix.cols() );
- choleskyInvertLargeScale ( choleskyMatrix, inverseKernelMatrix );
- }
- void KernelData::computeInverseKernelMultiply ( const Vector & x, Vector & result ) const
- {
- if ( choleskyMatrix.rows() == 0 )
- fthrow ( Exception, "Cholesky factorization was not initialized, use updateCholeskyFactorization() in advance" );
- choleskySolveLargeScale ( choleskyMatrix, x, result );
- }
- const NICE::Matrix & KernelData::getKernelMatrix() const
- {
- return kernelMatrix;
- }
- NICE::Matrix & KernelData::getKernelMatrix()
- {
- return kernelMatrix;
- }
- const NICE::Matrix & KernelData::getInverseKernelMatrix() const
- {
- return inverseKernelMatrix;
- };
- NICE::Matrix & KernelData::getInverseKernelMatrix()
- {
- return inverseKernelMatrix;
- };
- const NICE::Matrix & KernelData::getCholeskyMatrix() const
- {
- return choleskyMatrix;
- }
- const Matrix & KernelData::getCachedMatrix ( int i ) const
- {
- map<int, NICE::Matrix *>::const_iterator it = cachedMatrices.find ( i );
- if ( it != cachedMatrices.end() )
- return * ( it->second );
- else
- fthrow ( Exception, "Cached matrix with index " << i << " is not available." );
- }
- void KernelData::setCachedMatrix ( int i, Matrix *m )
- {
- cachedMatrices[i] = m;
- }
- uint KernelData::getKernelMatrixSize () const {
- uint mysize = ( kernelMatrix.rows() == 0 ) ? ( choleskyMatrix.rows() ) : kernelMatrix.rows();
- return mysize;
- };
- void KernelData::getLooEstimates ( const Vector & y, Vector & muLoo, Vector & sigmaLoo ) const
- {
- if ( inverseKernelMatrix.rows() != getKernelMatrixSize() )
- fthrow ( Exception, "updateInverseKernelMatrix() has to be called in advance to use this function\n" );
- if ( y.size() != inverseKernelMatrix.rows() )
- fthrow ( Exception, "inverse kernel matrix does not fit to the size of the vector of function values y\n" );
- Vector alpha;
- computeInverseKernelMultiply ( y, alpha );
- muLoo.resize ( y.size() );
- sigmaLoo.resize ( y.size() );
- for ( uint l = 0 ; l < y.size(); l++ )
- {
- sigmaLoo[l] = 1.0 / inverseKernelMatrix ( l, l );
- muLoo[l] = y[l] - alpha[l] * sigmaLoo[l];
- }
- }
- KernelData *KernelData::clone ( void ) const
- {
- return new KernelData ( *this );
- }
- /**
- * @brief Updates the GP-Likelihood, if only the i-th row and column has changed. Time is O(n^2) instaed O(n^3)
- * @author Alexander Lütz
- * @date 01/12/2010 (dd/mm/yyyy)
- */
- void KernelData::getGPLikelihoodWithOneNewRow ( const NICE::Vector & y, const double & oldLogdetK, const int & rowIndex, const NICE::Vector & newRow, const Vector & oldAlpha , Vector & newAlpha, double & loglike )
- {
- // oldAlpha = K^{-1} y
- // K' new kernel matrix = exchange the row and column at position rowIndex
- // with newRow
- // try to find U and V such that K' = K + U*V with U,V having rank 2
- // rowIndex'th base vector
- Vector ei ( y.size(), 0.0 );
- ei[rowIndex] = 1.0;
- // we have to consider the diagonal entry
- Vector a = newRow - kernelMatrix.getRow ( rowIndex ) ;
- a[rowIndex] = a[rowIndex] / 2;
- NICE::Matrix U ( y.size(), 2 );
- NICE::Matrix V ( 2, y.size() );
- for ( uint i = 0; i < y.size(); i++ )
- {
- U ( i, 0 ) = a[i];
- U ( i, 1 ) = ei[i];
- V ( 0, i ) = ei[i];
- V ( 1, i ) = a[i];
- }
- // Sherman Woodbury-Morrison Formula:
- // alpha_new = (K + UV)^{-1} y = K^{-1} y - K^{-1} U ( I + V
- // K^{-1} U )^{-1} V K^{-1} y = oldAlpha - B ( I + V B )^{-1} V oldAlpha
- // = oldAlpha - B F^{-1} V oldAlpha
- // with B = K^{-1} U and F = (I+VB)
- // Time complexity: 2 choleskySolve calls: O(n^2)
- NICE::Vector B_1;
- computeInverseKernelMultiply ( U.getColumn ( 0 ), B_1 );
- NICE::Vector B_2;
- computeInverseKernelMultiply ( U.getColumn ( 1 ), B_2 );
- NICE::Matrix B ( y.size(), 2 );
- for ( uint i = 0; i < y.size(); i++ )
- {
- B ( i, 0 ) = B_1[i];
- B ( i, 1 ) = B_2[i];
- }
- NICE::Matrix F ( 2, 2 );
- F.setIdentity();
- Matrix V_B ( 2, 2 );
- V_B.multiply ( V, B );
- F += V_B;
- // Time complexity: 1 linear equation system with 2 variables
- // can be computed in O(1) using a fixed implementation
- NICE::Matrix F_inv = NICE::Matrix ( 2, 2 );
- double denominator = F ( 0, 0 ) * F ( 1, 1 ) - F ( 0, 1 ) * F ( 1, 0 );
- F_inv ( 0, 0 ) = F ( 1, 1 ) / denominator;
- F_inv ( 0, 1 ) = -F ( 0, 1 ) / denominator;
- F_inv ( 1, 0 ) = - F ( 1, 0 ) / denominator;
- F_inv ( 1, 1 ) = F ( 0, 0 ) / denominator;
- Matrix M_oldAlpha ( y.size(), 1 );
- for ( uint i = 0; i < y.size(); i++ )
- {
- M_oldAlpha ( i, 0 ) = oldAlpha[i];
- }
- NICE::Matrix V_oldAlpha;
- V_oldAlpha.multiply ( V, M_oldAlpha );
- NICE::Matrix F_inv_V_old_Alpha;
- F_inv_V_old_Alpha.multiply ( F_inv, V_oldAlpha );
- NICE::Matrix M_newAlpha;
- M_newAlpha.multiply ( B, F_inv_V_old_Alpha );
- M_newAlpha *= -1;
- M_newAlpha += M_oldAlpha;
- newAlpha = NICE::Vector ( y.size() );
- for ( uint i = 0; i < y.size(); i++ )
- {
- newAlpha[i] = M_newAlpha ( i, 0 );
- }
- // Matrix Determinant Lemma
- // http://en.wikipedia.org/wiki/Matrix_determinant_lemma
- // det(K + U*V) = det(I + V * K^{-1} * U) * det(K)
- // logdet(K + U*V) = logdet( F ) + logdet(K)
- double logdetF = log ( F ( 0, 0 ) * F ( 1, 1 ) - F ( 0, 1 ) * F ( 1, 0 ) );
- double newLogdetK = logdetF + oldLogdetK;
- logdet = newLogdetK;
- loglike = newLogdetK + newAlpha.scalarProduct ( y );
- }
- /**
- * @brief Updates the GP-Likelihood, if only the i-th row and column has changed. Time is O(n^2) instaed O(n^3). This is only the first part. Usefull for multiclass-problems.
- * @author Alexander Lütz
- * @date 01/12/2010 (dd/mm/yyyy)
- */
- void KernelData::getGPLikelihoodWithOneNewRow_FirstPart ( const int & rowIndex, const NICE::Vector & newRow )
- {
- // oldAlpha = K^{-1} y
- // K' new kernel matrix = exchange the row and column at position rowIndex
- // with newRow
- // try to find U and V such that K' = K + U*V with U,V having rank 2
- // rowIndex'th base vector
- Vector ei ( newRow.size(), 0.0 );
- ei[rowIndex] = 1.0;
- // we have to consider the diagonal entry
- Vector a = newRow - kernelMatrix.getRow ( rowIndex ) ;
- a[rowIndex] = a[rowIndex] / 2;
- U.resize ( newRow.size(), 2 );
- V.resize ( 2, newRow.size() );
- // #pragma omp parallel for
- for ( uint i = 0; i < newRow.size(); i++ )
- {
- U ( i, 0 ) = a[i];
- U ( i, 1 ) = ei[i];
- V ( 0, i ) = ei[i];
- V ( 1, i ) = a[i];
- }
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- U:" << std::endl;
- for ( uint ik = 0; ik < U.rows(); ik++ )
- {
- for ( uint jk = 0; jk < U.cols(); jk++ )
- {
- std::cerr << U ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- V:" << std::endl;
- for ( uint ik = 0; ik < V.rows(); ik++ )
- {
- for ( uint jk = 0; jk < V.cols(); jk++ )
- {
- std::cerr << V ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- // Sherman Woodbury-Morrison Formula:
- // alpha_new = (K + UV)^{-1} y = K^{-1} y - K^{-1} U ( I + V
- // K^{-1} U )^{-1} V K^{-1} y = oldAlpha - B ( I + V B )^{-1} V oldAlpha
- // = oldAlpha - B F^{-1} V oldAlpha
- // with B = K^{-1} U and F = (I+VB)
- // Time complexity: 2 choleskySolve calls: O(n^2)
- NICE::Vector B_1;
- computeInverseKernelMultiply ( U.getColumn ( 0 ), B_1 );
- NICE::Vector B_2;
- computeInverseKernelMultiply ( U.getColumn ( 1 ), B_2 );
- B.resize ( newRow.size(), 2 );
- for ( uint i = 0; i < newRow.size(); i++ )
- {
- B ( i, 0 ) = B_1[i];
- B ( i, 1 ) = B_2[i];
- }
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- B:" << std::endl;
- for ( uint ik = 0; ik < B.rows(); ik++ )
- {
- for ( uint jk = 0; jk < B.cols(); jk++ )
- {
- std::cerr << B ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- F.resize ( 2, 2 );
- F.setIdentity();
- Matrix V_B ( 2, 2 );
- V_B.multiply ( V, B );
- F += V_B;
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- F:" << std::endl;
- for ( uint ik = 0; ik < F.rows(); ik++ )
- {
- for ( uint jk = 0; jk < F.cols(); jk++ )
- {
- std::cerr << F ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- // Time complexity: 1 linear equation system with 2 variables
- // can be computed in O(1) using a fixed implementation
- F_inv.resize ( 2, 2 );
- double denominator = F ( 0, 0 ) * F ( 1, 1 ) - F ( 0, 1 ) * F ( 1, 0 );
- F_inv ( 0, 0 ) = F ( 1, 1 ) / denominator;
- F_inv ( 0, 1 ) = -F ( 0, 1 ) / denominator;
- F_inv ( 1, 0 ) = - F ( 1, 0 ) / denominator;
- F_inv ( 1, 1 ) = F ( 0, 0 ) / denominator;
-
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- F_inv:" << std::endl;
- for ( uint ik = 0; ik < F_inv.rows(); ik++ )
- {
- for ( uint jk = 0; jk < F_inv.cols(); jk++ )
- {
- std::cerr << F_inv ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- NICE::Matrix MultiplicationResult ( F_inv.cols(), F_inv.cols(), 0.0 );
- MultiplicationResult.multiply ( F, F_inv );
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- F-inversion MultiplicationResult:" << std::endl;
- for ( uint ik = 0; ik < MultiplicationResult.rows(); ik++ )
- {
- for ( uint jk = 0; jk < MultiplicationResult.cols(); jk++ )
- {
- std::cerr << MultiplicationResult ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- }
- /**
- * @brief Updates the GP-Likelihood, if only the i-th row and column has changed. Time is O(n^2) instaed O(n^3). This is only the second part. Usefull for multiclass-problems.
- * @author Alexander Lütz
- * @date 01/12/2010 (dd/mm/yyyy)
- */
- void KernelData::getGPLikelihoodWithOneNewRow_SecondPart ( const NICE::Vector & y, const double & oldLogdetK, const Vector & oldAlpha , Vector & newAlpha, double & loglike )
- {
- Matrix M_oldAlpha ( y.size(), 1 );
- for ( uint i = 0; i < y.size(); i++ )
- {
- M_oldAlpha ( i, 0 ) = oldAlpha[i];
- }
- NICE::Matrix V_oldAlpha;
- V_oldAlpha.multiply ( V, M_oldAlpha );
- NICE::Matrix F_inv_V_old_Alpha;
- F_inv_V_old_Alpha.multiply ( F_inv, V_oldAlpha );
- NICE::Matrix M_newAlpha;
- M_newAlpha.multiply ( B, F_inv_V_old_Alpha );
- M_newAlpha *= -1;
- M_newAlpha += M_oldAlpha;
- newAlpha = NICE::Vector ( y.size() );
- for ( uint i = 0; i < y.size(); i++ )
- {
- newAlpha[i] = M_newAlpha ( i, 0 );
- }
- // Matrix Determinant Lemma
- // http://en.wikipedia.org/wiki/Matrix_determinant_lemma
- // det(K + U*V) = det(I + V * K^{-1} * U) * det(K)
- // logdet(K + U*V) = logdet( F ) + logdet(K)
- double logdetF = log ( F ( 0, 0 ) * F ( 1, 1 ) - F ( 0, 1 ) * F ( 1, 0 ) );
- double newLogdetK = logdetF + oldLogdetK;
- logdet = newLogdetK;
- loglike = newLogdetK + newAlpha.scalarProduct ( y );
- }
- /**
- * @brief Updates the GP-Likelihood, if only the i-th row and column has changed. Time is O(n^2) instaed O(n^3).
- * @author Alexander Lütz
- * @date 01/09/2011 (dd/mm/yyyy)
- */
- void KernelData::perform_Rank_2_Update ( const int & rowIndex, const NICE::Vector & newRow )
- {
- getGPLikelihoodWithOneNewRow_FirstPart ( rowIndex, newRow );
- Matrix prod_1;
- prod_1.multiply ( V, inverseKernelMatrix );
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- prod_1:" << std::endl;
- for ( uint ik = 0; ik < prod_1.rows(); ik++ )
- {
- for ( uint jk = 0; jk < prod_1.cols(); jk++ )
- {
- std::cerr << prod_1 ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- Matrix prod_2;
- prod_2.multiply ( F_inv, prod_1 );
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- prod_2:" << std::endl;
- for ( uint ik = 0; ik < prod_2.rows(); ik++ )
- {
- for ( uint jk = 0; jk < prod_2.cols(); jk++ )
- {
- std::cerr << prod_2 ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- Matrix prod_3;
- prod_3.multiply ( B, prod_2 );
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2_Update -- prod_3:" << std::endl;
- for ( uint ik = 0; ik < prod_3.rows(); ik++ )
- {
- for ( uint jk = 0; jk < prod_3.cols(); jk++ )
- {
- std::cerr << prod_3 ( ik, jk ) << " ";
- }
- std::cerr << std::endl;
- }
- }
- inverseKernelMatrix = inverseKernelMatrix - prod_3;
-
- // std::cerr << "perform rank 2 update: inverseKernelMatrix: " << inverseKernelMatrix << std::endl;
- //correct the stored kernel matrix after our computations
- for ( uint i = 0; i < newRow.size(); i++ )
- {
- kernelMatrix ( i, rowIndex ) = newRow[i];
- kernelMatrix ( rowIndex, i ) = newRow[i];
- }
- // std::cerr << "kernelMatrix: " << kernelMatrix << std::endl << " newRow: " << newRow << std::endl;
- }
- /**
- * @brief Updates the GP-Likelihood, if only k rows and colums are changed. Time is O(k^3+n^2) instaed O(n^3). Alternatively it could also be done with iteratively change one row, which leads to O(k*n^2).
- * @author Alexander Lütz
- * @date 01/09/2011 (dd/mm/yyyy)
- */
- void KernelData::perform_Rank_2k_Update ( const std::vector<int> & rowIndices, const std::vector<NICE::Vector> & newRows )
- {
- if ( ( rowIndices.size() != 0 ) && ( rowIndices.size() == newRows.size() ) )
- {
- std::vector<NICE::Vector> unity_vectors;
- std::vector<NICE::Vector> diff_vectors;
- for ( uint j = 0; j < rowIndices.size(); j++ )
- {
- NICE::Vector unity_vector ( newRows[0].size(), 0.0 );
- unity_vector[rowIndices[j] ] = 1.0;
- unity_vectors.push_back ( unity_vector );
- NICE::Vector a = newRows[j] - kernelMatrix.getRow ( rowIndices[j] );
- for ( uint x = 0; x < rowIndices.size(); x++ )
- {
- a[rowIndices[x] ] /= 2.0;
- }
- diff_vectors.push_back ( a );
- }
- U.resize ( newRows[0].size(), 2*rowIndices.size() );
- V.resize ( 2*rowIndices.size(), newRows[0].size() );
- for ( uint i = 0; i < newRows[0].size(); i++ )
- {
- for ( uint j = 0; j < rowIndices.size(); j++ )
- {
- U ( i, rowIndices.size() + j ) = ( unity_vectors[j] ) [i];
- U ( i, j ) = ( diff_vectors[j] ) [i];
- V ( rowIndices.size() + j, i ) = ( diff_vectors[j] ) [i];
- V ( j, i ) = ( unity_vectors[j] ) [i];
- }
- }
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- U: " << U << std::endl;
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- V: " << V << std::endl;
- }
- NICE::Matrix UV ( newRows[0].size(), newRows[0].size() );
- UV.multiply ( U, V );
- if ( verbose )
- {
- // we have to consider the entries which are added twice
- for ( int x = 0; x < ( int ) rowIndices.size(); x++ )
- {
- for ( int y = x; y < ( int ) rowIndices.size(); y++ )
- {
- UV ( rowIndices[x] , rowIndices[y] ) /= 2.0;
- if ( x != y )
- UV ( rowIndices[y] , rowIndices[x] ) /= 2.0;
- }
- }
- }
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- UV:" << UV << std::endl;
- }
- B.resize ( newRows[0].size(), 2*rowIndices.size() );
- for ( uint j = 0; j < 2*rowIndices.size(); j++ )
- {
- NICE::Vector B_row;
- computeInverseKernelMultiply ( U.getColumn ( j ), B_row );
- for ( uint i = 0; i < newRows[0].size(); i++ )
- {
- B ( i, j ) = B_row[i];
- }
- }
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- B:" << B << std::endl;
- }
- F.resize ( 2*rowIndices.size(), 2*rowIndices.size() );
- F.setIdentity();
- Matrix V_B ( 2*rowIndices.size(), 2*rowIndices.size() );
- V_B.multiply ( V, B );
- F += V_B;
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- F:" << F << std::endl;
- }
- //invert F!
- //we can't rely on methods like cholesky decomposition, since F has not to be positive definite
- F_inv = invert ( F );
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- F_inv:" << F_inv <<std::endl;
- }
- if ( verbose )
- {
- NICE::Matrix MultiplicationResult ( F.rows(), F_inv.cols(), 0.0 );
- MultiplicationResult.multiply ( F, F_inv );
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- F-inversion MultiplicationResult:" << MultiplicationResult << std::endl;
- }
- Matrix prod_1;
- prod_1.multiply ( V, inverseKernelMatrix );
- std::cerr << "prod_1: " << prod_1.rows() << " x " << prod_1.cols() << std::endl;
-
- std::cerr << "v and inverse matrix multiplied" << std::endl;
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- prod_1:" << prod_1 << std::endl;
- }
- Matrix prod_2;
- prod_2.resize(F.rows(), prod_1.cols());
-
- prod_2.multiply ( F_inv, prod_1 );
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- prod_2:" << prod_2 << std::endl;
- }
- std::cerr << "B: " << B.rows() << " x " << B.cols() << std::endl;
- Matrix prod_3;
- prod_3.multiply ( B, prod_2 );
-
- std::cerr << "prod_3 created: " << prod_3.rows() << " x " << prod_3.cols() << std::endl;
- if ( verbose )
- {
- std::cerr << std::endl << "KernelData::perform_Rank_2k_Update -- prod_3:" << prod_3 << std::endl;
- }
- inverseKernelMatrix = inverseKernelMatrix - prod_3;
- //remember the new kernel entries for the next time
- for ( uint i = 0; i < rowIndices.size(); i++ )
- {
- for ( uint ik = 0; ik < kernelMatrix.rows(); ik++ )
- {
- kernelMatrix ( ik, rowIndices[i] ) = ( newRows[i] ) [ik];
- kernelMatrix ( rowIndices[i], ik ) = ( newRows[i] ) [ik];
- }
- }
- }
- else
- {
- std::cerr << "Failure" << std::endl;
- }
- }
- void KernelData::delete_one_row ( const int & rowIndex )
- {
- if ( ( inverseKernelMatrix.rows() != 0 ) && ( inverseKernelMatrix.cols() != 0 ) )
- {
- inverseKernelMatrix.deleteCol ( rowIndex );
- inverseKernelMatrix.deleteRow ( rowIndex );
- }
- if ( ( choleskyMatrix.rows() != 0 ) && ( choleskyMatrix.cols() != 0 ) )
- {
- choleskyMatrix.deleteCol ( rowIndex );
- choleskyMatrix.deleteRow ( rowIndex );
- }
- if ( ( kernelMatrix.rows() != 0 ) && ( kernelMatrix.cols() != 0 ) )
- {
- kernelMatrix.deleteCol ( rowIndex );
- kernelMatrix.deleteRow ( rowIndex );
- }
- }
- void KernelData::delete_multiple_rows ( std::vector<int> & indices )
- {
- if ( ( inverseKernelMatrix.rows() >= indices.size() ) && ( inverseKernelMatrix.cols() >= indices.size() ) )
- {
- inverseKernelMatrix.deleteCols ( indices );
- inverseKernelMatrix.deleteRows ( indices );
- }
- if ( ( choleskyMatrix.rows() >= indices.size() ) && ( choleskyMatrix.cols() >= indices.size() ) )
- {
- choleskyMatrix.deleteCols ( indices );
- choleskyMatrix.deleteRows ( indices );
- }
- if ( ( kernelMatrix.rows() >= indices.size() ) && ( kernelMatrix.cols() >= indices.size() ) )
- {
- kernelMatrix.deleteCols ( indices );
- kernelMatrix.deleteRows ( indices );
- }
- }
- void KernelData::setKernelMatrix ( const NICE::Matrix & k_matrix )
- {
- kernelMatrix = k_matrix;
- }
- void KernelData::increase_size_by_One()
- {
- NICE::Matrix new_Kernel ( kernelMatrix.rows() + 1, kernelMatrix.cols() + 1 );
- new_Kernel.setBlock ( 0, 0, kernelMatrix );
- for ( uint i = 0; i < kernelMatrix.rows() - 1; i++ )
- {
- new_Kernel ( i, kernelMatrix.cols() ) = 0.0;
- new_Kernel ( kernelMatrix.rows(), i ) = 0.0;
- }
- new_Kernel ( kernelMatrix.rows(), kernelMatrix.cols() ) = 1.0;
- //NOTE Maybe it would be more efficient to work directly with pointers to the memory
- kernelMatrix.resize ( new_Kernel.rows(), new_Kernel.cols() );
- kernelMatrix = new_Kernel;
- new_Kernel.setBlock ( 0, 0, inverseKernelMatrix );
- //NOTE Maybe it would be more efficient to work directly with pointers to the memory
- inverseKernelMatrix.resize ( new_Kernel.rows(), new_Kernel.cols() );
- inverseKernelMatrix = new_Kernel;
- new_Kernel.setBlock ( 0, 0, choleskyMatrix );
- //NOTE Maybe it would be more efficient to work directly with pointers to the memory
- choleskyMatrix.resize ( new_Kernel.rows(), new_Kernel.cols() );
- choleskyMatrix = new_Kernel;
- }
- void KernelData::increase_size_by_k ( const uint & k )
- {
- NICE::Matrix new_Kernel ( kernelMatrix.rows() + k, kernelMatrix.cols() + k );
- new_Kernel.setBlock ( 0, 0, kernelMatrix );
- for ( uint i = 0; i < kernelMatrix.rows() - 1; i++ )
- {
- for ( uint j = 0; j < k; j++ )
- {
- new_Kernel ( i, kernelMatrix.cols() + j ) = 0.0;
- new_Kernel ( kernelMatrix.rows() + j, i ) = 0.0;
- }
- }
- for ( uint j = 0; j < k; j++ )
- {
- new_Kernel ( kernelMatrix.rows() + j, kernelMatrix.cols() + j ) = 1.0;
- }
- //NOTE Maybe it would be more efficient to work directly with pointers to the memory
- kernelMatrix.resize ( new_Kernel.rows(), new_Kernel.cols() );
- kernelMatrix = new_Kernel;
- new_Kernel.setBlock ( 0, 0, inverseKernelMatrix );
- //NOTE Maybe it would be more efficient to work directly with pointers to the memory
- inverseKernelMatrix.resize ( new_Kernel.rows(), new_Kernel.cols() );
- inverseKernelMatrix = new_Kernel;
- new_Kernel.setBlock ( 0, 0, choleskyMatrix );
- //NOTE Maybe it would be more efficient to work directly with pointers to the memory
- choleskyMatrix.resize ( new_Kernel.rows(), new_Kernel.cols() );
- choleskyMatrix = new_Kernel;
- }
|