-
Notifications
You must be signed in to change notification settings - Fork 171
Detect when MIP objectives must move in discrete steps. Tighten the dual bound using this info. #1239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Detect when MIP objectives must move in discrete steps. Tighten the dual bound using this info. #1239
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1227,7 +1227,13 @@ std::pair<node_status_t, rounding_direction_t> branch_and_bound_t<i_t, f_t>::upd | |
| policy.graphviz(search_tree, node_ptr, "lower bound", leaf_obj); | ||
| policy.update_pseudo_costs(node_ptr, leaf_obj); | ||
| node_ptr->lower_bound = leaf_obj; | ||
| if (original_lp_.objective_is_integral) { | ||
| if (original_lp_.objective_step.has_step()) { | ||
| f_t step = original_lp_.objective_step.step_size; | ||
| f_t bias = original_lp_.objective_step.bias; | ||
| // Round up to next value on the lattice: k * step + bias >= leaf_obj | ||
| f_t k = std::ceil((leaf_obj - bias) / step - settings_.integer_tol); | ||
| node_ptr->lower_bound = k * step + bias; | ||
| } else if (original_lp_.objective_is_integral) { | ||
| node_ptr->lower_bound = std::ceil(leaf_obj - settings_.integer_tol); | ||
| } | ||
| policy.on_optimal_callback(leaf_solution.x, leaf_obj); | ||
|
|
@@ -1345,8 +1351,18 @@ dual::status_t branch_and_bound_t<i_t, f_t>::solve_node_lp( | |
| lp_settings.concurrent_halt = &node_concurrent_halt_; | ||
| lp_settings.set_log(false); | ||
| f_t cutoff = upper_bound_.load(); | ||
| if (original_lp_.objective_is_integral) { | ||
| lp_settings.cut_off = std::ceil(cutoff - settings_.integer_tol) + settings_.dual_tol; | ||
| if (original_lp_.objective_step.has_step()) { | ||
| f_t step = original_lp_.objective_step.step_size; | ||
| f_t bias = original_lp_.objective_step.bias; | ||
| // Any improving feasible solution must have objective <= cutoff - step. | ||
| f_t k = std::floor((cutoff - bias) / step + settings_.integer_tol); | ||
| lp_settings.cut_off = (k - 1) * step + bias + settings_.dual_tol; | ||
| } else if (original_lp_.objective_is_integral) { | ||
| // If the objective is integral, any feasible solution should produce an upper bound that is | ||
| // (approximately) integral. We add a small tolerance and floor this value to get an integer, | ||
| // we then subtract 1, to stop simplex on problems that cannot improve the primal objective. | ||
| lp_settings.cut_off = | ||
| std::floor(cutoff + settings_.integer_tol) - 1 + settings_.dual_tol; | ||
|
Comment on lines
+1354
to
+1365
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The cutoff formula drops one attainable value when
Possible fix if (original_lp_.objective_step.has_step()) {
f_t step = original_lp_.objective_step.step_size;
f_t bias = original_lp_.objective_step.bias;
- // Any improving feasible solution must have objective <= cutoff - step.
- f_t k = std::floor((cutoff - bias) / step + settings_.integer_tol);
+ // Largest lattice value strictly below `cutoff`.
+ f_t k = std::ceil((cutoff - bias) / step - settings_.integer_tol);
lp_settings.cut_off = (k - 1) * step + bias + settings_.dual_tol;
} else if (original_lp_.objective_is_integral) {
- lp_settings.cut_off =
- std::floor(cutoff + settings_.integer_tol) - 1 + settings_.dual_tol;
+ lp_settings.cut_off =
+ std::ceil(cutoff - settings_.integer_tol) - 1 + settings_.dual_tol;
} else {🤖 Prompt for AI Agents |
||
| } else { | ||
| lp_settings.cut_off = cutoff + settings_.dual_tol; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fathom against the tightened node bound, not the raw LP objective.
After Lines 1230-1237,
node_ptr->lower_boundmay already be snapped up to the incumbent lattice value, but the branch/fathom check still usesleaf_obj. That keeps branching nodes that cannot produce a strictly improving integer solution anymore (for example,UB = 2,step = 0.5,leaf_obj = 1.7snaps toLB = 2.0and still branches here). Drive this decision from the tightened bound instead.Also applies to: 1247-1273
🤖 Prompt for AI Agents