From 94fa2457fa29130c9c56bf9bba274d6f251f9662 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Wed, 10 Nov 2021 21:07:15 +0000 Subject: [PATCH 01/22] First attempts of following Jamie's recipe for adding $(addToPre,.) functionality. I completed steps up to and including the single-threaded backend. --- .../genn/genn/code_generator/groupMerged.h | 9 ++++ include/genn/genn/neuronGroup.h | 2 + include/genn/genn/synapseGroup.h | 14 +++++ .../backends/single_threaded_cpu/backend.cc | 11 ++-- .../genn/code_generator/generateRunner.cc | 6 +++ src/genn/genn/code_generator/groupMerged.cc | 32 +++++++++++ .../code_generator/neuronUpdateGroupMerged.cc | 11 ++++ src/genn/genn/neuronGroup.cc | 18 ++++++- src/genn/genn/synapseGroup.cc | 53 +++++++++++++++++++ 9 files changed, 152 insertions(+), 4 deletions(-) diff --git a/include/genn/genn/code_generator/groupMerged.h b/include/genn/genn/code_generator/groupMerged.h index 6a07f1d8f5..84f095ecd4 100644 --- a/include/genn/genn/code_generator/groupMerged.h +++ b/include/genn/genn/code_generator/groupMerged.h @@ -613,6 +613,9 @@ class GENN_EXPORT NeuronGroupMergedBase : public GroupMerged &getSortedArchetypeMergedInSyns() const { return m_SortedMergedInSyns.front(); } + //! Get sorted vectors of merged outgoing synapse groups with presynaptic output belonging to archetype group + const std::vector &getSortedArchetypeMergedPreOutputOutSyns() const { return m_SortedMergedPreOutputSyns.front(); } + //! Get sorted vectors of current sources belonging to archetype group const std::vector &getSortedArchetypeCurrentSources() const { return m_SortedCurrentSources.front(); } @@ -920,6 +923,7 @@ class GENN_EXPORT NeuronGroupMergedBase : public GroupMerged> m_SortedMergedInSyns; + std::vector> m_SortedMergedPreOutputOutSyns; std::vector> m_SortedCurrentSources; }; @@ -1077,6 +1081,11 @@ class GENN_EXPORT SynapseGroupMergedBase : public GroupMerged &getOutSyn() const{ return m_OutSyn; } const std::vector &getFusedWUPreOutSyn() const { return m_FusedWUPreOutSyn; } + const std::vector &getFusedPreOuptputOutSyn() const { return m_FusedPreOutputOutSyn; } //! Gets pointers to all current sources which provide input to this neuron group const std::vector &getCurrentSources() const { return m_CurrentSources; } @@ -297,6 +298,7 @@ class GENN_EXPORT NeuronGroup std::vector m_FusedPSMInSyn; std::vector m_FusedWUPostInSyn; std::vector m_FusedWUPreOutSyn; + std::vector m_FusedPreOutputOutSyn; std::set m_SpikeEventCondition; unsigned int m_NumDelaySlots; std::vector m_CurrentSources; diff --git a/include/genn/genn/synapseGroup.h b/include/genn/genn/synapseGroup.h index 9b159585fa..9dfb68c8ad 100644 --- a/include/genn/genn/synapseGroup.h +++ b/include/genn/genn/synapseGroup.h @@ -221,6 +221,10 @@ class GENN_EXPORT SynapseGroup //! Get name of neuron input variable postsynaptic model will target /*! This will either be 'Isyn' or the name of one of the postsynaptic neuron's additional input variables. */ const std::string &getPSTargetVar() const{ return m_PSTargetVar; } + + //! Get name of neuron input variable which a presynaptic output specified with $(addToPre) will target + /*! This will either be 'Isyn' or the name of one of the presynaptic neuron's additional input variables. */ + const std::string &getPreTargetVar() const{ return m_PreTargetVar; } //! Get location of sparse connectivity initialiser extra global parameter by name /*! This is only used by extra global parameters which are pointers*/ @@ -280,6 +284,7 @@ class GENN_EXPORT SynapseGroup void setFusedPSVarSuffix(const std::string &suffix){ m_FusedPSVarSuffix = suffix; } void setFusedWUPreVarSuffix(const std::string &suffix){ m_FusedWUPreVarSuffix = suffix; } void setFusedWUPostVarSuffix(const std::string &suffix){ m_FusedWUPostVarSuffix = suffix; } + void setFusedPreOutputSuffix(const std::string &suffix){ m_FusedPreOutputSuffix = suffix; } void initDerivedParams(double dt); @@ -301,6 +306,7 @@ class GENN_EXPORT SynapseGroup const std::string &getFusedPSVarSuffix() const{ return m_FusedPSVarSuffix; } const std::string &getFusedWUPreVarSuffix() const { return m_FusedWUPreVarSuffix; } const std::string &getFusedWUPostVarSuffix() const { return m_FusedWUPostVarSuffix; } + const std::string &getFusedPreOutputSuffix() const { return m_FusedPreOutputSuffix; } //! Are any of this synapse group's weight update model variables referenced by a custom update bool areWUVarReferencedByCustomUpdate() const { return m_WUVarReferencedByCustomUpdate; } @@ -500,7 +506,15 @@ class GENN_EXPORT SynapseGroup /*! This may not be the name of this synapse group if it has been fused */ std::string m_FusedWUPostVarSuffix; + //! Suffix for weight update model presynaptic output variable + /*! This may not be the name of this synapse group if it has been fused */ + std::string m_FusedPreOutputSuffix; + //! Name of neuron input variable postsynaptic model will target /*! This should either be 'Isyn' or the name of one of the postsynaptic neuron's additional input variables. */ std::string m_PSTargetVar; + + //! Name of neuron input variable a presynaptic output specified with $(addToPre) will target + /*! This will either be 'Isyn' or the name of one of the presynaptic neuron's additional input variables. */ + std::string m_PreTargetVar; }; diff --git a/src/genn/backends/single_threaded_cpu/backend.cc b/src/genn/backends/single_threaded_cpu/backend.cc index 038bfe41c0..c740931d15 100644 --- a/src/genn/backends/single_threaded_cpu/backend.cc +++ b/src/genn/backends/single_threaded_cpu/backend.cc @@ -342,6 +342,8 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + s.getPostISynIndex(1, "j") + "] += $(0)"); } + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, "i") + "] += $(0)"); + // Call synapse dynamics handler s.generateSynapseUpdate(*this, os, modelMerged, synSubs); } @@ -367,12 +369,12 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge // generate the code for processing spike-like events if (s.getArchetype().isSpikeEventRequired()) { - genPresynapticUpdate(os, modelMerged, s, funcSubs, false); + genPresynapticUpdate(os, modelMerged, s, synSubs, false); } // generate the code for processing true spike events if (s.getArchetype().isTrueSpikeRequired()) { - genPresynapticUpdate(os, modelMerged, s, funcSubs, true); + genPresynapticUpdate(os, modelMerged, s, synSubs, true); } os << std::endl; } @@ -435,7 +437,8 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addVarSubstitution("id_syn", "((group->numTrgNeurons * i) + spike)"); } synSubs.addVarSubstitution("id_post", "spike"); - + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, "i") + "] += $(0)"); + s.generateSynapseUpdate(*this, os, modelMerged, synSubs); } } @@ -1453,6 +1456,8 @@ void Backend::genPresynapticUpdate(CodeStream &os, const ModelSpecMerged &modelM synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + sg.getPostISynIndex(1, "ipost") + "] += $(0)"); } + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, "ipre") + "] += $(0)"); + if (sg.getArchetype().getMatrixType() & SynapseMatrixConnectivity::SPARSE) { os << "const unsigned int npost = group->rowLength[ipre];" << std::endl; os << "for (unsigned int j = 0; j < npost; j++)"; diff --git a/src/genn/genn/code_generator/generateRunner.cc b/src/genn/genn/code_generator/generateRunner.cc index 573361fcda..39252fa305 100644 --- a/src/genn/genn/code_generator/generateRunner.cc +++ b/src/genn/genn/code_generator/generateRunner.cc @@ -1152,6 +1152,12 @@ MemAlloc CodeGenerator::generateRunner(const filesystem::path &outputPath, const } } } + // Loop through fused outgoing synapse populations with weightupdate models that have presynaptic output + for(const auto *sg : n.second.getFusedPreOuptputOutSyn()) { + backend.genArray(definitionsVar, definitionsInternalVar, runnerVarDecl, runnerVarAlloc, runnerVarFree, + model.getPrecision(), "revInSyn" + sg->getFusedPreOutputSuffix(), sg->getInSynLocation(), + sg->getSrcNeuronGroup()->getNumNeurons() * batchSize, mem); + } // Loop through merged postsynaptic weight updates of incoming synaptic populations for(const auto *sg: n.second.getFusedWUPreOutSyn()) { diff --git a/src/genn/genn/code_generator/groupMerged.cc b/src/genn/genn/code_generator/groupMerged.cc index 0727062320..0e354bfc08 100644 --- a/src/genn/genn/code_generator/groupMerged.cc +++ b/src/genn/genn/code_generator/groupMerged.cc @@ -194,6 +194,10 @@ NeuronGroupMergedBase::NeuronGroupMergedBase(size_t index, const std::string &pr orderNeuronGroupChildren(m_SortedMergedInSyns, &NeuronGroupInternal::getFusedPSMInSyn, init ? &SynapseGroupInternal::getPSInitHashDigest : &SynapseGroupInternal::getPSHashDigest); + // Build vector of vectors containing each child group's merged out syns with pre output, ordered to match those of the archetype group + orderNeuronGroupChildren(m_SortedMergedPreOutputOutSyns, &NeuronGroupInternal::getFusedPreOuptputOutSyn, + &SynapseGroupInternal::getPreOutputHashDigest); + // Build vector of vectors containing each child group's current sources, ordered to match those of the archetype group orderNeuronGroupChildren(m_SortedCurrentSources, &NeuronGroupInternal::getCurrentSources, init ? &CurrentSourceInternal::getInitHashDigest : &CurrentSourceInternal::getHashDigest); @@ -356,6 +360,14 @@ NeuronGroupMergedBase::NeuronGroupMergedBase(size_t index, const std::string &pr } } + // Loop through merged output synapses with presynaptic output of archetypical neuron group (0) in sorted order + for(size_t i = 0; i < getSortedArchetypeMergedPreOutputOutSyns().size(); i++) { + const SynapseGroupInternal *sg = getSortedArchetypeMergedPreOutputOutSyns().at(i); + + // Add pointer to revInSyn + addMergedPreOutputOutSynPointerField(precision, "revInSynOutSyn", i, backend.getDeviceVarPrefix() + "revInSyn"); + } + // Loop through current sources to archetypical neuron group in sorted order for(size_t i = 0; i < getSortedArchetypeCurrentSources().size(); i++) { const auto *cs = getSortedArchetypeCurrentSources().at(i); @@ -575,6 +587,17 @@ void NeuronGroupMergedBase::addMergedInSynPointerField(const std::string &type, return prefix + m_SortedMergedInSyns.at(groupIndex).at(archetypeIndex)->getFusedPSVarSuffix(); }); } +//---------------------------------------------------------------------------- +void NeuronGroupMergedBase::addMergedPreOutputOutSynPointerField(const std::string &type, const std::string &name, + size_t archetypeIndex, const std::string &prefix) +{ + assert(!Utils::isTypePointer(type)); + addField(type + "*", name + std::to_string(archetypeIndex), + [prefix, archetypeIndex, this](const NeuronGroupInternal &, size_t groupIndex) + { + return prefix + m_SortedMergedPreOutputOutSyns.at(groupIndex).at(archetypeIndex)->getFusedPreOutputSuffix(); + }); +} //---------------------------------------------------------------------------- @@ -871,6 +894,9 @@ SynapseGroupMergedBase::SynapseGroupMergedBase(size_t index, const std::string & else { addPSPointerField(precision, "inSyn", backend.getDeviceVarPrefix() + "inSyn"); } + if(getArchetype().isPresynapticOutputRequired()) { + addPreOutputPointerField(precision, "revInSyn", backend.getDeviceVarPrefix() + "revInSyn"); + } } if(role == Role::PresynapticUpdate) { @@ -1253,6 +1279,12 @@ void SynapseGroupMergedBase::addPSPointerField(const std::string &type, const st addField(type + "*", name, [prefix](const SynapseGroupInternal &sg, size_t) { return prefix + sg.getFusedPSVarSuffix(); }); } //---------------------------------------------------------------------------- +void SynapseGroupMergedBase::addPreOutputPointerField(const std::string &type, const std::string &name, const std::string &prefix) +{ + assert(!Utils::isTypePointer(type)); + addField(type + "*", name, [prefix](const SynapseGroupInternal &sg, size_t) { return prefix + sg.getFusedPreOutputSuffix(); }); +} +//---------------------------------------------------------------------------- void SynapseGroupMergedBase::addSrcPointerField(const std::string &type, const std::string &name, const std::string &prefix) { assert(!Utils::isTypePointer(type)); diff --git a/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc b/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc index 74f88a2fae..7cfccb1520 100644 --- a/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc +++ b/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc @@ -350,6 +350,17 @@ void NeuronUpdateGroupMerged::generateNeuronUpdate(const BackendBase &backend, C } } + // Loop through outgoing synapse groups with presynaptic output + for(size_t i = 0; i < getSortedArchetypeMergedPreOutputOutSyns().size(); i++) { + CodeStream::Scope b(os); + + os << sg->getPreOutputTargetVar() << "+= "; + os << "group->revInSynOutSyn" << i << "["; + os << getVarIndex(batchSize, VarAccessDuplication::DUPLICATE, popSubs["id"]) << "];" << std::endl; + os << "group->revInSynOutSyn" << i << "["; + os << getVarIndex(batchSize, VarAccessDuplication::DUPLICATE, popSubs["id"]) << "]= 0.0;" << std::endl; + } + // Loop through all of neuron group's current sources for(size_t i = 0; i < getSortedArchetypeCurrentSources().size(); i++) { const auto *cs = getSortedArchetypeCurrentSources().at(i); diff --git a/src/genn/genn/neuronGroup.cc b/src/genn/genn/neuronGroup.cc index f50fed4641..8a399acee6 100644 --- a/src/genn/genn/neuronGroup.cc +++ b/src/genn/genn/neuronGroup.cc @@ -379,7 +379,7 @@ void NeuronGroup::fusePrePostSynapses(bool fusePSM, bool fusePrePostWUM) } } - // Copy groups with some form of postsynaptic update into new vector + // Copy groups with some form of presynaptic update into new vector std::vector outSynWithPreUpdate; std::copy_if(getOutSyn().cbegin(), getOutSyn().cend(), std::back_inserter(outSynWithPreUpdate), [](SynapseGroupInternal *sg) @@ -395,6 +395,22 @@ void NeuronGroup::fusePrePostSynapses(bool fusePSM, bool fusePrePostWUM) &SynapseGroupInternal::canWUMPreUpdateBeFused, &SynapseGroupInternal::getWUPreFuseHashDigest, &SynapseGroupInternal::setFusedWUPreVarSuffix); } + + // Copy groups with output onto the presynaptic neuron into new vector + std::vector outSynWithPreOutput; + std::copy_if(getOutSyn().cbegin(), getOutSyn().cend(), std::back_inserter(outSynWithPreOutput), + [](SynapseGroupInternal *sg) + { + return (sg->isPresynapticOutputRequired()); + }); + + // If there are any + if(!outSynWithPreOutput.empty()) { + fuseSynapseGroups(outSynWithPreOutput, fusePSM, m_FusedPreOutputOutSyn, "FusedPreOut", getName(), "presynaptic synapse output", + &SynapseGroupInternal::canPreOutputBeFused, &SynapseGroupInternal::getPreOutputHashDigest, + &SynapseGroupInternal::setFusedPreOutputSuffix); + } + } //---------------------------------------------------------------------------- std::vector NeuronGroup::getFusedInSynWithPostCode() const diff --git a/src/genn/genn/synapseGroup.cc b/src/genn/genn/synapseGroup.cc index f57e520e61..b21859db2e 100644 --- a/src/genn/genn/synapseGroup.cc +++ b/src/genn/genn/synapseGroup.cc @@ -90,6 +90,21 @@ void SynapseGroup::setPSTargetVar(const std::string &varName) } } //---------------------------------------------------------------------------- +void SynapseGroup::setPreTargetVar(const std::string &varName) +{ + // If varname is either 'ISyn' or name of a presynaptic neuron group additional input variable, store + const auto additionalInputVars = getSrcNeuronGroup()->getNeuronModel()->getAdditionalInputVars(); + if(varName == "Isyn" || + std::find_if(additionalInputVars.cbegin(), additionalInputVars.cend(), + [&varName](const Models::Base::ParamVal &v){ return (v.name == varName); }) != additionalInputVars.cend()) + { + m_PreTargetVar = varName; + } + else { + throw std::runtime_error("Presynaptic neuron group has no input variable '" + varName + "'"); + } +} +//---------------------------------------------------------------------------- void SynapseGroup::setPSExtraGlobalParamLocation(const std::string ¶mName, VarLocation loc) { const size_t extraGlobalParamIndex = getPSModel()->getExtraGlobalParamIndex(paramName); @@ -388,6 +403,30 @@ bool SynapseGroup::isDendriticDelayRequired() const return false; } //---------------------------------------------------------------------------- +bool SynapseGroup::isPresynapticOutputRequired() const +{ + // If addToPre function is used in sim_code, return true + if(getWUModel()->getSimCode().find("$(addToPre") != std::string::npos) { + return true; + } + + // If addToPre function is used in learn_post_code, return true + if(getWUModel()->getLearnPostCode().find("$(addToPre") != std::string::npos) { + return true; + } + + // If addToPre function is used in event_code, return true + if(getWUModel()->getEventCode().find("$(addToPre") != std::string::npos) { + return true; + } + + // If addToPre function is used in synapse_dynamics, return true + if(getWUModel()->getSynapseDynamicsCode().find("$(addToPre") != std::string::npos) { + return true; + } + +} +//---------------------------------------------------------------------------- bool SynapseGroup::isProceduralConnectivityRNGRequired() const { return ((m_MatrixType & SynapseMatrixConnectivity::PROCEDURAL) && @@ -676,6 +715,12 @@ bool SynapseGroup::canWUMPostUpdateBeFused() const return true; } //---------------------------------------------------------------------------- +bool SynapseGroup::canPreOutputBeFused() const +{ + // There are no variables or other non-constant objects, so these can presumably always be fused + return true; +} +//---------------------------------------------------------------------------- boost::uuids::detail::sha1::digest_type SynapseGroup::getWUHashDigest() const { boost::uuids::detail::sha1 hash; @@ -744,6 +789,14 @@ boost::uuids::detail::sha1::digest_type SynapseGroup::getPSFuseHashDigest() cons return hash.get_digest(); } //---------------------------------------------------------------------------- +boost::uuids::detail::sha1::digest_type SynapseGroup::getPreOutputHashDigest() const +{ + boost::uuids::detail::sha1 hash; + Utils::updateHash(isPresynapticOutputRequired(), hash); + Utils::updateHash(getPreTargetVar(), hash); + return hash.get_digest(); +} +//---------------------------------------------------------------------------- boost::uuids::detail::sha1::digest_type SynapseGroup::getWUPreFuseHashDigest() const { boost::uuids::detail::sha1 hash; From 4f03d72bf7a30609e1941a57e21b0016af2b23ef Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Thu, 11 Nov 2021 20:09:46 +0000 Subject: [PATCH 02/22] Added a first simple test and removed compilation errors that occurred when the model generator was compiled. Model generator crashes with segmentation fault. --- .../genn/genn/code_generator/groupMerged.h | 6 ++- include/genn/genn/neuronGroupInternal.h | 1 + include/genn/genn/synapseGroup.h | 14 ++++++ include/genn/genn/synapseGroupInternal.h | 4 ++ .../backends/single_threaded_cpu/backend.cc | 12 +++--- src/genn/genn/code_generator/backendSIMT.cc | 12 +++++- .../code_generator/neuronUpdateGroupMerged.cc | 5 ++- .../presynapticUpdateStrategySIMT.cc | 43 ++++++++++++++++++- src/genn/genn/synapseGroup.cc | 2 +- 9 files changed, 87 insertions(+), 12 deletions(-) diff --git a/include/genn/genn/code_generator/groupMerged.h b/include/genn/genn/code_generator/groupMerged.h index 84f095ecd4..09bd76ca87 100644 --- a/include/genn/genn/code_generator/groupMerged.h +++ b/include/genn/genn/code_generator/groupMerged.h @@ -614,7 +614,7 @@ class GENN_EXPORT NeuronGroupMergedBase : public GroupMerged &getSortedArchetypeMergedInSyns() const { return m_SortedMergedInSyns.front(); } //! Get sorted vectors of merged outgoing synapse groups with presynaptic output belonging to archetype group - const std::vector &getSortedArchetypeMergedPreOutputOutSyns() const { return m_SortedMergedPreOutputSyns.front(); } + const std::vector &getSortedArchetypeMergedPreOutputOutSyns() const { return m_SortedMergedPreOutputOutSyns.front(); } //! Get sorted vectors of current sources belonging to archetype group const std::vector &getSortedArchetypeCurrentSources() const { return m_SortedCurrentSources.front(); } @@ -917,6 +917,9 @@ class GENN_EXPORT NeuronGroupMergedBase : public GroupMergedinSyn[" + s.getPostISynIndex(1, "j") + "] += $(0)"); } - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, "i") + "] += $(0)"); + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); // Call synapse dynamics handler s.generateSynapseUpdate(*this, os, modelMerged, synSubs); @@ -366,15 +366,15 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge os << "const auto *group = &mergedPresynapticUpdateGroup" << s.getIndex() << "[g]; " << std::endl; genSynapseIndexCalculation(os, s, 1); - + // generate the code for processing spike-like events if (s.getArchetype().isSpikeEventRequired()) { - genPresynapticUpdate(os, modelMerged, s, synSubs, false); + genPresynapticUpdate(os, modelMerged, s, funcSubs, false); } // generate the code for processing true spike events if (s.getArchetype().isTrueSpikeRequired()) { - genPresynapticUpdate(os, modelMerged, s, synSubs, true); + genPresynapticUpdate(os, modelMerged, s, funcSubs, true); } os << std::endl; } @@ -437,7 +437,7 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addVarSubstitution("id_syn", "((group->numTrgNeurons * i) + spike)"); } synSubs.addVarSubstitution("id_post", "spike"); - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, "i") + "] += $(0)"); + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); s.generateSynapseUpdate(*this, os, modelMerged, synSubs); } @@ -1456,7 +1456,7 @@ void Backend::genPresynapticUpdate(CodeStream &os, const ModelSpecMerged &modelM synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + sg.getPostISynIndex(1, "ipost") + "] += $(0)"); } - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, "ipre") + "] += $(0)"); + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + sg.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); if (sg.getArchetype().getMatrixType() & SynapseMatrixConnectivity::SPARSE) { os << "const unsigned int npost = group->rowLength[ipre];" << std::endl; diff --git a/src/genn/genn/code_generator/backendSIMT.cc b/src/genn/genn/code_generator/backendSIMT.cc index f9b579ca99..f035caf79d 100644 --- a/src/genn/genn/code_generator/backendSIMT.cc +++ b/src/genn/genn/code_generator/backendSIMT.cc @@ -737,6 +737,11 @@ void BackendSIMT::genPostsynapticUpdateKernel(CodeStream &os, const Substitution synSubs.addVarSubstitution("id_post", "shSpk[j]"); synSubs.addVarSubstitution("id_syn", "synAddress"); + if(sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, + getAtomic(modelMerged.getModel().getPrecision()) + "(&group->revInSyn[" + sg.getPreISynIndex(batchSize, synSubs["id_pre"]) + "], $(0))"); + } + sg.generateSynapseUpdate(*this, os, modelMerged, synSubs); if (sg.getArchetype().getMatrixType() & SynapseMatrixConnectivity::SPARSE) { @@ -797,7 +802,12 @@ void BackendSIMT::genSynapseDynamicsKernel(CodeStream &os, const Substitutions & else { synSubs.addFuncSubstitution("addToInSyn", 1, getAtomic(modelMerged.getModel().getPrecision()) + "(&group->inSyn[" + sg.getPostISynIndex(batchSize, synSubs["id_post"]) + "], $(0))"); } - + + if(sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, + getAtomic(modelMerged.getModel().getPrecision()) + "(&group->revInSyn[" + sg.getPreISynIndex(batchSize, synSubs["id_pre"]) + "], $(0))"); + } + sg.generateSynapseUpdate(*this, os, modelMerged, synSubs); } }); diff --git a/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc b/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc index 7cfccb1520..5ad3cc207c 100644 --- a/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc +++ b/src/genn/genn/code_generator/neuronUpdateGroupMerged.cc @@ -353,8 +353,9 @@ void NeuronUpdateGroupMerged::generateNeuronUpdate(const BackendBase &backend, C // Loop through outgoing synapse groups with presynaptic output for(size_t i = 0; i < getSortedArchetypeMergedPreOutputOutSyns().size(); i++) { CodeStream::Scope b(os); - - os << sg->getPreOutputTargetVar() << "+= "; + const auto *sg = getSortedArchetypeMergedPreOutputOutSyns().at(i); + + os << sg->getPreTargetVar() << "+= "; os << "group->revInSynOutSyn" << i << "["; os << getVarIndex(batchSize, VarAccessDuplication::DUPLICATE, popSubs["id"]) << "];" << std::endl; os << "group->revInSynOutSyn" << i << "["; diff --git a/src/genn/genn/code_generator/presynapticUpdateStrategySIMT.cc b/src/genn/genn/code_generator/presynapticUpdateStrategySIMT.cc index 1ece4f2258..bda44e2fbe 100644 --- a/src/genn/genn/code_generator/presynapticUpdateStrategySIMT.cc +++ b/src/genn/genn/code_generator/presynapticUpdateStrategySIMT.cc @@ -102,6 +102,10 @@ void PreSpan::genUpdate(CodeStream &os, const ModelSpecMerged &modelMerged, cons os << "const unsigned int spike = " << popSubs["id"] << ";" << std::endl; } + if(sg.getArchetype().isPresynapticOutputRequired()) { + os << "scalar lrevInSyn= 0.0;" << std::endl; + } + os << "if (spike < group->srcSpkCnt" << eventSuffix << "[" << sg.getPreSlot(batchSize) << "])"; { CodeStream::Scope b(os); @@ -164,6 +168,10 @@ void PreSpan::genUpdate(CodeStream &os, const ModelSpecMerged &modelMerged, cons backend.getAtomic(model.getPrecision()) + "(&group->inSyn[" + sg.getPostISynIndex(batchSize, "ipost") + "], $(0))"); } + if(sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "lrevInSyn += $(0)"); + } + if(trueSpike) { sg.generateSpikeUpdate(backend, os, modelMerged, synSubs); } @@ -176,6 +184,13 @@ void PreSpan::genUpdate(CodeStream &os, const ModelSpecMerged &modelMerged, cons if(!trueSpike && sg.getArchetype().isEventThresholdReTestRequired()) { os << CodeStream::CB(130); } + + // Should this be in the Postamble? + if(sg.getArchetype().isPresynapticOutputRequired()) { + // write lrevInSyn to global memory if not 0 + os << "if(lrevInSyn != 0.0) " << backend.getAtomic(model.getPrecision()) + "(&group->revInSyn[" + sg.getPreISynIndex(batchSize, "preInd") + "], lrevInSyn);" << std::endl; + } + } } //---------------------------------------------------------------------------- @@ -351,6 +366,11 @@ void PostSpan::genUpdate(CodeStream &os, const ModelSpecMerged &modelMerged, con } } + if(sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, + backend.getAtomic(model.getPrecision()) + "(&group->revInSyn[" + sg.getPreISynIndex(batchSize, synSubs["id_pre"]) + "], $(0))"); + } + if(trueSpike) { sg.generateSpikeUpdate(backend, os, modelMerged, synSubs); } @@ -471,6 +491,10 @@ void PreSpanProcedural::genUpdate(CodeStream &os, const ModelSpecMerged &modelMe os << "const unsigned int spike = " << popSubs["id"] << ";" << std::endl; } + if(sg.getArchetype().isPresynapticOutputRequired()) { + os << "scalar lrevInSyn= 0.0;" << std::endl; + } + // If there is a spike for this thread to process os << "if (spike < group->srcSpkCnt" << eventSuffix << "[" << sg.getPreSlot(batchSize) << "])"; { @@ -562,7 +586,11 @@ void PreSpanProcedural::genUpdate(CodeStream &os, const ModelSpecMerged &modelMe presynapticUpdateSubs.addFuncSubstitution("addToInSyn", 1, backend.getAtomic(model.getPrecision()) + "(&group->inSyn[" + sg.getPostISynIndex(batchSize, "$(id_post)") + "], $(0))"); } - + + if(sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "lrevInSyn += $(0)"); + } + // Generate presynaptic simulation code into new stringstream-backed code stream std::ostringstream presynapticUpdateStream; CodeStream presynapticUpdate(presynapticUpdateStream); @@ -582,6 +610,13 @@ void PreSpanProcedural::genUpdate(CodeStream &os, const ModelSpecMerged &modelMe if(!trueSpike && sg.getArchetype().isEventThresholdReTestRequired()) { os << CodeStream::CB(130); } + + // Should this be in the Postamble? + if(sg.getArchetype().isPresynapticOutputRequired()) { + // write lrevInSyn to global memory if not 0 + os << "if(lrevInSyn != 0.0) " << backend.getAtomic(model.getPrecision()) + "(&group->revInSyn[" + sg.getPreISynIndex(batchSize, "preInd") + "], lrevInSyn);" << std::endl; + } + } } //---------------------------------------------------------------------------- @@ -717,6 +752,12 @@ void PostSpanBitmask::genUpdate(CodeStream &os, const ModelSpecMerged &modelMerg synSubs.addVarSubstitution("id_syn", "synAddress"); synSubs.addVarSubstitution("id_post", "ipost"); synSubs.addFuncSubstitution("addToInSyn", 1, "shLg[(ibit * " + std::to_string(blockSize) + ") + " + backend.getThreadID() + "] += $(0)"); + + if(sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, + backend.getAtomic(modelMerged.getModel().getPrecision()) + "(&group->revInSyn[" + sg.getPreISynIndex(batchSize, synSubs["id_pre"]) + "], $(0))"); + } + if(trueSpike) { sg.generateSpikeUpdate(backend, os, modelMerged, synSubs); } diff --git a/src/genn/genn/synapseGroup.cc b/src/genn/genn/synapseGroup.cc index b21859db2e..fd92abc343 100644 --- a/src/genn/genn/synapseGroup.cc +++ b/src/genn/genn/synapseGroup.cc @@ -511,7 +511,7 @@ SynapseGroup::SynapseGroup(const std::string &name, SynapseMatrixType matrixType m_PSVarLocation(psVarInitialisers.size(), defaultVarLocation), m_PSExtraGlobalParamLocation(ps->getExtraGlobalParams().size(), defaultExtraGlobalParamLocation), m_ConnectivityInitialiser(connectivityInitialiser), m_SparseConnectivityLocation(defaultSparseConnectivityLocation), m_ConnectivityExtraGlobalParamLocation(connectivityInitialiser.getSnippet()->getExtraGlobalParams().size(), defaultExtraGlobalParamLocation), - m_FusedPSVarSuffix(name), m_FusedWUPreVarSuffix(name), m_FusedWUPostVarSuffix(name), m_PSTargetVar("Isyn") + m_FusedPSVarSuffix(name), m_FusedWUPreVarSuffix(name), m_FusedWUPostVarSuffix(name), m_PSTargetVar("Isyn"), m_PreTargetVar("Isyn") { // Validate names Utils::validatePopName(name, "Synapse group"); From 4a08d8623cf65e3dea68bcd0d3e94f98b8172781 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Thu, 11 Nov 2021 20:49:37 +0000 Subject: [PATCH 03/22] looked at a warning but decided not to change. --- src/genn/genn/code_generator/backendSIMT.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/genn/genn/code_generator/backendSIMT.cc b/src/genn/genn/code_generator/backendSIMT.cc index f035caf79d..9a16a4b820 100644 --- a/src/genn/genn/code_generator/backendSIMT.cc +++ b/src/genn/genn/code_generator/backendSIMT.cc @@ -247,7 +247,7 @@ void BackendSIMT::genNeuronPrevSpikeTimeUpdateKernel(CodeStream &os, const Subst genParallelGroup( os, kernelSubs, modelMerged.getMergedNeuronPrevSpikeTimeUpdateGroups(), idStart, [this](const NeuronGroupInternal &ng) { return padKernelSize(ng.getNumNeurons(), KernelNeuronUpdate); }, - [batchSize, this](CodeStream &os, const NeuronPrevSpikeTimeUpdateGroupMerged &ng, Substitutions &popSubs) + [batchSize,this](CodeStream &os, const NeuronPrevSpikeTimeUpdateGroupMerged &ng, Substitutions &popSubs) { CodeStream::Scope b(os); From 4a8eec09661f56613332b0cfc7ed5ad8df5a74e7 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Thu, 11 Nov 2021 20:54:05 +0000 Subject: [PATCH 04/22] Added some source files that were missing in the commit. --- .../Makefile | 20 +++++ .../decode_matrix_cont_individualg_dense.sln | 30 +++++++ ...code_matrix_cont_individualg_dense.vcxproj | 63 ++++++++++++++ .../model.cc | 82 +++++++++++++++++++ .../runner_guid.txt | 1 + .../test.cc | 52 ++++++++++++ .../simulation_test_cont_decoder_matrix_inv.h | 52 ++++++++++++ 7 files changed, 300 insertions(+) create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/model.cc create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc create mode 100644 tests/utils/simulation_test_cont_decoder_matrix_inv.h diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile new file mode 100644 index 0000000000..e5f5dbbcad --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile @@ -0,0 +1,20 @@ +CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include +OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) +DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) + +ifeq ($(DARWIN),DARWIN) + CXXFLAGS +=-Wno-return-type-c-linkage +endif + +.PHONY: all clean generated_code + +all: test + +test: test.cc generated_code + $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) + +generated_code: + $(MAKE) -C $(SIM_CODE) + +clean: + @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln b/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln new file mode 100644 index 0000000000..57a2f8e625 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decode_matrix_cont_individualg_dense", "decode_matrix_cont_individualg_dense.vcxproj", "{877A923D-1B16-4442-8C27-B90276305D60}" + ProjectSection(ProjectDependencies) = postProject + {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F} = {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "decode_matrix_cont_individualg_dense_CODE\runner.vcxproj", "{6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {877A923D-1B16-4442-8C27-B90276305D60}.Debug|x64.ActiveCfg = Debug|x64 + {877A923D-1B16-4442-8C27-B90276305D60}.Debug|x64.Build.0 = Debug|x64 + {877A923D-1B16-4442-8C27-B90276305D60}.Release|x64.ActiveCfg = Release|x64 + {877A923D-1B16-4442-8C27-B90276305D60}.Release|x64.Build.0 = Release|x64 + {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Debug|x64.ActiveCfg = Debug|x64 + {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Debug|x64.Build.0 = Debug|x64 + {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Release|x64.ActiveCfg = Release|x64 + {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj b/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj new file mode 100644 index 0000000000..49ca23c269 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj @@ -0,0 +1,63 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {877A923D-1B16-4442-8C27-B90276305D60} + + + + + + + + + Application + true + $(DefaultPlatformToolset) + true + MultiByte + + + + + + + + + + ./ + $(Platform)\$(Configuration)\ + test + + + + Level3 + MaxSpeed + Disabled + true + true + true + decode_matrix_cont_individualg_dense_CODE;$(GTEST_DIR);$(GTEST_DIR)/include + _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;%(PreprocessorDefinitions) + + + true + true + true + runner_Release.lib;%(AdditionalDependencies) + runner_Debug.lib;%(AdditionalDependencies) + + + + + + diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/model.cc b/tests/features/pre_output_decode_matrix_cont_individualg_dense/model.cc new file mode 100644 index 0000000000..f64d22d082 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/model.cc @@ -0,0 +1,82 @@ +//-------------------------------------------------------------------------- +/*! \file decode_matrix_cont_individualg_dense/model.cc + +\brief model definition file that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +#include "modelSpec.h" + +//---------------------------------------------------------------------------- +// PreNeuron +//---------------------------------------------------------------------------- +class PreNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PreNeuron, 0, 1); + + SET_SIM_CODE("$(x)= $(Isyn);\n"); + + SET_VARS({{"x", "scalar"}}); +}; + +IMPLEMENT_MODEL(PreNeuron); + +//---------------------------------------------------------------------------- +// PostNeuron +//---------------------------------------------------------------------------- +class PostNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PostNeuron, 0, 1); + + SET_VARS({{"x", "scalar"}}); +}; + +IMPLEMENT_MODEL(PostNeuron); + +//--------------------------------------------------------------------------- +// Continuous +//--------------------------------------------------------------------------- +class Continuous : public WeightUpdateModels::Base +{ +public: + DECLARE_MODEL(Continuous, 0, 1); + + SET_VARS({{"g", "scalar"}}); + + SET_SYNAPSE_DYNAMICS_CODE("$(addToPre, $(g) * $(x_post));\n"); +}; +IMPLEMENT_MODEL(Continuous); + + +void modelDefinition(ModelSpec &model) +{ +#ifdef CL_HPP_TARGET_OPENCL_VERSION + if(std::getenv("OPENCL_DEVICE") != nullptr) { + GENN_PREFERENCES.deviceSelectMethod = DeviceSelect::MANUAL; + GENN_PREFERENCES.manualDeviceID = std::atoi(std::getenv("OPENCL_DEVICE")); + } + if(std::getenv("OPENCL_PLATFORM") != nullptr) { + GENN_PREFERENCES.manualPlatformID = std::atoi(std::getenv("OPENCL_PLATFORM")); + } +#endif + model.setDT(0.1); + model.setName("pre_output_decode_matrix_cont_individualg_dense"); + + // Continuous synapse parameters + Continuous::VarValues staticSynapseInit(uninitialisedVar()); // 0 - Wij (nA) + + model.addNeuronPopulation("Pre", 4, {}, PreNeuron::VarValues(0.0)); + model.addNeuronPopulation("Post", 10, {}, PostNeuron::VarValues(0.0)); + + + model.addSynapsePopulation( + "Syn", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, "Pre", "Post", + {}, staticSynapseInit, + {}, {}); + + model.setPrecision(GENN_FLOAT); +} diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt b/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt new file mode 100644 index 0000000000..4e142050a9 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt @@ -0,0 +1 @@ +6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc new file mode 100644 index 0000000000..208cf76de6 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc @@ -0,0 +1,52 @@ +//-------------------------------------------------------------------------- +/*! \file decode_matrix_cont_individualg_dense/test.cc + +\brief Main test code that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +// Google test includes +#include "gtest/gtest.h" + +// Auto-generated simulation code includess +#include "decode_matrix_cont_individualg_dense_CODE/definitions.h" + +// **NOTE** base-class for simulation tests must be +// included after auto-generated globals are includes +#include "../../utils/simulation_test_cont_decoder_matrix_inv.h" + +//---------------------------------------------------------------------------- +// SimTest +//---------------------------------------------------------------------------- +class SimTest : public SimulationTestContDecoderMatrixInv +{ +public: + //---------------------------------------------------------------------------- + // SimulationTest virtuals + //---------------------------------------------------------------------------- + virtual void Init() + { + // Loop through presynaptic neurons + unsigned int c = 0; + for(unsigned int i = 0; i < 4; i++) + { + // Loop through postsynaptic neurons + for(unsigned int i = 0; i < 10; i++) + { + // Get value this pre synaptic neuron represents + const unsigned int i_value = (1 << i); + + // If this presynaptic neuron should be connected, add 1.0 otherwise 0.0 + gSyn[c++] = (((i + 1) & j_value) != 0) ? 1.0f : 0.0f; + } + } + } +}; + +TEST_F(SimTest, DecodeMatrixContIndividualgDense) +{ + // Check total error is less than some tolerance + EXPECT_TRUE(Simulate()); +} diff --git a/tests/utils/simulation_test_cont_decoder_matrix_inv.h b/tests/utils/simulation_test_cont_decoder_matrix_inv.h new file mode 100644 index 0000000000..c453a6f377 --- /dev/null +++ b/tests/utils/simulation_test_cont_decoder_matrix_inv.h @@ -0,0 +1,52 @@ +#pragma once + +// Standard C includes +#include + +// Test includes +#include "simulation_test.h" + +//---------------------------------------------------------------------------- +// SimulationTestContDecoderMatrixInv +//---------------------------------------------------------------------------- +class SimulationTestContDecoderMatrixInv : public SimulationTest +{ +public: + //---------------------------------------------------------------------------- + // Public API + //---------------------------------------------------------------------------- + bool Simulate() + { + for (int i = 0; i < 100; i++) { + // What value should neurons be representing this time step? + const unsigned int inValue = (i % 10) + 1; + + // Activate this neuron + // **NOTE** neurons start from zero + for(unsigned int j = 0; j < 10; j++) { + xPost[j] = (j == (inValue - 1)) ? 1.0f : 0.0f; + } + + pushPostStateToDevice(); + + // Step GeNN + StepGeNN(); + + // Loop through output neurons + unsigned int outValue = 0; + for(unsigned int j = 0; j < 4; j++) { + // If this neuron is representing 1 add value it represents to output + if(std::fabs(xPre[j] - 1.0f) < 1E-5) { + outValue += (1 << j); + } + } + + // If input value isn't correctly decoded, return false + if(outValue != inValue) { + return false; + } + } + + return true; + } +}; From 71e9d44f516c98b9802bc5764c87db7a1f175f8f Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Thu, 11 Nov 2021 21:36:45 +0000 Subject: [PATCH 05/22] Added a few forgotten checks for whether pre-synaptic output was required. --- .../backends/single_threaded_cpu/backend.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/genn/backends/single_threaded_cpu/backend.cc b/src/genn/backends/single_threaded_cpu/backend.cc index 0a2c90200d..caa8dc4981 100644 --- a/src/genn/backends/single_threaded_cpu/backend.cc +++ b/src/genn/backends/single_threaded_cpu/backend.cc @@ -342,8 +342,9 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + s.getPostISynIndex(1, "j") + "] += $(0)"); } - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); - + if(s.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); + } // Call synapse dynamics handler s.generateSynapseUpdate(*this, os, modelMerged, synSubs); } @@ -437,8 +438,10 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addVarSubstitution("id_syn", "((group->numTrgNeurons * i) + spike)"); } synSubs.addVarSubstitution("id_post", "spike"); - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); - + if (s.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); + } + s.generateSynapseUpdate(*this, os, modelMerged, synSubs); } } @@ -1456,8 +1459,10 @@ void Backend::genPresynapticUpdate(CodeStream &os, const ModelSpecMerged &modelM synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + sg.getPostISynIndex(1, "ipost") + "] += $(0)"); } - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + sg.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); - + if (sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + sg.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); + } + if (sg.getArchetype().getMatrixType() & SynapseMatrixConnectivity::SPARSE) { os << "const unsigned int npost = group->rowLength[ipre];" << std::endl; os << "for (unsigned int j = 0; j < npost; j++)"; From 071f784fa79ca6412218964e3cee78f371f95d06 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Thu, 11 Nov 2021 21:44:59 +0000 Subject: [PATCH 06/22] Added missing default return value - duh! --- src/genn/genn/synapseGroup.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/genn/genn/synapseGroup.cc b/src/genn/genn/synapseGroup.cc index fd92abc343..235fe17b90 100644 --- a/src/genn/genn/synapseGroup.cc +++ b/src/genn/genn/synapseGroup.cc @@ -424,7 +424,8 @@ bool SynapseGroup::isPresynapticOutputRequired() const if(getWUModel()->getSynapseDynamicsCode().find("$(addToPre") != std::string::npos) { return true; } - + + return false; } //---------------------------------------------------------------------------- bool SynapseGroup::isProceduralConnectivityRNGRequired() const From f358bcf13bfaf58d8d93c7ed5cabc7da2850ee23 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Fri, 12 Nov 2021 09:38:01 +0000 Subject: [PATCH 07/22] Corrected the test - must have been tired last night! --- .../pre_output_decode_matrix_cont_individualg_dense/test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc index 208cf76de6..1b6976ed8d 100644 --- a/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc @@ -11,7 +11,7 @@ suite of minimal models with known analytic outcomes that are used for continuou #include "gtest/gtest.h" // Auto-generated simulation code includess -#include "decode_matrix_cont_individualg_dense_CODE/definitions.h" +#include "pre_output_decode_matrix_cont_individualg_dense_CODE/definitions.h" // **NOTE** base-class for simulation tests must be // included after auto-generated globals are includes @@ -33,13 +33,13 @@ class SimTest : public SimulationTestContDecoderMatrixInv for(unsigned int i = 0; i < 4; i++) { // Loop through postsynaptic neurons - for(unsigned int i = 0; i < 10; i++) + for(unsigned int j = 0; j < 10; j++) { // Get value this pre synaptic neuron represents const unsigned int i_value = (1 << i); // If this presynaptic neuron should be connected, add 1.0 otherwise 0.0 - gSyn[c++] = (((i + 1) & j_value) != 0) ? 1.0f : 0.0f; + gSyn[c++] = (((j + 1) & i_value) != 0) ? 1.0f : 0.0f; } } } From a060ce8c8d2cd26fe4ea13517d5002decd7194da Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Fri, 12 Nov 2021 11:23:01 +0000 Subject: [PATCH 08/22] Added another test - fmod turned out to be a nightmare unsuitable for spike condition every 0.2 ms. --- .../Makefile | 20 +++++ .../model.cc | 86 +++++++++++++++++++ .../test.cc | 52 +++++++++++ .../simulation_test_decoder_matrix_inv.h | 59 +++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 tests/features/pre_output_decode_matrix_individualg_dense/Makefile create mode 100644 tests/features/pre_output_decode_matrix_individualg_dense/model.cc create mode 100644 tests/features/pre_output_decode_matrix_individualg_dense/test.cc create mode 100644 tests/utils/simulation_test_decoder_matrix_inv.h diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_individualg_dense/Makefile new file mode 100644 index 0000000000..e5f5dbbcad --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/Makefile @@ -0,0 +1,20 @@ +CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include +OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) +DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) + +ifeq ($(DARWIN),DARWIN) + CXXFLAGS +=-Wno-return-type-c-linkage +endif + +.PHONY: all clean generated_code + +all: test + +test: test.cc generated_code + $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) + +generated_code: + $(MAKE) -C $(SIM_CODE) + +clean: + @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/model.cc b/tests/features/pre_output_decode_matrix_individualg_dense/model.cc new file mode 100644 index 0000000000..b6a0b0bd36 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/model.cc @@ -0,0 +1,86 @@ +//-------------------------------------------------------------------------- +/*! \file decode_matrix_individualg_dense/model.cc + +\brief model definition file that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +#include "modelSpec.h" + +//---------------------------------------------------------------------------- +// PreNeuron +//---------------------------------------------------------------------------- +class PreNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PreNeuron, 0, 1); + + SET_SIM_CODE("$(x)= $(Isyn);\n"); + + SET_VARS({{"x", "scalar"}}); + + SET_THRESHOLD_CONDITION_CODE("std::fabs($(t)/0.2f - (int) ($(t)/0.2f)) < 1e-5"); + + SET_NEEDS_AUTO_REFRACTORY(false); +}; + +IMPLEMENT_MODEL(PreNeuron); + +//---------------------------------------------------------------------------- +// PostNeuron +//---------------------------------------------------------------------------- +class PostNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PostNeuron, 0, 1); + + SET_VARS({{"x", "scalar"}}); +}; + +IMPLEMENT_MODEL(PostNeuron); + +//--------------------------------------------------------------------------- +// Synapse +//--------------------------------------------------------------------------- +class Synapse : public WeightUpdateModels::Base +{ +public: + DECLARE_MODEL(Synapse, 0, 1); + + SET_VARS({{"g", "scalar"}}); + + SET_SIM_CODE("$(addToPre, $(g) * $(x_post));\n"); +}; +IMPLEMENT_MODEL(Synapse); + + +void modelDefinition(ModelSpec &model) +{ +#ifdef CL_HPP_TARGET_OPENCL_VERSION + if(std::getenv("OPENCL_DEVICE") != nullptr) { + GENN_PREFERENCES.deviceSelectMethod = DeviceSelect::MANUAL; + GENN_PREFERENCES.manualDeviceID = std::atoi(std::getenv("OPENCL_DEVICE")); + } + if(std::getenv("OPENCL_PLATFORM") != nullptr) { + GENN_PREFERENCES.manualPlatformID = std::atoi(std::getenv("OPENCL_PLATFORM")); + } +#endif + model.setDT(0.1); + model.setName("pre_output_decode_matrix_individualg_dense"); + + // synapse parameters + Synapse::VarValues staticSynapseInit(uninitialisedVar()); // 0 - Wij (nA) + + model.addNeuronPopulation("Pre", 4, {}, PreNeuron::VarValues(0.0)); + model.addNeuronPopulation("Post", 10, {}, PostNeuron::VarValues(0.0)); + + + model.addSynapsePopulation( + "Syn", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, "Pre", "Post", + {}, staticSynapseInit, + {}, {}); + + model.setPrecision(GENN_FLOAT); +} diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_individualg_dense/test.cc new file mode 100644 index 0000000000..d1f1284bea --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/test.cc @@ -0,0 +1,52 @@ +//-------------------------------------------------------------------------- +/*! \file decode_matrix_cont_individualg_dense/test.cc + +\brief Main test code that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +// Google test includes +#include "gtest/gtest.h" + +// Auto-generated simulation code includess +#include "pre_output_decode_matrix_individualg_dense_CODE/definitions.h" + +// **NOTE** base-class for simulation tests must be +// included after auto-generated globals are includes +#include "../../utils/simulation_test_decoder_matrix_inv.h" + +//---------------------------------------------------------------------------- +// SimTest +//---------------------------------------------------------------------------- +class SimTest : public SimulationTestContDecoderMatrixInv +{ +public: + //---------------------------------------------------------------------------- + // SimulationTest virtuals + //---------------------------------------------------------------------------- + virtual void Init() + { + // Loop through presynaptic neurons + unsigned int c = 0; + for(unsigned int i = 0; i < 4; i++) + { + // Loop through postsynaptic neurons + for(unsigned int j = 0; j < 10; j++) + { + // Get value this pre synaptic neuron represents + const unsigned int i_value = (1 << i); + + // If this presynaptic neuron should be connected, add 1.0 otherwise 0.0 + gSyn[c++] = (((j + 1) & i_value) != 0) ? 1.0f : 0.0f; + } + } + } +}; + +TEST_F(SimTest, DecodeMatrixContIndividualgDense) +{ + // Check total error is less than some tolerance + EXPECT_TRUE(Simulate()); +} diff --git a/tests/utils/simulation_test_decoder_matrix_inv.h b/tests/utils/simulation_test_decoder_matrix_inv.h new file mode 100644 index 0000000000..165e4c1502 --- /dev/null +++ b/tests/utils/simulation_test_decoder_matrix_inv.h @@ -0,0 +1,59 @@ +#pragma once + +// Standard C includes +#include + +// Test includes +#include "simulation_test.h" + +//---------------------------------------------------------------------------- +// SimulationTestContDecoderMatrixInv +//---------------------------------------------------------------------------- +class SimulationTestContDecoderMatrixInv : public SimulationTest +{ +public: + //---------------------------------------------------------------------------- + // Public API + //---------------------------------------------------------------------------- + bool Simulate() + { + for (int i = 0; i < 100; i++) { + // What value should neurons be representing this time step? + const unsigned int inValue = (i % 10) + 1; + + // Activate this neuron + // **NOTE** neurons start from zero + for(unsigned int j = 0; j < 10; j++) { + xPost[j] = (j == (inValue - 1)) ? 1.0f : 0.0f; + } + + pushPostStateToDevice(); + + // Step GeNN + StepGeNN(); + + // Loop through output neurons + unsigned int outValue = 0; + for(unsigned int j = 0; j < 4; j++) { + // If this neuron is representing 1 add value it represents to output + if(std::fabs(xPre[j] - 1.0f) < 1E-5) { + outValue += (1 << j); + } + } + pullPreCurrentSpikesFromDevice(); + if (std::fabs(t/0.2f - (int) (t/0.2f)) < 1e-5) { + // If input value isn't correctly decoded, return false + if(outValue != inValue) { + return false; + } + } + else { + if(fabs(outValue) > 1e-5) { + return false; + } + } + } + + return true; + } +}; From b4b3ba2bad91f4544b7bb030de8684a704703634 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Fri, 12 Nov 2021 11:29:35 +0000 Subject: [PATCH 09/22] Removing invalid Windows bits. --- .../decode_matrix_cont_individualg_dense.sln | 30 --------- ...code_matrix_cont_individualg_dense.vcxproj | 63 ------------------- .../runner_guid.txt | 1 - 3 files changed, 94 deletions(-) delete mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln delete mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj delete mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln b/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln deleted file mode 100644 index 57a2f8e625..0000000000 --- a/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.sln +++ /dev/null @@ -1,30 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decode_matrix_cont_individualg_dense", "decode_matrix_cont_individualg_dense.vcxproj", "{877A923D-1B16-4442-8C27-B90276305D60}" - ProjectSection(ProjectDependencies) = postProject - {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F} = {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "decode_matrix_cont_individualg_dense_CODE\runner.vcxproj", "{6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {877A923D-1B16-4442-8C27-B90276305D60}.Debug|x64.ActiveCfg = Debug|x64 - {877A923D-1B16-4442-8C27-B90276305D60}.Debug|x64.Build.0 = Debug|x64 - {877A923D-1B16-4442-8C27-B90276305D60}.Release|x64.ActiveCfg = Release|x64 - {877A923D-1B16-4442-8C27-B90276305D60}.Release|x64.Build.0 = Release|x64 - {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Debug|x64.ActiveCfg = Debug|x64 - {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Debug|x64.Build.0 = Debug|x64 - {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Release|x64.ActiveCfg = Release|x64 - {6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj b/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj deleted file mode 100644 index 49ca23c269..0000000000 --- a/tests/features/pre_output_decode_matrix_cont_individualg_dense/decode_matrix_cont_individualg_dense.vcxproj +++ /dev/null @@ -1,63 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {877A923D-1B16-4442-8C27-B90276305D60} - - - - - - - - - Application - true - $(DefaultPlatformToolset) - true - MultiByte - - - - - - - - - - ./ - $(Platform)\$(Configuration)\ - test - - - - Level3 - MaxSpeed - Disabled - true - true - true - decode_matrix_cont_individualg_dense_CODE;$(GTEST_DIR);$(GTEST_DIR)/include - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;%(PreprocessorDefinitions) - - - true - true - true - runner_Release.lib;%(AdditionalDependencies) - runner_Debug.lib;%(AdditionalDependencies) - - - - - - diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt b/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt deleted file mode 100644 index 4e142050a9..0000000000 --- a/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt +++ /dev/null @@ -1 +0,0 @@ -6E1E0B66-1EE0-4AF1-8150-69F23B07DF9F From 8296da799256b2b61f4df4cf808b44e85bfc1d3c Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Fri, 12 Nov 2021 17:37:54 +0000 Subject: [PATCH 10/22] Fixed test names and removed use of std namespace in genn code. --- .../pre_output_decode_matrix_cont_individualg_dense/test.cc | 2 +- .../pre_output_decode_matrix_individualg_dense/model.cc | 2 +- .../features/pre_output_decode_matrix_individualg_dense/test.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc index 1b6976ed8d..80c976d62f 100644 --- a/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/test.cc @@ -45,7 +45,7 @@ class SimTest : public SimulationTestContDecoderMatrixInv } }; -TEST_F(SimTest, DecodeMatrixContIndividualgDense) +TEST_F(SimTest, PreOutputDecodeMatrixContIndividualgDense) { // Check total error is less than some tolerance EXPECT_TRUE(Simulate()); diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/model.cc b/tests/features/pre_output_decode_matrix_individualg_dense/model.cc index b6a0b0bd36..7ec8e175a0 100644 --- a/tests/features/pre_output_decode_matrix_individualg_dense/model.cc +++ b/tests/features/pre_output_decode_matrix_individualg_dense/model.cc @@ -21,7 +21,7 @@ class PreNeuron : public NeuronModels::Base SET_VARS({{"x", "scalar"}}); - SET_THRESHOLD_CONDITION_CODE("std::fabs($(t)/0.2f - (int) ($(t)/0.2f)) < 1e-5"); + SET_THRESHOLD_CONDITION_CODE("fabs($(t)/0.2f - (int) ($(t)/0.2f)) < 1e-5"); SET_NEEDS_AUTO_REFRACTORY(false); }; diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_individualg_dense/test.cc index d1f1284bea..def13b148a 100644 --- a/tests/features/pre_output_decode_matrix_individualg_dense/test.cc +++ b/tests/features/pre_output_decode_matrix_individualg_dense/test.cc @@ -45,7 +45,7 @@ class SimTest : public SimulationTestContDecoderMatrixInv } }; -TEST_F(SimTest, DecodeMatrixContIndividualgDense) +TEST_F(SimTest, PreOutputDecodeMatrixIndividualgDense) { // Check total error is less than some tolerance EXPECT_TRUE(Simulate()); From 61eb47fda02fcdb5009abbc5abb91967e4ded8c1 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Fri, 12 Nov 2021 20:39:07 +0000 Subject: [PATCH 11/22] Added two more feature tests for event code and learn_post code. Fixed a bug where no pointer to revInSyn was added to merged group because it was in role Presynaptic and Dynamics only. Tydied some of the tests --- src/genn/genn/code_generator/groupMerged.cc | 7 +- .../Makefile | 20 +++++ .../model.cc | 86 ++++++++++++++++++ .../test.cc | 52 +++++++++++ .../test.cc | 2 +- .../Makefile | 20 +++++ .../model.cc | 87 +++++++++++++++++++ .../test.cc | 52 +++++++++++ .../simulation_test_decoder_matrix_inv.h | 4 +- 9 files changed, 324 insertions(+), 6 deletions(-) create mode 100644 tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile create mode 100644 tests/features/pre_output_decode_matrix_event_individualg_dense/model.cc create mode 100644 tests/features/pre_output_decode_matrix_event_individualg_dense/test.cc create mode 100644 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile create mode 100644 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/model.cc create mode 100644 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/test.cc diff --git a/src/genn/genn/code_generator/groupMerged.cc b/src/genn/genn/code_generator/groupMerged.cc index 0e354bfc08..c104846d18 100644 --- a/src/genn/genn/code_generator/groupMerged.cc +++ b/src/genn/genn/code_generator/groupMerged.cc @@ -894,9 +894,10 @@ SynapseGroupMergedBase::SynapseGroupMergedBase(size_t index, const std::string & else { addPSPointerField(precision, "inSyn", backend.getDeviceVarPrefix() + "inSyn"); } - if(getArchetype().isPresynapticOutputRequired()) { - addPreOutputPointerField(precision, "revInSyn", backend.getDeviceVarPrefix() + "revInSyn"); - } + } + // for all types of roles + if(getArchetype().isPresynapticOutputRequired()) { + addPreOutputPointerField(precision, "revInSyn", backend.getDeviceVarPrefix() + "revInSyn"); } if(role == Role::PresynapticUpdate) { diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile new file mode 100644 index 0000000000..e5f5dbbcad --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile @@ -0,0 +1,20 @@ +CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include +OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) +DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) + +ifeq ($(DARWIN),DARWIN) + CXXFLAGS +=-Wno-return-type-c-linkage +endif + +.PHONY: all clean generated_code + +all: test + +test: test.cc generated_code + $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) + +generated_code: + $(MAKE) -C $(SIM_CODE) + +clean: + @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/model.cc b/tests/features/pre_output_decode_matrix_event_individualg_dense/model.cc new file mode 100644 index 0000000000..e5d3e78fd4 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/model.cc @@ -0,0 +1,86 @@ +//-------------------------------------------------------------------------- +/*! \file decode_matrix_event_individualg_dense/model.cc + +\brief model definition file that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +#include "modelSpec.h" + +//---------------------------------------------------------------------------- +// PreNeuron +//---------------------------------------------------------------------------- +class PreNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PreNeuron, 0, 1); + + SET_SIM_CODE("$(x)= $(Isyn);\n"); + + SET_VARS({{"x", "scalar"}}); + + SET_NEEDS_AUTO_REFRACTORY(false); +}; + +IMPLEMENT_MODEL(PreNeuron); + +//---------------------------------------------------------------------------- +// PostNeuron +//---------------------------------------------------------------------------- +class PostNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PostNeuron, 0, 1); + + SET_VARS({{"x", "scalar"}}); +}; + +IMPLEMENT_MODEL(PostNeuron); + +//--------------------------------------------------------------------------- +// Synapse +//--------------------------------------------------------------------------- +class Synapse : public WeightUpdateModels::Base +{ +public: + DECLARE_MODEL(Synapse, 0, 1); + + SET_VARS({{"g", "scalar"}}); + + SET_EVENT_THRESHOLD_CONDITION_CODE("fabs($(t)/0.2f - (int) ($(t)/0.2f)) < 1e-5"); + + SET_EVENT_CODE("$(addToPre, $(g) * $(x_post));\n"); +}; +IMPLEMENT_MODEL(Synapse); + + +void modelDefinition(ModelSpec &model) +{ +#ifdef CL_HPP_TARGET_OPENCL_VERSION + if(std::getenv("OPENCL_DEVICE") != nullptr) { + GENN_PREFERENCES.deviceSelectMethod = DeviceSelect::MANUAL; + GENN_PREFERENCES.manualDeviceID = std::atoi(std::getenv("OPENCL_DEVICE")); + } + if(std::getenv("OPENCL_PLATFORM") != nullptr) { + GENN_PREFERENCES.manualPlatformID = std::atoi(std::getenv("OPENCL_PLATFORM")); + } +#endif + model.setDT(0.1); + model.setName("pre_output_decode_matrix_event_individualg_dense"); + + // synapse parameters + Synapse::VarValues staticSynapseInit(uninitialisedVar()); // 0 - Wij (nA) + + model.addNeuronPopulation("Pre", 4, {}, PreNeuron::VarValues(0.0)); + model.addNeuronPopulation("Post", 10, {}, PostNeuron::VarValues(0.0)); + + + model.addSynapsePopulation( + "Syn", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, "Pre", "Post", + {}, staticSynapseInit, + {}, {}); + + model.setPrecision(GENN_FLOAT); +} diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_event_individualg_dense/test.cc new file mode 100644 index 0000000000..2a322954bd --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/test.cc @@ -0,0 +1,52 @@ +//-------------------------------------------------------------------------- +/*! \file pre_output_decode_matrix_event_individualg_dense/test.cc + +\brief Main test code that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +// Google test includes +#include "gtest/gtest.h" + +// Auto-generated simulation code includess +#include "pre_output_decode_matrix_event_individualg_dense_CODE/definitions.h" + +// **NOTE** base-class for simulation tests must be +// included after auto-generated globals are includes +#include "../../utils/simulation_test_decoder_matrix_inv.h" + +//---------------------------------------------------------------------------- +// SimTest +//---------------------------------------------------------------------------- +class SimTest : public SimulationTestDecoderMatrixInv +{ +public: + //---------------------------------------------------------------------------- + // SimulationTest virtuals + //---------------------------------------------------------------------------- + virtual void Init() + { + // Loop through presynaptic neurons + unsigned int c = 0; + for(unsigned int i = 0; i < 4; i++) + { + // Loop through postsynaptic neurons + for(unsigned int j = 0; j < 10; j++) + { + // Get value this pre synaptic neuron represents + const unsigned int i_value = (1 << i); + + // If this presynaptic neuron should be connected, add 1.0 otherwise 0.0 + gSyn[c++] = (((j + 1) & i_value) != 0) ? 1.0f : 0.0f; + } + } + } +}; + +TEST_F(SimTest, PreOutputDecodeMatrixEventIndividualgDense) +{ + // Check total error is less than some tolerance + EXPECT_TRUE(Simulate()); +} diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_individualg_dense/test.cc index def13b148a..5e06dc063c 100644 --- a/tests/features/pre_output_decode_matrix_individualg_dense/test.cc +++ b/tests/features/pre_output_decode_matrix_individualg_dense/test.cc @@ -20,7 +20,7 @@ suite of minimal models with known analytic outcomes that are used for continuou //---------------------------------------------------------------------------- // SimTest //---------------------------------------------------------------------------- -class SimTest : public SimulationTestContDecoderMatrixInv +class SimTest : public SimulationTestDecoderMatrixInv { public: //---------------------------------------------------------------------------- diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile new file mode 100644 index 0000000000..e5f5dbbcad --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile @@ -0,0 +1,20 @@ +CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include +OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) +DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) + +ifeq ($(DARWIN),DARWIN) + CXXFLAGS +=-Wno-return-type-c-linkage +endif + +.PHONY: all clean generated_code + +all: test + +test: test.cc generated_code + $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) + +generated_code: + $(MAKE) -C $(SIM_CODE) + +clean: + @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/model.cc b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/model.cc new file mode 100644 index 0000000000..6183107e55 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/model.cc @@ -0,0 +1,87 @@ +//-------------------------------------------------------------------------- +/*! \file pre_output_decode_matrix_post_learn_individualg_dense/model.cc + +\brief model definition file that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +#include "modelSpec.h" + +//---------------------------------------------------------------------------- +// PreNeuron +//---------------------------------------------------------------------------- +class PreNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PreNeuron, 0, 1); + + SET_SIM_CODE("$(x)= $(Isyn);\n"); + + SET_VARS({{"x", "scalar"}}); + +}; + +IMPLEMENT_MODEL(PreNeuron); + +//---------------------------------------------------------------------------- +// PostNeuron +//---------------------------------------------------------------------------- +class PostNeuron : public NeuronModels::Base +{ +public: + DECLARE_MODEL(PostNeuron, 0, 1); + + SET_VARS({{"x", "scalar"}}); + + SET_THRESHOLD_CONDITION_CODE("fabs($(t)/0.2f - (int) ($(t)/0.2f)) < 1e-5"); + + SET_NEEDS_AUTO_REFRACTORY(false); +}; + +IMPLEMENT_MODEL(PostNeuron); + +//--------------------------------------------------------------------------- +// Synapse +//--------------------------------------------------------------------------- +class Synapse : public WeightUpdateModels::Base +{ +public: + DECLARE_MODEL(Synapse, 0, 1); + + SET_VARS({{"g", "scalar"}}); + + SET_LEARN_POST_CODE("$(addToPre, $(g) * $(x_post));\n"); +}; +IMPLEMENT_MODEL(Synapse); + + +void modelDefinition(ModelSpec &model) +{ +#ifdef CL_HPP_TARGET_OPENCL_VERSION + if(std::getenv("OPENCL_DEVICE") != nullptr) { + GENN_PREFERENCES.deviceSelectMethod = DeviceSelect::MANUAL; + GENN_PREFERENCES.manualDeviceID = std::atoi(std::getenv("OPENCL_DEVICE")); + } + if(std::getenv("OPENCL_PLATFORM") != nullptr) { + GENN_PREFERENCES.manualPlatformID = std::atoi(std::getenv("OPENCL_PLATFORM")); + } +#endif + model.setDT(0.1); + model.setName("pre_output_decode_matrix_post_learn_individualg_dense"); + + // synapse parameters + Synapse::VarValues staticSynapseInit(uninitialisedVar()); // 0 - Wij (nA) + + model.addNeuronPopulation("Pre", 4, {}, PreNeuron::VarValues(0.0)); + model.addNeuronPopulation("Post", 10, {}, PostNeuron::VarValues(0.0)); + + + model.addSynapsePopulation( + "Syn", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, "Pre", "Post", + {}, staticSynapseInit, + {}, {}); + + model.setPrecision(GENN_FLOAT); +} diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/test.cc b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/test.cc new file mode 100644 index 0000000000..f5cd7853c2 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/test.cc @@ -0,0 +1,52 @@ +//-------------------------------------------------------------------------- +/*! \file pre_output_decode_matrix_post_learn_individualg_dense/test.cc + +\brief Main test code that is part of the feature testing +suite of minimal models with known analytic outcomes that are used for continuous integration testing. +*/ +//-------------------------------------------------------------------------- + + +// Google test includes +#include "gtest/gtest.h" + +// Auto-generated simulation code includess +#include "pre_output_decode_matrix_post_learn_individualg_dense_CODE/definitions.h" + +// **NOTE** base-class for simulation tests must be +// included after auto-generated globals are includes +#include "../../utils/simulation_test_decoder_matrix_inv.h" + +//---------------------------------------------------------------------------- +// SimTest +//---------------------------------------------------------------------------- +class SimTest : public SimulationTestDecoderMatrixInv +{ +public: + //---------------------------------------------------------------------------- + // SimulationTest virtuals + //---------------------------------------------------------------------------- + virtual void Init() + { + // Loop through presynaptic neurons + unsigned int c = 0; + for(unsigned int i = 0; i < 4; i++) + { + // Loop through postsynaptic neurons + for(unsigned int j = 0; j < 10; j++) + { + // Get value this pre synaptic neuron represents + const unsigned int i_value = (1 << i); + + // If this presynaptic neuron should be connected, add 1.0 otherwise 0.0 + gSyn[c++] = (((j + 1) & i_value) != 0) ? 1.0f : 0.0f; + } + } + } +}; + +TEST_F(SimTest, PreOutputDecodeMatrixPostLearnIndividualgDense) +{ + // Check total error is less than some tolerance + EXPECT_TRUE(Simulate()); +} diff --git a/tests/utils/simulation_test_decoder_matrix_inv.h b/tests/utils/simulation_test_decoder_matrix_inv.h index 165e4c1502..8efedecbc6 100644 --- a/tests/utils/simulation_test_decoder_matrix_inv.h +++ b/tests/utils/simulation_test_decoder_matrix_inv.h @@ -7,9 +7,9 @@ #include "simulation_test.h" //---------------------------------------------------------------------------- -// SimulationTestContDecoderMatrixInv +// SimulationTestDecoderMatrixInv //---------------------------------------------------------------------------- -class SimulationTestContDecoderMatrixInv : public SimulationTest +class SimulationTestDecoderMatrixInv : public SimulationTest { public: //---------------------------------------------------------------------------- From 6c3c0b1357cb4b9b2e479202e74660a50c831fdd Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Tue, 16 Nov 2021 13:04:53 +0000 Subject: [PATCH 12/22] Added missing initialsation for revInSynOutSyn* variables. --- src/genn/genn/code_generator/groupMerged.cc | 2 -- src/genn/genn/code_generator/initGroupMerged.cc | 11 +++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/genn/genn/code_generator/groupMerged.cc b/src/genn/genn/code_generator/groupMerged.cc index c104846d18..1fa8186799 100644 --- a/src/genn/genn/code_generator/groupMerged.cc +++ b/src/genn/genn/code_generator/groupMerged.cc @@ -362,8 +362,6 @@ NeuronGroupMergedBase::NeuronGroupMergedBase(size_t index, const std::string &pr // Loop through merged output synapses with presynaptic output of archetypical neuron group (0) in sorted order for(size_t i = 0; i < getSortedArchetypeMergedPreOutputOutSyns().size(); i++) { - const SynapseGroupInternal *sg = getSortedArchetypeMergedPreOutputOutSyns().at(i); - // Add pointer to revInSyn addMergedPreOutputOutSynPointerField(precision, "revInSynOutSyn", i, backend.getDeviceVarPrefix() + "revInSyn"); } diff --git a/src/genn/genn/code_generator/initGroupMerged.cc b/src/genn/genn/code_generator/initGroupMerged.cc index 67935604ea..ba11bed221 100644 --- a/src/genn/genn/code_generator/initGroupMerged.cc +++ b/src/genn/genn/code_generator/initGroupMerged.cc @@ -383,6 +383,17 @@ void NeuronInitGroupMerged::generateInit(const BackendBase &backend, CodeStream [i, this](size_t v, size_t p) { return isOutSynWUMVarInitDerivedParamHeterogeneous(i, v, p); }); } + // Loop through outgoing synaptic populations with presynaptic output + for(size_t i = 0; i < getSortedArchetypeMergedPreOutputOutSyns().size(); i++) { + // If this synapse group's pre-synaptic input variable should be initialised on device + // Generate target-specific code to initialise variable + backend.genVariableInit(os, "group->numNeurons", "id", popSubs, + [&model, i] (CodeStream &os, Substitutions &varSubs) + { + os << "group->revInSynOutSyn" << i << "[" << varSubs["id"] << "] = " << model.scalarExpr(0.0) << ";" << std::endl; + }); + } + // Loop through current sources os << "// current source variables" << std::endl; for(size_t i = 0; i < getSortedArchetypeCurrentSources().size(); i++) { From f4d4445013689f951720920aa58c3d9e3e8c07d2 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Tue, 16 Nov 2021 13:36:07 +0000 Subject: [PATCH 13/22] Fixed a small issue where symlinks where left in /tmp if genn-buildmodel exited on an error --- bin/genn-buildmodel.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/genn-buildmodel.sh b/bin/genn-buildmodel.sh index d85614cce7..a8d75edf68 100755 --- a/bin/genn-buildmodel.sh +++ b/bin/genn-buildmodel.sh @@ -19,6 +19,8 @@ genn_help () { # handle script errors genn_error () { # $1=line, $2=code, $3=message echo "genn-buildmodel.sh:$1: error $2: $3" + rm $OUT_PATH + rm $MODEL_PATH exit "$2" } trap 'genn_error $LINENO 50 "command failure"' ERR From 9d2edaf89add3bd0a3e19b42fe154301c9e7a670 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 14:44:36 +0000 Subject: [PATCH 14/22] replace duplicate makefiles with symlinks --- .../Makefile | 21 +------------------ .../Makefile | 21 +------------------ .../Makefile | 21 +------------------ .../Makefile | 21 +------------------ 4 files changed, 4 insertions(+), 80 deletions(-) mode change 100644 => 120000 tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile mode change 100644 => 120000 tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile mode change 100644 => 120000 tests/features/pre_output_decode_matrix_individualg_dense/Makefile mode change 100644 => 120000 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile deleted file mode 100644 index e5f5dbbcad..0000000000 --- a/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include -OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) -DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) - -ifeq ($(DARWIN),DARWIN) - CXXFLAGS +=-Wno-return-type-c-linkage -endif - -.PHONY: all clean generated_code - -all: test - -test: test.cc generated_code - $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) - -generated_code: - $(MAKE) -C $(SIM_CODE) - -clean: - @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile new file mode 120000 index 0000000000..1302b13ca5 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/Makefile @@ -0,0 +1 @@ +../../utils/Makefile \ No newline at end of file diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile deleted file mode 100644 index e5f5dbbcad..0000000000 --- a/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include -OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) -DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) - -ifeq ($(DARWIN),DARWIN) - CXXFLAGS +=-Wno-return-type-c-linkage -endif - -.PHONY: all clean generated_code - -all: test - -test: test.cc generated_code - $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) - -generated_code: - $(MAKE) -C $(SIM_CODE) - -clean: - @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile new file mode 120000 index 0000000000..1302b13ca5 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/Makefile @@ -0,0 +1 @@ +../../utils/Makefile \ No newline at end of file diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_individualg_dense/Makefile deleted file mode 100644 index e5f5dbbcad..0000000000 --- a/tests/features/pre_output_decode_matrix_individualg_dense/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include -OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) -DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) - -ifeq ($(DARWIN),DARWIN) - CXXFLAGS +=-Wno-return-type-c-linkage -endif - -.PHONY: all clean generated_code - -all: test - -test: test.cc generated_code - $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) - -generated_code: - $(MAKE) -C $(SIM_CODE) - -clean: - @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_individualg_dense/Makefile new file mode 120000 index 0000000000..1302b13ca5 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/Makefile @@ -0,0 +1 @@ +../../utils/Makefile \ No newline at end of file diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile deleted file mode 100644 index e5f5dbbcad..0000000000 --- a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -CXXFLAGS +=-std=c++11 -Wall -Wpedantic -Wextra -I $(GTEST_DIR) -isystem $(GTEST_DIR)/include -OS_UPPER :=$(shell uname -s 2>/dev/null | tr [:lower:] [:upper:]) -DARWIN :=$(strip $(findstring DARWIN,$(OS_UPPER))) - -ifeq ($(DARWIN),DARWIN) - CXXFLAGS +=-Wno-return-type-c-linkage -endif - -.PHONY: all clean generated_code - -all: test - -test: test.cc generated_code - $(CXX) $(CXXFLAGS) test.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest_main.cc -o test -L$(SIM_CODE) -pthread -lrunner -Wl,-rpath $(SIM_CODE) - -generated_code: - $(MAKE) -C $(SIM_CODE) - -clean: - @rm -f test $(SIM_CODE)/librunner.so $(SIM_CODE)/*.o $(SIM_CODE)/*.d default.profraw diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile new file mode 120000 index 0000000000..1302b13ca5 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/Makefile @@ -0,0 +1 @@ +../../utils/Makefile \ No newline at end of file From f02ca8d0a084ce23f512f9c73776869db1e3b531 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 15:25:15 +0000 Subject: [PATCH 15/22] removed unnecessary hash element - this if this isn't the case, this hash is unused --- src/genn/genn/synapseGroup.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/genn/genn/synapseGroup.cc b/src/genn/genn/synapseGroup.cc index 235fe17b90..f0ffc06d0f 100644 --- a/src/genn/genn/synapseGroup.cc +++ b/src/genn/genn/synapseGroup.cc @@ -793,7 +793,6 @@ boost::uuids::detail::sha1::digest_type SynapseGroup::getPSFuseHashDigest() cons boost::uuids::detail::sha1::digest_type SynapseGroup::getPreOutputHashDigest() const { boost::uuids::detail::sha1 hash; - Utils::updateHash(isPresynapticOutputRequired(), hash); Utils::updateHash(getPreTargetVar(), hash); return hash.get_digest(); } From 2f082604f588d7273ad9126d4c95b24253e2b699 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 15:26:41 +0000 Subject: [PATCH 16/22] new unit test for fusing preUpdates --- tests/unit/neuronGroup.cc | 68 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/tests/unit/neuronGroup.cc b/tests/unit/neuronGroup.cc index eb9eb2220d..59539a425c 100644 --- a/tests/unit/neuronGroup.cc +++ b/tests/unit/neuronGroup.cc @@ -12,6 +12,19 @@ namespace { +class StaticPulseBack : public WeightUpdateModels::Base +{ +public: + DECLARE_WEIGHT_UPDATE_MODEL(StaticPulseBack, 0, 1, 0, 0); + + SET_VARS({{"g", "scalar", VarAccess::READ_ONLY}}); + + SET_SIM_CODE( + "$(addToInSyn, $(g));\n" + "$(addToPre, $(g));\n"); +}; +IMPLEMENT_MODEL(StaticPulseBack); + class WeightUpdateModelPost : public WeightUpdateModels::Base { public: @@ -249,7 +262,7 @@ TEST(NeuronGroup, Poisson) ASSERT_FALSE(ng->isInitRNGRequired()); } -TEST(NeuronGroup, MergeWUMPrePost) +TEST(NeuronGroup, FuseWUMPrePost) { ModelSpecInternal model; model.setFusePrePostWeightUpdateModels(true); @@ -370,7 +383,7 @@ TEST(NeuronGroup, MergeWUMPrePost) } -TEST(NeuronGroup, MergePSM) +TEST(NeuronGroup, FusePSM) { ModelSpecInternal model; model.setMergePostsynapticModels(true); @@ -444,6 +457,57 @@ TEST(NeuronGroup, MergePSM) ASSERT_NE(synInternal->getFusedPSVarSuffix(), synDelayInternal->getFusedPSVarSuffix()); } +TEST(NeuronGroup, FusePreOutput) +{ + ModelSpecInternal model; + model.setMergePostsynapticModels(true); + + LIFAdditional::ParamValues paramVals(0.25, 10.0, 0.0, 0.0, 20.0, 0.0, 5.0); + LIFAdditional::VarValues varVals(0.0, 0.0); + PostsynapticModels::ExpCurr::ParamValues psmParamVals(5.0); + PostsynapticModels::ExpCurr::ParamValues psmParamVals2(10.0); + StaticPulseBack::VarValues wumVarVals(0.1); + + // Add two neuron groups to model + model.addNeuronPopulation("Pre", 10, paramVals, varVals); + model.addNeuronPopulation("Post", 10, paramVals, varVals); + + // Create baseline synapse group + auto *syn = model.addSynapsePopulation( + "Syn", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, + "Pre", "Post", + {}, wumVarVals, + {}, {}); + + // Create second synapse group + auto *syn2 = model.addSynapsePopulation( + "Syn2", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, + "Pre", "Post", + {}, wumVarVals, + {}, {}); + + // Create synapse group with different target variable + auto *synTarget = model.addSynapsePopulation( + "SynTarget", SynapseMatrixType::DENSE_INDIVIDUALG, NO_DELAY, + "Pre", "Post", + {}, wumVarVals, + {}, {}); + synTarget->setPreTargetVar("Isyn2"); + + model.finalize(); + + // Cast synapse groups to internal types + auto synInternal = static_cast(syn); + auto syn2Internal = static_cast(syn2); + auto synTargetInternal = static_cast(synTarget); + + // Check that identically configured PSMs can be merged + ASSERT_EQ(synInternal->getFusedPreOutputSuffix(), syn2Internal->getFusedPreOutputSuffix()); + + // Check that PSMs targetting different variables cannot be merged + ASSERT_NE(synInternal->getFusedPreOutputSuffix(), synTargetInternal->getFusedPreOutputSuffix()); +} + TEST(NeuronGroup, CompareNeuronModels) { ModelSpecInternal model; From 32fc4d52b0a957ae9597d1d0c8f2e6fe0c8cbe71 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 15:41:42 +0000 Subject: [PATCH 17/22] fixed typo ``getFusedPreOuptputOutSyn`` to ``getFusedPreOutputOutSyn`` --- include/genn/genn/neuronGroup.h | 2 +- include/genn/genn/neuronGroupInternal.h | 2 +- src/genn/genn/code_generator/generateRunner.cc | 2 +- src/genn/genn/code_generator/groupMerged.cc | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/genn/genn/neuronGroup.h b/include/genn/genn/neuronGroup.h index b3096a809b..02a4795617 100644 --- a/include/genn/genn/neuronGroup.h +++ b/include/genn/genn/neuronGroup.h @@ -237,7 +237,7 @@ class GENN_EXPORT NeuronGroup const std::vector &getOutSyn() const{ return m_OutSyn; } const std::vector &getFusedWUPreOutSyn() const { return m_FusedWUPreOutSyn; } - const std::vector &getFusedPreOuptputOutSyn() const { return m_FusedPreOutputOutSyn; } + const std::vector &getFusedPreOutputOutSyn() const { return m_FusedPreOutputOutSyn; } //! Gets pointers to all current sources which provide input to this neuron group const std::vector &getCurrentSources() const { return m_CurrentSources; } diff --git a/include/genn/genn/neuronGroupInternal.h b/include/genn/genn/neuronGroupInternal.h index 68f3c1d3cc..8368670d4c 100644 --- a/include/genn/genn/neuronGroupInternal.h +++ b/include/genn/genn/neuronGroupInternal.h @@ -28,7 +28,7 @@ class NeuronGroupInternal : public NeuronGroup using NeuronGroup::injectCurrent; using NeuronGroup::getFusedPSMInSyn; using NeuronGroup::getFusedWUPostInSyn; - using NeuronGroup::getFusedPreOuptputOutSyn; + using NeuronGroup::getFusedPreOutputOutSyn; using NeuronGroup::getFusedWUPreOutSyn; using NeuronGroup::getOutSyn; using NeuronGroup::getCurrentSources; diff --git a/src/genn/genn/code_generator/generateRunner.cc b/src/genn/genn/code_generator/generateRunner.cc index 39252fa305..780634c2d7 100644 --- a/src/genn/genn/code_generator/generateRunner.cc +++ b/src/genn/genn/code_generator/generateRunner.cc @@ -1153,7 +1153,7 @@ MemAlloc CodeGenerator::generateRunner(const filesystem::path &outputPath, const } } // Loop through fused outgoing synapse populations with weightupdate models that have presynaptic output - for(const auto *sg : n.second.getFusedPreOuptputOutSyn()) { + for(const auto *sg : n.second.getFusedPreOutputOutSyn()) { backend.genArray(definitionsVar, definitionsInternalVar, runnerVarDecl, runnerVarAlloc, runnerVarFree, model.getPrecision(), "revInSyn" + sg->getFusedPreOutputSuffix(), sg->getInSynLocation(), sg->getSrcNeuronGroup()->getNumNeurons() * batchSize, mem); diff --git a/src/genn/genn/code_generator/groupMerged.cc b/src/genn/genn/code_generator/groupMerged.cc index 1fa8186799..3cb8588244 100644 --- a/src/genn/genn/code_generator/groupMerged.cc +++ b/src/genn/genn/code_generator/groupMerged.cc @@ -195,7 +195,8 @@ NeuronGroupMergedBase::NeuronGroupMergedBase(size_t index, const std::string &pr init ? &SynapseGroupInternal::getPSInitHashDigest : &SynapseGroupInternal::getPSHashDigest); // Build vector of vectors containing each child group's merged out syns with pre output, ordered to match those of the archetype group - orderNeuronGroupChildren(m_SortedMergedPreOutputOutSyns, &NeuronGroupInternal::getFusedPreOuptputOutSyn, + // **NOTE** this hash is only relevant for update, for init we don't care about target variables + orderNeuronGroupChildren(m_SortedMergedPreOutputOutSyns, &NeuronGroupInternal::getFusedPreOutputOutSyn, &SynapseGroupInternal::getPreOutputHashDigest); // Build vector of vectors containing each child group's current sources, ordered to match those of the archetype group From 4e4ee64080eb83222d73f55ed1984273a079507c Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 16:02:29 +0000 Subject: [PATCH 18/22] small hashing fixes * incorporate hashes of pre-output synapse groups in neuron group hashes * add a seperate (empty) hash for pre-output synapse group initialisation --- include/genn/genn/synapseGroup.h | 6 +++++- include/genn/genn/synapseGroupInternal.h | 1 + src/genn/genn/code_generator/groupMerged.cc | 3 +-- src/genn/genn/neuronGroup.cc | 17 +++++++++++------ src/genn/genn/synapseGroup.cc | 6 ++++++ 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/include/genn/genn/synapseGroup.h b/include/genn/genn/synapseGroup.h index 860e476fb0..3cde46256e 100644 --- a/include/genn/genn/synapseGroup.h +++ b/include/genn/genn/synapseGroup.h @@ -383,6 +383,10 @@ class GENN_EXPORT SynapseGroup /*! NOTE: this can only be called after model is finalized */ boost::uuids::detail::sha1::digest_type getPSInitHashDigest() const; + //! Generate hash of presynaptic output initialization component of this synapse group + /*! NOTE: this can only be called after model is finalized */ + boost::uuids::detail::sha1::digest_type getPreOutputInitHashDigest() const; + //! Generate hash of connectivity initialisation of this synapse group /*! NOTE: this can only be called after model is finalized */ boost::uuids::detail::sha1::digest_type getConnectivityInitHashDigest() const; @@ -390,7 +394,7 @@ class GENN_EXPORT SynapseGroup //! Generate hash of host connectivity initialisation of this synapse group /*! NOTE: this can only be called after model is finalized */ boost::uuids::detail::sha1::digest_type getConnectivityHostInitHashDigest() const; - + boost::uuids::detail::sha1::digest_type getVarLocationHashDigest() const; private: //------------------------------------------------------------------------ diff --git a/include/genn/genn/synapseGroupInternal.h b/include/genn/genn/synapseGroupInternal.h index ffa310db79..a13a31c393 100644 --- a/include/genn/genn/synapseGroupInternal.h +++ b/include/genn/genn/synapseGroupInternal.h @@ -62,6 +62,7 @@ class SynapseGroupInternal : public SynapseGroup using SynapseGroup::getWUPreInitHashDigest; using SynapseGroup::getWUPostInitHashDigest; using SynapseGroup::getPSInitHashDigest; + using SynapseGroup::getPreOutputInitHashDigest; using SynapseGroup::getConnectivityInitHashDigest; using SynapseGroup::getConnectivityHostInitHashDigest; using SynapseGroup::getVarLocationHashDigest; diff --git a/src/genn/genn/code_generator/groupMerged.cc b/src/genn/genn/code_generator/groupMerged.cc index 3cb8588244..5a6fec7c11 100644 --- a/src/genn/genn/code_generator/groupMerged.cc +++ b/src/genn/genn/code_generator/groupMerged.cc @@ -195,9 +195,8 @@ NeuronGroupMergedBase::NeuronGroupMergedBase(size_t index, const std::string &pr init ? &SynapseGroupInternal::getPSInitHashDigest : &SynapseGroupInternal::getPSHashDigest); // Build vector of vectors containing each child group's merged out syns with pre output, ordered to match those of the archetype group - // **NOTE** this hash is only relevant for update, for init we don't care about target variables orderNeuronGroupChildren(m_SortedMergedPreOutputOutSyns, &NeuronGroupInternal::getFusedPreOutputOutSyn, - &SynapseGroupInternal::getPreOutputHashDigest); + init ? &SynapseGroupInternal::getPreOutputInitHashDigest : &SynapseGroupInternal::getPreOutputHashDigest); // Build vector of vectors containing each child group's current sources, ordered to match those of the archetype group orderNeuronGroupChildren(m_SortedCurrentSources, &NeuronGroupInternal::getCurrentSources, diff --git a/src/genn/genn/neuronGroup.cc b/src/genn/genn/neuronGroup.cc index 8a399acee6..8788824ddc 100644 --- a/src/genn/genn/neuronGroup.cc +++ b/src/genn/genn/neuronGroup.cc @@ -499,15 +499,18 @@ boost::uuids::detail::sha1::digest_type NeuronGroup::getHashDigest() const // Update hash with hash list built from current sources updateHashList(getCurrentSources(), hash, &CurrentSourceInternal::getHashDigest); - // Update hash with hash list built from incoming synapse groups with post code + // Update hash with hash list built from fused incoming synapse groups with post code updateHashList(getFusedInSynWithPostCode(), hash, &SynapseGroupInternal::getWUPostHashDigest); - // Update hash with hash list built from outgoing synapse groups with pre code + // Update hash with hash list built from fused outgoing synapse groups with pre code updateHashList(getFusedOutSynWithPreCode(), hash, &SynapseGroupInternal::getWUPreHashDigest); - // Update hash with hash list built from merged incoming synapses + // Update hash with hash list built from fused incoming synapses updateHashList(getFusedPSMInSyn(), hash, &SynapseGroupInternal::getPSHashDigest); + // Update hash with hash list built from fused outgoing synapses with presynaptic output + updateHashList(getFusedPreOutputOutSyn(), hash, &SynapseGroupInternal::getPreOutputHashDigest); + return hash.get_digest(); } //---------------------------------------------------------------------------- @@ -530,15 +533,17 @@ boost::uuids::detail::sha1::digest_type NeuronGroup::getInitHashDigest() const // Update hash with hash list built from current sources updateHashList(getCurrentSources(), hash, &CurrentSourceInternal::getInitHashDigest); - // Update hash with hash list built from incoming synapse groups with post vars + // Update hash with hash list built from fused incoming synapse groups with post vars updateHashList(getFusedInSynWithPostVars(), hash, &SynapseGroupInternal::getWUPostInitHashDigest); - // Update hash with hash list built from outgoing synapse groups with pre vars + // Update hash with hash list built from fusedoutgoing synapse groups with pre vars updateHashList(getFusedOutSynWithPreVars(), hash, &SynapseGroupInternal::getWUPreInitHashDigest); - // Update hash with hash list built from merged incoming synapses + // Update hash with hash list built from fused incoming synapses updateHashList(getFusedPSMInSyn(), hash, &SynapseGroupInternal::getPSInitHashDigest); + // Update hash with hash list built from fused outgoing synapses with presynaptic output + updateHashList(getFusedPreOutputOutSyn(), hash, &SynapseGroupInternal::getPreOutputInitHashDigest); return hash.get_digest(); } //---------------------------------------------------------------------------- diff --git a/src/genn/genn/synapseGroup.cc b/src/genn/genn/synapseGroup.cc index f0ffc06d0f..833174eec9 100644 --- a/src/genn/genn/synapseGroup.cc +++ b/src/genn/genn/synapseGroup.cc @@ -941,6 +941,12 @@ boost::uuids::detail::sha1::digest_type SynapseGroup::getPSInitHashDigest() cons return hash.get_digest(); } //---------------------------------------------------------------------------- +boost::uuids::detail::sha1::digest_type SynapseGroup::getPreOutputInitHashDigest() const +{ + boost::uuids::detail::sha1 hash; + return hash.get_digest(); +} +//---------------------------------------------------------------------------- boost::uuids::detail::sha1::digest_type SynapseGroup::getConnectivityInitHashDigest() const { boost::uuids::detail::sha1 hash; From 0fb471e073661597fe57c679d83f4d03ad2e5505 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 16:02:42 +0000 Subject: [PATCH 19/22] unit test for merging related to pre-outputs --- tests/unit/neuronGroup.cc | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tests/unit/neuronGroup.cc b/tests/unit/neuronGroup.cc index 59539a425c..8aeab69c55 100644 --- a/tests/unit/neuronGroup.cc +++ b/tests/unit/neuronGroup.cc @@ -829,6 +829,89 @@ TEST(NeuronGroup, ComparePostsynapticModels) ASSERT_TRUE(deltaAlphaMergedInitGroup->isPSMVarInitParamHeterogeneous(alphaInitIndex, 0, 0)); } + +TEST(NeuronGroup, ComparePreOutput) +{ + ModelSpecInternal model; + + // Add two neuron groups to model + NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); + NeuronModels::Izhikevich::VarValues varVals(0.0, 0.0); + auto *ngPre0 = model.addNeuronPopulation("NeuronsPre0", 10, paramVals, varVals); + auto *ngPre1 = model.addNeuronPopulation("NeuronsPre1", 10, paramVals, varVals); + auto *ngPre2 = model.addNeuronPopulation("NeuronsPre2", 10, paramVals, varVals); + auto *ngPre3 = model.addNeuronPopulation("NeuronsPre3", 10, paramVals, varVals); + + model.addNeuronPopulation("NeuronsPost0", 10, paramVals, varVals); + model.addNeuronPopulation("NeuronsPost1", 10, paramVals, varVals); + model.addNeuronPopulation("NeuronsPost2", 10, paramVals, varVals); + + // Add two outgoing synapse groups to NeuronsPre0 + StaticPulseBack::VarValues staticPulseVarVals(0.1); + model.addSynapsePopulation("SG0", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre0", "NeuronsPost0", + {}, staticPulseVarVals, + {}, {}); + model.addSynapsePopulation("SG1", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre0", "NeuronsPost1", + {}, staticPulseVarVals, + {}, {}); + + // Do the same for NeuronsPre1 + model.addSynapsePopulation("SG2", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre1", "NeuronsPost0", + {}, staticPulseVarVals, + {}, {}); + model.addSynapsePopulation("SG3", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre1", "NeuronsPost1", + {}, staticPulseVarVals, + {}, {}); + + // Add three outgoing groups to NeuronPre2 + model.addSynapsePopulation("SG4", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre2", "NeuronsPost0", + {}, staticPulseVarVals, + {}, {}); + model.addSynapsePopulation("SG5", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre2", "NeuronsPost1", + {}, staticPulseVarVals, + {}, {}); + model.addSynapsePopulation("SG6", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre2", "NeuronsPost2", + {}, staticPulseVarVals, + {}, {}); + + // Add one outgoing groups to NeuronPre3 + model.addSynapsePopulation("SG7", SynapseMatrixType::SPARSE_GLOBALG_INDIVIDUAL_PSM, NO_DELAY, + "NeuronsPre3", "NeuronsPost0", + {}, staticPulseVarVals, + {}, {}); + + model.finalize(); + + NeuronGroupInternal *ngPre0Internal = static_cast(ngPre0); + NeuronGroupInternal *ngPre1Internal = static_cast(ngPre1); + NeuronGroupInternal *ngPre2Internal = static_cast(ngPre2); + NeuronGroupInternal *ngPre3Internal = static_cast(ngPre3); + ASSERT_EQ(ngPre0Internal->getHashDigest(), ngPre1Internal->getHashDigest()); + ASSERT_NE(ngPre0Internal->getHashDigest(), ngPre2Internal->getHashDigest()); + ASSERT_NE(ngPre0Internal->getHashDigest(), ngPre3Internal->getHashDigest()); + ASSERT_EQ(ngPre0Internal->getInitHashDigest(), ngPre1Internal->getInitHashDigest()); + ASSERT_NE(ngPre0Internal->getInitHashDigest(), ngPre2Internal->getInitHashDigest()); + ASSERT_NE(ngPre0Internal->getInitHashDigest(), ngPre3Internal->getInitHashDigest()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + // Check neurons are merged into six groups (one for each output group and one for each number of incoming synapses) + ASSERT_EQ(modelSpecMerged.getMergedNeuronUpdateGroups().size(), 6); + ASSERT_EQ(modelSpecMerged.getMergedNeuronInitGroups().size(), 6); +} + TEST(NeuronGroup, CompareWUPreUpdate) { ModelSpecInternal model; From 267b0de33096f6b94c6fb89c59fc459983263775 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Wed, 17 Nov 2021 16:23:57 +0000 Subject: [PATCH 20/22] replaced tabs with spaces --- .../backends/single_threaded_cpu/backend.cc | 18 +++++++++--------- src/genn/genn/code_generator/backendSIMT.cc | 4 ++-- .../genn/code_generator/initGroupMerged.cc | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/genn/backends/single_threaded_cpu/backend.cc b/src/genn/backends/single_threaded_cpu/backend.cc index caa8dc4981..8b37206710 100644 --- a/src/genn/backends/single_threaded_cpu/backend.cc +++ b/src/genn/backends/single_threaded_cpu/backend.cc @@ -342,8 +342,8 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + s.getPostISynIndex(1, "j") + "] += $(0)"); } - if(s.getArchetype().isPresynapticOutputRequired()) { - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); + if(s.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); } // Call synapse dynamics handler s.generateSynapseUpdate(*this, os, modelMerged, synSubs); @@ -438,10 +438,10 @@ void Backend::genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerge synSubs.addVarSubstitution("id_syn", "((group->numTrgNeurons * i) + spike)"); } synSubs.addVarSubstitution("id_post", "spike"); - if (s.getArchetype().isPresynapticOutputRequired()) { - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); + if (s.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + s.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); } - + s.generateSynapseUpdate(*this, os, modelMerged, synSubs); } } @@ -1459,10 +1459,10 @@ void Backend::genPresynapticUpdate(CodeStream &os, const ModelSpecMerged &modelM synSubs.addFuncSubstitution("addToInSyn", 1, "group->inSyn[" + sg.getPostISynIndex(1, "ipost") + "] += $(0)"); } - if (sg.getArchetype().isPresynapticOutputRequired()) { - synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + sg.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); - } - + if (sg.getArchetype().isPresynapticOutputRequired()) { + synSubs.addFuncSubstitution("addToPre", 1, "group->revInSyn[" + sg.getPreISynIndex(1, synSubs["id_pre"]) + "] += $(0)"); + } + if (sg.getArchetype().getMatrixType() & SynapseMatrixConnectivity::SPARSE) { os << "const unsigned int npost = group->rowLength[ipre];" << std::endl; os << "for (unsigned int j = 0; j < npost; j++)"; diff --git a/src/genn/genn/code_generator/backendSIMT.cc b/src/genn/genn/code_generator/backendSIMT.cc index 9a16a4b820..77b61bff69 100644 --- a/src/genn/genn/code_generator/backendSIMT.cc +++ b/src/genn/genn/code_generator/backendSIMT.cc @@ -186,9 +186,9 @@ size_t BackendSIMT::getPaddedNumCustomUpdateTransposeWUThreads(const CustomUpdat assert(cg.getSynapseGroup()->getMatrixType() & SynapseMatrixConnectivity::DENSE); const size_t paddedNumPre = padKernelSize(cg.getSynapseGroup()->getSrcNeuronGroup()->getNumNeurons(), KernelCustomTransposeUpdate); - const size_t paddedNumPost = padKernelSize(cg.getSynapseGroup()->getTrgNeuronGroup()->getNumNeurons(), KernelCustomTransposeUpdate); + const size_t paddedNumPost = padKernelSize(cg.getSynapseGroup()->getTrgNeuronGroup()->getNumNeurons(), KernelCustomTransposeUpdate); const size_t numCopies = cg.isBatched() ? batchSize : 1; - return numCopies * paddedNumPre * paddedNumPost / getKernelBlockSize(KernelCustomTransposeUpdate); + return numCopies * paddedNumPre * paddedNumPost / getKernelBlockSize(KernelCustomTransposeUpdate); } //-------------------------------------------------------------------------- size_t BackendSIMT::getNumPresynapticUpdateThreads(const SynapseGroupInternal &sg, const PreferencesBase &preferences) diff --git a/src/genn/genn/code_generator/initGroupMerged.cc b/src/genn/genn/code_generator/initGroupMerged.cc index ba11bed221..5872fe6461 100644 --- a/src/genn/genn/code_generator/initGroupMerged.cc +++ b/src/genn/genn/code_generator/initGroupMerged.cc @@ -385,9 +385,9 @@ void NeuronInitGroupMerged::generateInit(const BackendBase &backend, CodeStream // Loop through outgoing synaptic populations with presynaptic output for(size_t i = 0; i < getSortedArchetypeMergedPreOutputOutSyns().size(); i++) { - // If this synapse group's pre-synaptic input variable should be initialised on device - // Generate target-specific code to initialise variable - backend.genVariableInit(os, "group->numNeurons", "id", popSubs, + // If this synapse group's pre-synaptic input variable should be initialised + // on device, generate target-specific code to initialise variable + backend.genVariableInit(os, "group->numNeurons", "id", popSubs, [&model, i] (CodeStream &os, Substitutions &varSubs) { os << "group->revInSynOutSyn" << i << "[" << varSubs["id"] << "] = " << model.scalarExpr(0.0) << ";" << std::endl; From a26a0b174f6ad8529afb07d553747e4c6ea7f084 Mon Sep 17 00:00:00 2001 From: Thomas Nowotny Date: Wed, 17 Nov 2021 19:13:13 +0000 Subject: [PATCH 21/22] Added the pygenn handles to access setPreTargetVar. Added some basic documentation. I have briefly tested that the pygenn wrapper works for $(addToPre) and set_pre_target_var. This should now complete the $(addToPre) pull request. --- doxygen/10_UserManual.dox | 16 +++++++++++++++- makedoc.sh | 2 +- pygenn/genn_groups.py | 10 ++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/doxygen/10_UserManual.dox b/doxygen/10_UserManual.dox index ad9ac66d31..e01439184e 100644 --- a/doxygen/10_UserManual.dox +++ b/doxygen/10_UserManual.dox @@ -443,7 +443,7 @@ SET_SIM_CODE( \add_toggle_code_python sim_code="$(addToInSyn, $(inc));" \end_toggle_code -where "inc" is the increment of the synaptic input to a post-synaptic neuron for each pre-synaptic spike. The simulation code also typically contains updates to the internal synapse variables that may have contributed to $(inc). For an example, see WeightUpdateModels::StaticPulse for a simple synapse update model and WeightUpdateModels::PiecewiseSTDP for a more complicated model that uses STDP. +where "inc" is the increment of the synaptic input to a post-synaptic neuron for each pre-synaptic spike. The simulation code also typically contains updates to the internal synapse variables that may have contributed to \$(inc). For an example, see WeightUpdateModels::StaticPulse for a simple synapse update model and WeightUpdateModels::PiecewiseSTDP for a more complicated model that uses STDP. To apply input to the post-synaptic neuron with a dendritic (i.e. between the synapse and the postsynaptic neuron) delay you can instead use the \$(addToInSynDelay, weight, delay) function. For example \add_toggle_code_cpp @@ -457,6 +457,20 @@ where, once again, `inc` is the magnitude of the input step to apply and `delay` \note When using dendritic delays, the maximum dendritic delay for a synapse populations must be specified using the `SynapseGroup::setMaxDendriticDelayTimesteps()` function. +One can also define synaptic effects that occur in the reverse direction, i.e. terms that are added to a target variable in the persynaptic neuron using the \$(addToPre, expression) function. For instance, +\add_toggle_code_cpp +SET_SIM_CODE( + "$(addToPre, $(inc)*$(V_post));"); +\end_toggle_code +\add_toggle_code_python +sim_code="$(addToPre, $(inc)*$(V_post));" +\end_toggle_code +would add terms \$(inc)*\$(V_post) to the predefined presynaptic variable \$(Isyn) for each outgoing synapse of a presynaptic neuron. One can also set alternative input variables in the presynaptic neuron as the target variable of this reverse input using \add_cpp_python_text{SynapseGroup::setPreTargetVar(),`pygenn.SynapseGroup.pre_target_var`}, see section \ref neuron_additional_input on how to define additional input variables for a neuron population. +\note +\$(addToPre, expression) can be used in \add_cpp_python_text{SET_SIM_CODE(),`sim_code`}, \add_cpp_python_text{SET_EVENT_CODE(),`event_code`}, \add_cpp_python_text{SET_SYNAPSE_DYNAMICS_CODE(),`synapse_dynamics_code`}, \add_cpp_python_text{SET_LEARN_POST_CODE(),`learn_post_code`}. +\note +Unlike for normal forward synaptic actions, reverse synaptic actions with \$(addToPre,\$(inc)) are not modulated through a post-synaptic model but added directly into the indicated presynaptic target input variable, such as \$(Isyn). + - \add_cpp_python_text{SET_LEARN_POST_CODE(LEARN_POST_CODE),`learn_post_code=LEARN_POST_CODE`} defines the code which is used in the learnSynapsesPost kernel/function, which performs updates to synapses that are triggered by post-synaptic spikes. This is typically used in STDP-like models e.g. WeightUpdateModels::PiecewiseSTDP. - \add_cpp_python_text{SET_NEEDS_PRE_SPIKE_TIME(PRE_SPIKE_TIME_REQUIRED) and SET_NEEDS_POST_SPIKE_TIME(POST_SPIKE_TIME_REQUIRED),`is_pre_spike_time_required=PRE_SPIKE_TIME_REQUIRED` and `is_post_spike_time_required=POST_SPIKE_TIME_REQUIRED`} define whether the weight update needs to know the times of the spikes emitted from the pre and postsynaptic populations. These can then be accessed through \$(sT_pre) and \$(sT_post). For example an STDP rule would be likely to require: \add_toggle_code_cpp diff --git a/makedoc.sh b/makedoc.sh index a638f57e2b..98af7dee14 100755 --- a/makedoc.sh +++ b/makedoc.sh @@ -1,3 +1,3 @@ #! /bin/bash -export GENN_PATH=$(dirname $(realpath "$0")) +export GENN_PATH=/its/home/tn41/localdisk_projects/develop/genn (cat doxygen/genn-doxygen.conf ; echo "PROJECT_NUMBER=`cat version.txt`") | doxygen - diff --git a/pygenn/genn_groups.py b/pygenn/genn_groups.py index 3289af75bf..185f737319 100644 --- a/pygenn/genn_groups.py +++ b/pygenn/genn_groups.py @@ -918,6 +918,16 @@ def ps_target_var(self, var): """Sets name of neuron input variable postsynaptic model will target""" self.pop.set_pstarget_var(var) + @property + def pre_target_var(self): + """Gets name of neuron input variable $(addToPre) will target""" + return self.pop.get_pre_target_var() + + @pre_target_var.setter + def pre_target_var(self, var): + """Sets name of neuron input variable $(addToPre) will target""" + self.pop.set_pre_target_var(var) + def set_sparse_connections(self, pre_indices, post_indices): """Set ragged format connections between two groups of neurons From 9186f3e78685aa1687860a24d60138f1b8281e16 Mon Sep 17 00:00:00 2001 From: neworderofjamie Date: Thu, 18 Nov 2021 09:21:09 +0000 Subject: [PATCH 22/22] windows tests --- ...t_decode_matrix_cont_individualg_dense.sln | 30 +++++++++ ...code_matrix_cont_individualg_dense.vcxproj | 63 +++++++++++++++++++ .../runner_guid.txt | 1 + ..._decode_matrix_event_individualg_dense.sln | 30 +++++++++ ...ode_matrix_event_individualg_dense.vcxproj | 63 +++++++++++++++++++ .../runner_guid.txt | 1 + ...output_decode_matrix_individualg_dense.sln | 30 +++++++++ ...ut_decode_matrix_individualg_dense.vcxproj | 63 +++++++++++++++++++ .../runner_guid.txt | 1 + ...de_matrix_post_learn_individualg_dense.sln | 30 +++++++++ ...atrix_post_learn_individualg_dense.vcxproj | 63 +++++++++++++++++++ .../runner_guid.txt | 1 + 12 files changed, 376 insertions(+) create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.sln create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.vcxproj create mode 100644 tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt create mode 100644 tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.sln create mode 100644 tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.vcxproj create mode 100644 tests/features/pre_output_decode_matrix_event_individualg_dense/runner_guid.txt create mode 100644 tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.sln create mode 100644 tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.vcxproj create mode 100644 tests/features/pre_output_decode_matrix_individualg_dense/runner_guid.txt create mode 100644 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.sln create mode 100644 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.vcxproj create mode 100644 tests/features/pre_output_decode_matrix_post_learn_individualg_dense/runner_guid.txt diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.sln b/tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.sln new file mode 100644 index 0000000000..574fe0d43b --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pre_output_decode_matrix_cont_individualg_dense", "pre_output_decode_matrix_cont_individualg_dense.vcxproj", "{645D7257-7733-406C-818B-04DAD108F056}" + ProjectSection(ProjectDependencies) = postProject + {2A766C02-19A1-48BB-8321-8B2EF281AC92} = {2A766C02-19A1-48BB-8321-8B2EF281AC92} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "pre_output_decode_matrix_cont_individualg_dense_CODE\runner.vcxproj", "{2A766C02-19A1-48BB-8321-8B2EF281AC92}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {645D7257-7733-406C-818B-04DAD108F056}.Debug|x64.ActiveCfg = Debug|x64 + {645D7257-7733-406C-818B-04DAD108F056}.Debug|x64.Build.0 = Debug|x64 + {645D7257-7733-406C-818B-04DAD108F056}.Release|x64.ActiveCfg = Release|x64 + {645D7257-7733-406C-818B-04DAD108F056}.Release|x64.Build.0 = Release|x64 + {2A766C02-19A1-48BB-8321-8B2EF281AC92}.Debug|x64.ActiveCfg = Debug|x64 + {2A766C02-19A1-48BB-8321-8B2EF281AC92}.Debug|x64.Build.0 = Debug|x64 + {2A766C02-19A1-48BB-8321-8B2EF281AC92}.Release|x64.ActiveCfg = Release|x64 + {2A766C02-19A1-48BB-8321-8B2EF281AC92}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.vcxproj b/tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.vcxproj new file mode 100644 index 0000000000..88168ae87b --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/pre_output_decode_matrix_cont_individualg_dense.vcxproj @@ -0,0 +1,63 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {645D7257-7733-406C-818B-04DAD108F056} + + + + + + + + + Application + true + $(DefaultPlatformToolset) + true + MultiByte + + + + + + + + + + ./ + $(Platform)\$(Configuration)\ + test + + + + Level3 + MaxSpeed + Disabled + true + true + true + decode_matrix_cont_individualg_dense_CODE;$(GTEST_DIR);$(GTEST_DIR)/include + _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;%(PreprocessorDefinitions) + + + true + true + true + runner_Release.lib;%(AdditionalDependencies) + runner_Debug.lib;%(AdditionalDependencies) + + + + + + diff --git a/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt b/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt new file mode 100644 index 0000000000..d23b879da2 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_cont_individualg_dense/runner_guid.txt @@ -0,0 +1 @@ +2A766C02-19A1-48BB-8321-8B2EF281AC92 diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.sln b/tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.sln new file mode 100644 index 0000000000..55a5368337 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pre_output_decode_matrix_event_individualg_dense", "pre_output_decode_matrix_event_individualg_dense.vcxproj", "{0930A515-1317-450A-AA94-CED280C96D92}" + ProjectSection(ProjectDependencies) = postProject + {57342E02-3729-438F-8B26-D9EA28E889B5} = {57342E02-3729-438F-8B26-D9EA28E889B5} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "pre_output_decode_matrix_event_individualg_dense_CODE\runner.vcxproj", "{57342E02-3729-438F-8B26-D9EA28E889B5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0930A515-1317-450A-AA94-CED280C96D92}.Debug|x64.ActiveCfg = Debug|x64 + {0930A515-1317-450A-AA94-CED280C96D92}.Debug|x64.Build.0 = Debug|x64 + {0930A515-1317-450A-AA94-CED280C96D92}.Release|x64.ActiveCfg = Release|x64 + {0930A515-1317-450A-AA94-CED280C96D92}.Release|x64.Build.0 = Release|x64 + {57342E02-3729-438F-8B26-D9EA28E889B5}.Debug|x64.ActiveCfg = Debug|x64 + {57342E02-3729-438F-8B26-D9EA28E889B5}.Debug|x64.Build.0 = Debug|x64 + {57342E02-3729-438F-8B26-D9EA28E889B5}.Release|x64.ActiveCfg = Release|x64 + {57342E02-3729-438F-8B26-D9EA28E889B5}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.vcxproj b/tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.vcxproj new file mode 100644 index 0000000000..a359962242 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/pre_output_decode_matrix_event_individualg_dense.vcxproj @@ -0,0 +1,63 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {0930A515-1317-450A-AA94-CED280C96D92} + + + + + + + + + Application + true + $(DefaultPlatformToolset) + true + MultiByte + + + + + + + + + + ./ + $(Platform)\$(Configuration)\ + test + + + + Level3 + MaxSpeed + Disabled + true + true + true + pre_output_decode_matrix_event_individualg_dense_CODE;$(GTEST_DIR);$(GTEST_DIR)/include + _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;%(PreprocessorDefinitions) + + + true + true + true + runner_Release.lib;%(AdditionalDependencies) + runner_Debug.lib;%(AdditionalDependencies) + + + + + + diff --git a/tests/features/pre_output_decode_matrix_event_individualg_dense/runner_guid.txt b/tests/features/pre_output_decode_matrix_event_individualg_dense/runner_guid.txt new file mode 100644 index 0000000000..d90e7078ee --- /dev/null +++ b/tests/features/pre_output_decode_matrix_event_individualg_dense/runner_guid.txt @@ -0,0 +1 @@ +57342E02-3729-438F-8B26-D9EA28E889B5 diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.sln b/tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.sln new file mode 100644 index 0000000000..091eb25a48 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pre_output_decode_matrix_individualg_dense", "pre_output_decode_matrix_individualg_dense.vcxproj", "{58E1E70E-0479-49EB-B4C9-FEBE0DCDE54E}" + ProjectSection(ProjectDependencies) = postProject + {4AE5067A-9E20-411F-81EF-91B462C23A62} = {4AE5067A-9E20-411F-81EF-91B462C23A62} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "pre_output_decode_matrix_individualg_dense_CODE\runner.vcxproj", "{4AE5067A-9E20-411F-81EF-91B462C23A62}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {58E1E70E-0479-49EB-B4C9-FEBE0DCDE54E}.Debug|x64.ActiveCfg = Debug|x64 + {58E1E70E-0479-49EB-B4C9-FEBE0DCDE54E}.Debug|x64.Build.0 = Debug|x64 + {58E1E70E-0479-49EB-B4C9-FEBE0DCDE54E}.Release|x64.ActiveCfg = Release|x64 + {58E1E70E-0479-49EB-B4C9-FEBE0DCDE54E}.Release|x64.Build.0 = Release|x64 + {4AE5067A-9E20-411F-81EF-91B462C23A62}.Debug|x64.ActiveCfg = Debug|x64 + {4AE5067A-9E20-411F-81EF-91B462C23A62}.Debug|x64.Build.0 = Debug|x64 + {4AE5067A-9E20-411F-81EF-91B462C23A62}.Release|x64.ActiveCfg = Release|x64 + {4AE5067A-9E20-411F-81EF-91B462C23A62}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.vcxproj b/tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.vcxproj new file mode 100644 index 0000000000..c14d740770 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/pre_output_decode_matrix_individualg_dense.vcxproj @@ -0,0 +1,63 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {58E1E70E-0479-49EB-B4C9-FEBE0DCDE54E} + + + + + + + + + Application + true + $(DefaultPlatformToolset) + true + MultiByte + + + + + + + + + + ./ + $(Platform)\$(Configuration)\ + test + + + + Level3 + MaxSpeed + Disabled + true + true + true + pre_output_decode_matrix_individualg_dense_CODE;$(GTEST_DIR);$(GTEST_DIR)/include + _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;%(PreprocessorDefinitions) + + + true + true + true + runner_Release.lib;%(AdditionalDependencies) + runner_Debug.lib;%(AdditionalDependencies) + + + + + + diff --git a/tests/features/pre_output_decode_matrix_individualg_dense/runner_guid.txt b/tests/features/pre_output_decode_matrix_individualg_dense/runner_guid.txt new file mode 100644 index 0000000000..4d26c0f17c --- /dev/null +++ b/tests/features/pre_output_decode_matrix_individualg_dense/runner_guid.txt @@ -0,0 +1 @@ +4AE5067A-9E20-411F-81EF-91B462C23A62 diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.sln b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.sln new file mode 100644 index 0000000000..6a61b7d3de --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pre_output_decode_matrix_post_learn_individualg_dense", "pre_output_decode_matrix_post_learn_individualg_dense.vcxproj", "{43FFE605-6CE0-407A-A301-392210A4E20D}" + ProjectSection(ProjectDependencies) = postProject + {51307D3B-A9B2-4DF5-BE94-46D13DB2944} = {51307D3B-A9B2-4DF5-BE94-46D13DB2944} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "pre_output_decode_matrix_post_learn_individualg_dense_CODE\runner.vcxproj", "{51307D3B-A9B2-4DF5-BE94-46D13DB2944}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {43FFE605-6CE0-407A-A301-392210A4E20D}.Debug|x64.ActiveCfg = Debug|x64 + {43FFE605-6CE0-407A-A301-392210A4E20D}.Debug|x64.Build.0 = Debug|x64 + {43FFE605-6CE0-407A-A301-392210A4E20D}.Release|x64.ActiveCfg = Release|x64 + {43FFE605-6CE0-407A-A301-392210A4E20D}.Release|x64.Build.0 = Release|x64 + {51307D3B-A9B2-4DF5-BE94-46D13DB2944}.Debug|x64.ActiveCfg = Debug|x64 + {51307D3B-A9B2-4DF5-BE94-46D13DB2944}.Debug|x64.Build.0 = Debug|x64 + {51307D3B-A9B2-4DF5-BE94-46D13DB2944}.Release|x64.ActiveCfg = Release|x64 + {51307D3B-A9B2-4DF5-BE94-46D13DB2944}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.vcxproj b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.vcxproj new file mode 100644 index 0000000000..e942fb61fc --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/pre_output_decode_matrix_post_learn_individualg_dense.vcxproj @@ -0,0 +1,63 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {43FFE605-6CE0-407A-A301-392210A4E20D} + + + + + + + + + Application + true + $(DefaultPlatformToolset) + true + MultiByte + + + + + + + + + + ./ + $(Platform)\$(Configuration)\ + test + + + + Level3 + MaxSpeed + Disabled + true + true + true + pre_output_decode_matrix_post_learn_individualg_dense_CODE;$(GTEST_DIR);$(GTEST_DIR)/include + _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;%(PreprocessorDefinitions) + + + true + true + true + runner_Release.lib;%(AdditionalDependencies) + runner_Debug.lib;%(AdditionalDependencies) + + + + + + diff --git a/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/runner_guid.txt b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/runner_guid.txt new file mode 100644 index 0000000000..6f175d6c49 --- /dev/null +++ b/tests/features/pre_output_decode_matrix_post_learn_individualg_dense/runner_guid.txt @@ -0,0 +1 @@ +51307D3B-A9B2-4DF5-BE94-46D13DB2944