- In a script of AMPL commands, you may want
to test whether the most recent
`solve`encountered an unbounded or infeasible problem. - After you have solved a linear program by the simplex method, you may want to use the optimal basis partition to provide a good start for solving a related problem.

We begin by describing a convenient and precise new way of
testing the overall result of a solver run, and the result of the most
recent solver run for a specified objective or named problem. Then we
describe the *solver status* for variables and constraints and its
use to specify an advanced start. We conclude by describing a
complementary *AMPL status* that characterizes model components
that have not been sent to the solver for various reasons. For most
purposes, a variable or constraint's status of interest can be denoted
by adding the suffix `.status` to its name.

At the beginning of an AMPL session,ampl:modelampl:diet.mod;ampl:data diet2.dat;solve_result_num = -1 solve_result = '?' ampl:display solve_result_num, solve_result;MINOS 5.5: infeasible problem. 9 iterations ampl:solve;solve_result_num = 200 solve_result = infeasible ampl:display solve_result_num, solve_result;option solve_result_table '\ 0 solved\ 100 solved?\ 200 infeasible\ 300 unbounded\ 400 limit\ 500 failure\ ';option solve_result_table;

Normally this status information is used in scripts, where it can be tested to distinguish among cases that must be handled in different ways. As an example, the following script for the diet problem progressively decrements the sodium limit,number stringinterpretation0 - 99 solvedoptimal solution found100 - 199 solved?optimal solution indicated, but error likely200 - 299 infeasibleconstraints cannot be satisfied300 - 399 unboundedobjective can be improved without limit400 - 499 limitstopped by a limit that you set (such as on iterations)500 - 599 failurestopped by an error condition in the solver routines

Themodel diet.mod; data diet2a.dat; repeat { solve; if solve_result = "infeasible" then break; let n_max["NA"] := n_max["NA"] - 1000; };

The value ofsolve_result_num message at termination0 optimal solution 1 primal has unbounded optimal face 2 optimal integer solution 3 optimal integer solution within mipgap or absmipgap

The brief result message that the solver returns to AMPL is
also accessible via a built-in symbolic parameter, `solve_message`:

You can use AMPL's string functions to test the contents ofampl:solve_message = 'MINOS 5.5: infeasible problem.\ 9 iterations'display solve_message;

Solve results can be returned as described above only if AMPL's invocation of the solver has been successful. Invocation can fail because the operating system is unable to find or execute the specified solver, or because some low-level error prevents the solver from attempting or completing the optimization. Typical causes include a misspelled solver name, improper installation of the solver, missing or corrupt input files, insufficient memory or disk space, and termination of the solver process by an execution fault ("core dump") or a "break" from the keyboard.

The built-in parameter `solve_exitcode` records the
success or failure of the most recent solver invocation. Initially
`-1`, it is reset to 0 whenever there has been a successful
invocation, and to some nonzero value otherwise:

Here the failed invocation, due to the misspelled solver nameampl:ampl:reset;solve_exitcode = -1 ampl:display solve_exitcode;ampl:model diet.mod;ampl:data diet2.dat;ampl:option solver xplex;Cannot invoke xplex: No such file or directory exit code 4 <BREAK> ampl:solve;solve_exitcode = 1024 ampl:display solve_exitcode;solve_result = '?' solve_result_num = -1display solve_result, solve_result_num;

If `solve_exitcode` exceeds the value in option
`solve_exitcode_max`, then AMPL aborts any currently executing
compound commands (`include`, `commands`,
`repeat`, `for`, `if`). The default value of
`solve_exitcode_max` is 0, so that AMPL normally aborts compound
commands whenever a solver's invocation fails. A script that sets
`solve_exitcode_max` to a higher value may test the value of
`solve_exitcode`, but in general its interpretation is not
consistent across operating systems or solvers.

Appended to an objective or problem name, this suffix indicates the value of the corresponding built-in parameter at the most recent solve in which the objective or problem was current. Thus our sample script trnloc1p.run for Benders decomposition suffixesbuilt-in parameter suffixsolve_result .result solve_result_num .result_num solve_message .message solve_exitcode .exitcode

