summaryrefslogtreecommitdiff
path: root/doc/techreport.org
blob: 9fc65feb147f235d661284b2dbe641aa1475e99e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
# meta information for org-mode
#+TITLE: RaSimu technical design document
#+AUTHOR: Jan Huwald
#+EMAIL: jh@sotun.de
#+OPTIONS: H:5 toc:2
#+LaTeX_CLASS: book

* General Data and Computation Structure
** Properties
   The simulation has an open number of properties. A properties value
   is derieved from it's own and other properties' values of the past
   using a fixed rule.
*** Ontological Association
    Each property has an ontological associated type. It is instanced
    for every object of the given type. The type determines further
    under wich circumstances the update rule of the property is called
    and when snapshots of the properties current values are
    stored. The available ontological types and their relations are:

#+ATTR_LaTeX: scale=0.25
#+begin_ditaa OntoTypeDeps.png -r -o -s 2.5
  +--------+     n +--------+     many +---------+
  | Global | ----- | Neuron | -------- | Synapse |
  +--------+ 1     +--------+ 2        +---------+
     1|             1|  1|                1|
      |              |   |                 |
      |many	     |   |many             |1 
 +-----------+       | +-------+  many +--------------+
 | GlobalMsg |       | | Spike |------ | SpikeArrival |  
 +-----------+       | +-------+ 1     +--------------+
                     |many 
                   +-------------+
		   | RandomSpike |
		   +-------------+
#+end_ditaa
 
*** Temporal nature
    All properties of above graphs first row types are continuous, all
    of second row types discrete.

    For discrete properties every single event is stored. Continuous
    properties are only stored at checkpoints. Checkpoints are roughly
    at regular intervals but fine-structured to exactly match the time
    of incoming events, so that a continuous property is only stored at
    moments of modification by an discrete property.

    The value of a continuous property instance (e.g. membrane
    potential of neuron 42) can be accessed for any time, whereas
    discrete properties can not be directly adressed. Instead one can
    only query them based on inequalities or ranges (e.g. get current
    value of oldest spike emitted from neuron 42 before 23s simulation
    time).
*** Dependencies
    A properties value may depend only on a strictly limited number of other values. These are
    determined by the properties type as follows. The dependency is explicitely stated as a
    (Type,Name)-Pair.

**** Discrete Properties
     Each discrete property may only depend on properties whose type is in the same column in the
     graph above. For continuous properties it may only depend on the value at the timepoint of the
     instance creation.

     An alternatve formulation is that discrete properties are events conditionally created by
     properties with common type column.

**** Continuous Properties
     A continuous property may depend on
     - global properties
     - properties of the same type (and instance)
     - discrete properties that are stated in the following table and associated to the instance
       via topology

       |---------------+-------------------------------|
       | Property Type | Available Discrete Properties |
       |---------------+-------------------------------|
       | Global        | GlobalEvent, Spike            |
       | Neuron        | SpikeArrival                  |
       | Synapse       | Spike                         |
       |---------------+-------------------------------|

     If a global type property depends on a spike type property it automatically depends on every
     spike. Contrary, synapse type properties depending on a spike type property will only receive
     the spikes corresponding the networks topology.

**** Circular Dependencies
     The dependency graph may have loops but must be circle free under ommission of all inter-type
     dependencies.

** Parallelization
   - coarse grained :: parallelization using property partitions without inter-partition dependency circle
   - fined grained :: usually single threaded; parallelization within a property partition might be
                      used if the property has no temporal dependency (e.g. mapping one spike value
                      to another)

*** Communiation Primitive
    - coarse grained :: client server with message passing
    - fine grained :: CREW shared memory with a per property heap split into three parts: read only,
                      write only and unused fulfilling the properties:
      1. 2*sizeof(addr_t) <= read barrier <= write barrier <= some constant (like 16G)
      2. barriers are stored in the beginning of the heap
      3. barriers are updated lockless and atomic (one barrier at a time)
      4. barriers may only increase

    The CREW shared memory is implemented using mmap'ed files.

*** Property Partitions
    The properties are partioned into minimal sets of circular dependent properties (idealy each of
    cardinality 1). For each set two interfaces and corresponding programs exist:
    - a reader interface, which reads discrete properties and replays / extrapolates continuous
      properties
    - a writer interface, wich generates (and stores to file) the values used by the reader
      interface

    Additional reader interfaces may exist for discrete properties of an larger than one cardinality
    property partition, if they do not require additional dependencies (wich is usually the case).

