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.
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
data/README ADDED
@@ -0,0 +1,24 @@
1
+ ---------------------------------------------------------
2
+ Yinspire - An efficient spiking neural net simulator
3
+ ---------------------------------------------------------
4
+
5
+ COPYRIGHT
6
+
7
+ Copyright (c) 2007, 2008 by Michael Neumann (mneumann@ntecs.de).
8
+ All rights reserved.
9
+
10
+ LICENSE
11
+
12
+ Ruby License.
13
+
14
+ INSTALLATION
15
+
16
+ (should work on any Unix easily)
17
+ gem install yinspire
18
+
19
+ ABOUT
20
+
21
+ Yinspire is a very fast simulator for spiking neural nets. It's a
22
+ complete rewrite (using a mixture of Ruby and C++) of an existing
23
+ simulator called Inspire, which was developed at the University of
24
+ Karlsruhe.
@@ -0,0 +1,5 @@
1
+ build:
2
+ ruby make.rb
3
+
4
+ clean:
5
+ rm -rf bench work
@@ -0,0 +1,321 @@
1
+ #include "benchmark.h"
2
+ #include <time.h>
3
+ #include <stdlib.h>
4
+ #include <iostream>
5
+ #include <string>
6
+
7
+ struct ET_FLOAT
8
+ {
9
+ float priority;
10
+
11
+ bool operator ()(ET_FLOAT &a, ET_FLOAT &b) { return (a.priority > b.priority); }
12
+ static const char* element_type() { return "float"; }
13
+ static inline bool less(const ET_FLOAT &a, const ET_FLOAT &b) { return a.priority < b.priority; }
14
+ };
15
+
16
+
17
+ struct ET_DOUBLE
18
+ {
19
+ double priority;
20
+
21
+ bool operator ()(ET_DOUBLE &a, ET_DOUBLE &b) { return (a.priority > b.priority); }
22
+ static const char* element_type() { return "double"; }
23
+ static inline bool less(const ET_DOUBLE &a, const ET_DOUBLE &b) { return a.priority < b.priority; }
24
+ };
25
+
26
+
27
+ struct ET_STIMULI
28
+ {
29
+ float priority;
30
+ float weight;
31
+
32
+ inline bool operator ()(ET_STIMULI &a, ET_STIMULI &b) { return (a.priority > b.priority); }
33
+ static const char* element_type() { return "Stimuli/float"; }
34
+ static inline bool less(const ET_STIMULI &a, const ET_STIMULI &b) { return (a.priority < b.priority); }
35
+ };
36
+
37
+ /*
38
+ * Pairing heap needs additional fields
39
+ */
40
+ struct ET_STIMULI_PH
41
+ {
42
+ float priority;
43
+ float weight;
44
+
45
+ ET_STIMULI_PH *_next;
46
+ ET_STIMULI_PH *_previous;
47
+ ET_STIMULI_PH *_child;
48
+
49
+ inline static bool less(const ET_STIMULI_PH* e1, const ET_STIMULI_PH* e2)
50
+ {
51
+ return e1->priority < e2->priority;
52
+ }
53
+
54
+ inline static ET_STIMULI_PH*& next(ET_STIMULI_PH* e) { return e->_next; }
55
+ inline static ET_STIMULI_PH*& previous(ET_STIMULI_PH* e) { return e->_previous; }
56
+ inline static ET_STIMULI_PH*& child(ET_STIMULI_PH* e) { return e->_child; }
57
+
58
+ static const char* element_type() { return "Stimuli/float/PairingHeap"; }
59
+ };
60
+
61
+ /*
62
+ * Calendar queue needs an additional "next" field.
63
+ */
64
+ struct ET_STIMULI_CQ
65
+ {
66
+ float _priority;
67
+ float weight;
68
+
69
+ ET_STIMULI_CQ *_next;
70
+
71
+ inline static float priority(const ET_STIMULI_CQ* e)
72
+ {
73
+ return e->_priority;
74
+ }
75
+
76
+ inline static ET_STIMULI_CQ*& next(ET_STIMULI_CQ* e) { return e->_next; }
77
+
78
+ static const char* element_type() { return "Stimuli/float/CalendarQueue"; }
79
+ };
80
+
81
+ #include "bench_binaryheap.h"
82
+ #include "bench_pairingheap.h"
83
+ #include "bench_calendarqueue.h"
84
+ #include "bench_stlpq.h"
85
+
86
+ enum {
87
+ METHOD_CLASSIC_HOLD = 1,
88
+ METHOD_UPDOWN = 2
89
+ };
90
+
91
+ template<class ET, class PQ, class ACC>
92
+ void measure(Distribution *dis,
93
+ int queue_size,
94
+ int warmup_cycles,
95
+ int empty_cycles,
96
+ int cycles,
97
+ int method)
98
+ {
99
+ PQ pq;
100
+ Benchmark<PQ, ACC> bm(&pq, dis);
101
+ double time;
102
+ const char *method_name;
103
+
104
+ switch (method)
105
+ {
106
+ case METHOD_CLASSIC_HOLD:
107
+ time = bm.classic_hold(queue_size, warmup_cycles, empty_cycles, cycles);
108
+ method_name = "ClassicHold";
109
+ break;
110
+
111
+ case METHOD_UPDOWN:
112
+ time = bm.updown(queue_size, warmup_cycles, empty_cycles, cycles);
113
+ method_name = "UpDown";
114
+ break;
115
+
116
+ default:
117
+ throw "invalid method";
118
+ };
119
+
120
+ std::cout << "Method: " << method_name << std::endl;
121
+ std::cout << "Algorithm: " << ACC::algorithm_name() << std::endl;
122
+ std::cout << "ElementSize: " << sizeof(ET) << std::endl;
123
+ std::cout << "ElementType: " << ET::element_type() << std::endl;
124
+ std::cout << "Distribution: "; dis->output_name(std::cout); std::cout << std::endl;
125
+ std::cout << "QueueSize: " << queue_size << std::endl;
126
+ std::cout << "WarmupCycles: " << warmup_cycles << std::endl;
127
+ std::cout << "EmptyCycles: " << empty_cycles << std::endl;
128
+ std::cout << "Cycles: " << cycles << std::endl;
129
+ std::cout << "CompilerOptFlags: " << _COMPILER_OPTFLAGS_ << std::endl;
130
+ std::cout << "CompilerName: " << _COMPILER_NAME_ << std::endl;
131
+ std::cout << "CompileDate: " << _COMPILE_DATE_ << std::endl;
132
+ std::cout << "Uname: " << _UNAME_ << std::endl;
133
+ std::cout << "CpuFreq: " << _CPUFREQ_ << std::endl;
134
+ std::cout << "Time: " << time << std::endl;
135
+ std::cout << std::endl;
136
+ }
137
+
138
+ #define MEASURE(ns, et) measure<et, ns::T<et>::PQ, ns::T<et>::ACC>( \
139
+ dis, queue_size, warmup_cycles, empty_cycles, cycles, method);
140
+
141
+ #define ARG_GET(varname, meth) \
142
+ if (argp < argc) { \
143
+ varname = meth(argv[argp++]); \
144
+ } else { \
145
+ throw #varname " required"; \
146
+ }
147
+
148
+ void run(int argc, char **argv)
149
+ {
150
+ Distribution *dis;
151
+ int queue_size;
152
+ int warmup_cycles;
153
+ int empty_cycles;
154
+ int cycles;
155
+ int method;
156
+ std::string method_name;
157
+ std::string distribution;
158
+ std::string algorithm;
159
+ std::string element_type;
160
+
161
+ int argp = 1;
162
+
163
+ ARG_GET(queue_size, atoi);
164
+ ARG_GET(warmup_cycles, atoi);
165
+ ARG_GET(empty_cycles, atoi);
166
+ ARG_GET(cycles, atoi);
167
+
168
+ ARG_GET(method_name, std::string);
169
+
170
+ if (method_name == "ClassicHold")
171
+ {
172
+ method = METHOD_CLASSIC_HOLD;
173
+ }
174
+ else if (method_name == "UpDown")
175
+ {
176
+ method = METHOD_UPDOWN;
177
+ }
178
+ else
179
+ {
180
+ throw "invalid method name";
181
+ }
182
+
183
+ ARG_GET(distribution, std::string);
184
+
185
+ if (distribution == "Random")
186
+ {
187
+ dis = new RandomDistribution();
188
+ }
189
+ else if (distribution == "Exponential")
190
+ {
191
+ double exponential_a;
192
+ ARG_GET(exponential_a, atof);
193
+ dis = new ExponentialDistribution(exponential_a);
194
+ }
195
+ else if (distribution == "Uniform")
196
+ {
197
+ double uniform_a, uniform_b;
198
+ ARG_GET(uniform_a, atof);
199
+ ARG_GET(uniform_b, atof);
200
+ dis = new UniformDistribution(uniform_a, uniform_b);
201
+ }
202
+ else if (distribution == "Triangular")
203
+ {
204
+ double triangular_a, triangular_b;
205
+ ARG_GET(triangular_a, atof);
206
+ ARG_GET(triangular_b, atof);
207
+ dis = new TriangularDistribution(triangular_a, triangular_b);
208
+ }
209
+ else if (distribution == "NegativeTriangular")
210
+ {
211
+ double negtriangular_a, negtriangular_b;
212
+ ARG_GET(negtriangular_a, atof);
213
+ ARG_GET(negtriangular_b, atof);
214
+ dis = new NegativeTriangularDistribution(negtriangular_a, negtriangular_b);
215
+ }
216
+ else if (distribution == "Bimodal")
217
+ {
218
+ double bimodal_a, bimodal_b;
219
+ ARG_GET(bimodal_a, atof);
220
+ ARG_GET(bimodal_b, atof);
221
+ dis = new BimodalDistribution(bimodal_a, bimodal_b);
222
+ }
223
+ else if (distribution == "Pareto")
224
+ {
225
+ double pareto_a;
226
+ ARG_GET(pareto_a, atof);
227
+ dis = new ParetoDistribution(pareto_a);
228
+ }
229
+ else
230
+ {
231
+ throw "invalid distribution";
232
+ }
233
+
234
+ ARG_GET(algorithm, std::string);
235
+
236
+ if (algorithm == "BinaryHeap")
237
+ {
238
+ ARG_GET(element_type, std::string);
239
+
240
+ if (element_type == "FLOAT")
241
+ {
242
+ MEASURE(BenchBinaryHeap, ET_FLOAT);
243
+ }
244
+ else if (element_type == "DOUBLE")
245
+ {
246
+ MEASURE(BenchBinaryHeap, ET_DOUBLE);
247
+ }
248
+ else if (element_type == "STIMULI")
249
+ {
250
+ MEASURE(BenchBinaryHeap, ET_STIMULI);
251
+ }
252
+ else
253
+ {
254
+ throw "invalid element type";
255
+ }
256
+ }
257
+ else if (algorithm == "StlPq")
258
+ {
259
+ ARG_GET(element_type, std::string);
260
+
261
+ if (element_type == "FLOAT")
262
+ {
263
+ MEASURE(BenchStlPq, ET_FLOAT);
264
+ }
265
+ else if (element_type == "DOUBLE")
266
+ {
267
+ MEASURE(BenchStlPq, ET_DOUBLE);
268
+ }
269
+ else if (element_type == "STIMULI")
270
+ {
271
+ MEASURE(BenchStlPq, ET_STIMULI);
272
+ }
273
+ }
274
+ else if (algorithm == "PairingHeap")
275
+ {
276
+ ARG_GET(element_type, std::string);
277
+
278
+ if (element_type == "STIMULI")
279
+ {
280
+ MEASURE(BenchPairingHeap, ET_STIMULI_PH);
281
+ }
282
+ else
283
+ {
284
+ throw "invalid element type";
285
+ }
286
+ }
287
+ else if (algorithm == "CalendarQueue")
288
+ {
289
+ ARG_GET(element_type, std::string);
290
+
291
+ if (element_type == "STIMULI")
292
+ {
293
+ MEASURE(BenchCalendarQueue, ET_STIMULI_CQ);
294
+ }
295
+ else
296
+ {
297
+ throw "invalid element type";
298
+ }
299
+ }
300
+ else
301
+ {
302
+ throw "invalid algorithm";
303
+ }
304
+
305
+ if (argp != argc)
306
+ {
307
+ throw "too much arguments";
308
+ }
309
+ }
310
+
311
+ int main(int argc, char** argv)
312
+ {
313
+ try {
314
+ run(argc, argv);
315
+ } catch (const char *err)
316
+ {
317
+ std::cerr << "ERROR: " << err << std::endl;
318
+ return 1;
319
+ }
320
+ return 0;
321
+ }
@@ -0,0 +1,125 @@
1
+ WARMUP_CYCLES = 10_000_000
2
+ EMPTY_CYCLES = 100_000_000
3
+ CYCLES = 100_000_000
4
+
5
+ DISTRIBUTIONS = [
6
+ 'Random',
7
+ 'Exponential 1',
8
+ 'Uniform 0 2',
9
+ 'Triangular 0 1.5',
10
+ 'NegativeTriangular 0 1.5'
11
+ ]
12
+
13
+ ALGORITHMS = [
14
+ 'BinaryHeap FLOAT',
15
+ 'BinaryHeap DOUBLE',
16
+ 'BinaryHeap STIMULI',
17
+ 'StlPq FLOAT',
18
+ 'StlPq DOUBLE',
19
+ 'StlPq STIMULI',
20
+ 'PairingHeap STIMULI',
21
+ 'CalendarQueue STIMULI'
22
+ ]
23
+
24
+ REPEAT = 5
25
+ QUEUE_SIZES = (1..7).map {|x| 10**x}
26
+
27
+ def bench(queue_size, warmup_cycles, empty_cycles, cycles, distribution, algorithm)
28
+ cmd = "./bench #{queue_size} #{warmup_cycles} #{empty_cycles} #{cycles} ClassicHold"
29
+ cmd << " #{distribution} #{algorithm}"
30
+ p cmd
31
+ parse_result(`#{cmd}`)
32
+ end
33
+
34
+ def parse_result(str)
35
+ h = {}
36
+ str.split("\n").each do |line|
37
+ line.strip!
38
+ next if line.empty?
39
+ key, value = line.split(":", 2)
40
+ h[key] = value.strip
41
+ end
42
+ h
43
+ end
44
+
45
+ def bench_algorithm(algorithm, prefix, repeat=nil, distributions=nil, queue_sizes=nil)
46
+ repeat ||= REPEAT
47
+ distributions ||= DISTRIBUTIONS
48
+ queue_sizes ||= QUEUE_SIZES
49
+
50
+ h = {}
51
+ repeat.times do
52
+ distributions.each do |distr|
53
+ queue_sizes.each do |qs|
54
+ res = bench(qs, WARMUP_CYCLES, EMPTY_CYCLES, CYCLES, distr, algorithm)
55
+ h[res['Distribution']] ||= {}
56
+ (h[res['Distribution']][res['QueueSize']] ||= []) << res['Time'].to_f
57
+ end
58
+ end
59
+ end
60
+
61
+ dat = File.open(prefix + ".dat", "w+")
62
+ plot = File.open(prefix + ".plot", "w+")
63
+
64
+ plot << %{
65
+ set terminal pdf
66
+ # dashed
67
+ set output "#{prefix}.pdf"
68
+ set xlabel "Queue size (ld)"
69
+ set ylabel "Mean access time (ns)"
70
+ set format x "%L"
71
+ set logscale x 2
72
+ #set logscale y 2
73
+ set grid x y
74
+ set size ratio 1
75
+ set data style linespoints
76
+ set key top left
77
+ set key box
78
+ }
79
+
80
+ index = 0
81
+ h.each do |dis, h2|
82
+ dat.puts "# Distribution: #{dis}"
83
+ dat.puts "# queue size mean access time (ns)"
84
+
85
+ if index == 0
86
+ plot.print "plot "
87
+ else
88
+ plot.print ",\\\n"
89
+ end
90
+
91
+ plot.print %{ "#{prefix}.dat" index #{index} using 1:2 title "#{dis}"}
92
+ index += 1
93
+
94
+ arr = []
95
+ h2.each do |qs, times|
96
+ avg = (times.inject(0.0) {|i, s| s + i}) / times.size
97
+ avg *= 1_000_000_000 # convert to ns
98
+ arr << [qs, avg]
99
+ end
100
+ arr.sort_by {|qs,_| qs.to_i}.each do |qs, avg|
101
+ dat.print qs.to_s.ljust(11)
102
+ dat.puts avg.to_s.ljust(24)
103
+ end
104
+
105
+ dat.puts
106
+ dat.puts
107
+ end
108
+
109
+ plot.puts
110
+ dat.close
111
+ plot.close
112
+
113
+ system "gnuplot #{prefix}.plot"
114
+ end
115
+
116
+ Dir.mkdir('work') rescue nil
117
+
118
+ qs = (14..22).map {|x| 2**x}
119
+ #bench_algorithm("BinaryHeap STIMULI", "work/bh", 2, ["Random"], qs)
120
+ #bench_algorithm("StlPq STIMULI", "work/stl", 2, ["Random"], qs)
121
+ #bench_algorithm("BinaryHeap STIMULI", "work/test5", 2, ["Random"], [2**18, 2**19, 2**20])
122
+ #bench_algorithm("PairingHeap STIMULI", "work/pairing", 1, ["Random"], [2**10, 2**14, 2**18])
123
+ #bench_algorithm("BinaryHeap STIMULI", "work/binary", 1, ["Random"], [2**10, 2**14, 2**18])
124
+ #bench_algorithm("BinaryHeap STIMULI", "work/binary", 1, ["Random"], [2**10, 2**14, 2**18])
125
+ bench_algorithm("CalendarQueue STIMULI", "work/cq3", 1, ["Random"], [2**10, 2**14, 2**18, 2**20, 2**21])