#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); }