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

195 lines (156 sloc) 6.746 kb
#!/usr/bin/env python
"""Tests for Genetic Algorithm mutation functionality.
"""
# 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.Mutation.General import SafeFitnessMutation
from Bio.GA.Mutation.Simple import ConversionMutation
from Bio.GA.Mutation.Simple import SinglePositionMutation
class TestAlphabet(SingleLetterAlphabet):
"""Simple test alphabet.
"""
letters = ["1", "2", "3"]
def test_fitness(genome):
"""Simple class for calculating fitnesses.
"""
seq_genome = genome.toseq()
return int(str(seq_genome))
class MutationHelper:
"""Mixin class which provides useful functions for testing mutations.
"""
num_trials = 500
def _always_mutate(self, mutator, expected_percent):
"""Test the ability of a mutator to always mutate.
Arguments:
o mutator - The mutation class we're testing.
o expected_percent - The minimum percent of mutations we expect
to see under 'always mutate.' This will depend on how many letters
are in the alphabet and other factors.
"""
num_mutations = 0
for trial in range(self.num_trials):
new_org = mutator.mutate(self.organism)
# if we see a visilble mutation, mark it down
if new_org != self.organism:
num_mutations += 1
percent_mutants = float(num_mutations) / float(self.num_trials)
assert percent_mutants > expected_percent, \
"Did not recieve an acceptable number of mutations."
def _never_mutate(self, mutator):
"""Test that a mutator does not cause unexpected mutations.
"""
for trial in range(self.num_trials):
new_org = mutator.mutate(self.organism)
assert new_org == self.organism, "Unexpected mutation found"
class ConversionTest(unittest.TestCase, MutationHelper):
"""Test mutation which just converts one gene in the chromosome.
"""
def setUp(self):
genome = MutableSeq("1111", TestAlphabet())
self.organism = Organism(genome, test_fitness)
def test_always_mutate(self):
"""Test ability to cause mutations.
"""
mutator = ConversionMutation(mutation_rate = 1.0)
# when we mutate randomly by chance, we expect to get 2/3
# visible mutations (there are three letters in the alphabet and
# one change cannot be observed since it is a mutation back to itself)
# For a four letter genome, the chance of being exactly the same
# after mutations is about .01, so being better than 90% different
# if a reasonable expectation.
expected_percent = .9
self._always_mutate(mutator, expected_percent)
def test_never_mutate(self):
"""Make sure we do not mutate at unexpected times.
"""
mutator = ConversionMutation(mutation_rate = 0.0)
self._never_mutate(mutator)
class SinglePositionTest(unittest.TestCase, MutationHelper):
"""Test mutations at a single position in a genome.
"""
def setUp(self):
genome = MutableSeq("1111", TestAlphabet())
self.organism = Organism(genome, test_fitness)
def test_always_mutate(self):
"""Test ability to cause mutations.
"""
mutator = SinglePositionMutation(mutation_rate = 1.0)
# when we mutate randomly by chance, we expect to get 2/3
# visible mutations (there are three letters in the alphabet and
# one change cannot be observed since it is a mutation back to itself)
expected_percent = .6
self._always_mutate(mutator, expected_percent)
def test_never_mutate(self):
"""Make sure we do not mutate at unexpected times.
"""
mutator = SinglePositionMutation(mutation_rate = 0.0)
self._never_mutate(mutator)
class TestMutator:
"""Provide basic mutator ability.
"""
def __init__(self):
self.type = "lower"
def mutate(self, org):
org_genome_seq = org.genome.toseq()
old_org_genome = str(org_genome_seq)
new_org = org.copy()
if self.type == "same":
return new_org
elif self.type == "lower":
new_org.genome = MutableSeq(str(int(old_org_genome) - 1),
org_genome_seq.alphabet)
return new_org
elif self.type == "higher":
new_org.genome = MutableSeq(str(int(old_org_genome) + 1),
org_genome_seq.alphabet)
return new_org
else:
raise ValueError("Got type %s" % self.type)
class SafeFitnessTest(unittest.TestCase):
"""Test mutation which does not allow decreases in fitness.
"""
def setUp(self):
self.alphabet = TestAlphabet()
genome = MutableSeq("2", self.alphabet)
self.org = Organism(genome, test_fitness)
self.test_mutator = TestMutator()
def test_keep_higher(self):
"""Make sure we always keep the higher fitness.
"""
mutator = SafeFitnessMutation(self.test_mutator)
self.test_mutator.type = "same"
new_org = mutator.mutate(self.org)
assert (new_org == self.org), \
"Did not retain organism for same fitness."
self.test_mutator.type = "lower"
new_org = mutator.mutate(self.org)
assert (new_org == self.org), \
"Did not retain organism when crossover had lower fitness."
self.test_mutator.type = "higher"
new_org = mutator.mutate(self.org)
assert (new_org.fitness > self.org.fitness), \
"Did not get new organism when it had higher fitness."
def test_keep_new(self):
"""Make sure we always keep the new organism when specified.
"""
mutator = SafeFitnessMutation(self.test_mutator, 1.0)
self.test_mutator.type = "same"
new_org = mutator.mutate(self.org)
assert (new_org == self.org), \
"Did not retain organism for same fitness."
self.test_mutator.type = "lower"
new_org = mutator.mutate(self.org)
assert (new_org.fitness < self.org.fitness), \
"Did not get new organism when it had lower fitness."
self.test_mutator.type = "higher"
new_org = mutator.mutate(self.org)
assert (new_org.fitness > self.org.fitness), \
"Did not get new organism under higher fitness conditions."
if __name__ == "__main__":
runner = unittest.TextTestRunner(verbosity = 2)
unittest.main(testRunner=runner)
Jump to Line
Something went wrong with that request. Please try again.