Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/pr/minizinc-native-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Expose native optimization strategies through MiniZinc

MiniZinc users can now select automatic, racing, ordinary or explicitly
configured native solving through the experimental Gecode Optimize registration.
The default remains structural automatic selection. Solver flags expose the
existing improvements without requiring C++ integration or search annotations.

MiniZinc often emits binary decisions as integer `0..1` variables and wraps a
linear objective in an auxiliary variable. Preserve the source types and checks
while recognizing those binary domains internally. Bounded automatic presolve
eliminates one safely defined affine objective auxiliary, preserves any
restrictive auxiliary bounds, and reconstructs/checks its original value. This
lets ordinary MiniZinc knapsack models reach the existing exact DP route.

## Changes

- Advertise 21 namespaced MiniZinc controls for automatic feature switches,
racing allowances, checked LP frequency/tightening, root covers, search order,
reliability probes, Hamming neighborhoods, resource caps and diagnostics.
- Add `NativeAutoSettings` / `solve_native_auto_configured` and race
automatic-candidate settings. Disabled mechanisms remain disabled in reduced
and independent component solves. Explicit settings reject incompatible modes
or missing dependencies before solving.
- Dispatch every strategy with the remaining frontend time and shared solver
node budget. Optional diagnostics distinguish requested settings from actual
policy, LP/cut/probe activity, and neighborhood completion or skip reasons.
- Document supported combinations, executable examples and racing overhead.
Sequential exploration/restarting can increase CPU work or solve time;
several seconds or longer may find a much better strategy for a long solve.
- Track registration inputs in CMake so rebuilds update installed flags as well
as build-tree flags; verify the installed relative registration in place.

The experimental native integer scope is unchanged. This does not add numerical
LP/MILP/QP MiniZinc model support, conflict learning or parallel racing. The
benchmark dashboard is outside this PR.

## Validation

All **75 CTest entries pass**, as do **135 real MiniZinc checks** against each of
the build registration, installed registration and a checked-LP-disabled harness.
Three backend-free native coordinator tests also pass.

See [the QA walkthrough](../../docs/solver-parity/MINIZINC-CONTROLS-QA.md) for
the actual MiniZinc 2.10.1 commands, independent objective/witness checks,
algorithm activity and regression results. Tests also cover strict flag
forwarding, zero/finite budgets, output/proof markers, original domain and
objective reconstruction, and unavailable checked LP.

## Review base

This is a separate incremental PR: `codex/minizinc-native-controls` targets
`codex/solver-parity-pr` (`884795c874174fd293bab554ee8a544fe45580c1`). That
prerequisite branch contains the earlier optimization contribution. Its tree
matches integration checkpoint `b11a57c1d`; the new branch is based directly on
the review commit so the comparison contains only this MiniZinc work.

The repository's configured remote is a local checkout. Publish the prerequisite
review branch and this branch to the chosen GitHub fork before opening the
stacked pull request. No remote PR or merge is implied by this local preparation.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,10 @@ if(GECODE_OPTIMIZE_MINIZINC_REGISTRATION)
endif()
set(_gecode_optimize_msc_template "${PROJECT_SOURCE_DIR}/tools/flatzinc/gecode-optimize.msc.in")
set(_gecode_optimize_msc_encoder "${PROJECT_SOURCE_DIR}/tools/flatzinc/configure-optimize-msc.cmake")
# execute_process below generates the install registration at configure time.
# Keep it in sync when solver flags or JSON encoding change between builds.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${_gecode_optimize_msc_template}" "${_gecode_optimize_msc_encoder}")
set(_gecode_optimize_build_msc "${PROJECT_BINARY_DIR}/minizinc/$<CONFIG>/gecode-optimize.msc")
# Target paths are expanded before the encoder escapes them as JSON. This
# also supports multi-configuration builds and source/build paths with quotes.
Expand Down
5 changes: 5 additions & 0 deletions docs/solver-parity/FLATZINC-COMPILER.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ lost through an incomplete registry observer. Each source namespace/index maps
to a stable model variable; repeated declaration aliases retain separate source
mapping entries and output positions. Bool and int slot zero are different.

