Setting and Getting AMPL Options in amplpy#

options.ipynb Open In Colab Open In Deepnote Open In Kaggle Open In Gradient Open In SageMaker Studio Lab Powered by AMPL

Description: Shows every way amplpy exposes to set and get AMPL options — snake_case methods, dict-style indexing, camelCase aliases, and per-solve keyword overrides — covering interpreter options, solver-specific option strings, value types, and restore patterns.

Tags: amplpy, api, options, solver-options, highlights

Notebook author: Jürgen Lentz <lentz@ampl.com>


AMPL options control everything from which solver runs a model to how much diagnostic output the interpreter prints. amplpy gives you several equivalent ways to read and write them, which is convenient once you know they are equivalent — and confusing until then. This notebook lays them all out side by side.

Ways to set an option:

Method

Example

ampl.set_option(name, value)

ampl.set_option("solver", "highs")

ampl.option[name] = value

ampl.option["solver"] = "highs"

ampl.setOption(name, value)

camelCase alias, identical behaviour

ampl.solve(solver=..., <solver>_options=...)

sets a solver options string right before solving

Ways to get an option:

Method

Returns

ampl.get_option(name)

the current value, or None if the option was never set

ampl.option[name]

same, dict-style

ampl.getOption(name)

camelCase alias

# Install dependencies
%pip install -q amplpy
# Google Colab & Kaggle integration
from amplpy import AMPL, ampl_notebook

ampl = ampl_notebook(
    modules=["highs"],  # modules to install
    license_uuid="default",  # license to use
)  # instantiate AMPL object and register magics

Running example: the diet problem#

We reuse the classic diet problem to see options take effect on a real solve — most of the option mechanics themselves are demonstrated with short, standalone snippets.

import pandas as pd
import numpy as np
from amplpy import AMPL

foods = ["BEEF", "CHK", "FISH", "HAM", "MCH", "MTL", "SPG", "TUR"]
nutrs = ["A", "B1", "B2", "C"]

food_df = pd.DataFrame(
    {
        "cost":  [3.19, 2.59, 2.29, 2.89, 1.89, 1.99, 1.99, 2.49],
        "f_min": [0] * 8,
        "f_max": [100] * 8,
    },
    index=pd.Index(foods, name="FOOD"),
)
nutr_df = pd.DataFrame(
    {"n_min": [700] * 4, "n_max": [10000] * 4},
    index=pd.Index(nutrs, name="NUTR"),
)
amt_df = pd.DataFrame(
    np.array(
        [
            [60,  8,  8, 40, 15, 70, 25, 60],
            [10, 20, 15, 35, 15, 15, 25, 15],
            [15, 20, 10, 10, 15, 15, 15, 10],
            [20,  0, 10, 40, 35, 30, 50, 20],
        ]
    ),
    index=pd.Index(nutrs, name="NUTR"),
    columns=pd.Index(foods, name="FOOD"),
)

_MODEL = """
set FOOD;
set NUTR;
param cost {FOOD} > 0;
param f_min {FOOD} >= 0;
param f_max {j in FOOD} >= f_min[j];
param n_min {NUTR} >= 0;
param n_max {i in NUTR} >= n_min[i];
param amt {NUTR, FOOD} >= 0;
var Buy {j in FOOD} >= f_min[j], <= f_max[j];
minimize Total_Cost: sum {j in FOOD} cost[j] * Buy[j];
subject to Diet {i in NUTR}:
    n_min[i] <= sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];
"""

def make_ampl():
    """Return a fresh AMPL instance with the diet model and data loaded."""
    a = AMPL()
    a.eval(_MODEL)
    a.set["FOOD"] = foods
    a.set["NUTR"] = nutrs
    a.set_data(food_df, "FOOD")
    a.set_data(nutr_df, "NUTR")
    a.param["amt"] = amt_df
    return a

Two kinds of options#

Kind

Examples

Value

Interpreter options

solver, show_stats, presolve, relax_integrality

