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(\
63 "Alphabet type is unsupported: %s" % genome_alphabet.letters)
64
65 for org_num in range(num_organisms):
66 new_genome = MutableSeq(array.array(alphabet_type), genome_alphabet)
67
68
69 for gene_num in range(genome_size):
70 new_gene = letter_rand.choice(genome_alphabet.letters)
71 new_genome.append(new_gene)
72
73
74 all_orgs.append(Organism(new_genome, fitness_calculator))
75
76 return all_orgs
77
79 """Represent a single individual in a population.
80
81 Attributes:
82
83 o genome -- The genome of the organism. This is a Bio.MutableSeq
84 object that has the sequence of the genome, and the alphabet
85 describing all elements that can be a part of the genome.
86
87 o fitness -- The calculate fitness of the organism. This fitness is
88 based on the last time it was calculated using the fitness_calculator.
89 So... the fitness could potentially be out of date with the real genome
90 if you are not careful to recalculate it after changes with
91 recalculate_fitness()
92 """
93 - def __init__(self, genome, fitness_calculator, start_fitness = None):
94 """Initialize an organism
95
96 Arguments:
97
98 o genome -- A MutableSeq object representing the sequence of the
99 genome.
100
101 o fitness_calculator -- A funtion that will calculate the fitness
102 of the organism when given the organisms genome.
103
104 o start_fitness - the starting fitness corresponding with the
105 given genome. If not supplied, the fitness will be calculated
106 using fitness_calculator.
107 """
108 assert isinstance(genome, MutableSeq), "Genome must be a MutableSeq"
109
110 self.genome = genome
111 self._fitness_calc = fitness_calculator
112
113
114 if start_fitness is None:
115 self.fitness = self._fitness_calc(self.genome)
116 else:
117 self.fitness = start_fitness
118
120 """Provide a string output for debugging.
121 """
122 return "Genome: %s; Fitness %s" % (self.genome.data, self.fitness)
123
125 """Define comparisons for organisms.
126
127 Compare organisms by their genomes (as strings of letters).
128 """
129
130
131
132
133 return cmp(str(self.genome), str(other.genome))
134
136 """Return a copy of the organism.
137
138 This makes it easy to duplicate an organism before changing it.
139 """
140 copy_genome = self.genome[:]
141 return Organism(copy_genome, self._fitness_calc, self.fitness)
142
144 """Calculate and reset the fitness of the current genome
145
146 This should be called after the genome is updated to ensure that
147 fitness always stays in sync with the current genome.
148 """
149 self.fitness = self._fitness_calc(self.genome)
150