[Avida-SVN] r2804 - in branches/movement/source: actions analyze cpu main script

grabow38 at myxo.css.msu.edu grabow38 at myxo.css.msu.edu
Mon Sep 29 05:20:09 PDT 2008


Author: grabow38
Date: 2008-09-29 08:20:07 -0400 (Mon, 29 Sep 2008)
New Revision: 2804

Modified:
   branches/movement/source/actions/EnvironmentActions.cc
   branches/movement/source/actions/PopulationActions.cc
   branches/movement/source/actions/PrintActions.cc
   branches/movement/source/analyze/cAnalyze.cc
   branches/movement/source/analyze/cAnalyze.h
   branches/movement/source/analyze/cAnalyzeGenotype.h
   branches/movement/source/cpu/cHardwareBase.cc
   branches/movement/source/cpu/cHardwareBase.h
   branches/movement/source/cpu/cHardwareCPU.cc
   branches/movement/source/cpu/cHardwareCPU.h
   branches/movement/source/cpu/cHardwareManager.cc
   branches/movement/source/cpu/cInstSet.h
   branches/movement/source/cpu/cTestCPUInterface.h
   branches/movement/source/main/cAvidaConfig.h
   branches/movement/source/main/cDeme.h
   branches/movement/source/main/cOrgInterface.h
   branches/movement/source/main/cOrgMessagePredicate.h
   branches/movement/source/main/cOrganism.cc
   branches/movement/source/main/cOrganism.h
   branches/movement/source/main/cPopulation.cc
   branches/movement/source/main/cPopulationInterface.cc
   branches/movement/source/main/cPopulationInterface.h
   branches/movement/source/main/cStats.cc
   branches/movement/source/main/cStats.h
   branches/movement/source/script/AvidaScript.h
   branches/movement/source/script/cASNativeObject.h
   branches/movement/source/script/cDirectInterpretASTVisitor.cc
   branches/movement/source/script/cDirectInterpretASTVisitor.h
Log:
Merged development changes r2771:2803 into branches/movement.

