{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Monte Carlo simulation for project risk assessment"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"This notebook is an element of the free [risk-engineering.org courseware](https://risk-engineering.org/). It can be distributed under the terms of the [Creative Commons Attribution-ShareAlike licence](https://creativecommons.org/licenses/by-sa/4.0/).\n",
"\n",
"Author: Eric Marsden \n",
"\n",
"---\n",
"\n",
"This notebook contains an introduction to use of Python and the NumPy library for Monte Carlo simulation applied to a simple project risk problem. The [associated lecture slides](https://risk-engineering.org/monte-carlo-methods/) provide an introduction to the use of stochastic simulation methods."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Problem statement"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A construction project involves three tasks:\n",
"\n",
"- Task 1 is likely to take three days (70% probability), but it might also be completed in\n",
" two days (10% probability) or four days (20% probability)\n",
"\n",
"- Task 2 has a 60% probability of taking six days to finish, a 20% probability each of being completed in five days or eight days\n",
"\n",
"- Task 3 has an 80% probability of being completed in four days, 5% probability of being completed in three days and a 15% \n",
" probability of being completed in five days.\n",
" \n",
"Your task is to provide information to the project manager concerning the expected completion time of the project and possible delays."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Basic approach using best and worst case"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A basic approach to project risk would calculate best case and worst case project completion time. Our example is very simple so it’s easy to make this estimate by hand. We illustrate how to use interval arithmetic to resolve this kind of problem in more complex scenarios. We use the [mpmath Python library](http://mpmath.org/) for floating point arithmetic with arbitrary precision, which provides support for interval arithmetic. You may need to install this library, for instance with\n",
"\n",
"> pip install mpmath\n",
"\n",
"We assume that each task is dependent on the task before it, meaning that the three tasks must be executed in sequence. The total duration of the project is simply the sum of the individual task durations."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"mpi('10.0', '17.0')"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from mpmath import iv\n",
"\n",
"task1 = iv.mpf([2, 4])\n",
"task2 = iv.mpf([5, 8])\n",
"task3 = iv.mpf([3, 5])\n",
"task1 + task2 + task3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So the best case completion time is 10 days, and the worst case is 17 days. That’s a very big range of uncertainty in our project risk assessment!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Monte Carlo stochastic simulation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using a Monte Carlo stochastic simulation method, we will estimate the probability distribution of completion time, providing much more information for decision-making on project risk than only best and worst cases."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We start by defining a function that simulates the completion time of task 1. The functions use pseudorandom numbers generated from a uniform distribution. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import numpy\n",
"\n",
"def task1_days() -> int:\n",
" u = numpy.random.uniform()\n",
" if u < 0.7: return 3\n",
" if u < 0.8: return 2\n",
" return 4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let’s check that the function returns a plausible value if called once:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"task1_days()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then check that the distribution of a large number of calls looks plausible:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
"