Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 24

NOTES ON OPL SCRIPT

A block of statements for preprocessing or postprocessing


is marked by the keyword execute:
execute {
writeln("Hello World.");
}

Execute blocks can be named:


execute HELLO {
writeln("Hello World.");
}

Warning
No two execute blocks can have the same name within
the same model.
Any execute block placed before the objective or
constraints declaration is part of preprocessing; other
blocks are part of postprocessing.
The scripting context within an execute block
corresponds to the model declarations. You can think of the
statements within an execute block being embedded in
an ILOG Script block named with.
with (thisOPLModel) {
writeln("Hello World.");
}
where thisOPLModel is the instance of IloOplModel
representing the current OPL model.
Language User's Manual > The Application Areas > Linear
and Integer Programming > Linear Programming > A
Production Problem
PREVIOUS NEXT
A Production Problem

Consider again the production planning problem first


presented in the section Tuples. The model is depicted
again in Code Sample 5.1 below and the instance data in
Code Sample 5.2.
{string} Products = ...;
{string} Resources = ...;
float Consumption[Products][Resources] =
...;
float Capacity[Resources] = ...;
float Demand[Products] = ...;
float InsideCost[Products] = ...;
float OutsideCost[Products] = ...;
dvar float+ Inside[Products];
dvar float+ Outside[Products];
minimize
sum( p in Products )
( InsideCost[p] * Inside[p] +
OutsideCost[p] * Outside[p] );
subject to {
forall( r in Resources )
ctCapacity:
sum( p in Products )
Consumption[p][r] * Inside[p] <=
Capacity[r];
forall(p in Products)
ctDemand:
Inside[p] + Outside[p] >=
Demand[p];
}
Code Sample 5.1 A Production-Planning Problem
(production.mod)
Products = { "kluski", "capellini",
"fettucine" };
Resources = { "flour", "eggs" };
Consumption = [ [0.5, 0.2], [0.4, 0.4],
[0.3, 0.6] ];
Capacity = [ 20, 40 ];
Demand = [ 100, 200, 300 ];
InsideCost = [ 0.6, 0.8, 0.3 ];
OutsideCost = [ 0.8, 0.9, 0.4 ];
Code Sample 5.2 Instance Data for the Production-Planning
Problem (production.dat)

The model aims at minimizing the production cost for a


number of products while satisfying customer demand.
Each product can be produced either inside the company or
outside, at a higher cost. The inside production is
constrained by the company's resources, while outside
production is considered unlimited. The model first
declares the products and the resources. The data consists
of the description of the products, i.e., the demand, the
inside and outside costs, and the resource consumption, and
the capacity of the various resources. The variables for this
problem are the inside and outside production for each
product.
A Solution to production.mod
For these statements, OPL returns the optimal solution
Final Solution with objective 372.0000:
inside = [40.0000 0.0000 0.0000];
outside = [60.0000 200.0000 300.0000];

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > The
Application Areas > Linear and
Integer Programming > Linear
Programming > A Multi-Period
Production Planning Problem

PREVIOUS
A Multi-Period Production Planning NEXT
Problem
Large linear-programming problems are often obtained
from simpler ones by generalizing them along one or more
dimensions. A typical extension of production-planning
problems is to consider several production periods and to
include inventories in the model. This section presents a
multiperiod production planning model that generalizes the
model of the previous section A Production Problem.
The main generalization is to consider the demand for the
products over several periods and to allow the company to
produce more than the demand in a given period. Of
course, there is an inventory cost associated with storing
the additional production. Code Sample 5.3 depicts the new
model and Code Sample 5.4 describes the instance data.
{string} Products = ...;
{string} Resources = ...;
int NbPeriods = ...;
range Periods = 1..NbPeriods;
float Consumption[Resources][Products] =
...;
float Capacity[Resources] = ...;
float Demand[Products][Periods] = ...;
float InsideCost[Products] = ...;
float OutsideCost[Products] = ...;
float Inventory[Products] = ...;
float InvCost[Products] = ...;
dvar float+ Inside[Products][Periods];
dvar float+ Outside[Products][Periods];
dvar float+ Inv[Products][0..NbPeriods];

minimize
sum( p in Products, t in Periods )
(InsideCost[p]*Inside[p][t] +
OutsideCost[p]*Outside[p][t] +
InvCost[p]*Inv[p][t]);
subject to {
forall( r in Resources, t in Periods )
ctCapacity:
sum( p in Products )
Consumption[r][p] * Inside[p][t]
<= Capacity[r];
forall( p in Products , t in Periods )
ctDemand:
Inv[p][t-1] + Inside[p][t] +
Outside[p][t] == Demand[p][t] + Inv[p]
[t];
forall( p in Products )
ctInventory:
Inv[p][0] == Inventory[p];
};
tuple plan {
float inside;
float outside;
float inv;
}
plan Plan[p in Products][t in Periods] =
<Inside[p,t],Outside[p,t],Inv[p,t]>;
execute DISPLAY {
writeln("plan=",Plan);
}
Code Sample 5.3 A Multi-Period Production-Planning
Problem (mulprod.mod)
Products = { kluski capellini fettucine
};
Resources = { flour eggs };
NbPeriods = 3;
Consumption = [
[ 0.5, 0.4, 0.3 ],
[ 0.2, 0.4, 0.6 ]
];
Capacity = [ 20, 40 ];
Demand = [
[ 10 100 50 ]
[ 20 200 100]
[ 50 100 100]
];
Inventory = [ 0 0 0];
InvCost = [ 0.1 0.2 0.1];
InsideCost = [ 0.4, 0.6, 0.1 ];
OutsideCost = [ 0.8, 0.9, 0.4 ];
Code Sample 5.4 Instance Data for Multi-Period
Production-Planning Problem (mulprod.dat)
Most of the model generalizes smoothly. For instance, the capacity constraints stated for
all resources and all periods become