Modified: branches/movement/source/actions/EnvironmentActions.cc
===================================================================
--- branches/movement/source/actions/EnvironmentActions.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/actions/EnvironmentActions.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -582,9 +582,11 @@
 	void Process(cAvidaContext& ctx)
 	{
 		int time = m_world->GetStats().GetUpdate();
-		double m_res_count = -1*(tanh((time-182500)/50000)+1)*(0.5*sin(time/58.091)+0.5)+1;
+		double m_res_count = -m_scale*(tanh((time-182500)/50000)+1)*(0.5*sin(time/58.091)+0.5)+1;
 		if(m_res_count < 0.0)
 			m_res_count = 0.0;
+		if(m_res_count < 0.0)
+			m_res_count = 0.0;
 		cResource* res = m_world->GetEnvironment().GetResourceLib().GetResource(m_res_name);
 		if (res != NULL)
 			m_world->GetPopulation().SetResource(res->GetID(), m_res_count * m_scale);			
@@ -614,9 +616,11 @@
 	void Process(cAvidaContext& ctx)
 	{
 		int time = m_world->GetStats().GetUpdate();
-		double m_res_count = -1*(tanh((time-1825000)/500000)+1)*(0.5*sin(time/58.091)+0.5)+1;
+		double m_res_count = -m_scale*(tanh((time-1825000)/500000)+1)*(0.5*sin(time/58.091)+0.5)+1;
 		if(m_res_count < 0.0)
 			m_res_count = 0.0;
+		if(m_res_count < 0.0)
+			m_res_count = 0.0;
 		cResource* res = m_world->GetEnvironment().GetResourceLib().GetResource(m_res_name);
 		if (res != NULL)
 			m_world->GetPopulation().SetResource(res->GetID(), m_res_count* m_scale);			

Modified: branches/movement/source/actions/PopulationActions.cc
===================================================================
--- branches/movement/source/actions/PopulationActions.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/actions/PopulationActions.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -30,13 +30,17 @@
 #include "cGenome.h"
 #include "cGenomeUtil.h"
 #include "cHardwareManager.h"
+#include "cOrgMessagePredicate.h"
 #include "cPopulation.h"
 #include "cPopulationCell.h"
 #include "cStats.h"
 #include "cWorld.h"
 #include "cOrganism.h"
 
+#include <map>
+#include <set>
 
+
 /*
  Injects a single organism into the population.
  
@@ -1197,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: 
@@ -1230,8 +1253,70 @@
 };
 
 
+/*! 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) { }
+	
+	virtual ~cAssignRandomCellData() { }
+  
+  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.
+ 
+ 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:
@@ -1264,6 +1349,288 @@
   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).
+};
+
+
+/*! 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 cActionIteratedConsensus : public cAbstractMonitoringCompeteDemes, ConsensusSupport {
+public:
+	cActionIteratedConsensus(cWorld* world, const cString& args) : cAbstractMonitoringCompeteDemes(world, args), _replace(0) {
+		if(args.GetSize()) {
+			cString largs(args);
+			_replace = largs.PopWord().AsInt();
+		}
+	}
+	
+	//! Destructor.
+	virtual ~cActionIteratedConsensus() { }
+	
+	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.
+};
+
+
+/**** The below are merges-in-progress. ****/
+
+/*! Action to send an artificial flash to each deme in the population at a specified period.
+class cActionPacecarFlash : public cAction {
+public:
+	cActionPacecarFlash(cWorld* world, const cString& args): cAction(world, args), _pacecar(80) {
+		if(args.GetSize()) {
+			cString largs(args);
+			_pacecar = largs.PopWord().AsInt();
+		}
+	}
+	
+	//! Destructor.
+	virtual ~cActionPacecarFlash() { }
+	
+	static const cString GetDescription() { return "Arguments: [pacecar=80]"; }
+	
+ //! Send a flash 
+	virtual void Process(cAvidaContext& ctx) {
+	}
+	
+private:
+	int _pacecar; //!< Period for artificial flashes that will be sent to each deme.
+};
+ */
+
+
+/*! Compete demes based on the ability of their constituent organisms
+ to synchronize their flashes to a common phase and period.
+class cActionSynchronization : public cAbstractMonitoringCompeteDemes {
+public:
+  //! Constructor.
+  cActionSynchronization(cWorld* world, const cString& args) : cAbstractMonitoringCompeteDemes(world, args), _pacecar(0) {
+		if(args.GetSize()) {
+			cString largs(args);
+			_pacecar = largs.PopWord().AsInt();
+		}		
+  }
+  
+  //! Description of this event.
+  static const cString GetDescription() { return "No Arguments"; }
+  
+  //! Run this event on the population.
+  virtual void Process(cAvidaContext& ctx) {
+    std::vector<double> fitness;
+    for(int i=0; i<m_world->GetPopulation().GetNumDemes(); ++i) {
+      fitness.push_back(fitness_function(m_world->GetPopulation().GetDeme(i)));
+    }    
+    m_world->GetPopulation().CompeteDemes(fitness);
+  }
+  
+  //! Calculate the fitness of a deme (must return > 0.0).
+  virtual double fitness_function(const cDeme& deme) {
+    // How many unique organisms have flashed in the last SYNC_FITNESS_WINDOW updates?
+    int total_flashed = deme.GetUniqueFlashes();
+		
+    // If not everyone has flashed, fitness is just the number that have flashed:
+    if(total_flashed < deme.GetSize()) {
+      return 1.0 + total_flashed;
+    }
+    
+    // If everyone has flashed, fitness is the difference between max and average
+    // squared, added to the size of the deme.
+    const cDeme::flash_row& fr = deme.GetFlashRollingSum();
+    double avg = std::accumulate(fr.begin(), fr.end(), 0.0) / fr.size();
+    double max = *std::max_element(fr.begin(), fr.end());
+    
+    return 1.0 + deme.GetSize() + pow(max-avg, 2.0);
+  }
+};
+ */
+
+
+/*! Compete demes based on the ability of their constituent organisms
+ to synchronize their flashes to a common period, and yet distribute themselves
+ throughout phase-space (phase desynchronization).
+class cActionDesynchronization : public cActionCompeteDemesFlashTiming {
+public:
+  //! Constructor.
+  cActionCompeteDemesFlashTimingDesync(cWorld* world, const cString& args) : cActionCompeteDemesFlashTiming(world, args) {
+  }
+  
+  //! Description of this event.
+  static const cString GetDescription() { return "No Arguments"; }
+  
+  //! Calculate the fitness of a deme (must return > 0.0).
+  virtual double fitness_function(const cDeme& deme) {
+    // How many unique organisms have flashed in the last SYNC_FITNESS_WINDOW updates?
+    int total_flashed = deme.GetUniqueFlashes();
+    
+    // If not everyone has flashed, fitness is just the number that have flashed:
+    if(total_flashed < deme.GetSize()) {
+      return total_flashed + 1.0;
+    }
+    
+    // Let's find out the max number of flashes in any update:
+    const cDeme::flash_row& fr = deme.GetFlashRollingSum();
+    double max = *std::max_element(fr.begin(), fr.end());
+    
+    // And reward based on the difference:
+    return 1.0 + deme.GetSize() + pow(deme.GetSize()-max, 2.0);
+  }
+};
+ */
+
+
 class cAbstractCompeteDemes_AttackKillAndEnergyConserve : public cAbstractCompeteDemes {
 
   public:
@@ -1964,15 +2331,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<cActionIteratedConsensus>("IteratedConsensus");
+	
   action_lib->Register<cActionNewTrial>("NewTrial");
   action_lib->Register<cActionCompeteOrganisms>("CompeteOrganisms");
   

Modified: branches/movement/source/actions/PrintActions.cc
===================================================================
--- branches/movement/source/actions/PrintActions.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/actions/PrintActions.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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);
@@ -2692,6 +2697,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: branches/movement/source/analyze/cAnalyze.cc
===================================================================
--- branches/movement/source/analyze/cAnalyze.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/analyze/cAnalyze.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -1265,6 +1265,7 @@
   batch[cur_batch].SetAligned(false);
 }
 
+
 void cAnalyze::FindSexLineage(cString cur_string)
 {
   
@@ -1493,6 +1494,146 @@
   batch[cur_batch].SetAligned(false);
 }
 
+// @JEB 9-25-2008
+void cAnalyze::FindLastCommonAncestor(cString cur_string)
+{  
+
+/*
+  // Assumes that the current batch contains a population and all of its common ancestors
+  // Finds the last common ancestor among all current organisms that are still alive,
+  // i.e. have an update_died of -1.
+
+  cout << "Finding last common ancestor of batch " << cur_batch << endl;
+  
+  // Make a list of alive organisms
+  tListPlus<cAnalyzeGenotype> alive_list;
+  {
+    tListIterator<cAnalyzeGenotype> batch_it(batch[cur_batch].List());
+    cAnalyzeGenotype * test_genotype = NULL;
+    while ((test_genotype = batch_it.Next()) != NULL) {
+      if (test_genotype->GetUpdateDead() == -1) {
+        alive_list.Push(test_genotype);
+      }
+    }
+  }
+  
+  if (m_world->GetVerbosity() >= VERBOSE_ON) {
+    cout << "  Number of genotypes that are alive: " << alive_list.GetSize() << endl;
+    cout << "  Number of ancestor genotypes: " << batch[cur_batch].List().GetSize() << endl;
+  }
+    
+  // Extract the lineage of the first alive organism.
+  // The LCA must be among these genotypes. The approach is to step back one ancestor
+  // at a time, collect all of its descendants, and then check to see if there are
+  // andy alive organisms that have not been collected yet.
+  
+  // find the lineage of the first genotype...
+  cAnalyzeGenotype * first_alive_genotype = alive_list.Pop();
+  tListPlus<cAnalyzeGenotype> master_lineage;
+  {
+    master_lineage.Push(first_alive_genotype);
+    int next_id = first_alive_genotype->GetParentID();
+    bool found = true;
+    while (found == true) {
+      found = false;
+      
+      tListIterator<cAnalyzeGenotype> batch_it(batch[cur_batch].List());
+      cAnalyzeGenotype * found_gen = NULL;
+      while ((found_gen = batch_it.Next()) != NULL) {
+        if (found_gen->GetID() == next_id) {
+          master_lineage.Push(found_gen);
+          next_id = found_gen->GetParentID();
+          found = true;
+          break;
+        }
+      }
+    }
+  }
+ 
+  if (m_world->GetVerbosity() >= VERBOSE_ON) {
+    cout << "  Size of master lineage: " << master_lineage.GetSize() << endl;
+  }
+    
+  tListIterator<cAnalyzeGenotype> master_lineage_batch_it(master_lineage);
+  
+  while ((collect_genotype = master_lineage_batch_it.Next()) != NULL) {
+    
+    // collect all children of the current lineage genotype
+    tListPlus<cAnalyzeGenotype> collect_genotype_list;
+    collect_genotype_list.PushRear(collect_genotype);
+    tListIterator<cAnalyzeGenotype> collect_batch_it(collect_genotype_list);
+    
+    next_collect_genotype_list;
+    
+    int current_id = alive_genotype->GetID();
+    int parent_id = alive_genotype->GetParentID();
+    bool found_parent = true;
+    bool found_in_master_lineage = false;
+    while (found_parent == true) {
+        
+      // Check to see if this id is among those in the first lineage.       
+      tListIterator<cAnalyzeGenotype> master_lineage_batch_it(master_lineage);
+      cAnalyzeGenotype * master_lineage_genotype;
+      while ((master_lineage_genotype = master_lineage_batch_it.Next()) != NULL) {
+        if (master_lineage_genotype->GetID() == current_id) break;
+      }
+
+      found_in_master_lineage = master_lineage_genotype != NULL;
+      if (found_in_master_lineage) {
+        
+        // Remove anything in the master lineage that is past this point.
+        // as it is younger than the new most recent common ancestor
+        while ((master_lineage_genotype = master_lineage_batch_it.Next()) != NULL) {
+          master_lineage_batch_it.Remove();
+        }
+        
+        // We can also stop looking at ancestors of the current alive_genotype
+        if (found_in_master_lineage) break;
+      }
+      
+      // Find the ancestor of the current organism in the alive_genotype lineage
+      found_parent = false;      
+      tListIterator<cAnalyzeGenotype> batch_it(batch[cur_batch].List());
+      cAnalyzeGenotype * test_genotype = NULL;
+      while ((test_genotype = batch_it.Next()) != NULL) {
+        if (test_genotype->GetID() == parent_id) {
+          parent_id = test_genotype->GetParentID();
+          current_id = test_genotype->GetID();
+          found_parent = true;
+          break;
+        }
+      }
+    }
+    
+    // Warn if we did not find a common ancestor at all.
+    if (!found_in_master_lineage) { 
+      cout << "  Warning! Did not find common ancestor between two organisms. " << endl;
+    }
+    
+    if (m_world->GetVerbosity() >= VERBOSE_ON) {
+      cout << "  Size of master lineage: " << master_lineage.GetSize() << endl;
+    }
+  }
+  
+  // The first one left in this lineage is the one we want to save.
+  cAnalyzeGenotype * last_common_ancestor = master_lineage.Pop();
+  
+  // Delete everything else.
+  tListIterator<cAnalyzeGenotype> delete_batch_it(batch[cur_batch].List());
+  cAnalyzeGenotype * delete_genotype = NULL;
+  while ((delete_genotype = delete_batch_it.Next()) != NULL) {
+    if (delete_genotype->GetID() != last_common_ancestor->GetID()) {
+      delete batch[cur_batch].List().Pop();
+    }
+  }
+  
+  // And fill it back in with the good stuff.
+  batch[cur_batch].List().PushRear(last_common_ancestor);
+
+  */
+}
+
+
 void cAnalyze::SampleOrganisms(cString cur_string)
 {
   double fraction = cur_string.PopWord().AsDouble();
@@ -5388,6 +5529,87 @@
 }
 
 
+// Determine redundancy by calculating the percentage of the lifetimes
+// where fitness is decreased over a range of instruction failure probabilities.
+// @JEB 9-24-2008
+void cAnalyze::CommandAnalyzeRedundancyByInstFailure(cString cur_string)
+{
+  cString filename("analyze_redundancy_by_inst_failure.dat");
+  if (cur_string.GetSize() != 0) filename = cur_string.PopWord();
+  int replicates = 1000;
+  if (cur_string.GetSize() != 0) replicates = cur_string.PopWord().AsInt();
+
+  // Output is one line per organism in the current batch with columns.
+  cDataFile & df = m_world->GetDataFile(filename);
+  df.WriteComment( "Redundancy calculated by changing the probability of instruction failure" );
+  cString s;
+  s.Set("%i replicates at each chance of instruction failure", replicates);
+  df.WriteComment(s);
+  df.WriteTimeStamp();
+
+  // Loop through all of the genotypes in this batch...
+
+  tListIterator<cAnalyzeGenotype> batch_it(batch[cur_batch].List());
+  cAnalyzeGenotype * genotype = NULL;
+  while ((genotype = batch_it.Next()) != NULL) {
+
+    if (m_world->GetVerbosity() >= VERBOSE_ON) {
+      cout << "  Determining redundancy by instruction failure for " << genotype->GetName() << endl;
+    }
+    
+     cInstSet modify_inst_set = genotype->GetInstructionSet();
+      
+    // Modify the instruction set to include the current probability of failure.
+    for (int j=0; j<modify_inst_set.GetSize(); j++)
+    {
+      cString inst_name = modify_inst_set.GetName(j);
+      cInstruction inst = modify_inst_set.GetInst(inst_name);
+      modify_inst_set.SetProbFail(inst, 0);
+    }
+    genotype->SetInstructionSet(modify_inst_set);
+  
+    // Recalculate the baseline fitness
+    // May need to calculate multiple times to check for stochastic behavior....
+    genotype->Recalculate(m_ctx);
+    double baseline_fitness = genotype->GetFitness();
+  
+    if (baseline_fitness>0)
+    {
+      // Write information for this 
+      df.Write(genotype->GetName(), "genotype name");
+      df.Write(genotype->GetID(), "genotype id");
+      df.Write(baseline_fitness, "fitness");
+      
+      // Run the organism the specified number of replicates
+      
+      for (double log10_fc=-4.0; log10_fc<=0.0; log10_fc+=0.1)
+      {
+        double fc = exp(log10_fc*log(10));
+        
+        // Modify the instruction set to include the current probability of failure.
+        for (int j=0; j<modify_inst_set.GetSize(); j++)
+        {
+          cString inst_name = modify_inst_set.GetName(j);
+          cInstruction inst = modify_inst_set.GetInst(inst_name);
+          modify_inst_set.SetProbFail(inst, fc);
+        }
+        genotype->SetInstructionSet(modify_inst_set);
+        
+        // Recalculate the requested number of times
+        double chance = 0;
+        for (int i=0; i<replicates; i++)
+        {
+          genotype->Recalculate(m_ctx);
+          if (genotype->GetFitness() < baseline_fitness) chance++;
+        }      
+        s.Set("Inst prob fail %.3g", fc);
+        df.Write(chance/replicates, s);
+      }
+      df.Endl();
+    }
+  }
+}
+
 void cAnalyze::CommandMapMutations(cString cur_string)
 {
   cout << "Constructing genome mutations maps..." << endl;
@@ -9254,6 +9476,7 @@
   AddLibraryDef("FIND_LINEAGE", &cAnalyze::FindLineage);
   AddLibraryDef("FIND_SEX_LINEAGE", &cAnalyze::FindSexLineage);
   AddLibraryDef("FIND_CLADE", &cAnalyze::FindClade);
+  AddLibraryDef("FIND_LAST_COMMON_ANCESTOR", &cAnalyze::FindLastCommonAncestor);  
   AddLibraryDef("SAMPLE_ORGANISMS", &cAnalyze::SampleOrganisms);
   AddLibraryDef("SAMPLE_GENOTYPES", &cAnalyze::SampleGenotypes);
   AddLibraryDef("KEEP_TOP", &cAnalyze::KeepTopGenotypes);
@@ -9286,6 +9509,7 @@
   AddLibraryDef("MAP", &cAnalyze::CommandMapTasks);  // Deprecated...
   AddLibraryDef("MAP_TASKS", &cAnalyze::CommandMapTasks);
   AddLibraryDef("AVERAGE_MODULARITY", &cAnalyze::CommandAverageModularity);
+  AddLibraryDef("ANALYZE_REDUNDANCY_BY_INST_FAILURE", &cAnalyze::CommandAnalyzeRedundancyByInstFailure);
   AddLibraryDef("MAP_MUTATIONS", &cAnalyze::CommandMapMutations);
   AddLibraryDef("ANALYZE_COMPLEXITY", &cAnalyze::AnalyzeComplexity);
   AddLibraryDef("ANALYZE_FITNESS_TWO_SITES", &cAnalyze::AnalyzeFitnessLandscapeTwoSites);

Modified: branches/movement/source/analyze/cAnalyze.h
===================================================================
--- branches/movement/source/analyze/cAnalyze.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/analyze/cAnalyze.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -234,6 +234,7 @@
   void FindLineage(cString cur_string);
   void FindSexLineage(cString cur_string);
   void FindClade(cString cur_string);
+  void FindLastCommonAncestor(cString cur_string);
   void SampleOrganisms(cString cur_string);
   void SampleGenotypes(cString cur_string);
   void KeepTopGenotypes(cString cur_string);
@@ -268,6 +269,7 @@
   void CommandMapTasks(cString cur_string);
   void CommandAverageModularity(cString cur_string);
   void CommandAnalyzeModularity(cString cur_string);
+  void CommandAnalyzeRedundancyByInstFailure(cString cur_string);
   void CommandMapMutations(cString cur_string);
   void CommandMapDepth(cString cur_string);
   void CommandPairwiseEntropy(cString cur_string);

Modified: branches/movement/source/analyze/cAnalyzeGenotype.h
===================================================================
--- branches/movement/source/analyze/cAnalyzeGenotype.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/analyze/cAnalyzeGenotype.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -37,6 +37,9 @@
 #ifndef cGenome_h
 #include "cGenome.h"
 #endif
+#ifndef cInstSet_h
+#include "cInstSet.h"
+#endif
 #ifndef cLandscape_h
 #include "cLandscape.h"
 #endif
@@ -241,6 +244,7 @@
   // Set...
   void SetSequence(cString _sequence);
   void SetName(const cString & _name) { name = _name; }
+  void SetInstructionSet(cInstSet& _inst_set) { m_inst_set = _inst_set; }
   void SetAlignedSequence(const cString & _seq) { aligned_sequence = _seq; }
   void SetTag(const cString & _tag) { tag = _tag; }
 
@@ -285,6 +289,7 @@
   // Accessors...
   const cGenome & GetGenome() const { return genome; }
   const cString & GetName() const { return name; }
+  const cInstSet & GetInstructionSet() const { return m_inst_set; }
   const cString & GetAlignedSequence() const { return aligned_sequence; }
   cString GetExecutedFlags() const { return executed_flags; }
   cString GetAlignmentExecutedFlags() const;

Modified: branches/movement/source/cpu/cHardwareBase.cc
===================================================================
--- branches/movement/source/cpu/cHardwareBase.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cHardwareBase.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/cpu/cHardwareBase.h
===================================================================
--- branches/movement/source/cpu/cHardwareBase.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cHardwareBase.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/cpu/cHardwareCPU.cc
===================================================================
--- branches/movement/source/cpu/cHardwareCPU.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cHardwareCPU.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -210,11 +210,6 @@
     tInstLibEntry<tMethod>("sense-m100", &cHardwareCPU::Inst_SenseMult100, nInstFlag::STALL),   // the names to cStats::cStats() @JEB
 	tInstLibEntry<tMethod>("sense-diff-facing", &cHardwareCPU::Inst_SenseDiffFacing, nInstFlag::STALL),
     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),
@@ -466,6 +461,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"),
@@ -492,6 +503,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();
@@ -523,6 +535,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;
@@ -581,6 +594,7 @@
       }
     }
   }
