Skip to content

Replace Solver Status API#27

Merged
GermanHeim merged 16 commits into
mainfrom
solver-status
Jun 24, 2026
Merged

Replace Solver Status API#27
GermanHeim merged 16 commits into
mainfrom
solver-status

Conversation

@GermanHeim

@GermanHeim GermanHeim commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR replaces the SolverStatus with two enums: TerminationStatus (why the solver stopped) and PrimalStatus (whether a usable point came back).

This is a breaking change.

Checklist

  • I have updated the documentation accordingly
  • I have added tests that cover my changes
  • I have run cargo fmt and cargo clippy to ensure code quality
  • All default tests pass (cargo test)
  • cargo test --features gams passes (requires GAMS)
  • cargo test --features gurobi passes (requires Gurobi)
  • cargo test --features baron passes (requires BARON)

Summary by CodeRabbit

  • New Features
    • Solver results now expose separate termination (why the solve stopped) and primal_status (usable solution availability), plus has_solution().
    • Added best_bound and gap when finite bounds are available.
  • Bug Fixes
    • Improved termination/primal inference across solvers, including more reliable time-limit reporting (best objective only when a usable solution exists).
    • Refined backend outcome mappings (e.g., Gurobi/GAMS/BARON parsing and categorization).
  • Documentation
    • Updated READMEs and examples to use termination / primal_status instead of the prior status field.
  • Tests
    • Updated unit and integration tests to validate the new semantics and mappings.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The solver API now separates termination reasons from primal-point availability. Backend translators populate termination, primal_status, best_bound, and gap, and the READMEs, examples, and tests now use termination and has_solution() in result handling.

Changes

Termination and primal status split

