From b271d21a4d5433b229aa069098a1fd11ecc959f6 Mon Sep 17 00:00:00 2001 From: Ben Champion <6761956+BenChampion@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:39:08 +0000 Subject: [PATCH] First draft of Feasibility Jump integration --- src/mip/HighsFeasibilityJump.cpp | 91 ++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/src/mip/HighsFeasibilityJump.cpp b/src/mip/HighsFeasibilityJump.cpp index 7c31842621..57fb744409 100644 --- a/src/mip/HighsFeasibilityJump.cpp +++ b/src/mip/HighsFeasibilityJump.cpp @@ -19,17 +19,98 @@ void HighsMipSolverData::feasibilityJump() { printf("HighsMipSolverData::feasibilityJump called with primal bound of %g\n", lower_bound); - // Use feasibility jump to try to find an integer feasible solution + const HighsInt MAX_TOTAL_EFFORT = 1e6; + const HighsInt MAX_EFFORT_SINCE_LAST_IMPOVEMENT = 1e3; - const bool found_integer_feasible_solution = false; - std::vector col_value; + bool found_integer_feasible_solution = false; + std::vector col_value(model->num_col_, 0.0); double objective_function_value; + printf("DEBUG: configuring feasilibility jump\n"); + + // Configure Feasibility Jump and pass it the problem + external_feasibilityjump::equalityTolerance = epsilon; + external_feasibilityjump::violationTolerance = feastol; + + auto solver = external_feasibilityjump::FeasibilityJumpSolver(); + + printf("DEBUG: adding cols (vars)\n"); + + for (int i = 0; i < model->num_col_; ++i) { + external_feasibilityjump::VarType fjVarType; + if (model->integrality_[i] == HighsVarType::kContinuous) { + fjVarType = external_feasibilityjump::VarType::Continuous; + } else if (model->integrality_[i] == HighsVarType::kInteger) { + fjVarType = external_feasibilityjump::VarType::Integer; + } else { + printf( + "Feasibility Jump only supports continuous and integer variables. " + "Skipping Feasibility Jump...\n" + ); + return; + } + solver.addVar( + fjVarType, + model->col_lower_[i], + model->col_upper_[i], + model->col_cost_[i] + ); + } + + printf("DEBUG: adding rows (constraints)\n"); + + HighsInt numNzThisRow; + HighsInt* rowIndexBuffer = new HighsInt[model->num_col_]; + double* rowValueBuffer = new double[model->num_col_]; + + for (int i = 0; i < model->num_row_; ++i) { + bool hasFiniteLower = std::isfinite(model->row_lower_[i]); + bool hasFiniteUpper = std::isfinite(model->row_upper_[i]); + if (hasFiniteLower || hasFiniteUpper) { + model->a_matrix_.getRow(i, numNzThisRow, rowIndexBuffer, rowValueBuffer); + // TODO: check if relax_continuous == 1 really is the right thing to pass + if (hasFiniteLower) { + solver.addConstraint(external_feasibilityjump::RowType::Gte, + model->row_lower_[i], numNzThisRow, rowIndexBuffer, + rowValueBuffer, 1); + } + if (hasFiniteUpper) { + solver.addConstraint(external_feasibilityjump::RowType::Lte, + model->row_upper_[i], numNzThisRow, rowIndexBuffer, + rowValueBuffer, 1); + } + + } + } + + delete[] rowValueBuffer; + delete[] rowIndexBuffer; + + printf("DEBUG: calling Feasibility Jump\n"); + + auto fjControlCallback = + [=, &col_value, &found_integer_feasible_solution, + &objective_function_value](external_feasibilityjump::FJStatus status) + -> external_feasibilityjump::CallbackControlFlow { + if (std::isfinite(status.solutionObjectiveValue)) { + found_integer_feasible_solution = true; + col_value = std::vector(status.solution, + status.solution + status.numVars); + objective_function_value = status.solutionObjectiveValue; + } + if (status.effortSinceLastImprovement > MAX_EFFORT_SINCE_LAST_IMPOVEMENT || + status.totalEffort > MAX_TOTAL_EFFORT) { + return external_feasibilityjump::CallbackControlFlow::Terminate; + } else { + return external_feasibilityjump::CallbackControlFlow::Continue; + } + }; + + solver.solve(col_value.data(), fjControlCallback); + if (found_integer_feasible_solution) { // Feasibility jump has found a solution, so call addIncumbent to // (possibly) update the incumbent - col_value.assign(model->num_col_, 0); - objective_function_value = 0.0; addIncumbent(col_value, objective_function_value, kSolutionSourceFeasibilityJump); }