diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d00ee56f4..2a3379547d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -214,6 +214,8 @@ set(src_py_support_files set(src_capnp_specs_rel nupic/proto/ArrayProto.capnp nupic/proto/BitHistory.capnp + nupic/proto/Cell.capnp + nupic/proto/Cells4.capnp nupic/proto/ClaClassifier.capnp nupic/proto/ConnectionsProto.capnp nupic/proto/LinkProto.capnp @@ -222,6 +224,8 @@ set(src_capnp_specs_rel nupic/proto/PyRegionProto.capnp nupic/proto/RandomProto.capnp nupic/proto/RegionProto.capnp + nupic/proto/Segment.capnp + nupic/proto/SegmentUpdate.capnp nupic/proto/SparseBinaryMatrixProto.capnp nupic/proto/SparseMatrixProto.capnp nupic/proto/SpatialPoolerProto.capnp diff --git a/src/nupic/algorithms/Cell.cpp b/src/nupic/algorithms/Cell.cpp index 29f324de4d..cda1e1a0bb 100644 --- a/src/nupic/algorithms/Cell.cpp +++ b/src/nupic/algorithms/Cell.cpp @@ -20,6 +20,7 @@ * --------------------------------------------------------------------- */ +#include <nupic/proto/Cell.capnp.h> #include <nupic/algorithms/Cell.hpp> using namespace nupic::algorithms::Cells4; @@ -121,6 +122,34 @@ void Cell::updateDutyCycle(UInt iterations) } } +//----------------------------------------------------------------------------- +void Cell::write(CellProto::Builder& proto) const +{ + auto segmentsProto = proto.initSegments(_segments.size()); + for (UInt i = 0; i < _segments.size(); ++i) + { + auto segProto = segmentsProto[i]; + _segments[i].write(segProto); + } +} + +//----------------------------------------------------------------------------- +void Cell::read(CellProto::Reader& proto) +{ + auto segmentsProto = proto.getSegments(); + _segments.resize(segmentsProto.size()); + _freeSegments.resize(0); + for (UInt i = 0; i < segmentsProto.size(); ++i) + { + auto segProto = segmentsProto[i]; + _segments[i].read(segProto); + if (_segments[i].empty()) + { + _freeSegments.push_back(i); + } + } +} + //----------------------------------------------------------------------------- void Cell::save(std::ostream& outStream) const { diff --git a/src/nupic/algorithms/Cell.hpp b/src/nupic/algorithms/Cell.hpp index 66e96becdf..299ad40ef3 100644 --- a/src/nupic/algorithms/Cell.hpp +++ b/src/nupic/algorithms/Cell.hpp @@ -24,6 +24,8 @@ #define NTA_CELL_HPP #include <vector> +#include <nupic/proto/Cell.capnp.h> +#include <nupic/types/Serializable.hpp> #include <nupic/types/Types.hpp> #include <nupic/algorithms/Segment.hpp> @@ -44,7 +46,7 @@ namespace nupic { * mismatches in unit testing when comparing the Python TP to the C++ down to the * segment level. */ - class Cell + class Cell : Serializable<CellProto> { private: std::vector< Segment > _segments; // both 'active' and 'inactive' segments @@ -252,6 +254,14 @@ namespace nupic { return buff.str().size(); } + //---------------------------------------------------------------------- + using Serializable::write; + virtual void write(CellProto::Builder& proto) const override; + + //---------------------------------------------------------------------- + using Serializable::read; + virtual void read(CellProto::Reader& proto) override; + //---------------------------------------------------------------------- void save(std::ostream& outStream) const; diff --git a/src/nupic/algorithms/Cells4.cpp b/src/nupic/algorithms/Cells4.cpp index ac66a3ed22..7656349825 100644 --- a/src/nupic/algorithms/Cells4.cpp +++ b/src/nupic/algorithms/Cells4.cpp @@ -35,14 +35,14 @@ #include <assert.h> #include <cstring> #include <map> -#include <nupic/math/ArrayAlgo.hpp> // is_in -#include <nupic/math/StlIo.hpp> // binary_save +#include <nupic/algorithms/Cell.hpp> #include <nupic/algorithms/Cells4.hpp> #include <nupic/algorithms/SegmentUpdate.hpp> -#include <nupic/algorithms/Cell.hpp> +#include <nupic/math/ArrayAlgo.hpp> // is_in +#include <nupic/math/StlIo.hpp> // binary_save #include <nupic/os/FStream.hpp> - #include <nupic/os/Timer.hpp> +#include <nupic/proto/Cells4.capnp.h> using namespace nupic::algorithms::Cells4; @@ -1931,6 +1931,148 @@ void Cells4::reset() //} } + +//-------------------------------------------------------------------------------- +void Cells4::write(Cells4Proto::Builder& proto) const +{ + proto.setVersion(version()); + proto.setOwnsMemory(_ownsMemory); + auto randomProto = proto.initRng(); + _rng.write(randomProto); + proto.setNColumns(_nColumns); + proto.setNCellsPerCol(_nCellsPerCol); + proto.setActivationThreshold(_activationThreshold); + proto.setMinThreshold(_minThreshold); + proto.setNewSynapseCount(_newSynapseCount); + proto.setNIterations(_nIterations); + proto.setNLrnIterations(_nLrnIterations); + proto.setSegUpdateValidDuration(_segUpdateValidDuration); + proto.setInitSegFreq(_initSegFreq); + proto.setPermInitial(_permInitial); + proto.setPermConnected(_permConnected); + proto.setPermMax(_permMax); + proto.setPermDec(_permDec); + proto.setPermInc(_permInc); + proto.setGlobalDecay(_globalDecay); + proto.setDoPooling(_doPooling); + proto.setPamLength(_pamLength); + proto.setMaxInfBacktrack(_maxInfBacktrack); + proto.setMaxLrnBacktrack(_maxLrnBacktrack); + proto.setMaxSeqLength(_maxSeqLength); + proto.setLearnedSeqLength(_learnedSeqLength); + proto.setAvgLearnedSeqLength(_avgLearnedSeqLength); + proto.setMaxAge(_maxAge); + proto.setVerbosity(_verbosity); + proto.setMaxSegmentsPerCell(_maxSegmentsPerCell); + proto.setMaxSynapsesPerSegment(_maxSynapsesPerSegment); + proto.setCheckSynapseConsistency(_checkSynapseConsistency); + proto.setResetCalled(_resetCalled); + proto.setAvgInputDensity(_avgInputDensity); + proto.setPamCounter(_pamCounter); + + auto learnActiveStateTProto = proto.initLearnActiveStateT(); + _learnActiveStateT.write(learnActiveStateTProto); + auto learnActiveStateT1Proto = proto.initLearnActiveStateT1(); + _learnActiveStateT1.write(learnActiveStateT1Proto); + auto learnPredictedStateTProto = proto.initLearnPredictedStateT(); + _learnPredictedStateT.write(learnPredictedStateTProto); + auto learnPredictedStateT1Proto = proto.initLearnPredictedStateT1(); + _learnPredictedStateT1.write(learnPredictedStateT1Proto); + + auto cellListProto = proto.initCells(_nCells); + for (UInt i = 0; i < _nCells; ++i) + { + auto cellProto = cellListProto[i]; + _cells[i].write(cellProto); + } + + auto segmentUpdatesListProto = proto.initSegmentUpdates( + _segmentUpdates.size()); + for (UInt i = 0; i < _segmentUpdates.size(); ++i) + { + auto segmentUpdateProto = segmentUpdatesListProto[i]; + _segmentUpdates[i].write(segmentUpdateProto); + } +} + + +//-------------------------------------------------------------------------------- +void Cells4::read(Cells4Proto::Reader& proto) +{ + NTA_CHECK(proto.getVersion() == 2); + _ownsMemory = proto.getOwnsMemory(); + auto randomProto = proto.getRng(); + _rng.read(randomProto); + _nColumns = proto.getNColumns(); + _nCellsPerCol = proto.getNCellsPerCol(); + _activationThreshold = proto.getActivationThreshold(); + _minThreshold = proto.getMinThreshold(); + _newSynapseCount = proto.getNewSynapseCount(); + _nIterations = proto.getNIterations(); + _nLrnIterations = proto.getNLrnIterations(); + _segUpdateValidDuration = proto.getSegUpdateValidDuration(); + _initSegFreq = proto.getInitSegFreq(); + _permInitial = proto.getPermInitial(); + _permConnected = proto.getPermConnected(); + _permMax = proto.getPermMax(); + _permDec = proto.getPermDec(); + _permInc = proto.getPermInc(); + _globalDecay = proto.getGlobalDecay(); + _doPooling = proto.getDoPooling(); + _pamLength = proto.getPamLength(); + _maxInfBacktrack = proto.getMaxInfBacktrack(); + _maxLrnBacktrack = proto.getMaxLrnBacktrack(); + _maxSeqLength = proto.getMaxSeqLength(); + _learnedSeqLength = proto.getLearnedSeqLength(); + _avgLearnedSeqLength = proto.getAvgLearnedSeqLength(); + _maxAge = proto.getMaxAge(); + _verbosity = proto.getVerbosity(); + _maxSegmentsPerCell = proto.getMaxSegmentsPerCell(); + _maxSynapsesPerSegment = proto.getMaxSynapsesPerSegment(); + _checkSynapseConsistency = proto.getCheckSynapseConsistency(); + + _resetCalled = proto.getResetCalled(); + + _avgInputDensity = proto.getAvgInputDensity(); + _pamCounter = proto.getPamCounter(); + + auto learnActiveStateTProto = proto.getLearnActiveStateT(); + _learnActiveStateT.read(learnActiveStateTProto); + auto learnActiveStateT1Proto = proto.getLearnActiveStateT1(); + _learnActiveStateT1.read(learnActiveStateT1Proto); + auto learnPredictedStateTProto = proto.getLearnPredictedStateT(); + _learnPredictedStateT.read(learnPredictedStateTProto); + auto learnPredictedStateT1Proto = proto.getLearnPredictedStateT1(); + _learnPredictedStateT1.read(learnPredictedStateT1Proto); + + auto cellListProto = proto.getCells(); + _nCells = cellListProto.size(); + _cells.resize(_nCells); + for (UInt i = 0; i < cellListProto.size(); ++i) + { + auto cellProto = cellListProto[i]; + _cells[i].read(cellProto); + } + + auto segmentUpdatesListProto = proto.getSegmentUpdates(); + _segmentUpdates.clear(); + _segmentUpdates.resize(segmentUpdatesListProto.size()); + for (UInt i = 0; i < segmentUpdatesListProto.size(); ++i) + { + auto segmentUpdateProto = segmentUpdatesListProto[i]; + _segmentUpdates[i].read(segmentUpdateProto); + } + + rebuildOutSynapses(); + if (_checkSynapseConsistency || (_nCells * _maxSegmentsPerCell < 100000)) + { + NTA_CHECK(invariants(true)); + } + + _version = VERSION; +} + + //-------------------------------------------------------------------------------- void Cells4::save(std::ostream& outStream) const { diff --git a/src/nupic/algorithms/Cells4.hpp b/src/nupic/algorithms/Cells4.hpp index 2762a03fff..5ae8efc8f1 100644 --- a/src/nupic/algorithms/Cells4.hpp +++ b/src/nupic/algorithms/Cells4.hpp @@ -26,9 +26,11 @@ #include <ostream> #include <sstream> #include <fstream> -#include <nupic/types/Types.hpp> #include <nupic/algorithms/Segment.hpp> #include <nupic/algorithms/OutSynapse.hpp> +#include <nupic/proto/Cells4.capnp.h> +#include <nupic/types/Serializable.hpp> +#include <nupic/types/Types.hpp> #include <queue> #include <cstring> @@ -262,7 +264,7 @@ namespace nupic { CBasicActivity<It> _seg; }; - class Cells4 + class Cells4 : public Serializable<Cells4Proto> { public: @@ -1073,6 +1075,20 @@ namespace nupic { return tmp.str().size(); } + //---------------------------------------------------------------------- + /** + * Write the state to a proto or file + */ + using Serializable::write; + virtual void write(Cells4Proto::Builder& proto) const override; + + //---------------------------------------------------------------------- + /** + * Read the state into a proto or file + */ + using Serializable::read; + virtual void read(Cells4Proto::Reader& proto) override; + //---------------------------------------------------------------------- /** * Save the state to the given file diff --git a/src/nupic/algorithms/Segment.hpp b/src/nupic/algorithms/Segment.hpp index bf3bbfe7a2..441a03172d 100644 --- a/src/nupic/algorithms/Segment.hpp +++ b/src/nupic/algorithms/Segment.hpp @@ -33,6 +33,8 @@ #include <nupic/math/ArrayAlgo.hpp> // is_sorted #include <nupic/math/StlIo.hpp> // binary_save +#include <nupic/proto/Segment.capnp.h> +#include <nupic/types/Serializable.hpp> #include <nupic/algorithms/InSynapse.hpp> @@ -88,7 +90,7 @@ namespace nupic { /** * Encapsulate the arrays used to maintain per-cell state. */ - class CState + class CState : Serializable<CStateProto> { public: static const UInt VERSION = 1; @@ -165,6 +167,29 @@ namespace nupic { outStream << std::endl << "end" << std::endl; } + using Serializable::write; + virtual void write(CStateProto::Builder& proto) const override + { + proto.setVersion(VERSION); + proto.setFMemoryAllocatedByPython(_fMemoryAllocatedByPython); + auto pDataProto = proto.initPData(_nCells); + for (UInt i = 0; i < _nCells; ++i) + { + pDataProto[i] = _pData[i]; + } + } + using Serializable::read; + virtual void read(CStateProto::Reader& proto) override + { + NTA_CHECK(proto.getVersion() == 1); + _fMemoryAllocatedByPython = proto.getFMemoryAllocatedByPython(); + auto pDataProto = proto.getPData(); + _nCells = pDataProto.size(); + for (UInt i = 0; i < _nCells; ++i) + { + _pData[i] = pDataProto[i]; + } + } void load(std::istream& inStream) { UInt version; @@ -271,6 +296,27 @@ namespace nupic { } outStream << "end" << std::endl; } + void write(CStateProto::Builder& proto) const override + { + CState::write(proto); + proto.setCountOn(_countOn); + auto cellsOnProto = proto.initCellsOn(_cellsOn.size()); + for (UInt i = 0; i < _cellsOn.size(); ++i) + { + cellsOnProto.set(i, _cellsOn[i]); + } + } + void read(CStateProto::Reader& proto) override + { + CState::read(proto); + _countOn = proto.getCountOn(); + auto cellsOnProto = proto.getCellsOn(); + _cellsOn.resize(cellsOnProto.size()); + for (UInt i = 0; i < cellsOnProto.size(); ++i) + { + _cellsOn[i] = cellsOnProto[i]; + } + } void load(std::istream& inStream) { UInt version; @@ -334,7 +380,7 @@ namespace nupic { //----------------------------------------------------------------------- - class Segment + class Segment : Serializable<SegmentProto> { public: typedef std::vector< InSynapse > InSynapses; @@ -812,6 +858,48 @@ namespace nupic { return buff.str().size(); } + //---------------------------------------------------------------------- + using Serializable::write; + void write(SegmentProto::Builder& proto) const override + { + NTA_ASSERT(invariants()); + proto.setSeqSegFlag(_seqSegFlag); + proto.setFrequency(_frequency); + proto.setNConnected(_nConnected); + proto.setTotalActivations(_totalActivations); + proto.setPositiveActivations(_positiveActivations); + proto.setLastActiveIteration(_lastActiveIteration); + proto.setLastPosDutyCycle(_lastPosDutyCycle); + proto.setLastPosDutyCycleIteration(_lastPosDutyCycleIteration); + auto synapsesProto = proto.initSynapses(size()); + for (UInt i = 0; i < size(); ++i) + { + auto inSynapseProto = synapsesProto[i]; + inSynapseProto.setSrcCellIdx(_synapses[i].srcCellIdx()); + inSynapseProto.setPermanence(_synapses[i].permanence()); + } + } + + //---------------------------------------------------------------------- + using Serializable::read; + void read(SegmentProto::Reader& proto) override + { + _seqSegFlag = proto.getSeqSegFlag(); + _frequency = proto.getFrequency(); + _nConnected = proto.getNConnected(); + _totalActivations = proto.getTotalActivations(); + _positiveActivations = proto.getPositiveActivations(); + _lastActiveIteration = proto.getLastActiveIteration(); + _lastPosDutyCycle = proto.getLastPosDutyCycle(); + _lastPosDutyCycleIteration = proto.getLastPosDutyCycleIteration(); + _synapses.clear(); + for (auto inSynapseProto : proto.getSynapses()) + { + _synapses.emplace_back(inSynapseProto.getSrcCellIdx(), + inSynapseProto.getPermanence()); + } + } + //---------------------------------------------------------------------- inline void save(std::ostream& outStream) const { diff --git a/src/nupic/algorithms/SegmentUpdate.hpp b/src/nupic/algorithms/SegmentUpdate.hpp index 22acdfb0c3..a3711a3eb4 100644 --- a/src/nupic/algorithms/SegmentUpdate.hpp +++ b/src/nupic/algorithms/SegmentUpdate.hpp @@ -23,6 +23,8 @@ #ifndef NTA_SEGMENTUPDATE_HPP #define NTA_SEGMENTUPDATE_HPP +#include <nupic/proto/SegmentUpdate.capnp.h> +#include <nupic/types/Serializable.hpp> #include <nupic/types/Types.hpp> #include <vector> using namespace nupic; @@ -43,7 +45,7 @@ namespace nupic { * than the iteration they were created in. SegmentUpdates have a timeStamp, * and they are discarded without being applied if they become 'stale'. */ - class SegmentUpdate + class SegmentUpdate : Serializable<SegmentUpdateProto> { public: typedef std::vector<UInt>::const_iterator const_iterator; @@ -110,6 +112,41 @@ namespace nupic { */ bool invariants(Cells4* cells =nullptr) const; + //--------------------------------------------------------------------- + using Serializable::write; + void write(SegmentUpdateProto::Builder& proto) const override + { + proto.setSequenceSegment(_sequenceSegment); + proto.setCellIdx(_cellIdx); + proto.setSegIdx(_segIdx); + proto.setTimestamp(_timeStamp); + auto synapsesProto = proto.initSynapses(_synapses.size()); + for (UInt i = 0; i < _synapses.size(); ++i) + { + synapsesProto.set(i, _synapses[i]); + } + proto.setPhase1Flag(_phase1Flag); + proto.setWeaklyPredicting(_weaklyPredicting); + } + + //--------------------------------------------------------------------- + using Serializable::read; + void read(SegmentUpdateProto::Reader& proto) override + { + _sequenceSegment = proto.getSequenceSegment(); + _cellIdx = proto.getCellIdx(); + _segIdx = proto.getSegIdx(); + _timeStamp = proto.getTimestamp(); + auto synapsesProto = proto.getSynapses(); + _synapses.resize(synapsesProto.size()); + for (UInt i = 0; i < synapsesProto.size(); ++i) + { + _synapses[i] = synapsesProto[i]; + } + _phase1Flag = proto.getPhase1Flag(); + _weaklyPredicting = proto.getWeaklyPredicting(); + } + //--------------------------------------------------------------------- void save(std::ostream& outStream) const { diff --git a/src/nupic/proto/Cell.capnp b/src/nupic/proto/Cell.capnp new file mode 100644 index 0000000000..f95a9f9f63 --- /dev/null +++ b/src/nupic/proto/Cell.capnp @@ -0,0 +1,7 @@ +@0xcf9698b0f93fc8e4; + +using import "/nupic/proto/Segment.capnp".SegmentProto; + +struct CellProto { + segments @0 :List(SegmentProto); +} diff --git a/src/nupic/proto/Cells4.capnp b/src/nupic/proto/Cells4.capnp new file mode 100644 index 0000000000..045b3f7fd1 --- /dev/null +++ b/src/nupic/proto/Cells4.capnp @@ -0,0 +1,55 @@ +@0xd5c4908fa0384eda; + +using import "/nupic/proto/Cell.capnp".CellProto; +using import "/nupic/proto/RandomProto.capnp".RandomProto; +using import "/nupic/proto/Segment.capnp".CStateProto; +using import "/nupic/proto/SegmentUpdate.capnp".SegmentUpdateProto; + +# Next ID: 39 +struct Cells4Proto { + version @0 :UInt16; + ownsMemory @1 :Bool; + rng @2 :RandomProto; + nColumns @3 :UInt32; + nCellsPerCol @4 :UInt32; + activationThreshold @5 :UInt32; + minThreshold @6 :UInt32; + newSynapseCount @7 :UInt32; + nIterations @8 :UInt32; + nLrnIterations @9 :UInt32; + segUpdateValidDuration @10 :UInt32; + initSegFreq @11 :Float32; + permInitial @12 :Float32; + permConnected @13 :Float32; + permMax @14 :Float32; + permDec @15 :Float32; + permInc @16 :Float32; + globalDecay @17 :Float32; + doPooling @18 :Bool; + pamLength @19 :UInt32; + maxInfBacktrack @20 :UInt32; + maxLrnBacktrack @21 :UInt32; + maxSeqLength @22 :UInt32; + learnedSeqLength @23 :UInt32; + avgLearnedSeqLength @24 :Float32; + maxAge @25 :UInt32; + verbosity @26 :UInt8; + maxSegmentsPerCell @27 :UInt32; + maxSynapsesPerSegment @28 :UInt32; + checkSynapseConsistency @29 :Bool; + + # Internal variables + resetCalled @30 :Bool; + + avgInputDensity @31 :Float32; + pamCounter @32 :UInt32; + + # The various inference and learning states + learnActiveStateT @33 :CStateProto; + learnActiveStateT1 @34 :CStateProto; + learnPredictedStateT @35 :CStateProto; + learnPredictedStateT1 @36 :CStateProto; + + cells @37 :List(CellProto); + segmentUpdates @38 :List(SegmentUpdateProto); +} diff --git a/src/nupic/proto/Segment.capnp b/src/nupic/proto/Segment.capnp new file mode 100644 index 0000000000..b6d5720662 --- /dev/null +++ b/src/nupic/proto/Segment.capnp @@ -0,0 +1,33 @@ +@0xf2eaadec04697984; + +# Next ID: 2 +struct InSynapseProto { + srcCellIdx @0 :UInt32; + permanence @1 :Float32; +} + +# Next ID: 9 +struct SegmentProto { + seqSegFlag @0 :Bool; + frequency @1 :Float32; + nConnected @2 :UInt32; + totalActivations @3 :UInt32; + positiveActivations @4 :UInt32; + lastActiveIteration @5 :UInt32; + lastPosDutyCycle @6 :Float32; + lastPosDutyCycleIteration @7 :UInt32; + synapses @8 :List(InSynapseProto); +} + +# Next ID: 5 +struct CStateProto { + version @0 :UInt16; + fMemoryAllocatedByPython @1 :Bool; + # length of list is stored as nCells in class + pData @2 :Data; + + # CStateIndexed additional variables. If not using CStateIndexed, these + # values should be ignored. + countOn @3 :UInt32; + cellsOn @4 :List(UInt32); +} diff --git a/src/nupic/proto/SegmentUpdate.capnp b/src/nupic/proto/SegmentUpdate.capnp new file mode 100644 index 0000000000..3a1ae7c5dc --- /dev/null +++ b/src/nupic/proto/SegmentUpdate.capnp @@ -0,0 +1,12 @@ +@0xe7a17ea776969175; + +# Next ID: 7 +struct SegmentUpdateProto { + sequenceSegment @0 :Bool; + cellIdx @1 :UInt32; + segIdx @2 :UInt32; + timestamp @3 :UInt32; + synapses @4 :List(UInt32); + phase1Flag @5 :Bool; + weaklyPredicting @6 :Bool; +} diff --git a/src/test/unit/algorithms/Cells4Test.cpp b/src/test/unit/algorithms/Cells4Test.cpp index 5cd2b0c93d..89e9ffee39 100644 --- a/src/test/unit/algorithms/Cells4Test.cpp +++ b/src/test/unit/algorithms/Cells4Test.cpp @@ -27,11 +27,15 @@ #include <set> #include <vector> +#include <capnp/message.h> +#include <capnp/serialize.h> +#include <kj/std/iostream.h> #include <gtest/gtest.h> #include <nupic/algorithms/Cells4.hpp> #include <nupic/algorithms/Segment.hpp> #include <nupic/math/ArrayAlgo.hpp> // is_in +#include <nupic/proto/Cells4.capnp.h> using namespace nupic::algorithms::Cells4; @@ -78,6 +82,44 @@ std::vector<UInt> _getOrderedSynapseIndexesForSrcCells(const Segment& segment, } +TEST(Cells4Test, capnpSerialization) +{ + Cells4 cells( + 10, 2, 1, 1, 1, 1, 0.5, 0.8, 1, 0.1, 0.1, 0, false, -1, true, false); + std::vector<Real> input(10, 0.0); + input[1] = 1.0; + input[4] = 1.0; + input[5] = 1.0; + input[9] = 1.0; + std::vector<Real> output(10*2); + cells.compute(&input.front(), &output.front(), true, true); + + Cells4 secondCells( + 10, 2, 1, 1, 1, 1, 0.5, 0.8, 1, 0.1, 0.1, 0, false, -1, true, false); + { + capnp::MallocMessageBuilder message1; + Cells4Proto::Builder cells4Builder = message1.initRoot<Cells4Proto>(); + cells.write(cells4Builder); + std::stringstream ss; + kj::std::StdOutputStream out(ss); + capnp::writeMessage(out, message1); + + kj::std::StdInputStream in(ss); + capnp::InputStreamMessageReader message2(in); + Cells4Proto::Reader cells4Reader = message2.getRoot<Cells4Proto>(); + secondCells.read(cells4Reader); + } + + std::vector<Real> secondOutput(10*2); + cells.compute(&input.front(), &output.front(), true, true); + secondCells.compute(&input.front(), &secondOutput.front(), true, true); + for (UInt i = 0; i < 10; ++i) + { + ASSERT_EQ(output[i], secondOutput[i]) << "Outputs differ at index " << i; + } +} + + /* * Test Cells4::_generateListsOfSynapsesToAdjustForAdaptSegment.