Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

423 lines (320 sloc) 15.481 kb
#!/usr/bin/env python
"""Tests different Genetic Algorithm crossover classes.
"""
# standard library
import sys
import string
# biopython
from Bio.Seq import MutableSeq
# 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
# PyUnit
import unittest
def run_tests(argv):
ALL_TESTS = [SinglePointTest, FourPointTest, InterleaveTest,
TwoPointTest, UniformTest, SafeFitnessTest]
runner = unittest.TextTestRunner(sys.stdout, verbosity = 2)
test_loader = unittest.TestLoader()
test_loader.testMethodPrefix = 't_'
for test in ALL_TESTS:
cur_suite = test_loader.loadTestsFromTestCase(test)
runner.run(cur_suite)
class TestAlphabet:
"""Simple test alphabet.
"""
letters = ["1", "2", "3"]
def contains( self, oalpha ): return 1
def test_fitness(genome):
"""Simple class for calculating fitnesses.
"""
seq_genome = genome.toseq()
return int(seq_genome.data)
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)
def t_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."
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)
def t_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
def t_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 string.count( new_org_2.genome.tostring(), "1" ) == \
string.count( new_org_1.genome.tostring(), "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
def t_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 string.count( new_org_1.genome.tostring(), "1" ) == \
string.count( new_org_2.genome.tostring(), "2" ) and \
string.count( new_org_1.genome.tostring(), "2" ) == \
string.count( new_org_2.genome.tostring(), "1" ), \
"There should be equal, inverse distributions"
return
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)
def t_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
def t_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 string.count( new_org_1.genome.tostring(), "1" ) == \
string.count( new_org_2.genome.tostring(), "2" ) and \
string.count( new_org_1.genome.tostring(), "2" ) == \
string.count( new_org_2.genome.tostring(), "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
def t_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
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)
def t_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
def t_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 string.count( new_org_1.genome.tostring(), "1" ) == \
string.count( new_org_2.genome.tostring(), "2" ) and \
string.count( new_org_1.genome.tostring(), "2" ) == \
string.count( new_org_2.genome.tostring(), "1" ), \
"There should be equal, inverse distributions"
return
def t_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
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)
def t_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
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
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()
def t_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."
def t_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__":
sys.exit(run_tests(sys.argv))
Jump to Line
Something went wrong with that request. Please try again.