{
"metadata": {
"name": "",
"signature": "sha256:a658f43f42018ee8e01b77d4b02e78ca4cc14568aaa6ebbd6d3767b46554a761"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"parking"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*This problem's setting is borrowed from: B. Nelson (2010). Stochastic Modeling: Analysis and Simulation. Dover, New York.*\n",
"\n",
"Planning for construction of the the proposed Massive Mall — the largest shopping mall and indoor golf course in the world — includes determining the amount of customer parking to provide. Massive Mall will have a customer parking garage with 3 floors. The planners need to figure out how many parking spaces per floor the garage should have: if they are generous with the size of a parking space, they can fit 950 spaces in 1 floor; if they are stingy, then they can fit 960 spaces in 1 floor.\n",
"\n",
"Through forecasts based on historical data, surveys, and malls in similar markets, the planners have data on customer traffic to the mall and the amount of time customers spend shopping. In particular, on Saturdays:\n",
"\n",
"* the time between customer arrivals to the parking garage is forecast to be exponentially distributed with mean 1/1000 hours (i.e. 1000 customers per hour).\n",
"\n",
"* the time a customer spends in the mall is forecast to be exponentially distributed with mean 3 hours.\n",
"\n",
"\n",
"The mall will be open from 9 am to 9 pm on Saturdays.\n",
"\n",
"\n",
"1. Simulate the arrival and departure of customers from the parking garage on Saturdays, assuming that each floor has 950 spaces. Using 50 replications, give a point and interval estimate for the mean time average number of customers waiting for a parking spot.\n",
"\n",
"2. Simulate the arrival and departure of customers from the parking garage on Saturdays, assuming that each floor has 960. Using 50 replications, give a point and interval estimate for the mean time average number of customers waiting for a parking spot.\n",
"\n",
"3. Is it worth being stingy with the size of a parking space? In particular, are the mean time average number of customers waiting for a parking spot statistically different when each floor has 950 spaces vs. 960 spaces? Use the Levene test for equal variances and the $t$-test for equal means to answer this question.\n",
"\n",
"*Note.* These replicated simulations might take a few minutes (as opposed to a few seconds). "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can approach this problem in a similar way to the Fantastic Dan problem by thinking of each parking space as a \"server\", and the time a customer spends in the mall as the \"service time\". Below are the parameters, processes and resources for a SimPy model that simulates this parking garage system. \n",
"\n",
"Note that \n",
"\n",
"* the number of parking spaces per floor, `P.nSpacesPerFloor`, is set to `None` — it will be set later.\n",
"* all the time quantities are in minutes - this will make the output easier to interpret."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"##### Setup #####\n",
"# Friendly floating-point division\n",
"from __future__ import division\n",
"\n",
"# Import all simulation functions from SimPy\n",
"from SimPy.Simulation import *\n",
"\n",
"# Import mean, std, sqrt functions from numpy\n",
"from numpy import mean, std, sqrt\n",
"\n",
"# Import seed initializer and random sampling functions from NumPy\n",
"from numpy.random import seed, exponential\n",
"\n",
"# Import t random variable from scipy.stats\n",
"from scipy.stats import t, levene, ttest_ind\n",
"\n",
"\n",
"##### Parameters #####\n",
"class P:\n",
" ### To make the output easier to interpret, ###\n",
" ### let's make all time quantities in minutes ###\n",
" \n",
" # Interarrival times are exponentially distributed with mean 1/1000 hours\n",
" interarrivalTimeMean = 1/1000 * 60\n",
" \n",
" # Parking times are exponentially distributed with mean 3 hours\n",
" parkingTimeMean = 3 * 60\n",
" \n",
" # Number of floors\n",
" nFloors = 3\n",
" \n",
" # Number of parking spaces per floor\n",
" nSpacesPerFloor = None\n",
" \n",
" # Simulation time: 12 hours\n",
" simulationTimeMax = 12 * 60\n",
" \n",
"\n",
"##### Processes #####\n",
"# Customer\n",
"class Customer(Process):\n",
" def behavior(self):\n",
" # Customer arrives, joins queue for parking garage\n",
" yield request, self, R.garage\n",
" \n",
" # Customer enters parking garage and starts shopping\n",
" parkingTime = exponential(scale = P.parkingTimeMean)\n",
" yield hold, self, parkingTime\n",
" \n",
" # Customer finishes shopping, leaves garage\n",
" yield release, self, R.garage\n",
"\n",
"# Entrance\n",
"class Entrance(Process):\n",
" def behavior(self):\n",
" # At the start of the simulation, no customers have arrived\n",
" nCustomers = 0\n",
" \n",
" # Customer arrivals\n",
" while True:\n",
" # Wait until the next arrival\n",
" interarrivalTime = exponential(scale = P.interarrivalTimeMean)\n",
" yield hold, self, interarrivalTime\n",
" \n",
" # Create a new customer using the template defined in the Customer class\n",
" c = Customer(name=\"Customer {0}\".format(nCustomers))\n",
" \n",
" # Activate the customer's behavior\n",
" activate(c, c.behavior())\n",
"\n",
" # Count this new customer\n",
" nCustomers += 1\n",
"\n",
" \n",
"##### Resources #####\n",
"class R:\n",
" # Parking garage\n",
" garage = None"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Below is the function `model()` that actually runs the simulation. Note that\n",
"\n",
"* the function takes a value as input for the seed.\n",
"* the capacity of `R.garage` is `P.nFloors * P.nSpacesPerFloor`.\n",
"* the built-in monitors for `R.garage` has been activated.\n",
"* the function outputs the time average number of customers in the parking garage queue."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"##### Simulation #####\n",
"def model(inputSeed):\n",
" # Initialize SimPy \n",
" initialize()\n",
"\n",
" # Initialize a seed for the random number generator\n",
" seed(inputSeed)\n",
"\n",
" # Create the garage resource\n",
" R.garage = Resource(capacity = P.nFloors * P.nSpacesPerFloor, monitored = True)\n",
"\n",
" # Activate the entrance (to generate customers)\n",
" e = Entrance()\n",
" activate(e, e.behavior())\n",
" \n",
" # Run the simulation\n",
" simulate(until = P.simulationTimeMax)\n",
"\n",
" # Compute time average number of customers in queue\n",
" tAvgCustQ = R.garage.waitMon.timeAverage()\n",
" \n",
" # Return time average number of customers in queue\n",
" return tAvgCustQ"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"System 1: 950 spaces per floor"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# Number of floors\n",
"P.nSpacesPerFloor = 950\n",
"\n",
"# Number of replications\n",
"n = 50\n",
"\n",
"# Replicate simulation and capture performance measure\n",
"tAvgCustQ1Obs = [model(123*i) for i in range(n)]\n",
"\n",
"## Observed sample mean\n",
"tAvgCustQ1SM = mean(tAvgCustQ1Obs)\n",
"\n",
"# Observed sample standard deviation\n",
"tAvgCustQ1SSD = std(tAvgCustQ1Obs, ddof = 1)\n",
"\n",
"# Confidence level 0.05\n",
"alpha = 0.05\n",
"tAvgCustQ1CIL = tAvgCustQ1SM - t.ppf(1 - alpha/2, n - 1) * tAvgCustQ1SSD / sqrt(n)\n",
"tAvgCustQ1CIR = tAvgCustQ1SM + t.ppf(1 - alpha/2, n - 1) * tAvgCustQ1SSD / sqrt(n)\n",
"\n",
"print(\"GARAGE WITH {0} SPACES PER FLOOR\".format(P.nSpacesPerFloor))\n",
"print(\"Time average number of customers in queue:\")\n",
"print(\" Sample mean: {0}\".format(tAvgCustQ1SM))\n",
"print(\" Sample standard deviation: {0}\".format(tAvgCustQ1SSD))\n",
"print(\" {0}% confidence interval: [{1}, {2}]\".format((1 - alpha)*100, tAvgCustQ1CIL, tAvgCustQ1CIR))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"GARAGE WITH 950 SPACES PER FLOOR\n",
"Time average number of customers in queue:\n",
" Sample mean: 20.8058300629\n",
" Sample standard deviation: 14.6173219633\n",
" 95.0% confidence interval: [16.6516331306, 24.9600269952]\n"
]
}
],
"prompt_number": 3
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"System 2: 960 spaces per floor"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# Number of floors\n",
"P.nSpacesPerFloor = 960\n",
"\n",
"# Number of replications\n",
"n = 50\n",
"\n",
"# Replicate simulation and capture performance measure\n",
"tAvgCustQ2Obs = [model(123*i) for i in range(n)]\n",
"\n",
"## Observed sample mean\n",
"tAvgCustQ2SM = mean(tAvgCustQ2Obs)\n",
"\n",
"# Observed sample standard deviation\n",
"tAvgCustQ2SSD = std(tAvgCustQ2Obs, ddof = 1)\n",
"\n",
"# Confidence level 0.05\n",
"alpha = 0.05\n",
"tAvgCustQ2CIL = tAvgCustQ2SM - t.ppf(1 - alpha/2, n - 1) * tAvgCustQ2SSD / sqrt(n)\n",
"tAvgCustQ2CIR = tAvgCustQ2SM + t.ppf(1 - alpha/2, n - 1) * tAvgCustQ2SSD / sqrt(n)\n",
"\n",
"print(\"GARAGE WITH {0} SPACES PER FLOOR\".format(P.nSpacesPerFloor))\n",
"print(\"Time average number of customers in queue:\")\n",
"print(\" Sample mean: {0}\".format(tAvgCustQ2SM))\n",
"print(\" Sample standard deviation: {0}\".format(tAvgCustQ2SSD))\n",
"print(\" {0}% confidence interval: [{1}, {2}]\".format((1 - alpha)*100, tAvgCustQ2CIL, tAvgCustQ2CIR))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"GARAGE WITH 960 SPACES PER FLOOR\n",
"Time average number of customers in queue:\n",
" Sample mean: 12.6430592341\n",
" Sample standard deviation: 11.980747453\n",
" 95.0% confidence interval: [9.23816848598, 16.0479499823]\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Comparing System 1 and System 2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, we perform the Levene test: are the variances of the time average number of customers in the queue for both systems equal?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"(LeveneTS, LevenePValue) = levene(tAvgCustQ1Obs, tAvgCustQ2Obs)\n",
"print(\"Levene test p-value = {0}\".format(LevenePValue))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Levene test p-value = 0.131003386266\n"
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Assuming a significance level of 0.05, we **do not reject** the null hypothesis of the Levene test. Therefore, we can assume that the variances in both systems are equal."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we perform the $t$-test for equal means, assuming equal variances."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"(tTS, tPValue) = ttest_ind(tAvgCustQ1Obs, tAvgCustQ2Obs, equal_var = True)\n",
"print(\"t-test p-value = {0}\".format(tPValue))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"t-test p-value = 0.00290819099297\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Assuming a significance level of 0.05, we **reject** the null hypothesis of the $t$-test.\n",
"Therefore, we can assume that the mean time average number of customers in the queue are actually different across systems: the improvement in the mean time average number of customers in the queue (approximately -8) achieved by increasing the number of spaces per floor from 950 to 960 is statistically significant.\n",
"\n",
"Of course, whether this difference of -8 is worth the increased number of customers complaining about cramped parking spaces and dinged cars depends on what the planners value."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
}
],
"metadata": {}
}
]
}