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