//neural.cpp //Oguz Yetkin, Physics 499 //2 23 1998 //neural network implementation // //for now, I just want to write something that works. We shall //be expanding this as we go along // //array2d class works properly in allocating heightxwidth array //as of 3/1/1998, 12:16 am // //purpose: generate http://sprott.physics.wisc.edu/neural/bench.dat #include #include #include #include //for rand(int) #include #include //for RAND_MAX #include //for srand 4/21/1998 #include "neural.h" long double squash(long double value){ return tanh(value); } //array2d implementation array2d::array2d(int h, int w){ if(debug){ cout<<"\nCONSTRUCTING ARRAY2d, memory being allocated!!!"<=height||j>=width){ error=1; cerr<<"\ngetvalue: illegal subscripts!"<=height||j>=width){ error=1; cerr<<"\nputvalue: illegal subscripts!"<randomize(); b->randomize(); input->randomize(); output->randomize(); }//end Network::Network Network::~Network(){ //deallocate memory delete w; delete b; delete input; delete output; }//end Network::~Network int Network::propagate(){ //returns the current generation long double outerpart=0; long double innerpart=0; long double u; //could this be our memory leak??? long double* phiu=new long double[n+1]; //from Prof. Sprott's code int i,j,k; for(i=1;i<=n;i++){ u=w->base[i][0]; for(j=1;j<=d;j++){ u=u+(w->base[i][j])*(input->base[0][j]); } phiu[i]=squash(u); } for(j=1;j<=d;j++){ output->base[0][j]=0; for(i=1;i<=n;i++){ output->base[0][j]=output->base[0][j]+ (b->base[i][j])*phiu[i]; } } /* commented out 3/17/1998 by Oguz for(int k=1;k<=d;k++){ for(int i=1;i<=n;i++){ innerpart=0; for(int j=1;jbase[i][j])*input->base[0][k]; } //innerpart*=s; //commented out 3/17/1998 by Oguz innerpart=innerpart+s*(w->base[i][j]); innerpart=squash(innerpart); outerpart+=((b->base[i][k])*innerpart); } output->base[0][k]=outerpart; } */ //unnecessary, here for extensibility purposes for(i=0;i<=d;i++){ input->base[0][i]=output->base[0][i]; } delete[]phiu; //hope this still works, this might fix the memory leak return generation++; } //overloaded assignment operator for array2d //assumes left hand side is properly allocated and //IS OF THE SAME SIZE array2d &array2d::operator=(array2d &in){ //cout<<"\noperator= for array2d got called!!!"<randomize(); } void Neuron::dump(){ cout<<"\ndumping neuron: "<dump(); cout<<"\nincoming neighbors: "<dump(); cout<<"\noutput values"<dump(); //outvalues->dump(); dumpoutput(); } void Neuron::dumpoutput(){ //cout<dump(); //outvalues->dump(); //cout<=num_elements){ cout<<"\npush failed!"<num_elements); //outvalues=new List(input_weights->num_elements); //for now, we'll set output values equal to input weights, just to get it to compile //& not seg fault //just as a sanity check //output_values=new List(4); //assert(output_values); //assert(outvalues); s=in_s; } //written 4/1/1998 void Neuron::propagate(Neuron* world){ //we need not pass anything in since the neuron knows who its inputs are!!! //changed 4/8/1998 to divide weights by sqrt(m) static int firstrun=1; static long double m; static long double sqrt_m; //we don't want to do this more than once, or take a square root inside a loop if(firstrun){ firstrun=0; m=inputs->num_elements; sqrt_m=sqrt(m); } //changed 4/3/1998 to take into account that we only //get one output from the incoming neighbor //write propagate function--imoprtant!!! long i,j,k; i=j=k=0; long double value; //generic variable long double neighindex; long double weight; long double in_value; //incoming value from neuron long in_neighbor; int ok=1;//is everything OK? inputs->reset(); input_weights->reset(); //get ready to pop //don't care about outvalues anymore 4/3/1998 temp_output=0; value=0; //outvalues->current_pos=0; //we should have as many input weights as we have //incoming neighbors assert(input_weights->num_elements==inputs->num_elements); //for every incoming neighbor for(i=0;inum_elements;i++){ ok=inputs->pop(neighindex); //get the index of a neighbor assert(ok); in_neighbor=(long)neighindex; in_value=world[in_neighbor].output; assert(in_neighbor>=0); ok=input_weights->pop(weight); //get current input weight assert(ok); //value is an intermediate value value+=s*in_value*weight/sqrt_m; } temp_output=squash(value); //real output is assigned by commit() which is called by rNetwork::propagate() 4/3/1998 /* commented out 4/3/1998 for(j=0;jnum_elements;j++){ //for every component of output vector inputs->reset(); //reset the neighbor list value=0; for(i=0;inum_elements;i++){ //for every incoming neighbor ok=inputs->pop(neighindex); //get the index of a neighbor assert(ok); in_neighbor=(long)neighindex; assert(in_neighbor>=0); world[in_neighbor].outvalues->reset(); //so we can pop //value=0; //for every output value in the incoming neighbor's output vector input_weights->reset(); for(k=0;knum_elements;k++){ //calculate one output value //get current weight ok=input_weights->pop(weight); assert(ok); //for now, we should not run into problems--if we do, fix it!!! //ok=world[in_neighbor].outvalues->pop(in_value); in_value=world[in_neighbor].outvalues->L[j]; //assuming all output vectors the same size!!! assert(ok); value+=s*weight*in_value; } }//end middle for that has the purpose of handling output from a single incoming neighbor value=squash(value); //apply squashing function //outvalues->current_pos=0; //ok=outvalues->push(value); //assert(ok); //one of these is going to fail...I know it... outvalues->L[j]=value; }//end outer for, all neighbors done at this point */ } //this is where we should get rid of dynamic allocation. Causes bugs //when we keep track of all the outputs // //last update: 4/17/1998 Neuron & Neuron::operator=(Neuron& in){ selfindex=in.selfindex; *input_weights=*(in.input_weights); //we'd forgotten to do this, added 4/17/1998, 3:09 am *inputs=*(in.inputs); //we no longer use output_weights //4/3/1998 //4/17/1998, assuming following values are NULL //*output_weights=*(in.output_weights); //*outputs=*(in.outputs); //modified 4/33/1998 output=in.output; //is this working properly temp_output=in.temp_output; //this should NEVER fail! if(output!=in.output){ cout<<"\n!!!!A VERY STRAIGHTFORWARD ASSIGNMENT JUST FAILED in neural.cpp Neuron::operator=(). GO BACK TO YOUR DEBUGGER!!!\nhalting program..."<num_elements); //not used now //just for consistency's sake //*temp_net[i].outputs=*net[i].outputs; //net[i].outvalues=new List(net[i].input_weights->num_elements); //net[i].outvalues=get_output_seed(); //*temp_net[i].outvalues=*net[i].outvalues; net[i].s=getscale(); //temp_net[i].s=net[i].s; net[i].selfindex=i; //so we know who we are net[i].output=squash(myrand()); //temp_net[i].selfindex=net[i].selfindex; } /* for(i=0;ipush(rand()/RAND_MAX); inlist->push(rand()/RAND_MAX); inlist->push(rand()/RAND_MAX); inlist->push(rand()/RAND_MAX); // inlist->push(0.2321); inlist->push(0.6); inlist->push(0.9); inlist->push(0.1); firstrun=0; } */ inlist=new List(input_size); assert(inlist); for(long i=0;ipush(myrand()); //comment out later for optimization if(!ok){ cout<<"\ngetinweights is pushing past end of list at "<push(0.2); outlist->push(0.8); outlist->push(0.1); outlist->push(0.3); firstrun=0; } return outlist; } long double rNetwork::getscale(){ return s; //very arbitrary... } List* rNetwork::get_neigh_list(){ //this list should actually contain ints List* neighlist; int max_neighbors=input_size; //int num_neighbors=rand()%max_neighbors +1; long num_neighbors; num_neighbors=max_neighbors; //for now, for benchmarking purposes 4/1/1998 int ok=1; if(debug){ cout<<"\ndon't forget to delete list in real implementation!!!"<push( abs(rand()%net_size) ); assert(ok); } return neighlist; } List* rNetwork::get_output_seed(){ List* seed; if(debug){ cout<<"\ndon't forget to delete list later!"<push(0.2112); seed->push(0.3); seed->push(0.8); seed->push(0.5); return seed; } int rNetwork::propagate(){ long i,j,k; i=j=k=0; List* inputs; List* outputs; //initially, net and temp_net are the same network for(i=0;i