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