Documentation
Get started
Install SHOT, solve a first problem from the interface you already use, and set its options.
Install
The SHOTpy wheels include SHOT with the open-source subsolvers Cbc, Ipopt and HiGHS, and need Python 3.11 or later. They are built for Linux (x86-64) and macOS (Apple silicon, macOS 14 and later). On other Linux and macOS systems, pip builds SHOT from source, which needs the compiler and dependencies in the compilation instructions. Windows is not supported; use the Windows Subsystem for Linux.
pip install SHOTpy
Public wheels cannot include CPLEX, Gurobi or GAMS. If one of them is installed and licensed on your computer, build SHOTpy from source with it:
pip install SHOTpy --no-binary SHOTpy \
--config-settings=cmake.define.HAS_GUROBI=on \
--config-settings=cmake.define.GUROBI_DIR=/opt/gurobi1103/linux64Use the same pattern with HAS_CPLEX and CPLEX_DIR, or HAS_GAMS and GAMS_DIR.
SHOT is included in GAMS, and inside GAMS it can use any licensed NLP solver as subsolver. In GAMSPy, the Python modeling library of GAMS, SHOT is an add-on solver that you install separately. This is the easiest way to use SHOT.
pip install gamspy
gamspy install solver shotTo try SHOT without installing anything, submit a model in GAMS format to SHOT on the NEOS Server, a free internet-based service for numerical optimization.
SHOT compiles on Linux and macOS with CMake and a C++17 compiler; on Windows, use the Windows Subsystem for Linux. It needs a MIP solver and an NLP solver; the open-source Cbc, HiGHS and Ipopt are enough. HiGHS is compiled from its submodule by default.
git clone https://github.com/coin-or/SHOT.git
cd SHOT
git submodule update --init --recursive
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DCBC_DIR=/path/to/cbc \
-DIPOPT_DIR=/path/to/ipopt
cmake --build build --parallelCBC_DIR and IPOPT_DIR give the locations of Cbc and Ipopt, if CMake does not find them itself. To use an installed HiGHS instead of the submodule, add -DUSE_EXTERNAL_HIGHS=on and -DHIGHS_EXTERNAL_DIR=/path/to/highs. This builds the SHOT executable and the libSHOTSolver library in build/; add -DHAS_PYTHON=on to also build SHOTpy. Check the CMake output for lines saying that a solver was not found; such a solver is left out of the build.
SHOT reads AMPL (.nl) and OSiL (.osil) files out of the box. Reading GAMS (.gms) files requires SHOT to be compiled with a GAMS installation.
Solve a problem
import SHOTpy
solver = SHOTpy.Solver()
problem = SHOTpy.Problem(solver)
x = problem.addVariable("x", SHOTpy.VariableType.Real, 0.0, 10.0)
y = problem.addVariable("y", SHOTpy.VariableType.Integer, 0.0, 10.0)
problem.setObjective(SHOTpy.exp(x) + (y - 2.5)**2)
problem.addConstraint(x + y >= 3, "c")
problem.finalize()
solver.setProblem(problem)
solver.solveProblem()
print(solver.getModelReturnStatus(), solver.getPrimalSolution().point)Build the problem with the API, or read it from a file with solver.setProblem("problem.nl"), which also accepts .gms and .osil files. The tutorial notebook covers nonlinear expressions, settings and callbacks.
import gamspy as gp
m = gp.Container()
x = gp.Variable(m, name="x", type="integer")
y = gp.Variable(m, name="y", type="positive")
x.up = 10
y.up = 10
con = gp.Equation(m, name="con")
con[...] = gp.math.sqr(x - 4) + gp.math.sqr(y - 3) <= 4
model = gp.Model(m, name="model", equations=[con], problem="MINLP",
sense=gp.Sense.MIN, objective=2 * x + y)
model.solve(solver="SHOT")
print(model.objective_value)Install SHOT in GAMSPy with gamspy install solver shot, then pass solver="SHOT" to solve() for MINLP and MIQCP models.
* Select SHOT for the problem class, in the model or on the command line
option minlp = shot;
solve mymodel using minlp minimizing obj;You can also set it on the command line, e.g., gams model.gms minlp=shot.
import pyomo.environ as pyo
model = pyo.ConcreteModel()
# ... variables, constraints and objective ...
# SHOT is called through the AMPL Solver Library (ASL) interface
solver = pyo.SolverFactory("asl:SHOT") # or add executable="/path/to/SHOT"
solver.solve(model, tee=True)The SHOT executable must be on your path, or given with executable. With GAMS installed, you can also use SHOT through the Pyomo GAMS interface.
using JuMP, AmplNLWriter
model = Model(() -> AmplNLWriter.Optimizer("SHOT")) # or the full path to SHOT
# ... variables, constraints and objective ...
optimize!(model)JuMP calls SHOT through AmplNLWriter.jl, which writes the model in AMPL .nl format. A native JuMP interface is on the roadmap after SHOT 2.0.
# SHOT reads the .nl file and writes problem.sol next to it
./SHOT problem.nl --AMPLSHOT works with any modeling system that uses the AMPL Solver Library: models in .nl format and solutions in .sol format. In AMPL, set SHOT as the solver with option solver.
./SHOT problem.osil # OSiL is always supported
./SHOT problem.nl --timelimit=60 # AMPL
./SHOT problem.gms --mip=highs # GAMS
./SHOT --help # what this build supportsSHOT prints the dual and primal bounds as it iterates, and writes the solution in OSrL format and a log to SHOT.log.
#include "Solver.h"
auto solver = std::make_unique<SHOT::Solver>();
solver->updateSetting("Termination.TimeLimit", 60.0);
if(solver->setProblem("problem.osil") && solver->solveProblem())
{
double primal = solver->getPrimalBound();
double dual = solver->getCurrentDualBound();
}Link against libSHOTSolver to embed SHOT in other software; the console application is a thin wrapper around this API. Callbacks are registered with registerCallback.
Set options
Any setting can be given on the command line as Name=value, without spaces around
the =. Names are case sensitive. Unknown names are ignored, and SHOT lists them in a warning.
./SHOT problem.nl Termination.TimeLimit=100.0 Termination.ObjectiveGap.Relative=0.001
In SHOTpy and C++, use updateSetting before setProblem.
Settings can also be read from a file with --opt [file] (GAMS style) or
--osol [file] (OSoL); without a file name, SHOT writes a template. Common settings have shorthand flags:
| Flag | Effect |
|---|---|
--convex | Assume that the problem is convex |
--mip=<cbc|highs|cplex|gurobi> | Select the MIP solver of the dual strategy |
--nlp=<ipopt|gams|shot|uno> | Select the NLP solver of the primal strategy |
--tree=<single|multi> | Single-tree (branch and cut, CPLEX and Gurobi) or multi-tree strategy |
--threads=<n> | Maximum number of threads |
--absgap=<value> | Absolute objective gap tolerance |
--relgap=<value> | Relative objective gap tolerance |
--timelimit=<value> | Time limit in seconds |
--debug[=<directory>] | Write intermediate problems and solutions |
All settings
./SHOT --docs writes options.md with every setting, its type,
default value and description, generated from the build you run. It is the authoritative reference for your version.
Read the results
Console
The dual and primal bounds and the objective gap in each iteration. Set the detail with Output.Console.LogLevel, from 0 (trace) to 6 (off).
Log
SHOT.log in the current directory, or --log file.
Solution
Always in OSrL format, problem.osrl or --osrl file. Add --trc for a GAMS trace file and --sol for an AMPL solution file.
Exit code
0 when the run succeeded, whatever the model status; the status is in the result files.