#include "NsSystem.hh" #include "NsLayer.hh" /** * Implementation of the NsLayer class */ NsLayer::NsLayer(const string &id, const string &type) : id(id), type(type), width(props.getUint(id + '.' + "width")), height(props.getUint(id + '.' + "height")), k(props.getDouble(id + '.' + "k")), minInhibition(props.getDouble("minInhibition")), maxInhibition(props.getDouble("maxInhibition")), initInhibition(props.getDouble("initInhibition")), inhibIncr(props.getDouble("inhibIncr")), inhibition(initInhibition), isClamped(false), isFrozen(false), isLesioned(false), orthogonalPatterns(props.getBool("orthogonalPatterns")), nextPatternUnit(0), printPatterns(props.getBool("printPatterns")) { uint numUnits = width * height; for (uint i = 0; i < numUnits; i++) { units.push_back(new NsUnit(this, i)); } } void NsLayer::makePattern(const string &patId) { ABORT_IF(definedPatterns.count(patId) != 0, "Duplicate pattern ID"); NsPattern p; if (orthogonalPatterns) { for (uint i = 0; i < k * units.size(); i++) { ABORT_IF(nextPatternUnit >= units.size(), "too many patterns"); p.push_back(nextPatternUnit++); } } else { p = Util::randUniqueUintList(k * units.size(), units.size()); } definedPatterns.insert({patId, p}); definedPatternIds.push_back(patId); TRACE_DEBUG("{}.{} {}\n", id, patId, patternToStr(p)); } void NsLayer::setPattern(const NsPattern &pat) { if (!isFrozen) { clear(); for (auto id : pat) { units[id]->isActive = true; } } } void NsLayer::setPattern(const string &patId) { setPattern(definedPatterns.at(patId)); } void NsLayer::clearPatterns() { definedPatternIds.clear(); definedPatterns.clear(); } /** * Randomly select one of the trained patterns and activate it */ const string &NsLayer::setRandomPattern() { uint i = Util::randInt(0, definedPatternIds.size()); const string &pid = definedPatternIds[i]; setPattern(pid); TRACE_INFO("Layer {}, pattern {}", id, pid); return pid; } void NsLayer::clear() { for(auto u : units) { u->isActive = false; } } /** * Adjust inhibition level to drive the layer towards settling with the * number of active units = k */ void NsLayer::adjustInhibition() { ABORT_IF(isFrozen, "Makes no sense"); int target = k * units.size(); int error = (int) getNumActive() - target; // make an adjustment to the inhibition level // in proportion to the magnitude of the error inhibition = Util::bracket( inhibition + (double) error / target * inhibIncr, minInhibition, maxInhibition); TTRACE_DEBUG("inhib", "{} active: {} inhib: {}", id, getNumActive(), inhibition); } /** * Randomly set each unit to active or inactive with probability k */ void NsLayer::randomize() { ABORT_IF(isFrozen, "Makes no sense"); for(auto u : units) { u->isActive = (Util::randDouble(0.0, 1.0) < k); } } /** * Compute new activations for all units() */ void NsLayer::computeNewActivations() { ABORT_IF(isFrozen, "Makes no sense"); if (!isClamped) { for(auto u : units) { u->computeNewActivation(); } } } /** * Apply new activations for all units() */ void NsLayer::applyNewActivations() { ABORT_IF(isFrozen, "Makes no sense"); if (!isClamped) { for(auto u : units) { u->applyNewActivation(); } } } void NsLayer::setFrozen(bool state) { if (!isLesioned) { isFrozen = state; for(auto u : units) { u->setFrozen(state); } } } void NsLayer::lesion() { setFrozen(true); isLesioned = true; } void NsLayer::maintain() { for(auto u : units) { u->maintain(); } } uint NsLayer::getNumActive() const { uint numActive = 0; for(auto u : units) { if (u->isActive) { numActive++; } } return numActive; } void NsLayer::printState() const { printNumActive(); for(auto u : units) { u->printState(); } } /** * Count number of active target units * @param targetId ID of target pattern * @return Count of targeted active units */ uint NsLayer::getNumHits(const string &targetId) const { NsPattern target = definedPatterns.at(targetId); uint ret = 0; for (auto id : target) { if(units[id]->isActive) ret++; } return ret; } void NsLayer::printScoreHdr() { fmt::print("time score condition layer target hits extras\n"); } void NsLayer::printNumActiveHdr() { infoTrace("time layer id numActive\n"); } void NsLayer::printNumActive() const { infoTrace("{} layer {} {}\n", simTime, id, getNumActive()); } void NsLayer::printGrid(const string &tag, const string &targetId) const { bool targetKnown = (definedPatterns.count(targetId) != 0); if (targetKnown) { uint targetSize = definedPatterns.at(targetId).size(); uint numHits = getNumHits(targetId); uint numExtras = getNumActive() > numHits ? getNumActive() - numHits : 0; fmt::print("{} score {} {} {} {} {}\n", simTime / 24., tag, id, targetSize, numHits, numExtras); } else { if (printPatterns) { infoTrace("{} {} {}\n", simTime / 24., tag, id); } } if (printPatterns) { infoTrace("+{}+\n", string(2 * width -1, '-')); for (uint row = 0; row < height; row++) { infoTrace("|"); for (uint col = 0; col < width; col++) { infoTrace("{}{}", units[row * width + col]->isActive ? '*' : ' ', (col < width - 1) ? " " : ""); } infoTrace("|\n"); } infoTrace("+{}+\n", string(2 * width -1, '-')); } } string NsLayer::toStr(uint iLvl, const string &iStr) const { string ret = fmt::format("{}NsLayer[{}]: ", Util::repeatStr(iStr, iLvl), id); for (auto u: units) { ret += "\n" + u->toStr(iLvl + 1, iStr); } return ret; }