The CPM Procedure

Example 4.28 Use of the SETFINISHMILESTONE Option

A simple activity network is used to illustrate the use of the SETFINISHMILESTONE option in a couple of different scenarios.

The following DATA step reads the project network in AON format into a SAS data set named tasks. The data set (printed in Output 4.28.1) contains an Activity variable (act), a Successor variable (succ), a Lag variable (lag), and a Duration variable (dur). There are several milestones linked to other activities through different types of precedence constraints. The data set also contains some alignment constraints as specified by the variables target and trgttype. The treatment of the milestones will vary depending on the presence or absence of the alignment constraints. The data set also contains two variables that indicate the expected early schedule dates for the milestones corresponding to two different invocations of PROC CPM: the variable notrgtmd corresponds to the non-aligned schedule and the variable miledate corresponds to an invocation with the ALIGNDATE statement (the values for these variables are explained later).


data tasks;
   format act $7. succ $7. lag $4. target date7. 
          trgttype $3. miledate date7. notrgtmd date7. ;
   input act & succ & lag $ dur target & date7. 
         trgttype $ miledate & date7. notrgtmd & date7. ;
   datalines;
Task 0   Mile 1   ss_0 1 26Jan04  SGE .        .
Mile 1   Task 2   .    0  .       .   26Jan04  26Jan04
Task 2   .        .    1  .       .   .        .
Task 3   Mile 4   .    1  .       .   .        .
Mile 4   .        .    0  .       .   26Jan04  26Jan04
Task 5   Mile 6   .    1  .       .   .        .
Mile 6   Mile 7   FS_1 0  .       .   26Jan04  26Jan04
Mile 7   .        .    0  .       .   27Jan04  27Jan04
Task 8   Mile 9   SS_3 1  .       .   .        .
Mile 9   Mile 10  .    0  .       .   29Jan04  29Jan04
Mile 10  .        .    0  .       .   29Jan04  29Jan04
Task 11  Mile 12  .    2  .       .   .        .
Mile 12  Mile 13  FS_1 0 28Jan04  SGE 28Jan04  27Jan04
Mile 13  .        .    0  .       .   29Jan04  28Jan04
;

Output 4.28.1: Input Data Set

Schedule with option SETFINISHMILESTONE
Input Data Set

Obs act succ lag target trgttype miledate notrgtmd dur
1 Task 0 Mile 1 ss_0 26JAN04 SGE . . 1
2 Mile 1 Task 2   .   26JAN04 26JAN04 0
3 Task 2     .   . . 1
4 Task 3 Mile 4   .   . . 1
5 Mile 4     .   26JAN04 26JAN04 0
6 Task 5 Mile 6   .   . . 1
7 Mile 6 Mile 7 FS_1 .   26JAN04 26JAN04 0
8 Mile 7     .   27JAN04 27JAN04 0
9 Task 8 Mile 9 SS_3 .   . . 1
10 Mile 9 Mile 10   .   29JAN04 29JAN04 0
11 Mile 10     .   29JAN04 29JAN04 0
12 Task 11 Mile 12   .   . . 2
13 Mile 12 Mile 13 FS_1 28JAN04 SGE 28JAN04 27JAN04 0
14 Mile 13     .   29JAN04 28JAN04 0


Output 4.28.2: Default Schedule

Schedule with option SETFINISHMILESTONE
Default Schedule

