@@ -1401,6 +1401,20 @@ bool HighsMipSolverData::addIncumbent(const std::vector<double>& sol,
14011401 sol, possibly_store_as_new_incumbent)
14021402 : 0 ;
14031403
1404+ if (solution_source == kSolutionSourceHighsSolution ) {
1405+ printf (
1406+ " HighsMipSolverData::addIncumbent HiGHS solution Offset = %15.8g; Obj "
1407+ " = %15.8g; UB = %15.8g; PossAdd = %s" ,
1408+ mipsolver.model_ ->offset_ , solobj, upper_bound,
1409+ possibly_store_as_new_incumbent ? " T" : " F" );
1410+ if (possibly_store_as_new_incumbent) {
1411+ printf (" ; TransObj = %15.8g; TransSolobj < UB %s \n " , transformed_solobj,
1412+ transformed_solobj < upper_bound ? " T" : " F" );
1413+ } else {
1414+ printf (" \n " );
1415+ }
1416+ fflush (stdout);
1417+ }
14041418 if (possibly_store_as_new_incumbent) {
14051419 solobj = transformed_solobj;
14061420 if (solobj >= upper_bound) return false ;
@@ -2677,18 +2691,57 @@ void HighsMipSolverData::queryExternalSolution(
26772691 if (!mipsolver.options_mip_ ->mip_race_read_solutions ) return ;
26782692 MipRace& mip_race = mipsolver.mip_race_ ;
26792693 if (!mip_race.record ) return ;
2680- double instance_solution_objective_value = kHighsInf ;
2694+ double instance_objective_value = kHighsInf ;
26812695 std::vector<double > instance_solution;
26822696 for (HighsInt instance = 0 ; instance < mipRaceConcurrency (); instance++) {
26832697 if (instance == mip_race.my_instance ) continue ;
2684- if (!mip_race.newSolution (instance, instance_solution_objective_value ,
2698+ if (!mip_race.newSolution (instance, instance_objective_value ,
26852699 instance_solution))
26862700 continue ;
26872701 // Have read a new incumbent
2688- std::vector<double > reduced_instance_solution;
2689- reduced_instance_solution =
2702+ //
2703+ // Objective is assumed to be original_offset + (original_c)^T(original_x),
2704+ // but MIP solver bounds are based on the reduced objective
2705+ // (reduced_c)^T(reduced_x)
2706+ //
2707+ // Now, original_sense*[reduced_offset + (reduced_c)^T(reduced_x)] is an
2708+ // objective in the original space, so
2709+ //
2710+ // f0 + c0^Tx0 = s*(f1 + c1^Tx1)
2711+ //
2712+ // where 0 => original; 1 => reduced
2713+ //
2714+ // This allows the reduced objective value to be deduced as
2715+ //
2716+ // c1^Tx1 = s*(f0 + c0^Tx0) - f1
2717+ //
2718+ // (reduced_c)^T(reduced_x) = original_sense*[original_offset +
2719+ // (original_c)^T(original_x) - reduced_offset]
2720+ //
2721+ double reduced_instance_objective_value = instance_objective_value;
2722+ reduced_instance_objective_value *= int (mipsolver.orig_model_ ->sense_ );
2723+ reduced_instance_objective_value -= mipsolver.model_ ->offset_ ;
2724+ // Get the solution in the reduced space
2725+ std::vector<double > reduced_instance_solution =
26902726 postSolveStack.getReducedPrimalSolution (instance_solution);
2691- addIncumbent (reduced_instance_solution, instance_solution_objective_value,
2727+
2728+ double check_objective_value = 0 ;
2729+ for (HighsInt iCol = 0 ; iCol < mipsolver.model_ ->num_col_ ; iCol++)
2730+ check_objective_value +=
2731+ mipsolver.colCost (iCol) * reduced_instance_solution[iCol];
2732+ double dl_objective_value =
2733+ std::fabs (check_objective_value - reduced_instance_objective_value);
2734+ assert (dl_objective_value < 1e-12 * (1 + std::fabs (check_objective_value)));
2735+ printf (
2736+ " HighsMipSolverData::queryExternalSolution: (sense = %d; offset = "
2737+ " %11.4g) modified objective from %11.4g to %11.4g (Check = %11.4g; "
2738+ " Delta = %11.4g)\n " ,
2739+ int (mipsolver.orig_model_ ->sense_ ), mipsolver.model_ ->offset_ ,
2740+ instance_objective_value, reduced_instance_objective_value,
2741+ check_objective_value, dl_objective_value);
2742+ fflush (stdout);
2743+
2744+ addIncumbent (reduced_instance_solution, reduced_instance_objective_value,
26922745 kSolutionSourceHighsSolution );
26932746 }
26942747}
@@ -2956,15 +3009,15 @@ void MipRaceRecord::report(const HighsLogOptions log_options) const {
29563009 highsLogUser (log_options, HighsLogType::kInfo , " \n StartWrite: " );
29573010 for (HighsInt instance = 0 ; instance < mip_race_concurrency; instance++)
29583011 highsLogUser (log_options, HighsLogType::kInfo , " %20d" ,
2959- this ->incumbent [instance].start_write_incumbent );
3012+ int ( this ->incumbent [instance].start_write_incumbent ) );
29603013 highsLogUser (log_options, HighsLogType::kInfo , " \n Objective: " );
29613014 for (HighsInt instance = 0 ; instance < mip_race_concurrency; instance++)
29623015 highsLogUser (log_options, HighsLogType::kInfo , " %20.12g" ,
29633016 this ->incumbent [instance].objective );
29643017 highsLogUser (log_options, HighsLogType::kInfo , " \n FinishWrite: " );
29653018 for (HighsInt instance = 0 ; instance < mip_race_concurrency; instance++)
29663019 highsLogUser (log_options, HighsLogType::kInfo , " %20d" ,
2967- this ->incumbent [instance].finish_write_incumbent );
3020+ int ( this ->incumbent [instance].finish_write_incumbent ) );
29683021 highsLogUser (log_options, HighsLogType::kInfo , " \n " );
29693022}
29703023
@@ -2997,7 +3050,7 @@ void MipRace::update(const double objective,
29973050 // this->report();
29983051}
29993052
3000- bool MipRace::newSolution (const HighsInt instance, double objective,
3053+ bool MipRace::newSolution (const HighsInt instance, double & objective,
30013054 std::vector<double >& solution) {
30023055 assert (this ->record );
30033056 HighsInt new_incumbent_read = this ->record ->incumbent [instance].read (
0 commit comments