a "generic" problem

Carl Banks imbosol at aerojockey.com
Wed Feb 12 17:39:45 EST 2003


Sean Ross wrote:
> ISSUE 1:
> "How do I construct new instances of a class
> when I do not know the name of that class?"

Short answer: you can pass the class as an argument to the
GeneticAlgorithm __init__.  To exemplify:

    class GeneticAlgorithm:
        def __init__(self,chromosome_class,anything_else)
            self.chromosome_class = chromosome_class
            ...
        def onepoint(self, p1, p2):
            pivot = random.randrange(self.gene.length)
            c1 = self.chromosome_class(p1.gene[:pivot] + p2.gene[pivot:])
            c2 = self.chromosome_class(p2.gene[:pivot] + p1.gene[pivot:])
            return c1, c2


Rather, I suggest another possibility: to make onepoint a method of
Chromosome, instead.

    class Chromosome:
        def onepoint(self,other):
            klass = self.__class__
            pivot = random.randrange(self.gene.length)
            c1 = klass(self.gene[:pivot] + other.gene[pivot:])
            c2 = klass(other.gene[:pivot] + self.gene[pivot:])
            return c1, c2


Have your subclasses of Chromosome define a method xover which calls
the approproate crossover function:

    class ShakespeareQuoteChromosome(Chromosome):
        def xover(self,other):
            return self.onepoint(other)


This saves you from having to pass xover into crossover.  Maybe it's
not versatile enough for your needs, though.



[snip]
> On a slightly different issue:
> My Chromosome class provides a staticmethod generatepool()
> That returns a list of randomly initialized Chromosomes to
> populate the GeneticAlgorithm's initial pool.
> 
> It looks like this:
> 
>    def generatepool(population=100):
>        return [Chromosome() for chromo in xrange(population)]
>    generatepool = staticmethod(generatepool)
> 
> Unfortunately, for each subclass of chromosome, I need to
> override this method, e.g.,
> 
>    def generatepool(population=100):
>        return [SubClassName() for chromo in xrange(population)]
>    generatepool = staticmethod(generatepool)
>
[snip]
>
> "How do I implement this method, so that I do not need to
> override it for each sublass?"

If you pass the chromosome subclass as an argument to
GeneticAlgorithm, as I demonstrated above, the answer is to just make
generatepool a method of GeneticAlgorithm.

    class GeneticAlgorithm:
        def generatepool(population=100):
            return [self.chromosome_class() for chromo in xrange(population)]

In fact, I think you should do this even if you take my advice and
make onepoint a method of Chromosome.  Generating a population is an
operation of the genetic algorithm, not of the Chromosome, and it
ought to be a method of GeneticAlgorithm.


However, if you insist on making generatepool a method of Chromosome,
you should make it a classmethod instead of a staticmethod:

    class Chromosome:
        def generatepool(klass,population=100):
            return [klass() for chromo in xrange(population)]
        generatepool = classmethod(generatepool)



> And, finally, the Chromosome class keeps two class variables:
>    Chromosome.alphabet and Chromosome.length
> 
[snip]
> 
> When I subclass the Chromosome class, I often need to change the
> value of these two variables to fit the specific problem.
> 
> For instance, I had one alphabet that looked like:
>    Chromosome.alphabet = ((0,1),(1,0),(0,0))
> And another that included all ascii characters.
> 
> Since I use these to generate random genes for my chromosomes in __init__(),
> I need to change their values before I create instances of my subclasses.
> 
> ISSUE 3:
>   "Is there a way to overide the value of a class variable of the super
> class
>    inside the inheriting class?"

Unless I misunderstand what you're asking, all you have to do is set
an attribute of the derived class, like so:

class Chromosome(object):
    alphabet = ()
    length = 0

class BaklavaRecipeChromosome(Chromosome):
    alphabet = ('honey', 'orange', 'lemon', 'garlic')

BaklavaRecipeChromosome.length = 20


The one question you should ask yourself is whether you really need
alphabet and length to be variables of Chromosome?  I would define
these only in my derived classes.


> Thanks for your help. If you require more examples, and/or the entire code,
> let me know.

You're welcome.  No, you did a good job at including just the right
amount of detail.  Only thing is, you should quote methods inside a
class definition, 'cause it's hard to figure out which class they
belong to.

I've done genetic algorithms in Python (genetic programming,
actually), and I've faced many of the design issues you have, so I
hope this advice helps.


-- 
CARL BANKS




More information about the Python-list mailing list