yinspire 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|