Simulating a Process

Overview


In order to understand the distribution of the amount of time a typical process may take, it is often useful to simulate the process several times and average the results.

For the purposes of this page, a process is a series of steps, each that takes an amount of time. Each step may have dependencies on other steps, and the amount of time taken to complete a step can be random.

The simplified api method we will use assumes that a tasks can start as soon as all the tasks that it depends on are complete. If no depdencies are specified, the process length will be the length of the longest task.

simulations

Building a Process Tree


In the following code, we begin to set up a process tree for a project. Here we populate a dictionary named tasks with a set of task objects, each with a start time and a length.

Notice that the second task sets its start date as the start date of the first task plus its length (which should be the end date of the task)


let tasks = {};
tasks['set up database'] = {
  start: 0,
  length: 10
};
tasks['populate database'] = {
  start: tasks['set up database'].start + tasks['set up database'].length,
  length: 20
};
						 


Once we have this information, we can then easily compute various stats from the data structure. For instance, we can calculate the end date of the project as well as total number hours worked.


let end = Math.max(...Object.keys(tasks).map(p => tasks[p].start + tasks[p].length));
let total = $list(Object.keys(tasks).map(p => tasks[p].length)).sum();
					

Setting the Distribution Functions





tasks['set up database'] = {
  start: 0,
  length: 10*Math.random()
};
						 




Typically you will want to provide a function has some randomness and has an average and standard deviation that matches what you expect for the given step. For example, you could choose a Guassian (normal or bell curve) distribution with the appropriate mean and standard deviation. There are some downsides to using the normal, i.e., the normal distribution can go negative. This means you could generate steps with a negative amount of time. This may not be much of problem, as it may be unllikely, and as you will average the statistics over a largen number of samples, this ill defined samples may not influence the result that much. However, you could choose a better suited distribution, such as the lognormal distribution.


let ln = await import('/lib/statistics/distributions/lognormal/v1.0.0/lognormal.js');
tasks['set up database'] = {
  start: 0,
  length: ln.generate(1,1)
};

						 


Other distributions can be found:

distribution.

Running Simulations



let simulate = function(){
	let tasks = {};
	tasks['set up database'] = {
	  start: 0,
	  length: 10
	};
	tasks['populate database'] = {
	  start: tasks['set up database'].start + tasks['set up database'].length,
	  length: 20
	};						
	let end = Math.max(...Object.keys(tasks).map(p => tasks[p].start + tasks[p].length));	
	return end
}

let sims = [];
for(let i=0;i<100;i++){ 
	sims.push(simulate());
}
						 
Try it!

Contents