AMPL
An Introduction
Outline
• AMPL - What is it (good for)?
• Basics
• Starting a Problem
• Running the Problem
• Example
Outline (Continued)
• Two File Format
• Why Use a Data File?
• All About Sets
• Example (single file)
• Example with data file
• Logical Operators
Outline (A little More)
• Set Operations
• Set Indexing
• Syntax
• Where to get AMPL
AMPL
What is it (good for)?
AMPL is:
• A Mathematical Programming Language
• Supports over 30 solvers
• Only need to know syntax for AMPL to use many different solvers
AMPL does:
• Solves LP’s
• Solves IP’s
• Solves MIP’s, and non-linear programs
Basics
• Files you will need
• How to write them
• How to save them
Writing the .mod file
Open up a non-contextual text editor (e.g. GNU Emacs, OxEdit, or textedit), type the
model, save with file extension “.mod”
Syntax of File
• AMPL is a computer language, so it doesn’t understand what you mean
• Because of this, there is a particular format that AMPL files must have to run properly
• The format is fairly straightforward
• Here’s how it goes:
Order of entry
Enter the variables first, e.g.:
var x1 >=0;
var Sally >=4.5;
var smileyface <=-1;
var happy integer >=0;
Everything has to be identified before you use it, so AMPL knows it is there to use
Order of Entry- Cont.
Next enter the objective:
maximize OBJ: 3*x1 - happy + 2*Sally;
minimize COST: 3*x3 + 2*x1 - Sally;
maximize WHOCARES: 0;
A Quick Note:
AMPL is case sensitive, so “SALLY”, “Sally”, and “sally” are three different names for variables. If something isn’t working correctly, a case error is an easy thing to identify and fix.
Order of Entry - Cont.
Next enter the constraints:
subject to WOOD: 2*x1 - 40*happy<=27;
subject to WORK: x3 + 2.5*Sally<=34;
subject to MACHINE: happy - Sally<=14;
Put it all together:
var x1 >=0;
var Sally >=4.5;
var smileyface <=-1;
var happy integer >=0;
maximize OBJ: 3*x1 - happy + 2*Sally + 4.5*smileyface;
subject to WOOD: 2*x1 - 40*happy<=27;
subject to WORK: x3 + 2.5*Sally<=34;
subject to MACHINE: happy - 3*smileyface<=14;
Running the File
Once you have the file written and saved, we need to run it to get our
solution.
How to Run AMPL
• Open up AMPL• Tell AMPL what you want solved by:• “model <filepath>\project1.mod;” • If the file is in AMPL’s search path, you may be
able to just enter “model FILENAME.mod;”• If you want to use a different solver:• “option solver <solver name>;”• Tell AMPL to solve it:• “solve;”
Subject to Semicolons
• You may have noticed all the semicolons running around the file we put together, and in the commands to run the model.
• These tell AMPL where to separate lines, and things will not work properly without them.
• For instance, if you typed “solve” rather than “solve;”, AMPL would return a prompt that looks like this “ampl?”
Getting the variables
• This will only give you the optimal value, if it exists. How do you know the variable values that give this objective?
• Tell AMPL to give them to you:
• “display x1,x3,Sally,happy,smileyface;”
• This will display the variable values
• Remember, AMPL is case sensitive.
Put it all together• ampl: model data\ampl1.mod;
ampl: option solver cplex;ampl: solve;CPLEX 8.0.0, optimal integral solution found, objective value 712.2, 0 MIP iterations, 0 branch and bound nodesdisplay x1,x3,Sally,smileyface,happy;x1 = 0x3 = -1Sally = 22.33333happy = 11smileyface = 0
The .dat File
• AMPL supports using a separate file for the particular data
• The .dat file holds the values for the parameters, and the names of the variables
Why Use 2 Files?
• You may want to do similar problems
• You may need to modify the data, but not the model
• It makes finding and changing parameters easy
• It makes adding or removing variables easy
All About Sets
• AMPL lets you define sets in the model by declaring them: set SETNAME
• Once a set is declared, you can index parameters over it: param PARAMETER {i in SETNAME}
• Alternatively: param PARAMETER {SETNAME}• You can even index variables over sets: var
VARIABLE {i in SETNAME}• Also, you can use summation notation: sum {i in
SETNAME} VARIABLE[i]*PARAMETER[i]
A (Relatively) Simple Example
• Suppose there is a steel mill that can process raw steel into two products, bands and coils.
• The manager of the mill wants to maximize his profit, given the restrictions on processing time available, and the limitations on how much he can realistically sell of each
• Bands can be processed at 200 tons per hour, at a profit of $25 per ton, and at most 6000 tons can be sold
• Coils are processed at 140 tons per hour, at a profit of $30 per ton, with a market cap of 4000 tons
• There are 40 hours available per week to process the steel
The old way
• Without using sets or a .dat file, the model would look something like this:
var Bands;
var Coils;
maximize Profit: 25 * Bands + 30 * Coils;
subject to Time: (1/200)*Bands + (1/140)*Coils <= 40;
subject to B_Limit: 0 <= Bands <= 6000;
subject to C_Limit: 0 <= Coils <= 4000;
The New Way
Alternatively, we could split this into a .mod file and a .dat file:
steel.mod
set Products;param rate {i in Products};param profit {i in Products};param market {i in Products};param hours;var X {i in Products};maximize Total_Profit: sum {i in Products} X[i] * profit[i];subject to Time: sum {i in Products} X[i]/rate[i]<=hours;subject to Market {i in Products}: 0<= X[i] <= market[i];
steel.dat
set Products := bands coils;
param: rate market profit :=
bands 200 6000 25
coils 140 4000 30 ;
param hours := 40;
WHY????
• Right now, it looks like the old way is easier, right?
• What if we want to add a new product, rods?• In the old way, we would need to find every place
that something might change and alter it individually
• In the new way, we just have to change the .dat file
The Old Way, Updated
var Bands;var Coils;var Rods;maximize Profit: 25 * Bands + 30 * Coils + 28 *
Rods;subject to Time: (1/200)*Bands + (1/140)*Coils +
(1/160)*Rods <= 40;subject to B_Limit: 0 <= Bands <= 6000;subject to C_Limit: 0 <= Coils <= 4000;subject to R_Limit: 0<= Rods <= 5000;
Or, just change steel.dat
set Products := bands coils rods;
param: rate market profit :=
bands 200 6000 25
coils 140 4000 30
rods 160 5000 28 ;
param hours := 40;
Also…
• If you are dealing with large models, the .mod file can get REALLY big without a .dat file
• Changing the problem becomes very easy with a .dat file
Logical Operators
• AMPL supports some logical operators
• Boolean variables (true/false)
• If-then
• If-then-else
How to Use if-then-else
• Suppose all variables, except one, have the same upper bound, and the other has an upper bound that is twice that of the rest
• A constraint like this will take care of all the the upper bounds:
subject to UB {i in SETNAME }:
variable[i] <= 10*(if i=1 then 2 else 1);
Set Operations
• Basic set operations:– Union: U = A union B– Intersection: U = A inter B– Cartesian Product: U = {A,B}
Advantage of Set Operations
• Suppose we have 3 sets of products,– CANDY – TOYS – GAMES
• In our model we may need to declare the following parameters for each: – Price– Supply– Demand
Naïve Setup
– Param Price_C {CANDY};
– Param Price_T {TOYS};
– Param Price_G {GAMES};
– Param Supply_C {CANDY};
– Param Supply_T {TOYS};
– Param Supply_G {GAMES};
– Param Demand_C {CANDY};
– Param Demand_T {TOYS};
– Param Demand_G {GAMES};
Using Set Operation Union
Param Price {CANDY union TOYS union GAMES};
Param Supply {CANDY union TOYS union GAMES};
Param Demand {CANDY union TOYS union GAMES};
Even Better…
Set PRODUCTS = CANDY union TOYS union GAMES;
Param Price {PRODUCTS};
Param Supply {PRODUCTS};
Param Demand {PRODUCTS};
Compound Sets
• Suppose you have a set called PRODUCTS of products to sell at a store
• Consider that instead of one store you have three stores in different parts of the country
• Each store has a different level of each paramater
One Solution
• Instead of using the set PRODUCTS, make three different sets: – PRODUCTS_1 – PRODUCTS_2– PRODUCTS_3
• Let each of the three numbers represent one of your store locations
One Solution (cont…)
• Next, define each parameter for each set of products:– Param Price {PRODUCTS_1};– Param Supply {PRODUCTS_1};– Param Demand {PRODUCTS_1};– Param Price {PRODUCTS_2};– Param Supply {PRODUCTS_2};– …
Easier Solution
For a better solution use compound sets:
– Param Price {PRODUCTS, STORES};– Param Supply {PRODUCTS, STORES};– Param Demand {PRODUCTS, STORES};
Structure of {PRODUCTS, STORES}
• Suppose – PRODUCTS := oreos jenga lazertag ;– STORES := 1 2 3 ;
• Then {PRODUCTS, STORES} is the set of all combinations of products with stores:
(oreos,1) (oreos,2) (oreos,3)(jenga,1) (jenga,2) (jenga,3)(lazertag,1) (lazertag,2) (lazertag,3)
Specifying Data
• In your .dat file, your declaration of Demand could look like this:
param Demand: 1 2 3 :=
oreos 10 20 30
jenga 30 33 42
lazertag 40 30 22 ;
Set Indexing
Indexing of Sets
• Indexing of a one dimensional set
sum {i in PRODUCTS} cost[i]*make[i];
• Indexing is similar in compound sets• One can say
sum { (i,j) in {PRODUCTS, STORES}} cost[i]*make[i,j];or
sum { i in PRODUCTS, j in STORES} cost[i]*make[i,j];
When do we need indexing?
• We may declare a parameter with or without giving index values:
param Demand { PRODUCTS, STORES };
or
param Demand { i in PRODUCTS, j in STORES };
With PRODUCTS and STORES:
“The sales at each store will not exceed the demand for any given product at that store.”
Could be expressed as the following constraint:
subject to DEMAND {(i,j) in {PRODUCTS, STORES}}: Demand [i,j] >= Sell [i,j];
With PRODUCTS and STORES:
• Suppose we have another parameter:
Param Capacity {STORES};
• Let the capacity of a store be the total number of items it can sell all together
With PRODUCTS and STORES:
“The total sales at any given store can not exceed the sales capacity of that store.”
Could be expressed as follows
Subject to CAPACITY {j in STORES}:
Sum {i in PRODUCTS} Sell [i, j] <= Capacity [j];
Advanced Syntax
Tips and Shortcuts
Transposition
How to Transpose
• Recall an earlier example:
Param Demand: 1 2 3 :=
oreos 10 20 30
jenga 30 33 42
lazertag 40 30 22 ;
How to Transpose
• Data in Transposed form
Param Demand (tr): oreos jenga lazertag :=
1 10 30 40
2 20 33 30
3 30 42 22 ;
Why Transpose
• Not Necessary, but can help with data management
• What if we had 30 stores?
Param Demand (tr): oreos jenga lazertag :=1 10 30 402 20 33 303 30 42 22 ;
Omitted Data
Omitted Data Entry
Example: Consider the following data
Param: Cost Supply Demand :=
oreos10 20 30
jenga30 33 42
lazertag 40 30 22 ;
Omitted Data Entry
Suppose in addition to the data specified in the previous table, you have an additional parameter such as:
Param Calories {FOOD};
This parameter would apply to oreos, but not to jenga or lazertag.
Example
Param: Cost Supply Demand :=
oreos10 20 30
jenga30 33 42
lazertag 40 30 22 ;
Param: Calories :=
oreos 100 ;
Example
Param: Cost Supply Demand Calories:=
oreos 10 20 30 100
jenga 30 33 42 .
lazertag 40 30 22 . ;
We can use “.” to represent omitted data
Where to get AMPL
• http://www.ampl.com– Link to the web interface– Download the student edition
• For Windows, it is an easy installation• For Mac OS, use unix install. You may need to
install additional components• Walkthrough available at:
– http://www.ce.berkeley.edu/~bayen/ce191www/labs/lab3/amplInstallingUsing.pdf