simplekit 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/priority_queue.rb +90 -0
- data/lib/simplekit.rb +90 -0
- data/simplekit.gemspec +20 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b6161ac2dfac81db037d02c9b8c67c0c03b8c44c
|
4
|
+
data.tar.gz: 4fd108d466e784133715c59de4ff2f9e49b8e31d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d0f7a06954e3106acde5089fea579560a3b485d4bcc258f45473a439cf98b9f78bb6e72562f728214c2daefe29a6df50b5b9496deb60d1d93a2126ed0cbadffb
|
7
|
+
data.tar.gz: d8602e4a17b0b12793d1c03a789e8ee5a0fa91e6f539a0fa467a61963914decba6be8c2d0e6c5a46c2c872a7f3205ced7ee0f69a6ab04fa5f6ee98379bf3f44b
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Array-based PriorityQueue implementation
|
2
|
+
class PriorityQueue
|
3
|
+
def initialize
|
4
|
+
clear
|
5
|
+
end
|
6
|
+
|
7
|
+
def <<(element)
|
8
|
+
@elements << element
|
9
|
+
# bubble up the element that we just added
|
10
|
+
bubble_up(@elements.size - 1)
|
11
|
+
end
|
12
|
+
|
13
|
+
alias push <<
|
14
|
+
|
15
|
+
def peek
|
16
|
+
# the first element will always be the min, because of the heap constraint
|
17
|
+
@elements[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def pop
|
21
|
+
# remove the last element of the list
|
22
|
+
min = @elements[1]
|
23
|
+
|
24
|
+
# and make sure the tree is ordered again
|
25
|
+
bubble_down(1) unless empty?
|
26
|
+
min
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear
|
30
|
+
@elements = [nil]
|
31
|
+
end
|
32
|
+
|
33
|
+
def empty?
|
34
|
+
@elements.length < 2
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def bubble_up(index)
|
40
|
+
target = @elements[index]
|
41
|
+
loop do
|
42
|
+
parent_index = (index / 2)
|
43
|
+
|
44
|
+
# return if we reach the root or the parent is less than the child
|
45
|
+
if parent_index < 1 || @elements[parent_index] <= target
|
46
|
+
@elements[index] = target
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
# otherwise we exchange the child with the parent
|
51
|
+
@elements[index] = @elements[parent_index]
|
52
|
+
|
53
|
+
# and keep bubbling up
|
54
|
+
index = parent_index
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def bubble_down(index)
|
59
|
+
target = @elements.pop
|
60
|
+
return if empty?
|
61
|
+
loop do
|
62
|
+
child_index = (index * 2)
|
63
|
+
|
64
|
+
# stop if we reach the bottom of the tree
|
65
|
+
if child_index >= @elements.size
|
66
|
+
@elements[index] = target
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
# make sure we get the smallest child
|
71
|
+
not_the_last_element = child_index < @elements.size - 1
|
72
|
+
left_element = @elements[child_index]
|
73
|
+
right_element = @elements[child_index + 1]
|
74
|
+
child_index += 1 if not_the_last_element && right_element < left_element
|
75
|
+
|
76
|
+
# there is no need to continue if the parent element is already smaller
|
77
|
+
# then its children
|
78
|
+
if target <= @elements[child_index]
|
79
|
+
@elements[index] = target
|
80
|
+
return
|
81
|
+
end
|
82
|
+
|
83
|
+
@elements[index] = @elements[child_index]
|
84
|
+
|
85
|
+
# repeat the process until we reach a point where the parent
|
86
|
+
# is larger than its children
|
87
|
+
index = child_index
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/simplekit.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require_relative 'priority_queue'
|
2
|
+
|
3
|
+
# The +SimpleKit+ module provides basic event scheduling capabilities.
|
4
|
+
#
|
5
|
+
# Including +SimpleKit+ in your simulation model gives you methods +:run+,
|
6
|
+
# +:model_time+, +:schedule+, and +:halt+ as mixins. You <b>MUST NOT</b>
|
7
|
+
# provide your own implementations of methods with these names in your model.
|
8
|
+
# All but +:run+ are delegated to the +EventScheduler+ class.
|
9
|
+
module SimpleKit
|
10
|
+
# The set of module methods to be passed to the EventScheduler
|
11
|
+
# if not found in the model class.
|
12
|
+
DELEGATED_METHODS = [:model_time, :schedule, :halt].freeze
|
13
|
+
|
14
|
+
# Run your model by creating a new +EventScheduler+ and invoking its
|
15
|
+
# +run+ method.
|
16
|
+
def run
|
17
|
+
@my_sim = EventScheduler.new(self)
|
18
|
+
@my_sim.run
|
19
|
+
end
|
20
|
+
|
21
|
+
# If a method doesn't exist in the model class, try to delegate it
|
22
|
+
# to +EventScheduler+.
|
23
|
+
def method_missing(name, *args)
|
24
|
+
if DELEGATED_METHODS.include?(name)
|
25
|
+
@my_sim.send(name, *args)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Class +EventScheduler+ provides the computation engine for a
|
32
|
+
# discrete event simulation model. It uses an array-based priority
|
33
|
+
# queue implementation for the pending events list.
|
34
|
+
#
|
35
|
+
# Users must create a model class which:
|
36
|
+
# * implements an +init+ method;
|
37
|
+
# * Instantiates a model and invokes the +run+ method to start execution.
|
38
|
+
class EventScheduler
|
39
|
+
attr_reader :model_time, :user_model
|
40
|
+
|
41
|
+
# Initialize the +EventScheduler+ by remembering the specified model
|
42
|
+
# and setting up an empty event list.
|
43
|
+
def initialize(the_model)
|
44
|
+
@user_model = the_model
|
45
|
+
@event_list = PriorityQueue.new
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add an event to the pending events list.
|
49
|
+
#
|
50
|
+
# *Arguments*::
|
51
|
+
# - +event+ -> the event to be scheduled.
|
52
|
+
# - +delay+ -> the amount of time which should elapse before
|
53
|
+
# the event executes.
|
54
|
+
# - +args+ -> an optional list of arguments to pass to the event
|
55
|
+
# at invocation time.
|
56
|
+
def schedule(event, delay, *args)
|
57
|
+
raise 'Model scheduled event with negative delay.' if delay < 0
|
58
|
+
@event_list.push EventNotice.new(event, @model_time + delay, args)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Start execution of a model. The simulation +model_time+ is initialized
|
62
|
+
# to zero and the model is initialized via the mandatory +init+ method.
|
63
|
+
# Then loop while events are pending on the +event_list+. The event with
|
64
|
+
# the smallest time is popped, +model_time+ is updated to the event time,
|
65
|
+
# and the event method is invoked.
|
66
|
+
def run
|
67
|
+
@model_time = 0.0
|
68
|
+
@user_model.init
|
69
|
+
while (current_event = @event_list.pop)
|
70
|
+
@model_time = current_event.time
|
71
|
+
@user_model.send(current_event.event, *current_event.args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Clear the event list, which causes termination of the simulation.
|
76
|
+
# Never schedule any new events after invoking +halt+.
|
77
|
+
def halt
|
78
|
+
@event_list.clear
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# This is a private helper Struct for the EventScheduler class.
|
83
|
+
# Users should never try to access this directly.
|
84
|
+
EventNotice = Struct.new(:event, :time, *:args) do
|
85
|
+
include Comparable
|
86
|
+
def <=>(other)
|
87
|
+
time <=> other.time
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/simplekit.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
_VERSION = "0.4.5"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "simplekit"
|
6
|
+
s.version = _VERSION
|
7
|
+
s.date = "2017-12-01"
|
8
|
+
s.summary = "Discrete event simulation engine."
|
9
|
+
s.homepage = "https://gitlab.nps.edu/pjsanche/simplekit-ruby.git"
|
10
|
+
s.email = "pjs@alum.mit.edu"
|
11
|
+
s.description = "This is a minimal discrete event simulation scheduling algorithm for educational use."
|
12
|
+
s.author = "Paul J Sanchez"
|
13
|
+
s.files = %w[
|
14
|
+
simplekit.gemspec
|
15
|
+
lib/simplekit.rb
|
16
|
+
lib/priority_queue.rb
|
17
|
+
]
|
18
|
+
s.required_ruby_version = '>= 1.8.1'
|
19
|
+
s.license = 'MIT'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simplekit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul J Sanchez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-12-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: This is a minimal discrete event simulation scheduling algorithm for
|
14
|
+
educational use.
|
15
|
+
email: pjs@alum.mit.edu
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/priority_queue.rb
|
21
|
+
- lib/simplekit.rb
|
22
|
+
- simplekit.gemspec
|
23
|
+
homepage: https://gitlab.nps.edu/pjsanche/simplekit-ruby.git
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.8.1
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.6.14
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: Discrete event simulation engine.
|
47
|
+
test_files: []
|