+	m_last_cell_data = std::make_pair(false, 0);
 }
 
 void cHardwareCPU::cLocalThread::operator=(const cLocalThread& in_thread)
@@ -693,6 +707,12 @@
         exec = !( ctx.GetRandom().P(m_inst_set->GetProbFail(cur_inst)) );
       }
       
+      // Flag instruction as executed even if it failed (moved from SingleProcess_ExecuteInst)
+      // this allows division conditions to be met even if most instruction executions failed. @JEB
+      
+      // Mark the instruction as executed
+      IP().SetFlagExecuted();
+      
       // Add to the promoter inst executed count before executing the inst (in case it is a terminator)
       if (m_promoters_enabled) m_threads[m_cur_thread].IncPromoterInstExecuted();
 
@@ -748,10 +768,6 @@
   // Get a pointer to the corresponding method...
   int inst_idx = m_inst_set->GetLibFunctionIndex(actual_inst);
   
-  // Mark the instruction as executed
-  IP().SetFlagExecuted();
-	
-  
 #if INSTRUCTION_COUNT
   // instruction execution count incremented
   organism->GetPhenotype().IncCurInstCount(actual_inst.GetOp());
@@ -2166,6 +2182,7 @@
   GetRegister(REG_BX) = 0;
   GetRegister(REG_CX) = 0;
   StackClear();
