Line: 1 to 1 | ||||||||
---|---|---|---|---|---|---|---|---|

<-- Ready to Review - done - Lauren--> ## Sets in AMPL | ||||||||

Line: 20 to 20 | ||||||||

Return to top
## Declaring a Set | ||||||||

Changed: | ||||||||

< < | Sets are declared using the `set` keyword followed by a label, possibly some attributes and either a set literal or set expression. The most common attribute is set by the `within` keyword. This specifies that the set will only contain elements from the following set definition:
set ARCS within NODES cross NODES; # Elements of ARCS must have both elements in NODES
If you need a multi-dimensional set, but don't have the 1-dimensional sets to construct it yet you can use the set ROUTES dimen 2;There are some other set attributes, but we will not use them here. | |||||||

> > | Sets are declared using the `set` keyword followed by a label, possibly some attributes and either a set literal or set expression. The most common attribute is set by the `within` keyword. This specifies that the set will only contain elements from the following set definition: set ARCS within NODES cross NODES; # Elements of ARCS must have both elements in NODES
If you need a multi-dimensional set, but don't have the 1-dimensional sets to construct it yet you can use the set ROUTES dimen 2;There are some other set attributes, but we will not use them here. | |||||||

Set literals can be defined as a list of elements: | ||||||||

Changed: | ||||||||

< < | {'HOST', 'DEVICE', 'SWITCH', 'HUB', 'LINK', 'SUPERLINK'}or a sequence of numbers: param start; param end > start; param step; set NUMBERS := start .. end by step;If the `by step` is missing, the step is assumed to be 1:
set NUMBERS := 1..5; # NUMBERS = {1, 2, 3, 4, 5} Note Automatic set generation can only be done in the model environment, in the data environment you must define the set explicitly:
set NUMBERS := 1 2 3 4 5; # NUMBERS = {1, 2, 3, 4 5} | |||||||

> > | {'HOST', 'DEVICE', 'SWITCH', 'HUB', 'LINK', 'SUPERLINK'}or a sequence of numbers: param start; param end > start; param step; set NUMBERS := start .. end by step;If the `by step` is missing, the step is assumed to be 1: set NUMBERS := 1..5; # NUMBERS = {1, 2, 3, 4, 5} Note Automatic set generation can only be done in the model environment, in the data environment you must define the set explicitly: set NUMBERS := 1 2 3 4 5; # NUMBERS = {1, 2, 3, 4 5} | |||||||

Return to top | ||||||||

Line: 59 to 36 | ||||||||

- Use a logical expression (after the
`:` ) to indicate if an element (or pair of elements, or “tuple” of elements) should be included in the set.
| ||||||||

Changed: | ||||||||

< < | { <e> in <S>, [<f> in <T>, <g> in <U>, …] : <logical expression involving e [f, g, …]>} | |||||||

