Uploaded by Jarar Bukhari

Critical path method

advertisement
Critical Path Method
Introduction:
Critical path method is based on mathematical calculations and it is used for scheduling project activities.
This method was first introduced in 1950s as a joint venture between Remington Rand Corporation and
DuPont Corporation.
The initial critical path method was used for managing plant maintenance projects. Although the original
method was developed for construction work, this method can be used for any project where there are
interdependent activities.
Working:
The CPM algorithm uses the activities data to calculate the longest path of planned activities to the end of
the project, and the earliest and latest that each activity can start and finish without making the project
longer. This process determines which activities are "critical" (i.e., on the longest path) and which have
"total float" (i.e., can be delayed without making the project longer).
To accomplish that, two methods were created: one called WalkListAhead and the other called
WalkListAback.
The WalkListAhead method receives the array that stores the activities and performs the forward walking
inside the array calculating for each activity its earliest start time and earliest end time.
After the forward walking, the WalkListAback performs the backward walking calculating for each
activity its latest start time and latest end time.
To calculate the critical path, a method called CriticalPath verifies if each activity's earliest end time
minus the latest end time and earliest start time minus the latest start time are equal zero. If so, the activity
is part of the critical path and its Id is written in the screen. The project's total duration is also shown.
C# Code of Critical Path:
using System;
using System.Collections;
using System.Text;
using CriticalPathMethod;
namespace ComputerEngineering
{
class CPM
{
public CPM()
{
}
/// Number of activities
private static int na;
private static void Main(string[] args)
{
do
{
Console.Clear();
// Array to store the activities that'll be evaluated.
Activity[] list = null;
list = GetActivities(list);
list = WalkListAhead(list);
list = WalkListAback(list);
CriticalPath(list);
Console.Write(" Do you wanna a new critical path solution? y\\n: ");
}
while(Console.ReadKey().KeyChar == 'y' || Console.ReadKey().KeyChar == 'Y');
}
/// <summary>
/// Gets the activities that'll be evaluated by the critical path method.
/// </summary>
/// <param name="list">Array to store the activities that'll be evaluated.</param>
/// <returns>list</returns>
private static Activity[] GetActivities(Activity[] list)
{
do
{
Console.Write("\n
Number of activities: ");
if((na = int.Parse(Console.ReadLine())) < 2)
{
Console.Beep();
Console.Write("\n Invalid entry. The number must be >= 2.\n");
}
}
while(na < 2);
list = new Activity[na];
for(int i = 0; i < na; i++)
{
Activity activity = new Activity();
Console.Write("\n
Activity {0}\n", i + 1);
Console.Write("\n
ID: ", i + 1);
activity.Id = Console.ReadLine();
Console.Write("
Description: ", i + 1);
activity.Description = Console.ReadLine();
Console.Write("
Duration: ", i + 1);
activity.Duration = int.Parse(Console.ReadLine());
Console.Write(" Number of predecessors: ", i + 1);
int np = int.Parse(Console.ReadLine());
if(np != 0)
{
activity.Predecessors = new Activity[np];
string id;
for(int j = 0; j < np; j++)
{
Console.Write(" #{0} predecessor's ID: ", j + 1);
id = Console.ReadLine();
Activity aux = new Activity();
if((aux = aux.CheckActivity(list, id, i)) != null)
{
activity.Predecessors[j] = aux;
list[aux.GetIndex(list, aux, i)] = aux.SetSuccessors(aux, activity);
}
else
{
Console.Beep();
Console.Write("\n No match found! Try again.\n\n");
j--;
}
}
}
list[i] = activity;
}
return list;
}
/// <summary>
/// Performs the walk ahead inside the array of activities calculating for each
/// activity its earliest start time and earliest end time.
/// </summary>
/// <param name="list">Array storing the activities already entered.</param>
/// <returns>list</returns>
private static Activity[] WalkListAhead(Activity[] list)
{
list[0].Eet = list[0].Est + list[0].Duration;
for(int i = 1; i < na; i++)
{
foreach(Activity activity in list[i].Predecessors)
{
if(list[i].Est < activity.Eet)
list[i].Est = activity.Eet;
}
list[i].Eet = list[i].Est + list[i].Duration;
}
return list;
}
/// <summary>
/// Performs the walk aback inside the array of activities calculating for each
/// activity its latest start time and latest end time.
/// </summary>
/// <param name="list">Array storing the activities already entered.</param>
/// <returns>list</returns>
private static Activity[] WalkListAback(Activity[] list)
{
list[na - 1].Let = list[na - 1].Eet;
list[na - 1].Lst = list[na - 1].Let - list[na - 1].Duration;
for(int i = na - 2; i >= 0; i--)
{
foreach(Activity activity in list[i].Successors)
{
if(list[i].Let == 0)
list[i].Let = activity.Lst;
else
if(list[i].Let > activity.Lst)
list[i].Let = activity.Lst;
}
list[i].Lst = list[i].Let - list[i].Duration;
}
return list;
}
/// <summary>
/// Calculates the critical path by verifyng if each activity's earliest end time
/// minus the latest end time and earliest start time minus the latest start
/// time are equal zero. If so, then prints out the activity id that match the
/// criteria. Plus, prints out the project's total duration.
/// </summary>
/// <param name="list">Array containg the activities already entered.</param>
private static void CriticalPath(Activity[] list)
{
Console.Write("\n
Critical Path: ");
foreach(Activity activity in list)
{
if((activity.Eet - activity.Let == 0) && (activity.Est - activity.Lst == 0))
Console.Write("{0} ", activity.Id);
}
Console.Write("\n\n
Total duration: {0}\n\n", list[list.Length - 1].Eet);
}
}
}
ACTIVITY CLASS:
using System;
using System.Collections.Generic;
using System.Text;
namespace CriticalPathMethod
{
/// <summary>
/// Describes an activity according to the Critical Path Method.
/// </summary>
public class Activity
{
private string id;
private string description;
private int duration;
private int est;
private int lst;
private int eet;
private int let;
private Activity[] successors;
private Activity[] predecessors;
public Activity()
{
}
/// Identification concerning the activity.
public string Id
{
get
{
return id;
}
set
{
id = value;
}
}
/// <summary>
/// Brief description concerning the activity.
/// </summary>
public string Description
{
get
{
return description;
}
set
{
description = value;
}
}
/// <summary>
/// Total amount of time taken by the activity.
/// </summary>
public int Duration
{
get
{
return duration;
}
set
{
duration = value;
}
}
/// <summary>
/// Earliest start time
/// </summary>
public int Est
{
get
{
return est;
}
set
{
est = value;
}
}
/// <summary>
/// Latest start time
/// </summary>
public int Lst
{
get
{
return lst;
}
set
{
lst = value;
}
}
/// <summary>
/// Earliest end time
/// </summary>
public int Eet
{
get
{
return eet;
}
set
{
eet = value;
}
}
/// <summary>
/// Latest end time
/// </summary>
public int Let
{
get
{
return let;
}
set
{
let = value;
}
}
/// <summary>
/// Activities that come before the activity.
/// </summary>
public Activity[] Predecessors
{
get
{
return predecessors;
}
set
{
predecessors = value;
}
}
/// <summary>
/// Activities that come after the activity.
/// </summary>
public Activity[] Successors
{
get
{
return successors;
}
set
{
successors = value;
}
}
/// <summary>
/// Performs a check to verify if an activity exists.
/// </summary>
/// <param name="list">Array storing the activities already entered.</param>
/// <param name="id">ID being checked.</param>
/// <param name="i">Current activities' array index.</param>
/// <returns>Found activity or null.</returns>
public Activity CheckActivity(Activity[] list, string id, int i)
{
for(int j = 0; j < i; j++)
{
if(list[j].Id == id)
return list[j];
}
return null;
}
/// <summary>
/// Returns the index of a given activity.
/// </summary>
/// <param name="aux">Activity serving as an auxiliary referencing an existing
/// activity.</param>
/// <param name="i">Current activities' array index.</param>
/// <returns>index</returns>
public int GetIndex(Activity[] list, Activity aux, int i)
{
for(int j = 1; j < i; j++)
{
if(list[j].Id == aux.Id)
return j;
}
return 0;
}
/// <summary>
/// Fills out the aux's array of successors by checking if it has already been
/// filled up.
/// If so, instantiates a new aux2 that'll store the aux's current
/// successors plus the activity that's being entered. After that, aux receives the
/// reference of aux2.
/// Otherwise, store the activity being entered in the first index of aux's
/// successors array.
/// </summary>
/// <param name="aux">Activity serving as an auxiliary referencing an existing
/// activity.</param>
/// <param name="activity">Activity being entered.</param>
/// <returns>aux</returns>
public Activity SetSuccessors(Activity aux, Activity activity)
{
if(aux.Successors != null)
{
Activity aux2 = new Activity();
aux2.Successors = new Activity[aux.Successors.Length + 1];
aux.Successors.CopyTo(aux2.Successors, 0);
aux2.Successors[aux.Successors.Length] = activity;
aux.Successors = aux2.Successors;
}
else
{
aux.Successors = new Activity[1];
aux.Successors[0] = activity;
}
return aux;
}
}
}
Limitations:


For bigger projects, CPM networks can be complicated.
It also does not handle the scheduling of the resource allocation.
Example:
We are taking this example to check our code.
Output:
Download