Auryn simulator  v0.8.1-206-gb56e451
Plastic Spiking Neural Network Simulator
AurynVector.h
Go to the documentation of this file.
1 /*
2 * Copyright 2014-2018 Friedemann Zenke
3 *
4 * This file is part of Auryn, a simulation package for plastic
5 * spiking neural networks.
6 *
7 * Auryn is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Auryn is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Auryn. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * If you are using Auryn or parts of it for your work please cite:
21 * Zenke, F. and Gerstner, W., 2014. Limits to high-speed simulations
22 * of spiking neural networks using general-purpose computers.
23 * Front Neuroinform 8, 76. doi: 10.3389/fninf.2014.00076
24 */
25 
26 #ifndef AURYNVECTOR_H_
27 #define AURYNVECTOR_H_
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctime>
32 #include <assert.h>
33 #include "auryn_definitions.h"
34 
35 #include <boost/serialization/utility.hpp>
36 #include <boost/serialization/split_member.hpp>
37 
38 #include <boost/random/mersenne_twister.hpp>
39 #include <boost/random/variate_generator.hpp>
40 #include <boost/random/normal_distribution.hpp>
41 
42 namespace auryn {
43 
58  template <typename T, typename IndexType = NeuronID >
59  class AurynVector {
60  private:
61 
63  void * mem;
64 
65  friend class boost::serialization::access;
66  template<class Archive>
67  void serialize(Archive & ar, const unsigned int version)
68  {
69  ar & size;
70  for ( IndexType i = 0 ; i < size ; ++i )
71  ar & data[i];
72  }
73 
74  protected:
78  void check_size(IndexType x)
79  {
80 #ifndef NDEBUG
81  if ( x >= size ) {
83  }
84 #endif
85  }
86 
91  {
92 #ifndef NDEBUG
93  if ( v->size != size ) {
95  }
96 #endif
97  }
98 
100  void allocate(const NeuronID n) {
101 #if defined(CODE_USE_SIMD_INSTRUCTIONS_EXPLICITLY) && defined(CODE_ALIGNED_SIMD_INSTRUCTIONS)
102  std::size_t mem_alignment = sizeof(T)*SIMD_NUM_OF_PARALLEL_FLOAT_OPERATIONS;
103  std::size_t mem_size = sizeof(T)*n;
104  mem = malloc(mem_size+mem_alignment-1); // adds padding to allocated memory
105  T * ptr = (T*)mem;
106  if ( (unsigned long)mem%mem_alignment ) ptr = (T*)(((unsigned long)mem/mem_alignment+1)*mem_alignment);
108  // T * ptr = (T*)boost::alignment::aligned_alloc(sizeof(T)*SIMD_NUM_OF_PARALLEL_FLOAT_OPERATIONS,sizeof(T)*n);
109  if ( mem == NULL ) {
110  // TODO implement proper exception handling
112  }
113  assert(((unsigned long)ptr % mem_alignment) == 0);
114 #else
115  T * ptr = new T[n];
116 #endif
117  data = ptr;
118  size = n;
119  set_zero();
120  }
121 
122  void freebuf() {
123 #if defined(CODE_USE_SIMD_INSTRUCTIONS_EXPLICITLY) && defined(CODE_ALIGNED_SIMD_INSTRUCTIONS)
124  free(mem);
126  // boost::alignment::aligned_free(data);
127 #else
128  delete [] data;
129 #endif
130  }
131 
133  T fast_exp256(T x)
134  {
135  x = 1.0 + x / 256.0;
136  x *= x; x *= x; x *= x; x *= x;
137  x *= x; x *= x; x *= x; x *= x;
138  return x;
139  }
140 
141  protected:
142 
143  public:
151  IndexType size;
152 
154  T * data;
155 
157  AurynVector(IndexType n)
158  {
159  allocate(n);
160  }
161 
166  {
167  allocate(vec->size);
168  copy(vec);
169  }
170 
171 
173  virtual ~AurynVector()
174  {
175  freebuf();
176  }
177 
184  virtual void resize(IndexType new_size)
185  {
186  if ( size != new_size ) {
187  T * old_data = data;
188  IndexType old_size = size;
189  allocate(new_size);
190  // copy old data
191  const size_t copy_size = std::min(old_size,new_size) * sizeof(T);
192  memcpy(data, old_data, copy_size);
193  free(old_data);
194  }
195  }
196 
200  void copy(AurynVector * v)
201  {
202  check_size(v);
203  std::copy(v->data, v->data+v->size, data);
204  }
205 
207  T get(IndexType i)
208  {
209  check_size(i);
210  return data[i];
211  }
212 
217  T * ptr(IndexType i = 0)
218  {
219  check_size(i);
220  return data+i;
221  }
222 
224  void set(IndexType i, T value)
225  {
226  check_size(i);
227  data[i] = value;
228  }
229 
230 
232  void set_all(const T v)
233  {
234  for ( IndexType i = 0 ; i < size ; ++i ) {
235  data[i] = v;
236  }
237  }
238 
240  void set_zero()
241  {
242  set_all(0.0);
243  }
244 
246  void scale(const T a)
247  {
248  for ( IndexType i = 0 ; i < size ; ++i ) {
249  data[i] *= a;
250  }
251  }
252 
253 
255  void add(const T c)
256  {
257  for ( IndexType i = 0 ; i < size ; ++i ) {
258  data[i] += c;
259  }
260  }
261 
263  void add_specific(const IndexType i, const T c)
264  {
265  check_size(i);
266  data[i] += c;
267  }
268 
270  void mul_specific(const IndexType i, const T c)
271  {
272  check_size(i);
273  data[i] *= c;
274  }
275 
279  void add(AurynVector * v)
280  {
281  check_size(v);
282  for ( IndexType i = 0 ; i < size ; ++i ) {
283  data[i] += v->data[i];
284  }
285  }
286 
288  void sub(const T c)
289  {
290  add(-c);
291  }
292 
294  void sub(AurynVector * v)
295  {
296  check_size(v);
297  for ( IndexType i = 0 ; i < size ; ++i ) {
298  data[i] -= v->data[i];
299  }
300  }
301 
303  void mul(const T a)
304  {
305  scale(a);
306  }
307 
311  void mul(AurynVector * v)
312  {
313  check_size(v);
314  for ( IndexType i = 0 ; i < size ; ++i ) {
315  data[i] *= v->data[i];
316  }
317  }
318 
322  void div(const T a)
323  {
324  scale(1.0/a);
325  }
326 
330  void div(AurynVector * v)
331  {
332  check_size(v);
333  for ( IndexType i = 0 ; i < size ; ++i ) {
334  data[i] /= v->data[i];
335  }
336  }
337 
343  void div(AurynVector * a, AurynVector * b)
344  {
345  check_size(a);
346  for ( IndexType i = 0 ; i < size ; ++i ) {
347  data[i] = a->data[i]/b->data[i];
348  }
349  }
350 
357  void saxpy(const T a, AurynVector * x)
358  {
359  check_size(x);
360  for ( IndexType i = 0 ; i < size ; ++i ) {
361  data[i] += a * x->data[i];
362  }
363  }
364 
372  void follow(AurynVector<T,IndexType> * v, const T rate)
373  {
374  for ( IndexType i = 0 ; i < size ; ++i ) {
375  data[i] += rate*(v->data[i]-data[i]);
376  }
377  }
378 
380  void follow_scalar(const T a, const T rate)
381  {
382  for ( IndexType i = 0 ; i < size ; ++i ) {
383  data[i] += rate*(a-data[i]);
384  }
385  }
386 
389  {
390  check_size(v1);
391  check_size(v2);
392  for ( IndexType i = 0 ; i < size ; ++i ) {
393  data[i] = std::max(v1->data[i],v2->data[i]);
394  }
395  }
396 
399  {
400  elementwise_max(this,v1);
401  }
402 
406  void pow(const unsigned int n)
407  {
408  for ( IndexType i = 0 ; i < size ; ++i ) {
409  data[i] = std::pow(data[i],n);
410  }
411  }
412 
416  void fast_exp()
417  {
418  // mul(0.00390625); // ie. 1.0/256.0
419  // add(1.0);
420  // for ( int i = 0 ; i < 8 ; ++i ) {
421  // sqr();
422  // }
423  // seems as if the naive version is faster
424  for ( IndexType i = 0 ; i < size ; ++i ) {
425  data[i] = fast_exp256(data[i]);
426  }
427  }
428 
430  void exp()
431  {
432  for ( IndexType i = 0 ; i < size ; ++i ) {
433  data[i] = std::exp(data[i]);
434  }
435  }
436 
437 
440  void sigmoid(AurynVector * x, const T beta, const T thr)
441  {
442  diff(x,thr);
443  mul(-beta);
444  exp();
445  add(1.0);
446  inv();
447  }
448 
449 
453  void sqrt()
454  {
455  for ( IndexType i = 0 ; i < size ; ++i ) {
456  data[i] = std::sqrt(data[i]);
457  }
458  }
459 
461  void neg()
462  {
463  for ( IndexType i = 0 ; i < size ; ++i ) {
464  data[i] = -data[i];
465  }
466  }
467 
469  void inv()
470  {
471  for ( IndexType i = 0 ; i < size ; ++i ) {
472  data[i] = 1.0/data[i];
473  }
474  }
475 
479  void sum(AurynVector * a, AurynVector * b)
480  {
481  check_size(a);
482  check_size(b);
483  for ( IndexType i = 0 ; i < size ; ++i ) {
484  data[i] = a->data[i]+b->data[i];
485  }
486  }
487 
491  void sum(AurynVector * a, const T b)
492  {
493  check_size(a);
494  for ( IndexType i = 0 ; i < size ; ++i ) {
495  data[i] = a->data[i]+b;
496  }
497  }
498 
502  void diff(AurynVector * a, AurynVector * b)
503  {
504  check_size(a);
505  check_size(b);
506  for ( IndexType i = 0 ; i < size ; ++i ) {
507  data[i] = a->data[i]-b->data[i];
508  }
509  }
510 
514  void diff(AurynVector * a, const T b)
515  {
516  sum(a,-b);
517  }
518 
522  void diff(const T a, AurynVector * b)
523  {
524  check_size(b);
525  sum(b,-a);
526  neg();
527  }
528 
529 
533  void sqr()
534  {
535  this->mul(this);
536  }
537 
541  void abs()
542  {
543  sqr();
544  sqrt();
545  }
546 
549  void rect()
550  {
551  for ( IndexType i = 0 ; i < size ; ++i ) {
552  if ( data[i] < 0.0 ) {
553  data[i] = 0.0;
554  }
555  }
556  }
557 
560  void neg_rect()
561  {
562  for ( IndexType i = 0 ; i < size ; ++i ) {
563  if ( data[i] > 0.0 ) {
564  data[i] = 0.0;
565  }
566  }
567  }
568 
574  void clip(T min, T max)
575  {
576  for ( IndexType i = 0 ; i < size ; ++i ) {
577  if ( data[i] < min ) {
578  data[i] = min;
579  } else
580  if ( data[i] > max )
581  data[i] = max;
582  }
583  }
584 
593  double var()
594  {
595  double sum = 0.0;
596  double sum2 = 0.0;
597  for ( IndexType i = 0 ; i < size ; ++i ) {
598  double elem = get(i);
599  sum += elem;
600  sum2 += std::pow(elem,2);
601  }
602  double var = (sum2-(sum*sum)/size)/(size-1);
603  return var;
604  }
605 
606 
612  double std()
613  {
614  return std::sqrt(var());
615  }
616 
622  double mean()
623  {
624  return element_sum()/size;
625  }
626 
630  double element_sum()
631  {
632  double sum = 0.0;
633  for ( IndexType i = 0 ; i < size ; ++i ) {
634  sum += get(i);
635  }
636  return sum;
637  }
638 
642  double l1norm()
643  {
644  double sum = 0.0;
645  for ( IndexType i = 0 ; i < size ; ++i ) {
646  double e = get(i);
647  sum += std::abs(e);
648  }
649  return sum;
650  }
651 
652 
656  double l2norm()
657  {
658  double sum = 0.0;
659  for ( IndexType i = 0 ; i < size ; ++i ) {
660  double e = get(i);
661  sum += e*e;
662  }
663  return std::sqrt(sum);
664  }
665 
669  double max()
670  {
671  double max = -1e64; // TODO use numeric limits for this
672  for ( IndexType i = 0 ; i < size ; ++i ) {
673  double el = get(i);
674  if ( el > max ) max = el;
675  }
676  return max;
677  }
678 
682  double min()
683  {
684  double min = 1e64; // TODO use numeric limits for this
685  for ( IndexType i = 0 ; i < size ; ++i ) {
686  double el = get(i);
687  if ( el < min ) min = el;
688  }
689  return min;
690  }
691 
697  IndexType nonzero()
698  {
699  IndexType sum = 0;
700  for ( IndexType i = 0 ; i < size ; ++i ) {
701  if ( get(i) != 0 ) ++sum;
702  }
703  return sum;
704  }
705 
709  void zero_effective_zeros( const T epsilon = 1e-3)
710  {
711  for ( IndexType i = 0 ; i < size ; ++i ) {
712  if ( std::abs(get(i)) < epsilon ) set(i, 0.0);
713  }
714  }
715 
716  void add_random_normal(AurynState mean=0.0, AurynState sigma=1.0, unsigned int seed=8721)
717  {
718  if ( seed == 0 )
719  seed = static_cast<unsigned int>(std::time(0));
720  boost::mt19937 randgen(seed);
721  boost::normal_distribution<> dist((double)mean, (double)sigma);
722  boost::variate_generator<boost::mt19937&, boost::normal_distribution<> > die(randgen, dist);
723  AurynState rv;
724  for ( IndexType i = 0 ; i<size ; ++i ) {
725  rv = die();
726  data[i] += rv;
727  }
728  }
729 
730  void set_random_normal(AurynState mean=0.0, AurynState sigma=1.0, unsigned int seed=8721)
731  {
732  set_all(0.0);
733  add_random_normal(mean, sigma);
734  }
735 
738  void set_random(unsigned int seed = 0)
739  {
740  set_random_normal(0.0,1.0,seed);
741  }
742 
744  bool any() {
745  for ( IndexType i = 0 ; i < size ; ++i ) {
746  if ( get(i) ) return true;
747  }
748  return false;
749  }
750 
752  bool any(T eps) {
753  for ( IndexType i = 0 ; i < size ; ++i ) {
754  if ( std::abs(get(i))>eps ) return true;
755  }
756  return false;
757  }
758 
760  void print() {
761  for ( IndexType i = 0 ; i < size ; ++i ) {
762  std::cout << get(i) << " ";
763  }
764  std::cout << std::endl;
765  }
766 
768  void write_to_file(std::string filename) {
769 
770  std::ofstream outfile;
771  outfile.open(filename.c_str(),std::ios::out);
772  if (!outfile) {
773  std::stringstream oss;
774  throw AurynOpenFileException();
775  }
776 
777  outfile << std::setprecision(7);
778 
779  for ( IndexType i = 0 ; i < size ; ++i ) {
780  outfile << get(i) << "\n";
781  }
782 
783  outfile.close();
784  }
785  };
786 
787 
788 
789 
796  class AurynVectorFloat : public AurynVector<float,NeuronID>
797  {
798  private:
800 
801  public:
804 
807  {
808  };
809 
810 
811  virtual void resize(NeuronID new_size);
812  void scale(const float a);
813  void saxpy(const float a, AurynVectorFloat * x);
814  void clip(const float min, const float max);
815  void add(const float c);
816  void add(AurynVectorFloat * v);
817  void sum(AurynVectorFloat * a, AurynVectorFloat * b);
818  void sum(AurynVectorFloat * a, const float b);
819  void mul(const float a) { scale(a); };
820  void mul(AurynVectorFloat * v);
821  void diff(AurynVectorFloat * a, AurynVectorFloat * b);
822  void diff(AurynVectorFloat * a, const float b);
823  void diff(const float a, AurynVectorFloat * b );
824  void follow(AurynVectorFloat * v, const float rate);
825 
826  // TODO add pow function with intrinsics _mm_pow_ps
827 
828  };
829 
830 }
831 
832 
833 #endif /*AURYNVECTOR_H_*/
Default Auryn vector template.
Definition: auryn_definitions.h:327
void zero_effective_zeros(const T epsilon=1e-3)
Sets all values whose absolute value is smaller than epsilon to zero.
Definition: AurynVector.h:709
void check_size(AurynVector *v)
Checks if vector size matches to this instance.
Definition: AurynVector.h:90
void sum(AurynVector *a, AurynVector *b)
Computes the sum a+b and stores the result in this instance.
Definition: AurynVector.h:479
double l2norm()
Computes the l2 norm of the vector.
Definition: AurynVector.h:656
T fast_exp256(T x)
Computes approximation of exp(x) via fast series approximation up to n=256.
Definition: AurynVector.h:133
void sqr()
Squares each element.
Definition: AurynVector.h:533
void set_random(unsigned int seed=0)
Initializes vector elements with Gaussian of unit varince and a seed derived from system time if no s...
Definition: AurynVector.h:738
void elementwise_max(AurynVector *v1, AurynVector *v2)
Elementwise max operation.
Definition: AurynVector.h:388
void print()
Print vector elements to stdout for debugging.
Definition: AurynVector.h:760
void mul(AurynVector *v)
Element-wise vector multiply.
Definition: AurynVector.h:311
virtual ~AurynVector()
Default destructor.
Definition: AurynVector.h:173
void sum(AurynVector *a, const T b)
Computes the sum a+b and stores the result in this instance.
Definition: AurynVector.h:491
void check_size(IndexType x)
Checks if argument is larger than size and throws and exception if so.
Definition: AurynVector.h:78
T * data
Pointer to the array housing the data.
Definition: AurynVector.h:154
void set_all(const T v)
Set all elements to value v.
Definition: AurynVector.h:232
void sub(const T c)
Subtract constant c to each vector element.
Definition: AurynVector.h:288
void set_zero()
Set all elements to zero.
Definition: AurynVector.h:240
void allocate(const NeuronID n)
Implements aligned memory allocation.
Definition: AurynVector.h:100
double mean()
Computes the mean of the vector elements on this rank.
Definition: AurynVector.h:622
void mul(const float a)
Definition: AurynVector.h:819
int n
Definition: mkpat.py:5
void follow(AurynVector< T, IndexType > *v, const T rate)
Follows target vector v with rate.
Definition: AurynVector.h:372
IndexType size
Size of the vector.
Definition: AurynVector.h:151
double element_sum()
Computes the sum of the vector elements.
Definition: AurynVector.h:630
void fast_exp()
Computes an approximation of exp(x) for each vector element.
Definition: AurynVector.h:416
Definition: auryn_definitions.h:265
void diff(AurynVector *a, AurynVector *b)
Computes the difference a-b and stores the result in this instance.
Definition: AurynVector.h:502
void mul_specific(const IndexType i, const T c)
Multiply to specific vector element with data index i with the constant c.
Definition: AurynVector.h:270
Definition: auryn_definitions.h:208
void inv()
Computes 1./x of each element.
Definition: AurynVector.h:469
double min()
Returns the min of the vector elements.
Definition: AurynVector.h:682
void freebuf()
Definition: AurynVector.h:122
bool any()
Returns true if any element is nonzero.
Definition: AurynVector.h:744
double var()
Computes the variance of the vector elements on this rank.
Definition: AurynVector.h:593
AurynVector(AurynVector *vec)
Copy constructor.
Definition: AurynVector.h:165
void exp()
Computes exp(x) for each vector element.
Definition: AurynVector.h:430
void pow(const unsigned int n)
Takes each element to the n-th power.
Definition: AurynVector.h:406
Definition: ABSConnection.h:38
void neg()
Flips the sign of all elements.
Definition: AurynVector.h:461
IndexType nonzero()
Computes number of nonzero elements on this rank.
Definition: AurynVector.h:697
void sub(AurynVector *v)
Elementwise subtraction.
Definition: AurynVector.h:294
AurynFloat AurynState
Type for Auryn state variables (default single precision since it needs to be compatible with auryn_v...
Definition: auryn_definitions.h:160
void div(const T a)
Element-wise division.
Definition: AurynVector.h:322
void diff(AurynVector *a, const T b)
Computes the difference a-b and stores the result in this instance.
Definition: AurynVector.h:514
void abs()
Takes absolute value of each element.
Definition: AurynVector.h:541
void sigmoid(AurynVector *x, const T beta, const T thr)
Computes sigmoid(beta*(x-thr)) for each vector element and stores result in this instance.
Definition: AurynVector.h:440
void add(AurynVector *v)
Adds a vector v to the vector.
Definition: AurynVector.h:279
void set_random_normal(AurynState mean=0.0, AurynState sigma=1.0, unsigned int seed=8721)
Definition: AurynVector.h:730
void rect()
Rectifies all elements.
Definition: AurynVector.h:549
bool any(T eps)
Returns true if any element is nonzero.
Definition: AurynVector.h:752
Definition: auryn_definitions.h:306
void neg_rect()
Negatively rectifies all elements.
Definition: AurynVector.h:560
#define SIMD_NUM_OF_PARALLEL_FLOAT_OPERATIONS
Use Intel Cilk Plus – only has an effect when CODE_USE_SIMD_INSTRUCTIONS_EXPLICITLY is enabled...
Definition: auryn_definitions.h:64
void add_random_normal(AurynState mean=0.0, AurynState sigma=1.0, unsigned int seed=8721)
Definition: AurynVector.h:716
AurynVector(IndexType n)
Default constructor.
Definition: AurynVector.h:157
void copy(AurynVector *v)
Copies vector v.
Definition: AurynVector.h:200
void add(const T c)
Adds constant c to each vector element.
Definition: AurynVector.h:255
void diff(const T a, AurynVector *b)
Computes the difference a-b and stores the result in this instance.
Definition: AurynVector.h:522
~AurynVectorFloat()
Default destructor.
Definition: AurynVector.h:806
T * ptr(IndexType i=0)
Gets pointer to element i from vector.
Definition: AurynVector.h:217
double max()
Returns the max of the vector elements.
Definition: AurynVector.h:669
void div(AurynVector *v)
Element-wise vector division.
Definition: AurynVector.h:330
void sqrt()
Takes the square root of each element.
Definition: AurynVector.h:453
void follow_scalar(const T a, const T rate)
Like follow but with a scalar target value a.
Definition: AurynVector.h:380
void write_to_file(std::string filename)
Print vector elements to a text file for debugging.
Definition: AurynVector.h:768
double std()
Computes the standard deviation of all elements on this rank.
Definition: AurynVector.h:612
void add_specific(const IndexType i, const T c)
Adds the value c to specific vector element i.
Definition: AurynVector.h:263
Default AurynVectorFloat class for performance computation.
Definition: AurynVector.h:796
void elementwise_max(AurynVector *v1)
Elementwise max operation with another vector.
Definition: AurynVector.h:398
virtual void resize(IndexType new_size)
resize data array to new_size
Definition: AurynVector.h:184
void clip(T min, T max)
Clips all vector elements to the range min max.
Definition: AurynVector.h:574
double l1norm()
Computes the l1 norm of the vector.
Definition: AurynVector.h:642
void div(AurynVector *a, AurynVector *b)
Element-wise vector division which stores the result in this.
Definition: AurynVector.h:343
void saxpy(const T a, AurynVector *x)
SAXPY operation as in GSL.
Definition: AurynVector.h:357
std::string string
Standard library string type which is imported into Auryn namespace.
Definition: auryn_definitions.h:156
void mul(const T a)
Multiply all vector elements by constant.
Definition: AurynVector.h:303
unsigned int NeuronID
NeuronID is an unsigned integeger type used to index neurons in Auryn.
Definition: auryn_definitions.h:151
void scale(const T a)
Scales all vector elements by a.
Definition: AurynVector.h:246