# import
import random
import pandas as pd
import openpyxl
import numpy as np
import matplotlib.pyplot as plt
import copy
# calling the data
Parameter=pd.read_csv(r"C:\Users\user\Desktop\Parameter.csv")
Test_Data_Q=pd.read_csv(r"C:\Users\user\Desktop\Test_Data_Q.csv")
Test_Data_Q=Test_Data_Q.iloc[:36,:20]
# number of row and column
people_row=len(Test_Data_Q) #36
people_column=len(Test_Data_Q.columns) # 20 라인
#coefficients
zero_payload_desel=Parameter.iloc[0,1]
zero_payload_electric=Parameter.iloc[1,1]
variable_electric=Parameter.iloc[0,2]
variable_desel=Parameter.iloc[1,2]
ratio_desel=Parameter.iloc[0,3]
ratio_electric=Parameter.iloc[1,3]
# lists
fitness_value=[]
num_generation=[]
repaired_population=[]
operating_interval = []
# Ebs constraint
Ebs_constraint=500
Ebs_constraint_list= pd.DataFrame([Ebs_constraint]*people_row).T
# NUM OF Ebs
num_of_row_ebs = pd.DataFrame([0]*people_row).T
#interval of dispatching and distance
dispatching_interval = [5, 10, 20, 20, 10, 5, 5, 10, 20, 20, 10, 5, 10, 5, 5, 20, 10, 20, 5, 5, 10, 20, 20,10, 20, 20, 10, 5]
distance = [59, 30, 39, 20, 26, 60, 70, 35, 27, 57, 82, 44, 53, 74, 84, 48, 46, 87, 81, 50, 61, 34, 42, 20 ]
dispatching_interval = dispatching_interval[:20]
distance = distance[:20]
# operatng_interval
for _ in range(len(distance)) :
if distance[_] <=30 :
operating_interval .append(1)
elif distance[_] >31 and distance[_] <=60:
operating_interval .append(2)
else :
operating_interval.append(3)
# repair_rule
def repair_rule(repair):
repair = pd.DataFrame(repair)
row_sums = repair.sum(axis=1)
if (row_sums > 20).any():
# 무작위로 선택된 위치의 값을 1에서 0으로 변경
while True:
row = random.randint(0, people_row - 1)
col = random.randint(0, people_column - 1)
if repair.iloc[row, col] == 1:
repair.iloc[row, col] = 0
break # 변경이 이루어지면 반복 종료
repair = repair.values.tolist()
return repair
# initialize population
def initialize_population(population_size):
pre_population = [[[random.randint(0, 1) for _ in range(people_column)] for _ in range(people_row)] for _ in range(population_size)]
# for i in range(population_size) :
# repaired_population.append(repair_rule(pre_population[i]))
# return repaired_population
return pre_population
#interpreter
def interpreter(subject): #subject 는 data frame
interpreted = subject
for col in range (len(dispatching_interval)) : # 20번
if dispatching_interval[col] == 10:
for row in range(1, interpreted .shape[0]) :
if row % 2 != 0 :
interpreted .iloc[row , col] =2
elif dispatching_interval[col] == 20:
for row in range(1, interpreted .shape[0]) :
if row % 4 != 0 :
interpreted .iloc[row , col] =2
return interpreted
def changing_capacity(interpreted): # 거리 고려 완료
def_list = copy.deepcopy(Ebs_constraint_list)
for col in range (len(operating_interval)) : # 20번
if operating_interval[col] == 1:
for row in range(interpreted.shape[0]-1):
try:
if interpreted.iloc[row, col] == 1:
def_list.iloc[:,row+1:row+13] -= 1
except IndexError:
continue
elif operating_interval[col] == 2:
for row in range(interpreted.shape[0]-1):
try:
if interpreted.iloc[row, col] == 1:
def_list.iloc[:,row+1:row+25] -= 1
except IndexError:
continue
else :
for row in range(interpreted.shape[0]-1):
try:
if interpreted.iloc[row, col] == 1:
def_list.iloc[:,row+1:row+37] -= 1
except IndexError:
continue
return def_list
def cumulative_Ebs(interpreted):
def_list = copy.deepcopy(num_of_row_ebs)
for col in range (len(operating_interval)) : # 20번
if operating_interval[col] == 1:
for row in range(interpreted.shape[0]):
try:
if interpreted.iloc[row, col] == 1:
def_list.iloc[:,row+1:row+13] += 1
except IndexError:
continue
elif operating_interval[col] == 2:
for row in range(interpreted.shape[0]):
try:
if interpreted.iloc[row, col] == 1:
def_list.iloc[:,row+1:row+25] += 1
except IndexError:
continue
else :
for row in range(interpreted.shape[0]):
try:
if interpreted.iloc[row, col] == 1:
def_list.iloc[:,row+1:row+37] += 1
except IndexError:
continue
return def_list
# fitness function
def fitness(individual): #a = best_individual = 16x20
global people
total_value = 0
individual = pd.DataFrame(individual)
interpreted = interpreter(individual)
num_row_Ebs = cumulative_Ebs(interpreted)
Ebs_capacity= changing_capacity(interpreted) #16x1의 dataframe
# print("num row ebs")
# print(num_row_Ebs)
# print("ebs_capa")
# print(Ebs_capacity)
if (num_row_Ebs.values>Ebs_capacity.values).any() :
return 1/999999
for row in range(people_row): # 36
for column in range(people_column): # 20
if interpreted.iloc[row, column] == 1:
total_value += (distance[column] * zero_payload_electric + variable_electric * distance[column] * people.iloc[row, column]) * 0.6
elif interpreted.iloc[row, column] ==0 :
total_value += (distance[column] * zero_payload_desel + variable_desel * distance[column] * people.iloc[row,column]) * 3.06
return 1/total_value
# 교차 연산 (두 부모에서 두 자식 생성)
def crossover(parent1, parent2):
parent1 = pd.DataFrame(parent1)
parent2 = pd.DataFrame(parent2)
num_rows, num_columns = parent1.shape
crossover_point1 = random.randint(0, num_columns - 1)
crossover_point2 = random.randint(crossover_point1, num_columns)
child1 = pd.concat((parent1.iloc[:,:crossover_point1], parent2.iloc[:, crossover_point1:crossover_point2] ,parent1.iloc[:, crossover_point2:]), axis = 1)
child2 = pd.concat((parent2.iloc[:,:crossover_point1], parent1.iloc[:, crossover_point1:crossover_point2] ,parent2.iloc[:, crossover_point2:]), axis = 1)
return child1, child2
# 돌연변이 연산 (돌연변이가 발생할 확률이 있음)
def mutate(individual, mutation_rate):
num_rows ,num_columns = individual.shape
# print(num_rows)
for i in range(int(num_rows*num_columns*mutation_rate)):
row_idx = random.randint(0, num_rows - 1)
col_idx = random.randint(0, num_columns - 1)
current_value = individual.iloc[row_idx, col_idx]
individual.iloc[row_idx, col_idx] = 1 if current_value == 0 else 0
individual = individual.values.tolist()
return individual
# 유전 알고리즘 메인 함수
def genetic_algorithm(population_size, generations, crossover_rate, mutation_rate):
global last_optimal
global x
global fitness_value
population = initialize_population(population_size)
for generation in range(generations):
population.sort(key=fitness, reverse=True)
# 적합도가 가장 높은 개체 출력
best_individual = population[0]
a=best_individual
print(f"Generation {generation + 1}: Best Individual - {pd.DataFrame(best_individual)}, Fitness - {1/(fitness(a))}")
fitness_value.append(1/fitness(a))
num_generation.append(generation+1)
# 새로운 세대 생성
new_population = []
# 엘리트 개체(적합도가 가장 높은 개체)는 그대로 다음 세대로 전이 , 10개
for i in range(int(population_size/10)):
new_population.append(population[i])
# 교차 연산과 돌연변이 연산을 통해 새로운 개체 생성
while len(new_population) < population_size:
weights = [2**(-i) for i in range(len(population))] # 가중치
parent1 = random.choices(population, weights=weights)[0]
parent2 = random.choices(population, weights=weights)[0]
child1, child2 = crossover(parent1, parent2)
child1 = mutate(child1, mutation_rate)
child2 = mutate(child2, mutation_rate)
new_population.extend([child1,child2])
# 현재 세대 갱신
population = new_population
x = pd.DataFrame(population[0])
last_optimal=interpreter(x)
return
if __name__ == "__main__":
people=Test_Data_Q
genetic_algorithm(population_size=100, generations=50, crossover_rate=0.8, mutation_rate=0.05)
print("interpreted last optimal")
print(last_optimal)
print("last optimal Row Sums:" )
print(cumulative_Ebs(last_optimal))
print("dispatching_interval = ", dispatching_interval)
print("operatining_interval : ", operating_interval)
# figure
plt.plot(num_generation, fitness_value, marker='o')
plt.title('Fitness over Generations')
plt.xlabel('Generation')
plt.ylabel('Fitness')
plt.grid(True)
plt.show()
print(people_column)
print(people_row)