void FastLayeredNetwork<Type>::setLink(const Node &fromNodeIndex,const Node &toNodeIndex,Type weight)
    {
        if(toNodeIndex.z>=(int)layers.size() || fromNodeIndex.z>=(int)layers.size())
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
        }

        NetworkLayer<Type> &toLayer = layers[toNodeIndex.z];

        for(int a=0;a<(int)toLayer.fromLayers.size();a++)
        {
            if(toLayer.fromLayers[a] != fromNodeIndex.z)
            {
                //Not the source layer we are looking for
                continue;
            }

            NetworkLayer<Type> &fromLayer = layers[toLayer.fromLayers[a]];

            int fromNodeArrayIndex = fromNodeIndex.y*fromLayer.nodeStride + fromNodeIndex.x;
            int toNodeArrayIndex = toNodeIndex.y*toLayer.nodeStride + toNodeIndex.x;
            if(fromNodeArrayIndex>(int)fromLayer.nodeValues.size() || toNodeArrayIndex>(int)toLayer.nodeValues.size())
            {
                throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
            }

            toLayer.fromWeights[a][toNodeArrayIndex*toLayer.nodeValues.size()+fromNodeArrayIndex] = weight;
            return;
        }

        throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
    }
  void ExperimentRun::setupExperiment(int _experimentType, string _outputFileName)
  {
    experimentType = _experimentType;
    outputFileName = _outputFileName;
		
    cout << "SETTING UP EXPERIMENT TYPE: " << experimentType << endl;
		
    switch (experimentType)
      {
      case EXPERIMENT_RCQUADRATOT:
        experiments.push_back(shared_ptr<Experiment>(new RCQuadratotExperiment("")));
        break;
				
      default:
        cout << string("ERROR: Unknown Experiment Type!\n");
        throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Unknown Experiment Type!");
      }
    for (int a=1;a<NUM_THREADS;a++)
      {
        if(totalSubExperiments > 1) {
          cerr << "ERROR: cannot have a hybrid experiment with multiple treads!\n";
          exit(1);						
        }
        experiments.push_back(shared_ptr<Experiment>(experiments[0]->clone()));
      }
		
  }
Globals::Globals(string fileName)
    :
    nodeCounter(0),
    linkCounter(0),
    speciesCounter(0)
{
    cout << "Populating sigmoid table...";
    for (int a=0; a<6001; a++)
    {
        signedSigmoidTable[a] = ((1 / (1+exp(-((a-3000)/1000.0)))) - 0.5)*2.0;
        unsignedSigmoidTable[a] = 1 / (1+exp(-((a-3000)/1000.0)));
    }
    cout << "done!\n";

    cout << "Loading Parameter data from " << fileName << endl;

    if (fileName==string(""))
    {
        return;
    }

    ifstream infile;
    infile.open(fileName.c_str());

    if (infile.is_open()==false)
    {
        throw CREATE_LOCATEDEXCEPTION_INFO(string("COULD NOT OPEN GLOBALS .dat FILE: ")+fileName);
    }

    string line="test";
    istringstream instream;
    while (getline(infile,line))
    {
#if DEBUG_NEAT_GLOBALS
        cout << "LINE: " << line << endl;
#endif
#ifdef linux
        if (int(line[line.size()-1])==13) //DOS line breaks
            line.erase(line.begin()+(int(line.size())-1));
#endif
        if (line[0]==';') //comment
        {
            continue;
        }
        if (line.size()==0)
        {
            continue;
        }
        istringstream input(line);
        string parameterName;
        double value=0.0;
        input >> parameterName >> value;
        parameters.insert(parameterName,value);
    }

    cacheParameters();

    initRandom();
}
    void FastLayeredNetwork<Type>::setValue(const Node &nodeIndex,Type newValue)
    {
        if(nodeIndex.z>=(int)layers.size())
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
        }

        NetworkLayer<Type> &layer = layers[nodeIndex.z];

        int nodeArrayIndex = nodeIndex.y*layer.nodeStride + nodeIndex.x;
        if(nodeArrayIndex>(int)layer.nodeValues.size())
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
        }

        layer.nodeValues[nodeArrayIndex] = newValue;
    }
Beispiel #5
0
    Type GPUANN<Type>::getValue(const Node &nodeIndex)
    {
        if(nodeIndex.z>=(int)layers.size())
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
        }

        NetworkLayer<Type> &layer = layers[nodeIndex.z];

        int nodeArrayIndex = nodeIndex.y*layer.nodeStride + nodeIndex.x;
        if(nodeArrayIndex>(int)layer.nodeValues.size())
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("OOPS");
        }

        return layer.nodeValues[nodeArrayIndex];
    }
    GeneticPopulation::GeneticPopulation(string fileName)
            : onGeneration(-1)
    {
        TiXmlDocument doc(fileName);

        bool loadStatus;

        if (iends_with(fileName,".gz"))
        {
            loadStatus = doc.LoadFileGZ();
        }
        else
        {
            loadStatus = doc.LoadFile();
        }

        if (!loadStatus)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("Error trying to load the XML file!");
        }

        TiXmlElement *root;

        root = doc.FirstChildElement();

        {
            TiXmlElement *generationElement = root->FirstChildElement("GeneticGeneration");

            while (generationElement)
            {
                generations.push_back(shared_ptr<GeneticGeneration>(new GeneticGeneration(generationElement)));

                generationElement = generationElement->NextSiblingElement("GeneticGeneration");
                onGeneration++;
            }
        }

        if (onGeneration<0)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("Tried to load a population with no generations!");
        }

        adjustFitness();
    }
    const GeneticLinkGene *GeneticIndividual::getLink(int fromNodeID,int toNodeID) const
    {
        for (int a=0;a<(int)links.size();a++)
        {
            if (links[a].getFromNodeID()==fromNodeID&&links[a].getToNodeID()==toNodeID)
                return &links[a];
        }

        throw CREATE_LOCATEDEXCEPTION_INFO("Tried to get a link which doesn't exist!");
    }
    vector<shared_ptr<GeneticIndividual> >::iterator GeneticPopulation::getIndividualIterator(int a, int generation) {
        if (generation == -1)
            generation = int(generations.size() - 1); //onGeneration);

        if (generation >= int(generations.size()) || a >= generations[generation]->getIndividualCount()) {
            throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Generation out of range!\n");
        }

        return generations[generation]->getIndividualIterator(a);
    }
