diff --git a/src/genn/backends/single_threaded_cpu/backend.cc b/src/genn/backends/single_threaded_cpu/backend.cc index 29ac1961a6..9f00e9b0b1 100644 --- a/src/genn/backends/single_threaded_cpu/backend.cc +++ b/src/genn/backends/single_threaded_cpu/backend.cc @@ -1484,6 +1484,26 @@ bool Backend::isGlobalHostRNGRequired(const ModelSpecMerged &modelMerged) const return true; } + // If any custom updates require an RNG fo initialisation, return true + if(std::any_of(model.getCustomUpdates().cbegin(), model.getCustomUpdates().cend(), + [](const ModelSpec::CustomUpdateValueType &c) + { + return (c.second.isInitRNGRequired()); + })) + { + return true; + } + + // If any custom WU updates require an RNG fo initialisation, return true + if(std::any_of(model.getCustomWUUpdates().cbegin(), model.getCustomWUUpdates().cend(), + [](const ModelSpec::CustomUpdateWUValueType &c) + { + return (c.second.isInitRNGRequired()); + })) + { + return true; + } + return false; } //-------------------------------------------------------------------------- diff --git a/src/genn/genn/code_generator/backendSIMT.cc b/src/genn/genn/code_generator/backendSIMT.cc index 9f0965aa1c..6ae18a314e 100644 --- a/src/genn/genn/code_generator/backendSIMT.cc +++ b/src/genn/genn/code_generator/backendSIMT.cc @@ -136,6 +136,26 @@ bool BackendSIMT::isGlobalDeviceRNGRequired(const ModelSpecMerged &modelMerged) return true; } + // If any custom updates require an RNG fo initialisation, return true + if(std::any_of(model.getCustomUpdates().cbegin(), model.getCustomUpdates().cend(), + [](const ModelSpec::CustomUpdateValueType &c) + { + return (c.second.isInitRNGRequired()); + })) + { + return true; + } + + // If any custom WU updates require an RNG fo initialisation, return true + if(std::any_of(model.getCustomWUUpdates().cbegin(), model.getCustomWUUpdates().cend(), + [](const ModelSpec::CustomUpdateWUValueType &c) + { + return (c.second.isInitRNGRequired()); + })) + { + return true; + } + return false; } //-------------------------------------------------------------------------- diff --git a/tests/unit/customUpdate.cc b/tests/unit/customUpdate.cc index 19c64f593b..ea36020364 100644 --- a/tests/unit/customUpdate.cc +++ b/tests/unit/customUpdate.cc @@ -141,6 +141,94 @@ IMPLEMENT_MODEL(ReduceNeuronSharedVar); //-------------------------------------------------------------------------- // Tests //-------------------------------------------------------------------------- + +TEST(CustomUpdates, ConstantVarSum) +{ + ModelSpecInternal model; + + NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); + NeuronModels::Izhikevich::VarValues varVals(0.0, 0.0); + NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + + Sum::VarValues sumVarValues(0.0); + Sum::VarReferences sumVarReferences1(createVarRef(ng, "V"), createVarRef(ng, "U")); + + CustomUpdate *cu = model.addCustomUpdate("Sum", "CustomUpdate", + {}, sumVarValues, sumVarReferences1); + model.finalize(); + + CustomUpdateInternal *cuInternal = static_cast(cu); + ASSERT_FALSE(cuInternal->isZeroCopyEnabled()); + ASSERT_FALSE(cuInternal->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_FALSE(backend.isGlobalHostRNGRequired(modelSpecMerged)); +} + +TEST(CustomUpdates, UninitialisedVarSum) +{ + ModelSpecInternal model; + + NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); + NeuronModels::Izhikevich::VarValues varVals(0.0, 0.0); + NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + + Sum::VarValues sumVarValues(uninitialisedVar()); + Sum::VarReferences sumVarReferences1(createVarRef(ng, "V"), createVarRef(ng, "U")); + + CustomUpdate *cu = model.addCustomUpdate("Sum", "CustomUpdate", + {}, sumVarValues, sumVarReferences1); + model.finalize(); + + CustomUpdateInternal *cuInternal = static_cast(cu); + ASSERT_FALSE(cuInternal->isZeroCopyEnabled()); + ASSERT_FALSE(cuInternal->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_FALSE(backend.isGlobalHostRNGRequired(modelSpecMerged)); +} + +TEST(CustomUpdates, RandVarSum) +{ + ModelSpecInternal model; + + NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); + NeuronModels::Izhikevich::VarValues varVals(0.0, 0.0); + NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + + InitVarSnippet::Uniform::ParamValues dist(0.0, 1.0); + Sum::VarValues sumVarValues(initVar(dist)); + Sum::VarReferences sumVarReferences1(createVarRef(ng, "V"), createVarRef(ng, "U")); + + CustomUpdate *cu = model.addCustomUpdate("Sum", "CustomUpdate", + {}, sumVarValues, sumVarReferences1); + model.finalize(); + + CustomUpdateInternal *cuInternal = static_cast(cu); + ASSERT_FALSE(cuInternal->isZeroCopyEnabled()); + ASSERT_TRUE(cuInternal->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_TRUE(backend.isGlobalHostRNGRequired(modelSpecMerged)); +} TEST(CustomUpdates, VarReferenceTypeChecks) { ModelSpecInternal model; diff --git a/tests/unit/neuronGroup.cc b/tests/unit/neuronGroup.cc index 8aeab69c55..2afc9c7f79 100644 --- a/tests/unit/neuronGroup.cc +++ b/tests/unit/neuronGroup.cc @@ -211,55 +211,99 @@ TEST(NeuronGroup, InvalidName) TEST(NeuronGroup, ConstantVarIzhikevich) { - ModelSpec model; + ModelSpecInternal model; NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); NeuronModels::Izhikevich::VarValues varVals(0.0, 0.0); NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + model.finalize(); + ASSERT_FALSE(ng->isZeroCopyEnabled()); ASSERT_FALSE(ng->isSimRNGRequired()); ASSERT_FALSE(ng->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_FALSE(backend.isGlobalHostRNGRequired(modelSpecMerged)); } -TEST(NeuronGroup, UnitialisedVarIzhikevich) +TEST(NeuronGroup, UninitialisedVarIzhikevich) { - ModelSpec model; + ModelSpecInternal model; NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); NeuronModels::Izhikevich::VarValues varVals(uninitialisedVar(), uninitialisedVar()); NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + model.finalize(); + ASSERT_FALSE(ng->isZeroCopyEnabled()); ASSERT_FALSE(ng->isSimRNGRequired()); ASSERT_FALSE(ng->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_FALSE(backend.isGlobalHostRNGRequired(modelSpecMerged)); } -TEST(NeuronGroup, UnitialisedVarRand) +TEST(NeuronGroup, RandVarIzhikevich) { - ModelSpec model; + ModelSpecInternal model; InitVarSnippet::Uniform::ParamValues dist(0.0, 1.0); NeuronModels::Izhikevich::ParamValues paramVals(0.02, 0.2, -65.0, 8.0); NeuronModels::Izhikevich::VarValues varVals(0.0, initVar(dist)); NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + model.finalize(); + ASSERT_FALSE(ng->isZeroCopyEnabled()); ASSERT_FALSE(ng->isSimRNGRequired()); ASSERT_TRUE(ng->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_TRUE(backend.isGlobalHostRNGRequired(modelSpecMerged)); } TEST(NeuronGroup, Poisson) { - ModelSpec model; + ModelSpecInternal model; NeuronModels::PoissonNew::ParamValues paramVals(20.0); NeuronModels::PoissonNew::VarValues varVals(0.0); NeuronGroup *ng = model.addNeuronPopulation("Neurons0", 10, paramVals, varVals); + model.finalize(); + ASSERT_FALSE(ng->isZeroCopyEnabled()); ASSERT_TRUE(ng->isSimRNGRequired()); ASSERT_FALSE(ng->isInitRNGRequired()); + + // Create a backend + CodeGenerator::SingleThreadedCPU::Preferences preferences; + CodeGenerator::SingleThreadedCPU::Backend backend(model.getPrecision(), preferences); + + // Merge model + CodeGenerator::ModelSpecMerged modelSpecMerged(model, backend); + + ASSERT_TRUE(backend.isGlobalHostRNGRequired(modelSpecMerged)); } TEST(NeuronGroup, FuseWUMPrePost)