Package Bio :: Package GA :: Module Organism
[hide private]
[frames] | no frames]

Source Code for Module Bio.GA.Organism

  1  """Deal with an Organism in a Genetic Algorithm population. 
  2  """ 
  3  # standard modules 
  4  import sys  # for Python 3 hack 
  5  import random 
  6  import array 
  7   
  8  # Sequence objects from Biopython 
  9  from Bio.Seq import MutableSeq 
 10   
 11   
12 -def function_population(new_genome, num_organisms, fitness_calculator):
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 # a random number generator to get letters for the genome 55 letter_rand = random.Random() 56 57 # figure out what type of characters are in the alphabet 58 if isinstance(genome_alphabet.letters[0], str): 59 if sys.version_info[0] == 3: 60 alphabet_type = "u" # Use unicode string on Python 3 61 else: 62 alphabet_type = "c" # Use byte string on Python 2 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 # generate the genome randomly 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 # add the new organism with this genome 80 all_orgs.append(Organism(new_genome, fitness_calculator)) 81 82 return all_orgs
83 84
85 -class Organism(object):
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 # calculate the fitness of the genome 121 if start_fitness is None: 122 self.fitness = self._fitness_calc(self.genome) 123 else: 124 self.fitness = start_fitness
125
126 - def __str__(self):
127 """Provide a string output for debugging. 128 """ 129 return "Genome: %s; Fitness %s" % (str(self.genome), self.fitness)
130
131 - def __eq__(self, other):
132 """Compare organisms by their genomes (as strings of letters). 133 """ 134 # See Bio/Seq.py and the comments there about shifting to 135 # using simple string equality. Previously Seq objects used 136 # object equality, while MutableSeq objects used alphabet 137 # aware string equality. 138 return str(self.genome) == str(other.genome)
139
140 - def __ne__(self, other):
141 """Compare organisms by their genomes (as strings of letters). 142 """ 143 return str(self.genome) != str(other.genome)
144
145 - def __lt__(self, other):
146 """Compare organisms by their genomes (as strings of letters). 147 """ 148 return str(self.genome) < str(other.genome)
149
150 - def __le__(self, other):
151 """Compare organisms by their genomes (as strings of letters). 152 """ 153 return str(self.genome) <= str(other.genome)
154
155 - def __gt__(self, other):
156 """Compare organisms by their genomes (as strings of letters). 157 """ 158 return str(self.genome) > str(other.genome)
159
160 - def __ge__(self, other):
161 """Compare organisms by their genomes (as strings of letters). 162 """ 163 return str(self.genome) >= str(other.genome)
164
165 - def copy(self):
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
173 - def recalculate_fitness(self):
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