O
b
s
a
c
t
s
u
c
c
d
u
r
l
a
g
n
o
t
r
g
t
m
d
E
_
S
T
A
R
T
E
_
F
I
N
I
S
H
L
_
S
T
A
R
T
L
_
F
I
N
I
S
H
T
_
F
L
O
A
T
F
_
F
L
O
A
T
1 Task 0 Mile 1 1 ss_0 . 26JAN04 26JAN04 28JAN04 28JAN04 2 0
2 Mile 1 Task 2 0   26JAN04 26JAN04 26JAN04 28JAN04 28JAN04 2 0
3 Task 2   1   . 26JAN04 26JAN04 28JAN04 28JAN04 2 2
4 Task 3 Mile 4 1   . 26JAN04 26JAN04 28JAN04 28JAN04 2 0
5 Mile 4   0   26JAN04 27JAN04 27JAN04 29JAN04 29JAN04 2 2
6 Task 5 Mile 6 1   . 26JAN04 26JAN04 27JAN04 27JAN04 1 0
7 Mile 6 Mile 7 0 FS_1 26JAN04 27JAN04 27JAN04 28JAN04 28JAN04 1 0
8 Mile 7   0   27JAN04 28JAN04 28JAN04 29JAN04 29JAN04 1 1
9 Task 8 Mile 9 1 SS_3 . 26JAN04 26JAN04 26JAN04 26JAN04 0 0
10 Mile 9 Mile 10 0   29JAN04 29JAN04 29JAN04 29JAN04 29JAN04 0 0
11 Mile 10   0   29JAN04 29JAN04 29JAN04 29JAN04 29JAN04 0 0
12 Task 11 Mile 12 2   . 26JAN04 27JAN04 26JAN04 27JAN04 0 0
13 Mile 12 Mile 13 0 FS_1 27JAN04 28JAN04 28JAN04 28JAN04 28JAN04 0 0
14 Mile 13   0   28JAN04 29JAN04 29JAN04 29JAN04 29JAN04 0 0


First, the CPM procedure is invoked with the default treatment of milestones. The resulting schedule is printed in Output 4.28.2. Note the dates for the milestones. Compare these dates with the values of the early finish dates of the immediate predecessors.

The default behavior of the CPM procedure defines the start times for milestones to be at the beginning of the day after the predecessor task (with a standard FS_0 relationship) ends. Thus, for example, the activity, 'Mile 4' has E_START=27JAN04 because its predecessor, 'Task 3', has E_FINISH=26JAN04. The interpretation for these dates are that the early finish corresponds to the end of the day, while the early start of the milestone 'Mile 4' corresponds to the beginning of the day. However, in some situations you may want the milestone to be scheduled at the same time as the end of the predecessor activity. In other words, you may wish the early start time of the milestone 'Mile 4' to be displayed as 26JAN04, with the interpretation that this time actually denotes the end of the day, rather than the beginning. See the section Finish Milestones for details about the treatment of milestones. In the current example, the variable notrgtmd contains the desired milestone schedule dates corresponding to this special treatment of milestones. To obtain these desired dates, you must use the SETFINISHMILESTONE option.

/* Schedule the project */
proc cpm data=tasks out=out0 
         collapse interval=day
         date='26jan04'd;
   activity act;
   successor succ /lag=(lag);
   duration dur;
   id lag notrgtmd;
   run;

title2 'Default Schedule';
proc print; run;

Next, the CPM procedure is invoked with the option SETFINISHMILESTONE and the resulting schedule is printed in Output 4.28.3. Not all milestones are defined to denote the end of the displayed date; such milestones are referred to as finish milestone. The variables EFINMILE and LFINMILE indicate if the milestone is a finish milestone or not, corresponding to the early or late schedule, respectively. For example, the milestone 'Mile 12' has E_FINISH = 27JAN04 and the value of EFINMILE is '1', indicating that the activity finishes at the end of the day on January 27, 2004. The milestone 'Mile 13' (with a finish-to-start lag of 1 day) finishes at the end of the day on January 28, 2004. In fact, as the late finish schedule indicates, the value of L_FINISH for 'Mile 13' (and the project finish time) is the end of the day on 28JAN04. Both the variables EFINMILE and LFINMILE have the same values for all the activities in this example.

proc cpm data=tasks out=out1 
         collapse interval=day
         date='26jan04'd
         setfinishmilestone;
   activity act;
   successor succ /lag=(lag);
   duration dur;
   id lag notrgtmd;
   run;


title 'Schedule with option SETFINISHMILESTONE';
title2 'No Target Dates';
proc print heading=v; 
  id act;
  var succ lag dur notrgtmd e_start e_finish 
      l_start l_finish efinmile lfinmile;
  run;

