-
Notifications
You must be signed in to change notification settings - Fork 2
Support Sequential Backwards Pass #30
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
Support Sequential Backwards Pass #30
Conversation
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.
Pull Request Overview
This PR introduces a sequential_backward_pass option for the Benders decomposition algorithm, allowing cuts to be added during the backward pass itself rather than after. This represents an alternative execution strategy that may improve convergence in certain problem types.
- Added new
sequential_backward_passboolean option with corresponding infrastructure - Refactored cut-adding logic into reusable functions
_add_Benders_cut_to_object!and_add_strengthened_cut_to_object! - Updated backward pass to iterate in reverse order and conditionally skip post-pass cut addition
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/PlasmoBenders/src/Benders.jl | Added sequential_backward_pass option field, parameter, setter, and validation logic |
| lib/PlasmoBenders/src/solution.jl | Refactored cut-adding into separate functions and integrated sequential pass logic |
| lib/PlasmoBenders/src/utils.jl | Added sequential_backward_pass to boolean options list |
| lib/PlasmoBenders/src/PlasmoBenders.jl | Updated exports (with duplicate) |
| lib/PlasmoBenders/test/MIP_solve.jl | Added test cases for sequential backward pass |
| lib/PlasmoBenders/test/LP_solve.jl | Added test cases for sequential backward pass |
| lib/PlasmoBenders/examples/Benders_MILP.jl | Updated example to use new option |
| lib/PlasmoBenders/examples/Benders_MILP_parallel.jl | Updated example and cleaned up imports |
| lib/PlasmoBenders/Project.toml | Bumped version to 0.2.0 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if !(get_multicut(optimizer)) | ||
| theta_vars = _get_theta(optimizer, last_object) | ||
| theta_expr = sum(theta_vars[k] for k in 1:length(theta_vars)) | ||
| _add_cut_constraint!(optimizer, last_object, theta_expr, agg_rhs_expr) | ||
| end | ||
| end |
Copilot
AI
Oct 31, 2025
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.
This block is inside the for (j, object) in enumerate(next_objects) loop but should be outside it. The aggregated cut should only be added once after processing all objects, not once per object iteration.
| if !(get_multicut(optimizer)) | |
| theta_vars = _get_theta(optimizer, last_object) | |
| theta_expr = sum(theta_vars[k] for k in 1:length(theta_vars)) | |
| _add_cut_constraint!(optimizer, last_object, theta_expr, agg_rhs_expr) | |
| end | |
| end | |
| end | |
| if !(get_multicut(optimizer)) | |
| theta_vars = _get_theta(optimizer, last_object) | |
| theta_expr = sum(theta_vars[k] for k in 1:length(theta_vars)) | |
| _add_cut_constraint!(optimizer, last_object, theta_expr, agg_rhs_expr) | |
| end |
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.
No, I think this still needs to be inside the for loop because it needs to happen for each object.
Co-authored-by: Copilot <[email protected]>
In the original version of PlasmoBenders.jl, the backwards pass was asynchronous, such that the cuts were all computed in parallel and added to the previous subproblems. The most common version of the backwards pass in literature though is to do a sequential solve, where the last problem is solved, cuts are passed back to the previous stage, that stage is solved, cuts are passed back, and so forth. This allows for information to propagate from the final stage to the first stage. This PR implements this option via the keyword argument
sequential_backward_passwhich is by default false.