Skip to content

Make float improvement cuts strict in the objective bound - #273

Open
zayenz wants to merge 2 commits into
mainfrom
feature/float-step
Open

zayenz wants to merge 2 commits into
mainfrom
feature/float-step

Conversation

@zayenz

@zayenz zayenz commented Nov 3, 2026

Copy link
Copy Markdown
Member

The float model in MiniZinc/MiniZincIDE#220 finds its optimum at once and then never proves it. This makes the float improvement cuts in FlatZinc and in MiniModel's FloatMinimizeSpace/FloatMaximizeSpace strict in the objective bound, so the incumbent value is pruned as soon as the cut is posted.

Root cause

The cut obj < best - step was posted as obj <= best - step plus a disequality. NqFloat only fails once the objective is assigned, so the incumbent value stayed inside the objective bounds. Proving optimality then had to split the other float variables down to single ulps before the objective became assigned.

Change

  • FlatZinc (FlatZincSpace::constrain): post obj <= pred(lo(best - step)) when minimizing and obj >= succ(hi(best + step)) when maximizing. If that bound is at or beyond the float limits, the space fails. On assigned objectives this admits exactly the solutions the old cut admitted, so step 0 stays exact. The step is also initialized in the default constructor and read before the Gist branch, which used it uninitialized.
  • MiniModel (FloatMinimizeSpace::constrain, FloatMaximizeSpace::constrain): the same strict cut on the bound that compare ranks. The difference with the step is now rounded outward, so a positive step no longer admits an improvement slightly smaller than the step. With step 0, assigned costs are accepted exactly as before.
  • Changelog entries for both, under 7.0.0.

Testing

  • New tests FlatZinc::Float::CutExcludesIncumbent and Float::Basic::OptimizeCut constrain by an incumbent with objective 0.5 in both directions and require the unassigned objective's bound to exclude 0.5. Each fails without its fix.
  • The two Review cleanups for main branch #220 models now prove optimality, in 93 and 358 nodes, instead of running indefinitely.
  • The float examples that optimize (archimedean-spiral, golden-spiral, descartes-folium) find the same solutions in 3 to 4 percent fewer nodes.
  • check passed 536/536, all FlatZinc tests passed (149), and the Float::Rel and Float::Basic selections passed, in a macOS Release build. The changelog tidy check passed.

Not in this PR

Coarse-first float step schedules (optimize with a large relative step, then shrink it) are planned separately, together with portfolio search.

The cut obj < best - step was posted as obj <= best - step plus a
disequality that only fails once the objective is assigned. The incumbent
value therefore stayed inside the objective bounds, and proving optimality
could require splitting the other float variables down to single ulps. The
model in MiniZinc/MiniZincIDE#220 found its optimum at once and then did not
finish proving it.

Post obj <= pred(lo(best - step)) when minimizing and
obj >= succ(hi(best + step)) when maximizing instead. On assigned
objectives this admits exactly the solutions the old cut admitted, so step
0 stays exact, but the incumbent value is pruned immediately. The issue
model now proves optimality in 358 nodes instead of running indefinitely.

Also initialize the step in the default constructor and read it before the
Gist branch, which previously used it uninitialized.
FloatMinimizeSpace and FloatMaximizeSpace posted cost < best - step as
cost <= best - step plus a disequality that fails only once the cost is
assigned, so the incumbent cost stayed inside the cost bounds until then,
as in the FlatZinc cut fixed by the previous commit.

Post cost <= pred(lo(best - step)) when minimizing and
cost >= succ(hi(best + step)) when maximizing, computing the difference with
outward rounding. With step 0 this accepts exactly the assigned costs the
old cut accepted; with a positive step it no longer admits an improvement
smaller than the step through rounding. The float spiral and folium
examples find the same solutions in 3 to 4 percent fewer nodes.

This branch has not been deployed

No deployments
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