Ampl Tutorial

Embed Size (px)

Citation preview

  • 7/31/2019 Ampl Tutorial

    1/19

    An AMPL Tutorial

    CE 4920

    1 Introduction

    AMPL is a powerful modeling language for representing optimization problems, and interfacing with solverprograms for finding optimal solutions. AMPL itself is not a solver, but acts as a front-end for other programswhich do the actual solving, such as CPLEX, MINOS, or NITRO. These are commercial-grade programsused heavily in practice the good news is that AMPL takes care of each programs specific details, so youcan use any of these solvers without having to learn them separately. By default, the version of AMPL onthe course syllabus uses MINOS.

    These instructions are based on the Windows Visual Basic GUI version of AMPL, which can be downloadedfrom http://www.ampl.com/GUI/amplvb.zip. This is the version which is found in the lab computers. Ifyou are using another version, the interface may be different, but the instructions for writing models will bethe same.

    This tutorial should give you enough information to get started on the homework. If you want to learn moreabout AMPL, the absolute best resource is AMPL: A Modeling Language for Mathematical Programming,by Robert Fourer, David M. Gay, and Bruce W. Kernighan and published by Duxbury. Unfortunately itisnt free, but this is the official manual1.

    Many other free tutorials can be found online, depending on your skill with Google2. A few that Ive foundare

    http://www.ce.berkeley.edu/~bayen/ce191www/labs/lab3/ampl2.pdf http://holderfamily.dot5hosting.com/aholder/teach/courses/winter2008/OR/AMPLtutorial.

    pdf

    http://www.isye.gatech.edu/~jswann/teaching/AMPLTutorial.pdf

    A Google search is also a good bet if you are running into a specific problem with your model.

    2 A First Example

    Start AMPL by double-clicking the AmplWin icon (or finding it in the Start Menu). You should see a screensimilar to that in Figure 1. Notice the three windows in AMPL:

    The Command Interface is where you type commands for AMPL, and where the program will

    display any results. This window is located on the left.

    The Model Window is where you type your optimization program. You can also write your programusing another text editor (such as Notepad), save it with a .mod extension, and open it from AMPL.The model window is located at the top right.

    1UW doesnt have it in its libraries either, but you can obtain it from an interlibrary loan through Prospector.2Or, as I prefer to call it, Google-fu

    1

  • 7/31/2019 Ampl Tutorial

    2/19

    Figure 1: AMPL interface when first loaded.

    Table 1: Reservoir and stream information.Reservoir Stream

    Cost ($/1000 gal) 100 50Upper limit (1000 gal) 100

    Pollution (ppm) 50 250

    The Data Window is optional, and used if you have a long or complicated program. You have theoption of putting all of your data in this window, making the model cleaner and making it easier if youneed to change some of the input parameters. Usage of the data window will be discussed more nextweek.

    Lets go through a simple example, based on the water resources example from class on Monday. Recallthat the city needs 500,000 gallons of water per day, which can be drawn from either a reservoir or a stream.Characteristics of these two sources are found in Table 1. No more than 100,000 gallons per day can bedrawn from the stream, and the concentration of pollutants in the water served to the city cannot exceed100 ppm.

    2

  • 7/31/2019 Ampl Tutorial

    3/19

    In class, we showed that you could write this problem as

    minR,S

    100R + 50S

    s.t. R + S 500S 100

    50R + 250S

    R + S 100

    R, S 0where R and S were the amount of water drawn from the reservoir and stream, respectively, in thousandsof gallons per day.

    To represent this in AMPL, type the following into the model window:

    # Water source example from first lecture

    var Reservoir; # 1000s of gallons of water taken from the reservoir

    var Stream; # 1000s of gallons of water taken from the stream

    minimize cost: 100*Reservoir + 50*Stream;

    subject to water_demand: Reservoir + Stream >= 500;

    subject to stream_capacity: Stream = 0;

    The first line is a comment: whenever AMPL sees the pound sign (#), AMPL will ignore everything elsein that line, so you can use it to provide descriptions in plain English. Its good practice to use commentsfrequently, especially if you need to go back and look at an old problem, or if somebody else (such as theinstructor!) will have to read your model and make sense of it.

    The next two lines define the decision variables, Reservoir and Stream. Again, note the descriptive namesfor the variables: we could have just used R and S, but using the full name makes it easy to understand therest of the program. Comments are used at the end of the line to make it absolutely clear what is beingrepresented. (In this case, its important to remember that the units are in thousands of gallons.)

    One important thing: every line must end with a semicolon (;), except for comments. Those of you who arefamiliar with programming languages like C/C++ may recognize this rule. The reason is that AMPL letsyou split complicated equations across multiple lines, like this:

    subject to really_complicated_equation: (238x_1 + 385x_2 + sin(83x_3))^2

    + sqrt(log(x_4)) + x_5 / x_6

    + x_7 + x_8 + (x_1 + x_3 / sum{i in I} Area[i])

  • 7/31/2019 Ampl Tutorial

    4/19

    You also have the choice of giving AMPL a starting value for any of the variables, like this:

    var Reservoir := 50; # AMPL starts off by assuming 50,000 gallons from the reservoir.

    The colon before the equals sign is needed if you just type Reservoir = 50, AMPL interprets that to

    mean that Reservoir should always equal 50, not just at the start. For this example, a starting value isntneeded, but in more complicated problems you may need to give AMPL something in the right neighborhood.If AMPL is giving you strange solutions, or failing to solve your models altogether, try giving starting valuesfor some of your decision variables.

    Continuing with the example, the model file skips a line and then presents the objective function:

    minimize cost: 100*Reservoir + 50*Stream;

    You tell AMPL whether to minimize or maximize, give a label for the objective function, a colon (:), andthen give the mathematical expression. You have to use an asterisk (*) for multiplication (100Reservoirgives you an error), and again note the semicolon at the end of the line.

    The last part of the file shows the constraints, which all are of the form

    subject to pollution: (50*Reservoir + 250*Stream)/(Reservoir + Stream) = 0; # so they dont take up space in the constraints

    Note that the model is logically grouped according to the parts of an optimization problem: the decisionvariables are listed first, followed by the objective function, followed by the constraints.

    Now were ready to solve the model! Click on the Solve button (the fifth from the left, just below the menubar). The model you just typed will appear, in the command window, followed by something that looks like

    Presolve eliminates 3 constraints.Adjusted problem:

    2 variables, all nonlinear

    2 constraints; 4 linear nonzeros

    1 nonlinear constraints

    1 linear constraints

    1 linear objective; 2 nonzeros.

    4

  • 7/31/2019 Ampl Tutorial

    5/19

    Table 2: Selected mathematical functions in AMPL.Command Function

    abs(x) Returns |x|ceil(x) Rounds x up to the next largest integercos(x) Returns the cosine of x (x in radians)exp(x) Returns ex

    floor(x) Rounds x down to the next smallest integerlog(x) Natural logarithm of x

    x mod y The remainder when you divide x by ymax(x,y,z,...) Returns the largest of x,y,z,...min(x,y,z,...) Returns the smallest of x,y,z,...

    sin(x) Returns the sine of x (x in radians)sqrt(x) Returns

    x

    tan(x) Returns the sine of x (x in radians)

    MINOS 5.5: optimal solution found.

    1 iterations, objective 45000

    Nonlin evals: constrs = 5, Jac = 4.

    Most of these lines are details given by the solver MINOS, about how it actually solved the problem. The oneyou are most concerned with is the second from the bottom: objective 45000 tells you that the optimalsolution costs the city $45,000.

    But what about the decision variables? After all, what were really interested in is the values of Reservoirand Stream which give you that cost. The easiest way to do this is to double-click on the variable names inthe model window, and look at the command interface. Double-clicking on the words Reservoir and Streamtells you that R = 400, S = 100 is the best solution. Another way is to give AMPL a command directly, inthe text box at the very top of the command interface (labeled ampl:). Typing display Stream; will giveyou the value of Stream (dont forget the semicolon!), and typing display Reservoir, Stream; will giveyou both at once.

    3 Math functions

    For some of your models, you may need access to mathematical functions like logarithms, sine, cosine, andso forth. A partial listing of such functions is shown in Table 2

    More math functions can be found at http://archive.ite.journal.informs.org/Vol7No1/LeeRaffensperger/scite/amplhelp.html.

    4 Sets and the Data Window

    Entering everything into the model window is fine for small problems, like the above example, and likeProblem 4 on the first homework. However, lets say that the problem changed and a third water sourcebecame available (say, an aquifer under the city). If you knew the cost of obtaining water, the pollution,and the capacity, you could change the objective function and constraints accordingly. But what if there

    5

  • 7/31/2019 Ampl Tutorial

    6/19

    was a fourth, or a fifth? Eventually, it becomes very cumbersome to keep track of everything. To help withthis, AMPL lets you define sets to group similar items together, and gives you a data window so you canseparate the specific numbers from the structure of your model. This section describes how to use both.

    Lets use a transportation-based example to demonstrate. The state of Utah has $100 million to spend onroadway improvements this coming year, and they have to decide how much to spend on rural projects, and

    how much to spend on urban projects. So, let xrural and xurban represent the amount of money spent onthese two categories, in millions of dollars. The benefit from spending xrural on rural projects is

    Brural = 7000 log(1 + xrural)

    and the benefit from spending xurban on urban projects is

    Burban = 5000 log(1 + xurban)

    We want to maximize the net benefit to the state, that is, Brural + Burban xrural xurban.

    If we wanted, we could write this in the same style as before:

    var urban >= 0;

    var rural >= 0;

    maximize netBenefit: 7000log(1 + rural) + 5000log(1 + urban) - rural - urban;

    s.t. budgetLimit: rural + urban

  • 7/31/2019 Ampl Tutorial

    7/19

    var spending{i in LocationTypes} >= 0; #nonnegativity here

    maximize net_benefit: sum{i in LocationTypes} baseBenefit[i]*log(1 + spending[i])

    - sum{i in LocationTypes} spending[i];

    s.t. budgetLimit: sum{i in LocationTypes} spending[i] = 0;, including the nonnegativity constraint here

    to improve readability.

    To write the objective function, we can use summation notation using the set we have defined previously:sum{i in LocationTypes} baseBenefit[i]*log(1 + spending[i]) is exactly equivalent toiIB0i log(1+xi). Note that we refer to a particular baseBenefit or spending variable by using the index {[i]}, in squarebrackets.

    All well and good, but AMPL cant solve the model until we give it actual data. We havent even told ithow many different roadway categories there are! This is where the data window comes in handy. Type thefollowing into the data window (the bottom right window):

    # Example 2 - Data

    set LocationTypes := urban rural;

    param budget := 100; # millions of dollars

    param baseBenefit := urban 5000

    rural 7000;

    Notice that the set LocationTypes is defined a second time, except that here we actually say what theelements are, following a colon and equals sign. We give two elements: urban and rural. The next linegives the value of budget as 100 million dollars dont forget the colon before the equals sign. Finally,we define the base benefits. You give AMPL the label for each element, followed by the actual value, sobudget[urban] is 5000 and budget[rural] is 7000.

    Now we can solve the model. Click the Solve button, and AMPL will tell you that the optimal net benefitsare approximately 47,250. Double-clicking on spending gives you the entire vector of spending values:

    spending [*] :=

    rural 58.5

    urban 41.5;

    7

  • 7/31/2019 Ampl Tutorial

    8/19

    Table 3: Base benefits by facility type and year.Urban Suburban Rural

    Year 1 5000 6000 7000Year 2 3500 5000 6500Year 3 2000 4000 6000

    The use of sets saved you a lot of time if you had a lot of variables defined individually, you would have todouble click on each of them to see their optimal value. By defining a set, you can view all of them at once,and see that Utah should spend $58.5 million on rural roadways, and $41.5 million on urban ones.

    To see the flexibility that sets give you, lets say we wanted to add a third roadway category representingsuburban areas, with B0suburban = 6000. All we have to change are two lines in the data file, so it looks likethis:

    set LocationTypes := urban suburban rural;

    param budget := 100; # millions of dollars

    param baseBenefit := urban 5000suburban 6000

    rural 7000;

    Clicking Solve gives you the answer to your new problem: spend $39.1 million on rural roadways, $33.3million on suburban ones, and $27.6 on urban roadways. This increases the net benefits to approximately63,720.

    If we didnt use sets and the model window, we would have had to do a lot more typing and duplicationof effort (since the formula for benefits is still the same), and it would make the model appear much morecomplicated than it really is. A good principle of programming is to separate structure from data, which isexactly what AMPL accomplishes by including both a model window and a data window.

    5 Two-Dimensional Sets and Sets of Constraints

    When working with the spending allocation problem in the previous section, notice that its only concernedwith spending in the current year. What if we knew what the budget would be for the next three years(or at least an estimate)? In this case, we would have to decide how much to spend on each category ineach year. That is, the decision variables would be of the form xi,t, where i denotes the type of project(urban, suburban, rural), and t denotes the year in which the money is spent. Each year, the total amountof money spent cant exceed that years budget; lets say the budget is predicted to be $100 million in year1, $95 million in year 2, and $105 million in year 3. The benefits of spending xi,t million dollars is given byBi,t = B

    0i,t log(1 + xi,t) where B

    0i,t gives the base benefits for roadway type i in year t, given as in Table 3

    As before, our objective is to maximize the net benefits over the three years. We can write this optimization

    8

  • 7/31/2019 Ampl Tutorial

    9/19

    problem as

    minx

    iI

    3t=1

    B0i,t log(1 + xi,t) iI

    3t=1

    xi,t

    s.t.

    i

    I

    xi,t bt t {1, 2, 3}

    xi,t 0 t {1, 2, 3}, i I

    So, how does our AMPL program change? We need to account for several new things:

    x now has two dimensions: roadway class, and year when the money is spent B0 is now two-dimensional as well. We have a budget constraint for each of three three years, not just one.

    Heres the new AMPL source code; exactly how each of these changes were implemented is discussed below.

    The new model file is

    # Multiyear budget allocation model

    set LocationTypes;

    set Years;

    param budget{t in Years};

    param baseBenefit{i in LocationTypes, t in Years};

    var spending{i in LocationTypes, t in Years} >= 0;

    maximize net_benefit:sum{i in LocationTypes, t in Years}

    baseBenefit[i,t]*log(1 + spending[i,t])

    - sum{i in LocationTypes, t in Years}

    spending[i,t];

    s.t. budgetLimit{t in Years}:

    sum{i in LocationTypes} spending[i,t]

  • 7/31/2019 Ampl Tutorial

    10/19

    param baseBenefit: 1 2 3 :=

    urban 5000 3500 2000

    suburban 6000 5000 4000

    rural 7000 6500 6000;

    First, notice that we defined a second set Years, consisting of the elements 1, 2, and 3, to represent eachyear in our problem. We have to make the budget depend on the year, so we add the set notation {t inYears} after its declaration as a parameter.

    The first new syntax youll see is used to make baseBenefit and spending two-dimensional:

    param baseBenefit{i in LocationTypes, t in Years};

    var spending{i in LocationTypes, t in Years} >= 0;

    Since both of these depend on the location type and the year, both index sets are included in the curlybrackets, separated by a comma.

    The same notation is used to represent the double summation

    iI

    3t=1 B

    0i,t log(1 + xi,t) in the objective

    function: to sum over both indexes, we type sum{i in LocationTypes, t in Years} and refer to xi,t asspending[i,t] (note the square braces, with the two indices separated by a comma).

    A budget constraint exists for each year; but these constraints are very similar. So we can write themcompactly by using the label s.t. budgetLimit{t in Years}:. This notation creates a budget constraintfor every year, defined by the rest of the line: sum{i in LocationTypes} spending[i,t]

  • 7/31/2019 Ampl Tutorial

    11/19

    showing the spending breakdown for each roadway type and year. Notice that relatively little spendingoccurs on urban areas. This might cause political problems; lets say that your experience with Wyomingpolitics tells you that you need to spend at least a third of the money on urban areas over the three yearsin order to avoid nasty partisan bickering. In this case, we need to add a constraint saying that you spendat least $100 million on urban areas in the duration of the project. In AMPL we can include this by addingthe constraint

    s.t. urbanPolitics: sum{t in Years} spending[urban,t] >= 100;

    The important thing to notice here is that we put urban in single quotes. Why? t doesnt have to be inquotes, because its a variable which ranges over all possible years. urban, on the other hand, refers to aspecific element of spending. AMPL requires you to distinguish between these cases by enclosing specificlabels in single quotes. Re-solving the model, we get

    display spending;

    spending :=

    rural 1 33.9181

    rural 2 35.8767

    rural 3 44.5453

    suburban 1 28.9298suburban 2 27.3667

    suburban 3 29.3635

    urban 1 37.1521

    urban 2 31.7567

    urban 3 31.0912

    ;

    6 An Alternative Way to Define Sets

    Quite commonly the values in a set are all numeric in the previous example, the set Years simply consistedof the values 1, 2, and 3. Conceivably the number of years could be large, if we were doing a long-rangeplan, and it would certainly be tedious to list all of those. If we were allocating money to certain districtswhich were indexed numerically, again it could be very tedious (and typo-prone) to be forced to write outeach index. In such cases, AMPL provides a shortcut notation for defining sets of numbers: a..b representsthe set of all numbers between a and b inclusive. This notation is only accepted in the model window, notthe data window. At the end of this section, Ill show you a workaround so you can still use the compactnotation while keeping your code flexible and reusable.

    Consider the following infrastructure management problem. Your agency is responsible for maintaining fivebridges, and you need to plan how youll spend that money over the next ten years. The state of each bridgei in the t-th year is represented by a reliability score rti ranging from 0 to 100, where 100 represents like-newcondition and 0 means its going to fall down the next time a truck drives over it. Each year, the reliability

    score for every bridge drops by 5 to represent deterioration; any money you spend on that bridge in thatyear will increase its reliability score. For convenience, assume that money is measured in the same unitsas reliability score, so spending 1 unit of money will increase the reliability score on a bridge by 1. Agencypolicy is that no bridge should ever have a reliability score below 70, and the initial reliability scores for the5 bridges are 85, 75, 90, 95, and 100, respectively. How should you spend money to minimize total cost?

    Recall that the decision variables are anything you can control: in this case, you control the maintenance

    11

  • 7/31/2019 Ampl Tutorial

    12/19

    expenditure on each bridge in each year (call this xti), and in turn each bridges reliability score rti . The

    parameters are the quantities outside your control: the initial reliability score r1i for each bridge, and theamount of deterioration each year. Your objective is to minimize total cost, and your constraints are thedeterioration equation rt+1i = r

    ti 5 + xti and the maximum and minimum reliability scores (in addition to

    non-negativity of maintenance costs).

    We can write this mathematically as

    minx,r

    i=15

    10t=1

    xti

    s.t. rti = rt1i 5 + xti i {2, . . . , 5}, t {1, . . . , 10}

    70 rti 100 i {1, . . . , 5}, t {1, . . . , 10}xti 0 i {1, . . . , 5}, t {1, . . . , 10}

    or, in AMPL, we can use this model:

    set Bridges := 1..5;

    set Years := 1..10;

    param currentCondition{b in Bridges};

    param deteriorationRate;

    var maintenance{i in Bridges, t in Years} >= 0;

    var reliability{i in Bridges, t in Years};

    minimize totalCost: sum{i in Bridges, t in Years} maintenance[i,t];

    s.t. initialCondition{i in Bridges}:

    reliability[i,1] = currentCondition[i];

    s.t. deterioration{i in Bridges, t in 2..10}:

    reliability[i,t] = reliability[i,t-1] - deteriorationRate

    + maintenance[i,t];

    s.t. reliabilityLB{i in Bridges, t in Years}:

    reliability[i,t] >= 70;

    s.t. reliabilityUB{i in Bridges, t in Years}:

    reliability[i,t]

  • 7/31/2019 Ampl Tutorial

    13/19

    The sets are defined in the model window so that Bridges runs from 1 to 5, and Years runs from 1 to10.

    The reliability constraints were split into two: initialCondition forces the condition in year 1 toequal the initial value; and deterioration enforces the deterioration condition for all subsequentyears. Note that deterioration is only defined for years 2 to 10; year 1 is accounted for by the initialcondition.

    Solving this model, AMPL can tell you both the optimal maintenance schedule and the resulting reliabilityscores:

    display maintenance;

    maintenance [*,*] (tr)

    : 1 2 3 4 5 :=

    1 0 0 0 0 0

    2 0 0 0 0 0

    3 0 5 0 0 0

    4 0 5 0 0 0

    5 5 5 0 0 0

    6 5 5 5 0 0

    7 5 5 5 5 0

    8 5 5 5 5 5

    9 5 5 5 5 5

    10 5 5 5 5 5

    ;

    display reliability;

    reliability [*,*] (tr)

    : 1 2 3 4 5 :=

    1 85 75 90 95 100

    2 80 70 85 90 95

    3 75 70 80 85 904 70 70 75 80 85

    5 70 70 70 75 80

    6 70 70 70 70 75

    7 70 70 70 70 70

    8 70 70 70 70 70

    9 70 70 70 70 70

    10 70 70 70 70 70

    ;

    One thing might bother you if youre picky about reusable code: the fact that you typed out the number ofyears (10) in the model window, both when defining the set of years, and when defining the set of constraints.A way to get around that is to define a new parameter, such as numYears, so your code looks like this:

    # Model window

    param numYears;

    set Bridges := 1..5;

    set Years := 1..numYears;

    13

  • 7/31/2019 Ampl Tutorial

    14/19

    param currentCondition{b in Bridges};

    param deteriorationRate;

    var maintenance{i in Bridges, t in Years} >= 0;

    var reliability{i in Bridges, t in Years};

    minimize totalCost: sum{i in Bridges, t in Years} maintenance[i,t];

    s.t. initialCondition{i in Bridges}:

    reliability[i,1] = currentCondition[i];

    s.t. deterioration{i in Bridges, t in 2..numYears}:

    reliability[i,t] = reliability[i,t-1] - deteriorationRate

    + maintenance[i,t];

    s.t. reliabilityLB{i in Bridges, t in Years}:

    reliability[i,t] >= 70;

    s.t. reliabilityUB{i in Bridges, t in Years}:

    reliability[i,t]

  • 7/31/2019 Ampl Tutorial

    15/19

    option cplex_options sensitivity;

    Then, proceed to solve the model as usual. In addition to the previous functions, you now have access tothese commands:

    display .rc; displays the reduced cost of the decision variable . display .down; displays the lowest that the objective function coefficient of can be,

    for which the current basis is optimal.

    display .up; same as display .down, but gives the upper bound. display ; shows the marginal change in the objective function if the right-hand side

    of increases.

    display .down; displays the lowest that the right-hand side of can bebefore the optimal basis changes.

    display .up; same as display .down, but gives the upper bound.

    display .slack; shows the slack in .

    For example, with the infrastructure spending problem from Homework 33, we can see which years thebudget constraint is binding by typing display budget.slack;

    budget.slack [*] :=

    0 50

    1 0

    2 0

    3 7.55081

    4 29

    5 29

    6 35.1123

    7 40

    8 47.438

    9 50

    10 50

    ;

    In years 1 and 2, the budget constraint is tight (no slack left), whereas in the remaining years, the amountof unspent money can be seen. To find the range of budget values for which the current basic solution istopimal, type display budget.down, budget.up;

    : budget.down budget.up :=0 0 0

    1 43.7597 52.5361

    2 43.1356 67.4897

    3 42.4492 1e+20

    3AMPL code can be found in the solutions to this homework.

    15

  • 7/31/2019 Ampl Tutorial

    16/19

    4 21 1e+20

    5 21 1e+20

    6 14.8877 1e+20

    7 10 1e+20

    8 2.56198 1e+20

    9 0 1e+20

    10 0 1e+20;

    Notice how this relates to the slack in these constraints. For years 310, the entire budget isnt being spent;so no matter how large the budget is in these years, the optimal solution wont change. On the other hand, inyears 1 and 2, if the budget increases by a large enough amount ($2.5 million and $17.4 million, respectively),having this extra money available would fundamentally alter our spending plan. Likewise, looking at thelower bound, we see that no money at all is being spent in years 9 and 10; therefore, even if the budget iszero in these years, our optimal solution wont change. On the other hand, for the other years, if the budgetdecreases by a large enough amount, the optimal plan would change.

    8 Linear Programming and Network Optimization

    You may be wondering how to solve network problems (such as shortest path and minimum spanning tree)using software. One option is to write specialized code (or use an existing library). Another option is toformulate them as a linear program, and solve using AMPL. Consider the problem of finding the shortestpath from node 1 to node 4 in Figure 2 and Table 4 (reproduced from the network optimization notes).

    Remember that the first step in formulating an optimization problem is to specify the decision variables; inthis case, we need to find a certain path. Because each path consists of a set of arc, we might think to makea decision variable for each arc, indicating whether that arc is in our path or not. That is, xij = 1 if arc(i, j) is in the shortest path, and xij = 0 if not. The next step is to write the objective function. In this case,the cost of a path is simply the cost of its component arcs:

    (i,j)A:xij=1cij . However, notice that we can

    write this even more simply as

    (i,j)A xijcij .4 This should look familiar! Because the objective function islinear, we have hope that we can write a linear program to solve the shortest path problem.

    Thus, we hope that we can write linear constraints. The constraints indicate what is permissible for ourdecision variables xij . Clearly we have nonnegativity. Furthermore, for this problem, they must represent apath from node 1 to node 4. For one, this means that they have to be adjacent to each other. So, excludingthe origin and destination r and s, at every node i on the path we must have one arc entering this node,and one arc leaving this node. That is, xhi = 1 for some arc (h, i) A, and likewise xij = 1 for someother arc (i, j) A. Right now, it isnt clear how we can translate this into a constraint, but we summonmathematical courage and bravely push on. What if node i is not on the path? Then xhi and xij shouldequal zero for every arc (h, i) and (i, j). But again, it isnt clear how we say that this condition should holdonly for nodes not on the path. Is there anything common between the two?

    After some thinking, you might notice that both of these cases can be accounted for by requiring

    (h,i)A xhi =(i,j)A xij at every node (except the origin and destination). This can be thought of as flow conserva-

    tion: if the path enters the node (xhi = 1 for some (h, i)), it must leave as well (xij = 1 for some (i, j)).Likewise, if the path doesnt enter the node (xhi = 0 for all (h, i)) it cannot leave the node (xij = 0 for all

    4Because

    (i,j)A xijcij =

    (i,j)A:xij=1xijcij +

    (i,j)A:xij=0

    xijcij =

    (i,j)A:xij=11(cij) +

    (i,j)A:xij=0

    0(cij) =

    (i,j)A:xij=1cij

    16

  • 7/31/2019 Ampl Tutorial

    17/19

    (i, j)). Almost there! What about the origin and destination? It would be nice if we could write similarconstraints for these nodes, and indeed, we can. The path leaves the origin, but does not enter it; therefore

    (h,r)A xhr + 1 =

    (r,j)A xrj . Why does this work? The left-hand side is at least equal to one, so

    something on the right-hand hand side must equal one as well (something leaves). Furthermore, because theobjective is to minimize the total cost, the optimal solution will set xhr = 0 for all (h, r) A. Similarly, thepath enters the destination, but does not leave, so

    (h,s)Axhs = 1 +(s,j)A

    xsj. A concise way to write

    all of these constraints is

    (h,i)A

    xhi

    (i,j)A

    xij =

    1 i = r+1 i = s

    0 otherwise

    for every node i.

    One last trick before going to AMPL. As written, each of the summations is different for every node, becausedifferent arcs enter and leave. It would be more convenient if every node was directly connected to everyother node, because then the left-hand side of the constraints would be the same for every node. One wayto do this without disturbing the optimal solution is to create an arc between every pair of nodes with veryhigh cost (cij = M 0 if (i, j) / A). Then we can write the constraint as

    hN

    xhi jN

    xij = bi

    where bi =

    1 i = r+1 i = s

    0 otherwise

    . Thus, the linear program for the shortest path problem is

    minmathbfx

    (i,j)N2

    xijcij

    s.t.hN

    xhi jN

    xij = bi i N

    xij

    0

    (i, j)

    N2

    which can write using the following AMPL code:

    # Model

    param numNodes;

    set Nodes := 1..numNodes;

    param cost{i in Nodes, j in Nodes};

    param demand{i in Nodes};

    var flow{i in Nodes, j in Nodes} >= 0;

    minimize tripcost: sum{i in Nodes, j in Nodes} flow[i,j] * cost[i,j];

    s.t. conservation{i in Nodes}: sum{j in Nodes} flow[i,j] = demand[i] + sum{h in Nodes} flow[h,i]

    # Data

    17

  • 7/31/2019 Ampl Tutorial

    18/19

    Table 4: Costs for demonstration of shortest paths.Arc Cost

    (1,2) 2(1,3) 4(2,3) 1(2,4) 5(3,4) 2

    param numNodes = 4;

    param cost: 1 2 3 4 :=

    1 0 2 4 9999

    2 9999 0 1 5

    3 9999 9999 0 2

    4 9999 9999 9999 0;

    param demand :=

    1 1

    2 0

    3 0

    4 -1;

    Executing this code gives

    display flow;

    flow :=

    1 1 0

    1 2 1

    1 3 0

    1 4 02 1 0

    2 2 0

    2 3 1

    2 4 0

    3 1 0

    3 2 0

    3 3 0

    3 4 1

    4 1 0

    4 2 0

    4 3 0

    4 4 0

    ;

    indicating that the three arcs in the path are (1, 2), (2, 3), and (3, 4).

    18

  • 7/31/2019 Ampl Tutorial

    19/19

    Figure 2: Labeling of nodes and arcs.

    19