[Avida-SVN] r1618 - development/source/cpu

barrick at myxo.css.msu.edu barrick at myxo.css.msu.edu
Sun May 27 11:14:18 PDT 2007


Author: barrick
Date: 2007-05-27 14:14:18 -0400 (Sun, 27 May 2007)
New Revision: 1618

Modified:
   development/source/cpu/cHardwareGX.cc
   development/source/cpu/cHardwareGX.h
Log:
Various GX changes and additions:

processivity - p-copy sometimes causes both heads to fall off.
modularity - head/task instructions interefere with the other kind by reseting the input buffers or heads.
programid length limit.
divide tests done on the daughter are also done on the mother now to avoid artifactual survival of organisms with only DNAP.



Modified: development/source/cpu/cHardwareGX.cc
===================================================================
--- development/source/cpu/cHardwareGX.cc	2007-05-26 21:56:18 UTC (rev 1617)
+++ development/source/cpu/cHardwareGX.cc	2007-05-27 18:14:18 UTC (rev 1618)
@@ -53,6 +53,8 @@
 
 
 tInstLib<cHardwareGX::tMethod>* cHardwareGX::s_inst_slib = cHardwareGX::initInstLib();
+const double cHardwareGX::EXECUTABLE_COPY_PROCESSIVITY = 0.97;
+const double cHardwareGX::READABLE_COPY_PROCESSIVITY = 1.0;
 
 tInstLib<cHardwareGX::tMethod>* cHardwareGX::initInstLib(void)
 {
@@ -262,6 +264,9 @@
     tInstLibEntry<tMethod>("if-bind", &cHardwareGX::Inst_IfBind),
     tInstLibEntry<tMethod>("if-bind2", &cHardwareGX::Inst_IfBind2),
     tInstLibEntry<tMethod>("num-sites", &cHardwareGX::Inst_NumSites),
+    
+    tInstLibEntry<tMethod>("p-get", &cHardwareGX::Inst_ProgramidGet),
+    tInstLibEntry<tMethod>("p-put", &cHardwareGX::Inst_ProgramidPut),
 
     // These are dummy instructions used for making mutiple programids
     // look like one genome (for purposes of passing to offspring and printing).
@@ -399,15 +404,36 @@
       const cInstruction& cur_inst = IP().GetInst();
       
       m_advance_ip = true;
+      m_reset_inputs = false;
+      m_reset_heads = false;
       SingleProcess_ExecuteInst(ctx, cur_inst);
       
       // Break out if we just divided b/c the number of programids 
       // will have changed and it won't be obvious how to continue
       if (m_just_divided) break;
+      
       if (m_advance_ip == true) { 
         IP().Advance();
       }
       
+      if (m_reset_inputs) {
+        // Re-randomize the inputs
+        organism->GetOrgInterface().ResetInputs(ctx); 
+        // And clear the current input buffer
+        m_current->m_inputBuffer.Clear();     
+      }
+     
+      if (m_reset_heads)
+      {
+        // Set the read and write heads back to ourself
+        cHeadProgramid& write = GetHead(nHardware::HEAD_WRITE);
+        cHeadProgramid& read = GetHead(nHardware::HEAD_READ);      
+        read.GetProgramid()->RemoveContactingHead(read);
+        read.Set(0, m_current->m_id);     
+        write.GetProgramid()->RemoveContactingHead(write);
+        write.Set(0, m_current->m_id);                                      
+      }
+      
       // Update this programid stat
       m_current->IncCPUCyclesUsed();  
     }
@@ -2194,8 +2220,7 @@
 {
   bool return_value = Inst_TaskPut(ctx);          // Do a normal put
   organism->GetOrgInterface().ResetInputs(ctx);   // Now re-randomize the inputs this organism sees
-  m_current->m_inputBuffer.Clear();
-  //organism->ClearInput();                         // Also clear their input buffers, or they can still claim
+  m_current->m_inputBuffer.Clear();               // Also clear their input buffers, or they can still claim
                                                   // rewards for numbers no longer in their environment!
   return return_value;
 }