An integer domain contained in `0..1` uses an equivalent internal Binary variable
so native binary algorithms can recognize MiniZinc's integer decision encoding.
This is based only on original declarations, assignments and domain restrictions;
source type, aliases, integer output and all original domain checks are retained.

An immutable owning artifact is published only after every source predicate,
objective, control annotation and output entry is admitted. Unknown predicates,
equality reification, other globals, float/set variables and unhandled
Expand Down
8 changes: 8 additions & 0 deletions docs/solver-parity/FLATZINC-DRIVER.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ in a FlatZinc comment. Exact feasible-point checking does not certify a numerica
optimal bound or infeasibility claim. An unavailable selected backend fails
explicitly. There is no automatic backend or legacy-parser fallback.

The native route defaults to structural automatic selection. Namespaced
`--native-*` controls expose automatic feature switches, opt-in racing and
configured LP/search/branching/neighborhood settings; see the complete
[MiniZinc control reference](MINIZINC.md#native-algorithm-controls). The same
flags work in this filename-first direct interface. `--native-diagnostics on`
adds sanitized comment lines describing requested controls and actual work.
Native controls cannot be mixed with `--backend highs`.

See [the compiler](FLATZINC-COMPILER.md) for the admitted signatures and
[the capture layer](FLATZINC-CAPTURE.md) for grammar and lifecycle boundaries.
Unknown predicates, search annotations, unsupported domains and output types
Expand Down
116 changes: 116 additions & 0 deletions docs/solver-parity/MINIZINC-CONTROLS-QA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# MiniZinc native controls: QA walkthrough

Verified locally on macOS ARM64 with pinned MiniZinc **2.10.1**, its matching
standard library, and an isolated Release build. This is correctness, dispatch,
resource and packaging QA; no new performance benchmark or speedup claim is made.

## Results

- Full Release regression: **75/75 CTest entries pass**, including FAST, source
truth tables, frontend fault injection, native algorithms and Python bindings.
- Actual MiniZinc build registration: **135 process checks pass**, including
26 successful native-control scenarios and independent six-decision oracles.
- Installed registration: **135 checks pass** against the actual installed
executable and library using relative `.msc` paths. The executable resolves
libraries through `@loader_path/../lib`, without the build directory.
- Checked-LP-disabled harness: **135 MiniZinc checks plus three native tests
pass**. Runtime inspection confirms the isolated optimization library loads.
Explicit LP requests fail clearly; automatic/native/racing routes still work.
This harness disables native checked LP while retaining other HiGHS APIs.
- Backend-free build: **3/3** automatic, racing and presolve tests pass, including
backend-independent objective-reconstruction and malformed-result checks.
- JSON registration encoder: **10 cases pass**, preserving all 21 controls,
escaped paths and relocatable install paths.

All optimization witnesses below are checked against independent exhaustive
source-model oracles, including tied optima. The two small six-decision fixtures
both have optimum **12**. The tests check actual work rather than only acceptance
of command-line options.

| Walkthrough | Observed activity |
|---|---|
| Integer `0..1` knapsack, default auto | Objective auxiliary restored; eligible exact knapsack DP selected. |
| Same model, automatic knapsack disabled | Same optimum; DP route absent. |
| Racing with four nodes per probe | Two probes and selection of automatic route; one shared cumulative node budget. |
| Zero exploration / retained all-different global | Explicit race skip, correct result. |
| Configured reliability | 24 actual probe status calls. |
| Configured Hamming, radius 1 | One attempt and three local status calls; completion reason reported. |
| Configured root LP plus covers | Five LP calls, five checked bounds, four verified cover cuts. |
| Configured updated LP, cuts, reliability, Hamming | 31 checked bounds, four cuts and 20 branching probes. |

These are small-fixture activity counts, not recommended tuning constants or
general performance predictions. Hamming distance counts flattened binary slots;
the Boolean fixture also contains integer aliases, so one logical Boolean change
can require radius two. Optional mechanisms may correctly skip or do no useful
work on other models.

The gate verifies flag discovery and forwarding through the real MiniZinc parser,
all four modes, individual/all automatic switches, explicit dependencies,
zero optional allowances, global node limits of zero and one, zero frontier
storage, malformed/overflowing/repeated controls and whole-frontend timeouts.
Every printed completion marker must match the independently computed optimum;
interruptions may print only a checked witness or UNKNOWN. Diagnostic control
characters are sanitized before writing protocol comments.

The compiler tests verify that internal binary recognition preserves integer
source typing, output, aliases and domains. Native tests cover both signs of the
objective-defining equality, minimization/maximization, objective offsets,
restrictive auxiliary domains, disabled presolve/DP, original model identity and
active mask, supplied starts, shared budgets, cancellation and invalid child
results. No declaration name or `defines_var` annotation is trusted as proof of
equivalence.

Packaging QA caught a stale configure-time install registration in an existing
build. CMake now tracks the registration template and encoder as configure
dependencies, so changing advertised controls updates both build and install
registrations. The installed artifact contains all 21 controls and passes the
same real-compiler gate in place.

## Reproduce

From the solver repository, using the configured build described in
[the MiniZinc setup guide](MINIZINC.md#build-and-installation):

```sh
cmake --build build/native-structure/native-build -j 4
ctest --test-dir build/native-structure/native-build --output-on-failure
python3 -B test/optimize/minizinc_registration.py \
--minizinc ../deps/MiniZinc-2.10.1-aarch64-apple-darwin/bin/minizinc \
--binary build/native-structure/native-build/bin/fzn-gecode-optimize \
--registration build/native-structure/native-build/minizinc/Release/gecode-optimize.msc
```

To inspect the actual algorithm choices interactively:

```sh
mzn=../deps/MiniZinc-2.10.1-aarch64-apple-darwin/bin/minizinc
solver="$PWD/build/native-structure/native-build/minizinc/Release/gecode-optimize.msc"
"$mzn" --solver "$solver" --native-diagnostics on \
test/optimize/minizinc-fixtures/mzn-native-knapsack.mzn
"$mzn" --solver "$solver" --native-mode race \
--native-race-seconds 0.05 --native-race-nodes 4 --native-diagnostics on \
test/optimize/minizinc-fixtures/mzn-native-controls.mzn
"$mzn" --solver "$solver" --native-mode configured --native-lp root \
--native-root-cuts on --native-diagnostics on \
test/optimize/minizinc-fixtures/mzn-native-controls.mzn
```

Select `org.gecode.optimize.experimental` explicitly; the stock Gecode solver
registration does not expose these flags. Racing can increase CPU work or solve
time through exploration and restarting, even when a later strategy is faster.

The local JSON reports retain process checks, source/compiler/driver/configuration
and MiniZinc library hashes, requested settings, actual policy and work counters:

- `build/native-structure/native-build/minizinc-controls-registration.json`
- `build/native-structure/native-build/minizinc-controls-installed-registration.json`
- `build/native-structure/native-build/minizinc-controls-ctest.log`
- `build/minizinc-controls-no-lp/summary.json` and `reproduce.py`
- `build/optimize-core/minizinc-controls-ctest.log`

Build-tree driver SHA256:
`3efb21d82322aff323bd05add9ef9b5b34898a5478d8766df06fb8fd13538669`.
The compiler SHA256 is
`a8489069d77793862102ca5bab5b2e24822d4445226e4262b8d35287a9af702f`.
Other machines need not produce identical binaries or work counts. Remote CI,
Windows runtime behavior and a new sanitizer run are not claimed here.
Loading
Loading