© 2017 IBM Corporation
OPL best practices
Alex Fleischer afleischer@fr.ibm.com
June 2017
© 2017 IBM Corporation2
A popular linkedin post
 https://www.linkedin.com/pulse/how-opl-alex-fleischer
How to ... with OPL
783 views 44 likes 1 comment
© 2017 IBM Corporation3
Which followed even more popular
2,725 views 128 likes 24 comments
© 2017 IBM Corporation4
Agenda
 Call OPL from outside OPL
 Modeling tricks
 Practical tricks within OPL
 Decomposition
 Specific examples
 NB:
 This is an add-on to documentation and trainings
 This document will get better after feedback
 And you may find all examples at
• https://www.linkedin.com/pulse/how-opl-alex-fleischer
© 2017 IBM Corporation5
Agenda
 Call OPL from outside OPL
 Modeling tricks
 Practical tricks within OPL
 Decomposition
 Specific examples
© 2017 IBM Corporation6
Call OPL from Excel through VBA
© 2017 IBM Corporation7
Call OPL from Matlab
The main idea is to use "system" in Matlab
>> command = 'oplrun model.mod data.dat';
>> [status, cmdout] = system(command);
status is the return code given by oplrun.
© 2017 IBM Corporation8
Call OPL from Python
 import subprocess

 dat = open('diet.dat','w')
 writedat(dat,'FOODS',FOODS);
writedat(dat,'NUTRIENTS',NUTRIENTS);
writedat(dat,'FOOD_NUTRIENTS',FOOD_NUTRIENTS);
 dat.close()
 subprocess.check_call(
["C:/ILOG/CPLEXStudio1263/opl/bin/x64_win64/oplrun", "diet.mod", "diet.dat"])

© 2017 IBM Corporation9
Even further with ticdat from Opalytics
© 2017 IBM Corporation10
Call OPL from R
Diet.r is
system("oplrun diet.mod diet.dat")
To run this example, simply do
Rscript.exe diet.r
And in Rscript.exe diet.r you ll get
quantity = [0 2.1552 0 0 0 10 1.8312 0 0.9297]
cost = 2.690409172
amount = [2000 800 11.278 8518.4 25 256.81 51.174]
© 2017 IBM Corporation11
Agenda
 Call OPL from outside OPL
 Modeling tricks
 Practical tricks within OPL
 Decomposition
 Specific examples
© 2017 IBM Corporation12
How to describe a piecewise linear function with breakpoints rather than slopes
 float firstSlope=0.5;
float lastSlope=2.0;
tuple breakpoint // y=f(x)
{
key float x;
float y;
}
sorted { breakpoint } breakpoints={<0,0>,<1,1>,<2,4>};
float slopesBeforeBreakpoint[b in breakpoints]=
(b.x==first(breakpoints).x)
?firstSlope
:(b.y-prev(breakpoints,b).y)/(b.x-prev(breakpoints,b).x);
pwlFunction f=piecewise(b in breakpoints)
{ slopesBeforeBreakpoint[b]->b.x; lastSlope } (first(breakpoints).x, first(breakpoints).y);
assert forall(b in breakpoints) f(b.x)==b.y;
© 2017 IBM Corporation13
How to multiply a decision variable with a boolean decision variable
using CP;
dvar int x in 2..10;
dvar boolean b;
maximize x;
subject to
{
b*x<=7;
}
dvar int x in 2..10;
dvar boolean b;
dvar int bx;
maximize x;
subject to
{
bx<=7;
(b==1) => (bx==x);
(b==0) => (bx==0);
}
dvar int x in 2..10;
dvar boolean b;
dvar int bx;
maximize x;
subject to
{
bx<=7;
2*b<=bx;
bx<=10*b;
bx<=x-2*(1-b);
bx>=x-10*(1-b);
}
© 2017 IBM Corporation14
How to use a decision variable as an index in an array with CPLEX
using CP;
range r=1..5;
float value[r]=[2,3,4.5,1,0];
dvar int i in 1..5;
maximize value[i];
subject to
{
}
execute
{
writeln("i=",i);
}
range r=1..5;
float value[r]=[2,3,4.5,1,0];
dvar int i in 1..5;
maximize sum(k in r) value[k]*(k==i);
subject to
{
}
execute
{
writeln("i=",i);
}
© 2017 IBM Corporation15
Agenda
 Call OPL from outside OPL
 Modeling tricks
 Practical tricks within OPL
 Decomposition
 Specific examples