*** Rationale
    - maintain cache locality aside allowing an open number of properties
    - avoid the duplication of shared properties wihtin a single node
    - ensure that the shared memory can be emulated in a distributed memory environment with a
      common, lockable filesystem (e.g. NFS, OCFS).

* Implemenation Details
** Distribution Server
*** TODO define basic structure

** Slave
  The slave is a C++ programm wich calculates a (compile time) fixed
  set of properties. Several Slaves share a common database of
  property values using mmap'ed files.
*** mmap\_core
**** TODO test (logic, performance, nfs)

*** Properties
    - PropertyInstance :: Yields access to the value of a current property. Template logic is used
         to deduce the correct container type from the property. It may be instanced as write or
         read container. If writing, it will be backed by a mmap'ed container. If set to read and
         applied to a continuous property, it will only contain the last known value and will not be
         stored persistently.
    - property interaction classes :: Concentrate all methods which are applied on a property:
         evolution of the state, application of incoming and generation of outgoing events.
    - quantor types :: as described above
    - quantor class types :: indicating either discrete or continuous types
    - property lists :: store the the continuous (CPL) and discrete (DPL) properties  of a PropertyComposition
    - PropertyComposition :: hold the collection of properties of a simulation

#+ATTR_LaTeX: scale=0.4
#+begin_dot PropertiesMPLDeps.png -Tpng
digraph dsd {
  AP [ style=filled; label="actual\nproperties" ];
  XPtr [ label="pointer types:\nGlobalPtr\nNeuronPtr\nSynapsePtr\nGlobalMsgPtr\nSpikePtr\nSpikeArrivalPtr" ];
  PI [ label="property interaction:\nContinuousProperty<>\nDiscreteProperty<>" ];
  QUANT [ label="quantor types\nGlobal\nNeuron\nSynapse\nGlobalMsg\nSpike\nSpikeArrival" ];
  QCT [ label="quantor class types\nDiscreteProperty\nContinuousProperty" ];
  XPL [ label="property list:\nCPL<>, DPL<>" ];
  PA [ label="property list actions:\nPLA_Get, PLA_Evolve, ..." ];
  PropertyComposition [ label="PropertyComposition<>" ];

  PI -> { AP; PropertyInstance };
  AP -> { QUANT; PI; XPL };
  QUANT -> { XPtr; QCT };
  XPL -> { QUANT; AP; PA };
  PA -> XPL;
  PropertyComposition -> { XPL };
}
#+end_dot
**** Declaration of a Property
     1. use macro GEN_CP or GEN_DP to create a class for the property, containing it's name,
        storage type, quantor type, default value and (for continuous properties) it's evolution
        method.
     2. use macro GEN_CP_APPLY, ... to create actions depending on events.

You can than bundle the property using the PropertyList to a PropertyComposition which is then
used to execute or analyze the simulation.
**** Methods on Properties / Property List Actions
     All methods applied to properties are encapsulated into property list actions (PLA). Each PLA
     has a pre and a post method. Execution of a PLA instance means to apply it to the entire
     property list: first pre() from head to tail, then post() in the reverse direction. State can
     be stored per property and globally as illustrated below:

#+ATTR_LaTeX: scale=0.2
#+CAPTION: Control (solid) and data (dashed) flow of a property list action
#+begin_ditaa PLA_DataAndInstFlow.png -E -r -o -s 2.5
       +----------------+         other                           
       |  SomeProperty  |      properties                 
       |   +--------+   |      
   ------> | pre()  | -----------> ... ----+   
       |   +--------+   |                  |
       |                |                  |
       |    :           |                  |
       |    | local     |                  |
       |    | state     |                  |
       |    v           |                  |
       |                |                  |
       |   +--------+   |                  |
   <------ | post() | <----------- ... <---+
       |   |        |   |                     +----------------+
   <-=---- |        | <-------=--- ... <--=-- | NeutralElement |
       |   +--------+   |   fold              +----------------+
       +----------------+   state
#+end_ditaa

     It is noteworthy, that the type of the local state depends on the property visited. This allows
     for example to evolve an old value to a new one within pre(), store the new value as a local
     value and apply it in post() to the global data storage, thus not interfere with other
     properties, which depend on the value before evolution[fn::This two-phase update mechanism is
     neccessary to ensure determinism independent of the order and update rule of the
     properties]. It also allows to leave the local state empty for properties which are ignored by
     the PLA.
