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
@@ -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