summaryrefslogtreecommitdiff
path: root/fibre_elongation_model.hh
blob: 15db6311c406238d7c625a4b0d0b0f05299ec1fe (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
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
/*
  © Copyright 2008 Randal A. Koene <randalk@netmorph.org>
  
  With design assistance from J. van Pelt & A. van Ooyen, and support
  from the Netherlands Organization for Scientific Research (NWO)
  Program Computational Life Sciences grant CLS2003 (635.100.005) and
  from the EC Marie Curie Research and Training Network (RTN)
  NEURoVERS-it 019247.

  This file is part of NETMORPH.

  NETMORPH is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  NETMORPH is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with NETMORPH.  If not, see <http://www.gnu.org/licenses/>.
*/
// fibre_elongation_model.hh
// Randal A. Koene, 20051221

/* Documentation:
   This implements classes for models of neural fiber elongation
   during network development. These models seek to preserve the
   desired elongation statistics for axon and dendrite arbor.

   As terminal segments elongate, they are the obvious place in
   which to link to a fiber elongation model.

   The models here strive to abide by the guidelines for the
   network generation framework. For example, as a consequence of
   those guidelines, the models offer two types of constructors:
   (1) A constructor that determines if a chained model should
   be sought and linked, and that searches for parameter
   specifications at a given resolution. (2) A constructor that
   copies parameters from a schema and clones chained model
   objects. The first constructor is used when schemas are
   created. The second constructor is used when model objects
   are cloned according to the most subset specific schema
   (or directly from other model objects at the same resolution,
   as in the case of model propagation during branching at
   terminal segments).

   Some more documenation of the parameter specification method
   is available in neuron.cc.

   When creating a new model BASE, keep in mind the following:
   A. Find specifications, as at the top of neuron.cc.
   B. Allocate to arbor and terminal segments in prepost_structure.cc.
   C. Have a model selection function.
   D. Call handle_branching from terminal_segment::branch().
   E. Call handle_turning from terminal_segment::turn() (actually in turn_without_update_of_segment_vector()).
 */

#ifndef __FIBRE_ELONGATION_MODEL_HH
#include "event.hh"
#include "Command_Line_Parameters.hh"
#include "global.hh"
class elongation_rate_initialization_model_base;
#define __FIBRE_ELONGATION_MODEL_HH

#ifndef __FIBRE_STRUCTURE_HH
class terminal_segment;
class fibre_structure;
#endif

#ifdef TESTING_ELONGATION_TOTAL
extern double usedarborelongationfraction;
#endif

  /* To do:
     - Separate the tasks of (a) obtaining the amount of arbor elongation
       and (b) obtaining the proportions allocated to specific terminal
       segments by creating actual separate model classes. Each task could
       in fact be carried out by a chain of models.
       See also notes starting with TL#200602171257.1. [PARTLY DONE]
     - Link the models of task (a) to the pre/postsynaptic structures,
       see where best to link (i) model selection and (ii) calls to model
       functions for the models of task (b).
     - I can allow calls to (a) to occur once per cycle for each arbor,
       while calls to (b) can appear as needed (see current growth
       functions). Note that the assignment of proportions may also occur
       just once if that simplifies the distribution of elongation, i.e.
       (a) can call a proportion determining function of (b) in all
       terminal segments.
     - Create at least one functional derived class for the statistical
       approach.
     - In that class, obtain the mean elongation of an arbor for a specific
       time step. Also obtain the standard deviation and use a good
       probability density function for the random selection of the actual
       arbor elongation.
     - Divvie up the amount of fiber available among terminal segments,
       using plausible models for speeding up and slowing down of elongation.
       This is done in terms of a proportion of the available fiber, and
       that proportion can be determined by a combination of the chained
       elongation models.
     - Check to see if the explit handling in separate classes of the
       separate model tasks has any performance disadvantages.
     - Check to see that all guidelines of the framework were met.
   */

class arbor_elongation_model_base {
  // Each pre/postsynaptic arbor is designated an elongation model, since
  // the resources provided for elongation are hypothesized to be limited
  // and distributed per arbor. Some derived classes of this class
  // may allow sharing of the same object for many
  // arbors, in which case specific information is obtained when elongation
  // functions are called. Otherwise, each assigned elongation model object
  // is unique. If an elongation model object is shared by multiple arbors,
  // then such a model must define a delete_shared() function that counts
  // how many arbors are still using the object, so that it is only deleted
  // when no longer in use.
  // Elongation models to use can be chosen at general and increasingly
  // specific levels: network, neuron, pre/postsynaptic structure.
  // This base object enables chaining of multiple elongation models.
protected:
  arbor_elongation_model_base * contributing;
  double contributingweight;
  double prev_t; // equivalent of model t_0 (see TL#200603140355.2)
  probability_distribution_function * pdf; // this also needs cloning and deletion
  struct arbor_elongation_model_base_parameters {
    double dL; // elongation resources for this update
    arbor_elongation_model_base_parameters(double _dL): dL(_dL) {}
  } base_parameters;
  virtual ~arbor_elongation_model_base() { if (contributing) contributing->delete_shared(); if (pdf) delete pdf; }
public:
  arbor_elongation_model_base(arbor_elongation_model_base * aemcontrib, double & aemweight, arbor_elongation_model_base & schema);
  arbor_elongation_model_base(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual void delete_shared() { delete this; }
  void reset(double t = 0.0);
  virtual arbor_elongation_model_base * clone() = 0;
  int total_terminal_segments(fibre_structure * arbor, growth_cone_competition_type scope);
  virtual double predict_elongation(fibre_structure * arbor) = 0;
  virtual double predict(double weight, fibre_structure * arbor);
  virtual double elongation(fibre_structure * arbor);
  virtual String report_parameters_specific() = 0;
  String report_parameters();
};

typedef arbor_elongation_model_base * arbor_elongation_model_base_ptr;

class van_Pelt_arbor_elongation_model: public arbor_elongation_model_base {
  // This is an elongation model that deals specifically with establishing
  // the resources applied to elongation in an arbor, regardless of
  // the specific distribution to terminal segments. It uses the model
  // functions by van Pelt and Uylings to determine the elongation over a
  // time interval of development.
protected:
  struct van_Pelt_arbor_elongation_model_parameters {
    double _nu0; // initial mean elongation rate
    double _F; // parameter for the elongation rate dependency on the distribution of resources to multiple terminal segments (growth cones)
    growth_cone_competition_type _competition_with_all_trees; // select scope of N(t)
    //van_Pelt_arbor_elongation_model_parameters() {}
    van_Pelt_arbor_elongation_model_parameters(double nu0, double F, growth_cone_competition_type competition_with_all_trees): _nu0(nu0), _F(F), _competition_with_all_trees(competition_with_all_trees) {}
  } parameters;
public:
  van_Pelt_arbor_elongation_model(arbor_elongation_model_base * aemcontrib, double & aemweight, van_Pelt_arbor_elongation_model & schema);
  van_Pelt_arbor_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual arbor_elongation_model_base * clone();
  virtual double predict_elongation(fibre_structure * arbor);
  //void copy_parameters(van_Pelt_arbor_elongation_model_parameters & p) { p = parameters; }
  //double get_nu0() { return _nu0; }
  //double get_F() { return _F; }
  virtual String report_parameters_specific();
};

class Polynomial_O1_arbor_elongation_model: public arbor_elongation_model_base {
  // This arbor elongation model attempts to match elongation statistics as
  // in the van Pelt model, but is compatible with the polynomial approach to
  // branching. There is one significant difference in the elongation
  // calculation: The van Pelt model adjusts elongation according to the number
  // of terminal segments in all arbors of one kind (dendrite, axon) combined.
  // The Polynomial models adjust elongation according to the number of
  // terminal segments in the same arbor.
protected:
  // Note that I choose to allocate local parameters instead of inheriting
  // van_Pelt_arbor_elongation_model, so that I can specify different default
  // parameter values.
  struct Polynomial_O1_elongation_model_parameters {
    double _nu0; // initial mean elongation rate
    double _F; // parameter for the elongation rate dependency on the distribution of resources to multiple terminal segments (growth cones)
    Polynomial_O1_elongation_model_parameters(double nu0, double F): _nu0(nu0), _F(F) {}
  } parameters;
public:
  Polynomial_O1_arbor_elongation_model(arbor_elongation_model_base * aemcontrib, double & aemweight, Polynomial_O1_arbor_elongation_model & schema);
  Polynomial_O1_arbor_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual arbor_elongation_model_base * clone();
  virtual double predict_elongation(fibre_structure * arbor);
  virtual String report_parameters_specific();
};

class Polynomial_O3_arbor_elongation_model: public arbor_elongation_model_base {
  // Here the assumed polynomial is of order 3.
protected:
  // Note that I choose to allocate local parameters instead of inheriting
  // Polynomial_O1_arbor_elongation_model, so that I can specify different
  // default parameter values.
  struct Polynomial_O3_elongation_model_parameters {
    double _nu0; // initial mean elongation rate
    double _F; // parameter for the elongation rate dependency on the distribution of resources to multiple terminal segments (growth cones)
    double _nu1, _nu2; // square and cubic coefficients of elongation function
    Polynomial_O3_elongation_model_parameters(double nu0, double nu1, double nu2, double F): _nu0(nu0), _F(F), _nu1(nu1), _nu2(nu2) {}
  } parameters;
public:
  Polynomial_O3_arbor_elongation_model(arbor_elongation_model_base * aemcontrib, double & aemweight, Polynomial_O3_arbor_elongation_model & schema);
  Polynomial_O3_arbor_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual arbor_elongation_model_base * clone();
  virtual double predict_elongation(fibre_structure * arbor);
  virtual String report_parameters_specific();
};

class terminal_segment_elongation_model_base {
  // Models specific for terminal segments may be shared, in which case it
  // is sensible to designate them per pre/postsynaptic arbor.
  // Some derived classes of this calss
  // may allow sharing of the same object for many
  // arbors, in which case specific information is obtained when elongation
  // functions are called. Otherwise, each assigned elongation model object
  // is unique. If an elongation model object is shared by multiple arbors,
  // then such a model must define a delete_shared() function that counts
  // how many arbors are still using the object, so that it is only deleted
  // when no longer in use.
  // Elongation models to use can be chosen at general and increasingly
  // specific levels: network, neuron, pre/postsynaptic structure.
  // This base object enables chaining of multiple elongation models.
  friend class elongation_rate_initialization_model_base;
protected:
  terminal_segment_elongation_model_base * contributing;
  double contributingweight;
  double prev_t; // time of last elongation update
  double l_i_cache_t; // time of last perturbed expected elongation update
#ifndef REDUCED_MEMORY_PTSEM
  probability_distribution_function * pdf; // this also needs cloning and deletion
#endif
  struct terminal_segment_elongation_model_base_parameters {
    // The main purpose of l_i_cache: To cache the result of perturbed_expected_elongation(),
    //   so that multiple calculations per simulation time are avoided. This is done in
    //   the l_i_cache variable of the model at the HEAD of a chain of models.
    // Additional uses of l_i_cache: The cache value is READ in perturbed_expected_elongation()
    //   only if no function calls are needed, i.e. if the cached value is returned. Otherwise,
    //   the cached values is only WRITTEN to in perturbed_expected_elongation(). That means,
    //   it can be safely used as a local cache in functions called during calculations, such
    //   as predict_elongate(). Used as a local cache, l_i_cache will reflect the overall
    //   COMBINED result to functions in a model at the HEAD of a chain (since any local
    //   caching will be overwritten in perturbed_expected_elongation()), but will reflect a
    //   purely local value to functions in a model elsewhere in a chain. This difference can
    //   ALTER the implicit model response. E.g. the BESTL_TSEM will attempt to maintain the
    //   same combined elongation result if at the head of a chain, but will attempt to
    //   contribute the same expected elongation quota if elsewhere in a chain.
    //   [See TL#200709150740.1.]
    double l_i_cache; // perturbed expected elongation
    terminal_segment_elongation_model_base_parameters(double l_i): l_i_cache(l_i) {}
  } base_parameters;
  virtual ~terminal_segment_elongation_model_base() {
    if (contributing) contributing->delete_shared();
#ifndef REDUCED_MEMORY_PTSEM
    if (pdf) delete pdf;
#endif
  }
public:
  terminal_segment_elongation_model_base(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, terminal_segment_elongation_model_base & schema);
  terminal_segment_elongation_model_base(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual void delete_shared() { delete this; }
  void reset(double t = 0.0);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts) = 0;
  virtual void handle_branching(terminal_segment & ts1, terminal_segment & ts2);
  virtual void handle_turning(terminal_segment & ts);
  virtual double perturbed_expected_elongation();
  virtual double predict_elongate() = 0;
  virtual double predict(double weight);
  virtual void  elongate(terminal_segment * ts);
  virtual String report_parameters_specific() = 0;
  String report_parameters();
};

typedef terminal_segment_elongation_model_base * terminal_segment_elongation_model_base_ptr;

class simple_terminal_segment_elongation_model: public terminal_segment_elongation_model_base {
  // This elongation model has no memory and evenly divides resources,
  // prior to random perturbation (see generation-framework paper).
  // This is the equivalent of the legacy elongation model.
public:
  simple_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, simple_terminal_segment_elongation_model & schema);
  simple_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
  virtual String report_parameters_specific();
};

class inertia_terminal_segment_elongation_model: public terminal_segment_elongation_model_base {
  // This is an elongation model that deals specifically with the
  // allocation of a proportion of available elongation resources to a
  // particular terminal segment. This model implements a hypothesis of
  // physical inertia in the distribution of growth over terminal segments,
  // which may speed up or slow down for each terminal segment, but do so
  // in a reasonably gradual manner. This hypothesis is related to the
  // hypothesis at the base of the tension direction model.
  // This may be sensibly combined with a model that can react more
  // abruptly to features that are encountered in the environment.
public:
  inertia_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, inertia_terminal_segment_elongation_model & schema);
  inertia_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
  virtual String report_parameters_specific();
};

