-
Notifications
You must be signed in to change notification settings - Fork 113
Introduction to parasites
This introduction assumes some basic knowledge about Avida. In particular, familiarity with the basic organism and hardware as described here will be very useful to have.
With that said, parasites currently do not work in the default hardware but rather one that supports better threading capabilities – the TransSMT hardware. The differences aren’t huge, but they deserve their own documentation. Instead, I will just highlight major differences between the hardware types important for parasites, namely memoryspaces and threads.
Memory spaces are regions of memory reserved for genetic instructions such as an individual’s genome. To access these memory spaces, organisms execute the Set-Memory
instruction followed by one or more Nop
instructions specifying which space to use. In this hardware, the genome copy produced during self-replication must also be in a seperate memory space, as well as any thread processes an individual spawns.
Threads in this hardware are distinct code sequences that are executed either in parallel, where all threads execute an instruction per CPU cycle awarded to an individual, or round-robin, where a single instruction from a single thread is exected per awarded CPU cycle and each thread executes in turn. The number of threads an organism is allowed to have, as well as how they are scheduled is controlled by the following config options in the avida.cfg
file.
- MAX_CPU_THREADS 1 # Maximum number of Threads a CPU can spawn
- THREAD_SLICING_METHOD 0 # 0 = One thread executed per time slice. # 1 = All threads executed each time slice.
Parasites in Avida are almost identical to hosts, self-replicating by copying their genome instruction-by-instruction into a new memory space. However, instead of dividing this new genome off into the world, parasites attempt to infect a random organism in its host’s neighborhood (globaly if BIRTH_METHOD=4
or WORLD_GEOMETRY=7
, and honoring the WORLD_GEOMETRY
if BIRTH_METHOD
is set to any other value) with their offspring parasite genome, becoming a new thread on the host organism. Parasites attempt infection by calling the Inject
instruction, which is also Nop
-modified to identify the memory space the parasitic thread should occupy.
In order for infection to succede, the host must be able to accept a new thread in the memory space the parasite is attempting to occupy. This means the host must have fewer than MAX_CPU_THREADS
and that the host has not used the memory space specified by the Inject
instruction. More than one parasite per host is not currently supported, thus we typicaly set MAX_CPU_THREADS=2
. We can eliminate the effect of host-parasite coevolution via memory space allocation and specification (and as any unforseen side-effects such as parasites overwriting host offspring when specificying a particular memory space) by giving parasites memory spaces entirely seperate from their host’s (PARASITE_MEM_SPACES=1
).
Parasites as well as hosts can perform logic tasks, and we can use their task-based phenotypes to implement additional mechanisms determining if infection will succeed or not. The config option INFECTION_MECHANISM
already has several mechanisms implemented. The implemented options have the following behavior:
- 0 - Infection will succeed independent of task-based phenotypes
- 1 - Infection will succeed if the parasite and host have at least one overlapping task (Inverse Gene-for-Gene)
- 2 - Infection will succeed if the parasite does at least one task the host does not perform
- 3 - Infection will succeed if the parasite and host do the same tasks (Matching Alleles)
- 4 - Infection will succeed if the parasite performs all the tasks the host does as well as at least one additional task (Gene-for-Gene)
To have more control over how many CPU cycles a parasite steals from it’s host, PARASITE_VIRULENCE
determines the probability that a CPU cycle will be given to the parasite. Thus, when this option is set to 1, the parasite is completely virulent and overtakes all of its host’s CPU cycles. It is also possible to let the parasites evolve their own virulence by setting VIRULENCE_SOURCE=1
, and choosing values for both VIRULENCE_MUT_RATE
, which controls the probability of mutating a parasites virulence when a new parasite is born, and VIRULENCE_SD
, which is the standard deviation of a normal distribution used to determine how much virulence changes when it mutates.
Depiction of a Host-Parasite Interaction
InjectParasite
is typically called near the beginning of a run to infect a range of cells. It takes a parasite organism file, the memory space label, and the range of cells which should be infected.
PrintParasiteTasksData
and PrintHostTasksData
print the tasks performed by parasites and hosts respectively. Similarly, PrintHostPhenotypeData
and PrintParasitePhenotypeData
split up the phenotype data, such as the Shannon Diversity and Richness of unique host and parasite phenotypes.
- BIRTH_METHOD 4 #Population is well-mixed
- INJECT_METHOD 1 #Parasite thread is reset on successful infection
- MAX_CPU_THREADS 2 #Only allow one parasite per host
- INFECTION_MECHANISM 1 #Parasites infect hosts when they have at least one overlapping task
- PARASITE_VIRULENCE 0.8 #Parasites steal 80$ of their host’s CPU cycles
- VIRULENCE_SOURCE 0 #Parasites use virulence value from config, instead of evolving it
- PARASITE_MEM_SPACES 1 #Parasites get their own memory spaces
- PARASITE_NO_COPY_MUT 1 #Parasites don’t use copy mutation rates, so they can have independent mutation rates
- REQUIRE_SINGLE_REACTION 1 #Require hosts to perform at least one succesful reaction to reproduce
A set of complete config files and ancestral organisms can be found here.