#include <limits.h>
#include "MathUtil.hh"
#include "NsSystem.hh"
#include "NsConnection.hh"
/*
* Constructor
*/
NsConnection::NsConnection(const NsTract *tract,
const NsUnit *fromUnit,
NsUnit *toUnit)
: forceStaticInit(initializeStatics()),
isPotentiated(false),
fromUnit(fromUnit),
toUnit(toUnit),
tract(tract),
id(fmt::format("{}-{}", fromUnit->id, toUnit->id)),
psdSize(minPsdSize),
numCiAmpars(minNumCiAmpars),
numCpAmpars(minNumCpAmpars),
psiIsOn(false)
{
toUnit->inConnections.push_back(this);
}
/*
* Static member variables
*/
double NsConnection::minPsdSize;
double NsConnection::maxPsdSize;
double NsConnection::minNumCiAmpars;
double NsConnection::minNumCpAmpars;
double NsConnection::potProbK;
double NsConnection::potProbHalf;
/**
* Initialize static member variables This needs to happen before regular
* member variables are initialized in the constructor, but can't be done by
* static member initializers because it must happen after props have been
* initialized, which happens in main().
*
* Hence the 'forceStaticInit' member variable that forces this function to
* be called before any other member variables are initialized.
*/
bool NsConnection::initializeStatics()
{
static bool staticsInitialized = false;
if (!staticsInitialized) {
minPsdSize = props.getDouble("minPsdSize");
maxPsdSize = props.getDouble("maxPsdSize");
minNumCiAmpars = props.getDouble("minNumCiAmpars");
minNumCpAmpars = props.getDouble("minNumCpAmpars");
potProbK = props.getDouble("potProbK");
potProbHalf = props.getDouble("potProbHalf");
staticsInitialized = true;
}
return true;
}
/**
* Set 'isPotentiated' = true. This will cause CI-AMPARs to move into slots
* as they are vacated by decaying CP-AMPARs
*/
void NsConnection::potentiate(const char *tag)
{
isPotentiated = true;
infoTrace("{:.1f} potentiating {} ({}) [{}]\n",
(double) simTime / 24.,
id, tag, toUnit->lastNetInput);
}
/**
* Turn off isPotentiated flag; this will cause CI-AMPARs
* to start being removed;
*/
void NsConnection::depotentiate(const char *tag)
{
isPotentiated = false;
setNumCiAmpars(minNumCiAmpars);
infoTrace("{:.1f} depotentiating {} ({}) [{}]\n",
(double) simTime / 24.,
id, tag, getStrength());
}
/**
* Decay num CP-AMPARs no matter what. If the connection is potentiated AND
* Hebbian, drive in CI-AMPARs, otherwise decay them towards their min and
* shrink PSD.
*/
void NsConnection::amparTrafficking(double cpAmparRemovalRate,
double ciAmparInsertionRate,
double ciAmparRemovalRate)
{
setNumCpAmpars(numCpAmpars -
cpAmparRemovalRate * (numCpAmpars - minNumCpAmpars));
if (isPotentiated && !psiIsOn) {
if (fromUnit->isActive && toUnit->isActive) {
double delta = Util::min(ciAmparInsertionRate,
psdSize - (numCpAmpars + numCiAmpars));
setNumCiAmpars(numCiAmpars + delta);
}
} else {
// Constitutive CI-AMPAR removal
//
setNumCiAmpars(numCiAmpars -
ciAmparRemovalRate * (numCiAmpars - minNumCiAmpars));
}
// PSD size decays toward the greater of the number of inserted
// AMPARs and minPsdSize
//
double asymptote =
Util::max(numCpAmpars + numCiAmpars, minPsdSize);
psdSize -= tract->psdDecayRate * (psdSize - asymptote);
}
/**
* Remove all CI-AMPARs and replace them by CP-AMPARs
*/
void NsConnection::reactivate()
{
// Rapid removal of CI-AMPARs
//
setNumCiAmpars(minNumCiAmpars);
// Rapid replacement by CP-AMPARS
//
setNumCpAmpars(psdSize - numCiAmpars);
}
/**
*
*/
void NsConnection::stimulate(double learnRate, uint numStimCycles,
const char *tag)
{
if (learnRate > 0) {
learn(learnRate, numStimCycles, tag);
}
}
/**
* If the connection is in the Hebbian condition, grow the PSD in
* accordance with the number of learning cycles specified and fill
* vacant slots with CP-AMPARs. Then, with a probability depending on
* the number of learning cycles, potentiate the synapse.
*/
void NsConnection::learn(double learnRate, uint numStimCycles, const char *tag)
{
if (fromUnit->isActive && toUnit->isActive) {
for (uint i = 0; i < numStimCycles; i++) {
psdSize += learnRate * (maxPsdSize - psdSize);
}
setNumCpAmpars(psdSize - numCiAmpars);
if (!isPotentiated && !psiIsOn) {
// Probability of potentiation is an asigmoid function of
// stimulation level, reflecting a fuzzy threshold level e.g. of
// accumulated kinase in a series of spikes.
//
// The level of stimulation is just numStimCycles
//
double probOfPotentiation =
MathUtil::asigmoid(numStimCycles, potProbK, potProbHalf) *
tract->maxPotProb;
if (Util::randDouble(0.0, 1.0) < probOfPotentiation) {
potentiate(tag);
}
}
}
}
/*
* Calculate strength as the number of inserted AMPARs divided by
* maxPsdSize, the maximum number of AMPARs that can be inserted.
* Thus, strength is a number in the range 0.0 to 1.0
*/
double NsConnection::getStrength() const
{
return (numCiAmpars + numCpAmpars) / 100 /*maxPsdSize*/;
}
void NsConnection::printStateHdr()
{
infoTrace("time conn ID PSD-SIZE CI-AMPARS CP-AMPARS Potentiated Hebbian\n");
}
void NsConnection::printState() const
{
infoTrace("{} conn {} {:.1f} {} {} {} {}\n",
simTime / 24., id,
psdSize, numCiAmpars, numCpAmpars, isPotentiated, isHebbian());
}
string NsConnection::toStr(uint iLvl, const string &iStr) const
{
return fmt::format("{}{} psd={} ci={} cp={}",
Util::repeatStr(iStr, iLvl),
id,
psdSize, numCiAmpars, numCpAmpars);
}