1 /*
2  *  cTestCPU.cc
3  *  Avida
4  *
5  *  Called "test_cpu.cc" prior to 11/30/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 "cTestCPU.h"
24 
25 #include "cAvidaContext.h"
26 #include "cBioGroup.h"
27 #include "cCPUTestInfo.h"
28 #include "cEnvironment.h"
29 #include "cHardwareBase.h"
30 #include "cHardwareManager.h"
31 #include "cHardwareStatusPrinter.h"
32 #include "cInstSet.h"
33 #include "cOrganism.h"
34 #include "cPhenotype.h"
35 #include "cResource.h"
36 #include "cResourceCount.h"
37 #include "cResourceHistory.h"
38 #include "cResourceLib.h"
39 #include "cStringUtil.h"
40 #include "cTestCPUInterface.h"
41 #include "cWorld.h"
42 #include "tMatrix.h"
43 
44 #include <iomanip>
45 
46 using namespace std;
47 using namespace AvidaTools;
48 
49 
cTestCPU(cAvidaContext & ctx,cWorld * world)50 cTestCPU::cTestCPU(cAvidaContext& ctx, cWorld* world)
51 {
52   m_world = world;
53 	m_use_manual_inputs = false;
54   InitResources(ctx);
55 }
56 
57 
InitResources(cAvidaContext & ctx,int res_method,cResourceHistory * res,int update,int cpu_cycle_offset)58 void cTestCPU::InitResources(cAvidaContext& ctx, int res_method, cResourceHistory* res, int update, int cpu_cycle_offset)
59 {
60   //FOR DEMES
61   m_deme_resource_count.SetSize(0);
62 
63   m_res_method = (eTestCPUResourceMethod)res_method;
64   // Make sure it's valid
65   if (res_method < 0 || res_method >= RES_LAST) m_res_method = RES_INITIAL;
66 
67   // Setup the resources...
68   m_res = res;
69   m_res_cpu_cycle_offset = cpu_cycle_offset;
70   m_res_update = update;
71 
72   // Adjust updates if time_spent_offset is greater than a time slice
73   int ave_time_slice = m_world->GetConfig().AVE_TIME_SLICE.Get();
74   m_res_update += m_res_cpu_cycle_offset / ave_time_slice;
75   m_res_cpu_cycle_offset %= ave_time_slice;
76   assert(m_res_cpu_cycle_offset >= 0);
77 
78   // If they didn't send anything (usually during an avida run as opposed to analyze mode),
79   // then we set up a static variable (or just point to it) that reflects the initial conditions of the run
80   // from the environment file.  (JEB -- This code moved from cAnalyze::cAnalyze).
81   if (m_res_method == RES_INITIAL)
82   {
83     // Initialize the time oriented resource list to be just the initial
84     // concentrations of the resources in the environment.  This will only
85     // be changed if LOAD_RESOURCES analyze command is called.  If there are
86     // no resources in the environment or there is no environment, the list
87     // is empty then the all resources will default to 0.0
88     m_res = &m_world->GetEnvironment().GetResourceLib().GetInitialResourceLevels();
89   }
90 
91   const cResourceLib& resource_lib = m_world->GetEnvironment().GetResourceLib();
92   assert(resource_lib.GetSize() >= 0);
93 
94   // Set the resource count to zero by default
95   m_resource_count.SetSize(resource_lib.GetSize());
96   m_faced_cell_resource_count.SetSize(resource_lib.GetSize());
97   m_cell_resource_count.SetSize(resource_lib.GetSize());
98   for (int i = 0; i < resource_lib.GetSize(); i++) {
99     m_resource_count.Set(ctx, i, 0.0);
100     m_faced_cell_resource_count.Set(ctx, i, 0.0);
101     m_cell_resource_count.Set(ctx, i, 0.0);
102   }
103 
104   SetResourceUpdate(ctx, m_res_update, false);
105   // Round down to the closest update to choose how to initialize resources
106 }
107 
UpdateResources(cAvidaContext & ctx,int cpu_cycles_used)108 void cTestCPU::UpdateResources(cAvidaContext& ctx, int cpu_cycles_used)
109 {
110   int ave_time_slice = m_world->GetConfig().AVE_TIME_SLICE.Get();
111   if ((m_res_method >= RES_UPDATED_DEPLETABLE) && (cpu_cycles_used % ave_time_slice == 0))
112     SetResourceUpdate(ctx, m_res_update + 1, true);
113 }
114 
SetResourceUpdate(cAvidaContext & ctx,int update,bool round_to_closest)115 inline void cTestCPU::SetResourceUpdate(cAvidaContext& ctx, int update, bool round_to_closest)
116 {
117   // No resources defined? -- you can't do this!
118   if (!m_res) return;
119 
120   m_res_update = update;
121 
122   m_res->GetResourceCountForUpdate(ctx, update, m_resource_count, !round_to_closest);
123 }
124 
ModifyResources(cAvidaContext & ctx,const tArray<double> & res_change)125 void cTestCPU::ModifyResources(cAvidaContext& ctx, const tArray<double>& res_change)
126 {
127   //We only let the testCPU modify the resources if we are using a DEPLETABLE option. @JEB
128   if (m_res_method >= RES_UPDATED_DEPLETABLE) m_resource_count.Modify(ctx, res_change);
129 }
130 
131 
132 // NOTE: This method assumes that the organism is a fresh creation.
ProcessGestation(cAvidaContext & ctx,cCPUTestInfo & test_info,int cur_depth)133 bool cTestCPU::ProcessGestation(cAvidaContext& ctx, cCPUTestInfo& test_info, int cur_depth)
134 {
135   assert(test_info.org_array[cur_depth] != NULL);
136 
137   cOrganism & organism = *( test_info.org_array[cur_depth] );
138 
139   // Determine how long this organism should be tested for...
140   int time_allocated = m_world->GetConfig().TEST_CPU_TIME_MOD.Get() * organism.GetGenome().GetSize();
141   time_allocated += m_res_cpu_cycle_offset; // If the resource offset has us starting at a different time, adjust @JEB
142 
143   // Prepare the inputs...
144   cur_input = 0;
145   cur_receive = 0;
146 
147   // Prepare the resources
148   InitResources(ctx, test_info.m_res_method, test_info.m_res, test_info.m_res_update, test_info.m_res_cpu_cycle_offset);
149 
150 
151   // Determine if we're tracing and what we need to print.
152   cHardwareTracer* tracer = test_info.GetTraceExecution() ? (test_info.GetTracer()) : NULL;
153   std::ostream * tracerStream = NULL;
154   if (tracer != NULL) tracerStream = tracer->GetStream();
155 
156   // This way of keeping track of time is only used to update resources...
157   int time_used = m_res_cpu_cycle_offset; // Note: the offset is zero by default if no resources being used @JEB
158 
159   organism.GetHardware().SetTrace(tracer);
160   while (time_used < time_allocated && organism.GetPhenotype().GetNumDivides() == 0 && !organism.IsDead())
161   {
162     time_used++;
163 
164     // @CAO Need to watch out for parasites.
165 
166     // Resources will be updated as if each update takes a number of cpu cycles equal to the average time slice
167     UpdateResources(ctx, time_used);
168 
169     // Add extra info to trace files so that we can watch resource changes.
170     // This is a clumsy way to insert it in the trace file, but works for my purposes @JEB
171     if ( (m_res_method >= RES_UPDATED_DEPLETABLE) && (tracerStream != NULL) )
172     {
173       const cResourceLib& resource_lib = m_world->GetEnvironment().GetResourceLib();
174       assert(resource_lib.GetSize() >= 0);
175       *tracerStream << "Resources:";
176       // Print out resources
177       for(int i=0; i<resource_lib.GetSize(); i++)
178       {
179          *tracerStream << " " << m_resource_count.Get(ctx, i);
180       }
181       *tracerStream << endl;
182      }
183 
184      organism.GetHardware().SingleProcess(ctx);
185   }
186 
187 
188   // Output final resource information @JEB
189   if ( (m_res_method >= RES_UPDATED_DEPLETABLE) && (tracerStream != NULL) )
190   {
191     const cResourceLib& resource_lib = m_world->GetEnvironment().GetResourceLib();
192     assert(resource_lib.GetSize() >= 0);
193     *tracerStream << "Resources:";
194     // Print out resources
195     for(int i=0; i<resource_lib.GetSize(); i++)
196     {
197        *tracerStream << " " << m_resource_count.Get(ctx, i);
198     }
199     *tracerStream << endl;
200    }
201 
202 
203   organism.GetHardware().SetTrace(NULL);
204 
205   // Print out some final info in trace...
206   if (tracer != NULL) tracer->TraceTestCPU(time_used, time_allocated, organism);
207 
208   // For now, always return true.
209   return true;
210 }
211 
212 
TestGenome(cAvidaContext & ctx,cCPUTestInfo & test_info,const Genome & genome)213 bool cTestCPU::TestGenome(cAvidaContext& ctx, cCPUTestInfo& test_info, const Genome& genome)
214 {
215   ctx.SetTestMode();
216   test_info.Clear();
217   TestGenome_Body(ctx, test_info, genome, 0);
218   ctx.ClearTestMode();
219 
220   return test_info.is_viable;
221 }
222 
TestGenome(cAvidaContext & ctx,cCPUTestInfo & test_info,const Genome & genome,ofstream & out_fp)223 bool cTestCPU::TestGenome(cAvidaContext& ctx, cCPUTestInfo& test_info, const Genome& genome, ofstream& out_fp)
224 {
225   ctx.SetTestMode();
226   test_info.Clear();
227   TestGenome_Body(ctx, test_info, genome, 0);
228 
229   ////////////////////////////////////////////////////////////////
230   // IsViable() == false
231   //   max_depth == 0  : (0) Parent doesn't divide
232   //   max_depth == 1  : (2) Parent does divide, but child does not.
233   //   max_depth >= 2  : (3) Parent and child do divide, but neither true.
234   // ------------------------------------------------------------
235   // IsViable() == true
236   //   max_depth == 0  : (4) Parent Breed True
237   //   max_depth == 1  : (5) Parent NOT Breed True, but Child Does
238   //   max_depth >= 2  : (6) Multiple levels of non-breed true.
239   ////////////////////////////////////////////////////////////////
240 
241 
242   const int depth_comp = Min(test_info.max_depth, 2);
243   int repro_type = ((int) test_info.is_viable) * 3 + 1 + depth_comp;
244   if (test_info.is_viable == false && depth_comp == 0)  repro_type = 0;
245 
246   out_fp << test_info.is_viable << " "
247 	 << test_info.max_depth << " "
248 	 << test_info.depth_found << " "
249 	 << test_info.max_cycle << " "
250 	 << repro_type << endl;
251 
252   ctx.ClearTestMode();
253   return test_info.is_viable;
254 }
255 
TestGenome_Body(cAvidaContext & ctx,cCPUTestInfo & test_info,const Genome & genome,int cur_depth)256 bool cTestCPU::TestGenome_Body(cAvidaContext& ctx, cCPUTestInfo& test_info, const Genome& genome, int cur_depth)
257 {
258   assert(cur_depth < test_info.generation_tests);
259 
260   // Input sizes can vary based on environment settings, must at least initialize
261   m_use_random_inputs = test_info.GetUseRandomInputs(); // save this value in case ResetInputs is used.
262   if (!test_info.GetUseManualInputs())
263 		m_world->GetEnvironment().SetupInputs(ctx, input_array, m_use_random_inputs);
264   else
265 		input_array = test_info.manual_inputs;
266 
267   receive_array.Resize(3);
268   if (test_info.GetUseRandomInputs()) {
269     receive_array[0] = (15 << 24) + ctx.GetRandom().GetUInt(1 << 24);  // 00001111
270     receive_array[1] = (51 << 24) + ctx.GetRandom().GetUInt(1 << 24);  // 00110011
271     receive_array[2] = (85 << 24) + ctx.GetRandom().GetUInt(1 << 24);  // 01010101
272   } else {
273     receive_array[0] = 0x0f139f14;  // 00001111 00010011 10011111 00010100
274     receive_array[1] = 0x33083ee5;  // 00110011 00001000 00111110 11100101
275     receive_array[2] = 0x5562eb41;  // 01010101 01100010 11101011 01000001
276   }
277 
278 	if (cur_depth == 0) test_info.used_inputs = input_array;
279 
280   if (cur_depth > test_info.max_depth) test_info.max_depth = cur_depth;
281 
282   // Setup the organism we're working with now.
283   if (test_info.org_array[cur_depth] != NULL) {
284     delete test_info.org_array[cur_depth];
285   }
286   cOrganism* organism = new cOrganism(m_world, ctx, genome, -1, SRC_TEST_CPU);
287 
288   // Copy the test mutation rates
289   organism->MutationRates().Copy(test_info.MutationRates());
290 
291   test_info.org_array[cur_depth] = organism;
292   organism->SetOrgInterface(ctx, new cTestCPUInterface(this, test_info, cur_depth));
293   organism->GetPhenotype().SetupInject(genome.GetSequence());
294 
295   // Run the current organism.
296   ProcessGestation(ctx, test_info, cur_depth);
297 
298 
299   // Notify the organism that it has died to allow for various cleanup methods to run
300   organism->NotifyDeath(ctx);
301 
302 
303   // Must be able to divide twice in order to form a successful colony,
304   // assuming the CPU doesn't get reset on divides.
305   //
306   // The possibilities after this gestation cycle are:
307   //  1: It did not copy at all => Exit this level.
308   //  2: It copied true => Check next gestation cycle, or set is_viable.
309   //  3: Its copy looks like an ancestor => copy true.
310   //  4: It copied false => we must check the child.
311 
312   // Case 1:  ////////////////////////////////////
313   if (organism->GetPhenotype().GetNumDivides() == 0)  return false;
314 
315   // Case 2:  ////////////////////////////////////
316   if (organism->GetPhenotype().CopyTrue() == true) {
317     test_info.depth_found = cur_depth;
318     test_info.is_viable = true;
319     return true;
320   }
321 
322   // Case 3:  ////////////////////////////////////
323   bool is_ancestor = false;
324   for (int anc_depth = 0; anc_depth < cur_depth; anc_depth++) {
325     if (organism->OffspringGenome() == test_info.org_array[anc_depth]->GetGenome()){
326       is_ancestor = true;
327       const int cur_cycle = cur_depth - anc_depth;
328       if (test_info.max_cycle < cur_cycle) test_info.max_cycle = cur_cycle;
329       test_info.cycle_to = anc_depth;
330     }
331   }
332   if (is_ancestor) {
333     test_info.depth_found = cur_depth;
334     test_info.is_viable = true;
335     return true;
336   }
337 
338   // Case 4:  ////////////////////////////////////
339   // If we haven't reached maximum depth yet, check out the child.
340   if (cur_depth + 1 < test_info.generation_tests) {
341     // Run the offspring's genome.
342     return TestGenome_Body(ctx, test_info, organism->OffspringGenome(), cur_depth + 1);
343   }
344 
345   // All options have failed; just return false.
346   return false;
347 }
348 
349 
PrintGenome(cAvidaContext & ctx,const Genome & genome,cString filename,int update,bool for_groups,int last_birth_cell,int last_group_id,int last_forager_type)350 void cTestCPU::PrintGenome(cAvidaContext& ctx, const Genome& genome, cString filename, int update, bool for_groups, int last_birth_cell, int last_group_id, int last_forager_type)
351 {
352   if (filename == "") filename.Set("archive/%03d-unnamed.org", genome.GetSize());
353 
354   cCPUTestInfo test_info;
355   TestGenome(ctx, test_info, genome);
356 
357   // Open the file...
358   cDataFile& df = m_world->GetDataFile(filename);
359 
360   // Print the useful info at the top...
361   df.WriteTimeStamp();
362   cString c("");
363 
364   df.WriteComment(c.Set("Filename........: %s", static_cast<const char*>(filename)));
365 
366   if (update >= 0) df.WriteComment(c.Set("Update Output...: %d", update));
367   else df.WriteComment("Update Output...: N/A");
368 
369   df.WriteComment(c.Set("Is Viable.......: %d", test_info.IsViable()));
370   df.WriteComment(c.Set("Repro Cycle Size: %d", test_info.GetMaxCycle()));
371   df.WriteComment(c.Set("Depth to Viable.: %d", test_info.GetDepthFound()));
372 
373   df.WriteComment("");
374 
375   const int num_levels = test_info.GetMaxDepth() + 1;
376   for (int j = 0; j < num_levels; j++) {
377     df.WriteComment(c.Set("Generation: %d", j));
378 
379     cOrganism* organism = test_info.GetTestOrganism(j);
380     assert(organism != NULL);
381     cPhenotype& phenotype = organism->GetPhenotype();
382 
383     df.WriteComment(c.Set("Merit...........: %f", phenotype.GetMerit().GetDouble()));
384     df.WriteComment(c.Set("Gestation Time..: %d", phenotype.GetGestationTime()));
385     df.WriteComment(c.Set("Fitness.........: %f", phenotype.GetFitness()));
386     df.WriteComment(c.Set("Errors..........: %d", phenotype.GetLastNumErrors()));
387     df.WriteComment(c.Set("Genome Size.....: %d", organism->GetGenome().GetSize()));
388     df.WriteComment(c.Set("Copied Size.....: %d", phenotype.GetCopiedSize()));
389     df.WriteComment(c.Set("Executed Size...: %d", phenotype.GetExecutedSize()));
390 
391     if (for_groups) {
392       df.WriteComment(c.Set("Last Birth Group ID........: %d", last_group_id));
393       df.WriteComment(c.Set("Last Birth Forager Type....: %d", last_forager_type));
394       df.WriteComment(c.Set("Last Birth Cell............: %d", last_birth_cell));
395     }
396 
397     if (phenotype.GetNumDivides() == 0)
398       df.WriteComment("Offspring.......: NONE");
399     else if (phenotype.CopyTrue())
400       df.WriteComment("Offspring.......: SELF");
401     else if (test_info.GetCycleTo() != -1)
402       df.WriteComment(c.Set("Offspring.......: %d", test_info.GetCycleTo()));
403     else
404       df.WriteComment(c.Set("Offspring.......: %d", j + 1));
405 
406     df.WriteComment("");
407   }
408 
409   df.WriteComment("Tasks Performed:");
410 
411   const cEnvironment& env = m_world->GetEnvironment();
412   const tArray<int>& task_count = test_info.GetTestPhenotype().GetLastTaskCount();
413   const tArray<double>& task_qual = test_info.GetTestPhenotype().GetLastTaskQuality();
414   for (int i = 0; i < task_count.GetSize(); i++) {
415     df.WriteComment(c.Set("%s %d (%f)", static_cast<const char*>(env.GetTask(i).GetName()),
416                           task_count[i], task_qual[i]));
417   }
418 
419   // if resource bins are being used, print relevant information
420   if(m_world->GetConfig().USE_RESOURCE_BINS.Get())  {
421   	df.WriteComment("Tasks Performed Using Internal Resources:");
422 
423   	const tArray<int>& internal_task_count = test_info.GetTestPhenotype().GetLastInternalTaskCount();
424   	const tArray<double>& internal_task_qual = test_info.GetTestPhenotype().GetLastInternalTaskQuality();
425 
426   	for (int i = 0; i < task_count.GetSize(); i++) {
427   		df.WriteComment(c.Set("%s %d (%f)", static_cast<const char*>(env.GetTask(i).GetName()),
428   		                      internal_task_count[i], internal_task_qual[i]));
429   	}
430 
431   	const tArray<double>& rbins_total = test_info.GetTestPhenotype().GetLastRBinsTotal();
432   	const tArray<double>& rbins_avail = test_info.GetTestPhenotype().GetLastRBinsAvail();
433 
434   	df.WriteComment(        "Resources Collected: Name\t\tTotal\t\tAvailable");
435   	for (int i = 0; i < rbins_total.GetSize(); i++) {
436   		df.WriteComment(c.Set("                %d : %s\t\t%f\t\t%f\t\t", i,
437   		                      static_cast<const char*>(env.GetResourceLib().GetResource(i)->GetName()),
438   		                      rbins_total[i], rbins_avail[i]));
439   	}
440   }
441 
442   df.Endl();
443 
444   // Display the genome
445   genome.GetSequence().SaveInstructions(df.GetOFStream(), test_info.GetTestOrganism()->GetHardware().GetInstSet());
446 
447   m_world->GetDataFileManager().Remove(filename);
448 }
449 
450 
PrintBioGroup(cAvidaContext & ctx,cBioGroup * bg,cString filename,int update)451 void cTestCPU::PrintBioGroup(cAvidaContext& ctx, cBioGroup* bg, cString filename, int update)
452 {
453   if (!bg->HasProperty("genome")) return;
454 
455   Genome mg(bg->GetProperty("genome").AsString());
456 
457   if (filename == "") filename.Set("archive/%03d-unnamed.org", mg.GetSequence().GetSize());
458 
459   cCPUTestInfo test_info;
460   TestGenome(ctx, test_info, mg);
461 
462   // Open the file...
463   cDataFile& df = m_world->GetDataFile(filename);
464 
465   // Print the useful info at the top...
466   df.WriteTimeStamp();
467   cString c("");
468 
469   df.WriteComment(c.Set("Filename........: %s", static_cast<const char*>(filename)));
470 
471   if (update >= 0) df.WriteComment(c.Set("Update Output...: %d", update));
472   else df.WriteComment("Update Output...: N/A");
473 
474   df.WriteComment(c.Set("Is Viable.......: %d", test_info.IsViable()));
475   df.WriteComment(c.Set("Repro Cycle Size: %d", test_info.GetMaxCycle()));
476   df.WriteComment(c.Set("Depth to Viable.: %d", test_info.GetDepthFound()));
477 
478   df.WriteComment(c.Set("Genotype ID.....: %d", bg->GetID()));
479   df.WriteComment(c.Set("Tree Depth......: %d", bg->GetDepth()));
480 
481   if (bg->HasProperty("update_born")) df.WriteComment(c.Set("Update Born.....: %d", bg->GetProperty("update_born").AsInt()));
482   if (bg->HasProperty("parents")) df.WriteComment(c.Set("Parent(s).......: %s", (const char*)bg->GetProperty("parents").AsString()));
483 
484   df.WriteComment("");
485 
486   const int num_levels = test_info.GetMaxDepth() + 1;
487   for (int j = 0; j < num_levels; j++) {
488     df.WriteComment(c.Set("Generation: %d", j));
489 
490     cOrganism* organism = test_info.GetTestOrganism(j);
491     assert(organism != NULL);
492     cPhenotype& phenotype = organism->GetPhenotype();
493 
494     df.WriteComment(c.Set("Merit...........: %f", phenotype.GetMerit().GetDouble()));
495     df.WriteComment(c.Set("Gestation Time..: %d", phenotype.GetGestationTime()));
496     df.WriteComment(c.Set("Fitness.........: %f", phenotype.GetFitness()));
497     df.WriteComment(c.Set("Errors..........: %d", phenotype.GetLastNumErrors()));
498     df.WriteComment(c.Set("Genome Size.....: %d", organism->GetGenome().GetSize()));
499     df.WriteComment(c.Set("Copied Size.....: %d", phenotype.GetCopiedSize()));
500     df.WriteComment(c.Set("Executed Size...: %d", phenotype.GetExecutedSize()));
501 
502     if (phenotype.GetNumDivides() == 0)
503       df.WriteComment("Offspring.......: NONE");
504     else if (phenotype.CopyTrue())
505       df.WriteComment("Offspring.......: SELF");
506     else if (test_info.GetCycleTo() != -1)
507       df.WriteComment(c.Set("Offspring.......: %d", test_info.GetCycleTo()));
508     else
509       df.WriteComment(c.Set("Offspring.......: %d", j + 1));
510 
511     df.WriteComment("");
512   }
513 
514   df.WriteComment("Tasks Performed:");
515 
516   const cEnvironment& env = m_world->GetEnvironment();
517   const tArray<int>& task_count = test_info.GetTestPhenotype().GetLastTaskCount();
518   const tArray<double>& task_qual = test_info.GetTestPhenotype().GetLastTaskQuality();
519   for (int i = 0; i < task_count.GetSize(); i++) {
520     df.WriteComment(c.Set("%s %d (%f)", static_cast<const char*>(env.GetTask(i).GetName()),
521                           task_count[i], task_qual[i]));
522   }
523 
524   // if resource bins are being used, print relevant information
525   if(m_world->GetConfig().USE_RESOURCE_BINS.Get())  {
526   	df.WriteComment("Tasks Performed Using Internal Resources:");
527 
528   	const tArray<int>& internal_task_count = test_info.GetTestPhenotype().GetLastInternalTaskCount();
529   	const tArray<double>& internal_task_qual = test_info.GetTestPhenotype().GetLastInternalTaskQuality();
530 
531   	for (int i = 0; i < task_count.GetSize(); i++) {
532   		df.WriteComment(c.Set("%s %d (%f)", static_cast<const char*>(env.GetTask(i).GetName()),
533   		                      internal_task_count[i], internal_task_qual[i]));
534   	}
535 
536   	const tArray<double>& rbins_total = test_info.GetTestPhenotype().GetLastRBinsTotal();
537   	const tArray<double>& rbins_avail = test_info.GetTestPhenotype().GetLastRBinsAvail();
538 
539   	df.WriteComment(        "Resources Collected: Name\t\tTotal\t\tAvailable");
540   	for (int i = 0; i < rbins_total.GetSize(); i++) {
541   		df.WriteComment(c.Set("                %d : %s\t\t%f\t\t%f\t\t", i,
542   		                      static_cast<const char*>(env.GetResourceLib().GetResource(i)->GetName()),
543   		                      rbins_total[i], rbins_avail[i]));
544   	}
545   }
546 
547   df.Endl();
548 
549   // Display the genome
550   mg.GetSequence().SaveInstructions(df.GetOFStream(), test_info.GetTestOrganism()->GetHardware().GetInstSet());
551 
552   m_world->GetDataFileManager().Remove(filename);
553 }
554 
555 
ResetInputs(cAvidaContext & ctx)556 void cTestCPU::ResetInputs(cAvidaContext& ctx)
557 {
558 	if (!m_use_manual_inputs)
559 		m_world->GetEnvironment().SetupInputs(ctx, input_array, m_use_random_inputs);
560 }
561 
562