|
10 | 10 | Min, |
11 | 11 | Max, |
12 | 12 | ) |
| 13 | +from probabilit.distributions import Triangular |
13 | 14 | import numpy as np |
14 | 15 |
|
15 | 16 |
|
@@ -90,6 +91,44 @@ def test_mutual_fund_problem(self): |
90 | 91 | np.testing.assert_allclose(samples.mean(), 76583.58738496085) |
91 | 92 | np.testing.assert_allclose(samples.std(), 33483.2245611436) |
92 | 93 |
|
| 94 | + def test_total_person_hours(self): |
| 95 | + """Based on Example 19.2 from Risk Analysis: A Quantitative Guide, 3rd Edition by David Vose. |
| 96 | +
|
| 97 | + Estimate the number of person-hours requires to rivet 562 plates of a ship's hull. |
| 98 | + The quickest anyone has ever riveted a single plate is 3h 45min, while the worst time recorded is 5h 30min. |
| 99 | + Most likely value is estimated to be 4h 15min. |
| 100 | + What is the total person-hours? |
| 101 | +
|
| 102 | + Naively, we could model the problem as: |
| 103 | + total_person_hours = 562 * Triangular(3.75, 4.25, 5.5), |
| 104 | + but note that the triangular distribution here models the uncertainty of an individual plate, |
| 105 | + but we are using it as if it were the distribution of the average time for 562 plates. |
| 106 | +
|
| 107 | + A straight forward approach that gives the correct answer is to add 562 triangular distributions. |
| 108 | + """ |
| 109 | + |
| 110 | + rng = np.random.default_rng(42) |
| 111 | + num_rivets = 562 |
| 112 | + total_person_hours = 0 |
| 113 | + |
| 114 | + for i in range(num_rivets): |
| 115 | + total_person_hours += Triangular(low=3.75, mode=4.25, high=5.5, low_perc=0.00001, high_perc=0.99999) |
| 116 | + |
| 117 | + num_samples = 10000 |
| 118 | + res_total_person_hours = total_person_hours.sample(num_samples, rng) |
| 119 | + |
| 120 | + |
| 121 | + # The mean and standard deviation of a Triangular(3.75, 4.25, 5.5) are 4.5 and 0.368, |
| 122 | + # so by the Central Limit Theoreom we have that |
| 123 | + # total_person_hours = Normal(4.5 * 562, 0.368 * sqrt(562)) = Normal(2529, 8.724) |
| 124 | + expected_mean = 4.5 * num_rivets |
| 125 | + expected_std = 0.368 * np.sqrt(num_rivets) |
| 126 | + |
| 127 | + sample_mean = np.mean(res_total_person_hours) |
| 128 | + sample_std = np.std(res_total_person_hours) |
| 129 | + |
| 130 | + assert abs(sample_mean - expected_mean) < 0.3 |
| 131 | + assert abs(sample_std - expected_std) < 0.1 |
93 | 132 |
|
94 | 133 | def test_copying(): |
95 | 134 | # Create a graph |
|
0 commit comments