class second_order_terminal_segment_elongation_model: public terminal_segment_elongation_model_base {
  // This second order model maintains a parameter of elongation rate (or 
  // speed) and a parameter of acceleration. Together, these define the
  // relative state of terminal segment elongation (relative, since the
  // resulting elongation is scaled in proportion to the desired elongation
  // of other terminal segments that share the same resources).
  // A coefficient of inertia defines how strongly perturbations of the
  // acceleration affect the system.
protected:
  struct second_order_terminal_segment_elongation_model_parameters {
    double l_i_acceleration;
    double inertia;
    second_order_terminal_segment_elongation_model_parameters(double liacc, double _inertia): l_i_acceleration(liacc), inertia(_inertia) {}
  } parameters;
public:
  second_order_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, second_order_terminal_segment_elongation_model & schema);
  second_order_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
  virtual String report_parameters_specific();
};

class constrained_second_order_terminal_segment_elongation_model: public second_order_terminal_segment_elongation_model {
  // This model is identical to second_order_terminal_segment_elongation_model
  // in all respects, except that the relative elongation speeds are
  // constrained between the values 0.0 and 1.0, thereby moderating the
  // differences between elongation rates at competing terminal segments.
public:
  constrained_second_order_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, constrained_second_order_terminal_segment_elongation_model & schema);
  constrained_second_order_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
};