© 2017 IBM Corporation16
Displaying 2 dimensions objects in the OPL IDE
 tuple sequence_like {
int start;
int end;
string label;
int type;
};
{sequence_like} array2[i in 1..n] = {<j-1,j," ",Life[i][j]> | j in 1..n};
© 2017 IBM Corporation17
Export into a csv file
tuple t
{
string firstname;
int number;
}
{t} s={<"Nicolas",2>,<"Alexander",3>};
execute
{
var f=new IloOplOutputFile("export.csv");
for(var i in s)
{
f.writeln(i.firstname,";",i.number,";");
}
f.close();
}
writes a file export.csv
Nicolas;2;
Alexander;3;
© 2017 IBM Corporation18
Import from csv file
Suppose you have this export.cvs file
Nicolas;2;
Alexander;3;
Then you could write
tuple t
{
string firstname;
int number;
}
{t} s={};
execute
{
var f=new IloOplInputFile("export.csv");
while (!f.eof)
{
var str=f.readline();
//writeln(str);
var ar=str.split(";");
if (ar.length==3) s.add(ar[0],Opl.intValue(ar[1]));
}
f.close();
}
execute
{
writeln(s);
}
which will read the csv file and compute the tuple set s:
{<"Nicolas" 2> <"Alexander" 3>}
© 2017 IBM Corporation19
Cartesian product in OPL
tuple Tset {
{string} members;
}
{Tset} setOfTuples = {<{"1","2"}>,<{"4","5","6"}>,<{"8","9"}>};
int dimresult=prod(i in 1..card(setOfTuples)) card(item(setOfTuples,i-
1).members);
{string} setPool[i in 1..dimresult]={}; // pool of sets
{string} options[i in 1..card(setOfTuples)]=(item(setOfTuples,i-
1).members);
{Tset} result={};
//For this particular example, the function needs to return:
//{<{1,4,8}>,<{1,4,9}>,<{1,5,8}>,<{1,5,9}>,<{1,6,8}>,<{1,6,9}>,<{2,4,8}>,<{2
,4,9}>,<{2,5,8}>,<{2,5,9}>,<{2,6,8}>,<{2,6,9}>}
execute
{
options;
function nextone(ndimension,sizes,e)
{
e[1]++;
for(j=1;j<=ndimension;j++)
{
if (e[j]>= sizes[j] )
{
e[j]=0;
e[j+1]++;
}
}
}
var dim=setOfTuples.size;
writeln("dim=",dim);
var sizes=new Array(dim);
var e=new Array(dim);
var dimresult=1;
for(var i=1;i<=dim;i++)
{
sizes[i]=Opl.item(setOfTuples,i-1).members.size;
e[i]=0;
dimresult*=sizes[i];
writeln(sizes[i]);
}
for(var i=1;i<=dimresult;i++)
{
for(var j=1;j<=dim;j++)
{
write(e[j]," ");
setPool[i].add(Opl.item(options[j],e[j]));
}
writeln();
nextone(dim,sizes,e);
result.add(setPool[i]);
}
writeln(result);
}
© 2017 IBM Corporation20
Powerset in OPL
{string} s={"A","B","C","D"};
range r=1.. ftoi(pow(2,card(s)));
{string} s2 [k in r] = {i | i in s: ((k div (ftoi(pow(2,(ord(s,i))))) mod 2) == 1)};
execute
{
writeln(s2);
}
© 2017 IBM Corporation21
How to evaluate CPLEX random seed variability in OPL
int n=30; // number of random seeds
int d[1..n]; // duration
int o[1..n]; // objective
int iter[1..n]; // iterations
// start of the model we want to test
int Fixed = 100;
int NbWarehouses = 50;
int NbStores = 200;
assert( NbStores > NbWarehouses );
range Warehouses = 1..NbWarehouses;
range Stores = 1..NbStores;
int Capacity[w in Warehouses] =
NbStores div NbWarehouses +
w % ( NbStores div NbWarehouses );
int SupplyCost[s in Stores][w in Warehouses] =
1 + ( ( s + 10 * w ) % 100 );
dvar int Open[Warehouses] in 0..1;
dvar float Supply[Stores][Warehouses] in 0..1;
dexpr int TotalFixedCost = sum( w in Warehouses ) Fixed * Open[w];
dexpr float TotalSupplyCost = sum( w in Warehouses, s in Stores
) SupplyCost[s][w] * Supply[s][w];
minimize TotalFixedCost + TotalSupplyCost;
subject to {
forall( s in Stores )
ctStoreHasOneWarehouse:
sum( w in Warehouses )
Supply[s][w] == 1;
forall( w in Warehouses )
ctOpen:
sum( s in Stores )
Supply[s][w] <= Open[w] * Capacity[w];
}
// end of the model we want to test
main {
thisOplModel.generate();
var sum_d=0;
var sum_o=0;;
var sum_iter=0;
writeln("seed objective iteration runtime");
for(var i=1;i<=thisOplModel.n;i++)
{
var opl=new IloOplModel(thisOplModel.modelDefinition);
opl.generate();
cplex.randomseed=i;
var d1=new Date();
cplex.solve();
var d2=new Date();
thisOplModel.d[i]=d2-d1;
sum_d+=d2-d1;
thisOplModel.d[i]=d2-d1;
thisOplModel.o[i]=Opl.ftoi(Opl.round(cplex.getObjValue()));
sum_o+=thisOplModel.o[i];
thisOplModel.iter[i]=cplex.getNiterations();
sum_iter+=thisOplModel.iter[i];
writeln(i," ",thisOplModel.o[i]," ",thisOplModel.iter[i]," ",
thisOplModel.d[i]/1000);
cplex.clearModel();
}
writeln("-----------------------------------------");
writeln("average ",sum_o/thisOplModel.n," ",
sum_iter/thisOplModel.n," ",sum_d/thisOplModel.n/1000);
writeln("std dev ",Opl.standardDeviation(thisOplModel.o)," ",
Opl.standardDeviation(thisOplModel.iter)," ",Opl.standardDeviation(thisO
plModel.d)/1000);
}
© 2017 IBM Corporation22
Agenda
 Call OPL from outside OPL
 Modeling tricks
 Practical tricks within OPL
 Decomposition
 Specific examples