a single number, string, or flag

Solver option strings

highs_options, cplex_options, gurobi_options

one string bundling several key=value suboptions understood by that solver

Both kinds are read and written the same way from amplpy — the only difference is what you put in the value.

ampl = make_ampl()

ampl.set_option("solver", "highs")
ampl.set_option("show_stats", 1)
print("--- with show_stats = 1 ---")
ampl.solve()

ampl.set_option("show_stats", 0)
print("--- with show_stats = 0 ---")
ampl.solve()
--- with show_stats = 1 ---

8 variables, all linear
4 constraints, all linear; 31 nonzeros
	4 range constraints
1 linear objective; 8 nonzeros.
HiGHS 1.7.1: 

HiGHS 1.7.1: optimal solution; objective 88.2
1 simplex iterations
0 barrier iterations
--- with show_stats = 0 ---
HiGHS 1.7.1: 

HiGHS 1.7.1: optimal solution; objective 88.2
0 simplex iterations
0 barrier iterations

Three ways to set an option#

The three styles below all end up setting the same underlying AMPL option — they are interchangeable, so pick whichever reads best in context.

ampl = AMPL()

ampl.set_option("solver", "highs")
print("set_option:  ", ampl.get_option("solver"))

ampl.option["solver"] = "cplex"
print("option[...]: ", ampl.get_option("solver"))

ampl.setOption("solver", "highs")
print("setOption:   ", ampl.get_option("solver"))
set_option:   highs
option[...]:  cplex
setOption:    highs

Three ways to get an option#

get_option, option[...], and getOption all hand back a native Python value directly and are fully interchangeable.

ampl = AMPL()
ampl.set_option("solver", "highs")

print("get_option:  ", ampl.get_option("solver"))
print("option[...]: ", ampl.option["solver"])
print("getOption:   ", ampl.getOption("solver"))
get_option:   highs
option[...]:  highs
getOption:    highs

Solver-specific option strings#

A solver options string bundles several suboptions into one value, space-separated as key=value pairs. amplpy has no per-suboption getter for these — you set and get the whole string, and parse it yourself if you need individual values.

ampl = AMPL()
ampl.set_option("highs_options", "outlev=1 timelim=10 presolve=off")

raw = ampl.get_option("highs_options")
print("raw string:", raw)

parsed = dict(pair.split("=") for pair in raw.split())
print("parsed:    ", parsed)

# Change a single suboption and write the whole string back
parsed["timelim"] = "30"
ampl.set_option("highs_options", " ".join(f"{k}={v}" for k, v in parsed.items()))
print("updated:   ", ampl.get_option("highs_options"))
raw string: outlev=1 timelim=10 presolve=off
parsed:     {'outlev': '1', 'timelim': '10', 'presolve': 'off'}
updated:    outlev=1 timelim=30 presolve=off

Setting solver options via solve()#

ampl.solve() accepts <solver>_options as a keyword argument — a shortcut for calling set_option() right before solving. The option is set as a normal option and keeps its value afterwards, it is not automatically reverted.

ampl = make_ampl()
print("before solve:", ampl.get_option("highs_options"))

ampl.solve(solver="highs", highs_options="outlev=1")

print("after solve: ", ampl.get_option("highs_options"))
before solve: None
HiGHS 1.7.1: 
  tech:outlev = 1
Running HiGHS 1.7.1 (git hash: dcf3813): Copyright (c) 2024 HiGHS under MIT licence terms
Coefficient ranges:
  Matrix [8e+00, 7e+01]
  Cost   [2e+00, 3e+00]
  Bound  [1e+02, 1e+02]
  RHS    [7e+02, 1e+04]
Presolving model
4 rows, 8 cols, 31 nonzeros  0s
4 rows, 8 cols, 31 nonzeros  0s
Presolve : Reductions: rows 4(-0); columns 8(-0); elements 31(-0) - Not reduced
Problem not reduced by presolve: solving the LP
Using EKK dual simplex solver - serial
  Iteration        Objective     Infeasibilities num(sum)
          0     0.0000000000e+00 Pr: 4(2800) 0s
          1     8.8200000000e+01 Pr: 0(0) 0s
