Modeling and solving a simple problem: house building
Presents a simple problem of scheduling the tasks to build a house in such a manner that minimizes an objective.
In this section, you will learn how to:
use the dvar interval;
use the constraint endBeforeStart;
use the expressions startOf and endOf.
You will learn how to model and solve a simple problem, a problem of scheduling the tasks involved in building a house in a way that minimizes an objective. Here the objective is the cost associated with performing specific tasks before a preferred earliest start date or after a preferred latest end date. Some tasks must necessarily take place before other tasks, and each task has a given duration. To find a solution to this problem using OPL, you will use the three-stage method: describe, model, and solve.
Describe
The problem consists of assigning start dates to tasks in such a way that the resulting schedule satisfies precedence constraints and minimizes a criterion. The criterion for this problem is to minimize the earliness costs associated with starting certain tasks earlier than a given date and tardiness costs associated with completing certain tasks later than a given date.
For each task in the house building project, the following table shows the duration (measured in days) of the task along with the tasks that must finish before the task can start.
| Task | Duration | Preceding tasks |
|---|---|---|
| masonry | 35 | |
| carpentry | 15 | masonry |
| plumbing | 40 | masonry |
| ceiling | 15 | masonry |
| roofing | 5 | carpentry |
| painting | 10 | ceiling |
| windows | 5 | roofing |
| facade | 10 | roofing, plumbing |
| garden | 5 | roofing, plumbing |
| moving | 5 | windows, facade, garden, painting |
The other information for the problem includes the earliness and tardiness costs associated with some tasks.
| Task | Preferred earliest start date | Cost per day for starting early |
|---|---|---|
| masonry | 25 | 200.0 |
| carpentry | 75 | 300.0 |
| ceiling | 75 | 100.0 |
| Task | Preferred latest end date | Cost per day for ending late |
|---|---|---|
| moving | 100 | 400.0 |
Solving the problem consists of identifying starting dates for the tasks such that the cost, determined by the earliness and lateness costs, is minimized.
In OPL, the unit of time represented by an interval variable is not defined. As a result, the size of the masonry task in this problem could be 35 hours or 35 weeks or 35 months.
Step 1: Describe the problem
The first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.
Write a natural language description of this problem. Answer these questions:
What is the known information in this problem?
What are the decision variables or unknowns in this problem?
What are the constraints on these variables?
What is the objective?
Discussion
What is the known information in this problem?
There are ten house building tasks, each with a given duration. For each task, there is a list of tasks that must be completed before the task can start. Some tasks also have costs associated with an early start date or late end date.
What are the decision variables or unknowns in this problem?
The unknowns are the date that each task will start. The cost is determined by the assigned start dates.
What are the constraints on these variables?
In this case, each constraint specifies that a particular task may not begin until one or more given tasks have been completed.
What is the objective?
The objective is to minimize the cost incurred through earliness and tardiness costs.
Model
After you have written a description of your problem, you can use OPL to model and solve it.
Step 2: Open the example file
Still working with the scheduling_tutorial project, open the sched_time.mod file in the IDE editing area.
This file is an OPL model that is only partially completed. You will add the missing code in each step of this lesson. At the end, you will have completed the OPL model. IBM ILOG OPL gives you the means to represent the unknowns in this problem, the interval in which each task will occur, as interval variables.
Interval variable
Tasks are represented by the decision variable type interval in OPL.
An interval has a start, an end, a size and a length. An interval variable allows these values to be variable in the model.
The length of a present interval variable is equal to the difference between its end time and its start time. The size is the actual amount of time the task takes to process. By default, the size is equal to the length, which is the difference between the end and the start of the interval. In general, the size is a lower bound on the length.
An interval variable may be optional. Whether an interval is present in the solution or not is represented by a decision variable. If an interval is not present in the solution, this means that any constraint on this interval acts like the interval is “not there.” Exact semantics will depend on the specific constraint.
Logical relations can be expressed between the presence statuses of interval variables, allowing, for instance, to state that whenever the interval variable a is present then the interval variable b must also be present.
In your model, you first declare the interval variables, one for each task. Each variable represents the unknown information, the scheduled interval for each activity. After the model is executed, the values assigned to these interval variables will represent the solution to the problem.
For example, to create an interval with size 35 in OPL:
dvar interval masonry size 35;Step 3: Declare the interval variables
Add the following code after the comment //Declare the interval variables:
dvar interval masonry size 35;
dvar interval carpentry size 15;
dvar interval plumbing size 40;
dvar interval ceiling size 15;
dvar interval roofing size 5;
dvar interval painting size 10;
dvar interval windows size 5;
dvar interval facade size 10;
dvar interval garden size 5;
dvar interval moving size 5;
In this example, certain tasks can start only after other tasks have been completed. IBM ILOG OPL allows you to express constraints involving temporal relationships between pairs of interval variables using precedence constraints.
Precedence constraints
Precedence constraints are used to specify when one interval variable must start or end with respect to the start or end time of another interval. The following types of precedence constraints are available; if a and b denote interval variables, both interval variables are present, and delay is a number or integer expression (0 by default), then:
endBeforeEnd(a, b, delay) constrains at least the given delay to elapse between the end of
aand the end ofb. It imposes the inequality endTime(a) + delay <= endTime(b).endBeforeStart(a, b, delay) constrains at least the given delay to elapse between the end of
aand the start ofb. It imposes the inequality endTime(a) + delay <= startTime(b).endAtEnd(a, b, delay) constrains the given delay to separate the end of
aand the end ofab. It imposes the equality endTime(a) + delay == endTime(b).endAtStart(a, b, delay) constrains the given delay to separate the end of
aand the start ofb. It imposes the equality endTime(a) + delay == startTime(b).startBeforeEnd(a, b, delay) constrains at least the given delay to elapse between the start of
aand the end ofb. It imposes the inequality startTime(a) + delay <= endTime(b).startBeforeStart(a, b, delay) constrains at least the given delay to elapse between the start of
act1and the start ofact2. It imposes the inequality startTime(a) + delay <= startTime(b).startAtEnd(a, b, delay) constrains the given delay to separate the start of
aand the end ofb. It imposes the equality startTime(a) + delay == endTime(b).startAtStart(a, b, delay) constrains the given delay to separate the start of
aand the start ofb. It imposes the equality startTime(a) + delay == startTime(b).
If either interval a or b is not present in the solution, the constraint is automatically satisfied, and it is as if the constraint was never imposed.
Step 4: Add the precedence constraints
Add the following code after the comment //Add the precedence constraints:
endBeforeStart(masonry, carpentry);
endBeforeStart(masonry, plumbing);
endBeforeStart(masonry, ceiling);
endBeforeStart(carpentry, roofing);
endBeforeStart(ceiling, painting);
endBeforeStart(roofing, windows);
endBeforeStart(roofing, facade);
endBeforeStart(plumbing, facade);
endBeforeStart(roofing, garden);
endBeforeStart(plumbing, garden);
endBeforeStart(windows, moving);
endBeforeStart(facade, moving);
endBeforeStart(garden, moving);
endBeforeStart(painting, moving);
To model the cost for starting a task earlier than the preferred starting date, you use the expression startOf that represents the start time of an interval variable as an integer expression.
For each task that has an earliest preferred start date, you determine how many days before the preferred date it is scheduled to start using the expression startOf; this expression can be negative if the task starts after the preferred date. By taking the maximum of this value and 0 using maxl, you determine how many days early the task is scheduled to start. Weighting this value with the cost per day of starting early, you determine the cost associated with the task.
The cost for ending a task later than the preferred date is modeled in a similar manner using the expression endOf. The earliness and lateness costs can be summed to determine the total cost.
Step 5: Add the objective
Add the following code after the comment //Add the objective:
minimize 400 * maxl(endOf(moving) - 100, 0) +
200 * maxl(25 - startOf(masonry), 0) +
300 * maxl(75 - startOf(carpentry), 0) +
100 * maxl(75 - startOf(ceiling), 0);
Solve
Solving a problem consists of finding a value for each decision variable so that all constraints are satisfied. You may not always know beforehand whether there is a solution that satisfies all the constraints of the problem. In some cases, there may be no solution. In other cases, there may be many solutions to a problem.
Step 6: Execute and display the solution
After a solution has been found, you can use the start and end properties of the interval variables to access the assigned intervals. The code for displaying the solution has been provided for you:
execute {
writeln("Masonry : " + masonry.start + ".." + masonry.end);
writeln("Carpentry: " + carpentry.start + ".." + carpentry.end);
writeln("Plumbing : " + plumbing.start + ".." + plumbing.end);
writeln("Ceiling : " + ceiling.start + ".." + ceiling.end);
writeln("Roofing : " + roofing.start + ".." + roofing.end);
writeln("Painting : " + painting.start + ".." + painting.end);
writeln("Windows : " + windows.start + ".." + windows.end);
writeln("Facade : " + facade.start + ".." + facade.end);
writeln("Garden : " + garden.start + ".." + garden.end);
writeln("Moving : " + moving.start + ".." + moving.end);
}
Step 7: Run the model
Run the model. You should get the following results:
OBJECTIVE: 5000
Masonry : 20..55
Carpentry: 75..90
Plumbing : 55..95
Ceiling : 75..90
Roofing : 90..95
Painting : 90..100
Windows : 95..100
Facade : 95..105
Garden : 95..100
Moving : 105..110
As you can see, the overall cost is 5000 and moving will be completed by day 110.
You can also view the complete program online in the <Install_dir>/opl/examples/opl/sched_time/sched_time.mod file.