Você está na página 1de 11

Linear Programming in OPL Studio

A tutorial
c
Dr. C. Richard Wu and Mr. Tomasz Drabas 2010

Introduction
1. Brief description of the tutorials that will be held
2. Brief description of ILOG OPL Studio program
(a) Open the application
(b) Basic overview of panels, what are they used for
(c) Description of 2 files used to build models in OPL (.dat, .mod)
in .mod file first we declare data, then variables and decision
variables, and, at the end, the objective function and conditions
in .dat file the order of data declared MUST be the same, as in
.mod file
(d) How to build a model in ILOG OPL Studio (where and what to add
to make the whole model working)

Introduction to Linear Programming (LP)


An example: The Shortest Path problem

This example can be found in Massoud:2004, pages 10-13

2.1

Problem description

The problem seeks for the shortest path, from origin to destination. It consists
of inter-connected nodes (with costs assigned to each arc) refer to the Figure 1
on page 2. In this example nodes are equivalents of cities, and cost is the time
in minutes between each node.

2.2

Problem formulation

We are to minimize the time to get from origin (node #1) to destination (node
#10) through the connection of flights (refer to Figure 1 ). Hence, our aim is to:
M inimize

70x1,2 + 63x1,3 + 56x1,4 + . . .

In the above equation, when we decide to choose the flight from city e.g.
#1 to #2, we assign 1 to our decision variable; if we do not choose this path
1

2
70

25

67

50
69

63

56

19

67

72

31

87

10

97

52

51

45

72

17

69

18
61

29

79

73

54

15

85

69

Figure 1: Network with flight times between city pairs, source: Massoud:2004,
page 11
we would assign 0 to that. So, we can write that down as follows, i.e. binary
decision variables:

1 if arc (i, j) is chosen
xi,j =
(1)
0 otherwise
In our problem we have 3 sets of constraints:
1. source node: the flight originates from node #1, and we can use only 1 arc
from that node. Thus, we have:
x1,2 + x1,3 + x1,4 = 1
2. transshipment nodes: all other nodes (except origin and destination) are
transshipment nodes, so everything that comes in must go out. In other
words, the net flow through the node must equal 0. See the example for
node #2 (refer to the Figure 1):
x1,2 + x3,2 + x4,2 x2,3 x2,4 x2,5 x2,6 x2,7 = 0
3. destination node: the flight must end in the destination node; in our case it
is node #10. Thus, we have:
x5,10 + x6,10 + x7,10 + x9,10 = 1

In summary, we can rewrite the above problem as follows (a.k.a. the formulation of the problem):
Objective function
min

X X

ci,j xi,j

(2)

for j 6= 1

(3)

iM jM

Subject to
X

x1,j = 1

jM

xj,i

jM

xi,k = 0 for all () i 6= 1 or m

(4)

kM

xi,m = 1

for m

(5)

iM

where:
sets:
M

set of nodes

indices:
i,j,k

indices of nodes

parameters:
ci,j
m

=
=

cost of flow along the arc joining node i to node j


destination node (number of all nodes)

decision variable:
xi,j

our decision variable see equation (1)

2.3

Solving the problem with ILOG OPL Studio

2.3.1

Declaring data and data types

First, we must declare data and their types. We have m nodes (in our case
m = 10). So, in file shrtstPath.mod we will put:
int m=...;
range M=1..m;

The ...; after int m=, in OPL syntax, tells the program to look for the
data in the .dat file (in our situation, in the shrtstPath.dat). Alternatively, we
could write int m=10; and the program would not need to search for this
data in the data file. The range command produces an array, starting from
1 up to m. After that we declare the flow matrix (we do not have it in the
problem formulation), by having:
int flow[M][M]=...;

The above command tells the program, to look for the 10-by-10 (m-by-m)
matrix in the .dat file. Why do we need it? Because without it our model
would not know whether there is a unidirectional connection between node
3

e.g. 1 and 2, bidirectional connection between nodes e.g. 2 and 4, or there is no


connection between nodes e.g. 3 and 7. In the matrix (refer to the shrtstPath.dat
file) rows indicate origin node (so, e.g. row #1 indicate connections originating
from node #1), columns indicate destination node (connection to the nodes).
For example, lets take the first row: [0 1 1 1 0 0 0 0 0 0] this row
indicates, that we have connections from node #1 to nodes: #2, #3, and #4. If
we treated columns as a starting node we would see that there is no connection
to the node #1 (which is true, as we see in Figure 1).
However, we have bidirectional connections between nodes e.g. #2 and #4;
in the matrix we have then 1s in the points with coordinates (2, 4) and (4, 2). If
there is no connection between nodes we have 0. You must prepare this matrix
very carefully; otherwise, your results would not be correct (because inputs are
not right).
By declaring:
int c[M][M]=...;

We make our model to create another 10-by-10 matrix with costs (representing flight time) between two nodes. Having all the data declared, we need to
assert our decision variablerecall equation (1). In OPL we simply put:
dvar boolean x[M][M];

The word boolean describes a binary variable, so having only two values: 0
and 1exactly what we are looking for.
In ILOG OPL Studio, one can declare other data types: Integers to evoke
variables that can be only of integer values (like in our declaration of m; notice,
that our f low and c matrices have data of type int as well), Stringsused to
declare text variables (which we will learn how to declare during Tutorial 2),
and Floats, that are used to declare variables with real numbers.
2.3.2

Building model

Now, we can transform our model into OPL language. Recall equation (2). In
OPL we will have:
minimize
sum( i in M, j in M )
( x[i][j] * c[i][j] );

P
Notice, that we do not need to use double signs because we have already
summed up across i and j. Now go back to equations (3), (4) and (5), and
compare them with the following code:
subject to{
cfFirstNode:
sum( j in M) x[1][j] * flow[1][j] == 1;
forall (i in 2..(m-1))
cfNetworkFlow:
sum( j in M ) x[i][j] * flow[i][j]
- sum ( k in M ) x[k][i] * flow[k][i] == 0;

cfLastNode:
sum( i in M) x[i][m] * flow[i][10] == 1;
}

Isnt it straightforward? As you can see we use information from the f low
matrix to introduce information about the connections between particular nodes
into the model. The last thing we need to do here is to display the results. In
OPL we make that as follows:
execute DISPLAY_RESULTS
{
writeln("The model has chosen following routes:");
for (var i in M)
{
for (var j in M)
{
if (x[i][j] == 1)
{
writeln("Route x",i,j," has been chosen! ");
}
}
}
}

We use double loops for (...) because our decision variable xi,j has two
dimensions. Then, we filter out (using if(...) command) only those routes
that were chosen as a shortest paththe program writes the results (using
writeln(...);) on the screen. Notice, that in the writeln(...); the text
information that does not change ("Route x" and " has been chosen!")
we put in the quotation marks, while variables that change (i,j) are outside
the quotation marks, precedented and followed by commas.
2.3.3

Preparing Data Files

Now, lets take a brief look at our shrtstPath.dat file. As mentioned before, the
order of data declaration we did earlier in the .mod file MUST be conserved
in .dat file. Therefore, first we need to declare, how many nodes we have in
our model (m = 10;), followed by the connection matrix (flow), and matrix
of connection costs (c). Therefore, we have:
m = 10;
flow
[0 1
[0 0
[0 1
[0 1
[0 0
[0 0
[0 0
[0 0
[0 0
[0 0

=
1
1
0
1
0
0
0
0
0
0

[
1
1
1
0
0
0
0
0
0
0

0
1
1
1
0
1
0
0
0
0

0
1
1
1
1
0
0
0
0
0

0
1
0
0
1
1
0
1
1
0

0
0
0
0
1
1
1
0
1
0

0
0
0
1
1
1
1
1
0
0

0]
0]
0]
0]
1]
1]
1]
0]
1]
0]];

c = [
[0 70
[0 0
[0 25
[0 19
[0 0
[0 0
[0 0
[0 0
[0 0
[0 0

63
25
0
29
0
0
0
0
0
0

56
19
29
0
0
0
0
0
0
0

0
73
69
67
0
18
0
0
0
0

0
50
61
45
18
0
0
0
0
0

0
79
0
0
67
72
0
17
31
0

0
0
0
0
69
52
17
0
15
0

0
0
0
85
54
51
31
15
0
0

0]
0]
0]
0]
87]
97]
72]
0]
69]
0]];

As you can observe we need to finish declaration of each data-set with ;.


Note as well how we declare 2-dimensional matrices in OPL; it is simply an
array or arrays. It means that data originating out of node #1 must be put as
a row-array, thus we have [0 1 1 1 0 0 0 0 0 0]. To add the other dimensions, we simply put the sets of our arrays for each other node in between
brackets [];.
2.3.4

Results

When you hit the run button, you will get the results. How to read them?
Again, straightforward (just like we wanted) we should first fly to node #4
(starting from #1). After that we fly to node #6, and then go directly to node #10
from there. Too simple and you dont believe it?try some other ways, add
the time and see, if you can travel from node 1 to 10 in less than 198 minutes,
as our model indicated.

Multi-commodity problem

This example can be found in Massoud:2004 pages 18-21

3.1

Problem description

In this problem we have two types of commodities which we want to transfer


through a network of connections. We have to minimize the total cost of transporting these goods and satisfy the requirements of nodes #5, #6, and #7 for
each commodity (refer to Figure 2). We are also told that any shipment to and
from node #4 cannot exceed 50 units in total (sum of both commodities).

3.2

Problem formulation

As given in the problem description, we are to minimize the total cost of transporting those two commodities through our network. Therefore, we can write
the following formulation of the problem (refer to Figure 2):

40
35

50
25

30
20

30
30

30
10

3
7

8
4

Figure 2: Network for multi-commodity problem, source: Massoud:2004, page


19

M inimize

5x1,3,1 + 5x1,3,2 + 8x1,4,1 + 81,4,2 + . . .

We have two constraints in this problem: we must transfer the commodities


through the network from supply nodes (#1 and #2) to demand nodes (#5, #6,
and #7), and we have a capacity constraint over the node #4. Then, how do we
approach this?
We can address the first constraint as follows (example for node #3; again,
refer to the Figure 2):
commodity 1 : x1,3,1 + x2,3,1 x3,5,1 x3,6,1 x3,7,1 = 0
commodity 2 : x1,3,2 + x2,3,2 x3,5,2 x3,6,2 x3,7,2 = 0
It is a similar constraint as for those transshipment nodes in the previous example. It assures that everything that comes in must go out, so the balance is 0
(nothing is left within the node). Note that the problem is formulated in such a
way, that the sum of each commodity at the input nodes (#1 and #2) equals the
sum of each commodity at the output nodes (#5, #6, and #7).
Try to figure out how would above equations look for input nodes? How
about output ones?
As given in the problem description, we have a capacity constraint at node
#4we cannot ship to and from, through any connection, more than 50 units of
commodities. One can translate that in such a way that any flight arriving to or
departing from this airport cannot ship more than 50 tonnes due to technical
constraints of the airport e.g. length of a runway or unavailability of a specific
equipment to handle more than 50 tones. So, we have:
x1,4,1 + x1,4,2
x2,4,1 + x2,4,2
x4,5,1 + x4,5,2
x4,6,1 + x4,6,2
x4,7,1 + x4,7,2

50
50
50
50
50

Therefore, our problem can be written as follows:


Objective function
7

min

X X X

ci,j xi,j,k

(6)

iM jM kK

s.t.

xt,i,k

tM

xi,t,k = Bi,k ,

i M, k K

(7)

tM

xi,j,k Ui,j ,

i M, j M

(8)

kK

where:
sets:
M =
K =
indices:
=
i,j,t
=
k

set of nodes
set of commodities
indices of nodes
index of commodity

parameters:
ci,j
Bi,k
Ui,j

=
=
=

cost of flow along the arc joining node i to node j


demand for commodity k at node i
capacity constraint of the arc i, j

decision variable:
xi,j,k = decision variable tells us how much commodity k
should be sent through arc i, j

3.3

Solving the problem with ILOG OPL Studio

3.3.1

Declaring data

In this example we declare 5 input data:


int m=...;
range M=1..m;
int k=...;
range K=1..k;
int U[M][M]=...;
int B[M][K]=...;
int c[M][M]=...;

All the inputs are straightforward just compare them with descriptions of
variables from above. How about our objective function?
dvar int+ x[M][M][K];

What does int+ mean? It means that this decision variable can have only
positive integer values. If we had had int the set of possible values would
have ranged from to . Any ideas why we constrain our decision variable
for positive values only?

3.3.2

Building model

Declaration of the model is, again, easy to transpose:


minimize
sum( k in K, i,j in M )
( x[i][j][k] * c[i][j] );
subject to
{
forall (i in M, k in K)
cfDemandSupply:
sum( t in M) ( x[t][i][k] ) sum( t in M ) ( x[i][t][k] )
== B[i][k];
forall (i in M, j in M)
cfCapacity:
sum( k in K ) x[i][j][k] <= U[i][j];
}

As in the previous example, we have to display the results, i.e. how many
units of each commodity send through each arc. We use 3 loops for (for each
subindex i, j and k) to display only those arcs, that actually take their part in
the shipment:
execute DISPLAY_RESULTS
{
writeln("The model has chosen following routes:");
for (var i in M)
{
for (var j in M)
{
for (var k in K)
{
if (x[i][j][k] == 0)
{
}
else
{
writeln("Route x",i,j," has been chosen
to send ",x[i][j][k]," commodities
of ",k," type!");
}
}
}
}
}

3.3.3

Data file

The .dat file for this model looks as follows:


m = 7;
k = 2;

U = [
[0 0 500
[0 0 500
[0 0 0 0
[0 0 0 0
[0 0 0 0
[0 0 0 0
[0 0 0 0
];

50 0 0 0]
50 0 0 0]
500 500 500]
50 50 50]
0 0 0]
0 0 0]
0 0 0]

B = [
[-40 -35]
[-50 -25]
[0 0]
[0 0]
[30 20]
[30 30]
[30 10]
];
c = [
[0
[0
[0
[0
[0
[0
[0
];

0
0
0
0
0
0
0

5
7
0
0
0
0
0

8
4
0
0
0
0
0

0
0
1
3
0
0
0

0
0
5
4
0
0
0

0]
0]
8]
4]
0]
0]
0]

When you take a look at U you can see that for arc 1, 3 there are 500 units
allowed to be transported. As a matter of fact, it can be any other large number
e.g. 1,000. Note, however, that, as per our capacity constraint for node #4,
every arc connecting to and from node #4 is constrained at 50 (as we were told).
The second matrix that needs a small explanation is B (standing for demand). The negative values indicate that e.g. node #1 provides 40 units of
commodity 1 and 35 units of commodity 2. You can see that nodes #3 and
#4 have 0s; it comes from our assumption, that everything that comes into the
transshipment nodes must go out, so the balance needs to be 0. The last 3 nodes
receive goods, so their balances need to be positive.
3.3.4

Results

The model attained minimum cost at 1250. The flow of commodities through
the network is presented in the Figure 3
This manual was prepared in LATEX

10

40
35

40
35

30
20
5

30
20

50
25

0
10

30
20

30
20

30
30

30
10

3
7

20
5

8
30
10

Figure 3: Solution to the multi-commodity problem, source: own study

11

Você também pode gostar