avida-ed-library-build/docs/documentation/Development-|-Tutorial-|-Bi...

229 lines
13 KiB
Markdown

<p>
This document describes the interaction between organisms and the population.
</p>
<p>&nbsp;</p>
<h2>The Death of an Organism</h2>
<p>
When an organism is killed off, its location in the population (that is, its
population cell) needs to be emptied, the scheduler needs to be notified, and
various statistics need to be updated to reflect the recently deceased. All of
this is handled with the method below. In a default Avida setup, this method
will only be called when a cell needs to be cleared out for a new occupant,
but you've already seen this method used when you implemented the kill-related
events in a previous homework. We'll see it also called from code displayed in
the next section of this document.
</p>
<pre>
void <span class="class">cPopulation</span>::<span class="method">KillOrganism</span>(<span class="class">cPopulationCell</span>&amp; <span class="object">in_cell</span>)
{
<span class="comment">// do we actually have something to kill?</span>
if (<span class="object">in_cell</span>.<span class="method">IsOccupied</span>() == false) return;
<span class="comment">// Statistics...</span>
<span class="class">cOrganism</span>* <span class="object">organism</span> = <span class="object">in_cell</span>.<span class="method">GetOrganism</span>();
<span class="class">cGenotype</span>* <span class="object">genotype</span> = <span class="object">organism</span>-&gt;<span class="method">GetGenotype</span>();
<span class="object">m_world</span>-&gt;<span class="method">GetStats</span>().<span class="method">RecordDeath</span>();
<span class="object">num_organisms</span>--;
<span class="object">genotype</span>-&gt;<span class="method">RemoveOrganism</span>();
<span class="comment">// And clear it!</span>
<span class="object">in_cell</span>.<span class="method">RemoveOrganism</span>();
if (!<span class="object">organism</span>-&gt;<span class="method">GetIsRunning</span>()) delete <span class="object">organism</span>;
else <span class="object">organism</span>-&gt;<span class="method">GetPhenotype</span>().<span class="method">SetToDelete</span>();
<span class="comment">// Alert the scheduler that this cell has a 0 merit.</span>
<span class="object">schedule</span>-&gt;<span class="method">Adjust</span>(<span class="object">in_cell</span>.<span class="method">GetID</span>(), <span class="class">cMerit</span>(0));
<span class="comment">// Update the archive (note: genotype adjustment may be deferred)</span>
<span class="object">m_world</span>-&gt;<span class="method">GetClassificationManager</span>().<span class="method">AdjustGenotype</span>(*<span class="object">genotype</span>);
}
</pre>
<p>
This method takes as an argument the cell that needs to be emptied. It starts
off by making sure that the cell in question actually has an organism in it to
be killed. If not, it stops right there. If so, it records some statistics
about that organism's life, and updates its counter of living organisms to
reflect that there is one fewer.
</p>
<p>
Once the statistics are finished, the cell itself is cleared with the
<span class="class">cPopulationCell</span>::<span class="method">RemoveOrganism</span>()
method (in which the pointer to the organism it once contained is set to NULL).
At this point if the organism is not the currently running CPU it will be
deleted. Otherwise, a flag is set that marks the organism for deletion after
the current instruction has finished executing. Finally, the scheduler (which
is the object that doles out CPU cycles to the individual organisms) is updated
to reflect that this cell is now empty.
</p>
<p>&nbsp;</p>
<h2>Activating an Organism in a Specific Cell</h2>
<p>
If an organism is going to be placed into a specific cell of the population,
the method ActivateOrganism can be called on the population, telling it the
location in memory of the organism to be placed and the cell to place it in.
This method will call the <span class="method">KillOrganism</span>() method
to make sure the cell is unoccupied. This method is called from the
<span class="method">Inject</span>() method as well as
<span class="method">ActivateOffspring</span>(), described below.
Here is the ActivateOrganism method:
<pre>
void <span class="class">cPopulation</span>::<span class="method">ActivateOrganism</span>(<span class="class">cAvidaContext</span>&amp; <span class="object">ctx</span>, <span class="class">cOrganism</span>* <span class="object">in_organism</span>, <span class="class">cPopulationCell</span>&amp; <span class="object">target_cell</span>)
{
<span class="object">in_organism</span>-&gt;<span class="method">SetOrgInterface</span>(new <span class="class">cPopulationInterface</span>(<span class="object">m_world</span>));
<span class="comment">// If the organism does not have a genotype, give it one! No parent</span>
<span class="comment">// information is provided so we must set parents to NULL.</span>
if (<span class="object">in_organism</span>-&gt;<span class="method">GetGenotype</span>() == NULL) {
<span class="class">cGenotype</span>* <span class="object">new_genotype</span> = <span class="object">m_world</span>-&gt;<span class="method">GetClassificationManager</span>().<span class="method">GetGenotype</span>(<span class="object">in_organism</span>-&gt;<span class="method">GetGenome</span>(), NULL, NULL);
<span class="object">in_organism</span>-><span class="method">SetGenotype</span>(<span class="object">new_genotype</span>);
}
<span class="class">cGenotype</span>* <span class="object">in_genotype</span> = <span class="object">in_organism</span>-><span class="method">GetGenotype</span>();
<span class="comment">// Save the old genotype from this cell...</span>
<span class="class">cGenotype</span>* <span class="object">old_genotype</span> = NULL;
if (<span class="object">target_cell</span>.<span class="method">IsOccupied</span>()) {
<span class="object">old_genotype</span> = <span class="object">target_cell</span>.<span class="method">GetOrganism</span>()-&gt;<span class="method">GetGenotype</span>();
<span class="comment">// Sometimes a new organism will kill off the last member of its genotype</span>
<span class="comment">// in the population. Normally this would remove the genotype, so we</span>
<span class="comment">// want to defer adjusting that genotype until the new one is placed.</span>
<span class="object">old_genotype</span>-&gt;<span class="method">IncDeferAdjust</span>();
}
<span class="comment">// Update the contents of the target cell.</span>
<span class="method">KillOrganism</span>(<span class="object">target_cell</span>);
<span class="object">target_cell</span>.<span class="method">InsertOrganism</span>(*<span class="object">in_organism</span>);
<span class="comment">// Update the archive...</span>
<span class="object">in_genotype</span>-><span class="method">AddOrganism</span>();
if (<span class="object">old_genotype</span> != NULL) {
<span class="object">old_genotype</span>-&gt;<span class="method">DecDeferAdjust</span>();
<span class="object">m_world</span>-&gt;<span class="method">GetClassificationManager</span>().<span class="method">AdjustGenotype</span>(*<span class="object">old_genotype</span>);
}
<span class="object">m_world</span>-&gt;<span class="method">GetClassificationManager</span>().<span class="method">AdjustGenotype</span>(*<span class="object">in_genotype</span>);
<span class="comment">// Initialize the time-slice for this new organism.</span>
<span class="object">schedule</span>-><span class="method">Adjust</span>(<span class="object">target_cell</span>.<span class="method">GetID</span>(), <span class="object">in_organism</span>-><span class="method">GetPhenotype</span>().<span class="method">GetMerit</span>());
<span class="comment">// Special handling for certain birth methods.</span>
if (<span class="object">m_world</span>-&gt;<span class="method">GetConfig</span>().<span class="object">BIRTH_METHOD</span>.<span class="method">Get</span>() == POSITION_CHILD_FULL_SOUP_ELDEST) {
<span class="object">reaper_queue</span>.<span class="method">Push</span>(&amp;<span class="object">target_cell</span>);
}
<span class="object">num_organisms</span>++;
<span class="comment">// Statistics...</span>
<span class="object">m_world</span>-&gt;<span class="method">GetStats</span>().<span class="method">RecordBirth</span>(<span class="object">target_cell</span>.<span class="method">GetID</span>(), <span class="object">in_genotype</span>-><span class="method">GetID</span>(),
<span class="object">in_organism</span>-&gt;<span class="method">GetPhenotype</span>().<span class="method">ParentTrue</span>());
}
</pre>
<p>
The first thing we do build a new interface object and attach it to the
organism object. Next we check to see if the organism has already been
assigned its genotype. If an organism was born from a parent in the population,
it will have been assigned a genotype by the time this method is called. If it
does not have a genotype, however, the classification manager object will be
called to look up any genotypes that match this genome. The classification
manager will either return an exact match, or else create a new genotype, add it
to the archive, and return its pointer. In either case, we now have a genotype
for this organism.
</p>
<p>
Before we erase the organism currently in this cell, we want to keep track of
what genotype it was part of for use in updating the archive later. We then
kill the organism in the cell (as described above) and insert the new one.
The <span class="class">cPopulationCell</span>::<span class="method">InsertOrganism</span>()
method will setup the organism based on the environmental conditions of this
cell (mutation rate, tasks rewarded, etc), and store the organism for future
use.
</p>
<p>
We then adjust the genotype to let it know a new organism of its type has
been created, and tell the classification manager that it should also adjust
the genotypes to reflect their new abundances (one genotype has grown by one,
the other has shrunk, so the genotype ordering may change). Other maintenance
we need to do at this point includes adjusting the scheduler to let it know the
merit of this new organism, and the <code>reaper_queue</code> if we keep track
of the birth order of organisms so that we can always kill off the oldest in
the population.
</p>
<p>
Finally, we adjust some more statistics by incrementing the number of
organisms in the population and let the statistics object know that a new
organism was born, with all of its information. Remember, if this cell was
already occupied, KillOrganism() would have decremented it, so this will
properly reflect the number of organisms alive in the population at any moment.
</p>
<p>&nbsp;</p>
<h2>Placing an Offspring in the Population</h2>
<p>
When an organism gives birth, we must collect some relevant statistics,
which can best be accomplished in the population object. Then we must
place the offspring into its own cell in the population. This is all done
with the <span class="class">cPopulation</span>::<span class="method">ActivateOffspring</span>
method. This method takes as arguments the parent organism and child genome
that we're working with. It is called by the divide command via the
population interface. As this method is quite long, refer to it in the source
code in <kbd>cPopulation.cc</kbd> while reading the remainder of this section.
</p>
<p>
The first step in activating an offspring involves performing some book keeping
on the parent's phenotype via the <span class="method">DivideReset</span>()
method. After this, the child genome is submitted to the birth chamber. The
birth chamber is responsible for handling the details of reproduction, such as
genome recombination in sexual populations. The
<span class="method">SubmitOffspring</span>() method will add organism objects
to the <span class="object">child_array</span> for each offspring produced.
</p>
<p>
The next section of code is in charge of finding where in the population each
child organism should be placed. The cell of the parent is looked up, and then
the <span class="method">PositionChild</span>() method is called to determine
the child's cell.
</p>
<p>
If the parent is not about to be killed off (due to being replaced by one of
the children), we actually want to do a bit more work -- we need to adjust
it in the schedule in case its merit has changed over this gestation cycle,
and (if we are on a grid) we want to turn the child so that it is facing
its parent.
</p>
<p>
Finally, we collect a bunch of statistics for the parent's genotype object,
and we run ActivateOffspring for each offspring produced using the cell we have
chosen in order to place the child into the population.
</p>
<p>&nbsp;</p>
<h2>Injecting an Organism into the Population</h2>
<p>
Injecting a genome into the population that does not have a parent (such as
with the <code>Inject</code> action) is somewhat easier to deal with.
Basically, all that this method needs to do is build the organism with the
proper genome, determine its genotype, setup its phenotype, put it into a
test CPU to get its initial merit, and activate it! You should be able to
go line-by-line through the code to see how exactly this happens for
yourself. See
<span class="class">cPopulation</span>::<span class="method">InjectGenome</span>,
and more importantly
<span class="class">cPopulation</span>::<span class="method">InjectGenotype</span>
in <kbd>cPopulation.cc</kbd>.
</p>