+	m_last_cell_data = std::make_pair(false, 0);
   return true;
 }
 
@@ -3464,51 +3481,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);
@@ -7451,6 +7423,7 @@
  */
 bool cHardwareCPU::Inst_SetOpinion(cAvidaContext& ctx)
 {
+	assert(organism != 0);
   organism->SetOpinion(GetRegister(FindModifiedRegister(REG_BX)));
   return true;
 }
@@ -7462,6 +7435,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);
@@ -7471,3 +7445,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: branches/movement/source/cpu/cHardwareCPU.h
===================================================================
--- branches/movement/source/cpu/cHardwareCPU.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cHardwareCPU.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -469,10 +469,6 @@
   bool DoSenseDiffFacing(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);
@@ -674,6 +670,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
@@ -685,6 +682,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: branches/movement/source/cpu/cHardwareManager.cc
===================================================================
--- branches/movement/source/cpu/cHardwareManager.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cHardwareManager.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/cpu/cInstSet.h
===================================================================
--- branches/movement/source/cpu/cInstSet.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cInstSet.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -138,6 +138,9 @@
 
   // Insertion of new instructions...
   cInstruction ActivateNullInst();
+  
+  // Modification of instructions during run.
+  void SetProbFail(const cInstruction& inst, double _prob_fail) { m_lib_name_map[inst.GetOp()].prob_fail = _prob_fail; }
 
   // accessors for instruction library
   cInstLib* GetInstLib() { return m_inst_lib; }

