Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
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.