Conversation
'SolutionBuilder::build' calls 'update_indicators' once per bin, and each call recomputes the aggregate feasibility over every bin of the solution. The per-group weight vectors of a bin are only sized by its own 'update_indicators' pass, so while the first bins are processed the later ones still have empty 'weight' / 'weight_weighted_sum' vectors, and 'feasible_axle_weights' indexed them anyway: undefined behaviour that '_GLIBCXX_ASSERTIONS' reports as an out-of-range 'std::vector::operator[]' and that is an access violation with MSVC builds. 'feasible_total_weight' already skips such bins; do the same here. The last pass sees every bin sized, so the final feasibility is unchanged. Every multi-bin solution rebuilt on another instance goes through 'SolutionBuilder::build': 'Reduction::unreduce_solution' (since instance reduction runs by default, every bin packing / variable-sized bin packing solve that uses at least two bins hits this) and 'InstanceFlipper::unflip_solution'. The 'BoxStacksOptimizeTest' bin packing case aborts under '_GLIBCXX_ASSERTIONS' and crashes on Windows before this change; the new 'BoxStacks.SolutionBuilderTwoBinsBuiltAtOnce' test is the smallest solution that reaches it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A new instance, data/boxstacks/tests/bin_packing_postal_cartons_eur_pallets: three postal carton sizes (530 x 290 x 370, 530 x 230 x 290, 430 x 210 x 270 mm, 14 / 16 / 20 copies, one stackability id each) packed on 1200 x 800 x 1800 EUR pallets, bin packing; the certificate uses two pallets, which is optimal (volume bound 2), so optimize() reaches it without a time limit. 'BoxStacksSolutionBuilderReadTest' reads a multi-bin certificate through 'SolutionBuilder::read' + 'build' and checks bins, fullness and feasibility, for this instance and for bin_packing_two_item_types_pallets_time_limit: with the previous commit reverted both abort under '_GLIBCXX_ASSERTIONS' in 'Solution::feasible_axle_weights', as does the new instance in 'BoxStacksOptimizeTest'. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…anning SolutionBuilder::build calls update_indicators(bin_pos) once per bin, in order, and each call recomputed feasible_axle_weights() over every bin, including ones after bin_pos whose weight vectors update_indicators hadn't sized yet - the out-of-range read the PR's first commit guarded against. update_indicators(bin_pos) is only ever called once per bin_pos, in increasing order, and bins are never removed once added, so a bin's own weight feasibility, once computed, cannot change. Accumulate total_weight_feasible_ and axle_weights_feasible_ incrementally in update_indicators instead of rescanning every bin (sized or not) on every call. feasible_total_weight() and feasible_axle_weights() are replaced by plain total_weight_feasible()/axle_weights_feasible() getters, matching the existing callback_feasible()/item_copies_feasible() style; feasible_axle_weights(bin_pos), only ever called internally, is now private; and the feasibility getters (callback_feasible, total_weight_feasible, axle_weights_feasible, item_copies_feasible, feasible) are grouped together in the 'Getters: feasibility' section.
fontanf
force-pushed
the
fix/boxstacks-axle-weights-unsized-bins
branch
from
September 14, 2026 20:13
b697fa5 to
13e559e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #575.
SolutionBuilder::buildcallsupdate_indicatorsonce per bin, and each call recomputes the aggregate feasibility over every bin. The per-group weight vectors of a bin are only sized by its own pass, so while the first bins are processed the later ones still have emptyweight/weight_weighted_sumvectors, andfeasible_axle_weightsindexed them anyway: undefined behaviour that_GLIBCXX_ASSERTIONSreports as an out-of-rangestd::vector::operator[]and that is an access violation with MSVC.feasible_total_weightalready skips such bins; this does the same. The last pass sees every bin sized, so the final feasibility is unchanged.Reached by every multi-bin solution rebuilt on another instance (
Reduction::unreduce_solution, on by default since 24decc4, andInstanceFlipper::unflip_solution) and by reading a multi-bin certificate.Two commits:
boxstacks: skip unsized bins in Solution::feasible_axle_weights— the guard, plusBoxStacks.SolutionBuilderTwoBinsBuiltAtOnce, the smallest solution that reaches it.boxstacks: certificate-reading tests for multi-bin solutions— a new instancedata/boxstacks/tests/bin_packing_postal_cartons_eur_pallets(three postal carton sizes on 1200 x 800 x 1800 EUR pallets, bin packing, optimal in two pallets sooptimizereaches the certificate without a time limit), added toBoxStacksOptimizeTest; andBoxStacksSolutionBuilderReadTest, which reads a multi-bin certificate throughSolutionBuilder::read+buildand checks bins, fullness and feasibility, for this instance and forbin_packing_two_item_types_pallets_time_limit.Validation (Ubuntu 24.04, GCC 13, RelWithDebInfo with
-fsanitize=address -D_GLIBCXX_ASSERTIONS, CLP + HiGHS):PackingSolver_boxstacks_test: 21 tests pass.src/boxstacks/solution.cppreverted to master and the tests kept: bothBoxStacksSolutionBuilderReadTestcases,SolutionBuilderTwoBinsBuiltAtOnceand the postal-cartonBoxStacksOptimizeTestcase abort on the assertion infeasible_axle_weights.bin_packing_two_item_types_pallets_time_limitCLI run crashes with0xC0000005infeasible_axle_weights(solution.cpp:140) on master and completes with the patch (32 / 32 items in 2 of 4 pallets, 0.15 s); backtraces in the gist linked from [boxstacks] SolutionBuilder::build on a multi-bin solution reads past the empty weight vectors of the bins not processed yet (access violation on Windows since instance reduction) #575.Update: added a third commit,
boxstacks: accumulate axle weight feasibility per bin instead of rescanning, replacing the "skip unsized bins" rescan from the first commit.update_indicators(bin_pos)is only ever called once perbin_pos, in increasing order, and bins are never removed once added, so a bin's own axle weight feasibility, once computed, cannot change.feasible_axle_weights()is now split into a per-binfeasible_axle_weights(bin_pos)and anaxle_weights_feasible_flag ANDed with it right afterbin_posis sized inupdate_indicators, instead of rescanning every bin (sized or not) on every call. The no-argfeasible_axle_weights()is kept as a full loop over sized bins for existing external callers. Tests from the second commit are unchanged and still pass (21/21,PackingSolver_boxstacks_test, Ubuntu 24.04 GCC 13 RelWithDebInfo).