Logo Search packages:      
Sourcecode: python-biopython version File versions  Download package

test_GACrossover.py

#!/usr/bin/env python
"""Tests different Genetic Algorithm crossover classes.
"""
# standard library
import unittest

# biopython
from Bio.Seq import MutableSeq
from Bio.Alphabet import SingleLetterAlphabet

# local stuff
from Bio.GA.Organism               import Organism
from Bio.GA.Crossover.General      import SafeFitnessCrossover
from Bio.GA.Crossover.GeneralPoint import GeneralPointCrossover
from Bio.GA.Crossover.GeneralPoint import InterleaveCrossover
from Bio.GA.Crossover.TwoPoint     import TwoPointCrossover
from Bio.GA.Crossover.Point        import SinglePointCrossover
from Bio.GA.Crossover.Uniform      import UniformCrossover


00021 class TestAlphabet(SingleLetterAlphabet):
    """Simple test alphabet.
    """
    letters = ["1", "2", "3"]

00026     def contains( self, oalpha ): return 1
    
def test_fitness(genome):
    """Simple class for calculating fitnesses.
    """
    seq_genome = genome.toseq()
    return int(seq_genome.data)

00034 class SinglePointTest(unittest.TestCase):
    """Test simple point crossovers.
    """
    def setUp(self):
        self.alphabet = TestAlphabet()
        genome_1 = MutableSeq("11111", self.alphabet)
        self.org_1 = Organism(genome_1, test_fitness)

        genome_2 = MutableSeq("22222", self.alphabet)
        self.org_2 = Organism(genome_2, test_fitness)
        
        self.crossover  = SinglePointCrossover(1.0)
      
00047     def test_basic_crossover(self):
        """Test basic point crossover functionality.
        """
        start_genome_1 = self.org_1.genome[:]
        start_genome_2 = self.org_2.genome[:]
        
        new_org_1, new_org_2 = self.crossover.do_crossover(self.org_1,
                                                     self.org_2)

        assert new_org_1.genome != start_genome_1 and \
               new_org_2.genome != start_genome_2, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_2 != self.org_2, \
               "Returned an exact copy of the original organism."

00063 class UniformTest(unittest.TestCase):
    """Test simple point crossovers.
    """
    def setUp(self):
        self.alphabet = TestAlphabet()
        genome_1 = MutableSeq("11111111", self.alphabet)
        self.org_1 = Organism(genome_1, test_fitness)

        genome_2 = MutableSeq("22222222", self.alphabet)
        self.org_2 = Organism(genome_2, test_fitness)
        
      genome_3 = MutableSeq("333", self.alphabet)
      self.org_3 = Organism(genome_3, test_fitness)
      
        self.crossover = UniformCrossover(1.0, 0.8)

00079     def test_basic_crossover(self):
        """Test basic uniform crossover functionality.
        """
        start_genome_1 = self.org_1.genome[:]
        start_genome_2 = self.org_2.genome[:]
        
        new_org_1, new_org_2 = self.crossover.do_crossover(self.org_1,
                                                           self.org_2)

        assert new_org_1.genome != start_genome_1 and \
               new_org_2.genome != start_genome_2, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_2 != self.org_2, \
               "Returned an exact copy of the original organism."
      return

00096     def test_ds_prop_uniform_crossover(self):
      """Test properties of differing genome length, uniform crossovers.
      """
        new_org_1, new_org_2 = self.crossover.do_crossover(self.org_1,
                                                     self.org_3)


      assert len(new_org_1.genome) > len(new_org_2.genome), \
             "Strings are of wrong sizes after uniform crossover."

        assert new_org_2.genome.tostring().count("1") ==  \
             new_org_1.genome.tostring().count("3"),    \
             "There should be equal distributions of the smaller string"

      assert self.org_1.genome[len(new_org_2.genome):] == \
             new_org_1.genome[len(new_org_2.genome):], \
             "Uniform should not touch non-overlapping elements of genome"
      return
00114     def test_ss_prop_uniform_crossover(self):
      """Test properties of equal genome length, uniform crossovers.
      """
        new_org_1, new_org_2 = self.crossover.do_crossover(self.org_1,
                                                     self.org_2)


      assert len(new_org_1.genome) == len(new_org_2.genome), \
             "Strings are of different sizes after symmetric crossover."

        assert new_org_1.genome.tostring().count("1") ==  \
             new_org_2.genome.tostring().count("2") and \
             new_org_1.genome.tostring().count("2") ==  \
             new_org_2.genome.tostring().count("1"),    \
             "There should be equal, inverse distributions"
      return

