// Genesaver: copyright 2003 Sam Stafford. #include <math.h> #include <GL/glut.h> #include "globals.h" #include "Brain.h" #include "DNA.h" float light; Brain::Brain( DNA* dna, float* o ) { int i, j, k; char c; //Initialize input neurons to zero. for ( i = 0 ; i < 14 ; i++ ) { input[i] = Neuron(); input[i].axon = 0.0; input[i].x = ( i+1 ) * 2.0 / 15.0 - 1.0; input[i].active = true; } //Initialize lobes. for ( i = 0 ; i < 6 ; i++ ) { lobe[i] = Lobe(); //Remember, top level neurons have ONE dendrite each. for ( j = 0 ; j < 4 ; j++ ) for ( k = 1 ; k < 4 ; k++ ) { lobe[i].neur[0][j].dendrite[k] = NULL; lobe[i].neur[0][j].weight[k] = 0; } //Establish input pointers. //Left half of each lobe first, for historical reasons. c = dna->hchr.iden[i]; lobe[i].neur[0][0].dendrite[0] = &( input[ abs( (c%7)*2 ) ] ); lobe[i].neur[0][1].dendrite[0] = &( input[ abs( (c%7)*2 )+1 ] ); c = dna->hchr.iwgt[i]; lobe[i].neur[0][0].weight[0] = float( c / 32.0 ); lobe[i].neur[0][1].weight[0] = float( c / 32.0 ); CheckActive( & lobe[i].neur[0][0] ); CheckActive( & lobe[i].neur[0][1] ); //Now the right half. c = dna->hchr.iden[i+6]; lobe[i].neur[0][2].dendrite[0] = &( input[ abs( (c%7)*2 ) ] ); lobe[i].neur[0][3].dendrite[0] = &( input[ abs( (c%7)*2 )+1 ] ); c = dna->hchr.iwgt[i+6]; lobe[i].neur[0][2].weight[0] = float( c / 32.0 ); lobe[i].neur[0][3].weight[0] = float( c / 32.0 ); CheckActive( & lobe[i].neur[0][2] ); CheckActive( & lobe[i].neur[0][3] ); //Top level axons. for ( j = 0 ; j < 4 ; j++ ) { lobe[i].neur[0][j].thres = float( dna->ichr[i].ax0[j] / 255.0 ); } //Connect layer 1 to layer 0. for ( j = 0 ; j < 4 ; j++ ) { for ( k = 0 ; k < 4 ; k++ ) { lobe[i].neur[1][j].dendrite[k] = &( lobe[i].neur[0][k] ); if ( !lobe[i].neur[0][k].active && RandFloat() < D_M / 255.0 ) dna->ichr[i].wgt[j][k] = 0; lobe[i].neur[1][j].weight[k] = dna->ichr[i].wgt[j][k] / 32.0; } CheckActive( & lobe[i].neur[1][j] ); } //Bottom level axons. for ( j = 0 ; j < 4 ; j++ ) { lobe[i].neur[1][j].thres = float( dna->ichr[i].ax1[j] / 255.0 ); } lobe[i].neur[0][0].x = ( i * 4 + 1 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[0][1].x = ( i * 4 + 2 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[0][2].x = ( i * 4 + 3 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[0][3].x = ( i * 4 + 4 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[1][0].x = ( i * 4 + 1 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[1][1].x = ( i * 4 + 2 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[1][2].x = ( i * 4 + 3 ) * 2.0 / 25.0 - 1.0; lobe[i].neur[1][3].x = ( i * 4 + 4 ) * 2.0 / 25.0 - 1.0; } //Initialize outputs. for ( i = 0 ; i < 4 ; i++ ) //output neurons { for ( j = 0 ; j < 6 ; j++ ) //lobes { for ( k = 0 ; k < 4 ; k++ ) //bottom lobe neurons { output[i].dendrite[j*4+k] = &lobe[j].neur[1][k]; if ( !lobe[j].neur[1][k].active && RandFloat() < D_M / 255.0 ) dna->hchr.owgt[i][j*4+k] = 0; output[i].weight[j*4+k] = float( dna->hchr.owgt[i][j*4+k] / 32.0 ); } } } //Set pointer to "muscles" of animal. muscles = o; } Brain::~Brain(void) { } void Brain::CheckActive( Neuron* n ) //check if a neuron is in use { n->active = false; for ( int i = 0 ; i < 4 ; i++ ) { if ( n->weight[i] && n->dendrite[i] && n->dendrite[i]->active ) n->active = true; } } void Brain::Clear() //reset inputs { for ( int i = 0 ; i < 14 ; i++ ) input[i].axon = 0.0; } void Brain::Render() { int i, j, k; //Lobe synapses for ( i = 0 ; i < 6 ; i++ ) for ( j = 0 ; j < 4 ; j++ ) { for ( k = 0 ; k < 4 ; k++ ) { RenderSyn ( lobe[i].neur[1][j].weight[k], lobe[i].neur[1][j].dendrite[k], -0.4, lobe[i].neur[1][j].x, -0.6 ); } RenderSyn ( lobe[i].neur[0][j].weight[0], lobe[i].neur[0][j].dendrite[0], -0.2, lobe[i].neur[0][j].x, -0.4 ); } //Input neurons for ( i = 0 ; i < 14 ; i++ ) { RenderNeuron( input[i].axon, input[i].x, -0.2 ); } //Output synapses and neurons for ( i = 0 ; i < 4 ; i++ ) { for ( j = 0 ; j < 24 ; j++ ) { RenderSyn ( output[i].weight[j], output[i].dendrite[j], -0.6, ( i + 1 ) * 2.0 / 5.0 - 1.0, -0.8 ); } RenderNeuron( output[i].axon, ( i + 1 ) * 2.0 / 5.0 - 1.0, -0.8 ); } //Lobe neurons for ( i = 0 ; i < 6 ; i++ ) for ( j = 0 ; j < 4 ; j++ ) { RenderNeuron( lobe[i].neur[0][j].axon, lobe[i].neur[0][j].x, -0.4 ); RenderNeuron( lobe[i].neur[1][j].axon, lobe[i].neur[1][j].x, -0.6 ); } //Label over visual inputs. RenderLights(); } void Brain::RenderLights() { int i; if ( light > 0.6 ) light = -1.0; else if ( light < -1.0 ) light = 0.6; else light += 0.03 * /**step*/ 1; //replace with velocity magnitude float r, g, b, lp, rp; Color draw; for ( i = 0 ; i < 10 ; i++ ) { r = g = b = 0.0; switch( i ) { case 0: case 1: draw = Grey; break; case 2: case 3: draw = Red; break; case 4: case 5: draw = Green; break; case 6: case 7: draw = Blue; break; default: draw = Grey; break; } switch( draw ) { case Grey: r = g = b = 0.5; break; case Red: r = 1; break; case Green: g = 1 ; break; case Blue: b = 1 ; break; case Magenta: r = b = 1; break; case Yellow: r = g = 1; break; } if ( ( light > input[i].x - N_L ) && ( light < input[i].x + N_L ) ) { lp = 1.0 - ( light - ( input[i].x - N_L ) ) / N_L; rp = 1.0 - ( ( input[i].x + N_L ) - light ) / N_L; glBegin( GL_POLYGON ); SetColor( draw ); glVertex2f( light, -0.14 ); glVertex2f( light, -0.15 ); glColor3f( r * lp, g * lp, b * lp ); glVertex2f( input[i].x - N_L, -0.15 ); glVertex2f( input[i].x - N_L, -0.14 ); glEnd(); glBegin( GL_POLYGON ); SetColor( draw ); glVertex2f( light, -0.14 ); glVertex2f( light, -0.15 ); glColor3f( r * rp, g * rp, b * rp ); glVertex2f( input[i].x + N_L, -0.15 ); glVertex2f( input[i].x + N_L, -0.14 ); glEnd(); } else { glColor3f( r * 0.1, g * 0.1, b * 0.1 ); glBegin( GL_POLYGON ); glVertex2f( input[i].x - N_L, -0.15 ); glVertex2f( input[i].x - N_L, -0.14 ); glVertex2f( input[i].x + N_L, -0.14 ); glVertex2f( input[i].x + N_L, -0.15 ); glEnd(); } } } void Brain::RenderNeuron( float a, float x, float y ) { float r, g, b; if ( a >= 0.0 ) { r = 0.0; g = 0.0; b = a; } else { r = -a; g = 0.0; b = 0.0; } glColor3f( r, g, b ); glBegin( GL_POLYGON ); glVertex2f( x + N_R, y + N_R * 0.5 ); glVertex2f( x + N_R, y - N_R * 0.5 ); glVertex2f( x + N_R * 0.5, y - N_R ); glVertex2f( x - N_R * 0.5, y - N_R ); glVertex2f( x - N_R, y - N_R * 0.5 ); glVertex2f( x - N_R, y + N_R * 0.5 ); glVertex2f( x - N_R * 0.5, y + N_R ); glVertex2f( x + N_R * 0.5, y + N_R ); glEnd(); } void Brain::RenderSyn( float w, Neuron* n, float y1, float x2, float y2 ) { if ( !w || !n->active ) return; float r, g, b; float x1 = n->x; if ( w >= 0.0 ) { r = 0.0; g = w / 4.0; b = w / 4.0; } else { r = -w / 4.0; g = -w / 4.0; b = 0.0; } float d = 2.0 - n->axon ; r /= d; g /= d; b /= d; glBegin( GL_LINE_STRIP ); glColor3f( 0, 0, 0 ); glVertex2f( x1, y1 ); glColor3f( r, g, b ); glVertex2f( ( x1 + x2 ) / 2.0, ( y1 + y2 ) / 2.0 ); glColor3f( 0, 0, 0 ); glVertex2f( x2, y2 ); glEnd(); } void Brain::Think() //act on inputs previously cleared by Clear() and accumulated by See(). { int i, j, k; for ( i = 0; i < 2 ; i++ ) for ( j = 0; j < 6 ; j++ ) for( k = 0; k < 4 ; k++ ) { Fire( &( lobe[j].neur[i][k] ) ); } for ( i = 0; i < 4 ; i++ ) Fire( &output[i] ); for ( i = 0 ; i < 4 ; i++ ) { muscles[i] = output[i].axon; } } void Brain::Fire( Neuron* n ) { n->axon = 0.0; float d = 0.0; int e = n->dendrite[1] ? 4 : 1; for( int i = 0 ; i < e ; i++ ) { if ( n->weight[i] ) { n->axon += n->dendrite[i]->axon * n->weight[i]; d++; } } if ( d ) n->axon /= d; if ( n->thres > 0 ) n->axon = float( n->axon >= n->thres ? 1.0 : 0.0 ); if ( n->axon > 1.0 ) n->axon = 1.0; if ( n->axon < -1.0 ) n->axon = -1.0; } void Brain::Fire( BigNeuron* n ) { n->axon = 0.0; float d = 0.0; for ( int i = 0 ; i < 24 ; i++ ) { if ( n->weight[i] ) { n->axon += float( n->dendrite[i]->axon * n->weight[i] ); d++; } } if ( d ) n->axon /= d; if ( n->axon > 1.0 ) n->axon = 1.0; if ( n->axon < -1.0 ) n->axon = -1.0; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#6 | 4463 | Sam Stafford |
Notes on the genome. In the process of reviewing the neural wiring code I fixed an ancient bug with "boolean" neurons. Oops. |
||
#5 | 4446 | Sam Stafford |
Finished neural inputs, made size hereditary, auto-rotation of images once a certain amount of diffs have been consumed, saving genomes at finish. |
||
#4 | 4441 | Sam Stafford | Ported chase-cam view. | ||
#3 | 4440 | Sam Stafford | Bug fixes, new features, the usual. | ||
#2 | 4433 | Sam Stafford |
More work on this little project. The AI is still nonexistent. |
||
#1 | 4430 | Sam Stafford |
Start importing alife/AI code from Genesaver. Much tweaking will need to be done. |
||
//guest/sam_stafford/genesaver/src/Brain.cpp | |||||
#1 | 3052 | Sam Stafford |
Add Genesaver to the Public Depot. It's not in any way Perforce-related, but it does share a bit of code with Jamgraph, and it feels strange to have an open-source project that's not in the PD. |