[Avida-SVN] r2799 - in development/source: actions main

dk at myxo.css.msu.edu dk at myxo.css.msu.edu
Sat Sep 27 19:08:11 PDT 2008


Author: dk
Date: 2008-09-27 22:08:10 -0400 (Sat, 27 Sep 2008)
New Revision: 2799

Modified:
   development/source/actions/PopulationActions.cc
   development/source/main/cPopulation.cc
Log:
Addition of a monitoring form of compete demes, and an event for setting random cell data.

Modified: development/source/actions/PopulationActions.cc
===================================================================
--- development/source/actions/PopulationActions.cc	2008-09-27 17:39:46 UTC (rev 2798)
+++ development/source/actions/PopulationActions.cc	2008-09-28 02:08:10 UTC (rev 2799)
@@ -36,6 +36,8 @@
 #include "cWorld.h"
 #include "cOrganism.h"
 
+#include <map>
+#include <set>
 
 /*
  Injects a single organism into the population.
@@ -1230,7 +1232,63 @@
 };
 
 
+/*! Assign a random identifier to the data for each cell and save those IDs for later
+ use, respecting deme boundaries.
+ 
+ This is a little hackish; feel free to modify.
+ */
+class cAssignRandomCellData : public cAction { 
+public:
+  typedef std::map<int, std::set<int> > DataMap;
+	
+  cAssignRandomCellData(cWorld* world, const cString& args) : cAction(world, args) { }
+  
+  static const cString GetDescription() { return "No Arguments"; }
+  
+  virtual void Process(cAvidaContext& ctx) {
+		deme_to_id.clear();
+    for(int i=0; i<m_world->GetPopulation().GetNumDemes(); ++i) {
+      cDeme& deme = m_world->GetPopulation().GetDeme(i);
+      for(int j=0; j<deme.GetSize(); ++j) {
+				// Assign random data to each cell:
+        int d = m_world->GetRandom().GetInt(INT_MAX);
+        deme.GetCell(j).SetCellData(d);
+				// Save that data by deme in the map:
+        deme_to_id[deme.GetID()].insert(d);
+      }
+    }
+  }
+  
+  static bool IsCellDataInDeme(int data, const cDeme& deme) { 
+    DataMap::iterator i = deme_to_id.find(deme.GetID());
+    return i->second.find(data) != i->second.end();
+  }
+	
+	static void ReplaceCellData(int old_data, int new_data, const cDeme& deme) {
+		// Find all cells in the deme that hold the old data, and replace it with the new.
+		for(int i=0; i<deme.GetSize(); ++i) {
+			if(deme.GetCell(i).GetCellData() == old_data) {
+				deme.GetCell(i).SetCellData(new_data);
+			}
+		}
+		// Update the data map.
+		DataMap::iterator i = deme_to_id.find(deme.GetID());
+		i->second.erase(old_data);
+		i->second.insert(new_data);
+	}
+	
+	static const std::set<int>& GetDataInDeme(const cDeme& deme) {
+		return deme_to_id[deme.GetID()];
+	}
+  
+protected:
+  static std::map<int, std::set<int> > deme_to_id; //!< Map of deme ID -> set of all cell data in that deme.
+};
 
+//! Definition for static data.
+cAssignRandomCellData::DataMap cAssignRandomCellData::deme_to_id;
+
+
 /*! An abstract base class to ease the development of new deme competition fitness functions.
  */
 class cAbstractCompeteDemes : public cAction {
@@ -1264,6 +1322,69 @@
   virtual double Fitness(const cDeme& deme) = 0;
 };
 
