1 """Deal with an Organism in a Genetic Algorithm population.
2 """
3
4 import random
5 import array
6
7
8 from Bio.Seq import MutableSeq
9
11 """Generate a population given a function to create genomes
12
13 Arguments:
14
15 o new_genome - A function or callable object that will return
16 a genome that can be used for a new organism. This new genome
17 should be a MutableSeq object with a specified alphabet.
18
19 o num_organisms - The number of individuals we want in the population.
20
21 o fitness_calculator -- A funtion that will calculate the fitness
22 of the organism when given the organisms genome.
23 """
24 all_orgs = []
25
26 for org_num in range(num_organisms):
27 cur_genome = new_genome()
28 all_orgs.append(Organism(cur_genome, fitness_calculator))
29
30 return all_orgs
31
32 -def random_population(genome_alphabet, genome_size, num_organisms,
33 fitness_calculator):
34 """Generate a population of individuals with randomly set genomes.
35
36 Arguments:
37
38 o genome_alphabet -- An Alphabet object describing all of the
39 possible letters that could potentially be in the genome of an
40 organism.
41
42 o genome_size -- The size of each organisms genome.
43
44 o num_organism -- The number of organisms we want in the population.
45
46 o fitness_calculator -- A funtion that will calculate the fitness
47 of the organism when given the organisms genome.
48 """
49 all_orgs = []
50
51
52 letter_rand = random.Random()
53
54
55 if type(genome_alphabet.letters[0]) == type("A"):
56 alphabet_type = "c"
57 elif type(genome_alphabet.letters[0]) == type(1):
58 alphabet_type = "i"
59 elif type(genome_alphabet.letters[0]) == type(1.0):
60 alphabet_type = "d"
61 else:
62 raise ValueError("Alphabet type is unsupported: %s" % alphabet.letters)
63
64 for org_num in range(num_organisms):
65 new_genome = MutableSeq(array.array(alphabet_type), genome_alphabet)
66
67
68 for gene_num in range(genome_size):
69 new_gene = letter_rand.choice(genome_alphabet.letters)
70 new_genome.append(new_gene)
71
72
73 all_orgs.append(Organism(new_genome, fitness_calculator))
74
75 return all_orgs
76
78 """Represent a single individual in a population.
79
80 Attributes:
81
82 o genome -- The genome of the organism. This is a Bio.MutableSeq
83 object that has the sequence of the genome, and the alphabet
84 describing all elements that can be a part of the genome.
85
86 o fitness -- The calculate fitness of the organism. This fitness is
87 based on the last time it was calculated using the fitness_calculator.
88 So... the fitness could potentially be out of date with the real genome
89 if you are not careful to recalculate it after changes with
90 recalculate_fitness()
91 """
92 - def __init__(self, genome, fitness_calculator, start_fitness = None):
93 """Initialize an organism
94
95 Arguments:
96
97 o genome -- A MutableSeq object representing the sequence of the
98 genome.
99
100 o fitness_calculator -- A funtion that will calculate the fitness
101 of the organism when given the organisms genome.
102
103 o start_fitness - the starting fitness corresponding with the
104 given genome. If not supplied, the fitness will be calculated
105 using fitness_calculator.
106 """
107 assert isinstance(genome, MutableSeq), "Genome must be a MutableSeq"
108
109 self.genome = genome
110 self._fitness_calc = fitness_calculator
111
112
113 if start_fitness is None:
114 self.fitness = self._fitness_calc(self.genome)
115 else:
116 self.fitness = start_fitness
117
119 """Provide a string output for debugging.
120 """
121 return "Genome: %s; Fitness %s" % (self.genome.data, self.fitness)
122
124 """Define comparisons for organisms.
125
126 Compare organisms by their genomes.
127 """
128 return cmp(self.genome, other.genome)
129
131 """Return a copy of the organism.
132
133 This makes it easy to duplicate an organism before changing it.
134 """
135 copy_genome = self.genome[:]
136 return Organism(copy_genome, self._fitness_calc, self.fitness)
137
139 """Calculate and reset the fitness of the current genome
140
141 This should be called after the genome is updated to ensure that
142 fitness always stays in sync with the current genome.
143 """
144 self.fitness = self._fitness_calc(self.genome)
145