simplekit 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|