@@ -841,8 +841,9 @@ HighsStatus Highs::writeBasis(const std::string& filename) {
841841}
842842
843843HighsStatus Highs::presolve () {
844+ const HighsLogOptions& log_options = options_.log_options ;
844845 if (model_.needsMods (options_.infinite_cost )) {
845- highsLogUser (options_. log_options , HighsLogType::kError ,
846+ highsLogUser (log_options, HighsLogType::kError ,
846847 " Model contains infinite costs or semi-variables, so cannot "
847848 " be presolved independently\n " );
848849 return HighsStatus::kError ;
@@ -861,7 +862,7 @@ HighsStatus Highs::presolve() {
861862 max_threads = highs::parallel::num_threads ();
862863 if (options_.threads != 0 && max_threads != options_.threads ) {
863864 highsLogUser (
864- options_. log_options , HighsLogType::kError ,
865+ log_options, HighsLogType::kError ,
865866 " Option 'threads' is set to %d but global scheduler has already been "
866867 " initialized to use %d threads. The previous scheduler instance can "
867868 " be destroyed by calling Highs::resetGlobalScheduler().\n " ,
@@ -873,6 +874,8 @@ HighsStatus Highs::presolve() {
873874 }
874875
875876 bool using_reduced_lp = false ;
877+ reportPresolveReductions (log_options, model_presolve_status_, model_.lp_ ,
878+ presolve_.getReducedProblem ());
876879 switch (model_presolve_status_) {
877880 case HighsPresolveStatus::kNotPresolved : {
878881 // Shouldn't happen
@@ -915,7 +918,7 @@ HighsStatus Highs::presolve() {
915918 default : {
916919 // case HighsPresolveStatus::kOutOfMemory
917920 assert (model_presolve_status_ == HighsPresolveStatus::kOutOfMemory );
918- highsLogUser (options_. log_options , HighsLogType::kError ,
921+ highsLogUser (log_options, HighsLogType::kError ,
919922 " Presolve fails due to memory allocation error\n " );
920923 setHighsModelStatusAndClearSolutionAndBasis (
921924 HighsModelStatus::kPresolveError );
@@ -927,8 +930,7 @@ HighsStatus Highs::presolve() {
927930 presolved_model_.lp_ .setMatrixDimensions ();
928931 }
929932
930- highsLogUser (options_.log_options , HighsLogType::kInfo ,
931- " Presolve status: %s\n " ,
933+ highsLogUser (log_options, HighsLogType::kInfo , " Presolve status: %s\n " ,
932934 presolveStatusToString (model_presolve_status_).c_str ());
933935 return returnFromHighs (return_status);
934936}
@@ -1400,6 +1402,9 @@ HighsStatus Highs::optimizeModel() {
14001402 // presolved problem, since the iteration count is reset to zero
14011403 // if PDLP is used to clean up after postsolve
14021404 HighsInt presolved_lp_pdlp_iteration_count = 0 ;
1405+ // Log the presolve reductions
1406+ reportPresolveReductions (log_options, model_presolve_status_, incumbent_lp,
1407+ presolve_.getReducedProblem ());
14031408 switch (model_presolve_status_) {
14041409 case HighsPresolveStatus::kNotPresolved : {
14051410 ekk_instance_.lp_name_ = " Original LP" ;
@@ -1414,7 +1419,6 @@ HighsStatus Highs::optimizeModel() {
14141419 case HighsPresolveStatus::kNotReduced : {
14151420 ekk_instance_.lp_name_ = " Unreduced LP" ;
14161421 // Log the presolve reductions
1417- reportPresolveReductions (log_options, incumbent_lp, false );
14181422 solveLp (incumbent_lp, " Problem not reduced by presolve: solving the LP" ,
14191423 this_solve_original_lp_time);
14201424 return_status = interpretCallStatus (options_.log_options , call_status,
@@ -1454,8 +1458,6 @@ HighsStatus Highs::optimizeModel() {
14541458 return_status,
14551459 " cleanBounds" ) == HighsStatus::kError )
14561460 return HighsStatus::kError ;
1457- // Log the presolve reductions
1458- reportPresolveReductions (log_options, incumbent_lp, reduced_lp);
14591461 // Solving the presolved LP with strictly reduced dimensions
14601462 // so ensure that the Ekk instance is cleared
14611463 ekk_instance_.clear ();
@@ -1495,7 +1497,6 @@ HighsStatus Highs::optimizeModel() {
14951497 break ;
14961498 }
14971499 case HighsPresolveStatus::kReducedToEmpty : {
1498- reportPresolveReductions (log_options, incumbent_lp, true );
14991500 // Create a trivial optimal solution for postsolve to use
15001501 solution_.clear ();
15011502 basis_.clear ();
@@ -1625,6 +1626,9 @@ HighsStatus Highs::optimizeModel() {
16251626 presolve_.data_ .recovered_solution_ = solution_;
16261627 presolve_.data_ .recovered_basis_ = basis_;
16271628
1629+ if (model_presolve_status_ == HighsPresolveStatus::kReduced )
1630+ this ->lpKktCheck (presolve_.getReducedProblem (), " Before postsolve" );
1631+
16281632 this_postsolve_time = -timer_.read (timer_.postsolve_clock );
16291633 timer_.start (timer_.postsolve_clock );
16301634 HighsPostsolveStatus postsolve_status = runPostsolve ();
@@ -1633,8 +1637,11 @@ HighsStatus Highs::optimizeModel() {
16331637 presolve_.info_ .postsolve_time = this_postsolve_time;
16341638
16351639 if (postsolve_status == HighsPostsolveStatus::kSolutionRecovered ) {
1636- highsLogDev (log_options, HighsLogType::kVerbose ,
1637- " Postsolve finished\n " );
1640+ // Indicate that nontrivial postsolve has been performed
1641+ if (model_presolve_status_ == HighsPresolveStatus::kReduced ||
1642+ model_presolve_status_ == HighsPresolveStatus::kReducedToEmpty )
1643+ highsLogUser (log_options, HighsLogType::kInfo ,
1644+ " Performed postsolve\n " );
16381645 // Set solution and its status
16391646 solution_.clear ();
16401647 solution_ = presolve_.data_ .recovered_solution_ ;
@@ -1646,7 +1653,6 @@ HighsStatus Highs::optimizeModel() {
16461653 // and IPX determined optimality
16471654 solution_.dual_valid = true ;
16481655 this ->invalidateBasis ();
1649- this ->lpKktCheck (" After postsolve" );
16501656 } else {
16511657 //
16521658 // Hot-start the simplex solver for the incumbent LP
@@ -1779,7 +1785,7 @@ HighsStatus Highs::optimizeModel() {
17791785 // Unless the model status was determined using the strictly reduced LP, the
17801786 // HiGHS info is valid
17811787 if (!no_incumbent_lp_solution_or_basis) {
1782- this ->lpKktCheck (" On exit from optimizeModel() " );
1788+ this ->lpKktCheck (this -> model_ . lp_ );
17831789 info_.valid = true ;
17841790 }
17851791
@@ -2308,7 +2314,7 @@ HighsStatus Highs::setSolution(const HighsInt num_entries,
23082314 highsLogUser (options_.log_options , HighsLogType::kWarning ,
23092315 " setSolution: User set of indices has %d duplicate%s: last "
23102316 " value used\n " ,
2311- int (num_duplicates), num_duplicates > 1 ? " s " : " " );
2317+ int (num_duplicates), num_duplicates == 1 ? " " : " s " );
23122318 return_status = HighsStatus::kWarning ;
23132319 }
23142320
@@ -3522,8 +3528,8 @@ HighsPresolveStatus Highs::runPresolve(const bool force_lp_presolve,
35223528 // Start the MIP solver's timer so that timeout in presolve can be
35233529 // identified
35243530 solver.timer_ .start ();
3525- // Only place that HighsMipSolver::runPresolve is called
3526- solver.runPresolve (options_.presolve_reduction_limit );
3531+ // Only place that HighsMipSolver::runMipPresolve is called
3532+ solver.runMipPresolve (options_.presolve_reduction_limit );
35273533 presolve_return_status = solver.getPresolveStatus ();
35283534 // Assign values to data members of presolve_
35293535 presolve_.data_ .reduced_lp_ = solver.getPresolvedModel ();
@@ -4299,9 +4305,6 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
42994305 getKktFailures (this ->options_ , is_qp, this ->model_ .lp_ ,
43004306 this ->model_ .lp_ .col_cost_ , this ->solution_ , this ->info_ ,
43014307 get_residuals);
4302- highsLogUser (options_.log_options , HighsLogType::kInfo , " \n " );
4303- reportLpKktFailures (this ->model_ .lp_ , this ->options_ , this ->info_ ,
4304- " After postsolve" );
43054308 if (info_.num_primal_infeasibilities == 0 &&
43064309 info_.num_dual_infeasibilities == 0 ) {
43074310 model_status_ = HighsModelStatus::kOptimal ;
0 commit comments