Modified: branches/movement/source/cpu/cTestCPUInterface.h
===================================================================
--- branches/movement/source/cpu/cTestCPUInterface.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/cpu/cTestCPUInterface.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/main/cAvidaConfig.h
===================================================================
--- branches/movement/source/main/cAvidaConfig.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cAvidaConfig.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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");
   
@@ -475,8 +476,8 @@
   CONFIG_ADD_VAR(ENERGY_ENABLED, bool, 0, "Enable Energy Model. 0/1 (off/on)");
   CONFIG_ADD_VAR(ENERGY_GIVEN_ON_INJECT, int, 0, "Energy given to organism upon injection.");
   CONFIG_ADD_VAR(ENERGY_GIVEN_AT_BIRTH, int, 0, "Energy given to offspring upon birth.");
-  CONFIG_ADD_VAR(FRAC_PARENT_ENERGY_GIVEN_TO_ORG_AT_BIRTH, double, 0.5, "Fraction of perent's energy given to offspring organism.");
-  CONFIG_ADD_VAR(FRAC_PARENT_ENERGY_GIVEN_TO_DEME_AT_BIRTH, double, 0.5, "Fraction of perent's energy given to offspring deme.");
+  CONFIG_ADD_VAR(FRAC_PARENT_ENERGY_GIVEN_TO_ORG_AT_BIRTH, double, 0.5, "Fraction of parent's energy given to offspring organism.");
+  CONFIG_ADD_VAR(FRAC_PARENT_ENERGY_GIVEN_TO_DEME_AT_BIRTH, double, 0.5, "Fraction of parent's energy given to offspring deme.");
   CONFIG_ADD_VAR(FRAC_ENERGY_DECAY_AT_ORG_BIRTH, double, 0.0, "Fraction of energy lost due to decay during organism reproduction.");
   CONFIG_ADD_VAR(FRAC_ENERGY_DECAY_AT_DEME_BIRTH, double, 0.0, "Fraction of energy lost due to decay during deme reproduction.");
   CONFIG_ADD_VAR(NUM_INST_EXC_BEFORE_0_ENERGY, int, 0, "Number of instructions executed before energy is exhausted.");
@@ -563,6 +564,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: branches/movement/source/main/cDeme.h
===================================================================
--- branches/movement/source/main/cDeme.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cDeme.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -232,7 +232,7 @@
   void SetupDemeRes(int id, cResource * res, int verbosity);
   void UpdateDemeRes() { deme_resource_count.GetResources(); }
   void Update(double time_step) { deme_resource_count.Update(time_step); }
-  int GetRelativeCellID(int absolute_cell_id) { return absolute_cell_id % GetSize(); } //!< assumes all demes are the same size
+  int GetRelativeCellID(int absolute_cell_id) const { return absolute_cell_id % GetSize(); } //!< assumes all demes are the same size
 
   void SetCellEventGradient(int x1, int y1, int x2, int y2, int delay, int duration, bool static_pos, int time_to_live);
   int GetNumEvents();

Modified: branches/movement/source/main/cOrgInterface.h
===================================================================
--- branches/movement/source/main/cOrgInterface.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cOrgInterface.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/main/cOrgMessagePredicate.h
===================================================================
--- branches/movement/source/main/cOrgMessagePredicate.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cOrgMessagePredicate.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/main/cOrganism.cc
===================================================================
--- branches/movement/source/main/cOrganism.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cOrganism.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -602,6 +602,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;
@@ -805,3 +806,26 @@
   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);
+  DoOutput(ctx);
+}

