DEAP1.2.2(七) 约束操作

(七) 约束操作
演化算法通常情况下是无约束的,在这部分中,我们提出了一些方法去约束你的进化算法,这个教程是基于Coello[Coello 2002]的文章展开的。

  1. Penalty Function
    罚函数是最基本的个体约束方法,当它们处于一个特定区间时,这些个体不可以被计算适应值或者在某些问题中会禁止它们的使用。罚函数根据约束变化的数量对这些个体给出了适应度的缺陷。例如,在一个变化的约束中计算个体适应度,可以对它的适应度指定一个期待的值。这个被指定的值可以是常数或者随着有效解的变化而变化。下面的图展示了一个个体属性的适应度函数g(x)(绿色)和一个罚函数h(x)(红色),约束条件为3< x < 7。连续的曲线代表个体真实的适应度


    f(x)
constraints.png

上图中,左边的那个在是当变量不服从约束时,使用了常量互补方法h(x)= \ Delta(简单粗暴,直接放入可行域?)。中间的使用欧氏距离与之前的h(x)相加,构成了一个碗形的function,h(x) = delta + sqrt((x-x_{0})^2)。最后一张图则使用了一个平方项来提升“碗”的深度,h(x) = delta + (x-x_{0})^2,x_0指的是可行域的中心。

在DEAP中,一个罚函数可以被添加到任何适应度函数当中,使用在tools中的DeltaPenalty装饰符就可以实现这个目标。罚函数使用两个强制参数和一个可选参数。第一个参数是一个可以根据用户定义的界限返回有效个体的函数,第二个是无效个体和有效区域间的距离。最后一个参数则默认为0。在下面的例子中,我们将会展示如何获得上图中最右图的效果。

from math import sin
import random
from deap import tools, base, creator

#creating individuals
IND_LEN = 2 #each individual's length
#creating maxfit
creator.create('MaxFit', base.Fitness, weights = (1.0,))
#creating individual
creator.create('Individual',list, fitness = creator.MaxFit)

#called toolbox
toolbox = base.Toolbox()
#define generating style
toolbox.register('fltrand', random.uniform, 0, 10)
#define individual
toolbox.register('individual',tools.initRepeat, creator.Individual, toolbox.fltrand ,n = IND_LEN)

#define population
toolbox.register('population', tools.initRepeat, list, toolbox.individual) 

pop = toolbox.population(n = 200)

#define evalute
def evalFct(individual):
    """Evaluation function for the individual."""
    x = individual[0]
    return (x - 5)**2 * sin(x) * (x/3),

def feasible(individual):
    """Feasibility function for the individual. Returns True if feasible False
    otherwise."""
    if 3 < individual[0] < 7:
        return True
    return False

def distance(individual):
    """A distance function to the feasibility region."""
    return (individual[0] - 5.0)**2

toolbox = base.Toolbox()
toolbox.register("evaluate", evalFct)
toolbox.decorate("evaluate", tools.DeltaPenalty(feasible, 7.0, distance))


toolbox.register('crossover', tools.cxTwoPoint)
toolbox.register('mutate', tools.mutFlipBit, indpb = 0.5)
toolbox.register('select', tools.selTournament, tournsize = 3)

def simpleEA():
    #paramenters
    CXPB = 0.1 #possiblity of crossover
    MUPB = 0.1 #possiblity of mutation
    GEN = 40   #iteration number
    GR_SIZE = 200 #population size
    # generating pop
    #pop = toolbox.population(n = GR_SIZE)
    '''BEGIN!!!'''
    print('Start Evo')
    #calculating original group's fitness
    fitnesses = list(map(toolbox.evaluate, pop))
    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit
    print("  Evaluated %i individuals" % len(pop))    
    
    '''Evolution!!!'''
    for g in range(0, GEN):
        print('--generation %i-- ' %g)
        #select
        offspring = toolbox.select(pop, len(pop))
        offspring = list(map(toolbox.clone, offspring))
        #crossover
        for child1, child2 in zip(offspring[::1], offspring[1::2]):
            if random.random() < CXPB:
                toolbox.crossover(child1, child2)
                
                #delete fitness of those children
                del child1.fitness.values
                del child2.fitness.values
        
        #mutation
        for mutant in offspring:
            if random.random() < MUPB:
                toolbox.mutate(mutant)
                del mutant.fitness.values
        
        #evaluate those invalid individuals
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = list(map(toolbox.evaluate, invalid_ind))
        for ind, fit in zip(invalid_ind, fitnesses):
           ind.fitness.values = fit
        print('Evaluated %i individuals' %len(invalid_ind))
         
        #refresh the group by offsprings
        pop[:] = offspring
        
        #gather all fitness in one list

        fits = [ind.fitness.values[0] for ind in pop] 
               
        length = len(pop)
        mean = sum(fits) / length
        sum2 = sum(x*x for x in fits)
        std = abs(sum2 / length - mean**2)**0.5
        
        print("  Min %s" % min(fits))
        print("  Max %s" % max(fits))
        print("  Avg %s" % mean)
        print("  Std %s" % std)
    
    print("-- End of (successful) evolution --")
    
    best_ind = tools.selBest(pop, 1)[0]
    print("Best individual is %s, %s" % (best_ind, best_ind.fitness.values))


if __name__ == "__main__":
    simpleEA()

上面是一个简单地使用罚函数限制x范围的方法,从结果中可以看出,无论如何计算,x均不会超出7。罚函数在解决有约束规划问题上可以有很好的效果,它根据不同的惩罚规则将越界的数据点的适应度进行修正。

你可能感兴趣的:(DEAP1.2.2(七) 约束操作)