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