// This program has been placed into the public domain by its author. import java.util.Random; public class GeneRepairPloidity { final int pop_size = 100; final int mutation_attempts_per_generation = this.pop_size * 6; Individual[] population; int[] time_at_birth; final float mutation_rate = 0.5f; final int generation_max = 8000; int genome_size = 32; int time; long total_lifespan; long total_expressed_defects_at_birth; long total_deaths; double[] survival_chance; boolean sex; int ploidity; 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("Synergetic 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("Synergetic 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 = true; this.ploidity = 1; experiment("Haploid"); this.ploidity = 2; experiment("Diploid"); this.ploidity = 3; experiment("Polyploid"); 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_expressed_defects_at_birth = 0; this.total_deaths = 0; this.time = 0; this.population = new Individual[this.pop_size]; for (int idx = this.pop_size; --idx >= 0;) { this.population[idx] = new Individual(this.genome_size, this.ploidity); } 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 = getMember(idx).countExpressedDefects(); 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_expressed_defects_at_birth += getMember(idx).countExpressedDefects(); } private Individual reproduce() { Individual mother = getMember(chooseIndividualAtRandom()); if (this.sex) { return sexual(mother); } return mother.asexual(); } private Individual getMember(int parent_1) { return this.population[parent_1]; } private Individual sexual(Individual mother) { Individual father = getMember(chooseIndividualAtRandom()); return mother.recombine(father); } private void death(int idx) { this.total_deaths++; this.total_lifespan += this.time - this.time_at_birth[idx]; } private int chooseIndividualAtRandom() { 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) { getMember(chooseIndividualAtRandom()).mutate(); } } private void printStats() { log("Total number of deaths: " + this.total_deaths); log("Average lifespan:" + (this.total_lifespan / (float) this.total_deaths)); log("Average expressed mutations at birth:" + (this.total_expressed_defects_at_birth / (float) this.total_deaths)); log("Average expressed mutations per individual at end of run:" + (getFinalExpressedDefectCount() / (float) this.pop_size)); } private int getFinalExpressedDefectCount() { int bits = 0; for (int idx = this.pop_size; --idx >= 0;) { bits += getMember(idx).countExpressedDefects(); } return bits; } private void log(String s) { System.out.println(s); } public static void main(String args[]) { new GeneRepairPloidity().main(); } } //---------------------------------------------------- class Individual { int ploidity; int genome_size; final float mutation_rate = 0.5f; ChromosomeSet[] chromosomes_sets; Random random = new Random(); Individual(int genome_size, int ploidity) { this.genome_size = genome_size; this.ploidity = ploidity; this.chromosomes_sets = new ChromosomeSet[this.ploidity]; for (int idx = this.ploidity; --idx >= 0;) { this.chromosomes_sets[idx] = new ChromosomeSet(this.genome_size); } } int countExpressedDefects() { int bit_count = 0; for (int idx = this.genome_size; --idx >= 0;) { if (allGenesAreDefectiveAtLocus(idx)) { bit_count++; } } return bit_count; } boolean allGenesAreDefectiveAtLocus(int i) { for (int idx = this.ploidity; --idx >= 0;) { if (!this.chromosomes_sets[idx].genome[i]) { return false; } } return true; } void mutate() { for (int idx = this.ploidity; --idx >= 0;) { if (this.random.nextFloat() > this.mutation_rate) { this.chromosomes_sets[idx].mutate(); } } } Individual asexual() { Individual i = new Individual(this.genome_size, this.ploidity); for (int idx = this.ploidity; --idx >= 0;) { i.chromosomes_sets[idx] = this.chromosomes_sets[idx].asexual(); } return i; } Individual recombine(Individual mate) { Individual i = new Individual(this.genome_size, this.ploidity); for (int idx = this.ploidity; --idx >= 0;) { int mc = (int)(this.random.nextFloat() * this.ploidity); int fc = (int)(this.random.nextFloat() * this.ploidity); ChromosomeSet cs_m = this.chromosomes_sets[mc]; ChromosomeSet cs_f = mate.chromosomes_sets[fc]; i.chromosomes_sets[idx] = cs_m.recombine(cs_f); } return i; } public String toString() { String s = ""; for (int idx = this.ploidity; --idx >= 0;) { s += " >> " + this.chromosomes_sets[idx]; } return s; } } //---------------------------------------------------- class ChromosomeSet { Random random = new Random(); boolean[] genome; ChromosomeSet(int genome_size) { this.genome = new boolean[genome_size]; } void mutate() { int gene_index = (int) (this.random.nextFloat() * this.genome.length); this.genome[gene_index] = !this.genome[gene_index]; } ChromosomeSet recombine(ChromosomeSet mate) { ChromosomeSet ni = new ChromosomeSet(this.genome.length); for (int idx = this.genome.length; --idx >= 0;) { boolean mother = (this.random.nextInt() & 1) == 0; ni.genome[idx] = mother ? this.genome[idx] : mate.genome[idx]; } return ni; } ChromosomeSet asexual() { ChromosomeSet ni = new ChromosomeSet(this.genome.length); for (int idx = this.genome.length; --idx >= 0;) { ni.genome[idx] = this.genome[idx]; } return ni; } public String toString() { String s = ""; for (int idx = this.genome.length; --idx >= 0;) { s += " " + this.genome[idx]; } return s; } }