class initialized_CSO_terminal_segment_elongation_model: public constrained_second_order_terminal_segment_elongation_model {
  // This model is identical to the constrained_second_order_terminal_
  // segment_elongation_model in all respects, except that the initial
  // acceleration of the relative elongation speed of each new fiber can
  // be specified. A specifion of 0.0 can result in delayed elongation
  // (appearing as delayed branching), while negative specifications are
  // interpreted as "clone the parent or schema current acceleration".
  // If the initial acceleration parameter is not specified then the default
  // behavior is to clone the parent or schema current acceleration.
  // Note the special case when initial acceleration is specified as a
  // negative value and an object constructor receives no parent or schema
  // information (i.e. it is itself a schema), in which case the initial
  // value is determined by the base class constructor (see comments in the
  // fibre_elongation_model.cc source code for constructors of this class).
protected:
  struct initialized_CSO_terminal_segment_elongation_model_parameters {
    double initial_l_i_acceleration;
    initialized_CSO_terminal_segment_elongation_model_parameters(double initialliacceleration): initial_l_i_acceleration(initialliacceleration) {}
  } icsoparameters;
public:
  initialized_CSO_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, initialized_CSO_terminal_segment_elongation_model & schema);
  initialized_CSO_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual String report_parameters_specific();
};

