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