├── .gitattributes ├── .gitignore ├── CVRP ├── ACO_CVRP.py ├── ALNS_CVRP.py ├── DE_CVRP.py ├── DPSO_CVRP.py ├── DQPSO_CVRP.py ├── GA_CVRP.py ├── SA_CVRP.py └── TS_CVRP.py ├── LICENSE ├── MDHFVRPTW ├── ACO_MDHFVRPTW.py ├── DE_MDHFVRPTW.py ├── DPSO_MDHFVRPTW.py ├── GA_MDHVRPTW.py ├── SA_MDHFVRPTW.py └── TS_MDHFVRPTW.py ├── MDVRP ├── ACO_MDCVRP.py ├── ALNS_MDCVRP.py ├── DE_MDCVRP.py ├── DPSO_MDCVRP.py ├── GA_MDCVRP.py ├── SA_MDCVRP.py └── TS_MDCVRP.py ├── MDVRPTW ├── ACO_MDVRPTW.py ├── ALNS_MDVRPTW.py ├── DE_MDVRPTW.py ├── DPSO_MDVRPTW.py ├── GA_MDVRPTW.py ├── SA_MDVRPTW.py └── TS_MDVRPTW.py ├── README.md └── data ├── CVRP └── cvrp.xlsx ├── MDCVRP ├── demand.csv └── depot.csv ├── MDHVRPTW ├── demand.csv └── depot.csv └── MDVRPTW ├── demand.csv └── depot.csv /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # IPython 77 | profile_default/ 78 | ipython_config.py 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | .dmypy.json 111 | dmypy.json 112 | 113 | # Pyre type checker 114 | .pyre/ 115 | -------------------------------------------------------------------------------- /CVRP/ACO_CVRP.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import math 3 | import random 4 | import numpy as np 5 | import copy 6 | import xlsxwriter 7 | import matplotlib.pyplot as plt 8 | class Sol(): 9 | def __init__(self): 10 | self.nodes_seq=None 11 | self.obj=None 12 | self.routes=None 13 | class Node(): 14 | def __init__(self): 15 | self.id=0 16 | self.name='' 17 | self.seq_no=0 18 | self.x_coord=0 19 | self.y_coord=0 20 | self.demand=0 21 | class Model(): 22 | def __init__(self): 23 | self.best_sol=None 24 | self.node_list=[] 25 | self.sol_list=[] 26 | self.node_seq_no_list=[] 27 | self.depot=None 28 | self.number_of_nodes=0 29 | self.opt_type=0 30 | self.vehicle_cap=0 31 | self.distance={} 32 | self.popsize=100 33 | self.alpha=2 34 | self.beta=3 35 | self.Q=100 36 | self.rho=0.5 37 | self.tau={} 38 | def readXlsxFile(filepath,model): 39 | node_seq_no = -1 40 | df = pd.read_excel(filepath) 41 | for i in range(df.shape[0]): 42 | node=Node() 43 | node.seq_no=node_seq_no 44 | node.x_coord= df['x_coord'][i] 45 | node.y_coord= df['y_coord'][i] 46 | node.demand=df['demand'][i] 47 | if df['demand'][i] == 0: 48 | model.depot=node 49 | else: 50 | model.node_list.append(node) 51 | model.node_seq_no_list.append(node_seq_no) 52 | try: 53 | node.name=df['name'][i] 54 | except: 55 | pass 56 | try: 57 | node.id=df['id'][i] 58 | except: 59 | pass 60 | node_seq_no=node_seq_no+1 61 | model.number_of_nodes=len(model.node_list) 62 | 63 | def initParam(model): 64 | for i in range(model.number_of_nodes): 65 | for j in range(i+1,model.number_of_nodes): 66 | d=math.sqrt((model.node_list[i].x_coord-model.node_list[j].x_coord)**2+ 67 | (model.node_list[i].y_coord-model.node_list[j].y_coord)**2) 68 | model.distance[i,j]=d 69 | model.distance[j,i]=d 70 | model.tau[i,j]=10 71 | model.tau[j,i]=10 72 | def movePosition(model): 73 | sol_list=[] 74 | local_sol=Sol() 75 | local_sol.obj=float('inf') 76 | for k in range(model.popsize): 77 | #Random ant position 78 | nodes_seq=[int(random.randint(0,model.number_of_nodes-1))] 79 | all_nodes_seq=copy.deepcopy(model.node_seq_no_list) 80 | all_nodes_seq.remove(nodes_seq[-1]) 81 | #Determine the next moving position according to pheromone 82 | while len(all_nodes_seq)>0: 83 | next_node_no=searchNextNode(model,nodes_seq[-1],all_nodes_seq) 84 | nodes_seq.append(next_node_no) 85 | all_nodes_seq.remove(next_node_no) 86 | sol=Sol() 87 | sol.nodes_seq=nodes_seq 88 | sol.obj,sol.routes=calObj(nodes_seq,model) 89 | sol_list.append(sol) 90 | if sol.obj 0).index(True)] 105 | return next_node_no 106 | def upateTau(model): 107 | rho=model.rho 108 | for k in model.tau.keys(): 109 | model.tau[k]=(1-rho)*model.tau[k] 110 | #update tau according to sol.nodes_seq(solution of TSP) 111 | for sol in model.sol_list: 112 | nodes_seq=sol.nodes_seq 113 | for i in range(len(nodes_seq)-1): 114 | from_node_no=nodes_seq[i] 115 | to_node_no=nodes_seq[i+1] 116 | model.tau[from_node_no,to_node_no]+=model.Q/sol.obj 117 | 118 | #update tau according to sol.routes(solution of CVRP) 119 | # for sol in model.sol_list: 120 | # routes=sol.routes 121 | # for route in routes: 122 | # for i in range(len(route)-1): 123 | # from_node_no=route[i] 124 | # to_node_no=route[i+1] 125 | # model.tau[from_node_no,to_node_no]+=model.Q/sol.obj 126 | 127 | def splitRoutes(nodes_seq,model): 128 | num_vehicle = 0 129 | vehicle_routes = [] 130 | route = [] 131 | remained_cap = model.vehicle_cap 132 | for node_no in nodes_seq: 133 | if remained_cap - model.node_list[node_no].demand >= 0: 134 | route.append(node_no) 135 | remained_cap = remained_cap - model.node_list[node_no].demand 136 | else: 137 | vehicle_routes.append(route) 138 | route = [node_no] 139 | num_vehicle = num_vehicle + 1 140 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 141 | vehicle_routes.append(route) 142 | return num_vehicle,vehicle_routes 143 | def calDistance(route,model): 144 | distance=0 145 | depot=model.depot 146 | for i in range(len(route)-1): 147 | from_node=model.node_list[route[i]] 148 | to_node=model.node_list[route[i+1]] 149 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 150 | first_node=model.node_list[route[0]] 151 | last_node=model.node_list[route[-1]] 152 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 153 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 154 | return distance 155 | def calObj(nodes_seq,model): 156 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 157 | if model.opt_type==0: 158 | return num_vehicle,vehicle_routes 159 | else: 160 | distance=0 161 | for route in vehicle_routes: 162 | distance+=calDistance(route,model) 163 | return distance,vehicle_routes 164 | def plotObj(obj_list): 165 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 166 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 167 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 168 | plt.xlabel('Iterations') 169 | plt.ylabel('Obj Value') 170 | plt.grid() 171 | plt.xlim(1,len(obj_list)+1) 172 | plt.show() 173 | def outPut(model): 174 | work=xlsxwriter.Workbook('result.xlsx') 175 | worksheet=work.add_worksheet() 176 | worksheet.write(0,0,'opt_type') 177 | worksheet.write(1,0,'obj') 178 | if model.opt_type==0: 179 | worksheet.write(0,1,'number of vehicles') 180 | else: 181 | worksheet.write(0, 1, 'drive distance of vehicles') 182 | worksheet.write(1,1,model.best_sol.obj) 183 | for row,route in enumerate(model.best_sol.routes): 184 | worksheet.write(row+2,0,'v'+str(row+1)) 185 | r=[str(i)for i in route] 186 | worksheet.write(row+2,1, '-'.join(r)) 187 | work.close() 188 | def run(filepath,Q,alpha,beta,rho,epochs,v_cap,opt_type,popsize): 189 | """ 190 | :param filepath:Xlsx file path 191 | :param Q:Total pheromone 192 | :param alpha:Information heuristic factor 193 | :param beta:Expected heuristic factor 194 | :param rho:Information volatilization factor 195 | :param epochs:Iterations 196 | :param v_cap: Vehicle capacity 197 | :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 198 | :param popsize:Population size 199 | :return: 200 | """ 201 | model=Model() 202 | model.vehicle_cap=v_cap 203 | model.opt_type=opt_type 204 | model.alpha=alpha 205 | model.beta=beta 206 | model.Q=Q 207 | model.rho=rho 208 | model.popsize=popsize 209 | sol=Sol() 210 | sol.obj=float('inf') 211 | model.best_sol=sol 212 | history_best_obj = [] 213 | readXlsxFile(filepath,model) 214 | initParam(model) 215 | for ep in range(epochs): 216 | movePosition(model) 217 | upateTau(model) 218 | history_best_obj.append(model.best_sol.obj) 219 | print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj)) 220 | plotObj(history_best_obj) 221 | outPut(model) 222 | if __name__=='__main__': 223 | file='../data/cvrp.xlsx' 224 | run(filepath=file,Q=10,alpha=1,beta=5,rho=0.1,epochs=100,v_cap=60,opt_type=1,popsize=60) 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /CVRP/DE_CVRP.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import math 3 | import random 4 | import numpy as np 5 | import copy 6 | import xlsxwriter 7 | import matplotlib.pyplot as plt 8 | class Sol(): 9 | def __init__(self): 10 | self.nodes_seq=None 11 | self.obj=None 12 | self.routes=None 13 | class Node(): 14 | def __init__(self): 15 | self.id=0 16 | self.name='' 17 | self.seq_no=0 18 | self.x_coord=0 19 | self.y_coord=0 20 | self.demand=0 21 | class Model(): 22 | def __init__(self): 23 | self.best_sol=None 24 | self.node_list=[] 25 | self.sol_list=[] 26 | self.node_seq_no_list=[] 27 | self.depot=None 28 | self.number_of_nodes=0 29 | self.opt_type=0 30 | self.vehicle_cap=0 31 | self.Cr=0.5 32 | self.F=0.5 33 | self.popsize=4*self.number_of_nodes 34 | 35 | def readXlsxFile(filepath,model): 36 | # It is recommended that the vehicle depot data be placed in the first line of xlsx file 37 | node_seq_no =-1 #the depot node seq_no is -1,and demand node seq_no is 0,1,2,... 38 | df = pd.read_excel(filepath) 39 | for i in range(df.shape[0]): 40 | node=Node() 41 | node.id=node_seq_no 42 | node.seq_no=node_seq_no 43 | node.x_coord= df['x_coord'][i] 44 | node.y_coord= df['y_coord'][i] 45 | node.demand=df['demand'][i] 46 | if df['demand'][i] == 0: 47 | model.depot=node 48 | else: 49 | model.node_list.append(node) 50 | model.node_seq_no_list.append(node_seq_no) 51 | try: 52 | node.name=df['name'][i] 53 | except: 54 | pass 55 | try: 56 | node.id=df['id'][i] 57 | except: 58 | pass 59 | node_seq_no=node_seq_no+1 60 | model.number_of_nodes=len(model.node_list) 61 | def genInitialSol(model): 62 | nodes_seq=copy.deepcopy(model.node_seq_no_list) 63 | for i in range(model.popsize): 64 | seed=int(random.randint(0,10)) 65 | random.seed(seed) 66 | random.shuffle(nodes_seq) 67 | sol=Sol() 68 | sol.nodes_seq=copy.deepcopy(nodes_seq) 69 | sol.obj,sol.routes=calObj(nodes_seq,model) 70 | model.sol_list.append(sol) 71 | if sol.obj= 0: 80 | route.append(node_no) 81 | remained_cap = remained_cap - model.node_list[node_no].demand 82 | else: 83 | vehicle_routes.append(route) 84 | route = [node_no] 85 | num_vehicle = num_vehicle + 1 86 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 87 | vehicle_routes.append(route) 88 | return num_vehicle,vehicle_routes 89 | def calDistance(route,model): 90 | distance=0 91 | depot=model.depot 92 | for i in range(len(route)-1): 93 | from_node=model.node_list[route[i]] 94 | to_node=model.node_list[route[i+1]] 95 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 96 | first_node=model.node_list[route[0]] 97 | last_node=model.node_list[route[-1]] 98 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 99 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 100 | return distance 101 | def calObj(nodes_seq,model): 102 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 103 | if model.opt_type==0: 104 | return num_vehicle,vehicle_routes 105 | else: 106 | distance=0 107 | for route in vehicle_routes: 108 | distance+=calDistance(route,model) 109 | return distance,vehicle_routes 110 | def adjustRoutes(nodes_seq,model): 111 | all_node_list=copy.deepcopy(model.node_seq_no_list) 112 | repeat_node=[] 113 | for id,node_no in enumerate(nodes_seq): 114 | if node_no in all_node_list: 115 | all_node_list.remove(node_no) 116 | else: 117 | repeat_node.append(id) 118 | for i in range(len(repeat_node)): 119 | nodes_seq[repeat_node[i]]=all_node_list[i] 120 | return nodes_seq 121 | #Differential mutation; mutation strategies: DE/rand/1/bin 122 | def muSol(model,v1): 123 | x1=model.sol_list[v1].nodes_seq 124 | while True: 125 | v2=random.randint(0,model.number_of_nodes-1) 126 | if v2!=v1: 127 | break 128 | while True: 129 | v3=random.randint(0,model.number_of_nodes-1) 130 | if v3!=v2 and v3!=v1: 131 | break 132 | x2=model.sol_list[v2].nodes_seq 133 | x3=model.sol_list[v3].nodes_seq 134 | mu_x=[min(int(x1[i]+model.F*(x2[i]-x3[i])),model.number_of_nodes-1) for i in range(model.number_of_nodes) ] 135 | return mu_x 136 | #Differential Crossover 137 | def crossSol(model,vx,vy): 138 | cro_x=[] 139 | for i in range(model.number_of_nodes): 140 | if random.random()0: 99 | new_v.append(min(v_,model.Vmax)) 100 | else: 101 | new_v.append(max(v_,-model.Vmax)) 102 | new_x=[min(int(x[i]+new_v[i]),model.number_of_nodes-1) for i in range(model.number_of_nodes) ] 103 | new_x=adjustRoutes(new_x,model) 104 | model.v[id]=new_v 105 | 106 | new_x_obj,new_x_routes=calObj(new_x,model) 107 | if new_x_obj= 0: 136 | route.append(node_no) 137 | remained_cap = remained_cap - model.node_list[node_no].demand 138 | else: 139 | vehicle_routes.append(route) 140 | route = [node_no] 141 | num_vehicle = num_vehicle + 1 142 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 143 | vehicle_routes.append(route) 144 | return num_vehicle,vehicle_routes 145 | def calDistance(route,model): 146 | distance=0 147 | depot=model.depot 148 | for i in range(len(route)-1): 149 | from_node=model.node_list[route[i]] 150 | to_node=model.node_list[route[i+1]] 151 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 152 | first_node=model.node_list[route[0]] 153 | last_node=model.node_list[route[-1]] 154 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 155 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 156 | return distance 157 | def calObj(nodes_seq,model): 158 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 159 | if model.opt_type==0: 160 | return num_vehicle,vehicle_routes 161 | else: 162 | distance=0 163 | for route in vehicle_routes: 164 | distance+=calDistance(route,model) 165 | return distance,vehicle_routes 166 | def plotObj(obj_list): 167 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 168 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 169 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 170 | plt.xlabel('Iterations') 171 | plt.ylabel('Obj Value') 172 | plt.grid() 173 | plt.xlim(1,len(obj_list)+1) 174 | plt.show() 175 | def outPut(model): 176 | work=xlsxwriter.Workbook('result.xlsx') 177 | worksheet=work.add_worksheet() 178 | worksheet.write(0,0,'opt_type') 179 | worksheet.write(1,0,'obj') 180 | if model.opt_type==0: 181 | worksheet.write(0,1,'number of vehicles') 182 | else: 183 | worksheet.write(0, 1, 'drive distance of vehicles') 184 | worksheet.write(1,1,model.best_sol.obj) 185 | for row,route in enumerate(model.best_sol.routes): 186 | worksheet.write(row+2,0,'v'+str(row+1)) 187 | r=[str(i)for i in route] 188 | worksheet.write(row+2,1, '-'.join(r)) 189 | work.close() 190 | def run(filepath,epochs,popsize,Vmax,v_cap,opt_type,w,c1,c2): 191 | """ 192 | :param filepath: Xlsx file path 193 | :param epochs: Iterations 194 | :param popsize: Population size 195 | :param v_cap: Vehicle capacity 196 | :param Vmax: Max speed 197 | :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 198 | :param w: Inertia weight 199 | :param c1:Learning factors 200 | :param c2:Learning factors 201 | :return: 202 | """ 203 | model=Model() 204 | model.vehicle_cap=v_cap 205 | model.opt_type=opt_type 206 | model.w=w 207 | model.c1=c1 208 | model.c2=c2 209 | model.Vmax = Vmax 210 | readXlsxFile(filepath,model) 211 | history_best_obj=[] 212 | genInitialSol(model,popsize) 213 | history_best_obj.append(model.best_sol.obj) 214 | for ep in range(epochs): 215 | updatePosition(model) 216 | history_best_obj.append(model.best_sol.obj) 217 | print("%s/%s: best obj: %s"%(ep,epochs,model.best_sol.obj)) 218 | plotObj(history_best_obj) 219 | outPut(model) 220 | if __name__=='__main__': 221 | file='../data/cvrp.xlsx' 222 | run(filepath=file,epochs=100,popsize=150,Vmax=2,v_cap=70,opt_type=1,w=0.9,c1=1,c2=5) 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /CVRP/DQPSO_CVRP.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import math 3 | import random 4 | import numpy as np 5 | import copy 6 | import xlsxwriter 7 | import matplotlib.pyplot as plt 8 | class Sol(): 9 | def __init__(self): 10 | self.nodes_seq=None 11 | self.obj=None 12 | self.routes=None 13 | class Node(): 14 | def __init__(self): 15 | self.id=0 16 | self.name='' 17 | self.seq_no=0 18 | self.x_coord=0 19 | self.y_coord=0 20 | self.demand=0 21 | class Model(): 22 | def __init__(self): 23 | self.sol_list=[] 24 | self.best_sol=None 25 | self.node_list=[] 26 | self.node_seq_no_list=[] 27 | self.depot=None 28 | self.number_of_nodes=0 29 | self.opt_type=0 30 | self.vehicle_cap=0 31 | self.popsize=100 32 | self.pl=[] 33 | self.pg=None 34 | self.mg=None 35 | self.alpha=1.0 36 | def readXlsxFile(filepath,model): 37 | # It is recommended that the vehicle depot data be placed in the first line of xlsx file 38 | node_seq_no = -1 #the depot node seq_no is -1,and demand node seq_no is 0,1,2,... 39 | df = pd.read_excel(filepath) 40 | for i in range(df.shape[0]): 41 | node=Node() 42 | node.id=node_seq_no 43 | node.seq_no=node_seq_no 44 | node.x_coord= df['x_coord'][i] 45 | node.y_coord= df['y_coord'][i] 46 | node.demand=df['demand'][i] 47 | if df['demand'][i] == 0: 48 | model.depot=node 49 | else: 50 | model.node_list.append(node) 51 | model.node_seq_no_list.append(node_seq_no) 52 | try: 53 | node.name=df['name'][i] 54 | except: 55 | pass 56 | try: 57 | node.id=df['id'][i] 58 | except: 59 | pass 60 | node_seq_no=node_seq_no+1 61 | model.number_of_nodes=len(model.node_list) 62 | def genInitialSol(model): 63 | node_seq=copy.deepcopy(model.node_seq_no_list) 64 | best_sol=Sol() 65 | best_sol.obj=float('inf') 66 | mg=[0]*model.number_of_nodes 67 | for i in range(model.popsize): 68 | seed = int(random.randint(0, 10)) 69 | random.seed(seed) 70 | random.shuffle(node_seq) 71 | sol=Sol() 72 | sol.nodes_seq= copy.deepcopy(node_seq) 73 | sol.obj,sol.routes=calObj(sol.nodes_seq,model) 74 | model.sol_list.append(sol) 75 | #init the optimal position of each particle 76 | model.pl.append(sol.nodes_seq) 77 | #init the average optimal position of particle population 78 | mg=[mg[k]+node_seq[k]/model.popsize for k in range(model.number_of_nodes)] 79 | #init the optimal position of particle population 80 | if sol.obj= 0: 140 | route.append(node_no) 141 | remained_cap = remained_cap - model.node_list[node_no].demand 142 | else: 143 | vehicle_routes.append(route) 144 | route = [node_no] 145 | num_vehicle = num_vehicle + 1 146 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 147 | vehicle_routes.append(route) 148 | return num_vehicle,vehicle_routes 149 | def calDistance(route,model): 150 | distance=0 151 | depot=model.depot 152 | for i in range(len(route)-1): 153 | from_node=model.node_list[route[i]] 154 | to_node=model.node_list[route[i+1]] 155 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 156 | first_node=model.node_list[route[0]] 157 | last_node=model.node_list[route[-1]] 158 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 159 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 160 | return distance 161 | def calObj(nodes_seq,model): 162 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 163 | if model.opt_type==0: 164 | return num_vehicle,vehicle_routes 165 | else: 166 | distance=0 167 | for route in vehicle_routes: 168 | distance+=calDistance(route,model) 169 | return distance,vehicle_routes 170 | 171 | def plotObj(obj_list): 172 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 173 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 174 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 175 | plt.xlabel('Iterations') 176 | plt.ylabel('Obj Value') 177 | plt.grid() 178 | plt.xlim(1,len(obj_list)+1) 179 | plt.show() 180 | def outPut(model): 181 | work=xlsxwriter.Workbook('result.xlsx') 182 | worksheet=work.add_worksheet() 183 | worksheet.write(0,0,'opt_type') 184 | worksheet.write(1,0,'obj') 185 | if model.opt_type==0: 186 | worksheet.write(0,1,'number of vehicles') 187 | else: 188 | worksheet.write(0, 1, 'drive distance of vehicles') 189 | worksheet.write(1,1,model.best_sol.obj) 190 | for row,route in enumerate(model.best_sol.routes): 191 | worksheet.write(row+2,0,'v'+str(row+1)) 192 | r=[str(i)for i in route] 193 | worksheet.write(row+2,1, '-'.join(r)) 194 | work.close() 195 | def run(filepath,epochs,popsize,alpha,v_cap,opt_type): 196 | """ 197 | :param filepath: Xlsx file path 198 | :type str 199 | :param epochs:Iterations 200 | :type int 201 | :param popsize:Population size 202 | :type int 203 | :param alpha:Innovation(Control) parameters,(0,1] 204 | :type float, 205 | :param v_cap:Vehicle capacity 206 | :type float 207 | :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 208 | :type int,0 or 1 209 | :return: 210 | """ 211 | model=Model() 212 | model.vehicle_cap=v_cap 213 | model.opt_type=opt_type 214 | model.alpha=alpha 215 | model.popsize=popsize 216 | readXlsxFile(filepath,model) 217 | history_best_obj=[] 218 | genInitialSol(model) 219 | history_best_obj.append(model.best_sol.obj) 220 | for ep in range(epochs): 221 | updatePosition(model) 222 | history_best_obj.append(model.best_sol.obj) 223 | print("%s/%s: best obj: %s"%(ep,epochs,model.best_sol.obj)) 224 | plotObj(history_best_obj) 225 | outPut(model) 226 | if __name__=='__main__': 227 | file='../data/cvrp.xlsx' 228 | run(filepath=file,epochs=300,popsize=150,alpha=0.8,v_cap=80,opt_type=1) 229 | -------------------------------------------------------------------------------- /CVRP/GA_CVRP.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import math 3 | import random 4 | import numpy as np 5 | import copy 6 | import xlsxwriter 7 | import matplotlib.pyplot as plt 8 | class Sol(): 9 | def __init__(self): 10 | self.nodes_seq=None 11 | self.obj=None 12 | self.fit=None 13 | self.routes=None 14 | class Node(): 15 | def __init__(self): 16 | self.id=0 17 | self.name='' 18 | self.seq_no=0 19 | self.x_coord=0 20 | self.y_coord=0 21 | self.demand=0 22 | class Model(): 23 | def __init__(self): 24 | self.best_sol=None 25 | self.node_list=[] 26 | self.sol_list=[] 27 | self.node_seq_no_list=[] 28 | self.depot=None 29 | self.number_of_nodes=0 30 | self.opt_type=0 31 | self.vehicle_cap=0 32 | self.pc=0.5 33 | self.pm=0.2 34 | self.n_select=80 35 | self.popsize=100 36 | 37 | def readXlsxFile(filepath,model): 38 | #It is recommended that the vehicle depot data be placed in the first line of xlsx file 39 | node_seq_no =-1 #the depot node seq_no is -1,and demand node seq_no is 0,1,2,... 40 | df = pd.read_excel(filepath) 41 | for i in range(df.shape[0]): 42 | node=Node() 43 | node.id=node_seq_no 44 | node.seq_no=node_seq_no 45 | node.x_coord= df['x_coord'][i] 46 | node.y_coord= df['y_coord'][i] 47 | node.demand=df['demand'][i] 48 | if df['demand'][i] == 0: 49 | model.depot=node 50 | else: 51 | model.node_list.append(node) 52 | model.node_seq_no_list.append(node_seq_no) 53 | try: 54 | node.name=df['name'][i] 55 | except: 56 | pass 57 | try: 58 | node.id=df['id'][i] 59 | except: 60 | pass 61 | node_seq_no=node_seq_no+1 62 | model.number_of_nodes=len(model.node_list) 63 | def genInitialSol(model): 64 | nodes_seq=copy.deepcopy(model.node_seq_no_list) 65 | for i in range(model.popsize): 66 | seed=int(random.randint(0,10)) 67 | random.seed(seed) 68 | random.shuffle(nodes_seq) 69 | sol=Sol() 70 | sol.nodes_seq=copy.deepcopy(nodes_seq) 71 | model.sol_list.append(sol) 72 | 73 | def splitRoutes(nodes_seq,model): 74 | num_vehicle = 0 75 | vehicle_routes = [] 76 | route = [] 77 | remained_cap = model.vehicle_cap 78 | for node_no in nodes_seq: 79 | if remained_cap - model.node_list[node_no].demand >= 0: 80 | route.append(node_no) 81 | remained_cap = remained_cap - model.node_list[node_no].demand 82 | else: 83 | vehicle_routes.append(route) 84 | route = [node_no] 85 | num_vehicle = num_vehicle + 1 86 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 87 | vehicle_routes.append(route) 88 | return num_vehicle,vehicle_routes 89 | def calDistance(route,model): 90 | distance=0 91 | depot=model.depot 92 | for i in range(len(route)-1): 93 | from_node=model.node_list[route[i]] 94 | to_node=model.node_list[route[i+1]] 95 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 96 | first_node=model.node_list[route[0]] 97 | last_node=model.node_list[route[-1]] 98 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 99 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 100 | return distance 101 | def calFit(model): 102 | #calculate fit value:fit=Objmax-obj 103 | Objmax=-float('inf') 104 | best_sol=Sol()#record the local best solution 105 | best_sol.obj=float('inf') 106 | #计算目标函数 107 | for sol in model.sol_list: 108 | nodes_seq=sol.nodes_seq 109 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 110 | if model.opt_type==0: 111 | sol.obj=num_vehicle 112 | sol.routes=vehicle_routes 113 | if sol.obj>Objmax: 114 | Objmax=sol.obj 115 | if sol.objObjmax: 124 | Objmax=sol.obj 125 | if sol.obj < best_sol.obj: 126 | best_sol = copy.deepcopy(sol) 127 | #calculate fit value 128 | for sol in model.sol_list: 129 | sol.fit=Objmax-sol.obj 130 | #update the global best solution 131 | if best_sol.objmodel.popsize: 193 | break 194 | #mutation 195 | def muSol(model): 196 | sol_list=copy.deepcopy(model.sol_list) 197 | model.sol_list=[] 198 | while True: 199 | f1_index = int(random.randint(0, len(sol_list) - 1)) 200 | f1 = copy.deepcopy(sol_list[f1_index]) 201 | m1_index=random.randint(0,model.number_of_nodes-1) 202 | m2_index=random.randint(0,model.number_of_nodes-1) 203 | if m1_index!=m2_index: 204 | if random.random() <= model.pm: 205 | node1=f1.nodes_seq[m1_index] 206 | f1.nodes_seq[m1_index]=f1.nodes_seq[m2_index] 207 | f1.nodes_seq[m2_index]=node1 208 | model.sol_list.append(copy.deepcopy(f1)) 209 | else: 210 | model.sol_list.append(copy.deepcopy(f1)) 211 | if len(model.sol_list)>model.popsize: 212 | break 213 | def plotObj(obj_list): 214 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 215 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 216 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 217 | plt.xlabel('Iterations') 218 | plt.ylabel('Obj Value') 219 | plt.grid() 220 | plt.xlim(1,len(obj_list)+1) 221 | plt.show() 222 | def outPut(model): 223 | work=xlsxwriter.Workbook('result.xlsx') 224 | worksheet=work.add_worksheet() 225 | worksheet.write(0,0,'opt_type') 226 | worksheet.write(1,0,'obj') 227 | if model.opt_type==0: 228 | worksheet.write(0,1,'number of vehicles') 229 | else: 230 | worksheet.write(0, 1, 'drive distance of vehicles') 231 | worksheet.write(1,1,model.best_sol.obj) 232 | for row,route in enumerate(model.best_sol.routes): 233 | worksheet.write(row+2,0,'v'+str(row+1)) 234 | r=[str(i)for i in route] 235 | worksheet.write(row+2,1, '-'.join(r)) 236 | work.close() 237 | 238 | 239 | def run(filepath,epochs,pc,pm,popsize,n_select,v_cap,opt_type): 240 | """ 241 | :param filepath:Xlsx file path 242 | :param epochs:Iterations 243 | :param pc:Crossover probability 244 | :param pm:Mutation probability 245 | :param popsize:Population size 246 | :param n_select:Number of excellent individuals selected 247 | :param v_cap:Vehicle capacity 248 | :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 249 | :return: 250 | """ 251 | model=Model() 252 | model.vehicle_cap=v_cap 253 | model.opt_type=opt_type 254 | model.pc=pc 255 | model.pm=pm 256 | model.popsize=popsize 257 | model.n_select=n_select 258 | 259 | readXlsxFile(filepath,model) 260 | genInitialSol(model) 261 | history_best_obj = [] 262 | best_sol=Sol() 263 | best_sol.obj=float('inf') 264 | model.best_sol=best_sol 265 | for ep in range(epochs): 266 | calFit(model) 267 | selectSol(model) 268 | crossSol(model) 269 | muSol(model) 270 | history_best_obj.append(model.best_sol.obj) 271 | print("%s/%s, best obj: %s" % (ep,epochs,model.best_sol.obj)) 272 | plotObj(history_best_obj) 273 | outPut(model) 274 | if __name__=='__main__': 275 | file='../data/cvrp.xlsx' 276 | run(filepath=file,epochs=350,pc=0.6,pm=0.2,popsize=100,n_select=80,v_cap=80,opt_type=1) 277 | -------------------------------------------------------------------------------- /CVRP/SA_CVRP.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import math 3 | import random 4 | import numpy as np 5 | import copy 6 | import xlsxwriter 7 | import matplotlib.pyplot as plt 8 | class Sol(): 9 | def __init__(self): 10 | self.nodes_seq=None 11 | self.obj=None 12 | self.routes=None 13 | class Node(): 14 | def __init__(self): 15 | self.id=0 16 | self.name='' 17 | self.seq_no=0 18 | self.x_coord=0 19 | self.y_coord=0 20 | self.demand=0 21 | class Model(): 22 | def __init__(self): 23 | self.best_sol=None 24 | self.node_list=[] 25 | self.node_seq_no_list=[] 26 | self.depot=None 27 | self.number_of_nodes=0 28 | self.opt_type=0 29 | self.vehicle_cap=0 30 | 31 | def readXlsxFile(filepath,model): 32 | # It is recommended that the vehicle depot data be placed in the first line of xlsx file 33 | node_seq_no = -1#the depot node seq_no is -1,and demand node seq_no is 0,1,2,... 34 | df = pd.read_excel(filepath) 35 | for i in range(df.shape[0]): 36 | node=Node() 37 | node.id=node_seq_no 38 | node.seq_no=node_seq_no 39 | node.x_coord= df['x_coord'][i] 40 | node.y_coord= df['y_coord'][i] 41 | node.demand=df['demand'][i] 42 | if df['demand'][i] == 0: 43 | model.depot=node 44 | else: 45 | model.node_list.append(node) 46 | model.node_seq_no_list.append(node_seq_no) 47 | try: 48 | node.name=df['name'][i] 49 | except: 50 | pass 51 | try: 52 | node.id=df['id'][i] 53 | except: 54 | pass 55 | node_seq_no=node_seq_no+1 56 | model.number_of_nodes=len(model.node_list) 57 | 58 | def genInitialSol(node_seq): 59 | node_seq=copy.deepcopy(node_seq) 60 | random.seed(0) 61 | random.shuffle(node_seq) 62 | return node_seq 63 | def createActions(n): 64 | action_list=[] 65 | nswap=n//2 66 | # Single point exchange 67 | for i in range(nswap): 68 | action_list.append([1, i, i + nswap]) 69 | # Two point exchange 70 | for i in range(0, nswap, 2): 71 | action_list.append([2, i, i + nswap]) 72 | # Reverse sequence 73 | for i in range(0, n, 4): 74 | action_list.append([3, i, i + 3]) 75 | return action_list 76 | def doACtion(nodes_seq,action): 77 | nodes_seq=copy.deepcopy(nodes_seq) 78 | if action[0]==1: 79 | index_1=action[1] 80 | index_2=action[2] 81 | temporary=nodes_seq[index_1] 82 | nodes_seq[index_1]=nodes_seq[index_2] 83 | nodes_seq[index_2]=temporary 84 | return nodes_seq 85 | elif action[0]==2: 86 | index_1 = action[1] 87 | index_2 = action[2] 88 | temporary=[nodes_seq[index_1],nodes_seq[index_1+1]] 89 | nodes_seq[index_1]=nodes_seq[index_2] 90 | nodes_seq[index_1+1]=nodes_seq[index_2+1] 91 | nodes_seq[index_2]=temporary[0] 92 | nodes_seq[index_2+1]=temporary[1] 93 | return nodes_seq 94 | elif action[0]==3: 95 | index_1=action[1] 96 | index_2=action[2] 97 | nodes_seq[index_1:index_2+1]=list(reversed(nodes_seq[index_1:index_2+1])) 98 | return nodes_seq 99 | def splitRoutes(nodes_seq,model): 100 | num_vehicle = 0 101 | vehicle_routes = [] 102 | route = [] 103 | remained_cap = model.vehicle_cap 104 | for node_no in nodes_seq: 105 | if remained_cap - model.node_list[node_no].demand >= 0: 106 | route.append(node_no) 107 | remained_cap = remained_cap - model.node_list[node_no].demand 108 | else: 109 | vehicle_routes.append(route) 110 | route = [node_no] 111 | num_vehicle = num_vehicle + 1 112 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 113 | vehicle_routes.append(route) 114 | return num_vehicle,vehicle_routes 115 | def calDistance(route,model): 116 | distance=0 117 | depot=model.depot 118 | for i in range(len(route)-1): 119 | from_node=model.node_list[route[i]] 120 | to_node=model.node_list[route[i+1]] 121 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 122 | first_node=model.node_list[route[0]] 123 | last_node=model.node_list[route[-1]] 124 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 125 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 126 | return distance 127 | def calObj(nodes_seq,model): 128 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 129 | if model.opt_type==0: 130 | return num_vehicle,vehicle_routes 131 | else: 132 | distance=0 133 | for route in vehicle_routes: 134 | distance+=calDistance(route,model) 135 | return distance,vehicle_routes 136 | def plotObj(obj_list): 137 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 138 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 139 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 140 | plt.xlabel('Iterations') 141 | plt.ylabel('Obj Value') 142 | plt.grid() 143 | plt.xlim(1,len(obj_list)+1) 144 | plt.show() 145 | def outPut(model): 146 | work = xlsxwriter.Workbook('result.xlsx') 147 | worksheet = work.add_worksheet() 148 | worksheet.write(0, 0, 'opt_type') 149 | worksheet.write(1, 0, 'obj') 150 | if model.opt_type == 0: 151 | worksheet.write(0, 1, 'number of vehicles') 152 | else: 153 | worksheet.write(0, 1, 'drive distance of vehicles') 154 | worksheet.write(1, 1, model.best_sol.obj) 155 | for row, route in enumerate(model.best_sol.routes): 156 | worksheet.write(row + 2, 0, 'v' + str(row + 1)) 157 | r = [str(i) for i in route] 158 | worksheet.write(row + 2, 1, '-'.join(r)) 159 | work.close() 160 | def run(filepath,T0,Tf,detaT,v_cap,opt_type): 161 | """ 162 | :param filepath: Xlsx file path 163 | :param T0: Initial temperature 164 | :param Tf: Termination temperature 165 | :param deltaT: Step or proportion of temperature drop 166 | :param v_cap: Vehicle capacity 167 | :param opt_type: Optimization type:0:Minimize the cost of travel distance;1:Minimize the cost of travel time 168 | :return: 169 | """ 170 | model=Model() 171 | model.vehicle_cap=v_cap 172 | model.opt_type=opt_type 173 | readXlsxFile(filepath,model) 174 | action_list=createActions(model.number_of_nodes) 175 | history_best_obj=[] 176 | sol=Sol() 177 | sol.nodes_seq=genInitialSol(model.node_seq_no_list) 178 | sol.obj,sol.routes=calObj(sol.nodes_seq,model) 179 | model.best_sol=copy.deepcopy(sol) 180 | history_best_obj.append(sol.obj) 181 | Tk=T0 182 | nTk=len(action_list) 183 | while Tk>=Tf: 184 | for i in range(nTk): 185 | new_sol = Sol() 186 | new_sol.nodes_seq = doACtion(sol.nodes_seq, action_list[i]) 187 | new_sol.obj, new_sol.routes = calObj(new_sol.nodes_seq, model) 188 | deta_f=new_sol.obj-sol.obj 189 | #New interpretation of acceptance criteria 190 | if deta_f<0 or math.exp(-deta_f/Tk)>random.random(): 191 | sol=copy.deepcopy(new_sol) 192 | if sol.obj= 0: 108 | route.append(node_no) 109 | remained_cap = remained_cap - model.node_list[node_no].demand 110 | else: 111 | vehicle_routes.append(route) 112 | route = [node_no] 113 | num_vehicle = num_vehicle + 1 114 | remained_cap =model.vehicle_cap - model.node_list[node_no].demand 115 | vehicle_routes.append(route) 116 | return num_vehicle,vehicle_routes 117 | def calDistance(route,model): 118 | distance=0 119 | depot=model.depot 120 | for i in range(len(route)-1): 121 | from_node=model.node_list[route[i]] 122 | to_node=model.node_list[route[i+1]] 123 | distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) 124 | first_node=model.node_list[route[0]] 125 | last_node=model.node_list[route[-1]] 126 | distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) 127 | distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) 128 | return distance 129 | def calObj(nodes_seq,model): 130 | # calculate obj value 131 | num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) 132 | if model.opt_type==0: 133 | return num_vehicle,vehicle_routes 134 | else: 135 | distance=0 136 | for route in vehicle_routes: 137 | distance+=calDistance(route,model) 138 | return distance,vehicle_routes 139 | def plotObj(obj_list): 140 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 141 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 142 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 143 | plt.xlabel('Iterations') 144 | plt.ylabel('Obj Value') 145 | plt.grid() 146 | plt.xlim(1,len(obj_list)+1) 147 | plt.show() 148 | def outPut(model): 149 | work = xlsxwriter.Workbook('result.xlsx') 150 | worksheet = work.add_worksheet() 151 | worksheet.write(0, 0, 'opt_type') 152 | worksheet.write(1, 0, 'obj') 153 | if model.opt_type == 0: 154 | worksheet.write(0, 1, 'number of vehicles') 155 | else: 156 | worksheet.write(0, 1, 'drive distance of vehicles') 157 | worksheet.write(1, 1, model.best_sol.obj) 158 | for row, route in enumerate(model.best_sol.routes): 159 | worksheet.write(row + 2, 0, 'v' + str(row + 1)) 160 | r = [str(i) for i in route] 161 | worksheet.write(row + 2, 1, '-'.join(r)) 162 | work.close() 163 | def run(filepath,epochs,v_cap,opt_type): 164 | """ 165 | :param filepath: :Xlsx file path 166 | :param epochs: Iterations 167 | :param v_cap: Vehicle capacity 168 | :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 169 | :return: 无 170 | """ 171 | model=Model() 172 | model.vehicle_cap=v_cap 173 | model.opt_type=opt_type 174 | readXlsxFile(filepath,model) 175 | action_list=createActions(model.number_of_nodes) 176 | model.tabu_list=np.zeros(len(action_list)) 177 | history_best_obj=[] 178 | sol=Sol() 179 | sol.nodes_seq=genInitialSol(model.node_seq_no_list) 180 | sol.obj,sol.routes=calObj(sol.nodes_seq,model) 181 | model.best_sol=copy.deepcopy(sol) 182 | history_best_obj.append(sol.obj) 183 | for ep in range(epochs): 184 | local_new_sol=Sol() 185 | local_new_sol.obj=float('inf') 186 | for i in range(len(action_list)): 187 | if model.tabu_list[i]==0: 188 | new_sol=Sol() 189 | new_sol.nodes_seq=doACtion(sol.nodes_seq,action_list[i]) 190 | new_sol.obj,new_sol.routes=calObj(new_sol.nodes_seq,model) 191 | new_sol.action_id=i 192 | if new_sol.obj 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /MDVRP/ACO_MDCVRP.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | import numpy as np 4 | import copy 5 | import xlsxwriter 6 | import matplotlib.pyplot as plt 7 | import csv 8 | 9 | class Sol(): 10 | def __init__(self): 11 | self.node_id_list=None 12 | self.obj=None 13 | self.fit=None 14 | self.routes=None 15 | 16 | class Node(): 17 | def __init__(self): 18 | self.id=0 19 | self.x_coord=0 20 | self.y_coord=0 21 | self.demand=0 22 | self.depot_capacity=15 23 | 24 | class Model(): 25 | def __init__(self): 26 | self.best_sol=None 27 | self.demand_dict = {} 28 | self.depot_dict = {} 29 | self.demand_id_list = [] 30 | self.opt_type=0 31 | self.vehicle_cap=0 32 | self.distance_matrix={} 33 | self.popsize=100 34 | self.alpha=2 35 | self.beta=3 36 | self.Q=100 37 | self.tau0=10 38 | self.rho=0.5 39 | self.tau={} 40 | 41 | def readCsvFile(demand_file,depot_file,model): 42 | with open(demand_file,'r') as f: 43 | demand_reader=csv.DictReader(f) 44 | for row in demand_reader: 45 | node = Node() 46 | node.id = int(row['id']) 47 | node.x_coord = float(row['x_coord']) 48 | node.y_coord = float(row['y_coord']) 49 | node.demand = float(row['demand']) 50 | model.demand_dict[node.id] = node 51 | model.demand_id_list.append(node.id) 52 | 53 | with open(depot_file,'r') as f: 54 | depot_reader=csv.DictReader(f) 55 | for row in depot_reader: 56 | node = Node() 57 | node.id = row['id'] 58 | node.x_coord=float(row['x_coord']) 59 | node.y_coord=float(row['y_coord']) 60 | node.depot_capacity=float(row['capacity']) 61 | model.depot_dict[node.id] = node 62 | 63 | def initDistanceTau(model): 64 | for i in range(len(model.demand_id_list)): 65 | from_node_id = model.demand_id_list[i] 66 | for j in range(i+1,len(model.demand_id_list)): 67 | to_node_id=model.demand_id_list[j] 68 | dist=math.sqrt( (model.demand_dict[from_node_id].x_coord-model.demand_dict[to_node_id].x_coord)**2 69 | +(model.demand_dict[from_node_id].y_coord-model.demand_dict[to_node_id].y_coord)**2) 70 | model.distance_matrix[from_node_id,to_node_id]=dist 71 | model.distance_matrix[to_node_id,from_node_id]=dist 72 | model.tau[from_node_id,to_node_id]=model.tau0 73 | model.tau[to_node_id,from_node_id]=model.tau0 74 | for _,depot in model.depot_dict.items(): 75 | dist = math.sqrt((model.demand_dict[from_node_id].x_coord - depot.x_coord) ** 2 76 | + (model.demand_dict[from_node_id].y_coord -depot.y_coord)**2) 77 | model.distance_matrix[from_node_id, depot.id] = dist 78 | model.distance_matrix[depot.id, from_node_id] = dist 79 | 80 | def selectDepot(route,depot_dict,model): 81 | min_in_out_distance=float('inf') 82 | index=None 83 | for _,depot in depot_dict.items(): 84 | if depot.depot_capacity>0: 85 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 86 | if in_out_distance= 0: 104 | route.append(node_id) 105 | remained_cap = remained_cap - model.demand_dict[node_id].demand 106 | else: 107 | route,depot_dict=selectDepot(route,depot_dict,model) 108 | vehicle_routes.append(route) 109 | route = [node_id] 110 | num_vehicle = num_vehicle + 1 111 | remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand 112 | 113 | route, depot_dict = selectDepot(route, depot_dict, model) 114 | vehicle_routes.append(route) 115 | 116 | return num_vehicle,vehicle_routes 117 | 118 | def calRouteDistance(route,model): 119 | distance=0 120 | for i in range(len(route)-1): 121 | from_node=route[i] 122 | to_node=route[i+1] 123 | distance +=model.distance_matrix[from_node,to_node] 124 | return distance 125 | 126 | def calObj(node_id_list,model): 127 | num_vehicle, vehicle_routes = splitRoutes(node_id_list, model) 128 | if model.opt_type==0: 129 | return num_vehicle,vehicle_routes 130 | else: 131 | distance = 0 132 | for route in vehicle_routes: 133 | distance += calRouteDistance(route, model) 134 | return distance,vehicle_routes 135 | 136 | def movePosition(model): 137 | sol_list=[] 138 | local_sol=Sol() 139 | local_sol.obj=float('inf') 140 | for k in range(model.popsize): 141 | #随机初始化蚂蚁为止 142 | nodes_id=[int(random.randint(0,len(model.demand_id_list)-1))] 143 | all_nodes_id=copy.deepcopy(model.demand_id_list) 144 | all_nodes_id.remove(nodes_id[-1]) 145 | #确定下一个访问节点 146 | while len(all_nodes_id)>0: 147 | next_node_no=searchNextNode(model,nodes_id[-1],all_nodes_id) 148 | nodes_id.append(next_node_no) 149 | all_nodes_id.remove(next_node_no) 150 | sol=Sol() 151 | sol.node_id_list=nodes_id 152 | sol.obj,sol.routes=calObj(nodes_id,model) 153 | sol_list.append(sol) 154 | if sol.obj 0).index(True)] 170 | return next_node_id 171 | 172 | def upateTau(model): 173 | rho=model.rho 174 | for k in model.tau.keys(): 175 | model.tau[k]=(1-rho)*model.tau[k] 176 | #根据解的node_id_list属性更新路径信息素(TSP问题的解) 177 | for sol in model.sol_list: 178 | nodes_id=sol.node_id_list 179 | for i in range(len(nodes_id)-1): 180 | from_node_id=nodes_id[i] 181 | to_node_id=nodes_id[i+1] 182 | model.tau[from_node_id,to_node_id]+=model.Q/sol.obj 183 | 184 | def plotObj(obj_list): 185 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 186 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 187 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 188 | plt.xlabel('Iterations') 189 | plt.ylabel('Obj Value') 190 | plt.grid() 191 | plt.xlim(1,len(obj_list)+1) 192 | plt.show() 193 | 194 | def outPut(model): 195 | work=xlsxwriter.Workbook('result.xlsx') 196 | worksheet=work.add_worksheet() 197 | worksheet.write(0,0,'opt_type') 198 | worksheet.write(1,0,'obj') 199 | if model.opt_type==0: 200 | worksheet.write(0,1,'number of vehicles') 201 | else: 202 | worksheet.write(0, 1, 'drive distance of vehicles') 203 | worksheet.write(1,1,model.best_sol.obj) 204 | for row,route in enumerate(model.best_sol.routes): 205 | worksheet.write(row+2,0,'v'+str(row+1)) 206 | r=[str(i)for i in route] 207 | worksheet.write(row+2,1, '-'.join(r)) 208 | work.close() 209 | 210 | def plotRoutes(model): 211 | for route in model.best_sol.routes: 212 | x_coord=[model.depot_dict[route[0]].x_coord] 213 | y_coord=[model.depot_dict[route[0]].y_coord] 214 | for node_id in route[1:-1]: 215 | x_coord.append(model.demand_dict[node_id].x_coord) 216 | y_coord.append(model.demand_dict[node_id].y_coord) 217 | x_coord.append(model.depot_dict[route[-1]].x_coord) 218 | y_coord.append(model.depot_dict[route[-1]].y_coord) 219 | plt.grid() 220 | if route[0]=='d1': 221 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 222 | elif route[0]=='d2': 223 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 224 | else: 225 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 226 | plt.xlabel('x_coord') 227 | plt.ylabel('y_coord') 228 | plt.show() 229 | 230 | def run(demand_file,depot_file,Q,tau0,alpha,beta,rho,epochs,v_cap,opt_type,popsize): 231 | """ 232 | :param demand_file: demand file path 233 | :param depot_file: depot file path 234 | :param Q: Total pheromone 235 | :param tau0: Link path initial pheromone 236 | :param alpha: Information heuristic factor 237 | :param beta: Expected heuristic factor 238 | :param rho: Information volatilization factor 239 | :param epochs: Iterations 240 | :param v_cap: Vehicle capacity 241 | :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 242 | :param popsize:Population size 243 | :return: 244 | """ 245 | model=Model() 246 | model.vehicle_cap=v_cap 247 | model.opt_type=opt_type 248 | model.alpha=alpha 249 | model.beta=beta 250 | model.Q=Q 251 | model.tau0=tau0 252 | model.rho=rho 253 | model.popsize=popsize 254 | sol=Sol() 255 | sol.obj=float('inf') 256 | model.best_sol=sol 257 | history_best_obj = [] 258 | readCsvFile(demand_file,depot_file,model) 259 | initDistanceTau(model) 260 | for ep in range(epochs): 261 | movePosition(model) 262 | upateTau(model) 263 | history_best_obj.append(model.best_sol.obj) 264 | print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj)) 265 | plotObj(history_best_obj) 266 | plotRoutes(model) 267 | outPut(model) 268 | 269 | if __name__=='__main__': 270 | demand_file = '../datasets/MDCVRP/demand.csv' 271 | depot_file = '../datasets/MDCVRP/depot.csv' 272 | run(demand_file,depot_file,Q=10,tau0=10,alpha=1,beta=5,rho=0.1,epochs=100,v_cap=60,opt_type=1,popsize=60) 273 | 274 | 275 | 276 | -------------------------------------------------------------------------------- /MDVRP/DE_MDCVRP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2021/9/10 14:54 3 | # @Author : Praise 4 | # @File : DE_MDCVRP.py 5 | # obj: 6 | import math 7 | import random 8 | import numpy as np 9 | import copy 10 | import xlsxwriter 11 | import matplotlib.pyplot as plt 12 | import csv 13 | 14 | class Sol(): 15 | def __init__(self): 16 | self.node_id_list=None 17 | self.obj=None 18 | self.routes=None 19 | 20 | class Node(): 21 | def __init__(self): 22 | self.id=0 23 | self.x_coord=0 24 | self.y_coord=0 25 | self.demand=0 26 | self.depot_capacity=15 27 | 28 | class Model(): 29 | def __init__(self): 30 | self.best_sol=None 31 | self.sol_list=[] 32 | self.demand_dict={} 33 | self.depot_dict={} 34 | self.demand_id_list = [] 35 | self.distance_matrix = {} 36 | self.opt_type=0 37 | self.vehicle_cap=0 38 | self.Cr=0.5 39 | self.F=0.5 40 | self.popsize=4*len(self.demand_id_list) 41 | 42 | def readCsvFile(demand_file,depot_file,model): 43 | with open(demand_file,'r') as f: 44 | demand_reader=csv.DictReader(f) 45 | for row in demand_reader: 46 | node = Node() 47 | node.id = int(row['id']) 48 | node.x_coord = float(row['x_coord']) 49 | node.y_coord = float(row['y_coord']) 50 | node.demand = float(row['demand']) 51 | model.demand_dict[node.id] = node 52 | model.demand_id_list.append(node.id) 53 | 54 | with open(depot_file,'r') as f: 55 | depot_reader=csv.DictReader(f) 56 | for row in depot_reader: 57 | node = Node() 58 | node.id = row['id'] 59 | node.x_coord=float(row['x_coord']) 60 | node.y_coord=float(row['y_coord']) 61 | node.depot_capacity=float(row['capacity']) 62 | model.depot_dict[node.id] = node 63 | 64 | def calDistance(model): 65 | for i in range(len(model.demand_id_list)): 66 | from_node_id = model.demand_id_list[i] 67 | for j in range(i+1,len(model.demand_id_list)): 68 | to_node_id=model.demand_id_list[j] 69 | dist=math.sqrt( (model.demand_dict[from_node_id].x_coord-model.demand_dict[to_node_id].x_coord)**2 70 | +(model.demand_dict[from_node_id].y_coord-model.demand_dict[to_node_id].y_coord)**2) 71 | model.distance_matrix[from_node_id,to_node_id]=dist 72 | model.distance_matrix[to_node_id,from_node_id]=dist 73 | for _,depot in model.depot_dict.items(): 74 | dist = math.sqrt((model.demand_dict[from_node_id].x_coord - depot.x_coord) ** 2 75 | + (model.demand_dict[from_node_id].y_coord -depot.y_coord)**2) 76 | model.distance_matrix[from_node_id, depot.id] = dist 77 | model.distance_matrix[depot.id, from_node_id] = dist 78 | 79 | def selectDepot(route,depot_dict,model): 80 | min_in_out_distance=float('inf') 81 | index=None 82 | for _,depot in depot_dict.items(): 83 | if depot.depot_capacity>0: 84 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 85 | if in_out_distance= 0: 103 | route.append(node_id) 104 | remained_cap = remained_cap - model.demand_dict[node_id].demand 105 | else: 106 | route,depot_dict=selectDepot(route,depot_dict,model) 107 | vehicle_routes.append(route) 108 | route = [node_id] 109 | num_vehicle = num_vehicle + 1 110 | remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand 111 | 112 | route, depot_dict = selectDepot(route, depot_dict, model) 113 | vehicle_routes.append(route) 114 | 115 | return num_vehicle,vehicle_routes 116 | 117 | def calRouteDistance(route,model): 118 | distance=0 119 | for i in range(len(route)-1): 120 | from_node=route[i] 121 | to_node=route[i+1] 122 | distance +=model.distance_matrix[from_node,to_node] 123 | return distance 124 | 125 | def calObj(node_id_list,model): 126 | num_vehicle, vehicle_routes = splitRoutes(node_id_list, model) 127 | if model.opt_type==0: 128 | return num_vehicle,vehicle_routes 129 | else: 130 | distance = 0 131 | for route in vehicle_routes: 132 | distance += calRouteDistance(route, model) 133 | return distance,vehicle_routes 134 | 135 | def genInitialSol(model): 136 | demand_id_list=copy.deepcopy(model.demand_id_list) 137 | for i in range(model.popsize): 138 | seed=int(random.randint(0,10)) 139 | random.seed(seed) 140 | random.shuffle(demand_id_list) 141 | sol=Sol() 142 | sol.node_id_list=copy.deepcopy(demand_id_list) 143 | sol.obj,sol.routes=calObj(sol.node_id_list,model) 144 | model.sol_list.append(sol) 145 | if sol.obj0: 89 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 90 | if in_out_distance= 0: 108 | route.append(node_id) 109 | remained_cap = remained_cap - model.demand_dict[node_id].demand 110 | else: 111 | route,depot_dict=selectDepot(route,depot_dict,model) 112 | vehicle_routes.append(route) 113 | route = [node_id] 114 | num_vehicle = num_vehicle + 1 115 | remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand 116 | 117 | route, depot_dict = selectDepot(route, depot_dict, model) 118 | vehicle_routes.append(route) 119 | 120 | return num_vehicle,vehicle_routes 121 | 122 | def calRouteDistance(route,model): 123 | distance=0 124 | for i in range(len(route)-1): 125 | from_node=route[i] 126 | to_node=route[i+1] 127 | distance +=model.distance_matrix[from_node,to_node] 128 | return distance 129 | 130 | def calObj(node_id_list,model): 131 | num_vehicle, vehicle_routes = splitRoutes(node_id_list, model) 132 | if model.opt_type==0: 133 | return num_vehicle,vehicle_routes 134 | else: 135 | distance = 0 136 | for route in vehicle_routes: 137 | distance += calRouteDistance(route, model) 138 | return distance,vehicle_routes 139 | 140 | def genInitialSol(model,popsize): 141 | demand_id_list=copy.deepcopy(model.demand_id_list) 142 | best_sol=Sol() 143 | best_sol.obj=float('inf') 144 | for i in range(popsize): 145 | seed = int(random.randint(0, 10)) 146 | random.seed(seed) 147 | random.shuffle(demand_id_list) 148 | sol=Sol() 149 | sol.node_id_list= copy.deepcopy(demand_id_list) 150 | sol.obj,sol.routes=calObj(sol.node_id_list,model) 151 | model.sol_list.append(sol) 152 | model.v.append([model.Vmax]*len(model.demand_id_list)) 153 | model.pl.append(sol.node_id_list) 154 | if sol.obj0: 174 | new_v.append(min(v_,model.Vmax)) 175 | else: 176 | new_v.append(max(v_,-model.Vmax)) 177 | new_x=[min(int(x[i]+new_v[i]),len(model.demand_id_list)-1) for i in range(len(model.demand_id_list)) ] 178 | new_x=adjustRoutes(new_x,model) 179 | model.v[id]=new_v 180 | 181 | new_x_obj,new_x_routes=calObj(new_x,model) 182 | if new_x_obj0: 81 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 82 | if in_out_distance= 0: 100 | route.append(node_id) 101 | remained_cap = remained_cap - model.demand_dict[node_id].demand 102 | else: 103 | route,depot_dict=selectDepot(route,depot_dict,model) 104 | vehicle_routes.append(route) 105 | route = [node_id] 106 | num_vehicle = num_vehicle + 1 107 | remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand 108 | 109 | route, depot_dict = selectDepot(route, depot_dict, model) 110 | vehicle_routes.append(route) 111 | 112 | return num_vehicle,vehicle_routes 113 | 114 | def calRouteDistance(route,model): 115 | distance=0 116 | for i in range(len(route)-1): 117 | from_node=route[i] 118 | to_node=route[i+1] 119 | distance +=model.distance_matrix[from_node,to_node] 120 | return distance 121 | 122 | def calFit(model): 123 | #calculate fit value:fit=Objmax-obj 124 | max_obj=-float('inf') 125 | best_sol=Sol()#record the local best solution 126 | best_sol.obj=float('inf') 127 | 128 | for sol in model.sol_list: 129 | node_id_list=sol.node_id_list 130 | num_vehicle, vehicle_routes = splitRoutes(node_id_list, model) 131 | if model.opt_type==0: 132 | sol.obj=num_vehicle 133 | sol.routes=vehicle_routes 134 | if sol.obj>max_obj: 135 | max_obj=sol.obj 136 | if sol.objmax_obj: 145 | max_obj=sol.obj 146 | if sol.obj < best_sol.obj: 147 | best_sol = copy.deepcopy(sol) 148 | #calculate fit value 149 | for sol in model.sol_list: 150 | sol.fit=max_obj-sol.obj 151 | #update the global best solution 152 | if best_sol.objmodel.popsize: 225 | break 226 | 227 | def muSol(model): 228 | sol_list=copy.deepcopy(model.sol_list) 229 | model.sol_list=[] 230 | while True: 231 | f1_index = int(random.randint(0, len(sol_list) - 1)) 232 | f1 = copy.deepcopy(sol_list[f1_index]) 233 | m1_index=random.randint(0,len(model.demand_id_list)-1) 234 | m2_index=random.randint(0,len(model.demand_id_list)-1) 235 | if m1_index!=m2_index: 236 | if random.random() <= model.pm: 237 | node1=f1.node_id_list[m1_index] 238 | f1.node_id_list[m1_index]=f1.node_id_list[m2_index] 239 | f1.node_id_list[m2_index]=node1 240 | model.sol_list.append(copy.deepcopy(f1)) 241 | else: 242 | model.sol_list.append(copy.deepcopy(f1)) 243 | if len(model.sol_list)>model.popsize: 244 | break 245 | 246 | def plotObj(obj_list): 247 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 248 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 249 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 250 | plt.xlabel('Iterations') 251 | plt.ylabel('Obj Value') 252 | plt.grid() 253 | plt.xlim(1,len(obj_list)+1) 254 | plt.show() 255 | 256 | def outPut(model): 257 | work=xlsxwriter.Workbook('result.xlsx') 258 | worksheet=work.add_worksheet() 259 | worksheet.write(0,0,'opt_type') 260 | worksheet.write(1,0,'obj') 261 | if model.opt_type==0: 262 | worksheet.write(0,1,'number of vehicles') 263 | else: 264 | worksheet.write(0, 1, 'drive distance of vehicles') 265 | worksheet.write(1,1,model.best_sol.obj) 266 | for row,route in enumerate(model.best_sol.routes): 267 | worksheet.write(row+2,0,'v'+str(row+1)) 268 | r=[str(i)for i in route] 269 | worksheet.write(row+2,1, '-'.join(r)) 270 | work.close() 271 | 272 | def plotRoutes(model): 273 | for route in model.best_sol.routes: 274 | x_coord=[model.depot_dict[route[0]].x_coord] 275 | y_coord=[model.depot_dict[route[0]].y_coord] 276 | for node_id in route[1:-1]: 277 | x_coord.append(model.demand_dict[node_id].x_coord) 278 | y_coord.append(model.demand_dict[node_id].y_coord) 279 | x_coord.append(model.depot_dict[route[-1]].x_coord) 280 | y_coord.append(model.depot_dict[route[-1]].y_coord) 281 | plt.grid() 282 | if route[0]=='d1': 283 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 284 | elif route[0]=='d2': 285 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 286 | else: 287 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 288 | plt.xlabel('x_coord') 289 | plt.ylabel('y_coord') 290 | plt.show() 291 | 292 | def run(demand_file,depot_file,epochs,pc,pm,popsize,n_select,v_cap,opt_type): 293 | """ 294 | :param demand_file: demand file path 295 | :param depot_file: depot file path 296 | :param epochs:Iterations 297 | :param pc:Crossover probability 298 | :param pm:Mutation probability 299 | :param popsize:Population size 300 | :param n_select:Number of excellent individuals selected 301 | :param v_cap:Vehicle capacity 302 | :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 303 | :return: 304 | """ 305 | model=Model() 306 | model.vehicle_cap=v_cap 307 | model.opt_type=opt_type 308 | model.pc=pc 309 | model.pm=pm 310 | model.popsize=popsize 311 | model.n_select=n_select 312 | 313 | readCsvFile(demand_file,depot_file,model) 314 | calDistance(model) 315 | generateInitialSol(model) 316 | history_best_obj = [] 317 | best_sol=Sol() 318 | best_sol.obj=float('inf') 319 | model.best_sol=best_sol 320 | for ep in range(epochs): 321 | calFit(model) 322 | selectSol(model) 323 | crossSol(model) 324 | muSol(model) 325 | history_best_obj.append(model.best_sol.obj) 326 | print("%s/%s, best obj: %s" % (ep,epochs,model.best_sol.obj)) 327 | plotObj(history_best_obj) 328 | plotRoutes(model) 329 | outPut(model) 330 | 331 | if __name__=='__main__': 332 | demand_file='./MDCVRP/demand.csv' 333 | depot_file='./MDCVRP/depot.csv' 334 | run(demand_file,depot_file,epochs=100,pc=0.6,pm=0.2,popsize=100,n_select=80,v_cap=80,opt_type=1) 335 | -------------------------------------------------------------------------------- /MDVRP/SA_MDCVRP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2021/8/27 16:40 3 | # @Author : Praise 4 | # @File : SA_MDCVRP.py 5 | # @Software: PyCharm 6 | # obj : 7 | 8 | import math 9 | import random 10 | import numpy as np 11 | import copy 12 | import xlsxwriter 13 | import csv 14 | import matplotlib.pyplot as plt 15 | 16 | class Sol(): 17 | def __init__(self): 18 | self.node_id_list=None 19 | self.obj=None 20 | self.routes=None 21 | 22 | class Node(): 23 | def __init__(self): 24 | self.id=0 25 | self.x_coord=0 26 | self.y_coord=0 27 | self.demand=0 28 | self.depot_capacity=15 29 | 30 | class Model(): 31 | def __init__(self): 32 | self.best_sol=None 33 | self.demand_dict = {} 34 | self.depot_dict = {} 35 | self.demand_id_list = [] 36 | self.distance_matrix = {} 37 | self.opt_type=0 38 | self.vehicle_cap=0 39 | 40 | def readCsvFile(demand_file, depot_file, model): 41 | with open(demand_file,'r') as f: 42 | demand_reader=csv.DictReader(f) 43 | for row in demand_reader: 44 | node = Node() 45 | node.id = int(row['id']) 46 | node.x_coord = float(row['x_coord']) 47 | node.y_coord = float(row['y_coord']) 48 | node.demand = float(row['demand']) 49 | model.demand_dict[node.id] = node 50 | model.demand_id_list.append(node.id) 51 | 52 | with open(depot_file,'r') as f: 53 | depot_reader=csv.DictReader(f) 54 | for row in depot_reader: 55 | node = Node() 56 | node.id = row['id'] 57 | node.x_coord=float(row['x_coord']) 58 | node.y_coord=float(row['y_coord']) 59 | node.depot_capacity=float(row['capacity']) 60 | model.depot_dict[node.id] = node 61 | 62 | def calDistance(model): 63 | for i in range(len(model.demand_id_list)): 64 | from_node_id = model.demand_id_list[i] 65 | for j in range(i+1,len(model.demand_id_list)): 66 | to_node_id=model.demand_id_list[j] 67 | dist=math.sqrt( (model.demand_dict[from_node_id].x_coord-model.demand_dict[to_node_id].x_coord)**2 68 | +(model.demand_dict[from_node_id].y_coord-model.demand_dict[to_node_id].y_coord)**2) 69 | model.distance_matrix[from_node_id,to_node_id]=dist 70 | model.distance_matrix[to_node_id,from_node_id]=dist 71 | for _,depot in model.depot_dict.items(): 72 | dist = math.sqrt((model.demand_dict[from_node_id].x_coord - depot.x_coord) ** 2 73 | + (model.demand_dict[from_node_id].y_coord -depot.y_coord)**2) 74 | model.distance_matrix[from_node_id, depot.id] = dist 75 | model.distance_matrix[depot.id, from_node_id] = dist 76 | 77 | def selectDepot(route,depot_dict,model): 78 | min_in_out_distance=float('inf') 79 | index=None 80 | for _,depot in depot_dict.items(): 81 | if depot.depot_capacity>0: 82 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 83 | if in_out_distance= 0: 101 | route.append(node_id) 102 | remained_cap = remained_cap - model.demand_dict[node_id].demand 103 | else: 104 | route,depot_dict=selectDepot(route,depot_dict,model) 105 | vehicle_routes.append(route) 106 | route = [node_id] 107 | num_vehicle = num_vehicle + 1 108 | remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand 109 | 110 | route, depot_dict = selectDepot(route, depot_dict, model) 111 | vehicle_routes.append(route) 112 | 113 | return num_vehicle,vehicle_routes 114 | 115 | def calRouteDistance(route,model): 116 | distance=0 117 | for i in range(len(route)-1): 118 | from_node=route[i] 119 | to_node=route[i+1] 120 | distance +=model.distance_matrix[from_node,to_node] 121 | return distance 122 | 123 | def calObj(node_id_list,model): 124 | num_vehicle, vehicle_routes = splitRoutes(node_id_list, model) 125 | if model.opt_type==0: 126 | return num_vehicle,vehicle_routes 127 | else: 128 | distance = 0 129 | for route in vehicle_routes: 130 | distance += calRouteDistance(route, model) 131 | return distance,vehicle_routes 132 | 133 | def genInitialSol(node_id_list): 134 | node_id_list=copy.deepcopy(node_id_list) 135 | random.seed(0) 136 | random.shuffle(node_id_list) 137 | return node_id_list 138 | 139 | def createActions(n): 140 | action_list=[] 141 | nswap=n//2 142 | #第一种算子(Swap):前半段与后半段对应位置一对一交换 143 | for i in range(nswap): 144 | action_list.append([1,i,i+nswap]) 145 | #第二中算子(DSwap):前半段与后半段对应位置二对二交换 146 | for i in range(0,nswap,2): 147 | action_list.append([2,i,i+nswap]) 148 | #第三种算子(Reverse):指定长度的序列反序 149 | for i in range(0,n,4): 150 | action_list.append([3,i,i+3]) 151 | return action_list 152 | 153 | def doAction(node_id_list,action): 154 | node_id_list_=copy.deepcopy(node_id_list) 155 | if action[0]==1: 156 | index_1=action[1] 157 | index_2=action[2] 158 | node_id_list_[index_1],node_id_list_[index_2]=node_id_list_[index_2],node_id_list_[index_1] 159 | return node_id_list_ 160 | elif action[0]==2: 161 | index_1 = action[1] 162 | index_2 = action[2] 163 | temporary=[node_id_list_[index_1],node_id_list_[index_1+1]] 164 | node_id_list_[index_1]=node_id_list_[index_2] 165 | node_id_list_[index_1+1]=node_id_list_[index_2+1] 166 | node_id_list_[index_2]=temporary[0] 167 | node_id_list_[index_2+1]=temporary[1] 168 | return node_id_list_ 169 | elif action[0]==3: 170 | index_1=action[1] 171 | index_2=action[2] 172 | node_id_list_[index_1:index_2+1]=list(reversed(node_id_list_[index_1:index_2+1])) 173 | return node_id_list_ 174 | 175 | def plotObj(obj_list): 176 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 177 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 178 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 179 | plt.xlabel('Iterations') 180 | plt.ylabel('Obj Value') 181 | plt.grid() 182 | plt.xlim(1,len(obj_list)+1) 183 | plt.show() 184 | 185 | def outPut(model): 186 | work=xlsxwriter.Workbook('result.xlsx') 187 | worksheet=work.add_worksheet() 188 | worksheet.write(0,0,'opt_type') 189 | worksheet.write(1,0,'obj') 190 | if model.opt_type==0: 191 | worksheet.write(0,1,'number of vehicles') 192 | else: 193 | worksheet.write(0, 1, 'drive distance of vehicles') 194 | worksheet.write(1,1,model.best_sol.obj) 195 | for row,route in enumerate(model.best_sol.routes): 196 | worksheet.write(row+2,0,'v'+str(row+1)) 197 | r=[str(i)for i in route] 198 | worksheet.write(row+2,1, '-'.join(r)) 199 | work.close() 200 | 201 | def plotRoutes(model): 202 | for route in model.best_sol.routes: 203 | x_coord=[model.depot_dict[route[0]].x_coord] 204 | y_coord=[model.depot_dict[route[0]].y_coord] 205 | for node_id in route[1:-1]: 206 | x_coord.append(model.demand_dict[node_id].x_coord) 207 | y_coord.append(model.demand_dict[node_id].y_coord) 208 | x_coord.append(model.depot_dict[route[-1]].x_coord) 209 | y_coord.append(model.depot_dict[route[-1]].y_coord) 210 | plt.grid() 211 | if route[0]=='d1': 212 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 213 | elif route[0]=='d2': 214 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 215 | else: 216 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 217 | plt.xlabel('x_coord') 218 | plt.ylabel('y_coord') 219 | plt.show() 220 | 221 | def run(demand_file,depot_file,T0,Tf,deltaT,v_cap,opt_type): 222 | """ 223 | :param demand_file: Demand file path 224 | :param depot_file: Depot file path 225 | :param T0: Init temperature 226 | :param Tf: Final temperature 227 | :param deltaT: Step or proportion of temperature drop 228 | :param v_cap: Vehicle capacity 229 | :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 230 | :return: 231 | """ 232 | model=Model() 233 | model.vehicle_cap=v_cap 234 | model.opt_type=opt_type 235 | readCsvFile(demand_file,depot_file,model) 236 | calDistance(model) 237 | action_list=createActions(len(model.demand_id_list)) 238 | history_best_obj=[] 239 | sol=Sol() 240 | sol.node_id_list=genInitialSol(model.demand_id_list) 241 | sol.obj,sol.routes=calObj(sol.node_id_list,model) 242 | model.best_sol=copy.deepcopy(sol) 243 | history_best_obj.append(sol.obj) 244 | Tk=T0 245 | nTk=len(action_list) 246 | while Tk>=Tf: 247 | for i in range(nTk): 248 | new_sol = Sol() 249 | new_sol.node_id_list = doAction(sol.node_id_list, action_list[i]) 250 | new_sol.obj, new_sol.routes = calObj(new_sol.node_id_list, model) 251 | detla_f=new_sol.obj-sol.obj 252 | if detla_f<0 or math.exp(-detla_f/Tk)>random.random(): 253 | sol=copy.deepcopy(new_sol) 254 | if sol.obj0: 128 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 129 | if in_out_distance= 0: 147 | route.append(node_id) 148 | remained_cap = remained_cap - model.demand_dict[node_id].demand 149 | else: 150 | route,depot_dict=selectDepot(route,depot_dict,model) 151 | vehicle_routes.append(route) 152 | route = [node_id] 153 | num_vehicle = num_vehicle + 1 154 | remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand 155 | 156 | route, depot_dict = selectDepot(route, depot_dict, model) 157 | vehicle_routes.append(route) 158 | 159 | return num_vehicle,vehicle_routes 160 | 161 | def calRouteDistance(route,model): 162 | distance=0 163 | for i in range(len(route)-1): 164 | from_node=route[i] 165 | to_node=route[i+1] 166 | distance +=model.distance_matrix[from_node,to_node] 167 | return distance 168 | 169 | def calObj(node_id_list,model): 170 | num_vehicle, vehicle_routes = splitRoutes(node_id_list, model) 171 | if model.opt_type==0: 172 | return num_vehicle,vehicle_routes 173 | else: 174 | distance = 0 175 | for route in vehicle_routes: 176 | distance += calRouteDistance(route, model) 177 | return distance,vehicle_routes 178 | 179 | def plotObj(obj_list): 180 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 181 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 182 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 183 | plt.xlabel('Iterations') 184 | plt.ylabel('Obj Value') 185 | plt.grid() 186 | plt.xlim(1,len(obj_list)+1) 187 | plt.show() 188 | 189 | def outPut(model): 190 | work=xlsxwriter.Workbook('result.xlsx') 191 | worksheet=work.add_worksheet() 192 | worksheet.write(0,0,'opt_type') 193 | worksheet.write(1,0,'obj') 194 | if model.opt_type==0: 195 | worksheet.write(0,1,'number of vehicles') 196 | else: 197 | worksheet.write(0, 1, 'drive distance of vehicles') 198 | worksheet.write(1,1,model.best_sol.obj) 199 | for row,route in enumerate(model.best_sol.routes): 200 | worksheet.write(row+2,0,'v'+str(row+1)) 201 | r=[str(i)for i in route] 202 | worksheet.write(row+2,1, '-'.join(r)) 203 | work.close() 204 | 205 | def plotRoutes(model): 206 | for route in model.best_sol.routes: 207 | x_coord=[model.depot_dict[route[0]].x_coord] 208 | y_coord=[model.depot_dict[route[0]].y_coord] 209 | for node_id in route[1:-1]: 210 | x_coord.append(model.demand_dict[node_id].x_coord) 211 | y_coord.append(model.demand_dict[node_id].y_coord) 212 | x_coord.append(model.depot_dict[route[-1]].x_coord) 213 | y_coord.append(model.depot_dict[route[-1]].y_coord) 214 | plt.grid() 215 | if route[0]=='d1': 216 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 217 | elif route[0]=='d2': 218 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 219 | else: 220 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 221 | plt.xlabel('x_coord') 222 | plt.ylabel('y_coord') 223 | plt.show() 224 | 225 | def run(demand_file,depot_file,epochs,v_cap,opt_type): 226 | """ 227 | :param demand_file: demand file path 228 | :param depot_file: depot file path 229 | :param epochs: Iterations 230 | :param v_cap: Vehicle capacity 231 | :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 232 | :return: 233 | """ 234 | model=Model() 235 | model.vehicle_cap=v_cap 236 | model.opt_type=opt_type 237 | readCsvFile(demand_file,depot_file,model) 238 | calDistance(model) 239 | action_list=createActions(len(model.demand_id_list)) 240 | model.tabu_list=np.zeros(len(action_list)) 241 | history_best_obj=[] 242 | sol=Sol() 243 | sol.node_id_list=generateInitialSol(model.demand_id_list) 244 | sol.obj,sol.routes=calObj(sol.node_id_list,model) 245 | model.best_sol=copy.deepcopy(sol) 246 | history_best_obj.append(sol.obj) 247 | for ep in range(epochs): 248 | local_new_sol=Sol() 249 | local_new_sol.obj=float('inf') 250 | for i in range(len(action_list)): 251 | if model.tabu_list[i]==0: 252 | new_sol=Sol() 253 | new_sol.node_id_list=doAction(sol.node_id_list,action_list[i]) 254 | new_sol.obj,new_sol.routes=calObj(new_sol.node_id_list,model) 255 | new_sol.action_id=i 256 | if new_sol.obj0: 111 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 112 | if in_out_distance=0 else depot 208 | if V[n_4]+cost <= V[n_2]: 209 | V[n_2]=V[n_4]+cost 210 | Pred[n_2]=i-1 211 | j=j+1 212 | else: 213 | break 214 | if j==len(node_id_list): 215 | break 216 | route_list= extractRoutes(node_id_list,Pred,model) 217 | return len(route_list),route_list 218 | 219 | def calObj(sol,model): 220 | 221 | node_id_list=copy.deepcopy(sol.node_id_list) 222 | num_vehicle, sol.route_list = splitRoutes(node_id_list, model) 223 | # travel cost 224 | sol.timetable_list,sol.cost_of_time,sol.cost_of_distance =calTravelCost(sol.route_list,model) 225 | if model.opt_type == 0: 226 | sol.obj=sol.cost_of_distance 227 | else: 228 | sol.obj=sol.cost_of_time 229 | 230 | def movePosition(model): 231 | sol_list=[] 232 | local_sol=Sol() 233 | local_sol.obj=float('inf') 234 | for k in range(model.popsize): 235 | nodes_id=[int(random.randint(0,len(model.demand_id_list)-1))] 236 | all_nodes_id=copy.deepcopy(model.demand_id_list) 237 | all_nodes_id.remove(nodes_id[-1]) 238 | while len(all_nodes_id)>0: 239 | next_node_no=searchNextNode(model,nodes_id[-1],all_nodes_id) 240 | nodes_id.append(next_node_no) 241 | all_nodes_id.remove(next_node_no) 242 | sol=Sol() 243 | sol.node_id_list=nodes_id 244 | calObj(sol,model) 245 | sol_list.append(sol) 246 | if sol.obj 0).index(True)] 261 | return next_node_id 262 | 263 | def upateTau(model): 264 | rho=model.rho 265 | for k in model.tau.keys(): 266 | model.tau[k]=(1-rho)*model.tau[k] 267 | for sol in model.sol_list: 268 | nodes_id=sol.node_id_list 269 | for i in range(len(nodes_id)-1): 270 | from_node_id=nodes_id[i] 271 | to_node_id=nodes_id[i+1] 272 | model.tau[from_node_id,to_node_id]+=model.Q/sol.obj 273 | 274 | def plotObj(obj_list): 275 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 276 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 277 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 278 | plt.xlabel('Iterations') 279 | plt.ylabel('Obj Value') 280 | plt.grid() 281 | plt.xlim(1,len(obj_list)+1) 282 | plt.show() 283 | 284 | def outPut(model): 285 | work=xlsxwriter.Workbook('result.xlsx') 286 | worksheet=work.add_worksheet() 287 | worksheet.write(0, 0, 'cost_of_time') 288 | worksheet.write(0, 1, 'cost_of_distance') 289 | worksheet.write(0, 2, 'opt_type') 290 | worksheet.write(0, 3, 'obj') 291 | worksheet.write(1,0,model.best_sol.cost_of_time) 292 | worksheet.write(1,1,model.best_sol.cost_of_distance) 293 | worksheet.write(1,2,model.opt_type) 294 | worksheet.write(1,3,model.best_sol.obj) 295 | worksheet.write(2,0,'vehicleID') 296 | worksheet.write(2,1,'route') 297 | worksheet.write(2,2,'timetable') 298 | for row,route in enumerate(model.best_sol.route_list): 299 | worksheet.write(row+3,0,'v'+str(row+1)) 300 | r=[str(i)for i in route] 301 | worksheet.write(row+3,1, '-'.join(r)) 302 | r=[str(i)for i in model.best_sol.timetable_list[row]] 303 | worksheet.write(row+3,2, '-'.join(r)) 304 | work.close() 305 | 306 | def plotRoutes(model): 307 | for route in model.best_sol.route_list: 308 | x_coord=[model.depot_dict[route[0]].x_coord] 309 | y_coord=[model.depot_dict[route[0]].y_coord] 310 | for node_id in route[1:-1]: 311 | x_coord.append(model.demand_dict[node_id].x_coord) 312 | y_coord.append(model.demand_dict[node_id].y_coord) 313 | x_coord.append(model.depot_dict[route[-1]].x_coord) 314 | y_coord.append(model.depot_dict[route[-1]].y_coord) 315 | plt.grid() 316 | if route[0]=='d1': 317 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 318 | elif route[0]=='d2': 319 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 320 | else: 321 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 322 | plt.xlabel('x_coord') 323 | plt.ylabel('y_coord') 324 | plt.show() 325 | 326 | def run(demand_file,depot_file,Q,tau0,alpha,beta,rho,epochs,v_cap,opt_type,popsize): 327 | """ 328 | :param demand_file: demand file path 329 | :param depot_file: depot file path 330 | :param Q: total pheromone 331 | :param tau0: Link path initial pheromone 332 | :param alpha: Information heuristic factor 333 | :param beta: Expected heuristic factor 334 | :param rho: Information volatilization factor 335 | :param epochs: Iterations 336 | :param v_cap: Vehicle capacity 337 | :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 338 | :param popsize: Population size 339 | :return: 340 | """ 341 | model=Model() 342 | model.vehicle_cap=v_cap 343 | model.opt_type=opt_type 344 | model.alpha=alpha 345 | model.beta=beta 346 | model.Q=Q 347 | model.tau0=tau0 348 | model.rho=rho 349 | model.popsize=popsize 350 | sol=Sol() 351 | sol.obj=float('inf') 352 | model.best_sol=sol 353 | history_best_obj = [] 354 | readCSVFile(demand_file,depot_file,model) 355 | calDistanceTimeMatrix(model) 356 | for ep in range(epochs): 357 | movePosition(model) 358 | upateTau(model) 359 | history_best_obj.append(model.best_sol.obj) 360 | print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj)) 361 | plotObj(history_best_obj) 362 | plotRoutes(model) 363 | outPut(model) 364 | 365 | if __name__=='__main__': 366 | demand_file = './datasets/MDVRPTW/demand.csv' 367 | depot_file = './datasets/MDVRPTW/depot.csv' 368 | run(demand_file,depot_file,Q=10,tau0=10,alpha=1,beta=5,rho=0.1,epochs=100,v_cap=80,opt_type=0,popsize=60) 369 | -------------------------------------------------------------------------------- /MDVRPTW/DE_MDVRPTW.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2021/11/10 8:54 3 | # @Author : Praise 4 | # @File : DE_MDVRPTW.py 5 | # obj: 6 | import math 7 | import random 8 | import numpy as np 9 | import copy 10 | import xlsxwriter 11 | import matplotlib.pyplot as plt 12 | import csv 13 | import sys 14 | class Sol(): 15 | def __init__(self): 16 | self.obj=None 17 | self.node_id_list=[] 18 | self.cost_of_distance=None 19 | self.cost_of_time=None 20 | self.route_list=[] 21 | self.timetable_list=[] 22 | 23 | class Node(): 24 | def __init__(self): 25 | self.id=0 26 | self.x_coord=0 27 | self.y_cooord=0 28 | self.demand=0 29 | self.depot_capacity=0 30 | self.start_time=0 31 | self.end_time=1440 32 | self.service_time=0 33 | 34 | class Model(): 35 | def __init__(self): 36 | self.best_sol=None 37 | self.sol_list=[] 38 | self.demand_dict={} 39 | self.depot_dict={} 40 | self.depot_id_list=[] 41 | self.demand_id_list=[] 42 | self.distance_matrix={} 43 | self.time_matrix={} 44 | self.number_of_demands=0 45 | self.vehicle_cap=0 46 | self.vehicle_speed=1 47 | self.opt_type=1 48 | self.Cr=0.5 49 | self.F=0.5 50 | self.popsize=4*len(self.demand_id_list) 51 | 52 | def readCSVFile(demand_file,depot_file,model): 53 | with open(demand_file,'r') as f: 54 | demand_reader=csv.DictReader(f) 55 | for row in demand_reader: 56 | node = Node() 57 | node.id = int(row['id']) 58 | node.x_coord = float(row['x_coord']) 59 | node.y_coord = float(row['y_coord']) 60 | node.demand = float(row['demand']) 61 | node.start_time=float(row['start_time']) 62 | node.end_time=float(row['end_time']) 63 | node.service_time=float(row['service_time']) 64 | model.demand_dict[node.id] = node 65 | model.demand_id_list.append(node.id) 66 | model.number_of_demands=len(model.demand_id_list) 67 | 68 | with open(depot_file, 'r') as f: 69 | depot_reader = csv.DictReader(f) 70 | for row in depot_reader: 71 | node = Node() 72 | node.id = row['id'] 73 | node.x_coord = float(row['x_coord']) 74 | node.y_coord = float(row['y_coord']) 75 | node.depot_capacity = float(row['capacity']) 76 | node.start_time=float(row['start_time']) 77 | node.end_time=float(row['end_time']) 78 | model.depot_dict[node.id] = node 79 | model.depot_id_list.append(node.id) 80 | 81 | def calDistanceTimeMatrix(model): 82 | for i in range(len(model.demand_id_list)): 83 | from_node_id = model.demand_id_list[i] 84 | for j in range(i + 1, len(model.demand_id_list)): 85 | to_node_id = model.demand_id_list[j] 86 | dist = math.sqrt((model.demand_dict[from_node_id].x_coord - model.demand_dict[to_node_id].x_coord) ** 2 87 | + (model.demand_dict[from_node_id].y_coord - model.demand_dict[to_node_id].y_coord) ** 2) 88 | model.distance_matrix[from_node_id, to_node_id] = dist 89 | model.distance_matrix[to_node_id, from_node_id] = dist 90 | model.time_matrix[from_node_id,to_node_id] = math.ceil(dist/model.vehicle_speed) 91 | model.time_matrix[to_node_id,from_node_id] = math.ceil(dist/model.vehicle_speed) 92 | for _, depot in model.depot_dict.items(): 93 | dist = math.sqrt((model.demand_dict[from_node_id].x_coord - depot.x_coord) ** 2 94 | + (model.demand_dict[from_node_id].y_coord - depot.y_coord) ** 2) 95 | model.distance_matrix[from_node_id, depot.id] = dist 96 | model.distance_matrix[depot.id, from_node_id] = dist 97 | model.time_matrix[from_node_id,depot.id] = math.ceil(dist/model.vehicle_speed) 98 | model.time_matrix[depot.id,from_node_id] = math.ceil(dist/model.vehicle_speed) 99 | 100 | def selectDepot(route,depot_dict,model): 101 | min_in_out_distance=float('inf') 102 | index=None 103 | for _,depot in depot_dict.items(): 104 | if depot.depot_capacity>0: 105 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 106 | if in_out_distance=0 else depot 202 | if V[n_4]+cost <= V[n_2]: 203 | V[n_2]=V[n_4]+cost 204 | Pred[n_2]=i-1 205 | j=j+1 206 | else: 207 | break 208 | if j==len(node_id_list): 209 | break 210 | route_list= extractRoutes(node_id_list,Pred,model) 211 | return len(route_list),route_list 212 | 213 | def calObj(sol,model): 214 | 215 | node_id_list=copy.deepcopy(sol.node_id_list) 216 | num_vehicle, sol.route_list = splitRoutes(node_id_list, model) 217 | # travel cost 218 | sol.timetable_list,sol.cost_of_time,sol.cost_of_distance =calTravelCost(sol.route_list,model) 219 | if model.opt_type == 0: 220 | sol.obj=sol.cost_of_distance 221 | else: 222 | sol.obj=sol.cost_of_time 223 | 224 | def genInitialSol(model): 225 | demand_id_list=copy.deepcopy(model.demand_id_list) 226 | for i in range(model.popsize): 227 | seed=int(random.randint(0,10)) 228 | random.seed(seed) 229 | random.shuffle(demand_id_list) 230 | sol=Sol() 231 | sol.node_id_list=copy.deepcopy(demand_id_list) 232 | calObj(sol,model) 233 | model.sol_list.append(sol) 234 | if sol.obj0: 110 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 111 | if in_out_distance=0 else depot 207 | if V[n_4]+cost <= V[n_2]: 208 | V[n_2]=V[n_4]+cost 209 | Pred[n_2]=i-1 210 | j=j+1 211 | else: 212 | break 213 | if j==len(node_id_list): 214 | break 215 | route_list= extractRoutes(node_id_list,Pred,model) 216 | return len(route_list),route_list 217 | 218 | def calObj(sol,model): 219 | node_id_list=copy.deepcopy(sol.node_id_list) 220 | num_vehicle, sol.route_list = splitRoutes(node_id_list, model) 221 | sol.timetable_list,sol.cost_of_time,sol.cost_of_distance =calTravelCost(sol.route_list,model) 222 | if model.opt_type == 0: 223 | sol.obj=sol.cost_of_distance 224 | else: 225 | sol.obj=sol.cost_of_time 226 | 227 | def genInitialSol(model,popsize): 228 | demand_id_list=copy.deepcopy(model.demand_id_list) 229 | best_sol=Sol() 230 | best_sol.obj=float('inf') 231 | for i in range(popsize): 232 | seed = int(random.randint(0, 10)) 233 | random.seed(seed) 234 | random.shuffle(demand_id_list) 235 | sol=Sol() 236 | sol.node_id_list= copy.deepcopy(demand_id_list) 237 | calObj(sol,model) 238 | model.sol_list.append(sol) 239 | model.v.append([model.Vmax]*len(model.demand_id_list)) 240 | model.pl.append(sol.node_id_list) 241 | if sol.obj0: 261 | new_v.append(min(v_,model.Vmax)) 262 | else: 263 | new_v.append(max(v_,-model.Vmax)) 264 | new_x=[min(int(x[i]+new_v[i]),len(model.demand_id_list)-1) for i in range(len(model.demand_id_list)) ] 265 | new_x=adjustRoutes(new_x,model) 266 | model.v[id]=new_v 267 | new_sol=Sol() 268 | new_sol.node_id_list=new_x 269 | calObj(new_sol,model) 270 | if new_sol.obj0: 101 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 102 | if in_out_distance=0 else depot 198 | if V[n_4]+cost <= V[n_2]: 199 | V[n_2]=V[n_4]+cost 200 | Pred[n_2]=i-1 201 | j=j+1 202 | else: 203 | break 204 | if j==len(node_id_list): 205 | break 206 | route_list= extractRoutes(node_id_list,Pred,model) 207 | return len(route_list),route_list 208 | 209 | def calObj(sol,model): 210 | 211 | node_id_list=copy.deepcopy(sol.node_id_list) 212 | num_vehicle, sol.route_list = splitRoutes(node_id_list, model) 213 | # travel cost 214 | sol.timetable_list,sol.cost_of_time,sol.cost_of_distance =calTravelCost(sol.route_list,model) 215 | if model.opt_type == 0: 216 | sol.obj=sol.cost_of_distance 217 | else: 218 | sol.obj=sol.cost_of_time 219 | 220 | def genInitialSol(node_id_list): 221 | node_id_list=copy.deepcopy(node_id_list) 222 | random.seed(0) 223 | random.shuffle(node_id_list) 224 | return node_id_list 225 | 226 | def createActions(n): 227 | action_list=[] 228 | nswap=n//2 229 | for i in range(nswap): 230 | action_list.append([1,i,i+nswap]) 231 | for i in range(0,nswap,2): 232 | action_list.append([2,i,i+nswap]) 233 | for i in range(0,n,4): 234 | action_list.append([3,i,i+3]) 235 | return action_list 236 | 237 | def doAction(node_id_list,action): 238 | node_id_list_=copy.deepcopy(node_id_list) 239 | if action[0]==1: 240 | index_1=action[1] 241 | index_2=action[2] 242 | node_id_list_[index_1],node_id_list_[index_2]=node_id_list_[index_2],node_id_list_[index_1] 243 | return node_id_list_ 244 | elif action[0]==2: 245 | index_1 = action[1] 246 | index_2 = action[2] 247 | temporary=[node_id_list_[index_1],node_id_list_[index_1+1]] 248 | node_id_list_[index_1]=node_id_list_[index_2] 249 | node_id_list_[index_1+1]=node_id_list_[index_2+1] 250 | node_id_list_[index_2]=temporary[0] 251 | node_id_list_[index_2+1]=temporary[1] 252 | return node_id_list_ 253 | elif action[0]==3: 254 | index_1=action[1] 255 | index_2=action[2] 256 | node_id_list_[index_1:index_2+1]=list(reversed(node_id_list_[index_1:index_2+1])) 257 | return node_id_list_ 258 | 259 | def plotObj(obj_list): 260 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 261 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 262 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 263 | plt.xlabel('Iterations') 264 | plt.ylabel('Obj Value') 265 | plt.grid() 266 | plt.xlim(1,len(obj_list)+1) 267 | plt.show() 268 | 269 | def outPut(model): 270 | work=xlsxwriter.Workbook('result.xlsx') 271 | worksheet=work.add_worksheet() 272 | worksheet.write(0, 0, 'cost_of_time') 273 | worksheet.write(0, 1, 'cost_of_distance') 274 | worksheet.write(0, 2, 'opt_type') 275 | worksheet.write(0, 3, 'obj') 276 | worksheet.write(1,0,model.best_sol.cost_of_time) 277 | worksheet.write(1,1,model.best_sol.cost_of_distance) 278 | worksheet.write(1,2,model.opt_type) 279 | worksheet.write(1,3,model.best_sol.obj) 280 | worksheet.write(2,0,'vehicleID') 281 | worksheet.write(2,1,'route') 282 | worksheet.write(2,2,'timetable') 283 | for row,route in enumerate(model.best_sol.route_list): 284 | worksheet.write(row+3,0,'v'+str(row+1)) 285 | r=[str(i)for i in route] 286 | worksheet.write(row+3,1, '-'.join(r)) 287 | r=[str(i)for i in model.best_sol.timetable_list[row]] 288 | worksheet.write(row+3,2, '-'.join(r)) 289 | work.close() 290 | 291 | def plotRoutes(model): 292 | for route in model.best_sol.route_list: 293 | x_coord=[model.depot_dict[route[0]].x_coord] 294 | y_coord=[model.depot_dict[route[0]].y_coord] 295 | for node_id in route[1:-1]: 296 | x_coord.append(model.demand_dict[node_id].x_coord) 297 | y_coord.append(model.demand_dict[node_id].y_coord) 298 | x_coord.append(model.depot_dict[route[-1]].x_coord) 299 | y_coord.append(model.depot_dict[route[-1]].y_coord) 300 | plt.grid() 301 | if route[0]=='d1': 302 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 303 | elif route[0]=='d2': 304 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 305 | else: 306 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 307 | plt.xlabel('x_coord') 308 | plt.ylabel('y_coord') 309 | plt.show() 310 | 311 | def run(demand_file,depot_file,T0,Tf,deltaT,v_cap,opt_type): 312 | """ 313 | :param demand_file: Demand file path 314 | :param depot_file: Depot file path 315 | :param T0: Init temperature 316 | :param Tf: Final temperature 317 | :param deltaT: Step or proportion of temperature drop 318 | :param v_cap: Vehicle capacity 319 | :param opt_type: Optimization type:0:Minimize the cost of travel distance;1:Minimize the cost of travel time 320 | :return: 321 | """ 322 | model=Model() 323 | model.vehicle_cap=v_cap 324 | model.opt_type=opt_type 325 | readCSVFile(demand_file,depot_file,model) 326 | calDistanceTimeMatrix(model) 327 | action_list=createActions(len(model.demand_id_list)) 328 | history_best_obj=[] 329 | sol=Sol() 330 | sol.node_id_list=genInitialSol(model.demand_id_list) 331 | calObj(sol,model) 332 | model.best_sol=copy.deepcopy(sol) 333 | history_best_obj.append(sol.obj) 334 | Tk=T0 335 | nTk=len(action_list) 336 | while Tk>=Tf: 337 | for i in range(nTk): 338 | new_sol = Sol() 339 | new_sol.node_id_list = doAction(sol.node_id_list, action_list[i]) 340 | calObj(new_sol, model) 341 | detla_f=new_sol.obj-sol.obj 342 | if detla_f<0 or math.exp(-detla_f/Tk)>random.random(): 343 | sol=copy.deepcopy(new_sol) 344 | if sol.obj0: 104 | in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id] 105 | if in_out_distance=0 else depot 201 | if V[n_4]+cost <= V[n_2]: 202 | V[n_2]=V[n_4]+cost 203 | Pred[n_2]=i-1 204 | j=j+1 205 | else: 206 | break 207 | if j==len(node_id_list): 208 | break 209 | route_list= extractRoutes(node_id_list,Pred,model) 210 | return len(route_list),route_list 211 | 212 | def calObj(sol,model): 213 | 214 | node_id_list=copy.deepcopy(sol.node_id_list) 215 | num_vehicle, sol.route_list = splitRoutes(node_id_list, model) 216 | # travel cost 217 | sol.timetable_list,sol.cost_of_time,sol.cost_of_distance =calTravelCost(sol.route_list,model) 218 | if model.opt_type == 0: 219 | sol.obj=sol.cost_of_distance 220 | else: 221 | sol.obj=sol.cost_of_time 222 | 223 | def createActions(n): 224 | action_list=[] 225 | nswap=n//2 226 | # Swap 227 | for i in range(nswap): 228 | action_list.append([1,i,i+nswap]) 229 | # DSwap 230 | for i in range(0,nswap,2): 231 | action_list.append([2,i,i+nswap]) 232 | # Reverse 233 | for i in range(0,n,4): 234 | action_list.append([3,i,i+3]) 235 | return action_list 236 | 237 | def doAction(node_id_list,action): 238 | node_id_list_=copy.deepcopy(node_id_list) 239 | if action[0]==1: 240 | index_1=action[1] 241 | index_2=action[2] 242 | node_id_list_[index_1],node_id_list_[index_2]=node_id_list_[index_2],node_id_list_[index_1] 243 | return node_id_list_ 244 | elif action[0]==2: 245 | index_1 = action[1] 246 | index_2 = action[2] 247 | temporary=[node_id_list_[index_1],node_id_list_[index_1+1]] 248 | node_id_list_[index_1]=node_id_list_[index_2] 249 | node_id_list_[index_1+1]=node_id_list_[index_2+1] 250 | node_id_list_[index_2]=temporary[0] 251 | node_id_list_[index_2+1]=temporary[1] 252 | return node_id_list_ 253 | elif action[0]==3: 254 | index_1=action[1] 255 | index_2=action[2] 256 | node_id_list_[index_1:index_2+1]=list(reversed(node_id_list_[index_1:index_2+1])) 257 | return node_id_list_ 258 | 259 | def generateInitialSol(node_id_list): 260 | node_id_list_=copy.deepcopy(node_id_list) 261 | random.seed(0) 262 | random.shuffle(node_id_list_) 263 | return node_id_list_ 264 | 265 | def plotObj(obj_list): 266 | plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese 267 | plt.rcParams['axes.unicode_minus'] = False # Show minus sign 268 | plt.plot(np.arange(1,len(obj_list)+1),obj_list) 269 | plt.xlabel('Iterations') 270 | plt.ylabel('Obj Value') 271 | plt.grid() 272 | plt.xlim(1,len(obj_list)+1) 273 | plt.show() 274 | 275 | def outPut(model): 276 | work=xlsxwriter.Workbook('result.xlsx') 277 | worksheet=work.add_worksheet() 278 | worksheet.write(0, 0, 'cost_of_time') 279 | worksheet.write(0, 1, 'cost_of_distance') 280 | worksheet.write(0, 2, 'opt_type') 281 | worksheet.write(0, 3, 'obj') 282 | worksheet.write(1,0,model.best_sol.cost_of_time) 283 | worksheet.write(1,1,model.best_sol.cost_of_distance) 284 | worksheet.write(1,2,model.opt_type) 285 | worksheet.write(1,3,model.best_sol.obj) 286 | worksheet.write(2,0,'vehicleID') 287 | worksheet.write(2,1,'route') 288 | worksheet.write(2,2,'timetable') 289 | for row,route in enumerate(model.best_sol.route_list): 290 | worksheet.write(row+3,0,'v'+str(row+1)) 291 | r=[str(i)for i in route] 292 | worksheet.write(row+3,1, '-'.join(r)) 293 | r=[str(i)for i in model.best_sol.timetable_list[row]] 294 | worksheet.write(row+3,2, '-'.join(r)) 295 | work.close() 296 | 297 | def plotRoutes(model): 298 | for route in model.best_sol.route_list: 299 | x_coord=[model.depot_dict[route[0]].x_coord] 300 | y_coord=[model.depot_dict[route[0]].y_coord] 301 | for node_id in route[1:-1]: 302 | x_coord.append(model.demand_dict[node_id].x_coord) 303 | y_coord.append(model.demand_dict[node_id].y_coord) 304 | x_coord.append(model.depot_dict[route[-1]].x_coord) 305 | y_coord.append(model.depot_dict[route[-1]].y_coord) 306 | plt.grid() 307 | if route[0]=='d1': 308 | plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5) 309 | elif route[0]=='d2': 310 | plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5) 311 | else: 312 | plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5) 313 | plt.xlabel('x_coord') 314 | plt.ylabel('y_coord') 315 | plt.show() 316 | 317 | def run(demand_file,depot_file,epochs,v_cap,opt_type): 318 | """ 319 | :param demand_file: demand file path 320 | :param depot_file: depot file path 321 | :param epochs: Iterations 322 | :param v_cap: Vehicle capacity 323 | :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance 324 | :return: 无 325 | """ 326 | model=Model() 327 | model.vehicle_cap=v_cap 328 | model.opt_type=opt_type 329 | readCSVFile(demand_file,depot_file,model) 330 | calDistanceTimeMatrix(model) 331 | action_list=createActions(len(model.demand_id_list)) 332 | model.tabu_list=np.zeros(len(action_list)) 333 | history_best_obj=[] 334 | sol=Sol() 335 | sol.node_id_list=generateInitialSol(model.demand_id_list) 336 | calObj(sol,model) 337 | model.best_sol=copy.deepcopy(sol) 338 | history_best_obj.append(sol.obj) 339 | for ep in range(epochs): 340 | local_new_sol=Sol() 341 | local_new_sol.obj=float('inf') 342 | for i in range(len(action_list)): 343 | if model.tabu_list[i]==0: 344 | new_sol=Sol() 345 | new_sol.node_id_list=doAction(sol.node_id_list,action_list[i]) 346 | calObj(new_sol,model) 347 | new_sol.action_id=i 348 | if new_sol.obj