class decaying_second_order_terminal_segment_elongation_model: public second_order_terminal_segment_elongation_model {
  // This model is identical to second_order_terminal_segment_elongation_model
  // in all respects, except that the acceleration of elongation speed decays
  // toward zero unless it is sufficiently perturbed from zero.
protected:
  struct decaying_second_order_terminal_segment_elongation_model_parameters {
    double t_decay;
    decaying_second_order_terminal_segment_elongation_model_parameters(double tdecay): t_decay(tdecay) {}
  } dsoparameters;
public:
  decaying_second_order_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, decaying_second_order_terminal_segment_elongation_model & schema);
  decaying_second_order_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
  virtual String report_parameters_specific();
};

class delayed_branch_terminal_segment_elongation_model: public terminal_segment_elongation_model_base {
  // This terminal segment elongation model can temporarily control
  // elongation of a new terminal segment after a bifurcation. This enables
  // delayed branching, while simply generating all branches according to
  // global stochastic functions.
  // Note: When used, the delay is automatically applied to "daughter"
  // branches at bifurcations, since those receive a new cloned copy of
  // the parent models, so that the delay is initialized in the
  // constructor.
  // See DIL#20050927095951.1.
protected:
  struct delayed_branch_terminal_segment_elongation_model_parameters {
    // The delay_time_constant parameter specifies the time constant of an
    // exponential function that governs the probability of specific
    // delay duration in this non-mechanistic delayed branching model.
    // [***INCOMPLETE] Adjust this to the way it is described in the
    // paper!
    double delay_time_constant;
    delayed_branch_terminal_segment_elongation_model_parameters(double d_t_c): delay_time_constant(d_t_c) {}
  } parameters;
    // The elongation_commencement variable is the computed time after
    // which elongation will no longer be delayed.
  double elongation_commencement;
public:
  delayed_branch_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, delayed_branch_terminal_segment_elongation_model & schema);
  delayed_branch_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
  virtual String report_parameters_specific();
};

