/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the HiGHS linear optimization suite */ /* */ /* Written and engineered 2008-2022 at the University of Edinburgh */ /* */ /* Available as open-source under the MIT License */ /* */ /* Authors: Julian Hall, Ivet Galabova, Leona Gottwald and Michael */ /* Feldmeier */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /**@file simplex/HighsSimplexAnalysis.cpp * @brief */ #include //#include #include #include "HConfig.h" #include "parallel/HighsParallel.h" #include "simplex/HighsSimplexAnalysis.h" #include "simplex/SimplexTimer.h" #include "util/FactorTimer.h" #include "util/HFactor.h" void HighsSimplexAnalysis::setup(const std::string lp_name, const HighsLp& lp, const HighsOptions& options, const HighsInt simplex_iteration_count_) { // Copy Problem size numRow = lp.num_row_; numCol = lp.num_col_; numTot = numRow + numCol; model_name_ = lp.model_name_; lp_name_ = lp_name; // Set up analysis logic short-cuts analyse_lp_data = kHighsAnalysisLevelModelData & options.highs_analysis_level; analyse_simplex_summary_data = kHighsAnalysisLevelSolverSummaryData & options.highs_analysis_level; analyse_simplex_runtime_data = kHighsAnalysisLevelSolverRuntimeData & options.highs_analysis_level; analyse_factor_data = kHighsAnalysisLevelNlaData & options.highs_analysis_level; analyse_simplex_data = analyse_simplex_summary_data || analyse_simplex_runtime_data; last_user_log_time = -kHighsInf; delta_user_log_time = 5e0; setupSimplexTime(options); setupFactorTime(options); // Copy tolerances from options // allow_dual_steepest_edge_to_devex_switch = // options.simplex_dual_edge_weight_strategy == // kSimplexEdgeWeightStrategyChoose; // dual_steepest_edge_weight_log_error_threshold = // options.dual_steepest_edge_weight_log_error_threshold; // AnIterIt0 = simplex_iteration_count_; // AnIterCostlyDseFq = 0; // AnIterNumCostlyDseIt = 0; // Copy messaging parameter from options messaging(options.log_options); // Initialise the densities col_aq_density = 0; row_ep_density = 0; row_ap_density = 0; row_DSE_density = 0; col_steepest_edge_density = 0; col_basic_feasibility_change_density = 0; row_basic_feasibility_change_density = 0; col_BFRT_density = 0; primal_col_density = 0; // Set the row_dual_density to 1 since it's assumed all costs are at // least perturbed from zero, if not initially nonzero dual_col_density = 1; // Set up the data structures for scatter data tran_stage.resize(NUM_TRAN_STAGE_TYPE); tran_stage[TRAN_STAGE_FTRAN_LOWER].name_ = "FTRAN lower"; tran_stage[TRAN_STAGE_FTRAN_UPPER_FT].name_ = "FTRAN upper FT"; tran_stage[TRAN_STAGE_FTRAN_UPPER].name_ = "FTRAN upper"; tran_stage[TRAN_STAGE_BTRAN_UPPER].name_ = "BTRAN upper"; tran_stage[TRAN_STAGE_BTRAN_UPPER_FT].name_ = "BTRAN upper FT"; tran_stage[TRAN_STAGE_BTRAN_LOWER].name_ = "BTRAN lower"; for (HighsInt tran_stage_type = 0; tran_stage_type < NUM_TRAN_STAGE_TYPE; tran_stage_type++) { TranStageAnalysis& stage = tran_stage[tran_stage_type]; initialiseScatterData(20, stage.rhs_density_); stage.num_decision_ = 0; stage.num_wrong_original_sparse_decision_ = 0; stage.num_wrong_original_hyper_decision_ = 0; stage.num_wrong_new_sparse_decision_ = 0; stage.num_wrong_new_hyper_decision_ = 0; } original_start_density_tolerance.resize(NUM_TRAN_STAGE_TYPE); new_start_density_tolerance.resize(NUM_TRAN_STAGE_TYPE); historical_density_tolerance.resize(NUM_TRAN_STAGE_TYPE); predicted_density_tolerance.resize(NUM_TRAN_STAGE_TYPE); for (HighsInt tran_stage_type = 0; tran_stage_type < NUM_TRAN_STAGE_TYPE; tran_stage_type++) { original_start_density_tolerance[tran_stage_type] = 0.05; new_start_density_tolerance[tran_stage_type] = 0.05; } historical_density_tolerance[TRAN_STAGE_FTRAN_LOWER] = 0.15; historical_density_tolerance[TRAN_STAGE_FTRAN_UPPER] = 0.10; historical_density_tolerance[TRAN_STAGE_BTRAN_UPPER] = 0.10; historical_density_tolerance[TRAN_STAGE_BTRAN_LOWER] = 0.15; predicted_density_tolerance[TRAN_STAGE_FTRAN_LOWER] = 0.10; predicted_density_tolerance[TRAN_STAGE_FTRAN_UPPER] = 0.10; predicted_density_tolerance[TRAN_STAGE_BTRAN_UPPER] = 0.10; predicted_density_tolerance[TRAN_STAGE_BTRAN_LOWER] = 0.10; // Initialise the measures used to analyse accuracy of steepest edge weights // const HighsInt dual_edge_weight_strategy = options.simplex_dual_edge_weight_strategy; if (dual_edge_weight_strategy == kSimplexEdgeWeightStrategyChoose || dual_edge_weight_strategy == kSimplexEdgeWeightStrategySteepestEdge) { // Initialise the measures used to analyse accuracy of steepest edge weights num_dual_steepest_edge_weight_check = 0; num_dual_steepest_edge_weight_reject = 0; num_wrong_low_dual_steepest_edge_weight = 0; num_wrong_high_dual_steepest_edge_weight = 0; average_frequency_low_dual_steepest_edge_weight = 0; average_frequency_high_dual_steepest_edge_weight = 0; average_log_low_dual_steepest_edge_weight_error = 0; average_log_high_dual_steepest_edge_weight_error = 0; max_average_frequency_low_dual_steepest_edge_weight = 0; max_average_frequency_high_dual_steepest_edge_weight = 0; max_sum_average_frequency_extreme_dual_steepest_edge_weight = 0; max_average_log_low_dual_steepest_edge_weight_error = 0; max_average_log_high_dual_steepest_edge_weight_error = 0; max_sum_average_log_extreme_dual_steepest_edge_weight_error = 0; } num_devex_framework = 0; num_iteration_report_since_last_header = -1; num_invert_report_since_last_header = -1; // Set values used to skip an iteration report when column (row) // choice has found nothing in primal (dual) simplex entering_variable = -1; pivotal_row_index = -1; // Set following averages to illegal values so that first average is // set equal to first value average_concurrency = -1; average_fraction_of_possible_minor_iterations_performed = -1; sum_multi_chosen = 0; sum_multi_finished = 0; if (analyse_simplex_summary_data) { AnIterPrevIt = simplex_iteration_count_; AnIterOpRec* AnIter; AnIter = &AnIterOp[kSimplexNlaBtranFull]; AnIter->AnIterOpName = "BTRAN Full"; AnIter = &AnIterOp[kSimplexNlaPriceFull]; AnIter->AnIterOpName = "PRICE Full"; AnIter = &AnIterOp[kSimplexNlaBtranBasicFeasibilityChange]; AnIter->AnIterOpName = "BTRAN BcFsCg"; AnIter = &AnIterOp[kSimplexNlaPriceBasicFeasibilityChange]; AnIter->AnIterOpName = "PRICE BcFsCg"; AnIter = &AnIterOp[kSimplexNlaBtranEp]; AnIter->AnIterOpName = "BTRAN e_p"; AnIter = &AnIterOp[kSimplexNlaPriceAp]; AnIter->AnIterOpName = "PRICE a_p"; AnIter = &AnIterOp[kSimplexNlaFtran]; AnIter->AnIterOpName = "FTRAN"; AnIter = &AnIterOp[kSimplexNlaFtranBfrt]; AnIter->AnIterOpName = "FTRAN BFRT"; AnIter = &AnIterOp[kSimplexNlaFtranDse]; AnIter->AnIterOpName = "FTRAN DSE"; AnIter = &AnIterOp[kSimplexNlaBtranPse]; AnIter->AnIterOpName = "BTRAN PSE"; for (HighsInt k = 0; k < kNumSimplexNlaOperation; k++) { AnIter = &AnIterOp[k]; if ((k == kSimplexNlaPriceAp) || (k == kSimplexNlaPriceBasicFeasibilityChange) || (k == kSimplexNlaPriceFull)) { AnIter->AnIterOpHyperCANCEL = 1.0; AnIter->AnIterOpHyperTRAN = 1.0; AnIter->AnIterOpRsDim = numCol; } else { if ((k == kSimplexNlaBtranEp) || (k == kSimplexNlaBtranBasicFeasibilityChange) || (k == kSimplexNlaBtranFull)) { AnIter->AnIterOpHyperCANCEL = kHyperCancel; AnIter->AnIterOpHyperTRAN = kHyperBtranU; } else { AnIter->AnIterOpHyperCANCEL = kHyperCancel; AnIter->AnIterOpHyperTRAN = kHyperFtranL; } AnIter->AnIterOpRsDim = numRow; } AnIter->AnIterOpNumCa = 0; AnIter->AnIterOpNumHyperOp = 0; AnIter->AnIterOpNumHyperRs = 0; AnIter->AnIterOpSumLog10RsDensity = 0; initialiseValueDistribution("", "density ", 1e-8, 1.0, 10.0, AnIter->AnIterOp_density); } HighsInt last_rebuild_reason = kRebuildReasonCount - 1; for (HighsInt k = 1; k <= last_rebuild_reason; k++) AnIterNumInvert[k] = 0; num_col_price = 0; num_row_price = 0; num_row_price_with_switch = 0; num_primal_cycling_detections = 0; num_dual_cycling_detections = 0; // Initialise the dual simplex flip/shift records num_quad_chuzc = 0; num_heap_chuzc = 0; sum_quad_chuzc_size = 0; sum_heap_chuzc_size = 0; max_quad_chuzc_size = 0; max_heap_chuzc_size = 0; num_improve_choose_column_row_call = 0; num_remove_pivot_from_pack = 0; num_correct_dual_primal_flip = 0; min_correct_dual_primal_flip_dual_infeasibility = kHighsInf; max_correct_dual_primal_flip = 0; num_correct_dual_cost_shift = 0; max_correct_dual_cost_shift_dual_infeasibility = 0; max_correct_dual_cost_shift = 0; net_num_single_cost_shift = 0; num_single_cost_shift = 0; max_single_cost_shift = 0; sum_single_cost_shift = 0; HighsInt last_edge_weight_mode = (HighsInt)EdgeWeightMode::kSteepestEdge; for (HighsInt k = 0; k <= last_edge_weight_mode; k++) AnIterNumEdWtIt[k] = 0; AnIterTraceNumRec = 0; AnIterTraceIterDl = 1; AnIterTraceRec* lcAnIter = &AnIterTrace[0]; lcAnIter->AnIterTraceIter = AnIterIt0; lcAnIter->AnIterTraceTime = timer_->getWallTime(); initialiseValueDistribution("Primal step summary", "", 1e-16, 1e16, 10.0, primal_step_distribution); initialiseValueDistribution("Dual step summary", "", 1e-16, 1e16, 10.0, dual_step_distribution); initialiseValueDistribution("Simplex pivot summary", "", 1e-8, 1e16, 10.0, simplex_pivot_distribution); initialiseValueDistribution("Factor pivot threshold summary", "", kMinPivotThreshold, kMaxPivotThreshold, kPivotThresholdChangeFactor, factor_pivot_threshold_distribution); initialiseValueDistribution("Numerical trouble summary", "", 1e-16, 1.0, 10.0, numerical_trouble_distribution); initialiseValueDistribution("Edge weight error summary", "", 1e-16, 1.0, 10.0, edge_weight_error_distribution); initialiseValueDistribution("", "1 ", 1e-16, 1e16, 10.0, cost_perturbation1_distribution); initialiseValueDistribution("", "2 ", 1e-16, 1e16, 10.0, cost_perturbation2_distribution); initialiseValueDistribution("FTRAN upper sparse summary - before", "", 1e-8, 1.0, 10.0, before_ftran_upper_sparse_density); initialiseValueDistribution("FTRAN upper sparse summary - after", "", 1e-8, 1.0, 10.0, before_ftran_upper_hyper_density); initialiseValueDistribution("FTRAN upper hyper-sparse summary - before", "", 1e-8, 1.0, 10.0, ftran_upper_sparse_density); initialiseValueDistribution("FTRAN upper hyper-sparse summary - after", "", 1e-8, 1.0, 10.0, ftran_upper_hyper_density); initialiseValueDistribution("Cleanup dual change summary", "", 1e-16, 1e16, 10.0, cleanup_dual_change_distribution); initialiseValueDistribution("Cleanup primal change summary", "", 1e-16, 1e16, 10.0, cleanup_primal_step_distribution); initialiseValueDistribution("Cleanup primal step summary", "", 1e-16, 1e16, 10.0, cleanup_primal_change_distribution); initialiseValueDistribution("Cleanup dual step summary", "", 1e-16, 1e16, 10.0, cleanup_dual_step_distribution); } } void HighsSimplexAnalysis::setupSimplexTime(const HighsOptions& options) { analyse_simplex_time = kHighsAnalysisLevelSolverTime & options.highs_analysis_level; if (analyse_simplex_time) { // Set up the thread clocks HighsInt max_threads = highs::parallel::num_threads(); thread_simplex_clocks.clear(); for (HighsInt i = 0; i < max_threads; i++) { HighsTimerClock clock; clock.timer_pointer_ = timer_; thread_simplex_clocks.push_back(clock); } SimplexTimer simplex_timer; for (HighsTimerClock& clock : thread_simplex_clocks) simplex_timer.initialiseSimplexClocks(clock); } } void HighsSimplexAnalysis::setupFactorTime(const HighsOptions& options) { analyse_factor_time = kHighsAnalysisLevelNlaTime & options.highs_analysis_level; if (analyse_factor_time) { // Set up the thread clocks HighsInt max_threads = highs::parallel::num_threads(); thread_factor_clocks.clear(); for (HighsInt i = 0; i < max_threads; i++) { HighsTimerClock clock; clock.timer_pointer_ = timer_; thread_factor_clocks.push_back(clock); } pointer_serial_factor_clocks = &thread_factor_clocks[0]; FactorTimer factor_timer; for (HighsTimerClock& clock : thread_factor_clocks) factor_timer.initialiseFactorClocks(clock); } else { pointer_serial_factor_clocks = NULL; } } void HighsSimplexAnalysis::messaging(const HighsLogOptions& log_options_) { log_options = log_options_; } void HighsSimplexAnalysis::iterationReport() { const bool simple_report = false; if (simple_report) { printf( "Iter %5d: (%6d; %6d) delta_primal = %11.4g; dual_step = %11.4g; " "primal_step = %11.4g\n", (int)simplex_iteration_count, (int)leaving_variable, (int)entering_variable, primal_delta, dual_step, primal_step); } if (*log_options.log_dev_level < (HighsInt)kIterationReportLogType) return; const bool header = (num_iteration_report_since_last_header < 0) || (num_iteration_report_since_last_header > 49); if (header) { iterationReport(header); num_iteration_report_since_last_header = 0; } iterationReport(false); } void HighsSimplexAnalysis::invertReport() { if (*log_options.log_dev_level) { const bool header = (num_invert_report_since_last_header < 0) || (num_invert_report_since_last_header > 49) || (num_iteration_report_since_last_header >= 0); if (header) { invertReport(header); num_invert_report_since_last_header = 0; } invertReport(false); // Force an iteration report header if this is an INVERT report without an // rebuild_reason if (!rebuild_reason) num_iteration_report_since_last_header = -1; } else { const bool force = false; userInvertReport(force); } } void HighsSimplexAnalysis::invertReport(const bool header) { analysis_log = std::unique_ptr(new std::stringstream()); reportAlgorithmPhase(header); reportIterationObjective(header); if (analyse_simplex_runtime_data) { if (simplex_strategy == kSimplexStrategyDualMulti) { // Report on threads and PAMI reportThreads(header); reportMulti(header); } reportDensity(header); // reportCondition(header); } reportInfeasibility(header); // if (analyse_simplex_runtime_data) reportInvert(header); highsLogDev(log_options, HighsLogType::kInfo, "%s\n", analysis_log->str().c_str()); if (!header) num_invert_report_since_last_header++; } void HighsSimplexAnalysis::userInvertReport(const bool force) { if (last_user_log_time < 0) { const bool header = true; userInvertReport(header, force); } userInvertReport(false, force); } void HighsSimplexAnalysis::userInvertReport(const bool header, const bool force) { const double highs_run_time = timer_->readRunHighsClock(); if (!force && highs_run_time < last_user_log_time + delta_user_log_time) return; analysis_log = std::unique_ptr(new std::stringstream()); reportIterationObjective(header); reportInfeasibility(header); reportRunTime(header, highs_run_time); highsLogUser(log_options, HighsLogType::kInfo, "%s\n", analysis_log->str().c_str()); if (!header) last_user_log_time = highs_run_time; if (highs_run_time > 200 * delta_user_log_time) delta_user_log_time *= 10; } void HighsSimplexAnalysis::dualSteepestEdgeWeightError( const double computed_edge_weight, const double updated_edge_weight) { const double kWeightErrorThreshold = 4.0; const bool accept_weight = updated_edge_weight >= kAcceptDseWeightThreshold * computed_edge_weight; HighsInt low_weight_error = 0; HighsInt high_weight_error = 0; double weight_error; string error_type = " OK"; num_dual_steepest_edge_weight_check++; if (!accept_weight) num_dual_steepest_edge_weight_reject++; if (updated_edge_weight < computed_edge_weight) { // Updated weight is low weight_error = computed_edge_weight / updated_edge_weight; if (weight_error > kWeightErrorThreshold) { low_weight_error = 1; error_type = " Low"; } average_log_low_dual_steepest_edge_weight_error = 0.99 * average_log_low_dual_steepest_edge_weight_error + 0.01 * log(weight_error); } else { // Updated weight is correct or high weight_error = updated_edge_weight / computed_edge_weight; if (weight_error > kWeightErrorThreshold) { high_weight_error = 1; error_type = "High"; } average_log_high_dual_steepest_edge_weight_error = 0.99 * average_log_high_dual_steepest_edge_weight_error + 0.01 * log(weight_error); } average_frequency_low_dual_steepest_edge_weight = 0.99 * average_frequency_low_dual_steepest_edge_weight + 0.01 * low_weight_error; average_frequency_high_dual_steepest_edge_weight = 0.99 * average_frequency_high_dual_steepest_edge_weight + 0.01 * high_weight_error; max_average_frequency_low_dual_steepest_edge_weight = max(max_average_frequency_low_dual_steepest_edge_weight, average_frequency_low_dual_steepest_edge_weight); max_average_frequency_high_dual_steepest_edge_weight = max(max_average_frequency_high_dual_steepest_edge_weight, average_frequency_high_dual_steepest_edge_weight); max_sum_average_frequency_extreme_dual_steepest_edge_weight = max(max_sum_average_frequency_extreme_dual_steepest_edge_weight, average_frequency_low_dual_steepest_edge_weight + average_frequency_high_dual_steepest_edge_weight); max_average_log_low_dual_steepest_edge_weight_error = max(max_average_log_low_dual_steepest_edge_weight_error, average_log_low_dual_steepest_edge_weight_error); max_average_log_high_dual_steepest_edge_weight_error = max(max_average_log_high_dual_steepest_edge_weight_error, average_log_high_dual_steepest_edge_weight_error); max_sum_average_log_extreme_dual_steepest_edge_weight_error = max(max_sum_average_log_extreme_dual_steepest_edge_weight_error, average_log_low_dual_steepest_edge_weight_error + average_log_high_dual_steepest_edge_weight_error); if (analyse_simplex_runtime_data) { const bool report_weight_error = false; if (report_weight_error && weight_error > 0.5 * kWeightErrorThreshold) { printf( "DSE Wt Ck |%8" HIGHSINT_FORMAT "| OK = %1d (%4" HIGHSINT_FORMAT " / %6" HIGHSINT_FORMAT ") (c %10.4g, u %10.4g, er %10.4g " "- " "%s): Low (Fq %10.4g, Er %10.4g); High (Fq%10.4g, Er%10.4g) | %10.4g " "%10.4g %10.4g %10.4g %10.4g %10.4g\n", simplex_iteration_count, accept_weight, num_dual_steepest_edge_weight_check, num_dual_steepest_edge_weight_reject, computed_edge_weight, updated_edge_weight, weight_error, error_type.c_str(), average_frequency_low_dual_steepest_edge_weight, average_log_low_dual_steepest_edge_weight_error, average_frequency_high_dual_steepest_edge_weight, average_log_high_dual_steepest_edge_weight_error, max_average_frequency_low_dual_steepest_edge_weight, max_average_frequency_high_dual_steepest_edge_weight, max_sum_average_frequency_extreme_dual_steepest_edge_weight, max_average_log_low_dual_steepest_edge_weight_error, max_average_log_high_dual_steepest_edge_weight_error, max_sum_average_log_extreme_dual_steepest_edge_weight_error); } } } bool HighsSimplexAnalysis::predictEndDensity(const HighsInt tran_stage_type, const double start_density, double& end_density) { return predictFromScatterData(tran_stage[tran_stage_type].rhs_density_, start_density, end_density); } void HighsSimplexAnalysis::afterTranStage( const HighsInt tran_stage_type, const double start_density, const double end_density, const double historical_density, const double predicted_end_density, const bool use_solve_sparse_original_HFactor_logic, const bool use_solve_sparse_new_HFactor_logic) { TranStageAnalysis& stage = tran_stage[tran_stage_type]; const double rp = false; const double kMaxHyperDensity = 0.1; if (predicted_end_density > 0) { stage.num_decision_++; if (end_density <= kMaxHyperDensity) { // Should have done hyper-sparse TRAN if (use_solve_sparse_original_HFactor_logic) { // Original logic makes wrong decision to use sparse TRAN if (rp) { printf("Original: Wrong sparse: "); const double start_density_tolerance = original_start_density_tolerance[tran_stage_type]; const double this_historical_density_tolerance = historical_density_tolerance[tran_stage_type]; if (start_density > start_density_tolerance) { printf("(start = %10.4g > %4.2f) or ", start_density, start_density_tolerance); } else { printf(" start = %10.4g ", start_density); } if (historical_density > this_historical_density_tolerance) { printf("(historical = %10.4g > %4.2f); ", historical_density, this_historical_density_tolerance); } else { printf(" historical = %10.4g ", historical_density); } printf("end = %10.4g", end_density); if (end_density < 0.1 * historical_density) printf(" !! OG"); printf("\n"); } stage.num_wrong_original_sparse_decision_++; } if (use_solve_sparse_new_HFactor_logic) { // New logic makes wrong decision to use sparse TRAN if (rp) { printf("New : Wrong sparse: "); const double start_density_tolerance = original_start_density_tolerance[tran_stage_type]; const double end_density_tolerance = predicted_density_tolerance[tran_stage_type]; if (start_density > start_density_tolerance) { printf("(start = %10.4g > %4.2f) or ", start_density, start_density_tolerance); } else { printf(" start = %10.4g ", start_density); } if (predicted_end_density > end_density_tolerance) { printf("( predicted = %10.4g > %4.2f); ", predicted_end_density, end_density_tolerance); } else { printf(" predicted = %10.4g ", predicted_end_density); } printf("end = %10.4g", end_density); if (end_density < 0.1 * predicted_end_density) printf(" !! NW"); printf("\n"); } stage.num_wrong_new_sparse_decision_++; } } else { // Should have done sparse TRAN if (!use_solve_sparse_original_HFactor_logic) { // Original logic makes wrong decision to use hyper TRAN if (rp) { printf( "Original: Wrong hyper: (start = %10.4g <= %4.2f) and " "(historical = %10.4g <= %4.2f); end = %10.4g", start_density, original_start_density_tolerance[tran_stage_type], historical_density, historical_density_tolerance[tran_stage_type], end_density); if (end_density > 10.0 * historical_density) printf(" !! OG"); printf("\n"); } stage.num_wrong_original_hyper_decision_++; } if (!use_solve_sparse_new_HFactor_logic) { // New logic makes wrong decision to use hyper TRAN if (rp) { printf( "New : Wrong hyper: (start = %10.4g <= %4.2f) and ( " "predicted = %10.4g <= %4.2f); end = %10.4g", start_density, new_start_density_tolerance[tran_stage_type], predicted_end_density, predicted_density_tolerance[tran_stage_type], end_density); if (end_density > 10.0 * predicted_end_density) printf(" !! NW"); printf("\n"); } stage.num_wrong_new_hyper_decision_++; } } } updateScatterData(start_density, end_density, stage.rhs_density_); regressScatterData(stage.rhs_density_); } void HighsSimplexAnalysis::simplexTimerStart(const HighsInt simplex_clock, const HighsInt thread_id) { if (!analyse_simplex_time) return; // assert(analyse_simplex_time); thread_simplex_clocks[thread_id].timer_pointer_->start( thread_simplex_clocks[thread_id].clock_[simplex_clock]); } void HighsSimplexAnalysis::simplexTimerStop(const HighsInt simplex_clock, const HighsInt thread_id) { if (!analyse_simplex_time) return; // assert(analyse_simplex_time); thread_simplex_clocks[thread_id].timer_pointer_->stop( thread_simplex_clocks[thread_id].clock_[simplex_clock]); } bool HighsSimplexAnalysis::simplexTimerRunning(const HighsInt simplex_clock, const HighsInt thread_id) { if (!analyse_simplex_time) return false; // assert(analyse_simplex_time); return thread_simplex_clocks[thread_id].timer_pointer_->clock_start [thread_simplex_clocks[thread_id].clock_[simplex_clock]] < 0; } HighsInt HighsSimplexAnalysis::simplexTimerNumCall(const HighsInt simplex_clock, const HighsInt thread_id) { if (!analyse_simplex_time) return -1; // assert(analyse_simplex_time); return thread_simplex_clocks[thread_id] .timer_pointer_ ->clock_num_call[thread_simplex_clocks[thread_id].clock_[simplex_clock]]; } double HighsSimplexAnalysis::simplexTimerRead(const HighsInt simplex_clock, const HighsInt thread_id) { if (!analyse_simplex_time) return -1.0; // assert(analyse_simplex_time); return thread_simplex_clocks[thread_id].timer_pointer_->read( thread_simplex_clocks[thread_id].clock_[simplex_clock]); } HighsTimerClock* HighsSimplexAnalysis::getThreadFactorTimerClockPointer() { HighsTimerClock* factor_timer_clock_pointer = NULL; if (analyse_factor_time) { HighsInt thread_id = highs::parallel::thread_num(); factor_timer_clock_pointer = &thread_factor_clocks[thread_id]; } return factor_timer_clock_pointer; } void HighsSimplexAnalysis::iterationRecord() { assert(analyse_simplex_summary_data); HighsInt AnIterCuIt = simplex_iteration_count; if (rebuild_reason > 0) AnIterNumInvert[rebuild_reason]++; if (AnIterCuIt > AnIterPrevIt) AnIterNumEdWtIt[(HighsInt)edge_weight_mode] += (AnIterCuIt - AnIterPrevIt); AnIterTraceRec& lcAnIter = AnIterTrace[AnIterTraceNumRec]; // if (simplex_iteration_count == // AnIterTraceIterRec[AnIterTraceNumRec]+AnIterTraceIterDl) { if (simplex_iteration_count == lcAnIter.AnIterTraceIter + AnIterTraceIterDl) { if (AnIterTraceNumRec == kAnIterTraceMaxNumRec) { for (HighsInt rec = 1; rec <= kAnIterTraceMaxNumRec / 2; rec++) AnIterTrace[rec] = AnIterTrace[2 * rec]; AnIterTraceNumRec = AnIterTraceNumRec / 2; AnIterTraceIterDl = AnIterTraceIterDl * 2; } else { AnIterTraceNumRec++; AnIterTraceRec& lcAnIter = AnIterTrace[AnIterTraceNumRec]; lcAnIter.AnIterTraceIter = simplex_iteration_count; lcAnIter.AnIterTraceTime = timer_->getWallTime(); if (average_fraction_of_possible_minor_iterations_performed > 0) { lcAnIter.AnIterTraceMulti = average_fraction_of_possible_minor_iterations_performed; } else { lcAnIter.AnIterTraceMulti = 0; } lcAnIter.AnIterTraceDensity[kSimplexNlaFtran] = col_aq_density; lcAnIter.AnIterTraceDensity[kSimplexNlaBtranEp] = row_ep_density; lcAnIter.AnIterTraceDensity[kSimplexNlaPriceAp] = row_ap_density; lcAnIter.AnIterTraceDensity[kSimplexNlaFtranBfrt] = col_aq_density; if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) { lcAnIter.AnIterTraceDensity[kSimplexNlaFtranDse] = row_DSE_density; lcAnIter.AnIterTraceDensity[kSimplexNlaBtranPse] = col_steepest_edge_density; lcAnIter.AnIterTraceCostlyDse = costly_DSE_measure; } else { lcAnIter.AnIterTraceDensity[kSimplexNlaFtranDse] = 0; lcAnIter.AnIterTraceCostlyDse = 0; } lcAnIter.AnIterTrace_simplex_strategy = (HighsInt)simplex_strategy; lcAnIter.AnIterTrace_edge_weight_mode = (HighsInt)edge_weight_mode; } } AnIterPrevIt = AnIterCuIt; updateValueDistribution(primal_step, cleanup_primal_step_distribution); updateValueDistribution(dual_step, cleanup_dual_step_distribution); updateValueDistribution(primal_step, primal_step_distribution); updateValueDistribution(dual_step, dual_step_distribution); updateValueDistribution(pivot_value_from_column, simplex_pivot_distribution); updateValueDistribution(factor_pivot_threshold, factor_pivot_threshold_distribution); // Only update the distribution of legal values for // numerical_trouble. Illegal values are set in PAMI since it's not // known in minor iterations if (numerical_trouble >= 0) updateValueDistribution(numerical_trouble, numerical_trouble_distribution); updateValueDistribution(edge_weight_error, edge_weight_error_distribution); } void HighsSimplexAnalysis::iterationRecordMajor() { assert(analyse_simplex_summary_data); sum_multi_chosen += multi_chosen; sum_multi_finished += multi_finished; assert(multi_chosen > 0); const double fraction_of_possible_minor_iterations_performed = 1.0 * multi_finished / multi_chosen; if (average_fraction_of_possible_minor_iterations_performed < 0) { average_fraction_of_possible_minor_iterations_performed = fraction_of_possible_minor_iterations_performed; } else { average_fraction_of_possible_minor_iterations_performed = kRunningAverageMultiplier * fraction_of_possible_minor_iterations_performed + (1 - kRunningAverageMultiplier) * average_fraction_of_possible_minor_iterations_performed; } if (average_concurrency < 0) { average_concurrency = num_concurrency; } else { average_concurrency = kRunningAverageMultiplier * num_concurrency + (1 - kRunningAverageMultiplier) * average_concurrency; } } void HighsSimplexAnalysis::operationRecordBefore( const HighsInt operation_type, const HVector& vector, const double historical_density) { assert(analyse_simplex_summary_data); operationRecordBefore(operation_type, vector.count, historical_density); } void HighsSimplexAnalysis::operationRecordBefore( const HighsInt operation_type, const HighsInt current_count, const double historical_density) { double current_density = 1.0 * current_count / numRow; AnIterOpRec& AnIter = AnIterOp[operation_type]; AnIter.AnIterOpNumCa++; if (current_density <= AnIter.AnIterOpHyperCANCEL && historical_density <= AnIter.AnIterOpHyperTRAN) AnIter.AnIterOpNumHyperOp++; } void HighsSimplexAnalysis::operationRecordAfter(const HighsInt operation_type, const HVector& vector) { assert(analyse_simplex_summary_data); operationRecordAfter(operation_type, vector.count); } void HighsSimplexAnalysis::operationRecordAfter(const HighsInt operation_type, const HighsInt result_count) { AnIterOpRec& AnIter = AnIterOp[operation_type]; const double result_density = 1.0 * result_count / AnIter.AnIterOpRsDim; if (result_density <= kHyperResult) AnIter.AnIterOpNumHyperRs++; if (result_density > 0) { AnIter.AnIterOpSumLog10RsDensity += log(result_density) / log(10.0); } else { /* // TODO Investigate these zero norms double vectorNorm = 0; for (HighsInt index = 0; index < AnIter.AnIterOpRsDim; index++) { double vectorValue = vector.array[index]; vectorNorm += vectorValue * vectorValue; } vectorNorm = sqrt(vectorNorm); printf("Strange: operation %s has result density = %g: ||vector|| = %g\n", AnIter.AnIterOpName.c_str(), result_density, vectorNorm); */ } updateValueDistribution(result_density, AnIter.AnIterOp_density); } void HighsSimplexAnalysis::summaryReport() { assert(analyse_simplex_summary_data); HighsInt AnIterNumIter = simplex_iteration_count - AnIterIt0; if (AnIterNumIter <= 0) return; printf("\nAnalysis of %" HIGHSINT_FORMAT " iterations (%" HIGHSINT_FORMAT " to %" HIGHSINT_FORMAT ")\n", AnIterNumIter, AnIterIt0 + 1, simplex_iteration_count); if (AnIterNumIter <= 0) return; HighsInt lc_EdWtNumIter; lc_EdWtNumIter = AnIterNumEdWtIt[(HighsInt)EdgeWeightMode::kSteepestEdge]; if (lc_EdWtNumIter > 0) printf("DSE for %12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) iterations\n", lc_EdWtNumIter, (100 * lc_EdWtNumIter) / AnIterNumIter); lc_EdWtNumIter = AnIterNumEdWtIt[(HighsInt)EdgeWeightMode::kDevex]; if (lc_EdWtNumIter > 0) printf("Dvx for %12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) iterations\n", lc_EdWtNumIter, (100 * lc_EdWtNumIter) / AnIterNumIter); lc_EdWtNumIter = AnIterNumEdWtIt[(HighsInt)EdgeWeightMode::kDantzig]; if (lc_EdWtNumIter > 0) printf("Dan for %12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) iterations\n", lc_EdWtNumIter, (100 * lc_EdWtNumIter) / AnIterNumIter); for (HighsInt k = 0; k < kNumSimplexNlaOperation; k++) { AnIterOpRec& AnIter = AnIterOp[k]; HighsInt lcNumCa = AnIter.AnIterOpNumCa; printf("\n%-10s performed %" HIGHSINT_FORMAT " times\n", AnIter.AnIterOpName.c_str(), AnIter.AnIterOpNumCa); if (lcNumCa > 0) { HighsInt lcHyperOp = AnIter.AnIterOpNumHyperOp; HighsInt lcHyperRs = AnIter.AnIterOpNumHyperRs; HighsInt pctHyperOp = (100 * lcHyperOp) / lcNumCa; HighsInt pctHyperRs = (100 * lcHyperRs) / lcNumCa; double lcRsDensity = pow(10.0, AnIter.AnIterOpSumLog10RsDensity / lcNumCa); HighsInt lcAnIterOpRsDim = AnIter.AnIterOpRsDim; HighsInt lcNumNNz = lcRsDensity * lcAnIterOpRsDim; printf("%12" HIGHSINT_FORMAT " hyper-sparse operations (%3" HIGHSINT_FORMAT "%%)\n", lcHyperOp, pctHyperOp); printf("%12" HIGHSINT_FORMAT " hyper-sparse results (%3" HIGHSINT_FORMAT "%%)\n", lcHyperRs, pctHyperRs); printf("%12g density of result (%" HIGHSINT_FORMAT " / %" HIGHSINT_FORMAT " nonzeros)\n", lcRsDensity, lcNumNNz, lcAnIterOpRsDim); logValueDistribution(log_options, AnIter.AnIterOp_density, AnIter.AnIterOpRsDim); } } HighsInt NumInvert = 0; HighsInt last_rebuild_reason = kRebuildReasonCount - 1; for (HighsInt k = 1; k <= last_rebuild_reason; k++) NumInvert += AnIterNumInvert[k]; if (NumInvert > 0) { HighsInt lcNumInvert = 0; printf("\nInvert performed %" HIGHSINT_FORMAT " times: average frequency = %" HIGHSINT_FORMAT "\n", NumInvert, AnIterNumIter / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonUpdateLimitReached]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to update limit reached\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonSyntheticClockSaysInvert]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to pseudo-clock\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonPossiblyOptimal]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to possibly optimal\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonPossiblyPrimalUnbounded]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to possibly primal unbounded\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonPossiblyDualUnbounded]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to possibly dual unbounded\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonPossiblySingularBasis]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to possibly singular basis\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); lcNumInvert = AnIterNumInvert[kRebuildReasonPrimalInfeasibleInPrimalSimplex]; if (lcNumInvert > 0) printf("%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) Invert operations due to primal infeasible in primal " "simplex\n", lcNumInvert, (100 * lcNumInvert) / NumInvert); } HighsInt suPrice = num_col_price + num_row_price + num_row_price_with_switch; if (suPrice > 0) { printf("\n%12" HIGHSINT_FORMAT " Price operations:\n", suPrice); printf("%12" HIGHSINT_FORMAT " Col Price (%3" HIGHSINT_FORMAT "%%)\n", num_col_price, (100 * num_col_price) / suPrice); printf("%12" HIGHSINT_FORMAT " Row Price (%3" HIGHSINT_FORMAT "%%)\n", num_row_price, (100 * num_row_price) / suPrice); printf("%12" HIGHSINT_FORMAT " Row PriceWSw (%3" HIGHSINT_FORMAT "%%)\n", num_row_price_with_switch, (100 * num_row_price_with_switch / suPrice)); } printf("\n%12" HIGHSINT_FORMAT " (%3" HIGHSINT_FORMAT "%%) costly DSE iterations\n", num_costly_DSE_iteration, (100 * num_costly_DSE_iteration) / AnIterNumIter); // Look for any Devex data to summarise if (num_devex_framework) { printf("\nDevex summary\n"); printf("%12" HIGHSINT_FORMAT " Devex frameworks\n", num_devex_framework); printf("%12" HIGHSINT_FORMAT " average number of iterations\n", AnIterNumEdWtIt[(HighsInt)EdgeWeightMode::kDevex] / num_devex_framework); } if (num_primal_cycling_detections + num_dual_cycling_detections) { printf("\nCycling detected %" HIGHSINT_FORMAT " times:", num_primal_cycling_detections + num_dual_cycling_detections); if (num_primal_cycling_detections) { printf("%" HIGHSINT_FORMAT " in primal simplex", num_primal_cycling_detections); if (num_dual_cycling_detections) printf("; "); } if (num_dual_cycling_detections) printf("%" HIGHSINT_FORMAT " in dual simplex", num_dual_cycling_detections); printf("\n"); } const double average_quad_chuzc_size = num_quad_chuzc ? sum_quad_chuzc_size / num_quad_chuzc : 0; const double average_heap_chuzc_size = num_heap_chuzc ? sum_heap_chuzc_size / num_heap_chuzc : 0; if (num_quad_chuzc + num_heap_chuzc) { printf("\nQuad/heap CHUZC summary\n"); if (num_quad_chuzc) printf("%12" HIGHSINT_FORMAT " quad CHUZC: average / max = %d / %" HIGHSINT_FORMAT "\n", num_quad_chuzc, (int)average_quad_chuzc_size, max_quad_chuzc_size); if (num_heap_chuzc) printf("%12" HIGHSINT_FORMAT " heap CHUZC: average / max = %d / %" HIGHSINT_FORMAT "\n", num_heap_chuzc, (int)average_heap_chuzc_size, max_heap_chuzc_size); } printf("\ngrepQuadHeapChuzc,%s,%s, %" HIGHSINT_FORMAT ", ,%d,%" HIGHSINT_FORMAT ", %" HIGHSINT_FORMAT ", ,%d,%" HIGHSINT_FORMAT "\n", model_name_.c_str(), lp_name_.c_str(), num_quad_chuzc, (int)average_quad_chuzc_size, max_quad_chuzc_size, num_heap_chuzc, (int)average_heap_chuzc_size, max_heap_chuzc_size); if (num_improve_choose_column_row_call >= 0) { printf("\nDual_CHUZC: Number of improve CHUZC row calls = %d\n", (int)num_improve_choose_column_row_call); printf("Dual_CHUZC: Number of pivots removed from pack = %d\n", (int)num_remove_pivot_from_pack); } else { assert(num_remove_pivot_from_pack == 0); } if (num_correct_dual_primal_flip + num_correct_dual_cost_shift + num_single_cost_shift) { printf("\nFlip/shift summary\n"); if (num_correct_dual_primal_flip) { printf( "%12" HIGHSINT_FORMAT " correct dual primal flips (max = %g) for min dual infeasiblity " "= %g\n", num_correct_dual_primal_flip, max_correct_dual_primal_flip, min_correct_dual_primal_flip_dual_infeasibility); } if (num_correct_dual_cost_shift) { printf( "%12" HIGHSINT_FORMAT " correct dual cost shifts (max = %g) for max dual infeasiblity " "= %g\n", num_correct_dual_cost_shift, max_correct_dual_cost_shift, max_correct_dual_cost_shift_dual_infeasibility); } if (num_single_cost_shift) { printf("%12" HIGHSINT_FORMAT " single cost shifts (sum / max = %g / %g)\n", num_single_cost_shift, sum_single_cost_shift, max_single_cost_shift); } } printf("\ngrepFlipShift,%s,%s,%" HIGHSINT_FORMAT ",%g,%g,%" HIGHSINT_FORMAT ",%g,%g,%" HIGHSINT_FORMAT ",%g,%g\n", model_name_.c_str(), lp_name_.c_str(), num_correct_dual_primal_flip, max_correct_dual_primal_flip, min_correct_dual_primal_flip_dual_infeasibility, num_correct_dual_cost_shift, max_correct_dual_cost_shift, max_correct_dual_cost_shift_dual_infeasibility, num_single_cost_shift, sum_single_cost_shift, max_single_cost_shift); // Look for any PAMI data to summarise if (sum_multi_chosen > 0) { const HighsInt pct_minor_iterations_performed = (100 * sum_multi_finished) / sum_multi_chosen; printf("\nPAMI summary: for average of %0.1g threads \n", average_concurrency); printf("%12" HIGHSINT_FORMAT " Major iterations\n", multi_iteration_count); printf("%12" HIGHSINT_FORMAT " Minor iterations\n", sum_multi_finished); printf("%12" HIGHSINT_FORMAT " Total rows chosen: performed %3" HIGHSINT_FORMAT "%% of possible minor " "iterations\n\n", sum_multi_chosen, pct_minor_iterations_performed); } highsLogDev(log_options, HighsLogType::kInfo, "\nCost perturbation summary\n"); logValueDistribution(log_options, cost_perturbation1_distribution); logValueDistribution(log_options, cost_perturbation2_distribution); logValueDistribution(log_options, before_ftran_upper_sparse_density, numRow); logValueDistribution(log_options, ftran_upper_sparse_density, numRow); logValueDistribution(log_options, before_ftran_upper_hyper_density, numRow); logValueDistribution(log_options, ftran_upper_hyper_density, numRow); logValueDistribution(log_options, primal_step_distribution); logValueDistribution(log_options, dual_step_distribution); logValueDistribution(log_options, simplex_pivot_distribution); logValueDistribution(log_options, factor_pivot_threshold_distribution); logValueDistribution(log_options, numerical_trouble_distribution); logValueDistribution(log_options, edge_weight_error_distribution); logValueDistribution(log_options, cleanup_dual_change_distribution); logValueDistribution(log_options, cleanup_primal_step_distribution); logValueDistribution(log_options, cleanup_dual_step_distribution); logValueDistribution(log_options, cleanup_primal_change_distribution); if (AnIterTraceIterDl >= 100) { // Possibly (usually) add a temporary record for the final // iterations: may end up with one more than // kAnIterTraceMaxNumRec records, so ensure that there is // enough space in the arrays // const bool add_extra_record = simplex_iteration_count > AnIterTrace[AnIterTraceNumRec].AnIterTraceIter; if (add_extra_record) { AnIterTraceNumRec++; AnIterTraceRec& lcAnIter = AnIterTrace[AnIterTraceNumRec]; lcAnIter.AnIterTraceIter = simplex_iteration_count; lcAnIter.AnIterTraceTime = timer_->getWallTime(); if (average_fraction_of_possible_minor_iterations_performed > 0) { lcAnIter.AnIterTraceMulti = average_fraction_of_possible_minor_iterations_performed; } else { lcAnIter.AnIterTraceMulti = 0; } lcAnIter.AnIterTraceDensity[kSimplexNlaFtran] = col_aq_density; lcAnIter.AnIterTraceDensity[kSimplexNlaBtranEp] = row_ep_density; lcAnIter.AnIterTraceDensity[kSimplexNlaPriceAp] = row_ap_density; lcAnIter.AnIterTraceDensity[kSimplexNlaFtranBfrt] = col_aq_density; if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) { lcAnIter.AnIterTraceDensity[kSimplexNlaFtranDse] = row_DSE_density; lcAnIter.AnIterTraceDensity[kSimplexNlaBtranPse] = col_steepest_edge_density; lcAnIter.AnIterTraceCostlyDse = costly_DSE_measure; } else { lcAnIter.AnIterTraceDensity[kSimplexNlaFtranDse] = 0; lcAnIter.AnIterTraceCostlyDse = 0; } lcAnIter.AnIterTrace_simplex_strategy = (HighsInt)simplex_strategy; lcAnIter.AnIterTrace_edge_weight_mode = (HighsInt)edge_weight_mode; } // Determine whether the Multi and steepest edge columns should be reported double su_multi_values = 0; double su_dse_values = 0; double su_pse_values = 0; for (HighsInt rec = 1; rec <= AnIterTraceNumRec; rec++) { AnIterTraceRec& lcAnIter = AnIterTrace[rec]; su_multi_values += fabs(lcAnIter.AnIterTraceMulti); su_dse_values += fabs(lcAnIter.AnIterTraceDensity[kSimplexNlaFtranDse]); su_pse_values += fabs(lcAnIter.AnIterTraceDensity[kSimplexNlaBtranPse]); } const bool report_multi = su_multi_values > 0; const bool rp_dual_steepest_edge = su_dse_values > 0; const bool rp_primal_steepest_edge = su_pse_values > 0; printf("\n Iteration speed analysis\n"); AnIterTraceRec& lcAnIter = AnIterTrace[0]; HighsInt fmIter = lcAnIter.AnIterTraceIter; double fmTime = lcAnIter.AnIterTraceTime; printf(" Iter ( FmIter: ToIter) Time Iter/sec "); if (report_multi) printf("| PAMI "); printf("| C_Aq R_Ep R_Ap "); if (rp_dual_steepest_edge) printf(" DSE "); if (rp_primal_steepest_edge) printf(" PSE "); printf("| EdWt "); if (rp_dual_steepest_edge) { printf("| CostlyDse\n"); } else { printf("\n"); } for (HighsInt rec = 1; rec <= AnIterTraceNumRec; rec++) { AnIterTraceRec& lcAnIter = AnIterTrace[rec]; HighsInt toIter = lcAnIter.AnIterTraceIter; double toTime = lcAnIter.AnIterTraceTime; HighsInt dlIter = toIter - fmIter; if (rec < AnIterTraceNumRec && dlIter != AnIterTraceIterDl) printf("STRANGE: %" HIGHSINT_FORMAT " = dlIter != AnIterTraceIterDl = %" HIGHSINT_FORMAT "\n", dlIter, AnIterTraceIterDl); double dlTime = toTime - fmTime; HighsInt iterSpeed = 0; if (dlTime > 0) iterSpeed = dlIter / dlTime; HighsInt lc_simplex_strategy = lcAnIter.AnIterTrace_simplex_strategy; HighsInt lc_edge_weight_mode = lcAnIter.AnIterTrace_edge_weight_mode; std::string str_edge_weight_mode; if (lc_edge_weight_mode == (HighsInt)EdgeWeightMode::kSteepestEdge) str_edge_weight_mode = "DSE"; else if (lc_edge_weight_mode == (HighsInt)EdgeWeightMode::kDevex) str_edge_weight_mode = "Dvx"; else if (lc_edge_weight_mode == (HighsInt)EdgeWeightMode::kDantzig) str_edge_weight_mode = "Dan"; else str_edge_weight_mode = "XXX"; printf("%12" HIGHSINT_FORMAT " (%12" HIGHSINT_FORMAT ":%12" HIGHSINT_FORMAT ") %9.4f %12" HIGHSINT_FORMAT " ", dlIter, fmIter, toIter, dlTime, iterSpeed); if (report_multi) { const HighsInt pct = (100 * lcAnIter.AnIterTraceMulti); printf("| %3" HIGHSINT_FORMAT " ", pct); } printf("|"); printOneDensity(lcAnIter.AnIterTraceDensity[kSimplexNlaFtran]); printOneDensity(lcAnIter.AnIterTraceDensity[kSimplexNlaBtranEp]); printOneDensity(lcAnIter.AnIterTraceDensity[kSimplexNlaPriceAp]); double use_DSE_density; HighsInt local_simplex_strategy = lcAnIter.AnIterTrace_simplex_strategy; if (rp_dual_steepest_edge) { if (lc_edge_weight_mode == (HighsInt)EdgeWeightMode::kSteepestEdge) { use_DSE_density = lcAnIter.AnIterTraceDensity[kSimplexNlaFtranDse]; } else { use_DSE_density = 0; } printOneDensity(use_DSE_density); } printf(" | %3s ", str_edge_weight_mode.c_str()); if (rp_dual_steepest_edge) { double use_costly_dse; printf("| "); if (lc_edge_weight_mode == (HighsInt)EdgeWeightMode::kSteepestEdge) { use_costly_dse = lcAnIter.AnIterTraceCostlyDse; } else { use_costly_dse = 0; } printOneDensity(use_costly_dse); } printf("\n"); fmIter = toIter; fmTime = toTime; } printf("\n"); // Remove any temporary record added for the final iterations if (add_extra_record) AnIterTraceNumRec--; } } void HighsSimplexAnalysis::summaryReportFactor() { for (HighsInt tran_stage_type = 0; tran_stage_type < NUM_TRAN_STAGE_TYPE; tran_stage_type++) { TranStageAnalysis& stage = tran_stage[tran_stage_type]; // printScatterData(stage.name_, stage.rhs_density_); printScatterDataRegressionComparison(stage.name_, stage.rhs_density_); if (!stage.num_decision_) return; printf("Of %10" HIGHSINT_FORMAT " Sps/Hyper decisions made using regression:\n", stage.num_decision_); printf(" %10" HIGHSINT_FORMAT " wrong sparseTRAN; %10" HIGHSINT_FORMAT " wrong hyperTRAN: using original " "logic\n", stage.num_wrong_original_sparse_decision_, stage.num_wrong_original_hyper_decision_); printf(" %10" HIGHSINT_FORMAT " wrong sparseTRAN; %10" HIGHSINT_FORMAT " wrong hyperTRAN: using new " "logic\n", stage.num_wrong_new_sparse_decision_, stage.num_wrong_new_hyper_decision_); } } void HighsSimplexAnalysis::reportSimplexTimer() { assert(analyse_simplex_time); SimplexTimer simplex_timer; simplex_timer.reportSimplexInnerClock(thread_simplex_clocks[0]); } void HighsSimplexAnalysis::reportFactorTimer() { assert(analyse_factor_time); FactorTimer factor_timer; HighsInt max_threads = highs::parallel::num_threads(); for (HighsInt i = 0; i < max_threads; i++) { // for (HighsTimerClock clock : thread_factor_clocks) { printf("reportFactorTimer: HFactor clocks for thread %" HIGHSINT_FORMAT " / %" HIGHSINT_FORMAT "\n", i, max_threads - 1); factor_timer.reportFactorClock(thread_factor_clocks[i]); } if (max_threads > 1) { HighsTimer* timer_pointer = thread_factor_clocks[0].timer_pointer_; HighsTimerClock all_factor_clocks; all_factor_clocks.timer_pointer_ = timer_pointer; vector& clock = all_factor_clocks.clock_; factor_timer.initialiseFactorClocks(all_factor_clocks); for (HighsInt i = 0; i < max_threads; i++) { vector& thread_clock = thread_factor_clocks[i].clock_; for (HighsInt clock_id = 0; clock_id < FactorNumClock; clock_id++) { HighsInt all_factor_iClock = clock[clock_id]; HighsInt thread_factor_iClock = thread_clock[clock_id]; timer_pointer->clock_num_call[all_factor_iClock] += timer_pointer->clock_num_call[thread_factor_iClock]; timer_pointer->clock_time[all_factor_iClock] += timer_pointer->clock_time[thread_factor_iClock]; } } printf("reportFactorTimer: HFactor clocks for all %" HIGHSINT_FORMAT " threads\n", max_threads); factor_timer.reportFactorClock(all_factor_clocks); } } void HighsSimplexAnalysis::updateInvertFormData(const HFactor& factor) { assert(analyse_factor_data); const bool report_kernel = false; num_invert++; assert(factor.basis_matrix_num_el); double invert_fill_factor = ((1.0 * factor.invert_num_el) / factor.basis_matrix_num_el); if (report_kernel) printf("INVERT fill = %6.2f", invert_fill_factor); sum_invert_fill_factor += invert_fill_factor; running_average_invert_fill_factor = 0.95 * running_average_invert_fill_factor + 0.05 * invert_fill_factor; double kernel_relative_dim = (1.0 * factor.kernel_dim) / numRow; if (report_kernel) printf("; kernel dim = %11.4g", kernel_relative_dim); if (factor.kernel_dim) { num_kernel++; max_kernel_dim = max(kernel_relative_dim, max_kernel_dim); sum_kernel_dim += kernel_relative_dim; running_average_kernel_dim = 0.95 * running_average_kernel_dim + 0.05 * kernel_relative_dim; HighsInt kernel_invert_num_el = factor.invert_num_el - (factor.basis_matrix_num_el - factor.kernel_num_el); assert(factor.kernel_num_el); double kernel_fill_factor = (1.0 * kernel_invert_num_el) / factor.kernel_num_el; sum_kernel_fill_factor += kernel_fill_factor; running_average_kernel_fill_factor = 0.95 * running_average_kernel_fill_factor + 0.05 * kernel_fill_factor; if (report_kernel) printf("; fill = %6.2f", kernel_fill_factor); const double kMajorKernelRelativeDimThreshold = 0.1; if (kernel_relative_dim > kMajorKernelRelativeDimThreshold) { num_major_kernel++; sum_major_kernel_fill_factor += kernel_fill_factor; running_average_major_kernel_fill_factor = 0.95 * running_average_major_kernel_fill_factor + 0.05 * kernel_fill_factor; } } if (report_kernel) printf("\n"); } void HighsSimplexAnalysis::reportInvertFormData() { assert(analyse_factor_data); printf("grep_kernel,%s,%s,%" HIGHSINT_FORMAT ",%" HIGHSINT_FORMAT ",%" HIGHSINT_FORMAT ",", model_name_.c_str(), lp_name_.c_str(), num_invert, num_kernel, num_major_kernel); if (num_kernel) printf("%g", sum_kernel_dim / num_kernel); printf(",%g,%g,", running_average_kernel_dim, max_kernel_dim); if (num_invert) printf("Fill-in,%g", sum_invert_fill_factor / num_invert); printf(","); if (num_kernel) printf("%g", sum_kernel_fill_factor / num_kernel); printf(","); if (num_major_kernel) printf("%g", sum_major_kernel_fill_factor / num_major_kernel); printf(",%g,%g,%g\n", running_average_invert_fill_factor, running_average_kernel_fill_factor, running_average_major_kernel_fill_factor); } void HighsSimplexAnalysis::iterationReport(const bool header) { analysis_log = std::unique_ptr(new std::stringstream()); if (!header) { if (dualAlgorithm()) { if (pivotal_row_index < 0) return; } else { if (entering_variable < 0) return; } } reportAlgorithmPhase(header); reportIterationObjective(header); if (analyse_simplex_runtime_data) { reportDensity(header); reportIterationData(header); reportInfeasibility(header); } highsLogDev(log_options, kIterationReportLogType, "%s\n", analysis_log->str().c_str()); if (!header) num_iteration_report_since_last_header++; } void HighsSimplexAnalysis::reportAlgorithmPhase(const bool header) { if (header) { *analysis_log << " "; } else { std::string algorithm_name; if (dualAlgorithm()) { algorithm_name = "Du"; } else { algorithm_name = "Pr"; } *analysis_log << highsFormatToString("%2sPh%1" HIGHSINT_FORMAT, algorithm_name.c_str(), solve_phase); } } void HighsSimplexAnalysis::reportIterationObjective(const bool header) { if (header) { *analysis_log << " Iteration Objective "; } else { *analysis_log << highsFormatToString(" %10" HIGHSINT_FORMAT " %20.10e", simplex_iteration_count, objective_value); } } void HighsSimplexAnalysis::reportInfeasibility(const bool header) { if (header) { *analysis_log << " Infeasibilities num(sum)"; } else { // Primal infeasibility information may not be known if dual ray // has proved primal infeasibility if (num_primal_infeasibility <= kHighsIllegalInfeasibilityCount || sum_primal_infeasibility >= kHighsIllegalInfeasibilityMeasure) return; if (solve_phase == 1) { *analysis_log << highsFormatToString(" Ph1: %" HIGHSINT_FORMAT "(%g)", num_primal_infeasibility, sum_primal_infeasibility); } else { *analysis_log << highsFormatToString(" Pr: %" HIGHSINT_FORMAT "(%g)", num_primal_infeasibility, sum_primal_infeasibility); } if (sum_dual_infeasibility > 0) { *analysis_log << highsFormatToString("; Du: %" HIGHSINT_FORMAT "(%g)", num_dual_infeasibility, sum_dual_infeasibility); } } } void HighsSimplexAnalysis::reportThreads(const bool header) { assert(analyse_simplex_runtime_data); if (header) { *analysis_log << highsFormatToString(" Concurr."); } else if (num_concurrency > 0) { *analysis_log << highsFormatToString( " %2" HIGHSINT_FORMAT "|%2" HIGHSINT_FORMAT "|%2" HIGHSINT_FORMAT "", min_concurrency, num_concurrency, max_concurrency); } else { *analysis_log << highsFormatToString(" | | "); } } void HighsSimplexAnalysis::reportMulti(const bool header) { assert(analyse_simplex_runtime_data); if (header) { *analysis_log << highsFormatToString(" Multi"); } else if (average_fraction_of_possible_minor_iterations_performed >= 0) { *analysis_log << highsFormatToString( " %3" HIGHSINT_FORMAT "%%", (HighsInt)(100 * average_fraction_of_possible_minor_iterations_performed)); } else { *analysis_log << highsFormatToString(" "); } } void HighsSimplexAnalysis::reportOneDensity(const double density) { assert( // analyse_simplex_summary_data || analyse_simplex_runtime_data); const HighsInt log_10_density = intLog10(density); if (log_10_density > -99) { *analysis_log << highsFormatToString(" %4" HIGHSINT_FORMAT "", log_10_density); } else { *analysis_log << highsFormatToString(" "); } } void HighsSimplexAnalysis::printOneDensity(const double density) { assert(analyse_simplex_summary_data || analyse_simplex_runtime_data); const HighsInt log_10_density = intLog10(density); if (log_10_density > -99) { printf(" %4" HIGHSINT_FORMAT "", log_10_density); } else { printf(" "); } } void HighsSimplexAnalysis::reportDensity(const bool header) { assert(analyse_simplex_runtime_data); const bool rp_steepest_edge = edge_weight_mode == EdgeWeightMode::kSteepestEdge; if (header) { *analysis_log << highsFormatToString(" C_Aq R_Ep R_Ap"); if (rp_steepest_edge) { *analysis_log << highsFormatToString(" S_Ed"); } else { *analysis_log << highsFormatToString(" "); } } else { reportOneDensity(col_aq_density); reportOneDensity(row_ep_density); reportOneDensity(row_ap_density); double use_steepest_edge_density; if (rp_steepest_edge) { if (simplex_strategy == kSimplexStrategyPrimal) { use_steepest_edge_density = col_steepest_edge_density; } else { use_steepest_edge_density = row_DSE_density; } } else { use_steepest_edge_density = 0; } reportOneDensity(use_steepest_edge_density); } } void HighsSimplexAnalysis::reportInvert(const bool header) { if (header) return; *analysis_log << " " << rebuild_reason_string; } /* void HighsSimplexAnalysis::reportCondition(const bool header) { assert(analyse_simplex_runtime_data); if (header) { *analysis_log << highsFormatToString(" k(B)"); } else { *analysis_log << highsFormatToString(" %10.4g", basis_condition); } } */ // Primal: // * primal_delta - 0 // * dual_step - ThDu (theta_dual) - dual infeasibility from CHUZC // * primal_step - ThPr (theta_primal_ - primal step from CHUZR // // Dual: // * primal_delta - DlPr (delta_primal) - primal infeasibility from CHUZR // * dual_step - ThDu (theta_dual) - dual step from CHUZC // * primal_step - ThPr (theta_primal) - step to bound of leaving variable // after pivoting void HighsSimplexAnalysis::reportIterationData(const bool header) { if (header) { *analysis_log << highsFormatToString( " EnC LvC LvR ThDu ThPr " "DlPr NumCk Aa"); } else if (pivotal_row_index >= 0) { *analysis_log << highsFormatToString( " %7" HIGHSINT_FORMAT " %7" HIGHSINT_FORMAT " %7" HIGHSINT_FORMAT, entering_variable, leaving_variable, pivotal_row_index); if (entering_variable >= 0) { *analysis_log << highsFormatToString( " %11.4g %11.4g %11.4g %11.4g %11.4g", dual_step, primal_step, primal_delta, numerical_trouble, pivot_value_from_column); } else { // Unboundedness in dual simplex assert(dualAlgorithm()); *analysis_log << highsFormatToString( " %11.4g ", primal_delta); } } else { // Bound swap in primal simplex assert(!dualAlgorithm()); *analysis_log << highsFormatToString( " %7" HIGHSINT_FORMAT " %7" HIGHSINT_FORMAT " %7" HIGHSINT_FORMAT " %11.4g %11.4g ", entering_variable, leaving_variable, pivotal_row_index, dual_step, primal_step); } } void HighsSimplexAnalysis::reportRunTime(const bool header, const double run_time) { if (header) return; *analysis_log << highsFormatToString(" %ds", (int)run_time); } HighsInt HighsSimplexAnalysis::intLog10(const double v) { double log10V = v > 0 ? -2.0 * log(v) / log(10.0) : 99; HighsInt intLog10V = log10V; return intLog10V; } bool HighsSimplexAnalysis::dualAlgorithm() { return (simplex_strategy == kSimplexStrategyDual || simplex_strategy == kSimplexStrategyDualTasks || simplex_strategy == kSimplexStrategyDualMulti); }