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 new 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 kth 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.
|