RelativePosition RoombotBuildPlan::getMinimalPosition() const
{
    if(positions.size() == 0) throw CREATE_LOCATEDEXCEPTION_INFO ("Can not get minimal position in empty buildplan");
    RelativePosition result = positions.at(0);
    
    for(size_t i=1; i<positions.size(); i++){
        if(positions.at(i) < result){
            result = positions.at(i);
        }
    }
    
    return result;
}
Beispiel #10
0
    int Random::getRandomWithinRange(int min,int max)
    {
        int randNum = min + (intGen()%( (max-min) + 1));

#if DEBUG_RANDOM
        if(randNum<min || randNum>max)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Random number out of range!");
        }
#endif

        return randNum;
    }
Beispiel #11
0
    double Random::getRandomDouble(double low,double high)
    {
        double randNum = realGen()*(high-low) + low;

#if DEBUG_RANDOM
        if(randNum<low || randNum>=high)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Random number out of range!");
        }
#endif

        return randNum;
    }
Beispiel #12
0
    int Random::getRandomInt(int limit)
    {
        int randNum = intGen()%limit;

#if DEBUG_RANDOM
        if(randNum<0 || randNum>=limit)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Random number out of range!");
        }
#endif

        return randNum;
    }
Beispiel #13
0
    double Random::getRandomDouble()
    {
        double randNum = realGen();

#if DEBUG_RANDOM
        if(randNum<0.0 || randNum>=1.0)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Random number out of range!");
        }
#endif

        return realGen();
    }
Node * RoombotModule::getNode(Field * field, std::string name) const
{
    int fieldCount = field->getCount();
    Node * node;
    Field * nameField;
    
    if (fieldCount == -1)
        throw CREATE_LOCATEDEXCEPTION_INFO("Field is not a multi-field.");
    
    for (int i = 0; i < fieldCount; i++) {
        node = field->getMFNode(i);
        nameField = node->getField("name");
        
        if (nameField != NULL) {
            
            if (nameField->getSFString().compare(name) == 0) {
                return node;
            }
        }
    }
    
    throw CREATE_LOCATEDEXCEPTION_INFO("Field: " + name + " not found.");
}
    void GeneticGeneration::cleanup()
    {
        if (!sortedByFitness)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("You aren't supposed to acll this until you sort by fitness!");
        }

        while (individuals.size()>1)
        {
            //cout << "CLEANING UP!\n";
            //Never delete the generation champion (remember that they are sorted by fitness at this point).

            individuals.erase(individuals.begin()+1);
        }
    }
  void ExperimentRun::setupExperimentInProgressUseDat(string _datFile, string populationFileName,string _outputFileName)
  {
    outputFileName = _outputFileName;
    //datFile = _datFile;
    PRINT(populationFileName);
    {
      TiXmlDocument doc(populationFileName);
			
      bool loadStatus;
			
      if (iends_with(populationFileName,".gz"))
        {
          loadStatus = doc.LoadFileGZ();
        }
      else
        {
          loadStatus = doc.LoadFile();
        }
			
      if (!loadStatus)
        {
          cerr << "Error trying to load the XML file!" << endl;
          throw CREATE_LOCATEDEXCEPTION_INFO("Error trying to load the XML file!");
        }
			
      TiXmlElement *element = doc.FirstChildElement();
			
      NEAT::Globals* globals = NEAT::Globals::init(element);
      (void) globals; //to get rid of unused variable warning
			
      NEAT::Globals::getSingleton()->overrideParametersFromFile(_datFile);
      NEAT::Globals::getSingleton()->setOutputFilePrefix(outputFileName); //set the name of the outputPrefixFile                                                                                                                                                                                               
			
      //Destroy the document
    }
		
    int experimentType = int(NEAT::Globals::getSingleton()->getParameterValue("ExperimentType")+0.001);
		
    cout << "Loading Experiment: " << experimentType << endl;
		
    setupExperiment(experimentType,_outputFileName);
		
    cout << "Experiment set up.  Creating population...\n";
		
    createPopulation(populationFileName);
		
    cout << "Population Created\n";
  }
