User guide · 2.0 development

Configuring Solver Settings

SHOT provides extensive configuration options through its settings system.

Accessing and Modifying Settings

# Create the solver first
solver = SHOTpy.Solver()

# Create a simple problem
problem = SHOTpy.Problem(solver)
x = problem.addVariable("x", SHOTpy.VariableType.Real, 0.0, 10.0)
problem.setObjective(x)

problem.finalize()
solver.setProblem(problem)

# Get current values
print("Current Settings:")
time_limit = solver.getDoubleSetting("Termination.TimeLimit")
print(f"  Time limit: {time_limit} seconds")

abs_gap = solver.getDoubleSetting("Termination.ObjectiveGap.Absolute")
print(f"  Absolute gap tolerance: {abs_gap}")

# Modify settings
print("\nModifying settings...")
solver.updateSetting("Termination.TimeLimit", 300.0)  # 5 minutes
solver.updateSetting("Termination.ObjectiveGap.Absolute", 1e-6)

# Verify changes
new_time = solver.getDoubleSetting("Termination.TimeLimit")
new_gap = solver.getDoubleSetting("Termination.ObjectiveGap.Absolute")
print(f"  New time limit: {new_time} seconds")
print(f"  New absolute gap: {new_gap}")

Common Settings

Change the settings before calling solver.setProblem(). That call reformulates the problem, chooses the solution strategy, and creates the MIP and NLP solvers with their parameters, so most settings are fixed from then on: e.g., the MIP and NLP solvers, the tree strategy, the reformulation and bound tightening settings, and all subsolver settings (Subsolver.*). A setting changed afterwards is accepted without a message, but may have no effect, or only a partial one: e.g., a new Termination.ObjectiveGap.Relative is used by SHOT’s own termination check but not by the MIP solver. Settings that SHOT only reads while solving, such as Termination.TimeLimit and the output settings, can also be changed afterwards.

Here are some frequently used settings:

solver = SHOTpy.Solver()

# The settings are changed before setProblem(), which creates the solution strategy and the MIP and NLP solvers

# Termination criteria
solver.updateSetting("Termination.TimeLimit", 600.0)              # Max time in seconds
solver.updateSetting("Termination.ObjectiveGap.Absolute", 1e-5)   # Absolute gap
solver.updateSetting("Termination.ObjectiveGap.Relative", 1e-4)   # Relative gap

# Output settings: 0 = Trace, 1 = Debug, 2 = Info, 3 = Warning, 4 = Error, 5 = Critical, 6 = Off
solver.updateSetting("Output.Console.LogLevel", 2)

# MIP solver selection, among those this build of SHOT has (convert enum to int)
for available, mipSolver in [(SHOTpy.HAS_GUROBI, SHOTpy.MIPSolver.Gurobi), (SHOTpy.HAS_CPLEX, SHOTpy.MIPSolver.Cplex),
                             (SHOTpy.HAS_HIGHS, SHOTpy.MIPSolver.Highs), (SHOTpy.HAS_CBC, SHOTpy.MIPSolver.Cbc)]:
    if available:
        solver.updateSetting("Dual.MIP.Solver", int(mipSolver))
        break

# NLP solver selection
if SHOTpy.HAS_IPOPT:
    solver.updateSetting("Primal.FixedInteger.Solver", int(SHOTpy.PrimalNLPSolver.Ipopt))

print("Settings configured successfully!")

# Verify some settings
print(f"Time limit: {solver.getDoubleSetting('Termination.TimeLimit')} seconds")
print(f"Log level: {solver.getIntSetting('Output.Console.LogLevel')}")
print(f"MIP solver: {SHOTpy.MIPSolver(solver.getIntSetting('Dual.MIP.Solver')).name}")

# The problem is then created, finalized and given to the solver
problem = SHOTpy.Problem(solver)
x = problem.addVariable("x", SHOTpy.VariableType.Real, 0.0, 10.0)
problem.setObjective(x)
problem.finalize()
assert solver.setProblem(problem)