该程序主要有三部分,分别是主函数main、种群schedule、遗传算法genetic三部分,需要在同一目录下创建这三个函数,直接贴代码了。
main.py
import prettytable
from schedule import Schedule
from genetic import GeneticOptimize
def vis(schedule):
"""visualization Class Schedule.
Arguments:
schedule: List, Class Schedule
"""
col_labels = ['week/slot', '1', '2', '3', '4', '5']
table_vals = [[i + 1, '', '', '', '', ''] for i in range(5)]
table = prettytable.PrettyTable(col_labels, hrules=prettytable.ALL)
for s in schedule:
weekDay = s.weekDay
slot = s.slot
text = 'course: {} \n class: {} \n room: {} \n teacher: {}'.format(s.courseId, s.classId, s.roomId, s.teacherId)
table_vals[weekDay - 1][slot] = text
for row in table_vals:
table.add_row(row)
print(table)
if __name__ == '__main__':
schedules = []
# add schedule
schedules.append(Schedule(201, 1201, 11101))
schedules.append(Schedule(201, 1201, 11101))
schedules.append(Schedule(202, 1201, 11102))
schedules.append(Schedule(202, 1201, 11102))
schedules.append(Schedule(203, 1201, 11103))
schedules.append(Schedule(203, 1201, 11103))
schedules.append(Schedule(206, 1201, 11106))
schedules.append(Schedule(206, 1201, 11106))
schedules.append(Schedule(202, 1202, 11102))
schedules.append(Schedule(202, 1202, 11102))
schedules.append(Schedule(204, 1202, 11104))
schedules.append(Schedule(204, 1202, 11104))
schedules.append(Schedule(206, 1202, 11106))
schedules.append(Schedule(206, 1202, 11106))
schedules.append(Schedule(205, 1202, 11105))
schedules.append(Schedule(205, 1202, 11105))
schedules.append(Schedule(203, 1203, 11103))
schedules.append(Schedule(203, 1203, 11103))
schedules.append(Schedule(204, 1203, 11104))
schedules.append(Schedule(204, 1203, 11104))
schedules.append(Schedule(205, 1203, 11105))
schedules.append(Schedule(205, 1203, 11105))
schedules.append(Schedule(206, 1203, 11106))
schedules.append(Schedule(206, 1203, 11106))
# optimization
ga = GeneticOptimize(popsize=100,mutprob=0.3, elite=20, maxiter=20000)
res = ga.evolution(schedules, 4)
# visualization
vis_res = []
for r in res:
if r.classId == 1201:
vis_res.append(r)
vis(vis_res)
# vis_res = []
# for r in res:
# if r.classId == 1202:
# vis_res.append(r)
# vis(vis_res)
# vis_res = []
# for r in res:
# if r.classId == 1203:
# vis_res.append(r)
# vis(vis_res)
schedule.py
import numpy as np
class Schedule:
"""Class Schedule.
"""
def __init__(self, courseId, classId, teacherId):
"""Init
Arguments:
courseId: int, unique course id.
classId: int, unique class id.
teacherId: int, unique teacher id.
"""
self.courseId = courseId
self.classId = classId
self.teacherId = teacherId
self.roomId = 0
self.weekDay = 0
self.slot = 0
def random_init(self, roomRange):
"""random init.
Arguments:
roomSize: int, number of classrooms.
"""
self.roomId = np.random.randint(1, roomRange + 1, 1)[0]
self.weekDay = np.random.randint(1, 6, 1)[0]
self.slot = np.random.randint(1, 6, 1)[0]
def schedule_cost(population, elite):
"""calculate conflict of class schedules.
Arguments:
population: List, population of class schedules.
elite: int, number of best result.
Returns:
index of best result.
best conflict score.
"""
conflicts = []
n = len(population[0])
for p in population:
conflict = 0
for i in range(0, n - 1):
for j in range(i + 1, n):
# check course in same time and same room
if p[i].roomId == p[j].roomId and p[i].weekDay == p[j].weekDay and p[i].slot == p[j].slot:
conflict += 1
# check course for one class in same time
if p[i].classId == p[j].classId and p[i].weekDay == p[j].weekDay and p[i].slot == p[j].slot:
conflict += 1
# check course for one teacher in same time
if p[i].teacherId == p[j].teacherId and p[i].weekDay == p[j].weekDay and p[i].slot == p[j].slot:
conflict += 1
# check same course for one class in same day
if p[i].classId == p[j].classId and p[i].courseId == p[j].courseId and p[i].weekDay == p[j].weekDay:
conflict += 1
conflicts.append(conflict)
index = np.array(conflicts).argsort()
return index[: elite], conflicts[index[0]]
genetic.py
import copy
import numpy as np
from schedule import schedule_cost
class GeneticOptimize:
"""Genetic Algorithm.
"""
def __init__(self, popsize, mutprob,elite, maxiter,mutprob2=0.5):
# size of population
self.popsize = popsize
# prob of mutation
self.mutprob = mutprob
# number of elite
self.elite = elite
# iter times
self.maxiter = maxiter
#定义更大的变异率
self.mutprob2=mutprob2
def init_population(self, schedules, roomRange):
"""Init population
Arguments:
schedules: List, population of class schedules.
roomRange: int, number of classrooms.
"""
self.population = []
for i in range(self.popsize):
entity = []
for s in schedules:
s.random_init(roomRange)
entity.append(copy.deepcopy(s))
self.population.append(entity)
def mutate(self, eiltePopulation,roomRange):
"""Mutation Operation
Arguments:
eiltePopulation: List, population of elite schedules.
roomRange: int, number of classrooms. roomRange
Returns:
ep: List, population after mutation.
"""
#修改变异的个体数目
e = np.random.randint(0, 5, 1)[0]
#e = np.random.randint(0, self.elite, 1)[0]
pos = np.random.randint(0, 2, 1)[0]
ep = copy.deepcopy(eiltePopulation[e])
for p in ep:
pos = np.random.randint(0, 3, 1)[0]
operation = np.random.rand()
if pos == 0:
p.roomId = self.addSub(p.roomId, operation, roomRange)
if pos == 1:
p.weekDay = self.addSub(p.weekDay, operation, 5)
if pos == 2:
p.slot = self.addSub(p.slot, operation, 5)
return ep
def addSub(self, value, op, valueRange):
"""Add or sub operation in mutation.
Arguments:
value: int, value to be mutated.
op: double, prob of operation.
valueRange: int, range of value.
Returns:
value: int, mutated value.
"""
if op > 0.5:
if value < valueRange:
value += 1
else:
value -= 1
else:
if value - 1 > 0:
value -= 1
else:
value += 1
return value
def crossover(self, eiltePopulation):
"""Crossover Operation
Arguments:
eiltePopulation: List, population of elite schedules.
Returns:
ep: List, population after crossover.
"""
e1 = np.random.randint(0, self.elite, 1)[0]
e2 = np.random.randint(0, self.elite, 1)[0]
pos = np.random.randint(0, 2, 1)[0]
ep1 = copy.deepcopy(eiltePopulation[e1])
ep2 = eiltePopulation[e2]
for p1, p2 in zip(ep1, ep2):
if pos == 0:
p1.weekDay = p2.weekDay
p1.slot = p2.slot
if pos == 1:
p1.roomId = p2.roomId
return ep1
def evolution(self, schedules, roomRange):
"""evolution
Arguments:
schedules: class schedules for optimization.
elite: int, number of best result.
Returns:
index of best result.
best conflict score.
"""
# Main loop .
bestScore = 0
bestSchedule = None
self.init_population(schedules, roomRange)
for i in range(self.maxiter):
eliteIndex, bestScore = schedule_cost(self.population, self.elite)
#print('Iter: {} | conflict: {}'.format(i + 1, bestScore))
if bestScore == 0:
bestSchedule = self.population[eliteIndex[0]]
break
# Start with the pure winners
newPopulation = [self.population[index] for index in eliteIndex]
#精英个体为10,取前5个为优秀个体
betterpopulation=newPopulation[:5]
worsepopulation=newPopulation[5:]
# Add mutated and bred forms of the winners
while len(newPopulation) < self.popsize:
if np.random.rand() < self.mutprob:
# Mutation
newp = self.mutate(betterpopulation, roomRange)
if np.random.rand() < self.mutprob2:
# Mutation2
newp = self.mutate(worsepopulation, roomRange)
# if np.random.rand() < self.mutprob:
# newp = self.mutate(newPopulation, roomRange)
# else:
if np.random.rand()< 0.9:
# Crossover
newp = self.crossover(newPopulation)
newPopulation.append(newp)
self.population = newPopulation
return bestSchedule
也可以直接去我主页下载打包的程序,免费。程序弄好之后还需要安装一下相关的包,如果有问题可以在评论区留言。