277 lines
25 KiB
HTML
277 lines
25 KiB
HTML
<!DOCTYPE html>
|
||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="generator" content="pandoc" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||
<title>10.5 Creating a Discrete-Event Simulation</title>
|
||
<style>
|
||
code{white-space: pre-wrap;}
|
||
span.smallcaps{font-variant: small-caps;}
|
||
span.underline{text-decoration: underline;}
|
||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||
ul.task-list{list-style: none;}
|
||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||
div.sourceCode { margin: 1em 0; }
|
||
pre.sourceCode { margin: 0; }
|
||
@media screen {
|
||
div.sourceCode { overflow: auto; }
|
||
}
|
||
@media print {
|
||
pre > code.sourceCode { white-space: pre-wrap; }
|
||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||
}
|
||
pre.numberSource code
|
||
{ counter-reset: source-line 0; }
|
||
pre.numberSource code > span
|
||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||
pre.numberSource code > span > a:first-child::before
|
||
{ content: counter(source-line);
|
||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||
border: none; display: inline-block;
|
||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||
-khtml-user-select: none; -moz-user-select: none;
|
||
-ms-user-select: none; user-select: none;
|
||
padding: 0 4px; width: 4em;
|
||
color: #aaaaaa;
|
||
}
|
||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||
div.sourceCode
|
||
{ }
|
||
@media screen {
|
||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||
}
|
||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||
code span.at { color: #7d9029; } /* Attribute */
|
||
code span.bn { color: #40a070; } /* BaseN */
|
||
code span.bu { } /* BuiltIn */
|
||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||
code span.ch { color: #4070a0; } /* Char */
|
||
code span.cn { color: #880000; } /* Constant */
|
||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||
code span.dt { color: #902000; } /* DataType */
|
||
code span.dv { color: #40a070; } /* DecVal */
|
||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||
code span.ex { } /* Extension */
|
||
code span.fl { color: #40a070; } /* Float */
|
||
code span.fu { color: #06287e; } /* Function */
|
||
code span.im { } /* Import */
|
||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||
code span.op { color: #666666; } /* Operator */
|
||
code span.ot { color: #007020; } /* Other */
|
||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||
code span.ss { color: #bb6688; } /* SpecialString */
|
||
code span.st { color: #4070a0; } /* String */
|
||
code span.va { color: #19177c; } /* Variable */
|
||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||
</style>
|
||
<link rel="stylesheet" href="../tufte.css" />
|
||
<!--[if lt IE 9]>
|
||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||
<![endif]-->
|
||
</head>
|
||
<body>
|
||
<div style="display:none">
|
||
\(
|
||
\newcommand{\NOT}{\neg}
|
||
\newcommand{\AND}{\wedge}
|
||
\newcommand{\OR}{\vee}
|
||
\newcommand{\XOR}{\oplus}
|
||
\newcommand{\IMP}{\Rightarrow}
|
||
\newcommand{\IFF}{\Leftrightarrow}
|
||
\newcommand{\TRUE}{\text{True}\xspace}
|
||
\newcommand{\FALSE}{\text{False}\xspace}
|
||
\newcommand{\IN}{\,{\in}\,}
|
||
\newcommand{\NOTIN}{\,{\notin}\,}
|
||
\newcommand{\TO}{\rightarrow}
|
||
\newcommand{\DIV}{\mid}
|
||
\newcommand{\NDIV}{\nmid}
|
||
\newcommand{\MOD}[1]{\pmod{#1}}
|
||
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
|
||
\newcommand{\N}{\mathbb N}
|
||
\newcommand{\Z}{\mathbb Z}
|
||
\newcommand{\Q}{\mathbb Q}
|
||
\newcommand{\R}{\mathbb R}
|
||
\newcommand{\C}{\mathbb C}
|
||
\newcommand{\cA}{\mathcal A}
|
||
\newcommand{\cB}{\mathcal B}
|
||
\newcommand{\cC}{\mathcal C}
|
||
\newcommand{\cD}{\mathcal D}
|
||
\newcommand{\cE}{\mathcal E}
|
||
\newcommand{\cF}{\mathcal F}
|
||
\newcommand{\cG}{\mathcal G}
|
||
\newcommand{\cH}{\mathcal H}
|
||
\newcommand{\cI}{\mathcal I}
|
||
\newcommand{\cJ}{\mathcal J}
|
||
\newcommand{\cL}{\mathcal L}
|
||
\newcommand{\cK}{\mathcal K}
|
||
\newcommand{\cN}{\mathcal N}
|
||
\newcommand{\cO}{\mathcal O}
|
||
\newcommand{\cP}{\mathcal P}
|
||
\newcommand{\cQ}{\mathcal Q}
|
||
\newcommand{\cS}{\mathcal S}
|
||
\newcommand{\cT}{\mathcal T}
|
||
\newcommand{\cV}{\mathcal V}
|
||
\newcommand{\cW}{\mathcal W}
|
||
\newcommand{\cZ}{\mathcal Z}
|
||
\newcommand{\emp}{\emptyset}
|
||
\newcommand{\bs}{\backslash}
|
||
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
|
||
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
|
||
\newcommand{\abs}[1]{\left | #1 \right |}
|
||
\newcommand{\xspace}{}
|
||
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
|
||
\)
|
||
</div>
|
||
<header id="title-block-header">
|
||
<h1 class="title">10.5 Creating a Discrete-Event Simulation</h1>
|
||
</header>
|
||
<section>
|
||
<p>Let’s put together all of the classes we’ve designed over the course of this chapter to create a full simulation our of food delivery system. In this section, we’ll first learn about how the main simulation loop works. Then, we’ll turn our attention to the possible ways a simulation can be configured, and how to incorporate these configuration options as part of the public interface of a class.</p>
|
||
<h2 id="the-main-simulation-loop">The main simulation loop</h2>
|
||
<p>Before we get to creating a full simulation class, we’ll discuss how our simulation works. The type of simulation we’re learning about is called a <strong>discrete-event simulation</strong>, because it is driven by individual events occurring at specified periods of time.</p>
|
||
<p>A discrete-event simulation runs as follows:</p>
|
||
<ol type="1">
|
||
<li>It keeps track of a collection of events, which begins with some initial events. The collection is a <em>priority queue</em>, where an event’s priority is its timestamp (earlier timestamps mean higher priority).</li>
|
||
<li>The highest-priority event (i.e., the one with the earliest timestamp) is removed and processed. Any new events it generates are added to the priority queue.</li>
|
||
<li>Step 2 repeats until there are no events left.</li>
|
||
</ol>
|
||
<p>The algorithm is remarkably simple, though it does rely on a slightly modified version of our <em>priority queue</em> implementation from <a href="" title="../09-abstraction/07-priority-queues.html">Section 9.7</a>.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">In that section, we used <code>int</code>s to represent priority, while here we’re using <code>datetime.datetime</code> values.</span> Assuming we have such an implementation called <code>EventQueueList</code>, here is how we could write a simple function that runs this simulation loop:</p>
|
||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">def</span> run_simulation(initial_events: <span class="bu">list</span>[Event], system: FoodDeliverySystem) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb1-2"><a href="#cb1-2"></a> events <span class="op">=</span> EventQueueList() <span class="co"># Initialize an empty priority queue of events</span></span>
|
||
<span id="cb1-3"><a href="#cb1-3"></a> <span class="cf">for</span> event <span class="kw">in</span> initial_events:</span>
|
||
<span id="cb1-4"><a href="#cb1-4"></a> events.enqueue(event)</span>
|
||
<span id="cb1-5"><a href="#cb1-5"></a></span>
|
||
<span id="cb1-6"><a href="#cb1-6"></a> <span class="co"># Repeatedly remove and process the next event</span></span>
|
||
<span id="cb1-7"><a href="#cb1-7"></a> <span class="cf">while</span> <span class="kw">not</span> events.is_empty():</span>
|
||
<span id="cb1-8"><a href="#cb1-8"></a> event <span class="op">=</span> events.dequeue()</span>
|
||
<span id="cb1-9"><a href="#cb1-9"></a></span>
|
||
<span id="cb1-10"><a href="#cb1-10"></a> new_events <span class="op">=</span> event.handle_event(system)</span>
|
||
<span id="cb1-11"><a href="#cb1-11"></a> <span class="cf">for</span> new_event <span class="kw">in</span> new_events:</span>
|
||
<span id="cb1-12"><a href="#cb1-12"></a> events.enqueue(new_event)</span></code></pre></div>
|
||
<p>The main reason for this implementation’s simplicity is abstraction. Remember that <code>Event</code> is an abstract class; the complex behaviour of how different events are handled is deferred to its concrete subclasses via our calls to <code>event.handle_event</code>. Our <code>run_simulation</code> function is <em>polymorphic</em>: it works regardless of what <code>Event</code> instances it’s given in its <code>initial_events</code> parameter, or what new events are generated and stored in <code>new_events</code>. The only thing our function needs to be able to do is call the <code>handle_event</code> method on each event object, which we can assume is present because it is defined in the <code>Event</code> public interface.</p>
|
||
<h2 id="a-simulation-class">A simulation class</h2>
|
||
<p>Next, we will take our <code>run_simulation</code> in the previous section and “wrap” it inside a new class. This isn’t necessary to the running of the simulation, but is a standard practice in an object-oriented design, and makes it easier to both configure the simulation parameters and report results after the simulation is complete.</p>
|
||
<p>We’re going to begin with a sketch of a class to represent our simulation:</p>
|
||
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">class</span> FoodDeliverySimulation:</span>
|
||
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">"""A simulation of the food delivery system.</span></span>
|
||
<span id="cb2-3"><a href="#cb2-3"></a><span class="co"> """</span></span>
|
||
<span id="cb2-4"><a href="#cb2-4"></a> <span class="co"># Private Instance Attributes:</span></span>
|
||
<span id="cb2-5"><a href="#cb2-5"></a> <span class="co"># - _system: The FoodDeliverySystem instance that this simulation uses.</span></span>
|
||
<span id="cb2-6"><a href="#cb2-6"></a> <span class="co"># - _events: A collection of the events to process during the simulation.</span></span>
|
||
<span id="cb2-7"><a href="#cb2-7"></a> _system: FoodDeliverySystem</span>
|
||
<span id="cb2-8"><a href="#cb2-8"></a> _events: EventQueue</span>
|
||
<span id="cb2-9"><a href="#cb2-9"></a></span>
|
||
<span id="cb2-10"><a href="#cb2-10"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, start_time: datetime.datetime, num_days: <span class="bu">int</span>,</span>
|
||
<span id="cb2-11"><a href="#cb2-11"></a> num_couriers: <span class="bu">int</span>, num_customers: <span class="bu">int</span>,</span>
|
||
<span id="cb2-12"><a href="#cb2-12"></a> num_restaurants: <span class="bu">int</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb2-13"><a href="#cb2-13"></a> <span class="co">"""Initialize a new simulation with the given simulation parameters.</span></span>
|
||
<span id="cb2-14"><a href="#cb2-14"></a></span>
|
||
<span id="cb2-15"><a href="#cb2-15"></a><span class="co"> start_time: the starting time of the simulation</span></span>
|
||
<span id="cb2-16"><a href="#cb2-16"></a><span class="co"> num_days: the number of days that the simulation runs</span></span>
|
||
<span id="cb2-17"><a href="#cb2-17"></a><span class="co"> num_couriers: the number of couriers in the system</span></span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a><span class="co"> num_customers: the number of customers in the system</span></span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a><span class="co"> num_restaurants: the number of restaurants in the system</span></span>
|
||
<span id="cb2-20"><a href="#cb2-20"></a><span class="co"> """</span></span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> <span class="va">self</span>._events <span class="op">=</span> EventQueueList()</span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> <span class="va">self</span>._system <span class="op">=</span> FoodDeliverySystem()</span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a></span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a> <span class="va">self</span>._populate_initial_events(start_time, num_days)</span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a> <span class="va">self</span>._generate_system(num_couriers, num_customers, num_restaurants)</span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a></span>
|
||
<span id="cb2-27"><a href="#cb2-27"></a> <span class="kw">def</span> _populate_initial_events(<span class="va">self</span>, start_time: datetime.datetime, num_days: <span class="bu">int</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a> <span class="co">"""Populate this simulation's Event priority queue with GenerateOrdersEvents.</span></span>
|
||
<span id="cb2-29"><a href="#cb2-29"></a></span>
|
||
<span id="cb2-30"><a href="#cb2-30"></a><span class="co"> One new GenerateOrderEvent is generated per day, starting with start_time and</span></span>
|
||
<span id="cb2-31"><a href="#cb2-31"></a><span class="co"> repeating num_days times.</span></span>
|
||
<span id="cb2-32"><a href="#cb2-32"></a><span class="co"> """</span></span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a></span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a> <span class="kw">def</span> _generate_system(<span class="va">self</span>, num_couriers: <span class="bu">int</span>, num_customers: <span class="bu">int</span>, num_restaurants: <span class="bu">int</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb2-35"><a href="#cb2-35"></a> <span class="co">"""Populate this simulation's FoodDeliverySystem with the specified number of entities.</span></span>
|
||
<span id="cb2-36"><a href="#cb2-36"></a><span class="co"> """</span></span>
|
||
<span id="cb2-37"><a href="#cb2-37"></a></span>
|
||
<span id="cb2-38"><a href="#cb2-38"></a> <span class="kw">def</span> run(<span class="va">self</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb2-39"><a href="#cb2-39"></a> <span class="co">"""Run this simulation.</span></span>
|
||
<span id="cb2-40"><a href="#cb2-40"></a><span class="co"> """</span></span>
|
||
<span id="cb2-41"><a href="#cb2-41"></a> <span class="cf">while</span> <span class="kw">not</span> <span class="va">self</span>._events.is_empty():</span>
|
||
<span id="cb2-42"><a href="#cb2-42"></a> event <span class="op">=</span> <span class="va">self</span>._events.dequeue()</span>
|
||
<span id="cb2-43"><a href="#cb2-43"></a></span>
|
||
<span id="cb2-44"><a href="#cb2-44"></a> new_events <span class="op">=</span> event.handle_event(<span class="va">self</span>._system)</span>
|
||
<span id="cb2-45"><a href="#cb2-45"></a> <span class="cf">for</span> new_event <span class="kw">in</span> new_events:</span>
|
||
<span id="cb2-46"><a href="#cb2-46"></a> <span class="va">self</span>._events.enqueue(new_event)</span></code></pre></div>
|
||
<p>There are a few key items to note in this (incomplete) implementation:</p>
|
||
<ol type="1">
|
||
<li><p>The <code>run_simulation</code> method has been renamed to simply <code>run</code>, since it’s a method in the <code>FoodDeliverySimulation</code> class.</p></li>
|
||
<li><p>The local variable <code>events</code> and parameter <code>system</code> from the function are now instance attributes for the <code>FoodDeliverySimulation</code> class, and have been moved out of the <code>run</code> method entirely. It’s the job of <code>FoodDeliverySimulation.__init__</code> to initialize these objects.</p></li>
|
||
<li><p>The initializer takes in several parameters representing <em>configuration values</em> for the simulation. It then uses these values in two helper methods to initialize the <code>_system</code> and <code>_events</code> objects. These methods are marked private (named with a leading underscore) because they’re only meant to be called by the initializer, and not code outside of the class.</p>
|
||
<p>Here is how we could use the <code>FoodDeliverySimulation</code> class:</p>
|
||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="op">>>></span> simulation <span class="op">=</span> FoodDeliverySimulation(datetime.datetime(<span class="dv">2020</span>, <span class="dv">11</span>, <span class="dv">30</span>), <span class="dv">7</span>, <span class="dv">4</span>, <span class="dv">100</span>, <span class="dv">50</span>)</span>
|
||
<span id="cb3-2"><a href="#cb3-2"></a><span class="op">>>></span> simulation.run()</span></code></pre></div></li>
|
||
</ol>
|
||
<p>Next, we’ll briefly discuss one way to implement each of the two key helper methods for the initializer, <code>_populate_initial_events</code> and <code>_generate_system</code>.</p>
|
||
<h3 id="populating-initial-events">Populating initial events</h3>
|
||
<p>The key idea for our first helper method is that given a start time and a number of days, our initial events will be a series of <code>GenerateOrderEvents</code> that will generate <code>NewOrderEvents</code> when they are processed. Here is the basic skeleton, which will be leave as an exercise for you to complete:</p>
|
||
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a> <span class="kw">def</span> _populate_initial_events(<span class="va">self</span>, start_time: datetime.datetime, num_days: <span class="bu">int</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">"""Populate this simulation's Event priority queue with GenerateOrdersEvents.</span></span>
|
||
<span id="cb4-3"><a href="#cb4-3"></a></span>
|
||
<span id="cb4-4"><a href="#cb4-4"></a><span class="co"> One new GenerateOrderEvent is generated per day, starting with start_time and</span></span>
|
||
<span id="cb4-5"><a href="#cb4-5"></a><span class="co"> repeating num_days times.</span></span>
|
||
<span id="cb4-6"><a href="#cb4-6"></a><span class="co"> """</span></span>
|
||
<span id="cb4-7"><a href="#cb4-7"></a> <span class="cf">for</span> day <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">0</span>, num_days):</span>
|
||
<span id="cb4-8"><a href="#cb4-8"></a> <span class="co"># 1. Create a GenerateOrderEvent for the given day after the start time.</span></span>
|
||
<span id="cb4-9"><a href="#cb4-9"></a></span>
|
||
<span id="cb4-10"><a href="#cb4-10"></a> <span class="co"># 2. Enqueue the new event.</span></span></code></pre></div>
|
||
<h3 id="populating-the-system-entities">Populating the system entities</h3>
|
||
<p>The way that our simulation is currently set up, our <code>FoodDeliverySystem</code> instance will contain all restaurants, customers, and couriers before the events start being processed. That is, we assume that only <em>orders</em> are dynamic in our system; the restaurants, customers, and couriers do not change over time.</p>
|
||
<p>The easiest way to populate these three entity types is to randomly generate new instances of each of these classes. We’ve shown an example with <code>Customer</code>s below.</p>
|
||
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1"></a> <span class="kw">def</span> _generate_system(<span class="va">self</span>, num_couriers: <span class="bu">int</span>, num_customers: <span class="bu">int</span>, num_restaurants: <span class="bu">int</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb5-2"><a href="#cb5-2"></a> <span class="co">"""Populate this simulation's FoodDeliverySystem with the specified number of entities.</span></span>
|
||
<span id="cb5-3"><a href="#cb5-3"></a><span class="co"> """</span></span>
|
||
<span id="cb5-4"><a href="#cb5-4"></a> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">0</span>, num_customers):</span>
|
||
<span id="cb5-5"><a href="#cb5-5"></a> location <span class="op">=</span> _generate_location()</span>
|
||
<span id="cb5-6"><a href="#cb5-6"></a> customer <span class="op">=</span> Customer(<span class="ss">f'Customer </span><span class="sc">{i}</span><span class="ss">'</span>, location)</span>
|
||
<span id="cb5-7"><a href="#cb5-7"></a> <span class="va">self</span>._system.add_customer(customer)</span>
|
||
<span id="cb5-8"><a href="#cb5-8"></a></span>
|
||
<span id="cb5-9"><a href="#cb5-9"></a> <span class="co"># Couriers and Restaurants are similar</span></span>
|
||
<span id="cb5-10"><a href="#cb5-10"></a> ...</span>
|
||
<span id="cb5-11"><a href="#cb5-11"></a></span>
|
||
<span id="cb5-12"><a href="#cb5-12"></a></span>
|
||
<span id="cb5-13"><a href="#cb5-13"></a><span class="co"># Outside the class: helper for generating random locations in Toronto</span></span>
|
||
<span id="cb5-14"><a href="#cb5-14"></a>TORONTO_COORDS <span class="op">=</span> (<span class="fl">43.747743</span>, <span class="fl">43.691170</span>, <span class="op">-</span><span class="fl">79.633951</span>, <span class="op">-</span><span class="fl">79.176646</span>)</span>
|
||
<span id="cb5-15"><a href="#cb5-15"></a></span>
|
||
<span id="cb5-16"><a href="#cb5-16"></a></span>
|
||
<span id="cb5-17"><a href="#cb5-17"></a><span class="kw">def</span> _generate_location() <span class="op">-></span> <span class="bu">tuple</span>[<span class="bu">float</span>, <span class="bu">float</span>]:</span>
|
||
<span id="cb5-18"><a href="#cb5-18"></a> <span class="co">"""Return a randomly-generated location (latitude, longitude) within the Toronto bounds.</span></span>
|
||
<span id="cb5-19"><a href="#cb5-19"></a><span class="co"> """</span></span>
|
||
<span id="cb5-20"><a href="#cb5-20"></a> <span class="cf">return</span> (random.uniform(TORONTO_COORDS[<span class="dv">0</span>], TORONTO_COORDS[<span class="dv">1</span>]),</span>
|
||
<span id="cb5-21"><a href="#cb5-21"></a> random.uniform(TORONTO_COORDS[<span class="dv">2</span>], TORONTO_COORDS[<span class="dv">3</span>]))</span></code></pre></div>
|
||
<h2 id="putting-it-all-together">Putting it all together</h2>
|
||
<p>After completing the implementation of these two helper methods, you are ready to run the simulation! Try doing the following in the Python console:</p>
|
||
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="op">>>></span> simulation <span class="op">=</span> FoodDeliverySimulation(datetime.datetime(<span class="dv">2020</span>, <span class="dv">11</span>, <span class="dv">30</span>), <span class="dv">7</span>, <span class="dv">4</span>, <span class="dv">100</span>, <span class="dv">50</span>)</span>
|
||
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">>>></span> simulation.run()</span></code></pre></div>
|
||
<p>Of course, we aren’t printing anything out, and the <code>FoodDeliverySimualtion.run</code> method doesn’t actually return anything. You are free to insert some <code>print</code> calls to see whether events are actually being processed, but that’s not the only way to see the results of the simulation.</p>
|
||
<p>Once the simulation is complete, <code>self._system</code> will have accumulated several completed orders, as a <code>list[Order]</code>. We can access these values and perform any kind of computation on them we want, just like we did all the way back in Chapter 4!</p>
|
||
<p>For example, we might ask:</p>
|
||
<ul>
|
||
<li>How many orders were delivered in total?</li>
|
||
<li>What was the average number of orders delivered per courier?</li>
|
||
<li>For a given restaurant, which menu items were most popular?</li>
|
||
<li><em>What else can you come up with?</em></li>
|
||
</ul>
|
||
</section>
|
||
<footer>
|
||
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
|
||
</footer>
|
||
</body>
|
||
</html>
|