forall( r in Resources, t in Periods )


ctCapacity:
sum( p in Products )
Consumption[r][p] * Inside[p][t]
<= Capacity[r];

The most novel part of the statement is the constraint


linking the demand, the inventory, and the production:
forall( p in Products , t in Periods )
ctDemand:
Inv[p][t-1] + Inside[p][t] +
Outside[p][t] == Demand[p][t] + Inv[p]
[t];

The constraint states that, for each product p and each


period t, the inventory of period t-1 added to the
production of period t is equated to the demand of period t
plus the inventory of period t. Of course, the fact that the
variables inv[p][t] are constrained to be nonnegative is
critical to satisfying the demand and to disallow back
orders. The objective function is also generalized to add the
inventory costs.
Note also the type declaration

tuple plan {
float inside;
float outside;
float inv;
}

and the display instructions


plan Plan[p in Products][t in Periods] =
<Inside[p,t],Outside[p,t],Inv[p,t]>;
execute DISPLAY {
writeln("plan=",Plan);
}

which were added to produce a visually pleasing display.


A Solution to mulprod.mod
For example, on the instance data depicted in Figure 5.1,
OPL produces the optimal solution
Optimal solution found with objective:
457
plan=
[[<10.0000 0.0000 0.0000> <0.0000
100.0000 0.0000> <0.0000 50.0000
0.0000>]
[<0.0000 20.0000 0.0000> <0.0000
200.0000 0.0000> <0.0000 100.0000
0.0000>]
[<50.0000 0.0000 0.0000> <66.6667
33.3333 0.0000> <66.6667 33.3333
0.0000>]]

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG
Script for OPL > Tutorial: Flow
Control and Multiple Searches >
What You Are Going to Do
PREVIOUS NEXT
What You Are Going to Do

More precisely, let us assume that you want to solve the


original model, then increase the capacity for the flour
ingredient, then solve again. You want to do this as many
times as possible. Doing so, you will obtain the optimal
value for this problem for each possible value of flour
capacity. When the flour capacity is too high and no
solution is found, you will stop the experience.
You will start with the following steps:
1. Defining a "main" Block to indicate that you want do
flow control scripting to manipulate different models
and/or searches.
2. Loading the Necessary Structures: the model
definition, the initial model data, and the
IloOplModel instance that creates the link between
them.
3. Generating the Optimization Model from the initial
data.
You will then proceed with, iteratively,
4. Solving the Current Optimization Model with the
current data:
o if there is no solution, then quit

o if there is a solution, print the objective value


5. Getting the Data Elements from an IloOplModel
Instance
6. Modifying Some of the Data Elements: modify the
data element for the flour capacity
7. Creating a New OPL Model with the Modified Data:
use the model definition and modified data elements
and create a new IloOplModel instance to link
them
8. Complete Model: generate the new current
optimization model

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG
Script for OPL > Tutorial: Flow
Control and Multiple Searches > What
You Are Going to Do > Defining a
"main" Block
PREVIOUS NEXT
Defining a "main" Block

Flow control means solving several models in sequence


and, possibly, modifying data or passing results from one
model to the data of another model. To operate flow
control, you need to add a main block to your .mod file
using this syntax:
main {
...
}

When a .mod file contains a main block, the IDE (or the
oplrun command) starts the execution of this model by
running that main block first.

Note that the two optimization models can use the same
model definition (that is, the same .mod file) as is the case
in this example.

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG
Script for OPL > Tutorial: Flow
Control and Multiple Searches > What
You Are Going to Do > Loading the
Necessary Structures
PREVIOUS NEXT
Loading the Necessary Structures

The structures you will use to manipulate models and data


are listed in Table 9.1.
Table 9.1 Scripting: Structures to Manipulate Models
and Data
Name Role
IloOplModelDefinition Links to the .mod file
representation of the
model
IloOplDataSource Links to a .dat file
representation of the data
IloCplex An instance of the CPLEX
algorithm
IloOplModel A structure linking one
model definition to
(possibly) one or several
data sources

See the Reference Manual of ILOG Script Extensions for