#ifdef INCLUDE_BRANCHWISE_COMPETING_ICSO_TSEM
class branchwise_competing_ICSO_terminal_segment_elongation_model: public initialized_CSO_terminal_segment_elongation_model {
  // In this model, terminal segments compete for resources on a branch-by-branch bases. This model is
  // planned in DIL#20060323042401.1 and described in ~/src/nnmodels/nibr/elongation-competing-per-bifurcation.pdf.
};
#endif

class BESTL_terminal_segment_elongation_model: public terminal_segment_elongation_model_base {
  // This elongation model assumes that elongation rates between bifurcation points are
  // fixed at the value in the parameter cache. A new elongation rate is drawn only
  // after bifurcation. This class overloads the handle_branching() function.
  // In the simplest form, no perturbation is applied at all at updates. This is
  // very similar to the BESTL model used in [PELT:VARIABILITY].
  // With this TSEM it is also possible to add some elongation at the onset of each
  // new branch, based on the assumption that branching takes some time and that
  // branches already have some length once branching is completed (see TL#200805220909.1).
protected:
  probability_distribution_function * branchpdf; // this also needs cloning and deletion
public:
  BESTL_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, BESTL_terminal_segment_elongation_model & schema);
  BESTL_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  ~BESTL_terminal_segment_elongation_model() { if (branchpdf) delete branchpdf; }
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual double predict_elongate();
  virtual void handle_branching(terminal_segment & ts1, terminal_segment & ts2);
  virtual String report_parameters_specific();
};

class BESTL_nonnormalizing_terminal_segment_elongation_model: public BESTL_terminal_segment_elongation_model {
  // This elongation model is similar to the BESTL TSEM, but it assumes that F=0 at the
  // arbor level and does not apply normalization. In other words, the elongation speed
  // of each growth cone is absolute and not relative to the elongation speed of other
  // growth cones!
  // Beware: THIS DOES ASSUME THAT F=0! This also assumes that the nonnorm
  // BESTL ERI model is used.
  // (See TL#200805301000.1.)
public:
  BESTL_nonnormalizing_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, BESTL_nonnormalizing_terminal_segment_elongation_model & schema);
  BESTL_nonnormalizing_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  ~BESTL_nonnormalizing_terminal_segment_elongation_model() { if (branchpdf) delete branchpdf; }
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual void elongate(terminal_segment * ts);
  //virtual double predict_elongate();
  //virtual void handle_branching(terminal_segment & ts1, terminal_segment & ts2);
  virtual String report_parameters_specific();
};

