# OPL Optimization Programming Language Today we will look at OPL Structure Syntax Modelling Linear Problems in OPL Constraint Programming in OPL.

## Presentation on theme: "OPL Optimization Programming Language Today we will look at OPL Structure Syntax Modelling Linear Problems in OPL Constraint Programming in OPL."— Presentation transcript:

OPL Optimization Programming Language Today we will look at OPL Structure Syntax Modelling Linear Problems in OPL Constraint Programming in OPL

Mathematical Modelling Language Using AMPL var B; var T; maximize profit: 25*B+30*T; subject to: (1/200)*B+(1/140)*T <= 40; subject to: 0 <= B <= 6000; subject to: 0 <= T <= 4000; solve;

Modelling Languages Mathematical Modelling Languages (AMPL, GAMS) very high-level specification of (typically linear) models specialized optimization algorithms limited flexibility for search Constraint Programming programming language backtracking search with consistency based methods to refine variable domains limited optimization capabilities limited data structures flexible specification of search, heuristics, etc.

Modelling Languages OPL combines both approaches High-level specification of linear programs High-level specification of constraint programs Expressive data structures Flexible search Specialized optimization algorithms BUT: not a universal programming language OPL models can be solved using linear programming integer programming techniques (branch&bound etc) backtracking search + consistency techniques The OPL system identifies the class of problem and chooses the appropriate technique.

enum Products { gas, chloride }; enum Components { nitrogen, hydrogen, chlorine }; float+ demand[Products, Components] = [ [1, 3, 0], [1, 4, 1] ]; float+ profit[Products] = [30, 40]; float+ stock[Components] = [50, 180, 40]; var float+ production[Products]; maximize sum (p in Products) profit[p] * production[p] subject to { forall (c in Components) sum (p in Products) demand[p, c] * production[p] <= stock[c] }; Linear Programming in OPL Constraints Objective Variables Data Gas=NH3, Chloride=NH4CL

int nbItems = 5; range Items 1..nbItems; int capacity= 1000; int value[Items] = [ 59,44,30,12,170 ]; int weight[Items] = [ 20, 30, 16, 22, 70 ]; var int take[Items] in 0..capacity; maximize sum(i in Items) value[i] * take[i] subject to sum(i in Items) weight[i] * take[i] <= capacity; (Mixed) Integer Programming in OPL Knapsack Problem

Separating the Data In a reusable model the concrete instance data is separated from the generic part of the problem. enum Products...; enum Components...; float+ demand[Products, Components] =...; float+ profit[Products] =...; float+ stock[Components] =...; var float+ production[Products]; maximize sum (p in Products) profit[p] * production[p] subject to { forall (c in Components) sum (p in Products) demand[p, c] * production[p] <= stock[c] };

Model Data Initialization of model data can be performed in a separate data file. Products= { gas, chloride }; Components= {nitrogen, hydrogne, chlorine}; demand=[[1, 3, 0], [1, 4, 1]]; profit= [40,50]; stock= [50, 180, 40];

Basic Data Types OPL knows only two basic data types. Integer:int x=2; int+x=2;(positive only) Real:float x=2.5; float+x=2.5;(positive only) All other types must be declared.

Type Declarations Enumerations enum Colors {red, green, blue}; Colors todaysSky = blue; Ranges range Queens1..4; range Queens1..boardSize; Queens position= 1; Float Range range float angle{0.0..2*3.1415] OPL knows most structured data types that are used in typical programming languages: Enumerations, Arrays and Records. Additionally, some structured types typically needed in in mathematical modelling are available: Ranges (Intervals) and Sets.

int+ fn[1..10] = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; Range I 1..10; int+ fn[I] = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; enum Colors {red, green, blue, orange, purple, yellow}; int+ amount[Colors]= [100, 300, 250, 50, 320, 90]; {Colors} primary= { red, green, blue }; int+ amount[primary]= { 100, 300, 250 }; Arrays Arrays can be indexed by any enumerable type -- ranges (integer), enumerations and sets Set declaration Set index

enum Products { gas, chloride }; enum Components {nitrogen, hydrogen, chlorine}; float+ demand[Products, Components] =...; demand=[[1, 3, 0], [1, 4, 1]]; or demand=#[ gas: #[nitrogen: 1, hydrogen: 3 chlorine: 0]# chloride: #[nitrogen: 1, hydrogen: 4, chlorine: 1]# ]# Array Initialization An array can either be initalized by enumerating its elements or by using explicit indices

Generic Array Initialization If the array elements are dependent on the index generic expressions can be used for their initialization int+ fn[i in 1..10] = i This also works for multi-dimensional arrays, for example range d1..10; int a[d,d] =...; int aTransposed[i in d, j in d] = a[j,i];

Structures (Records) Once declared, structures can be used like any other data type struct Coord { int x; int y; }; Coord x = ; {Coord} xs= {,, }; Coord xa[1..3]= [,, ]; an important usage of structures is for the representation of sparse problems Elements of a structure can be addressed by name int xCoords[i in 1..3] = xa[i].x ;

Sets A set is always implicitly ordered! Sets can be initialized generically with range expressions query-like expressions {int+} s1={ 3, 4, 5, 6 }; {int+} s2={ 5, 1, 3, 7, 9 }; {int}=s1 union s2; also: inter, diff, symdiff {int+} s= 1..10; struct Interval{ int+ low, int+ high; }; {Interval} nonEmpty= { | ordered i,j in s }; {Interval} nonEmpty= { # # | ordered i,j in s }; {int+} odd1= 1..100 by 2; {int+} odd2= {i | i in 1..100 : i mod 2 = 1 };

Exploiting Sparsity Sparse problems should be modelled with arrays indexed by elements of sets instead of by elements of ranges. This keeps the arrays small. Consider a weighted graph: int maxNode =...; int+ Node 1..maxNode; float+ edgeWeight[Node, Node]=...; If the graph is sparse, the following is likely to be more efficient: int+ Node 1..maxNode; struct Edge {Node start; Node end;}; {Edge} edges={, }; float+ edgeWeight[edges]=[ 3.2, 4.4, 1.7 ]; This array has only 3 elements (edgeWeight[ ], etc.)

Variables Variables must be declared explicitly using var. They are ``logical’’ or ``mathematical’’ variables. It is the role of OPL to find values for them. Admissible types are int, int+ float, float+ enumerations arrays of these types varintx; varintxin 0..100; varintx[0..10, 0..10]in 0..100; enum Colors {red, green, blue, orange, purple, yellow}; enum Rooms{lounge, bed, kitchen, study, bath}; varColorspaint[Rooms]; var floatamount[r in Routes] in 0.0..capacity[r];

Input and Output Input can be taken from data files or from the user int maxFromFile =...; int maxFromUser<< “Input number of positions”; The implementation OPLstudio also offers an interactive browser. var floatamount[r in Routes] in 0.0..capacity[r];... float+ slack[r in Routes]= capacity[r]-amount[r]; display(r in Routes: amount[r]>0) slack[r]; display sum(r in Routes) slack[r]; Output is generated using the display keyword

Consistency Conditions (Integrity) Like in relational databases, consistency conditions or integrity conditions can be asserted. These allow input data to be checked. These raise an execution exception when violated. assert forall (p in Products) sum(s in Suppliers) supply[s,p] = sum(c in Customers) demand[c,p];

Expressions A number of mathematical expressions are supported: abs, sqrt, ceil, distToInt, floor, frac, nearest, trunc float f = 5.5; float g = sqrt(2*f); Integer expressions only support +, -, *, /, mod int x=3; int y=22; int z=y mod x; Float expressions must explicitly be converted to integer: int x = ftoi(floor(f))

Aggregates Aggregate expressions are specified directly without using loops: int cost[Edges] =...; {Edge} path =...; int totalCost = sum(e in path) cost[e]; The following types of aggregates are supported: min(minimum) max(maximum) sum(summation) prod(product)

Piecewise Linear Functions 10 20 30 sum(p in products) piecewise{2 -> 10; 1 -> 20, 0.5}(0,0) amount[p]; point on function breakpoint slope argument amount[p]

Constraints Float constraints: linear or piecewise linear Discrete constraints: arbitrary relations on integers or enumerations Basic Constraints forall(t in tasks) t.end >= t.start+t.duration Boolean Combinations forall ( ordered t1, t2 in tasks) t1.start >= t2.start+t2.length \/ t2.start >= t1.start+t1.length;

Linear Programming Example A company produces and sells different kinds of products. Each product can be produced inside of the company from certain resources at a fixed cost or bought at another cost from outside. The company can only produce a limited amount of each product since there is a limit on the available resources. The company wants to decide which amount to produce inside and which amount to buy to satisfy a given customer demand. It should maximise profit but must satisfy the resource constraints.

Planning enum Products...; enum Resources...; float+ consumption[Products,Resources] =...; float+ capacity[Resources] =...; float+ demand[Products] =...; float+ insideCost[Products] =...; float+ outsideCost[Products] =...; var float+ inside[Products]; var float+ outside[Products]; Product Types Resource Types Amount of resource required to produce a given product Cost of producing product Amount of product to produce Available resources Demand for product minimize sum(p in Products) (insideCost[p]*inside[p] + outsideCost[p]*outside[p]) subject to { forall(r in Resources) sum(p in Products) consumption[p,r]*inside[p] <= capacity[r]; forall(p in Products) inside[p] + outside[p] >= demand[p];};

Planning (Data) Products = {penne orecchiette 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]; (Answer) Optimal Solution with Objective Value 372.0000 inside[penne] = 40.0000 inside[orecchiette] = 0.0000 inside[fettucine] = 0.0000 outside[penne] = 60.0000 outside[orecchiette] = 200.0000 outside[fettucine] = 300.0000

Better Planning Model enum Products...; enum Resources...; struct ProductData { float+ demand; float+ insideCost; float+ outsideCost; float+ consumption[Resources]; }; ProductData product[Products] = …; var float+ inside[Products]; var float+ outside[Products];

Better Planning Model minimize sum(p in Products) (product[p].insideCost*inside[p] + product[p].outsideCost*outside[p] ) subject to { forall(r in Resources) sum(p in Products) product[p].consumption[r]*inside[p] <= capacity[r]; forall(p in Products) inside[p] + outside[p] >= product[p].demand; };

Linear Programming Example II (1) An oil company sells three kinds of gas namesuper regulardiesel price\$70\$60\$50 octane>= 10>= 8>= 6 lead<= 1<= 2<= 1 demand300020001000 (2) These are produced from three kinds of crude oil namecrude1crude2crude3 octane1268 lead0.52.03.0 (3) If the company advertises one of its products, it will sell 10 barrels more per \$1 spent on advertising. (4) The cost of transforming oil into gasoline is \$4 (per barrel). (5) The company can buy 5000 barrels of each crude oil per day. (6) The maximum production capacity is 14000 barrels per day

Blending Problem (Declarations) enum Gasolines...; enum Oils...; struct GasType { float+ demand; float+ price; float+ octane; float+ lead; }; struct OilType { float+ capacity; float+ price; float+ octane; float+ lead; }; GasType gas[Gasolines] =...; OilType oil[Oils] =...; float+ maxProduction =...; float+ prodCost =...; var float+ a[Gasolines]; var float+ blend[Oils,Gasolines]; Advertising investment blend[o,g]: #barrels o blended into #barrels g

Blending Problem (Data) Gasolines = { super regular diesel }; Oils = { crude1 crude2 crude3 }; gas = [ # # ]; oil = [ # # ]; maxProduction = 14000; prodCost = 4;

Blending Problem (Model) maximize sum(g in Gasolines, o in Oils) (gas[g].price - oil[o].price - prodCost) * blend[o,g] - sum(g in Gasolines) a[g] subject to { forall(g in Gasolines) sum(o in Oils) blend[o,g] = gas[g].demand + 10*a[g]; forall(o in Oils) sum(g in Gasolines) blend[o,g] <= oil[o].capacity; sum(o in Oils, g in Gasolines) blend[o,g] <= maxProduction; forall(g in Gasolines) sum(o in Oils) (oil[o].octane - gas[g].octane) * blend[o,g] >= 0; forall(g in Gasolines) sum(o in Oils) (oil[o].lead - gas[g].lead) * blend[o,g] <= 0; };

Multistage Planning Example A company produces and sells three different kinds of products. Each product can be produced inside of the company from certain resources at a fixed cost or bought at another cost from outside. The company wants to decide which amount to produce inside and which amount to buy to satisfy a given customer demand. The company can only produce a limited amount of each product per month, but it can decide to produce more than it sells and store the overproduction in an inventory for later sale. Holding a product in the inventory incurs a product-dependent storage cost.

Multistage Planning (Declarations) enum Products...; enum Resources...; int nbPeriods =...; range Periods 1..nbPeriods; struct Plan { float+ inside; float+ outside; float+ inv; }; float+ consumption[Resources,Products] =...; float+ capacity[Resources] =...; float+ demand[Products,Periods] =...; float+ insideCost[Products] =...; float+ outsideCost[Products] =...; float+ inventory[Products] =...; float+ invCost[Products] =...; var float+ inside[Products,Periods]; var float+ outside[Products,Periods]; var float+ inv[Products,0..nbPeriods]; Product Types Resource Types Time Period (Months) Initial Inventory Contents Inventory Contents in Period i only needed for result display

Multistage Planning (Model) 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) sum(p in Products) consumption[r,p] * inside[p,t] <= capacity[r]; forall(p in Products, t in Periods) inv[p,t-1] + inside[p,t] + outside[p,t] = demand[p,t] + inv[p,t]; forall(p in Products) inv[p,0] = inventory[p]; }; The crucial “trick” is to link the inventory from time period t to t+1 with the framed statement.

Multistage Planning (Output) struct Plan { float+ inside; float+ outside; float+ inv; }; Plan plan[p in Products, t in Periods] = ; output, e.g. plan[prod1, 1] = plan[prod1, 2] = etc...

Constraint Programming in OPL var int queens[1..4] in 1..4; solve { forall(ordered i,j in 1..4) { queens[i] <> queens[j] ; queens[i] + i <> queens[j] + j ; queens[i] - i <> queens[j] - j }; Constraints Variables 1 3 2 4 Q1 Q2 Q3 Q4

Relations as Boolean Functions All boolean expressions are treated as binary values. Higher order expressions can be treated as integer functions: int numbers[0..max] =...; int count[i in 0..max] = sum(j in 0..max) (numbers[j]=i); This generalizes to the use of other boolean expressions: & (and), \/ (or), not, => (implication), (equivalence) int numbers[0..max] =...; Interval ranges[0..max] =...; int count [i in 0..max] = sum(j in 0..max) ( numbers[j] > ranges[i].low & numbers[j] < ranges[i].high );

Higher Order Constraints Basic Constraints forall(t in tasks) t.end >= t.start+t.duration Boolean Combinations forall ( ordered t1, t2 in tasks) t1.start >= t2.start+t2.length \/ t2.start >= t1.start+t1.length; Higher Order count[i] = sum(j in 0..10) (s[j]=i)

Stable Marriages A group of n women and n men must be grouped into n couples such that if a man x prefers a woman y to his own partner, then y must prefer her own partner to x. (and vice versa) Otherwise the couple is deemed unstable. enum Women...; enum Men...; int rankWomen[Women,Men] =...; int rankMen[Men,Women] =...; var Women wife[Men]; var Men husband[Women];

Stable Marriages solve { forall(m in Men) husband[wife[m]] = m; forall(w in Women) wife[husband[w]] = w; forall(m in Men & o in Women) rankMen[m,o] rankWomen[o,husband[o]] < rankWomen[o,m]; forall(w in Women & o in Men) rankWomen[w,o] rankMen[o,wife[o]] < rankMen[o,w]; };

Magic Series A magic series is a series of integers in which the i-th integer is equal to the number of occurrences of i in the series, e.g. [1,2,1,0] (note that the first index is 0) Higher Order int n << "Number of Variables:"; range Range 0..n-1; range Domain 0..n; var Domain s[Range]; solve { forall(i in Range) s[i] = sum(j in Range) (s[j] = i); sum(i in Range) s[i] = n; sum(i in Range) s[i]*i = n; }; Higher order constraints are handled internally by using 0-1 variables. Redundant Constraints

Global Constraints alldifferent(arr) if all elements in the array arr are different circuit(succ) if the integer array succ interpreted as node labels such that succ[i] is the successor of node i describes a Hamiltonian circuit distribute(occ, val, arr) if occ[i] is the count of val[i] in the array arr // Magic Series with Global Constraints range Range 0..n-1; range Domain 0..n; int value[i in Range ] = i; var Domain s[Range]; solve { distribute(s,value,s); };

Constraint Programming Constraint programming uses backtracking search in combination with consistency based methods to reduce the domain of the finite domain variables. The shape and size of the resulting search tree depends on the order in which variables are chosen to be ``labelled’’ I.e. given a value and in what order the values in the variables domain are tried. To see this consider X≠Y, Y≠Z, Z≠X D(X) = {1,2}, D(Y)={1,2}, D(Z)={1,2,3} and the different trees that will result when using arc consistency in combination with backtracking search

Search in OPL OPL allows the modeller to control how the search tree is constructed by specifying the order in which to label variables and the order in which to try values. It provides a mini-programming language for specifying the search procedure choice iteration conditional construct local variables

Search--Simple Example var int queen[1..4] in 1..4; solve { forall (ordered i, j in 1..4) { queen[i] <> queen[j]; queen[i]+i <> queen[j]+j; queen[i]-i <> queen[j]-j; } }; search { forall(i in 1..4) tryall(v in 1..4) queen[i]=v; }; Specify variables to label Specify values to try Add constraint

Basic Search search { try x1=v11 | x1=v12 |... | x1=v1m1 endtry; try x2=v21 | x1=v22 |... | x1=v2m2 endtry;... try xn=vn1 | xn=vn2 |... | xn=vnm1 endtry; } Assigns values to each of the xi in turn in ascending order. Values are tried in the order of occurrence. Generates a backtracking search tree with levels corresponding to variables order of branches on level i corresponding to values vij

Search search { try queen[1]=1 | queen[1]=2 | queen[1]=3| queen[1]=4 endtry; try queen[2]=1 | queen[2]=2 | queen[2]=3| queen[2]=4 endtry; try queen[3]=1 | queen[3]=2 | queen[3]=3| queen[3]=4 endtry; try queen[4]=1 | queen[4]=2 | queen[4]=3| queen[4]=4 endtry; }; search queen[1]=1queen[1]=2 queen[2]=1queen[2]=4... queen[2]=1queen[2]=4... queen[4]=1queen[4]=3... queen[3]=1 √

Tryall search { forall(i in 1..4) tryall(v in 1..4) queen[i]=v; }; equivalent to search { try queen[1]=1 | queen[1]=2 | queen[1]=3| queen[1]=4 endtry; try queen[2]=1 | queen[2]=2 | queen[2]=3| queen[2]=4 endtry; try queen[3]=1 | queen[3]=2 | queen[3]=3| queen[3]=4 endtry; try queen[4]=1 | queen[4]=2 | queen[4]=3| queen[4]=4 endtry; }; try all even numbers from 100 down to 2 tryall(x in 1..100 : x mod 2 = 0 ordered by decreasing x) tryall(var in Bounds) [: Relation] [Order]

Search Quantifiers forall(v in Range [:Relation] [Order]) specifies the variables to be labelled (like universal quantification or iteration) Dynamic ordering can be used dsize(x)domain size dmax(x)maximum value in domain dmin(x)minimum value in domain These allow the modeller to specify heuristics

First Fail Search Heuristic A good heuristic is to fail as quickly as possible: this is called the first-fail heuristic I.e. choose the variable with the smallest domain to label next search { forall(i in 1..4 ordered by increasing dsize(queen[i])) tryall(v in 1..4) queen[i]=v; };

Choice in Search Note: The choices in a try instruction can be general constraints (and not only equations) Conditionals can be used inside search search { forall(I in 1..10) if I mod 10 = 0 then tryall(v in 1..10 ordered by increasing I) x[I]=v else tryall(v in 1..10 ordered by decreasing I) x[I]=v endif; };

Iterative Search Note: The choices in a try instruction can be general constraints (and not only equations) while Relation do Choice... iterates a choice statement until the condition becomes true. search { while not bound(x) do let m=dmin(x) in try x=m | x <> m endtry }; The select instruction allows selection of data satisfying some condition

Linear Relaxation A reflective function allows direct access to the linear relaxation (Simplex value). Branch and bound can therefore be programmed by the search instruction while not bound(x) do let v=simplexValue(x) in let f=floor(v) in let c=ceiling(v) in try x = c endtry; We can use local variables let Var=Expression in Choice binds a new local variable

Predefined Search if no special search strategy is required simplified built-in search procedures can be used. search {forall(i in 1..4) tryall(v in 1..4) queen[i]=v; }; search {forall(i in 1..4) generate(queen[i]); }; Generate also extends canonically to arrays: search { generate(queen); }; generateSize(x)in increasing order of dsize(x) (=generate) generateMinin increasing order of dmin(x) generateMaxin increasing order of dmax(x)

Data-driven Constructs As part of the search one can include constraint- or data-driven expressions. when open[w] = 0 do forall(c in Customers) supply[c] <> w; Addition of this constraint is delayed until open[w] =0 holds. I.e. when it is first encountered open[w] =0 is checked to see if it holds, if so the body is executed, if it definitely does not then the constraint is deleted and if the value of open[w] is not known then the constraint suspends until the value is set. Apart from when OPL provides onValue, onRange and onDomain.

Integer Programming Example Problem: a company wants to build a number of warehouses to supply its stores. (1) There is a universal fixed maintenance cost for every warehouse. (2) There is an individual maximum capacity (stores) for each warehouse. (3) The transport costs depend on the warehouse and the supplied store. (4) Each store must be supplied by a single warehouse. (but a warehouse can supply several stores)

Warehouse Problem (Declarations) range Boolean 0..1; int fixed =...; enum Warehouses...; int nbStores =...; range Stores 0..nbStores-1; int capacity[Warehouses] =...; int supplyCost[Stores,Warehouses] =...; var Boolean open[Warehouses]; var Boolean supply[Stores,Warehouses]; Decision Variables Shall a warehouse be opened? Which warehouse supplies which store?

Warehouse Problem (Data) fixed = 30; Warehouses = {Bonn,Bordeaux,London,Paris,Rome}; nbStores = 10; capacity = [1,4,2,1,3]; supplyCost = [ [ 20, 24, 11, 25, 30 ], [ 28, 27, 82, 83, 74 ], [ 74, 97, 71, 96, 70 ], [ 2, 55, 73, 69, 61 ], [ 46, 96, 59, 83, 4 ], [ 42, 22, 29, 67, 59 ], [ 1, 5, 73, 59, 56 ], [ 10, 73, 13, 43, 96 ], [ 93, 35, 63, 85, 46 ], [ 47, 65, 55, 71, 95 ] ];

Warehouse Problem (Model) minimize sum(w in Warehouses) fixed * open[w] + sum(w in Warehouses, s in Stores) supplyCost[s,w] * supply[s,w] subject to { forall(s in Stores) sum(w in Warehouses) supply[s,w] = 1; forall(w in Warehouses, s in Stores) supply[s,w] <= open[w]; forall(w in Warehouses) sum(s in Stores) supply[s,w] <= capacity[w]; }; display open; {Stores} storesof[w in Warehouses] = { s | s in Stores : supply[s,w] }; display storesof;

Warehouse Problem with Constraints (Declarations) int fixed =...; int nbStores =...; enum Warehouses...; range Stores 0..nbStores-1; int capacity[Warehouses] =...; int supplyCost[Stores,Warehouses] =...; var int open[Warehouses] in 0..1; var Warehouses supplier[Stores]; New (Constraint) Decision Variables (in red) Array of suppliers for each store indexed by store

Warehouse Problem (constraints) minimize sum(s in Stores) supplyCost[s,supplier[s]] + sum(w in Warehouses) fixed * open[w] subject to { forall(s in Stores ) open[supplier[s]] = 1; forall(w in Warehouses) sum(s in Stores) (supplier[s] = w) <= capacity[w]; }; Note the higher-order constraints: these cannot be rewritten as an integer program Note the use of a variable as an array index

Regret Heuristics search { forall(s in Stores ordered by decreasing regretdmin(cost[s])) tryall(w in Warehouses ordered by increasing supplyCost[s,w]) supplier[s] = w; generateSeq(open); }; Idea: Give priority to assignments for which using the second best value causes the maximal change in the objective. regretdmin(x): Difference between two lowest values in dom(x). regretdmax(x): Difference between two highest values in dom(x). Results in a search that assigns the warehouse in order of maximal regret for cost[s] = supplyCost[s,supplier[s]] try possible suppliers in increasing order of supply cost Note that generateSeq(open) uses default labelling to assign values to variables in the array open

Warehouse Problem with Constraints II (Declarations) int fixed =...; int nbStores =...; enum Warehouses...; range Stores 0..nbStores-1; int capacity[Warehouses] =...; int supplyCost[Stores,Warehouses] =...; int maxCost = max(s in Stores, w in Warehouses) supplyCost[s,w]; var int open[Warehouses] in 0..1; var Warehouses supplier[Stores]; var int cost[Stores] in 0..maxCost; New (Constraint) Decision Variables (in red) supply cost for each store

Warehouse Problem II (constraints) minimize sum(s in Stores) cost[s] + sum(w in Warehouses) fixed * open[w] subject to { forall(s in Stores) cost[s] = supplyCost[s,supplier[s]]; forall(s in Stores ) open[supplier[s]] = 1; forall(w in Warehouses) sum(s in Stores) (supplier[s] = w) <= capacity[w]; };

Warehouse Problem (search heuristics) search { forall(s in Stores ordered by decreasing regretdmin(cost[s])) tryall(w in Warehouses ordered by increasing supplyCost[s,w]) supplier[s] = w; generateSeq(open); }; The model is no longer a linear program, but we can now easily specify a search heuristics!

Integration of IP and CP Linear Integer Programming and Constraint Programming can often be used for the same problem. Their advantages are complementary: Linear IP / 0-1 ProgrammingConstraint Programming + faster algorithms- search required - complicated modelling+ high expressiveness - little influence on search+ explicit heuristics Combining both approaches can be done by linking constraint variables with integer variables (using constraints) using linear relaxation on numerical constraint variables.

Steps for combining the models: copy one model into the other link constraint variables with integer variables (using constraints) forall(s in Stores) supply[s,supplier[s]] = 1; forall(s in Stores) cost[s]= sum(w in Warehouses) supplyCost[s,w] * supply[s,w] use a linear objective and instruct OPL to use linear relaxation minimize with linear relaxation sum(w in Warehouses) fixed * open[w] + sum(w in Warehouses, s in Stores) supplyCost[s,w] * supply[s,w] Integrated Warehouse Model We can now integrate both models in order to utilize a combination of linear programming algorithms constraint propagation search heuristics

range Boolean 0..1; int fixed =...; int nbStores =...; enum Warehouses...; range Stores 0..nbStores-1; int capacity[Warehouses] =...; int supplyCost[Stores,Warehouses] =...; int maxCost = max(s in Stores, w in Warehouses) supplyCost[s,w]; var Boolean open[Warehouses]; var Boolean supply[Stores,Warehouses]; var Warehouses supplier[Stores]; var int cost[Stores] in 0..maxCost; Revised Warehouse Model (Declarations) shared

minimize with linear relaxation sum(w in Warehouses) fixed * open[w] + sum(w in Warehouses, s in Stores) supplyCost[s,w] * supply[s,w] subject to { forall(s in Stores) sum(w in Warehouses) supply[s,w] = 1; forall(w in Warehouses, s in Stores) supply[s,w] <= open[w]; forall(w in Warehouses) sum(s in Stores) supply[s,w] <= capacity[w]; forall(s in Stores) cost[s] = supplyCost[s,supplier[s]]; forall(s in Stores ) open[supplier[s]] = 1; forall(w in Warehouses) sum(s in Stores) (supplier[s] = w) <= capacity[w]; forall(s in Stores) supply[s,supplier[s]] = 1; forall(s in Stores) cost[s] = sum(w in Warehouses) supplyCost[s,w] * supply[s,w] }; Integrated Warehouse Model

Scheduling OPL provides specialised data types and search strategies for modelling and solving scheduling and resource allocation applications. The basic model is that you schedule activities. An activity a has a starting time start a duration duration a finish time end an implicit constraint that a.end = a.start+a.duration Activity carpentry; carpentry.duration = 10; Activities can be optionally initialised with their duration Activity carpentry(10); var int durationCarpentry in 8..10; Activity carpentry(durationCarpentry);

Scheduling Activities are scheduled over the global-time interval [scheduleOrigen,scheduleHorizon] Both scheduleOrigen and scheduleHorizon must be initialised before declaring schedule activities. scheduleOrigen = 0; scheduleHorizon = 364; Typically one adds constraints on the order of activities b.start >= a.end; a precedes b;

Resources Activities can require or consume resources. A unary resource is a resource than cannot be shared by two activities. UnaryResource crane; Activity excavation(3); excavation requires crane; A discrete resource with capacity n has n different instances of the resource DiscreteResource crane(4); excavation requires(2) crane; Sometimes an activity ``consumes’’ the resource, I.e. it is not available afterwards DiscreteResource budget(1000); excavation consumes(2000) budget;

Breakable Resources In the real-world there may be periods such as the weekend in which a resource is unavailable. These periods are often called breaks. periodicBreak(crane,5,2,7); break(crane,10,12); Activities may or may not be interuptable by breaks. By default they are not breakable Activity excavation breakable; More generally one can vary the capacity of a discrete resource over time capacityMax(crane,10,12,4); capacityMin(crane,1,20,2);

Reservoirs Sometimes activities may themselves generate the resources needed by other activities. Resources that can be created and used by activities are called reservoirs Reservoir Budget(20000); Activity produceWidget, sellWidget; produceWidget consumes(1000) Budget; sellWidget provides(1200) Budget;

Reservoirs Sometimes activities may themselves generate the resources needed by other activities. Resources that can be created and used by activities are called reservoirs Reservoir Budget(20000); Activity produceWidget, sellWidget; produceWidget consumes(1000) Budget; sellWidget provides(1200) Budget;

House Scheduling enum Tasks {masonry, carpentry, plumbing, ceiling, roofing, painting}; int duration[Tasks] = [7,3,8,3,1,2]; Activity a[t in Tasks](duration(t)); DiscreteResource budget(24000); minimize a[painting].end subject to { a[masonry] precedes a[carpentry]; a[masonry] precedes a[plumbing]; a[masonry] precedes a[ceiling]; a[carpentry] precedes a[roofing]; a[carpentry] precedes a[painting]; a[ceiling] precedes a[painting]; capacityMax(budget,0,15,20000); forall(t in Tasks) a[t] consumes(1000*duration[t]) budget; };

House Scheduling Optimal solution with Objective value: 20 a[masonry] = [0 -- 7 --> 7] a[carpentry] = [7 -- 3 --> 10] a[plumbing] = [7 -- 8 --> 15] a[ceiling] = [15 -- 3 --> 18] a[roofing] = [10 -- 1 --> 11] a[painting] = [18 -- 2 --> 20]

Where is it??? Installed on honspc06 and honspc09-14. 8 machines in total OPLstudio binary /usr/local/ilog/bin/i86_linux2_glibc2.1_egcs1.1/oplst MUST set ILOG_LICENSE_FILE to /usr/local/ilog/access.ilm Xwin needs to be set to 16 bit: done automatically startx -- -bpp 16 Report problems to tech@help.csse.monash.edu.au (cc me)

OPLStudio It is installed on honspc01-15 under Windows XP but only 10 users can use it at a time. Report problems to tech@help.csse.monash.edu.au (cc me)

Summary Homework Read P. van Hentenryck, The OPL Optimization Programming Language Trace the examples of this lecture in OPL Studio In this unit we have looked at the modelling language OPL Structure and Syntax Modelling Linear Problems in OPL Constraint Programming in OPL

Download ppt "OPL Optimization Programming Language Today we will look at OPL Structure Syntax Modelling Linear Problems in OPL Constraint Programming in OPL."

Similar presentations