void TargetWeightsExperiment::populateSubstrate(shared_ptr<const NEAT::GeneticIndividual> individual) 
    {
        //cout << "Populating substrate...";
        NEAT::FastNetwork <double> network = individual->spawnFastPhenotypeStack<double>();        //JMC: this network is the CPPN used to produce the substrate (neural network)
        //progress_timer t;
        
        int linkCount=0;

        int counter=0;
        double x1Val,y1Val,x2Val,y2Val;
        
        for (int y1=0;y1<numNodesY;y1++)
        {
            //cout << "loop: " << endl;
            for (int x1=0;x1<numNodesX;x1++)
            {
                for (int y2=0;y2<numNodesY;y2++)
                {
                    for (int x2=0;x2<numNodesX;x2++)
                    {
                    
                        x1Val = mapXYvalToNormalizedGridCoord(x1, numNodesX);  //see function for description
                        y1Val = mapXYvalToNormalizedGridCoord(y1, numNodesY);
                        x2Val = mapXYvalToNormalizedGridCoord(x2, numNodesX);  //see function for description
                        y2Val = mapXYvalToNormalizedGridCoord(y2, numNodesY);
                        
                        //cout << "x1: " << setw(5)  << setprecision(2) << x1Val << "  y1: " << setw(5) << y1Val << "  x2: " << setw(5) << setprecision(2) << x2Val << "  y2: " << setw(5) << y2Val << endl;
                        network.reinitialize();
                        network.setValue("X1",x1Val);
                        network.setValue("Y1",y1Val);
                        network.setValue("X2",x2Val);
                        network.setValue("Y2",y2Val);

                        network.setValue("Bias",0.3);                       //JMC: we have just set the inputs to the     to be x1,y1,x2,y2,bias 
                        
                        
                        //cout << "RUNNING UPDATE ON CPPN----------------------------------------------------------------------------------------" << endl;
                        network.update();                                   //JMC: on this line we run the CPPN network...  
                        //cout << "DONE RUNNING UPDATE ON CPPN----------------------------------------------------------------------------------------" << endl;
                                                                              

                        double greyVal = network.getValue("Output");        //JMC: and here we get the CPPN output (which is the weight of the connection between the two)

                        //substrate.getLink(counter)->weight = ( greyVal*3.0 );

                        //for the target weight experiment we do not want to make it easier for them to get zero nor do we need to normalize the greyValue, so just use it
                        
                        substrate.getLink(counter)->weight = greyVal;
                        linkCount++;

                        counter++;
                    }
                }
            }
        }

        //cout << "done!\n";

        //cout << "Number of expressed links: " << linkCount << endl;
    }
    void XorExperiment::processIndividualPostHoc(shared_ptr<NEAT::GeneticIndividual> individual)
    {
        NEAT::FastNetwork<float> network = individual->spawnFastPhenotypeStack<float>();

        //TODO Put in userdata

        double fitness = 10.0;
        double maxFitness = 10.0;

        for (int x1=0;x1<2;x1++)
        {
            for (int x2=0;x2<2;x2++)
            {
                network.reinitialize();

                network.setValue("X1",x1);
                network.setValue("X2",x2);
                network.setValue("Bias",0.3f);

                network.update();

                double value = network.getValue("Output");

                double expectedValue = (double)(x1 ^ x2);

                fitness += (5000*(2-fabs(value-expectedValue)));
                maxFitness += 5000*2;
            }
        }

        cout << "POST HOC ANALYSIS: " << fitness << "/" << maxFitness << endl;
    }
    void XorExperiment::processGroup(shared_ptr<NEAT::GeneticGeneration> generation)
    {
        NEAT::FastNetwork<float> network = group[0]->spawnFastPhenotypeStack<float>();

        group[0]->reward(10);

        for (int x1=0;x1<2;x1++)
        {
            for (int x2=0;x2<2;x2++)
            {
                network.reinitialize();

                network.setValue("X1",x1);
                network.setValue("X2",x2);
                network.setValue("Bias",0.3f);

                network.update();

                double value = network.getValue("Output");

                double expectedValue = (double)(x1 ^ x2);

                group[0]->reward(5000*(2-fabs(value-expectedValue)));
            }
        }
    }
    void ShapesExperiment::printNetworkCPPN(shared_ptr<const NEAT::GeneticIndividual> individual)
    {
      cout << "Printing cppn network" << endl;
      ofstream network_file;        
      network_file.open ("networkCPPN-ThatSolvedTheProblem.txt", ios::trunc );
      
      NEAT::FastNetwork <double> network = individual->spawnFastPhenotypeStack <double>();        //JMC: this creates the network CPPN associated with this individual used to produce the substrate (neural network)

      network_file << "num links:" << network.getLinkCount() << endl;
      network_file << "num nodes:" << network.getNodeCount() << endl;
 
      int numLinks = network.getLinkCount();
      int numNodes = network.getNodeCount();
      ActivationFunction activationFunction;

      //print out which node corresponds to which integer (e.g. so you can translate a fromNode of 1 to "x1"  
      map<string,int> localNodeNameToIndex = *network.getNodeNameToIndex();
      for( map<string,int>::iterator iter = localNodeNameToIndex.begin(); iter != localNodeNameToIndex.end(); iter++ ) {
        network_file << (*iter).first << " is node number: " << (*iter).second << endl;
      }
      
      for (size_t a=0;a<numLinks;a++)
      {
          
          NetworkIndexedLink <double> link = *network.getLink(a);
           
          network_file << link.fromNode << "->" << link.toNode << " : " << link.weight << endl;
      }
      for (size_t a=0;a<numNodes;a++)
      {          
          activationFunction = *network.getActivationFunction(a);           
          network_file << " activation function " << a << ": ";
          if(activationFunction == ACTIVATION_FUNCTION_SIGMOID) network_file << "ACTIVATION_FUNCTION_SIGMOID";
          if(activationFunction == ACTIVATION_FUNCTION_SIN) network_file << "ACTIVATION_FUNCTION_SIN";
          if(activationFunction == ACTIVATION_FUNCTION_COS) network_file << "ACTIVATION_FUNCTION_COS";
          if(activationFunction == ACTIVATION_FUNCTION_GAUSSIAN) network_file << "ACTIVATION_FUNCTION_GAUSSIAN";
          if(activationFunction == ACTIVATION_FUNCTION_SQUARE) network_file << "ACTIVATION_FUNCTION_SQUARE";
          if(activationFunction == ACTIVATION_FUNCTION_ABS_ROOT) network_file << "ACTIVATION_FUNCTION_ABS_ROOT";
          if(activationFunction == ACTIVATION_FUNCTION_LINEAR) network_file << "ACTIVATION_FUNCTION_LINEAR";
          if(activationFunction == ACTIVATION_FUNCTION_ONES_COMPLIMENT) network_file << "ACTIVATION_FUNCTION_ONES_COMPLIMENT";
          if(activationFunction == ACTIVATION_FUNCTION_END) network_file << "ACTIVATION_FUNCTION_END";
          network_file << endl;
      }

      network_file.close();

      return;
    }