OPL f for more information on these classes.
When a main block is executed, a variable called
thisOplModel representing the IloOplModel
instance is available by default. This variable links to the
model definition that contains the main block currently
executed and to the associated .dat files (if they exist) to
run the model. The model definition uses
IloOplModelSource instance that is initialized with
the model name. There is also a variable called cplex
which corresponds to an already created instance of the
CPLEX algorithm.
If you want to run another model and/or use other data, you
may create your own IloOplModel instance, like this:
var src = new
IloOplModelSource("cutstock_sub.mod");
var def = new
IloOplModelDefinition(src);
var opl2 = new IloOplModel(def,cplex);

To create a new data source using a different .dat file,


you can write:
var data = new
IloOplDataSource("mulprod.dat")

Then, to link the IloOplModel instance to a new data


source, write:
opl2.addDataSource(data);

In the mulprod_main example, you don't need to create


all these structures since you want to use the already
defined thisOplModel instance which corresponds to
the model included in the mulprod_main.mod file.

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG
Script for OPL > Tutorial: Flow
Control and Multiple Searches > What
You Are Going to Do > Generating the
Optimization Model
PREVIOUS NEXT
Generating the Optimization Model

When your IloOplModel instance is created, you can


generate the optimization model and feed it to your CPLEX
algorithm by calling the generate() function. In the
mulprod_main example, it is called on the
thisOplModel instance:
thisOplModel.generate();

After this call, the CPLEX instance is ready to solve.

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG
Script for OPL > Tutorial: Flow
Control and Multiple Searches > What
You Are Going to Do > Solving the
Current Optimization Model
PREVIOUS
Solving the Current Optimization NEXT
Model

To solve the current optimization model, just call the


solve() function on the IloCplex instance. This function returns
true or false depending on whether a solution has been found. If a solution is found, you
can ask for the objective value as follows:

if ( cplex.solve() ) {
curr = cplex.getObjValue();
writeln();
writeln("OBJECTIVE: ",curr);
ofile.writeln("Objective with
capFlour = ", capFlour, " is ", curr);
}
else {
writeln("No solution!");
break;
}

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG
Script for OPL > Tutorial: Flow
Control and Multiple Searches > What
You Are Going to Do > Generating the
Optimization Model
What are Data Elements?
You cannot directly change the data in a "data source". This
data source represents what is in a .dat file and the only
way to change it would be to modify the .dat file.
However, you can ask for another editable view of this
data. This other view is referred to as the "data elements" of
the OPL model. These data elements can be modified and
then used as a data source for another model.
Using Data Elements
In the mulprod_main example, you want to get the data
from the current model at each successful iteration, modify
it, and use it to solve another optimization model.
1. To get the elements of the IloOplModel instance,
write:
var data = produce.dataElements;
2. To reuse the same model definition, write:
var def = produce.modelDefinition;

Language User's Manual > ILOG Script for OPL >


Tutorial: Flow Control and Multiple Searches > What You
Are Going to Do > Modifying Some of the Data Elements
PREVIOUS NEXT
Modifying Some of the Data
Elements

You can access and modify some data in the data elements
obtained from the current OPL model, as follows:
data.capacity["flour"] = capFlour;

Then, the value of the variable capacity["flour"] is


modified in the structure of the data elements.

Note
1. Only data external to the model can be modified. Data
elements that are defined inline within the model file
cannot be modified.
2. You can also use data elements to add new elements,
but only for scalar types.

Copyright 1987-2006 ILOG S.A.


PREVIOUS NEXT
All rights reserved. Legal terms.
Language User's Manual > ILOG Script
for OPL > Tutorial: Flow Control and
Multiple Searches > What You Are
Going to Do > Creating a New OPL
Model with the Modified Data
PREVIOUS
Creating a New OPL Model with the NEXT
Modified Data

You can now:


1. Reuse the model definition and use the modified data
elements to create a new OPL model.
produce = new IloOplModel(def,cplex);
produce.addDataSource(data);
2. Generate the optimization model as before:
produce.generate();

The cplex instance is filled with the new optimization model which corresponds
to the same model definition but uses the modified data elements.

Note
The cplex instance that was also used for the original model
does not contain the original optimization model anymore.

Copyright 1987-2006 ILOG S.A. All PREVIOUS


rights reserved. Legal terms. NEXT

See OPL for complete model


PREVIOUS NEXT
Basic Flow Control Script

To help you get started with flow control scripting, Code


Sample 9.4 shows a basic script which summarizes the minimal steps.
// Skeleton that calls mulprod example
main {
var source = new
IloOplModelSource("../../../../../opl/mu
lprod.mod");
var cplex = new IloCplex();
var def = new
IloOplModelDefinition(source);
var opl = new IloOplModel(def,cplex);
var data = new
IloOplDataSource("../../../../../opl/mul
prod.dat");
opl.addDataSource(data);
opl.generate();
if (cplex.solve()) {
writeln("OBJ = " + cplex.getObjValue());
}
else {
writeln("No solution");
}
opl.end();
data.end();
def.end();
cplex.end();
source.end();
}

Code Sample 9.4 Basic Flow Control

You might also like