@@ -3234,6 +3259,8 @@
 */
 bool cHardwareGX::Inst_NewProgramid(cAvidaContext& ctx, bool executable, bool bindable, bool readable)
 {
+  m_reset_inputs = true;
+
   // Do some maintenance on the programid where the write head was previously.
   // (1) Adjust the number of heads on it; this could make it executable!
   // (2) \todo Delete if it has no instructions or is below a certain size?
@@ -3241,8 +3268,19 @@
   m_programids[write_head_contacted]->RemoveContactingHead(GetHead(nHardware::HEAD_WRITE));
   GetHead(nHardware::HEAD_WRITE).Set(0, m_current->m_id); // Immediately set the write head back to itself
   
-  // If we've reached the programid limit, then deal with that
-  if(m_programids.size() >= MAX_PROGRAMIDS) {
+  // If we've reached a programid limit, then deal with that
+  
+  // \todo Keep track of total programid length as it is allocated
+  // rather than adding it back up every time we hit this code
+  // Technically, this currently counts incorrectly (depending on your POV) because
+  // p-copy leaves a blank instruction in the spot where it is going to write next.
+  int used_length = 0;
+  for (unsigned int i=0; i<m_programids.size(); i++) {
+    used_length += m_programids[i]->GetMemory().GetSize();
+  }
+
+  if ( (m_programids.size() >= MAX_PROGRAMIDS) || (used_length > MAX_PROGRAMID_TOTAL_LENGTH) ) {
+  
     //Decide on a programid to destroy, currently highest number of cpu cycles executed
     //\todo more methods of choosing..
   
@@ -3307,6 +3345,8 @@
 */
 bool cHardwareGX::Inst_Bind(cAvidaContext& ctx) 
 {
+  m_reset_inputs = true;
+
   // Get the label that we're trying to match.
   // Do this first to advance IP past it.
   ReadLabel();
@@ -3355,6 +3395,8 @@
 */
 bool cHardwareGX::Inst_Bind2(cAvidaContext& ctx)
 {
+  m_reset_inputs = true;
+
   // Get the label we're searching for.
   ReadLabel();
   
@@ -3451,6 +3493,8 @@
 */
 bool cHardwareGX::Inst_ProgramidCopy(cAvidaContext& ctx)
 {
+  m_reset_inputs = true;
+
   cHeadProgramid& write = GetHead(nHardware::HEAD_WRITE);
   cHeadProgramid& read = GetHead(nHardware::HEAD_READ);
   read.Adjust(); // Strange things can happen (like we're reading from a programid that was being written).
@@ -3478,7 +3522,6 @@
   }
   
   // Allocate space for one additional instruction if the write head is at the end
-  // Otherwise the write head will improperly 
   if(write.GetMemory().GetSize() == write.GetPosition() + 1) {
     write.GetMemory().Resize(write.GetMemory().GetSize() + 1);
   }
@@ -3499,6 +3542,20 @@
     write++;
   }
   
+  // "Jump" Mutations
+  
+  if ( ctx.GetRandom().P(0.0000) )
+  {
+    // Set the read head to a random position
+    int new_read_pos = ctx.GetRandom().GetInt(read.GetMemory().GetSize());
+    read.Set(new_read_pos, read.GetMemSpace());
+  
+    // Reset any start/end labels that we might have been copying.
+    m_current->m_copying_site = false;
+    m_current->m_copying_label.Clear();
+  }
+  
+  
   // Peek at the next inst to see if it is a NOP
   // If it isn't, then we can compare the label and possibly fall off  
   if(m_current->m_copying_site) {
@@ -3524,7 +3581,12 @@
       return true;
     }
   }
-   
+  
+  // Check our processivity - read and write heads fall off with some probability
+  // What kind of programid are we writing?
+  double terminate_p =  1 - ((m_programids[read.GetMemSpace()]->GetReadable()) ? READABLE_COPY_PROCESSIVITY : EXECUTABLE_COPY_PROCESSIVITY);
+  if ( ctx.GetRandom().P(terminate_p) ) m_reset_heads = true;
+  
   return true;
 }
 
@@ -3535,6 +3597,9 @@
 */
 bool cHardwareGX::Inst_ProgramidDivide(cAvidaContext& ctx)
 {
+  // Even if unsuccessful, we reset task inputs
+  m_reset_inputs = true;
+
   //This stuff is usually set by Divide_CheckViable, leaving it zero causes problems
   cPhenotype& phenotype = organism->GetPhenotype();
   organism->GetPhenotype().SetLinesExecuted(1);
@@ -3615,7 +3680,7 @@
   bool daughter_has_executable = false;
   bool daughter_has_bindable = false;
   
-  // Calculate these conditions.
+  // Calculate these conditions for offspring.
   for(programid_list::iterator i=offspring.begin(); i!=offspring.end(); ++i) {
     ++num_daughter_programids;
     if((*i)->GetReadable()) {
@@ -3626,6 +3691,22 @@
   }
   assert(daughter_has_bindable); // We know this should be there...
   
+  int num_mother_programids = 0;
+  int mother_genome_length = 0;
+  bool mother_has_executable = false;
+  bool mother_has_bindable = false;
+  
+  // Calculate these conditions for parent.
+  for(programid_list::iterator i=parent.begin(); i!=parent.end(); ++i) {
+    ++num_mother_programids;
+    if((*i)->GetReadable()) {
+      mother_genome_length += (*i)->GetMemory().GetSize();
+    }
+    mother_has_executable = mother_has_executable || (*i)->GetExecutable();
+    mother_has_bindable = mother_has_bindable || (*i)->GetBindable();
+  }
+  assert(mother_has_bindable); // We know this should be there...
+  
   // And check them.  Note that if this check fails, we have *not* modified the
   // state of the calling programid.
   if((num_daughter_programids == 0) 
@@ -3634,6 +3715,12 @@
     // \todo link to original genome length
     return false;
   }
+  if((num_mother_programids == 0) 
+     || (!mother_has_executable) 
+     || (mother_genome_length < 50)) { 
+    // \todo link to original genome length
+    return false;
+  }
   
   // Ok, we're good to go.  We have to create the offspring's genome and delete the
   // offspring's programids from m_programids.
@@ -3668,7 +3755,20 @@
   return true;
 }
 
+bool cHardwareGX::Inst_ProgramidGet(cAvidaContext& ctx)
+{
+  m_reset_heads = true;
+  return Inst_TaskGet(ctx);
+}
 
+bool cHardwareGX::Inst_ProgramidPut(cAvidaContext& ctx)
+{
+  m_reset_inputs = true;
+  m_reset_heads = true;
+  return Inst_TaskPut(ctx);
+}
+
+
 //! Adds a new programid to the current cHardwareGX.
 void cHardwareGX::AddProgramid(programid_ptr programid) 
 { 

Modified: development/source/cpu/cHardwareGX.h
===================================================================
--- development/source/cpu/cHardwareGX.h	2007-05-26 21:56:18 UTC (rev 1617)
+++ development/source/cpu/cHardwareGX.h	2007-05-27 18:14:18 UTC (rev 1618)
@@ -68,7 +68,13 @@
 class cMutation;
 class cOrganism;
 
+/* The big TODO list
 
+1. Create a cGXOrganism class and remove all of the psudo-genome nonsense.
+   This will fix the artifact that programid ages get reset in the daughter.
+
+*/
+
 /*! Each organism may have a cHardwareGX structure that keeps track of the 
 * current status of simulated hardware.  This particular CPU architecture is
 * designed to explore the evolution of gene expression and also the effect
@@ -86,11 +92,14 @@
 
   //!< \todo JEB Make these config options
   static const unsigned int MAX_PROGRAMIDS = 32; //!< Number of cProgramids that an organism can allocate.
+  static const int MAX_PROGRAMID_TOTAL_LENGTH = 1000; // New programids cannot be created if above this cumulative length.
   static const int PROGRAMID_REPLACEMENT_METHOD = 0;
    //!< Controls what happens when we try to allocate a new cProgramid, but are up against the limit
   // 0 = Fail if no programids available
   // 1 = Replace the programid that has completed the most instructions
   static const int MAX_PROGRAMID_AGE = 2000; // Number of inst a cProgramid executes before ceasing to exist
+  static const double EXECUTABLE_COPY_PROCESSIVITY;
+  static const double READABLE_COPY_PROCESSIVITY;
 
   unsigned int m_last_unique_id_assigned; // Counter so programids can be assigned unique IDs for tracking
 
@@ -238,6 +247,8 @@
   bool m_advance_ip;         // Should the IP advance after this instruction?
   bool m_executedmatchstrings;	// Have we already executed the match strings instruction?
   bool m_just_divided; // Did we just divide (in which case end execution of programids until next cycle).
+  bool m_reset_inputs; // Flag to make it easy for instructions to reset all inputs (force task modularity).
+  bool m_reset_heads;  // Flas to make it easy for instructions to reset heads back (force task modularity).
 
   // Instruction costs...
 #if INSTRUCTION_COSTS
@@ -556,6 +567,8 @@
   bool Inst_NumSites(cAvidaContext& ctx); //!< Count the number of corresponding binding sites
   bool Inst_ProgramidCopy(cAvidaContext& ctx); //!< Like h-copy, but fails if read/write heads not on other programids and will not write over
   bool Inst_ProgramidDivide(cAvidaContext& ctx); //!< Like h-divide, 
+  bool Inst_ProgramidGet(cAvidaContext& ctx); //!< Like get with head resets.
+  bool Inst_ProgramidPut(cAvidaContext& ctx); //!< Like put with head and input resets.
   
   //!< Add/Remove a new programid to/from the list and give it the proper index within the list so we keep track of memory spaces...
   void AddProgramid(programid_ptr programid);




More information about the Avida-cvs mailing list