Back to index

python-biopython  1.60
test_GASelection.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # This code is part of the Biopython distribution and governed by its
00003 # license.  Please see the LICENSE file that should have been included
00004 # as part of this package.
00005 
00006 """Tests for Genetic Algorithm classes that provide selection capabilities.
00007 """
00008 # standard library
00009 import random
00010 import unittest
00011 
00012 # biopython
00013 from Bio.Seq import MutableSeq
00014 from Bio.Alphabet import SingleLetterAlphabet
00015 
00016 # local stuff
00017 from Bio.GA.Organism import Organism
00018 from Bio.GA.Selection.Diversity import DiversitySelection
00019 from Bio.GA.Selection.Tournament import TournamentSelection
00020 from Bio.GA.Selection.RouletteWheel import RouletteWheelSelection
00021 
00022 
00023 # --- helper classes and functions
00024 
00025 class TestAlphabet(SingleLetterAlphabet):
00026     """Simple test alphabet.
00027     """                        
00028     letters = ["0", "1", "2", "3"]
00029 
00030 def test_fitness(genome):
00031     """Simple class for calculating fitnesses.
00032     """
00033     genome_seq = genome.toseq()
00034     return int(genome_seq.tostring())
00035 
00036 class NoSelection:
00037     """A simple 'selection' class that just returns the generated population.
00038     """
00039     def select(self, population):
00040         return population
00041 
00042 class NoMutation:
00043     """Simple 'mutation' class that doesn't do anything.
00044     """
00045     def mutate(self, org):
00046         return org.copy()
00047 
00048 class NoCrossover:
00049     """Simple 'crossover' class that doesn't do anything.
00050     """
00051     def do_crossover(self, org_1, org_2):
00052         return org_1.copy(), org_2.copy()
00053 
00054 class NoRepair:
00055     """Simple 'repair' class that doesn't do anything.
00056     """
00057     def repair(self, org):
00058         return org.copy()
00059 
00060 def random_genome():
00061     """Return a random genome string.
00062     """
00063     alphabet = TestAlphabet()
00064 
00065     new_genome = ""
00066     for letter in range(3):
00067         new_genome += random.choice(alphabet.letters)
00068 
00069     return MutableSeq(new_genome, alphabet)
00070 
00071 def random_organism():
00072     """Generate a random organism.
00073     """
00074     genome = random_genome()
00075     return Organism(genome, test_fitness)
00076 
00077 # --- the actual test classes
00078 
00079 class DiversitySelectionTest(unittest.TestCase):
00080     """Test selection trying to maximize diversity.
00081     """
00082     def setUp(self):
00083         self.selector = DiversitySelection(NoSelection(), random_genome)
00084 
00085     def test_get_new_organism(self):
00086         """Getting a new organism not in the new population.
00087         """
00088         org = random_organism()
00089         old_pop = [org]
00090         new_pop = []
00091 
00092         new_org = self.selector._get_new_organism(new_pop, old_pop)
00093         self.assertEqual(new_org, org,
00094                          "Got an unexpected organism %s" % new_org)
00095 
00096     def test_no_retrieve_organism(self):
00097         """Test not getting an organism already in the new population.
00098         """
00099         org = random_organism()
00100         old_pop = [org]
00101         new_pop = [org]
00102 
00103         new_org = self.selector._get_new_organism(new_pop, old_pop)
00104         #assert new_org != org, "Got organism already in the new population."
00105         #TODO - Why was the above commented out?
00106 
00107     def test_selection(self):
00108         """Test basic selection on a small population.
00109         """
00110         pop = [random_organism() for org_num in range(50)]
00111 
00112         new_pop = self.selector.select(pop)
00113 
00114         self.assertEqual(len(new_pop), len(pop),
00115                          "Did not maintain population size.")
00116 
00117 class TournamentSelectionTest(unittest.TestCase):
00118     """Test selection based on a tournament style scheme.
00119     """
00120     def setUp(self):
00121         self.selector = TournamentSelection(NoMutation(), NoCrossover(),
00122                                             NoRepair(), 2)
00123 
00124     def test_select_best(self):
00125         """Ensure selection of the best organism in a population of 2.
00126         """
00127         #Create any two non equal organisms
00128         org_1 = random_organism()
00129         while True:
00130             org_2 = random_organism()
00131             if org_2.fitness != org_1.fitness:
00132                 break
00133         #Sort them so org_1 is most fit
00134         if org_2.fitness > org_1.fitness:
00135             org_1, org_2 = org_2, org_1
00136         self.assertTrue(org_1.fitness > org_2.fitness)
00137         
00138         pop = [org_1, org_2]
00139         new_pop = self.selector.select(pop)
00140         for org in new_pop:
00141             self.assertEqual(org, org_1,
00142                              "Got a worse organism selected.")
00143 
00144         #Just to make sure the selector isn't doing something
00145         #silly with the order, try this with the input reserved:
00146         pop = [org_2, org_1]
00147         new_pop = self.selector.select(pop)
00148         for org in new_pop:
00149             self.assertEqual(org, org_1,
00150                              "Got a worse organism selected.")
00151 
00152     def test_selection(self):
00153         """Test basic selection on a small population.
00154         """
00155         pop = [random_organism() for org_num in range(50)]
00156         new_pop = self.selector.select(pop)
00157 
00158         self.assertEqual(len(new_pop), len(pop),
00159                          "Did not maintain population size.")
00160 
00161 
00162 class RouletteWheelSelectionTest(unittest.TestCase):
00163     """Test selection using a roulette wheel selection scheme.
00164     """
00165     def setUp(self):
00166         self.selector = RouletteWheelSelection(NoMutation(), NoCrossover(),
00167                                                NoRepair())
00168 
00169     def test_select_best(self):
00170         """Ensure selection of a best organism in a population of 2.
00171         """
00172         worst_genome = MutableSeq("0", TestAlphabet())
00173         worst_org = Organism(worst_genome, test_fitness)
00174 
00175         better_genome = MutableSeq("1", TestAlphabet())
00176         better_org = Organism(better_genome, test_fitness)
00177 
00178         new_pop = self.selector.select([worst_org, better_org])
00179         for org in new_pop:
00180             self.assertEqual(org, better_org,
00181                              "Worse organism unexpectly selected.")
00182 
00183     def test_selection(self):
00184         """Test basic selection on a small population.
00185         """
00186         pop = [random_organism() for org_num in range(50)]
00187         new_pop = self.selector.select(pop)
00188 
00189         self.assertEqual(len(new_pop), len(pop),
00190                          "Did not maintain population size.")
00191 
00192         
00193 if __name__ == "__main__":
00194     runner = unittest.TextTestRunner(verbosity = 2)
00195     unittest.main(testRunner=runner)