// Fixed host pooling is followed by a genuine AltAILIF/Delta learned classifier. // Feature counts are repeated spikes in ONE packet; all weighted arithmetic is KNP. #include #include #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; templatestd::vector read(const std::filesystem::path&p){std::ifstream f(p,std::ios::binary);if(!f)throw std::runtime_error("Missing file "+p.string());std::vectorb((std::istreambuf_iterator(f)),{});if(b.size()%sizeof(T))throw std::runtime_error("Truncated file");std::vectorv(b.size()/sizeof(T));std::memcpy(v.data(),b.data(),b.size());return v;} int main(int argc,char**argv)try{ if(argc!=5)throw std::runtime_error("counts.bin modeldir cpu|cuda results.csv"); auto x=read(argv[1]),w=read(std::filesystem::path(argv[2])/"weights.bin"),bias=read(std::filesystem::path(argv[2])/"bias.bin"); size_t nf=w.size();if((nf!=800&&nf!=256)||x.empty()||x.size()%nf||bias.size()!=1)throw std::runtime_error("Invalid dimensions"); int max_count=nf==256?64:640; int max_weight=nf==256?127:31; int64_t bound=std::abs(int64_t(bias[0]));for(auto a:w){if(std::abs(int64_t(a))>max_weight)throw std::runtime_error("Invalid weight");bound+=int64_t(max_count)*std::abs(a);}if(bound>=16777216)throw std::runtime_error("Exact integer bound exceeded"); for(auto a:x)if(a<0||a>max_count)throw std::runtime_error("Invalid count"); std::vectorchunks;int64_t b=bias[0];while(b){int z=std::clamp(b,-65535,65535);chunks.push_back(z);b-=z;} N n;n.activation_threshold_=1;n.negative_activation_threshold_=0;n.is_reset_=true;n.is_diff_=false;n.saturate_=true;n.do_not_save_=true;n.potential_reset_value_=0;n.potential_leak_=0; P neurons([&](size_t){return n;},2);std::vectors; for(int c=0;c<2;c++)for(size_t i=0;istd::optional{return s[i];},s.size());auto pid=proj.get_uid(),nid=neurons.get_uid(); knp::framework::Network net;net.add_population(std::move(neurons));net.add_projection(std::move(proj));knp::framework::Model m(std::move(net));knp::core::UID ic,oc;m.add_input_channel(ic,pid);m.add_output_channel(oc,nid); size_t count=x.size()/nf;auto gen=[&](knp::core::Step step){knp::core::messaging::SpikeData v;if(step>=count)return v;for(size_t i=0;ispikes(count*2); for(auto&msg:e.get_loader().get_output_channel(oc).read_some_from_buffer(0,count+1)){if(msg.header_.send_time_==0)continue;size_t i=msg.header_.send_time_-1;if(ispikes[i*2]?1:0)<<'\n';out.close();std::cout<<"READOUT "<