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,77 @@
|
|
1
|
+
#include "neuron_srm_01.h"
|
2
|
+
#include "simulator.h"
|
3
|
+
#include <math.h>
|
4
|
+
|
5
|
+
// formerly known as KernelbasedLIF
|
6
|
+
|
7
|
+
|
8
|
+
Neuron_SRM_01::Neuron_SRM_01()
|
9
|
+
{
|
10
|
+
this->tau_m = 0.0;
|
11
|
+
this->tau_ref = 0.0;
|
12
|
+
this->ref_weight = 0.0;
|
13
|
+
this->mem_pot = 0.0;
|
14
|
+
this->const_threshold = 0.0;
|
15
|
+
}
|
16
|
+
|
17
|
+
void
|
18
|
+
Neuron_SRM_01::dump(jsonHash *into)
|
19
|
+
{
|
20
|
+
}
|
21
|
+
|
22
|
+
void
|
23
|
+
Neuron_SRM_01::load(jsonHash *data)
|
24
|
+
{
|
25
|
+
super::load(data);
|
26
|
+
|
27
|
+
this->tau_m = data->get_number("tau_m", 0.0);
|
28
|
+
this->tau_ref = data->get_number("tau_ref", 0.0);
|
29
|
+
this->ref_weight = data->get_number("ref_weight", 0.0);
|
30
|
+
this->mem_pot = data->get_number("mem_pot", 0.0);
|
31
|
+
this->const_threshold = data->get_number("const_threshold", 0.0);
|
32
|
+
}
|
33
|
+
|
34
|
+
void
|
35
|
+
Neuron_SRM_01::stimulate(simtime at, real weight, NeuralEntity *source)
|
36
|
+
{
|
37
|
+
if (at >= this->last_fire_time + this->abs_refr_duration)
|
38
|
+
{
|
39
|
+
++this->simulator->stat_event_counter;
|
40
|
+
super::stimulate(at, weight, source);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
void
|
45
|
+
Neuron_SRM_01::process(simtime at)
|
46
|
+
{
|
47
|
+
real weight = stimuli_sum(at);
|
48
|
+
const real delta = at - this->last_fire_time - this->abs_refr_duration;
|
49
|
+
|
50
|
+
if (delta < 0.0) return;
|
51
|
+
|
52
|
+
/*
|
53
|
+
* Calculate new membrane potential
|
54
|
+
*/
|
55
|
+
|
56
|
+
this->mem_pot = weight + this->mem_pot * real_exp( -(at - this->last_spike_time)/this->tau_m );
|
57
|
+
this->last_spike_time = at;
|
58
|
+
|
59
|
+
/*
|
60
|
+
* Calculate dynamic threshold
|
61
|
+
*/
|
62
|
+
const real dynamic_threshold = this->ref_weight * real_exp(-delta/this->tau_ref);
|
63
|
+
|
64
|
+
if (this->mem_pot >= this->const_threshold + dynamic_threshold)
|
65
|
+
{
|
66
|
+
fire(at);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
void
|
71
|
+
Neuron_SRM_01::fire(simtime at)
|
72
|
+
{
|
73
|
+
this->simulator->stat_record_fire_event(at, this);
|
74
|
+
this->mem_pot = 0.0;
|
75
|
+
this->last_fire_time = at;
|
76
|
+
fire_synapses(at);
|
77
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#ifndef __YINSPIRE__NEURON_SRM_01__
|
2
|
+
#define __YINSPIRE__NEURON_SRM_01__
|
3
|
+
|
4
|
+
#include "neuron.h"
|
5
|
+
|
6
|
+
class Neuron_SRM_01 : public Neuron
|
7
|
+
{
|
8
|
+
typedef Neuron super;
|
9
|
+
|
10
|
+
protected:
|
11
|
+
|
12
|
+
real tau_m;
|
13
|
+
real tau_ref;
|
14
|
+
real ref_weight;
|
15
|
+
real mem_pot;
|
16
|
+
real const_threshold;
|
17
|
+
|
18
|
+
public:
|
19
|
+
|
20
|
+
Neuron_SRM_01();
|
21
|
+
|
22
|
+
public:
|
23
|
+
|
24
|
+
virtual void dump(jsonHash *into);
|
25
|
+
virtual void load(jsonHash *data);
|
26
|
+
|
27
|
+
virtual void stimulate(simtime at, real weight, NeuralEntity *source);
|
28
|
+
virtual void process(simtime at);
|
29
|
+
|
30
|
+
protected:
|
31
|
+
|
32
|
+
void fire(simtime at);
|
33
|
+
|
34
|
+
};
|
35
|
+
|
36
|
+
#endif
|
@@ -0,0 +1,151 @@
|
|
1
|
+
#include <math.h>
|
2
|
+
#include <string>
|
3
|
+
#include "simulator.h"
|
4
|
+
#include "json/json_parser.h"
|
5
|
+
|
6
|
+
Simulator::Simulator()
|
7
|
+
{
|
8
|
+
this->schedule_current_time = 0.0;
|
9
|
+
this->schedule_step = INFINITY;
|
10
|
+
this->schedule_next_step = this->schedule_current_time + this->schedule_step;
|
11
|
+
this->schedule_stepping_list_root = NULL;
|
12
|
+
this->stimuli_tolerance = 0.0;
|
13
|
+
this->stat_event_counter = 0;
|
14
|
+
this->stat_fire_counter = 0;
|
15
|
+
}
|
16
|
+
|
17
|
+
void
|
18
|
+
Simulator::entity_register_type(const char *type, entity_factory_t factory)
|
19
|
+
{
|
20
|
+
this->types[type] = factory;
|
21
|
+
}
|
22
|
+
|
23
|
+
NeuralEntity*
|
24
|
+
Simulator::entity_allocate(const char* type)
|
25
|
+
{
|
26
|
+
entity_factory_t factory = this->types[type];
|
27
|
+
return factory();
|
28
|
+
}
|
29
|
+
|
30
|
+
void
|
31
|
+
Simulator::load(const char *filename)
|
32
|
+
{
|
33
|
+
jsonHash *data = jsonParser::parse_file_mmap(filename)->asHash();
|
34
|
+
|
35
|
+
std::string format = data->get("format")->asString()->value;
|
36
|
+
|
37
|
+
if (format != "yinspire.c")
|
38
|
+
{
|
39
|
+
throw "unrecognized data format";
|
40
|
+
}
|
41
|
+
|
42
|
+
jsonHash *templates = data->get("templates")->asHash();
|
43
|
+
jsonArray *entities = data->get("entities")->asArray();
|
44
|
+
jsonArray *connections = data->get("connections")->asArray();
|
45
|
+
jsonHash *events = data->get("events")->asHash();
|
46
|
+
|
47
|
+
/*
|
48
|
+
* construct entities
|
49
|
+
*/
|
50
|
+
jsonArrayIterator_EACH(entities, e)
|
51
|
+
{
|
52
|
+
jsonArray *entity_spec = e->asArray();
|
53
|
+
jsonString *id = entity_spec->get(0)->asString();
|
54
|
+
jsonString *template_name = entity_spec->get(1)->asString();
|
55
|
+
|
56
|
+
jsonArray *t = templates->get(template_name)->asArray();
|
57
|
+
|
58
|
+
jsonString *type = t->get(0)->asString();
|
59
|
+
jsonHash *hash = t->get(1)->asHash();
|
60
|
+
|
61
|
+
NeuralEntity *entity = entity_allocate(type->value.c_str());
|
62
|
+
|
63
|
+
entity->set_id(strdup(id->asString()->value.c_str()));
|
64
|
+
entity->set_simulator(this);
|
65
|
+
this->entities[entity->get_id()] = entity;
|
66
|
+
|
67
|
+
entity->load(hash);
|
68
|
+
}
|
69
|
+
|
70
|
+
/*
|
71
|
+
* connect entities
|
72
|
+
*/
|
73
|
+
jsonArrayIterator_EACH(connections, conn)
|
74
|
+
{
|
75
|
+
NeuralEntity *from = NULL;
|
76
|
+
jsonArrayIterator_EACH(conn->asArray(), i)
|
77
|
+
{
|
78
|
+
std::string &id = i->asString()->value;
|
79
|
+
NeuralEntity *e = this->entities[id.c_str()];
|
80
|
+
if (from == NULL) from = e;
|
81
|
+
else from->connect(e);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
/*
|
86
|
+
* events
|
87
|
+
*/
|
88
|
+
jsonHashIterator_EACH(events, key, val)
|
89
|
+
{
|
90
|
+
NeuralEntity *entity = this->entities[key->value.c_str()];
|
91
|
+
jsonArrayIterator_EACH(val->asArray(), e)
|
92
|
+
{
|
93
|
+
entity->stimulate(e->asNumber()->value, INFINITY, NULL);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
data->ref_decr();
|
98
|
+
}
|
99
|
+
|
100
|
+
void
|
101
|
+
Simulator::run(simtime stop_at)
|
102
|
+
{
|
103
|
+
while (true)
|
104
|
+
{
|
105
|
+
simtime next_stop = MIN(stop_at, this->schedule_next_step);
|
106
|
+
|
107
|
+
/*
|
108
|
+
* Calculate all events from the priority queue until the next time
|
109
|
+
* step is reached.
|
110
|
+
*/
|
111
|
+
while (!this->schedule_pq.empty())
|
112
|
+
{
|
113
|
+
NeuralEntity *top = this->schedule_pq.top();
|
114
|
+
if (top->get_schedule_at() >= next_stop)
|
115
|
+
break;
|
116
|
+
this->schedule_current_time = top->get_schedule_at();
|
117
|
+
this->schedule_pq.pop();
|
118
|
+
top->process(top->get_schedule_at());
|
119
|
+
}
|
120
|
+
|
121
|
+
if (this->schedule_current_time >= stop_at)
|
122
|
+
break;
|
123
|
+
|
124
|
+
if (this->schedule_stepping_list_root == NULL && this->schedule_pq.empty())
|
125
|
+
break;
|
126
|
+
|
127
|
+
/*
|
128
|
+
* Calculate the entities that require stepped processing.
|
129
|
+
*/
|
130
|
+
this->schedule_current_time = this->schedule_next_step;
|
131
|
+
|
132
|
+
if (this->schedule_stepping_list_root != NULL)
|
133
|
+
{
|
134
|
+
// FIXME: collect all entities in an array. then process them.
|
135
|
+
}
|
136
|
+
|
137
|
+
this->schedule_next_step += this->schedule_step;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
void
|
142
|
+
Simulator::schedule_update(NeuralEntity *entity)
|
143
|
+
{
|
144
|
+
this->schedule_pq.update(entity);
|
145
|
+
}
|
146
|
+
|
147
|
+
void
|
148
|
+
Simulator::stat_record_fire_event(simtime at, NeuralEntity *source)
|
149
|
+
{
|
150
|
+
++this->stat_fire_counter;
|
151
|
+
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#ifndef __YINSPIRE__SIMULATOR__
|
2
|
+
#define __YINSPIRE__SIMULATOR__
|
3
|
+
|
4
|
+
#include "types.h"
|
5
|
+
#include "neural_entity.h"
|
6
|
+
#include "memory_allocator.h"
|
7
|
+
#include "algo/indexed_binary_heap.h"
|
8
|
+
#include <string.h>
|
9
|
+
#include <map>
|
10
|
+
|
11
|
+
struct ltstr
|
12
|
+
{
|
13
|
+
inline bool operator()(const char *s1, const char *s2) const
|
14
|
+
{
|
15
|
+
return strcmp(s1, s2) < 0;
|
16
|
+
}
|
17
|
+
};
|
18
|
+
|
19
|
+
class Simulator
|
20
|
+
{
|
21
|
+
friend class NeuralEntity;
|
22
|
+
|
23
|
+
protected:
|
24
|
+
|
25
|
+
/*
|
26
|
+
* The current time.
|
27
|
+
*/
|
28
|
+
simtime schedule_current_time;
|
29
|
+
|
30
|
+
/*
|
31
|
+
* The time step used for stepped scheduling.
|
32
|
+
*/
|
33
|
+
simtime schedule_step;
|
34
|
+
|
35
|
+
/*
|
36
|
+
* The time of the next step.
|
37
|
+
*/
|
38
|
+
simtime schedule_next_step;
|
39
|
+
|
40
|
+
/*
|
41
|
+
* The tolerance (time difference) up to which local stimuli are
|
42
|
+
* accumulated.
|
43
|
+
*/
|
44
|
+
simtime stimuli_tolerance;
|
45
|
+
|
46
|
+
/*
|
47
|
+
* Priority queue used to schedule the entities.
|
48
|
+
*/
|
49
|
+
IndexedBinaryHeap<NeuralEntity *, MemoryAllocator<NeuralEntity*>, NeuralEntity> schedule_pq;
|
50
|
+
|
51
|
+
/*
|
52
|
+
* If stepped scheduling is used, this points to the
|
53
|
+
* first entity in the stepped schedule list.
|
54
|
+
*/
|
55
|
+
NeuralEntity *schedule_stepping_list_root;
|
56
|
+
|
57
|
+
/*
|
58
|
+
* An id -> NeuralEntity mapping
|
59
|
+
*
|
60
|
+
* Contains all entities known by the simulator.
|
61
|
+
*/
|
62
|
+
std::map<const char *, NeuralEntity *, ltstr> entities;
|
63
|
+
|
64
|
+
/*
|
65
|
+
* An entity type name -> "factory function for this type" mapping.
|
66
|
+
*/
|
67
|
+
typedef NeuralEntity* (*entity_factory_t)();
|
68
|
+
std::map<const char *, entity_factory_t, ltstr> types;
|
69
|
+
|
70
|
+
public:
|
71
|
+
|
72
|
+
/*
|
73
|
+
* Constructor
|
74
|
+
*/
|
75
|
+
Simulator();
|
76
|
+
|
77
|
+
/*
|
78
|
+
* Load the neural net from +filename+.
|
79
|
+
*/
|
80
|
+
void load(const char *filename);
|
81
|
+
|
82
|
+
/*
|
83
|
+
* Start the simulation.
|
84
|
+
*/
|
85
|
+
void run(simtime stop_at);
|
86
|
+
|
87
|
+
/*
|
88
|
+
* Register an entity type and the corresponding +factory+ function.
|
89
|
+
*/
|
90
|
+
void entity_register_type(const char *type, entity_factory_t factory);
|
91
|
+
|
92
|
+
/*
|
93
|
+
* Allocate an entity of the specified +type+.
|
94
|
+
*/
|
95
|
+
NeuralEntity *entity_allocate(const char *type);
|
96
|
+
|
97
|
+
/*
|
98
|
+
* If an entity has changed it's scheduling time,
|
99
|
+
* it has to call this method to reflect the change within the
|
100
|
+
* priority queue.
|
101
|
+
*/
|
102
|
+
void schedule_update(NeuralEntity *entity);
|
103
|
+
|
104
|
+
/*
|
105
|
+
* Notify that a fire event has happened
|
106
|
+
*/
|
107
|
+
void stat_record_fire_event(simtime at, NeuralEntity *source);
|
108
|
+
|
109
|
+
public:
|
110
|
+
|
111
|
+
uint stat_fire_counter;
|
112
|
+
uint stat_event_counter;
|
113
|
+
|
114
|
+
};
|
115
|
+
|
116
|
+
#endif
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#include "synapse.h"
|
2
|
+
#include "neuron.h"
|
3
|
+
#include <assert.h>
|
4
|
+
|
5
|
+
Synapse::Synapse()
|
6
|
+
{
|
7
|
+
this->weight = 0.0;
|
8
|
+
this->delay = 0.0;
|
9
|
+
this->pre_neuron = NULL;
|
10
|
+
this->post_neuron = NULL;
|
11
|
+
this->next_pre_synapse = NULL;
|
12
|
+
this->next_post_synapse = NULL;
|
13
|
+
}
|
14
|
+
|
15
|
+
void
|
16
|
+
Synapse::dump(jsonHash *into)
|
17
|
+
{
|
18
|
+
}
|
19
|
+
|
20
|
+
void
|
21
|
+
Synapse::load(jsonHash *data)
|
22
|
+
{
|
23
|
+
super::load(data);
|
24
|
+
|
25
|
+
this->weight = data->get_number("weight", 0.0);
|
26
|
+
this->delay = data->get_number("delay", 0.0);
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
void
|
31
|
+
Synapse::stimulate(simtime at, real weight, NeuralEntity *source)
|
32
|
+
{
|
33
|
+
/*
|
34
|
+
* Only propagate the stimulation if it doesn't originate from the
|
35
|
+
* post Neuron. Stimuli from a post Neuron are handled by a specific
|
36
|
+
* Synapse class (e.g. Hebb).
|
37
|
+
*
|
38
|
+
* We ignore the weight parameter that is passed by the Neuron.
|
39
|
+
*/
|
40
|
+
if (source != this->post_neuron)
|
41
|
+
{
|
42
|
+
this->post_neuron->stimulate(at + this->delay, this->weight, this);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
/*
|
48
|
+
* Adding a pre synapse. Target must be a Neuron.
|
49
|
+
*
|
50
|
+
* O(1)
|
51
|
+
*/
|
52
|
+
void
|
53
|
+
Synapse::connect(NeuralEntity *target)
|
54
|
+
{
|
55
|
+
Neuron *neuron = dynamic_cast<Neuron*>(target);
|
56
|
+
|
57
|
+
if (this->post_neuron != NULL || this->next_pre_synapse != NULL)
|
58
|
+
throw "Synapse already connected";
|
59
|
+
|
60
|
+
this->next_pre_synapse = neuron->first_pre_synapse;
|
61
|
+
neuron->first_pre_synapse = this;
|
62
|
+
this->post_neuron = neuron;
|
63
|
+
}
|
64
|
+
|
65
|
+
/*
|
66
|
+
* O(n)
|
67
|
+
*/
|
68
|
+
void
|
69
|
+
Synapse::disconnect(NeuralEntity *target)
|
70
|
+
{
|
71
|
+
Neuron *neuron = dynamic_cast<Neuron*>(target);
|
72
|
+
|
73
|
+
if (this->post_neuron != neuron)
|
74
|
+
throw "Synapse not connected to this Neuron";
|
75
|
+
|
76
|
+
/*
|
77
|
+
* Find the synapse in the linked list that precedes +this+.
|
78
|
+
*/
|
79
|
+
Synapse *prev = NULL;
|
80
|
+
Synapse *curr = neuron->first_pre_synapse;
|
81
|
+
|
82
|
+
while (true)
|
83
|
+
{
|
84
|
+
if (curr == NULL) break;
|
85
|
+
if (curr == this) break;
|
86
|
+
prev = curr;
|
87
|
+
curr = curr->next_pre_synapse;
|
88
|
+
}
|
89
|
+
|
90
|
+
if (curr != this)
|
91
|
+
throw "Synapse not in pre synapse list";
|
92
|
+
|
93
|
+
/*
|
94
|
+
* Remove ourself (this) from linked list
|
95
|
+
*/
|
96
|
+
if (prev == NULL)
|
97
|
+
{
|
98
|
+
/*
|
99
|
+
* we are the last synapse in the pre synapse list.
|
100
|
+
*/
|
101
|
+
assert(neuron->first_pre_synapse == this);
|
102
|
+
neuron->first_pre_synapse = NULL;
|
103
|
+
}
|
104
|
+
else
|
105
|
+
{
|
106
|
+
prev->next_pre_synapse = this->next_pre_synapse;
|
107
|
+
}
|
108
|
+
|
109
|
+
this->post_neuron = NULL;
|
110
|
+
this->next_pre_synapse = NULL;
|
111
|
+
}
|
112
|
+
|
113
|
+
void
|
114
|
+
Synapse::each_connection(void (*yield)(NeuralEntity *self, NeuralEntity *conn))
|
115
|
+
{
|
116
|
+
yield(this, this->post_neuron);
|
117
|
+
}
|