Decision Science: Programming

20 阅读16分钟

Decision Science: Programming Assignment
Haide College, Autumn Semester 2024
Due dates:
• Milestone (quiz): 7 November 2024, 23:59. [5% course mark]
• Submission (code): 14 November 2024, 23:59 [20% course mark]
Purpose
The purpose of this assessment is to create a fully functional simulation of a more complex system. Building
simulations is one of the key objectives of this course. You will need to be able to do this in an industry or
government job working in decision sciences. Building a simulation is also the best way to absorb and gain a
deep understanding of the ideas and topics that are discussed in this course. Even if you are just managing
simulations projects, you should have some experience in creating the simulation itself.
This is quite a large and difficult task, but the assessment will provide considerable structure.
Outcomes
This Task addresses the following Course Learning Outcomes:
• communicate how randomness and controlled variation can be used to model complex systems in a range
of application domains such as industry, health, and transportation;
• create a model of a real-world problem specified in words and implement it as a discrete-event simulation;
• validate results from a discrete-event simulation.
Scenario
You will be simulating a passport (immigration) control queuing system at an airport. This is based on the
queuing system for foreign travelers arriving at Qingdao airport.
Passengers get off their flight, walk to the passport checkpoint area and join a single primary queue. When
they get near the front of this queue they are organised into several short secondary queues. Each secondary
queue leads to a counter staffed by an attendant, who checks the passenger’s passport and clears them to their
journey.
Additional features. The airport uses some strategies to make this process more efficient. This includes:

  1. extra counters open when the system is busy, and close when it is less busy
  2. attendants regularly rotate so they can take breaks
  3. passengers may be served at a counter not corresponding to their outside their allocated secondary queue
    in some circumstances
    Assumptions
    You should assume the following:
    • all queues operates in a First in First Out (FIFO) basis
    • there are 2 counters open at the start of the simulation
    • Times: all times are independent and
    – The interarrival time between flights is exponential with an expected value of 45 minutes
    – The number of passengers on each flight who will pass through this passport control area is uniformly
    distributed between 15 and 25 passengers (similar to the number of foreign arrivals on a plane to
    Qingdao)
    – The transit time for a passenger to walk from the plane to the queueing system is uniformly
    distributed between 5 and 30 minutes
    – The service time for passengers once they reach a counter is Pareto distributed with a minimum
    time of 2 minutes and an expected value of 4 minutes
    The following 代写Decision Science: Programming assumptions relate to the additional features of the system.
    1
    • Additional feature 1. Extra counters open when the system is busy, and close when it is less busy
    – Let ncounters be the number of counters currently open, and N be the total number of passengers
    in the queuing system (main queue, all secondary queues and in service). An extra counter will
    open if N > 10 × ncounters. A counter will close if N < 10 × (ncounters − 2).
    – There are a minimum of 2 counters and a maximum of 5 counters
    – When a counter “closes” this mean that no more passengers are accepted into its secondary queue.
    Any passengers currently in the secondary queue will be served as usual.
    • Additional feature 2. Attendants regularly rotate so they can take breaks
    – Some of the counter attendants rotate at an interval of 30 minutes, during which time service at
    the counter is paused for 1 minute. This means that the service time for any passenger at a rotating
    counter will increase by 1 minute.
    – For odd numbered counters, the first rotation is at 30 minutes from the start of the simulation
    (and then every 2 × 30 = 60 minutes)
    – For even numbered counters, the first rotation is at 60 minutes from the start of the simulation
    (and then every 2 × 30 = 60 minutes)
    • Additional feature 3. Passengers may be served at a counter not corresponding to their allocated
    secondary queue in some circumstances.
    – A passenger at the front of their secondary queue, who has been in their secondary queue for more
    than 20 minutes will be served next at any available open counter. In the case of multiple passengers
    in this situation, priority is given to the passenger who has spent the longest waiting time in their
    secondary queue.
    – If an open counter is available and its secondary queue is empty, they will serve a passenger from
    another secondary queue. Priority is given to the passenger with the longest secondary queue
    waiting time.
    • The airport is open 24 hours, 7 days a week.
    – The behaviour of the system is not influenced by the time of day.
    • The airport has specified that they consider a single simulation running for one day of simulated time
    (1440 minutes) to be sufficient for statistical relevance.
    Questions
    The airport’s management would like to plan for an anticipated increase in passenger numbers, as the number
    of arrivals using this passport queueing system is expected to double in the next five years. They would like
    to understand how best to manage their staff, if additional counters need to be built, and whether their are
    any aspects of the queuing system that can be fine-tuned. Based upon passenger feedback, passengers are
    concerned with total amount of time they must spend in this queuing system.
    The airport’s management wish to identify the minimum number of counters that will ensure the expected
    total time in the queuing system when the number of customers double is no worse than the current level.
    Airport management is also concerned with the well-being of their attendants, so would like to understand how
    the frequency and length of their rotation impacts passenger experience.
    Note. You do not have to answer these questions as part of this assignment, but this motivates the
    use of parameters so we can vary the assumptions of our model.
    Your Task
    This assessment is scaffolded into three parts:
    • Part 1: Modelling (Module 2)
    • Part 2: Programming (Module 3)
    • Part 3: Verification and testing (Module 4)
    The details of each part are outlined in later in this brief. It is suggested you work through each of these in
    order, although there may be some back and forth between Parts 2 & 3.
    2
    Requirements
    This assessment is worth 25% of your course mark. This is split between two parts:
    Milestone online quiz (5%). Answer a series of short multiple choice/numerical answer questions to
    demonstrate your understanding of the queuing model and functionality of the simulation.
    • Submission requirement: Submit online quiz via Cloudcampus.
    Julia code (20%). Write a simulation code in Julia according to the specification provided in this document.
    There are a total of 80 marks for this part of the assessment, broken down as follows:
    • Basic functionality: code implements the basic functionality of this queuing system, as per the specification.
    [40 marks]
    • Additional feature 1: code implements this feature correctly. [12 marks]
    • Additional feature 2: code implements this feature correctly. [12 marks]
    • Additional feature 3: code implements this feature correctly. [12 marks]
    • Code style: submission meets general style guidelines for good Julia code. [4 marks]
    All the above are detailed in the rubric at the end of this document. Here you are required to submit a single
    .jl file, which contains type definitions, data structures and functions to run the simulation.
    • Submission requirement: Submit Julia file via Cloudcampus.
    • Submission requirement: An include command on your file must not give an error, if it does give an
    you will get 0 marks (since this prevents your code from being automatically tested).
    If you need clarification about any of the above, please ask course staff during workshop, via email or via the
    course discussion board.
    3
    Part 1: Modelling
    In this part, you will model the system that you will be implementing.
    The system
    You will be simulating a passport (immigration) control queuing system at an airport. This is based on the
    queuing system for foreign travelers arriving at Qingdao airport.
    See page 1 (“Scenario”) of this document for a detailed description of the system.
    Tasks for Part 1
    Before you commence coding you should perform a series of modelling tasks. These tasks will prepare you for
    Part 2, when you will implement a simulation in Julia. You should work through these tasks and complete the
    online milestone quiz. Note you are not required to submit written responses to these points.
  4. Draw a schematic of the system. This can be a rough sketch on a piece of paper - this is a great way to
    get an initial understanding of the system.
  5. Describe the state(s) of the system.
    Hint: What state details are needed to answer supermarket owner’s questions?
  6. Describe the number of entities in the system in relation to the state(s).
    Hint: A simple equation may be helpful in this description.
  7. Assume there are four events in the simulation: passengers leaves the aircraft after landing
    (FlightDisembarks), passenger arrives at queue (Arrival), passenger departs queue (Departure)
    and attendants rotating for a break (for additional feature 2, RotateAttendants). For each event:
    • describe how each event changes the state of the system.
    • describe the new events that may be created as a result of this event.
  8. Draw a state diagram, illustrating the possibly states of the system and how the state changes in response
    to the various events.
  9. Draw a flow chart illustrating your simulation structure.
    To be clear, you will not be asked to submit written responses to the above but your understanding of these
    points will be assessed via the milestone quiz (worth 5% of your course mark).
    It is not possible to write a simulation code working through the above detail, so take your time here to get
    some clear ideas about what you need to code before you start Part 2.
    4
    Part 2: Programming
    In this part, you will start to program the model.
    Reminder
    The system to be modelled is described in page 1 of this document (“Scenario”)
    Tasks for Part 2
    Before starting the process of coding up your simulation, go back to your work from Part 1 and think about if
    there are any further modelling details needed here. In particular you might like to carefully think about how to
    model/implement the three “Additional features”.
    The main task here is to write code to implement a discrete-event simulation of the system.
    • The code should follow the style of some other codes presented in this course. You might like to use
    these as a starting point, or perhaps find it easier to start from an empty file.
    • The process you need to follow is outlined below under the heading Specification.
    By the end of this part, you should have a working simulation that can output results.
    In Part 3 you will test it and use it to create some data with a simulation harness.
    As part of your assessment, you will be required to submit one .jl file with your code for implementing the
    discrete-event simulation.
    Specification
    This week you will start coding your simulation. A good deal of the structure of the code is provided.
    • This is to help you! There is a lot written below, but by following it carefully you will get a big start
    towards developing your simulation.
    • It ensure that everyone has a common starting point.
    • It makes it easier to review and assess your progress by ensuring that everyone adopts the same basic
    structure for their implementation.
    The last point is important. Your mark is be based on automated testing of your code. Hence you must set up
    your code in the manner given, paying particular attention to setting up the data types exactly as described
    below, otherwise these test will fail and you will lose marks.
    Here are the required specification details:
  10. Filenames. Your code must be included in a single .jl files. These should be named:
    • AirportOverseasPassports.jl
    This should contain all of your data structures and functions. You will be provided with a file to run
    this code AirportOverseasPassports_run.jl which will include the first file and run the simulation
    for a set of parameters.
  11. You should use the standard packages that you have been using in this course.
    These include:
    • DataStructures
    • Distributions
    • StableRNGs
    • CSV
    You may wish to use a small set of additional packages such as Dates or Printf.
    Do not use any packages other than these or those that have been discussed in the course.
  12. Your code must specify three data structures:
    abstract type Event end
    mutable struct Passenger
    ...
    5
    mutable struct State ...
    Each will contain fields as required. The state structure should contain any queues or lists required, for
    instance, the event list. More detail about each follows.
  13. The abstract type Event will have the following subtypes:
    • FlightDisembarks . . . an aircraft lands and unloads passengers
    • Arrival . . . a passenger arrives at the queuing system
    • Departure . . . a passenger finish their passport check and leaves
    • RotateAttendants . . . the counter attendants take a break
    Each subtype of Event must be a mutable struct and must contain the following fields (with the
    types indicated):
    • FlightDisembarks
    – id . . . an integer valued event ID number (Int64)
    – flight_id . . . the ID of the flight (Int64)
    – no_passengers . . . the number of passengers from the flight that will be processed by the
    queuing system, or nothing if the flight has not yet unloaded (Union{Nothing,Int64})
    • Arrival
    – id . . . an integer valued event ID number (Int64)
    – flight_id . . . the ID of the passenger’s flight
    – disembark_time . . . the time the passenger’s flight was unloaded (Float64)
    – passenger_id . . . an integer valued passenger ID number, or nothing if the event does not
    yet have a customer allocated (Union{Nothing,Int64})
    • Departure
    – id . . . an integer valued event ID number (Int64)
    – passenger_id . . . the ID of the departing passenger (Int64)
    – counter_id . . . the counter that serviced that serviced the passenger, or nothing if they
    have not yet been served (Union{Nothing,Int64})
    • RotateAttendants
    – id . . . an integer valued event ID number (Int64)
    – odd_attendants . . . true if odd numbered counters are rotating, false if even numbered
    counters are rotating (Bool)
    You may optionally define constructor functions for each of these above subtypes (to initialise some fields
    with nothing or a particular value as appropriate).
  14. The data structure Passenger should contain fields to record important event times in the lifetime of
    the passenger. These are
    • id . . . an integer valued customer ID number (Int64)
    • flight_id . . . the ID of the passenger’s flight (Int64)
    • disembark_time . . . the time the passenger’s flight was unloaded (Float64)
    • enter_primary_time . . . the time the passenger entered the primary queue (Float64)
    • enter_secondary_time . . . the time the passenger entered the primary queue (Union{Float64,
    Nothing})
    • start_service_time . . . the time the passenger starts service (Union{Float64, Nothing})
    • end_service_time . . . the time the passenger ends service (Union{Float64, Nothing})
    • secondary_id . . . the ID of the passenger’s allocated secondary queue (Union{Int64, Nothing})
    • counter_id . . . the ID of the counter the passenger was served by (Union{Int64, Nothing})
    • attendant_rotated . . . true if the attendant rotated during service, false if not (Bool)
    Initially unknown values above should be set to nothing when the Passenger is created. Similarly,
    attendant_rotated should be initialised as false.
  15. The data structure State will contain an event list (priority queue), queues for all resources in the system
    and a few other details. These must be
    • time . . . the current system time (Float64)
    • event_list . . . the list of scheduled event (PriorityQueue{Event,Float64}, here priority is
    the time of the event)
    • primary_queue . . . queue of passengers waiting in the primary queue (Queue{Passenger})
    • secondary_queues . . . vector of queues of passengers waiting in the secondary queues
    (Vector{Queue{Passenger}})
    6
    • in_service . . . vector of passengers currently being served, or nothing if there is no passenger
    at a given counter (Vector{Union{Passenger,Nothing}})
    • n_entities . . . a counter of the number of entities in the simulation so far (Int64)
    • n_events . . . a counter of the number of events in the simulation so far (Int64)
    • n_flights . . . a counter of the number of flights that have unloaded passengers (Int64)
    • n_open_counters . . . the number of currently open counter (Int64)
    The constructor function for State should initialise all queues with empty queues of the correct type,
    time to 0.0 and the counters to 0.
  16. Parameters
    Your code should have a data structure struct Parameters for passing parameters as given in the
    below table
    parameter
    type description
    seed Int64 random seed for the simulation
    min_counters Int64 minimum number of counters
    max_counters Int64 maximum number of counters
    secondary_queue_length Int64 length of the secondary queues
    mean_interflight Float64 mean time between planes unloading
    min_no_passengers Int64 minimum number of passengers from plane to queue
    max_no_passengers Int64 maximum number of passengers from plane to queue
    min_passenger_transit_time Float64 minimum time to get from plane to queuing system
    max_passenger_transit_time Float64 minimum time to get from plane to queuing system
    min_service_time Float64 minimum time for passenger to complete service
    expected_service_time Float64 expected time for passenger to complete service
    final_time Float64 the final time for the simulation
    attendant_rotation_interval Float64 the time between attendant rotations
    attendant_rotation_time Float64 the time it takes for attendants to rotate
    secondary_rush_time Float64 waiting time for a passenger to go to the next available counter
    helpful_attendants Bool counter will serve passenger from outside their secondary queue
    Note some of these parameters are important to implementing some of the additional features:
    • Additional feature 1: min_counters and max_counters; feature switched off if these are equal.
    • Additional feature 2: attendant_rotation_interval and attendant_rotation_time; feature
    can be switched off if the interval is set to be greater than the total simulation time.
    • Additional features 3: secondary_rush_time and helpful_attendants; feature switched off if
    helpful_attendants is false.
  17. Random number generators
    Your code will use three random number generators. Store these as functions in a data structure struct
    RandomNGs. For convenience, also store here a function that returns the resolution time. The code to
    define this data structure is as follows
    struct RandomNGs
    rng::StableRNGs.LehmerRNG
    interflight_time::Function
    no_passengers::Function
    transit_times::Function
    service_time::Function
    end
    You should define a constructor function with
    function RandomNGs(P::Parameters)
    that takes the parameters structure as input and returns the random number generator and the four
    functions. Initialise the random number generator as follows
    rng = StableRNG( P.seed )
    The four functions should similarly use variables from the parameters structure, and be consistent with
    the modelling assumptions given earlier in this document.
    7
  18. Initialisation function
    Your code have an initialise function that takes as input the parameters of the system and returns
    an initial system state and creates the random number generators you are going to use.
    The initialisation function should also create a new system state and inject an initial FlightDisembarks
    at time 0.0. If you are implementing additional feature 2 the function should add an initial
    FlightDisembarks at t=P.attendant_rotation_interval (this is 30 minutes in the example output).
    The function should return the system state and the random number structure.
    function initialise(P::Parameters)
    R = RandomNGs(P)
    system = State(P)