class BESTLNN_pyramidal_AD_terminal_segment_elongation_model: public BESTL_nonnormalizing_terminal_segment_elongation_model {
  // This elongation model is similar to the non-normalizing BESTL TSEM, but
  // it is intended specifically for use with all_pyramidal_dendrites_sps,
  // since this TSEM uses parameters that describe a prototype apical
  // dendrite of a pyramidal neuron.
  // Beware: THIS DOES ASSUME THAT F=0! This also assumes that the nonnorm
  // BESTL ERI model is used.
protected:
  struct BESTLNN_pyramidal_AD_terminal_segment_elongation_model_parameters {
    double trunk_length_SQ;
    int num_obliques;
    double dist2nextoblique;
    String prefix;
    BESTLNN_pyramidal_AD_terminal_segment_elongation_model_parameters(double tr_len_SQ, int n_o, double d2_o, String p): trunk_length_SQ(tr_len_SQ), num_obliques(n_o), dist2nextoblique(d2_o), prefix(p) {}
  } parameters;
  probability_distribution_function * trunklengthpdf; // this also needs cloning and deletion
  probability_distribution_function * obliquespdf; // this also needs cloning and deletion
  probability_distribution_function * obliqueanglepdf; // this also needs cloning and deletion
  void initialize_parameters();
public:
  BESTLNN_pyramidal_AD_terminal_segment_elongation_model(terminal_segment_elongation_model_base * tsemcontrib, double & tsemweight, BESTLNN_pyramidal_AD_terminal_segment_elongation_model & schema);
  BESTLNN_pyramidal_AD_terminal_segment_elongation_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  ~BESTLNN_pyramidal_AD_terminal_segment_elongation_model() {
    if (trunklengthpdf) delete trunklengthpdf;
    if (obliquespdf) delete obliquespdf;
    if (obliqueanglepdf) delete obliqueanglepdf;
  }
  virtual terminal_segment_elongation_model_base * clone(terminal_segment * ts);
  virtual void set_next_oblique_distance();
  virtual void set_tuft_models(terminal_segment * ts);
  virtual void set_oblique_models(terminal_segment * ts);
  virtual void elongate(terminal_segment * ts);
  //virtual double predict_elongate();
  //virtual void handle_branching(terminal_segment & ts1, terminal_segment & ts2);
  virtual String report_parameters_specific();
};

class elongation_rate_initialization_model_base {
  // Specific models that determine the initial elongation rate of
  // terminal segments after a bifurcation. The cached perturbed elongation
  // quota terminal_segment::base_parameters.l_i_cache is set.
  // Note that with most TSEMs this is not necessary during growth prior to
  // bifurcation, since the quota has no effect then. All elongation
  // resources determined at the arbor level are used for elongation at the
  // single growth cone.
  // Some TSEM, such as the nonnorm_BESTL TSEM do make use of the
  // root_initialize() function that is provided by certain ERI models. In
  // the case of the BESTL TSEM this is necessary in order to draw an
  // initial elongation rate from a distribution, since no further variation
  // of that rate takes place until a first branching event.
  // (See TL#200807020156.10.)
  //
  // Models specific for terminal segments may be shared, in which case it
  // is sensible to designate them per pre/postsynaptic arbor.
  // Some derived classes of this class
  // may allow sharing of the same object for many
  // arbors, in which case specific information is obtained when elongation
  // functions are called. Otherwise, each assigned elongation model object
  // is unique. If an elongation model object is shared by multiple arbors,
  // then such a model must define a delete_shared() function that counts
  // how many arbors are still using the object, so that it is only deleted
  // when no longer in use.
  // Elongation models to use can be chosen at general and increasingly
  // specific levels: network, neuron, pre/postsynaptic structure.
  // This base object enables chaining of multiple elongation models.
  //
  // Note that this model relates to considerations described in
  // TL#200709152200.1 and linked task log entries.
protected:
  elongation_rate_initialization_model_base * contributing;
  double contributingweight;
  //probability_distribution_function * pdf; // this also needs cloning and deletion
  /* struct elongation_rate_initialization_model_base_parameters {
    sometype something; // perturbed expected elongation
    elongation_rate_initialization_model_base_parameters(sometype _something): something(_something) {}
    } base_parameters; */
  double Get_Mean_and_Max_Quotas(terminal_segment * t, double & maxquota);
  virtual ~elongation_rate_initialization_model_base() {
    if (contributing) contributing->delete_shared();
    //if (pdf) delete pdf;
  }
public:
  elongation_rate_initialization_model_base(elongation_rate_initialization_model_base * ericontrib, double & eriweight, elongation_rate_initialization_model_base & schema);
  elongation_rate_initialization_model_base(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual void delete_shared() { delete this; }
  virtual elongation_rate_initialization_model_base * clone() = 0;
  virtual void handle_branching(terminal_segment & ts1, terminal_segment & ts2);
  virtual void handle_turning(terminal_segment & ts);
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0) = 0;
  virtual double predict(double weight, double & predictedquota1, double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2);
  virtual void initialize(terminal_segment * ts1, terminal_segment * ts2);
  virtual void root_initialize(double & l_i_cache) {}
  virtual String report_parameters_specific() = 0;
  String report_parameters();
};