**** Property Update
     Discrete properties are created once and then remain constant. Contrary, continuous properties
     may be updated by advancing time or incoming events. Both situations are handled by PLAs:
     - PLA\_Evolve :: advance the time of an instance without incoming events
     - PLA\_Apply :: apply an incoming event to an instance and return if an event would be generated
     - PLA\_Generate :: generate the announced event and set the instance the to post-event state

     Because during the simulation an evolve is only called before application of an external event
     and events are only created at the time of an incoming event, these three PLAs are usually
     called together and in the above order.
*** Interfaces
**** Reading
     A Reader interface allows several ways to access the property values.

***** TODO Replay
      - Scope :: property partitions
      - Parameters :: {begin, end, delta} time, callback functions, initial folding pointer

      For each property of the associated partition a callback routine as given. The reader replays
      all properties in temporal ascending order (and without violating causality for coincident
      events). Every time a discrete property instance is generated the corresponding callback is
      executed. For continuous properties' callback this happens at begin time, end time and exactly
      every time delta.

      The callback is given the time, current value of the corresponding property and an additional
      pointer wich might be used to store a state during a folding operation. This pointer's value
      is returned by the previous callback function or set to the initial folding pointer for the
      first execution.

      Instead of a callback function a compile time function (object) might be used, if I have the
      time to implement it.
***** Range
      - Scope :: single properties
      - Parameters :: {begin, end} time

      Let you iterate over all property values within [begin time, end time]. In case of a discrete
      property this gives all instances. In case of a continuous property this gives all values at
      the exact times when it was influenced by an discrete property.

      For continuous properties only forward iteration is possible. For discrete properties backward
      iterating is allowed, too.
****** Extrapolating Range
       - Scope :: single continuous properties
       - Parameters :: {begin, end, delta} time

       Let you iterate over all property values at { begin + k * delta, end : k in {0,...} }. Forward
       only.
****** Structural Constraints
       Depending on the properties quantity type the following structural constraints are available
       to determine wich subsets of the quantity instances are of interest:

      |---------------+----------------------------------|
      | Quantity Type | Constraints                      |
      |---------------+----------------------------------|
      | Global        | all                              |
      | Neuron        | all                              |
      |               | group {X}                        |
      | Synapse       | all                              |
      |               | from neurons {X}                 |
      |               | to neurons {Y}                   |
      |               | from neurons {X}, to neurons {Y} |
      |---------------+----------------------------------|
      | GlobalEvent   | all                              |
      | Spike         | all                              |
      |               | from neurons {X}                 |
      |               | to neurons {Y}                   |
      |               | from neurons {X}, to neurons {Y} |
      | SpikeArrival  | all                              |
      |               | to neurons {Y}                   |
      |---------------+----------------------------------|
****** Associated Ranges
       Ranges may allow "navigation" within the data set by offering to return (thereby newly
       created) associated ranges of the current element of the range. For example when iterating
       over all spikes received by neuron A one may ask for a range giving all spikes sent by the
       sender B of the spike currently in focus.

       Consider the sources for availability.
***** Query
      - Scope :: single properties
      - Parameters :: time

      Return the properties' value at time (continuous property) or at the maximal available
      timepoint before time (discrete property). Using this more often than O(1) within a programm
      should be avoided for efficiency reasons.
**** Writing

*** Memory Mapped Data Structures
    The following figure gives an overview of the structures described in this section and their dependencies.
#+ATTR_LaTeX: scale=0.3
#+CAPTION: Dependencies of data structures. Memory mapped containers are denoted as rectangles, composed data structures as hexagons and indexed data structures as ellipses
#+begin_dot DataStructDeps.png -Tpng
digraph dsd {
  Scalar [ shape="box" ];
  Vector [ shape="box" ];
  Heap [ shape="box" ];
  Checkpoint [ shape="box" ];
  Array [ shape="hexagon" ];
  PriorityQueue [ shape="hexagon" ];
  NeuronProperties [ label="Neuron\nProperties" ];
  SynapseProperties [ label="Synapse\nProperties" ];
  GlobalProperties [ label="Global\nProperties" ];
  SpikeProperties [ label="Spike\nProperties" ];
  SpikeArrivalProperties [ label="SpikeArrival\nProperties" ];

  Scalar ->{ Heap; Vector; SpikeProperties };
  Vector -> { Heap; Checkpoint; SpikeProperties };
  Array -> { NeuronProperties; Checkpoint; SpikeArrivalProperties };
  Checkpoint -> { NeuronProperties; SynapseProperties; GlobalProperties };
  SpikeProperties -> SpikeArrivalProperties;
  PriorityQueue -> PendingEvents;
  Heap -> PendingEvents;
}
#+end_dot
**** MMapped Containers
     The following entities have a corresponding memory mapped file for each of their instances.