add an arrival at time 0.0

t0 = 0.0
system.n_events += 1
system.n_flights += 1
enqueue!( system.event_list, FlightDisembarks(system.n_events,system.n_flights),t0)

add the first attendant rotation

system.n_events += 1
enqueue!( system.event_list, RotateAttendants(system.n_events,true),P.attendant_rotation_interval)
return (system, R)
end
All you need to do here is copy and paste the above function into your code.
10. Update functions (overall)
Your code must have a set of update! functions with signatures:
function update!( S::State, P::Parameters, R::RandomNGs, E::SomeEvent )
Each update function should process one of your event types so you will need one function per event
type.
Each update! function should modify the state S appropriately, including
• update any state variables
• allocate a passenger to the event (if appropriate)
• add any new events created from this one to the event list
• move entities between the various queues as appropriate (for example, primary to secondary).
These functions must not have side effects. That is, they should not write out any information to files,
or interact with global variables. However, your functions may throw an error if the input is invalid.
Some additional details of the behaviour of these function can be inferred from the provided example
output files.
11. Update function (for Arrival)
This function should process an Arrival event in a manner consistent with the system description and
assumptions.
As in example codes from the course, you may find it helpful to write an additional function to use here
to move a customers around the various queues or into service (common to this and the Departure
update function).
12. Update function (Departure)
This function should process a Departure event in a manner consistent with the system description and
assumptions.
13. Update function (FlightDisembarks)
This function should process a FlightDisembarks event in a manner consistent with the system
description and assumptions.
14. Update function (RotateAttendant)
This function should process a RotateAttendant event in a manner consistent with the system description
and assumptions.
8
15. State-based and entity-based output files
Your code must output two CSV files. The files should both begin with some metadata and parameters
(you can include comments preceded with a #). These should be stored in subfolders named for the
random seed and some parameter values.
• The first file state.csv should contain a time-ordered list of all events that are processed in the
simulation.
This should be written from the point of view after the event. For instance, you should report the
system that an arriving passenger sees immediately after their arrival.
The CSV file should have columns titled:
event_ID,time,event,upcoming_arrivals,primary_length,secondary_lengths,in_service,n_total,n_open_counters
Here upcoming_arrivals should be a count of Arrival events in the event_list, and n_total is
the total number of people checking out, including those in service and those with a problem. See the
provided example files for formatting of the vectors in secondary_lengths and in_service.
• The second file entities.csv should contain a list of all entities that have completed service. The
CSV file should have columns titled (note the header should be one line as in the example output):

passenger_id,flight_id,disembark_time,enter_primary,enter_secondary,start_service,end_service,secondary_id,...  
counter_id,attendant_rotated  

You will need to write and construct these CSV files line by line. This is most easily done with println
statements, but you may use a package like CSV or Printf if you prefer.
16. Run function(s)
You code should contain a top-level function run_checkout_sim with the signature
run_checkout_sim(P::Parameters)
This function should take the parameters structure as its input. It should then
• initialise the system state,
• create the output files (and subfolders)
• write metadata, parameters and the header to the output files
• run the simulation by calling the run! function (see below)
• close the output files
The run! should have the signature
run!(system::State, P::Parameters, R::RandomNGs, fid_state::IO, fid_entities::IO)
This function should run the main simulation loop up to the final time given in the Parameters. It
should write output to the state.csv file for all events and to the entities.csv for Departure events
only. It should also update the system time before the update! function is called.
17. Code style
Your code must be written with good style. See Julia’s style guidelines for further information.
In particular:
• use comments (in English) efficiently and effectively
• store commonly used code as functions
9
Further Julia hints on PriorityQueue
When a problem occurs, the depature time of the customer will be extended. That is, you need to change the
time, i.e. the priority, of the corresponding departure event.
You can modify the priority of an object in a priority queue in Julia as follows:
using DataStructures
pq = PriorityQueue()
pq["a"] = 10; pq["b"] = 5; pq["c"] = 7;
pq
Output:
PriorityQueue{Any, Any, Base.Order.ForwardOrdering} with 3 entries:
"b" => 5
"c" => 7
"a" => 10
To change the priority of an object:
pq["a"] = 0 # change the priority of "a"
pq
Output:
PriorityQueue{Any, Any, Base.Order.ForwardOrdering} with 2 entries:
"a" => 0
"b" => 5
"c" => 7
Note that the order of the items in the queue has now changed. However, be careful here since the above
approch would not update the time stored in the Event structure.
Additionally, you may find it useful to iterate over the keys of a PriorityQueue as follows (continuing from
the above code):
for k in keys(pq)
if k == "c"
pq[k] = 3
end
end
pq
Output:
PriorityQueue{Any, Any, Base.Order.ForwardOrdering} with 2 entries:
"a" => 0
"c" => 3
"b" => 5
This last piece of code may seem overly complex for this example, but can be adapted for the purposes here.
Additionally, you may find it helpful to use the dequeue_pair!, peek and delete! functions for priority
queues. Try using these on the above example as follows:
key, priority = dequeue_pair!(pq) # dequeue, return key and priority
peek(pq) # look at the top of the queue, without removing
delete(pq, "c") # delete an item with a given key
10
Part 3: Verification and testing
Note that no marks are directly associated with the activities described below. This is all about
testing your code thoroughly to ensure it works as expected!
In this part, you will test your implementation to make sure it can output results and is consistent with some
provided output.
Tasks for Part 3
Although you might not need to modify the code in AirportOverseasPassports.jl, you may need to modify
it in response to bugs found in testing.
The main tasks will be to verify that your code works correctly (as described in Module 3: Verification), and to
construct a small simulation harness in which to run a set of comparison simulations (as described in Module 4:
Tools to Automate Simulation). Following these steps will help to detect any issues/bugs and ensure you get
the maximum number of marks for the code you have written.

  1. Test and verify your code.
    Compare the output of your code to the provided sample outputs:
    • state_all.csv and entities_all.csv . . . output for the simulation with all additional features
    implemented (parameters in metadata)
    • state_basic.csvandentities_basic.csv‘ . . . output for simulation with no additional features (param eters in metadata)
    If you have implemented your code exactly as specified, and used the same seed and random number
    generation, your output should look very, very similar (the only differences should be in details such as
    numbers of decimal points, white-spacing or ID numbers).
    However, your code may result in some differences. Some are important and others less so. You need to
    be quite analytical to understand which. That is, what differences occur because of a minor change in
    the order of actions, and what differences are caused by bugs. If there are differences, you should create
    some of your own tests to understand what is different from the code that produced the above results.
  2. Create a test harness that will run your code for 100 different seed values ranging from 1–100. This
    could simply be a script that looped over these values.
    This will create 100 versions of the simulation, so by selectively examining the output and/or computing
    summary statistics you can get a better sense of how well your simulation functions. In particular,
    changing the seed can reveal “edge cases”, that is a situation that occurs rarely (and might not have
    been in the sample output), which may lead to an error in your code.
    Additionally, from these outputs, you could perform some statistical analysis to inform the airport’s
    management about their questions. Note you do not need to answer these questions as part of this
    assessment (that process will be part of the Project Report for a different problem).
    11
    Detailed rubric
    You will be assessed on the following components of your work. [80 marks total]
    • Basic functionality: code implements the basic functionality of this queuing system, as per the specification.
    [40 marks]
    • Additional feature 1: code implements this feature correctly. [12 marks]
    • Additional feature 2: code implements this feature correctly. [12 marks]
    • Additional feature 3: code implements this feature correctly. [12 marks]
    • Code style: submission meets general style guidelines for good Julia code. [4 marks]
    The marking scheme for each component is given in detail below.
    Basic functionality

WX:codinghelp