typedef elongation_rate_initialization_model_base * elongation_rate_initialization_model_base_ptr;

class length_distribution_eri_model: public elongation_rate_initialization_model_base {
  // This model uses the initial lengths (parts of remainders) of the two terminal segments,
  // when available, as a hint to their relative initial elongation quotas.
protected:
  probability_distribution_function * pdf; // this also needs cloning and deletion
  virtual ~length_distribution_eri_model() {
    if (pdf) delete pdf;
  }
public:
  length_distribution_eri_model(elongation_rate_initialization_model_base * ericontrib, double & eriweight, length_distribution_eri_model & schema);
  length_distribution_eri_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual elongation_rate_initialization_model_base * clone();
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0);
  virtual String report_parameters_specific();
};

class nonnorm_BESTL_length_distribution_eri_model: public length_distribution_eri_model {
  // This model uses the initial lengths (parts of remainders) of the two terminal segments,
  // when available, as a hint to which branch should receive the greater initial elongation rate.
  // This ERI model is compatible with the nonnorm_BESTL TSEM and treats the ERI distribution as a
  // distribution of absolute elongation rates.
public:
  nonnorm_BESTL_length_distribution_eri_model(elongation_rate_initialization_model_base * ericontrib, double & eriweight, nonnorm_BESTL_length_distribution_eri_model & schema);
  nonnorm_BESTL_length_distribution_eri_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual elongation_rate_initialization_model_base * clone();
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0);
  virtual void root_initialize(double & l_i_cache);
  virtual String report_parameters_specific();
};

class pure_stochastic_eri_model: public elongation_rate_initialization_model_base {
  // This model does not take into account initial lengths.
protected:
  probability_distribution_function * pdf; // this also needs cloning and deletion
  virtual ~pure_stochastic_eri_model() {
    if (pdf) delete pdf;
  }
public:
  pure_stochastic_eri_model(elongation_rate_initialization_model_base * ericontrib, double & eriweight, pure_stochastic_eri_model & schema);
  pure_stochastic_eri_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual elongation_rate_initialization_model_base * clone();
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0);
  virtual String report_parameters_specific();
};

class zero_eri_model: public elongation_rate_initialization_model_base {
  // This model assumes initialization with a zero quota. Elongation depends on
  // modification or perturbation of that initial elongation rate quota.
public:
  zero_eri_model(elongation_rate_initialization_model_base * ericontrib, double & eriweight, zero_eri_model & schema);
  zero_eri_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual elongation_rate_initialization_model_base * clone();
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0);
  virtual String report_parameters_specific();
};

class unitary_eri_model: public elongation_rate_initialization_model_base {
  // This model assumes initialization with a 1.0 quota.
  struct unitary_eri_model_parameters {
    double initialquota; // perturbed expected elongation
    unitary_eri_model_parameters(double _initialquota): initialquota(_initialquota) {}
    } unitary_parameters;
public:
  unitary_eri_model(elongation_rate_initialization_model_base * ericontrib, double & eriweight, unitary_eri_model & schema);
  unitary_eri_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual elongation_rate_initialization_model_base * clone();
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0);
  virtual String report_parameters_specific();
};

class continue_defaults_eri_model: public elongation_rate_initialization_model_base {
  // This model continues the branch that received the longest remainder of preceding
  // elongation with the quota of the parent fiber, while the other branch is initialized
  // according to default values (often zero, 1.0 in the case of BESTL TSEM).
public:
  continue_defaults_eri_model(elongation_rate_initialization_model_base * ericontrib, double & eriweight, continue_defaults_eri_model & schema);
  continue_defaults_eri_model(String & thislabel, String & label, Command_Line_Parameters & clp);
  virtual elongation_rate_initialization_model_base * clone();
  virtual void predict_initial_quota(double & predictedquota1,double & predictedquota2, terminal_segment * ts1, terminal_segment * ts2,double weight = 1.0);
  virtual String report_parameters_specific();
};