> > | { | |||||||

Set expressions may also involve one or more set operators: | ||||||||

Line: 80 to 54 | ||||||||

Sets are usually defined in a data file: | ||||||||

Changed: | ||||||||

< < | set NODES := Youngstown Pittsburgh Cincinnati 'Kansas City' Chicago Albany Houston Tempe Gary ; | |||||||

> > | set NODES := Youngstown Pittsburgh Cincinnati 'Kansas City' Chicago Albany Houston Tempe Gary ; | |||||||

although they may be defined during declaration using either an explicit set literal or using a set expression: | ||||||||

Changed: | ||||||||

< < | set KIND := {'HOST', 'DEVICE', 'SWITCH', 'HUB', 'LINK', 'SUPERLINK'}; set COMPONENT := {C in CLASSES : (kind[C] = 'HOST' ) or (kind[C] = 'DEVICE') or (kind[C] = 'HUB' ) or (kind[C] = 'SWITCH')}; set FABRIC := NODE union LINK; | |||||||

> > | set KIND := {'HOST', 'DEVICE', 'SWITCH', 'HUB', 'LINK', 'SUPERLINK'}; set COMPONENT := {C in CLASSES : (kind[C] = 'HOST' ) or (kind[C] = 'DEVICE') or (kind[C] = 'HUB' ) or (kind[C] = 'SWITCH')}; set FABRIC := NODE union LINK; | |||||||

and sets may also be defined dynamically: | ||||||||

Changed: | ||||||||

< < | set SEARCH within VERTICES; let SEARCH := {v in VERTICES: (v, w) in EDGES}; | |||||||

> > | set SEARCH within VERTICES; let SEARCH := {v in VERTICES: (v, w) in EDGES}; | |||||||

## Defining 2-Dimensional SetsThere are three different ways to define 2-dimensional sets. The "best" way to use depends on the set. | ||||||||

Changed: | ||||||||

< < | -
**Using a List**You simply list the elements in the set. This is good for sparse sets.model; set ARCS within NODES cros NODES; data; set ARCS := (Youngstown, Albany), (Youngstown, Cincinnati), ... ; -
**Using a Table**You give a table using the first index set for the rows and the second index set for the columns, then you place a`+` where an element exists and a`-` where there is no element. This is good for dense sets.set ARCS: Cincinnati 'Kansas City' Chicago Albany Houston Tempe Gary := Youngstown + + + + - - - Pittsburgh + + + - - - + Cincinnati - - - + + - - 'Kansas City' - - - - + + - Chicago - - - - - + + ; -
**Using an Array**You define a list of column indices for each row index. This is a good for sets with a few elements for each row.set ARCS := (Youngstown, *) Cincinnati ‘Kansas City’ Chicago Albany (Pittsburgh, *) Cincinnati ‘Kansas City’ Chicago Gary (Cincinnati, *) Albany Houston ...
| |||||||

> > | -
**Using a List**You simply list the elements in the set. This is good for sparse sets.model; set ARCS within NODES cross NODES; data; set ARCS := (Youngstown, Albany), (Youngstown, Cincinnati), ... ; -
**Using a Table**You give a table using the first index set for the rows and the second index set for the columns, then you place a`+` where an element exists and a`-` where there is no element. This is good for dense sets.set ARCS: Cincinnati 'Kansas City' Chicago Albany Houston Tempe Gary := Youngstown + + + + - - - Pittsburgh + + + - - - + Cincinnati - - - + + - - 'Kansas City' - - - - + + - Chicago - - - - - + + ; -
**Using an Array**You define a list of column indices for each row index. This is a good for sets with a few elements for each row.set ARCS := (Youngstown, *) Cincinnati ‘Kansas City’ Chicago Albany (Pittsburgh, *) Cincinnati ‘Kansas City’ Chicago Gary (Cincinnati, *) Albany Houston ...
| |||||||

Return to top | ||||||||

Line: 148 to 78 | ||||||||

You can create sets where the elements are ordered using the `ordered` keyword during definition. | ||||||||

Changed: | ||||||||

< < | set MONTHS ordered; | |||||||

> > | set MONTHS ordered; | |||||||

AMPL will put the elements in this set in the order they appear in the data file (or `let` statement). AMPL also understands the following operations for ordered sets: | ||||||||

Changed: | ||||||||

< < | ord(e, ORD_SET) # The position of e in ORD_SET first(ORD_SET) # The first element in ORD_SET last(ORD_SET) # The last element in ORD_SET prev(e, ORD_SET) # The element before e in ORD_SET next(e, ORD_SET) # The element after e in ORD_SET member(i, ORDSET) # The element at position i in ORD_SET | |||||||

> > | ord(e, ORD_SET) # The position of e in ORD_SET first(ORD_SET) # The first element in ORD_SET last(ORD_SET) # The last element in ORD_SET prev(e, ORD_SET) # The element before e in ORD_SET next(e, ORD_SET) # The element after e in ORD_SET member(i, ORDSET) # The element at position i in ORD_SET | |||||||

Return to top | ||||||||

Line: 169 to 90 | ||||||||

Consider the following AMPL statement from the The American Steel Planning Problem. We use `ord` in the creation of `TIME_ARCS` : | ||||||||

Changed: | ||||||||

< < | # The set of time-staged arcs set TIME_ARCS within TIME_NODES cross TIME_NODES := { (m, t) in TIME_NODES, (n, u) in TIME_NODES : ( ( (m, n) in ARCS) and (t = u) ) or # The transportation arcs ( (m = n) and (ord(t, MONTHS) + 1 = ord(u, MONTHS)) )}; # The storage arcs | |||||||

> > | # The set of time-staged arcs set TIME_ARCS within TIME_NODES cross TIME_NODES := { (m, t) in TIME_NODES, (n, u) in TIME_NODES : ( ( (m, n) in ARCS) and (t = u) ) or # The transportation arcs ( (m = n) and (ord(t, MONTHS) + 1 = ord(u, MONTHS)) )}; # The storage arcs | |||||||

There are many concepts within this one statement, let's look at them one at a time. | ||||||||

Line: 184 to 99 | ||||||||

There are many operations we can perform on sets (see Set Expressions). We have seen that `cross` creates all pairs of two sets, so `TIME_NODES cross TIME_NODES` creates a set of all pairs of `TIME_NODES` .
Some set operations may be looped over indexing sets. For example, to generate all the transportation arcs in the time-staged network you could use the following statement: | ||||||||

Changed: | ||||||||

< < | set TRANSPORT_ARCS := union {t in MONTHS} (union {(m, n) ARCS} {(m, t, n, t)});or you could loop over `MONTHS` and `ARCS` simultaneously:
set TRANSPORT_ARCS := union {t in MONTHS, (m, n) in ARCS} {(m, t, n, t)}; | |||||||

> > | set TRANSPORT_ARCS := union {t in MONTHS} (union {(m, n) ARCS} {(m, t, n, t)});or you could loop over `MONTHS` and `ARCS` simultaneously: set TRANSPORT_ARCS := union {t in MONTHS, (m, n) in ARCS} {(m, t, n, t)}; | |||||||

## Set Membership and Subsets
We have seen how to loop over a set using the | ||||||||

Changed: | ||||||||

< < | set ARCS within NODES cross NODES;means each arc is created between two nodes. | |||||||

> > | set ARCS within NODES cross NODES;means each arc is created between two nodes. | |||||||

## Ordered Set Operators
The final condition on | ||||||||

Changed: | ||||||||

< < | ( (m = n) and (ord(t, MONTHS) + 1 = ord(u, MONTHS)) )};creates the "storage" arcs. We could use next(t, MONTHS) = u or t = prev(u, MONTHS) except for a problem when `t` is `June` or `u` is `April` , respectively. When you use `prev` or `next` you must be careful of the first and last members of the set respectively. However, you can use `first` or `last` to check if you are using these elements. | |||||||

