|
| 1 | +/* |
| 2 | + * Cell.cpp |
| 3 | + * |
| 4 | + * Created on: Sep 22, 2011 |
| 5 | + * Author: barry |
| 6 | + * |
| 7 | + * Represents an HTM sequence cell that belongs to a given Column. |
| 8 | + */ |
| 9 | + |
| 10 | +#include <stdio.h> |
| 11 | +#include <vector> |
| 12 | +#include <set> |
| 13 | +#include "Region.h" |
| 14 | + |
| 15 | +int MIN_SYNAPSES_PER_SEGMENT_THRESHOLD = 1; |
| 16 | + |
| 17 | +/** |
| 18 | + * Create a new Cell belonging to the specified Column. The index is an |
| 19 | + * integer id to distinguish this Cell from others in the Column. |
| 20 | + */ |
| 21 | +Cell::Cell() { |
| 22 | + _isActive = false; |
| 23 | + _wasActive = false; |
| 24 | + _isPredicting = false; |
| 25 | + _wasPredicted = false; |
| 26 | + _isLearning = false; |
| 27 | + _wasLearning = false; |
| 28 | +} |
| 29 | + |
| 30 | +Cell::~Cell() { |
| 31 | + for(unsigned int i=0; i<_segments.size(); ++i) |
| 32 | + delete _segments[i]; |
| 33 | + _segments.clear(); |
| 34 | + for(std::list<SegmentUpdateInfo*>::iterator iter = _segmentUpdates.begin(); |
| 35 | + iter!=_segmentUpdates.end(); ++iter) { |
| 36 | + delete (*iter); //TODO better way to do this? |
| 37 | + } |
| 38 | + _segmentUpdates.clear(); |
| 39 | +} |
| 40 | + |
| 41 | +Region* Cell::getRegion() { |
| 42 | + return _column->getRegion(); |
| 43 | +} |
| 44 | + |
| 45 | +/** |
| 46 | + * Advance this cell to the next time step. The current state of this cell |
| 47 | + * (active, learning, predicting) will be set as the previous state and the current |
| 48 | + * state will be reset to no cell activity by default until it can be determined. |
| 49 | + */ |
| 50 | +void Cell::nextTimeStep() { |
| 51 | + _wasActive = _isActive; |
| 52 | + _wasPredicted = _isPredicting; |
| 53 | + _wasLearning = _isLearning; |
| 54 | + _isActive = false; |
| 55 | + _isPredicting = false; |
| 56 | + _isLearning = false; |
| 57 | +} |
| 58 | + |
| 59 | +/** |
| 60 | + * Create a new segment for this Cell. The new segment will initially connect to |
| 61 | + * at most newSynapseCount synapses randomly selected from the set of cells that |
| 62 | + * were in the learning state at t-1 (specified by the learningCells parameter). |
| 63 | + * @param learningCells: the set of available learning cells to add to the segment. |
| 64 | + * @return the segment that was just created. |
| 65 | + */ |
| 66 | +Segment* Cell::createSegment(std::set<Cell*>& learningCells) { |
| 67 | + std::set<Synapse*> added; |
| 68 | + Segment* newSegment = new Segment(_column->getRegion()->getSegActiveThreshold()); |
| 69 | + newSegment->createSynapsesToLearningCells(learningCells, added); |
| 70 | + _segments.push_back(newSegment); |
| 71 | + return newSegment; |
| 72 | +} |
| 73 | + |
| 74 | +/** |
| 75 | + * For this cell, return a segment that was active in the previous time |
| 76 | + * step. If multiple segments were active, sequence segments are given preference. |
| 77 | + * Otherwise, segments with most activity are given preference. |
| 78 | + */ |
| 79 | +Segment* Cell::getPreviousActiveSegment() { |
| 80 | + std::vector<Segment*> activeSegs; |
| 81 | + for(unsigned int i=0; i<_segments.size(); ++i) { |
| 82 | + if(_segments[i]->wasActive()) |
| 83 | + activeSegs.push_back(_segments[i]); |
| 84 | + } |
| 85 | + |
| 86 | + if(activeSegs.size()==1) //if only 1 active segment, return it |
| 87 | + return activeSegs[0]; |
| 88 | + |
| 89 | + if(activeSegs.size() > 1) { |
| 90 | + //if >1 active segments, sequence segments given priority |
| 91 | + std::vector<Segment*> sequenceSegs; |
| 92 | + for(unsigned int i=0; i<activeSegs.size(); ++i) { |
| 93 | + if(activeSegs[i]->isSequence()) { |
| 94 | + sequenceSegs.push_back(activeSegs[i]); |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + if(sequenceSegs.size()==1) |
| 99 | + return sequenceSegs[0]; |
| 100 | + else if(sequenceSegs.size() > 1) { |
| 101 | + activeSegs.clear(); |
| 102 | + for(unsigned int i=0; i<sequenceSegs.size(); ++i) |
| 103 | + activeSegs.push_back(sequenceSegs[i]); |
| 104 | + } |
| 105 | + |
| 106 | + //if multiple possible segments, return segment with most activity |
| 107 | + Segment* bestSegment = activeSegs[0]; |
| 108 | + int mostActiveSyns = bestSegment->getPrevActiveSynapseCount(); |
| 109 | + for(unsigned int i=1; i<activeSegs.size(); ++i) { |
| 110 | + int activeSyns = activeSegs[i]->getPrevActiveSynapseCount(); |
| 111 | + if(activeSyns > mostActiveSyns) { |
| 112 | + mostActiveSyns = activeSyns; |
| 113 | + bestSegment = activeSegs[i]; |
| 114 | + } |
| 115 | + } |
| 116 | + return bestSegment; |
| 117 | + } |
| 118 | + |
| 119 | + return NULL; |
| 120 | +} |
| 121 | + |
| 122 | +/** |
| 123 | + * Return a SegmentUpdateInfo object containing proposed changes to the specified |
| 124 | + * segment. If the segment is None, then a new segment is to be added, otherwise |
| 125 | + * the specified segment is updated. If the segment exists, find all active |
| 126 | + * synapses for the segment (either at t or t-1 based on the 'previous' parameter) |
| 127 | + * and mark them as needing to be updated. If newSynapses is true, then |
| 128 | + * Region.newSynapseCount - len(activeSynapses) new synapses are added to the |
| 129 | + * segment to be updated. The (new) synapses are randomly chosen from the set |
| 130 | + * of current learning cells (within Region.localityRadius if set). |
| 131 | + * |
| 132 | + * These segment updates are only applied when the applySegmentUpdates |
| 133 | + * method is later called on this Cell. |
| 134 | + */ |
| 135 | +SegmentUpdateInfo* Cell::updateSegmentActiveSynapses(bool previous, Segment* segment, |
| 136 | + bool newSynapses) { |
| 137 | + std::set<Synapse*> activeSyns; |
| 138 | + if(segment!=NULL) { |
| 139 | + if(previous) |
| 140 | + segment->getPrevActiveSynapses(activeSyns); |
| 141 | + else |
| 142 | + segment->getActiveSynapses(activeSyns); |
| 143 | + } |
| 144 | + |
| 145 | + SegmentUpdateInfo* segmentUpdate = |
| 146 | + new SegmentUpdateInfo(this, segment, activeSyns, newSynapses); |
| 147 | + _segmentUpdates.push_back(segmentUpdate); |
| 148 | + return segmentUpdate; |
| 149 | +} |
| 150 | + |
| 151 | +/** |
| 152 | + * This function reinforces each segment in this Cell's SegmentUpdateInfo. |
| 153 | + * Using the segmentUpdateInfo, the following changes are |
| 154 | + * performed. If positiveReinforcement is true then synapses on the active |
| 155 | + * list get their permanence counts incremented by permanenceInc. All other |
| 156 | + * synapses get their permanence counts decremented by permanenceDec. If |
| 157 | + * positiveReinforcement is false, then synapses on the active list get |
| 158 | + * their permanence counts decremented by permanenceDec. After this step, |
| 159 | + * any synapses in segmentUpdate that do yet exist get added with a permanence |
| 160 | + * count of initialPerm. These new synapses are randomly chosen from the |
| 161 | + * set of all cells that have learnState output = 1 at time step t. |
| 162 | + */ |
| 163 | +void Cell::applySegmentUpdates(bool positiveReinforcement) { |
| 164 | + for(std::list<SegmentUpdateInfo*>::iterator iter = _segmentUpdates.begin(); |
| 165 | + iter!=_segmentUpdates.end(); ++iter) { |
| 166 | + SegmentUpdateInfo* segInfo = (*iter); |
| 167 | + Segment* segment = segInfo->getSegment(); |
| 168 | + |
| 169 | + if(segment!=NULL) { |
| 170 | + if(positiveReinforcement) |
| 171 | + segment->updatePermanences(segInfo->getActiveSynapses()); |
| 172 | + else |
| 173 | + segment->decreasePermanences(segInfo->getActiveSynapses()); |
| 174 | + } |
| 175 | + |
| 176 | + //add new synapses (and new segment if necessary) |
| 177 | + if(segInfo->getAddNewSynapses() && positiveReinforcement) { |
| 178 | + if(segment==NULL) { |
| 179 | + if(segInfo->numLearningCells() > 0)//only add if learning cells available |
| 180 | + segment = segInfo->createCellSegment(); |
| 181 | + } |
| 182 | + else if(segInfo->numLearningCells() > 0) { |
| 183 | + //add new synapses to existing segment |
| 184 | + segInfo->createSynapsesToLearningCells(); |
| 185 | + } |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + //delete segment update instances after they are applied |
| 190 | + for(std::list<SegmentUpdateInfo*>::iterator iter = _segmentUpdates.begin(); |
| 191 | + iter!=_segmentUpdates.end(); ++iter) { |
| 192 | + delete (*iter); //TODO test if this is ok |
| 193 | + } |
| 194 | + _segmentUpdates.clear(); |
| 195 | +} |
| 196 | + |
| 197 | +/** |
| 198 | + * For this cell (at t-1 if previous=True else at t), find the segment (only |
| 199 | + * consider sequence segments if isSequence is True, otherwise only consider |
| 200 | + * non-sequence segments) with the largest number of active synapses. |
| 201 | + * This routine is aggressive in finding the best match. The permanence |
| 202 | + * value of synapses is allowed to be below connectedPerm. |
| 203 | + * The number of active synapses is allowed to be below activationThreshold, |
| 204 | + * but must be above minThreshold. The routine returns that segment. |
| 205 | + * If no segments are found, then None is returned. |
| 206 | + */ |
| 207 | +Segment* Cell::getBestMatchingSegment(bool isSequence, bool previous) { |
| 208 | + Segment* bestSegment = NULL; |
| 209 | + int bestSynapseCount = MIN_SYNAPSES_PER_SEGMENT_THRESHOLD; |
| 210 | + for(unsigned int i=0; i<_segments.size(); ++i) { |
| 211 | + if(_segments[i]->isSequence()==isSequence) { |
| 212 | + int synCount = 0; |
| 213 | + if(previous) |
| 214 | + synCount = _segments[i]->getPrevActiveSynapseCount(false); |
| 215 | + else |
| 216 | + synCount = _segments[i]->getActiveSynapseCount(false); |
| 217 | + |
| 218 | + if(synCount > bestSynapseCount) { |
| 219 | + bestSynapseCount = synCount; |
| 220 | + bestSegment = _segments[i]; |
| 221 | + } |
| 222 | + } |
| 223 | + } |
| 224 | + return bestSegment; |
| 225 | +} |
| 226 | + |
| 227 | +/** |
| 228 | + * Return true if this cell has a currently active sequence segment. |
| 229 | + */ |
| 230 | +bool Cell::hasActiveSequenceSegment() { |
| 231 | + for(unsigned int i=0; i<_segments.size(); ++i) { |
| 232 | + if(_segments[i]->isActive() && _segments[i]->isSequence()) |
| 233 | + return true; |
| 234 | + } |
| 235 | + return false; |
| 236 | +} |
| 237 | + |
0 commit comments