Search code examples
setconstraintsampl

AMPL: define constraints in specific elements of a set


I have this structure:

set U;
param d {i in U};

How can I add constraints in the first, second and third element of d?

I'm abstracting the size of U because I guess it's better, but in fact, for my problem, U has only 3 elements and so do d.

I wouldn't like to create 3 params for U and 3 vars for d.


Solution

  • As you've implemented this, U is an unordered set. This means that the "first element of U" isn't clearly defined. Since U is the index set for d, it follows that "the first element of d" also isn't clearly defined.

    For example, consider the following code:

    set U := {"fish","chips","salt"};
    var d{U} := 0;
    solve;
    display d;
    

    The answer is displayed as:

    d [*] :=
    chips  0
     fish  0
     salt  0
    ;
    

    Note that AMPL has sorted the elements of U in a different order to the order in which I declared them. (Specifically, it's alphabetised them.)

    So the answer to this question depends on what exactly you mean by "add constraints in the first, second and third element of d".

    If you just want to apply the same constraint to every member of d, you can use a single constraint indexed over U:

    set U := {"fish","chips","salt"};
    var d{U};
    
    s.t. constrain_all{u in U}: d[u] >= 0;
    

    If you want to apply a specific constraint to each member of d by name, you can use a similar format:

    set U := {"fish","chips","salt"};
    var d{U};
    
    s.t. constrain_fish: d["fish"] >= 0;
    s.t. constrain_chips: d["chips"] >= 5;
    s.t. constrain_salt: d["salt"] >= 10;
    

    If you do have a specific ordering on U, then you need to declare U as an ordered set. Each element of U then has a specific cardinality within that set and you can use the "member" and "ord" functions to reference elements of U by position. For example:

    set U := {"fish","chips","salt"} ordered;
    var d{U};
    
    s.t. constrain_fish: d["fish"] >= 0;
    s.t. constrain_chips: d["chips"] >= 5;
    s.t. constrain_salt: d["salt"] >= 10;
    
    s.t. constrain_second_member_of_U: d[member(2,U)] >= 25;
    
    minimize of: sum{u in U} d[u];
    solve;
    display d;
    

    As written, this requires d["chips"] to be greater than or equal to 25. However, if I changed the declaration of U from {"fish","chips","salt"} to {"chips","fish","salt"}, that constraint would now apply to d["fish"] instead of d["chips"].

    If I wanted to set a constraint on (say) the 5th-10th members of d, I could write something like:

    s.t. constrain_5th_to_10th{u in U: ord(u,U) >= 5, ord(u,U) <= 10}: d[u] >= 100;
    

    See chapter 5 of the AMPL Book for more info on ordered sets.