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

dk at myxo.css.msu.edu dk at myxo.css.msu.edu
Sun Sep 28 14:11:06 PDT 2008


Author: dk
Date: 2008-09-28 17:11:05 -0400 (Sun, 28 Sep 2008)
New Revision: 2802

Modified:
   development/source/actions/PopulationActions.cc
   development/source/actions/PrintActions.cc
   development/source/cpu/cHardwareBase.cc
   development/source/cpu/cHardwareBase.h
   development/source/cpu/cHardwareCPU.cc
   development/source/cpu/cHardwareCPU.h
   development/source/cpu/cHardwareManager.cc
   development/source/cpu/cTestCPUInterface.h
   development/source/main/cAvidaConfig.h
   development/source/main/cOrgInterface.h
   development/source/main/cOrgMessagePredicate.h
   development/source/main/cOrganism.cc
   development/source/main/cOrganism.h
   development/source/main/cPopulation.cc
   development/source/main/cPopulationInterface.cc
   development/source/main/cPopulationInterface.h
   development/source/main/cStats.cc
   development/source/main/cStats.h
Log:
Updating the development branch with the majority of the code related to
consensus and synchronization.  There are still some tricky bits that have to
be integrated, but this is most of it.  Everything here is pretty standard,
except for a small change to cHardwareManager to support online tracing -- that
is, tracing organisms that are not running in the test CPU.


Modified: development/source/actions/PopulationActions.cc
===================================================================
--- development/source/actions/PopulationActions.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/actions/PopulationActions.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -30,6 +30,7 @@
 #include "cGenome.h"
 #include "cGenomeUtil.h"
 #include "cHardwareManager.h"
+#include "cOrgMessagePredicate.h"
 #include "cPopulation.h"
 #include "cPopulationCell.h"
 #include "cStats.h"
@@ -39,6 +40,7 @@
 #include <map>
 #include <set>
 
+
 /*
  Injects a single organism into the population.
  
@@ -1199,6 +1201,25 @@
 };
 
 
+/*! This action enables the tracking of all messages that are sent in each deme. */
+class cActionTrackAllMessages : public cAction {
+public:
+  cActionTrackAllMessages(cWorld* world, const cString& args) : cAction(world, args) { }
+
+  static const cString GetDescription() { return "No Arguments"; }
+	
+  void Process(cAvidaContext& ctx) {
+		s_pred = new cOrgMessagePred_AllData(m_world);
+		m_world->GetStats().AddMessagePredicate(s_pred);
+  }
+	
+private:
+	static cOrgMessagePred_AllData* s_pred;
+};
+
+cOrgMessagePred_AllData* cActionTrackAllMessages::s_pred=0;
+
+
 /*
  Compete all of the demes using a basic genetic algorithm approach. Fitness
  of each deme is determined differently depending on the competition_type: 
@@ -1290,6 +1311,10 @@
 
 
 /*! An abstract base class to ease the development of new deme competition fitness functions.
+ 
+ This base class does the bookkeeping associated with deme competitions, including calling a virtual
+ function to calculate the fitness of each deme at the right time, collecting those fitness values in
+ a vector, and finally invoking the deme competition.
  */
 class cAbstractCompeteDemes : public cAction {
 public:
@@ -1385,6 +1410,116 @@
 };
 
 