Modified: branches/movement/source/main/cOrganism.h
===================================================================
--- branches/movement/source/main/cOrganism.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cOrganism.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -439,6 +439,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: branches/movement/source/main/cPopulation.cc
===================================================================
--- branches/movement/source/main/cPopulation.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cPopulation.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -1147,14 +1147,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);
@@ -1205,7 +1206,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);
@@ -1232,7 +1239,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) {
@@ -2172,7 +2179,7 @@
     }
   }
 
-return successfully_seeded;
+	return successfully_seeded;
 }
 
 void cPopulation::InjectDemeFounder(int _cell_id, cGenotype& _genotype, cPhenotype* _phenotype)

Modified: branches/movement/source/main/cPopulationInterface.cc
===================================================================
--- branches/movement/source/main/cPopulationInterface.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cPopulationInterface.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/main/cPopulationInterface.h
===================================================================
--- branches/movement/source/main/cPopulationInterface.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cPopulationInterface.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -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: branches/movement/source/main/cStats.cc
===================================================================
--- branches/movement/source/main/cStats.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cStats.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -1268,8 +1268,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.
   }  
 }
@@ -1331,29 +1330,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) {
@@ -1712,7 +1706,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);
@@ -1745,3 +1738,94 @@
   
   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 when an organism issues a flash instruction.
+ 
+ We do some pretty detailed tracking here in order to support the use of flash
+ messages in deme competition.  All flashes are tracked per deme.
+ */
+void cStats::SentFlash(cOrganism& organism) {
+  ++m_flash_count;	
+	if(organism.GetOrgInterface().GetDeme() != 0) {
+		const cDeme* deme = organism.GetOrgInterface().GetDeme();
+		m_flash_times[GetUpdate()][deme->GetID()].push_back(deme->GetRelativeCellID(organism.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_flash_times.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, demeid, cellid) tuples, representing the update at which that cell flashed.");
+  df.WriteTimeStamp();
+	
+	for(PopulationFlashes::iterator i=m_flash_times.begin(); i!=m_flash_times.end(); ++i) {
+		for(DemeFlashes::iterator j=i->second.begin(); j!=i->second.end(); ++j) {
+			for(CellFlashes::iterator k=j->second.begin(); k!=j->second.end(); ++k) {
+				df.Write(i->first, "Update [update]");
+				df.Write(j->first, "Deme ID [demeid]");
+				df.Write(*k, "Deme-relative cell ID that issued a flash at this update [relcellid]");
+				df.Endl();
+			}
+		}
+	}
+	
+	m_flash_times.clear();
+}

Modified: branches/movement/source/main/cStats.h
===================================================================
--- branches/movement/source/main/cStats.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/main/cStats.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -868,6 +868,33 @@
   
 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:
+	typedef std::vector<int> CellFlashes; //!< Typedef for a list of cell IDs.
+	typedef std::map<int, CellFlashes> DemeFlashes; //!< Typedef for cell IDs (in this deme) -> list of cell IDs.
+	typedef std::map<int, DemeFlashes> PopulationFlashes; //!< Typedef for deme IDs -> flashes in that deme.
+  //! Called immediately after an organism has issued a "flash" to its neighbors.
+  void SentFlash(cOrganism& organism);
+	//! Retrieve the cell ID -> flash time map.
+	const PopulationFlashes& GetFlashTimes() { return m_flash_times; }
+  //! 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.
+	PopulationFlashes m_flash_times; //!< For tracking flashes that have occurred throughout this population.
 };
 
 

Modified: branches/movement/source/script/AvidaScript.h
===================================================================
--- branches/movement/source/script/AvidaScript.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/script/AvidaScript.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -164,6 +164,7 @@
   AS_DIRECT_INTERPRET_ERR_KEY_NOT_FOUND,
   AS_DIRECT_INTERPRET_ERR_MATRIX_OP_TYPE_MISMATCH,
   AS_DIRECT_INTERPRET_ERR_MATRIX_SIZE_MISMATCH,
+  AS_DIRECT_INTERPRET_ERR_NATIVE_OBJECT_TYPE_MISMATCH,
   AS_DIRECT_INTERPRET_ERR_OBJECT_ASSIGN_FAIL,
   AS_DIRECT_INTERPRET_ERR_TYPE_CAST,
   AS_DIRECT_INTERPRET_ERR_UNDEFINED_TYPE_OP,

Modified: branches/movement/source/script/cASNativeObject.h
===================================================================
--- branches/movement/source/script/cASNativeObject.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/script/cASNativeObject.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -33,17 +33,40 @@
 
 class cASNativeObject 
 {
+private:
+  int m_ref_count;
   
 public:
-  cASNativeObject() { ; }
+  cASNativeObject() : m_ref_count(1) { ; }
   virtual ~cASNativeObject() { ; }
   
-  bool CallMethod(int mid, int argc, cASCPPParameter args[]) { return false; } // @TODO
+  virtual const char* GetType() = 0;
   
+  virtual bool CallMethod(int mid, int argc, cASCPPParameter args[]) = 0;
+  
   int LookupValue(const cString& val_name) { return AS_NOT_FOUND; } // @TODO
   int LookupMethod(const cString& meth_name) { return AS_NOT_FOUND; } // @TODO
   
-  void Release() { ; }
+  inline cASNativeObject* GetReference() { m_ref_count++; return this; }
+  inline void RemoveReference() { m_ref_count--; if (m_ref_count == 0) delete this; }
+  inline bool IsShared() { return (m_ref_count > 1); }
 };
 
+
+template<class NativeClass, const char* TypeName>
+class tASNativeObject : public cASNativeObject
+{
+private:
+  NativeClass* m_object;
+  
+public:
+  tASNativeObject(NativeClass* obj) : m_object(obj) { ; }
+  ~tASNativeObject() { delete m_object; }
+
+  const char* GetType() { return TypeName; }
+  
+  bool CallMethod(int mid, int argc, cASCPPParameter args[]) { return false; } // @TODO;  
+};
+  
+
 #endif

Modified: branches/movement/source/script/cDirectInterpretASTVisitor.cc
===================================================================
--- branches/movement/source/script/cDirectInterpretASTVisitor.cc	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/script/cDirectInterpretASTVisitor.cc	2008-09-29 12:20:07 UTC (rev 2804)
@@ -116,7 +116,10 @@
     case TYPE(CHAR):        m_call_stack[sp + var_id].value.as_char = asChar(m_rtype, m_rvalue, node); break;
     case TYPE(FLOAT):       m_call_stack[sp + var_id].value.as_float = asFloat(m_rtype, m_rvalue, node); break;
     case TYPE(INT):         m_call_stack[sp + var_id].value.as_int = asInt(m_rtype, m_rvalue, node); break;
-    case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - assignment
+    
+    case TYPE(OBJECT_REF):
+      m_call_stack[sp + var_id].value.as_nobj->RemoveReference();
+      m_call_stack[sp + var_id].value.as_nobj = asNativeObject(symtbl->GetVariableType(var_id).info, m_rtype, m_rvalue, node);
 
     case TYPE(VAR):
       m_call_stack[sp + var_id].value = m_rvalue;
@@ -212,7 +215,10 @@
       case TYPE(CHAR):        m_call_stack[var_idx].value.as_char = asChar(val.type, val.value, node); break;
       case TYPE(FLOAT):       m_call_stack[var_idx].value.as_float = asFloat(val.type, val.value, node); break;
       case TYPE(INT):         m_call_stack[var_idx].value.as_int = asInt(val.type, val.value, node); break;
-      case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - foreach assignment
+      case TYPE(OBJECT_REF):
+        m_call_stack[var_idx].value.as_nobj->RemoveReference();
+        m_call_stack[var_idx].value.as_nobj = asNativeObject(var_type.info, val.type, val.value, node);
+        break;
         
       case TYPE(ARRAY):
         m_call_stack[var_idx].value.as_array->RemoveReference();
@@ -306,7 +312,7 @@
       case TYPE(DICT):        m_call_stack[m_sp + var_id].value.as_dict = asDict(m_rtype, m_rvalue, node); break;
       case TYPE(FLOAT):       m_call_stack[m_sp + var_id].value.as_float = asFloat(m_rtype, m_rvalue, node); break;
       case TYPE(INT):         m_call_stack[m_sp + var_id].value.as_int = asInt(m_rtype, m_rvalue, node); break;
-      case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - var def assignment
+      case TYPE(OBJECT_REF):  m_call_stack[m_sp + var_id].value.as_nobj = asNativeObject(node.GetType().info, m_rtype, m_rvalue, node); break;
       case TYPE(MATRIX):      m_call_stack[m_sp + var_id].value.as_matrix = asMatrix(m_rtype, m_rvalue, node); break;
       case TYPE(STRING):
         delete m_call_stack[m_sp + var_id].value.as_string;
@@ -342,6 +348,8 @@
     } else {
       INTERPRET_ERROR(INTERNAL);
     }