00131 class InterleaveTest(unittest.TestCase):
    """Test 'simple' 4-point crossovers.
    """
    def setUp(self):
        self.alphabet = TestAlphabet()
        genome_1 = MutableSeq("11111", self.alphabet)
        self.org_1 = Organism(genome_1, test_fitness)

        genome_2 = MutableSeq("22222", self.alphabet)
        self.org_2 = Organism(genome_2, test_fitness)
        
        genome_3 = MutableSeq("333333333", self.alphabet)
        self.org_3 = Organism(genome_3, test_fitness)
        
      self._crossover  = InterleaveCrossover(1.0)

00147     def test_basic_crossover(self):
        """Test basic interleave crossover functionality.
        """
        start_genome_1 = self.org_1.genome[:]
        start_genome_2 = self.org_2.genome[:]
        
        new_org_1, new_org_2 = self._crossover.do_crossover(self.org_1,
                                                          self.org_2)

      assert new_org_1.genome != start_genome_1 and \
               new_org_2.genome != start_genome_2, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_2 != self.org_2, \
               "Returned an exact copy of the original organism."
      return
             
00164     def test_prop_sym_crossover(self):
      """Test properties of interleave point crossover.
      """
        new_org_1, new_org_2 = self._crossover.do_crossover(self.org_1,
                                                    self.org_2)

      assert len(new_org_1.genome) == len(new_org_2.genome), \
             "Strings are of different sizes after symmetric crossover."

        assert new_org_1.genome.tostring().count("1" ) ==  \
             new_org_2.genome.tostring().count("2" ) and \
             new_org_1.genome.tostring().count("2" ) ==  \
             new_org_2.genome.tostring().count("1" ),    \
             "There should be equal, inverse distributions"
             
      assert new_org_1.genome.tostring() == "12121" and  \
             new_org_2.genome.tostring() == "21212",     \
             "Did not interleave."
             
      return

00185     def test_prop_asym_crossover(self):
      """Test basic interleave crossover with asymmetric genomes.
      """
        start_genome_1 = self.org_1.genome[:]
        start_genome_3 = self.org_3.genome[:]

      new_org_1, new_org_3 = self._crossover.do_crossover(self.org_1,
                                                          self.org_3)
      
      assert new_org_1.genome != start_genome_1 and \
               new_org_3.genome != start_genome_3, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_3 != self.org_3, \
               "Returned an exact copy of the original organism."
             
      assert new_org_1.genome.tostring() == "13131" and  \
             new_org_3.genome.tostring() == "31313333",  \
             "Did not interleave with growth."
      return
    
00206 class FourPointTest(unittest.TestCase):
    """Test 'simple' 4-point crossovers.
    """
    def setUp(self):
        self.alphabet = TestAlphabet()
        genome_1 = MutableSeq("11111", self.alphabet)
        self.org_1 = Organism(genome_1, test_fitness)

        genome_2 = MutableSeq("22222", self.alphabet)
        self.org_2 = Organism(genome_2, test_fitness)
        
      self.sym_crossover  = GeneralPointCrossover(3,1.0)
      self.asym_crossover = GeneralPointCrossover(4,1.0)
      
00220     def test_basic_crossover(self):
        """Test basic 4-point crossover functionality.
        """
        start_genome_1 = self.org_1.genome[:]
        start_genome_2 = self.org_2.genome[:]
        
        new_org_1, new_org_2 = self.sym_crossover.do_crossover(self.org_1,
                                                             self.org_2)

      assert new_org_1.genome != start_genome_1 and \
               new_org_2.genome != start_genome_2, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_2 != self.org_2, \
               "Returned an exact copy of the original organism."
      return
             
00237     def test_prop_sym_crossover(self):
      """Test properties of symmetric 4-point crossover.
      """
        new_org_1, new_org_2 = self.sym_crossover.do_crossover(self.org_1,
                                                             self.org_2)

      assert len(new_org_1.genome) == len(new_org_2.genome), \
             "Strings are of different sizes after symmetric crossover."

      
        assert new_org_1.genome.tostring().count("1") ==  \
             new_org_2.genome.tostring().count("2") and \
             new_org_1.genome.tostring().count("2") ==  \
             new_org_2.genome.tostring().count("1"),    \
             "There should be equal, inverse distributions"
             
      return
    
00255     def test_basic_asym_crossover(self):
        """Test basic asymmetric 2-point crossover functionality.
        """
        start_genome_1 = self.org_1.genome[:]
        start_genome_2 = self.org_2.genome[:]
        
        new_org_1, new_org_2 = self.asym_crossover.do_crossover(self.org_1,
                                                              self.org_2)

        assert new_org_1.genome != start_genome_1 and \
               new_org_2.genome != start_genome_2, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_2 != self.org_2, \
               "Returned an exact copy of the original organism."

      return
    
    
00274 class TwoPointTest(unittest.TestCase):
    """Test simple 2-point crossovers.
    """
    def setUp(self):
        self.alphabet = TestAlphabet()
        genome_1 = MutableSeq("11111111", self.alphabet)
        self.org_1 = Organism(genome_1, test_fitness)

        genome_2 = MutableSeq("22222222", self.alphabet)
        self.org_2 = Organism(genome_2, test_fitness)
        
      self.asym_crossover = TwoPointCrossover(1.0)