+/*! This class contains methods that are useful for consensus-related problems.
+ */
+class ConsensusSupport {
+public:
+	ConsensusSupport() { }
+	virtual ~ConsensusSupport() { }
+	
+	/*! Returns a pair (support, opinion), where support is equal to the maximum 
+	 number of organisms within the deme that have set their opinion to the same value,
+	 and opinion is the value that they have set their (shared) opinion to.
+	 */	 
+	virtual std::pair<unsigned int, cOrganism::Opinion> max_support(const cDeme& deme) {
+		typedef std::vector<cOrganism::Opinion> OpinionList;
+		OpinionList opinions;
+		// For each organism in the deme:
+		for(int i=0; i<deme.GetSize(); ++i) {
+			cOrganism* org = deme.GetOrganism(i);
+			if((org != 0) && org->HasOpinion()) {
+				// Get its current opinion (we don't care about the date here):
+				opinions.push_back(org->GetOpinion().first);
+			}
+		}
+		
+		// Go through the list of opinions, count & filter:
+		typedef std::map<cOrganism::Opinion, unsigned int> OpinionMap;
+		unsigned int support=0;
+		cOrganism::Opinion opinion=0;
+		OpinionMap opinion_counts;
+		for(OpinionList::iterator i=opinions.begin(); i!=opinions.end(); ++i) {
+			// filter:
+			if(cAssignRandomCellData::IsCellDataInDeme(*i, deme)) {
+				// count:
+				++opinion_counts[*i];
+				// find support:
+				if(opinion_counts[*i] > support) {
+					support = opinion_counts[*i];
+					opinion = *i;
+				}
+			}
+		}		
+		return std::make_pair(support, opinion);
+	}	
+};
+
+
+/*! This class rewards for solving the Iterated Consensus Dilemma, where organisms
+ are to repeatedly reach consensus on one of a set of values.
+ 
+ Each organism is initialized with access to a single value, so the first part of
+ the ICD is to distribute knowledge of all possible values.  The second part of 
+ the ICD is to determine which of the possible values should be selected by the
+ group.  The third, and final, part of the ICD is for the group to iterate this
+ problem, so that consensus on as many values as possible is reached in the shortest
+ amount of time.
+ */
+class cIteratedConsensus : public cAbstractMonitoringCompeteDemes, ConsensusSupport {
+public:
+	cIteratedConsensus(cWorld* world, const cString& args) : cAbstractMonitoringCompeteDemes(world, args), _replace(0) {
+		if(args.GetSize()) {
+			cString largs(args);
+			_replace = largs.PopWord().AsInt();
+		}
+	}
+	
+	static const cString GetDescription() { return "Arguments: [int compete_period=100 [int replace_number=0]]"; }
+	
+	//! Calculate the current fitness of this deme.
+  virtual double Fitness(const cDeme& deme) {
+		return max_support(deme).first + 1;
+	}
+	
+	/*! Determine if the organisms in this deme have reached consensus, and if so,
+	 record that fact and reset so that they can "iterate" (try to reach consensus
+	 again).  This version includes protection against resetting to an "easy" value,
+	 removing the ability for organisms to continually filter in one direction to
+	 solve ICD.
+	 
+	 Resets always reset the cell data of the agreed-upon value, and if _replace is
+	 greater than zero, we also reset the cell data of other cells, which are
+	 selected at random with replacement.
+	 
+	 Called during every update (depending on configuration).  Return values are
+	 summed and included in final fitness calculation. */
+	virtual double Update(cDeme& deme) {
+		std::pair<unsigned int, cOrganism::Opinion> support = max_support(deme);
+		
+		// Have all organisms in this deme reached consensus?
+		if(support.first == static_cast<unsigned int>(deme.GetSize())) {
+			// Yes; change the cell data for the value that was agreed upon:
+			int min_data = *cAssignRandomCellData::GetDataInDeme(deme).begin();
+			int max_data = *cAssignRandomCellData::GetDataInDeme(deme).rbegin();
+			cAssignRandomCellData::ReplaceCellData(support.second, m_world->GetRandom().GetInt(min_data+1, max_data-1), deme);
+			
+			// Now reset the others:
+			for(int i=0; i<_replace; ++i) {
+				int cell_id = m_world->GetRandom().GetInt(deme.GetSize());
+				int cell_data = deme.GetCell(cell_id).GetCellData();
+				cAssignRandomCellData::ReplaceCellData(cell_data, m_world->GetRandom().GetInt(min_data+1, max_data-1), deme);
+			}
+			
+			return deme.GetSize();
+		}
+		return 0.0;
+	}
+	
+private:
+	int _replace; //!< Number of cell datas that will be replaced on successful consensus.
+};
+
+
 class cAbstractCompeteDemes_AttackKillAndEnergyConserve : public cAbstractCompeteDemes {
 
   public:
@@ -2085,15 +2220,19 @@
   action_lib->Register<cActionModMutProb>("ModMutProb");
   action_lib->Register<cActionZeroMuts>("ZeroMuts");
 
+	action_lib->Register<cActionTrackAllMessages>("TrackAllMessages");
+	
   action_lib->Register<cActionCompeteDemes>("CompeteDemes");
   action_lib->Register<cActionReplicateDemes>("ReplicateDemes");
   action_lib->Register<cActionDivideDemes>("DivideDemes");
   action_lib->Register<cActionResetDemes>("ResetDemes");
   action_lib->Register<cActionCopyDeme>("CopyDeme");
 
-/****AbstractCompeteDemes sub-classes****/
+	/****AbstractCompeteDemes sub-classes****/
   action_lib->Register<cAbstractCompeteDemes_AttackKillAndEnergyConserve>("CompeteDemes_AttackKillAndEnergyConserve");
-  
+  action_lib->Register<cAssignRandomCellData>("AssignRandomCellData");
+  action_lib->Register<cIteratedConsensus>("IteratedConsensus");
+	
   action_lib->Register<cActionNewTrial>("NewTrial");
   action_lib->Register<cActionCompeteOrganisms>("CompeteOrganisms");
   

Modified: development/source/actions/PrintActions.cc
===================================================================
--- development/source/actions/PrintActions.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/actions/PrintActions.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -107,7 +107,12 @@
 STATS_OUT_FILE(PrintDemeOrgTasksExeData,    deme_org_tasks_exe.dat  );
 STATS_OUT_FILE(PrintDemeOrgReactionData,    deme_org_reactions.dat  );
 STATS_OUT_FILE(PrintGermlineData,           germline.dat        );
+STATS_OUT_FILE(PrintPredicatedMessages,     messages.dat        );
+STATS_OUT_FILE(PrintCellData,               cell_data.dat       );
+STATS_OUT_FILE(PrintCurrentOpinions,        opinions.dat        );
 STATS_OUT_FILE(PrintPerDemeGenPerFounderData,   deme_gen_between_founders.dat );
+STATS_OUT_FILE(PrintSynchronizationData,    sync.dat            );
+STATS_OUT_FILE(PrintDetailedSynchronizationData, sync-detail.dat);
 // @WRE: Added output event for collected visit counts
 STATS_OUT_FILE(PrintCellVisitsData,         visits.dat			);
 STATS_OUT_FILE(PrintFlowRateTuples,         flow_rate_tuples.dat);
@@ -2688,6 +2693,12 @@
   
   action_lib->Register<cActionPrintDemeTestamentStats>("PrintDemeTestamentStats");
   
+	action_lib->Register<cActionPrintPredicatedMessages>("PrintPredicatedMessages");
+	action_lib->Register<cActionPrintCellData>("PrintCellData");
+	action_lib->Register<cActionPrintCurrentOpinions>("PrintCurrentOpinions");
+	action_lib->Register<cActionPrintSynchronizationData>("PrintSynchronizationData");
+  action_lib->Register<cActionPrintDetailedSynchronizationData>("PrintDetailedSynchronizationData");
+	
   // deme output files
   action_lib->Register<cActionPrintDemeAllStats>("PrintDemeAllStats");
   action_lib->Register<cActionPrintDemeAllStats>("PrintDemeStats"); //duplicate of previous

Modified: development/source/cpu/cHardwareBase.cc
===================================================================
--- development/source/cpu/cHardwareBase.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/cpu/cHardwareBase.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -913,3 +913,8 @@
     for (int i = 0; i < num_inst_cost; i++) inst_energy_cost[i] = m_inst_set->GetEnergyCost(cInstruction(i));
   }
 }
+
+//! Called when the organism that owns this CPU has received a flash from a neighbor.
+void cHardwareBase::ReceiveFlash() {
+  m_world->GetDriver().RaiseFatalException(1, "Method cHardwareBase::ReceiveFlash must be overriden.");
+}

Modified: development/source/cpu/cHardwareBase.h
===================================================================
--- development/source/cpu/cHardwareBase.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/cpu/cHardwareBase.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -204,6 +204,11 @@
   bool Inst_DoubleEnergyUsage(cAvidaContext& ctx);
   bool Inst_HalfEnergyUsage(cAvidaContext& ctx);
   bool Inst_DefaultEnergyUsage(cAvidaContext& ctx);
+	
+	// -------- Synchronization --------
+public:
+  //! Called when the organism that owns this CPU has received a flash from a neighbor.
+  virtual void ReceiveFlash();	
 };
 
 

