--- title: "CPM and PERT" author: "Adam Kucharski" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{CPM and PERT} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Example of CPM analysis in the *critpath* package The table below provides information on the structure of the graph and the duration of activities in some example project. The same dataset is available in the *critpath* package as *cpmexample1*. This example assumes that the durations are deterministic. Starting and ending node numbers are provided for each activity. It is also possible to pass the structure of the graph through a list of immediate predecessors. See the *Introduction* vignette. ```{r, echo = FALSE} from <- c(1, 1, 1, 2, 3, 4) to <- c(2, 3, 4, 4, 4, 5) label <- c("A", "B", "C", "D", "E", "F") time <- c(3, 2, 5, 1, 1, 3) knitr::kable(cbind(as.numeric(from), to, label, time), col.names = c("Start. node", "End. node", "Name", "Duration"), align = "cccc", caption = "Tab. 1. Data for the CPM model") ``` We will perform the following analyzes: - making a graph of connections between activities, - finding the start and end times of all activities, - indicating the bottlenecks of the project (critical activities), - puting critical activities on the graph, - making a Gantt chart, - making ASAP and ALAP charts. **Notice!** The *critpath* requires additional packages to be installed. The required packages are *DiagrammeR*, *ggplot2*, *reshape2* and *stringr*. You can preview what the graph looks like before solving it. The *plot_graphAOA()* function is used for this. ```{r, echo = FALSE, include = FALSE} library(critpath) plot_graphAOA(cpmexample1) ``` ```{r, fig.align = 'center', fig.cap = "Fig. 1. Graph for the cpmexample1 dataset"} plot_graphAOA(cpmexample1) ``` The next two items from the list above are performed by the *solve_pathAOA()* function. It creates the schedule of the project and requires two arguments: data frame prepared according to the scheme described above and a logical argument indicating what kind of duration (deterministic or stochastic) we are dealing with. ```{r} x <- solve_pathAOA(cpmexample1, deterministic = TRUE) ``` After the calculations are completed, a message is displayed with the directive term. The result of the *solve_pathAOA()* function is saved to the list. Its elements vary slightly depending on the type of method used. For the CPM, these will be: 1. A saved graph created with a *DiagrammeR* package. 2. The schedule of the project. 3. Project completion time. 4. List of critical activities. 5. A table with free float and conditional float values. Operator "[" returns objects of the list type. In turn, the operator "[[" allows you to access the value of a specific list item. ```{r} # Schedule x[2] # Directive deadline x[3] # Critical activities x[4] # Free float and conditional float values x[5] ``` The first element of the list *x* is used by other functions in the package. It belongs to the *dgr_graph* class supported by the *DiagrammeR* package. It is possible to perform operations described in the manual of this package. Asterisks in the last column of the schedule indicate which activities are critical. Now, let's draw a graph with the critical activities marked. We will use the *plot_graphAOA()* function again but with different argument. It will be a list created after solving the problem. This requires the use of the *solved*"* argument. ```{r, fig.align = 'center', fig.cap = "Fig. 2. Critical path for the cpmexample1 dataset"} plot_graphAOA(solved = x) ``` The next element of the CPM analysis will be the Gantt chart. The *plot_gantt()* function requires the *ggplot2* and *reshape2* packages to be installed first. It also takes the list produced by the *solve_pathAOA()* function as a mandatory argument. Optional argument *bar_size* determines the thickness of the bar of the drawn activity. The default is 10, and if appropriate, this argument need not be provided. ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 3. Gantt chart for the cpmexample1 dataset"} plot_gantt(x) ``` The activities are displayed in the order they were entered. The critical ones are marked with *CR* and the non-critical ones with *NC*. Additionally, total floats greater than zero have been added for non-critical activities. Based on the Gantt chart we can plot two more charts. The first one is the ASAP chart which shows effetcs of starting activity as early as possible and end it as early as possible. It can be achieved withe the *plot_asap()* function. ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 4. ASAP chart for the cpmexample1 dataset"} plot_asap(x) ``` On the other hand, the ALAP chart shows effetcs of starting activity as late as possible and end it as late as possible. It can be achieved with the *plot_alap()* function. ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 5. ALAP chart for the cpmexample1 dataset"} plot_alap(x) ``` The plot_gantt(), plot_asap(), plot_alap() functions have an optional show_dummy parameter. If it is set to TRUE, dummy activities will be placed on the chart. ## Example of PERT analysis in the *critpath* package We will use a different data than in CPM. This data is available in a set named *pertexample1*. Let us assume that the durations are described with three numerical values as in Table 2. The package allows you to calculate the expected value and variance according to several different formulas (check the solve_pathAOA() function help). In this example, we will use classic formulas. ```{r, echo = FALSE} from <- c(1, 2, 3, 3, 3, 4, 5, 6, 7) to <- c(2, 3, 4, 5, 6, 7, 7, 7, 8) label <- c("A", "B", "C", "D", "E", "F", "G", "H", "I") opt_time <- c(3, 5, 5, 1, 6, 2, 5, 3, 4) likely_time <- c(5, 7, 5, 6, 8, 6, 6, 5, 6) pes_time <- c(7, 9, 8, 8, 10, 7, 7, 7, 8) knitr::kable(cbind(as.numeric(from), to, label, opt_time, likely_time, pes_time), col.names = c("Start. node", "End. node", "Name", "Optimistic dur.", "Most likely dur.", "Pessimistic dur."), align = "cccccc", caption = "Tab. 2. Data for the PERT model") ``` We are interested in the following types of analyzes: - determining the start and end times for each activity, - identifying the bottlenecks of the project (critical activities), - placing critical activities on the graph, - making a Gantt chart, - making ASAP and ALAP charts, - indication of directive terms for the risk-taker and the belayer schedules. Duration in PERT is a random variable, so we will change the *deterministic* argument to *FALSE*. ```{r} y <- solve_pathAOA(pertexample1, deterministic = FALSE) ``` After solving the problem, a message appears giving the parameters of the normal distribution of a random variable describing the project completion time. Below we display the elements of the list storing the solution. It contains one more element than the list created for the CPM method. The *Time* column contains the expected duration of the activity. ```{r} # Schedule y[2] # Expected completion time y[3] # Standard deviation of the completion time y[4] # Critical activities y[5] # Free float and conditional float values y[6] ``` The activity graph, the Gantt, ASAP anad ALAP charts are obtained in the same way as before. ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 6. Critical path for the pertexample1 dataset"} plot_graphAOA(solved = y) ``` ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 7. Gantt chart for the pertexample1 dataset"} plot_gantt(y) ``` ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 8. ASAP chart for the pertexample1 dataset"} plot_asap(y) ``` ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 9. ALAP chart for the pertexample1 dataset"} plot_alap(y) ``` To set deadlines corresponding to the schedules of the risk-taker and the belayer, we will use the *PERT_newtime()* function. ```{r} # Risk-taker's schedule PERT_newtime(new_prob = 0.3, y) # Belayer's schedule PERT_newtime(new_prob = 0.6, y) ``` The *PERT_newprob()* function answers to the question about the probability of completing the project for a given directive deadline. For example the probability that the project will end after 30 days ```{r} PERT_newprob(new_DT = 30, y) ``` Besides, the *plot_norm()* function draws a plot of the normal distribution of a random variable describing the expected directive deadline. ```{r, fig.align = 'center', fig.width = 6, fig.cap = "Fig. 10. Normal distribution for the pertexample1 dataset"} plot_norm(y) ``` Additional vertical lines indicate the schedules of the risk-taker and the belayer.