+  } else if (node.GetType().type == TYPE(OBJECT_REF)) {
+    // @TODO - set native object ref to special NULL value
   }
 }
 
@@ -1243,7 +1251,7 @@
         case TYPE(DICT):        m_call_stack[sp + var_id].value.as_dict = asDict(m_rtype, m_rvalue, node); break;
         case TYPE(FLOAT):       m_call_stack[sp + var_id].value.as_float = asFloat(m_rtype, m_rvalue, node); break;
         case TYPE(INT):         m_call_stack[sp + var_id].value.as_int = asInt(m_rtype, m_rvalue, node); break;
-        case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - func call arg assignment
+        case TYPE(OBJECT_REF):  m_call_stack[sp + var_id].value.as_nobj = asNativeObject(func_symtbl->GetVariableType(var_id).info, m_rtype, m_rvalue, node); break;
         case TYPE(MATRIX):      m_call_stack[sp + var_id].value.as_matrix = asMatrix(m_rtype, m_rvalue, node); break;
         case TYPE(STRING):
           {
@@ -1275,7 +1283,7 @@
       case TYPE(DICT):        m_rvalue.as_dict = asDict(m_rtype, m_rvalue, node); break;
       case TYPE(FLOAT):       m_rvalue.as_float = asFloat(m_rtype, m_rvalue, node); break;
       case TYPE(INT):         m_rvalue.as_int = asInt(m_rtype, m_rvalue, node); break;
-      case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - return
+      case TYPE(OBJECT_REF):  m_rvalue.as_nobj = asNativeObject(node.GetType().info, m_rtype, m_rvalue, node); break;
       case TYPE(MATRIX):      m_rvalue.as_matrix = asMatrix(m_rtype, m_rvalue, node); break;
       case TYPE(STRING):      m_rvalue.as_string = asString(m_rtype, m_rvalue, node); break;
       case TYPE(VAR):         break;
@@ -1434,7 +1442,7 @@
     switch (node.GetType().type) {
       case TYPE(ARRAY):       m_rvalue.as_ref = new cArrayVarRef(m_call_stack[sp + var_id].value); break;
       case TYPE(DICT):        m_rvalue.as_ref = new cDictVarRef(m_call_stack[sp + var_id].value); break;
-      case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - var ref object assignment
+      case TYPE(OBJECT_REF):  m_rvalue.as_ref = new cNativeObjectVarRef(m_call_stack[sp + var_id].value); break;
       case TYPE(MATRIX):      m_rvalue.as_ref = new cMatrixVarRef(m_call_stack[sp + var_id].value); break;
       case TYPE(STRING):      m_rvalue.as_ref = new cStringVarRef(m_call_stack[sp + var_id].value); break;
         
@@ -1459,7 +1467,7 @@
       case TYPE(STRING):      m_rvalue.as_string = new cString(*m_call_stack[sp + var_id].value.as_string); break;
 
       
-      case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - var ref assignment
+      case TYPE(OBJECT_REF):  m_rvalue.as_nobj = m_call_stack[sp + var_id].value.as_nobj->GetReference(); break;
         
       default:
         INTERPRET_ERROR(INTERNAL);
@@ -1490,7 +1498,10 @@
       case TYPE(CHAR):        m_call_stack[var_idx].value.as_char = asChar(val.type, val.value, node); break;
       case TYPE(FLOAT):       m_call_stack[var_idx].value.as_float = asFloat(val.type, val.value, node); break;
       case TYPE(INT):         m_call_stack[var_idx].value.as_int = asInt(val.type, val.value, node); break;
-      case TYPE(OBJECT_REF):  INTERPRET_ERROR(INTERNAL); // @TODO - assignment
+      case TYPE(OBJECT_REF):
+        m_call_stack[var_idx].value.as_nobj->RemoveReference();
+        m_call_stack[var_idx].value.as_nobj = asNativeObject(var_type.info, val.type, val.value, node);
+        break;
         
       case TYPE(VAR):
         m_call_stack[var_idx].value = val.value;
@@ -1757,6 +1768,22 @@
 }
 
 
+cASNativeObject* cDirectInterpretASTVisitor::asNativeObject(const cString& info, const sASTypeInfo& type, uAnyType value,
+                                                            cASTNode& node)                                                           
+{
+  switch (type.type) {
+    case TYPE(OBJECT_REF):
+      if (type.info != info) INTERPRET_ERROR(NATIVE_OBJECT_TYPE_MISMATCH, *info, *type.info);
+      return value.as_nobj;
+      
+    default:
+      INTERPRET_ERROR(TYPE_CAST, mapType(type), mapType(TYPE(OBJECT_REF)));
+  }
+  
+  return NULL;
+}
+
+
 cString* cDirectInterpretASTVisitor::asString(const sASTypeInfo& type, uAnyType value, cASTNode& node)
 {
   switch (type.type) {
@@ -1786,9 +1813,9 @@
         return str;
       }
 
-    case TYPE(OBJECT_REF): // @TODO - as string
+    case TYPE(OBJECT_REF):
     {
-      cString* str = new cString(cStringUtil::Stringf("< object >"));
+      cString* str = new cString(cStringUtil::Stringf("< %s object @ %p >", value.as_nobj->GetType(), value.as_nobj));
       return str;
     }
       
@@ -2196,9 +2223,7 @@
       case TYPE(ARRAY):   return value.as_array == lval.value.as_array;
       case TYPE(DICT):    return value.as_dict == lval.value.as_dict;
       case TYPE(MATRIX):  return value.as_matrix == lval.value.as_matrix;
-        
-      case TYPE(OBJECT_REF): // @TODO - aggregate value compare
-        return value.as_void == lval.value.as_void;
+      case TYPE(OBJECT_REF): return value.as_nobj == lval.value.as_nobj;
       
       default:
         break;
@@ -2497,8 +2522,21 @@
 }
 
 
+bool cDirectInterpretASTVisitor::cNativeObjectVarRef::Get(const sAggregateValue& idx, sAggregateValue& val)
+{
+  // @TODO - get indexed native var
+  return false;
+}
 
+bool cDirectInterpretASTVisitor::cNativeObjectVarRef::Set(sAggregateValue& idx, sAggregateValue& val)
+{
+  // @TODO - set indexed native var
+  return false;
+}
 
+
+
+
 bool cDirectInterpretASTVisitor::cObjectIndexRef::Get(const sAggregateValue& idx, sAggregateValue& val)
 {
   sAggregateValue o_val;
@@ -2721,6 +2759,13 @@
     case AS_DIRECT_INTERPRET_ERR_MATRIX_SIZE_MISMATCH:
       std::cerr << "matrix size mismatch for '" << VA_ARG_STR << "' operation" << ERR_ENDL;
       break;
+    case AS_DIRECT_INTERPRET_ERR_NATIVE_OBJECT_TYPE_MISMATCH:
+      {
+        const char* otype = VA_ARG_STR;
+        const char* itype = VA_ARG_STR;
+        std::cerr << "expected object of type '" << otype << "', received '" << itype << "'" << ERR_ENDL;
+      }
+      break;
     case AS_DIRECT_INTERPRET_ERR_OBJECT_ASSIGN_FAIL:
       std::cerr << "aggregate assignment failed" << ERR_ENDL;
       break;

Modified: branches/movement/source/script/cDirectInterpretASTVisitor.h
===================================================================
--- branches/movement/source/script/cDirectInterpretASTVisitor.h	2008-09-28 23:08:43 UTC (rev 2803)
+++ branches/movement/source/script/cDirectInterpretASTVisitor.h	2008-09-29 12:20:07 UTC (rev 2804)
@@ -54,6 +54,7 @@
     cLocalDict* as_dict;
     cLocalMatrix* as_matrix;
     cObjectRef* as_ref;
+    cASNativeObject* as_nobj;
     void* as_void;
   } uAnyType;
   
@@ -133,6 +134,7 @@
   int asInt(const sASTypeInfo& type, uAnyType value, cASTNode& node);
   double asFloat(const sASTypeInfo& type, uAnyType value, cASTNode& node);
   cLocalMatrix* asMatrix(const sASTypeInfo& type, uAnyType value, cASTNode& node);
+  cASNativeObject* asNativeObject(const cString& info, const sASTypeInfo& type, uAnyType value, cASTNode& node);
   cString* asString(const sASTypeInfo& type, uAnyType value, cASTNode& node);
   
   ASType_t getRuntimeType(ASType_t ltype, ASType_t rtype, bool allow_str = false);
@@ -307,20 +309,20 @@
     bool Set(sAggregateValue& idx, sAggregateValue& val);
   };
   
-  class cNativeObjectRef : public cObjectRef
+  class cNativeObjectVarRef : public cObjectRef
   {
   private:
-    cASNativeObject* m_no;
+    uAnyType& m_var;
     
   public:
-    cNativeObjectRef();
-    ~cNativeObjectRef() { m_no->Release(); }
+    cNativeObjectVarRef(uAnyType& var) : m_var(var) { ; }
+    ~cNativeObjectVarRef() { ; }
     
     bool IsWritable() { return false; } 
-    bool Get(sAggregateValue& val) { return false; }
-    bool Get(const sAggregateValue& idx, sAggregateValue& val) { return false; }
+    bool Get(sAggregateValue& val) { val.value = m_var; val.type = AS_TYPE_OBJECT_REF; return false; }
+    bool Get(const sAggregateValue& idx, sAggregateValue& val);
     bool Set(sAggregateValue& val) { return false; }
-    bool Set(sAggregateValue& idx, sAggregateValue& val) { return false; }    
+    bool Set(sAggregateValue& idx, sAggregateValue& val);
   };
   
   class cObjectIndexRef : public cObjectRef




More information about the Avida-cvs mailing list