Modified: development/source/cpu/cHardwareCPU.cc
===================================================================
--- development/source/cpu/cHardwareCPU.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/cpu/cHardwareCPU.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -209,11 +209,6 @@
     tInstLibEntry<tMethod>("sense-unit", &cHardwareCPU::Inst_SenseUnit, nInstFlag::STALL),      // and want to keep stats, also add
     tInstLibEntry<tMethod>("sense-m100", &cHardwareCPU::Inst_SenseMult100, nInstFlag::STALL),   // the names to cStats::cStats() @JEB
     tInstLibEntry<tMethod>("if-resources", &cHardwareCPU::Inst_IfResources, nInstFlag::STALL),
-    // Data collection
-    tInstLibEntry<tMethod>("collect-cell-data", &cHardwareCPU::Inst_CollectCellData, nInstFlag::STALL),
-    tInstLibEntry<tMethod>("kill-cell-event", &cHardwareCPU::Inst_KillCellEvent, nInstFlag::STALL),
-    tInstLibEntry<tMethod>("kill-faced-cell-event", &cHardwareCPU::Inst_KillFacedCellEvent, nInstFlag::STALL),
-    tInstLibEntry<tMethod>("collect-cell-data-and-kill-event", &cHardwareCPU::Inst_CollectCellDataAndKillEvent, nInstFlag::STALL),
 
     tInstLibEntry<tMethod>("donate-rnd", &cHardwareCPU::Inst_DonateRandom, nInstFlag::STALL),
     tInstLibEntry<tMethod>("donate-kin", &cHardwareCPU::Inst_DonateKin, nInstFlag::STALL),
@@ -449,6 +444,22 @@
     // These are STALLs because opinions are only relevant with respect to time.
     tInstLibEntry<tMethod>("set-opinion", &cHardwareCPU::Inst_SetOpinion, nInstFlag::STALL),
     tInstLibEntry<tMethod>("get-opinion", &cHardwareCPU::Inst_GetOpinion, nInstFlag::STALL),