00287     def test_basic_asym_crossover(self):
        """Test basic asymmetric 2-point crossover functionality.
        """
        start_genome_1 = self.org_1.genome[:]
        start_genome_2 = self.org_2.genome[:]
        
        new_org_1, new_org_2 = self.asym_crossover.do_crossover(self.org_1,
                                                              self.org_2)

        assert new_org_1.genome != start_genome_1 and \
               new_org_2.genome != start_genome_2, \
               "Did not perform a crossover when expected."

        assert new_org_1 != self.org_1 and new_org_2 != self.org_2, \
               "Returned an exact copy of the original organism."

      return
    
00305 class TestCrossover:
    """Provide basic crossover functionality for testing SafeFitness.
    """
    def __init__(self):
        # whether or not to produce new organisms with lower fitness
        # higher fitness, or the same organism
        self.type = "lower"

    def do_crossover(self, org_1, org_2):
        seq_org1 = org_1.genome.toseq()
        seq_org2 = org_2.genome.toseq()
        org1_genome = seq_org1.data
        org2_genome = seq_org2.data

        new_org_1 = org_1.copy()
        new_org_2 = org_2.copy()
        
        if self.type == "same":
            return new_org_1, new_org_2
        elif self.type == "lower":
            new_org1_genome = str(int(org1_genome) - 1)
            new_org2_genome = str(int(org2_genome) - 1)

            new_org_1.genome = MutableSeq(new_org1_genome,
                                          org_1.genome.alphabet)
            new_org_2.genome = MutableSeq(new_org2_genome,
                                          org_2.genome.alphabet)
        elif self.type == "higher":
            new_org1_genome = str(int(org1_genome) + 1)
            new_org2_genome = str(int(org2_genome) + 1)
        else:
            raise ValueError("Got type %s" % self.type)

        new_org_1.genome = MutableSeq(new_org1_genome,
                                      org_1.genome.alphabet)
        new_org_2.genome = MutableSeq(new_org2_genome,
                                      org_2.genome.alphabet)

        return new_org_1, new_org_2
                
00345 class SafeFitnessTest(unittest.TestCase):
    """Tests for crossovers which do not reduce fitness.
    """
    def setUp(self):
        self.alphabet = TestAlphabet()
        genome_1 = MutableSeq("2", self.alphabet)
        self.org_1 = Organism(genome_1, test_fitness)

        genome_2 = MutableSeq("2", self.alphabet)
        self.org_2 = Organism(genome_2, test_fitness)

        self.test_crossover = TestCrossover()

00358     def test_keep_higher(self):
        """Make sure we always keep higher fitness when specified.
        """
        crossover = SafeFitnessCrossover(self.test_crossover)

        self.test_crossover.type = "same"
        new_org_1, new_org_2 = crossover.do_crossover(self.org_1, self.org_2)

        assert (new_org_1 == self.org_1 and new_org_2 == self.org_2), \
               "Did not retain organism for same fitness."

        self.test_crossover.type = "lower"
        new_org_1, new_org_2 = crossover.do_crossover(self.org_1, self.org_2)

        assert (new_org_1 == self.org_1 and new_org_2 == self.org_2), \
               "Did not retain organism when crossover had lower fitness."

        self.test_crossover.type = "higher"
        new_org_1, new_org_2 = crossover.do_crossover(self.org_1, self.org_2)

        assert (new_org_1.fitness > self.org_1.fitness and
                new_org_2.fitness > self.org_2.fitness), \
                "Did not get new organism when it had higher fitness."

00382     def test_keep_lower(self):
        """Make sure we do normal crossover functionality when specified.
        """
        crossover = SafeFitnessCrossover(self.test_crossover, 1.0)

        self.test_crossover.type = "same"
        new_org_1, new_org_2 = crossover.do_crossover(self.org_1, self.org_2)

        assert (new_org_1 == self.org_1 and new_org_2 == self.org_2), \
               "Did not retain organism for same fitness."

        self.test_crossover.type = "lower"
        new_org_1, new_org_2 = crossover.do_crossover(self.org_1, self.org_2)

        assert (new_org_1 != self.org_1 and new_org_2 != self.org_2), \
               "Did not retain lower fitness organism in crossover."

        self.test_crossover.type = "higher"
        new_org_1, new_org_2 = crossover.do_crossover(self.org_1, self.org_2)

        assert (new_org_1.fitness > self.org_1.fitness and
                new_org_2.fitness > self.org_2.fitness), \
                "Did not get new organism under higher fitness conditions."

if __name__ == "__main__":
    runner = unittest.TextTestRunner(verbosity = 2)
    unittest.main(testRunner=runner)

Generated by  Doxygen 1.6.0   Back to index