-
Caution
- 주의! 원서에 있는 코드랑 다른 부분이 존재합니다!
-
순서변경
-
편의를 위해 아래와 같이 순서를 재배치함
def crossover_operation() def mutation_operation() def crossover_blend() def mutation_random_deviation() def selection_rank_with_elite()def selection_rank_with_elite() def crossover_operation() def crossover_blend() def mutation_operation() def mutation_random_deviation()
-
-
코드변경 - 기존 코드에서는 선택된 엘리트 개체도 순위 선택에 포함시킴
- 엘리트 선택을 먼저 하기 위해 코드를 위로 올림
selected = sorted_individuals[0:elite_size]
- 엘리트 선택을 먼저 하기 위해 코드를 위로 올림
-
코드추가
- 엘리트 선택이 된 개체를 제거하기 위한 코드 추가
del sorted_individuals[0:elite_size]
- 엘리트 선택이 된 개체를 제거하기 위한 코드 추가
-
- 주의! 원서에 있는 코드랑 다른 부분이 존재합니다!
-
Toolbox
import random from multiprocessing.pool import Pool import copy import random # 병렬 처리를 위한 프로세스풀 생성하는 함수 def create_pool(): return Pool(processes=4) # 유전자의 값이 허용된 범위를 벗어나지 않도록 제약을 거는 함수 def constraints(x): if x > 10: return 10 elif x < -10: return -10 return x # 순위 선택 기반의 엘리트 선택 def selection_rank_with_elite(individuals, elite_size=0): # 적합도 기준 내림차순 정렬 sorted_individuals = sorted(individuals, key=lambda ind: ind.fitness, reverse=True) # 엘리트 선택: 상위 elite_size개의 개체를 먼저 선택 selected = sorted_individuals[0:elite_size] # 엘리트 개체를 제외한 나머지 개체들로 리스트 갱신 del sorted_individuals[0:elite_size] # 순위 간격 계산 rank_distance = 1 / len(individuals) # 순위 점수 계산 ranks = [(1 - i * rank_distance) for i in range(len(individuals))] ranks_sum = sum(ranks) # 나머지 개체는 확률 기반으로 선택 for i in range(len(sorted_individuals) - elite_size): shave = random.random() * ranks_sum # 무작위 선택 임계값 rank_sum = 0 for i in range(len(sorted_individuals)): rank_sum += ranks[i] if rank_sum > shave: selected.append(sorted_individuals[i]) break return selected # 선택된 개체 리스트 반환 # 개체 집단에 대해 교차 연산을 병렬로 수행하는 함수 ( 짝을 지어주겠다 ) def crossover_operation(population, method, prob): pool = create_pool() # 병렬처리를 위한 프로세스 풀 생성 crossed_offspring = [] # 최종 교차 결과가 저장될 리스트 to_cross = [] # 교차 대상이 되는 개체 쌍 저장 result = [] # 병렬 결과 저장용 # 개체들을 2개씩 묶어 반복 for ind1, ind2 in zip(population[::2], population[1::2]): # 주어진 확률에 따라 교차 수행 여부 결정 if random.random() < prob: # prob의 확률로 교차할지 결정 to_cross.extend([ind1, ind2]) # 교차 수행 예정 else: crossed_offspring.extend([ind1, ind2]) # 교차 없이 그대로 유지 # 실제 교차 연산 수행 (병렬 처리) for i in range(0, len(to_cross), 2): result.append( pool.apply_async(method, args=(to_cross[i], to_cross[i + 1])) ) # 병렬 처리 종료 및 결과 수집 pool.close() # 새로운 작업을 추가 하지 못하게 닫아버림 pool.join() # 현재 실행중인 작업이 모두 끝날 때까지 대기 # 결과 수집 for r in result: crossed_offspring.extend(r.get()) # 최종 교차 결과 반환 return crossed_offspring # 두 부모 유전자를 섞어 자식 유전자 두 개를 생성하는 함수 ( 지어진 짝을 가지고 교차를 하겠다 ) def crossover_blend(p1, p2, alpha): # 부모 유전자의 복사본 생성 c1 = copy.deepcopy(p1) #deepcopy는 원본이 변경되지 않도록 하기 위해 사용 c2 = copy.deepcopy(p2) # 각 유전자 위치별로 섞기 for i in range(len(p1)): # 교차 범위 하한(Lower bound)과 상한(Upper bound) 계산 l = min(c1[i], c2[i]) - alpha * abs(c2[i] - c1[i]) u = max(c1[i], c2[i]) + alpha * abs(c2[i] - c1[i]) # 새로운 유전자 값을 범위 내에서 무작위로 선택 c1[i] = round(l + random.random() * (u - l), 2) c2[i] = round(l + random.random() * (u - l), 2) # 자식 유전자 리스트 반환 return [c1, c2] # 개체 집단에 대해 돌연변이 연산을 병렬로 수행하는 함수 ( 전체 개체중 prob%의 개체만 돌연변이를 시키겠다 ) def mutation_operation(population, method, prob): pool = create_pool() # 병렬처리 풀 생성 mutated_offspring = [] # 최종 결과 저장용 to_mutate = [] # 돌연변이 대상 result = [] # 병렬 결과 # 각 개체에 대해 돌연변이 여부 판단 for ind in population: if random.random() < prob: # prob의 확률로 돌연변할지 결정 to_mutate.append(ind) # 돌연변이 대상 else: mutated_offspring.append(ind) # 그대로 유지 # 돌연변이 수행 (병렬 처리) for ind in to_mutate: result.append(pool.apply_async(method, args=(ind,))) # 병렬 처리 종료 및 결과 수집 pool.close() # 새로운 작업을 추가 하지 못하게 닫아버림 pool.join() # 현재 실행중인 작업이 모두 끝날 때까지 대기 # 결과 수집 for r in result: mutated_offspring.append(r.get()) # 최종 돌연변이이 결과 반환 return mutated_offspring # 한 개체의 유전자에 확률적으로 돌연변이를 가하는 함수 ( p%의 확률로 돌연변이를 실행하겠다 ) def mutation_random_deviation(ind, mu, sigma, p): # 부모 유전자의 복사본 생성 mut = copy.deepcopy(ind) for i in range(len(mut)): # 확률적으로 돌연변이 적용 if random.random() < p: # 정규분포에서 값을 더함 mut[i] = mut[i] + random.gauss(mu, sigma) #큰 변화보다는 작은 탐색 위주로 동작한다 → 국지적 최적화에 유리 return mut # 변경된 유전자 반환