From a581fda5562e6669d2a8a6f458fc924dcfa009eb Mon Sep 17 00:00:00 2001 From: pjs <pjs@alum.mit.edu> Date: Mon, 9 Jul 2018 12:36:29 -0700 Subject: [PATCH] Updated arg passing & demos --- demos/MyModelArgs.rb | 8 ++-- demos/sptf.rb | 89 ++++++++++++++++++++++++++++++++++++++++++++ lib/simplekit.rb | 6 +-- 3 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 demos/sptf.rb diff --git a/demos/MyModelArgs.rb b/demos/MyModelArgs.rb index ebbd404..d75ff65 100644 --- a/demos/MyModelArgs.rb +++ b/demos/MyModelArgs.rb @@ -7,13 +7,13 @@ class MyModel def init @x = 1 - schedule(:increment, rand(2), n: 1, c: 97) + schedule(:increment, rand(2), n: 1, char: 'z'.ord) end - def increment(n:, c:) + def increment(n:, char:) @x += n - schedule(:increment, 2.0 * rand(2), n: @x, c: c + 1) - printf "%f, %f, %c\n", model_time, @x, c + schedule(:increment, 2.0 * rand(2), n: @x, char: char - 1) + printf "%f, %f, %c\n", model_time, @x, char schedule(:halt, 0.0) if model_time > 10 end end diff --git a/demos/sptf.rb b/demos/sptf.rb new file mode 100644 index 0000000..e19ad0d --- /dev/null +++ b/demos/sptf.rb @@ -0,0 +1,89 @@ +#!/usr/bin/env ruby + +require_relative '../lib/simplekit' +require_relative '../lib/priority_queue' + +# Customer class to store arrival times and processing times. +class Customer + attr_reader :arrival_time, :processing_time + + def initialize(arrival, processing) + @arrival_time = arrival + @processing_time = processing + end + + include Comparable + def <=>(other) + processing_time <=> other.processing_time + end +end + +# Demonstration model of a shortest-processing-time-first queueing system. +# There are k servers and both the arrival and service processes could +# be anything. +class SPTF + include SimpleKit + + # Constructor - initializes the model parameters. + # param: arrivalRate - The rate at which customers arrive to the system. + # param: serviceRate - The rate at which individual servers serve. + # param: maxServers - The total number of servers in the system. + # param: closeTime - The time the server would like to shut down. + def initialize(arrivalRate, serviceRate, maxServers, closeTime) + @arrivalRate = arrivalRate + @serviceRate = serviceRate + @maxServers = maxServers + @closeTime = closeTime + end + + # Initialize the model state and schedule any necessary events. + def init + @numAvailableServers = @maxServers + @q = PriorityQueue.new + schedule(:arrival, 0.0) + end + + + # An arrival event generates a customer and their associated service + # time, adds the customer to the queue, schedules the next arrival, + # and schedules a beginService event if a server is available. + def arrival + @q.push Customer.new(model_time, exponential(@serviceRate)) + schedule(:arrival, exponential(@arrivalRate)) + schedule(:beginService, 0.0) if (@numAvailableServers > 0) + end + + # Start service for the first customer in line, removing that + # customer from the queue and utilizing one of the available + # servers. An endService will be scheduled. Report the current + # time and how long this customer spent in line. + def beginService + current_customer = @q.pop + @numAvailableServers -= 1 + schedule(:endService, current_customer.processing_time) + printf "%f,%f\n", model_time, model_time - current_customer.arrival_time + end + + # Frees up an available server, and schedules a beginService if + # anybody is waiting in line. If the line is empty and it's after + # the desired closing time, halt the simulation. + def endService + @numAvailableServers += 1 + if (@q.empty?) + halt if model_time >= @closeTime + else + schedule(:beginService, 0.0) + end + end + + # Exponential random variate generator. + # param: rate - The rate (= 1 / mean) of the distribution. + # returns: A realization of the specified distribution. + def exponential(rate) + -Math.log(rand) / rate + end + +end + +# Instantiate an SPTF object with a particular parameterization and run it. +SPTF.new(4.5, 1.0, 5, 100.0).run diff --git a/lib/simplekit.rb b/lib/simplekit.rb index 1f00ad3..96b5fd1 100644 --- a/lib/simplekit.rb +++ b/lib/simplekit.rb @@ -55,7 +55,7 @@ module SimpleKit # at invocation time. def schedule(event, delay, **args) raise 'Model scheduled event with negative delay.' if delay < 0 - @event_list.push EventNotice.new(event, @model_time, delay, args) + @event_list.push EventNotice.new(event, @model_time, delay, **args) end # Start execution of a model. The simulation +model_time+ is initialized @@ -71,7 +71,7 @@ module SimpleKit if current_event.args.empty? @user_model.send(current_event.event) else - @user_model.send(current_event.event, current_event.args) + @user_model.send(current_event.event, **current_event.args) end end end @@ -88,7 +88,7 @@ module SimpleKit private class EventNotice attr_reader :event, :time, :time_stamp, :args - def initialize(event, time, delay, **args) + def initialize(event, time, delay, args) @event = event @time_stamp = time @time = time + delay -- GitLab