> > | ( (m = n) and (ord(t, MONTHS) + 1 = ord(u, MONTHS)) )};creates the "storage" arcs. We could use next(t, MONTHS) = u or t = prev(u, MONTHS) except for a problem when `t` is `June` or `u` is `April` , respectively. When you use `prev` or `next` you must be careful of the first and last members of the set respectively. However, you can use `first` or `last` to check if you are using these elements. | |||||||

Return to top
## Restricted SetsWhen using display or printf statements we saw that we could restrict the members of a set being printed, e.g., | ||||||||

Changed: | ||||||||

< < | display {(m, n) in ARCS : Supply[m] > 0}; # Display all arcs from supply nodes | |||||||

> > | display {(m, n) in ARCS : Supply[m] > 0}; # Display all arcs from supply nodes | |||||||

We can do this when creating sets, e. g., `TIME_NODES` , or when using a set as an index for variables, parameters or constraints. For example, rather than setting the upper bound of `UnderProduction` to be 0 for all non-supply nodes (since non-supply nodes don't produce anything) we could only create this variable for the supply nodes (in fact this may be preferable since there will be less variables). | ||||||||

Changed: | ||||||||

< < | var UnderProduction {(n, t) in TIME_NODES : Supply[n, t] > 0} >= 0, integer; | |||||||

> > | var UnderProduction {(n, t) in TIME_NODES : Supply[n, t] > 0} >= 0, integer; | |||||||

We could make sure this variable is only added to the constraints for the supply nodes (e.g., `ConserveFlow` constraints) by using a conditional expression. | ||||||||

Changed: | ||||||||

< < | subject to ConserveFlow {(n, t) in TIME_NODES}: sum {(m, s) in TIME_NODES: (m, s, n, t) in TIME_ARCS} Shipment[m, s, n, t] + Supply[n, t] - if Supply[n, t] > 0 then UnderProduction[n, t] = ... | |||||||

> > | subject to ConserveFlow {(n, t) in TIME_NODES}: sum {(m, s) in TIME_NODES: (m, s, n, t) in TIME_ARCS} Shipment[m, s, n, t] + Supply[n, t] - if Supply[n, t] > 0 then UnderProduction[n, t] = ... | |||||||

Return to top | ||||||||

Line: 238 to 132 | ||||||||

We have already seen different ways of declaring 2-dimensional sets. We have now encountered higher dimensional sets, e.g., `TIME_ARCS` has 4 dimensions. We generated `TIME_ARCS` automatically, but we could have specified it using a data file. | ||||||||

Changed: | ||||||||

< < | set TIME_ARCS within TIME_NODES cross TIME_NODES; | |||||||

> > | set TIME_ARCS within TIME_NODES cross TIME_NODES; | |||||||

List | ||||||||

Changed: | ||||||||

< < | set TIME_ARCS := (Youngstown, April, Albany, April) (Youngstown, April, Youngstown, May) ... ; | |||||||

> > | set TIME_ARCS := (Youngstown, April, Albany, April) (Youngstown, April, Youngstown, May) ... ; | |||||||

Table | ||||||||

Changed: | ||||||||

< < | set TIME_ARCS : = (*, May, *, May) Cincinnati 'Kansas City' Albany ... := Youngstown + + + ... Pittsburgh + + - ... ... ; | |||||||

> > | set TIME_ARCS : = (*, May, *, May) Cincinnati 'Kansas City' Albany ... := Youngstown + + + ... Pittsburgh + + - ... ... ; | |||||||

Array | ||||||||

Changed: | ||||||||

< < | set TIME_ARCS := (*, May, *, May) (Youngstown, Cincinnati) ... ... ; | |||||||

> > | set TIME_ARCS := (*, May, *, May) (Youngstown, Cincinnati) ... ... ; | |||||||

or | ||||||||

Changed: | ||||||||

< < | set TIME_ARCS := (Youngstown, May, *, May) Cincinnati 'Kansas City' ... ... ; | |||||||

> > | set TIME_ARCS := (Youngstown, May, *, May) Cincinnati 'Kansas City' ... ... ; | |||||||

Return to top
## Efficient Generation of Sets
When creating models, generating sets by looping over all possibilities and removing those that don't fit some conditions (e.g., like the | ||||||||

Changed: | ||||||||

< < | # The set of time-staged arcs set TIME_ARCS within TIME_NODES cross TIME_NODES := { (m, t) in TIME_NODES, (n, u) in TIME_NODES : ( ( (m, n) in ARCS) and (t = u) ) or # The transportation arcs ( (m = n) and (ord(t, MONTHS) + 1 = ord(u, MONTHS)) )}; # The storage arcs | |||||||

> > | ||||||||

to create `TIME_ARCS` you could use these statements | ||||||||

Changed: | ||||||||

< < | set TRANSPORT_ARCS := union {t in MONTHS, (m, n) in ARCS} {(m, t, n, t)}; set STORAGE_ARCS := union {t in MONTHS, (m, n) in ARCS : t <> last(MONTHS)} {(m, t, n, next(t, MONTHS)}; set TIME_ARCS within TIME_NODES cross TIME_NODES := TRANSPORT_ARCS union STORAGE_ARCS; | |||||||

> > | set TRANSPORT_ARCS := union {t in MONTHS, (m, n) in ARCS} {(m, t, n, t)}; set STORAGE_ARCS := union {t in MONTHS, (m, n) in ARCS : t <> last(MONTHS)} {(m, t, n, next(t, MONTHS)}; set TIME_ARCS within TIME_NODES cross TIME_NODES := TRANSPORT_ARCS union STORAGE_ARCS; | |||||||

Rather than looping over all possibilities and only keeping those that are appropriate, the new statement only loops over smaller sets that can be used to build up the `TIME_NODES` set efficiently. |

View topic | History: r15 < r14 < r13 < r12 | More topic actions...

Copyright © 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.

Ideas, requests, problems regarding TWiki? Send feedback

Ideas, requests, problems regarding TWiki? Send feedback