Layer / File(s) Summary
Shared result contract
crates/oximo-solver/src/status.rs, crates/oximo-solver/src/result.rs, crates/oximo-solver/src/lib.rs, crates/oximo-solver/README.md, crates/oximo/src/lib.rs, crates/oximo/README.md, README.md, crates/oximo-baron/README.md, crates/oximo-gams/README.md, crates/oximo-gurobi/README.md, crates/oximo-highs/README.md
TerminationStatus and PrimalStatus replace SolverStatus, SolverResult carries termination, primal_status, best_bound, and gap, and the crate exports and solver docs match the new contract.
BARON translation
crates/oximo-baron/src/translate.rs, crates/oximo-baron/README.md, crates/oximo/tests/solve_baron.rs
BARON now derives termination from res.lst, infers primal availability from model status, computes best_bound and gap, and updates its example and tests.
GAMS translation
crates/oximo-gams/src/translate.rs, crates/oximo-gams/README.md, crates/oximo/tests/solve_gams.rs
GAMS now maps modelstat/solvestat into termination, infers primal_status, uses result.has_solution() for pool handling, and updates its example and integration tests.
Gurobi translation
crates/oximo-gurobi/src/translate.rs, crates/oximo-gurobi/README.md, crates/oximo-gurobi/tests/nonlinear.rs, crates/oximo/tests/solve_gurobi.rs
Gurobi now maps outcomes to termination, drives solution collection from SolCount, infers primal_status, and updates its examples and tests.
HiGHS translation
crates/oximo-highs/src/translate.rs, crates/oximo-highs/README.md
HiGHS now maps model status to termination, drives solution collection from a has_point flag, and updates its README and QP tests.
Generic usage updates
crates/oximo/examples/*, crates/oximo/tests/solve.rs
The root README, oximo README, examples, and generic solve tests now match on result.termination and use result.has_solution() where solution presence matters.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main breaking API replacement from SolverStatus to the new status enums.
Description check ✅ Passed The description covers the breaking change and checklist, though it omits the Changes Made and Related Issues sections.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch solver-status

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
crates/oximo-solver/src/status.rs (1)

32-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct contract tests for the new status helpers.

admits_primal() and PrimalStatus::infer() now define the shared incumbent/solution semantics for every translator, but this module doesn't pin the key combinations down yet. A small table-driven test over Optimal, LocallyOptimal, the limit states, and NotSolved would make future backend mapping changes much safer.

Also applies to: 64-82

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/oximo-solver/src/status.rs` around lines 32 - 48, Add direct
table-driven contract tests in the status module to lock down the shared
semantics between TerminationStatus::admits_primal() and PrimalStatus::infer().
Cover the key combinations mentioned in the review, including Optimal,
LocallyOptimal, the various limit states, and NotSolved, and assert the expected
primal-availability/inferral behavior so translator mapping changes are caught
early. Use the existing TerminationStatus and PrimalStatus symbols in this
module to place the tests alongside the helper implementations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/oximo-baron/README.md`:
- Around line 54-56: The README’s `## Result` section is still documenting the
old `status`-based API, while the example above already uses
`result.termination`, `result.primal_status`, and `result.objective()`. Update
the later result-field list to match the renamed fields and new success model,
and remove any remaining references to the removed `status` field so the
`Result` documentation is consistent with the current API.

In `@crates/oximo-baron/src/translate.rs`:
- Line 563: The `PrimalStatus::infer` call in `translate` is using
`!solutions.is_empty()` as a proxy for a usable primal point, but the `nodeopt
== -3` fallback can add a `SolutionPoint` with an empty `primal` map. Update the
status inference logic so it only treats entries in `solutions` as usable when
they actually contain primal data, and ensure the
`SolutionPoint`/`has_solution()` path reflects that distinction. Also tighten
the existing `nodeopt == -3` regression test to assert that this fallback does
not report a usable solution via `has_solution()`, `primal()`, or `value_of()`.

In `@crates/oximo-gams/README.md`:
- Around line 58-60: Update the README’s later ## Result documentation to match
the new split result API shown in the example, replacing references to the
removed status field and pre-split contract with the current result fields used
by Result::termination, Result::primal_status, and Result::objective(). Keep the
terminology consistent throughout the document so the Result section and the
example describe the same contract.

In `@crates/oximo-gurobi/src/translate.rs`:
- Around line 79-90: Do not use TerminationStatus alone to imply a primal
solution in translate.rs: the collect_solution/single-point path in translate
should only mark a feasible primal when Gurobi actually has an incumbent. Update
collect_solution and the call site that computes primal_status to gate on
SolCount/X availability (and not just admits_primal or limit/interrupted
termination), so has_solution() stays false when no real solution exists.

In `@crates/oximo/README.md`:
- Around line 267-272: The README example in the `match result.termination`
snippet should not assume `result.objective()` is always present for
`TerminationStatus::Optimal`; update the example to avoid unwrapping the
objective and instead handle the optional value safely, since
`Result::objective` can be absent even when a feasible solution exists. Keep the
example aligned with the `TerminationStatus` handling shown in
`result.termination` and use a pattern that prints the objective only when it is
available.

In `@README.md`:
- Around line 267-272: The README example still implies that
TerminationStatus::Optimal alone guarantees an objective is available, which
conflicts with the new split between termination and solution presence. Update
the match on result.termination so the Optimal arm also guards any call to
result.objective() with result.has_solution() (or the equivalent primal_status
check), and adjust the sample text to show that objective reads are
solution-dependent rather than tied to termination alone. Keep the TimeLimit arm
consistent with this pattern and reference the result.has_solution() /
result.objective() APIs in the example narrative.

---

Nitpick comments:
In `@crates/oximo-solver/src/status.rs`:
- Around line 32-48: Add direct table-driven contract tests in the status module
to lock down the shared semantics between TerminationStatus::admits_primal() and
PrimalStatus::infer(). Cover the key combinations mentioned in the review,
including Optimal, LocallyOptimal, the various limit states, and NotSolved, and
assert the expected primal-availability/inferral behavior so translator mapping
changes are caught early. Use the existing TerminationStatus and PrimalStatus
symbols in this module to place the tests alongside the helper implementations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dc4bae8d-c465-4fb6-8d2a-6b10219c45c2

📥 Commits

Reviewing files that changed from the base of the PR and between ee7a751 and 6f3038f.

📒 Files selected for processing (25)
  • README.md
  • crates/oximo-baron/README.md
  • crates/oximo-baron/src/translate.rs
  • crates/oximo-gams/README.md
  • crates/oximo-gams/src/translate.rs
  • crates/oximo-gurobi/README.md
  • crates/oximo-gurobi/src/translate.rs
  • crates/oximo-gurobi/tests/nonlinear.rs
  • crates/oximo-highs/README.md
  • crates/oximo-highs/src/translate.rs
  • crates/oximo-solver/README.md
  • crates/oximo-solver/src/lib.rs
  • crates/oximo-solver/src/result.rs
  • crates/oximo-solver/src/status.rs
  • crates/oximo/README.md
  • crates/oximo/examples/baron_robot.rs
  • crates/oximo/examples/lot_sizing.rs
  • crates/oximo/examples/parametric_pricing.rs
  • crates/oximo/examples/process_selection.rs
  • crates/oximo/examples/reaction_path.rs
  • crates/oximo/src/lib.rs
  • crates/oximo/tests/solve.rs
  • crates/oximo/tests/solve_baron.rs
  • crates/oximo/tests/solve_gams.rs
  • crates/oximo/tests/solve_gurobi.rs

Comment thread crates/oximo-baron/README.md
Comment thread crates/oximo-baron/src/translate.rs Outdated
Comment thread crates/oximo-gams/README.md
Comment thread crates/oximo-gurobi/src/translate.rs Outdated
Comment thread crates/oximo/README.md
Comment thread README.md
@GermanHeim GermanHeim merged commit 16f0525 into main Jun 24, 2026
3 checks passed
@GermanHeim GermanHeim deleted the solver-status branch June 24, 2026 19:34
GermanHeim added a commit that referenced this pull request Jun 27, 2026
Since #27 is a breaking change, we can already remove the deprecated code.
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