criticalpath - R Package Implementation of Critical Path Method

Rubens Jose Rosa, Marcos dos Santos, Thiago Marques

2022-01-10

library(criticalpath)

criticalpath package is an R implementation of the Critical Path Method (CPM). CPM is a method used to estimate the minimum project duration and determine the amount of scheduling flexibility on the logical network paths within the schedule model. The flexibility is in terms of early start, early finish, late start, late finish, total float and free float. Beside, it permits to quantify the complexity of network diagram through the analysis of topological indicators. Finally, it permits to change the activities duration to perform what-if scenario analysis.

With this package, you can calculate the following CPM parameters:

The aim of this package is to apply critical path method, for project managers and researchers to make experiments with CPM parameters.

1 How to create a schedule

To create a schedule, you need to add activities and their relations in it. Optionally, you may define a title and a reference. You have the following alternatives to create a schedule:

  1. Create a schedule with activities and relations.
  2. Create a schedule, add activities and relations to it.
  3. Create a schedule and add activities at the same time that add relations to it.
  4. Create a schedule and add activities to it.

Lets see example from each one.

1.1 Create a schedule with activities and relations

Make a schedule with activities and relations between activities. For this, you have the following steps:

  1. create an empty schedule:
    • sch_new()
  2. define the title of the schedule:
    • sch_title()
  3. define the reference of the schedule:
    • sch_reference()
  4. add activities to the schedule:
    • sch_add_activities()
  5. add relations to the schedule:
    • sch_add_relations()
  6. plan the schedule
    • sch_plan()

Attention: The sch_plan() function is crucial: it responsible to apply the Critical Path Method (CPM).

Example:

sch <- sch_new() %>% 
  sch_title("Project 1: Cost Information System") %>% 
  sch_reference("VANHOUCKE, Mario.
    Integrated project management and control:
    first comes the theory, then the practice.
    Gent: Springer, 2014, p. 6") %>% 
  sch_add_activities(
    id        = 1:17,
    name      = paste("a", as.character(1:17), sep=""),
    duration  = c(1L,2L,2L,4L,3L,3L,3L,2L,1L,1L,2L,1L,1L,1L,1L,2L,1L)
  ) %>% 
  sch_add_relations(
  from = c(1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L,  3L,  4L,  5L,  6L,
           7L,  8L,  9L, 10L, 11L, 11L, 12L, 12L, 13L, 13L, 14L, 14L, 15L, 15L),
  to   = c(2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 11L, 11L,
           12L, 13L, 14L, 15L, 16L, 17L, 16L, 17L, 16L, 17L, 16L, 17L, 16L, 17L)
  ) %>% 
  sch_plan()

sch_duration(sch)
#> [1] 11
sch_activities(sch)
#> # A tibble: 17 x 14
#>       id name  duration milestone critical early_start early_finish late_start
#>    <int> <chr>    <int> <lgl>     <lgl>          <int>        <int>      <int>
#>  1     1 a1           1 FALSE     TRUE               0            1          0
#>  2     2 a2           2 FALSE     TRUE               1            3          1
#>  3     3 a3           2 FALSE     FALSE              1            3          3
#>  4     4 a4           4 FALSE     TRUE               3            7          3
#>  5     5 a5           3 FALSE     FALSE              3            6          4
#>  6     6 a6           3 FALSE     FALSE              3            6          4
#>  7     7 a7           3 FALSE     FALSE              3            6          5
#>  8     8 a8           2 FALSE     FALSE              3            5          6
#>  9     9 a9           1 FALSE     FALSE              3            4          7
#> 10    10 a10          1 FALSE     FALSE              3            4          7
#> 11    11 a11          2 FALSE     TRUE               7            9          7
#> 12    12 a12          1 FALSE     FALSE              6            7          8
#> 13    13 a13          1 FALSE     FALSE              5            6          8
#> 14    14 a14          1 FALSE     FALSE              4            5          8
#> 15    15 a15          1 FALSE     FALSE              4            5          8
#> 16    16 a16          2 FALSE     TRUE               9           11          9
#> 17    17 a17          1 FALSE     FALSE              9           10         10
#> # ... with 6 more variables: late_finish <int>, total_float <int>,
#> #   free_float <int>, progr_level <int>, regr_level <int>, topo_float <int>
sch_relations(sch)
#> # A tibble: 26 x 8
#>     from    to type    lag critical   ord i_from  i_to
#>    <int> <int> <chr> <int> <lgl>    <int>  <int> <int>
#>  1     1     2 FS        0 TRUE         1      1     2
#>  2     1     3 FS        0 FALSE        2      1     3
#>  3     2     4 FS        0 TRUE         3      2     4
#>  4     2     5 FS        0 FALSE        4      2     5
#>  5     2     6 FS        0 FALSE        5      2     6
#>  6     3     7 FS        0 FALSE        6      3     7
#>  7     3     8 FS        0 FALSE        7      3     8
#>  8     3     9 FS        0 FALSE        8      3     9
#>  9     3    10 FS        0 FALSE        9      3    10
#> 10     4    11 FS        0 TRUE        10      4    11
#> # ... with 16 more rows

1.2 Create a schedule, add activities and relations to it

Create a schedule and add each activity to it, one by one. Also, add each relation to it, one by one, too. Steps:

  1. create an empty schedule:
    • sch_new()
  2. define the title of the schedule:
    • sch_title()
  3. define the reference of the schedule:
    • sch_reference()
  4. add each activity to the schedule:
    • sch_add_activity()
  5. add each relation to the schedule:
    • sch_add_relation()
  6. plan the schedule
    • sch_plan()

Attention: The sch_plan() function is crucial: it responsible to apply the Critical Path Method (CPM).

Example:

sch <- sch_new() %>% 
  sch_title("Project 3: Old Carriage House Renovation") %>% 
  sch_reference(
  "VANHOUCKE, Mario. Integrated project management and control:
  first comes the theory, then the practice. Gent: Springer, 2014, p. 11") %>% 
  sch_add_activity( 1L, "a1" , 2L) %>% 
  sch_add_activity( 2L, "a2" , 2L) %>% 
  sch_add_activity( 3L, "a3" , 4L) %>% 
  sch_add_activity( 4L, "a4" , 3L) %>% 
  sch_add_activity( 5L, "a5" , 4L) %>% 
  sch_add_activity( 6L, "a6" , 1L) %>% 
  sch_add_activity( 7L, "a7" , 1L) %>% 
  sch_add_activity( 8L, "a8" , 1L) %>% 
  sch_add_activity( 9L, "a9" , 1L) %>% 
  sch_add_activity(10L, "a10", 1L) %>% 
  sch_add_activity(11L, "a11", 3L) %>% 
  sch_add_activity(12L, "a12", 2L) %>% 
  sch_add_activity(13L, "a13", 1L) %>% 
  sch_add_activity(14L, "a14", 1L) %>% 
  sch_add_activity(15L, "a15", 2L) %>% 
  sch_add_activity(16L, "a16", 1L) %>% 
  sch_add_activity(17L, "a17", 1L) %>% 
  sch_add_relation( 1L,  2L) %>% 
  sch_add_relation( 2L,  3L) %>% 
  sch_add_relation( 3L,  4L) %>% 
  sch_add_relation( 4L,  5L) %>% 
  sch_add_relation( 5L,  6L) %>% 
  sch_add_relation( 6L,  7L) %>% 
  sch_add_relation( 6L,  8L) %>% 
  sch_add_relation( 6L,  9L) %>% 
  sch_add_relation( 7L, 10L) %>% 
  sch_add_relation( 8L, 10L) %>% 
  sch_add_relation( 9L, 10L) %>% 
  sch_add_relation(10L, 11L) %>% 
  sch_add_relation(10L, 13L) %>% 
  sch_add_relation(11L, 12L) %>% 
  sch_add_relation(12L, 15L) %>% 
  sch_add_relation(13L, 14L) %>% 
  sch_add_relation(14L, 15L) %>% 
  sch_add_relation(15L, 16L) %>% 
  sch_add_relation(16L, 17L) %>% 
  sch_plan()

sch_duration(sch)
#> [1] 27
sch_activities(sch)
#> # A tibble: 17 x 14
#>       id name  duration milestone critical early_start early_finish late_start
#>    <int> <chr>    <int> <lgl>     <lgl>          <int>        <int>      <int>
#>  1     1 a1           2 FALSE     TRUE               0            2          0
#>  2     2 a2           2 FALSE     TRUE               2            4          2
#>  3     3 a3           4 FALSE     TRUE               4            8          4
#>  4     4 a4           3 FALSE     TRUE               8           11          8
#>  5     5 a5           4 FALSE     TRUE              11           15         11
#>  6     6 a6           1 FALSE     TRUE              15           16         15
#>  7     7 a7           1 FALSE     TRUE              16           17         16
#>  8     8 a8           1 FALSE     TRUE              16           17         16
#>  9     9 a9           1 FALSE     TRUE              16           17         16
#> 10    10 a10          1 FALSE     TRUE              17           18         17
#> 11    11 a11          3 FALSE     TRUE              18           21         18
#> 12    12 a12          2 FALSE     TRUE              21           23         21
#> 13    13 a13          1 FALSE     FALSE             18           19         21
#> 14    14 a14          1 FALSE     FALSE             19           20         22
#> 15    15 a15          2 FALSE     TRUE              23           25         23
#> 16    16 a16          1 FALSE     TRUE              25           26         25
#> 17    17 a17          1 FALSE     TRUE              26           27         26
#> # ... with 6 more variables: late_finish <int>, total_float <int>,
#> #   free_float <int>, progr_level <int>, regr_level <int>, topo_float <int>
sch_relations(sch)
#> # A tibble: 19 x 8
#>     from    to type    lag critical   ord i_from  i_to
#>    <int> <int> <chr> <int> <lgl>    <int>  <int> <int>
#>  1     1     2 FS        0 TRUE         1      1     2
#>  2     2     3 FS        0 TRUE         2      2     3
#>  3     3     4 FS        0 TRUE         3      3     4
#>  4     4     5 FS        0 TRUE         4      4     5
#>  5     5     6 FS        0 TRUE         5      5     6
#>  6     6     7 FS        0 TRUE         6      6     7
#>  7     6     8 FS        0 TRUE         7      6     8
#>  8     6     9 FS        0 TRUE         8      6     9
#>  9     7    10 FS        0 TRUE         9      7    10
#> 10     8    10 FS        0 TRUE        10      8    10
#> 11     9    10 FS        0 TRUE        11      9    10
#> 12    10    11 FS        0 TRUE        12     10    11
#> 13    10    13 FS        0 FALSE       13     10    13
#> 14    11    12 FS        0 TRUE        14     11    12
#> 15    13    14 FS        0 FALSE       16     13    14
#> 16    12    15 FS        0 TRUE        15     12    15
#> 17    14    15 FS        0 FALSE       17     14    15
#> 18    15    16 FS        0 TRUE        18     15    16
#> 19    16    17 FS        0 TRUE        19     16    17

1.3 Create a schedule and add activities at the same time that add relations to it

Add an activity to a schedule in the same time that adds relations. The steps are:

  1. create an empty schedule:
    • sch_new()
  2. define the title of the schedule:
    • sch_title()
  3. define the reference of the schedule:
    • sch_reference()
  4. add each activity to the schedule and, in the same time, the activity’s relation:
    • sch_add_activity()
  5. plan the schedule
    • sch_plan()

Attention: The sch_plan() function is crucial: it responsible to apply the Critical Path Method (CPM).

Example:

# Create a schedule
sch <- sch_new() %>% 
  sch_title("Fictitious Project Example") %>% 
  sch_reference("VANHOUCKE, Mario. Measuring time:
  improving project performance using earned value management.
  Gent: Springer, 2009, p. 18") %>% 
  sch_add_activity( 1L, "a1" , 0L,  2L,3L,4L) %>% 
  sch_add_activity( 2L, "a2" , 4L,  5L) %>% 
  sch_add_activity( 3L, "a3" , 9L, 10L) %>% 
  sch_add_activity( 4L, "a4" , 1L,  6L) %>% 
  sch_add_activity( 5L, "a5" , 4L,  9L) %>% 
  sch_add_activity( 6L, "a6" , 5L,  7L) %>% 
  sch_add_activity( 7L, "a7" , 1L,  8L,11L) %>% 
  sch_add_activity( 8L, "a8" , 7L, 12L) %>% 
  sch_add_activity( 9L, "a9" , 8L, 12L) %>% 
  sch_add_activity(10L, "a10", 3L, 12L) %>% 
  sch_add_activity(11L, "a11", 3L, 12L) %>% 
  sch_add_activity(12L, "a12", 0L) %>% 
  sch_plan()

sch_duration(sch)
#> [1] 16
sch_activities(sch)
#> # A tibble: 12 x 14
#>       id name  duration milestone critical early_start early_finish late_start
#>    <int> <chr>    <int> <lgl>     <lgl>          <int>        <int>      <int>
#>  1     1 a1           0 TRUE      TRUE               0            0          0
#>  2     2 a2           4 FALSE     TRUE               0            4          0
#>  3     3 a3           9 FALSE     FALSE              0            9          4
#>  4     4 a4           1 FALSE     FALSE              0            1          2
#>  5     5 a5           4 FALSE     TRUE               4            8          4
#>  6     6 a6           5 FALSE     FALSE              1            6          3
#>  7     7 a7           1 FALSE     FALSE              6            7          8
#>  8     8 a8           7 FALSE     FALSE              7           14          9
#>  9     9 a9           8 FALSE     TRUE               8           16          8
#> 10    10 a10          3 FALSE     FALSE              9           12         13
#> 11    11 a11          3 FALSE     FALSE              7           10         13
#> 12    12 a12          0 TRUE      TRUE              16           16         16
#> # ... with 6 more variables: late_finish <int>, total_float <int>,
#> #   free_float <int>, progr_level <int>, regr_level <int>, topo_float <int>
sch_relations(sch)
#> # A tibble: 14 x 8
#>     from    to type    lag critical   ord i_from  i_to
#>    <int> <int> <chr> <int> <lgl>    <int>  <int> <int>
#>  1     1     2 FS        0 TRUE         1      1     2
#>  2     1     3 FS        0 FALSE        2      1     3
#>  3     1     4 FS        0 FALSE        3      1     4
#>  4     2     5 FS        0 TRUE         4      2     5
#>  5     3    10 FS        0 FALSE        5      3    10
#>  6     4     6 FS        0 FALSE        6      4     6
#>  7     5     9 FS        0 TRUE         7      5     9
#>  8    10    12 FS        0 FALSE       13     10    12
#>  9     6     7 FS        0 FALSE        8      6     7
#> 10     9    12 FS        0 TRUE        12      9    12
#> 11     7     8 FS        0 FALSE        9      7     8
#> 12     7    11 FS        0 FALSE       10      7    11
#> 13     8    12 FS        0 FALSE       11      8    12
#> 14    11    12 FS        0 FALSE       14     11    12

1.4 Create a schedule and add activities to it

Creates a schedule only with activities. The steps are:

  1. create an empty schedule:
    • sch_new()
  2. define the title of the schedule:
    • sch_title()
  3. define the reference of the schedule:
    • sch_reference()
  4. add each activity to the schedule :
    • sch_add_activity()
  5. plan the schedule
    • sch_plan()

Attention: The sch_plan() function is crucial: it responsible to apply the Critical Path Method (CPM).

Example:

# Activities added one by one
sch <- sch_new() %>% 
  sch_add_activity(1L, "Task 1", 5L) %>% 
  sch_add_activity(2L, "Task 2", 6L) %>% 
  sch_add_activity(3L, "Task 3", 8L) %>% 
  sch_add_activity(4L, "Task 4", 6L) %>% 
  sch_add_activity(5L, "Task 5", 9L) %>% 
  sch_add_activity(6L, "Task 6", 3L) %>% 
  sch_add_activity(7L, "Task 7", 4L) %>% 
  sch_plan()
sch_duration(sch)
#> [1] 9
sch_activities(sch)
#> # A tibble: 7 x 14
#>      id name   duration milestone critical early_start early_finish late_start
#>   <int> <chr>     <int> <lgl>     <lgl>          <int>        <int>      <int>
#> 1     1 Task 1        5 FALSE     FALSE              0            5          4
#> 2     2 Task 2        6 FALSE     FALSE              0            6          3
#> 3     3 Task 3        8 FALSE     FALSE              0            8          1
#> 4     4 Task 4        6 FALSE     FALSE              0            6          3
#> 5     5 Task 5        9 FALSE     TRUE               0            9          0
#> 6     6 Task 6        3 FALSE     FALSE              0            3          6
#> 7     7 Task 7        4 FALSE     FALSE              0            4          5
#> # ... with 6 more variables: late_finish <int>, total_float <int>,
#> #   free_float <int>, progr_level <int>, regr_level <int>, topo_float <int>

1.5 Observations

2 How to get schedule information

After schedule creation, it is possible access several type of information, such as Title, Reference and Schedule Duration.

2.1 Title

A project title for identification. It depends on user of the class. Its use are:

2.2 Reference

A reference from project origin, for example, a book, a paper, a corporation, or nothing.

2.3 Duration

An integer value that indicate the project duration calculated by CPM, that is made by sch_plan(sch) function. You can only read the schedule duration.

2.4 Example

# Create a schedule
sch <- sch_new() %>% 
  sch_title("Fictitious Project Example") %>% 
  sch_reference("VANHOUCKE, Mario. Measuring time:
    improving project performance using earned value management.
    Gent: Springer, 2009, p. 18") %>% 
# Add activities and relations to it.
  sch_add_activity(  1L, "a1" , 0L,  2L,3L,4L) %>% 
  sch_add_activity(  2L, "a2" , 4L,  5L) %>% 
  sch_add_activity(  3L, "a3" , 9L,  10L) %>% 
  sch_add_activity(  4L, "a4" , 1L,  6L) %>% 
  sch_add_activity(  5L, "a5" , 4L,  9L) %>% 
  sch_add_activity(  6L, "a6" , 5L,  7L) %>% 
  sch_add_activity(  7L, "a7" , 1L,  8L,11L) %>% 
  sch_add_activity(  8L, "a8" , 7L, 12L) %>% 
  sch_add_activity(  9L, "a9" , 8L, 12L) %>% 
  sch_add_activity( 10L, "a10", 3L, 12L) %>% 
  sch_add_activity( 11L, "a11", 3L, 12L) %>% 
  sch_add_activity( 12L, "a12", 0L) %>% 
  sch_plan()
sch_title(sch)
#> [1] "Fictitious Project Example"
sch_reference(sch) %>% cat()
#> VANHOUCKE, Mario. Measuring time:
#>     improving project performance using earned value management.
#>     Gent: Springer, 2009, p. 18
sch_duration(sch)
#> [1] 16

3 How to get activities properties

There several methods about activities that you can use to get information about them. After you add activities to a schedule, you may want to know how much activities has in a schedule or when each activity is planned to start or to finish. In this section, we will explain how you can find these information.

3.1 Has Any Activity

A logical value that indicate if the schedule has any activity. A TRUE value means that the schedule has some activity; a FALSE, means that the schedule is empty.

3.2 Number of Activities

Number of activities in a schedule as an integer value.

3.3 Get Activity

Gets an activity by id. It returns a tibble with one line about activity. The structure of a data is described in next topic.

3.4 Activities

Return a tibble with all activities of a schedule. This is the main information calculated by CPM. The tibble is formed by following columns:

# Create a schedule
sch <- sch_new() %>% 
  sch_title("Fictitious Project Example") %>% 
  sch_reference("VANHOUCKE, Mario. Measuring time:
    improving project performance using earned value management.
    Gent: Springer, 2009, p. 18") 

sch_has_any_activity(sch)  # FALSE
#> [1] FALSE
sch_nr_activities(sch)     # 0
#> [1] 0

# Add activities and relations to it.
sch %<>% 
  sch_add_activity(  1L, "a1" , 0L,  2L,3L,4L) %>% 
  sch_add_activity(  2L, "a2" , 4L,  5L) %>% 
  sch_add_activity(  3L, "a3" , 9L,  10L) %>% 
  sch_add_activity(  4L, "a4" , 1L,  6L) %>% 
  sch_add_activity(  5L, "a5" , 4L,  9L) %>% 
  sch_add_activity(  6L, "a6" , 5L,  7L) %>% 
  sch_add_activity(  7L, "a7" , 1L,  8L,11L) %>% 
  sch_add_activity(  8L, "a8" , 7L, 12L) %>% 
  sch_add_activity(  9L, "a9" , 8L, 12L) %>% 
  sch_add_activity( 10L, "a10", 3L, 12L) %>% 
  sch_add_activity( 11L, "a11", 3L, 12L) %>% 
  sch_add_activity( 12L, "a12", 0L) %>% 
  sch_plan()

sch_has_any_activity(sch)  # TRUE
#> [1] TRUE
sch_nr_activities(sch)     # 12
#> [1] 12

sch_get_activity(sch, 10L)
#> # A tibble: 1 x 14
#>      id name  duration milestone critical early_start early_finish late_start
#>   <int> <chr>    <int> <lgl>     <lgl>          <int>        <int>      <int>
#> 1    10 a10          3 FALSE     FALSE              9           12         13
#> # ... with 6 more variables: late_finish <int>, total_float <int>,
#> #   free_float <int>, progr_level <int>, regr_level <int>, topo_float <int>
sch_activities(sch)
#> # A tibble: 12 x 14
#>       id name  duration milestone critical early_start early_finish late_start
#>    <int> <chr>    <int> <lgl>     <lgl>          <int>        <int>      <int>
#>  1     1 a1           0 TRUE      TRUE               0            0          0
#>  2     2 a2           4 FALSE     TRUE               0            4          0
#>  3     3 a3           9 FALSE     FALSE              0            9          4
#>  4     4 a4           1 FALSE     FALSE              0            1          2
#>  5     5 a5           4 FALSE     TRUE               4            8          4
#>  6     6 a6           5 FALSE     FALSE              1            6          3
#>  7     7 a7           1 FALSE     FALSE              6            7          8
#>  8     8 a8           7 FALSE     FALSE              7           14          9
#>  9     9 a9           8 FALSE     TRUE               8           16          8
#> 10    10 a10          3 FALSE     FALSE              9           12         13
#> 11    11 a11          3 FALSE     FALSE              7           10         13
#> 12    12 a12          0 TRUE      TRUE              16           16         16
#> # ... with 6 more variables: late_finish <int>, total_float <int>,
#> #   free_float <int>, progr_level <int>, regr_level <int>, topo_float <int>

3.5 Gantt Matrix

Create a matrix that represents a Gantt chart, a matrix where “1” indicate that an activity is planned to be in execution.

In this matrix, the rows represent activities, whereas the columns represents the activity execution period. So, the number of columns is equal to project duration.

sch <- sch_new() %>% 
  sch_title("A project") %>%
  sch_reference("From criticalpath") %>% 
  sch_add_activities(
    id        = c( 1L,   2L,   3L,   4L ),
    name      = c("A", "B", "C", "D"),
    duration  = c( 2L,   3L,   1L,   2L )
  ) %>% 
  sch_add_relations(
    from = c(1L, 2L, 4L, 4L),
    to   = c(3L, 3L, 1L, 2L)
  ) %>% 
  sch_plan()

gantt <- sch_gantt_matrix(sch)

gantt
#>   1 2 3 4 5 6
#> 1 0 0 1 1 0 0
#> 2 0 0 1 1 1 0
#> 3 0 0 0 0 0 1
#> 4 1 1 0 0 0 0
#> attr(,"class")
#> [1] "Gantt"  "matrix" "array"

# What is the effort by time period?
colSums(gantt) # 1 1 2 2 1 1
#> 1 2 3 4 5 6 
#> 1 1 2 2 1 1

# What is the duration by activities?
rowSums(gantt) # 2 3 1 2
#> 1 2 3 4 
#> 2 3 1 2

# what is the S curve
cumsum(colSums(gantt))
#> 1 2 3 4 5 6 
#> 1 2 4 6 7 8
plot(cumsum(colSums(gantt)), type="l", lwd=3)

xyw <- sch_xy_gantt_matrix(sch)
xyw
#>      [,1] [,2] [,3]
#> [1,]    3    1    1
#> [2,]    4    1    1
#> [3,]    3    2    1
#> [4,]    4    2    1
#> [5,]    5    2    1
#> [6,]    6    3    1
#> [7,]    1    4    1
#> [8,]    2    4    1
plot(xyw[, 1:2])

4 How to change activities duration

Change activities duration and calculates critical path. This way is faster than creating a new schedule with new duration. The order of duration is the insertion order of activities.

sch <- sch_new() %>% 
  sch_title("Project 2: Patient Transport System") %>% 
  sch_reference(
  "VANHOUCKE, Mario. Integrated project management and control:
  first comes the theory, then the practice. Gent: Springer, 2014, p. 9") %>% 
  sch_add_activities(
    id        = 1:17,
    name      = paste("a", as.character(1:17), sep=""),
    duration  = c(1L,1L,3L,2L, 2L,2L,2L,1L, 4L,5L,3L,3L, 4L,5L,1L,5L,2L)
  ) %>% 
  sch_add_relations(
    from = c(1L, 2L, 3L, 3L, 4L, 5L, 6L, 7L, 8L,  8L,  8L,
      8L,  8L,  9L, 10L, 11L, 12L, 13L, 13L, 14L, 14L, 15L, 15L),
    to   = c(2L, 3L, 4L, 6L, 5L, 8L, 7L, 8L, 9L, 10L, 11L,
     12L, 13L, 14L, 14L, 14L, 14L, 14L, 15L, 16L, 17L, 16L, 17L)
  ) %>% 
  sch_plan()

#Project duration
sch_duration(sch) # 25
#> [1] 25

#Activities duration
sch_activities(sch)$duration
#>  [1] 1 1 3 2 2 2 2 1 4 5 3 3 4 5 1 5 2

new_durations <- c(1L,2L,5L, 4L,3L, 2L,1L, 5L, 3L,5L,5L,3L,4L, 2L,1L, 2L,4L)
sch %<>% 
  sch_change_activities_duration(new_durations)

#Project duration
sch_duration(sch) # 31
#> [1] 31
#Activities duration
sch_activities(sch)$duration
#>  [1] 1 2 5 4 3 2 1 5 3 5 5 3 4 2 1 2 4

Now, we will create the same schedule, but with activities insertion in random order. The relation between activities will be the same.

Then, will change the activities duration with the same data as above. The new schedule duration will be the same.

n <- sch %>% sch_nr_activities()
set.seed(45678)
i <- sample(n)

another_schedule <- sch_new() %>% 
  sch_add_activities(
    id        = sch_activities(sch)$id[i],
    name      = sch_activities(sch)$name[i],
    duration  = sch_activities(sch)$duration[i]
  ) %>%
  sch_add_relations(
    from = c(1L, 2L, 3L, 3L, 4L, 5L, 6L, 7L, 8L,  8L,  8L,
             8L,  8L,  9L, 10L, 11L, 12L, 13L, 13L, 14L, 14L, 15L, 15L),
    to   = c(2L, 3L, 4L, 6L, 5L, 8L, 7L, 8L, 9L, 10L, 11L,
             12L, 13L, 14L, 14L, 14L, 14L, 14L, 15L, 16L, 17L, 16L, 17L)
  ) %>%
  sch_plan()


another_schedule %<>% sch_change_activities_duration(new_durations[i])
# Second schedule.
sch_duration(another_schedule)
#> [1] 31

# First schedule.
sch_duration(sch)
#> [1] 31

5 How to get relations properties

5.1 Relation Properties

There are several methods about relations that you can use to get information about them. After you add activities and relations to a schedule, you may want to know how much relations has in a schedule or which relations belong to critical path. In this section, we will explain how you can find these information.

# Create a schedule
sch <- sch_new() %>% 
  sch_title("Fictitious Project Example") %>% 
  sch_reference("VANHOUCKE, Mario. Measuring time:
  improving project performance using earned value management.
  Gent: Springer, 2009, p. 18")

sch_has_any_relation(sch)  # FALSE
#> [1] FALSE
sch_nr_relations(sch)      # 0
#> [1] 0

sch %<>% 
  sch_add_activity( 1L, "a1" , 0L,  2L,3L,4L) %>% 
  sch_add_activity( 2L, "a2" , 4L,  5L) %>% 
  sch_add_activity( 3L, "a3" , 9L, 10L) %>% 
  sch_add_activity( 4L, "a4" , 1L,  6L) %>% 
  sch_add_activity( 5L, "a5" , 4L,  9L) %>% 
  sch_add_activity( 6L, "a6" , 5L,  7L) %>% 
  sch_add_activity( 7L, "a7" , 1L,  8L,11L) %>% 
  sch_add_activity( 8L, "a8" , 7L, 12L) %>% 
  sch_add_activity( 9L, "a9" , 8L, 12L) %>% 
  sch_add_activity(10L, "a10", 3L, 12L) %>% 
  sch_add_activity(11L, "a11", 3L, 12L) %>% 
  sch_add_activity(12L, "a12", 0L) %>% 
  sch_plan()


sch_has_any_relation(sch)  # TRUE
#> [1] TRUE
sch_nr_relations(sch)      # 14
#> [1] 14

sch_relations(sch)
#> # A tibble: 14 x 8
#>     from    to type    lag critical   ord i_from  i_to
#>    <int> <int> <chr> <int> <lgl>    <int>  <int> <int>
#>  1     1     2 FS        0 TRUE         1      1     2
#>  2     1     3 FS        0 FALSE        2      1     3
#>  3     1     4 FS        0 FALSE        3      1     4
#>  4     2     5 FS        0 TRUE         4      2     5
#>  5     3    10 FS        0 FALSE        5      3    10
#>  6     4     6 FS        0 FALSE        6      4     6
#>  7     5     9 FS        0 TRUE         7      5     9
#>  8    10    12 FS        0 FALSE       13     10    12
#>  9     6     7 FS        0 FALSE        8      6     7
#> 10     9    12 FS        0 TRUE        12      9    12
#> 11     7     8 FS        0 FALSE        9      7     8
#> 12     7    11 FS        0 FALSE       10      7    11
#> 13     8    12 FS        0 FALSE       11      8    12
#> 14    11    12 FS        0 FALSE       14     11    12

5.2 Successors and Predecessors

A schedule is structured by activities and each activity has zero, one or more successors and predecessors. Besides, a relation may be redundant. In criticalpath package there are several methods to deal these properties.

# Create a schedule
sch <- sch_new() %>% 
  sch_title("Fictitious Project Example") %>% 
  sch_reference("VANHOUCKE, Mario. Measuring time:
    improving project performance using earned value management.
    Gent: Springer, 2009, p. 18") %>% 
  sch_add_activity( 2L, "a2" , 4L,  5L, 12L) %>% 
  sch_add_activity( 3L, "a3" , 9L, 10L) %>% 
  sch_add_activity( 4L, "a4" , 1L,  6L) %>% 
  sch_add_activity( 5L, "a5" , 4L,  9L) %>% 
  sch_add_activity( 6L, "a6" , 5L,  7L) %>% 
  sch_add_activity( 7L, "a7" , 1L,  8L,11L) %>% 
  sch_add_activity( 8L, "a8" , 7L, 12L) %>% 
  sch_add_activity( 9L, "a9" , 8L, 12L) %>% 
  sch_add_activity(10L, "a10", 3L, 12L) %>% 
  sch_add_activity(11L, "a11", 3L, 12L) %>% 
  sch_add_activity(12L, "a12", 0L) %>% 
  sch_plan()

sch_all_successors(sch, 2) # 5, 9, 12
#> [1]  5  9 12
sch_all_successors(sch, 7) # 8, 11, 12
#> [1]  8 11 12
sch_all_successors(sch, 10) # 12
#> [1] 12

sch_successors(sch, 2) # 5, 12
#> [1]  5 12
sch_successors(sch, 7) # 8, 11
#> [1]  8 11
sch_successors(sch, 10) # 12
#> [1] 12

sch_all_predecessors(sch, 2) # nothing
#> numeric(0)
sch_all_predecessors(sch, 7) # 6, 4
#> [1] 6 4
sch_all_predecessors(sch, 10) # 3
#> [1] 3

sch_predecessors(sch, 2) # nothing
#> integer(0)
sch_predecessors(sch, 7) # 6
#> [1] 6
sch_predecessors(sch, 10) # 3
#> [1] 3

sch_is_redundant(sch, 2, 5)  #FALSE
#> [1] FALSE
sch_is_redundant(sch, 2, 12) #TRUE
#> [1] TRUE

6 How to get topological properties: Topological Indicators

Shows information about network structure. It may be of four type:

SP Serial or Parallel: It shows the closeness of a network to a serial or parallel graph. As the network becomes serial, the SP increase, until one; As the network becomes parallel, the SP decrease until zero. - sch_topoi_sp()

AD Activity Distribution: Measures the distribution of the activities over the levels. If AD is approximately equal zero, each level has same numbers of activities. Otherwise, if AD is equal one, the quantity of each level is not uniformly distributed. - sch_topoi_ad()

LA Length of Arcs: Measures the presence of long arcs based on the difference between the progressive level of the end activity and the start node of each relation. If LA is approximately equal zero, the progressive level between activities are as far as possible. Otherwise, if LA is equal one, the relation distance are one. - sch_topoi_la()

TF Topological Float Indicator: Measures the topological float of each activity. If TF = 0, there is no float between activities. If TF = 1, there is float between activities and they may be shift without affecting other activities. - sch_topoi_tf()

# Create a schedule
sch <- sch_new() %>% 
  sch_title("Fictitious Project Example") %>%
  sch_reference("VANHOUCKE, Mario. Measuring time:
    improving project performance using earned value management.
    Gent: Springer, 2009, p. 18") %>% 
  # Add activities and relations to it.
  sch_add_activity( 1L, "a1" , 0L,  2L,3L,4L) %>% 
  sch_add_activity( 2L, "a2" , 4L,  5L) %>% 
  sch_add_activity( 3L, "a3" , 9L, 10L) %>% 
  sch_add_activity( 4L, "a4" , 1L,  6L) %>% 
  sch_add_activity( 5L, "a5" , 4L,  9L) %>% 
  sch_add_activity( 6L, "a6" , 5L,  7L) %>% 
  sch_add_activity( 7L, "a7" , 1L,  8L,11L) %>% 
  sch_add_activity( 8L, "a8" , 7L, 12L) %>% 
  sch_add_activity( 9L, "a9" , 8L, 12L) %>% 
  sch_add_activity(10L, "a10", 3L, 12L) %>% 
  sch_add_activity(11L, "a11", 3L, 12L) %>% 
  sch_add_activity(12L, "a12", 0L) %>% 
  sch_plan()

sch_topoi_sp(sch)
#> [1] 0.4545455
sch_topoi_ad(sch)
#> [1] 0.4
sch_topoi_la(sch)
#> [1] 0.07692308
sch_topoi_tf(sch)
#> [1] 0.2333333

7 References

Csardi, G. & Nepusz, T. (2005). The Igraph Software Package for Complex Network Research. InterJournal. Complex Systems. 1695.

Project Management Institute (2017) A Guide to the Project Management Body of Knowledge (PMBOK Guide). Sixth Edition.

Project Management Institute (2017) PMI Lexicon of Project Management Terms: Version 3.2.

Vanhoucke, M. (2009) Measuring Time: Improving Project Performance Using Earned Value Management. Springer-Verlag US.

Vanhoucke, M. (2013) Project Management with Dynamic Scheduling: Baseline Scheduling, Risk Analysis and Project Control. Springer-Verlag Berlin Heidelberg.

Vanhoucke, M. (2014) Integrated Project Management and Control: First Comes the Theory, then the Practice. Springer International Publishing Switzerland.