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
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])