***** Scalar
      A scalar is a mmaped integer of arbitrary (compile time determined) size. For parallelisation
      purposes it's value must not decrease. It is used to store bounds for arrays.
***** Vector
      An Vector is the core data structure of rasimu. It is a memory mapped file, containing a
      regular data structure of equally sized elements. The elements have a compile time fixed width
      of $2^n$ bits. An element is retrieved by a nonnegative integer.

      Each array has a potentially unlimited size, but is constrained by the compile time determined
      number of pages allocated via the mmap call[fn:2]. Each array is accompanied by to Scalars:
      the current read and write barrier.

      As syntactic sugar each array has an associated pointer object which could be used for read
      access in any case and for write access if the width of the array elements is equal or greater
      $8b$.
***** Checkpoint
      A checkpoint stores the latest perfect value of a property at regular (compile time fixed)
      time interval. A perfect value is one, which is obtained immideatly after appying a discrete
      event to a continuous property. Compared to storing the properties value exactly at regular
      intervals, that way no superficious time evolution of the value and thus no numerical
      deviation of the stored value from the one used for further computation is possible. This
      allows deterministically stopping and restarting the simulation and is thus core of the used
      replay techniques.

      A checkpoint is implemented as two Vectors, each storing one Array per time slice. The Arrays
      width is compile time fixed. One vector stores the last perfect value of each time slice, the
      other the time at which it occured.
      occured. 
***** Heap
      A checkpointed heap of variable length[fn:3]. It stores the latest state of the heap for each
      time slice. Write access is only allowed to the latest heap - or corresponding to a time
      greater or equal to the last access time. In contrast to a Checkpoint the time point of the
      last modification is not stored.

      When crossing the boundaries between two time slices the Heap copies it's payload to a new
      location. To densely pack all payload instances the payload class has to offer a
      size()-method.
**** Composed data structures
     The following entities can be used as element of the above container data structures. This
     demands that they are copy and default constructable, self-contained and position independent.
***** Array
      A vector is continuous patch of memory containg a fixed number of equal sized elements. Both -
      vector width and element width - are compile time fixed. Array and element width must be of
      the form $2^n$.
***** PriorityQueue
      As seen on TV! A priority queue based on binary heaps.
**** Indexed data structures
     The following entities store the aforementioned properties using the containers above. The
     general principle is that for each ontological type a single index exists, wich allows
     navigating in multiple bodies of the same ontological type - one body per property. The index
     itself may consist of several mmaped containers. Each index offers a specialised allocator to
     allow creation of new elements.
***** Continuous properties
      Storage of continuous properties is implemented using a
      Checkpoint object. For *Global properties* the Vector's element
      is a time scalar. For *Neuron* and *Synapse properties* it is an
      Array of time scalars - for each neuron/synapse the last perfect
      value occured at a different time. The corresponding body of
      each property is structured the same way - Vector of scalar
      values for global properties, Vector of Arrays of scalar values
      for neuron and synapse properties.
***** Discrete Properties
      All discrete properties are stored using Vectors in temporally ascending order accompanied by
      an index which associates each property instance with the time of its occurence. Because each
      neurons frequency is roughly constant, binary searching an element in the index is possible in
      $O(n\log{n})$ time.

      *GlobalEvent properties* have a simple index: an Vector of ascendingly sorted timepoints of
      their occurence. The body is an Vector of the corresponding properties.

      *Spike properties* are stored in temporally ascending order. The index consists of an Vector of
      scalars for each of the following table's properties.

     |--------+-----------+------------------------------------|
     | Type   | Width [b] | Description                        |
     |--------+-----------+------------------------------------|
     | time   |        64 | time point when the spike happened |
     | neuron |        16 | id of the neuron firing the spike  |
     | prev   |        32 | id of last spike of that neuron    |
     | next   |        32 | id of next spike of that neuron    |
     |--------+-----------+------------------------------------|
      
      The spike property body is an Vector with the property values as elements.

      For *SpikeArrival properties* the Spike property index is reused. But the bodies are Arrays
      of SpikeArrival property values. The Array width is set to $2^{\lceil\log\max{fanout}\rceil}$
      so that all spike arrivals corresponding to one spike could be stored in one Array. They are
      thus stored sorted ascendingly in the time of the outgoing spike instead of the spike arrival
      time[fn:1].

