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.
- 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
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'Yinspire/Core/NeuralEntity'
|
2
|
+
require 'Yinspire/Core/Scheduling/Simulator'
|
3
|
+
|
4
|
+
class Simulator
|
5
|
+
|
6
|
+
#
|
7
|
+
# The tolerance (time difference) up to which local stimuli are
|
8
|
+
# accumulated.
|
9
|
+
#
|
10
|
+
property :stimuli_tolerance, 'simtime', :init => Infinity
|
11
|
+
|
12
|
+
#
|
13
|
+
# Statistics counter
|
14
|
+
#
|
15
|
+
property :event_counter, 'uint'
|
16
|
+
property :fire_counter, 'uint'
|
17
|
+
|
18
|
+
stub_method :record_fire, {:at => 'simtime'},{:weight => 'real'},{:source => NeuralEntity}
|
19
|
+
|
20
|
+
#
|
21
|
+
# Overwrite!
|
22
|
+
#
|
23
|
+
def record_fire(at, weight, source)
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :entities
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@entities = Hash.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def run(stop_at=nil)
|
33
|
+
schedule_run(stop_at || Infinity)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'Yinspire/Core/Stimulus'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Module contains code to store local stimuli in a priority queue. Used
|
5
|
+
# by several Neuron models.
|
6
|
+
#
|
7
|
+
module StimuliMixin; cplus2ruby
|
8
|
+
|
9
|
+
#
|
10
|
+
# Each NeuralEntity has it's own local stimuli priority queue.
|
11
|
+
# Neurons make use of this whereas Synapses do not.
|
12
|
+
#
|
13
|
+
# Nevertheless we put this into the base class for simplicity reasons
|
14
|
+
# and as it's quite low overhead (12 bytes).
|
15
|
+
#
|
16
|
+
property :stimuli_pq, 'BinaryHeap<Stimulus, MemoryAllocator<Stimulus> >'
|
17
|
+
|
18
|
+
#
|
19
|
+
# Returns a Ruby array in the form [at1, weight1, at2, weight2]
|
20
|
+
# for +stimuli_pq+.
|
21
|
+
#
|
22
|
+
method :stimuli_pq_to_a, {:returns => Object}, %{
|
23
|
+
VALUE ary = rb_ary_new();
|
24
|
+
@stimuli_pq.each(Stimulus::dump_to_a, &ary);
|
25
|
+
return ary;
|
26
|
+
}
|
27
|
+
|
28
|
+
#
|
29
|
+
# Add a Stimuli to the local priority queue.
|
30
|
+
#
|
31
|
+
method :stimuli_add, {:at => 'simtime'},{:weight => 'real'}, %{
|
32
|
+
Stimulus s; s.at = at; s.weight = weight;
|
33
|
+
|
34
|
+
if (@simulator->stimuli_tolerance >= 0.0)
|
35
|
+
{
|
36
|
+
Stimulus *parent = @stimuli_pq.find_parent(s);
|
37
|
+
|
38
|
+
if (parent != NULL && (s.at - parent->at) <= @simulator->stimuli_tolerance)
|
39
|
+
{
|
40
|
+
parent->weight += s.weight;
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
@stimuli_pq.push(s);
|
46
|
+
schedule(@stimuli_pq.top().at);
|
47
|
+
}
|
48
|
+
|
49
|
+
#
|
50
|
+
# Consume all Stimuli until +till+ and return the sum of the weights.
|
51
|
+
#
|
52
|
+
method :stimuli_sum, {:till => 'simtime'},{:returns => 'real'}, %{
|
53
|
+
real weight = 0.0;
|
54
|
+
|
55
|
+
while (!@stimuli_pq.empty() && @stimuli_pq.top().at <= till)
|
56
|
+
{
|
57
|
+
weight += @stimuli_pq.top().weight;
|
58
|
+
@stimuli_pq.pop();
|
59
|
+
}
|
60
|
+
|
61
|
+
/*
|
62
|
+
* NOTE: we don't have to remove the entity from the schedule if the
|
63
|
+
* pq is empty.
|
64
|
+
*/
|
65
|
+
if (!@stimuli_pq.empty())
|
66
|
+
{
|
67
|
+
schedule(@stimuli_pq.top().at);
|
68
|
+
}
|
69
|
+
|
70
|
+
return weight;
|
71
|
+
}
|
72
|
+
|
73
|
+
#
|
74
|
+
# Consume all Stimuli until +till+ and return the sum of the weights.
|
75
|
+
# This treats infinitive values specially and instead of summing them,
|
76
|
+
# it sets +is_inf+ to +true+.
|
77
|
+
#
|
78
|
+
method :stimuli_sum_inf, {:till => 'simtime'},{:is_inf => 'bool&'},{:returns => 'real'}, %{
|
79
|
+
real weight = 0.0;
|
80
|
+
is_inf = false;
|
81
|
+
|
82
|
+
while (!@stimuli_pq.empty() && @stimuli_pq.top().at <= till)
|
83
|
+
{
|
84
|
+
if (isinf(@stimuli_pq.top().weight))
|
85
|
+
{
|
86
|
+
is_inf = true;
|
87
|
+
}
|
88
|
+
else
|
89
|
+
{
|
90
|
+
weight += @stimuli_pq.top().weight;
|
91
|
+
}
|
92
|
+
@stimuli_pq.pop();
|
93
|
+
}
|
94
|
+
|
95
|
+
if (!@stimuli_pq.empty())
|
96
|
+
{
|
97
|
+
schedule(@stimuli_pq.top().at);
|
98
|
+
}
|
99
|
+
|
100
|
+
return weight;
|
101
|
+
}
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#
|
2
|
+
# The data structure used for storing a fire impluse or any other form
|
3
|
+
# of stimulation.
|
4
|
+
#
|
5
|
+
class Stimulus
|
6
|
+
|
7
|
+
cplus2ruby :no_wrap => true
|
8
|
+
cplus2ruby :order => -1
|
9
|
+
|
10
|
+
property :at, :simtime
|
11
|
+
property :weight, :real
|
12
|
+
|
13
|
+
static_method :less, {:a => 'const Stimulus&'}, {:b => 'const Stimulus&'}, {:returns => 'bool'}, %{
|
14
|
+
return (a.at < b.at);
|
15
|
+
}, :inline => true
|
16
|
+
|
17
|
+
#
|
18
|
+
# Appends +at+ and +weight+ to the Ruby array passed as +ary+.
|
19
|
+
#
|
20
|
+
static_method :dump_to_a, {:s => 'const Stimulus&'},{:ary => 'void*'}, %{
|
21
|
+
rb_ary_push(*((VALUE*)ary), rb_float_new(s.at));
|
22
|
+
rb_ary_push(*((VALUE*)ary), rb_float_new(s.weight));
|
23
|
+
}
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'Yinspire/Core/NeuralEntity'
|
2
|
+
require 'Yinspire/Core/Neuron'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Base class of all Synapses. Defines the structure that is special for
|
6
|
+
# a Synapse, i.e. that a Synapse has a pre and a post-Neuron. Also
|
7
|
+
# each Synapse has a +weight+ and a +delay+.
|
8
|
+
#
|
9
|
+
class Synapse < NeuralEntity
|
10
|
+
|
11
|
+
property :pre_neuron, Neuron
|
12
|
+
property :post_neuron, Neuron
|
13
|
+
|
14
|
+
#
|
15
|
+
# Those pointers are part of an internal linked-list that
|
16
|
+
# starts at a Neuron and connects all pre-synapses of an Neuron
|
17
|
+
# together. In the same way it connects all post-synapses of an
|
18
|
+
# Neuron together.
|
19
|
+
#
|
20
|
+
property :next_pre_synapse, Synapse
|
21
|
+
property :next_post_synapse, Synapse
|
22
|
+
property :prev_pre_synapse, Synapse
|
23
|
+
property :prev_post_synapse, Synapse
|
24
|
+
|
25
|
+
#
|
26
|
+
# The fire weight of a Synapse.
|
27
|
+
#
|
28
|
+
property :weight, 'real', :marshal => true
|
29
|
+
|
30
|
+
#
|
31
|
+
# The propagation delay of a Synapse.
|
32
|
+
#
|
33
|
+
property :delay, 'simtime', :marshal => true
|
34
|
+
|
35
|
+
#
|
36
|
+
# Adding a pre synapse. Target must be a Neuron.
|
37
|
+
#
|
38
|
+
def connect(target)
|
39
|
+
target.add_pre_synapse(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def disconnect(target)
|
43
|
+
target.delete_pre_synapse(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def each_connection
|
47
|
+
yield self.post_neuron
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Only propagate the stimulation if it doesn't originate from the
|
52
|
+
# post Neuron. Stimuli from a post Neuron are handled by a specific
|
53
|
+
# Synapse class (e.g. Hebb).
|
54
|
+
#
|
55
|
+
# NOTE: We ignore the weight parameter that is passed by the Neuron.
|
56
|
+
#
|
57
|
+
method :stimulate, {:at => 'simtime'},{:weight => 'real'},{:source => NeuralEntity}, %{
|
58
|
+
if (source != @post_neuron)
|
59
|
+
{
|
60
|
+
@post_neuron->stimulate(at + @delay, @weight, this);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Common super class of all Dumpers.
|
3
|
+
#
|
4
|
+
class Dumper
|
5
|
+
|
6
|
+
def initialize(simulator)
|
7
|
+
@simulator = simulator
|
8
|
+
@entities = @simulator.entities
|
9
|
+
end
|
10
|
+
|
11
|
+
def dump_entities
|
12
|
+
entities = {}
|
13
|
+
@entities.each {|id, entity|
|
14
|
+
entities[id] = [entity.entity_type || raise, entity.dump]
|
15
|
+
}
|
16
|
+
entities
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'Yinspire/Dumpers/Dumper'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Dumper for the GraphViz[1] dot format.
|
5
|
+
#
|
6
|
+
# Only dumps the net, not the stimulis.
|
7
|
+
#
|
8
|
+
# [1]: http://www.graphviz.org/
|
9
|
+
#
|
10
|
+
class Dumper_Dot < Dumper
|
11
|
+
|
12
|
+
#
|
13
|
+
# NOTE: Unconnected synapses are not shown.
|
14
|
+
#
|
15
|
+
def dump(out)
|
16
|
+
out << "digraph {\n"
|
17
|
+
out << "node [shape = circle];\n"
|
18
|
+
|
19
|
+
@entities.each_value {|entity|
|
20
|
+
next unless entity.kind_of?(Neuron)
|
21
|
+
entity.each_connection do |syn|
|
22
|
+
out << "#{entity.id.inspect} -> #{syn.post_neuron.id.inspect} [label = #{syn.id.inspect} ];\n"
|
23
|
+
end
|
24
|
+
}
|
25
|
+
out << "}\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
class GraphML
|
4
|
+
|
5
|
+
class Graph < Struct.new(:id, :data, :nodes, :edges); end
|
6
|
+
class Node < Struct.new(:id, :data); end
|
7
|
+
class Edge < Struct.new(:id, :data, :source, :target); end
|
8
|
+
|
9
|
+
attr_reader :graphs
|
10
|
+
|
11
|
+
def self.parse(io)
|
12
|
+
doc = REXML::Document.new(io)
|
13
|
+
new().parse(doc)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@keys = Hash.new
|
18
|
+
@graphs = Hash.new
|
19
|
+
@ids = Hash.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(doc)
|
23
|
+
parse_keys(doc.root)
|
24
|
+
parse_graphs(doc.root)
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def check_id(id)
|
31
|
+
raise "duplicate id: #{ id }" if @ids.has_key?(id)
|
32
|
+
@ids[id] = true
|
33
|
+
id
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_keys(root)
|
37
|
+
root.elements.each('key') do |el|
|
38
|
+
id = check_id(el.attributes['id'])
|
39
|
+
(@keys[el.attributes['for']] ||= {})[id] = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_graphs(root)
|
44
|
+
root.elements.each('graph') do |g|
|
45
|
+
graph = GraphML::Graph.new
|
46
|
+
graph.id = check_id(g.attributes['id'])
|
47
|
+
graph.data = parse_data(g, 'graph')
|
48
|
+
graph.nodes = Hash.new
|
49
|
+
graph.edges = Hash.new
|
50
|
+
@graphs[graph.id] = graph
|
51
|
+
|
52
|
+
g.elements.each('node') do |el|
|
53
|
+
node = GraphML::Node.new
|
54
|
+
node.id = check_id(el.attributes['id'])
|
55
|
+
node.data = parse_data(el, 'node')
|
56
|
+
graph.nodes[node.id] = node
|
57
|
+
end
|
58
|
+
|
59
|
+
g.elements.each('edge') do |el|
|
60
|
+
# FIXME: for now always assume directed edges
|
61
|
+
edge = GraphML::Edge.new
|
62
|
+
edge.id = check_id(el.attributes['id'])
|
63
|
+
edge.source = graph.nodes[el.attributes['source']] || raise
|
64
|
+
edge.target = graph.nodes[el.attributes['target']] || raise
|
65
|
+
edge.data = parse_data(el, 'edge')
|
66
|
+
graph.edges[edge.id] = edge
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_data(root, for_el)
|
72
|
+
hash = Hash.new
|
73
|
+
root.elements.each('data') do |el|
|
74
|
+
key, value = el.attributes['key'], el.text
|
75
|
+
raise unless @keys[for_el][key]
|
76
|
+
hash[key] = value
|
77
|
+
end
|
78
|
+
hash
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if __FILE__ == $0
|
83
|
+
p GraphML.parse(File.open("../../../examples/nets/skorpion.graphml"))
|
84
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Common super class of all Loaders.
|
3
|
+
#
|
4
|
+
# Uses Cplus2Ruby property annotations to automatically assign
|
5
|
+
# properties:
|
6
|
+
#
|
7
|
+
# property :name, :marshal => true, :init => 123
|
8
|
+
#
|
9
|
+
class Loader
|
10
|
+
|
11
|
+
def initialize(simulator)
|
12
|
+
@simulator = simulator
|
13
|
+
@entities = @simulator.entities
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
#
|
19
|
+
# Create an object with id +id+ of class +entity_type+, where
|
20
|
+
# +entity_type+ is a string.
|
21
|
+
#
|
22
|
+
# Argument +data+ is a hash that contains the property values.
|
23
|
+
#
|
24
|
+
def create_entity(entity_type, id, data)
|
25
|
+
entity = NeuralEntity.new_from_name(entity_type, id, @simulator)
|
26
|
+
entity.load(data)
|
27
|
+
raise if @entities[id]
|
28
|
+
@entities[id] = entity
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#
|
2
|
+
# Load a neuronal net from GraphML format.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2007, 2008 by Michael Neumann (mneumann@ntecs.de)
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'Yinspire/Loaders/Loader'
|
8
|
+
require 'Yinspire/Loaders/GraphML'
|
9
|
+
|
10
|
+
class Loader_GraphML < Loader
|
11
|
+
|
12
|
+
TYPE_MAP = {
|
13
|
+
'NEURONTYPE_KBLIF' => 'Neuron_SRM01',
|
14
|
+
'NEURONTYPE_EKERNEL' => 'Neuron_SRM02',
|
15
|
+
'SYNAPSE_DEFAULT' => 'Synapse',
|
16
|
+
'SYNAPSE_HEBB' => 'Synapse_Hebb'
|
17
|
+
}
|
18
|
+
|
19
|
+
PARAM_MAP = {
|
20
|
+
'absRefPeriod' => ['abs_refr_duration', 'real'],
|
21
|
+
'neuronLFT' => ['last_fire_time', 'real'],
|
22
|
+
'neuronLSET' => ['last_spike_time', 'real'],
|
23
|
+
'neuron_tauM' => ['tau_m', 'real'],
|
24
|
+
'neuron_tauRef' => ['tau_ref', 'real'],
|
25
|
+
'neuron_constThreshold' => ['const_threshold', 'real'],
|
26
|
+
'neuron_refWeight' => ['ref_weight', 'real'],
|
27
|
+
'neuron_arpTime' => ['abs_refr_duration', 'real'],
|
28
|
+
'synapse_weight' => ['weight', 'real'],
|
29
|
+
'synapse_delay' => ['delay', 'real'],
|
30
|
+
'neuronPSP' => ['mem_pot', 'real'],
|
31
|
+
'neuronReset' => ['reset', 'real'],
|
32
|
+
'neuron_tauM' => ['tau_m', 'real'],
|
33
|
+
'neuron_tauRecov' => ['tau_ref', 'real'],
|
34
|
+
'neuron_uReset' => ['u_reset', 'real'],
|
35
|
+
'neuron_threshold' => ['const_threshold', 'real']
|
36
|
+
}
|
37
|
+
|
38
|
+
def load(file)
|
39
|
+
File.open(file) do |f|
|
40
|
+
gml = GraphML.parse(f)
|
41
|
+
g = gml.graphs.values.first
|
42
|
+
default_neuron_type = g.data['graph_default_neuron_type']
|
43
|
+
default_synapse_type = g.data['graph_default_synapse_type']
|
44
|
+
|
45
|
+
#
|
46
|
+
# Create Neurons
|
47
|
+
#
|
48
|
+
g.nodes.each_value {|node|
|
49
|
+
create(node.id, node.data, default_neuron_type, 'neuron_type')
|
50
|
+
}
|
51
|
+
|
52
|
+
#
|
53
|
+
# Create Synapses
|
54
|
+
#
|
55
|
+
g.edges.each_value {|edge|
|
56
|
+
create(edge.id, edge.data, default_synapse_type, 'synapse_type')
|
57
|
+
}
|
58
|
+
|
59
|
+
#
|
60
|
+
# Create Connections between Neurons and Synapses.
|
61
|
+
#
|
62
|
+
g.edges.each_value {|edge|
|
63
|
+
a = @entities[edge.source.id] || raise
|
64
|
+
b = @entities[edge.id] || raise
|
65
|
+
c = @entities[edge.target.id] || raise
|
66
|
+
a.connect(b)
|
67
|
+
b.connect(c)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
#
|
75
|
+
# Parameter +kind+ is either of "neuron_type" or "synapse_type".
|
76
|
+
#
|
77
|
+
def create(id, data, default_type, kind)
|
78
|
+
entity_type = (TYPE_MAP[data[kind] || default_type] || raise)
|
79
|
+
data.delete(kind)
|
80
|
+
create_entity(entity_type, id, conv_params(data))
|
81
|
+
end
|
82
|
+
|
83
|
+
def conv_params(data)
|
84
|
+
hash = {}
|
85
|
+
data.each {|k,v|
|
86
|
+
name, type = PARAM_MAP[k] || raise
|
87
|
+
case type
|
88
|
+
when 'real'
|
89
|
+
hash[name] = v.strip.to_f
|
90
|
+
else
|
91
|
+
raise
|
92
|
+
end
|
93
|
+
}
|
94
|
+
return hash
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|