Ejemplo n.º 1
0
def mutate(value, lower, upper, size):
    """
    Mutate value in the domain [lower,upper] with mutation 'size' as a decimal 
    percentage of the domain.
    WARNING:
        Doesn't work if the mutation size is too big and breaches both ends
        of the domain! 
    """
    
    # Define a random size for the mutation in the domain
    deltav = size*(upper - lower)
    
    vmax = value + deltav
    
    vmin = value - deltav

    if vmax > upper:
        
        # Percentage of the the total mutation size that fell in the domain
        bias = (upper - value)/deltav
        
        mutated = numpy.random.uniform(vmin, upper)
        
        # This compensated for the smaller region after 'value'
        while not (mutated >= value or flip(bias)):
        
            mutated = numpy.random.uniform(vmin, upper)
            
    elif vmin < lower:
        
        # Do the same as above but in the case where the mutation size breaches
        # the lower bound of the domain
        bias = (value - lower)/deltav
                        
        mutated = numpy.random.uniform(lower, vmax)
        
        # This compensated for the smaller region after 'value'
        while not (mutated <= value or flip(bias)):
        
            mutated = numpy.random.uniform(lower, vmax)
            
    else:
        
        # If the mutation size doesn't breach the domain bounds, just make a 
        # random mutation        
        mutated = numpy.random.uniform(vmin, vmax)
        
    return mutated
Ejemplo n.º 2
0
def recomb_pop(population, pop_fitness, recomb, lower, upper):
    """
    Recombines the whole population according to a fitness function and a 
    recombination strategy.
    
    Parameters:
    
        population: list of elements in the population. Each element should be
            an Nx1 dimensional array like
            
        pop_fitness: list of the fitness of each element in the population
            
        recomb: function object of the recombination strategy
        
        lower: list with the lower bounds of the parameter space
        
        upper: list with the upper bounds of the parameter space
    """
    
    assert len(lower) == len(upper) == len(population[0]), \
        "upper and lower must have the same number of elements " + \
        "as there are dimensions in the problem"

    assert len(pop_fitness) == len(population), \
        "Need a fitness value for every element in the population."

    new_pop = []
    
    pop_size = len(population) 
    
    for i, element, fitness in zip(xrange(pop_size), population, pop_fitness):
                
        if flip(fitness):
            
            left_over_pop = population[0:i] + population[i+1:]
            left_over_fit = pop_fitness[0:i] + pop_fitness[i+1:]
            
            for mate, mate_fitness in zip(left_over_pop, left_over_fit):
                
                if flip(mate_fitness):
                    
                    child = recomb(element, fitness, mate, mate_fitness)

                    new_pop.append(child)
                    
                    if len(new_pop) == pop_size:
                        
                        break
        
        if len(new_pop) == pop_size:
            
            break
    
    while len(new_pop) != pop_size:
        
        estimate = []
        
        for l, u in zip(lower, upper):
            
            estimate.append(numpy.random.uniform(l, u))
            
        new_pop.append(numpy.array(estimate))
    
    return new_pop
Ejemplo n.º 3
0
def evolve(fitness, goal, dims, pop_size, lower, upper, prob_mutation=0.005, \
           mutation_size=0.1, max_it=100):
    """
    Evolve a population using a given fitness criterion.
    
    Parameters:
    
        fitness: function object that calculates the fitness of each element in
                 the population. Input: list of elements representing the 
                 population. Each element is a list of size 'dims'. 
                 Output: List with the fitness of each element as a float value
                 in the range [0:1]
                 
        goal: function object that calculates the goal function due to an
              element of the population
                 
        dims: number of dimensions in the problem
        
        pop_size: how many individuals in the population
        
        lower: list with the lower bounds of the parameter space
        
        upper: list with the upper bounds of the parameter space
        
        prob_mutation: the probability of a mutation occurring at each iteration
        
        mutation_size: percentage of the parameter space that will be allowed
                       during the mutation
        
        max_it: maximum number of iterations
        
    Output:
        
        [best_elements, best_goals]
            best_elements: list with the optimum element at each iteration
            best_goals: list with the goal function value of each optimum 
                        element       
    """
    
    assert len(lower) == len(upper) == dims, \
        "upper and lower must have the same number of elements " + \
        "as there are dimensions in the problem"
    
    assert prob_mutation >= 0 and prob_mutation <= 1, \
        "prob_mutation must be in the range [0:1]"
    
    
    # Begin with a random population
    population = []
    
    for i in xrange(pop_size):
                
        estimate = []
        
        for l, u in zip(lower, upper):
            
            estimate.append(numpy.random.uniform(l, u))
            
        population.append(numpy.array(estimate))
        
    pop_fitness = fitness(population)    
    
    best_fit = max(pop_fitness)
    
    best = [population[pop_fitness.index(best_fit)]]
    
    best_goal = [goal(*best[-1])]
    
    # Evolve until reaching stagnation or max_it
    for iteration in xrange(max_it):
        
        population = recomb_pop(population, pop_fitness, wmean_recomb, \
                                lower, upper)
    
        # Mutate the unlucky ones
        for element in population:
            
            if flip(prob_mutation):
                
                p = numpy.random.randint(dims)
                
                element[p] = mutate(element[p], lower[p], upper[p], \
                                    size=mutation_size)
        
        pop_fitness = fitness(population)
    
        best_fit = max(pop_fitness)
        
        best.append(population[pop_fitness.index(best_fit)])
            
        best_goal.append(goal(*best[-1]))
        
        print "it %d:" % (iteration)
        print "  best goal:", best_goal[-1]
        print "  best:", best[-1]

        if abs((best_goal[-1] - best_goal[-2])/best_goal[-2]) <= 10**(-4):
            
            break
    
    return best, best_goal
Ejemplo n.º 4
0
def randwalk(func, dims, lower, upper, num_solutions, threshold=0.40):
    """
    Optimize using a random walk.
    
    Parameters:
        
        func: function object to be optimized
        
        dims: number of arguments the function receives
        
        lower: array with lower bounds of the parameter space
        
        upper: array with upper bounds of the parameter space
        
        step_sizes: step size in each dimension
        
        maxit: maximum iterations
        
        threshold: chance of accepting an upward step (range [0:1])
        
    Returns:
    
        [best_goal, best_estimate, goals, estimates]:
        
            best_goal: the smallest value of the goal function that was found
            
            best_estimate: point in the parameter space where 'best_goal' was 
                           found
                           
            goals: list of the goal function through the iterations
            
            estimates: list of the points where 'goals' where found  
    """
        
    # Keep all the steps recorded
    estimates = []
    
    goals = []
    
    solution_i = 0
        
    while solution_i < threshold*num_solutions:
        
        for j in xrange(num_solutions):
            
            tmp = numpy.zeros(dims)
            
            for i in xrange(dims):
                
                tmp[i] = numpy.random.uniform(lower[i], upper[i])
                
            goal = func(*tmp)
        
            if solution_i == 0:
                
                survival_prob = 1
                
            else:
                
                survival_prob = abs((max(goals) - goal)/(max(goals) - min(goals)))
            
            if flip(survival_prob):
                
                estimate = tmp
                
                if solution_i == 0 or goal < best_goal:
                    
                    best_goal = goal
                    
                    best_estimate = estimate
                
                estimates.append(estimate)
                
                goals.append(goal)
                
                solution_i += 1
                
                if solution_i == num_solutions:
                    
                    break
                
    return best_goal, best_estimate, goals, numpy.array(estimates)
Ejemplo n.º 5
0
def simulated_annealing(func, dims, lower, upper, step_sizes, \
                        tstart, tfinal, tstep, it_per_t):
    """
    Optimize using Simulated Annealing.
    
    Parameters:
        
        func: function object to be optimized
        
        dims: number of arguments the function receives
        
        lower: array with lower bounds of the parameter space
        
        upper: array with upper bounds of the parameter space
        
        step: list with the step sizes in each dimension
        
        maxit: maximum iterations
        
        threshold: chance of accepting an upward step (range [0:1])
        
    Returns:
    
        [best_goal, best_estimate, goals, estimates]:
        
            best_goal: the smallest value of the goal function that was found
            
            best_estimate: point in the parameter space where 'best_goal' was 
                           found
                           
            goals: list of the goal function through the iterations
            
            estimates: list of the points where 'goals' where found  
    """
    
    # Make random initial estimate
    estimate = []
    
    for i in xrange(dims):
        
        estimate.append(numpy.random.uniform(lower[i], upper[i]))
        
    estimate = numpy.array(estimate)
    
    goal = func(*estimate)
     
    best_estimate = estimate
    
    best_goal = goal 
    
    # Keep all the steps recorded
    estimates = [estimate]
    
    goals = [goal]
        
    step = numpy.empty_like(estimate)
    
    time_steps = numpy.arange(0, tfinal+1, 1, 'f')
    
    cooling_schedule = tstart*0.99**(time_steps)

    for temperature in cooling_schedule:
       
        accepted = 0
        
        for iteration in xrange(it_per_t):
            
            # Make a random perturbation
            for i in xrange(dims):
                
                step[i] = numpy.random.uniform(-step_sizes[i], step_sizes[i])
                
                # If the step takes the estimate out of the bounds, bring it
                # back.
                if estimate[i] + step[i] > upper[i]:
                    
                    step[i] = -step[i]
                    
                if estimate[i] + step[i] < lower[i]:
                                        
                    step[i] = -step[i]           
                    
            tmp = estimate + step
            
            goal = func(*tmp)
            
            delta_goal = goals[-1] - goal
            
            survival_prob = math.exp(delta_goal/temperature)
            
            if delta_goal > 0 or flip(survival_prob):
                                            
                estimate = tmp
                
                if goal < best_goal:
                    
                    best_goal = goal
                    
                    best_estimate = estimate        
                
                estimates.append(estimate)
                
                goals.append(goal)
                
                accepted += 1
                
        if accepted == 0:
            
            print "Exited due to frozen system: temp = %g" % (temperature)
            
            break
        
    return best_goal, best_estimate, goals, numpy.array(estimates)     
Ejemplo n.º 6
0
def mutated_rw(func, lower, upper, num_agentes, prob_mutation=0.01, \
               size_mutation=0.1, max_it=100, threshold=0.8):
    """
    Random Walk with mutations. (1D)
    """
    
    # Generate random agents
    agents = numpy.zeros(num_agentes)
    
    goals = numpy.zeros(num_agentes)
    
    for i in xrange(num_agentes):
        
        agents[i] = numpy.random.uniform(lower, upper)
        
        goals[i] = func(agents[i])
        
        if i == 0 or best_goal > goals[i]:
            
            best_agent = agents[i]
            
            best_goal = goals[i]
            
    survivors = []
    
    for iteration in xrange(max_it):
            
        survivors = []
        
        # Kill all the unworthy! (according to a survival probability)        
        for i in xrange(num_agentes):
                        
            survival_prob = math.exp(-abs((goals[i] - min(goals))/min(goals)))
            
            if flip(survival_prob):
                
                survivors.append(agents[i])
                
        if len(survivors) >= threshold*num_agentes:
            
            print "Enough survivors: %d out of %d" % (len(survivors), \
                                                      num_agentes)
            
            break
                
        # Mutate the survivors
        for i in xrange(len(survivors)):
            
            if flip(prob_mutation):
            
                agents[i] = mutate(survivors[i], lower, upper, size_mutation)
            
            else:
                
                agents[i] = survivors[i]
            
            goals[i] = func(agents[i])
            
            if best_goal > goals[i]:
                
                best_agent = agents[i]
                
                best_goal = goals[i]
            
        for i in xrange(len(survivors), num_agentes):
            
            agents[i] = numpy.random.uniform(lower, upper)
            
            goals[i] = func(agents[i])
            
            if best_goal > goals[i]:
                
                best_agent = agents[i]
                
                best_goal = goals[i]        
    
    print "Needed %d iterations." % (iteration + 1)
    
    return best_agent, best_goal, agents, goals