0

The evolve function is having problems as is the mutate one.

    from random import randint, random
    from operator import add
    from functools import reduce



   def individual(length, min, max):
        'Create a member of the population.'
        return [randint(min,max) for x in range(length)]


    def population(count, length, min, max):
        'Create a number of individuals (i.e. a population).'
        return [ individual(length, min, max) for x in range(count) ]


    def fitness(individual, target):
        'Determine the fitness of an individual. Lower is better.'
        sum = reduce(add, individual, 0)
        return abs(target-sum)


    def grade(pop, target):
        'Find average fitness for a population.'
        summed = reduce(add, (fitness(x, target) for x in pop), 0)
        return summed / (len(pop) * 1.0)


    chance_to_mutate = 0.01
    for i in p:
        if chance_to_mutate > random():
            place_to_modify = randint(0,len(i))
            i[place_to_modify] = randint(min(i), max(i))


    def evolve(pop, target, retain=0.2, random_select=0.05, mutate=0.01):
        graded = [(fitness(x, target), x) for x in pop]
        graded = [x[1] for x in sorted(graded)]
        retain_length = int(len(graded)*retain)
        parents = graded[:retain_length]

        # randomly add other individuals to promote genetic diversity
        for individual in graded[retain_length:]:
            if random_select > random():
                parents.append(individual)

        # mutate some individuals
        for individual in parents:
            if mutate > random():
                pos_to_mutate = randint(0, len(individual)-1)
                # this mutation is not ideal, because it
                # restricts the range of possible values,
                # but the function is unaware of the min/max
                # values used to create the individuals,
                individual[pos_to_mutate] = randint(
                    min(individual), max(individual))

        # crossover parents to create children
        parents_length = len(parents)
        desired_length = len(pop) - parents_length
        children = []
        while len(children) < desired_length:
            male = randint(0, parents_length-1)
            female = randint(0, parents_length-1)
            if male != female:
                male = parents[male]
                female = parents[female]
                half = len(male) / 2
                child = male[:half] + female[half:]
                children.append(child)

        parents.extend(children)
        return parents

    target = 371
    p_count = 100
    i_length = 5
    i_min = 0
    i_max = 100
    p = population(p_count, i_length, i_min, i_max)
    fitness_history = [grade(p, target),]
    for i in range(100):
        p = evolve(p, target)
        fitness_history.append(grade(p, target))

    for datum in fitness_history:
       print(datum)

I am following this website http://lethain.com/genetic-algorithms-cool-name-damn-simple/. It was written for Python 2.6 so it does not work for 3. I have updated it mostly but can't get it to work.

4
  • 1
    You're being close-voted; please see stackoverflow.com/help/how-to-ask and add enough details to your question so that people can help, like what doesn't work about it - what it should do, compared to what it actually does, and how we can test it. Commented Jun 23, 2015 at 19:21
  • There is no mutate function. Commented Jun 23, 2015 at 19:27
  • You may wish to save yourself some typing @TessellatingHeckler, if next time you type [ask] instead of stackoverflow.com/help/how-to-ask. Commented Jun 24, 2015 at 11:11
  • Thank you @boardrider, I'll try and remember that. (Although I didn't actually type it, I close-voted the question, and copied the link from the close vote, so I could comment with a bit of explanation). Commented Jun 25, 2015 at 13:54

1 Answer 1

3

The errors that the code caused should have been informative enough. The slicing done by:

male[:half] + female[half:] 

Was using half, which was a float at the time. The primary difference was:

half = int(len(male) / 2)

Which is likely the intended functionality. You cannot use floats to index an array, only ints.

Here is what it should be:

from random import randint, random
from functools import reduce
from operator import add
def individual(length, min, max):
    'Create a member of the population.'
    return [randint(min,max) for x in range(length)]


def population(count, length, min, max):
    'Create a number of individuals (i.e. a population).'
    return [ individual(length, min, max) for x in range(count) ]


def fitness(individual, target):
    'Determine the fitness of an individual. Lower is better.'
    sum = reduce(add, individual, 0)
    return abs(target-sum)


def grade(pop, target):
    'Find average fitness for a population.'
    summed = reduce(add, (fitness(x, target) for x in pop), 0)
    return summed / (len(pop) * 1.0)


def evolve(pop, target, retain=0.2, random_select=0.05, mutate=0.01):
    graded = [(fitness(x, target), x) for x in pop]
    graded = [x[1] for x in sorted(graded)]
    retain_length = int(len(graded)*retain)
    parents = graded[:retain_length]

# randomly add other individuals to promote genetic diversity
for individual in graded[retain_length:]:
    if random_select > random():
        parents.append(individual)

# mutate some individuals
for individual in parents:
    if mutate > random():
        pos_to_mutate = randint(0, len(individual)-1)
        # this mutation is not ideal, because it
        # restricts the range of possible values,
        # but the function is unaware of the min/max
        # values used to create the individuals,
        individual[pos_to_mutate] = randint(
            min(individual), max(individual))

# crossover parents to create children
parents_length = len(parents)
desired_length = len(pop) - parents_length
children = []
while len(children) < desired_length:
    male = randint(0, parents_length-1)
    female = randint(0, parents_length-1)
    if male != female:
        male = parents[male]
        female = parents[female]
        half = int(len(male) / 2)
        child = male[:half] + female[half:]
        children.append(child)

parents.extend(children)
return parents

target = 371
p_count = 100
i_length = 5
i_min = 0
i_max = 100
p = population(p_count, i_length, i_min, i_max)
fitness_history = [grade(p, target),]
chance_to_mutate = 0.01
for i in p:
    if chance_to_mutate > random():
        place_to_modify = randint(0,len(i))
        i[place_to_modify] = randint(min(i), max(i))
for i in range(100):
    p = evolve(p, target)
    fitness_history.append(grade(p, target))

for datum in fitness_history:
   print(datum)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.