Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Organisms always inherit trait values from their parents #11

Open
FergusonAJ opened this issue Oct 29, 2021 · 1 comment
Open

Organisms always inherit trait values from their parents #11

FergusonAJ opened this issue Oct 29, 2021 · 1 comment

Comments

@FergusonAJ
Copy link
Collaborator

Overview

When an offspring organism is created from a parent, all the offspring's traits will be copies of the parent's traits.
This occurs even when the trait was given a default value to use.

Details

The Organism class inherits from emp::AnnotatedType, which contains an emp::DataMap. This allows users to create and store traits on Organisms.

However, neither the Organism class nor the emp::Annotatedtype class explicitly define a copy constructor, and the DataMap copy constructor simply copies over the raw memory from the original DataMap.
Offspring are created by first cloning the original organism and then optionally applying mutations. The process of cloning an organism uses its copy constructor (called via ManagerModule::CloneObject_impl()). Thus the offspring has a DataMap that is a direct copy of the parent's.

Potential solutions

  • For a rough, short-term fix, the user can manually reset the trait via MABE's built in module method OnPlacement()
  • Long term, the header comments in core/TraitInfo.hpp specify multiple INIT methods for traits. Implementing these methods should alleviate this issue.

Replication instructions

A working example of this issue can be found at https://github.com/FergusonAJ/MABE2/tree/trait_issue
The only modification to the source code was allowing users to deactivate modules in the config files events.
A sample config files, settings/issue.mabe is included:

random_seed = 0;       // Seed for random number generator; use 0 to base on time.
Population main_pop;            // Collection of organisms
Population next_pop;            // Collection of organisms
Value pop_size = 5;            // Local value variable.
CommandLine cl {                // Handle basic I/O on the command line.
  format = "fitness:max,fitness:mean";// Column format to use in the file.
  target = "main_pop";          // Which population(s) should we print from?
}
EvalNK eval_nk {                // Evaluate bitstrings on an NK fitness lanscape.
  target = "main_pop";          // Which population(s) should we evaluate?
  N = 100;                      // Number of bits required in output
  K = 3;                        // Number of bits used in each gene
  bits_trait = "bits";          // Which trait stores the bit sequence to evaluate?
  fitness_trait = "fitness";    // Which trait should we store NK fitness in?
}
FileOutput output {             // Output collected data into a specified file.
  filename = "output.csv";      // Name of file for output data.
  format = "fitness:max,fitness:mean,fitness:0,fitness:1,fitness:2,fitness:3,fitness:4";// Column format to use in the file.
  target = "main_pop";          // Which population(s) should we print from?
  output_updates = "0:1";      // Which updates should we output data?
}
SelectTournament select_t {     // Select the top fitness organisms from random subgroups for replication.
  select_pop = "main_pop";      // Population from which to select parents
  birth_pop = "next_pop";       // Population into which offspring should be placed
  tournament_size = 2;          // Number of orgs in each tournament
  num_tournaments = 5;        // Number of tournaments to run
  fitness_fun = "fitness";      // Trait equation that produces fitness value to use
}
GrowthPlacement place_next {    // Always appened births to the end of a population.
  target = "main_pop,next_pop"; // Population(s) to manage.
}
MovePopulation sync_gen {       // Move organisms from one populaiton to another.
  from_pop = "next_pop";        // Population to move organisms from.
  to_pop = "main_pop";          // Population to move organisms into.
  reset_to = 1;                 // Should we erase organisms at the destination?
}
BitsOrg bits_org {              // Organism consisting of a series of N bits.
  N = 100;                      // Number of bits in organism
  mut_prob = 0.01;              // Probability of each bit mutating on reproduction.
  output_name = "bits";         // Name of variable to contain bit sequence.
  init_random = 1;              // Should we randomize ancestor?  (0 = all zeros)
}

@start(0) PRINT("random_seed = ", random_seed, "\n");
@start(0) INJECT("bits_org", "main_pop", pop_size);
@update(5) eval_nk._active = 0;
@update(10) EXIT();

In particular, we care that the EvalNK module is deactivated at the start of the 5th update. Thus no organisms born on or after that update should receive fitness scores.
However, upon running the file it is clear that organisms born after update 4 still have a fitness trait:

#update, fitness:max, fitness:mean, fitness:0, fitness:1, fitness:2, fitness:3, fitness:4
0, 0, 0, 0, 0, 0, 0, 0
1, 55.0215, 52.1714, 49.5619, 49.5619, 53.3559, 53.3559, 55.0215
2, 54.8404, 53.1193, 53.3559, 54.8404, 52.0221, 52.0221, 53.3559
3, 55.0693, 53.8883, 55.0693, 54.6868, 52.4995, 54.6868, 52.4995
4, 55.9023, 54.9373, 52.4995, 55.9023, 54.4799, 55.9023, 55.9023
5, 57.3455, 55.5606, 53.3297, 57.3455, 56.4527, 53.3297, 57.3455
6, 57.3455, 56.8098, 57.3455, 57.3455, 56.4527, 56.4527, 56.4527
7, 57.3455, 56.9884, 57.3455, 56.4527, 56.4527, 57.3455, 57.3455
8, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455
9, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455
10, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455, 57.3455

Indeed, by the final update all organisms have a fitness score of 57.3455, which is expected because it was the highest score in update 4 and thus swept the population. While these offspring organisms were never actually evaluated, they maintain the score of their parent organisms. This is despite the evaluate/EvalNK.hpp file setting the default fitness value to 0.
AddOwnedTrait<double>(fitness_trait, "NK fitness value", 0.0);

@mercere99
Copy link
Owner

This occurs because and Offspring's DataMap is inhereted from its parents. We need to make trait settings work that can specify things like "copy from parent", "copy from parent into" (to, for example, track a parental stat on an offspring), "reset to default value", or "run this special function."

Currently this can be hacked by using signals, but a more efficient solution is needed.

catenaccianna pushed a commit to catenaccianna/MABE2 that referenced this issue Mar 11, 2024
Allow analysis of a single Avida org
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants