Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions cpp/src/dual_simplex/branch_and_bound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ node_status_t branch_and_bound_t<i_t, f_t>::solve_node(search_tree_t<i_t, f_t>&
lp_settings.set_log(false);
lp_settings.cut_off = upper_bound + settings_.dual_tol;
lp_settings.inside_mip = 2;
lp_settings.time_limit = settings_.time_limit - toc(stats_.start_time);

// in B&B we only have equality constraints, leave it empty for default
std::vector<char> row_sense;
Expand Down Expand Up @@ -739,7 +740,7 @@ void branch_and_bound_t<i_t, f_t>::exploration_ramp_up(search_tree_t<i_t, f_t>*
}
}

if (toc(stats_.start_time) > settings_.time_limit) {
if (now > settings_.time_limit) {
status_ = mip_exploration_status_t::TIME_LIMIT;
return;
}
Expand Down Expand Up @@ -836,17 +837,17 @@ void branch_and_bound_t<i_t, f_t>::explore_subtree(i_t id,
}
}

if (toc(stats_.start_time) > settings_.time_limit) {
if (now > settings_.time_limit) {
status_ = mip_exploration_status_t::TIME_LIMIT;
break;
return;
}

node_status_t node_status =
solve_node(search_tree, node_ptr, leaf_problem, Arow, upper_bound, settings_.log, 'B');

if (node_status == node_status_t::TIME_LIMIT) {
status_ = mip_exploration_status_t::TIME_LIMIT;
break;
return;

} else if (node_status == node_status_t::HAS_CHILDREN) {
// The stack should only contain the children of the current parent.
Expand Down Expand Up @@ -972,11 +973,13 @@ void branch_and_bound_t<i_t, f_t>::diving_thread(lp_problem_t<i_t, f_t>& leaf_pr
continue;
}

if (toc(stats_.start_time) > settings_.time_limit) { return; }

node_status_t node_status =
solve_node(subtree, node_ptr, leaf_problem, Arow, upper_bound, log, 'D');

if (node_status == node_status_t::TIME_LIMIT) {
break;
return;

} else if (node_status == node_status_t::HAS_CHILDREN) {
auto [first, second] = child_selection(node_ptr);
Expand Down Expand Up @@ -1035,7 +1038,6 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut
original_lp_, stats_.start_time, lp_settings, root_relax_soln_, root_vstatus_, edge_norms_);
stats_.total_lp_iters = root_relax_soln_.iterations;
stats_.total_lp_solve_time = toc(stats_.start_time);
assert(root_vstatus_.size() == original_lp_.num_cols);
if (root_status == lp_status_t::INFEASIBLE) {
settings_.log.printf("MIP Infeasible\n");
// FIXME: rarely dual simplex detects infeasible whereas it is feasible.
Expand All @@ -1059,6 +1061,7 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut
return set_final_solution(solution, -inf);
}

assert(root_vstatus_.size() == original_lp_.num_cols);
set_uninitialized_steepest_edge_norms<i_t, f_t>(edge_norms_);

root_objective_ = compute_objective(original_lp_, root_relax_soln_.x);
Expand Down
20 changes: 11 additions & 9 deletions cpp/src/dual_simplex/device_sparse_matrix.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -173,18 +173,20 @@ class device_csc_matrix_t {
col_index.resize(x.size(), stream);
RAFT_CUDA_TRY(cudaMemsetAsync(col_index.data(), 0, sizeof(i_t) * col_index.size(), stream));
// Scatter 1 when there is a col start in col_index
thrust::for_each(
rmm::exec_policy(stream),
thrust::make_counting_iterator(i_t(1)), // Skip the first 0
thrust::make_counting_iterator(static_cast<i_t>(col_start.size() - 1)), // Skip the end index
[span_col_start = cuopt::make_span(col_start),
span_col_index = cuopt::make_span(col_index)] __device__(i_t i) {
span_col_index[span_col_start[i]] = 1;
});
if (col_start.size() > 2) {
thrust::for_each(rmm::exec_policy(stream),
thrust::make_counting_iterator(i_t(1)), // Skip the first 0
thrust::make_counting_iterator(
static_cast<i_t>(col_start.size() - 1)), // Skip the end index
[span_col_start = cuopt::make_span(col_start),
span_col_index = cuopt::make_span(col_index)] __device__(i_t i) {
span_col_index[span_col_start[i]] = 1;
});
}

// Inclusive cumulative sum to have the corresponding column for each entry
rmm::device_buffer d_temp_storage;
size_t temp_storage_bytes;
size_t temp_storage_bytes{0};
cub::DeviceScan::InclusiveSum(
nullptr, temp_storage_bytes, col_index.data(), col_index.data(), col_index.size(), stream);
d_temp_storage.resize(temp_storage_bytes, stream);
Expand Down
5 changes: 5 additions & 0 deletions cpp/src/dual_simplex/pinned_host_allocator.cu
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ bool operator!=(const PinnedHostAllocator<T>&, const PinnedHostAllocator<U>&) no
template class PinnedHostAllocator<double>;
template double vector_norm_inf<int, double, PinnedHostAllocator<double>>(
const std::vector<double, PinnedHostAllocator<double>>& x);

template bool operator==(const PinnedHostAllocator<double>&,
const PinnedHostAllocator<double>&) noexcept;
template bool operator!=(const PinnedHostAllocator<double>&,
const PinnedHostAllocator<double>&) noexcept;
#endif
template class PinnedHostAllocator<int>;

Expand Down
4 changes: 3 additions & 1 deletion cpp/src/linear_programming/solve.cu
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,9 @@ optimization_problem_solution_t<i_t, f_t> solve_lp(optimization_problem_t<i_t, f
if (run_presolve) {
// allocate no more than 10% of the time limit to presolve.
// Note that this is not the presolve time, but the time limit for presolve.
const double presolve_time_limit = std::min(0.1 * lp_timer.remaining_time(), 60.0);
// But no less than 1 second, to avoid early timeout triggering known crashes
const double presolve_time_limit =
std::max(1.0, std::min(0.1 * lp_timer.remaining_time(), 60.0));
presolver = std::make_unique<detail::third_party_presolve_t<i_t, f_t>>();
auto [reduced_problem, feasible] =
presolver->apply(op_problem,
Expand Down
2 changes: 1 addition & 1 deletion cpp/src/mip/diversity/population.cu
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ std::vector<solution_t<i_t, f_t>> population_t<i_t, f_t>::get_external_solutions
sol.copy_new_assignment(h_entry.solution);
sol.compute_feasibility();
if (!sol.get_feasible()) {
CUOPT_LOG_ERROR(
CUOPT_LOG_DEBUG(
"External solution %d is infeasible, excess %g, obj %g, int viol %g, var viol %g, cstr "
"viol %g, n_feasible %d/%d, integers %d/%d",
counter,
Expand Down
32 changes: 19 additions & 13 deletions cpp/src/mip/local_search/local_search.cu
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,13 @@ void local_search_t<i_t, f_t>::stop_cpufj_scratch_threads()
template <typename i_t, typename f_t>
bool local_search_t<i_t, f_t>::do_fj_solve(solution_t<i_t, f_t>& solution,
fj_t<i_t, f_t>& in_fj,
f_t time_limit,
const std::string& source)
{
if (time_limit == 0.) return solution.get_feasible();

timer_t timer(time_limit);

auto h_weights = cuopt::host_copy(in_fj.cstr_weights, solution.handle_ptr->get_stream());
auto h_objective_weight = in_fj.objective_weight.value(solution.handle_ptr->get_stream());
for (auto& cpu_fj : ls_cpu_fj) {
Expand All @@ -242,7 +247,8 @@ bool local_search_t<i_t, f_t>::do_fj_solve(solution_t<i_t, f_t>& solution,
}

// Run GPU solver and measure execution time
auto gpu_fj_start = std::chrono::high_resolution_clock::now();
auto gpu_fj_start = std::chrono::high_resolution_clock::now();
in_fj.settings.time_limit = timer.remaining_time();
in_fj.solve(solution);

// Stop CPU solver
Expand Down Expand Up @@ -320,9 +326,9 @@ void local_search_t<i_t, f_t>::generate_fast_solution(solution_t<i_t, f_t>& solu
constraint_prop.apply_round(solution, 1., constr_prop_timer);
if (solution.compute_feasibility()) { return; }
if (timer.check_time_limit()) { return; };
fj.settings.time_limit = std::min(3., timer.remaining_time());
f_t time_limit = std::min(3., timer.remaining_time());
// run fj on the solution
do_fj_solve(solution, fj, "fast");
do_fj_solve(solution, fj, time_limit, "fast");
// TODO check if FJ returns the same solution
// check if the solution is feasible
if (solution.compute_feasibility()) { return; }
Expand Down Expand Up @@ -381,11 +387,11 @@ bool local_search_t<i_t, f_t>::run_fj_until_timer(solution_t<i_t, f_t>& solution
bool is_feasible;
fj.settings.n_of_minimums_for_exit = 1e6;
fj.settings.mode = fj_mode_t::EXIT_NON_IMPROVING;
fj.settings.time_limit = timer.remaining_time() * 0.95;
fj.settings.update_weights = false;
fj.settings.feasibility_run = false;
fj.copy_weights(weights, solution.handle_ptr);
do_fj_solve(solution, fj, "until_timer");
f_t time_limit = timer.remaining_time() * 0.95;
do_fj_solve(solution, fj, time_limit, "until_timer");
CUOPT_LOG_DEBUG("Initial FJ feasibility done");
is_feasible = solution.compute_feasibility();
if (fj.settings.feasibility_run || timer.check_time_limit()) { return is_feasible; }
Expand All @@ -410,11 +416,11 @@ bool local_search_t<i_t, f_t>::run_fj_annealing(solution_t<i_t, f_t>& solution,
fj.settings.mode = fj_mode_t::EXIT_NON_IMPROVING;
fj.settings.candidate_selection = fj_candidate_selection_t::FEASIBLE_FIRST;
fj.settings.iteration_limit = ls_config.iteration_limit;
fj.settings.time_limit = std::min(10., timer.remaining_time());
fj.settings.parameters.allow_infeasibility_iterations = 100;
fj.settings.update_weights = 1;
fj.settings.baseline_objective_for_longer_run = ls_config.best_objective_of_parents;
do_fj_solve(solution, fj, "annealing");
f_t time_limit = std::min(10., timer.remaining_time());
do_fj_solve(solution, fj, time_limit, "annealing");
bool is_feasible = solution.compute_feasibility();

fj.settings = prev_settings;
Expand Down Expand Up @@ -460,14 +466,14 @@ bool local_search_t<i_t, f_t>::check_fj_on_lp_optimal(solution_t<i_t, f_t>& solu
solution.assign_random_within_bounds(perturbation_ratio);
}
cuopt_func_call(solution.test_variable_bounds(false));
f_t lp_run_time_after_feasible = 1.;
f_t lp_run_time_after_feasible = std::min(1., timer.remaining_time());
timer_t bounds_prop_timer = timer_t(std::min(timer.remaining_time(), 10.));
bool is_feasible =
constraint_prop.apply_round(solution, lp_run_time_after_feasible, bounds_prop_timer);
if (!is_feasible) {
const f_t lp_run_time = 2.;
relaxed_lp_settings_t lp_settings;
lp_settings.time_limit = lp_run_time;
lp_settings.time_limit = std::min(lp_run_time, timer.remaining_time());
lp_settings.tolerance = solution.problem_ptr->tolerances.absolute_tolerance;
run_lp_with_vars_fixed(
*solution.problem_ptr, solution, solution.problem_ptr->integer_indices, lp_settings);
Expand All @@ -479,8 +485,8 @@ bool local_search_t<i_t, f_t>::check_fj_on_lp_optimal(solution_t<i_t, f_t>& solu
fj.settings.n_of_minimums_for_exit = 20000;
fj.settings.update_weights = true;
fj.settings.feasibility_run = false;
fj.settings.time_limit = std::min(30., timer.remaining_time());
do_fj_solve(solution, fj, "on_lp_optimal");
f_t time_limit = std::min(30., timer.remaining_time());
do_fj_solve(solution, fj, time_limit, "on_lp_optimal");
return solution.get_feasible();
}

Expand All @@ -496,8 +502,8 @@ bool local_search_t<i_t, f_t>::run_fj_on_zero(solution_t<i_t, f_t>& solution, ti
fj.settings.n_of_minimums_for_exit = 20000;
fj.settings.update_weights = true;
fj.settings.feasibility_run = false;
fj.settings.time_limit = std::min(30., timer.remaining_time());
bool is_feasible = do_fj_solve(solution, fj, "on_zero");
f_t time_limit = std::min(30., timer.remaining_time());
bool is_feasible = do_fj_solve(solution, fj, time_limit, "on_zero");
return is_feasible;
}

Expand Down
5 changes: 4 additions & 1 deletion cpp/src/mip/local_search/local_search.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ class local_search_t {
population_t<i_t, f_t>* population_ptr = nullptr);
void resize_vectors(problem_t<i_t, f_t>& problem, const raft::handle_t* handle_ptr);

bool do_fj_solve(solution_t<i_t, f_t>& solution, fj_t<i_t, f_t>& fj, const std::string& source);
bool do_fj_solve(solution_t<i_t, f_t>& solution,
fj_t<i_t, f_t>& fj,
f_t time_limit,
const std::string& source);

i_t ls_threads() const { return ls_cpu_fj.size() + scratch_cpu_fj.size(); }
void save_solution_and_add_cutting_plane(solution_t<i_t, f_t>& solution,
Expand Down