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 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: []