Beispiel #17
0
Globals::Globals(TiXmlElement *root)
    :
    nodeCounter(-1),
    linkCounter(-1),
    speciesCounter(-1)
{
    cout << "Populating sigmoid table...";
    for (int a=0; a<6001; a++)
    {
        signedSigmoidTable[a] = ((1 / (1+exp(-((a-3000)/1000.0)))) - 0.5)*2.0;
        unsignedSigmoidTable[a] = 1 / (1+exp(-((a-3000)/1000.0)));
    }
    cout << "done!\n";

    TiXmlAttribute *firstAttribute = root->FirstAttribute();

    while (firstAttribute)
    {
        if (iequals(firstAttribute->Name(),"NodeCounter"))
        {
            nodeCounter = firstAttribute->IntValue();
        }
        else if (iequals(firstAttribute->Name(),"LinkCounter"))
        {
            linkCounter = firstAttribute->IntValue();
        }
        else if (iequals(firstAttribute->Name(),"SpeciesCounter"))
        {
            speciesCounter = firstAttribute->IntValue();
        }
        else
        {
            addParameter( firstAttribute->Name() , firstAttribute->DoubleValue());
        }

        firstAttribute = firstAttribute->Next();
    }

    if (nodeCounter==-1 || linkCounter==-1 || speciesCounter==-1)
    {
        throw CREATE_LOCATEDEXCEPTION_INFO("MALFORMED XML!");
    }

    cacheParameters();

    initRandom();
}
    FastLayeredNetwork<Type>::FastLayeredNetwork(const vector<NetworkLayer<Type> > &_layers)
        :
        Network<Type>(),
        layers(_layers)
    {
        //Perform a sanity check on the layers
        for(size_t toLayer=0;toLayer<layers.size();toLayer++)
        {
            for(int a=0;a<(int)layers[toLayer].fromLayers.size();a++)
            {
                size_t fromLayer = layers[toLayer].fromLayers[a];

                if(fromLayer>=toLayer)
                {
                    throw CREATE_LOCATEDEXCEPTION_INFO("Network is not feed-forward!");
                }
            }
        }
    }
    void GeneticIndividual::addNode(GeneticNodeGene node)
    {
        int nodeID = node.getID();
        for (int a=0;a<(int)nodes.size();a++)
        {
            int curID = nodes[a].getID();
            if (curID==nodeID)
			{
                throw CREATE_LOCATEDEXCEPTION_INFO("Oops, tried to add a node when it already existed!");
			}
            else if (curID>nodeID)
            {
                nodes.insert(nodes.begin()+a,node);
                return;
            }
        }

        nodes.push_back(node);
    }
    shared_ptr<GeneticIndividual> GeneticPopulation::getIndividual(int a, int generation) {
#ifdef DEBUG_GENPOP
        cout << a << ',' << generations.size() << endl;
#endif
        if (generation == -1) {
#ifdef DEBUG_GENPOP
            cout << "NO GEN GIVEN: USING onGeneration\n";
#endif
            generation = int(generations.size() - 1); //onGeneration);
        }

        if (generation >= int(generations.size()) || a >= generations[generation]->getIndividualCount()) {
            cout << "GET_INDIVIDUAL: GENERATION OUT OF RANGE!\n";
            throw CREATE_LOCATEDEXCEPTION_INFO("GET_INDIVIDUAL: GENERATION OUT OF RANGE!\n");
        }
#ifdef DEBUG_GENPOP
        cout << "return" << endl;
#endif
        return generations[generation]->getIndividual(a);
    }
    void GeneticIndividual::addLink(GeneticLinkGene link)
    {
        int linkID = link.getID();
        for (int a=0;a<(int)links.size();a++)
        {
            int curID = links[a].getID();
            if (curID==linkID)
            {
                throw CREATE_LOCATEDEXCEPTION_INFO("Oops, tried to add a link when it already existed!");
            }

            else if (curID>linkID)
            {
                links.insert(links.begin()+a,link);
                return;
            }
        }

        links.push_back(link);
    }
    void ExperimentRun::start()
    {
        if(true) {//NEAT::Globals::getSingleton()->getParameterValue("MultiObjective") > 0.5) {
            boost::filesystem::remove(outputFileName);
            boost::filesystem::remove(outputFileName+string(".gz"));
        }
        cout << "Experiment started\n";
#ifndef _DEBUG
        try
        {
#endif

            int maxGenerations = int(NEAT::Globals::getSingleton()->getParameterValue("MaxGenerations"));

            started=running=true;

            clock_t start,current,reference;
            start  = clock();
            reference = clock();

			
			//resuming an old experiment, want to produce next gen right away because last one already evaluated
			if ((population->getGenerationCount()-1) > 0) { 
                mutex::scoped_lock scoped_lock(*populationMutex);

                cout << "PRODUCING NEXT GENERATION\n";
                produceNextGeneration();
                cout << "DONE PRODUCING\n";							
			}
			
			int startGen = population->getGenerationCount()-1;
			
            for (int generations=(population->getGenerationCount()-1);generations<maxGenerations;generations++)
            {            
                current = clock();
                double time = (double(current)-double(reference))/CLOCKS_PER_SEC;
                if(time >= 3600.0 ) { //if at least an hour elapsed
                    double elapsed = (double(current)-double(start))/CLOCKS_PER_SEC;
                    printf("TIME_STATS: best fitness = %5.5f, generation = %d, elapsed time = %5.5f s\n", population->getBestAllTimeIndividual()->getFitness(), generations - 1,elapsed);
                    reference = clock();
                }

                if (generations>startGen)
                {
                    mutex::scoped_lock scoped_lock(*populationMutex);
                    //set IDs before reproducing so maintain ancestry -- NO LONGER NEEDED SINCE IDs will have been set in finishEvaluations
					//population->getGeneration()->setIDs();

                    cout << "PRODUCING NEXT GENERATION\n";
                    produceNextGeneration();
                    cout << "DONE PRODUCING\n";

//                    cout << "DUMPING REPRODUCED FROM PREVIOUS GENERATION\n";
//                    population->dumpReproducedFromPreviousGeneration(outputFileName/*+string(".backup.xml")*/,true,true);
//                    cout << "DONE DUMPING\n";
                }

                if (experiments[0]->performUserEvaluations())
                {
#ifdef HCUBE_NOGUI
                    throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: TRIED TO USE INTERACTIVE EVOLUTION WITH NO GUI!");
#else
                    frame->getUserEvaluationFrame()->updateEvaluationPanels();
                    running=false;
                    while (!running)
                    {
                        boost::xtime xt;
                        boost::xtime_get(&xt, boost::TIME_UTC);
                        xt.sec += 1;
                        boost::thread::sleep(xt); // Sleep for 1/2 second
                        //cout << "Sleeping while user evaluates!\n";
                    }
#endif
                }
                else
                {
                    while (!running)
                    {
                        boost::xtime xt;
                        boost::xtime_get(&xt, boost::TIME_UTC);
                        xt.sec += 1;
                        boost::thread::sleep(xt); // Sleep for 1/2 second
                    }
                    evaluatePopulation();
                }

                cout << "Finishing evaluations\n";
                finishEvaluations();
                cout << "Evaluations Finished\n";
            }

            //if want to dump all will be taken care of from finishEvaluations now for all gens
            //cout << "DUMPING ALL INDIVIDUALS FROM FINAL GENERATION\n";
            //population->getGeneration()->setIDs();
            //population->dump(outputFileName/*+string(".backup.xml")*/,true,true);
            //cout << "DONE DUMPING\n";

            cout << "Experiment finished\n";

            //cout << "Saving Dump...";
            //population->dump(outputFileName,true,false);
            //cout << "Done!\n";


            if(true) {//NEAT::Globals::getSingleton()->getParameterValue("MultiObjective") > 0.5) {
                //need to combine files into one
                //TiXmlDocument doc();
                TiXmlElement *root = new TiXmlElement("Genetics");
                NEAT::Globals::getSingleton()->dump(root);


                /*
                stringstream ss;
                //root->Print(ss,0);


                ss << root;
                string s = ss.str();

                */
                cout << "Merging Output Files...";

                TiXmlPrinter rootPrinter;
                root->Accept( &rootPrinter );
                string s = rootPrinter.CStr();

                ofstream out( outputFileName.c_str() );
                string lastGenFileName = outputFileName + string(".lastgen.xml");
                ofstream out2( lastGenFileName.c_str() );

                out << s.substr(0, s.length() - 3) << ">" <<endl;
                out2 << s.substr(0, s.length() - 3) << ">" <<endl;

                int maxGenerations = int(NEAT::Globals::getSingleton()->getParameterValue("MaxGenerations"));
                for(int i=0; i<maxGenerations; i++) {
                    stringstream ss;
                    ss << i;
                    TiXmlDocument doc( outputFileName + string("-") + ss.str() + string(".backup.xml.gz") );
                    doc.LoadFileGZ();
                    TiXmlPrinter printer;
                    doc.Accept(&printer);
                    out << printer.CStr() << endl;
                    if( i == (maxGenerations - 1))
                        out2 << printer.CStr() << endl;
                }
                out << "</Genetics>" << endl;
                out2 << "</Genetics>" << endl;
                out.close();
                out2.close();
                cout << "Done!\n";
                cout << "Compressing Merged File...";
                stringstream ss;
                ss << "gzip " << outputFileName;
                std::system(ss.str().c_str());
                stringstream ssLastGen;
                ssLastGen << "gzip " << lastGenFileName;
                std::system(ssLastGen.str().c_str());

                cout << "Done!\n";
                cout << "Deleting backup files...";
                for(int i=0; i<maxGenerations; i++) {
                    stringstream ss2;
                    ss2 << outputFileName << "-" << i << ".backup.xml.gz";
                    boost::filesystem::remove(ss2.str());
                }
                boost::filesystem::remove(outputFileName + string("-root.backup.xml"));
                cout << "Done!\n";


            } else {
                cout << "Saving best individuals...";
                string bestFileName = outputFileName.substr(0,outputFileName.length()-4)+string("_best.xml");
                population->dumpBest(bestFileName,true,true);
                cout << "Done!\n";

                cout << "Deleting backup file...";
                boost::filesystem::remove(outputFileName+string(".backup.xml"));
                cout << "Done!\n";
            }
#ifndef _DEBUG
        }
        catch (const std::exception &ex)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(ex.what());
        }
        catch (...)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE("AN UNKNOWN EXCEPTION HAS BEEN THROWN!");
        }