As another example, consider the small McDonald's diet model. Its objective functions are defined as:if SubPoint.result = "infeasible" then { ...

After minimizing three of these objectives, we can view the solve status values for all of them:minimize Total_Cost: sum {j in FOOD} cost[j] * Buy[j]; minimize Nutr_Amt {i in NUTR}: sum {j in FOOD} amt[i,j] * Buy[j];

For the objectives that have not yet been used, theampl:ampl:model diet1.mod;ampl:data diet1.dat;CPLEX 5.0: optimal integer solution; objective 15.05 74 simplex iterations 69 branch-and-bound nodes Objective = Total_Cost ampl:solve;ampl:objective Nutr_Amt['Cal'];CPLEX 5.0: optimal integer solution; objective 2500 11 simplex iterations 3 branch-and-bound nodes ampl:solve;ampl:objective Nutr_Amt['VitC'];CPLEX 5.0: optimal integer solution; objective 100 34 simplex iterations 26 branch-and-bound nodes ampl:solve;Total_Cost.result = solved Nutr_Amt.result [*] := Cal solved Carbo '?' Protein '?' VitA '?' VitC solved Calc '?' Iron '?' ;display Total_Cost.result, Nutr_Amt.result;

In addition to the variables declared by `var`
statements in an AMPL model, solvers also define "slack" or
"artificial" variables that are associated with constraints. Solver
statuses for these latter variables are defined in a similar way, as
explained in the next section. Both variables and constraints also
have an "AMPL status" that distinguishes those in the current problem
from those that have been removed from the problem by presolve or by
commands such as `drop`. The interpretation of AMPL statuses
and their relationship to solver statuses are considered in a
subsequent section.

The major use of solver status values from an optimal basic
solution is to provide a good starting point for the next optimization
run. The new option `send_statuses`, when left at its default
value of 1, instructs AMPL to include statuses with the information
about variables sent to the solver at each `solve`. You can see
the effect of this feature in almost any sensitivity analysis that
re-solves after making some small change to the problem. As an
example, consider what happens when the multi-period production example
from the AMPL book is solved repeatedly after increases of 5% in the
availability of labor. With the `send_statuses` option set to
0, the solver reports about 30 iterations of the simplex method each
time it is run:

Withampl:ampl:model steelT3.mod;ampl:data steelT3.dat;ampl:option send_statuses 0;CPLEX 5.0: optimal solution; objective 514521.7143 30 iterations (1 in phase I) ampl:solve;ampl:let {t in 1..T} avail[t] := 1.05 * avail[t];CPLEX 5.0: optimal solution; objective 537104 31 iterations (1 in phase I) ampl:solve;ampl:let {t in 1..T} avail[t] := 1.05 * avail[t];CPLEX 5.0: optimal solution; objective 560800.4 31 iterations (1 in phase I) ampl:solve;ampl:let {t in 1..T} avail[t] := 1.05 * avail[t];CPLEX 5.0: optimal solution; objective 585116.22 30 iterations (1 in phase I)solve;

Eachampl:ampl:model steelT3.mod;ampl:data steelT3.dat;CPLEX 5.0: optimal solution; objective 514521.7143 30 iterations (1 in phase I) ampl:solve;ampl:let {t in 1..T} avail[t] := 1.05 * avail[t];CPLEX 5.0: optimal solution; objective 537104 3 iterations (2 in phase I) ampl:solve;ampl:let {t in 1..T} avail[t] := 1.05 * avail[t];CPLEX 5.0: optimal solution; objective 560800.4 0 iterations ampl:solve;ampl:let {t in 1..T} avail[t] := 1.05 * avail[t];CPLEX 5.0: optimal solution; objective 585116.22 2 iterations (1 in phase I)solve;

The following discussion explains how you can view, interpret, and change variables' status values in the AMPL environment. You don't need to know any of this to use optimal bases as starting points as shown above, but these features can be useful in certain advanced circumstances.

AMPL refers to a variable's solver status by appending
`.sstatus` to its name. Thus you can exhibit the statuses of
variables by use of the `display` command. At the beginning of
a session (or after a `reset`), when no problem has yet been
solved, all variables have the status `none`:

