#include "scalehmm.h" // ============================================================ // Hidden Markov Model implemented with scaling strategy // ============================================================ // Public ===================================================== // Constructor and Destructor --------------------------------- ScaleHMM::ScaleHMM(int T, int N, int verbosity) { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; //FILE_LOG(logDEBUG2) << "Initializing univariate ScaleHMM"; this->xvariate = UNIVARIATE; this->verbosity = verbosity; this->T = T; this->N = N; this->A = CallocDoubleMatrix(N, N); this->scalefactoralpha = (double*) Calloc(T, double); this->scalealpha = CallocDoubleMatrix(T, N); this->scalebeta = CallocDoubleMatrix(T, N); this->densities = CallocDoubleMatrix(N, T); this->proba = (double*) Calloc(N, double); this->gamma = CallocDoubleMatrix(N, T); this->states_prev = (bool*) Calloc(T, bool); this->sumgamma = (double*) Calloc(N, double); this->sumxi = CallocDoubleMatrix(N, N); this->logP = -INFINITY; this->dlogP = INFINITY; this->sumdiff_state_last = 0; // this->num_nonzero_A_into_state = (int*) Calloc(N, int); // this->index_nonzero_A_into_state = allocIntMatrix(N, N); // this->transition_cutoff = 1e-10; // this->sparsity_cutoff = 0.0; } ScaleHMM::ScaleHMM(int T, int N, int Nmod, int verbosity) { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; //FILE_LOG(logDEBUG2) << "Initializing multivariate ScaleHMM"; this->xvariate = MULTIVARIATE; this->verbosity = verbosity; this->T = T; this->N = N; this->A = CallocDoubleMatrix(N, N); this->scalefactoralpha = (double*) Calloc(T, double); this->scalealpha = CallocDoubleMatrix(T, N); this->scalebeta = CallocDoubleMatrix(T, N); this->densities = CallocDoubleMatrix(N, T); // this->tdensities = CallocDoubleMatrix(T, N); this->proba = (double*) Calloc(N, double); this->gamma = CallocDoubleMatrix(N, T); this->sumgamma = (double*) Calloc(N, double); this->sumxi = CallocDoubleMatrix(N, N); this->logP = -INFINITY; this->dlogP = INFINITY; // this->sumdiff_state_last = 0; this->Nmod = Nmod; // this->num_nonzero_A_into_state = (int*) Calloc(N, int); // this->index_nonzero_A_into_state = allocIntMatrix(N, N); // this->transition_cutoff = 1e-10; // this->sparsity_cutoff = 0.7; } ScaleHMM::~ScaleHMM() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; FreeDoubleMatrix(this->A, this->N); Free(this->scalefactoralpha); FreeDoubleMatrix(this->scalealpha, this->T); FreeDoubleMatrix(this->scalebeta, this->T); FreeDoubleMatrix(this->densities, this->N); // if (this->xvariate==MULTIVARIATE) // { // FreeDoubleMatrix(this->tdensities, this->T); // } FreeDoubleMatrix(this->gamma, this->N); FreeDoubleMatrix(this->sumxi, this->N); Free(this->proba); Free(this->sumgamma); for (int iN=0; iN<this->N; iN++) { //FILE_LOG(logDEBUG1) << "Deleting density functions"; delete this->densityFunctions[iN]; } // Free(this->num_nonzero_A_into_state); // FreeIntMatrix(this->index_nonzero_A_into_state, this->N); } // Methods ---------------------------------------------------- void ScaleHMM::initialize_transition_probs(double* initial_A, bool use_initial_params) { if (use_initial_params) { for (int iN=0; iN<this->N; iN++) { for (int jN=0; jN<this->N; jN++) { // convert from vector to matrix representation this->A[jN][iN] = initial_A[iN*this->N + jN]; } } } else { double self = 0.9; // self = 1.0 / this->N; // set to uniform double other = (1.0 - self) / (this->N - 1.0); for (int iN=0; iN<this->N; iN++) { for (int jN=0; jN<this->N; jN++) { if (iN == jN) this->A[iN][jN] = self; else this->A[iN][jN] = other; // Save value to initial A initial_A[jN*this->N + iN] = this->A[iN][jN]; } } } // // Initialize sparsity exploit such that no sparsity exploit is done in first iteration // for (int iN=0; iN<this->N; iN++) // { // this->num_nonzero_A_into_state[iN] = this->N; // } } void ScaleHMM::initialize_proba(double* initial_proba, bool use_initial_params) { if (use_initial_params) { for (int iN=0; iN<this->N; iN++) { this->proba[iN] = initial_proba[iN]; } } else { for (int iN=0; iN<this->N; iN++) { this->proba[iN] = (double)1/this->N; // Save value to initial proba initial_proba[iN] = this->proba[iN]; } } } void ScaleHMM::baumWelch(int* maxiter, int* maxtime, double* eps) { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; double logPold = -INFINITY; double logPnew; // Parallelization settings // #ifdef _OPENMP // omp_set_nested(1); // #endif // measuring the time this->baumWelchStartTime_sec = time(NULL); if (this->xvariate == UNIVARIATE) { //FILE_LOG(logINFO) << ""; // Rprintf("\n"); //FILE_LOG(logINFO) << "INITIAL PARAMETERS"; // Rprintf("INITIAL PARAMETERS\n"); this->print_uni_params(); this->print_uni_iteration(0); } else if (this->xvariate == MULTIVARIATE) { this->print_multi_iteration(0); //FILE_LOG(logDEBUG2) << "Calling calc_densities() from baumWelch()"; //FILE_LOG(logINFO) << "Precomputing densities ..."; if (this->verbosity>=1) Rprintf("HMM: Precomputing densities ...\n"); try { this->calc_densities(); } catch(...) { throw; } this->print_multi_iteration(0); // Print densities // int bs = 100; // char buffer [100]; // int cx; // for (int t=0; t<this->T; t++) // { // cx = 0; // cx += snprintf(buffer+cx, bs-cx, "t=%d\t", t); // for (int iN=0; iN<this->N; iN++) // { // cx += snprintf(buffer+cx, bs-cx, "%.6f\t", this->densities[iN][t]); // } // //FILE_LOG(logDEBUG) << buffer; // } } R_CheckUserInterrupt(); // Do the Baum-Welch this->baumWelchTime_real = difftime(time(NULL),this->baumWelchStartTime_sec); int iteration = 0; while (((this->baumWelchTime_real < *maxtime) or (*maxtime < 0)) and ((iteration < *maxiter) or (*maxiter < 0))) { iteration++; if (this->xvariate == UNIVARIATE) { //FILE_LOG(logDEBUG1) << "Calling calc_densities() from baumWelch()"; try { this->calc_densities(); } catch(...) { throw; } R_CheckUserInterrupt(); } //FILE_LOG(logDEBUG1) << "Calling forward() from baumWelch()"; try { this->forward(); } catch(...) { throw; } R_CheckUserInterrupt(); //FILE_LOG(logDEBUG1) << "Calling backward() from baumWelch()"; try { this->backward(); } catch(...) { throw; } R_CheckUserInterrupt(); //FILE_LOG(logDEBUG1) << "Calling calc_loglikelihood() from baumWelch()"; this->calc_loglikelihood(); logPnew = this->logP; if(std::isnan(logPnew)) { //FILE_LOG(logERROR) << "logPnew = " << logPnew; throw nan_detected; } this->dlogP = logPnew - logPold; //FILE_LOG(logDEBUG1) << "Calling calc_sumxi() from baumWelch()"; this->calc_sumxi(); R_CheckUserInterrupt(); //FILE_LOG(logDEBUG1) << "Calling calc_gamma() from baumWelch()"; this->calc_gamma(); R_CheckUserInterrupt(); if (this->xvariate == UNIVARIATE) { // clock_t clocktime = clock(), dtime; // difference in state assignments //FILE_LOG(logDEBUG1) << "Calculating differences in state assignments in baumWelch()"; int state_last = 0; int state_last_old = 0; int statesum = 0; for (int t=0; t<this->T; t++) { state_last_old = this->states_prev[t]; if (this->gamma[this->N-1][t]>0.5) { state_last = 1; } this->states_prev[t] = state_last; statesum += std::abs(state_last-state_last_old); state_last = 0; state_last_old = 0; } this->sumdiff_state_last = statesum; } R_CheckUserInterrupt(); // Print information about current iteration if (this->xvariate == UNIVARIATE) { this->print_uni_iteration(iteration); } else if (this->xvariate == MULTIVARIATE) { this->print_multi_iteration(iteration); } // Check convergence if(this->dlogP < *eps) //it has converged { //FILE_LOG(logINFO) << "Convergence reached!\n"; if (this->verbosity>=1) Rprintf("HMM: Convergence reached!\n"); if (this->xvariate == UNIVARIATE) this->check_for_state_swap(); break; } else {// not converged this->baumWelchTime_real = difftime(time(NULL),this->baumWelchStartTime_sec); if (iteration == *maxiter) { //FILE_LOG(logINFO) << "Maximum number of iterations reached!"; if (this->verbosity>=1) Rprintf("HMM: Maximum number of iterations reached!\n"); if (this->xvariate == UNIVARIATE) this->check_for_state_swap(); break; } else if ((this->baumWelchTime_real >= *maxtime) and (*maxtime >= 0)) { //FILE_LOG(logINFO) << "Exceeded maximum time!"; if (this->verbosity>=1) Rprintf("HMM: Exceeded maximum time!\n"); if (this->xvariate == UNIVARIATE) this->check_for_state_swap(); break; } logPold = logPnew; } // // Re-Initialize the sparsity exploit variables // int nonzero_counter [this->N]; // for (int iN=0; iN<this->N; iN++) // { // this->num_nonzero_A_into_state[iN] = 0; // nonzero_counter[iN] = 0; // for (int jN=0; jN<this->N; jN++) // { // this->index_nonzero_A_into_state[iN][jN] = 0; // } // } // Updating initial probabilities proba and transition matrix A for (int iN=0; iN<this->N; iN++) { this->proba[iN] = this->gamma[iN][0]; //FILE_LOG(logDEBUG4) << "sumgamma["<<iN<<"] = " << sumgamma[iN]; this->sumgamma[iN] = 0; for (int jN=0; jN<this->N; jN++) { this->sumgamma[iN] += this->sumxi[iN][jN]; } if (this->sumgamma[iN] == 0) { //FILE_LOG(logINFO) << "Not reestimating A["<<iN<<"][x] because sumgamma["<<iN<<"] = 0"; // Rprintf("Not reestimating A[%d][x] because sumgamma[%d] = 0\n", iN, iN); } else { for (int jN=0; jN<this->N; jN++) { //FILE_LOG(logDEBUG4) << "sumxi["<<iN<<"]["<<jN<<"] = " << sumxi[iN][jN]; this->A[iN][jN] = this->sumxi[iN][jN] / this->sumgamma[iN]; // // This could give performance increase, but risks numerical instabilities // if (this->logA[iN][jN] < log(1.0/(double)(this->T*10))) // { // this->logA[iN][jN] = -INFINITY; // this->A[iN][jN] = 0; // } // // Save the indices of non-zero transitions for sparsity exploit. We also get numerical instabilities here. // if (this->A[iN][jN] > this->transition_cutoff) // { // this->num_nonzero_A_into_state[jN]++; // this->index_nonzero_A_into_state[jN][nonzero_counter[jN]] = iN; // nonzero_counter[jN]++; // } if (std::isnan(this->A[iN][jN])) { //FILE_LOG(logERROR) << "updating transition probabilities"; //FILE_LOG(logERROR) << "A["<<iN<<"]["<<jN<<"] = " << A[iN][jN]; //FILE_LOG(logERROR) << "sumxi["<<iN<<"]["<<jN<<"] = " << sumxi[iN][jN]; //FILE_LOG(logERROR) << "sumgamma["<<iN<<"] = " << sumgamma[iN]; throw nan_detected; } } } } // // Check if sparsity exploit will be used in the next iteration // for (int iN=0; iN<this->N; iN++) // { // if (this->num_nonzero_A_into_state[iN] < this->sparsity_cutoff*this->N) // { // //FILE_LOG(logINFO) << "Will use sparsity exploit for state " << iN; // if (this->num_nonzero_A_into_state[iN] == 0) // { // //FILE_LOG(logINFO) << "No non-zero elements into state " << iN; // } // } // } if (this->xvariate == UNIVARIATE) { // Update the parameters of the distribution // clock_t clocktime = clock(), dtime; #pragma omp parallel for for (int iN=0; iN<this->N; iN++) { this->densityFunctions[iN]->update(this->gamma[iN]); } // dtime = clock() - clocktime; // //FILE_LOG(logDEBUG) << "updating distributions: " << dtime << " clicks"; R_CheckUserInterrupt(); } } /* main loop end */ //Print the last results if (this->xvariate == UNIVARIATE) { //FILE_LOG(logINFO) << ""; // Rprintf("\n"); //FILE_LOG(logINFO) << "FINAL ESTIMATION RESULTS"; // Rprintf("FINAL ESTIMATION RESULTS\n"); this->print_uni_params(); } // Return values *maxiter = iteration; *eps = this->dlogP; this->baumWelchTime_real = difftime(time(NULL),this->baumWelchStartTime_sec); *maxtime = this->baumWelchTime_real; } void ScaleHMM::check_for_state_swap() { // only check for state swap if we have 3 states if (this->N == 3) { std::vector<double> weights(this->N); std::vector<double> maxdens(this->N); std::vector<double> cutoff_logdens(this->N); std::vector<double> logdens_at_0(this->N); // calculate weights, maxdens and logdens at cutoff weights = this->calc_weights(); maxdens[0] = weights[0]; maxdens[1] = weights[1] * Max(this->densities[1], this->T); maxdens[2] = weights[2] * Max(this->densities[2], this->T); cutoff_logdens[0] = log(weights[0]) + this->densityFunctions[0]->getLogDensityAt(this->cutoff); cutoff_logdens[1] = log(weights[1]) + this->densityFunctions[1]->getLogDensityAt(this->cutoff); cutoff_logdens[2] = log(weights[2]) + this->densityFunctions[2]->getLogDensityAt(this->cutoff); logdens_at_0[0] = log(weights[0]) + this->densityFunctions[0]->getLogDensityAt(0); logdens_at_0[1] = log(weights[1]) + this->densityFunctions[1]->getLogDensityAt(0); logdens_at_0[2] = log(weights[2]) + this->densityFunctions[2]->getLogDensityAt(0); // get highest value where both distributions are non-zero double logdens_1, logdens_2; bool doswap = false; for (int i1=this->cutoff; i1>=0; i1--) { logdens_1 = log(weights[1]) + this->densityFunctions[1]->getLogDensityAt(i1); logdens_2 = log(weights[2]) + this->densityFunctions[2]->getLogDensityAt(i1); // Rprintf("i1 = %d\n",i1); // Rprintf("logdens_1 = %g\n",logdens_1); // Rprintf("logdens_2 = %g\n",logdens_2); if (logdens_1 != logdens_2) { if (logdens_1 > logdens_2) { doswap = true; } break; } } //FILE_LOG(logINFO) << "mean(0) = "<<this->densityFunctions[0]->get_mean() << ", mean(1) = "<<this->densityFunctions[1]->get_mean() << ", mean(2) = "<<this->densityFunctions[2]->get_mean(); // Rprintf("mean(0) = %g, mean(1) = %g, mean(2) = %g\n", this->densityFunctions[0]->get_mean(), this->densityFunctions[1]->get_mean(), this->densityFunctions[2]->get_mean()); //FILE_LOG(logINFO) << "weight(0) = "<<weights[0] << ", weight(1) = "<<weights[1] << ", weight(2) = "<<weights[2]; // Rprintf("weight(0) = %g, weight(1) = %g, weight(2) = %g\n", weights[0], weights[1], weights[2]); //FILE_LOG(logINFO) << "maxdens(0) = "<<maxdens[0] << ", maxdens(1) = "<<maxdens[1] << ", maxdens(2) = "<<maxdens[2]; // Rprintf("maxdens(0) = %g, maxdens(1) = %g, maxdens(2) = %g\n", maxdens[0], maxdens[1], maxdens[2]); //FILE_LOG(logINFO) << "logdensity at x = "<<this->cutoff <<": logdens(0) = "<<cutoff_logdens[0] << ", logdens(1) = "<<cutoff_logdens[1] << ", logdens(2) = "<<cutoff_logdens[2]; // Rprintf("logdensity at x = %d: logdens(0) = %g, logdens(1) = %g, logdens(2) = %g\n", this->cutoff, cutoff_logdens[0], cutoff_logdens[1], cutoff_logdens[2]); // Different methods for state swapping detection // 1) Compare means. Does not work for all datasets. // if (this->densityFunctions[1]->get_mean() > this->densityFunctions[2]->get_mean()) //states 1 and 2 need to be exchanged // 2) Compare density values at upper cutoff. Works for most datasets. // if (cutoff_logdens[1] > cutoff_logdens[2]) //states 1 and 2 need to be exchanged // 3) Compare max(density values). Does not work for all datasets. // if (maxdens[1] < maxdens[2]) // 4) Compare density values at 0. Does not work for all datasets. // if (logdens_at_0[1] < logdens_at_0[2]) // 5) Compare logdens at highest value where both distributions are non-zero. if (doswap) { //FILE_LOG(logINFO) << "...swapping states"; // Rprintf("...swapping states\n"); NegativeBinomial *tempDens = new NegativeBinomial(); tempDens->copy(this->densityFunctions[2]); // tempDens is densifunc[2] this->densityFunctions[2]->copy(this->densityFunctions[1]); this->densityFunctions[1]->copy(tempDens); delete tempDens; // swap proba double temp; temp=this->proba[1]; this->proba[1]=this->proba[2]; this->proba[2]=temp; // swap transition matrix temp = this->A[0][2]; this->A[0][2] = this->A[0][1]; A[0][1] = temp; temp = this->A[1][0]; this->A[1][0] = this->A[2][0]; A[2][0] = temp; temp = this->A[1][1]; this->A[1][1] = this->A[2][2]; A[2][2] = temp; temp = this->A[1][2]; this->A[1][2] = this->A[2][1]; A[2][1] = temp; // swap dens double * tempp; tempp = this->densities[1]; this->densities[1] = this->densities[2]; this->densities[2] = tempp; // recalculate other baum-welch stuff //FILE_LOG(logDEBUG1) << "Calling forward() from check_for_state_swap()"; try { this->forward(); } catch(...) { throw; } R_CheckUserInterrupt(); //FILE_LOG(logDEBUG1) << "Calling backward() from check_for_state_swap()"; try { this->backward(); } catch(...) { throw; } R_CheckUserInterrupt(); //FILE_LOG(logDEBUG1) << "Calling calc_sumxi() from check_for_state_swap()"; this->calc_sumxi(); R_CheckUserInterrupt(); //FILE_LOG(logDEBUG1) << "Calling calc_gamma() from check_for_state_swap()"; this->calc_gamma(); R_CheckUserInterrupt(); // recalculate weight, maxdens and logdens at cutoff weights = this->calc_weights(); maxdens[0] = weights[0]; maxdens[1] = weights[1] * Max(this->densities[1], this->T); maxdens[2] = weights[2] * Max(this->densities[2], this->T); cutoff_logdens[0] = log(weights[0]) + this->densityFunctions[0]->getLogDensityAt(this->cutoff); cutoff_logdens[1] = log(weights[1]) + this->densityFunctions[1]->getLogDensityAt(this->cutoff); cutoff_logdens[2] = log(weights[2]) + this->densityFunctions[2]->getLogDensityAt(this->cutoff); logdens_at_0[0] = log(weights[0]) + this->densityFunctions[0]->getLogDensityAt(0); logdens_at_0[1] = log(weights[1]) + this->densityFunctions[1]->getLogDensityAt(0); logdens_at_0[2] = log(weights[2]) + this->densityFunctions[2]->getLogDensityAt(0); //FILE_LOG(logINFO) << "mean(0) = "<<this->densityFunctions[0]->get_mean() << ", mean(1) = "<<this->densityFunctions[1]->get_mean() << ", mean(2) = "<<this->densityFunctions[2]->get_mean(); // Rprintf("mean(0) = %g, mean(1) = %g, mean(2) = %g\n", this->densityFunctions[0]->get_mean(), this->densityFunctions[1]->get_mean(), this->densityFunctions[2]->get_mean()); //FILE_LOG(logINFO) << "weight(0) = "<<weights[0] << ", weight(1) = "<<weights[1] << ", weight(2) = "<<weights[2]; // Rprintf("weight(0) = %g, weight(1) = %g, weight(2) = %g\n", weights[0], weights[1], weights[2]); //FILE_LOG(logINFO) << "maxdens(0) = "<<maxdens[0] << ", maxdens(1) = "<<maxdens[1] << ", maxdens(2) = "<<maxdens[2]; // Rprintf("maxdens(0) = %g, maxdens(1) = %g, maxdens(2) = %g\n", maxdens[0], maxdens[1], maxdens[2]); //FILE_LOG(logINFO) << "logdensity at x = "<<this->cutoff <<": logdens(0) = "<<cutoff_logdens[0] << ", logdens(1) = "<<cutoff_logdens[1] << ", logdens(2) = "<<cutoff_logdens[2]; // Rprintf("logdensity at x = %d: logdens(0) = %g, logdens(1) = %g, logdens(2) = %g\n", this->cutoff, cutoff_logdens[0], cutoff_logdens[1], cutoff_logdens[2]); } } } std::vector<double> ScaleHMM::calc_weights() { std::vector<double> weights(this->N); #pragma omp parallel for for (int iN=0; iN<this->N; iN++) { // Do not use weights[iN] = ( this->sumgamma[iN] + this->gamma[iN][T-1] ) / this->T; here, since states are swapped and gammas not double sum_over_gammas_per_state = 0; for (int t=0; t<this->T; t++) { sum_over_gammas_per_state += this->gamma[iN][t]; } weights[iN] = sum_over_gammas_per_state / this->T; } return(weights); } void ScaleHMM::calc_weights(double* weights) { #pragma omp parallel for for (int iN=0; iN<this->N; iN++) { // Do not use weights[iN] = ( this->sumgamma[iN] + this->gamma[iN][T-1] ) / this->T; here, since states are swapped and gammas not double sum_over_gammas_per_state = 0; for (int t=0; t<this->T; t++) { sum_over_gammas_per_state += this->gamma[iN][t]; } weights[iN] = sum_over_gammas_per_state / this->T; } } // Getters and Setters ---------------------------------------- int ScaleHMM::get_N() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; return(this->N); } int ScaleHMM::get_T() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; return(this->T); } void ScaleHMM::get_posteriors(double** post) { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; for (int iN=0; iN<this->N; iN++) { for (int t=0; t<this->T; t++) { post[iN][t] = this->gamma[iN][t]; } } } double ScaleHMM::get_posterior(int iN, int t) { //FILE_LOG(logDEBUG4) << __PRETTY_FUNCTION__; return(this->gamma[iN][t]); } double ScaleHMM::get_density(int iN, int t) { //FILE_LOG(logDEBUG3) << __PRETTY_FUNCTION__; return(this->densities[iN][t]); } double ScaleHMM::get_proba(int i) { return( this->proba[i] ); } double ScaleHMM::get_A(int i, int j) { return( this->A[i][j] ); } double ScaleHMM::get_logP() { return( this->logP ); } void ScaleHMM::set_cutoff(int cutoff) { this->cutoff = cutoff; } // Private ==================================================== // Methods ---------------------------------------------------- void ScaleHMM::forward() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; // clock_t time = clock(), dtime; // if (this->xvariate==UNIVARIATE) // { std::vector<double> alpha(this->N); // Initialization this->scalefactoralpha[0] = 0.0; for (int iN=0; iN<this->N; iN++) { alpha[iN] = this->proba[iN] * this->densities[iN][0]; //FILE_LOG(logDEBUG4) << "alpha["<<iN<<"] = " << alpha[iN]; this->scalefactoralpha[0] += alpha[iN]; } //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<0<<"] = " << scalefactoralpha[0]; for (int iN=0; iN<this->N; iN++) { this->scalealpha[0][iN] = alpha[iN] / this->scalefactoralpha[0]; //FILE_LOG(logDEBUG4) << "scalealpha["<<0<<"]["<<iN<<"] = " << scalealpha[0][iN]; } // Induction for (int t=1; t<this->T; t++) { this->scalefactoralpha[t] = 0.0; for (int iN=0; iN<this->N; iN++) { double helpsum = 0.0; for (int jN=0; jN<this->N; jN++) { helpsum += this->scalealpha[t-1][jN] * this->A[jN][iN]; } alpha[iN] = helpsum * this->densities[iN][t]; //FILE_LOG(logDEBUG4) << "alpha["<<iN<<"] = " << alpha[iN]; this->scalefactoralpha[t] += alpha[iN]; } //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<t<<"] = " << scalefactoralpha[t]; for (int iN=0; iN<this->N; iN++) { this->scalealpha[t][iN] = alpha[iN] / this->scalefactoralpha[t]; //FILE_LOG(logDEBUG4) << "scalealpha["<<t<<"]["<<iN<<"] = " << scalealpha[t][iN]; if(std::isnan(this->scalealpha[t][iN])) { //FILE_LOG(logERROR) << __PRETTY_FUNCTION__; for (int jN=0; jN<this->N; jN++) { //FILE_LOG(logERROR) << "scalealpha["<<t-1<<"]["<<jN<<"] = " << scalealpha[t-1][jN]; //FILE_LOG(logERROR) << "A["<<iN<<"]["<<jN<<"] = " << A[iN][jN]; } //FILE_LOG(logERROR) << "scalefactoralpha["<<t<<"] = "<<scalefactoralpha[t] << ", densities = "<<densities[iN][t]; //FILE_LOG(logERROR) << "scalealpha["<<t<<"]["<<iN<<"] = " << scalealpha[t][iN]; throw nan_detected; } } } // } // else if (this->xvariate==MULTIVARIATE) // { // // std::vector<double> alpha(this->N); // // Initialization // this->scalefactoralpha[0] = 0.0; // for (int iN=0; iN<this->N; iN++) // { // alpha[iN] = this->proba[iN] * this->tdensities[0][iN]; // //FILE_LOG(logDEBUG4) << "alpha["<<iN<<"] = " << alpha[iN]; // this->scalefactoralpha[0] += alpha[iN]; // } // //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<0<<"] = " << scalefactoralpha[0]; // for (int iN=0; iN<this->N; iN++) // { // this->scalealpha[0][iN] = alpha[iN] / this->scalefactoralpha[0]; // //FILE_LOG(logDEBUG4) << "scalealpha["<<0<<"]["<<iN<<"] = " << scalealpha[0][iN]; // } // // Induction // for (int t=1; t<this->T; t++) // { // this->scalefactoralpha[t] = 0.0; // for (int iN=0; iN<this->N; iN++) // { // double helpsum = 0.0; // for (int jN=0; jN<this->N; jN++) // { // helpsum += this->scalealpha[t-1][jN] * this->A[jN][iN]; // } // alpha[iN] = helpsum * this->tdensities[t][iN]; // //FILE_LOG(logDEBUG4) << "alpha["<<iN<<"] = " << alpha[iN]; // this->scalefactoralpha[t] += alpha[iN]; // } // //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<t<<"] = " << scalefactoralpha[t]; // for (int iN=0; iN<this->N; iN++) // { // this->scalealpha[t][iN] = alpha[iN] / this->scalefactoralpha[t]; // //FILE_LOG(logDEBUG4) << "scalealpha["<<t<<"]["<<iN<<"] = " << scalealpha[t][iN]; // if(std::isnan(this->scalealpha[t][iN])) // { // //FILE_LOG(logERROR) << __PRETTY_FUNCTION__; // for (int jN=0; jN<this->N; jN++) // { // //FILE_LOG(logERROR) << "scalealpha["<<t-1<<"]["<<jN<<"] = " << scalealpha[t-1][jN]; // //FILE_LOG(logERROR) << "A["<<iN<<"]["<<jN<<"] = " << A[iN][jN]; // } // //FILE_LOG(logERROR) << "scalefactoralpha["<<t<<"] = "<<scalefactoralpha[t] << ", tdensities = "<<tdensities[t][iN]; // //FILE_LOG(logERROR) << "scalealpha["<<t<<"]["<<iN<<"] = " << scalealpha[t][iN]; // throw nan_detected; // } // } // } // // } // dtime = clock() - time; // //FILE_LOG(logDEBUG) << "forward(): " << dtime << " clicks"; } void ScaleHMM::backward() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; // clock_t time = clock(), dtime; // if (this->xvariate==UNIVARIATE) // { std::vector<double> beta(this->N); // Initialization for (int iN=0; iN<this->N; iN++) { beta[iN] = 1.0; //FILE_LOG(logDEBUG4) << "beta["<<iN<<"] = " << beta[iN]; } //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<T-1<<"] = " << scalefactoralpha[T-1]; for (int iN=0; iN<this->N; iN++) { this->scalebeta[T-1][iN] = beta[iN] / this->scalefactoralpha[T-1]; //FILE_LOG(logDEBUG4) << "scalebeta["<<T-1<<"]["<<iN<<"] = " << scalebeta[T-1][iN]; } // Induction for (int t=this->T-2; t>=0; t--) { for (int iN=0; iN<this->N; iN++) { beta[iN] = 0.0; for(int jN=0; jN<this->N; jN++) { beta[iN] += this->A[iN][jN] * this->densities[jN][t+1] * this->scalebeta[t+1][jN]; } //FILE_LOG(logDEBUG4) << "beta["<<iN<<"] = " << beta[iN]; } //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<t<<"] = " << scalefactoralpha[t]; for (int iN=0; iN<this->N; iN++) { this->scalebeta[t][iN] = beta[iN] / this->scalefactoralpha[t]; //FILE_LOG(logDEBUG4) << "scalebeta["<<t<<"]["<<iN<<"] = " << scalebeta[t][iN]; if (std::isnan(this->scalebeta[t][iN])) { //FILE_LOG(logERROR) << __PRETTY_FUNCTION__; for (int jN=0; jN<this->N; jN++) { //FILE_LOG(logERROR) << "scalebeta["<<jN<<"]["<<t+1<<"] = " << scalebeta[t+1][jN]; //FILE_LOG(logERROR) << "A["<<iN<<"]["<<jN<<"] = " << A[iN][jN]; //FILE_LOG(logERROR) << "densities["<<jN<<"]["<<t+1<<"] = " << densities[jN][t+1]; } //FILE_LOG(logERROR) << "this->scalefactoralpha[t]["<<t<<"] = "<<this->scalefactoralpha[t] << ", densities = "<<densities[iN][t]; //FILE_LOG(logERROR) << "scalebeta["<<iN<<"]["<<t<<"] = " << scalebeta[t][iN]; throw nan_detected; } } } // } // else if (this->xvariate==MULTIVARIATE) // { // // std::vector<double> beta(this->N); // // Initialization // for (int iN=0; iN<this->N; iN++) // { // beta[iN] = 1.0; // //FILE_LOG(logDEBUG4) << "beta["<<iN<<"] = " << beta[iN]; // } // //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<T-1<<"] = " << scalefactoralpha[T-1]; // for (int iN=0; iN<this->N; iN++) // { // this->scalebeta[T-1][iN] = beta[iN] / this->scalefactoralpha[T-1]; // //FILE_LOG(logDEBUG4) << "scalebeta["<<T-1<<"]["<<iN<<"] = " << scalebeta[T-1][iN]; // } // // Induction // for (int t=this->T-2; t>=0; t--) // { // for (int iN=0; iN<this->N; iN++) // { // //FILE_LOG(logDEBUG4) << "Calculating backward variable for state " << iN; // beta[iN] = 0.0; // for(int jN=0; jN<this->N; jN++) // { // beta[iN] += this->A[iN][jN] * this->tdensities[t+1][jN] * this->scalebeta[t+1][jN]; // } // } // //FILE_LOG(logDEBUG4) << "scalefactoralpha["<<t<<"] = " << scalefactoralpha[t]; // for (int iN=0; iN<this->N; iN++) // { // this->scalebeta[t][iN] = beta[iN] / this->scalefactoralpha[t]; // //FILE_LOG(logDEBUG4) << "scalebeta["<<t<<"]["<<iN<<"] = " << scalebeta[t][iN]; // if (std::isnan(this->scalebeta[t][iN])) // { // //FILE_LOG(logERROR) << __PRETTY_FUNCTION__; // for (int jN=0; jN<this->N; jN++) // { // //FILE_LOG(logERROR) << "scalebeta["<<jN<<"]["<<t+1<<"] = " << scalebeta[t+1][jN]; // //FILE_LOG(logERROR) << "A["<<iN<<"]["<<jN<<"] = " << A[iN][jN]; // //FILE_LOG(logERROR) << "tdensities["<<t+1<<"]["<<jN<<"] = " << tdensities[t+1][jN]; // } // //FILE_LOG(logERROR) << "this->scalefactoralpha[t]["<<t<<"] = "<<this->scalefactoralpha[t] << ", tdensities = "<<densities[t][iN]; // //FILE_LOG(logERROR) << "scalebeta["<<iN<<"]["<<t<<"] = " << scalebeta[t][iN]; // throw nan_detected; // } // } // } // // } // dtime = clock() - time; // //FILE_LOG(logDEBUG) << "backward(): " << dtime << " clicks"; } void ScaleHMM::calc_gamma() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; // clock_t time = clock(), dtime; // Compute the gammas (posteriors) and sumgamma #pragma omp parallel for for (int iN=0; iN<this->N; iN++) { for (int t=0; t<this->T; t++) { this->gamma[iN][t] = this->scalealpha[t][iN] * this->scalebeta[t][iN] * this->scalefactoralpha[t]; } } // dtime = clock() - time; // //FILE_LOG(logDEBUG) << "calc_gamma(): " << dtime << " clicks"; } void ScaleHMM::calc_sumxi() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; // clock_t time = clock(), dtime; double xi; // Initialize the sumxi for (int iN=0; iN<this->N; iN++) { for (int jN=0; jN<this->N; jN++) { this->sumxi[iN][jN] = 0.0; } } // if (this->xvariate==UNIVARIATE) // { #pragma omp parallel for for (int iN=0; iN<this->N; iN++) { //FILE_LOG(logDEBUG3) << "Calculating sumxi["<<iN<<"][jN]"; for (int t=0; t<this->T-1; t++) { for (int jN=0; jN<this->N; jN++) { xi = this->scalealpha[t][iN] * this->A[iN][jN] * this->densities[jN][t+1] * this->scalebeta[t+1][jN]; this->sumxi[iN][jN] += xi; } } } // } // else if (this->xvariate==MULTIVARIATE) // { // // #pragma omp parallel for // for (int iN=0; iN<this->N; iN++) // { // //FILE_LOG(logDEBUG3) << "Calculating sumxi["<<iN<<"][jN]"; // for (int t=0; t<this->T-1; t++) // { // for (int jN=0; jN<this->N; jN++) // { // xi = this->scalealpha[t][iN] * this->A[iN][jN] * this->tdensities[t+1][jN] * this->scalebeta[t+1][jN]; // this->sumxi[iN][jN] += xi; // } // } // } // // } // dtime = clock() - time; // //FILE_LOG(logDEBUG) << "calc_sumxi(): " << dtime << " clicks"; } void ScaleHMM::calc_loglikelihood() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; // clock_t time = clock(), dtime; this->logP = 0.0; for (int t=0; t<this->T; t++) { this->logP += log(this->scalefactoralpha[t]); } // dtime = clock() - time; // //FILE_LOG(logDEBUG) << "calc_loglikelihood(): " << dtime << " clicks"; } void ScaleHMM::calc_densities() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; // clock_t time = clock(), dtime; // Errors thrown inside a #pragma must be handled inside the thread std::vector<bool> nan_encountered(this->N); #pragma omp parallel for for (int iN=0; iN<this->N; iN++) { //FILE_LOG(logDEBUG3) << "Calculating densities for state " << iN; try { this->densityFunctions[iN]->calc_densities(this->densities[iN]); } catch(std::exception& e) { if (strcmp(e.what(),"nan detected")==0) { nan_encountered[iN]=true; } else { throw; } } } for (int iN=0; iN<this->N; iN++) { if (nan_encountered[iN]==true) { throw nan_detected; } } // Check if the density for all states is close to zero and correct to prevent NaNs // double zero_cutoff = 1.18e-37; // 32-bit precision is 1.18e-38 double zero_cutoff = 2.23e-307; // 64-bit precision is 2.23e-308 std::vector<double> temp(this->N); // t=0 for (int iN=0; iN<this->N; iN++) { temp[iN] = this->densities[iN][0]; } if (*std::max_element(temp.begin(), temp.end()) < zero_cutoff) { for (int iN=0; iN<this->N; iN++) { this->densities[iN][0] = zero_cutoff; } } // t>0 for (int t=1; t<this->T; t++) { for (int iN=0; iN<this->N; iN++) { temp[iN] = this->densities[iN][t]; } if (*std::max_element(temp.begin(), temp.end()) < zero_cutoff) { for (int iN=0; iN<this->N; iN++) { this->densities[iN][t] = this->densities[iN][t-1]; } } } // dtime = clock() - time; // //FILE_LOG(logDEBUG) << "calc_densities(): " << dtime << " clicks"; } void ScaleHMM::print_uni_iteration(int iteration) { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; if (this->verbosity>=1) { this->baumWelchTime_real = difftime(time(NULL),this->baumWelchStartTime_sec); int bs = 106; char buffer [106]; if (iteration % 20 == 0) { snprintf(buffer, bs, "%10s%20s%20s%19s%d%15s", "Iteration", "log(P)", "dlog(P)", "Diff in state ",this->N-1, "Time in sec"); //FILE_LOG(logITERATION) << buffer; Rprintf("%s\n", buffer); } if (iteration == 0) { snprintf(buffer, bs, "%10s%20s%20s%20s%*d", "0", "-inf", "-", "-", 15, this->baumWelchTime_real); } else if (iteration == 1) { snprintf(buffer, bs, "%*d%*f%20s%*d%*d", 10, iteration, 20, this->logP, "inf", 20, this->sumdiff_state_last, 15, this->baumWelchTime_real); } else { snprintf(buffer, bs, "%*d%*f%*f%*d%*d", 10, iteration, 20, this->logP, 20, this->dlogP, 20, this->sumdiff_state_last, 15, this->baumWelchTime_real); } //FILE_LOG(logITERATION) << buffer; Rprintf("%s\n", buffer); // Flush Rprintf statements to R console R_FlushConsole(); } } void ScaleHMM::print_multi_iteration(int iteration) { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; if (this->verbosity>=1) { this->baumWelchTime_real = difftime(time(NULL),this->baumWelchStartTime_sec); int bs = 86; char buffer [86]; if (iteration % 20 == 0) { snprintf(buffer, bs, "%10s%20s%20s%15s", "Iteration", "log(P)", "dlog(P)", "Time in sec"); //FILE_LOG(logITERATION) << buffer; Rprintf("%s\n", buffer); } if (iteration == 0) { snprintf(buffer, bs, "%10s%20s%20s%*d", "0", "-inf", "-", 15, this->baumWelchTime_real); } else if (iteration == 1) { snprintf(buffer, bs, "%*d%*f%20s%*d", 10, iteration, 20, this->logP, "inf", 15, this->baumWelchTime_real); } else { snprintf(buffer, bs, "%*d%*f%*f%*d", 10, iteration, 20, this->logP, 20, this->dlogP, 15, this->baumWelchTime_real); } //FILE_LOG(logITERATION) << buffer; Rprintf("%s\n", buffer); // Flush Rprintf statements to R console R_FlushConsole(); } } void ScaleHMM::print_uni_params() { //FILE_LOG(logDEBUG2) << __PRETTY_FUNCTION__; if (this->verbosity>=2) { int bs = 82; char buffer [82]; int cx; snprintf(buffer, bs, " -------------------------------------------------------------------------------"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); snprintf(buffer, bs, "|%80s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); // print loglik snprintf(buffer, bs, "| log(P) = %*.6f%54s", 16, this->logP, "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); snprintf(buffer, bs, "|%80s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); // print initial probabilities cx = snprintf(buffer, bs, "|%7s", ""); for (int iN=0; iN<this->N; iN++) { cx += snprintf(buffer+cx, bs-cx, "proba[%d] = %.6f ", iN, this->proba[iN]); } cx += snprintf(buffer+cx, bs-cx, " |"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); snprintf(buffer, bs, "|%80s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); // print transition probabilities for (int iN=0; iN<this->N; iN++) { cx = snprintf(buffer, bs, "|%7s", ""); for (int jN=0; jN<this->N; jN++) { cx += snprintf(buffer+cx, bs-cx, "A[%d][%d] = %.6f ", iN, jN, this->A[iN][jN]); } cx += snprintf(buffer+cx, bs-cx, " |"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); } // print emission parameters snprintf(buffer, bs, "|%80s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); for (int iN=0; iN<this->N; iN++) { if (iN == 1) { snprintf(buffer, bs, "| unmodified component%59s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); } if (iN == 2) { snprintf(buffer, bs, "| modified component%61s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); } if (this->densityFunctions[iN]->get_name() == NEGATIVE_BINOMIAL) { NegativeBinomial* temp = (NegativeBinomial*)this->densityFunctions[iN]; double curR = temp->get_size(); double curP = temp->get_prob(); double curMean = temp->get_mean(); double curVar = temp->get_variance(); snprintf(buffer, bs, "| r = %*.6f, p = %*.6f, mean = %*.2f, var = %*.2f%20s", 9, curR, 9, curP, 6, curMean, 8, curVar, "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); } } snprintf(buffer, bs, "|%80s", "|"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); snprintf(buffer, bs, " -------------------------------------------------------------------------------"); //FILE_LOG(logINFO) << buffer; Rprintf("%s\n", buffer); //FILE_LOG(logINFO) << ""; Rprintf("\n"); // Flush Rprintf statements to R console R_FlushConsole(); } }