#endif
    }
    bool GeneticIndividual::mutateAddNode(int fromNodeID,int toNodeID)
    {
        if (fromNodeID>=0&&fromNodeID==toNodeID)
        {
            throw CREATE_LOCATEDEXCEPTION_INFO("Error: Tried to create a node within a loop connection");
        }

        GeneticLinkGene *randomLink;

        bool allowAddNodeToRecurrentConnection
            = (
            Globals::getSingleton()->getParameterValue("AllowAddNodeToRecurrentConnection")>
            Globals::getSingleton()->getRandom().getRandomDouble()
            );

        int chances=0;
        //cout << __FILE__ << ": Trying to add a node\n";


        int tmpFromNodeID,tmpToNodeID;

		int randomLinkIndex;

        while (true)
        {
            chances++;
			//cout << "Trying to add node...\n";
            if (chances>=200000)
            {
                //cout << "Blown second chance limit.  Giving up\n";
                return false;
            }
            if (chances>=100000)
            {
				randomLinkIndex = (randomLinkIndex+1)%links.size();
				//cout << "Blown chance limit.  incrementing over all possible links\n";
            }
			else
			{
				//This loop ensures that you don't get a recurrent or loop connection when you add complexity.
				randomLinkIndex = Globals::getSingleton()->getRandom().getRandomInt(int(links.size()));
			}

            if (fromNodeID>=0)
            {
                randomLink = getLink(fromNodeID,toNodeID);

                tmpFromNodeID = fromNodeID;
                tmpToNodeID = toNodeID;
            }
            else
            {
                randomLink = &links[randomLinkIndex];

                tmpFromNodeID = randomLink->getFromNodeID();
                tmpToNodeID = randomLink->getToNodeID();
				
				//cout << "IDs: " << tmpFromNodeID << " , " << tmpToNodeID << endl;
            }

            if (tmpFromNodeID==tmpToNodeID)
            {
                //loop link, try again
				//cout << "Loop link, ignore\n";
                continue;
            }

            GeneticNodeGene *fromNode=NULL,*toNode=NULL;

            for (int a=0;a<(int)nodes.size();a++)
            {
                //This loop goes through and gets the sum of the two nodes' drawing positions for averaging.
                if (nodes[a].getID()==tmpFromNodeID)
                    fromNode = &nodes[a];

                if (nodes[a].getID()==tmpToNodeID)
                    toNode = &nodes[a];
            }

            if (!fromNode->isEnabled() || !toNode->isEnabled())
            {
                //Disabled nodes, don't add anything.
				//cout << "One of the nodes is disabled...\n";
                continue;
            }

            if (fromNode->getDrawingPosition()>=toNode->getDrawingPosition())
            {
                //Recurrent connection.
				//cout << "Recurrent connection.  Ignoring\n";
                if (!allowAddNodeToRecurrentConnection)
                    continue;
            }

            if(fromNode->isTopologyFrozen() && toNode->isTopologyFrozen())
            {
				//cout << "Topology frozen on both nodes.  Ignoring\n";
                //Don't add links between two frozen topology nodes
                continue;
            }

            double newPosition = (fromNode->getDrawingPosition()+toNode->getDrawingPosition())/2.0;

            randomLink->setAge(0);
            randomLink->setWeight(randomLink->getWeight()/2.0);

            bool randomActivation=false;

            if (Globals::getSingleton()->getParameterValue("ExtraActivationFunctions")>Globals::getSingleton()->getRandom().getRandomDouble())
                randomActivation=true;

            GeneticNodeGene newNode = GeneticNodeGene("","HiddenNode",newPosition,randomActivation);

            GeneticLinkGene sourceLink = GeneticLinkGene(randomLink->getFromNodeID(),newNode.getID(),1.0);
            GeneticLinkGene destLink = GeneticLinkGene(newNode.getID(),randomLink->getToNodeID(),randomLink->getWeight()/2.0);

            addNode(newNode);
            addLink(sourceLink);
            addLink(destLink);
            if (Globals::getSingleton()->getParameterValue("AddBiasToHiddenNodes")>Globals::getSingleton()->getRandom().getRandomDouble())
            {
                int biasNodeID=-1;
                for (int a=0;a<(int)nodes.size();a++)
                {
                    if (nodes[a].getName()==string("Bias"))
                    {
                        biasNodeID=(int)a;
                        break;
                    }
                }

                if (biasNodeID==-1)
                {
                    throw CREATE_LOCATEDEXCEPTION_INFO("Error, tried to add link from bias node when biad node didn't exist!");
                }

                if (randomLink->getFromNodeID()==biasNodeID)
                {
                    //Oops, the from link was already the bias node, don't bother
                }
                else
                {
                    GeneticLinkGene biasLink = GeneticLinkGene(biasNodeID,newNode.getID(),0.0);
                    addLink(biasLink);
                }
            }
            return true;
        }
    }
    void EvaluationSet::run()
    {
#ifndef _DEBUG
        try
#endif
        {
            //Process individuals sequentially
            running=true;

            vector<shared_ptr<NEAT::GeneticIndividual> >::iterator tmpIterator;

            tmpIterator = individualIterator;
            for (int a=0;a<individualCount;a++,tmpIterator++)
            {
                while (!running)
                {
                    boost::xtime xt;
                    boost::xtime_get(&xt, boost::TIME_UTC_);
                    xt.sec += 1;
                    boost::thread::sleep(xt); // Sleep for 1 second
                }

                experiment->addIndividualToGroup(*tmpIterator);

                if (experiment->getGroupSize()==experiment->getGroupCapacity())
                {
                    //cout << "Processing group...\n";
                    experiment->processGroup(generation);

                    //cout << "Done Processing group\n";
                    experiment->clearGroup();
                }
            }

            if (experiment->getGroupSize()>0)
            {
                //Oops, maybe you specified a bad # of threads?
                throw CREATE_LOCATEDEXCEPTION_INFO("Error, individuals were left over after run finished!");
            }

            finished=true;
        }
#ifndef _DEBUG
        catch (string s)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(s);
        }
        catch (const char *s)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(s);
        }
        catch (const std::exception &ex)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(ex.what());
        }
        catch (...)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE("An unknown exception has occured!");
        }