Output 4.28.3: Schedule with SETFINISHMILESTONE Option

Schedule with option SETFINISHMILESTONE
No Target Dates

a
c
t
s
u
c
c
l
a
g
d
u
r
n
o
t
r
g
t
m
d
E
_
S
T
A
R
T
E
_
F
I
N
I
S
H
L
_
S
T
A
R
T
L
_
F
I
N
I
S
H
E
F
I
N
M
I
L
E
L
F
I
N
M
I
L
E
Task 0 Mile 1 ss_0 1 . 26JAN04 26JAN04 28JAN04 28JAN04 . .
Mile 1 Task 2   0 26JAN04 26JAN04 26JAN04 28JAN04 28JAN04 . .
Task 2     1 . 26JAN04 26JAN04 28JAN04 28JAN04 . .
Task 3 Mile 4   1 . 26JAN04 26JAN04 28JAN04 28JAN04 . .
Mile 4     0 26JAN04 26JAN04 26JAN04 28JAN04 28JAN04 1 1
Task 5 Mile 6   1 . 26JAN04 26JAN04 27JAN04 27JAN04 . .
Mile 6 Mile 7 FS_1 0 26JAN04 26JAN04 26JAN04 27JAN04 27JAN04 1 1
Mile 7     0 27JAN04 27JAN04 27JAN04 28JAN04 28JAN04 1 1
Task 8 Mile 9 SS_3 1 . 26JAN04 26JAN04 26JAN04 26JAN04 . .
Mile 9 Mile 10   0 29JAN04 29JAN04 29JAN04 29JAN04 29JAN04 . .
Mile 10     0 29JAN04 29JAN04 29JAN04 29JAN04 29JAN04 . .
Task 11 Mile 12   2 . 26JAN04 27JAN04 26JAN04 27JAN04 . .
Mile 12 Mile 13 FS_1 0 27JAN04 27JAN04 27JAN04 27JAN04 27JAN04 1 1
Mile 13     0 28JAN04 28JAN04 28JAN04 28JAN04 28JAN04 1 1


The next invocation of CPM illustrates the effect of alignment constraints on the milestones. As explained in the section Finish Milestones, imposing an alignment constraint of type SGE on a milestone may change it from a finish milestone to a start milestone (default behavior) as far as the early schedule of the project is concerned. In the following program, the CPM procedure is invoked with the SETFINISHMILESTONE option and the ALIGNDATE and ALIGNTYPE statements. The resulting schedule is printed in Output 4.28.4. The early schedule of the milestones should now correspond to the values in the variable miledate. Note also that the activities 'Mile 12' and 'Mile 13' are no longer finish milestones, as indicated by missing values for the variable EFINMILE. The 'SGE' alignment constraint with a target date of 28JAN04 moves the milestone 'Mile 12' to the beginning of January 28, 2004, instead of the end of January 27, 2004.

proc cpm data=tasks out=out2 
         collapse
         interval=day
         date='26jan04'd
         setfinishmilestone;
   activity act;
   successor succ /lag=(lag);
   duration dur;
   aligndate target;
   aligntype trgttype;
   id target trgttype lag miledate;
   run;

title 'Schedule with option SETFINISHMILESTONE';
title2 'Target Dates change Early Schedule for some Milestones';
proc print heading=v; 
  id act;
  var succ lag target trgttype miledate e_start e_finish 
      l_start l_finish efinmile lfinmile;
  run;

Output 4.28.4: Effect of Alignment Constraints

Schedule with option SETFINISHMILESTONE
Target Dates change Early Schedule for some Milestones

