yinspire 0.1.0
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.
- data/README +24 -0
- data/bench/pq/Makefile +5 -0
- data/bench/pq/bench.cc +321 -0
- data/bench/pq/bench.rb +125 -0
- data/bench/pq/bench_binaryheap.h +46 -0
- data/bench/pq/bench_calendarqueue.h +58 -0
- data/bench/pq/bench_pairingheap.h +61 -0
- data/bench/pq/bench_stlpq.h +46 -0
- data/bench/pq/benchmark.h +225 -0
- data/bench/pq/distribution.h +93 -0
- data/bench/pq/make.rb +24 -0
- data/bin/yinspire +186 -0
- data/examples/nets/gereon2005.c.json +93723 -0
- data/examples/nets/gereon2005.yin +232650 -0
- data/examples/nets/skorpion.graphml +396 -0
- data/examples/nets/spiketrains_angle_180.txt +8 -0
- data/lib/Algorithms/Array.h +52 -0
- data/lib/Algorithms/BinaryHeap.h +265 -0
- data/lib/Algorithms/CalendarQueue.h +257 -0
- data/lib/Algorithms/IndexedBinaryHeap.h +90 -0
- data/lib/Algorithms/PairingHeap.h +169 -0
- data/lib/Allocators/ChunkedFreelistAllocator.h +96 -0
- data/lib/Allocators/MemoryAllocator.h +45 -0
- data/lib/Allocators/RubyMemoryAllocator.h +37 -0
- data/lib/Yinspire.rb +69 -0
- data/lib/Yinspire/All.rb +10 -0
- data/lib/Yinspire/Core/NeuralEntity.rb +133 -0
- data/lib/Yinspire/Core/Neuron.rb +162 -0
- data/lib/Yinspire/Core/Scheduling/NeuralEntity.rb +123 -0
- data/lib/Yinspire/Core/Scheduling/Simulator.rb +94 -0
- data/lib/Yinspire/Core/Simulator.rb +36 -0
- data/lib/Yinspire/Core/StimuliMixin.rb +103 -0
- data/lib/Yinspire/Core/Stimulus.rb +25 -0
- data/lib/Yinspire/Core/Synapse.rb +64 -0
- data/lib/Yinspire/Dumpers/Dumper.rb +19 -0
- data/lib/Yinspire/Dumpers/Dumper_Dot.rb +28 -0
- data/lib/Yinspire/Loaders/GraphML.rb +84 -0
- data/lib/Yinspire/Loaders/Loader.rb +31 -0
- data/lib/Yinspire/Loaders/Loader_GraphML.rb +97 -0
- data/lib/Yinspire/Loaders/Loader_JSON.rb +181 -0
- data/lib/Yinspire/Loaders/Loader_Spike.rb +42 -0
- data/lib/Yinspire/Loaders/Loader_Yin.rb +62 -0
- data/lib/Yinspire/Loaders/YinScanner.rb +247 -0
- data/lib/Yinspire/Models/Neuron_Base.rb +38 -0
- data/lib/Yinspire/Models/Neuron_Input.rb +12 -0
- data/lib/Yinspire/Models/Neuron_InputOutput.rb +39 -0
- data/lib/Yinspire/Models/Neuron_Output.rb +15 -0
- data/lib/Yinspire/Models/Neuron_SRM01.rb +50 -0
- data/lib/Yinspire/Models/Neuron_SRM02.rb +64 -0
- data/lib/Yinspire/Models/Synapse_Hebb.rb +67 -0
- data/pure_cpp/Makefile +22 -0
- data/pure_cpp/README +2 -0
- data/pure_cpp/src/algo/binary_heap.h +277 -0
- data/pure_cpp/src/algo/indexed_binary_heap.h +90 -0
- data/pure_cpp/src/json/json.cc +542 -0
- data/pure_cpp/src/json/json.h +182 -0
- data/pure_cpp/src/json/json_parser.cc +685 -0
- data/pure_cpp/src/json/json_parser.h +15 -0
- data/pure_cpp/src/json/json_parser.rl +213 -0
- data/pure_cpp/src/main.cc +49 -0
- data/pure_cpp/src/memory_allocator.h +45 -0
- data/pure_cpp/src/neural_entity.cc +208 -0
- data/pure_cpp/src/neural_entity.h +243 -0
- data/pure_cpp/src/neuron.cc +136 -0
- data/pure_cpp/src/neuron.h +70 -0
- data/pure_cpp/src/neuron_srm_01.cc +77 -0
- data/pure_cpp/src/neuron_srm_01.h +36 -0
- data/pure_cpp/src/simulator.cc +151 -0
- data/pure_cpp/src/simulator.h +116 -0
- data/pure_cpp/src/synapse.cc +117 -0
- data/pure_cpp/src/synapse.h +60 -0
- data/pure_cpp/src/types.h +18 -0
- data/run.rb +68 -0
- data/tools/conv_jsonc_to_yin.rb +165 -0
- data/tools/converter.rb +93 -0
- data/tools/json_writer.rb +122 -0
- data/yinspire.gemspec +20 -0
- metadata +156 -0
data/lib/Yinspire/All.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'Yinspire/Models/Neuron_Input'
|
2
|
+
require 'Yinspire/Models/Neuron_Output'
|
3
|
+
require 'Yinspire/Models/Neuron_SRM01'
|
4
|
+
require 'Yinspire/Models/Neuron_SRM02'
|
5
|
+
require 'Yinspire/Models/Synapse_Hebb'
|
6
|
+
require 'Yinspire/Loaders/Loader_JSON'
|
7
|
+
require 'Yinspire/Loaders/Loader_GraphML'
|
8
|
+
require 'Yinspire/Loaders/Loader_Yin'
|
9
|
+
require 'Yinspire/Loaders/Loader_Spike'
|
10
|
+
require 'Yinspire/Dumpers/Dumper_Dot'
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'Yinspire/Core/Simulator'
|
2
|
+
require 'Yinspire/Core/Scheduling/NeuralEntity'
|
3
|
+
|
4
|
+
#
|
5
|
+
# NeuralEntity is the base class of all entities in a neural net, i.e.
|
6
|
+
# Neurons and Synapses.
|
7
|
+
#
|
8
|
+
class NeuralEntity
|
9
|
+
|
10
|
+
#
|
11
|
+
# Entity type name to class mapping.
|
12
|
+
#
|
13
|
+
@@entity_type_map = Hash.new
|
14
|
+
def self.entity_type_map() @@entity_type_map end
|
15
|
+
|
16
|
+
|
17
|
+
#
|
18
|
+
# Entity class to type name mapping.
|
19
|
+
#
|
20
|
+
@@entity_type_map_reverse = Hash.new
|
21
|
+
def self.entity_type_map_reverse() @@entity_type_map_reverse end
|
22
|
+
|
23
|
+
def entity_type() @@entity_type_map_reverse[self.class] end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Annotation cache for loading entities.
|
27
|
+
#
|
28
|
+
@@entity_ann_load_cache = Hash.new
|
29
|
+
def self.entity_ann_load_cache() @@entity_ann_load_cache end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Annotation cache for dumping entities.
|
33
|
+
#
|
34
|
+
@@entity_ann_dump_cache = Hash.new
|
35
|
+
def self.entity_ann_dump_cache() @@entity_ann_dump_cache end
|
36
|
+
|
37
|
+
def self.new_from_name(name, *args, &block)
|
38
|
+
(@@entity_type_map[name] || raise(ArgumentError)).new(*args, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.class_from_name(name)
|
42
|
+
(@@entity_type_map[name] || raise(ArgumentError))
|
43
|
+
end
|
44
|
+
|
45
|
+
def load(hash)
|
46
|
+
a = @@entity_ann_load_cache[self.class]
|
47
|
+
hash.each {|key, value|
|
48
|
+
if meth = a[key]
|
49
|
+
send(meth, value)
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def dump
|
55
|
+
hash = Hash.new
|
56
|
+
@@entity_ann_dump_cache[self.class].each {|key|
|
57
|
+
hash[key] = send(key)
|
58
|
+
}
|
59
|
+
hash
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(id=nil, simulator=nil, &block)
|
63
|
+
self.id = id
|
64
|
+
self.simulator = simulator
|
65
|
+
block.call(self) if block
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Each NeuralEntity has an +id+ associated which uniquely identifies
|
70
|
+
# itself within a Simulator instance. This +id+ is usually assigned by the
|
71
|
+
# Simulator (during loading or constructing a neural net) and SHOULD
|
72
|
+
# NOT be changed afterwards (because it's used as a key in a Hash).
|
73
|
+
#
|
74
|
+
property :id
|
75
|
+
|
76
|
+
#
|
77
|
+
# Each NeuralEntity has a reference back to the Simulator. This is
|
78
|
+
# used for example to update it's scheduling or to report a fire
|
79
|
+
# event.
|
80
|
+
#
|
81
|
+
# Like +id+, this is assigned by the Simulator.
|
82
|
+
#
|
83
|
+
property :simulator, Simulator
|
84
|
+
|
85
|
+
#
|
86
|
+
# Connect +self+ with +target+.
|
87
|
+
#
|
88
|
+
def connect(target) raise "abstract method" end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Disconnect +self+ from all connections.
|
92
|
+
#
|
93
|
+
def disconnect(target) raise "abstract method" end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Iterates over each connection. To be overwritten by subclasses!
|
97
|
+
#
|
98
|
+
def each_connection() raise "abstract method" end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Disconnect +self+ from all connections.
|
102
|
+
#
|
103
|
+
def disconnect_all
|
104
|
+
each_connection {|conn| disconnect(conn) }
|
105
|
+
end
|
106
|
+
|
107
|
+
virtual :stimulate, :process, :process_stepped
|
108
|
+
|
109
|
+
#
|
110
|
+
# Stimulate an entity +at+ a specific time with a specific +weight+
|
111
|
+
# and from a specific +source+.
|
112
|
+
#
|
113
|
+
# Overwrite!
|
114
|
+
#
|
115
|
+
method :stimulate, {:at => 'simtime'},{:weight => 'real'},{:source => NeuralEntity}, nil
|
116
|
+
|
117
|
+
#
|
118
|
+
# This method is called when a NeuralEntity reaches it's scheduling
|
119
|
+
# time.
|
120
|
+
#
|
121
|
+
# Overwrite if you need this behaviour!
|
122
|
+
#
|
123
|
+
method :process, {:at => 'simtime'}, nil
|
124
|
+
|
125
|
+
#
|
126
|
+
# This method is called in each time-step, if and only if a
|
127
|
+
# NeuralEntity had enabled stepped scheduling.
|
128
|
+
#
|
129
|
+
# Overwrite if you need this behaviour!
|
130
|
+
#
|
131
|
+
method :process_stepped, {:at => 'simtime'},{:step => 'simtime'}, nil
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'Yinspire/Core/NeuralEntity'
|
2
|
+
require 'Yinspire/Core/Synapse'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Base class of all Neurons. Defines the structure that is special for a
|
6
|
+
# Neuron, i.e. that a Neuron has pre- and post-Synapses.
|
7
|
+
#
|
8
|
+
class Neuron < NeuralEntity
|
9
|
+
|
10
|
+
property :first_pre_synapse, Synapse
|
11
|
+
property :first_post_synapse, Synapse
|
12
|
+
property :last_pre_synapse, Synapse
|
13
|
+
property :last_post_synapse, Synapse
|
14
|
+
|
15
|
+
def add_pre_synapse(syn)
|
16
|
+
raise ArgumentError, "Synapse expected" unless syn.kind_of?(Synapse)
|
17
|
+
raise "Synapse already connected" if syn.post_neuron || syn.next_pre_synapse
|
18
|
+
|
19
|
+
if last = self.last_pre_synapse
|
20
|
+
assert(last.next_pre_synapse == nil) # missing method: neuron instead of synapse
|
21
|
+
last.next_pre_synapse = syn
|
22
|
+
self.last_pre_synapse = syn # advance tail pointer
|
23
|
+
else
|
24
|
+
assert(self.first_pre_synapse == nil)
|
25
|
+
self.first_pre_synapse = self.last_pre_synapse = syn
|
26
|
+
end
|
27
|
+
|
28
|
+
syn.post_neuron = self
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_post_synapse(syn)
|
32
|
+
raise ArgumentError, "Synapse expected" unless syn.kind_of?(Synapse)
|
33
|
+
raise "Synapse already connected" if syn.pre_neuron || syn.next_post_synapse
|
34
|
+
|
35
|
+
if last = self.last_post_synapse
|
36
|
+
assert(last.next_post_synapse == nil)
|
37
|
+
last.next_post_synapse = syn
|
38
|
+
self.last_post_synapse = syn # advance tail pointer
|
39
|
+
else
|
40
|
+
assert(self.first_post_synapse == nil)
|
41
|
+
self.first_post_synapse = self.last_post_synapse = syn
|
42
|
+
end
|
43
|
+
|
44
|
+
syn.pre_neuron = self
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_pre_synapse(syn)
|
48
|
+
raise ArgumentError, "Synapse expected" unless syn.kind_of?(Synapse)
|
49
|
+
raise "Synapse not connected to this Neuron" if syn.post_neuron != self
|
50
|
+
|
51
|
+
prev = find_preceding_synapse(syn, first_pre_synapse(), :next_pre_syapse)
|
52
|
+
|
53
|
+
#
|
54
|
+
# Remove +target+ from linked list.
|
55
|
+
#
|
56
|
+
if prev
|
57
|
+
prev.next_pre_synapse = target.next_post_synapse
|
58
|
+
self.last_post_synapse = prev if self.last_post_synapse == target
|
59
|
+
else
|
60
|
+
#
|
61
|
+
# target is the only synapse in the post synapse list.
|
62
|
+
#
|
63
|
+
assert self.first_post_synapse == target
|
64
|
+
assert self.last_post_synapse == target
|
65
|
+
self.first_post_synapse = nil
|
66
|
+
self.last_post_synapse = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
target.pre_neuron = nil
|
70
|
+
target.next_post_synapse = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def delete_post_synapse(syn)
|
74
|
+
# FIXME
|
75
|
+
raise "target must be Synapse" unless target.kind_of?(Synapse)
|
76
|
+
raise "Synapse not connected to this Neuron" if target.pre_neuron != self
|
77
|
+
|
78
|
+
#
|
79
|
+
# Find the synapse in the linked list that precedes +target+.
|
80
|
+
#
|
81
|
+
prev = nil
|
82
|
+
curr = self.first_post_synapse
|
83
|
+
|
84
|
+
while true
|
85
|
+
break if curr == target
|
86
|
+
break unless curr
|
87
|
+
prev = curr
|
88
|
+
curr = curr.next_post_synapse
|
89
|
+
end
|
90
|
+
|
91
|
+
raise "Synapse not in post synapse list" if curr != target
|
92
|
+
|
93
|
+
#
|
94
|
+
# Remove +target+ from linked list.
|
95
|
+
#
|
96
|
+
if prev
|
97
|
+
prev.next_post_synapse = target.next_post_synapse
|
98
|
+
self.last_post_synapse = prev if self.last_post_synapse == target
|
99
|
+
else
|
100
|
+
#
|
101
|
+
# target is the only synapse in the post synapse list.
|
102
|
+
#
|
103
|
+
assert self.first_post_synapse == target
|
104
|
+
assert self.last_post_synapse == target
|
105
|
+
self.first_post_synapse = nil
|
106
|
+
self.last_post_synapse = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
target.pre_neuron = nil
|
110
|
+
target.next_post_synapse = nil
|
111
|
+
end
|
112
|
+
|
113
|
+
alias connect add_post_synapse
|
114
|
+
alias disconnect delete_post_synapse
|
115
|
+
|
116
|
+
#
|
117
|
+
# Iterates over each outgoing connection (post synapses).
|
118
|
+
#
|
119
|
+
def each_connection
|
120
|
+
syn = self.first_post_synapse
|
121
|
+
while syn
|
122
|
+
yield syn
|
123
|
+
syn = syn.next_post_synapse
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
#
|
130
|
+
# Find the synapse in the linked list that precedes +syn+, starting
|
131
|
+
# at synapse +first+ and using the +next_method+ chain (e.g.
|
132
|
+
# :next_pre_synapse or :next_post_synapse).
|
133
|
+
#
|
134
|
+
def find_preceding_synapse(syn, first, next_method)
|
135
|
+
prev, curr = nil, first
|
136
|
+
|
137
|
+
while true
|
138
|
+
break if curr == syn
|
139
|
+
break unless curr
|
140
|
+
prev = curr
|
141
|
+
curr = curr.send(next_method)
|
142
|
+
end
|
143
|
+
|
144
|
+
raise "Synapse not in pre synapse list" if curr != syn
|
145
|
+
return prev
|
146
|
+
end
|
147
|
+
|
148
|
+
method :stimulate_pre_synapses, {:at => 'simtime'}, {:weight => 'real'}, %{
|
149
|
+
for (Synapse *syn = @first_pre_synapse; syn != NULL; syn = syn->next_pre_synapse)
|
150
|
+
{
|
151
|
+
syn->stimulate(at, weight, this);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
method :stimulate_post_synapses, {:at => 'simtime'}, {:weight => 'real'}, %{
|
156
|
+
for (Synapse *syn = @first_post_synapse; syn != NULL; syn = syn->next_post_synapse)
|
157
|
+
{
|
158
|
+
syn->stimulate(at, weight, this);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
#
|
2
|
+
# Extends class NeuralEntity for methods related to
|
3
|
+
# scheduling.
|
4
|
+
#
|
5
|
+
class NeuralEntity
|
6
|
+
|
7
|
+
#
|
8
|
+
# The index of this entity in the entity priority queue managed by the
|
9
|
+
# Simulator. If +schedule_index+ is zero then the entity is currently
|
10
|
+
# not present in the priority queue and as such the entity is not
|
11
|
+
# scheduled at a specific time.
|
12
|
+
#
|
13
|
+
property :schedule_index, 'uint'
|
14
|
+
|
15
|
+
#
|
16
|
+
# If the entity has events in the future, this is the timestamp of the
|
17
|
+
# next event.
|
18
|
+
#
|
19
|
+
property :schedule_at, 'simtime', :init => Infinity
|
20
|
+
|
21
|
+
#
|
22
|
+
# If stepped scheduling is used, these two properties reference the
|
23
|
+
# previous/next entity in the stepped-scheduling list.
|
24
|
+
#
|
25
|
+
property :schedule_stepping_list_prev, NeuralEntity
|
26
|
+
property :schedule_stepping_list_next, NeuralEntity
|
27
|
+
|
28
|
+
#
|
29
|
+
# To be able to modify the stepped scheduling list
|
30
|
+
# (schedule_stepping_list_prev/next) during stepped schedule
|
31
|
+
# processing, we build up an internal linked list that we use to
|
32
|
+
# traverse all entities that require stepped schedule processing.
|
33
|
+
#
|
34
|
+
# This is cheaper than using an externalized linked list, as we would
|
35
|
+
# have to allocate memory which we overcome with this approach.
|
36
|
+
#
|
37
|
+
# This is only used by the simulator!
|
38
|
+
#
|
39
|
+
property :schedule_stepping_list_internal_next, NeuralEntity
|
40
|
+
|
41
|
+
#
|
42
|
+
# Schedule the entity at a specific time. Only schedule if the new
|
43
|
+
# schedule time is before the current schedule time.
|
44
|
+
#
|
45
|
+
method :schedule, {:at => 'simtime'}, %{
|
46
|
+
// FIXME: make sure that @schedule_at is
|
47
|
+
// reset when entity is removed from pq!
|
48
|
+
if (at < @schedule_at)
|
49
|
+
{
|
50
|
+
@schedule_at = at;
|
51
|
+
@simulator->schedule_update(this);
|
52
|
+
}
|
53
|
+
}, :inline => true
|
54
|
+
|
55
|
+
#
|
56
|
+
# Returns +true+ if stepped scheduling is enabled, +false+ otherwise.
|
57
|
+
#
|
58
|
+
method :schedule_stepping_enabled, {:returns => 'bool'}, %{
|
59
|
+
return (@schedule_stepping_list_prev != NULL &&
|
60
|
+
@schedule_stepping_list_next != NULL);
|
61
|
+
}
|
62
|
+
|
63
|
+
#
|
64
|
+
# Enables stepped scheduling.
|
65
|
+
#
|
66
|
+
method :schedule_enable_stepping, {}, %{
|
67
|
+
if (!schedule_stepping_enabled())
|
68
|
+
{
|
69
|
+
NeuralEntity*& root = @simulator->schedule_stepping_list_root;
|
70
|
+
if (root != NULL)
|
71
|
+
{
|
72
|
+
@schedule_stepping_list_prev = root;
|
73
|
+
@schedule_stepping_list_next = root->schedule_stepping_list_next;
|
74
|
+
root->schedule_stepping_list_next = this;
|
75
|
+
@schedule_stepping_list_next->schedule_stepping_list_prev = this;
|
76
|
+
}
|
77
|
+
else
|
78
|
+
{
|
79
|
+
root = this;
|
80
|
+
@schedule_stepping_list_prev = this;
|
81
|
+
@schedule_stepping_list_next = this;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
#
|
87
|
+
# Disables stepped scheduling.
|
88
|
+
#
|
89
|
+
method :schedule_disable_stepping, {}, %{
|
90
|
+
if (schedule_stepping_enabled())
|
91
|
+
{
|
92
|
+
if (@schedule_stepping_list_prev != @schedule_stepping_list_next)
|
93
|
+
{
|
94
|
+
@schedule_stepping_list_prev->schedule_stepping_list_next = @schedule_stepping_list_next;
|
95
|
+
@schedule_stepping_list_next->schedule_stepping_list_prev = @schedule_stepping_list_prev;
|
96
|
+
}
|
97
|
+
else
|
98
|
+
{
|
99
|
+
/*
|
100
|
+
* We are the last entity in the stepping list.
|
101
|
+
*/
|
102
|
+
@simulator->schedule_stepping_list_root = NULL;
|
103
|
+
@schedule_stepping_list_prev = NULL;
|
104
|
+
@schedule_stepping_list_next = NULL;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
#
|
110
|
+
# Accessor function for BinaryHeap
|
111
|
+
#
|
112
|
+
static_method :less, {:a => NeuralEntity},{:b => NeuralEntity},{:returns => 'bool'}, %{
|
113
|
+
return (a->schedule_at < b->schedule_at);
|
114
|
+
}, :inline => true
|
115
|
+
|
116
|
+
#
|
117
|
+
# Accessor function for BinaryHeap
|
118
|
+
#
|
119
|
+
static_method :index, {:a => NeuralEntity},{:returns => 'uint&'}, %{
|
120
|
+
return a->schedule_index;
|
121
|
+
}, :inline => true
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'Yinspire/Core/NeuralEntity'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Extends class Simulator for methods related to
|
5
|
+
# scheduling.
|
6
|
+
#
|
7
|
+
class Simulator
|
8
|
+
|
9
|
+
#
|
10
|
+
# The current simulation time.
|
11
|
+
#
|
12
|
+
property :schedule_current_time, 'simtime'
|
13
|
+
|
14
|
+
#
|
15
|
+
# The time step used for stepped scheduling.
|
16
|
+
#
|
17
|
+
property :schedule_step, 'simtime', :init => Infinity
|
18
|
+
|
19
|
+
#
|
20
|
+
# The time of the next step.
|
21
|
+
#
|
22
|
+
property :schedule_next_step, 'simtime', :init => Infinity
|
23
|
+
|
24
|
+
#
|
25
|
+
# Priority queue used to schedule the entities.
|
26
|
+
#
|
27
|
+
property :schedule_pq, 'IndexedBinaryHeap<NeuralEntity*, MemoryAllocator<NeuralEntity*>, NeuralEntity>',
|
28
|
+
:mark => 'mark_schedule_pq()'
|
29
|
+
|
30
|
+
method :mark_schedule_pq, {}, %{
|
31
|
+
@schedule_pq.each(Simulator::mark_schedule_pq_iter, NULL);
|
32
|
+
}
|
33
|
+
|
34
|
+
static_method :mark_schedule_pq_iter, {:s => 'NeuralEntity* const&'}, {:ptr => 'void*'}, %{
|
35
|
+
if (s) rb_gc_mark(s->__obj__);
|
36
|
+
}
|
37
|
+
|
38
|
+
#
|
39
|
+
# If stepped scheduling is used, this points to the first entiy in the
|
40
|
+
# stepped schedule list.
|
41
|
+
#
|
42
|
+
property :schedule_stepping_list_root, NeuralEntity
|
43
|
+
|
44
|
+
#
|
45
|
+
# Run the simulation.
|
46
|
+
#
|
47
|
+
method :schedule_run, {:stop_at => 'simtime'}, %{
|
48
|
+
while (true)
|
49
|
+
{
|
50
|
+
simtime next_stop = MIN(stop_at, @schedule_next_step);
|
51
|
+
|
52
|
+
/*
|
53
|
+
* Calculate all events from the priority queue until the next time
|
54
|
+
* step is reached.
|
55
|
+
*/
|
56
|
+
while (!@schedule_pq.empty())
|
57
|
+
{
|
58
|
+
NeuralEntity *top = @schedule_pq.top();
|
59
|
+
if (top->schedule_at >= next_stop)
|
60
|
+
break;
|
61
|
+
@schedule_current_time = top->schedule_at;
|
62
|
+
@schedule_pq.pop();
|
63
|
+
top->process(top->schedule_at);
|
64
|
+
}
|
65
|
+
|
66
|
+
if (@schedule_current_time >= stop_at)
|
67
|
+
break;
|
68
|
+
|
69
|
+
if (@schedule_stepping_list_root == NULL && @schedule_pq.empty())
|
70
|
+
break;
|
71
|
+
|
72
|
+
/*
|
73
|
+
* Calculate the entities that require stepped processing.
|
74
|
+
*/
|
75
|
+
@schedule_current_time = @schedule_next_step;
|
76
|
+
|
77
|
+
if (@schedule_stepping_list_root != NULL)
|
78
|
+
{
|
79
|
+
// FIXME: collect all entities in an array. then process them.
|
80
|
+
}
|
81
|
+
|
82
|
+
@schedule_next_step += @schedule_step;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
#
|
87
|
+
# If an entity has changed it's scheduling time, it has to call this
|
88
|
+
# method to reflect the change within the priority queue.
|
89
|
+
#
|
90
|
+
method :schedule_update, {:entity => NeuralEntity}, %{
|
91
|
+
@schedule_pq.update(entity);
|
92
|
+
}, :inline => true
|
93
|
+
|
94
|
+
end
|