#lang scribble/doc @(require scribble/manual scribblings/icons (for-label scheme/base plot/plot "../simulation-with-graphics.ss")) @title[#:tag "events"]{Events} @local-table-of-contents[] In a simulation model, an @deftech{event} represents an action that will take place in the (simulated) future. In the PLT Scheme Simulation Collection, an event represents the (smulated) future application of a procedural object to a list of arguments. @section{The @scheme[event] Structure} @schemeblock[ (struct event (_time _priority _process _function _arguments _event-list _linked-event-list)) time : (<=/c 0.0) priority : real? process : (or/c process? false/c) function : (or/c procedure? false/c) arguments : list? event-list : (or/c event-list? false/c) linked-event-list : (or/c event-list? false/c) ] Defines an event. Note that since the @schemefont{function} field can contain any procedural object, including a continuation, any event can call the @scheme[wait/work] function. This is a slight extension to the definition of event given above in that an event may represent a sequence of actions that take place over a (simulated) duration. @itemize{ @item{@schemefont{time}---The (simulated) time the event is to occur.} @item{@schemefont{priority}---The priority if the event. Priorities are real numbers with larger numbers representing higher priority.} @item{@schemefont{process}---The process owning the event or @scheme[#f] if the event does not belong to any process.} @item{@schemefont{function}---The procedural object that implements the event or @scheme{#f}.} @item{@schemefont{arguments}---A list of the arguments for the @schemefont{function}.} @item{@schemefont{event-list}---The event list in which the event is currently stored or @scheme[#f]. This is used when it is necessary to unschedule an event from whatever event list it might be stored in. An event can only be stored on one event list at any particular time.} @item{@schemefont{linked-event-list}--- An event list storing events that are linked to this one or @scheme[#f]. This is used to implement linked events (i.e. those scheduled using the @schemefont{(when @italic{event})} scheduling specification.)} } @defproc[(make-event (time (<=/c 0.0)) (priority real?) (process (or/c process? false/c)) (function (or/c procedure? false/c)) (arguments list?)) event?]{ Returns a newly created event with the corresponsing fields set to the values of @scheme[time], @scheme[priority], @scheme[function], and @scheme[arguments]. The @schemefont{event-list} and @schemefont{linked-event-list} fields are initialized to @scheme[#f]. Note that @scheme[make-event] is not typically used in user code. Instead, the @scheme[schedule] macro is used to create and schedule events.} @section{Event Lists} @(margin-note finger "It isn't generally necessary to explicitly manipulate the event lists in user code. See Chapter 13 Simulation Control (Advanced).") An @deftech{event list} stores a list of events. Events are stored in order of their @schemefont{time} and @schemefont{priority} values. @schemeblock[ (struct event-list (_events)) _events : list? ] Defines an event list. The current implementation just encapsulates a list that stores the events. @itemize{ @item{schemefont{events}---A list of the events on the event list.} } @defproc[(make-event-list) event-list?]{ Returns a new, empty event list.} @defproc[(event-list-empty? (event-list event-list?)) boolean?]{ Returns true, @scheme[#t], if the @scheme[event-list] is empty, and false, @scheme[#f], otherwise.} @defproc[(event-list-add! (event-list event-list?) (event event?)) any]{ Adds @scheme[event] to @scheme[event list]. Currently, the event list is ordered by @schemefont{time} and @schemefont{priority}.} @defproc[(event-list-remove! (event-list event-list?) (event event?)) any]{ Removes @scheme[event] from @scheme[event-list]. No error is signaled if the specified @scheme[event] is not on the event list.} @defproc[(event-list-pop! (event-list event-list?)) event?]{ Remove the first event from @scheme[event-list] and returns it.} @section{Example---Functions as Events} This example is a simulation model of a simple system. Customer arrivals are exponentialy distributed with an interrival time of four minutes. The time a customer remains in the system is uniformly distributed between two and ten minutes. The output is a simple trace of customer arrivals and departures. The random distribution functions are provided by the PLT Scheme Science Collection. @schememod[ scheme/base (code:comment "Example 0 - Functions as Events") (require (planet williams/simulation/simulation)) (require (planet williams/science/random-distributions)) (define (generator n) (for ((i (in-range n))) (wait (random-exponential 4.0)) (schedule now (customer i)))) (define (customer i) (printf "~a: customer ~a enters~n" (current-simulation-time) i) (work (random-flat 2.0 10.0)) (printf "~a: customer ~a leaves~n" (current-simulation-time) i)) (define (run-simulation n) (with-new-simulation-environment (schedule (at 0.0) (generator n)) (start-simulation))) (run-simulation 10) ] Produces the following output. @verbatim{ 0.6153910608822503: customer 0 enters 5.599485116393393: customer 1 enters 6.411843645405005: customer 2 enters 8.48917994426752: customer 0 leaves 10.275428842274628: customer 1 leaves 14.749397986170655: customer 2 leaves 23.525886616767437: customer 3 enters 27.18604340910279: customer 3 leaves 32.1644631797164: customer 4 enters 33.14558760001698: customer 5 enters 39.67682614849173: customer 4 leaves 40.486553934113665: customer 6 enters 41.168084930967424: customer 5 leaves 45.72670063299798: customer 6 leaves 46.747675912143016: customer 7 enters 49.212327970772435: customer 8 enters 50.556538752352886: customer 9 enters 51.46738784004611: customer 8 leaves 52.514846525674855: customer 7 leaves 56.11635302397275: customer 9 leaves } The @scheme[require] forms load the simulation collection and the @schemefont{random-distributions} subcollection of the science collection from PLaneT---downloading them if necessary. The @schemefont{generator} function generates customers into the system. It takes a single argument, @schemefont{n}, which is the total number of customers to generate. It provides the appropriate interrival time by waiting between each customer. After the wait, it schedules an event to represent the customer in the system. It does this @schemefont{n} times to generate the appropriate number of customers. The @schemefont{customer} function represents a unique customer in the system. It takes a single argument, @schemefont{i}, which is a unique integer between @math{0} and @math{n-1}, inclusive. The customer prints it's arrival, works a random length of time, prints it's departure, and ends. The @schemefont{run-simulation} function sets up and runs the simulation model. It creates a new simulation environment for the simulation model, schedules the generator to start execute as soon as the model starts (i.e. at time 0.0), and starts the simulation main loop by calling @scheme[start-simulation]. Note that the @scheme[with-new-simulation-environment] isn't actually required in this case. However, it is a good idea to always use it to ensure the simulation model begins execution with a clean simulation environment. Finally, the @schemefont{(run-simulation 10)} form executes the simulation model, specifying a total of ten customers. We will build on this trivial simulation model as we define more advanced simulation models. A few things to note at this point are: @itemize{ @item{Executing this simulation model will always give the same output---even across the various platforms supported by PLT Scheme. This is the default behavior of the random number generation package we are using.} @item{Events are basically the delayed execution of procedural objects under the control of the simulation main loop.} @item{Events can span simulated time. That is calls to @scheme[wait/work] (or, equivalently, @scheme[wait] or @scheme[work] perform as expected inside of events.)} @item{We will subsequently see that are many things that events can't do---such as utilize resources. But for simple elements, like the @schemefont{generator}, events are appropriate.} }