+		
+		// Data collection
+		tInstLibEntry<tMethod>("if-cell-data-changed", &cHardwareCPU::Inst_IfCellDataChanged, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("collect-cell-data", &cHardwareCPU::Inst_CollectCellData, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("kill-cell-event", &cHardwareCPU::Inst_KillCellEvent, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("kill-faced-cell-event", &cHardwareCPU::Inst_KillFacedCellEvent, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("collect-cell-data-and-kill-event", &cHardwareCPU::Inst_CollectCellDataAndKillEvent, nInstFlag::STALL),
+		
+		// Synchronization
+    tInstLibEntry<tMethod>("flash", &cHardwareCPU::Inst_Flash, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("if-recvd-flash", &cHardwareCPU::Inst_IfRecvdFlash, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("flash-info", &cHardwareCPU::Inst_FlashInfo, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("flash-info-b", &cHardwareCPU::Inst_FlashInfoB, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("reset-flash-info", &cHardwareCPU::Inst_ResetFlashInfo, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("hard-reset", &cHardwareCPU::Inst_HardReset, nInstFlag::STALL),
+    tInstLibEntry<tMethod>("get-cycles", &cHardwareCPU::Inst_GetCycles, nInstFlag::STALL),		
 
     // Must always be the last instruction in the array
     tInstLibEntry<tMethod>("NULL", &cHardwareCPU::Inst_Nop, 0, "True no-operation instruction: does nothing"),
@@ -475,6 +486,7 @@
 
 cHardwareCPU::cHardwareCPU(cWorld* world, cOrganism* in_organism, cInstSet* in_m_inst_set)
 : cHardwareBase(world, in_organism, in_m_inst_set)
+, m_last_cell_data(false, 0)
 {
   /* FIXME:  reorganize storage of m_functions.  -- kgn */
   m_functions = s_inst_slib->GetFunctions();
@@ -506,6 +518,7 @@
 , m_advance_ip(hardware_cpu.m_advance_ip)
 , m_executedmatchstrings(hardware_cpu.m_executedmatchstrings)
 , m_epigenetic_state(hardware_cpu.m_epigenetic_state)
+, m_last_cell_data(false, 0)
 {
 #if INSTRUCTION_COSTS
   m_inst_cost = hardware_cpu.m_inst_cost;
@@ -564,6 +577,7 @@
       }
     }
   }
+	m_last_cell_data = std::make_pair(false, 0);
 }
 
 void cHardwareCPU::cLocalThread::operator=(const cLocalThread& in_thread)
@@ -2151,6 +2165,7 @@
   GetRegister(REG_BX) = 0;
   GetRegister(REG_CX) = 0;
   StackClear();
+	m_last_cell_data = std::make_pair(false, 0);
   return true;
 }
 
@@ -3299,51 +3314,6 @@
 }
 
 
-bool cHardwareCPU::Inst_CollectCellData(cAvidaContext& ctx) {
-  const int out_reg = FindModifiedRegister(REG_BX);
-  GetRegister(out_reg) = organism->GetCellData();
-  return true;
-}
-
-bool cHardwareCPU::Inst_KillCellEvent(cAvidaContext& ctx) {
-  // Fail if we're running in the test CPU.
-  if((organism->GetOrgInterface().GetDemeID() < 0) || (organism->GetCellID() < 0))
-    return false;
-
-  const int reg = FindModifiedRegister(REG_BX);
-  int eventID = organism->GetCellData();
-  GetRegister(reg) = organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
-  return true;
-}
-
-bool cHardwareCPU::Inst_KillFacedCellEvent(cAvidaContext& ctx) {
-  // Fail if we're running in the test CPU.
-  if((organism->GetOrgInterface().GetDemeID() < 0) || (organism->GetCellID() < 0))
-    return false;
-
-  const int reg = FindModifiedRegister(REG_BX);
-  int eventID = organism->GetNeighborCellContents();
-  GetRegister(reg) = organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
-  
-  if(GetRegister(reg))
-    organism->SetEventKilled();
-  
-  return true;
-}
-
-bool cHardwareCPU::Inst_CollectCellDataAndKillEvent(cAvidaContext& ctx) {
-  // Fail if we're running in the test CPU.
-  if((organism->GetOrgInterface().GetDemeID() < 0) || (organism->GetCellID() < 0))
-    return false;
-  
-  const int out_reg = FindModifiedRegister(REG_BX);
-  int eventID = organism->GetCellData();
-  GetRegister(out_reg) = eventID;
-  
-  organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
-  return true;
-}
-
 void cHardwareCPU::DoDonate(cOrganism* to_org)
 {
   assert(to_org != NULL);
@@ -6647,6 +6617,7 @@
  */
 bool cHardwareCPU::Inst_SetOpinion(cAvidaContext& ctx)
 {
+	assert(organism != 0);
   organism->SetOpinion(GetRegister(FindModifiedRegister(REG_BX)));
   return true;
 }
@@ -6658,6 +6629,7 @@
  */
 bool cHardwareCPU::Inst_GetOpinion(cAvidaContext& ctx)
 {
+	assert(organism != 0);
   if(organism->HasOpinion()) {
     const int opinion_reg = FindModifiedRegister(REG_BX);
     const int age_reg = FindNextRegister(opinion_reg);
@@ -6667,3 +6639,158 @@
   }
   return true;
 }
+
+
+/*! Collect this cell's data, and place it in ?BX?.  Set the flag indicating that
+ this organism has collected cell data to true, and set the last collected cell data
+ as well.
+ */
+bool cHardwareCPU::Inst_CollectCellData(cAvidaContext& ctx)
+{
+  assert(organism != 0);
+  const int out_reg = FindModifiedRegister(REG_BX);
+  GetRegister(out_reg) = organism->GetCellData();
+	// Update last collected cell data:
+	m_last_cell_data = std::make_pair(true, GetRegister(out_reg));
+  return true;
+}
+
+
+/*! Detect if the cell data in which this organism lives has changed since the
+ last time that this organism has collected cell data.  Note that this process
+ DOES NOT take into account organism movement, and it only works with explicit
+ collection of cell data.
+ */
+bool cHardwareCPU::Inst_IfCellDataChanged(cAvidaContext& ctx)
+{
+  assert(organism != 0);
+	// If we haven't collected cell data yet, or it's the same as the current cell data, advance
+	// the IP:
+	if(!m_last_cell_data.first || (m_last_cell_data.second == organism->GetCellData())) {
+		IP().Advance();
+	}
+	
+	return true;
+}
+
+
+bool cHardwareCPU::Inst_KillCellEvent(cAvidaContext& ctx) {
+  // Fail if we're running in the test CPU.
+  if((organism->GetOrgInterface().GetDemeID() < 0) || (organism->GetCellID() < 0))
+    return false;
+	
+  const int reg = FindModifiedRegister(REG_BX);
+  int eventID = organism->GetCellData();
+  GetRegister(reg) = organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
+  return true;
+}
+
+
+bool cHardwareCPU::Inst_KillFacedCellEvent(cAvidaContext& ctx) {
+  // Fail if we're running in the test CPU.
+  if((organism->GetOrgInterface().GetDemeID() < 0) || (organism->GetCellID() < 0))
+    return false;
+	
+  const int reg = FindModifiedRegister(REG_BX);
+  int eventID = organism->GetNeighborCellContents();
+  GetRegister(reg) = organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
+  
+  if(GetRegister(reg))
+    organism->SetEventKilled();
+  
+  return true;
+}
+
+
+bool cHardwareCPU::Inst_CollectCellDataAndKillEvent(cAvidaContext& ctx) {
+  // Fail if we're running in the test CPU.
+  if((organism->GetOrgInterface().GetDemeID() < 0) || (organism->GetCellID() < 0))
+    return false;
+  
+  const int out_reg = FindModifiedRegister(REG_BX);
+  int eventID = organism->GetCellData();
+  GetRegister(out_reg) = eventID;
+  
+  organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
+  return true;
+}
+
+
+/*! Called when the organism that owns this CPU has received a flash from a neighbor. */
+void cHardwareCPU::ReceiveFlash() {
+  m_flash_info.first = 1; // Yes, we've received a flash.
+  m_flash_info.second = m_cycle_counter; // When we received it.
+}
+
+
+/*! Send a "flash" event to all neighboring organisms. */
+bool cHardwareCPU::Inst_Flash(cAvidaContext& ctx) {
+  assert(organism != 0);
+  organism->SendFlash(ctx);
+  return true;
+}
+
+
+/*! Test if this organism has ever recieved a flash event. */
+bool cHardwareCPU::Inst_IfRecvdFlash(cAvidaContext& ctx) {
+  assert(organism != 0);
+  if(m_flash_info.first == 0) {
+    IP().Advance();
+  }
+  return true;
+}
+
+
+/*! Retrieve if & when this organism has last received a flash. */
+bool cHardwareCPU::Inst_FlashInfo(cAvidaContext& ctx) {
+  assert(organism != 0);
+  const int bx = FindModifiedRegister(REG_BX);
+  const int cx = FindNextRegister(bx);
+  
+  if(m_flash_info.first > 0) {
+    assert(m_cycle_counter >= m_flash_info.second);
+    GetRegister(bx) = m_flash_info.first;
+    GetRegister(cx) = m_cycle_counter - m_flash_info.second;
+  } else {
+    GetRegister(bx) = 0;
+    GetRegister(cx) = 0;
+  }
+  return true;
+}
+
+
+/*! Retrieve if (but not when) this organism has last received a flash. */
+bool cHardwareCPU::Inst_FlashInfoB(cAvidaContext& ctx) {
+  assert(organism != 0);
+  const int bx = FindModifiedRegister(REG_BX);
+  
+  if(m_flash_info.first > 0) {
+    assert(m_cycle_counter >= m_flash_info.second);
+    GetRegister(bx) = m_flash_info.first;
+  } else {
+    GetRegister(bx) = 0;
+  }
+  return true;
+}
+
+
+bool cHardwareCPU::Inst_ResetFlashInfo(cAvidaContext& ctx) {
+  assert(organism != 0);
+  m_flash_info.first = 0;
+  m_flash_info.second = 0;
+  return true;
+}
+
+
+bool cHardwareCPU::Inst_HardReset(cAvidaContext& ctx) {
+  Reset();
+  m_advance_ip = false;
+  return true;
+}
+
+
+//! Current "time": the number of cycles this CPU has been "alive."
+bool cHardwareCPU::Inst_GetCycles(cAvidaContext& ctx) {
+  GetRegister(FindModifiedRegister(REG_BX)) = m_cycle_counter;
+  return true;
+}

Modified: development/source/cpu/cHardwareCPU.h
===================================================================
--- development/source/cpu/cHardwareCPU.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/cpu/cHardwareCPU.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -466,10 +466,6 @@
   bool DoSense(cAvidaContext& ctx, int conversion_method, double base);
   //! Execute the following instruction if all resources are above their min level.
   bool Inst_IfResources(cAvidaContext& ctx);
-  bool Inst_CollectCellData(cAvidaContext& ctx);
-  bool Inst_KillCellEvent(cAvidaContext& ctx);
-  bool Inst_KillFacedCellEvent(cAvidaContext& ctx);
-  bool Inst_CollectCellDataAndKillEvent(cAvidaContext& ctx);
 
   void DoDonate(cOrganism * to_org);
   void DoEnergyDonate(cOrganism* to_org);
@@ -654,6 +650,7 @@
   bool Inst_DropPheromone(cAvidaContext& ctx);
 
   // -------- Opinion support --------
+public:
   /* These instructions interact with the "opinion" support in cOrganism.h.  The
    idea is that we're enabling organisms to express an opinion about *something*,
    where that something is defined by the particular tasks and/or (deme) fitness function
@@ -665,6 +662,45 @@
   bool Inst_SetOpinion(cAvidaContext& ctx);
   //! Retrieve this organism's current opinion.
   bool Inst_GetOpinion(cAvidaContext& ctx);
+
+	// -------- Cell Data Support --------
+public:
+	//! Collect this cell's data, and place it in a register.
+  bool Inst_CollectCellData(cAvidaContext& ctx);
+	//! Detect if this cell's data has changed since the last collection.
+	bool Inst_IfCellDataChanged(cAvidaContext& ctx);
+	bool Inst_KillCellEvent(cAvidaContext& ctx);
+  bool Inst_KillFacedCellEvent(cAvidaContext& ctx);
+  bool Inst_CollectCellDataAndKillEvent(cAvidaContext& ctx);
+	
+private:
+	std::pair<bool, int> m_last_cell_data; //<! If cell data has been previously collected, and it's value.
+	
+	// -------- Synchronization primitives --------
+public:
+  //! Called when the owning organism receives a flash from a neighbor.
+  virtual void ReceiveFlash();
+  //! Sends a "flash" to all neighboring organisms.
+  bool Inst_Flash(cAvidaContext& ctx);
+  //! Test if this organism has ever received a flash.
+  bool Inst_IfRecvdFlash(cAvidaContext& ctx);
+  //! Get if & when this organism last received a flash.
+  bool Inst_FlashInfo(cAvidaContext& ctx);
+  //! Get if (but not when) this organism last received a flash.
+  bool Inst_FlashInfoB(cAvidaContext& ctx);  
+  //! Reset the information this organism has regarding receiving a flash.
+  bool Inst_ResetFlashInfo(cAvidaContext& ctx);  
+  //! Reset the entire CPU.
+  bool Inst_HardReset(cAvidaContext& ctx);
+  //! Current "time": the number of cycles this CPU has been "alive."
+  bool Inst_GetCycles(cAvidaContext& ctx);
+	
+private:
+  /*! Used to track the last flash received; first=whether we've received a flash, 
+	 second= #cycles since we've received a flash, or 0 if we haven't. */
+  std::pair<unsigned int, unsigned int> m_flash_info;
+  //! Cycle timer; counts the number of cycles this virtual CPU has executed.
+  unsigned int m_cycle_counter;	
 };
 
 

Modified: development/source/cpu/cHardwareManager.cc
===================================================================
--- development/source/cpu/cHardwareManager.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/cpu/cHardwareManager.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -29,6 +29,7 @@
 #include "cHardwareSMT.h"
 #include "cHardwareTransSMT.h"
 #include "cHardwareGX.h"
+#include "cHardwareStatusPrinter.h"
 #include "cInitFile.h"
 #include "cInstSet.h"
 #include "cWorld.h"
@@ -67,40 +68,56 @@
 		default:
       m_world->GetDriver().RaiseFatalException(1, "Unknown/Unsupported HARDWARE_TYPE specified");
   }
-  
+
   if (filename == "" || filename == "-") {
     filename = default_filename;
     m_world->GetDriver().NotifyComment(cString("Using default instruction set: ") + filename);
   }
   
-  
   if (m_world->GetConfig().INST_SET_FORMAT.Get()) {
     m_inst_set->LoadFromConfig();
   } else {
     m_inst_set->LoadFromLegacyFile(filename);
   }
-  
 }
 
 cHardwareBase* cHardwareManager::Create(cOrganism* in_org, cInstSet* inst_set)
 {
+  static unsigned int cpu=0;
   assert(in_org != NULL);
-  
-  switch (m_type)
-  {
+	
+  cHardwareBase* hw=0;
+	
+  switch (m_type) {
     case HARDWARE_TYPE_CPU_ORIGINAL:
-      return new cHardwareCPU(m_world, in_org, inst_set);
+      hw = new cHardwareCPU(m_world, in_org, m_inst_set);
+      break;
     case HARDWARE_TYPE_CPU_SMT:
-      return new cHardwareSMT(m_world, in_org, inst_set);
+      hw = new cHardwareSMT(m_world, in_org, m_inst_set);
+      break;
     case HARDWARE_TYPE_CPU_TRANSSMT:
-      return new cHardwareTransSMT(m_world, in_org, inst_set);
+      hw = new cHardwareTransSMT(m_world, in_org, m_inst_set);
+      break;
     case HARDWARE_TYPE_CPU_EXPERIMENTAL:
-      return new cHardwareExperimental(m_world, in_org, inst_set);
+      hw = new cHardwareExperimental(m_world, in_org, m_inst_set);
+      break;
     case HARDWARE_TYPE_CPU_GX:
-      return new cHardwareGX(m_world, in_org, inst_set);
+      hw = new cHardwareGX(m_world, in_org, m_inst_set);
+      break;
     default:
-      return NULL;
+      m_world->GetDriver().RaiseFatalException(-1, "Unrecognized hardware type.");
+      break;
   }
+  
+  // Are we tracing the execution of this cpu?
+  if(m_world->GetConfig().TRACE_EXECUTION.Get()) {
+    std::ostringstream filename;
+    filename << "trace-" << cpu++ << ".trace";    
+    hw->SetTrace(new cHardwareStatusPrinter(m_world->GetDataFileOFStream(filename.str().c_str())));
+  }
+  
+  assert(hw != 0);
+  return hw;
 }
 
 bool cHardwareManager::SupportsSpeculative()

Modified: development/source/cpu/cTestCPUInterface.h
===================================================================
--- development/source/cpu/cTestCPUInterface.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/cpu/cTestCPUInterface.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -88,10 +88,9 @@
   bool TestOnDivide() { return false; }
   int GetFacing() { return 0; }
   bool SendMessage(cOrgMessage& msg) { return false; }
-  
-  bool BcastAlarm(int jump_label, int bcast_range) { return false; }
-  
+	bool BcastAlarm(int jump_label, int bcast_range) { return false; }
   void DivideOrgTestamentAmongDeme(double value) {;}
+	void SendFlash() { }
 };
 
 

Modified: development/source/main/cAvidaConfig.h
===================================================================
--- development/source/main/cAvidaConfig.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cAvidaConfig.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -283,6 +283,7 @@
   CONFIG_ADD_VAR(RANDOM_SEED, int, 0, "Random number seed (0 for based on time)");
   CONFIG_ADD_VAR(HARDWARE_TYPE, int, 0, "0 = Original CPUs\n1 = New SMT CPUs\n2 = Transitional SMT\n3 = Experimental CPU\n4 = Gene Expression CPU");
   CONFIG_ADD_VAR(SPECULATIVE, bool, 1, "Enable speculative execution");
+	CONFIG_ADD_VAR(TRACE_EXECUTION, bool, 0, "Trace the execution of all organisms in the population (default=off,SLOW!)");
   CONFIG_ADD_VAR(BCAST_HOPS, int, 1, "Number of hops to broadcast an alarm");
   CONFIG_ADD_VAR(ALARM_SELF, bool, 0, "Does sending an alarm move sender IP to alarm label?\n0=no\n1=yes");
   
@@ -553,6 +554,12 @@
   CONFIG_ADD_VAR(LOG_INJECT, bool, 0, "Log injection of organisms.  0/1 (off/on)");
   CONFIG_ADD_VAR(INJECT_LOG_START, int, 0, "Update at which to start logging injection of\norganisms");
   
+	// -------- Synchronization config options --------
+  CONFIG_ADD_GROUP(SYNCHRONIZATION_GROUP, "Synchronization settings");
+  CONFIG_ADD_VAR(SYNC_FITNESS_WINDOW, int, 100, "Number of updates over which to calculate fitness (default=100).");
+  CONFIG_ADD_VAR(SYNC_FLASH_LOSSRATE, double, 0.0, "P() to lose a flash send (0.0==off).");
+  CONFIG_ADD_VAR(SYNC_TEST_FLASH_ARRIVAL, int, -1, "CPU cycle at which an organism will receive a flash (off=-1, default=-1, analyze mode only.)");	
+	
   CONFIG_ADD_CUSTOM_FORMAT(INST_SET_NEW, "Instruction Set Definition");
   CONFIG_ADD_FORMAT_VAR(INST, "Instruction entry in the instruction set");
   

Modified: development/source/main/cOrgInterface.h
===================================================================
--- development/source/main/cOrgInterface.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cOrgInterface.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -98,10 +98,9 @@
   virtual bool UpdateMerit(double new_merit) = 0;
   virtual bool TestOnDivide() = 0;
   virtual bool SendMessage(cOrgMessage& msg) = 0;
-
   virtual bool BcastAlarm(int jump_jabel, int bcast_range) = 0;
   virtual void DivideOrgTestamentAmongDeme(double value) = 0;
-  
+	virtual void SendFlash() = 0;
 };
 
 #endif

Modified: development/source/main/cOrgMessagePredicate.h
===================================================================
--- development/source/main/cOrgMessagePredicate.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cOrgMessagePredicate.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -24,14 +24,19 @@
 #ifndef cOrgMessagePredicate_h
 #define cOrgMessagePredicate_h
 
+#include "cDeme.h"
+#include "cDemeCellEvent.h"
+#include "cOrganism.h"
+#include "cOrgMessage.h"
+#include "cPopulation.h"
+#include "cStats.h"
+
 #include <iostream>
 #include <functional>
 #include <set>
+#include <vector>
 
-#include "cOrgMessage.h"
-#include "cOrganism.h"
 
-
 /*! \brief An STL-compatible predicate on cOrgMessages.  The intent here is to
 provide a straightforward way to track arbitrary messages *wherever* they appear
 in the population.  The most utility can be had from message predicates if they're
@@ -40,7 +45,7 @@
 {
   virtual ~cOrgMessagePredicate() { }
   virtual bool operator()(const cOrgMessage& msg) = 0;
-  virtual void Print(std::ostream& out) { }
+  virtual void Print(int update, std::ostream& out) { }
   virtual void Reset() { }
   virtual bool PreviouslySatisfied() = 0;
   virtual cString GetName() = 0;
@@ -49,6 +54,35 @@
 };
 
 
+/*! A predicate that tracks all sent messages. */
+struct cOrgMessagePred_AllData : public cOrgMessagePredicate
+{
+	typedef std::vector<cOrgMessage> t_message_list;
+	
+	cOrgMessagePred_AllData(cWorld* world) : m_world(world) { }
+	virtual ~cOrgMessagePred_AllData() { }
+
+  virtual bool operator()(const cOrgMessage& msg) {
+		m_msgs.push_back(msg);
+		return true;
+	}
+  
+	virtual void Print(int update, std::ostream& out) {
+		for(t_message_list::iterator i=m_msgs.begin(); i!=m_msgs.end(); ++i) {
+			out << update << " ALL " << i->GetData() << " " << i->GetLabel() << endl;
+		}
+	}
+	
+  virtual void Reset() { m_msgs.clear(); }
+  virtual bool PreviouslySatisfied() { return false; }
+  virtual cString GetName() { return "cOrgMessagePred_All"; }
+  virtual void UpdateStats(cStats& stats) { }
+  virtual cDemeCellEvent* GetEvent() { return NULL; }
+	
+	cWorld* m_world;
+	t_message_list m_msgs;
+};
+
 /*! A predicate that returns true and tracks the sending cell_id for messages
 that contain the same data field as this predicate was constructed with.
 */
@@ -63,7 +97,7 @@
     return true;
   }
   
-  virtual void Print(std::ostream& out) { 
+  virtual void Print(int update, std::ostream& out) { 
     out << "data==" << m_data << ":{";
     for(std::set<int>::iterator i=m_cell_ids.begin(); i!=m_cell_ids.end(); ++i) {
       out << *i << ",";
@@ -98,7 +132,7 @@
     return true;
   }
   
-  virtual void print(std::ostream& out) { 
+  virtual void print(int update, std::ostream& out) { 
 //    cPopulationCell::t_id_map& ids = cPopulationCell::GetRandomCellIDMap();
 //    int badMSGs = 0;
 //    
@@ -169,7 +203,7 @@
   }
   
   //need to print update!!!
-  virtual void Print(std::ostream& out) {
+  virtual void Print(int update, std::ostream& out) {
     if(m_event->IsDead()) {
       return;
     }
@@ -261,7 +295,7 @@
     return m_event_received;
   }
   
-  virtual void Print(std::ostream& out) {
+  virtual void Print(int update, std::ostream& out) {
     if(m_event->IsDead()) {
       return;
     }

Modified: development/source/main/cOrganism.cc
===================================================================
--- development/source/main/cOrganism.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cOrganism.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -537,6 +537,7 @@
 void cOrganism::PrintStatus(ostream& fp, const cString& next_name)
 {
   fp << "---------------------------" << endl;
+	fp << "U:" << m_world->GetStats().GetUpdate() << endl;
   m_hardware->PrintStatus(fp);
   m_phenotype.PrintStatus(fp);
   fp << endl;
@@ -740,3 +741,29 @@
   InitOpinions();
   m_opinion->opinion_list.push_back(std::make_pair(opinion, m_world->GetStats().GetUpdate()));
 }
+
+
+/*! Called when an organism receives a flash from a neighbor. */
+void cOrganism::ReceiveFlash() {
+  m_hardware->ReceiveFlash();
+}
+
+
+/*! Called by the "flash" instruction. */
+void cOrganism::SendFlash(cAvidaContext& ctx) {
+  assert(m_interface);
+  
+  // Check to see if we should lose the flash:
+  if((m_world->GetConfig().SYNC_FLASH_LOSSRATE.Get() > 0.0) &&
+     (m_world->GetRandom().P(m_world->GetConfig().SYNC_FLASH_LOSSRATE.Get()))) {
+    return;
+  }
+  
+  // Flash not lost; continue.
+  m_interface->SendFlash();
+  m_world->GetStats().SentFlash(*this);
+  if(m_interface->GetDeme() != 0) {
+    //m_interface->GetDeme()->OrganismFlashed(*this);
+  }
+  DoOutput(ctx);
+}

Modified: development/source/main/cOrganism.h
===================================================================
--- development/source/main/cOrganism.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cOrganism.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -432,6 +432,14 @@
   };
   cOpinionSupport* m_opinion; //!< Lazily-initialized pointer to the opinion data.
   // -------- End of opinion support --------
+	
+	// -------- Synchronization support --------
+public:
+  //! Called when a neighboring organism issues a "flash" instruction.    
+  void ReceiveFlash();
+  //! Sends a "flash" to all neighboring organisms.
+  void SendFlash(cAvidaContext& ctx);
+  // -------- End of synchronization support --------	
 };
 
 

Modified: development/source/main/cPopulation.cc
===================================================================
--- development/source/main/cPopulation.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cPopulation.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -1155,7 +1155,7 @@
     if(deme_counts[i] == 1)
       ReplaceDeme(deme_array[i], deme_array[i]);
   }
-
+	
   // Now, while we can find both a source deme (one with a count greater than 1)
   // and a target deme (one with a count of 0), replace the target with the source.
   while(true) {

Modified: development/source/main/cPopulationInterface.cc
===================================================================
--- development/source/main/cPopulationInterface.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cPopulationInterface.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -335,3 +335,17 @@
     }
   }
 }
+
+/*! Send a flash to all neighboring organisms. */
+void cPopulationInterface::SendFlash() {
+  cPopulationCell& cell = m_world->GetPopulation().GetCell(m_cell_id);
+  assert(cell.IsOccupied());
+	
+  for(int i=0; i<cell.ConnectionList().GetSize(); ++i) {
+    cPopulationCell* neighbor = cell.ConnectionList().GetFirst();
+    if(neighbor->IsOccupied()) {
+      neighbor->GetOrganism()->ReceiveFlash();
+    }
+    cell.ConnectionList().CircNext();
+  }
+}

Modified: development/source/main/cPopulationInterface.h
===================================================================
--- development/source/main/cPopulationInterface.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cPopulationInterface.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -105,9 +105,10 @@
   bool TestOnDivide();
   //! Send a message to the faced organism.
   bool SendMessage(cOrgMessage& msg);
-  bool BcastAlarm(int jump_label, int bcast_range);
-  
+  bool BcastAlarm(int jump_label, int bcast_range);  
   void DivideOrgTestamentAmongDeme(double value);
+	//! Send a flash to all neighboring organisms.
+  void SendFlash();
 };
 
 

Modified: development/source/main/cStats.cc
===================================================================
--- development/source/main/cStats.cc	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cStats.cc	2008-09-28 21:11:05 UTC (rev 2802)
@@ -1238,8 +1238,7 @@
 void cStats::SentMessage(const cOrgMessage& msg)
 {
   // Check to see if this message matches any of our predicates.
-  for(message_pred_ptr_list::iterator i=m_message_predicates.begin(); 
-      i!=m_message_predicates.end(); ++i) {
+  for(message_pred_ptr_list::iterator i=m_message_predicates.begin(); i!=m_message_predicates.end(); ++i) {
     (**i)(msg); // Predicate is responsible for tracking info about messages.
   }  
 }
@@ -1301,29 +1300,24 @@
 
 /*! This method prints information contained within all active message predicates.
 
-about  specific messages that are being tracked.
-The messages that are being tracked are setup by the AddTrackedMessage method below.
-
-The format of this log file is:
-<update> \
-<predicate>:{<cell_id>,...}...
-*/
+ Each row of the data file has the following format: 
+   update predicate_name predicate_data...
+ */
 void cStats::PrintPredicatedMessages(const cString& filename)
 {
   cDataFile& df = m_world->GetDataFile(filename);
   df.WriteColumnDesc("update [update]");
-  df.WriteColumnDesc("predicate:{p_info,...}...");
+	df.WriteColumnDesc("predicate name: [pname]");
+  df.WriteColumnDesc("predicate data: [pdata]");
   df.FlushComments();
   
-  df.WriteAnonymous(GetUpdate());
   std::ofstream& out = df.GetOFStream();
   for(message_pred_ptr_list::iterator i=m_message_predicates.begin();
       i!=m_message_predicates.end(); ++i) {
-    (*i)->Print(out);
+    (*i)->Print(GetUpdate(), out);
     (*i)->Reset();
-    out << " ";
   }
-  df.Endl();  
+//  df.Endl();  
 }
 
 void cStats::PrintPredSatFracDump(const cString& filename) {
@@ -1682,7 +1676,6 @@
   df.WriteComment("First column gives the current update, all further columns give the number");
   df.WriteComment("number of generations that passed between the parent and current deme's founders");
 
-
 	df.Write(m_update,   "Update");
   for(int i=0; i<m_world->GetPopulation().GetNumDemes(); ++i) {
     cDeme& deme = m_world->GetPopulation().GetDeme(i);
@@ -1715,3 +1708,81 @@
   
   m_deme_fitness.clear();
 }
+
+
+/*! Prints the cell data from every cell, including the deme for that cell. */
+void cStats::PrintCellData(const cString& filename) {
+	cDataFile& df = m_world->GetDataFile(filename);
+	df.WriteComment("Cell data per udpate.");
+	df.WriteTimeStamp();
+	
+	for(int i=0; i<m_world->GetPopulation().GetSize(); ++i) {
+		const cPopulationCell& cell = m_world->GetPopulation().GetCell(i);
+		df.Write(GetUpdate(), "Update [update]");
+		df.Write(cell.GetID(), "Global cell ID [globalid]");
+		df.Write(cell.GetDemeID(), "Deme ID for cell [demeid]");
+		df.Write(cell.GetCellData(), "Cell data [data]");
+		df.Endl();
+	}
+}
+
+
+void cStats::PrintCurrentOpinions(const cString& filename) {
+	cDataFile& df = m_world->GetDataFile(filename);
+	df.WriteComment("Current opinions of each organism.");
+	df.WriteTimeStamp();
+	df.WriteComment("1: Update [update]");
+	df.WriteComment("2: Global cell ID [globalid]");
+	df.WriteComment("3: Current opinion [opinion]");
+	df.FlushComments();
+
+	for(int i=0; i<m_world->GetPopulation().GetSize(); ++i) {
+		const cPopulationCell& cell = m_world->GetPopulation().GetCell(i);
+		df.WriteAnonymous(GetUpdate());
+		df.WriteAnonymous(cell.GetID());
+		if(cell.IsOccupied() && cell.GetOrganism()->HasOpinion()) {
+			df.WriteAnonymous(cell.GetOrganism()->GetOpinion().first);
+		} else {
+			df.WriteAnonymous(0);
+		}
+		df.Endl();
+	}	
+}
+
+/*! Called after an organism flashes. */
+void cStats::SentFlash(cOrganism& organism) {
+  ++m_flash_count;
+  m_flashed_cells.push_back(organism.GetOrgInterface().GetCellID());
+}
+
+
+/*! Print statistics about synchronization flashes. */
+void cStats::PrintSynchronizationData(const cString& filename) {
+  cDataFile& df = m_world->GetDataFile(filename);
+  
+  df.WriteComment("Avida synchronization data");
+  df.WriteTimeStamp();
+  df.Write(m_update, "Update [update]");
+  df.Write(m_flash_count, "Flash count [fcount]");
+  df.Endl();
+  
+  m_flash_count = 0;
+  m_flashed_cells.clear();
+}
+
+
+/*! Print detailed synchronization data. */
+void cStats::PrintDetailedSynchronizationData(const cString& filename) {
+  cDataFile& df = m_world->GetDataFile(filename);
+  
+  df.WriteComment("Detailed Avida synchronization data");
+  df.WriteComment("Rows are (update, cellid) tuples, representing the update at which that cell flashed.");
+  df.WriteTimeStamp();
+  for(std::vector<int>::iterator i=m_flashed_cells.begin(); i!=m_flashed_cells.end(); ++i) {
+    df.Write(GetUpdate(), "Update [update]");
+    df.Write(*i, "Cellid [cellid]");
+    df.Endl();
+  }
+  
+  m_flashed_cells.clear();
+}

Modified: development/source/main/cStats.h
===================================================================
--- development/source/main/cStats.h	2008-09-28 16:17:13 UTC (rev 2801)
+++ development/source/main/cStats.h	2008-09-28 21:11:05 UTC (rev 2802)
@@ -836,6 +836,28 @@
   
 private:
   std::vector<double> m_deme_fitness; //!< Fitness of each deme during last deme competition.
+	
+	// -------- Cell data support --------
+public:
+	//! Prints the cell data from every cell in the population.
+	void PrintCellData(const cString& filename);
+	
+	// -------- Opinion support --------
+public:
+	//! Prints the current opinions of all organisms in the population.
+	void PrintCurrentOpinions(const cString& filename);
+	
+	// -------- Synchronization support --------
+public:
+  //! Called immediately after an organism has issued a "flash" to its neighbors.
+  void SentFlash(cOrganism& organism);
+  //! Print statistics about synchronization flashes.
+  void PrintSynchronizationData(const cString& filename);
+  //! Print detailed information regarding synchronization flashes.
+  void PrintDetailedSynchronizationData(const cString& filename);
+protected:
+  int m_flash_count; //!< Number of flashes that have occured since last PrintSynchronizationData.
+  std::vector<int> m_flashed_cells; //!< List of cellids that have flashed since last PrintDetailedSynchronizationData.	
 };
 
 




More information about the Avida-cvs mailing list