+
+/*! An abstract base class to ease the development of new deme competition fitness functions 
+ that require a per-update monitoring of each deme.
+ 
+ The idea here is that in addition to normal deme competition, we also have periodic housekeeping to do.
+ This housekeeping may or may not influence the final fitness value (once deme competition is triggered).
+ 
+ In the events file, when using any deme competition strategy that uses cAbstractMonitoringCompeteDemes,
+ the execution of the event corresponds to when the Update(...) method will be called, while the integer parameter
+ to the event is the period (in updates) of deme competition.  So this:
+ 
+ u 1:1:end SomeFormOfCompeteDemes 400
+ 
+ will call Update(...) every update, but only calls Fitness(...) every 400 updates.
+ 
+ WARNING: The compete_period argument MUST be an even multiple of the update period!
+ If it isn't, competition won't ever be triggered.  We're not preventing this, 'cause
+ there might be good reasons you'd want that...
+ */
+class cAbstractMonitoringCompeteDemes : public cAbstractCompeteDemes {
+public:
+	//! Constructor.
+	cAbstractMonitoringCompeteDemes(cWorld* world, const cString& args) : cAbstractCompeteDemes(world, args), _compete_period(100) {
+		if(args.GetSize()) {
+			cString largs(args);
+			_compete_period = largs.PopWord().AsInt();
+		}
+  }
+  
+	//! Destructor.
+	virtual ~cAbstractMonitoringCompeteDemes() { }
+	
+	/*! Update each deme, and possibly compete them.
+
+	 Calls Update(...) on every execution, but only calls Fitness(...) when the current
+	 update is an even multiple of the competition period.
+	 */	
+	virtual void Process(cAvidaContext& ctx) {
+		_update_fitness.resize(m_world->GetPopulation().GetNumDemes());													 
+    for(int i=0; i<m_world->GetPopulation().GetNumDemes(); ++i) {
+			_update_fitness[i] += Update(m_world->GetPopulation().GetDeme(i));
+		}
+		
+		if((m_world->GetStats().GetUpdate() % _compete_period) == 0) {
+			std::vector<double> fitness;
+			for(int i=0; i<m_world->GetPopulation().GetNumDemes(); ++i) {
+				fitness.push_back(pow(_update_fitness[i] + Fitness(m_world->GetPopulation().GetDeme(i)), 2.0));
+				assert(fitness.back() >= 0.0);
+			}			
+			m_world->GetPopulation().CompeteDemes(fitness);
+			_update_fitness.clear();
+		}
+	}
+	
+	//! Called on each action invocation, *including* immediately prior to fitness calculation.
+	virtual double Update(cDeme& deme) = 0;
+	
+protected:
+	int _compete_period; //!< Period at which demes compete.
+	std::vector<double> _update_fitness; //!< Running sum of returns from Update(cDeme).
+};
+
+
 class cAbstractCompeteDemes_AttackKillAndEnergyConserve : public cAbstractCompeteDemes {
 
   public:

Modified: development/source/main/cPopulation.cc
===================================================================
--- development/source/main/cPopulation.cc	2008-09-27 17:39:46 UTC (rev 2798)
+++ development/source/main/cPopulation.cc	2008-09-28 02:08:10 UTC (rev 2799)
@@ -1063,14 +1063,15 @@
     deme_count[from_deme_id]--;
     deme_count[to_deme_id]++;
     
-    cDeme & from_deme = deme_array[from_deme_id];
-    cDeme & to_deme   = deme_array[to_deme_id];
+    cDeme& from_deme = deme_array[from_deme_id];
+    cDeme& to_deme   = deme_array[to_deme_id];
     
+		// Ideally, the below bit of code would be replaced with a call to ReplaceDeme:
+		// ReplaceDeme(from_deme, to_deme);
+		//
+		// But, use of InjectClone messes that up, breaking consistency.  So the next
+		// time that someone comes in here looking to refactor, consider fixing this.    
     
-    ///    ReplaceDeme(cDeme& source_deme, cDeme& target_deme)
-    
-    
-    
     // Do the actual copy!
     for (int i = 0; i < from_deme.GetSize(); i++) {
       int from_cell_id = from_deme.GetCellID(i);
@@ -1121,7 +1122,13 @@
   
   // Stat-tracking:
   m_world->GetStats().CompeteDemes(fitness);
-  
+
+  // This is to facilitate testing.  Obviously we can't do competition if there's
+	// only one deme, but we do want the stat-tracking.
+	if(fitness.size()==1) {
+		return; 
+	}	
+	
   // Now, select the demes to live.  Each deme has a probability to replicate that is
   // equal to its fitness / total fitness.
   const double total_fitness = std::accumulate(fitness.begin(), fitness.end(), 0.0);
@@ -2088,7 +2095,7 @@
     }
   }
 
-return successfully_seeded;
+	return successfully_seeded;
 }
 
 void cPopulation::InjectDemeFounder(int _cell_id, cGenotype& _genotype, cPhenotype* _phenotype)




More information about the Avida-cvs mailing list