a
c
t
s
u
c
c
l
a
g
t
a
r
g
e
t
t
r
g
t
t
y
p
e
m
i
l
e
d
a
t
e
E
_
S
T
A
R
T
E
_
F
I
N
I
S
H
L
_
S
T
A
R
T
L
_
F
I
N
I
S
H
E
F
I
N
M
I
L
E
L
F
I
N
M
I
L
E
Task 0 Mile 1 ss_0 26JAN04 SGE . 26JAN04 26JAN04 28JAN04 28JAN04 . .
Mile 1 Task 2   .   26JAN04 26JAN04 26JAN04 28JAN04 28JAN04 . .
Task 2     .   . 26JAN04 26JAN04 28JAN04 28JAN04 . .
Task 3 Mile 4   .   . 26JAN04 26JAN04 28JAN04 28JAN04 . .
Mile 4     .   26JAN04 26JAN04 26JAN04 28JAN04 28JAN04 1 1
Task 5 Mile 6   .   . 26JAN04 26JAN04 27JAN04 27JAN04 . .
Mile 6 Mile 7 FS_1 .   26JAN04 26JAN04 26JAN04 27JAN04 27JAN04 1 1
Mile 7     .   27JAN04 27JAN04 27JAN04 28JAN04 28JAN04 1 1
Task 8 Mile 9 SS_3 .   . 26JAN04 26JAN04 26JAN04 26JAN04 . .
Mile 9 Mile 10   .   29JAN04 29JAN04 29JAN04 29JAN04 29JAN04 . .
Mile 10     .   29JAN04 29JAN04 29JAN04 29JAN04 29JAN04 . .
Task 11 Mile 12   .   . 26JAN04 27JAN04 26JAN04 27JAN04 . .
Mile 12 Mile 13 FS_1 28JAN04 SGE 28JAN04 28JAN04 28JAN04 27JAN04 27JAN04 . 1
Mile 13     .   29JAN04 29JAN04 29JAN04 28JAN04 28JAN04 . 1


The interpretation of the start and finish times for a milestone depends on whether it is a start milestone or a finish milestone. By default, all milestones are start milestones and are assumed to be scheduled at the beginning of the date specified in the start or finish time variable. As such, PROC GANTT displays these milestones at the start of the corresponding days on the Gantt chart. However, if a milestone is a finish milestone then it may not be displayed correctly on the Gantt chart, depending on the scale of the display.

In this example, PROC GANTT is used to display the schedule produced in Output 4.28.4. Recall that the schedule is saved in the data set out2. First, PROC GANTT is invoked without any modifications to the schedule data set. The resulting Gantt chart is displayed in Output 4.28.5. The finish milestones (with values of EFINMILE = '1') are not plotted correctly. For example, 'Mile 6' is plotted at the beginning instead of the end of the schedule bar for the predecessor activity, 'Act 5'. To correct this problem, you can adjust the schedule variables for the finish milestones and plot the new values, as illustrated by the second invocation of PROC GANTT. The corrected Gantt chart is displayed in Output 4.28.6.

title h=1.5 'Schedule with option SETFINISHMILESTONE and ALIGNDATE';
title2 'Gantt Chart of Early Schedule without adjustment';
proc gantt data=out2(drop=l_:);
   chart / compress act=act succ=succ lag=lag
           scale=7 height=1.7
           cprec=cyan cmile=magenta
           caxis=black
           dur=dur nojobnum nolegend;
   id act succ lag e_start efinmile;
   run;

/* Save adjusted E_START and E_FINISH times for finish 
milestones */
data temp;
set out2;
format estart efinish date7.;
estart = e_start;
efinish = e_finish;
if efinmile then do;
   estart=estart+1;
   efinish=efinish+1;
   end;
run;


/* Plot the adjusted start and finish times for the 
   early schedule */
title h=1.5 'Schedule with option SETFINISHMILESTONE and ALIGNDATE';
title2 'Gantt Chart of Early Schedule after adjustment';
proc gantt data=temp(drop=l_:);
   chart / compress act=act succ=succ lag=lag 
           scale=7 height=1.7
           es=estart ef=efinish
           cprec=cyan cmile=magenta
           caxis=black
           dur=dur nojobnum  nolegend;
   id act succ lag e_start efinmile;
   run;

Output 4.28.5: Gantt Chart of Unadjusted Schedule

Gantt Chart of Unadjusted Schedule


Output 4.28.6: Gantt Chart of Adjusted Schedule

Gantt Chart of Adjusted Schedule