Beispiel #5
0
void printNetwork(NEAT::FastNetwork<double> &testNetwork)
{
	return;
	
	cout << "Network links:\n";
	cout << testNetwork.getLink("Input0","Hidden1")->weight << endl;
	cout << testNetwork.getLink("Input0","Hidden2")->weight << endl;
	cout << endl;
	
	cout << testNetwork.getLink("Input1","Hidden1")->weight << endl;
	cout << testNetwork.getLink("Input1","Hidden2")->weight << endl;
	cout << endl;
	
	cout << testNetwork.getLink("Input2","Hidden1")->weight << endl;
	cout << testNetwork.getLink("Input2","Hidden2")->weight << endl;
	cout << endl;
	
	cout << testNetwork.getLink("Hidden0","Output0")->weight << endl;
	cout << testNetwork.getLink("Hidden1","Output0")->weight << endl;
	cout << testNetwork.getLink("Hidden2","Output0")->weight << endl;
	cout << endl;
	
	CREATE_PAUSE("");
}
    void ShapesExperiment::processInteractiveEvaluation(int _genNumber)
    {
		vector <int> fitnessScores;
		writeAndTeeUpParentsOrderFile();

		//if the command line is telling us which orgs to select, handle that and return (skip the rest of the function)
		if(int(NEAT::Globals::getSingleton()->getParameterValue("NeedToInjectFitnessValuesFromCommandLine")))
		{
			
			NEAT::Globals::getSingleton()->setParameterValue("NeedToInjectFitnessValuesFromCommandLine", 0.0); //set flag so we don't enter this condition the next time around
			
			if(int(NEAT::Globals::getSingleton()->getParameterValue("SeedingSoDecrementByOne"))) firstGenSeedingSoDontPrintParentsFile = true;

			
			//initialize default (non-selected) fitness values
			for(int z=0;z< group.size();z++)
			{
				fitnessScores.push_back(1);
			}
			
			if(int(NEAT::Globals::getSingleton()->getParameterValue("StartVfFileIndexesAtOne")))
			  {
			    firstGen = false; //don't make the gen num zero if branching
			  }

			
			//get vector that lists the orgs we need to mark as selected (variable sized)
			vector <int> listOfOrgsInjectedAsSelected = NEAT::Globals::getSingleton()->getInjectOrgsSelected();
			if (!listOfOrgsInjectedAsSelected.size()>=1)
			{
				cout << "You must provide a list of orgs to mark as selected with the -F flag" << endl;
			}
			
			//mark those orgs as selected
			for(int z=0;z<listOfOrgsInjectedAsSelected.size();z++)
			{
				PRINT(listOfOrgsInjectedAsSelected[z]);
				fitnessScores[(listOfOrgsInjectedAsSelected[z])] = 1000;
			}

			cout << "result of command line arguments being used to make initial selection" << endl;
			for(int z=0;z< group.size();z++)
			{
				PRINT(fitnessScores[z]);
				shared_ptr<NEAT::GeneticIndividual> individual = group[z];
				if (fitnessScores[z]>	5) individual->reward(fitnessScores[z]);	//if picked by user (either as champ or tie-for-second, use those scores
				else individual->reward(1);	 
			}
			return;
		}
		
		
//		writeAndTeeUpParentsOrderFile(); //delme if you moved this up above the one-time for inserted fitness and like it...this was it's original position

		viewThresh = 100000;	//how long the user has to input their champ
		vector <CMesh> meshesToDraw;
		
		NEAT::FastNetwork <double> network;

		//initializes continuous space array with zeros. +1 is because we need to sample
		// these points at all corners of each voxel, leading to n+1 points in any dimension
		CArray3Df ContinuousArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array
		CArray3Df rColorArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array of red color for each voxel
		CArray3Df gColorArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array of green color for each voxel
		CArray3Df bColorArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array of blue color for each voxel
		

		int px, py, pz; //temporary variable to store locations as we iterate
		float xNormalized;
		float yNormalized;
		float zNormalized;
		float distanceFromCenter = 0.0;
		float distanceFromCenterXY = 0.0;
		float distanceFromCenterYZ = 0.0;
		float distanceFromCenterXZ = 0.0;
		float arcTan2Val = 0.0;
		float distanceFromShell = 0.0;
		float insideOutside = 0.0;
		
		int ai;
		float e;

		//START HACK v.2
		string line;
		ifstream file("/home/achen/csv/pure.csv"); //FILE NAME
		float store2 [2000];
		
		int i= 0;
		
		while (getline(file,line)){
		  store2[i]= atof(line.c_str());
		  i++;
		}

		file.close();
		i= 0;
		
		int voxelCount=0;
		shared_ptr<NEAT::GeneticIndividual> individual;
		
		for(int z=0;z< group.size();z++)
		{
			cout << "generating shape: " << z << endl;
			individual = group[z];									
			network = individual->spawnFastPhenotypeStack<double>();        //JMC: this is the CPPN network
			
			voxelCount=0;
				
			cout << "JMC INTERACTIVE HACKING" << endl;
			for (int j=0; j<ContinuousArray.GetFullSize(); j++)  //iterate through each location of the continuous matrix
			{ 
				ContinuousArray.GetXYZ(&px, &py, &pz, j); //gets XYZ location of this element in the array
				xNormalized = mapXYvalToNormalizedGridCoord(px, num_x_voxels);
				yNormalized = mapXYvalToNormalizedGridCoord(py, num_y_voxels);
				zNormalized = mapXYvalToNormalizedGridCoord(pz, num_z_voxels);

				cout << px << endl;
            
            //ACHEN: Will change variable name...
				e= store2[i];
				i++;

				//ACHEN: LOGGING POSITIONS
				//cout << "(" << xNormalized << "," << yNormalized << "," << zNormalized << ")" << endl; 

				//calculate input vars
				if(addDistanceFromCenter)   distanceFromCenter   = sqrt(pow(double(xNormalized),2.0)+pow(double(yNormalized),2.0)+pow(double(zNormalized),2.0));
				if(addDistanceFromCenterXY) distanceFromCenterXY = sqrt(pow(double(xNormalized),2.0)+pow(double(yNormalized),2.0));
				if(addDistanceFromCenterYZ) distanceFromCenterYZ = sqrt(pow(double(yNormalized),2.0)+pow(double(zNormalized),2.0));
				if(addDistanceFromCenterXZ) distanceFromCenterXZ = sqrt(pow(double(xNormalized),2.0)+pow(double(zNormalized),2.0));				
				if(addArcTan2) arcTan2Val = atan2(yNormalized, zNormalized);
												
				network.reinitialize();								//reset CPPN
				//next three lines are zeroed out for shell debugging
				//cout << "JMC HACKING VALUES TO ZERO" << endl;
				
				//network.setValue("x",0);					//set the input numbers
				//network.setValue("y",0);
				//network.setValue("z",0);

				//network.setValue("x",xNormalized);					//set the input numbers
			  //network.setValue("y",yNormalized);
				//network.setValue("z",zNormalized);
				if(addDistanceFromShell) network.setValue("ds",e); //ACHEN: Shell distance
				if(addDistanceFromCenter) network.setValue("d",distanceFromCenter);
				if(addDistanceFromCenterXY) network.setValue("dxy",distanceFromCenterXY);
				if(addDistanceFromCenterYZ) network.setValue("dyz",distanceFromCenterYZ);
				if(addDistanceFromCenterXZ) network.setValue("dxz",distanceFromCenterXZ);
				if(addArcTan2) network.setValue("arcTan2",arcTan2Val);
				//network.setValue("Bias",0.3);                      
				
				network.update();                                   //JMC: on this line we run the CPPN network...  
				
				ContinuousArray[j] = network.getValue("Output");        //JMC: and here we get the CPPN output (which is the weight of the connection between the two)
				
				//hack directly into array @#
				//ContinuousArray[j] = e;
				//cout << "e: " << e << "   i " << i ;



								
				if(useColor){
					rColorArray[j]     = (1 + network.getValue("Output-colorR"))/2.0;
					gColorArray[j]     = (1 + network.getValue("Output-colorG"))/2.0;
					bColorArray[j]     = (1 + network.getValue("Output-colorB"))/2.0;
				}
				
//				PRINT(rColorArray[j]);

				if (ContinuousArray[j]>voxelExistsThreshold) voxelCount++;
				
			}

			i=0;
			
			std::cout << "Performing marching cubes...\n";
			CMesh OutputMesh;
			CMarchCube::SingleMaterialMultiColor(&OutputMesh, &ContinuousArray, &rColorArray, &gColorArray, &bColorArray, voxelExistsThreshold, VoxelSize*1000);	//jmc: last argument is the threshold above which we consider the voxel to be extant
			
			meshesToDraw.push_back(OutputMesh);
						
		}

		
		cout << "drawing shapes" << endl;
		fitnessScores = drawShapes(meshesToDraw, _genNumber);

		cout << "fitness values used when not getting list of selected orgs from command line" << endl;
		for(int z=0;z< group.size();z++)
		{
			PRINT(fitnessScores[z]);
			shared_ptr<NEAT::GeneticIndividual> individual = group[z];
			if (fitnessScores[z]>	5) individual->reward(fitnessScores[z]);	//if picked by user (either as champ or tie-for-second, use those scores
			else 
			{
				individual->reward(1);	
			}
		}
		
					
    }
    double ShapesExperiment::processEvaluation(shared_ptr<NEAT::GeneticIndividual> individual)
    {
        #if SHAPES_EXPERIMENT_DEBUG
        cout << "JMC: evaluating fitness in ShapesExperiment::processEvaluation\n";
        #endif

		bool EvolvingTarget = true;
		bool EvolvingInteractive;
		
		if(EvolvingTarget == true) {EvolvingInteractive = false; viewThresh = 0.5;}
		else {					   EvolvingInteractive = true; }

		
		float InteractiveFitnessScore = 0.0; //since we raise to the power of two, it can be zero
		
		
		//initializes continuous space array with zeros. +1 is because we need to sample
		// these points at all corners of each voxel, leading to n+1 points in any dimension
		CArray3Df ContinuousArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array

		//TODO; If you end up not using color, then pound define these out when not using them
		CArray3Df rColorArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array of colors for each voxel
		CArray3Df gColorArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array of colors for each voxel
		CArray3Df bColorArray(num_x_voxels, num_y_voxels, num_z_voxels); //evolved array of colors for each voxel
		
		NEAT::FastNetwork <double> network = individual->spawnFastPhenotypeStack<double>();        //JMC: this is the CPPN network

		int px, py, pz; //temporary variable to store locations as we iterate
		float xNormalized;
		float yNormalized;
		float zNormalized;
		float distanceFromCenter;
		float distanceFromCenterXY;
		float distanceFromCenterYZ;
		float distanceFromCenterXZ;
		float distanceFromShell;
		float insideOutside;
		float arcTan2Val;
		int ai;
		/**
		//START HACK PREPARATIONS
		string line;
		ifstream file("/home/achen/csv/pure.csv"); //FILE NAME
		float store [2000];
		
		int i= 0;
		float e= 0;

		while (getline(file,line)){
		  store[i]= atof(line.c_str());
		  i++;
		}

		file.close();
		**/		
		for (int j=0; j<ContinuousArray.GetFullSize(); j++)  //iterate through each location of the continuous matrix
		{ 
			ContinuousArray.GetXYZ(&px, &py, &pz, j); //gets XYZ location of this element in the array
			xNormalized = mapXYvalToNormalizedGridCoord(px, num_x_voxels);
			yNormalized = mapXYvalToNormalizedGridCoord(py, num_y_voxels);
			zNormalized = mapXYvalToNormalizedGridCoord(pz, num_z_voxels);
			
			//Array hack
			//e= store[i];
			//i++;

    			//calculate input vars
			if(addDistanceFromCenter)   distanceFromCenter   = sqrt(pow(double(xNormalized),2.0)+pow(double(yNormalized),2.0)+pow(double(zNormalized),2.0));			
			if(addDistanceFromCenterXY) distanceFromCenterXY = sqrt(pow(double(xNormalized),2.0)+pow(double(yNormalized),2.0));
			if(addDistanceFromCenterYZ) distanceFromCenterYZ = sqrt(pow(double(yNormalized),2.0)+pow(double(zNormalized),2.0));
			if(addDistanceFromCenterXZ) distanceFromCenterXZ = sqrt(pow(double(xNormalized),2.0)+pow(double(zNormalized),2.0));				
			if(addArcTan2) arcTan2Val = atan2(yNormalized, zNormalized);
			
			network.reinitialize();								//reset CPPN
			network.setValue("x",xNormalized);					//set the input numbers
			network.setValue("y",yNormalized);
			network.setValue("z",zNormalized);
			if(addDistanceFromCenter) network.setValue("d",distanceFromCenter);
			if(addDistanceFromCenterXY) network.setValue("dxy",distanceFromCenterXY);
			if(addDistanceFromCenterYZ) network.setValue("dyz",distanceFromCenterYZ);
			if(addDistanceFromCenterXZ) network.setValue("dxz",distanceFromCenterXZ);
			//if(addDistanceFromShell) network.setValue("ds",e); //ACHEN: Shell distance
			//if(addInsideOrOutside) network.setValue("inout",e);
			if(addArcTan2) network.setValue("arcTan2",arcTan2Val);
			network.setValue("Bias",0.3);                       
							
			network.update();                                   //JMC: on this line we run the CPPN network...  
			
			ContinuousArray[j] = network.getValue("Output");        //JMC: and here we get the CPPN output (which is the weight of the connection between the two)
			if(useColor){
				rColorArray[j]     = network.getValue("Output-colorR");
				gColorArray[j]     = network.getValue("Output-colorG");
				bColorArray[j]     = network.getValue("Output-colorB");
			}
			

		}

		int numberSameVoxels = compareEvolvedArrayToTargetArray(ContinuousArray);
		double percentSameVoxels = double(numberSameVoxels)/double(ContinuousArray.GetFullSize());
		
		
		PRINT(percentSameVoxels);
		
		
		//std::cout << "Performing marching cubes...\n";
		CMesh OutputMesh;
		CMarchCube::SingleMaterial(&OutputMesh, &ContinuousArray, voxelExistsThreshold);	//jmc: last argument is the threshold above which we consider the voxel to be extant

		//save stl file for new all-time highs
		if (percentSameVoxels - maxPercentSoFar > 0.001)
		{	
			printf("++++++++++++++++++++++++++++++++ New all time high! PercentSameVoxelx = %f\n", percentSameVoxels);
			maxPercentSoFar = percentSameVoxels;
			allTimeHighCounter++;

			string suffix = ".stl";
			string allTimeNumAsString;
			string percentSameVoxelsAsFloat; 

			//convert allTimeHigh to string
			std::stringstream tempVar;
			std::stringstream tempVarPercent;
			tempVar << allTimeHighCounter;
			allTimeNumAsString = tempVar.str();
			tempVarPercent << percentSameVoxels;
			percentSameVoxelsAsFloat = tempVarPercent.str();
			
			string filename = "ChamNum" + allTimeNumAsString + "-Fit_" + percentSameVoxelsAsFloat + suffix;
			cout << "filename is " << filename << endl;
			
				std::cout << "Saving file - " << filename << endl;
		}


		//Draw function goes here
		#ifdef VISUALIZESHAPES
		//InteractiveFitnessScore = drawShape(EvolvingInteractive, OutputMesh); //InteractiveFitnessScore ignored in target based evolution
		#endif
		
		double fitness = 0;
		if(EvolvingInteractive){ fitness = double(InteractiveFitnessScore); PRINT(InteractiveFitnessScore);}  
		else if (EvolvingTarget) fitness = double(percentSameVoxels); 
		else {cout << "error: what is your fitness function?" << endl; exit(-1);}
		
		double exponentiatedFitness = pow(2000,double(fitness));
		assert(exponentiatedFitness >0);						//no fitness scores of zero allowed

		return exponentiatedFitness; 

    }