class terminal_segment_elongation_event: public Event {
protected:
  terminal_segment * ts;
public:
  terminal_segment_elongation_event(terminal_segment * _ts): ts(_ts) {}
  terminal_segment_elongation_event(double _t, terminal_segment * _ts): Event(_t), ts(_ts) {}
  virtual void event();
};

// global variables
extern arbor_elongation_model general_arbor_elongation_model;
extern String general_arbor_elongation_model_root;
extern terminal_segment_elongation_model general_terminal_segment_elongation_model;
extern String general_terminal_segment_elongation_model_root;
// [Now using the regular protocol natural set arrays.] extern arbor_elongation_model_base * general_arbor_elongation_model_schema;
// [Now using the regular protocol natural set arrays.] extern terminal_segment_elongation_model_base * general_terminal_segment_elongation_model_schema;
// See http://rak.minduploading.org:8080/caspan/Members/randalk/model-specification-implementation/.
extern elongation_rate_initialization_model default_elongation_rate_initialization_model; // identifier, changed when a different universal model is set
extern String universal_elongation_rate_initialization_model_root; // Used only to report if chaining at the universal set level.

// Region and natural subset specific schemas (initialized in neuron.cc:general_neuron_parameters_interface::parse_CLP(Command_Line_Parameters & clp, network & net))
typedef arbor_elongation_model_base_ptr * region_arbor_elongation_model_base_ptr;
extern region_arbor_elongation_model_base_ptr * arbor_elongation_model_region_subset_schemas;
// Region and natural subset specific schemas (initialized in neuron.cc:general_neuron_parameters_interface::parse_CLP(Command_Line_Parameters & clp, network & net))
typedef terminal_segment_elongation_model_base_ptr * region_terminal_segment_elongation_model_base_ptr;
extern region_terminal_segment_elongation_model_base_ptr * terminal_segment_elongation_model_region_subset_schemas;
// Region and natural subset specific schemas (initialized in neuron.cc:general_neuron_parameters_interface::parse_CLP(Command_Line_Parameters & clp, network & net))
typedef elongation_rate_initialization_model_base_ptr * region_elongation_rate_initialization_model_base_ptr;
extern region_elongation_rate_initialization_model_base_ptr * elongation_rate_initialization_model_region_subset_schemas;

// Indices for a few natural subsets, see TL#200603120618.2
/* Now using the regular protocol natural set arrays.*/
#define ALL_AXONS_AEM                      0
#define ALL_DENDRITES_AEM                  1
#define ALL_PYRAMIDAL_AXONS_AEM            2
#define ALL_PYRAMIDAL_DENDRITES_AEM        3
#define ALL_INTERNEURON_AXONS_AEM          4
#define ALL_INTERNEURON_DENDRITES_AEM      5
#define ALL_APICAL_PYRAMIDAL_DENDRITES_AEM 6
#define NUM_NATURAL_SUBSETS_AEM            7
#define ALL_AXONS_TSEM                      0
#define ALL_DENDRITES_TSEM                  1
#define ALL_PYRAMIDAL_AXONS_TSEM            2
#define ALL_PYRAMIDAL_DENDRITES_TSEM        3
#define ALL_INTERNEURON_AXONS_TSEM          4
#define ALL_INTERNEURON_DENDRITES_TSEM      5
#define ALL_APICAL_PYRAMIDAL_DENDRITES_TSEM 6
#define NUM_NATURAL_SUBSETS_TSEM            7

// functions

arbor_elongation_model_base * arbor_elongation_model_selection(String & label, Command_Line_Parameters & clp, arbor_elongation_model_base * superior_set, arbor_elongation_model_base_ptr & aembptr);
terminal_segment_elongation_model_base * terminal_segment_elongation_model_selection(String & label, Command_Line_Parameters & clp, terminal_segment_elongation_model_base * superior_set, terminal_segment_elongation_model_base_ptr & tsembptr);
elongation_rate_initialization_model_base * elongation_rate_initialization_model_selection(String & label, Command_Line_Parameters & clp, elongation_rate_initialization_model_base * superior_set, elongation_rate_initialization_model_base_ptr & eribptr);

#endif