229 lines
13 KiB
Markdown
229 lines
13 KiB
Markdown
<p>
|
|
This document describes the interaction between organisms and the population.
|
|
</p>
|
|
|
|
|
|
<p> </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>& <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>-><span class="method">GetGenotype</span>();
|
|
<span class="object">m_world</span>-><span class="method">GetStats</span>().<span class="method">RecordDeath</span>();
|
|
|
|
<span class="object">num_organisms</span>--;
|
|
<span class="object">genotype</span>-><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>-><span class="method">GetIsRunning</span>()) delete <span class="object">organism</span>;
|
|
else <span class="object">organism</span>-><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>-><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>-><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> </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>& <span class="object">ctx</span>, <span class="class">cOrganism</span>* <span class="object">in_organism</span>, <span class="class">cPopulationCell</span>& <span class="object">target_cell</span>)
|
|
{
|
|
<span class="object">in_organism</span>-><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>-><span class="method">GetGenotype</span>() == NULL) {
|
|
<span class="class">cGenotype</span>* <span class="object">new_genotype</span> = <span class="object">m_world</span>-><span class="method">GetClassificationManager</span>().<span class="method">GetGenotype</span>(<span class="object">in_organism</span>-><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>()-><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>-><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>-><span class="method">DecDeferAdjust</span>();
|
|
<span class="object">m_world</span>-><span class="method">GetClassificationManager</span>().<span class="method">AdjustGenotype</span>(*<span class="object">old_genotype</span>);
|
|
}
|
|
<span class="object">m_world</span>-><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>-><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>(&<span class="object">target_cell</span>);
|
|
}
|
|
|
|
<span class="object">num_organisms</span>++;
|
|
|
|
<span class="comment">// Statistics...</span>
|
|
<span class="object">m_world</span>-><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>-><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> </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> </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>
|