CARLsim  6.1.0
CARLsim: a GPU-accelerated SNN simulator
connection_monitor_core.cpp
Go to the documentation of this file.
1 /* * Copyright (c) 2016 Regents of the University of California. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3. The names of its contributors may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *********************************************************************************************** *
31 * CARLsim
32 * created by: (MDR) Micah Richert, (JN) Jayram M. Nageswaran
33 * maintained by:
34 * (MA) Mike Avery <averym@uci.edu>
35 * (MB) Michael Beyeler <mbeyeler@uci.edu>,
36 * (KDC) Kristofor Carlson <kdcarlso@uci.edu>
37 * (TSC) Ting-Shuo Chou <tingshuc@uci.edu>
38 * (HK) Hirak J Kashyap <kashyaph@uci.edu>
39 *
40 * CARLsim v1.0: JM, MDR
41 * CARLsim v2.0/v2.1/v2.2: JM, MDR, MA, MB, KDC
42 * CARLsim3: MB, KDC, TSC
43 * CARLsim4: TSC, HK
44 * CARLsim5: HK, JX, KC
45 * CARLsim6: LN, JX, KC, KW
46 *
47 * CARLsim available from http://socsci.uci.edu/~jkrichma/CARLsim/
48 * Ver 12/31/2016
49 */
51 
52 #include <snn.h> // CARLsim private implementation
53 #include <snn_definitions.h> // KERNEL_ERROR, KERNEL_INFO, ...
54 
55 #include <sstream> // std::stringstream
56 #include <algorithm> // std::sort
57 #include <iomanip> // std::setfill, std::setw
58 #include <float.h> // FLT_EPSILON
59 
60 
61 
62 // we aren't using namespace std so pay attention!
63 ConnectionMonitorCore::ConnectionMonitorCore(SNN* snn,int monitorId,short int connId,int grpIdPre,int grpIdPost) {
64  snn_ = snn;
65  connId_= connId;
66  grpIdPre_ = grpIdPre;
67  grpIdPost_ = grpIdPost;
68  monitorId_ = monitorId;
69 
70  wtTime_ = -1;
71  wtTimeLast_ = -1;
72  wtTimeWrite_ = -1;
73 
74  connFileId_ = NULL;
75  needToWriteFileHeader_ = true;
76  needToInit_ = true;
77  connFileSignature_ = 202029319;
78  connFileVersion_ = 0.3f;
79 
80  minWt_ = -1.0f;
81  maxWt_ = -1.0f;
82 
83  connFileTimeIntervalSec_ = 1;
84 }
85 
87  if (!needToInit_)
88  return;
89 
90  nNeurPre_ = snn_->getGroupNumNeurons(grpIdPre_);
91  nNeurPost_ = snn_->getGroupNumNeurons(grpIdPost_);
92  isPlastic_ = snn_->isConnectionPlastic(connId_);
93  nSynapses_ = snn_->getNumSynapticConnections(connId_);
94 
95  ConnectConfig connInfo = snn_->getConnectConfig(connId_);
96  minWt_ = 0.0f; // for now, no non-zero min weights allowed
97  maxWt_ = fabs(connInfo.maxWt);
98 
99  assert(nNeurPre_>0);
100  assert(nNeurPost_>0);
101 
102  // use KERNEL_{ERROR|WARNING|etc} typesetting (const FILE*)
103  fpInf_ = snn_->getLogFpInf();
104  fpErr_ = snn_->getLogFpErr();
105  fpDeb_ = snn_->getLogFpDeb();
106  fpLog_ = snn_->getLogFpLog();
107 
108  // init weight matrix with right dimensions
109  for (int i = 0; i < nNeurPre_; i++) {
110  std::vector<float> wt;
111  for (int j = 0; j < nNeurPost_; j++) {
112  wt.push_back(NAN);
113  }
114  wtMat_.push_back(wt);
115  wtMatLast_.push_back(wt);
116  }
117 
118  // then load current weigths from SNN into weight matrix
119  updateStoredWeights();
120 }
121 
123  if (connFileId_!=NULL) {
124  // flush: store last snapshot to file if update interval set
125  if (connFileTimeIntervalSec_ > 0) {
126  // make sure SNN is not already deallocated!
127  assert(snn_!=NULL);
128  writeConnectFileSnapshot(snn_->getSimTime(), snn_->getWeightMatrix2D(connId_));
129  }
130 
131  // then close file and clean up
132  fclose(connFileId_);
133  connFileId_ = NULL;
134  needToInit_ = true;
135  needToWriteFileHeader_ = true;
136  }
137 }
138 
139 // +++++ PUBLIC METHODS: +++++++++++++++++++++++++++++++++++++++++++++++//
140 
141 // calculate weight changes since last update (element-wise )
142 std::vector< std::vector<float> > ConnectionMonitorCore::getWeights() {
143  return wtMat_;
144 }
145 
146 // calculate weight changes since last update (element-wise )
147 std::vector< std::vector<float> > ConnectionMonitorCore::getPrevWeights() {
148  return wtMatLast_;
149 }
150 
151 // calculate weight changes since last update (element-wise )
152 std::vector< std::vector<float> > ConnectionMonitorCore::calcWeightChanges() {
153  updateStoredWeights();
154  std::vector< std::vector<float> > wtChange(nNeurPre_, std::vector<float>(nNeurPost_));
155 
156  // take the naive approach for now
157  for (int i=0; i<nNeurPre_; i++) {
158  for (int j=0; j<nNeurPost_; j++) {
159  wtChange[i][j] = wtMat_[i][j] - wtMatLast_[i][j];
160  }
161  }
162 
163  return wtChange;
164 }
165 
166 
167 // reset weight matrix
169  for (int i=0; i<nNeurPre_; i++) {
170  for (int j=0; j<nNeurPost_; j++) {
171  wtMat_[i][j] = NAN;
172  wtMatLast_[i][j] = NAN;
173  }
174  }
175 }
176 
177 // find number of incoming synapses for a specific post neuron
178 int ConnectionMonitorCore::getFanIn(int neurPostId) {
179  assert(neurPostId<nNeurPost_);
180  int nSyn = 0;
181  for (int i=0; i<nNeurPre_; i++) {
182  if (!std::isnan(wtMat_[i][neurPostId])) {
183  nSyn++;
184  }
185  }
186  return nSyn;
187 }
188 
189 // find number of outgoing synapses of a specific pre neuron
191  assert(neurPreId<nNeurPre_);
192  int nSyn = 0;
193  for (int j=0; j<nNeurPost_; j++) {
194  if (!std::isnan(wtMat_[neurPreId][j])) {
195  nSyn++;
196  }
197  }
198  return nSyn;
199 }
200 
201 float ConnectionMonitorCore::getMaxWeight(bool getCurrent) {
202  float maxVal = minWt_;
203  if (getCurrent) {
204  updateStoredWeights();
205 
206  // find currently largest weight value
207  for (int i=0; i<nNeurPre_; i++) {
208  for (int j=0; j<nNeurPost_; j++) {
209  // skip entries in matrix where no synapse exists
210  if (std::isnan(wtMat_[i][j]))
211  continue;
212 
213  if (wtMat_[i][j] > maxVal) {
214  maxVal = wtMat_[i][j];
215  }
216  }
217  }
218  } else {
219  // return RangeWeight.max
220  maxVal = maxWt_;
221  }
222 
223  return maxVal;
224 }
225 
226 float ConnectionMonitorCore::getMinWeight(bool getCurrent) {
227  float minVal = maxWt_;
228  if (getCurrent) {
229  updateStoredWeights();
230 
231  // find currently largest weight value
232  for (int i=0; i<nNeurPre_; i++) {
233  for (int j=0; j<nNeurPost_; j++) {
234  // skip entries in matrix where no synapse exists
235  if (std::isnan(wtMat_[i][j]))
236  continue;
237 
238  if (wtMat_[i][j] < minVal) {
239  minVal = wtMat_[i][j];
240  }
241  }
242  }
243  } else {
244  // return RangeWeight.min
245  minVal = minWt_;
246  }
247 
248  return minVal;
249 }
250 
251 // find number of synapses whose weights changed
253  assert(minAbsChange>=0.0);
254  std::vector< std::vector<float> > wtChange = calcWeightChanges();
255 
256  int nChanged = 0;
257  for (int i=0; i<nNeurPre_; i++) {
258  for (int j=0; j<nNeurPost_; j++) {
259  // skip entries in matrix where no synapse exists
260  if (std::isnan(wtMat_[i][j]))
261  continue;
262 
263  if (fabs(wtChange[i][j]) >= minAbsChange) {
264  nChanged++;
265  }
266  }
267  }
268  return nChanged;
269 }
270 
271 // finds the number of weights with values in some range
272 int ConnectionMonitorCore::getNumWeightsInRange(double minVal, double maxVal) {
273  assert(maxVal>=minVal);
274 
275  updateStoredWeights();
276 
277  // make sure values are inside a reasonable range
278  if (minVal<=getMinWeight(false) && minVal>=getMaxWeight(false)) {
279  return getNumSynapses();
280  }
281 
282  int cnt = 0;
283  for (int i=0; i<nNeurPre_; i++) {
284  for (int j=0; j<nNeurPost_; j++) {
285  // skip entries in matrix where no synapse exists
286  if (std::isnan(wtMat_[i][j]))
287  continue;
288 
289  if (wtMat_[i][j]>=minVal && wtMat_[i][j]<=maxVal) {
290  cnt++;
291  }
292  }
293  }
294 
295  return cnt;
296 }
297 
298 // finds the number of weights with some exact weight value
300  // make sure value is inside a reasonable range
301  if (value<getMinWeight(false) || value>getMaxWeight(false)) {
302  return 0;
303  }
304 
305  return getNumWeightsInRange(value-FLT_EPSILON, value+FLT_EPSILON);
306 }
307 
308 // calculate total absolute amount of weight change
310  std::vector< std::vector<float> > wtChange = calcWeightChanges();
311  double wtTotalChange = 0.0;
312  for (int i=0; i<nNeurPre_; i++) {
313  for (int j=0; j<nNeurPost_; j++) {
314  // skip entries in matrix where no synapse exists
315  if (std::isnan(wtMat_[i][j]))
316  continue;
317  wtTotalChange += fabs(wtChange[i][j]);
318  }
319  }
320  return wtTotalChange;
321 }
322 
324  updateStoredWeights();
325 
326  KERNEL_INFO("(t=%.3fs) ConnectionMonitor ID=%d: %d(%s) => %d(%s)",
327  (getTimeMsCurrentSnapshot()/1000.0f), connId_,
328  grpIdPre_, snn_->getGroupName(grpIdPre_).c_str(),
329  grpIdPost_, snn_->getGroupName(grpIdPost_).c_str());
330 
331  // generate header
332  std::stringstream header, header2;
333  header << " pre\\post |";
334  header2 << "----------|";
335  for (int j=0; j<nNeurPost_; j++) {
336  header << std::setw(9) << std::setfill(' ') << j << " |";
337  header2 << "-----------";
338  }
339  KERNEL_INFO("%s",header.str().c_str());
340  KERNEL_INFO("%s",header2.str().c_str());
341 
342  for (int i=0; i<nNeurPre_; i++) {
343  std::stringstream line;
344  line << std::setw(9) << std::setfill(' ') << i << " |";
345  for (int j=0; j<nNeurPost_; j++) {
346  line << std::fixed << std::setprecision(4) << (std::isnan(wtMat_[i][j])?" ":(wtMat_[i][j]>=0?" ":" "))
347  << wtMat_[i][j] << " ";
348  }
349  KERNEL_INFO("%s",line.str().c_str());
350  }
351 }
352 
353 void ConnectionMonitorCore::printSparse(int neurPostId, int maxConn, int connPerLine, bool storeNewSnapshot) {
354  assert(neurPostId<nNeurPost_);
355  assert(maxConn>0);
356  assert(connPerLine>0);
357 
358  // give the option of not storing the new snapshot
359  std::vector< std::vector<float> > wtNew, wtOld;
360  long int timeNew, timeOld;
361  if (!storeNewSnapshot) {
362  // make a copy of current snapshots so that we can restore them later
363  wtNew = wtMat_;
364  wtOld = wtMatLast_;
365  timeNew = wtTime_;
366  timeOld = wtTimeLast_;
367  }
368 
369  updateStoredWeights();
370  KERNEL_INFO("(t=%.3fs) ConnectionMonitor ID=%d %d(%s) => %d(%s): [preId,postId] wt (+/-wtChange in %ldms) "
371  "show first %d", getTimeMsCurrentSnapshot()/1000.0f, connId_,
372  grpIdPre_, snn_->getGroupName(grpIdPre_).c_str(), grpIdPost_, snn_->getGroupName(grpIdPost_).c_str(),
373  getTimeMsSinceLastSnapshot(), maxConn);
374 
375  int postA, postZ;
376  if (neurPostId==ALL) {
377  postA = 0;
378  postZ = nNeurPost_ - 1;
379  } else {
380  postA = neurPostId;
381  postZ = neurPostId;
382  }
383 
384  std::vector< std::vector<float> > wtChange;
385  if (isPlastic_) {
386  wtChange = calcWeightChanges();
387  }
388 
389  std::stringstream line;
390  int nConn = 0;
391  int maxIntDigits = ceil(log10((double)std::max<int>(nNeurPre_,nNeurPost_))); // LN2021 Fix c++17
392  for (int i=0; i<nNeurPre_; i++) {
393  for (int j = postA; j <= postZ; j++) {
394  // display only so many connections
395  if (nConn>=maxConn)
396  break;
397 
398  if (!std::isnan(wtMat_[i][j])) {
399  line << "[" << std::setw(maxIntDigits) << i << "," << std::setw(maxIntDigits) << j << "] "
400  << std::fixed << std::setprecision(4) << wtMat_[i][j];
401  if (isPlastic_) {
402  line << " (" << ((wtChange[i][j]<0)?"":"+");
403  line << std::setprecision(4) << wtChange[i][j] << ")";
404  }
405  line << " ";
406  if (!(++nConn % connPerLine)) {
407  KERNEL_INFO("%s",line.str().c_str());
408  line.str(std::string());
409  }
410  }
411  }
412  }
413  // flush
414  if (nConn % connPerLine)
415  KERNEL_INFO("%s",line.str().c_str());
416 
417  if (!storeNewSnapshot) {
418  wtMat_ = wtNew;
419  wtMatLast_ = wtOld;
420  wtTime_ = timeNew;
421  wtTimeLast_ = timeOld;
422  }
423 
424 }
425 
427  // \TODO consider the case where this function is called more than once
428  if (connFileId_!=NULL)
429  KERNEL_ERROR("ConnectionMonitorCore: setConnectFileId has already been called.");
430 
431  connFileId_=connFileId;
432 
433  if (connFileId_==NULL) {
434  needToWriteFileHeader_ = false;
435  }
436  else {
437  // for now: file pointer has changed, so we need to write header (again)
438  needToWriteFileHeader_ = true;
439  writeConnectFileHeader();
440  }
441 }
442 
444  assert(intervalSec==-1 || intervalSec>=1);
445  connFileTimeIntervalSec_ = intervalSec;
446 }
447 
448 // updates the internally stored last two snapshots (current one and last one)
449 void ConnectionMonitorCore::updateStoredWeights() {
450  if (snn_->getSimTime() > wtTime_) {
451  // time has advanced: get new weights
452  wtMatLast_ = wtMat_;
453  wtTimeLast_ = wtTime_;
454 
455  wtMat_ = snn_->getWeightMatrix2D(connId_);
456  wtTime_ = snn_->getSimTime();
457  }
458 }
459 
460 // returns a current snapshot
461 std::vector< std::vector<float> > ConnectionMonitorCore::takeSnapshot() {
462  updateStoredWeights();
463  writeConnectFileSnapshot(wtTime_, wtMat_);
464  return wtMat_;
465 }
466 
467 // write the header section of the spike file
468 // this should be done once per file, and should be the very first entries in the file
469 void ConnectionMonitorCore::writeConnectFileHeader() {
470  init();
471 
472  if (!needToWriteFileHeader_)
473  return;
474 
475  // write file signature
476  if (!fwrite(&connFileSignature_,sizeof(int),1,connFileId_))
477  KERNEL_ERROR("ConnectionMonitorCore: writeConnectFileHeader has fwrite error");
478 
479  // write version number
480  if (!fwrite(&connFileVersion_,sizeof(float),1,connFileId_))
481  KERNEL_ERROR("ConnectionMonitorCore: writeConnectFileHeader has fwrite error");
482 
483  // write connection id
484  if (!fwrite(&connId_,sizeof(short int),1,connFileId_))
485  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
486 
487  // write pre group info: group id and Grid3D dimensions
488  Grid3D gridPre = snn_->getGroupGrid3D(grpIdPre_);
489  if (!fwrite(&grpIdPre_,sizeof(int),1,connFileId_))
490  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
491  if (!fwrite(&(gridPre.numX),sizeof(int),1,connFileId_))
492  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
493  if (!fwrite(&(gridPre.numY),sizeof(int),1,connFileId_))
494  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
495  if (!fwrite(&(gridPre.numZ),sizeof(int),1,connFileId_))
496  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
497 
498  // write post group info: group id and # neurons
499  Grid3D gridPost = snn_->getGroupGrid3D(grpIdPost_);
500  if (!fwrite(&grpIdPost_,sizeof(int),1,connFileId_))
501  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
502  if (!fwrite(&(gridPost.numX),sizeof(int),1,connFileId_))
503  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
504  if (!fwrite(&(gridPost.numY),sizeof(int),1,connFileId_))
505  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
506  if (!fwrite(&(gridPost.numZ),sizeof(int),1,connFileId_))
507  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
508 
509  // write number of synapses
510  if (!fwrite(&nSynapses_,sizeof(int),1,connFileId_))
511  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
512 
513  // write synapse type (fixed=false, plastic=true)
514  if (!fwrite(&isPlastic_,sizeof(bool),1,connFileId_))
515  KERNEL_ERROR("ConnectionMonitor: writeConnectFileHeader has fwrite error");
516 
517  // write minWt and maxWt
518  if (!fwrite(&minWt_,sizeof(float),1,connFileId_))
519  KERNEL_ERROR("ConnectionMonitorCore: writeConnectFileHeader has fwrite error");
520  if (!fwrite(&maxWt_,sizeof(float),1,connFileId_))
521  KERNEL_ERROR("ConnectionMonitorCore: writeConnectFileHeader has fwrite error");
522 
523 
524  // \TODO: write delays
525 
526  needToWriteFileHeader_ = false;
527 }
528 
529 void ConnectionMonitorCore::writeConnectFileSnapshot(int simTimeMs, std::vector< std::vector<float> > wts) {
530  // don't write if we have already written this timestamp to file (or file doesn't exist)
531  if ((long long)simTimeMs <= wtTimeWrite_ || connFileId_==NULL) {
532  return;
533  }
534 
535  wtTimeWrite_ = (long long)simTimeMs;
536 
537  // write time stamp
538  if (!fwrite(&wtTimeWrite_,sizeof(long long),1,connFileId_))
539  KERNEL_ERROR("ConnectionMonitor: writeConnectFileSnapshot has fwrite error");
540 
541  // write all weights
542  for (int i=0; i<nNeurPre_; i++) {
543  for (int j=0; j<nNeurPost_; j++) {
544  if (!fwrite(&wts[i][j],sizeof(float),1,connFileId_)) {
545  KERNEL_ERROR("ConnectionMonitor: writeConnectFileSnapshot has fwrite error");
546  }
547  }
548  }
549 }
#define ALL
CARLsim common definitions.
long int getTimeMsSinceLastSnapshot()
returns the time passed between current and last snapshot
std::vector< std::vector< float > > getWeights()
LN20201118 returns calculates current and reports them in 2D weight matrix.
float getMinWeight(bool getCurrent=false)
returns min weight in the connection (getCurrent=false: RangeWeight.min, true: current smallest) ...
std::vector< std::vector< float > > takeSnapshot()
ConnectionMonitorCore(SNN *snn, int monitorId, short int connId, int grpIdPre, int grpIdPost)
constructor, created by CARLsim::setConnectionMonitor
float getMaxWeight(bool getCurrent=false)
returns max weight in the connection (getCurrent=false: RangeWeight.max, true: current largest) ...
~ConnectionMonitorCore()
destructor, cleans up all the memory upon object deletion
int getFanIn(int neurPostId)
returns number of incoming synapses to post-synaptic neuron
std::vector< std::vector< float > > getPrevWeights()
LN20201118 returns calculates previous weights and reports them in 2D weight matrix.
double getTotalAbsWeightChange()
returns absolute sum of all weight changes since last snapshot
#define KERNEL_ERROR(formatc,...)
The configuration of a connection.
void setConnectFileId(FILE *connFileId)
sets pointer to connection file
Grid3D getGroupGrid3D(int grpId)
#define KERNEL_INFO(formatc,...)
A struct to arrange neurons on a 3D grid (a primitive cubic Bravais lattice with cubic side length 1)...
int getNumWeightsInRange(double minVal, double maxVal)
returns number of weights with values in range e[minVal,maxVal] (inclusive)
int getNumSynapses()
returns number of synapses that exist in the connection
std::string getGroupName(int grpId)
const FILE * getLogFpLog()
returns file pointer to log file
Definition: snn.h:602
void print()
prints current weight state as 2D matrix (non-existent synapses: NAN, existent but zero weigth: 0...
void writeConnectFileSnapshot(int simTimeMs, std::vector< std::vector< float > > wts)
writes each snapshot to connect file
int getNumSynapticConnections(short int connectionId)
gets number of connections associated with a connection ID
void printSparse(int neurPostId=ALL, int maxConn=100, int connPerLine=4, bool storeNewSnapshot=true)
const FILE * getLogFpErr()
returns file pointer to error log
Definition: snn.h:598
Contains all of CARLsim&#39;s core functionality.
Definition: snn.h:138
int getNumWeightsChanged(double minAbsChanged=1e-5)
returns number of weights with >=minAbsChanged weight change since last snapshot
int getNumWeightsWithValue(double value)
returns number of weights that have a certain value
void setUpdateTimeIntervalSec(int intervalSec)
sets time update interval (seconds) for periodically storing weights to file
std::vector< std::vector< float > > getWeightMatrix2D(short int connId)
void clear()
deletes data from the 2D weight matrix
int getSimTime()
Definition: snn.h:667
const FILE * getLogFpDeb()
returns file pointer to debug log
Definition: snn.h:600
std::vector< std::vector< float > > calcWeightChanges()
calculates weight changes since last snapshot and reports them in 2D weight change matrix ...
long int getTimeMsCurrentSnapshot()
returns the timestamp of the current snapshot (not necessarily CARLsim::getSimTime) ...
bool isConnectionPlastic(short int connId)
returns whether synapses in connection are fixed (false) or plastic (true)
int getGroupNumNeurons(int gGrpId)
Definition: snn.h:641
ConnectConfig getConnectConfig(short int connectId)
required for homeostasis
const FILE * getLogFpInf()
function writes population weights from gIDpre to gIDpost to file fname in binary.
Definition: snn.h:596
int getFanOut(int neurPreId)
returns number of outgoing synapses of pre-synaptic neuron