diff --git a/src/shogun/base/progress.h b/src/shogun/base/progress.h index bcfc155098b..5fda47f0c20 100644 --- a/src/shogun/base/progress.h +++ b/src/shogun/base/progress.h @@ -123,6 +123,28 @@ namespace shogun lock.unlock(); } + void print_progress_absolute( + float64_t current_val, float64_t val, float64_t min_val, float64_t max_val) + { + lock.lock(); + if (val - m_min_value > + m_max_value - m_min_value) + { + lock.unlock(); + return; + } + print_progress_absolute_impl(current_val, val, min_val, max_val); + if (val - m_min_value == + m_max_value - m_min_value) + { + print_end(); + lock.unlock(); + return; + } + lock.unlock(); + } + + /** * Manually increment to max size the current value * to print a complete progress bar. @@ -238,6 +260,106 @@ namespace shogun } } + /** + * Logic implementation fo the absolute progress bar. + */ + void print_progress_absolute_impl( + float64_t current_val, float64_t val, float64_t min_value, float64_t max_value) const + { + // Check if the progress was enabled + if (!m_io.get_show_progress()) + return; + + m_current_value.store(current_val); + + if (max_value <= min_value) + return; + + // Check for terminal dimension. This is for provide + // a minimal resize functionality. + set_screen_size(); + + float64_t difference = max_value - min_value, v = -1, + estimate = 0, total_estimate = 0; + float64_t size_chunk = -1; + + // Check if we have enough space to show the progress bar + // Use only a fraction of it to account for the size of the + // time displayed (decimals and integer). + int32_t progress_bar_space = + (m_columns_num - 50 - m_prefix.length()) * 0.9; + + // TODO: this guy here brokes testing + // REQUIRE( + // progress_bar_space > 0, + // "Not enough terminal space to show the progress bar!\n") + + char str[1000]; + float64_t runtime = CTime::get_curtime(); + + if (difference > 0.0) + v = 100 * (val - min_value) / + (max_value - min_value); + + // Set up chunk size + size_chunk = difference / (float64_t)progress_bar_space; + + if (m_last_progress == 0) + { + m_last_progress_time = runtime; + m_last_progress = v; + } + else + { + m_last_progress = v - 1e-6; + + if ((v != 100.0) && (runtime - m_last_progress_time < 0.5)) + return; + + m_last_progress_time = runtime; + estimate = (1 - v / 100) * + (m_last_progress_time - m_progress_start_time) / + (v / 100); + total_estimate = + (m_last_progress_time - m_progress_start_time) / (v / 100); + } + + /** Print the actual progress bar to screen **/ + m_io.message(MSG_MESSAGEONLY, "", "", -1, "%s |", m_prefix.c_str()); + for (index_t i = 1; i < progress_bar_space; i++) + { + if (m_current_value.load() - min_value > i * size_chunk) + { + m_io.message( + MSG_MESSAGEONLY, "", "", -1, "%s", + get_pb_char().c_str()); + } + else + { + m_io.message(MSG_MESSAGEONLY, "", "", -1, " "); + } + } + m_io.message(MSG_MESSAGEONLY, "", "", -1, "| %.2f\%", current_val); + + if (estimate > 120) + { + snprintf( + str, sizeof(str), + " %%1.1f minutes remaining %%1.1f minutes total\r"); + m_io.message( + MSG_MESSAGEONLY, "", "", -1, str, estimate / 60, + total_estimate / 60); + } + else + { + snprintf( + str, sizeof(str), + " %%1.1f seconds remaining %%1.1f seconds total\r"); + m_io.message( + MSG_MESSAGEONLY, "", "", -1, str, estimate, total_estimate); + } + } + /** Print the progress bar end. */ void print_end() const { @@ -499,6 +621,20 @@ namespace shogun m_printer->print_progress(); } + /** + * Print the absolute progress bar. This method must be called + * each time we want the progress bar to be updated. + * + * @param current_val current value + * @param val value + * @param min_val minimum value + * @param max_val maximum value + */ + void print_absolute(float64_t current_val, float64_t val, float64_t min_value, float64_t max_value) const + { + m_printer->print_progress_absolute(current_val, val, min_value, max_value); + } + /** * Print the progress bar end. This method must be called * one time, after the loop. @@ -518,6 +654,24 @@ namespace shogun m_printer->print_progress(); } + /** + * Print the progress bar end. This method must be called + * one time, after the loop. + * @code + * auto pr = progress(range(0,10), ASCII); + * for (int i=0; i<10; i++) + * { + * // Do stuff + * pr.print_absolute(); + * } + * pr.complete_absolute(); + * @endcode + */ + void complete_absolute() const + { + m_printer->print_progress_absolute(100, 100, 0, 100); + } + private: /** * Set up progress range. diff --git a/src/shogun/classifier/svm/SVMLight.cpp b/src/shogun/classifier/svm/SVMLight.cpp index 0facabb00b9..7daf67617f5 100644 --- a/src/shogun/classifier/svm/SVMLight.cpp +++ b/src/shogun/classifier/svm/SVMLight.cpp @@ -52,6 +52,8 @@ #ifdef HAVE_PTHREAD #include +#include + #endif using namespace shogun; @@ -640,7 +642,7 @@ int32_t CSVMLight::optimize_to_convergence(int32_t* docs, int32_t* label, int32_ CTime start_time; mkl_converged=false; - + auto pb = progress(range(10), *this->io); #ifdef CYGWIN for (;((iteration<100 || (!mkl_converged && callback) ) || (retrain && (!terminate))); iteration++){ #else @@ -901,7 +903,7 @@ int32_t CSVMLight::optimize_to_convergence(int32_t* docs, int32_t* label, int32_ if (bestmaxdiff>worstmaxdiff) worstmaxdiff=bestmaxdiff; - SG_ABS_PROGRESS(bestmaxdiff, -CMath::log10(bestmaxdiff), -CMath::log10(worstmaxdiff), -CMath::log10(epsilon), 6) + pb.print_absolute(bestmaxdiff, -CMath::log10(bestmaxdiff), -CMath::log10(worstmaxdiff), -CMath::log10(epsilon)); /* Terminate loop */ if (m_max_train_time > 0 && start_time.cur_time_diff() > m_max_train_time) { @@ -910,6 +912,7 @@ int32_t CSVMLight::optimize_to_convergence(int32_t* docs, int32_t* label, int32_ } } /* end of loop */ + pb.complete_absolute(); SG_DEBUG("inactive:%d\n", inactivenum) diff --git a/src/shogun/multiclass/GMNPLib.cpp b/src/shogun/multiclass/GMNPLib.cpp index fe77e120b13..ed6c291975b 100644 --- a/src/shogun/multiclass/GMNPLib.cpp +++ b/src/shogun/multiclass/GMNPLib.cpp @@ -62,6 +62,7 @@ gmnplib.c: Library of solvers for Generalized Minimal Norm Problem (GMNP). #include #include +#include #include #include @@ -348,6 +349,7 @@ int8_t CGMNPLib::gmnp_imdm(float64_t *vector_c, /* Main optimization loop */ /* ------------------------------------------------------------ */ + auto pb = progress(range(10), *this->io); col_u = (float64_t*)get_col(u,-1); while( exitflag == -1 ) { @@ -420,10 +422,11 @@ int8_t CGMNPLib::gmnp_imdm(float64_t *vector_c, else if(t >= tmax) exitflag = 0; /* print info */ - SG_ABS_PROGRESS(CMath::abs((UB-LB)/UB), + pb.print_absolute(CMath::abs((UB-LB)/UB), -CMath::log10(CMath::abs(UB-LB)), -CMath::log10(1.0), - -CMath::log10(tolrel), 6); + -CMath::log10(tolrel)); + if(verb && (t % verb) == 0 ) { SG_PRINT("%d: UB=%f, LB=%f, UB-LB=%f, (UB-LB)/|UB|=%f \n", t, UB, LB, UB-LB,(UB-LB)/UB); @@ -451,7 +454,7 @@ int8_t CGMNPLib::gmnp_imdm(float64_t *vector_c, } /* print info about last iteration*/ - SG_DONE() + pb.complete_absolute(); if(verb && (t % verb) ) { SG_PRINT("exit: UB=%f, LB=%f, UB-LB=%f, (UB-LB)/|UB|=%f \n", UB, LB, UB-LB,(UB-LB)/UB); diff --git a/src/shogun/multiclass/LaRank.cpp b/src/shogun/multiclass/LaRank.cpp index b84efa1709f..4d04285c8c2 100644 --- a/src/shogun/multiclass/LaRank.cpp +++ b/src/shogun/multiclass/LaRank.cpp @@ -47,6 +47,7 @@ **********************************************************************/ #include +#include #include #include @@ -638,6 +639,7 @@ bool CLaRank::train_machine(CFeatures* data) int32_t n_it = 1; float64_t gap = DBL_MAX; + auto pb = progress(range(0, 10), *this->io); SG_INFO("Training on %d examples\n", nb_train) while (gap > get_C() && (!CSignal::cancel_computations()) && n_it < max_iteration) // stopping criteria @@ -661,13 +663,13 @@ bool CLaRank::train_machine(CFeatures* data) SG_DEBUG("End of iteration %d\n", n_it) SG_DEBUG("Train error (online): %f%%\n", (tr_err / nb_train) * 100) gap = computeGap (); - SG_ABS_PROGRESS(gap, -CMath::log10(gap), -CMath::log10(DBL_MAX), -CMath::log10(get_C()), 6) + pb.print_absolute(gap, -CMath::log10(gap), -CMath::log10(DBL_MAX), -CMath::log10(get_C())); if (!batch_mode) // skip stopping criteria if online mode gap = 0; n_it++; } - SG_DONE() + pb.complete_absolute(); if (n_it >= max_iteration && gap > get_C()) {