6 #ifdef DROPPINGTHISINRPACKAGE
10 #include <Eigen/Dense>
14 #include "boost/math/special_functions.hpp"
27 constexpr T inv_sqrt_2pi = T(0.3989422804014327);
31 constexpr T sqrt_two_over_pi(0.797884560802865);
35 constexpr T log_two_pi (1.83787706640935);
39 constexpr T log_two_over_pi (-0.451582705289455);
43 constexpr T log_pi (1.1447298858494);
55 template<
typename float_t>
56 float_t twiceFisher(float_t phi)
58 if ( (phi <= -1.0) || (phi >= 1.0) )
59 throw std::invalid_argument(
"error: phi was not between -1 and 1" );
61 return std::log(1.0 + phi) - std::log(1.0 - phi);
71 template<
typename float_t>
72 float_t invTwiceFisher(float_t psi)
74 float_t ans = (1.0 - std::exp(psi)) / ( -1.0 - std::exp(psi) );
76 if ( (ans <= -1.0) || (ans >= 1.0) )
77 std::cerr <<
"error: there was probably overflow for exp(psi) \n";
88 template<
typename float_t>
89 float_t logit(float_t p)
91 if ( (p <= 0.0) || (p >= 1.0))
92 std::cerr <<
"error: p was not between 0 and 1 \n";
94 return std::log(p) - std::log(1.0 - p);
103 template<
typename float_t>
104 float_t inv_logit(float_t r)
106 float_t ans = 1.0/( 1.0 + std::exp(-r) );
108 if ( (ans <= 0.0) || (ans >= 1.0))
109 std::cerr <<
"error: there was probably underflow for exp(-r) \n";
120 template<
typename float_t>
121 float_t log_inv_logit(float_t r)
123 if(r < -750.00 || r > 750.00) std::cerr <<
"warning: log_inv_logit might be under/over-flowing\n";
124 return -std::log(1.0 + std::exp(-r));
134 template<
typename float_t>
135 float_t log_sum_exp(float_t a, float_t b)
137 float_t m = std::max(a,b);
138 return m + std::log(std::exp(a-m) + std::exp(b-m));
154 template<
typename float_t>
155 float_t evalUnivNorm(float_t x, float_t mu, float_t sigma,
bool log)
157 float_t exponent = -.5*(x - mu)*(x-mu)/(sigma*sigma);
160 return -std::log(sigma) - .5*log_two_pi<float_t> + exponent;
162 return inv_sqrt_2pi<float_t> * std::exp(exponent) / sigma;
166 return -std::numeric_limits<float_t>::infinity();
182 template<
typename float_t>
183 float_t evalUnivNorm_unnorm(float_t x, float_t mu, float_t sigma,
bool log)
185 float_t exponent = -.5*(x - mu)*(x-mu)/(sigma*sigma);
190 return std::exp(exponent);
194 return -std::numeric_limits<float_t>::infinity();
207 template<
typename float_t>
208 float_t evalUnivStdNormCDF(float_t x)
211 float_t a1 = 0.254829592;
212 float_t a2 = -0.284496736;
213 float_t a3 = 1.421413741;
214 float_t a4 = -1.453152027;
215 float_t a5 = 1.061405429;
216 float_t p = 0.3275911;
222 float_t xt = std::fabs(x)/std::sqrt(2.0);
225 float_t t = 1.0/(1.0 + p*xt);
226 float_t y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*std::exp(-xt*xt);
228 return 0.5*(1.0 + sign*y);
240 template<
typename float_t>
241 float_t evalUnivBeta(float_t x, float_t alpha, float_t beta,
bool log)
243 if( (x > 0.0) && (x < 1.0) && (alpha > 0.0) && (beta > 0.0) ){
245 return std::lgamma(alpha + beta) - std::lgamma(alpha) - std::lgamma(beta) + (alpha - 1.0)*std::log(x) + (beta - 1.0) * std::log(1.0 - x);
247 return pow(x, alpha-1.0) * pow(1.0-x, beta-1.0) * std::tgamma(alpha + beta) / ( std::tgamma(alpha) * std::tgamma(beta) );
252 return -std::numeric_limits<float_t>::infinity();
268 template<
typename float_t>
269 float_t evalUnivBeta_unnorm(float_t x, float_t alpha, float_t beta,
bool log)
271 if( (x > 0.0) && (x < 1.0) && (alpha > 0.0) && (beta > 0.0) ){
273 return (alpha - 1.0)*std::log(x) + (beta - 1.0) * std::log(1.0 - x);
275 return pow(x, alpha-1.0) * pow(1.0-x, beta-1.0);
280 return -std::numeric_limits<float_t>::infinity();
296 template<
typename float_t>
297 float_t evalUnivInvGamma(float_t x, float_t alpha, float_t beta,
bool log)
299 if ( (x > 0.0) && (alpha > 0.0) && (beta > 0.0) ){
301 return alpha * std::log(beta) - std::lgamma(alpha) - (alpha + 1.0)*std::log(x) - beta/x;
303 return pow(x, -alpha-1.0) * exp(-beta/x) * pow(beta, alpha) / std::tgamma(alpha);
307 return -std::numeric_limits<float_t>::infinity();
323 template<
typename float_t>
324 float_t evalUnivInvGamma_unnorm(float_t x, float_t alpha, float_t beta,
bool log)
326 if ( (x > 0.0) && (alpha > 0.0) && (beta > 0.0) ){
328 return (-alpha - 1.0)*std::log(x) - beta/x;
330 return pow(x, -alpha-1.0) * exp(-beta/x);
334 return -std::numeric_limits<float_t>::infinity();
349 template<
typename float_t>
350 float_t evalUnivHalfNorm(float_t x, float_t sigmaSqd,
bool log)
352 if( (x >= 0.0) && (sigmaSqd > 0.0)){
354 return .5*log_two_over_pi<float_t> - .5*std::log(sigmaSqd) - .5*x*x / sigmaSqd;
356 return std::exp(-.5*x*x/sigmaSqd) * sqrt_two_over_pi<float_t> / std::sqrt(sigmaSqd);
360 return -std::numeric_limits<float_t>::infinity();
375 template<
typename float_t>
376 float_t evalUnivHalfNorm_unnorm(float_t x, float_t sigmaSqd,
bool log)
378 if( (x >= 0.0) && (sigmaSqd > 0.0)){
380 return -.5*x*x / sigmaSqd;
382 return std::exp(-.5*x*x/sigmaSqd);
386 return -std::numeric_limits<float_t>::infinity();
404 template<
typename float_t>
405 float_t evalUnivTruncNorm(float_t x, float_t mu, float_t sigma, float_t lower, float_t upper,
bool log)
407 if( (sigma > 0.0) && (lower <= x) & (x <= upper) ){
409 return evalUnivNorm(x, mu, sigma,
true)
410 - std::log( evalUnivStdNormCDF((upper-mu)/sigma) - evalUnivStdNormCDF((lower-mu)/sigma));
412 return evalUnivNorm(x,mu,sigma,
false)
413 / ( evalUnivStdNormCDF((upper-mu)/sigma) - evalUnivStdNormCDF((lower-mu)/sigma) );
418 return -std::numeric_limits<float_t>::infinity();
436 template<
typename float_t>
437 float_t evalUnivTruncNorm_unnorm(float_t x, float_t mu, float_t sigma, float_t lower, float_t upper,
bool log)
439 if( (sigma > 0.0) && (lower <= x) & (x <= upper) ){
441 return evalUnivNorm_unnorm(x, mu, sigma,
true);
443 return evalUnivNorm_unnorm(x, mu, sigma,
false);
447 return -std::numeric_limits<float_t>::infinity();
463 template<
typename float_t>
464 float_t evalLogitNormal(float_t x, float_t mu, float_t sigma,
bool log)
466 if( (x >= 0.0) && (x <= 1.0) && (sigma > 0.0)){
468 float_t exponent = -.5*(logit(x) - mu)*(logit(x) - mu) / (sigma*sigma);
470 return -std::log(sigma) - .5*log_two_pi<float_t> - std::log(x) - std::log(1.0-x) + exponent;
472 return inv_sqrt_2pi<float_t> * std::exp(exponent) / (x * (1.0-x) * sigma);
476 return -std::numeric_limits<float_t>::infinity();
492 template<
typename float_t>
493 float_t evalLogitNormal_unnorm(float_t x, float_t mu, float_t sigma,
bool log)
495 if( (x >= 0.0) && (x <= 1.0) && (sigma > 0.0)){
497 float_t exponent = -.5*(logit(x) - mu)*(logit(x) - mu) / (sigma*sigma);
499 return -std::log(x) - std::log(1.0-x) + exponent;
501 return std::exp(exponent) / x / (1.0-x);
505 return -std::numeric_limits<float_t>::infinity();
521 template<
typename float_t>
522 float_t evalTwiceFisherNormal(float_t x, float_t mu, float_t sigma,
bool log)
526 if( (x >= -1.0) && (x <= 1.0) && (sigma > 0.0)){
528 float_t exponent = std::log((1.0+x)/(1.0-x)) - mu;
529 exponent = -.5*exponent*exponent/sigma/sigma;
531 return -std::log(sigma) - .5*log_two_pi<float_t> + std::log(2.0) - std::log(1.0+x) - std::log(1.0-x) + exponent;
533 return inv_sqrt_2pi<float_t> * 2.0 * std::exp(exponent)/( (1.0-x)*(1.0+x)*sigma );
537 return -std::numeric_limits<float_t>::infinity();
553 template<
typename float_t>
554 float_t evalTwiceFisherNormal_unnorm(float_t x, float_t mu, float_t sigma,
bool log)
558 if( (x >= -1.0) && (x <= 1.0) && (sigma > 0.0)){
560 float_t exponent = std::log((1.0+x)/(1.0-x)) - mu;
561 exponent = -.5*exponent*exponent/sigma/sigma;
563 return -std::log(1.0+x) - std::log(1.0-x) + exponent;
565 return std::exp(exponent)/(1.0-x)/(1.0+x);
569 return -std::numeric_limits<float_t>::infinity();
585 template<
typename float_t>
586 float_t evalLogNormal(float_t x, float_t mu, float_t sigma,
bool log)
588 if( (x > 0.0) && (sigma > 0.0)){
590 float_t exponent = std::log(x)-mu;
591 exponent = -.5 * exponent * exponent / sigma / sigma;
593 return -std::log(x) - std::log(sigma) - .5*log_two_pi<float_t> + exponent;
595 return inv_sqrt_2pi<float_t> * std::exp(exponent)/(sigma*x);
599 return -std::numeric_limits<float_t>::infinity();
615 template<
typename float_t>
616 float_t evalLogNormal_unnorm(float_t x, float_t mu, float_t sigma,
bool log)
618 if( (x > 0.0) && (sigma > 0.0)){
620 float_t exponent = std::log(x)-mu;
621 exponent = -.5 * exponent * exponent / sigma / sigma;
623 return -std::log(x) + exponent;
625 return std::exp(exponent)/x;
629 return -std::numeric_limits<float_t>::infinity();
645 template<
typename float_t>
646 float_t evalUniform(float_t x, float_t lower, float_t upper,
bool log)
649 if( (x > lower) && (x <= upper)){
651 float_t width = upper-lower;
653 return -std::log(width);
659 return -std::numeric_limits<float_t>::infinity();
676 template<
typename float_t>
677 float_t evalUniform_unnorm(float_t x, float_t lower, float_t upper,
bool log)
680 if( (x > lower) && (x <= upper)){
689 return -std::numeric_limits<float_t>::infinity();
707 template<
typename float_t>
708 float_t evalScaledT(float_t x, float_t mu, float_t sigma, float_t dof,
bool log)
711 if( (sigma > 0.0) && (dof > 0.0) ){
713 float_t zscore = (x-mu)/sigma;
714 float_t lmt = - .5*(dof+1.0)*std::log(1.0 + (zscore*zscore)/dof);
716 return std::lgamma(.5*(dof+1.0)) - std::log(sigma) - .5*std::log(dof) - .5*log_pi<float_t> - std::lgamma(.5*dof) + lmt;
718 return std::exp(std::lgamma(.5*(dof+1.0)) - std::log(sigma) - .5*std::log(dof) - .5*log_pi<float_t> - std::lgamma(.5*dof) + lmt);
721 return -std::numeric_limits<float_t>::infinity();
737 template<
typename float_t>
738 float_t evalScaledT_unnorm(float_t x, float_t mu, float_t sigma, float_t dof,
bool log)
740 if( (sigma > 0.0) && (dof > 0.0) ){
742 float_t zscore = (x-mu)/sigma;
743 float_t lmt = - .5*(dof+1.0)*std::log(1.0 + (zscore*zscore)/dof);
747 return std::exp(lmt);
750 return -std::numeric_limits<float_t>::infinity();
764 template<
typename int_t,
typename float_t>
765 float_t evalDiscreteUnif(int_t x,
int k,
bool log)
767 if( (1 <= x) && (x <= k) ){
769 return -std::log(
static_cast<float_t
>(k));
771 return 1.0 /
static_cast<float_t
>(k);
775 return -std::numeric_limits<float_t>::infinity();
790 template<
typename int_t,
typename float_t>
791 float_t evalDiscreteUnif_unnorm(int_t x, int_t k,
bool log)
793 if( (1 <= x) && (x <= k) ){
801 return -std::numeric_limits<float_t>::infinity();
815 template<
typename int_t,
typename float_t>
816 float_t evalBernoulli(int_t x, float_t p,
bool log)
818 if( ((x == 0) || (x == 1)) && ( (0.0 <= p) && (p <= 1.0) ) ){
820 return (x==1) ? std::log(p) : std::log(1.0-p);
822 return (x==1) ? p : (1.0-p);
826 return -std::numeric_limits<float_t>::infinity();
842 template<
typename int_t,
typename float_t>
843 float_t evalSkellam(int_t x, float_t mu1, float_t mu2,
bool log)
845 if( (mu1 > 0) && (mu2 > 0) ){
851 using boost::math::tools::evaluate_polynomial;
852 float_t z = 2*std::sqrt(mu1*mu2);
853 float_t log_I(-std::numeric_limits<float_t>::infinity());
872 static const float_t P[]
873 = {1.00000000000000000e+00, 2.49999999999999909e-01,
874 2.77777777777782257e-02, 1.73611111111023792e-03,
875 6.94444444453352521e-05, 1.92901234513219920e-06,
876 3.93675991102510739e-08, 6.15118672704439289e-10,
877 7.59407002058973446e-12, 7.59389793369836367e-14,
878 6.27767773636292611e-16, 4.34709704153272287e-18,
879 2.63417742690109154e-20, 1.13943037744822825e-22,
880 9.07926920085624812e-25};
881 log_I = log_sum_exp<float_t>(0.0, 2.0*std::log(z) - std::log(4.0) + std::log(evaluate_polynomial(P, mu1*mu2)));
887 static const float_t P[]
888 = {3.98942280401425088e-01, 4.98677850604961985e-02,
889 2.80506233928312623e-02, 2.92211225166047873e-02,
890 4.44207299493659561e-02, 1.30970574605856719e-01,
891 -3.35052280231727022e+00, 2.33025711583514727e+02,
892 -1.13366350697172355e+04, 4.24057674317867331e+05,
893 -1.23157028595698731e+07, 2.80231938155267516e+08,
894 -5.01883999713777929e+09, 7.08029243015109113e+10,
895 -7.84261082124811106e+11, 6.76825737854096565e+12,
896 -4.49034849696138065e+13, 2.24155239966958995e+14,
897 -8.13426467865659318e+14, 2.02391097391687777e+15,
898 -3.08675715295370878e+15, 2.17587543863819074e+15};
900 log_I = z + std::log(evaluate_polynomial(P, 1.0/z)) - 0.5*std::log(z);
906 static const float_t P[] = {3.98942280401432905e-01, 4.98677850491434560e-02,
907 2.80506308916506102e-02, 2.92179096853915176e-02,
908 4.53371208762579442e-02};
909 log_I = z + std::log(evaluate_polynomial(P, 1.0/z)) - 0.5*std::log(z);
913 }
else if(std::abs(x)==1){
922 static const float_t P[]
923 = {8.333333333333333803e-02, 6.944444444444341983e-03,
924 3.472222222225921045e-04, 1.157407407354987232e-05,
925 2.755731926254790268e-07, 4.920949692800671435e-09,
926 6.834657311305621830e-11, 7.593969849687574339e-13,
927 6.904822652741917551e-15, 5.220157095351373194e-17,
928 3.410720494727771276e-19, 1.625212890947171108e-21,
929 1.332898928162290861e-23};
932 float_t Q[3] = {1, 0.5, evaluate_polynomial(P, a)};
933 log_I = std::log(z) + std::log(evaluate_polynomial(Q, a)) - std::log(2.0);
939 static const double P[]
940 = {3.989422804014406054e-01, -1.496033551613111533e-01,
941 -4.675104253598537322e-02, -4.090895951581637791e-02,
942 -5.719036414430205390e-02, -1.528189554374492735e-01,
943 3.458284470977172076e+00, -2.426181371595021021e+02,
944 1.178785865993440669e+04, -4.404655582443487334e+05,
945 1.277677779341446497e+07, -2.903390398236656519e+08,
946 5.192386898222206474e+09, -7.313784438967834057e+10,
947 8.087824484994859552e+11, -6.967602516005787001e+12,
948 4.614040809616582764e+13, -2.298849639457172489e+14,
949 8.325554073334618015e+14, -2.067285045778906105e+15,
950 3.146401654361325073e+15, -2.213318202179221945e+15};
951 log_I = z + std::log(evaluate_polynomial(P, 1.0/z)) - 0.5*std::log(z);
956 static const double P[]
957 = {3.989422804014314820e-01, -1.496033551467584157e-01,
958 -4.675105322571775911e-02, -4.090421597376992892e-02,
959 -5.843630344778927582e-02};
960 log_I = z + std::log(evaluate_polynomial(P, 1.0/z)) - 0.5*std::log(z);
966 float_t lim = std::pow((x*x + 2.5) / (2 * z), 3) / 24;
968 if (lim < std::numeric_limits<float_t>::epsilon()* 10) {
972 float_t num = mu - 1;
981 log_I = z - .5*std::log(z) - .5*log_two_pi<float_t> + std::log(s);
987 int_t absx = (x < 0) ? -x : x;
988 float_t lm1m2 = std::log(mu1) + std::log(mu2);
989 float_t first = .5*absx*lm1m2;
990 float_t second = 0.0;
991 float_t third = std::lgamma(absx+1);
992 log_I = first - second - third;
996 float_t last_iter_log_I;
999 second += std::log(m);
1000 third += std::log(m+absx);
1001 last_iter_log_I = log_I;
1002 log_I = log_sum_exp<float_t>(log_I, first - second - third);
1005 std::cout <<
"first, second, third, mu1, mu2: " << first <<
", " << second <<
", " << third <<
", " << mu1 <<
", " << mu2 <<
"\n";
1006 }
while(log_I != last_iter_log_I);
1011 float_t log_mass = -mu1 - mu2 + .5*x*(std::log(mu1) - std::log(mu2)) + log_I;
1019 return std::exp(log_mass);
1023 return -std::numeric_limits<float_t>::infinity();
1047 template<std::
size_t dim,
typename float_t>
1048 float_t evalMultivNorm(
const Eigen::Matrix<float_t,dim,1> &x,
1049 const Eigen::Matrix<float_t,dim,1> &meanVec,
1050 const Eigen::Matrix<float_t,dim,dim> &covMat,
1053 using Mat = Eigen::Matrix<float_t,dim,dim>;
1054 Eigen::LLT<Mat> lltM(covMat);
1055 if(lltM.info() == Eigen::NumericalIssue)
return log ? -std::numeric_limits<float_t>::infinity() : 0.0;
1056 Mat L = lltM.matrixL();
1057 float_t quadform = (lltM.solve(x-meanVec)).squaredNorm();
1060 for(
size_t i = 0; i < dim; ++i){
1061 ld += std::log(L(i,i));
1065 float_t logDens = -.5*log_two_pi<float_t> * dim - .5*ld - .5*quadform;
1070 return std::exp(logDens);
1087 template<std::
size_t dim,
typename float_t>
1088 float_t evalMultivT(
const Eigen::Matrix<float_t,dim,1> &x,
1089 const Eigen::Matrix<float_t,dim,1> &locVec,
1090 const Eigen::Matrix<float_t,dim,dim> &shapeMat,
1094 if(dof <= 0.0)
return log ? -std::numeric_limits<float_t>::infinity() : 0.0;
1095 using Mat = Eigen::Matrix<float_t,dim,dim>;
1096 Eigen::LLT<Mat> lltM(shapeMat);
1097 if(lltM.info() == Eigen::NumericalIssue)
return log ? -std::numeric_limits<float_t>::infinity() : 0.0;
1098 Mat L = lltM.matrixL();
1099 float_t quadform = (lltM.solve(x-locVec)).squaredNorm();
1102 for(
size_t i = 0; i < dim; ++i){
1103 ld += std::log(L(i,i));
1107 float_t logDens = std::lgamma(.5*(dof+dim)) - .5*dim*std::log(dof) - .5*dim*log_pi<float_t>
1108 - std::lgamma(.5*dof) -.5*ld - .5*(dof+dim)*std::log( 1.0 + quadform/dof );
1113 return std::exp(logDens);
1129 template<std::
size_t bigd, std::
size_t smalld,
typename float_t>
1130 float_t evalMultivNormWBDA(
const Eigen::Matrix<float_t,bigd,1> &x,
1131 const Eigen::Matrix<float_t,bigd,1> &meanVec,
1132 const Eigen::Matrix<float_t,bigd,1> &A,
1133 const Eigen::Matrix<float_t,bigd,smalld> &U,
1134 const Eigen::Matrix<float_t,smalld,smalld> &C,
1138 using bigmat = Eigen::Matrix<float_t,bigd,bigd>;
1139 using smallmat = Eigen::Matrix<float_t,smalld,smalld>;
1141 bigmat Ainv = A.asDiagonal().inverse();
1142 smallmat Cinv = C.inverse();
1143 smallmat I = Cinv + U.transpose()*Ainv*U;
1144 bigmat SigInv = Ainv - Ainv * U * I.ldlt().solve(U.transpose() * Ainv);
1145 Eigen::LLT<bigmat> lltSigInv(SigInv);
1146 bigmat L = lltSigInv.matrixL();
1147 float_t quadform = (L * (x-meanVec)).squaredNorm();
1151 float_t halfld (0.0);
1153 for(
size_t i = 0; i < bigd; ++i){
1154 halfld += std::log(L(i,i));
1157 return -.5*log_two_pi<float_t> * bigd + halfld - .5*quadform;
1161 float_t normConst = std::pow(inv_sqrt_2pi<float_t>, bigd) * L.determinant();
1162 return normConst * std::exp(-.5* quadform);
1180 template<std::
size_t dim,
typename float_t>
1181 float_t evalWishart(
const Eigen::Matrix<float_t,dim,dim> &X,
1182 const Eigen::Matrix<float_t,dim,dim> &Vinv,
1183 const unsigned int &n,
1186 using Mat = Eigen::Matrix<float_t,dim,dim>;
1187 Eigen::LLT<Mat> lltX(X);
1188 Eigen::LLT<Mat> lltVinv(Vinv);
1189 if((n < dim) | (lltX.info() == Eigen::NumericalIssue) | (lltVinv.info() == Eigen::NumericalIssue))
return log ? -std::numeric_limits<float_t>::infinity() : 0.0;
1193 float_t ldvinv (0.0);
1194 Mat Lx = lltX.matrixL();
1195 Mat Lvi = lltVinv.matrixL();
1196 float_t logGammaNOver2 = .25*dim*(dim-1)*log_pi<float_t>;
1199 for(
size_t i = 0; i < dim; ++i){
1200 ldx += std::log(Lx(i,i));
1201 ldvinv += std::log(Lvi(i,i));
1202 logGammaNOver2 += std::lgamma(.5*(n-i));
1207 float_t logDens = .5*(n - dim -1)*ldx - .5*(Vinv*X).trace() - .5*n*dim*std::log(2.0) + .5*n*ldvinv - logGammaNOver2;
1212 return std::exp(logDens);
1229 template<std::
size_t dim,
typename float_t>
1230 float_t evalInvWishart(
const Eigen::Matrix<float_t,dim,dim> &X,
1231 const Eigen::Matrix<float_t,dim,dim> &Psi,
1232 const unsigned int &nu,
1235 using Mat = Eigen::Matrix<float_t,dim,dim>;
1236 Eigen::LLT<Mat> lltX(X);
1237 Eigen::LLT<Mat> lltPsi(Psi);
1238 if((nu < dim) | (lltX.info() == Eigen::NumericalIssue) | (lltPsi.info() == Eigen::NumericalIssue))
return log ? -std::numeric_limits<float_t>::infinity() : 0.0;
1242 float_t ldPsi (0.0);
1243 Mat Lx = lltX.matrixL();
1244 Mat Lpsi = lltPsi.matrixL();
1245 float_t logGammaNuOver2 = .25*dim*(dim-1)*log_pi<float_t>;
1248 for(
size_t i = 0; i < dim; ++i){
1249 ldx += std::log(Lx(i,i));
1250 ldPsi += std::log(Lpsi(i,i));
1251 logGammaNuOver2 += std::lgamma(.5*(nu-i));
1258 float_t logDens = .5*nu*ldPsi - .5*(nu + dim + 1.0)*ldx - .5*(Psi*X.inverse() ).trace() - .5*nu*dim*std::log(2.0) - logGammaNuOver2;
1264 return std::exp(logDens);