***** Pending Events
      implemented as heap of priority queues, wich gives a regular
      snapshot of the pending events
** Properties Definition
   Properties can be defined via the CPP macros explained below, or
   using a model definition DSL, which is translated into these
   macros. The later way is preferred.
*** Available variables
    * td :: time difference since to gapped (only with evolution of
            continuous variables)
    * id :: the id of the thing to calculate
    * all properties of the same quantor class and associated quantor
      classes which are unique
*** Continuous Properties
    A continuous property is defined using the macros GEN_CP,
    GEN_CP_EVOLVE and GEN_CP_APPLY. GEN_CP defines the type and its
    static properties. It takes the quantor type (parameter 1), the
    properties name as C++ type (2) and string (3), the backing C++
    type (4) and its initial value (5). The backing type usually is
    int, float or bool.

    The time evolution of the property is defined using GEN_CP_EVOLVE
    which takes the property name (1) and assigns a RHS expression (2)
    to it. This expression has to calculate the new value of a given
    instance of itself at time $t + td$ using the time delta between
    last update $td$, absolute time of last update $t$ and the
    previous value $self$ of the given $instance$ at time $t$. To get
    values of other properties the macro _CP can be used with a
    property name (1). It can however only be used to get properties
    of the same instance of the property under evolution. If access to
    properties of a different quantor type is neccessary the
    Property_Get template function has to be used. Note that this is
    only allowed for associated quantor types (e.g. accessing a Neuron
    property during the evolution of a Spike property). Properties of
    non-associated instances of any quantor type is prohibited.

    The behaviour under incoming events may be defined using the macro
    GEN_CP_APPLY. It is given the quantor type of continuous property
    (1) receiving the discrete property of the given quantor type (2).
    continuous (2) property. .. TODO (generation of events via 3 bool
    flags, update of value)
    
*** Discrete Properties
    Discrete Properties are more complex in their data dependency. At
    the same time they are fewer in numbers and have a smaller
    implementation burden regarding the range accessors. Thus no
    macros arre given to ease their implementation and the have to be
    defined as template specialisations of .. TODO
** Adding new quantor
   There is no central list of quantors admissible for compile time
   programming, yet. To add a new quantor one has to call several
   macros and create some custom structures:
   * quant_types.hpp: declare quantor via GEN_QUANT_PROP (respectively
     GEN_DQ_PROP) and add to appropriate quantor list
   * add to account in report_spacereq and report_names
   * pointers.hpp: add specialization for Ptr<>

   Depending on the temporal nature of the quantor, additional
   definitions are neccessary:
*** Continuous quants
    * context.hpp: specialization of ContinuousContext
    * to be continued
*** Discrete quants
    * event.hpp: add specialization of Event<>
    * sim_loop.hpp:
      * SimLoop(): add to ctor  of queues, indices
      * run(): add to type switch (macro HT)
      * handleEvent(): add to event creation (macro MGE)
    * context.hpp: spezialisation of DelieveryContext
** Tools
*** simulate
    Run the simulation until a given timepoint. May be terminated with
    C-c without causing data corruption.
*** convert_topology
    Read a plain text topology file and convert it into the rasimu
    storage format.
*** bootstrap
    Bootstrap the simulation by initializing all values (except those
    touched by convert_topology). A global message is created as well
    as a random spike for each neuron.
*** replay
    Replay a given property of given instance for the given interval
    at the given time delta.
*** coarse_replay
    Like replay, but instead of rerunning a part of the simulation
    only the values stored in the regular snapshots are displayed.
*** spike_out
    List all outgoing spikes of a given neuron in a given timespan.
*** report_names
    Lists all properties defined wihtin the current model and gives
    their quantor class.
*** report_spacereq
    The programm report_spacereq calculates the space requirements for
    typical simulation scenarios and the attribution of different
    quantity types to these numbers. It is also an example on how to
    (ab)use metaprogramming to implement compile-time reflection on
    the property definitions.
*** tests
    Named core/test_bla a number of illustrative test cases and
    performance benchmarks for almost all components can be found. The
    tests are successful if their exit status is zero. Beyond
    regression testing these files are useful entry points for
    studying the source code as they stress isolated issues.
* Footnotes

[fn:1] This is a space optimisation, because typical SpikeArrival properties are 1 or 2 bit wide and
thus far smaller than a complete index of spike arrival events.

[fn:2] However this value can be increased during a simulation using recompilation of the simulator.

[fn:3] The length has to be a multiple of one machine word for alignment reasons.
contact: Jan Huwald // Impressum