Model   status      : Optimal
Simplex   iterations: 1
Objective value     :  8.8200000000e+01
HiGHS run time      :          0.00
HiGHS 1.7.1: optimal solution; objective 88.2
1 simplex iterations
0 barrier iterations
after solve:  outlev=1

Value types and unset options#

set_option() accepts Python int, float, str, and bool. AMPL options are fundamentally numeric or string values, so a Python bool is stored and returned as 0/1, not as True/False. get_option() returns None only for a name that was never set — well-known options always have a default.

ampl = AMPL()

ampl.set_option("show_stats", True)
print("bool in:   ", ampl.get_option("show_stats"), type(ampl.get_option("show_stats")))

ampl.set_option("solver", "highs")
print("string:    ", ampl.get_option("solver"), type(ampl.get_option("solver")))

print("known default (never set): presolve =", ampl.get_option("presolve"))
print("unknown, never set:        ", ampl.get_option("not_a_real_option"))
bool in:    1 <class 'int'>
string:     highs <class 'str'>
known default (never set): presolve = 10
unknown, never set:         None

Pattern — temporarily overriding an option#

Save the previous value with get_option(), set the new one, and restore it in a finally block — a small context manager makes this a one-liner and mirrors the save/restore pattern used for output and error handlers in the companion notebooks.

from contextlib import contextmanager


@contextmanager
def temporary_option(ampl, name, value):
    previous = ampl.get_option(name)
    ampl.set_option(name, value)
    try:
        yield
    finally:
        ampl.set_option(name, previous)


ampl = make_ampl()
ampl.set_option("solver", "highs")

print("before:", ampl.get_option("show_stats"))
with temporary_option(ampl, "show_stats", 1):
    print("inside:", ampl.get_option("show_stats"))
    ampl.solve()
print("after: ", ampl.get_option("show_stats"))
before: 0
inside: 1

8 variables, all linear
4 constraints, all linear; 31 nonzeros
	4 range constraints
1 linear objective; 8 nonzeros.
HiGHS 1.7.1: 

HiGHS 1.7.1: optimal solution; objective 88.2
1 simplex iterations
0 barrier iterations
after:  0

Resetting all options to their defaults#

ampl.eval("reset options;") clears every option back to its AMPL default in one call — useful between independent runs in the same session so leftover options from a previous experiment cannot leak in.

ampl = AMPL()
ampl.set_option("solver", "highs")
ampl.set_option("show_stats", 1)
print("before reset:", ampl.get_option("solver"), ampl.get_option("show_stats"))

ampl.eval("reset options;")
print("after reset: ", repr(ampl.get_option("solver")), ampl.get_option("show_stats"))
before reset: highs 1
after reset:  '' 0

Summary#

Way

Set

Get

snake_case methods

ampl.set_option(name, value)

ampl.get_option(name)

dict-style

ampl.option[name] = value

ampl.option[name]

camelCase alias

ampl.setOption(name, value)

ampl.getOption(name)

per-solve shortcut

ampl.solve(solver=..., <solver>_options=...)

—

Key points:

  • All setter/getter styles are interchangeable — they read and write the exact same underlying AMPL option.

  • Interpreter options (solver, show_stats, presolve, …) hold a single value; solver option strings (highs_options, cplex_options, …) bundle several key=value suboptions in one string that you parse yourself.

  • ampl.solve(solver=..., <solver>_options=...) is a convenience for setting a solver’s option string right before solving — the value persists afterwards, it is not scoped to that call.

  • get_option() returns None only for a name that has never been set; documented options always come back with their AMPL default.

  • ampl.eval("reset options;") clears every option back to its default.

  • Errors while setting an invalid option name go through the active ErrorHandler — see error_handler.ipynb.