After an invocation of a simplex method solver, the sameampl:ampl:model diet.mod;ampl:data diet2a.dat;Buy.sstatus [*] := BEEF none CHK none FISH none HAM none MCH none MTL none SPG none TUR none ;display Buy.sstatus;

Two of the variables --ampl:MINOS 5.5: optimal solution found. 13 iterations, objective 118.0594032 ampl:solve;Buy.sstatus [*] := BEEF bas CHK low FISH low HAM upp MCH upp MTL upp SPG bas TUR low ;display Buy.sstatus;

Numbers and short strings representing status values are given in the first two columns. (The numbers are mainly for communication between AMPL and solvers, though you can access them by using the suffixampl:option sstatus_table '\ 0 none no status assigned\ 1 bas basic\ 2 sup superbasic\ 3 low nonbasic <= (normally =) lower bound\ 4 upp nonbasic >= (normally =) upper bound\ 5 equ nonbasic at equal lower and upper bounds\ 6 btw nonbasic between bounds\ ';option sstatus_table;

You can change a variable's status by use of AMPL's
`let` command. This facility is sometimes useful when you want
to re-solve a problem after a small, well-defined change. For example,
consider the variables defined in our cutting-stock model, `cut1.mod`:

At each pass through the Gilmore-Gomory procedure, as implemented inparam nPAT integer >= 0; # number of patterns set PATTERNS := 1..nPAT; # set of patterns var Cut {PATTERNS} integer >= 0; # rolls cut using each pattern

It turns out that this change tends to reduce the number of iterations in each re-optimization of the cutting problem, at least with some simplex solvers. Setting a few statuses in this way is not guaranteed to reduce the number of iterations, however. Its success depends on the particular problem and solver, and on their interaction with a number of complicating factors:let Cut[nPAT].sstatus := "bas";

- After the problem and statuses have been modified, the statuses
conveyed to the solver at the next
`solve`may not properly define a basic solution. - After the problem has been modified, AMPL's presolve phase may send
a different subset of variables and constraints to the solver (unless
option
`presolve`is set to zero). As a result, the statuses conveyed to the solver may not correspond to a useful starting point for the next`solve`, and may not properly define a basic solution. - Some solvers, notably MINOS, use the current values as well as the
statuses of the variables in constructing the starting point at the
next
`solve`(unless option`reset_initial_guesses`is set to one).

For models that have several `var` declarations, AMPL's generic synonyms for variables provide a convenient way of
getting information about the statuses of all variables. Using
expressions such as `_var`, `_varname` and
`_var.sstatus` in a `display` statement, you can produce
a quick summary table of the
results. You can also easily list the names of all variables that
satisfy some condition, by using the statuses to define an appropriate
subset of the variables. Here, for example, are the names of all the
basic variables:

To display the values of the variables along with their names, you could use the same statement withampl:_varname[j] [*] := 1 "Make['bands',1]" 2 "Make['bands',2]" 3 "Make['bands',3]" 4 "Make['bands',4]" 5 "Make['coils',1]" 6 "Make['coils',2]" 7 "Make['coils',3]" 8 "Make['coils',4]" 15 "Inv['coils',1]" 22 "Sell['bands','east',4]" 32 "Sell['coils','west',2]" 33 "Sell['coils','west',3]" ;display {j in 1.._nvars: _var[j].sstatus = "bas"} _varname[j];

A simplex solver gains two advantages from having these "logical" variables added to the "structural" ones its gets from AMPL:

- The linear program is converted to a simpler form, in which the
only inequalities are the bounds on the variables.
- The solver's initialization (or "crash") routines can be designed so that they always find a starting basis quickly.

To accommodate statuses of logical variables, AMPL permits a
solver to return status values corresponding to the constraints as well
as the variables. The solver status of a constraint -- written as the
constraint name suffixed by `.sstatus` -- is interpreted as the
status of the logical variable associated with that constraint. For
example, in our diet model, where the constraints are all inequalities,

the logical variables are slacks that have the same variety of statuses as the structural variables:subject to diet {i in NUTR}: n_min[i] <= sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];

