#include #include #include #include #include namespace { void check_cuda(const torch::Tensor& x) { TORCH_CHECK(x.is_cuda(), "all tensors must be CUDA tensors"); TORCH_CHECK(x.is_contiguous(), "all tensors must be contiguous"); } __global__ void state_kernel(float* v, float* g, int* refractory, float* arrival, unsigned char* spikes, int* counts, int n, float gd, float alpha, float rest, float reset, float threshold, int ref_steps) { int i=blockIdx.x*blockDim.x+threadIdx.x; if(i>=n) return; float gi=__fadd_rn(__fmul_rn(g[i],gd),arrival[i]); g[i]=gi; arrival[i]=0.0f; int r=refractory[i]; r=r>0?r-1:0; refractory[i]=r; float vi=v[i]; bool available=r==0; if(available){ float leak=__fsub_rn(vi,rest); float drive=__fsub_rn(gi,leak); vi=__fadd_rn(vi,__fmul_rn(alpha,drive)); } else vi=reset; bool fired=available && vi>=threshold; if(fired){vi=reset;refractory[i]=ref_steps;counts[i]+=1;} v[i]=vi;spikes[i]=fired?1:0; } __global__ void force_kernel(float* v,int* refractory,unsigned char* spikes, int* counts,const int64_t* targets, const unsigned char* forced,int n,float reset, int ref_steps){ int j=blockIdx.x*blockDim.x+threadIdx.x; if(j>=n||!forced[j]) return; int64_t i=targets[j]; if(spikes[i]||refractory[i]!=0) return; spikes[i]=1;v[i]=reset;refractory[i]=ref_steps;counts[i]+=1; } __global__ void fill_edges_kernel(const int64_t* indptr,const int64_t* sources, const int64_t* offsets,int64_t* output,int n){ int j=blockIdx.x*blockDim.x+threadIdx.x; if(j>=n) return; int64_t src=sources[j],begin=indptr[src],degree=indptr[src+1]-begin,out=offsets[j]; for(int64_t k=0;k source -> edge_id order supplied by the host. __global__ void segmented_sum_kernel(const int64_t* edges,const int64_t* starts, const int* targets,const float* weights, float* destination,int segments, int64_t edge_count){ int s=blockIdx.x*blockDim.x+threadIdx.x; if(s>=segments) return; int64_t begin=starts[s],end=(s+1>>(v.data_ptr(),g.data_ptr(),refractory.data_ptr(),arrival.data_ptr(),spikes.data_ptr(),counts.data_ptr(),n,(float)gd,(float)alpha,(float)rest,(float)reset,(float)threshold,(int)ref_steps);C10_CUDA_KERNEL_LAUNCH_CHECK(); } void force_step_cuda(torch::Tensor v,torch::Tensor refractory,torch::Tensor spikes, torch::Tensor counts,torch::Tensor targets,torch::Tensor forced, double reset,int64_t ref_steps){ check_cuda(targets);check_cuda(forced);int n=targets.numel();force_kernel<<<(n+255)/256,256>>>(v.data_ptr(),refractory.data_ptr(),spikes.data_ptr(),counts.data_ptr(),targets.data_ptr(),forced.data_ptr(),n,(float)reset,(int)ref_steps);C10_CUDA_KERNEL_LAUNCH_CHECK(); } void fill_edges_cuda(torch::Tensor indptr,torch::Tensor sources,torch::Tensor offsets,torch::Tensor output){ check_cuda(indptr);check_cuda(sources);check_cuda(offsets);check_cuda(output);int n=sources.numel();fill_edges_kernel<<<(n+255)/256,256>>>(indptr.data_ptr(),sources.data_ptr(),offsets.data_ptr(),output.data_ptr(),n);C10_CUDA_KERNEL_LAUNCH_CHECK(); } void segmented_sum_cuda(torch::Tensor edges,torch::Tensor starts,torch::Tensor targets, torch::Tensor weights,torch::Tensor destination){ check_cuda(edges);check_cuda(starts);check_cuda(targets);check_cuda(weights);check_cuda(destination); TORCH_CHECK(edges.scalar_type()==torch::kInt64&&starts.scalar_type()==torch::kInt64&&targets.scalar_type()==torch::kInt32,"index dtype mismatch"); int n=targets.numel();if(n) segmented_sum_kernel<<<(n+255)/256,256>>>(edges.data_ptr(),starts.data_ptr(),targets.data_ptr(),weights.data_ptr(),destination.data_ptr(),n,edges.numel());C10_CUDA_KERNEL_LAUNCH_CHECK(); }