oximo-gams
GAMS backend for oximo.
Writes an oximo Model to a temporary .gms file, invokes the GAMS executable via std::process::Command, and parses the solution from a PUT-generated text file. Supports LP, MILP, QP, MIQP, NLP, and MINLP model kinds.
The sub-solver is determined by the GAMS installation (default) or set explicitly via GamsOptions::solver. Any solver available in your GAMS distribution can be targeted, see Sub-solver selection below.
Requirements
A licensed GAMS installation must be on PATH.
- Download and install GAMS for your platform.
- Obtain and activate a GAMS license.
- Verify by running
gamsin a terminal.
If gams is not on PATH, pass an explicit path via GamsOptions::gams_path or Gams::with_exec:
use Gams;
let solver = with_exec;
Usage
Enable the gams feature on the umbrella oximo crate:
[]
= { = "0.5.1", = ["gams"] }
To use this crate directly:
[]
= "0.5.1"
= "0.5.1"
= "0.5.1"
Quick example
use *;
use Gams;
let m = new;
variable!;
variable!;
constraint!;
constraint!;
constraint!;
objective!;
let result = new.solve?;
println!;
println!;
println!;
Run the bundled example:
Options
GamsOptions is a plain struct with builder methods. Universal options come from UniversalOptionsExt.
Universal options (via UniversalOptionsExt)
| Method | GAMS statement | Default |
|---|---|---|
.time_limit(Duration) |
option ResLim = <seconds>; |
none |
.threads(usize) |
option threads = <n>; |
none |
.verbose(bool) |
Forwards GAMS stdout/stderr to raw_log (suppresses lo=0) |
none |
GAMS-specific options
| Method | Description | Default |
|---|---|---|
.mip_gap(f64) |
option OptCR = <gap>; relative MIP optimality gap |
none |
.solver(config) |
Sub-solver selection, see below | none |
.gams_path(path) |
Override path to the gams executable |
"gams" from PATH |
use Duration;
use GamsOptions;
use UniversalOptionsExt;
let opts = default
.time_limit
.threads
.mip_gap
.verbose;
Sub-solver selection
Pass a GamsSolverConfig to .solver(...) to select a GAMS sub-solver. This emits
option {LP|MIP|NLP|MINLP|QCP|MIQCP} = <NAME>; in the generated .gms file, scoped to
the solve type resolved from Model::kind() (QP -> QCP, MIQP -> MIQCP).
use ;
// Named selection, no typed option file
let opts = default.solver;
// Or via Custom for any solver name not in the enum
let opts = default.solver;
Per-solver typed options
Wrap the sub-solver's options struct in GamsSolverConfig to have oximo write a
<solver>.opt file. GAMS picks it up via model.optfile = 1. Each struct exposes
one builder setter per documented GAMS option.
use ;
use Duration;
use UniversalOptionsExt;
let opts = default
.time_limit
.solver;
For any option without a generated setter, push a verbatim line onto the public
raw field:
use ;
let cfg = Cplex;
The Gams<Name>Options structs and GamsSolverConfig are generated at build
time from the checked-in option-snapshots/, one struct per
GAMS solver oximo supports from a modelling standpoint: ALPHAECP, ANTIGONE, BARON,
CBC, CONOPT, CONOPT3, COPT, CPLEX, DECIS, DICOPT, GUROBI, HIGHS, IPOPT, KNITRO,
LINDO, MINOS, MOSEK, ODHCPLEX, SBB, SCIP, SHOT, SNOPT, SOPLEX and XPRESS. Each
solver's options are documented at https://www.gams.com/latest/docs/S_<NAME>.html.
For any other solver, select it by name with
GamsSolverConfig::Named(GamsSolver::Custom("NAME".into())), or write verbatim
option lines with GamsSolverConfig::Raw(GamsSolver::Custom("NAME".into()), vec![..]).
Result
SolverResult fields, populated whenever a usable point is available (primal_status is FeasiblePoint or OptimalPoint):
solutions- primal points (Vec<SolutionPoint>), best first. Each point holds itsprimalvalues keyed byVarIdand itsobjective. The vector holds the incumbent, plus any alternative points read from a sub-solver solution pool (e.g. CPLEXsolnpool). Access the best point viaresult.objective()/result.value_of(var)and the rest viaresult.solution(i)dual- constraint marginals (GAMS.m), keyed byConstraintId, access viaresult.dual_of(c)reduced_costs- variable marginals, keyed byVarIdtermination- why the solve stopped, driven by the GAMS solve status (solvestat), with the model status (modelstat) resolving the outcome on normal completion (Optimal,Infeasible,Unbounded,TimeLimit,IterationLimit, ...)primal_status- whether a usable point came back (NoSolution/FeasiblePoint/OptimalPoint),result.has_solution()is the shortcutbest_bound/gap- left unset (None), not exposed in the GAMS PUT solution filesolve_time- wall time around the GAMS process invocationiterations- iterations used, read from the GAMS model attributeoximo_m.iterusdsolver_name-GAMS/<sub-solver>when one is selected viaGamsOptions::solver(e.g.GAMS/CPLEX,GAMS/BARON), otherwise justGAMSraw_log- GAMS stdout/stderr, populated whenverbose(true)or when GAMS exits non-zero
dual and reduced_costs are filled with whatever marginals GAMS reports, for every model kind: globally valid duals for LP, locally valid duals at the returned point for QP/NLP, and duals of the integer-fixed problem for MIP/MIQP/MINLP (most GAMS solver links re-solve with integers fixed, e.g. CPLEX solvefinal). Entries the solver did not compute (NA/UNDF) are skipped, so a solver configured to skip the fixed re-solve simply leaves the maps empty.
License
MIT OR Apache-2.0
Note: GAMS itself is commercial software. A valid GAMS license is required at runtime. This crate is not affiliated with GAMS Development Corporation.