#endif
    }
    void EvaluationSet::run()
    {
#ifndef _DEBUG
        try
#endif
        {
            //Process individuals sequentially
            running=true;

            vector<shared_ptr<NEAT::GeneticIndividual> >::iterator tmpIterator;

            tmpIterator = individualIterator;
            for (int a=0;a<individualCount;a++,tmpIterator++)
            {
                while (!running)
                {
                    boost::xtime xt;
                    boost::xtime_get(&xt, boost::TIME_UTC); //(nac: changed for latest version of boost)
                    xt.sec += 1;
					cout << "jmc: used1!\n"; exit(3);
                    boost::thread::sleep(xt); // Sleep for 1 second
                }

                experiment->addIndividualToGroup(*tmpIterator);

                if (experiment->getGroupSize()==experiment->getGroupCapacity())
                {
                    //cout << "Processing group...\n";
                    experiment->processGroup(generation);
                    //cout << "Done Processing group\n";
                    experiment->clearGroup();
                }
            }

            if (experiment->getGroupSize()>0)
            {
                //Oops, maybe you specified a bad # of threads?
                throw CREATE_LOCATEDEXCEPTION_INFO("Error, individuals were left over after run finished! Do you have the c++ flag -DINTERACTIVELYEVOLVINGSHAPES set? Did you set getGroupCapacity to return the pop size in HCUBE_Experiment.h? or there may have been a bad (or negative, or zero) fitness value for an organism?");
            }

            finished=true;
        }
#ifndef _DEBUG
        catch (string s)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(s);
        }
        catch (const char *s)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(s);
        }
        catch (const std::exception &ex)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE(ex.what());
        }
        catch (...)
        {
			cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
            CREATE_PAUSE("An unknown exception has occured!");
        }
