main.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /*
  2. * main.cpp
  3. *
  4. * This file is part of the refactored Izhikevich polychronization model application.
  5. *
  6. * This source code is based on the poly_spnet.cpp and spnet.cpp source code available at
  7. * https://www.izhikevich.org/publications/spnet.htm.
  8. *
  9. * Copyright (C) 2018, Author: G. Trensch
  10. *
  11. * The refactored Izhikevich polychronization model application is free software:
  12. * you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation, either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * It is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this application. If not, see <http://www.gnu.org/licenses/>.
  24. *
  25. */
  26. #include "params.h"
  27. #if( __RUN_REFACTORED_VERSION__ )
  28. #include <math.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <cstring>
  32. #include "globals.h"
  33. #include "utils.h"
  34. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  35. // = C H E C K P A R A M E T E R S E T T I N G S
  36. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  37. #ifndef SIM_TIME
  38. #error SIM_TIME not defined!
  39. #endif
  40. #ifdef GENERATE_NETWORK_FROM_EXTERNAL_DATA
  41. #if( GENERATE_NETWORK_FROM_EXTERNAL_DATA )
  42. #ifndef INFILE_CONNECTION_MATRIX
  43. #error INFILE_CONNECTION_MATRIX not defined!
  44. #endif
  45. #ifndef INFILE_DELAY_MATRIX
  46. #error INFILE_DELAY_MATRIX not defined!
  47. #endif
  48. #ifndef INFILE_WEIGHT_MATRIX
  49. #error INFILE_WEIGHT_MATRIX not defined!
  50. #endif
  51. #else
  52. #ifndef OUTFILE_CONNECTIONS
  53. #error OUTFILE_CONNECTIONS not defined!
  54. #endif
  55. #ifndef OUTFILE_DELAYS
  56. #error OUTFILE_DELAYS not defined!
  57. #endif
  58. #ifndef OUTFILE_STIMULUS
  59. #error OUTFILE_STIMULUS not defined!
  60. #endif
  61. #endif
  62. #else
  63. #error GENERATE_NETWORK_FROM_EXTERNAL_DATA not defined!
  64. #endif
  65. #ifdef USE_EXTERNAL_STIMULUS
  66. #if( USE_EXTERNAL_STIMULUS )
  67. #ifndef INFILE_STIMULUS
  68. #error INFILE_STIMULUS not defined!
  69. #endif
  70. #endif
  71. #else
  72. #error USE_EXTERNAL_STIMULUS not defined!
  73. #endif
  74. #ifndef USE_STDP
  75. #error USE_STDP not defined!
  76. #endif
  77. #ifndef OUTFILE_FIRINGS
  78. #error OUTFILE_FIRINGS not defined!
  79. #endif
  80. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  81. // = F O R W A R D D E C L A R A T I O N S
  82. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  83. void InitializeNetwork();
  84. void InitializeSimulation();
  85. void FinalizeSimulation();
  86. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  87. // = M A I N E N T R Y
  88. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  89. int main() {
  90. printf( "\n\n%s\n\n", PARAM_INFO_STRING );
  91. printf( "[INFO] Running simulation for %d seconds\n", SIM_TIME );
  92. #if( ODE_SOLVER_REFINEMENT )
  93. for( int i = 0; i < NUM_TOTAL_NEURONS; ++i ) {
  94. spike[i] = 0;
  95. }
  96. #endif
  97. InitializeSimulation();
  98. InitializeNetwork();
  99. for( int simTimeSecond = 0; simTimeSecond < SIM_TIME; ++simTimeSecond ) { // simulation loop [seconds]
  100. for( int t = 0; t < 1000; ++t ) { // simulation loop [milliseconds]
  101. // clear I_ext[] and select a random neuron for input
  102. for( int i = 0; i < NUM_TOTAL_NEURONS; ++i ) {
  103. I_ext[i] = 0.0;
  104. }
  105. // REFACTOR COMMENT: the original implementation does not allow networks sizes < 1000 neurons
  106. // for( int idx = 0; idx < NUM_TOTAL_NEURONS / 1000; ++idx ) { ... }
  107. #if( USE_EXTERNAL_STIMULUS )
  108. int inputNeuron = GetNextExternalStimulusFromFile(INFILE_STIMULUS, simTimeSecond, t);
  109. #else
  110. int inputNeuron = GET_RANDOM_INT( NUM_TOTAL_NEURONS );
  111. #endif
  112. if( inputNeuron > 0 && inputNeuron != RC_NOID) {
  113. I_ext[inputNeuron] = I_EXT;
  114. }
  115. #ifdef OUTFILE_STIMULUS
  116. RecordRandomStimulusToFile( OUTFILE_STIMULUS, simTimeSecond, t, inputNeuron );
  117. #endif
  118. #if( ODE_SOLVER_REFINEMENT )
  119. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  120. if( spike[n] > 0 ) { // Does neuron n has fired?
  121. if( spike[n] > 1 ) printf( "[INFO] More than 1 spike in simulation interval.\n" );
  122. spike[n] = 0;
  123. LTP[n][t + MAX_SYNAPSE_DELAY] = 0.1;
  124. LTD[n] = 0.12;
  125. for( int idx = 0; idx < numPreSynapticNeuronsOfTarget[n]; ++idx ) { // LTP: pre-synaptic spike precedes post-synaptic spike
  126. int preSynNeuron = listOfPresynapticNeurons[n][idx];
  127. int preSynNeuron_correspondingDelay = listOfPresynapticDelays[n][idx];
  128. *listOfPointersToSynapticWeights_derivatives[n][idx] += LTP[preSynNeuron][t + MAX_SYNAPSE_DELAY - preSynNeuron_correspondingDelay - 1];
  129. }
  130. firings[numFirings][TIME] = t;
  131. firings[numFirings][NEURON] = n;
  132. numFirings++;
  133. if( numFirings == MAX_NUM_FIRINGS) {
  134. printf( "[WARNING] Two many spikes at t = %d (ignoring all)\n", t );
  135. numFirings = 1;
  136. }
  137. }
  138. }
  139. #else
  140. for( int n= 0; n < NUM_TOTAL_NEURONS; ++n ) {
  141. if( v[n] >= RS_FS_THR ) { // Does neuron n has fired?
  142. v[n] = RS_FS_C; // threshold dynamics
  143. u[n] += d[n];
  144. LTP[n][t + MAX_SYNAPSE_DELAY] = 0.1;
  145. LTD[n] = 0.12;
  146. for ( int idx = 0; idx < numPreSynapticNeuronsOfTarget[n]; ++idx ) { // LTP: pre-synaptic spike precedes post-synaptic spike
  147. int preSynNeuron = listOfPresynapticNeurons[n][idx];
  148. int preSynNeuron_correspondingDelay = listOfPresynapticDelays[n][idx];
  149. *listOfPointersToSynapticWeights_derivatives[n][idx] += LTP[preSynNeuron][t + MAX_SYNAPSE_DELAY - preSynNeuron_correspondingDelay - 1];
  150. }
  151. firings[numFirings][TIME] = t;
  152. firings[numFirings][NEURON] = n;
  153. numFirings++;
  154. if( numFirings == MAX_NUM_FIRINGS ) {
  155. printf( "[INFO] Two many spikes at t = %d (ignoring all).\n", t );
  156. numFirings = 1;
  157. }
  158. }
  159. }
  160. #endif
  161. // Go back through firings as far as MAX_SYNAPSE_DELAY lasts. Calculate I_ext for the next time step.
  162. // Take the delays of the synapses into account. I_ext applies in the next simulation step.
  163. //
  164. // | | |
  165. // | | | | | | | | <-- spikes
  166. // ---+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--> simulation time
  167. // -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12
  168. // t
  169. //
  170. // | |
  171. // +--------------+ MAX_SYNAPSE_DELAY (e.g., 5)
  172. int idx = numFirings - 1; // array index starts with 0
  173. while( t - firings[idx][TIME] < MAX_SYNAPSE_DELAY ) {
  174. int neuronFired = firings[idx][NEURON];
  175. int timeSinceNeuronFired = t - firings[idx][TIME];
  176. int numEntriesOfDelay = numEntriesPerDelay[neuronFired][timeSinceNeuronFired];
  177. for( int i = 0; i < numEntriesOfDelay; ++i ) {
  178. int s = listOfSynsByNeuronAndDelay[neuronFired][timeSinceNeuronFired][i];
  179. int postSynNeuron = matrixOfPostSynapticNeurons[neuronFired][s];
  180. I_ext[postSynNeuron] += matrixOfSynapticWeights[neuronFired][s];
  181. if( neuronFired < NUM_EXCITATORY_NEURONS) { // LTD: this spike is before postsynaptic spikes
  182. matrixOfSynapticWeights_derivatives[neuronFired][s] -= LTD[postSynNeuron];
  183. }
  184. }
  185. idx--;
  186. }
  187. // = = = = = = = = = = = = = = = = = = = = = =
  188. // = UPDATE NETWORK STATE
  189. // = = = = = = = = = = = = = = = = = = = = = =
  190. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  191. #if( ODE_SOLVER_REFINEMENT )
  192. for( int intCycles = 0; intCycles < ODE_SOLVER_STEPS; ++intCycles ) {
  193. v[n] += (1.0 / ODE_SOLVER_STEPS) * ((0.04 * v[n] + 5) * v[n] + 140 - u[n] + I_ext[n]);
  194. u[n] += (1.0 / ODE_SOLVER_STEPS) * (a[n] * (RS_FS_B * v[n] - u[n]));
  195. #if( LOG_MIN_MAX_V_U )
  196. // log min and max values of v(t) and u(t)
  197. if( v[n] > v_max ) v_max = v[n];
  198. if( v[n] < v_min ) v_min = v[n];
  199. if( u[n] > u_max ) u_max = u[n];
  200. if( u[n] < u_min ) u_min = u[n];
  201. #endif
  202. // threshold detection for exact integration
  203. if( v[n] >= 30.0 ) {
  204. v[n] = RS_FS_C;
  205. u[n] += d[n];
  206. spike[n]++; // remember the spike event, which is aligned to next grid point
  207. }
  208. }
  209. #else // original implementation
  210. v[n] += 0.5 * ((0.04 * v[n] + 5) * v[n] + 140 - u[n] + I_ext[n]); // for numerical stability
  211. v[n] += 0.5 * ((0.04 * v[n] + 5) * v[n] + 140 - u[n] + I_ext[n]); // time step is 0.5 ms
  212. u[n] += a[n] * (RS_FS_B * v[n] - u[n]);
  213. #if( LOG_MIN_MAX_V_U ) // log min and max values of v(t) and u(t)
  214. if(v[n] > v_max) v_max = v[n];
  215. if(v[n] < v_min) v_min = v[n];
  216. if(u[n] > u_max) u_max = u[n];
  217. if(u[n] < u_min) u_min = u[n];
  218. #endif
  219. #endif
  220. LTP[n][t + MAX_SYNAPSE_DELAY + 1] = 0.95 * LTP[n][t + MAX_SYNAPSE_DELAY];
  221. LTD[n] *= 0.95;
  222. }
  223. } // end of simulation loop [milliseconds]
  224. // every minute: report on the average firing rate of the excitatory and inhibitory population
  225. if( simTimeSecond > 0 && (simTimeSecond + 1) % 60 == 0 ) {
  226. int spikesTotalExcitatory = 0;
  227. int spikesTotalInhibitory = 0;
  228. for( int idx = 0; idx < numFirings; ++idx ) {
  229. if( firings[idx][NEURON] < NUM_EXCITATORY_NEURONS) {
  230. spikesTotalExcitatory++;
  231. }
  232. else {
  233. spikesTotalInhibitory++;
  234. }
  235. }
  236. printf( "[INFO] Simulation time: %d seconds\n", simTimeSecond + 1 );
  237. printf( "[INFO] ... Firing rate (excitatory) = %f\n",
  238. (double) spikesTotalExcitatory / (double) NUM_EXCITATORY_NEURONS);
  239. printf( "[INFO] ... Firing rate (inhibitory) = %f\n",
  240. (double) spikesTotalInhibitory / (double) NUM_INHIBITORY_NEURONS);
  241. #if(LOG_MIN_MAX_V_U)
  242. printf( "[INFO] ... v_max = %f\n", v_max );
  243. printf( "[INFO] ... v_min = %f\n", v_min );
  244. printf( "[INFO] ... u_max = %f\n", u_max );
  245. printf( "[INFO] ... u_min = %f\n", u_min );
  246. #endif
  247. }
  248. // = = = = = = = = = = = = = = = = = = = = = =
  249. // = SAVE FIVE SELECTED NETWORK STATES
  250. // = = = = = = = = = = = = = = = = = = = = = =
  251. #ifdef SELECTED_STATE_1_AFTER_N_SECONDS
  252. #ifndef OUTFILE_STATE_1_WEIGHT_MATRIX
  253. #error OUTFILE_STATE_1_WEIGHT_MATRIX not defined!
  254. #endif
  255. if( simTimeSecond == SELECTED_STATE_1_AFTER_N_SECONDS - 1 ) {
  256. ExportWeightMatrixToFile( OUTFILE_STATE_1_WEIGHT_MATRIX );
  257. }
  258. #endif
  259. #ifdef SELECTED_STATE_2_AFTER_N_SECONDS
  260. #ifndef OUTFILE_STATE_2_WEIGHT_MATRIX
  261. #error OUTFILE_STATE_2_WEIGHT_MATRIX not defined!
  262. #endif
  263. if( simTimeSecond == SELECTED_STATE_2_AFTER_N_SECONDS - 1 ) {
  264. ExportWeightMatrixToFile( OUTFILE_STATE_2_WEIGHT_MATRIX );
  265. }
  266. #endif
  267. #ifdef SELECTED_STATE_3_AFTER_N_SECONDS
  268. #ifndef OUTFILE_STATE_3_WEIGHT_MATRIX
  269. #error OUTFILE_STATE_3_WEIGHT_MATRIX not defined!
  270. #endif
  271. if( simTimeSecond == SELECTED_STATE_3_AFTER_N_SECONDS - 1 ) {
  272. ExportWeightMatrixToFile( OUTFILE_STATE_3_WEIGHT_MATRIX );
  273. }
  274. #endif
  275. #ifdef SELECTED_STATE_4_AFTER_N_SECONDS
  276. #ifndef OUTFILE_STATE_4_WEIGHT_MATRIX
  277. #error OUTFILE_STATE_4_WEIGHT_MATRIX not defined!
  278. #endif
  279. if( simTimeSecond == SELECTED_STATE_4_AFTER_N_SECONDS - 1 ) {
  280. ExportWeightMatrixToFile( OUTFILE_STATE_4_WEIGHT_MATRIX );
  281. }
  282. #endif
  283. #ifdef SELECTED_STATE_5_AFTER_N_SECONDS
  284. #ifndef OUTFILE_STATE_5_WEIGHT_MATRIX
  285. #error OUTFILE_STATE_5_WEIGHT_MATRIX not defined!
  286. #endif
  287. if( simTimeSecond == SELECTED_STATE_5_AFTER_N_SECONDS - 1 ) {
  288. ExportWeightMatrixToFile( OUTFILE_STATE_5_WEIGHT_MATRIX );
  289. }
  290. #endif
  291. RecordNetworkActivityToFile( OUTFILE_FIRINGS, simTimeSecond, numFirings );
  292. // = = = = = = = = = = = = = = = = = = = = = =
  293. // = PREPARE NEXT SIMULATION TIME STEP
  294. // = = = = = = = = = = = = = = = = = = = = = =
  295. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  296. for( int i = 0; i < MAX_SYNAPSE_DELAY + 1; ++i ) {
  297. LTP[n][i] = LTP[n][1000 + i];
  298. }
  299. }
  300. int k = numFirings - 1;
  301. while( 1000 - firings[k][TIME] < MAX_SYNAPSE_DELAY) {
  302. k--;
  303. }
  304. for( int i = 1; i < numFirings - k; ++i ) {
  305. firings[i][TIME] = firings[k + i][TIME] - 1000;
  306. firings[i][NEURON] = firings[k + i][NEURON];
  307. }
  308. numFirings = numFirings - k;
  309. #if( USE_STDP )
  310. // = = = = = = = = = = = = = = = = = = = = = =
  311. // = UPDATE SYNAPTIC WEIGHTS
  312. // = = = = = = = = = = = = = = = = = = = = = =
  313. // only excitatory connections are modified
  314. for( int n = 0; n < NUM_EXCITATORY_NEURONS; ++n ) {
  315. for( int s = 0; s < NUM_SYNAPSES_PER_NEURON; ++s ) {
  316. // REFACTOR COMMENT:
  317. // The following two lines have a different order in spnet.cpp.
  318. matrixOfSynapticWeights_derivatives[n][s] *= 0.9;
  319. matrixOfSynapticWeights[n][s] += 0.01 + matrixOfSynapticWeights_derivatives[n][s];
  320. if( matrixOfSynapticWeights[n][s] > MAX_SYNAPTIC_STRENGTH) {
  321. matrixOfSynapticWeights[n][s] = MAX_SYNAPTIC_STRENGTH;
  322. }
  323. if( matrixOfSynapticWeights[n][s] < 0 ) {
  324. matrixOfSynapticWeights[n][s] = 0.0;
  325. }
  326. }
  327. }
  328. #endif
  329. } // end of simulation loop [seconds]
  330. FinalizeSimulation();
  331. printf( "\n\nSimulation terminated normally! \n\n" );
  332. return (0);
  333. }
  334. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  335. // = Initialize the polychronization network
  336. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  337. void InitializeNetwork() {
  338. // initialize izhikevich neuron parameters
  339. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  340. if( n < NUM_EXCITATORY_NEURONS ) { // excitatory neurons, RS type
  341. a[n] = RS_A;
  342. d[n] = RS_D;
  343. v[n] = RS_V_INIT;
  344. u[n] = RS_U_INIT;
  345. }
  346. else { // inhibitory neurons, FS type
  347. a[n] = FS_A;
  348. d[n] = FS_D;
  349. v[n] = FS_V_INIT;
  350. u[n] = FS_U_INIT;
  351. }
  352. }
  353. // = = = = = = = = = = = = = = = = = = = = = =
  354. // = CONNECTION MATRIX
  355. // = = = = = = = = = = = = = = = = = = = = = =
  356. #if( GENERATE_NETWORK_FROM_EXTERNAL_DATA )
  357. ImportConnectionMatrixFromFile( INFILE_CONNECTION_MATRIX );
  358. #else
  359. // fill matrixOfPostSynapticNeurons[n][n] with random target neurons
  360. // avoid self-assignments and multiple connections
  361. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  362. for( int s = 0; s < NUM_SYNAPSES_PER_NEURON; ++s ) {
  363. bool duplicateTarget = false;
  364. bool selfAssigned = false;
  365. int randomTargetNeuron = 0;
  366. do {
  367. duplicateTarget = false;
  368. selfAssigned = false;
  369. if( n < NUM_EXCITATORY_NEURONS ) { // excitatory neurons can connect to all neurons
  370. randomTargetNeuron = GET_RANDOM_INT( NUM_TOTAL_NEURONS );
  371. }
  372. else { // inhibitory neurons can connect to excitatory neurons only
  373. randomTargetNeuron = GET_RANDOM_INT( NUM_EXCITATORY_NEURONS );
  374. }
  375. if( randomTargetNeuron == n ) {
  376. selfAssigned = true;
  377. }
  378. for( int i = 0; i < s; ++i ) {
  379. if( matrixOfPostSynapticNeurons[n][i] == randomTargetNeuron ) {
  380. duplicateTarget = true;
  381. }
  382. }
  383. } while( duplicateTarget || selfAssigned );
  384. matrixOfPostSynapticNeurons[n][s] = randomTargetNeuron;
  385. }
  386. }
  387. #endif
  388. #ifdef OUTFILE_CONNECTIONS
  389. ExportConnectionMatrixToFile( OUTFILE_CONNECTIONS );
  390. #endif
  391. #if __DEBUG__
  392. PrintMatrixOfPostSynapticNeurons();
  393. #endif
  394. // = = = = = = = = = = = = = = = = = = = = = =
  395. // = WEIGHT MATRIX
  396. // = = = = = = = = = = = = = = = = = = = = = =
  397. #if(GENERATE_NETWORK_FROM_EXTERNAL_DATA)
  398. ImportWeightMatrixFromFile(INFILE_WEIGHT_MATRIX);
  399. #else
  400. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  401. for( int s = 0; s < NUM_SYNAPSES_PER_NEURON; ++s ) {
  402. if( n < NUM_EXCITATORY_NEURONS) {
  403. matrixOfSynapticWeights[n][s] = INIT_EXC_SYNAPTIC_WEIGHT;
  404. }
  405. else {
  406. matrixOfSynapticWeights[n][s] = INIT_INH_SYNAPTIC_WEIGHT;
  407. }
  408. matrixOfSynapticWeights_derivatives[n][s] = 0.0;
  409. }
  410. }
  411. #endif
  412. #ifdef OUTFILE_WEIGHTS_INITIAL
  413. ExportWeightMatrixToFile(OUTFILE_WEIGHTS_INITIAL);
  414. #endif
  415. #if __DEBUG__
  416. PrintMatrixOfSynapticWeights();
  417. #endif
  418. // = = = = = = = = = = = = = = = = = = = = = =
  419. // = DELAY MATRIX
  420. // = = = = = = = = = = = = = = = = = = = = = =
  421. #if(GENERATE_NETWORK_FROM_EXTERNAL_DATA)
  422. ImportDelayMatrixFromFile(INFILE_DELAY_MATRIX);
  423. #else
  424. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  425. short synapseCorrespondingToDelay = 0;
  426. for( int delayIdx = 0; delayIdx < MAX_SYNAPSE_DELAY; ++delayIdx ) {
  427. numEntriesPerDelay[n][delayIdx] = 0;
  428. }
  429. if( n < NUM_EXCITATORY_NEURONS ) {
  430. // For the excitatory neurons the delays are drawn from a uniform integer distribution.
  431. // e.g.:
  432. // delayIdx: 0 1 2 3 4 5 6 .......... each slot corresponds to a delay value, i.e., 0 -> 1 ms, 1 -> 2 ms etc.
  433. // 0, 1 2, 3 4, 5 6, 7 8, 9 9, 10 11, 12 ... each slot has space for NUM_SYNAPSES_PER_NEURON (which is not needed) and
  434. // holds the synapse numbers corresponding to that delay
  435. // REFACTOR COMMENT: In the Matlab implementation this is random.
  436. // This algorithm implicitly creates as many entries in delays as NUM_SYNAPSES_PER_NEURON.
  437. // This only works if NUM_SYNAPSES_PER_NEURON is a multiple of MAX_SYNAPSE_DELAY!
  438. for( int delayIdx = 0; delayIdx < MAX_SYNAPSE_DELAY; ++delayIdx ) {
  439. for( int synListIdx = 0; synListIdx < (NUM_SYNAPSES_PER_NEURON / MAX_SYNAPSE_DELAY); ++synListIdx ) {
  440. listOfSynsByNeuronAndDelay[n][delayIdx][synListIdx] = synapseCorrespondingToDelay++;
  441. numEntriesPerDelay[n][delayIdx]++;
  442. }
  443. }
  444. }
  445. else {
  446. // the inhibitory synapse delay is always 1 ms, thus, all synapses are added to delayIdx 0.
  447. for( int synListIdx = 0; synListIdx < NUM_SYNAPSES_PER_NEURON; ++synListIdx ) {
  448. listOfSynsByNeuronAndDelay[n][0][synListIdx] = synapseCorrespondingToDelay++;
  449. numEntriesPerDelay[n][0]++;
  450. }
  451. }
  452. }
  453. #endif
  454. // for all neurons: find the excitatory presynaptic neurons and delays and store them in lists
  455. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  456. numPreSynapticNeuronsOfTarget[n] = 0;
  457. }
  458. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  459. for( int excPreSynNeuron = 0; excPreSynNeuron < NUM_EXCITATORY_NEURONS; ++excPreSynNeuron ) {
  460. for( int s = 0; s < NUM_SYNAPSES_PER_NEURON; ++s ) {
  461. int targetNeuron = matrixOfPostSynapticNeurons[excPreSynNeuron][s];
  462. if( targetNeuron == n ) {
  463. int idx = numPreSynapticNeuronsOfTarget[n];
  464. listOfPresynapticNeurons[n][idx] = excPreSynNeuron;
  465. // determine the delay of a connection and store it in a list
  466. for( int delayIdx = 0; delayIdx < MAX_SYNAPSE_DELAY; ++delayIdx ) {
  467. int excPreSynNeuron_numEntriesOfDelay = numEntriesPerDelay[excPreSynNeuron][delayIdx];
  468. for( int i = 0; i < excPreSynNeuron_numEntriesOfDelay; ++i ) {
  469. short synapse = listOfSynsByNeuronAndDelay[excPreSynNeuron][delayIdx][i];
  470. int postSynNeuron = matrixOfPostSynapticNeurons[excPreSynNeuron][synapse];
  471. if( postSynNeuron == n ) {
  472. int idx = numPreSynapticNeuronsOfTarget[n];
  473. listOfPresynapticDelays[n][idx] = delayIdx;
  474. // REFACTOR COMMENT: delayIdx represents the delay value, where 0 represents 1ms, thus,
  475. // one needs to distinguish between a 1ms delay and an empty entry.
  476. // This is done by tracking the number of entries in delays_numEntriesPerDelay.
  477. }
  478. }
  479. }
  480. // maintain list of pointers into the weight matrices; used for weight update
  481. {
  482. int idx = numPreSynapticNeuronsOfTarget[n];
  483. // REFACTOR COMMENT: dead code removed
  484. // listOfPointersToSynapticWeights[n][idx] = &matrixOfSynapticWeights[excPreSynNeuron][s];
  485. listOfPointersToSynapticWeights_derivatives[n][idx] = &matrixOfSynapticWeights_derivatives[excPreSynNeuron][s];
  486. idx++;
  487. numPreSynapticNeuronsOfTarget[n] = idx;
  488. }
  489. }
  490. }
  491. }
  492. }
  493. #if __DEBUG__
  494. PrintMatrixOfSynapticDelays();
  495. #endif
  496. #ifdef OUTFILE_DELAYS
  497. ExportDelayMatrixToFile( OUTFILE_DELAYS );
  498. #endif
  499. // REFACTOR COMMENT: the array is much larger and remains uninitialized
  500. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  501. for( int d = 0; d < 1 + MAX_SYNAPSE_DELAY; ++d ) {
  502. LTP[n][d] = 0.0;
  503. }
  504. }
  505. for( int n = 0; n < NUM_TOTAL_NEURONS; ++n ) {
  506. LTD[n] = 0.0;
  507. }
  508. // REFACTOR COMMENT: just for the algorithm; does not contribute to the network activity
  509. numFirings = 1; // dummy spike ...
  510. firings[0][TIME] = -MAX_SYNAPSE_DELAY; // ... at -MAX_SYNAPSE_DELAY for ...
  511. firings[0][NEURON] = 0; // ... neuron n = 0
  512. #ifdef OUTFILE_CON_WEIGHT_DELAY_INITIAL
  513. ExportConnectionMatrixWeightAndDelay(OUTFILE_CON_WEIGHT_DELAY_INITIAL);
  514. #endif
  515. }
  516. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  517. // = Initialize simulation: set seed, delete previously created files, open files
  518. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  519. void InitializeSimulation() {
  520. srand( 0 ); // set a seed (repeatability)
  521. #if( LOG_MIN_MAX_V_U )
  522. v_max = 0.0;
  523. v_min = 0.0;
  524. u_max = 0.0;
  525. u_min = 0.0;
  526. #endif
  527. #ifdef OUTFILE_STIMULUS
  528. DeleteFile( OUTFILE_STIMULUS );
  529. #endif
  530. #ifdef OUTFILE_CONNECTIONS
  531. DeleteFile( OUTFILE_CONNECTIONS );
  532. #endif
  533. #ifdef OUTFILE_DELAYS
  534. DeleteFile( OUTFILE_DELAYS );
  535. #endif
  536. #ifdef OUTFILE_CON_WEIGHT_DELAY_INITIAL
  537. DeleteFile(OUTFILE_CON_WEIGHT_DELAY_INITIAL);
  538. #endif
  539. #ifdef OUTFILE_WEIGHTS_INITIAL
  540. DeleteFile(OUTFILE_WEIGHTS_INITIAL);
  541. #endif
  542. DeleteFile( OUTFILE_FIRINGS );
  543. // open files which are required throughout the entire simulation
  544. #ifdef OUTFILE_STIMULUS
  545. pFileStimulusOutput = fopen( OUTFILE_STIMULUS, "w" );
  546. if( pFileStimulusOutput == nullptr ) {
  547. printf( "[ERROR] Failed to open stimulus output file. Filename: %s\n", OUTFILE_STIMULUS );
  548. exit( RC_ERROR_EXIT );
  549. }
  550. #endif
  551. #if(USE_EXTERNAL_STIMULUS)
  552. pFileStimulusInput = fopen(INFILE_STIMULUS,"r" );
  553. if(pFileStimulusInput == nullptr) {
  554. printf( "[ERROR] Failed to open stimulus input file. Filename: %s\n", INFILE_STIMULUS );
  555. exit( RC_ERROR_EXIT );
  556. }
  557. #endif
  558. }
  559. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  560. // = Finalize simulation: free resources
  561. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  562. void FinalizeSimulation() {
  563. if( pFileStimulusInput != nullptr ) fclose( pFileStimulusInput );
  564. if( pFileStimulusOutput != nullptr ) fclose( pFileStimulusOutput );
  565. }
  566. #else // original version
  567. // original version of the Izhikevich polychronization model available for download at
  568. // https://www.izhikevich.org/publications/spnet.htm
  569. #include "poly_spnet.cpp"
  570. #endif