当前位置:网站首页>CCF CSP 202109-3 脉冲神经网络

CCF CSP 202109-3 脉冲神经网络

2022-06-10 21:21:00 Brienzz

#include <iostream>
#include <cstring> 
using namespace std;
static unsigned long Next = 1;
//RAND_MAX assumed to be 32767
int myrand(void)  //题目中已给出的伪随机数生成函数 
{
	Next = Next * 1103515245 + 12345;
	return((unsigned)(Next/65536)%32768);
}

int N, S, P, T;
double Dt; //Delta_t 时间间隔 

//定义存储结构体,神经元和突触 
int rn;
struct neural{
	double v_pre, u_pre; //神经元内状态参数v和u的前一时间间隔整数倍的时刻,即前一记录时刻的状态 
	double v, u; //神经元内状态v和u为当前记录时刻的状态 
	double a, b, c, d; //神经元内的其他参数,常量 ,a和b是用来通过上一记录时刻计算此时记录时刻的状态所需要用到的参数 
					   //c和d是当该神经元某时刻受到所有脉冲之和大于或等于30时,用来再次重置v和u 
}NN[1000];

int r[1000]; //用来存储每个脉冲源的参数,即r 
double IK[1000][10000] = {0}; //记录突触的某个时刻出结点和延迟后时间 的突触传播的强度 ,即某个强度,什么时刻,到达某个出结点
								//又因为出结点的编号恰好与神经元对应,即到达的是某个编号的神经元 

struct edg{
	int from, to; //突触的入结点编号,出结点编号 
	double w;    //在该突触上传播的脉冲强度,虽然脉冲是神经元或脉冲源发射脉冲
				//但由于突触的方向是单向的,所以,可以只记录传播时的脉冲强度 
	int D;   //突触上的传播延迟 
}e[1000];


//按题目要求输入 
int main()
{
	scanf("%d %d %d %d", &N, &S, &P, &T); //N个神经元,S个突触,P个脉冲源,从0时刻仿真到T时刻 
	scanf("%lf", &Dt); //仿真期间,每隔Dt的时间间隔记录一次 
	int rn;  //具有相同初始状态v,u和内部参数a,b,c,d的神经元个数 
	double vv, uu, aa, bb, cc, dd; //初始时即0时刻时,神经元的状态,和自己设置的四个参数 
	
	int sum = 0;
	while(sum<N) //输入神经元的参数 
	{
		scanf("%d %lf %lf %lf %lf %lf %lf", &rn, &vv, &uu, &aa, &bb, &cc, &dd);
		for(int i=sum; i<sum+rn; i++)
		{
			NN[i].v_pre = NN[i].v = vv;
			NN[i].u_pre = NN[i].u = uu;
			NN[i].a = aa;
			NN[i].b = bb;
			NN[i].c = cc;
			NN[i].d = dd;
		}
		sum = sum + rn;
	}
	
	for(int i=0; i<P; i++)
		scanf("%d", &r[i]);   //输入每个脉冲源的参数,用来和伪随机数作比较,以判断是否发出脉冲信号
							  //存放在r数组中 
		
	for(int i=0; i<S; i++) //输入每个突触的参数 
	{
		int ff, tt;
		double ww;
		int DD;
		scanf("%d %d %lf %d", &ff, &tt, &ww, &DD);
		e[i].from = ff;  //突触的入结点编号 
		e[i].to = tt;    //突触的出结点编号 
		e[i].w = ww;     //突触传播的脉冲强度 ,突触出结点所受到的脉冲 
		e[i].D = DD;     //突触的传播延迟 
	}
	
	
//计算所有脉冲源在1到T时刻,是否会发送脉冲,
//并将脉冲强度值赋值到连接的神经元IK中 
	for(int t=1; t<T; t++)  //遍历每个记录时刻 
	{
		for(int i=0; i<P; i++) //遍历每个脉冲源,
		{
			if(r[i]>myrand()) //依次判断每个脉冲源是否发送脉冲信号 
			{
				for(int j=0; j<S; j++) //若脉冲源要发射脉冲,遍历每个突触 
				{
					if((e[j].from == i+N) && (t+e[j].D <= T)) //因为脉冲源的编号排在神经元之后,而神经元的数量为N,而i在【0,p】之间,所以脉冲源的编号在【N,N+i】之间 
					{										//如果突触的入结点编号等于脉冲源编号, 且当前记录时刻加上在突触上的延时时间,还在仿真时间内 
						IK[e[j].to][t+e[j].D] = e[j].w;     //则把当前突触传播的脉冲强度,用IK记录,突触的出结点,和延迟后的时刻 ,即突触的出结点所连接的神经元接受脉冲的时刻 
					}
				}
			}
		}
	}
	

//计算每个时刻,每个神经元按照公式计算。
//如果满足条件,发出脉冲。 
	int cnt[1000] = {0};
	for(int t=1; t<=T; t++)  //每个时刻判断一次所有的神经元 
	{
		for(int i=0; i<N; i++)  //遍历每个神经源 
		{
			NN[i].v = NN[i].v_pre + Dt*(0.04*NN[i].v_pre*NN[i].v_pre + 5*NN[i].v_pre + 140.0 - NN[i].u_pre) + IK[i][t];
			NN[i].u = NN[i].u_pre + Dt*NN[i].a*(NN[i].b*NN[i].v_pre - NN[i].u_pre);
			if (NN[i].v >= 30) //如果神经元内v的值满足条件 
			{
				cnt[i]++;       //则发射脉冲 ,记录神经元发射的脉冲次数 
				NN[i].v = NN[i].c;  
				NN[i].u = NN[i].u + NN[i].d;  //如题,重置神经元内部参数 
				for(int j=0; j<S; j++)   //遍历每个突触 
				{
					if((e[j].from == i) && (t+e[j].D <= T))  //突触的入结点等于若神经元的编号,且延迟后在时间范围内 
					{
						IK[e[j].to][t+e[j].D] += e[j].w; //则把突触的出结点所连接的神经元在当前时刻延迟后所收的的脉冲,加上当前时刻的脉冲 
					}
				}
			}
			NN[i].v_pre = NN[i].v; 
			NN[i].u_pre = NN[i].u;   //更新神经元内部的参数,每过一个纪录时刻,神经元内参数的当前时刻状态就变成了前一时刻的状态 
		}
	}

	//遍历每个神经元,求得T时刻的最值和发送脉冲数的最值 
	double minv = NN[0].v, maxv = NN[0].v; //存储所有神经元的v的最值 
    int mincnt = cnt[0], maxcnt = cnt[0];  //存储所有神经元的脉冲次数的最值
	for(int i=1; i<N; i++) //遍历每个神经元 
	{
		if(minv > NN[i].v) minv = NN[i].v;  //寻找所有神经元V的最小值,并记录 
		if(maxv < NN[i].v) maxv = NN[i].v;  //寻找所有神经元V的最大值,并记录
		if(mincnt > cnt[i]) mincnt = cnt[i];
		if(maxcnt < cnt[i]) maxcnt = cnt[i];  //同理 
	}
	printf("%.3lf %.3lf\n", minv, maxv); //输出结果 
	printf("%d %d\n",mincnt, maxcnt);
	return 0;
}

原网站

版权声明
本文为[Brienzz]所创,转载请带上原文链接,感谢
https://blog.csdn.net/futurech/article/details/124978766