#endif
    }
    void ExperimentRun::setupExperimentInProgress(
        string populationFileName,
        string _outputFileName
    )
    {
        outputFileName = _outputFileName;

        {
            TiXmlDocument *doc = new TiXmlDocument(populationFileName);
            
            cout << "Loading population\n";

            bool loadStatus;

            if (iends_with(populationFileName,".gz"))
            {
                loadStatus = doc->LoadFileGZ();
            }
            else
            {
                loadStatus = doc->LoadFile();
            }

            if (!loadStatus)
            {
                throw CREATE_LOCATEDEXCEPTION_INFO("Error trying to load the XML file!");
            }

            TiXmlElement *element = doc->FirstChildElement();

            NEAT::Globals* globals = NEAT::Globals::init(element);
            
            //Destroy the document
            delete doc;
            
            cout << "Population loaded\n";


        }


        int experimentType = int(NEAT::Globals::getSingleton()->getParameterValue("ExperimentType")+0.001);

        NEAT::Globals::getSingleton()->seedRandom((unsigned int)(NEAT::Globals::getSingleton()->getParameterValue("ActualRandomSeed")+0.001));

        cout << "Loading Experiment: " << experimentType << endl;

        setupExperiment(experimentType,_outputFileName);

        cout << "Experiment set up.  Creating population...\n";

        createPopulation(populationFileName);

        cout << "Population Created\n";
        
        /*cout << "Cleaning up old generations\n";
        
		population->cleanupOld(population->getGenerationCount()-1);
		
		cout << "Done cleaning\n";*/
		
    }
    void GeneticPopulation::produceNextGeneration() {


        cout << "In produce next generation loop...\n";
        //This clears the link history so future links with the same toNode and fromNode will have different IDs
        Globals::getSingleton()->clearNodeHistory();
        Globals::getSingleton()->clearLinkHistory();

        int numParents = int(generations[generations.size() - 1/*onGeneration*/]->getIndividualCount());

        //check that no org has fitness <= zero
        for (int a = 0; a < numParents; a++) {
            PRINT(generations[generations.size() - 1/*onGeneration*/]->getIndividual(a)->getFitness());

            if (generations[generations.size() - 1/*onGeneration*/]->getIndividual(a)->getFitness() < 1e-6) {
                throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Fitness must be a positive number!\n");
            }
        }


        double totalFitness = 0;

        //get sum of adjusted fitness for all species together
        for (int a = 0; a < (int) species.size(); a++) {
            totalFitness += species[a]->getAdjustedFitness();
        }
        int totalOffspring = 0;
        //give each species a fitness proportional to its adjusted fitness
        for (int a = 0; a < (int) species.size(); a++) {
            double adjustedFitness = species[a]->getAdjustedFitness();
            int offspring = int(adjustedFitness / totalFitness * numParents);
            totalOffspring += offspring;
            species[a]->setOffspringCount(offspring);
        }
        //cout << "Pausing\n";
        //int result = system("PAUSE");
        //(void) result;

        //Some offspring were truncated.  Give these N offspring to the species that had the best N individuals
        while (totalOffspring < numParents) {
            for (int a = 0; totalOffspring < numParents && a < generations[generations.size() - 1/*onGeneration*/]->getIndividualCount(); a++) {
                shared_ptr<GeneticIndividual> ind = generations[generations.size() - 1/*onGeneration*/]->getIndividual(a);
                shared_ptr<GeneticSpecies> gs = getSpecies(ind->getSpeciesID());
                gs->setOffspringCount(gs->getOffspringCount() + 1);
                totalOffspring++;

                /*
                //Try to give 2 offspring to the very best individual if it only has one offspring.
                //This fixes the problem where the best indiviudal sits in his own species
                //and duplicates every generation.
                if(a==0&&gs->getOffspringCount()==1&&totalOffspring<numParents)
                {
                gs->setOffspringCount(gs->getOffspringCount()+1);
                totalOffspring++;
                }*/

            }
        }

        //report stats on species
        for (int a = 0; a < (int) species.size(); a++) {
            cout << "Species ID: " << species[a]->getID() << " Age: " << species[a]->getAge() << " last improv. age: " << species[a]->getAgeOfLastImprovement() << " Fitness: " << species[a]->getFitness() << "*" << species[a]->getMultiplier() << "=" << species[a]->getAdjustedFitness() << " Size: " << int(species[a]->getIndividualCount()) << " Offspring: " << int(species[a]->getOffspringCount()) << endl;
        }

        //jmc: This is the new generation container
        vector<shared_ptr<GeneticIndividual> > babies;

        double totalIndividualFitness = 0;

        //jmc: clear the flag of whether they have reproduced (I think that is what that flag does.)
        for (int a = 0; a < (int) species.size(); a++) {
            species[a]->setReproduced(false);
        }

        int smallestSpeciesSizeWithElitism = int(Globals::getSingleton()->getParameterValue("SmallestSpeciesSizeWithElitism"));
        static double mutateSpeciesChampionProbability = Globals::getSingleton()->getParameterValue("MutateSpeciesChampionProbability");

        double ForceCopyGenerationChampionParamVal = Globals::getSingleton()->getParameterValue("ForceCopyGenerationChampion");
        bool forceCopyGenerationChampion = (ForceCopyGenerationChampionParamVal > Globals::getSingleton()->getRandom().getRandomDouble()); //getRandom between but not including 0 and 1 (Avida RNG and NEAT)


        for (int a = 0; a < generations[generations.size() - 1/*onGeneration*/]->getIndividualCount(); a++) //Go through and add the species champions (including ties for champ, which jmc added)
 {
            shared_ptr<GeneticIndividual> ind = generations[generations.size() - 1/*onGeneration*/]->getIndividual(a);
            shared_ptr<GeneticSpecies> species = getSpecies(ind->getSpeciesID());
            //            if (!species->isReproduced())  //original code assumed it would only store the champ of each species, so if this flag works. but it doesn't work to preserve ties for champ.
            if (!species->isReproduced() //jmc: if the species has not been checked yet to determine the fitness of its champ
                    || ind->getFitness() == species->getBestIndividual()->getFitness()) //or if the fitness of this org equals the species champ
            {
                species->setReproduced(true);

                //This is the first and best organism of this species to be added, so it's the species champion
                //of this generation
                if (ind->getFitness() > species->getBestIndividual()->getFitness()) {
                    //We have a new all-time species champion!
                    species->setBestIndividual(ind);
                    cout << "Species " << species->getID() << " has a new champ with fitness " << species->getBestIndividual()->getFitness() << endl;
                }

                if ((a == 0 && forceCopyGenerationChampion) || (species->getOffspringCount() >= smallestSpeciesSizeWithElitism)) {
                    //Copy species champion.
                    bool mutateChampion;
                    if (Globals::getSingleton()->getRandom().getRandomDouble() < mutateSpeciesChampionProbability)
                        mutateChampion = true;
                    else {
                        mutateChampion = false;
                    }
                    babies.push_back(shared_ptr<GeneticIndividual>(new GeneticIndividual(ind, mutateChampion, babies.size())));
                    species->decrementOffspringCount();
                }

                if (a == 0) {
                    species->updateAgeOfLastImprovement();
                }
            }
            totalIndividualFitness += ind->getFitness();
        }

        double averageFitness = totalIndividualFitness / generations[generations.size() - 1/*onGeneration*/]->getIndividualCount();
        cout << "Generation " << int(onGeneration) << ": " << "overall_average = " << averageFitness << endl;

#ifdef PRINT_GENETIC_PERTUBATION_INFO
        //print the gen number to this file
        ofstream mutationEffects_file;
        mutationEffects_file.open("mutationEffects.txt", ios::app);
        mutationEffects_file << "\nGeneration " << int(onGeneration + 1) << ": " << endl; //plus 1 cause we print this line to the file before this gens data
        mutationEffects_file.close();

        ofstream mutationAndCrossoverEffects_file;
        mutationAndCrossoverEffects_file.open("mutationAndCrossoverEffects.txt", ios::app);
        mutationAndCrossoverEffects_file << "\nGeneration " << int(onGeneration + 1) << ": " << endl; //plus 1 cause we print this line to the file before this gens data
        mutationAndCrossoverEffects_file.close();

        ofstream crossoverEffects_file;
        crossoverEffects_file.open("crossoverEffects.txt", ios::app);
        crossoverEffects_file << "\nGeneration " << int(onGeneration + 1) << ": " << endl; //plus 1 cause we print this line to the file before this gens data
        crossoverEffects_file.close();
#endif


        cout << "Champion fitness: " << generations[generations.size() - 1/*onGeneration*/]->getIndividual(0)->getFitness() << endl;

        if (generations[generations.size() - 1/*onGeneration*/]->getIndividual(0)->getUserData()) {
            cout << "Champion data: " << generations[generations.size() - 1/*onGeneration*/]->getIndividual(0)->getUserData()->summaryToString() << endl;
        }
        cout << "# of Species: " << int(species.size()) << endl;
        cout << "compat threshold: " << Globals::getSingleton()->getParameterValue("CompatibilityThreshold") << endl;

        for (int a = 0; a < (int) species.size(); a++) {
            //cout << "jmc: Making babies for species" << a << endl;
            species[a]->makeBabies(babies);
        }
        //cout << "jmc: done making babies\n";
        if ((int) babies.size() != generations[generations.size() - 1/*onGeneration*/]->getIndividualCount()) {
            cout << "Population size changed! (or there may have been a bad (or negative, or zero) fitness value for an organism?)\n";
            throw CREATE_LOCATEDEXCEPTION_INFO("Population size changed!");
        }

        cout << "Making new generation\n";
        shared_ptr<GeneticGeneration> newGeneration(generations[generations.size() - 1/*onGeneration*/]->produceNextGeneration(babies, onGeneration + 1));
        //cout << "Done Making new generation!\n";

        /*for(int a=0;a<4;a++)
        {
        for(int b=0;b<4;b++)
        {
        cout << babies[a]->getCompatibility(babies[b]) << '\t';
        }

        cout << endl;
        }*/

        generations.push_back(newGeneration);
        onGeneration++;
    }
  void ExperimentRun::start()
  {
    cout << "Experiment started\n";
		

#ifndef DEBUG_EXPRUN
    try
      {
#endif
        int maxGenerations = int(NEAT::Globals::getSingleton()->getParameterValue("MaxGenerations"));
			
        started=running=true;
			
        for (int generations=(population->getGenerationCount()-1);generations<GET_PARAMETER("MaxGenerations");generations++)
          {
            cout << "CURRENT SUBEXPERIMENT: " << currentSubExperiment << " Generation:" << generations << endl;

            if (generations>0) 
              {
                // TODO: replace OR with experiments[currentSubExperiment].getExperimentName() == "HYBRID"
                if(experiments[currentSubExperiment]->getExperimentName() == "HYBRID" && switchSubExperiment(generations))
                  //					if((experimentType == EXPERIMENT_LEGSWING_HYBRID || experimentType == EXPERIMENT_BITMIRRORING_HYBRID || experimentType == EXPERIMENT_TARGETWEIGHTS_HYBRID) && switchSubExperiment(generations))
                  {
                    cout << "\n\n"
                         << "************************\n"
                         << "Switching SubExperiment:  Hyper -> FT\n"
                         << "************************\n\n";
                    // copy population from (currentSubExperiment-1)%totalSubExperiments to currentSubExperiment using HyperNEAT to P-NEAT converter
                    population = shared_ptr<NEAT::GeneticPopulation>(experiments[currentSubExperiment]->createInitialPopulation(population, experiments[(currentSubExperiment + 1) % totalSubExperiments]));
                    //TODO: check that this copying works
						
                    //THESE CAN COME OUT when Hyper -> NEAT works
                    cout << "changing the following three parameter settings from the HyperNEAT settings of:" << endl;
                    cout << "MutateAddNodeProbability: " << NEAT::Globals::getSingleton()->getParameterValue("MutateAddNodeProbability") << endl;
                    cout << "MutateAddLinkProbability: " << NEAT::Globals::getSingleton()->getParameterValue("MutateAddLinkProbability") << endl;
                    cout << "MutateDemolishLinkProbability: " << NEAT::Globals::getSingleton()->getParameterValue("MutateDemolishLinkProbability") << endl;
                    NEAT::Globals::getSingleton()->setParameterValue("MutateAddNodeProbability",0.0);
                    NEAT::Globals::getSingleton()->setParameterValue("MutateAddLinkProbability",0.0);
                    NEAT::Globals::getSingleton()->setParameterValue("MutateDemolishLinkProbability",0.0);
                    cout << endl << "to the FT-NEAT values of: " << endl;
                    cout << "MutateAddNodeProbability: " << NEAT::Globals::getSingleton()->getParameterValue("MutateAddNodeProbability") << endl;
                    cout << "MutateAddLinkProbability: " << NEAT::Globals::getSingleton()->getParameterValue("MutateAddLinkProbability") << endl;
                    cout << "MutateDemolishLinkProbability: " << NEAT::Globals::getSingleton()->getParameterValue("MutateDemolishLinkProbability") << endl << endl;
						
                    if(experiments[currentSubExperiment]->getHybrid_FTMutateOnlyProbability() != -1.0)
                      NEAT::Globals::getSingleton()->setParameterValue("MutateOnlyProbability", experiments[currentSubExperiment]->getHybrid_FTMutateOnlyProbability());
						
                    if(experiments[currentSubExperiment]->getHybrid_FTMutateLinkProbability() != -1.0)
                      NEAT::Globals::getSingleton()->setParameterValue("MutateLinkProbability", experiments[currentSubExperiment]->getHybrid_FTMutateLinkProbability());
						
                    //THESE CAN COME OUT ONCE THIS WORKS
                    cout << "MutateOnlyProbability" << NEAT::Globals::getSingleton()->getParameterValue("MutateOnlyProbability") << endl;
                    cout << "MutateLinkProbability" << NEAT::Globals::getSingleton()->getParameterValue("MutateLinkProbability") << endl;
                  } else {
                  mutex::scoped_lock scoped_lock(*populationMutex);
                  cout << "\nPRODUCING NEXT GENERATION\n";
                  produceNextGeneration(); 
                }
              }
				
            if (experiments[currentSubExperiment]->performUserEvaluations())
              {
                throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: TRIED TO USE INTERACTIVE EVOLUTION WITH NO GUI!");
              }
            else
              {
                while (!running)
                  {
                    boost::xtime xt;

                    boost::xtime_get(&xt, boost::TIME_UTC_);

                    xt.sec += 1;
                    // boost::thread::sleep(xt); // Sleep for 1/2 second
                    usleep(500000);
                  }
#ifdef INTERACTIVELYEVOLVINGSHAPES
                stringstream genNum; 
                genNum << setw(5) << std::setfill('0') << generations;
                population->dumpLast(outputFileName +"_"+ genNum.str()+".xml",true,false); //print out xml file each generation
#endif
					
										
                cout << "about to evaluatePopulation\n";					
                evaluatePopulation();
              }
				
#ifdef DEBUG_EXPRUN
            cout << "Finishing evaluations\n";
#endif
            finishEvaluations();
            experimentRunPrintToGenChampFile();
				
#ifdef DEBUG_EXPRUN
            cout << "Evaluations Finished\n";
#endif
          }
        cout << "Experiment finished\n";
			
        
			
        cout << "Saving Dump...";
        population->dump(outputFileName+string("_pop.xml"),true,false);
        cout << "Done!\n";

			
        cout << "Saving best individuals...";
        string bestFileName = outputFileName.substr(0,outputFileName.length()-4)+string("_best.xml");
        population->dumpBest(bestFileName,true,true);
        cout << "Done!\n";
			
        cout << "Skippped deleting backup files because of problem with boost!";
        //cout << "Deleting backup file...";
        //boost::filesystem::remove(outputFileName+string(".backup.xml.gz"));
        //cout << "Done!\n";
			
#ifndef DEBUG_EXPRUN
      }
    catch (const std::exception &ex)
      {
        cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
        CREATE_PAUSE(ex.what());
      }
    catch (...)
      {
        cout << "CAUGHT ERROR AT " << __FILE__ << " : " << __LINE__ << endl;
        CREATE_PAUSE("AN UNKNOWN EXCEPTION HAS BEEN THROWN!");
      }
#endif
  }
    void ExperimentRun::setupExperiment(
        int _experimentType,
        string _outputFileName
    )
    {
        experimentType = _experimentType;
        outputFileName = _outputFileName;

        cout << "SETTING UP EXPERIMENT TYPE: " << experimentType << endl;
		cout << "Using output file: " << outputFileName << endl;
		

		string experimentName = outputFileName.substr(0, outputFileName.find("."));
		
        switch (experimentType)
        {

        case EXPERIMENT_TIC_TAC_TOE:
            experiments.push_back(shared_ptr<Experiment>(new TicTacToeExperiment("")));
            break;
        case EXPERIMENT_TIC_TAC_TOE_GAME:
            experiments.push_back(shared_ptr<Experiment>(new TicTacToeGameExperiment("")));
            break;
        case EXPERIMENT_TIC_TAC_TOE_NO_GEOM_GAME:
            experiments.push_back(shared_ptr<Experiment>(new TicTacToeGameNoGeomExperiment("")));
            break;

        case EXPERIMENT_XOR:
            experiments.push_back(shared_ptr<Experiment>(new XorExperiment("")));
            break;

        case EXPERIMENT_FIND_POINT_EXPERIMENT:
            experiments.push_back(shared_ptr<Experiment>(new FindPointExperiment("")));
            break;
        case EXPERIMENT_FIND_CLUSTER_EXPERIMENT:
            experiments.push_back(shared_ptr<Experiment>(new FindClusterExperiment("")));
            break;
        case EXPERIMENT_FIND_CLUSTER_NO_GEOM_EXPERIMENT:
            experiments.push_back(shared_ptr<Experiment>(new FindClusterNoGeomExperiment("")));
            break;

        case EXPERIMENT_CHECKERS:
            experiments.push_back(shared_ptr<Experiment>(new CheckersExperiment("")));
            break;
        case EXPERIMENT_CHECKERS_NO_GEOM:
            experiments.push_back(shared_ptr<Experiment>(new CheckersExperimentNoGeom("")));
            break;

        case EXPERIMENT_CHECKERS_ORIGINAL_FOGEL:
            experiments.push_back(shared_ptr<Experiment>(new CheckersExperimentOriginalFogel("")));
            break;

        case EXPERIMENT_EVOLVE_MORPH_TRIMESH:
            experiments.push_back(shared_ptr<Experiment>(new EvolveMorphTrimeshExperiment(experimentName)));
            break;

        default:
            cout << string("ERROR: Unknown Experiment Type!\n");
            throw CREATE_LOCATEDEXCEPTION_INFO("ERROR: Unknown Experiment Type!");
        }
        for (int a=1;a<NUM_THREADS;a++)
        {
            experiments.push_back(shared_ptr<Experiment>(experiments[0]->clone()));
        }

    }
    ModularNetwork GeneticIndividual::spawnPhenotypeStack() const
    {
        vector<NetworkNode *> networkNodes;
        for (int a=0;a<(int)nodes.size();a++)
        {
            if (!nodes[a].isEnabled())
                continue;

            NetworkNode *networkNode;
            if (nodes[a].getType()==string("NetworkSensor"))
                networkNode = new NetworkNode(nodes[a].getName(),false,nodes[a].getActivationFunction());
            else
                networkNode = new NetworkNode(nodes[a].getName(),true,nodes[a].getActivationFunction());
            networkNodes.push_back(networkNode);
        }

        double linkGeneMinimumWeightForPhentoype =
            Globals::getSingleton()->getParameterValue("LinkGeneMinimumWeightForPhentoype");

        vector<NetworkLink *> networkLinks;
        for (int a=0;a<(int)links.size();a++)
        {
            const GeneticLinkGene *linkGene = &links[a];

            if (!linkGene->isEnabled()||( fabs(linkGene->getWeight())<linkGeneMinimumWeightForPhentoype ))
                continue;


            NetworkNode *fromNode=NULL;
            NetworkNode *toNode=NULL;

            bool create=true;

            int fromNodeIndex=-1,toNodeIndex=-1;

            for (int b=0;b<(int)nodes.size();b++)
            {
                //this holds because there's a match between genotype indicies and phenotype indicies
                if (nodes[b].getID()==links[a].getFromNodeID())
                {
                    fromNode = networkNodes[b];
                    fromNodeIndex = (int)b;
                }

                if (nodes[b].getID()==links[a].getToNodeID())
                {
                    toNode = networkNodes[b];
                    toNodeIndex = (int)b;
                }

                if (fromNode!=NULL&&toNode!=NULL)
                    break;

                if ((b+1) == (int)nodes.size()) //couldn't find a nodeID.  Node must have been disabled
                {
                    create=false;
                    break;
                }

            }

            if (fromNodeIndex==-1 || toNodeIndex==-1)
            {
                throw CREATE_LOCATEDEXCEPTION_INFO("ERROR!");
            }

            if (create)
                networkLinks.push_back(
                new NetworkLink(
                fromNode,
                toNode,
                nodes[fromNodeIndex].getDrawingPosition()<nodes[toNodeIndex].getDrawingPosition(),
                links[a].getWeight()
                )
                );
        }

        ModularNetwork network(networkNodes,networkLinks);

        while (!networkNodes.empty())
        {
            delete networkNodes[0];
            networkNodes.erase(networkNodes.begin());
        }

        while (!networkLinks.empty())
        {
            delete networkLinks[0];
            networkLinks.erase(networkLinks.begin());
        }

        return network;
    }