AMPL > >Faqs

In general, AMPL interprets `a..b`

as `{a, a+1, a+2, ..., b-1, b}`

. Thus when `T`

is greater than one, `T..1`

is an empty set. To specify the ordered set that goes from `T`

down to `1`

, write `T..1 by -1`

.

You have declared `set S`

in your model and `set S := 50 .. 70`

in your data. Set expressions are not recognized in AMPL’s data mode, however. Instead AMPL tries to recognize `50 .. 70`

as a space-delimited list of members of `S`

, with the result that it has found three members: the numbers `50`

and `70`

, and the string `".."`

.

To define `S`

to equal `50 .. 70`

by use of your data file, first declare `S`

in your model by

param begin; param end > begin; set S := begin .. end;

Then state in the data file:

param begin := 50; param end := 70;

Alternatively, it’s legal to give `set S = 50 .. 70`

as your declaration of `S`

. This is a less desirable approach, however, because it moves some of the specific data values into the model.

There’s no specific arg min operator in AMPL. However, proceeding directly from the definition, you can define the arg min explicitly by a set expression like

{s in S: b[s] = min {i in S} b[i]}

This expression gives a subset of `S`

, however, containing all of the members of `S`

that achieve the minimum. To get just one member representing the arg min, you can define this to be an ordered set,

set b_argmin ordered := {s in S: b[s] = min {i in S} b[i]};

Then `first(b_argmin)`

is guaranteed to be one member of `S`

that minimizes `b[i]`

.

As an alternative, you can use AMPL’s `for`

and `if`

commands to write a script that loops over `S`

to compute the arg min explicitly:

param bmin; param imin symbolic in S; let bmin := Infinity; for {i in S} { if b[i] < bmin then { let bmin := b[i]; let imin := i; } }

In general this is a slower alternative than defining `b_argmin`

as above. It admits a greater variety of generalizations in complex cases, however.

AMPL can index model components by objects (numbers and character strings) but not by sets of objects. Hence you can’t model a power set directly. You may be able to get the same effect, however, by constructing a numbered list of subsets.

As an example, suppose that you want to index over all subsets of the set of the first `n`

nonnegative integers. You can declare:

param n integer > 0; set S := 0 .. n - 1; set SS := 0 .. 2**n - 1; set POW {k in SS} := {i in S: (k div 2**i) mod 2 = 1};

Since there are `n`

members of `S`

, there are `2**n`

subsets of `S`

. Hence there exists a one-to-one correspondence between the members of the set `SS := 0 .. 2**n - 1`

and the subsets of `S`

. By use of a simple encoding, you can make this correspondence explicit; the indexed collection of sets `POW`

above is declared such that `POW[k]`

is the `k`

th distinct subset of `S`

. (To see the whole power set, type `display POW`

.)

Much the same can be done for an arbitrary ordered set S:

set S ordered; param n := card {S}; set SS := 0 .. (2**n - 1); set POW {k in SS} := {i in S: (k div 2**(ord(i)-1)) mod 2 = 1};

Either way, you can use indexing over `POW`

to get the effect of indexing over the power set. In the following example, each member `s`

of `S`

has a weight `Wt[s]`

, and the average “weight” of all members of any subset of `S`

is constrained not to exceed `n/2`

:

var Wt {S} >= 0; subj to MaxWt {k in SS}: sum {i in POW[k]} Wt[i] <= (n / 2) * card(POW[k]);

A more involved example, which represents a traveling salesman problem as an integer program, is provided in tsp.mod. Constraints like this can be useful for studying and testing certain formulations of combinatorial problems, provided that the underlying set (`S`

in our example) is kept to a reasonably small size.

AMPL does not define any ordering on pairs, triples, or objects of higher dimension. Thus `next`

, `prev`

, and other functions that apply to objects in ordered sets cannot be applied to pairs, triples, or tuples of higher dimension. For the same reason, `first`

, `last`

and other functions of ordered sets may not be applied to multi-dimensional sets.

You may apply these functions to individual indices of a multi-dimensional parameter or variable, however. The following examples are from steelT2.mod (Figure 5-3) of the AMPL book:

subject to balance0 {j in PROD}: Make[j,first(WEEKS)] + inv0[j] = Sell[j,first(WEEKS)] + Inv[j,first(WEEKS)]; subject to balance {j in PROD, t in WEEKS: ord(t) > 1}: Make[j,t] + Inv[j,prev(t)] = Sell[j,t] + Inv[j,t];

Most models that involve both ordered and multidimensional sets can be handled by some variation of this approach.

Either a data table gave values for the parameter with incorrect subscripts, or the parameter’s indexing set changed, causing some previously valid subscripts to become invalid. For example, in the diet.mod + diet.dat example (Figures 2-1 and 2-2) of the AMPL book, values of parameter cost are supplied for all eight members of set `FOOD`

:

ampl: display cost; cost [*] := BEEF 3.19 FISH 2.29 MCH 1.89 SPG 1.99 CHK 2.59 HAM 2.89 MTL 1.99 TUR 2.49 ;

If you remove the member `CHK`

from `FOOD`

, using for example a `let`

command, then you get a message that `cost["CHK"]`

has also been dropped from the data:

ampl: let FOOD := FOOD diff {"CHK"}; ampl: display cost; Error executing "display" command: error processing param cost: invalid subscript cost['CHK'] discarded. cost [*] := BEEF 3.19 HAM 2.89 MTL 1.99 TUR 2.49 FISH 2.29 MCH 1.89 SPG 1.99

Since `cost["CHK"]`

has now been dropped, no further error message will appear if you type `display cost`

again.

To avoid error messages of this sort, you can define a more flexible set structure for your model as shown in dietflex.mod and dietflex.dat. The auxiliary set `DIET_DROP`

defaults to empty, so that the problem is solved for all foods; but you can change `DIET_DROP`

to `{"CHK"}`

to solve without member `CHK`

:

ampl: model dietflex.mod; ampl: data dietflex.dat; ampl: option show_stats 1; ampl: solve; 8 variables, all linear 6 constraints, all linear; 47 nonzeros 1 linear objective; 8 nonzeros. MINOS 5.4: optimal solution found. 13 iterations, objective 118.0594032 ampl: let FOOD_DROP := {"CHK"}; ampl: solve; 7 variables, all linear 6 constraints, all linear; 42 nonzeros 1 linear objective; 7 nonzeros. MINOS 5.4: optimal solution found. 3 iterations, objective 117.3218891

Changing `FOOD_DROP`

does not affect the set `FOOD_ALL`

, and consequently all of the subscripts in the data remain valid.