yinspire 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/README +24 -0
  2. data/bench/pq/Makefile +5 -0
  3. data/bench/pq/bench.cc +321 -0
  4. data/bench/pq/bench.rb +125 -0
  5. data/bench/pq/bench_binaryheap.h +46 -0
  6. data/bench/pq/bench_calendarqueue.h +58 -0
  7. data/bench/pq/bench_pairingheap.h +61 -0
  8. data/bench/pq/bench_stlpq.h +46 -0
  9. data/bench/pq/benchmark.h +225 -0
  10. data/bench/pq/distribution.h +93 -0
  11. data/bench/pq/make.rb +24 -0
  12. data/bin/yinspire +186 -0
  13. data/examples/nets/gereon2005.c.json +93723 -0
  14. data/examples/nets/gereon2005.yin +232650 -0
  15. data/examples/nets/skorpion.graphml +396 -0
  16. data/examples/nets/spiketrains_angle_180.txt +8 -0
  17. data/lib/Algorithms/Array.h +52 -0
  18. data/lib/Algorithms/BinaryHeap.h +265 -0
  19. data/lib/Algorithms/CalendarQueue.h +257 -0
  20. data/lib/Algorithms/IndexedBinaryHeap.h +90 -0
  21. data/lib/Algorithms/PairingHeap.h +169 -0
  22. data/lib/Allocators/ChunkedFreelistAllocator.h +96 -0
  23. data/lib/Allocators/MemoryAllocator.h +45 -0
  24. data/lib/Allocators/RubyMemoryAllocator.h +37 -0
  25. data/lib/Yinspire.rb +69 -0
  26. data/lib/Yinspire/All.rb +10 -0
  27. data/lib/Yinspire/Core/NeuralEntity.rb +133 -0
  28. data/lib/Yinspire/Core/Neuron.rb +162 -0
  29. data/lib/Yinspire/Core/Scheduling/NeuralEntity.rb +123 -0
  30. data/lib/Yinspire/Core/Scheduling/Simulator.rb +94 -0
  31. data/lib/Yinspire/Core/Simulator.rb +36 -0
  32. data/lib/Yinspire/Core/StimuliMixin.rb +103 -0
  33. data/lib/Yinspire/Core/Stimulus.rb +25 -0
  34. data/lib/Yinspire/Core/Synapse.rb +64 -0
  35. data/lib/Yinspire/Dumpers/Dumper.rb +19 -0
  36. data/lib/Yinspire/Dumpers/Dumper_Dot.rb +28 -0
  37. data/lib/Yinspire/Loaders/GraphML.rb +84 -0
  38. data/lib/Yinspire/Loaders/Loader.rb +31 -0
  39. data/lib/Yinspire/Loaders/Loader_GraphML.rb +97 -0
  40. data/lib/Yinspire/Loaders/Loader_JSON.rb +181 -0
  41. data/lib/Yinspire/Loaders/Loader_Spike.rb +42 -0
  42. data/lib/Yinspire/Loaders/Loader_Yin.rb +62 -0
  43. data/lib/Yinspire/Loaders/YinScanner.rb +247 -0
  44. data/lib/Yinspire/Models/Neuron_Base.rb +38 -0
  45. data/lib/Yinspire/Models/Neuron_Input.rb +12 -0
  46. data/lib/Yinspire/Models/Neuron_InputOutput.rb +39 -0
  47. data/lib/Yinspire/Models/Neuron_Output.rb +15 -0
  48. data/lib/Yinspire/Models/Neuron_SRM01.rb +50 -0
  49. data/lib/Yinspire/Models/Neuron_SRM02.rb +64 -0
  50. data/lib/Yinspire/Models/Synapse_Hebb.rb +67 -0
  51. data/pure_cpp/Makefile +22 -0
  52. data/pure_cpp/README +2 -0
  53. data/pure_cpp/src/algo/binary_heap.h +277 -0
  54. data/pure_cpp/src/algo/indexed_binary_heap.h +90 -0
  55. data/pure_cpp/src/json/json.cc +542 -0
  56. data/pure_cpp/src/json/json.h +182 -0
  57. data/pure_cpp/src/json/json_parser.cc +685 -0
  58. data/pure_cpp/src/json/json_parser.h +15 -0
  59. data/pure_cpp/src/json/json_parser.rl +213 -0
  60. data/pure_cpp/src/main.cc +49 -0
  61. data/pure_cpp/src/memory_allocator.h +45 -0
  62. data/pure_cpp/src/neural_entity.cc +208 -0
  63. data/pure_cpp/src/neural_entity.h +243 -0
  64. data/pure_cpp/src/neuron.cc +136 -0
  65. data/pure_cpp/src/neuron.h +70 -0
  66. data/pure_cpp/src/neuron_srm_01.cc +77 -0
  67. data/pure_cpp/src/neuron_srm_01.h +36 -0
  68. data/pure_cpp/src/simulator.cc +151 -0
  69. data/pure_cpp/src/simulator.h +116 -0
  70. data/pure_cpp/src/synapse.cc +117 -0
  71. data/pure_cpp/src/synapse.h +60 -0
  72. data/pure_cpp/src/types.h +18 -0
  73. data/run.rb +68 -0
  74. data/tools/conv_jsonc_to_yin.rb +165 -0
  75. data/tools/converter.rb +93 -0
  76. data/tools/json_writer.rb +122 -0
  77. data/yinspire.gemspec +20 -0
  78. metadata +156 -0
