1 /*
2  *  cHardwareBase.cc
3  *  Avida
4  *
5  *  Called "hardware_base.cc" prior to 11/17/05.
6  *  Copyright 1999-2011 Michigan State University. All rights reserved.
7  *  Copyright 1999-2003 California Institute of Technology.
8  *
9  *
10  *  This file is part of Avida.
11  *
12  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
13  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
14  *
15  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
19  *  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "cHardwareBase.h"
24 
25 #include "avida/core/WorldDriver.h"
26 
27 #include "cAvidaContext.h"
28 #include "cCodeLabel.h"
29 #include "cCPUTestInfo.h"
30 #include "cEnvironment.h"
31 #include "cHardwareManager.h"
32 #include "cHardwareStatusPrinter.h"
33 #include "cHeadCPU.h"
34 #include "cInstSet.h"
35 #include "cOrganism.h"
36 #include "cPhenotype.h"
37 #include "cPopulation.h"
38 #include "cPopulationCell.h"
39 #include "cRandom.h"
40 #include "cStats.h"
41 #include "cTestCPU.h"
42 #include "cWorld.h"
43 #include "nHardware.h"
44 #include "tArrayUtils.h"
45 
46 using namespace Avida;
47 using namespace AvidaTools;
48 
49 
cHardwareBase(cWorld * world,cOrganism * in_organism,cInstSet * inst_set)50 cHardwareBase::cHardwareBase(cWorld* world, cOrganism* in_organism, cInstSet* inst_set)
51 : m_world(world), m_organism(in_organism), m_inst_set(inst_set), m_tracer(NULL), m_minitracer(NULL), m_minitrace_file(null_str)
52 , m_microtrace(false), m_topnavtrace(false)
53 , m_has_costs(inst_set->HasCosts()), m_has_ft_costs(inst_set->HasFTCosts()) , m_has_energy_costs(m_inst_set->HasEnergyCosts())
54 , m_has_res_costs(m_inst_set->HasResCosts()), m_has_fem_res_costs(m_inst_set->HasFemResCosts())
55 , m_has_female_costs(m_inst_set->HasFemaleCosts()), m_has_choosy_female_costs(m_inst_set->HasChoosyFemaleCosts())
56 , m_has_post_costs(inst_set->HasPostCosts())
57 {
58 	m_task_switching_cost=0;
59 	int switch_cost =  world->GetConfig().TASK_SWITCH_PENALTY.Get();
60 	m_has_any_costs = (m_has_costs | m_has_ft_costs | m_has_energy_costs | m_has_res_costs | m_has_fem_res_costs | switch_cost | m_has_female_costs |
61                      m_has_choosy_female_costs | m_has_post_costs);
62   m_implicit_repro_active = (m_world->GetConfig().IMPLICIT_REPRO_TIME.Get() ||
63                              m_world->GetConfig().IMPLICIT_REPRO_CPU_CYCLES.Get() ||
64                              m_world->GetConfig().IMPLICIT_REPRO_BONUS.Get() ||
65                              m_world->GetConfig().IMPLICIT_REPRO_END.Get() ||
66                              m_world->GetConfig().IMPLICIT_REPRO_ENERGY.Get());
67 
68   assert(m_organism != NULL);
69 }
70 
71 
Reset(cAvidaContext & ctx)72 void cHardwareBase::Reset(cAvidaContext& ctx)
73 {
74   m_organism->HardwareReset(ctx);
75   m_microtracer.Resize(0);
76   m_navtraceloc.Resize(0);
77   m_navtracefacing.Resize(0);
78   m_navtraceupdate.Resize(0);
79   m_inst_cost = 0;
80   m_active_thread_costs.Resize(m_world->GetConfig().MAX_CPU_THREADS.Get());
81   m_active_thread_costs.SetAll(0);
82   m_active_thread_post_costs.Resize(m_world->GetConfig().MAX_CPU_THREADS.Get());
83   m_active_thread_post_costs.SetAll(0);
84   m_female_cost = 0;
85 
86   const int num_inst_cost = m_inst_set->GetSize();
87 
88   if (m_has_ft_costs) {
89     m_inst_ft_cost.Resize(num_inst_cost);
90     for (int i = 0; i < num_inst_cost; i++) m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
91   }
92 
93   if (m_has_energy_costs) {
94     m_inst_energy_cost.Resize(num_inst_cost);
95     for (int i = 0; i < num_inst_cost; i++) m_inst_energy_cost[i] = m_inst_set->GetEnergyCost(cInstruction(i));
96   }
97 
98   if (m_has_res_costs) {
99     m_inst_res_cost.Resize(num_inst_cost);
100     for (int i = 0; i < num_inst_cost; i++) m_inst_res_cost[i] = m_inst_set->GetResCost(cInstruction(i));
101   }
102 
103   if (m_has_fem_res_costs) {
104     m_inst_fem_res_cost.Resize(num_inst_cost);
105     for (int i = 0; i < num_inst_cost; i++) m_inst_fem_res_cost[i] = m_inst_set->GetFemResCost(cInstruction(i));
106   }
107 
108   if (m_has_costs) {
109     m_thread_inst_cost.Resize(num_inst_cost);
110     for (int i = 0; i < num_inst_cost; i++) m_thread_inst_cost[i] = m_inst_set->GetCost(cInstruction(i));
111   }
112 
113   if (m_has_post_costs) {
114     m_thread_inst_post_cost.Resize(num_inst_cost);
115     for (int i = 0; i < num_inst_cost; i++) m_thread_inst_post_cost[i] = m_inst_set->GetPostCost(cInstruction(i));
116   }
117 
118   internalReset();
119 }
120 
calcExecutedSize(const int parent_size)121 int cHardwareBase::calcExecutedSize(const int parent_size)
122 {
123   int executed_size = 0;
124   const cCPUMemory& memory = GetMemory();
125   for (int i = 0; i < parent_size; i++) {
126     if (memory.FlagExecuted(i)) executed_size++;
127   }
128   return executed_size;
129 }
130 
Divide_CheckViable(cAvidaContext & ctx,const int parent_size,const int child_size,bool using_repro)131 bool cHardwareBase::Divide_CheckViable(cAvidaContext& ctx, const int parent_size, const int child_size, bool using_repro)
132 {
133 #define ORG_FAULT(error) if (ctx.OrgFaultReporting()) m_organism->Fault(FAULT_LOC_DIVIDE, FAULT_TYPE_ERROR, error)
134 
135   // Make sure the organism is okay with dividing now...
136   // Moved to end of function @LZ
137 
138   const int juv_age = m_world->GetConfig().JUV_PERIOD.Get();
139   const int parent_age = m_organism->GetPhenotype().GetTimeUsed();
140   if (parent_age < juv_age) {
141     ORG_FAULT(cStringUtil::Stringf("Org is juvenile (%d < %d)", parent_age, juv_age));
142     return false;
143   }
144 
145   const int min_age = m_world->GetConfig().MIN_CYCLES.Get();
146   if (parent_age < min_age) {
147     ORG_FAULT(cStringUtil::Stringf("Org too young (%d < %d)", parent_age, min_age));
148     return false;
149   }
150 
151   // Make sure that neither parent nor child will be below the minimum size.
152   const int genome_size = m_organism->GetGenome().GetSize();
153   const double size_range = m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get();
154   const int min_size = Max(MIN_GENOME_LENGTH, static_cast<int>(genome_size / size_range));
155   const int max_size = Min(MAX_GENOME_LENGTH, static_cast<int>(genome_size * size_range));
156 
157   if (child_size < min_size || child_size > max_size) {
158     ORG_FAULT(cStringUtil::Stringf("Invalid offspring length (%d)", child_size));
159     return false; // (divide fails)
160   }
161   if (parent_size < min_size || parent_size > max_size) {
162     ORG_FAULT(cStringUtil::Stringf("Invalid post-divide length (%d)",parent_size));
163     return false; // (divide fails)
164   }
165 
166   // Absolute minimum and maximum child/parent size limits -- @JEB
167   const int max_genome_size = m_world->GetConfig().MAX_GENOME_SIZE.Get();
168   const int min_genome_size = m_world->GetConfig().MIN_GENOME_SIZE.Get();
169   if ( (min_genome_size && (child_size < min_genome_size)) || (max_genome_size && (child_size > max_genome_size)) ) {
170     ORG_FAULT(cStringUtil::Stringf("Invalid absolute offspring length (%d)",child_size));
171     return false; // (divide fails)
172   }
173 
174   if ( (min_genome_size && (parent_size < min_genome_size)) || (max_genome_size && (parent_size > max_genome_size)) ) {
175     ORG_FAULT(cStringUtil::Stringf("Invalid absolute post-divide length (%d)",parent_size));
176     return false; // (divide fails)
177   }
178 
179   // Count the number of lines executed in the parent, and make sure the
180   // specified fraction has been reached.
181 
182   const int executed_size = calcExecutedSize(parent_size);
183   const int min_exe_lines = static_cast<int>(parent_size * m_world->GetConfig().MIN_EXE_LINES.Get());
184   if (executed_size < min_exe_lines) {
185     ORG_FAULT(cStringUtil::Stringf("Too few executed lines (%d < %d)", executed_size, min_exe_lines));
186     return false; // (divide fails)
187   }
188 
189   // Repro organisms mark their entire genomes as copied
190   int copied_size = parent_size;
191   if (!using_repro) {
192     // Normal organisms check to see how much was copied
193     copied_size = calcCopiedSize(parent_size, child_size); // Fails for REPRO organisms
194     const int min_copied = static_cast<int>(child_size * m_world->GetConfig().MIN_COPIED_LINES.Get());
195 
196     if (copied_size < min_copied) {
197       ORG_FAULT(cStringUtil::Stringf("Too few copied commands (%d < %d)", copied_size, min_copied));
198       return false; // (divide fails)
199     }
200   }
201 
202   if (m_world->GetConfig().USE_FORM_GROUPS.Get()) {
203     if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) {
204       if (m_world->GetConfig().DEFAULT_GROUP.Get() != -1) {
205         m_organism->GetOrgInterface().SetOpinion(m_world->GetConfig().DEFAULT_GROUP.Get(), m_organism);
206       } else {
207         // No default group, so divide fails (group opinion is required by cPopulation::ActivateOffspring)
208         return false;
209       }
210     }
211   }
212 
213   if (m_organism->Divide_CheckViable(ctx) == false)
214   {
215     if (m_world->GetConfig().DIVIDE_FAILURE_RESETS.Get())
216     {
217       internalResetOnFailedDivide();
218     }
219     return false; // (divide fails)
220   }
221 
222 
223   // Save the information we collected here...
224   cPhenotype& phenotype = m_organism->GetPhenotype();
225   phenotype.SetLinesExecuted(executed_size);
226   phenotype.SetLinesCopied(copied_size);
227 
228   // Determine the fitness of this organism as compared to its parent...
229   if (m_world->GetTestSterilize() && !phenotype.IsInjected()) {
230     const int merit_base = phenotype.CalcSizeMerit();
231     const double cur_fitness = merit_base * phenotype.GetCurBonus() / phenotype.GetTimeUsed();
232     const double fitness_ratio = cur_fitness / phenotype.GetLastFitness();
233     const tArray<int>& childtasks = phenotype.GetCurTaskCount();
234     const tArray<int>& parenttasks = phenotype.GetLastTaskCount();
235 
236     bool sterilize = false;
237 
238     if (fitness_ratio < nHardware::FITNESS_NEUTRAL_MIN) {
239       if (ctx.GetRandom().P(m_organism->GetSterilizeNeg())) sterilize = true;
240     } else if (fitness_ratio <= nHardware::FITNESS_NEUTRAL_MAX) {
241       if (ctx.GetRandom().P(m_organism->GetSterilizeNeut())) sterilize = true;
242     } else {
243       if (ctx.GetRandom().P(m_organism->GetSterilizePos())) sterilize = true;
244     }
245 
246     // for sterilize task loss *SLG
247     if (ctx.GetRandom().P(m_organism->GetSterilizeTaskLoss()))
248     {
249       bool del = false;
250       bool added = false;
251       for (int i=0; i<childtasks.GetSize(); i++)
252       {
253         if (childtasks[i] > parenttasks[i]) {
254           added = true;
255           break;
256         }
257         else if (childtasks[i] < parenttasks[i])
258           del = true;
259       }
260       sterilize = (del & !added);
261     }
262 
263     if (sterilize) {
264       // Don't let this organism have this or any more children!
265       phenotype.IsFertile() = false;
266       return false;
267     }
268   }
269 
270   return true; // (divide succeeds!)
271 #undef ORG_FAULT
272 }
273 
274 
275 /*
276  Return the number of mutations that occur on divide.  AWC 06/29/06
277  Limit the number of mutations that occur to be less than or equal to maxmut (defaults to INT_MAX)
278  */
Divide_DoMutations(cAvidaContext & ctx,double mut_multiplier,const int maxmut)279 int cHardwareBase::Divide_DoMutations(cAvidaContext& ctx, double mut_multiplier, const int maxmut)
280 {
281   int max_genome_size = m_world->GetConfig().MAX_GENOME_SIZE.Get();
282   int min_genome_size = m_world->GetConfig().MIN_GENOME_SIZE.Get();
283   if (!max_genome_size || max_genome_size > MAX_GENOME_LENGTH) max_genome_size = MAX_GENOME_LENGTH;
284   if (!min_genome_size || min_genome_size < MIN_GENOME_LENGTH) min_genome_size = MIN_GENOME_LENGTH;
285 
286   int totalMutations = 0;
287   Sequence& offspring_genome = m_organism->OffspringGenome().GetSequence();
288 
289   m_organism->GetPhenotype().SetDivType(mut_multiplier);
290 
291   // All slip, translocation, and LGT mutations should happen first, so that there is a chance
292   // of getting a point mutation within one copy in the same divide.
293 
294   // Divide Slip Mutations - NOT COUNTED.
295   if (m_organism->TestDivideSlip(ctx)) doSlipMutation(ctx, offspring_genome);
296 
297   // Poisson Slip Mutations - NOT COUNTED
298   unsigned int num_poisson_slip = m_organism->NumDividePoissonSlip(ctx);
299   for (unsigned int i = 0; i < num_poisson_slip; i++) { doSlipMutation(ctx, offspring_genome);  }
300 
301   // Slip Mutations (per site) - NOT COUNTED
302   if (m_organism->GetDivSlipProb() > 0) {
303     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(),
304                                                   m_organism->GetDivSlipProb() / mut_multiplier);
305     for (int i = 0; i < num_mut; i++) doSlipMutation(ctx, offspring_genome);
306   }
307 
308 
309   // Divide Translocation Mutations - NOT COUNTED.
310   if (m_organism->TestDivideTrans(ctx)) doTransMutation(ctx, offspring_genome);
311 
312   // Poisson Translocation Mutations - NOT COUNTED
313   unsigned int num_poisson_trans = m_organism->NumDividePoissonTrans(ctx);
314   for (unsigned int i = 0; i < num_poisson_trans; i++) { doTransMutation(ctx, offspring_genome);  }
315 
316   // Translocation Mutations (per site) - NOT COUNTED
317   if (m_organism->GetDivTransProb() > 0) {
318     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(),
319                                                   m_organism->GetDivTransProb() / mut_multiplier);
320     for (int i = 0; i < num_mut; i++) doTransMutation(ctx, offspring_genome);
321   }
322 
323 
324   // Divide Lateral Gene Transfer Mutations - NOT COUNTED.
325   if (m_organism->TestDivideLGT(ctx)) doLGTMutation(ctx, offspring_genome);
326 
327   // Poisson Lateral Gene Transfer Mutations - NOT COUNTED
328   unsigned int num_poisson_lgt = m_organism->NumDividePoissonLGT(ctx);
329   for (unsigned int i = 0; i < num_poisson_lgt; i++) { doLGTMutation(ctx, offspring_genome);  }
330 
331   // Lateral Gene Transfer Mutations (per site) - NOT COUNTED
332   if (m_organism->GetDivLGTProb() > 0) {
333     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(),
334                                                   m_organism->GetDivLGTProb() / mut_multiplier);
335     for (int i = 0; i < num_mut; i++) doLGTMutation(ctx, offspring_genome);
336   }
337 
338 
339   // HGT Mutations - NOT COUNTED
340 	// HGT is a location-dependent random process; each type is tested over in
341 	// cPopulationInterface.
342 	if(m_world->GetConfig().ENABLE_HGT.Get()) {
343 		m_organism->GetOrgInterface().DoHGTMutation(ctx, m_organism->OffspringGenome());
344 	}
345 
346 
347   // Divide Mutations
348   if (m_organism->TestDivideMut(ctx) && totalMutations < maxmut) {
349     const unsigned int mut_line = ctx.GetRandom().GetUInt(offspring_genome.GetSize());
350     char before_mutation = offspring_genome[mut_line].GetSymbol();
351     offspring_genome[mut_line] = m_inst_set->GetRandomInst(ctx);
352     offspring_genome.GetMutationSteps().AddSubstitutionMutation(mut_line, before_mutation, offspring_genome[mut_line].GetSymbol());
353     totalMutations++;
354   }
355 
356 
357   // Poisson Divide Mutations
358   unsigned int num_poisson_mut = m_organism->NumDividePoissonMut(ctx);
359   for (unsigned int i=0; i<num_poisson_mut; i++)
360   {
361     if (totalMutations >= maxmut) break;
362     const unsigned int mut_line = ctx.GetRandom().GetUInt(offspring_genome.GetSize());
363     char before_mutation = offspring_genome[mut_line].GetSymbol();
364     offspring_genome[mut_line] = m_inst_set->GetRandomInst(ctx);
365     offspring_genome.GetMutationSteps().AddSubstitutionMutation(mut_line, before_mutation, offspring_genome[mut_line].GetSymbol());
366     totalMutations++;
367   }
368 
369 
370   // Divide Insertions
371   if (m_organism->TestDivideIns(ctx) && offspring_genome.GetSize() < max_genome_size && totalMutations < maxmut) {
372     const unsigned int mut_line = ctx.GetRandom().GetUInt(offspring_genome.GetSize() + 1);
373     offspring_genome.Insert(mut_line, m_inst_set->GetRandomInst(ctx));
374     offspring_genome.GetMutationSteps().AddInsertionMutation(mut_line, offspring_genome[mut_line].GetSymbol());
375     totalMutations++;
376   }
377 
378 
379   // Poisson Divide Insertions
380   unsigned int num_poisson_ins = m_organism->NumDividePoissonIns(ctx);
381   for (unsigned int i=0; i<num_poisson_ins; i++)
382   {
383     if (offspring_genome.GetSize() >= max_genome_size) break;
384     if (totalMutations >= maxmut) break;
385     const unsigned int mut_line = ctx.GetRandom().GetUInt(offspring_genome.GetSize() + 1);
386     offspring_genome.Insert(mut_line, m_inst_set->GetRandomInst(ctx));
387     offspring_genome.GetMutationSteps().AddInsertionMutation(mut_line, offspring_genome[mut_line].GetSymbol());
388     totalMutations++;
389   }
390 
391 
392   // Divide Deletions
393   if (m_organism->TestDivideDel(ctx) && offspring_genome.GetSize() > min_genome_size && totalMutations < maxmut) {
394     const unsigned int mut_line = ctx.GetRandom().GetUInt(offspring_genome.GetSize());
395     offspring_genome.GetMutationSteps().AddDeletionMutation(mut_line, offspring_genome[mut_line].GetSymbol());
396     offspring_genome.Remove(mut_line);
397     totalMutations++;
398   }
399 
400 
401   // Poisson Divide Deletions
402   unsigned int num_poisson_del = m_organism->NumDividePoissonDel(ctx);
403   for (unsigned int i=0; i<num_poisson_del; i++)
404   {
405     if (offspring_genome.GetSize() <= min_genome_size) break;
406     if (totalMutations >= maxmut) break;
407     const unsigned int mut_line = ctx.GetRandom().GetUInt(offspring_genome.GetSize());
408     offspring_genome.GetMutationSteps().AddDeletionMutation(mut_line, offspring_genome[mut_line].GetSymbol());
409     offspring_genome.Remove(mut_line);
410     totalMutations++;
411   }
412 
413 
414   // Divide Uniform Mutations
415   if (m_organism->TestDivideUniform(ctx) && totalMutations < maxmut) {
416     if (doUniformMutation(ctx, offspring_genome)) totalMutations++;
417   }
418 
419 
420   // Divide Mutations (per site)
421   if (m_organism->GetDivMutProb() > 0 && totalMutations < maxmut) {
422     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(),
423                                                   m_organism->GetDivMutProb() / mut_multiplier);
424     // If we have lines to mutate...
425     if (num_mut > 0 && totalMutations < maxmut) {
426       for (int i = 0; i < num_mut && totalMutations < maxmut; i++) {
427         int site = ctx.GetRandom().GetUInt(offspring_genome.GetSize());
428         char before_mutation = offspring_genome[site].GetSymbol();
429         offspring_genome[site] = m_inst_set->GetRandomInst(ctx);
430         offspring_genome.GetMutationSteps().AddSubstitutionMutation(site, before_mutation, offspring_genome[site].GetSymbol());
431         totalMutations++;
432       }
433     }
434   }
435 
436   // Insert Mutations (per site)
437   if (m_organism->GetDivInsProb() > 0 && totalMutations < maxmut) {
438     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(), m_organism->GetDivInsProb());
439 
440     // If would make creature too big, insert up to max_genome_size
441     if (num_mut + offspring_genome.GetSize() > max_genome_size) {
442       num_mut = max_genome_size - offspring_genome.GetSize();
443     }
444 
445     // If we have lines to insert...
446     if (num_mut > 0) {
447       // Build a sorted list of the sites where mutations occured
448       tArray<int> mut_sites(num_mut);
449       for (int i = 0; i < num_mut; i++) mut_sites[i] = ctx.GetRandom().GetUInt(offspring_genome.GetSize() + 1);
450       tArrayUtils::QSort(mut_sites);
451 
452       // Actually do the mutations (in reverse sort order)
453       for (int i = mut_sites.GetSize() - 1; i >= 0; i--) {
454         offspring_genome.Insert(mut_sites[i], m_inst_set->GetRandomInst(ctx));
455         offspring_genome.GetMutationSteps().AddInsertionMutation(mut_sites[i], offspring_genome[mut_sites[i]].GetSymbol());
456       }
457 
458       totalMutations += num_mut;
459     }
460   }
461 
462 
463   // Delete Mutations (per site)
464   if (m_organism->GetDivDelProb() > 0 && totalMutations < maxmut) {
465     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(), m_organism->GetDivDelProb());
466 
467     // If would make creature too small, delete down to min_genome_size
468     if (offspring_genome.GetSize() - num_mut < min_genome_size) {
469       num_mut = offspring_genome.GetSize() - min_genome_size;
470     }
471 
472     // If we have lines to delete...
473     for (int i = 0; i < num_mut; i++) {
474       int site = ctx.GetRandom().GetUInt(offspring_genome.GetSize());
475       offspring_genome.GetMutationSteps().AddDeletionMutation(site, offspring_genome[site].GetSymbol());
476       offspring_genome.Remove(site);
477     }
478 
479     totalMutations += num_mut;
480   }
481 
482 
483 
484   // Uniform Mutations (per site)
485   if (m_organism->GetDivUniformProb() > 0 && totalMutations < maxmut) {
486     int num_mut = ctx.GetRandom().GetRandBinomial(offspring_genome.GetSize(),
487                                                   m_organism->GetDivUniformProb() / mut_multiplier);
488 
489     // If we have lines to mutate...
490     if (num_mut > 0 && totalMutations < maxmut) {
491       for (int i = 0; i < num_mut && totalMutations < maxmut; i++) {
492         if (doUniformMutation(ctx, offspring_genome)) totalMutations++;
493       }
494     }
495   }
496 
497 
498   cCPUMemory& memory = GetMemory();
499 
500   // Parent Substitution Mutations (per site)
501   if (m_organism->GetParentMutProb() > 0.0 && totalMutations < maxmut) {
502     int num_mut = ctx.GetRandom().GetRandBinomial(memory.GetSize(), m_organism->GetParentMutProb());
503 
504     // If we have lines to mutate...
505     if (num_mut > 0) {
506       for (int i = 0; i < num_mut && totalMutations < maxmut; i++) {
507         int site = ctx.GetRandom().GetUInt(memory.GetSize());
508         char before_mutation = memory[site].GetSymbol();
509         memory[site] = m_inst_set->GetRandomInst(ctx);
510         memory.GetMutationSteps().AddSubstitutionMutation(site, before_mutation, memory[site].GetSymbol());
511         totalMutations++;
512       }
513     }
514   }
515 
516   // Parent Insert Mutations (per site)
517   if (m_organism->GetParentInsProb() > 0.0 && totalMutations < maxmut) {
518     int num_mut = ctx.GetRandom().GetRandBinomial(memory.GetSize(), m_organism->GetParentInsProb());
519 
520     // If would make creature too big, insert up to max_genome_size
521     if (num_mut + memory.GetSize() > max_genome_size) {
522       num_mut = max_genome_size - memory.GetSize();
523     }
524 
525     // If we have lines to insert...
526     if (num_mut > 0) {
527       // Build a sorted list of the sites where mutations occured
528       tArray<int> mut_sites(num_mut);
529       for (int i = 0; i < num_mut; i++) mut_sites[i] = ctx.GetRandom().GetUInt(memory.GetSize() + 1);
530       tArrayUtils::QSort(mut_sites);
531 
532       // Actually do the mutations (in reverse sort order)
533       for (int i = mut_sites.GetSize() - 1; i >= 0; i--) {
534         memory.Insert(mut_sites[i], m_inst_set->GetRandomInst(ctx));
535         memory.GetMutationSteps().AddInsertionMutation(mut_sites[i], memory[mut_sites[i]].GetSymbol());
536       }
537 
538       totalMutations += num_mut;
539     }
540   }
541 
542 
543   // Parent Deletion Mutations (per site)
544   if (m_organism->GetParentDelProb() > 0 && totalMutations < maxmut) {
545     int num_mut = ctx.GetRandom().GetRandBinomial(memory.GetSize(), m_organism->GetParentDelProb());
546 
547     // If would make creature too small, delete down to min_genome_size
548     if (memory.GetSize() - num_mut < min_genome_size) {
549       num_mut = memory.GetSize() - min_genome_size;
550     }
551 
552     // If we have lines to delete...
553     for (int i = 0; i < num_mut; i++) {
554       int site = ctx.GetRandom().GetUInt(memory.GetSize());
555       memory.GetMutationSteps().AddDeletionMutation(site, memory[site].GetSymbol());
556       memory.Remove(site);
557     }
558 
559     totalMutations += num_mut;
560   }
561 
562 
563   return totalMutations;
564 }
565 
566 
doUniformMutation(cAvidaContext & ctx,Sequence & genome)567 bool cHardwareBase::doUniformMutation(cAvidaContext& ctx, Sequence& genome)
568 {
569 
570   int mut = ctx.GetRandom().GetUInt((m_inst_set->GetSize() * 2) + 1);
571 
572   if (mut < m_inst_set->GetSize()) { // point
573     int site = ctx.GetRandom().GetUInt(genome.GetSize());
574     genome[site] = cInstruction(mut);
575   } else if (mut == m_inst_set->GetSize()) { // delete
576     int min_genome_size = m_world->GetConfig().MIN_GENOME_SIZE.Get();
577     if (!min_genome_size || min_genome_size < MIN_GENOME_LENGTH) min_genome_size = MIN_GENOME_LENGTH;
578     if (genome.GetSize() == min_genome_size) return false;
579     int site = ctx.GetRandom().GetUInt(genome.GetSize());
580     genome.Remove(site);
581   } else { // insert
582     int max_genome_size = m_world->GetConfig().MAX_GENOME_SIZE.Get();
583     if (!max_genome_size || max_genome_size > MAX_GENOME_LENGTH) max_genome_size = MAX_GENOME_LENGTH;
584     if (genome.GetSize() == max_genome_size) return false;
585     int site = ctx.GetRandom().GetUInt(genome.GetSize() + 1);
586     genome.Insert(site, cInstruction(mut - m_inst_set->GetSize() - 1));
587   }
588 
589   return true;
590 }
591 
doUniformCopyMutation(cAvidaContext & ctx,cHeadCPU & head)592 void cHardwareBase::doUniformCopyMutation(cAvidaContext& ctx, cHeadCPU& head)
593 {
594   int mut = ctx.GetRandom().GetUInt((m_inst_set->GetSize() * 2) + 1);
595   //Anya added code for Head to Head kazi experiment
596   bool in_List = false;
597   char test_inst = head.GetInst().GetSymbol();
598   cString no_mut_list = m_world->GetConfig().NO_MUT_INSTS.Get();
599   for(int i=0; i<(int)strlen(no_mut_list); i++) {
600     if ((char) no_mut_list[i] == test_inst) in_List = true;
601   }
602   if (!in_List) {
603     if (mut < m_inst_set->GetSize()) head.SetInst(cInstruction(mut));
604     else if (mut == m_inst_set->GetSize()) head.RemoveInst();
605     else head.InsertInst(cInstruction(mut - m_inst_set->GetSize() - 1));
606   }
607 
608 }
609 
610 
611 
612 // Slip Mutations
613 // As if the read head jumped from one random position of the offspring
614 // to another random position and continued reading to the end.
615 // This can cause large deletions or tandem duplications.
616 // Unlucky organisms might exceed the allowed length (randomly) if these mutations occur.
doSlipMutation(cAvidaContext & ctx,Sequence & genome,int from)617 void cHardwareBase::doSlipMutation(cAvidaContext& ctx, Sequence& genome, int from)
618 {
619   Sequence genome_copy = Sequence(genome);
620 
621   // All combinations except beginning to past end allowed
622   if (from < 0) from = ctx.GetRandom().GetInt(genome_copy.GetSize() + 1);
623   int to = (from == 0) ? ctx.GetRandom().GetInt(genome_copy.GetSize()) : ctx.GetRandom().GetInt(genome_copy.GetSize() + 1);
624 
625   // Resize child genome
626   int insertion_length = (from - to);
627   genome.Resize(genome.GetSize() + insertion_length);
628 
629   // Fill insertion
630   if (insertion_length > 0) {
631     tArray<bool> copied_so_far(insertion_length);
632     copied_so_far.SetAll(false);
633     for (int i = 0; i < insertion_length; i++) {
634       switch (m_world->GetConfig().SLIP_FILL_MODE.Get()) {
635           //Duplication
636         case 0:
637           genome[from + i] = genome_copy[to + i];
638           break;
639 
640           //Empty (nop-X)
641         case 1:
642           genome[from + i] = m_inst_set->GetInst("nop-X");
643           break;
644 
645           //Random
646         case 2:
647           genome[from + i] = m_inst_set->GetRandomInst(ctx);
648           break;
649 
650           //Scrambled order
651         case 3:
652         {
653           int copy_index = m_world->GetRandom().GetInt(insertion_length - i);
654           int test = 0;
655           int passed = copy_index;
656           while (passed >= 0) {
657             if (copied_so_far[test]) {
658               copy_index++;
659             } else { //this one hasn't been chosen, so we count it.
660               passed--;
661             }
662             test++;
663           }
664           genome[from + i] = genome[to + copy_index];
665           copied_so_far[copy_index] = true;
666         }
667           break;
668 
669           //Empty (nop-C)
670         case 4:
671           genome[from + i] = m_inst_set->GetInst("nop-C");
672           break;
673 
674         default:
675           m_world->GetDriver().RaiseException("Unknown SLIP_FILL_MODE\n");
676       }
677     }
678   }
679 
680   // Deletion / remaining genome
681   if (insertion_length < 0) insertion_length = 0;
682   for (int i = insertion_length; i < genome_copy.GetSize() - to; i++) genome[from + i] = genome_copy[to + i];
683   genome.GetMutationSteps().AddSlipMutation(from, to);
684 
685   if (m_world->GetVerbosity() >= VERBOSE_DETAILS) {
686     cout << "SLIP MUTATION from " << from << " to " << to << endl;
687     cout << "Parent: " << genome_copy.AsString()   << endl;
688     cout << "Offspring: " << genome.AsString() << endl;
689   }
690 }
691 
692 
693 
694 // Translocation Mutations
695 // Similar to slip mutations, described above.  However, insertion location is also chosen randomly.
doTransMutation(cAvidaContext & ctx,Sequence & genome,int from)696 void cHardwareBase::doTransMutation(cAvidaContext& ctx, Sequence& genome, int from)
697 {
698   Sequence genome_copy(genome);
699 
700   // All combinations except beginning to past end allowed
701   if (from < 0) from = ctx.GetRandom().GetInt(genome_copy.GetSize() + 1);
702   int to = (from == 0) ? ctx.GetRandom().GetInt(genome_copy.GetSize()) : ctx.GetRandom().GetInt(genome_copy.GetSize() + 1);
703 
704   // Resize child genome
705   int insertion_length = (from - to);
706   genome.Resize(genome.GetSize() + insertion_length);
707 
708   // Select insertion location
709   int ins_loc = ctx.GetRandom().GetInt(genome_copy.GetSize() + 1);
710 
711   // Fill insertion
712   if (insertion_length > 0) {
713     switch (m_world->GetConfig().TRANS_FILL_MODE.Get()) {
714         //Duplication
715       case 0:
716         for (int i = 0; i < insertion_length; i++) genome[ins_loc + i] = genome_copy[to + i];
717         break;
718 
719         //Scrambled order
720       case 1:
721       {
722         tArray<bool> copied_so_far(insertion_length);
723         copied_so_far.SetAll(false);
724         for (int i = 0; i < insertion_length; i++) {
725           int copy_index = m_world->GetRandom().GetInt(insertion_length - i);
726           int test = 0;
727           int passed = copy_index;
728           while (passed >= 0) {
729             if (copied_so_far[test]) {
730               copy_index++;
731             } else { //this one hasn't been chosen, so we count it.
732               passed--;
733             }
734             test++;
735           }
736           genome[ins_loc + i] = genome[to + copy_index];
737           copied_so_far[copy_index] = true;
738         }
739       }
740         break;
741 
742       default:
743         m_world->GetDriver().RaiseException("Unknown TRANS_FILL_MODE\n");
744     }
745   }
746 
747   if (insertion_length < 0) {
748     // Deletion
749     for (int i = ins_loc; i < genome.GetSize(); i++) genome[i] = genome_copy[i - insertion_length];
750   } else {
751     // Copy remaining genome
752     for (int i = ins_loc; i < genome_copy.GetSize(); i++) genome[i + insertion_length] = genome_copy[i];
753   }
754 }
755 
756 
757 // Lateral Gene Transfer Mutations
758 // Similar to Translocation mutations, except that the source fragments come from other organism genomes
doLGTMutation(cAvidaContext & ctx,Sequence & genome)759 void cHardwareBase::doLGTMutation(cAvidaContext& ctx, Sequence& genome)
760 {
761 
762   // All combinations except beginning to past end allowed
763   int from = ctx.GetRandom().GetInt(genome.GetSize() + 1);
764   int to = (from == 0) ? ctx.GetRandom().GetInt(genome.GetSize()) : ctx.GetRandom().GetInt(genome.GetSize() + 1);
765 
766   // Resize child genome
767   int insertion_length = (from - to);
768 
769   if (insertion_length > 0) {
770     Sequence ins_seq;
771     if (m_organism->GetOrgInterface().GetLGTFragment(ctx, m_world->GetConfig().LGT_SOURCE_REGION.Get(), m_organism->GetGenome(), ins_seq)) {
772       Sequence genome_copy(genome);
773       genome.Resize(genome.GetSize() + ins_seq.GetSize());
774       int ins_loc = ctx.GetRandom().GetInt(genome_copy.GetSize() + 1);
775 
776       // Insert the transfered fragment
777       switch (m_world->GetConfig().LGT_FILL_MODE.Get()) {
778           // Duplication
779         case 0:
780           for (int i = 0; i < ins_seq.GetSize(); i++) genome[i + ins_loc] = ins_seq[i];
781           break;
782 
783           // Scrambled
784         case 1:
785         {
786           for (int i = 0; i < ins_seq.GetSize(); i++) {
787             int copy_index = m_world->GetRandom().GetInt(ins_seq.GetSize() - i);
788             genome[ins_loc + i] = ins_seq[copy_index];
789             ins_seq[copy_index] = ins_seq[ins_seq.GetSize() - i - 1];
790           }
791         }
792 
793         default:
794           m_world->GetDriver().RaiseException("Unknown LGT_FILL_MODE\n");
795       }
796 
797       // Copy over the rest of the sequence
798       for (int i = ins_loc; i < genome_copy.GetSize(); i++) genome[i + ins_seq.GetSize()] = genome_copy[i];
799     } else {
800       // Fragment selection failed, mutation fallback to translocation
801       doTransMutation(ctx, genome);
802     }
803   } else if (insertion_length < 0) {
804     // Deletion
805     Sequence genome_copy(genome);
806     genome.Resize(genome.GetSize() + insertion_length);
807     for (int i = 0; (to + i) < genome_copy.GetSize() - to; i++) genome[from + i] = genome_copy[to + i];
808   }
809 }
810 
811 
812 
813 
814 /*
815  Return the number of mutations that occur on divide.  AWC 06/29/06
816  Limit the number of mutations that occur to be less than or equat to maxmut (defaults to INT_MAX)
817  */
Divide_DoExactMutations(cAvidaContext & ctx,double mut_multiplier,const int pointmut)818 unsigned cHardwareBase::Divide_DoExactMutations(cAvidaContext& ctx, double mut_multiplier, const int pointmut)
819 {
820   int maxmut = pointmut;
821   int totalMutations = 0;
822   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
823 
824   m_organism->GetPhenotype().SetDivType(mut_multiplier);
825 
826   // Divide Mutations
827   if (totalMutations < maxmut) {
828     const unsigned int mut_line = ctx.GetRandom().GetUInt(child_genome.GetSize());
829     child_genome[mut_line] = m_inst_set->GetRandomInst(ctx);
830     totalMutations++;
831   }
832 
833   // Divide Mutations (per site)
834   if (m_organism->GetDivMutProb() > 0 && totalMutations < maxmut) {
835     int num_mut = pointmut;
836     // If we have lines to mutate...
837     if (num_mut > 0 && totalMutations < maxmut) {
838       for (int i = 0; i < num_mut && totalMutations < maxmut; i++) {
839         int site = ctx.GetRandom().GetUInt(child_genome.GetSize());
840         child_genome[site] = m_inst_set->GetRandomInst(ctx);
841         totalMutations++;
842         cerr << "Resampling here " << totalMutations << endl;
843       }
844     }
845   }
846 
847   return totalMutations;
848 }
849 
850 
851 // test whether the offspring creature contains an advantageous mutation.
852 /*
853  Return true iff only a reversion is performed -- returns false is sterilized regardless of whether or
854  not a reversion is performed.  AWC 06/29/06
855  */
Divide_TestFitnessMeasures(cAvidaContext & ctx)856 bool cHardwareBase::Divide_TestFitnessMeasures(cAvidaContext& ctx)
857 {
858   cPhenotype & phenotype = m_organism->GetPhenotype();
859   phenotype.CopyTrue() = ( m_organism->OffspringGenome() == m_organism->GetGenome() );
860   phenotype.ChildFertile() = true;
861 
862   // Only continue if we're supposed to do a fitness test on divide...
863   // This means you must add a check for your config option to cWorld::setup()
864   // -- search for "m_test_on_div".
865   if (m_organism->GetTestOnDivide() == false) return false;
866 
867   // If this was a perfect copy, then we don't need to worry about any other
868   // tests...  Theoretically, we need to worry about the parent changing,
869   // but as long as the child is always compared to the original genotype,
870   // this won't be an issue.
871   if (phenotype.CopyTrue() == true) return false;
872 
873   const double parent_fitness = m_organism->GetTestFitness(ctx);
874   const tArray<int>& parenttasks = phenotype.GetCurTaskCount();
875   const double neut_min = parent_fitness * (1.0 - m_organism->GetNeutralMin());
876   const double neut_max = parent_fitness * (1.0 + m_organism->GetNeutralMax());
877 
878   cTestCPU* testcpu = m_world->GetHardwareManager().CreateTestCPU(ctx);
879   cCPUTestInfo test_info;
880   test_info.UseRandomInputs();
881   testcpu->TestGenome(ctx, test_info, m_organism->OffspringGenome());
882   const double child_fitness = test_info.GetGenotypeFitness();
883   delete testcpu;
884 
885   bool revert = false;
886   bool sterilize = false;
887 
888   // If implicit mutations are turned off, make sure this won't spawn one.
889   if (m_organism->GetSterilizeUnstable() == true) {
890     if (test_info.GetMaxDepth() > 0) sterilize = true;
891   }
892 
893   if (child_fitness == 0.0) {
894     // Fatal mutation... test for reversion.
895     if (ctx.GetRandom().P(m_organism->GetRevertFatal())) revert = true;
896     if (ctx.GetRandom().P(m_organism->GetSterilizeFatal())) sterilize = true;
897   } else if (child_fitness < neut_min) {
898     if (ctx.GetRandom().P(m_organism->GetRevertNeg())) revert = true;
899     if (ctx.GetRandom().P(m_organism->GetSterilizeNeg())) sterilize = true;
900   } else if (child_fitness <= neut_max) {
901     if (ctx.GetRandom().P(m_organism->GetRevertNeut())) revert = true;
902     if (ctx.GetRandom().P(m_organism->GetSterilizeNeut())) sterilize = true;
903   } else {
904     if (ctx.GetRandom().P(m_organism->GetRevertPos())) revert = true;
905     if (ctx.GetRandom().P(m_organism->GetSterilizePos())) sterilize = true;
906   }
907 
908   // If task loss without gain is to be sterilized or reverted,
909   // check for it and act appropriately.
910   int RorS = 0;	// 0 = neither, 1 = revert, 2 = sterilize
911   if (ctx.GetRandom().P(m_organism->GetRevertTaskLoss()))
912     RorS = 1;
913   else if (ctx.GetRandom().P(m_organism->GetSterilizeTaskLoss()))
914     RorS = 2;
915   // check if child has lost any tasks parent had AND not gained any new tasks
916   if (RorS) {
917     const tArray<int>& childtasks = test_info.GetTestPhenotype().GetLastTaskCount();
918     bool del = false;
919     bool added = false;
920     for (int i=0; i<childtasks.GetSize(); i++)
921     {
922       if (childtasks[i] > parenttasks[i]) {
923         added = true;
924         break;
925       }
926       else if (childtasks[i] < parenttasks[i])
927         del = true;
928     }
929     if (RorS == 1)
930       revert = (del & !added);
931     else
932       sterilize = (del & !added);
933   }
934 
935   // If mutations granting EQU should be reverted, check for EQU
936   // and flag for reversion.
937   // The probabilistic check is placed under guard so as not to
938   // affect consistency by using a random number if the feature
939   // is not used.
940   if (m_organism->GetRevertEquals() != 0) {
941     if (ctx.GetRandom().P(m_organism->GetRevertEquals())) {
942       const tArray<int>& child_tasks = test_info.GetTestPhenotype().GetLastTaskCount();
943       if (child_tasks[child_tasks.GetSize() - 1] >= 1) {
944         revert = true;
945         m_world->GetStats().AddNewTaskCount(child_tasks.GetSize() - 1);
946       }
947     }
948   }
949 
950   // Ideally, we won't have reversions and sterilizations turned on at the
951   // same time, but if we do, give revert the priority.
952   if (revert == true) {
953     m_organism->OffspringGenome() = m_organism->GetGenome();
954   }
955 
956   if (sterilize == true) {
957     m_organism->GetPhenotype().ChildFertile() = false;
958   }
959 
960   return (!sterilize) && revert;
961 }
962 
963 // test whether the offspring creature contains an advantageous mutation.
964 /*
965  Return true iff only a reversion is performed -- returns false is sterilized regardless of whether or
966  not a reversion is performed.  AWC 06/29/06
967  */
Divide_TestFitnessMeasures1(cAvidaContext & ctx)968 bool cHardwareBase::Divide_TestFitnessMeasures1(cAvidaContext& ctx)
969 {
970   cPhenotype & phenotype = m_organism->GetPhenotype();
971   phenotype.CopyTrue() = (m_organism->OffspringGenome() == m_organism->GetGenome());
972   phenotype.ChildFertile() = true;
973 
974   // Only continue if we're supposed to do a fitness test on divide...
975   // This means you must add a check for your config option to cWorld::setup()
976   // -- search for "m_test_on_div".
977   if (m_organism->GetTestOnDivide() == false) return false;
978 
979   // If this was a perfect copy, then we don't need to worry about any other
980   // tests...  Theoretically, we need to worry about the parent changing,
981   // but as long as the child is always compared to the original genotype,
982   // this won't be an issue.
983   if (phenotype.CopyTrue() == true) return false;
984 
985   const double parent_fitness = m_organism->GetTestFitness(ctx);
986   const tArray<int>& parenttasks = phenotype.GetCurTaskCount();
987   const double neut_min = parent_fitness * (1.0 - m_organism->GetNeutralMin());
988   const double neut_max = parent_fitness * (1.0 + m_organism->GetNeutralMax());
989 
990   cTestCPU* testcpu = m_world->GetHardwareManager().CreateTestCPU(ctx);
991   cCPUTestInfo test_info;
992   test_info.UseRandomInputs();
993   testcpu->TestGenome(ctx, test_info, m_organism->OffspringGenome());
994   const double child_fitness = test_info.GetGenotypeFitness();
995   delete testcpu;
996 
997   bool revert = false;
998   bool sterilize = false;
999 
1000   // If implicit mutations are turned off, make sure this won't spawn one.
1001   if (m_organism->GetSterilizeUnstable() > 0) {
1002     if (test_info.GetMaxDepth() > 0) sterilize = true;
1003   }
1004 
1005   if (m_organism->GetSterilizeUnstable() > 1 && !test_info.IsViable()) {
1006     sterilize = true;
1007   }
1008 
1009   if (child_fitness == 0.0) {
1010     // Fatal mutation... test for reversion.
1011     if (ctx.GetRandom().P(m_organism->GetRevertFatal())) revert = true;
1012     if (ctx.GetRandom().P(m_organism->GetSterilizeFatal())) sterilize = true;
1013   } else if (child_fitness < neut_min) {
1014     if (ctx.GetRandom().P(m_organism->GetRevertNeg())) revert = true;
1015     if (ctx.GetRandom().P(m_organism->GetSterilizeNeg())) sterilize = true;
1016   } else if (child_fitness <= neut_max) {
1017     if (ctx.GetRandom().P(m_organism->GetRevertNeut())) revert = true;
1018     if (ctx.GetRandom().P(m_organism->GetSterilizeNeut())) sterilize = true;
1019   } else {
1020     if (ctx.GetRandom().P(m_organism->GetRevertPos())) revert = true;
1021     if (ctx.GetRandom().P(m_organism->GetSterilizePos())) sterilize = true;
1022   }
1023 
1024   int RorS = 0;	// 0 = neither, 1 = revert, 2 = sterilize
1025   if (ctx.GetRandom().P(m_organism->GetRevertTaskLoss()))
1026 	  RorS = 1;
1027   else if (ctx.GetRandom().P(m_organism->GetSterilizeTaskLoss()))
1028 	  RorS = 2;
1029   // check if child has lost any tasks parent had AND not gained any new tasks
1030   if (RorS) {
1031 	  const tArray<int>& childtasks = test_info.GetTestPhenotype().GetLastTaskCount();
1032 	  bool del = false;
1033 	  bool added = false;
1034 	  for (int i=0; i<childtasks.GetSize(); i++)
1035 	  {
1036 		  if (childtasks[i] > parenttasks[i]) {
1037 			  added = true;
1038 			  break;
1039 		  }
1040 		  else if (childtasks[i] < parenttasks[i])
1041 			  del = true;
1042 	  }
1043 	  if (RorS == 1)
1044 		  revert = (del & !added);
1045 	  else
1046 		  sterilize = (del & !added);
1047   }
1048 
1049   // If mutations granting EQU should be reverted, check for EQU
1050   // and flag for reversion.
1051   // The probabilistic check is placed under guard so as not to
1052   // affect consistency by using a random number if the feature
1053   // is not used.
1054   if (m_organism->GetRevertEquals() != 0) {
1055     if (ctx.GetRandom().P(m_organism->GetRevertEquals())) {
1056       const tArray<int>& child_tasks = test_info.GetTestPhenotype().GetLastTaskCount();
1057       if (child_tasks[child_tasks.GetSize() - 1] >= 1) {
1058         revert = true;
1059         m_world->GetStats().AddNewTaskCount(child_tasks.GetSize() - 1);
1060       }
1061     }
1062   }
1063 
1064   // Ideally, we won't have reversions and sterilizations turned on at the
1065   // same time, but if we do, give revert the priority.
1066   if (revert == true) {
1067 	  m_organism->OffspringGenome() = m_organism->GetGenome();
1068   }
1069 
1070   if (sterilize == true) {
1071 	  m_organism->GetPhenotype().ChildFertile() = false;
1072   }
1073 
1074   return (!sterilize) && revert;
1075 }
1076 
PointMutate(cAvidaContext & ctx,double override_mut_rate)1077 int cHardwareBase::PointMutate(cAvidaContext& ctx, double override_mut_rate)
1078 {
1079   const int max_genome_size = m_world->GetConfig().MAX_GENOME_SIZE.Get();
1080   const int min_genome_size = m_world->GetConfig().MIN_GENOME_SIZE.Get();
1081 
1082   cCPUMemory& memory = GetMemory();
1083   int totalMutations = 0;
1084 
1085 //  const int num_muts = ctx.GetRandom().GetRandBinomial(memory.GetSize(), mut_rate);
1086 //
1087 //  for (int i = 0; i < num_muts; i++) {
1088 //    const int pos = ctx.GetRandom().GetUInt(memory.GetSize());
1089 //    memory[pos] = m_inst_set->GetRandomInst(ctx);
1090 //    memory.SetFlagMutated(pos);
1091 //    memory.SetFlagPointMut(pos);
1092 //  }
1093 
1094 
1095   // Point Substitution Mutations (per site)
1096   if (m_organism->GetPointMutProb() > 0.0 || override_mut_rate > 0.0) {
1097     double mut_rate = (override_mut_rate > 0.0) ? override_mut_rate : m_organism->GetPointMutProb();
1098     int num_mut = ctx.GetRandom().GetRandBinomial(memory.GetSize(), mut_rate);
1099 
1100     // If we have lines to mutate...
1101     if (num_mut > 0) {
1102       for (int i = 0; i < num_mut; i++) {
1103         int site = ctx.GetRandom().GetUInt(memory.GetSize());
1104         char before_mutation = memory[site].GetSymbol();
1105         memory[site] = m_inst_set->GetRandomInst(ctx);
1106         memory.GetMutationSteps().AddSubstitutionMutation(site, before_mutation, memory[site].GetSymbol());
1107         totalMutations++;
1108       }
1109     }
1110   }
1111 
1112   // Point Insert Mutations (per site)
1113   if (m_organism->GetPointInsProb() > 0.0) {
1114     int num_mut = ctx.GetRandom().GetRandBinomial(memory.GetSize(), m_organism->GetPointInsProb());
1115 
1116     // If would make creature too big, insert up to max_genome_size
1117     if (num_mut + memory.GetSize() > max_genome_size) {
1118       num_mut = max_genome_size - memory.GetSize();
1119     }
1120 
1121     // If we have lines to insert...
1122     if (num_mut > 0) {
1123       // Build a sorted list of the sites where mutations occured
1124       tArray<int> mut_sites(num_mut);
1125       for (int i = 0; i < num_mut; i++) mut_sites[i] = ctx.GetRandom().GetUInt(memory.GetSize() + 1);
1126       tArrayUtils::QSort(mut_sites);
1127 
1128       // Actually do the mutations (in reverse sort order)
1129       for (int i = mut_sites.GetSize() - 1; i >= 0; i--) {
1130         memory.Insert(mut_sites[i], m_inst_set->GetRandomInst(ctx));
1131         memory.GetMutationSteps().AddInsertionMutation(mut_sites[i], memory[mut_sites[i]].GetSymbol());
1132       }
1133 
1134       totalMutations += num_mut;
1135     }
1136   }
1137 
1138 
1139   // Point Deletion Mutations (per site)
1140   if (m_organism->GetPointDelProb() > 0) {
1141     int num_mut = ctx.GetRandom().GetRandBinomial(memory.GetSize(), m_organism->GetPointDelProb());
1142 
1143     // If would make creature too small, delete down to min_genome_size
1144     if (memory.GetSize() - num_mut < min_genome_size) {
1145       num_mut = memory.GetSize() - min_genome_size;
1146     }
1147 
1148     // If we have lines to delete...
1149     for (int i = 0; i < num_mut; i++) {
1150       int site = ctx.GetRandom().GetUInt(memory.GetSize());
1151       memory.GetMutationSteps().AddDeletionMutation(site, memory[site].GetSymbol());
1152       memory.Remove(site);
1153     }
1154 
1155     totalMutations += num_mut;
1156   }
1157 
1158 
1159 
1160 
1161   return totalMutations;
1162 }
1163 
1164 
FindLabelFull(const cCodeLabel & label)1165 cHeadCPU cHardwareBase::FindLabelFull(const cCodeLabel& label)
1166 {
1167   assert(label.GetSize() > 0); // Trying to find label of 0 size!
1168 
1169   cHeadCPU temp_head(this);
1170 
1171   while (temp_head.InMemory()) {
1172     // If we are not in a label, jump to the next checkpoint...
1173     if (!m_inst_set->IsNop(temp_head.GetInst())) {
1174       temp_head.AbsJump(label.GetSize());
1175       continue;
1176     }
1177 
1178     // Otherwise, rewind to the begining of this label...
1179 
1180     while (!(temp_head.AtFront()) && m_inst_set->IsNop(temp_head.GetInst(-1)))
1181       temp_head.AbsJump(-1);
1182 
1183     // Calculate the size of the label being checked, and make sure they
1184     // are equal.
1185 
1186     int size = 0;
1187     bool label_match = true;
1188     do {
1189       // Check if the nop matches
1190       if (size < label.GetSize() && label[size] != m_inst_set->GetNopMod(temp_head.GetInst()))
1191         label_match = false;
1192 
1193       // Increment the current position and length calculation
1194       temp_head.AbsJump(1);
1195       size++;
1196 
1197       // While still within memory and the instruction is a nop
1198     } while (temp_head.InMemory() && m_inst_set->IsNop(temp_head.GetInst()));
1199 
1200     if (size != label.GetSize()) continue;
1201 
1202     // temp_head will point to the first non-nop instruction after the label, or the end of the memory space
1203     //   if this is a match, return this position
1204     if (label_match) return temp_head;
1205   }
1206 
1207   // The label does not exist in this creature.
1208 
1209   temp_head.AbsSet(-1);
1210   return temp_head;
1211 }
1212 
GetInputBuf()1213 tBuffer<int>& cHardwareBase::GetInputBuf()
1214 {
1215   return m_organism->GetInputBuf();
1216 }
1217 
GetOutputBuf()1218 tBuffer<int>& cHardwareBase::GetOutputBuf()
1219 {
1220   return m_organism->GetOutputBuf();
1221 }
1222 
1223 
Inst_Nop(cAvidaContext & ctx)1224 bool cHardwareBase::Inst_Nop(cAvidaContext& ctx)          // Do Nothing.
1225 {
1226   return true;
1227 }
1228 
1229 
1230 // @JEB Check implicit repro conditions -- meant to be called at the end of SingleProcess
checkImplicitRepro(cAvidaContext & ctx,bool exec_last_inst)1231 void cHardwareBase::checkImplicitRepro(cAvidaContext& ctx, bool exec_last_inst)
1232 {
1233   //Dividing a dead organism causes all kinds of problems
1234   if (m_organism->IsDead()) return;
1235 
1236   if( (m_world->GetConfig().IMPLICIT_REPRO_TIME.Get() && (m_organism->GetPhenotype().GetTimeUsed() >= m_world->GetConfig().IMPLICIT_REPRO_TIME.Get()))
1237      || (m_world->GetConfig().IMPLICIT_REPRO_CPU_CYCLES.Get() && (m_organism->GetPhenotype().GetCPUCyclesUsed() >= m_world->GetConfig().IMPLICIT_REPRO_CPU_CYCLES.Get()))
1238      || (m_world->GetConfig().IMPLICIT_REPRO_BONUS.Get() && (m_organism->GetPhenotype().GetCurBonus() >= m_world->GetConfig().IMPLICIT_REPRO_BONUS.Get()))
1239      || (m_world->GetConfig().IMPLICIT_REPRO_END.Get() && exec_last_inst)
1240      || (m_world->GetConfig().IMPLICIT_REPRO_ENERGY.Get() && (m_organism->GetPhenotype().GetStoredEnergy() >= m_world->GetConfig().IMPLICIT_REPRO_ENERGY.Get())) )
1241   {
1242     Inst_Repro(ctx);
1243   }
1244 }
1245 
1246 //This must be overridden by the specific CPU to function properly
Inst_Repro(cAvidaContext & ctx)1247 bool cHardwareBase::Inst_Repro(cAvidaContext& ctx)
1248 {
1249   cout << "This hardware type does not have a =repro= instruction. IMPLICIT_REPRO conditions cannot be used!" << endl;
1250   exit(1);
1251   return false;
1252 }
1253 
1254 
Inst_DoubleEnergyUsage(cAvidaContext & ctx)1255 bool cHardwareBase::Inst_DoubleEnergyUsage(cAvidaContext& ctx)
1256 {
1257   cPhenotype& phenotype = m_organism->GetPhenotype();
1258   phenotype.DoubleEnergyUsage();
1259   double newOrgMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy()  * phenotype.GetEnergyUsageRatio());
1260   m_organism->UpdateMerit(newOrgMerit);
1261   return true;
1262 }
1263 
Inst_HalveEnergyUsage(cAvidaContext & ctx)1264 bool cHardwareBase::Inst_HalveEnergyUsage(cAvidaContext& ctx)
1265 {
1266   cPhenotype& phenotype = m_organism->GetPhenotype();
1267   phenotype.HalveEnergyUsage();
1268   double newOrgMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy()  * phenotype.GetEnergyUsageRatio());
1269   m_organism->UpdateMerit(newOrgMerit);
1270   return true;
1271 }
1272 
Inst_DefaultEnergyUsage(cAvidaContext & ctx)1273 bool cHardwareBase::Inst_DefaultEnergyUsage(cAvidaContext& ctx)
1274 {
1275   cPhenotype& phenotype = m_organism->GetPhenotype();
1276   phenotype.DefaultEnergyUsage();
1277   double newOrgMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy()  * phenotype.GetEnergyUsageRatio());
1278   m_organism->UpdateMerit(newOrgMerit);
1279   return true;
1280 }
1281 
1282 
1283 // This method will test to see if all costs have been paid associated
1284 // with executing an instruction and only return true when that instruction
1285 // should proceed.
SingleProcess_PayPreCosts(cAvidaContext & ctx,const cInstruction & cur_inst,const int thread_id)1286 bool cHardwareBase::SingleProcess_PayPreCosts(cAvidaContext& ctx, const cInstruction& cur_inst, const int thread_id)
1287 {
1288   if (m_world->GetConfig().ENERGY_ENABLED.Get() > 0) {
1289     // TODO:  Get rid of magic number. check avaliable energy first
1290     double energy_req = m_inst_energy_cost[cur_inst.GetOp()] * (m_organism->GetPhenotype().GetMerit().GetDouble() / 100.0); //compensate by factor of 100
1291 
1292     if (energy_req > 0.0) {
1293       if (m_organism->GetPhenotype().GetStoredEnergy() >= energy_req) {
1294         m_inst_energy_cost[cur_inst.GetOp()] = 0.0;
1295         // subtract energy used from current org energy.
1296         m_organism->GetPhenotype().ReduceEnergy(energy_req);
1297 
1298         // tracking sleeping organisms
1299         if (m_inst_set->ShouldSleep(cur_inst)) m_organism->SetSleeping(true);
1300       } else {
1301         m_organism->GetPhenotype().SetToDie();
1302         return false; // no more, your died...  (evil laugh)
1303       }
1304     }
1305   }
1306 
1307   // If task switching costs need to be paid off...
1308   if (m_task_switching_cost > 0) {
1309     m_task_switching_cost--;
1310     // update deme level stats
1311     cDeme* deme = m_organism->GetOrgInterface().GetDeme();
1312     if(deme != NULL) {
1313       deme->IncNumSwitchingPenalties(1);
1314     }
1315     return false;
1316   }
1317 
1318   // If first time cost hasn't been paid off...
1319   if (m_has_ft_costs && m_inst_ft_cost[cur_inst.GetOp()] > 0) {
1320     m_inst_ft_cost[cur_inst.GetOp()]--;       // dec cost
1321     return false;
1322   }
1323 
1324   // Check for res_costs and fail if org does not have enough resources to process instruction
1325   // As post-cost, res_cost will not be paid unless all pre-costs are paid and all restrictions inside of instruction pass
1326   if (m_has_res_costs || m_has_fem_res_costs) {
1327 
1328     double res_cost = m_inst_set->GetResCost(cur_inst);
1329     double fem_res_cost = m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE ? m_inst_set->GetFemResCost(cur_inst) : 0;
1330     double res_req = res_cost + fem_res_cost;
1331 
1332     const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
1333     tArray<double> res_change(res_count.GetSize());
1334     res_change.SetAll(0.0);
1335 
1336     const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
1337     if (resource < 0) cout << "Instruction resource costs require use of COLLECT_SPECIFIC_RESOURCE and USE_RESOURCE_BINS" << '\n';
1338     assert(resource >= 0);
1339 
1340     double res_stored = m_organism->GetRBin(resource);
1341     // fail if org does not have enough resources to process instruction
1342     if (res_stored < res_req) return false;
1343   }
1344 
1345   //@CHC: If this organism is female, or a choosy female, we may need to impose additional costs for her to execute the instruction
1346   int per_use_cost = 0;
1347   if (m_has_costs) {
1348     per_use_cost = m_thread_inst_cost[cur_inst.GetOp()]; //*THIS IS THE LINE!!!!
1349   }
1350   bool add_female_costs = false;
1351   if (m_has_female_costs) {
1352     if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
1353       if (m_inst_set->GetFemaleCost(cur_inst)) {
1354         add_female_costs = true;
1355         per_use_cost += m_inst_set->GetFemaleCost(cur_inst);
1356       }
1357     }
1358   }
1359   bool add_choosy_female_costs = false;
1360   if (m_has_choosy_female_costs) {
1361     if ((m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) & (m_organism->GetPhenotype().GetMatePreference() != MATE_PREFERENCE_RANDOM)) {
1362       if (m_inst_set->GetChoosyFemaleCost(cur_inst)) {
1363         add_choosy_female_costs = true;
1364         per_use_cost += m_inst_set->GetChoosyFemaleCost(cur_inst);
1365       }
1366     }
1367   }
1368   // Next, look at the per use costs
1369   if (m_has_costs | add_female_costs | add_choosy_female_costs | m_has_post_costs) {
1370     // Current ACTIVE thread-specific execution cost being paid, decrement and return false
1371     // if ACTIVE post cost already being paid (from previous executed instruction), pay this before doing anything else
1372     if (m_active_thread_post_costs[thread_id] > 1) {
1373       m_active_thread_post_costs[thread_id]--;
1374       return false;
1375     }
1376     if (m_active_thread_post_costs[thread_id] == 1) m_active_thread_post_costs[thread_id] = 0;
1377 
1378     if (m_active_thread_costs[thread_id] > 1) {
1379       m_active_thread_costs[thread_id]--;
1380       return false;
1381     }
1382 
1383     // no already active thread-specific execution cost, but this instruction has a cost, setup the counter and return false
1384     // if active PRE costs, pay these before executing instruction
1385     if (!m_active_thread_costs[thread_id] && per_use_cost > 1) { //used to be: m_thread_inst_cost[cur_inst.GetOp()] > 1) {
1386       m_active_thread_costs[thread_id] = per_use_cost - 1;
1387       return false;
1388     }
1389     // If we fall to here, execution is allowed now...any pre-cost is paid
1390     if (m_active_thread_costs[thread_id] == 1) m_active_thread_costs[thread_id] = 0;
1391   }
1392 
1393   if (m_world->GetConfig().ENERGY_ENABLED.Get() > 0) {
1394     m_inst_energy_cost[cur_inst.GetOp()] = m_inst_set->GetEnergyCost(cur_inst); // reset instruction energy cost
1395   }
1396   return true;
1397 }
1398 
IsPayingActiveCost(cAvidaContext & ctx,const int thread_id)1399 bool cHardwareBase::IsPayingActiveCost(cAvidaContext& ctx, const int thread_id)
1400 {
1401   if (m_active_thread_post_costs[thread_id] > 1) return true;
1402   return false;
1403 }
1404 
SingleProcess_PayPostResCosts(cAvidaContext & ctx,const cInstruction & cur_inst)1405 void cHardwareBase::SingleProcess_PayPostResCosts(cAvidaContext& ctx, const cInstruction& cur_inst)
1406 {
1407   if (m_has_res_costs || m_has_fem_res_costs) {
1408 
1409     double res_cost = m_inst_set->GetResCost(cur_inst);
1410     double fem_res_cost = m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE ? m_inst_set->GetFemResCost(cur_inst) : 0;
1411     double res_req = res_cost + fem_res_cost;
1412 
1413     const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
1414     tArray<double> res_change(res_count.GetSize());
1415     res_change.SetAll(0.0);
1416 
1417     const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
1418     if (resource < 0) cout << "Instruction resource costs require use of COLLECT_SPECIFIC_RESOURCE and USE_RESOURCE_BINS" << '\n';
1419     assert(resource >= 0);
1420 
1421     // subtract res used from current bin by adding negative value
1422     double cost = res_req * -1.0;
1423     m_organism->AddToRBin(resource, cost);
1424   }
1425   return;
1426 }
1427 
SingleProcess_SetPostCPUCosts(cAvidaContext & ctx,const cInstruction & cur_inst,const int thread_id)1428 void cHardwareBase::SingleProcess_SetPostCPUCosts(cAvidaContext& ctx, const cInstruction& cur_inst, const int thread_id)
1429 {
1430   if (m_has_post_costs) {
1431     int per_use_post_cost = m_thread_inst_post_cost[cur_inst.GetOp()];
1432     // for post-cost, setup the new counter after allowing initial execution to proceed...this will cause the next instruction to pause before execution
1433     if (!m_active_thread_post_costs[thread_id] && per_use_post_cost > 1) {
1434       m_active_thread_post_costs[thread_id] = per_use_post_cost;
1435     }
1436   }
1437   return;
1438 }
1439 
1440 //! Called when the organism that owns this CPU has received a flash from a neighbor.
ReceiveFlash()1441 void cHardwareBase::ReceiveFlash()
1442 {
1443   m_world->GetDriver().RaiseFatalException(1, "Method cHardwareBase::ReceiveFlash must be overriden.");
1444 }
1445 
1446 /*! Retrieve a fragment of this organism's genome that extends downstream from the read head.
1447  */
GetGenomeFragment(unsigned int downstream)1448 Sequence cHardwareBase::GetGenomeFragment(unsigned int downstream) {
1449 	cHeadCPU tmp(GetHead(nHardware::HEAD_READ));
1450 	Sequence fragment(downstream);
1451 	for(; downstream>0; --downstream, tmp.Advance()) {
1452 		fragment.Append(tmp.GetInst());
1453 	}
1454 	return fragment;
1455 }
1456 
1457 /*! Insert a genome fragment at the current write head.
1458  */
InsertGenomeFragment(const Sequence & fragment)1459 void cHardwareBase::InsertGenomeFragment(const Sequence& fragment) {
1460 	cHeadCPU& wh = GetHead(nHardware::HEAD_WRITE);
1461 	wh.GetMemory().Insert(wh.GetPosition(), fragment);
1462 	wh.Adjust();
1463 }
1464 
SetMiniTrace(const cString & filename,const int gen_id,const cString & genotype)1465 void cHardwareBase::SetMiniTrace(const cString& filename, const int gen_id, const cString& genotype)
1466 {
1467   cHardwareTracer* minitracer = new cHardwareStatusPrinter(m_world->GetDataFileOFStream(filename));
1468   m_minitracer = minitracer;
1469   m_minitrace_file = filename;
1470   SetupMiniTraceFileHeader(filename, gen_id, genotype);
1471 }
1472 
RecordMicroTrace(const cInstruction & cur_inst)1473 void cHardwareBase::RecordMicroTrace(const cInstruction& cur_inst)
1474 {
1475   m_microtracer.Push(cur_inst.GetSymbol());
1476 }
1477 
PrintMicroTrace(int gen_id)1478 void cHardwareBase::PrintMicroTrace(int gen_id)
1479 {
1480   if (m_microtrace) {
1481     m_world->GetStats().PrintMicroTraces(m_microtracer, m_organism->GetPhenotype().GetUpdateBorn(), m_organism->GetID(), m_organism->GetForageTarget(), gen_id);
1482     m_microtrace = false;
1483   }
1484 }
1485 
RecordNavTrace(bool use_avatar)1486 void cHardwareBase::RecordNavTrace(bool use_avatar)
1487 {
1488   int loc = m_organism->GetOrgInterface().GetCellID();
1489   if (use_avatar) loc = m_organism->GetOrgInterface().GetAVCellID();
1490 
1491   int facing = m_organism->GetOrgInterface().GetFacedDir();
1492   if (use_avatar) facing = m_organism->GetOrgInterface().GetAVFacing();
1493 
1494   m_navtraceloc.Push(loc);
1495   m_navtracefacing.Push(facing);
1496   m_navtraceupdate.Push(m_world->GetStats().GetUpdate());
1497 }
1498 
DeleteMiniTrace(bool print_reacs)1499 void cHardwareBase::DeleteMiniTrace(bool print_reacs)
1500 {
1501   if (m_minitracer != NULL) {
1502     if (print_reacs) PrintMiniTraceReactions();
1503     delete m_minitracer;
1504     m_minitracer = NULL;
1505     bool success = m_world->GetDataFileManager().Remove(m_minitrace_file);
1506     assert(success);
1507   }
1508 }
1509 
PrintMiniTraceReactions()1510 void cHardwareBase::PrintMiniTraceReactions()
1511 {
1512   if (m_minitracer != NULL) {
1513     m_world->GetStats().PrintMiniTraceReactions(m_organism);
1514   }
1515 }
1516 
1517