LogDetApproxBaiAndGolub.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * @file LogDetApproxBaiAndGolub.cpp
  3. * @brief LogDet Approximation as stated by Bai and Golub ("Bounds for the Trace of the Inverse and the Determinant of Symmetric Positive Definite Matrices" in Annals of Numerical Mathematics) (Implementation)
  4. * @author Alexander Freytag
  5. * @date 05-01-2012 (dd-mm-yyyy)
  6. */
  7. #include <limits>
  8. #include <cmath>
  9. #include "gp-hik-core/algebra/LogDetApproxBaiAndGolub.h"
  10. #include "core/vector/VectorT.h"
  11. using namespace NICE;
  12. using namespace std;
  13. LogDetApproxBaiAndGolub::LogDetApproxBaiAndGolub()
  14. {
  15. verbose = false;
  16. }
  17. LogDetApproxBaiAndGolub::~LogDetApproxBaiAndGolub()
  18. {
  19. }
  20. void LogDetApproxBaiAndGolub::setVerbose(const bool & _verbose)
  21. {
  22. verbose = _verbose;
  23. }
  24. double LogDetApproxBaiAndGolub::getLogDetApproximation(const NICE::Matrix & A)
  25. {
  26. //todo compute lowest and largest eigenvalue if suitable methods here!
  27. double lambdaLowerBound(0.0);
  28. NICE::Vector ones(A.rows(), 1.0);
  29. NICE::Vector rightMultiplication;
  30. rightMultiplication.multiply(A, ones);
  31. //there is no nice way for multiplying two NICE::Vectors and returning a scalar :(
  32. rightMultiplication *= ones;
  33. //TODO For some reason I get an compilation error here: /home/luetz/code/fast-hik/nice/./core/vector/VectorT.tcc:539: undefined reference to `ippGetStatusString(IppStatus)'
  34. //Therefor the nasty workaround :(
  35. // double lambdaUpperBound(rightMultiplication.Sum());
  36. double lambdaUpperBound(0);
  37. for ( uint i = 0; i < rightMultiplication.size(); i++)
  38. {
  39. lambdaUpperBound += rightMultiplication[i];
  40. }
  41. //we could also call return getLogDetApproximation(A,lambdaUpperBound,lambdaLowerBound); - but this would need a second function call and we only have to write 3 extra lines of code
  42. double logDetLowerBound(getLogDetApproximationLowerBound(A.trace(), A.squaredFrobeniusNorm(), lambdaLowerBound, A.rows()) );
  43. double logDetUpperBound(getLogDetApproximationUpperBound(A.trace(), A.squaredFrobeniusNorm(), lambdaUpperBound, A.rows()) );
  44. return (fabs(logDetLowerBound) + fabs(logDetUpperBound) ) / 2.0;
  45. }
  46. double LogDetApproxBaiAndGolub::getLogDetApproximation(const NICE::Matrix A, const double & lambdaUpperBound, const double & lambdaLowerBound)
  47. {
  48. double logDetLowerBound(getLogDetApproximationLowerBound(A.trace(), A.squaredFrobeniusNorm(), lambdaLowerBound, A.rows()) );
  49. double logDetUpperBound(getLogDetApproximationUpperBound(A.trace(), A.squaredFrobeniusNorm(), lambdaUpperBound, A.rows()) );
  50. return (fabs(logDetLowerBound) + fabs(logDetUpperBound) ) / 2.0;
  51. }
  52. double LogDetApproxBaiAndGolub::getLogDetApproximation(const double & mu1, const double & mu2, const double & lambdaUpperBound, const double & lambdaLowerBound, const int & n )
  53. {
  54. double logDetLowerBound(getLogDetApproximationLowerBound(mu1, mu2, lambdaLowerBound, n) );
  55. double logDetUpperBound(getLogDetApproximationUpperBound(mu1, mu2, lambdaUpperBound, n) );
  56. return (logDetLowerBound + logDetUpperBound ) / 2.0;
  57. }
  58. double LogDetApproxBaiAndGolub::getLogDetApproximationUpperBound(const double & mu1, const double & mu2, const double & lambdaUpperBound, const int & n )
  59. {
  60. double tUpper(numeric_limits<double>::max());
  61. if ( (lambdaUpperBound*n-mu1) != 0)
  62. tUpper = (lambdaUpperBound*mu1 - mu2) / (lambdaUpperBound*n-mu1);
  63. // if ( tUpper < 1e-10 ) {
  64. // fthrow(Exception, "LogDetApproxBaiAndGolub::getLogDetApproximationLowerBound: tUpper < 0.0 !! " << mu1 << " " << mu2 << " " << n << " " << lambdaUpperBound );
  65. // }
  66. // boundUpper = [log(beta) , log(tUpper)] * ([beta , tUpper; power(beta,2), power(tUpper,2)]^-1 * [mu1;mu2]);
  67. //inversion of a 2x2-matrix can be done explicitely: A^{-1} = \frac{1}{ad-bc} \bmatrix{ d & -b \\ -c & a}
  68. NICE::Matrix InnerMatrix(2,2);
  69. InnerMatrix(0,0) = pow(tUpper,2);
  70. InnerMatrix(0,1) = -tUpper;
  71. InnerMatrix(1,0) = -pow(lambdaUpperBound,2);
  72. InnerMatrix(1,1) = lambdaUpperBound;
  73. InnerMatrix *= 1.0/(lambdaUpperBound*pow(tUpper,2) - tUpper*pow(lambdaUpperBound,2));
  74. NICE::Vector leftSide(2);
  75. leftSide(0) = log(lambdaUpperBound);
  76. leftSide(1) = log(tUpper);
  77. if (verbose)
  78. {
  79. cerr << "Left side: " << leftSide << endl;
  80. cerr << InnerMatrix << endl;
  81. }
  82. NICE::Vector rightSide(2);
  83. rightSide(0) = mu1;
  84. rightSide(1) = mu2;
  85. NICE::Vector rightMultiplication;
  86. rightMultiplication.multiply(InnerMatrix,rightSide);
  87. //there is no nice way for multiplying two NICE::Vectors and returning a scalar :(
  88. leftSide *= rightMultiplication;
  89. // return leftSide.Sum();
  90. //TODO For some reason I get an compilation error here: /home/luetz/code/fast-hik/nice/./core/vector/VectorT.tcc:539: undefined reference to `ippGetStatusString(IppStatus)'
  91. //Therefor the nasty workaround :(
  92. double result(0.0);
  93. for ( uint i = 0; i < leftSide.size(); i++)
  94. {
  95. result += leftSide[i];
  96. }
  97. return result;
  98. }
  99. double LogDetApproxBaiAndGolub::getLogDetApproximationLowerBound(const double & mu1, const double & mu2, const double & lambdaLowerBound, const int & n )
  100. {
  101. double tLower(numeric_limits<double>::max());
  102. if ( (lambdaLowerBound*n-mu1) != 0)
  103. tLower = (lambdaLowerBound*mu1 - mu2) / (lambdaLowerBound*n-mu1);
  104. // boundLower = [log(alpha) , log(tLower)] * ([alpha , tLower; power(alpha,2), power(tLower,2)]\[mu1;mu2]);
  105. //inversion of a 2x2-matrix can be done explicitely: A^{-1} = \frac{1}{ad-bc} \bmatrix{ d & -b \\ -c & a}
  106. NICE::Matrix InnerMatrix(2,2);
  107. InnerMatrix(0,0) = pow(tLower,2);
  108. InnerMatrix(0,1) = -tLower;
  109. InnerMatrix(1,0) = -pow(lambdaLowerBound,2);
  110. InnerMatrix(1,1) = lambdaLowerBound;
  111. InnerMatrix *= 1.0/(lambdaLowerBound*pow(tLower,2) - tLower*pow(lambdaLowerBound,2));
  112. NICE::Vector leftSide(2);
  113. leftSide(0) = log(lambdaLowerBound);
  114. leftSide(1) = log(tLower);
  115. NICE::Vector rightSide(2);
  116. rightSide(0) = mu1;
  117. rightSide(1) = mu2;
  118. NICE::Vector rightMultiplication;
  119. rightMultiplication.multiply(InnerMatrix,rightSide);
  120. return leftSide.scalarProduct( rightMultiplication );
  121. // //there is no nice way for multiplying two NICE::Vectors and returning a scalar so far
  122. // leftSide *= rightMultiplication;
  123. //
  124. // //nasty workaround for leftSide.Sum(), which does not compile properly on all machines
  125. // double result(0.0);
  126. //
  127. // for ( uint i = 0; i < leftSide.size(); i++)
  128. // {
  129. // result += leftSide[i];
  130. // }
  131. // return result;
  132. }