Skip to content

Commit dba2223

Browse files
committed
add C++ implementation of HTM (much better performance)
1 parent 45a1bc0 commit dba2223

File tree

14 files changed

+2497
-0
lines changed

14 files changed

+2497
-0
lines changed

src/HTM/cpp/AbstractCell.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* AbstractCell.h
3+
*
4+
* Created on: Sep 28, 2011
5+
* Author: barry
6+
*
7+
* AbstractCell is an interface used by HTM Region cells
8+
* that can represent either proximal (input) cells or distal
9+
* (temporal context) cells.
10+
*/
11+
12+
#ifndef ABSTRACTCELL_H_
13+
#define ABSTRACTCELL_H_
14+
15+
class AbstractCell {
16+
public:
17+
virtual bool isActive() = 0;
18+
virtual bool wasActive() = 0;
19+
virtual bool wasLearning() = 0;
20+
virtual bool isDistal() { return false; }
21+
};
22+
23+
#endif /* ABSTRACTCELL_H_ */

src/HTM/cpp/Cell.cpp

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
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+

src/HTM/cpp/Cell.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Cell.h
3+
*
4+
* Created on: Sep 22, 2011
5+
* Author: barry
6+
*
7+
* class Cell:
8+
* Represents an HTM sequence cell that belongs to a given Column.
9+
*/
10+
11+
#ifndef CELL_H_
12+
#define CELL_H_
13+
14+
#include <list>
15+
#include "AbstractCell.h"
16+
#include "Segment.h"
17+
#include "SegmentUpdateInfo.h"
18+
19+
class Region;
20+
class Column;
21+
22+
class Cell : public AbstractCell {
23+
public:
24+
Cell();
25+
~Cell();
26+
inline void init(Column* column, int index) { _column = column; _index = index; }
27+
inline int getIndex() { return _index; }
28+
inline bool isDistal() { return true; }
29+
30+
bool isActive() { return _isActive; }
31+
inline bool isLearning() { return _isLearning; }
32+
inline bool isPredicting() { return _isPredicting; }
33+
34+
bool wasActive() { return _wasActive; }
35+
bool wasLearning() { return _wasLearning; }
36+
inline bool wasPredicted() { return _wasPredicted; }
37+
38+
inline void setActive(bool active) { _isActive = active; }
39+
inline void setLearning(bool learning) { _isLearning = learning; }
40+
inline void setPredicting(bool predicting) { _isPredicting = predicting; }
41+
42+
void nextTimeStep();
43+
Segment* createSegment(std::set<Cell*>& learningCells);
44+
Segment* getPreviousActiveSegment();
45+
SegmentUpdateInfo* updateSegmentActiveSynapses(bool previous=false,
46+
Segment* segment=0, bool newSynapses=false);
47+
void applySegmentUpdates(bool positiveReinforcement);
48+
Segment* getBestMatchingSegment(bool isSequence, bool previous=false);
49+
bool hasActiveSequenceSegment();
50+
51+
inline int numSegments() { return _segments.size(); }
52+
inline Segment* getSegment(int i) { return _segments[i]; }
53+
Column* getColumn() { return _column; }
54+
Region* getRegion();
55+
56+
private:
57+
Column* _column;
58+
int _index;
59+
bool _isActive;
60+
bool _wasActive;
61+
bool _isPredicting;
62+
bool _wasPredicted;
63+
bool _isLearning;
64+
bool _wasLearning;
65+
std::vector<Segment*> _segments;
66+
67+
std::list<SegmentUpdateInfo*> _segmentUpdates;
68+
69+
};
70+
71+
#endif /* CELL_H_ */
72+

0 commit comments

Comments
 (0)