Skip to content

irregular: fix the local search on infeasible sub-instances - #628

Merged
fontanf merged 1 commit into
masterfrom
irregular-fix-local-search-lp
Oct 3, 2026
Merged

fontanf merged 1 commit into
masterfrom
irregular-fix-local-search-lp

Conversation

@fontanf

@fontanf fontanf commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

Problem

With use_local_search=True (off by default), BinPackingWithLeftovers threw linear_programming_minimize_shrinkage(...): wrong LP solution, even for a single 5x5 square in a 10x10 bin, with or without the reduction:

  • Through sequential_feasibility, the local search solves Feasibility sub-instances whose bin gets narrower at each iteration. Here, one asked for the 5-wide square in a 4.95-wide bin.
  • On that infeasible sub-instance, pack_item had no iteration limit and no progress check. It solved about 23,000 shrinkage LPs until the time limit.
  • HiGHS then stopped the last LP on the time limit with no solution, and the empty solution failed the check.

Once that loop stopped, a second bug showed up on data/irregular/tests/multiple_bins.json. When the selected bin had no free space left, assign_item_to_bin placed the new item at the bin centre, inside another item. find_best_edge_separator then threw (violated separation constraint). This also happens on master, but there the time-limit crash came first.

Also found while investigating:

  • In linear_programming_minimize_shrinkage, the bin bounds were aabb_scaled * scale_value, scaled twice, so they didn't restrict the items. linear_programming_anchor mixed scaled and original units in the same way.
  • Debugging leftovers:
    • initial_solution.txt was written in the working directory at each LP, and infeasible.mps plus exit(1) on an infeasible LP, which would kill a Python process.
    • tmp.json was written, and traces printed to the standard output, before the internal errors.

Fix

  • LP not solved to optimality: linear_programming_minimize_shrinkage and linear_programming_anchor check parameters.timer.needs_to_end().
    • If the time limit is reached, they stop and keep the current solution. Before, linear_programming_anchor would have taken an empty solution as the new positions.
    • Otherwise, they throw with the HiGHS model status.
  • pack_item gives up, and the local search stops on that sub-instance:
    • if the item fits in no bin of the sub-instance. optimize_item_types_fit only checks the original instance, and the bins of these sub-instances are narrower;
    • if the selected bin has no free space left;
    • in the non-anytime modes only, after OptimizeParameters::not_anytime_local_search_maximum_number_of_iterations_without_improvement (default 100) iterations without the sum of the items' scale factors increasing. In anytime mode, it keeps trying until the time limit.
      • This is what makes an infeasible probe end in the non-anytime modes. The default time limit is infinite, so without it optimize() would never return.
      • On the irregular test instances, 339 of the 340 successful packings needed no such iteration, and the last one needed 81.
      • The parameter is also available in Python and on the command line (--not-anytime-local-search-maximum-number-of-iterations-without-improvement).
  • Fix the scaling of the bin bounds in both LPs.
  • Remove the debugging leftovers.

Testing

  • New test_local_search_bin_packing_with_leftovers: 1 and 4 squares, with and without the reduction. It also checks that no file is written in the working directory.
  • New test_local_search_full_bin: multiple_bins.json.
  • test_parameters covers the new parameter.
  • The local search on every instance of data/irregular/tests no longer throws.
  • Checked by hand, not in the unit tests (time limits make them unreliable): 48 runs with short time limits (0.01 s to 1 s), in non-anytime and anytime modes, raised no error. A temporary trace confirmed that LPs were interrupted by the time limit in these runs (16 in non-anytime mode), and that needs_to_end() was then true.
  • C++ irregular unit tests: 123 passed. Python tests: 354 passed, 13 skipped, 1 xfailed (test_knapsack_hole, fixed by irregular: keep the holes of item types copied from another instance #627).

Not fixed

On some BinPackingWithLeftovers instances, sequential_feasibility with the local search still runs until the time limit, e.g. three 5x5 and two 4x4 squares in a 20x10 bin. It keeps solving narrower sub-instances after its first solution. This isn't new: on master the same instance also reached the time limit, then threw.

@fontanf
fontanf force-pushed the irregular-fix-local-search-lp branch from 2ebade4 to edc4b9b Compare October 3, 2026 09:15
With 'use_local_search', BinPackingWithLeftovers (through
'sequential_feasibility') solves Feasibility sub-instances with bins
narrower than needed. On such a sub-instance, 'pack_item' kept solving
the shrinkage LP until the time limit; the LP then interrupted by the
time limit had no solution, which made 'linear_programming_minimize_shrinkage'
throw ('wrong LP solution').

- 'linear_programming_minimize_shrinkage' and 'linear_programming_anchor'
  stop and keep the current solution when the time limit is reached. If
  the LP isn't solved to optimality otherwise, they throw with the model
  status ('exit(1)' on an infeasible LP is removed).
- 'pack_item' gives up if the item fits in no bin of the sub-instance, or
  if the selected bin has no free space left (the item used to be placed
  inside another one, which made 'find_best_edge_separator' throw).
- In the non-anytime modes, 'pack_item' also gives up after
  'OptimizeParameters::not_anytime_local_search_maximum_number_of_iterations_without_improvement'
  (100) iterations without increasing the sum of the scale factors of the
  items. In anytime mode, it keeps trying until the time limit.
- The bin bounds were scaled twice in 'linear_programming_minimize_shrinkage'
  ('aabb_scaled * scale_value'), so they didn't restrict the items, and
  mixed scaled and original units in 'linear_programming_anchor'.
- Remove debugging leftovers: the files written in the working directory
  ('initial_solution.txt' at each LP, 'infeasible.mps', 'tmp.json') and the
  outputs printed on the standard output.
@fontanf
fontanf force-pushed the irregular-fix-local-search-lp branch from edc4b9b to 626c013 Compare October 3, 2026 09:30
@fontanf
fontanf merged commit ff71840 into master Oct 3, 2026
11 checks passed
@fontanf
fontanf deleted the irregular-fix-local-search-lp branch October 3, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant