Skip to content

Commit

Permalink
First draft of Feasibility Jump integration
Browse files Browse the repository at this point in the history
  • Loading branch information
BenChampion committed Nov 29, 2024
1 parent f4d421d commit b271d21
Showing 1 changed file with 86 additions and 5 deletions.
91 changes: 86 additions & 5 deletions src/mip/HighsFeasibilityJump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<double> col_value;
bool found_integer_feasible_solution = false;
std::vector<double> 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<double>(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);
}
Expand Down

0 comments on commit b271d21

Please sign in to comment.