//This program has been placed into the public domain by its author. import java.util.Random; public class GeneRepair { final int pop_size = 100; final int mutation_attempts_per_generation = this.pop_size * 10; int[] population; int[] time_at_birth; final double mutation_rate = 0.1; final int generation_max = 20000; int time = 0; long total_lifespan; long total_mutations_at_birth; long total_deaths; double[] survival_chance; boolean sex; Random random = new Random(); private void main() { this.survival_chance = new double[32]; log("Zero epistasis: effects of mutations on mortality are independent"); for (int i = 0; i < 32; i++) { this.survival_chance[i] = Math.pow(0.9f, i); } metaExperiment(); log("Dysergetic epistasis: mutations have diminishing effect on mortality"); for (int i = 0; i < 32; i++) { this.survival_chance[i] = 0.1; } this.survival_chance[0] = 1; this.survival_chance[1] = 0.4; this.survival_chance[2] = 0.2; metaExperiment(); log("Dysergetic epistasis: mutations have diminishing effect on mortality"); for (int i = 0; i < 32; i++) { this.survival_chance[i] = 1 / (i + 1); } metaExperiment(); log("Snenergetic epistasis: mutations have an increasingly negative effect on mortality"); for (int i = 0; i < 32; i++) { this.survival_chance[i] = (i < 16) ? 1.0 : 0.0; } metaExperiment(); log("Snenergetic epistasis: mutations have an increasingly negative effect on mortality"); for (int i = 0; i < 32; i++) { this.survival_chance[i] = 1.0 - i / 33.0; } metaExperiment(); } private void metaExperiment() { this.sex = false; experiment("Asexual"); this.sex = true; experiment("Sexual"); log("-----"); } private void experiment(String name) { log(name + " experiment"); init(); do { iterate(); } while (this.time < this.generation_max); printStats(); } private void init() { this.total_lifespan = 0; this.total_mutations_at_birth = 0; this.total_deaths = 0; this.time = 0; this.population = new int[this.pop_size]; this.time_at_birth = new int[this.pop_size]; } private void iterate() { mutateAll(); selectionAll(); this.time++; } private void selectionAll() { for (int idx = this.pop_size; --idx >= 0;) { selection(idx); } } private void selection(int idx) { int total_bits = countBits(getMember(idx)); double probability = this.random.nextDouble(); if (this.survival_chance[total_bits] < probability) { deathAndReproduce(idx); } } private void deathAndReproduce(int idx) { death(idx); reproduction(idx); } private void reproduction(int idx) { this.population[idx] = reproduce(); this.time_at_birth[idx] = this.time; this.total_mutations_at_birth += countBits(getMember(idx)); } private int reproduce() { int parent_1 = chooseIndividualAtRandom(); if (this.sex) { return sexual(parent_1); } return getMember(parent_1); } private int getMember(int parent_1) { return this.population[parent_1]; } private int sexual(int parent_1) { int bit_mask_maternal = this.random.nextInt(); int bit_mask_paternal = (-1 ^ bit_mask_maternal); int parent_2 = chooseIndividualAtRandom(); int genes_maternal = getMember(parent_1) & bit_mask_maternal; int genes_paternal = getMember(parent_2) & bit_mask_paternal; return genes_maternal | genes_paternal; } private void death(int idx) { this.total_deaths++; this.total_lifespan += this.time - this.time_at_birth[idx]; } private int chooseIndividualAtRandom() { // using "*" is poor style - but is good enough here... return (int) (this.random.nextFloat() * this.pop_size); } private void mutateAll() { for (int idx = this.mutation_attempts_per_generation; --idx >= 0;) { simulateCosmicRays(); } } private void simulateCosmicRays() { if (this.random.nextFloat() < this.mutation_rate) { mutate(chooseIndividualAtRandom()); } } private void mutate(int idx) { int bit_mask = 1 << (this.random.nextInt() & 31); this.population[idx] ^= bit_mask; } private void printStats() { log("Deaths: " + this.total_deaths + " - Average lifespan:" + (this.total_lifespan / (float)this.total_deaths)); int bits = 0; for (int idx = this.pop_size; --idx >= 0;) { bits += countBits(getMember(idx)); } log("Average mutations at birth:" + (this.total_mutations_at_birth / (float)this.total_deaths)); log("Average mutations per individual at end of run:" + (bits / (float)this.pop_size)); } private void log(String s) { System.out.println(s); } private int countBits(int value) { int bit_count = 0; for (int idx = 32; --idx >= 0;) { int bit_mask = 1 << idx; if ((value & bit_mask) != 0) { bit_count++; } } return bit_count; } public static void main(String args[]) { new GeneRepair().main(); } }