@@ -0,0 +1,181 @@
1
+ require 'Yinspire/Loaders/Loader'
2
+ require 'yaml' # YAML is a superset of JSON
3
+
4
+ class Loader_JSON < Loader
5
+
6
+ def load(filename)
7
+ @entities = Hash.new
8
+ data = YAML.load(File.read(filename))
9
+
10
+ case data['format']
11
+ when 'yinspire.1'
12
+ load_v1(data)
13
+ when 'yinspire.c'
14
+ load_c(data)
15
+ else
16
+ raise "invalid format"
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ #
23
+ # Format:
24
+ #
25
+ # {
26
+ # templates: {
27
+ # 'MyNeuron' => ['Neuron_SRM01', {tau_m: 0.5, :ref_weight: 0.1}],
28
+ # 'MySynapse' => ['Synapse', {weight: 1.0, delay: 0.5}]
29
+ # },
30
+ # entities: {
31
+ # 'id1' => ['MyNeuron', {tau_m: 5.1, const_threshold: 0.44}],
32
+ # 'id2' => ['Neuron_SRM01', {}],
33
+ # 'id3' => ['MySynapse'],
34
+ # 'id4' => 'MyNeuron'
35
+ # },
36
+ # connections: {
37
+ # 'id1' => ['id2', 'id3'],
38
+ # 'id2' => ['id1']
39
+ # },
40
+ # events: {
41
+ # 'id1' => [100.0, 101.0, timestamp_x, timestamp_y],
42
+ # 'id2' => [444, 555]
43
+ # }
44
+ # }
45
+ #
46
+ # Every "section" is optional.
47
+ #
48
+ def load_v1(data)
49
+ templates = data['templates'] || {}
50
+ entities = data['entities'] || {}
51
+ connections = data['connections'] || {}
52
+ events = data['events'] || {}
53
+
54
+ #
55
+ # construct entities
56
+ #
57
+ hash = Hash.new
58
+ entities.each do |id, entity_spec|
59
+ type, data = *entity_spec
60
+
61
+ if t = templates[type]
62
+ type, template_data = *t
63
+ hash.update(template_data) if template_data
64
+ end
65
+
66
+ hash.update(data) if data
67
+
68
+ create_entity(type, id, hash)
69
+
70
+ hash.clear
71
+ end
72
+
73
+ #
74
+ # connect them
75
+ #
76
+ connections.each do |src, destinations|
77
+ entity = @entities[src]
78
+ destinations.each do |dest|
79
+ entity.connect(@entities[dest])
80
+ end
81
+ end
82
+
83
+ #
84
+ # stimulate with events
85
+ #
86
+ events.each do |id, time_series|
87
+ entity = @entities[id]
88
+ time_series.each do |at|
89
+ entity.stimulate(at, Infinity, nil)
90
+ end
91
+ end
92
+ end
93
+
94
+ #
95
+ # This is a version for the pure C++ version of Yinspire. It doesn't
96
+ # use hashes for entities and connections (because the C++ JSON library
97
+ # does not implement efficient hash lookup).
98
+ #
99
+ # {
100
+ # templates: {
101
+ # 'MyNeuron' => ['Neuron_SRM01', {tau_m: 0.5, :ref_weight: 0.1}],
102
+ # 'MySynapse' => ['Synapse', {weight: 1.0, delay: 0.5}]
103
+ # },
104
+ # entities: [
105
+ # ['id1', 'MyNeuron'],
106
+ # ['id2', 'Neuron_SRM01'],
107
+ # ['id3', 'MySynapse'],
108
+ # ['id4', 'MyNeuron']
109
+ # ],
110
+ # connections: {
111
+ # ['id1', 'id2', 'id3'],
112
+ # ['id2', 'id1']
113
+ # },
114
+ # events: {
115
+ # 'id1' => [100.0, 101.0, timestamp_x, timestamp_y],
116
+ # 'id2' => [444, 555]
117
+ # }
118
+ # }
119
+ #
120
+ # Every "section" is optional.
121
+ #
122
+ # BUGS:
123
+ #
124
+ # The C++ version does not currently implement to specify an
125
+ # entity like this:
126
+ #
127
+ # ['id1', 'Neuron_SRM01', {...}]
128
+ #
129
+ def load_c(data)
130
+ templates = data['templates'] || {}
131
+ entities = data['entities'] || []
132
+ connections = data['connections'] || []
133
+ events = data['events'] || {}
134
+
135
+ #
136
+ # construct entities
137
+ #
138
+ hash = Hash.new
139
+ entities.each do |arr|
140
+ hash.clear
141
+
142
+ id, type, data = *arr
143
+
144
+ if t = templates[type]
145
+ type, template_data = *t
146
+ hash.update(template_data)
147
+ end
148
+
149
+ if data
150
+ hash.update(data)
151
+ raise # FIXME: C++ version is invalid, because it assume that there
152
+ # is no data!
153
+ end
154
+
155
+ create_entity(type, id, hash)
156
+ end
157
+
158
+ #
159
+ # connect them
160
+ #
161
+ connections.each do |arr|
162
+ src, *destinations = *arr
163
+ raise if destinations.empty?
164
+ entity = @entities[src] || raise
165
+ destinations.each do |dest|
166
+ entity.connect(@entities[dest] || raise)
167
+ end
168
+ end
169
+
170
+ #
171
+ # stimulate with events
172
+ #
173
+ events.each do |id, time_series|
174
+ entity = @entities[id] || raise
175
+ time_series.each do |at|
176
+ entity.stimulate(at, Infinity, nil)
177
+ end
178
+ end
179
+ end
180
+
181
+ end
@@ -0,0 +1,42 @@
1
+ require 'Yinspire/Loaders/Loader'
2
+
3
+ #
4
+ # Loader for spikes in the format:
5
+ #
6
+ # Id1 weight1@time1 time2 time3 ...
7
+ # Id2 time1 time2 time3 ...
8
+ # ...
9
+ #
10
+ # Weight values (e.g. 1.0@time1) are optional.
11
+ #
12
+ # Lines beginning with "#" are comments.
13
+ #
14
+ class Loader_Spike < Loader
15
+
16
+ def load(filename)
17
+ File.open(filename, 'r') do |f|
18
+ while line = f.gets
19
+ line.strip!
20
+ next if line =~ /^#/ # comment
21
+
22
+ #
23
+ # The following code is to help Matlab to generate spike trains
24
+ # more easily and allows spaces before and after the "@", e.g.
25
+ # "123 @ 444".
26
+ #
27
+ line.gsub!(/\s+@\s+/, '')
28
+
29
+ id, *spikes = line.split
30
+ raise if spikes.empty?
31
+ entity = @entities[id] || raise
32
+
33
+ spikes.each do |spike|
34
+ weight, at = spike.split("@")
35
+ weight, at = Infinity, weight if at.nil? # spike is a pure time-value
36
+ entity.stimulate(at.to_f, weight.to_f, nil)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,62 @@
1
+ require 'Yinspire/Loaders/Loader'
2
+ require 'Yinspire/Loaders/YinScanner'
3
+
4
+ #
5
+ # This is a human readable data format for describing neural nets
6
+ # as well as stimulations.
7
+ #
8
+ # Note that it is a streaming scanner/parser, i.e. it's important
9
+ # to put the template definitions before you actually use them.
10
+ # The same applies to stimulations and connections!
11
+ #
12
+ class Loader_Yin < Loader
13
+ require 'enumerator'
14
+
15
+ def load(filename)
16
+ templates = {}
17
+ hash = Hash.new
18
+ YinScanner.new(File.read(filename)).scan do |cmd|
19
+ case cmd.shift
20
+ when :entity
21
+ ids, type, prop_list = *cmd
22
+
23
+ hash.clear
24
+ if t = templates[type]
25
+ type, template_data = *t
26
+ hash.update(template_data) if template_data
27
+ end
28
+ hash.update(prop_list) if prop_list
29
+
30
+ ids.each {|id| create_entity(type, id, hash) }
31
+ when :connect
32
+ cmd.first.each_cons(2) do |from, to|
33
+ from.each {|f|
34
+ entity = @entities[f]
35
+ to.each {|t| entity.connect(@entities[t]) }
36
+ }
37
+ end
38
+ when :stimulate
39
+ ids, stimuls = *cmd
40
+
41
+ ids.map! {|id| @entities[id] }
42
+
43
+ stimuls.each do |sti|
44
+ at, weight = *sti
45
+ weight ||= Infinity
46
+ ids.each {|entity|
47
+ entity.stimulate(at, weight, nil)
48
+ }
49
+ end
50
+ when :template
51
+ ids, base_type, prop_list = *cmd
52
+ ids.each do |id|
53
+ raise if templates[id]
54
+ templates[id] = [base_type, prop_list]
55
+ end
56
+ else
57
+ raise
58
+ end
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,247 @@
1
+ class YinScanner
2
+ require 'strscan'
3
+
4
+ def initialize(str)
5
+ @s = StringScanner.new(str)
6
+ @inf = 1.0/0.0
7
+ end
8
+
9
+ def scan
10
+ while cmd = scan_command()
11
+ yield cmd
12
+ end
13
+ skip_ws()
14
+ raise "ParseError" unless @s.eos?
15
+ end
16
+
17
+ protected
18
+
19
+ def skip_ws
20
+ while @s.skip(/(\s+)/) or # skip whitespace
21
+ @s.skip(/[#](.*)/) # skip comments
22
+ end
23
+ end
24
+
25
+ def scan_property
26
+ pos = @s.pos
27
+ if name = scan_id()
28
+ skip_ws()
29
+ if @s.skip(/=/)
30
+ value = scan_value()
31
+ if value != nil
32
+ return name, value
33
+ end
34
+ end
35
+ end
36
+
37
+ @s.pos = pos
38
+ return nil
39
+ end
40
+
41
+ def scan_command
42
+ skip_ws()
43
+ type = nil
44
+ if str = @s.scan(/(TEMPLATE|ENTITY|CONNECT|STIMULATE)\s+/)
45
+ str.strip!
46
+ str.downcase!
47
+ type = str.to_sym
48
+ end
49
+
50
+ ids = scan_idlist()
51
+ raise "ParseError" if type != nil and ids.empty?
52
+ return nil if ids.empty?
53
+
54
+ scanned_type = scan_type()
55
+
56
+ raise "ParseError" if (type and type != scanned_type) or scanned_type.nil?
57
+
58
+ case scanned_type
59
+ when :entity, :template
60
+ id = scan_id()
61
+ raise "ParseError" unless id
62
+ prop_list = scan_propertylist()
63
+ return scanned_type, ids, id, prop_list
64
+ when :stimulate
65
+ stimuls = scan_stimulationlist()
66
+ raise "ParseError" unless stimuls
67
+ return scanned_type, ids, stimuls
68
+ when :connect
69
+ conns = []
70
+ conns << ids
71
+ loop do
72
+ l = scan_idlist()
73
+ break if l.empty?
74
+ conns << l
75
+
76
+ skip_ws()
77
+ break unless @s.skip(/->/)
78
+ end
79
+ raise "ParseError" if conns.size < 2
80
+ return scanned_type, conns
81
+ else
82
+ nil
83
+ end
84
+ end
85
+
86
+ def scan_propertylist
87
+ pos = @s.pos
88
+ skip_ws()
89
+ props = {}
90
+ if @s.skip(/[{]/)
91
+ loop do
92
+ name, value = scan_property()
93
+ break unless name
94
+ props[name] = value
95
+ end
96
+ skip_ws()
97
+ return props if @s.skip(/[}]/)
98
+ end
99
+
100
+ @s.pos = pos
101
+ return nil
102
+ end
103
+
104
+ def scan_value
105
+ skip_ws()
106
+ if str = @s.scan(/[+-]?[0-9]+([.][0-9]+([eE][+-]?[0-9]+)?)?/)
107
+ str.to_f
108
+ elsif @s.skip(/[+]?Inf(inity)?/i)
109
+ @inf
110
+ elsif @s.skip(/[-]?Inf(inity)?/i)
111
+ -@inf
112
+ elsif @s.skip(/true/)
113
+ true
114
+ elsif @s.skip(/false/)
115
+ false
116
+ else
117
+ nil
118
+ end
119
+ end
120
+
121
+ # no skip_ws!
122
+ def scan_float
123
+ if str = @s.scan(/[+-]?[0-9]+([.][0-9]+([eE][+-]?[0-9]+)?)?/)
124
+ str.to_f
125
+ elsif @s.skip(/[+]?Inf(inity)?/i)
126
+ @inf
127
+ elsif @s.skip(/[-]?Inf(inity)?/i)
128
+ -@inf
129
+ else
130
+ nil
131
+ end
132
+ end
133
+
134
+ def scan_stimulationlist
135
+ pos = @s.pos
136
+ skip_ws()
137
+ stimuls = []
138
+ if @s.skip(/[{]/)
139
+ loop do
140
+ arr = scan_stimulation()
141
+ break unless arr
142
+ stimuls << arr
143
+ end
144
+ skip_ws()
145
+ return stimuls if @s.skip(/[}]/)
146
+ end
147
+
148
+ @s.pos = pos
149
+ return nil
150
+ end
151
+
152
+ # [weight@]at
153
+ # no skip_ws!
154
+ #
155
+ def scan_stimulation
156
+ pos = @s.pos
157
+ skip_ws()
158
+
159
+ if at = scan_float()
160
+ if @s.skip(/@/)
161
+ weight = at
162
+ if at = scan_float()
163
+ return at, weight
164
+ end
165
+ else
166
+ return at
167
+ end
168
+ end
169
+
170
+ @s.pos = pos
171
+ return nil
172
+ end
173
+
174
+ def scan_id
175
+ pos = @s.pos
176
+ skip_ws()
177
+ if @s.skip(/["]/)
178
+ id = @s.scan(/[^"]+/)
179
+ unless @s.skip(/["]/)
180
+ @s.pos = pos
181
+ id = nil
182
+ end
183
+ else
184
+ id = @s.scan(/\w+/)
185
+ end
186
+ return id
187
+ end
188
+
189
+ def scan_idlist
190
+ ids = []
191
+ loop do
192
+ id = scan_id()
193
+ break unless id
194
+ ids << id
195
+ skip_ws()
196
+ break unless @s.skip(/,/) # we expect a "," here
197
+ end
198
+ ids
199
+ end
200
+
201
+ def scan_type
202
+ skip_ws()
203
+ if @s.skip(/[=]/) then :entity
204
+ elsif @s.skip(/->/) then :connect
205
+ elsif @s.skip(/[!]/) then :stimulate
206
+ elsif @s.skip(/[<]/) then :template
207
+ else
208
+ nil
209
+ end
210
+ end
211
+ end
212
+
213
+ if __FILE__ == $0
214
+ s = YinScanner.new(<<-EOS)
215
+ #
216
+ # This is a comment
217
+ # This also.
218
+ #
219
+ # Command names like "TEMPLATE", "ENTITY", "CONNECT" and "STIMULATE"
220
+ # are optional.
221
+ #
222
+
223
+ TEMPLATE InputType < Neuron_Input {
224
+ const_threshold = +1.2e+200
225
+ last_spike_time = -Infinity
226
+ }
227
+
228
+ ENTITY Input1, "input2", Input2, Input3 = InputType
229
+ ENTITY Input4 = InputType
230
+
231
+ Input5, Input6 = Neuron_SRM01 {
232
+ mem_pot = 10.0
233
+ }
234
+
235
+ Syn1, Syn2, Syn3 = Synapse {
236
+ weight = 2.3
237
+ delay = 0.4
238
+ }
239
+
240
+ CONNECT Input1 -> Syn1, Syn2 -> Input5
241
+
242
+ STIMULATE Input1, Input5 ! {
243
+ 123@4.4 Inf@23.3 4.5 # weight defaults to Infinity
244
+ }
245
+ EOS
246
+ s.scan {|cmd| p cmd}
247
+ end