© 2017 IBM Corporation23
Hybrid CPO and CPLEX
int n=20;
int values[0..(n+2)*(n+2)-1];
main {
var n=20;
var source1 = new IloOplModelSource("lifegameip.mod");
var cplex = new IloCplex();
var def1 = new IloOplModelDefinition(source1);
var source2 = new IloOplModelSource("lifegamecp.mod");
var cp = new IloCP();
var def2 = new IloOplModelDefinition(source2);
var opl1 = new IloOplModel(def1,cplex);
var opl2 = new IloOplModel(def2,cp);
opl1.generate();
opl2.generate();
var objValues=new Array(2*5);
for(var iter=1;iter<=5;iter++)
{
cplex.tilim=10;
cplex.solve();
writeln("cplex objective = ",cplex.getObjValue());
objValues[iter*2-1]=cplex.getObjValue();
cp.param.timelimit=10;
cp.param.SearchType=24;
// Warmstart
var sol=new IloOplCPSolution();
for(var i=0;i<=(n+2)*(n+2)-1;i++) sol.setValue(opl2.x[i],opl1.x[i]);
cp.setStartingPoint(sol);
cp.param.SearchType=24;
//opl2.Obj.LB=cplex.getObjValue();
cp.solve();
writeln("cpo objective =",cp.getObjValue());
objValues[iter*2]=cp.getObjValue();
var vectors = new IloOplCplexVectors();
// We attach the values (defined as data) as starting solution
// for the variables x.
for(var i=0;i<=(n+2)*(n+2)-1;i++) thisOplModel.values[i]=opl2.x[i];
vectors.attach(opl1.x,thisOplModel.values);
vectors.setVectors(cplex);
}
writeln("list of objectives") ;
for(var i=1;i<=10;i++) writeln(objValues[i]);
}
© 2017 IBM Corporation24
How to change the model without regeneration, incremental cplex matrix modification
dvar float+ Gas;
dvar float+ Chloride;
maximize 40 * Gas+ 50 * Chloride;
subject to {
ctMaxTotal:
Gas+ Chloride<= 50;
ctMaxTotal2:
3 * Gas+ 4 * Chloride<= 180;
ctMaxChloride:
Chloride<= 40;
ctEmpty:
Gas<=infinity;
}
execute
{
writeln("Gas = ",Gas);
writeln("Chloride = ",Chloride);
writeln("Objective =
",cplex.getObjValue());
main
{
thisOplModel.generate();
cplex.solve();
thisOplModel.postProcess();
writeln();
writeln("And then we add the
constraint Chloride - Gas <=5");
writeln();
thisOplModel.ctEmpty.UB=5;
thisOplModel.ctEmpty.setCoef(this
OplModel.Gas,-1);
thisOplModel.ctEmpty.setCoef(this
OplModel.Chloride,1);
cplex.solve();
thisOplModel.postProcess();
}
© 2017 IBM Corporation25
How to solve the same model with different data ? Change a value and generate again
float maxOfx = ...;
dvar float x;
maximize x;
subject to {
x<=maxOfx;
}
execute
{
writeln("x= ",x);
}
main {
var source = new
IloOplModelSource("sub.mod");
var cplex = new IloCplex();
var def = new IloOplModelDefinition(source);
for(var k=1;k<=10;k++)
{
var opl = new IloOplModel(def,cplex);
var data2= new IloOplDataElements();
data2.maxOfx=k;
opl.addDataSource(data2);
opl.generate();
if (cplex.solve()) {
opl.postProcess();
writeln("OBJ = " + cplex.getObjValue());
} else {
writeln("No solution");
}
opl.end();
}
}
© 2017 IBM Corporation26
How to solve the same model with different data ? Change an array and generate again
int y[1..2][1..2]=...;
execute
{
writeln("y=",y);
}
dvar float x;
maximize x;
subject to {
x<=sum(i in 1..2, j in 1..2) y[i][j];
}
int a[1..2][1..2];
main {
var source = new IloOplModelSource("sub.mod");
var cplex = new IloCplex();
var def = new IloOplModelDefinition(source);
for(var k=11;k<=15;k++)
{
var opl = new IloOplModel(def,cplex);
var data2= new IloOplDataElements();
data2.y=thisOplModel.a;
data2.y[1][1]=k;
opl.addDataSource(data2);
opl.generate();
if (cplex.solve()) {
writeln("OBJ = " + cplex.getObjValue());
} else {
writeln("No solution");
}
data2.end();
opl.end();
}
}
© 2017 IBM Corporation27
How to solve the same model with different data ? Change a set and generate again
{int} y=...;
execute
{
writeln("y=",y);
}
dvar float x;
maximize x;
subject to {
x<=sum(i in y)i;
}
execute
{
writeln("x=",x);
}
{int} s={};
main {
var source = new IloOplModelSource("sub.mod");
var cplex = new IloCplex();
var def = new IloOplModelDefinition(source);
for(var k=1;k<=5;k++)
{
var opl = new IloOplModel(def,cplex);
var data2= new IloOplDataElements();
data2.y=thisOplModel.s;
data2.y.add(k);
opl.addDataSource(data2);
opl.generate();
if (cplex.solve()) {
writeln("OBJ = " + cplex.getObjValue());
} else {
writeln("No solution");
}
data2.end();
opl.end();
}
}
© 2017 IBM Corporation28
Solve Anyway
int prefsolveanyway1[1..1]=[0];
int prefsolveanyway2[1..1]=[0];
int prefsolveanyway3[1..1]=[0];
int priority[1..3]=[1,2,3];
dvar int x;
dvar int y;
dvar int z;
subject to
{
0<=x<=20;
0<=y<=20;
0<=z<=20;
forall(i in 1..1) ct1:y-x>=7;
forall(i in 1..1) ct2:z-y>=9;
forall(i in 1..1) ct3:z-x<=10;
}
main {
function writeRelaxation(opl)
{
var iter = opl.relaxationIterator;
for(var c in iter)
{
var constraint=c.ct;
writeln(constraint.name);
writeln("LB = ",c.LB);
writeln("UB = ",c.UB);
writeln("relaxedLB = ",c.relaxedLB);
writeln("relaxedUB = ",c.relaxedUB);
}
}
thisOplModel.generate();
var def = thisOplModel.modelDefinition;
// Default behavior
writeln("Default Behavior");
writeln();
var cplex1 = new IloCplex();
var opl1 = new IloOplModel(def, cplex1);
opl1.settings.relaxationLevel=1;
writeln("Solve Anyway");
// Priority 1 : ct1
// Priority 2 : ct2
// Priority 3 : ct3
var currentPriority = 1;
var noSolution=1;
while (noSolution==1)
{
writeln();
var cplex2 = new IloCplex();
var opl2 = new IloOplModel(def, cplex2);
opl2.generate();
writeln("relaxing priority less than ",currentPriority) ;
if (opl2.priority[1]<=currentPriority) opl2.prefsolveanyway1[1]=1; else
opl2.prefsolveanyway1[1]=0;
if (opl2.priority[2]<=currentPriority) opl2.prefsolveanyway2[1]=1; else
opl2.prefsolveanyway2[1]=0;
if (opl2.priority[3]<=currentPriority) opl2.prefsolveanyway3[1]=1; else
opl2.prefsolveanyway3[1]=0;
opl2.relaxationIterator.attach(opl2.ct1, opl2.prefsolveanyway1);
opl2.relaxationIterator.attach(opl2.ct2, opl2.prefsolveanyway2);
opl2.relaxationIterator.attach(opl2.ct3, opl2.prefsolveanyway3);
writeRelaxation(opl2);
writeln("cplex status = ",cplex2.getCplexStatus());
if (cplex2.getCplexStatus()==14)
{
noSolution=0;
writeln("x,y,z = ",opl2.x," ",opl2.y," ",opl2.z);
}
currentPriority++;
}
opl2.end();
cplex2.end();
© 2017 IBM Corporation29
Agenda
 Call OPL from outside OPL
 Modeling tricks
 Practical tricks within OPL
 Decomposition
 Specific examples
© 2017 IBM Corporation30
TSP with CPO
 minimize endOf(itvs[n+1]) - (n+1);
subject to
{
startOf(itvs[1])==0; // break sym
noOverlap(seq,Dist,true); // nooverlap with a distance matrix
last(seq, itvs[n+1]); // last node
}
 NB:
 For big instances, CPLEX works better than CPO but as soon as you add side
constraints then CPO can tackle whereas CPLEX not always can
 Plus CPO gives a solution any time wheras with CPLEX you need a flow
control to remove circuits.
© 2017 IBM Corporation31
DEA (Data Envelopment Analysis)
 "Data envelopment analysis (DEA) is a nonparametric method in
operations research and economics for the estimation of production
frontiers. It is used to empirically measure productive efficiency of
decision making units (or DMUs). Although DEA has a strong link to
production theory in economics, the tool is also used for
benchmarking in operations management, where a set of measures
is selected to benchmark the performance of manufacturing and
service operations." (Wikipedia)
 This method relies on linear programming and looks at the past
 ( ex post)
 Always the same model, no ad hoc model so quick to implement
© 2017 IBM Corporation32
Data Envelopment Analysis (DEA) in OPL
int nbDMU=...;
int nbInputs= ...;
int nbOutputs=...;
range DMU=1..nbDMU;
range Input=1..nbInputs;
range Output=1..nbOutputs;
// Input
float X[DMU][Input]=...;
// Output
float Y[DMU][Output]=...;
int refDMU=...; // We want to measure efficiency of that DMU
assert refDMU in DMU;
dvar float+ theta;
dvar float+ lambda[DMU];
minimize theta;
subject to
{
forall(j in Input)
ctInput:
sum(i in DMU) (lambda[i]*X[i][j]) <= theta*X[refDMU][j];
forall(j in Output)
ctOutput:
sum(i in DMU) (lambda[i]*Y[i][j]) >= Y[refDMU][j];
}
execute
{
writeln("theta= ",theta);
if (theta==1) writeln("Efficient DMU");
// Loop to measure efficiency for all
DMU
main
{
thisOplModel.generate();
for(var dmu in thisOplModel.DMU)
{
writeln("DMU",dmu);
for(j in thisOplModel.Input)
thisOplModel.ctInput[j].setCoef(thisO
plModel.theta,-
thisOplModel.X[dmu][j]);
for(j in thisOplModel.Output)
thisOplModel.ctOutput[j].LB=thisOplM
odel.Y[dmu][j];
cplex.solve();
thisOplModel.postProcess();
}
© 2017 IBM Corporation33
How to import docplexcloud solution into a local OPL session
from docloud.job import JobClient
client = JobClient(url, key)
// Run the model in docplexcloud
with open("model/diet.mod", "rb") as modFile:
resp = client.execute(input=[{"name":"diet.mod",
"file":modFile},
"model/diet.dat"],
output="results.json",
log="solver.log",
gzip=True,
waittime=300,
delete_on_completion=True)
// import the json result file
import json
with open('results.json') as data_file:
data = json.load(data_file)
// write that into a .dat
res = open("sol.dat", "w")
res.write("s={");
quote='"'
for i in data["s"]:
res.write("<"+quote+i["food"]+quote+
","
+quote+i["nutrient"]+quote+","+str(i["
value"])+",>")
res.write("};")
res.close()
OPL best practices - Doing more with less easier

OPL best practices - Doing more with less easier

  • 1.
    © 2017 IBMCorporation OPL best practices Alex Fleischer afleischer@fr.ibm.com June 2017
  • 2.
    © 2017 IBMCorporation2 A popular linkedin post  https://www.linkedin.com/pulse/how-opl-alex-fleischer How to ... with OPL 783 views 44 likes 1 comment
  • 3.
    © 2017 IBMCorporation3 Which followed even more popular 2,725 views 128 likes 24 comments
  • 4.
    © 2017 IBMCorporation4 Agenda  Call OPL from outside OPL  Modeling tricks  Practical tricks within OPL  Decomposition  Specific examples  NB:  This is an add-on to documentation and trainings  This document will get better after feedback  And you may find all examples at • https://www.linkedin.com/pulse/how-opl-alex-fleischer
  • 5.
    © 2017 IBMCorporation5 Agenda  Call OPL from outside OPL  Modeling tricks  Practical tricks within OPL  Decomposition  Specific examples
  • 6.
    © 2017 IBMCorporation6 Call OPL from Excel through VBA
  • 7.
    © 2017 IBMCorporation7 Call OPL from Matlab The main idea is to use "system" in Matlab >> command = 'oplrun model.mod data.dat'; >> [status, cmdout] = system(command); status is the return code given by oplrun.
  • 8.
    © 2017 IBMCorporation8 Call OPL from Python  import subprocess   dat = open('diet.dat','w')  writedat(dat,'FOODS',FOODS); writedat(dat,'NUTRIENTS',NUTRIENTS); writedat(dat,'FOOD_NUTRIENTS',FOOD_NUTRIENTS);  dat.close()  subprocess.check_call( ["C:/ILOG/CPLEXStudio1263/opl/bin/x64_win64/oplrun", "diet.mod", "diet.dat"]) 
  • 9.
    © 2017 IBMCorporation9 Even further with ticdat from Opalytics
  • 10.
    © 2017 IBMCorporation10 Call OPL from R Diet.r is system("oplrun diet.mod diet.dat") To run this example, simply do Rscript.exe diet.r And in Rscript.exe diet.r you ll get quantity = [0 2.1552 0 0 0 10 1.8312 0 0.9297] cost = 2.690409172 amount = [2000 800 11.278 8518.4 25 256.81 51.174]
  • 11.
    © 2017 IBMCorporation11 Agenda  Call OPL from outside OPL  Modeling tricks  Practical tricks within OPL  Decomposition  Specific examples
  • 12.
    © 2017 IBMCorporation12 How to describe a piecewise linear function with breakpoints rather than slopes  float firstSlope=0.5; float lastSlope=2.0; tuple breakpoint // y=f(x) { key float x; float y; } sorted { breakpoint } breakpoints={<0,0>,<1,1>,<2,4>}; float slopesBeforeBreakpoint[b in breakpoints]= (b.x==first(breakpoints).x) ?firstSlope :(b.y-prev(breakpoints,b).y)/(b.x-prev(breakpoints,b).x); pwlFunction f=piecewise(b in breakpoints) { slopesBeforeBreakpoint[b]->b.x; lastSlope } (first(breakpoints).x, first(breakpoints).y); assert forall(b in breakpoints) f(b.x)==b.y;
  • 13.
    © 2017 IBMCorporation13 How to multiply a decision variable with a boolean decision variable using CP; dvar int x in 2..10; dvar boolean b; maximize x; subject to { b*x<=7; } dvar int x in 2..10; dvar boolean b; dvar int bx; maximize x; subject to { bx<=7; (b==1) => (bx==x); (b==0) => (bx==0); } dvar int x in 2..10; dvar boolean b; dvar int bx; maximize x; subject to { bx<=7; 2*b<=bx; bx<=10*b; bx<=x-2*(1-b); bx>=x-10*(1-b); }
  • 14.
    © 2017 IBMCorporation14 How to use a decision variable as an index in an array with CPLEX using CP; range r=1..5; float value[r]=[2,3,4.5,1,0]; dvar int i in 1..5; maximize value[i]; subject to { } execute { writeln("i=",i); } range r=1..5; float value[r]=[2,3,4.5,1,0]; dvar int i in 1..5; maximize sum(k in r) value[k]*(k==i); subject to { } execute { writeln("i=",i); }
  • 15.
    © 2017 IBMCorporation15 Agenda  Call OPL from outside OPL  Modeling tricks  Practical tricks within OPL  Decomposition  Specific examples
  • 16.
    © 2017 IBMCorporation16 Displaying 2 dimensions objects in the OPL IDE  tuple sequence_like { int start; int end; string label; int type; }; {sequence_like} array2[i in 1..n] = {<j-1,j," ",Life[i][j]> | j in 1..n};
  • 17.
    © 2017 IBMCorporation17 Export into a csv file tuple t { string firstname; int number; } {t} s={<"Nicolas",2>,<"Alexander",3>}; execute { var f=new IloOplOutputFile("export.csv"); for(var i in s) { f.writeln(i.firstname,";",i.number,";"); } f.close(); } writes a file export.csv Nicolas;2; Alexander;3;
  • 18.
    © 2017 IBMCorporation18 Import from csv file Suppose you have this export.cvs file Nicolas;2; Alexander;3; Then you could write tuple t { string firstname; int number; } {t} s={}; execute { var f=new IloOplInputFile("export.csv"); while (!f.eof) { var str=f.readline(); //writeln(str); var ar=str.split(";"); if (ar.length==3) s.add(ar[0],Opl.intValue(ar[1])); } f.close(); } execute { writeln(s); } which will read the csv file and compute the tuple set s: {<"Nicolas" 2> <"Alexander" 3>}
  • 19.
    © 2017 IBMCorporation19 Cartesian product in OPL tuple Tset { {string} members; } {Tset} setOfTuples = {<{"1","2"}>,<{"4","5","6"}>,<{"8","9"}>}; int dimresult=prod(i in 1..card(setOfTuples)) card(item(setOfTuples,i- 1).members); {string} setPool[i in 1..dimresult]={}; // pool of sets {string} options[i in 1..card(setOfTuples)]=(item(setOfTuples,i- 1).members); {Tset} result={}; //For this particular example, the function needs to return: //{<{1,4,8}>,<{1,4,9}>,<{1,5,8}>,<{1,5,9}>,<{1,6,8}>,<{1,6,9}>,<{2,4,8}>,<{2 ,4,9}>,<{2,5,8}>,<{2,5,9}>,<{2,6,8}>,<{2,6,9}>} execute { options; function nextone(ndimension,sizes,e) { e[1]++; for(j=1;j<=ndimension;j++) { if (e[j]>= sizes[j] ) { e[j]=0; e[j+1]++; } } } var dim=setOfTuples.size; writeln("dim=",dim); var sizes=new Array(dim); var e=new Array(dim); var dimresult=1; for(var i=1;i<=dim;i++) { sizes[i]=Opl.item(setOfTuples,i-1).members.size; e[i]=0; dimresult*=sizes[i]; writeln(sizes[i]); } for(var i=1;i<=dimresult;i++) { for(var j=1;j<=dim;j++) { write(e[j]," "); setPool[i].add(Opl.item(options[j],e[j])); } writeln(); nextone(dim,sizes,e); result.add(setPool[i]); } writeln(result); }
  • 20.
    © 2017 IBMCorporation20 Powerset in OPL {string} s={"A","B","C","D"}; range r=1.. ftoi(pow(2,card(s))); {string} s2 [k in r] = {i | i in s: ((k div (ftoi(pow(2,(ord(s,i))))) mod 2) == 1)}; execute { writeln(s2); }
  • 21.
    © 2017 IBMCorporation21 How to evaluate CPLEX random seed variability in OPL int n=30; // number of random seeds int d[1..n]; // duration int o[1..n]; // objective int iter[1..n]; // iterations // start of the model we want to test int Fixed = 100; int NbWarehouses = 50; int NbStores = 200; assert( NbStores > NbWarehouses ); range Warehouses = 1..NbWarehouses; range Stores = 1..NbStores; int Capacity[w in Warehouses] = NbStores div NbWarehouses + w % ( NbStores div NbWarehouses ); int SupplyCost[s in Stores][w in Warehouses] = 1 + ( ( s + 10 * w ) % 100 ); dvar int Open[Warehouses] in 0..1; dvar float Supply[Stores][Warehouses] in 0..1; dexpr int TotalFixedCost = sum( w in Warehouses ) Fixed * Open[w]; dexpr float TotalSupplyCost = sum( w in Warehouses, s in Stores ) SupplyCost[s][w] * Supply[s][w]; minimize TotalFixedCost + TotalSupplyCost; subject to { forall( s in Stores ) ctStoreHasOneWarehouse: sum( w in Warehouses ) Supply[s][w] == 1; forall( w in Warehouses ) ctOpen: sum( s in Stores ) Supply[s][w] <= Open[w] * Capacity[w]; } // end of the model we want to test main { thisOplModel.generate(); var sum_d=0; var sum_o=0;; var sum_iter=0; writeln("seed objective iteration runtime"); for(var i=1;i<=thisOplModel.n;i++) { var opl=new IloOplModel(thisOplModel.modelDefinition); opl.generate(); cplex.randomseed=i; var d1=new Date(); cplex.solve(); var d2=new Date(); thisOplModel.d[i]=d2-d1; sum_d+=d2-d1; thisOplModel.d[i]=d2-d1; thisOplModel.o[i]=Opl.ftoi(Opl.round(cplex.getObjValue())); sum_o+=thisOplModel.o[i]; thisOplModel.iter[i]=cplex.getNiterations(); sum_iter+=thisOplModel.iter[i]; writeln(i," ",thisOplModel.o[i]," ",thisOplModel.iter[i]," ", thisOplModel.d[i]/1000); cplex.clearModel(); } writeln("-----------------------------------------"); writeln("average ",sum_o/thisOplModel.n," ", sum_iter/thisOplModel.n," ",sum_d/thisOplModel.n/1000); writeln("std dev ",Opl.standardDeviation(thisOplModel.o)," ", Opl.standardDeviation(thisOplModel.iter)," ",Opl.standardDeviation(thisO plModel.d)/1000); }
  • 22.
    © 2017 IBMCorporation22 Agenda  Call OPL from outside OPL  Modeling tricks  Practical tricks within OPL  Decomposition  Specific examples
  • 23.
    © 2017 IBMCorporation23 Hybrid CPO and CPLEX int n=20; int values[0..(n+2)*(n+2)-1]; main { var n=20; var source1 = new IloOplModelSource("lifegameip.mod"); var cplex = new IloCplex(); var def1 = new IloOplModelDefinition(source1); var source2 = new IloOplModelSource("lifegamecp.mod"); var cp = new IloCP(); var def2 = new IloOplModelDefinition(source2); var opl1 = new IloOplModel(def1,cplex); var opl2 = new IloOplModel(def2,cp); opl1.generate(); opl2.generate(); var objValues=new Array(2*5); for(var iter=1;iter<=5;iter++) { cplex.tilim=10; cplex.solve(); writeln("cplex objective = ",cplex.getObjValue()); objValues[iter*2-1]=cplex.getObjValue(); cp.param.timelimit=10; cp.param.SearchType=24; // Warmstart var sol=new IloOplCPSolution(); for(var i=0;i<=(n+2)*(n+2)-1;i++) sol.setValue(opl2.x[i],opl1.x[i]); cp.setStartingPoint(sol); cp.param.SearchType=24; //opl2.Obj.LB=cplex.getObjValue(); cp.solve(); writeln("cpo objective =",cp.getObjValue()); objValues[iter*2]=cp.getObjValue(); var vectors = new IloOplCplexVectors(); // We attach the values (defined as data) as starting solution // for the variables x. for(var i=0;i<=(n+2)*(n+2)-1;i++) thisOplModel.values[i]=opl2.x[i]; vectors.attach(opl1.x,thisOplModel.values); vectors.setVectors(cplex); } writeln("list of objectives") ; for(var i=1;i<=10;i++) writeln(objValues[i]); }
  • 24.
    © 2017 IBMCorporation24 How to change the model without regeneration, incremental cplex matrix modification dvar float+ Gas; dvar float+ Chloride; maximize 40 * Gas+ 50 * Chloride; subject to { ctMaxTotal: Gas+ Chloride<= 50; ctMaxTotal2: 3 * Gas+ 4 * Chloride<= 180; ctMaxChloride: Chloride<= 40; ctEmpty: Gas<=infinity; } execute { writeln("Gas = ",Gas); writeln("Chloride = ",Chloride); writeln("Objective = ",cplex.getObjValue()); main { thisOplModel.generate(); cplex.solve(); thisOplModel.postProcess(); writeln(); writeln("And then we add the constraint Chloride - Gas <=5"); writeln(); thisOplModel.ctEmpty.UB=5; thisOplModel.ctEmpty.setCoef(this OplModel.Gas,-1); thisOplModel.ctEmpty.setCoef(this OplModel.Chloride,1); cplex.solve(); thisOplModel.postProcess(); }
  • 25.
    © 2017 IBMCorporation25 How to solve the same model with different data ? Change a value and generate again float maxOfx = ...; dvar float x; maximize x; subject to { x<=maxOfx; } execute { writeln("x= ",x); } main { var source = new IloOplModelSource("sub.mod"); var cplex = new IloCplex(); var def = new IloOplModelDefinition(source); for(var k=1;k<=10;k++) { var opl = new IloOplModel(def,cplex); var data2= new IloOplDataElements(); data2.maxOfx=k; opl.addDataSource(data2); opl.generate(); if (cplex.solve()) { opl.postProcess(); writeln("OBJ = " + cplex.getObjValue()); } else { writeln("No solution"); } opl.end(); } }
  • 26.
    © 2017 IBMCorporation26 How to solve the same model with different data ? Change an array and generate again int y[1..2][1..2]=...; execute { writeln("y=",y); } dvar float x; maximize x; subject to { x<=sum(i in 1..2, j in 1..2) y[i][j]; } int a[1..2][1..2]; main { var source = new IloOplModelSource("sub.mod"); var cplex = new IloCplex(); var def = new IloOplModelDefinition(source); for(var k=11;k<=15;k++) { var opl = new IloOplModel(def,cplex); var data2= new IloOplDataElements(); data2.y=thisOplModel.a; data2.y[1][1]=k; opl.addDataSource(data2); opl.generate(); if (cplex.solve()) { writeln("OBJ = " + cplex.getObjValue()); } else { writeln("No solution"); } data2.end(); opl.end(); } }
  • 27.
    © 2017 IBMCorporation27 How to solve the same model with different data ? Change a set and generate again {int} y=...; execute { writeln("y=",y); } dvar float x; maximize x; subject to { x<=sum(i in y)i; } execute { writeln("x=",x); } {int} s={}; main { var source = new IloOplModelSource("sub.mod"); var cplex = new IloCplex(); var def = new IloOplModelDefinition(source); for(var k=1;k<=5;k++) { var opl = new IloOplModel(def,cplex); var data2= new IloOplDataElements(); data2.y=thisOplModel.s; data2.y.add(k); opl.addDataSource(data2); opl.generate(); if (cplex.solve()) { writeln("OBJ = " + cplex.getObjValue()); } else { writeln("No solution"); } data2.end(); opl.end(); } }
  • 28.
    © 2017 IBMCorporation28 Solve Anyway int prefsolveanyway1[1..1]=[0]; int prefsolveanyway2[1..1]=[0]; int prefsolveanyway3[1..1]=[0]; int priority[1..3]=[1,2,3]; dvar int x; dvar int y; dvar int z; subject to { 0<=x<=20; 0<=y<=20; 0<=z<=20; forall(i in 1..1) ct1:y-x>=7; forall(i in 1..1) ct2:z-y>=9; forall(i in 1..1) ct3:z-x<=10; } main { function writeRelaxation(opl) { var iter = opl.relaxationIterator; for(var c in iter) { var constraint=c.ct; writeln(constraint.name); writeln("LB = ",c.LB); writeln("UB = ",c.UB); writeln("relaxedLB = ",c.relaxedLB); writeln("relaxedUB = ",c.relaxedUB); } } thisOplModel.generate(); var def = thisOplModel.modelDefinition; // Default behavior writeln("Default Behavior"); writeln(); var cplex1 = new IloCplex(); var opl1 = new IloOplModel(def, cplex1); opl1.settings.relaxationLevel=1; writeln("Solve Anyway"); // Priority 1 : ct1 // Priority 2 : ct2 // Priority 3 : ct3 var currentPriority = 1; var noSolution=1; while (noSolution==1) { writeln(); var cplex2 = new IloCplex(); var opl2 = new IloOplModel(def, cplex2); opl2.generate(); writeln("relaxing priority less than ",currentPriority) ; if (opl2.priority[1]<=currentPriority) opl2.prefsolveanyway1[1]=1; else opl2.prefsolveanyway1[1]=0; if (opl2.priority[2]<=currentPriority) opl2.prefsolveanyway2[1]=1; else opl2.prefsolveanyway2[1]=0; if (opl2.priority[3]<=currentPriority) opl2.prefsolveanyway3[1]=1; else opl2.prefsolveanyway3[1]=0; opl2.relaxationIterator.attach(opl2.ct1, opl2.prefsolveanyway1); opl2.relaxationIterator.attach(opl2.ct2, opl2.prefsolveanyway2); opl2.relaxationIterator.attach(opl2.ct3, opl2.prefsolveanyway3); writeRelaxation(opl2); writeln("cplex status = ",cplex2.getCplexStatus()); if (cplex2.getCplexStatus()==14) { noSolution=0; writeln("x,y,z = ",opl2.x," ",opl2.y," ",opl2.z); } currentPriority++; } opl2.end(); cplex2.end();
  • 29.
    © 2017 IBMCorporation29 Agenda  Call OPL from outside OPL  Modeling tricks  Practical tricks within OPL  Decomposition  Specific examples
  • 30.
    © 2017 IBMCorporation30 TSP with CPO  minimize endOf(itvs[n+1]) - (n+1); subject to { startOf(itvs[1])==0; // break sym noOverlap(seq,Dist,true); // nooverlap with a distance matrix last(seq, itvs[n+1]); // last node }  NB:  For big instances, CPLEX works better than CPO but as soon as you add side constraints then CPO can tackle whereas CPLEX not always can  Plus CPO gives a solution any time wheras with CPLEX you need a flow control to remove circuits.
  • 31.
    © 2017 IBMCorporation31 DEA (Data Envelopment Analysis)  "Data envelopment analysis (DEA) is a nonparametric method in operations research and economics for the estimation of production frontiers. It is used to empirically measure productive efficiency of decision making units (or DMUs). Although DEA has a strong link to production theory in economics, the tool is also used for benchmarking in operations management, where a set of measures is selected to benchmark the performance of manufacturing and service operations." (Wikipedia)  This method relies on linear programming and looks at the past  ( ex post)  Always the same model, no ad hoc model so quick to implement
  • 32.
    © 2017 IBMCorporation32 Data Envelopment Analysis (DEA) in OPL int nbDMU=...; int nbInputs= ...; int nbOutputs=...; range DMU=1..nbDMU; range Input=1..nbInputs; range Output=1..nbOutputs; // Input float X[DMU][Input]=...; // Output float Y[DMU][Output]=...; int refDMU=...; // We want to measure efficiency of that DMU assert refDMU in DMU; dvar float+ theta; dvar float+ lambda[DMU]; minimize theta; subject to { forall(j in Input) ctInput: sum(i in DMU) (lambda[i]*X[i][j]) <= theta*X[refDMU][j]; forall(j in Output) ctOutput: sum(i in DMU) (lambda[i]*Y[i][j]) >= Y[refDMU][j]; } execute { writeln("theta= ",theta); if (theta==1) writeln("Efficient DMU"); // Loop to measure efficiency for all DMU main { thisOplModel.generate(); for(var dmu in thisOplModel.DMU) { writeln("DMU",dmu); for(j in thisOplModel.Input) thisOplModel.ctInput[j].setCoef(thisO plModel.theta,- thisOplModel.X[dmu][j]); for(j in thisOplModel.Output) thisOplModel.ctOutput[j].LB=thisOplM odel.Y[dmu][j]; cplex.solve(); thisOplModel.postProcess(); }
  • 33.
    © 2017 IBMCorporation33 How to import docplexcloud solution into a local OPL session from docloud.job import JobClient client = JobClient(url, key) // Run the model in docplexcloud with open("model/diet.mod", "rb") as modFile: resp = client.execute(input=[{"name":"diet.mod", "file":modFile}, "model/diet.dat"], output="results.json", log="solver.log", gzip=True, waittime=300, delete_on_completion=True) // import the json result file import json with open('results.json') as data_file: data = json.load(data_file) // write that into a .dat res = open("sol.dat", "w") res.write("s={"); quote='"' for i in data["s"]: res.write("<"+quote+i["food"]+quote+ "," +quote+i["nutrient"]+quote+","+str(i[" value"])+",>") res.write("};") res.close()