// Per-step conformance against the actual KNP CPU backend, including export and pause/resume. #include #include #include #include #include #include #include #include #include using P=knp::core::Population; using R=knp::core::Projection; using N=knp::neuron_traits::neuron_parameters; using Type=knp::synapse_traits::OutputType; struct Trace {std::vector states;std::vector spikes;}; unsigned bits(float v) {unsigned result;std::memcpy(&result,&v,4);return result;} Trace run(const char *backend_path,bool split) { P a([](size_t i){N n;n.activation_threshold_=3+i;n.negative_activation_threshold_=i%2?7:0; n.potential_=i?static_cast(static_cast(i%5)-2):-0.F; n.potential_reset_value_=i%3;n.potential_leak_=static_cast(i%3)-1; n.activity_time_=i%4==0?0:(i%4==1?-2:(i%4==2?1:INT64_MAX)); n.is_diff_=i%2;n.is_reset_=i%3!=0;n.saturate_=i%2;n.leak_rev_=i%2;n.do_not_save_=i%5==0; return n;},11); P b([](size_t i){N n;n.activation_threshold_=5+i;n.negative_activation_threshold_=0;return n;},4); auto auid=a.get_uid(),buid=b.get_uid(); R input(knp::core::UID{false},auid,[](size_t j)->std::optional{ unsigned d=j%4==0?64:(j%4==1?7:(j%4==2?2:1)); return R::Synapse{{static_cast(static_cast(j%9)-4),d,Type::EXCITATORY},j%600,j/600};},11*600); R bias(knp::core::UID{false},auid,[](size_t j)->std::optional{ return R::Synapse{{2,2,Type::INHIBITORY_CURRENT},0,j};},11); R output(auid,buid,[](size_t j)->std::optional{ return R::Synapse{{static_cast(static_cast(j%7)-3),static_cast(1+j%2),Type::EXCITATORY},j%11,j/11};},44); R recurrent(auid,auid,[](size_t j)->std::optional{ return R::Synapse{{-2,2,Type::EXCITATORY},j,(j+1)%11};},11); auto input_uid=input.get_uid(),bias_uid=bias.get_uid(); knp::framework::Network net; net.add_population(std::move(a));net.add_population(std::move(b)); net.add_projection(std::move(input));net.add_projection(std::move(bias));net.add_projection(std::move(output));net.add_projection(std::move(recurrent)); knp::framework::Model model(std::move(net)); knp::core::UID channel,outa,outb; model.add_input_channel(channel,input_uid);model.add_input_channel(channel,bias_uid); model.add_output_channel(outa,auid);model.add_output_channel(outb,buid); auto generator=[](knp::core::Step step){knp::core::messaging::SpikeData data; if(step<30) {for(unsigned i=0;i<600;++i) if((i+step)%7==0) data.push_back(i); if(step%5==0) {data.push_back(0);data.push_back(0);}} return data;}; knp::framework::BackendLoader loader; knp::framework::ModelExecutor executor(model,loader.load(backend_path),{{channel,generator}}); Trace trace; auto snapshot=[&](size_t step) { std::ostringstream row;row<get_network_data(); auto &it=data.population_range.first;auto &end=data.population_range.second; while(*it!=*end) {auto variant=**it;const auto &pop=std::get

(variant); for(const auto &n:pop) row<<','<(-1); auto execute=[&](size_t limit) {executor.start([&](size_t step){if(step!=last){snapshot(step);last=step;}return stepstd::optional{ return R::Synapse{{scenario==0?0.5F:(scenario==2?65535.F:1.F),static_cast(scenario==1?65:1),Type::EXCITATORY},0,0};},scenario==2?257:1); auto pid=p.get_uid(),rid=r.get_uid();knp::framework::Network net;net.add_population(std::move(p));net.add_projection(std::move(r)); knp::framework::Model model(std::move(net));knp::core::UID input;model.add_input_channel(input,rid); bool failed=false; try {knp::framework::BackendLoader loader;knp::framework::ModelExecutor executor(model,loader.load(gpu),{{input,[](knp::core::Step){return knp::core::messaging::SpikeData{0};}}});executor.start([](size_t step){return step<3;});} catch(const std::exception &e) {failed=true;std::cout<<"Expected rejection "<