There are a total of 6 basic variables, equal in number to the 6 constraints (one for each member of setampl:ampl:model diet.mod;ampl:data diet2a.dat;ampl:option show_stats 1;8 variables, all linear 6 constraints, all linear; 47 nonzeros 1 linear objective; 8 nonzeros. MINOS 5.5: optimal solution found. 13 iterations, objective 118.0594032 ampl:solve;Buy.sstatus [*] := BEEF bas CHK low FISH low HAM upp MCH upp MTL upp SPG bas TUR low ; ampl:display Buy.sstatus;diet.sstatus [*] := A bas B1 bas B2 low C bas CAL bas NA upp ;display diet.sstatus;

the logical variables are artificials that receive the statussubject to Supply {i in ORIG}: sum {j in DEST} Trans[i,j] = supply[i]; subject to Demand {j in DEST}: sum {i in ORIG} Trans[i,j] = demand[j];

One artificial variable, on the constraintampl:ampl:model transp.mod;ampl:data transp.dat;MINOS 5.5: optimal solution found. 13 iterations, objective 196200 ampl:solve;: _conname _con.sstatus := 1 "Supply['GARY']" equ 2 "Supply['CLEV']" equ 3 "Supply['PITT']" equ 4 "Demand['FRA']" bas 5 "Demand['DET']" equ 6 "Demand['LAN']" equ 7 "Demand['WIN']" equ 8 "Demand['STL']" equ 9 "Demand['FRE']" equ 10 "Demand['LAF']" equ ;display _conname,_con.sstatus;

Here's an example of the most common cases, using one of our diet models:ampl:option astatus_table '\ 0 in normal state (in problem)\ 1 drop removed by drop command\ 2 pre eliminated by presolve\ 3 fix fixed by fix command\ 4 sub defined variable, substituted out\ 5 unused not used in current problem\ ';option astatus_table;

An AMPL status ofampl:ampl:model dietu.mod;ampl:data dietu.dat;ampl:drop diet_min['CAL'];ampl:fix Buy['SPG'] := 5;ampl:fix Buy['CHK'] := 3;MINOS 5.5: optimal solution found. 3 iterations, objective 54.76 ampl:solve;Buy.astatus [*] := BEEF in CHK fix FISH in HAM in MCH in MTL in SPG fix TUR in ; ampl:display Buy.astatus;diet_min.astatus [*] := A in B1 pre B2 pre C in CAL drop ;display diet_min.astatus;

- Variables
`Buy['CHK']`and`Buy['SPG']`have AMPL status`"fix"`because the`fix`command was used to specify their values in the solution. - Constraint
`diet_min['CAL']`has AMPL status`"drop"`because it was removed by use of the`drop`command. - Constraints
`diet_min['B1']`and`diet_min['B2']`have AMPL status`"pre"`because they were removed from the problem by simplifications performed in AMPL's presolve phase.

Not shown here are the AMPL statusampl:ampl:model dietobj.mod;ampl:data dietobj.dat;ampl:objective total_cost['JEWEL'];MINOS 5.5: optimal solution found. 8 iterations, objective 74.3532967 ampl:solve;total_cost.astatus [*] := 'A&P' drop JEWEL in VONS drop ;display total_cost.astatus;

For a variable or constraint, you will normally be interested in only
one of the statuses at a time: the solver status if the variable or
constraint was included in the problem sent most recently to the
solver, or the AMPL status otherwise. Thus AMPL provides the suffix
`.status` to denote the one status of interest:

In general,ampl:: Buy.status Buy.astatus Buy.sstatus := BEEF low in low CHK fix fix none FISH low in low HAM low in low MCH bas in bas MTL low in low SPG fix fix none TUR low in low ; ampl:display Buy.status, Buy.astatus, Buy.sstatus;: diet_min.status diet_min.astatus diet_min.sstatus := A bas in bas B1 pre pre none B2 pre pre none C low in low CAL drop drop none ;display diet_min.status, diet_min.astatus, diet_min.sstatus;

Write to

*Return to the AMPL update page.*

LAST MODIFIED 30 JUL 1998 BY 4er.