Beispiel #8
0
void populateSubstrate(boost::shared_ptr<const NEAT::GeneticIndividual> individual) {
	NEAT::FastNetwork<double> network = individual->spawnFastPhenotypeStack<
			double> ();
	// for all nodes in the source layer
	for (int y1 = 0; y1 < numNodesY; y1++) {
		for (int x1 = 0; x1 < numNodesX; x1++) {

			// compute source node's coordinates in the NEAT nodeLookup
			const int x1mod = x1 - numNodesX / 2;
			const int y1mod = y1 - numNodesY / 2;

			// compute source node's coordinates in the CPPN
			const double x1normal = (x1 - numNodesX / 2) / double((numNodesX
					- 1) / 2);
			const double y1normal = (y1 - numNodesY / 2) / double((numNodesY
					- 1) / 2);

			// for all nodes in the target layer
			for (int y2 = 0; y2 < numNodesY; y2++) {
				for (int x2 = 0; x2 < numNodesX; x2++) {
				   for(int z1normal = -1; z1normal <= 0; z1normal+=1) {
					// compute target node's coordinates in the NEAT nodeLookup
					const int x2mod = x2 - numNodesX / 2;
					const int y2mod = y2 - numNodesY / 2;

					// compute target node's coordinates in the CPPN
					const double x2normal = (x2 - numNodesX / 2)
							/ double((numNodesX - 1) / 2);
					const double y2normal = (y2 - numNodesY / 2)
							/ double((numNodesY - 1) / 2);

					double z2normal = z1normal + 1;

					//// set up the CPPN input

					network.reinitialize();
					network.setValue("X1", x1normal);
					network.setValue("Y1", y1normal);
					network.setValue("Z1", x2normal);

					network.setValue("X2", y2normal);
					network.setValue("Y2", x2normal);
					network.setValue("Z2", y2normal);

					/// work transparently with Deltas
					if (network.hasNode("DeltaX") && network.hasNode("DeltaY") && network.hasNode("DeltaZ")) {
						network.setValue("DeltaX", x2normal - x1normal);
						network.setValue("DeltaY", y2normal - y1normal);
						network.setValue("DeltaZ", z2normal - z1normal);
					}

					/// work transparently with homogeneous & heterogeneous controllers
					if (heterogeneous_controller == true && network.hasNode(
							"T1") && network.hasNode("T2")) {
						//						screen << "Working with heterogeneous controllers"<<endl;
						double t1normal;
						double t2normal;

						double bodyLength(3.0); // Was 3.0 for original layout

						if (id <= 7) {
							t1normal = (id - 4) / bodyLength;
							t2normal = 0.25;
						} else {
							t1normal = (id - 13) / bodyLength;
							t2normal = -0.25;
						}

						network.setValue("T1", t1normal);
						network.setValue("T2", t2normal);

						if (network.hasNode("DeltaT")) {
							network.setValue("DeltaT", sqrt(t1normal * t1normal +  t2normal * t2normal)); //  (t2normal - t1normal)
						}
					} else {
						//						screen << "Working with homogeneous controllers"<<endl;
						heterogeneous_controller = false;
					}

					if (network.hasNode("Bias")) {
						// set CPPN bias
						network.setValue("Bias", CPPN_BIAS);
					}

					// propagate CPPN
					network.update();

					// get the weights for the two links between selected source-target
					// coordinates, between layers A & B, and B & C
					double output = network.getValue("Output");

					NetworkIndexedLink<double>* link;

					/// get NEAT network link object
					link = substrate.getLink(nameLookup[Node(x1mod, y1mod, z1normal + 1)],
							nameLookup[Node(x2mod, y2mod, z2normal + 1)]);

					/// set link value according to threshold

					output = pow(output, 171);

					if (fabs(output) > WEIGHT_TRESHOLD) {
						if (output > 0.0)
							link->weight = output * WEIGHT_SCALER;
						else
							link->weight = output * WEIGHT_SCALER;
					} else {
						link->weight = (0.0);
					}

				#ifdef USE_BIASES
				if(network.hasNode("Bias_out")){
					/// set the node's  biases using just the (x1,y1) values provided
					/// by the CPPN for the biases
					if (x2 == 0 && y2 == 0 && z2normal == 1)  {
						double nodeBias;
						// bias for target node
						nodeBias = network.getValue("Bias_out");
						substrate.setBias(nameLookup[Node(x1mod, y1mod, z2normal + 1)],
								nodeBias);

					}
				}
				#endif
			   }

			 }
			}
		}
	}
}