├── .vscode
└── settings.json
├── README.md
├── exact_algorithms
├── DP.py
└── __pycache__
│ └── DP.cpython-39.pyc
├── heuristics
├── __pycache__
│ └── iterative_improvement_procedure.cpython-39.pyc
├── exact_partitioning.py
├── greedy_partitioning.py
└── iterative_improvement_procedure.py
└── other_functions
├── __pycache__
├── basic_functions.cpython-39.pyc
├── generating_functions.cpython-39.pyc
├── route_drawing.cpython-39.pyc
└── solving_TSP.cpython-39.pyc
├── basic_functions.py
├── generating_functions.py
├── route_drawing.py
└── solving_TSP.py
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.analysis.extraPaths": [
3 | "c:\\東工大\\塩浦研\\修論\\計算実験\\spanning_tree_scheduling\\Pareto_algorithms",
4 | "c:\\東工大\\塩浦研\\修論\\計算実験\\spanning_tree_scheduling\\PTAS",
5 | "c:\\東工大\\塩浦研\\修論\\計算実験\\spanning_tree_scheduling",
6 | "c:\\users\\kaito\\github_programs\\TSP-D\\other_functions"
7 | ]
8 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Traveling Salesman Problem with Drone
2 | This repository contains algorithms for solving Traveling Salesman Problem with Drone (TSP-D). TSP-D is a new planning problem that combine a truck and a drone to make effective deliveries in the near future. There are several types of heuristics and exact algorithms. Algorithms are coded with Python3. You can find exact or heuristic solutions of TSP-D and also can view the delivery routes of the truck and the drone. These were used in my research for bachelor's degree at Tokyo Institute of Technology in 2020.
3 |
4 | ## Finding exact solutions
5 | DP for TSP-D was proposed by Bouman, Agatz and Schmidt.
6 | ```
7 | └─exact_algorithms
8 | │ DP.py
9 | ```
10 |
11 | ## Finding heuristic solutions
12 | Two kinds of heuristic algorithms for TSP-D was proposed by Agatz, Bouman, and Schmidt. Also there are some procedures to improve the outputs of the heuristics.
13 |
14 | ```
15 | └─heuristics
16 | │ exact_partitioning.py
17 | | greedy_partitioning.py
18 | | iterative_improvement_procedure.py
19 | ```
20 |
21 | ## Other functions
22 |
23 | There are some python files that define other functions that is needed to run the main files.
24 |
25 | ```
26 | └─other_functions
27 | | basic_functions.py
28 | | generating_functions.py
29 | | route_drawing.py
30 | | solving_TSP.py
31 | ```
32 |
33 |
34 |
35 | ## References
36 | P. Bouman, N. Agatz, and M. Schmidt. “Dynamic programming approaches for the traveling
37 | salesman problem with drone.” Networks 72(2018), 528-542.
38 |
39 | N. Agatz, P. Bouman, and M. Schmidt. “Optimization approaches for the traveling salesman
40 | problem with drone.” Transportation Science 52(2018), 965-981
41 |
--------------------------------------------------------------------------------
/exact_algorithms/DP.py:
--------------------------------------------------------------------------------
1 | # you can change pass that fit to your environment
2 | import sys
3 | sys.path.append('c:\\users\\kaito\\github_programs\\TSP-D\\other_functions')
4 | sys.path.append("../")
5 | from generating_functions import *
6 | from route_drawing import *
7 | from basic_functions import t_cost,d_cost
8 | import itertools
9 | import time
10 |
11 |
12 | # V : coordinates of customers
13 | # depot : truck and drone start from depot and get back to depot
14 |
15 | def DP_for_TSPD(V,depot,alpha):
16 | n=len(V)
17 | Dt={}
18 | truck={}
19 | for i in range(1,n+1):
20 | for a in itertools.combinations(range(n),i):
21 | S=frozenset(a)
22 | for v in range(n):#始点
23 | for w in S:#終点
24 | Dt[(S,v,w)]=float('inf')#無限大に初期化
25 | if i==1:
26 | Dt[(S,v,w)]=t_cost(V[v],V[w])
27 | truck[(S,v,w)]=[w]
28 | else:
29 | Sw=S-set([w])
30 | for u in Sw:
31 | z=Dt[(Sw,v,u)]+t_cost(V[u],V[w])
32 | p=truck[(Sw,v,u)]+[w]
33 | if z
T[i,k,j]:
42 | M[i,j]=T[i,k,j]
43 | Mdrone[tsp[i],tsp[j]]=[tsp[k]]
44 | else:
45 | for k in range(i+1,n):
46 | if M[i,j]>T[i,k,j]:
47 | M[i,j]=T[i,k,j]
48 | Mdrone[tsp[i],tsp[j]]=[tsp[k]]
49 | for k in range(0,j):
50 | if M[i,j]>T[i,k,j]:
51 | M[i,j]=T[i,k,j]
52 | Mdrone[tsp[i],tsp[j]]=[tsp[k]]
53 | M[n-1,0]=t_cost(V[tsp[n-1]],V[tsp[0]])
54 |
55 | for i in range(tsp.index(depot)+1,tsp.index(depot)+n+1):
56 | D[depot,tsp[i%n]]=float('inf')
57 | Dres=float('inf')
58 | D[depot,depot]=0
59 | route[depot,depot]=[[depot]]
60 | for j in range(tsp.index(depot),i):
61 | if j%n!=i%n:
62 | d=M[j%n,i%n]+D[depot,tsp[j%n]]
63 | r=route[depot,tsp[j%n]]+[[tsp[j%n],tsp[i%n]]]
64 | if i==tsp.index(depot)+n:
65 | if Dres>d:
66 | Dres=d
67 | route[depot,depot]=r
68 |
69 | else:
70 | if D[depot,tsp[i%n]]>d:
71 | D[depot,tsp[i%n]]=d
72 | route[depot,tsp[i%n]]=r
73 |
74 | pathlen=len(route[depot,depot])
75 | path=[]
76 | for i in range(pathlen-1):
77 | path=path+route[depot,depot][i+1]
78 | if (route[depot,depot][i+1][0],route[depot,depot][i+1][1]) in Mdrone:
79 | path=path+[Mdrone[route[depot,depot][i+1][0],route[depot,depot][i+1][1]]]
80 | else:
81 | path=path+[[]]
82 |
83 | label={i:"truck" for i in tsp}
84 | for i in path:
85 | if type(i) == int:
86 | label[i] = "combined"
87 | else:
88 | if len(i) > 0:
89 | label[i[0]] = "drone"
90 |
91 | dset=set()
92 | for i in range(len(path)):
93 | if type(path[i])==list and len(path[i])==1:
94 | dset.add(path[i][0])
95 | return Dres,label,dset
96 |
97 | # initial route is calculated by using mst 2-approximation algorithm for TSP.
98 | def MST_exact_partitioning(V,depot,alpha):
99 | tsp=two_approximation_for_TSP(V)
100 | return exact_partitioning(V,tsp,depot,alpha)
101 |
102 | # initial route is calculated by using 2-opt algorithm for TSP
103 | def two_opt_exact_partitioning(V,depot,alpha):
104 | tsp = two_opt_for_TSP(V)
105 | return exact_partitioning(V,tsp,depot,alpha)
106 |
107 | # initial route is calculated by using DP for TSP.
108 | def DP_exact_partitioning(V,depot,alpha):
109 | tsp=DP_for_TSP(V)
110 | return exact_partitioning(V,tsp,depot,alpha)
111 |
112 |
113 | ## using iterative improvement procedure
114 | def improve_twopmove_exact(alg,V,depot,alpha):
115 | tsp=improve(two_points_move,exact_partitioning,alg(V),depot,V,alpha)
116 | return exact_partitioning(V,tsp,depot,alpha)
117 |
118 | def improve_twooptmove_exact(alg,V,depot,alpha):
119 | tsp=improve(two_opt_move,exact_partitioning,alg(V),depot,V,alpha)
120 | return exact_partitioning(V,tsp,depot,alpha)
121 |
122 | def improve_onepmove_exact(alg,V,depot,alpha):
123 | tsp=improve(one_point_move,exact_partitioning,alg(V),depot,V,alpha)
124 | return exact_partitioning(V,tsp,depot,alpha)
125 |
126 | def improve_all_exact(alg,V,depot,alpha):
127 | tsp=improve_all(exact_partitioning,alg(V),depot,V,alpha)
128 | return exact_partitioning(V,tsp,depot,alpha)
129 |
130 | def MST_exact_partitioning_all_improved(V,depot,alpha):
131 | tsp=improve_all(exact_partitioning,two_approximation_for_TSP(V),depot,V,alpha)
132 | return exact_partitioning(V,tsp,depot,alpha)
133 |
134 | def two_opt_exact_partitioning_all_improved(V,depot,alpha):
135 | tsp = improve_all(exact_partitioning,two_opt_for_TSP(V),depot,V,alpha)
136 | return exact_partitioning(V,tsp,depot,alpha)
137 |
138 | def DP_exact_partitioning_all_improved(V,depot,alpha):
139 | tsp=improve_all(exact_partitioning,DP_for_TSP(V),depot,V,alpha)
140 | return exact_partitioning(V,tsp,depot,alpha)
141 |
142 | def main():
143 | # you can change the size of the problems here
144 | n = 7
145 | # you can change the character of the testcases here
146 | V = testcase_uniform(n)
147 | # you can change the spped rate (alpha) between truck and drone here
148 | alpha = 2
149 |
150 | print("------------------------------------------------------------------------------------------------------------------------------------------------")
151 | start = time.time()
152 | total_cost,label,drone_nodes = two_opt_exact_partitioning(V,0,alpha)
153 | end = time.time()
154 | print(f"running time of two_opt_exact_partitioning : {round(end-start,4)} sec")
155 | print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
156 | drawing_routes_using_labels(V,label,0,drone_nodes)
157 | # print("------------------------------------------------------------------------------------------------------------------------------------------------")
158 | # start = time.time()
159 | # total_cost,path,drone_nodes = DP_exact_partitioning(V,0,alpha)
160 | # end = time.time()
161 | # print(f"running time of DP_exact_partitioning : {round(end-start,4)} sec")
162 | # print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
163 |
164 | print("------------------------------------------------------------------------------------------------------------------------------------------------")
165 | start = time.time()
166 | total_cost,path,drone_nodes = two_opt_exact_partitioning_all_improved(V,0,alpha)
167 | end = time.time()
168 | print(f"running time of two_opt_exact_partitioning_all_improved : {round(end-start,4)} sec")
169 | print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
170 | drawing_routes_using_labels(V,label,0,drone_nodes)
171 |
172 | # print("------------------------------------------------------------------------------------------------------------------------------------------------")
173 | # start = time.time()
174 | # total_cost,path,drone_nodes = DP_exact_partitioning_all_improved(V,0,alpha)
175 | # end = time.time()
176 | # print(f"running time of DP_exact_partitioning_all_improved : {round(end-start,4)} sec")
177 | # print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
178 |
179 | print("------------------------------------------------------------------------------------------------------------------------------------------------")
180 |
181 | if __name__ == '__main__':
182 | main()
--------------------------------------------------------------------------------
/heuristics/greedy_partitioning.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import sys
3 | # you can change pass that fit to your environment
4 | sys.path.append('c:\\users\\kaito\\github_programs\\TSP-D\\other_functions')
5 | sys.path.append("../")
6 | from generating_functions import *
7 | from route_drawing import *
8 | from basic_functions import t_cost,d_cost,t_pathcost
9 | from solving_TSP import *
10 | from iterative_improvement_procedure import *
11 | import time
12 |
13 | def greedy_partitioning(V,tsp,depot,alpha):#depotはindex指定ではない
14 | label={}
15 | operation={}
16 | flyop={}
17 | driveop={}
18 | tsptotal=0
19 | for i in tsp:
20 | label[i]='simple'
21 | tsptotal=tsptotal+t_cost(V[tsp[i]],V[tsp[(i+1)%len(tsp)]])
22 | n=len(label)
23 | tspdtotal=tsptotal
24 | while 'simple' in label.values():
25 | ms=[]
26 | for i in range(n):
27 | if label[tsp[i]]!='simple' or tsp[i]==depot:
28 | ms.append(-float('inf'))
29 | else:
30 | mfsi=t_cost(V[tsp[i-1]],V[tsp[i]])+t_cost(V[tsp[i]],V[tsp[(i+1)%n]])-max(d_cost(V[tsp[i-1]],V[tsp[i]],alpha)+d_cost(V[tsp[i]],V[tsp[(i+1)%n]],alpha),t_cost(V[tsp[i-1]],V[tsp[(i+1)%n]]))
31 | ms.append(mfsi)
32 | for i in range(n):
33 | if label[tsp[i-1]]=='combined' and tsp[(i-1)]!=depot:
34 | if label[tsp[i]]=='simple':
35 | j=i-2
36 | while label[tsp[j]]!='combined':
37 | if label[tsp[j]]=='drone':
38 | dronenode=j
39 | if label[tsp[(j-1)]]=='combined':
40 | pls=t_cost(V[tsp[i-1]],V[tsp[i]])+operation[(tsp[dronenode],tsp[j-1],tsp[i-1])]-max(d_cost(V[tsp[j-1]],V[tsp[dronenode]],alpha)+d_cost(V[tsp[dronenode]],V[tsp[i]],alpha),driveop[(tsp[dronenode],tsp[j-1],tsp[i-1])]+t_cost(V[tsp[i-1]],V[tsp[i]]))
41 | ms.append(pls)
42 | break
43 | j=j-1
44 | else: ms.append(-float('inf'))
45 | else: ms.append(-float('inf'))
46 | for i in range(n):
47 | if label[tsp[(i+1)%n]]=='combined' and tsp[(i+1)%n]!=depot:
48 | if label[tsp[i]]=='simple':
49 | j=(i+2)%n
50 | while label[tsp[j]]!='combined':
51 | if label[tsp[j]]=='drone':
52 | dronenode=j
53 | if label[tsp[(j+1)%n]]=='combined':
54 | prs=t_cost(V[tsp[i]],V[tsp[(i+1)%n]])+operation[(tsp[dronenode],tsp[(i+1)%n],tsp[(j+1)%n])]-max(d_cost(V[tsp[i]],V[tsp[dronenode]],alpha)+d_cost(V[tsp[dronenode]],V[tsp[(j+1)%n]],alpha),driveop[(tsp[dronenode],tsp[(i+1)%n],tsp[(j+1)%n])]+t_cost(V[tsp[i]],V[tsp[(i+1)%n]]))
55 | ms.append(prs)
56 | break
57 | j=(j+1)%n
58 | else: ms.append(-float('inf'))
59 | else: ms.append(-float('inf'))
60 | i = numpy.argmax(ms)
61 | if ms[i]>0:
62 | tspdtotal=tspdtotal-ms[i]
63 | if i//n==0:#makeflysaving
64 | label[tsp[i]]='drone'
65 | label[tsp[i-1]]='combined'
66 | label[tsp[(i+1)%n]]='combined'
67 | flyop[(tsp[i],tsp[i-1],tsp[(i+1)%n])]=d_cost(V[tsp[i-1]],V[tsp[i]],alpha)+d_cost(V[tsp[i]],V[tsp[(i+1)%n]],alpha)
68 | driveop[(tsp[i],tsp[i-1],tsp[(i+1)%n])]=t_cost(V[tsp[i-1]],V[tsp[(i+1)%n]])
69 | operation[(tsp[i],tsp[i-1],tsp[(i+1)%n])]=max(flyop[(tsp[i],tsp[i-1],tsp[(i+1)%n])],driveop[(tsp[i],tsp[i-1],tsp[(i+1)%n])])
70 | elif i//n==1:#pushleftsaving
71 | label[tsp[i%n]]='combined'
72 | label[tsp[(i-1)%n]]='truck'
73 | j=(i-2)%n
74 | while label[tsp[j]]!='combined':
75 | if label[tsp[j]]=='drone':
76 | dronenode=j
77 | if label[tsp[j-1]]=='combined':
78 | flyop[(tsp[dronenode],tsp[j-1],tsp[i%n])]=d_cost(V[tsp[j-1]],V[tsp[dronenode]],alpha)+d_cost(V[tsp[dronenode]],V[tsp[i%n]],alpha)
79 | driveop[(tsp[dronenode],tsp[j-1],tsp[i%n])]=driveop[(tsp[dronenode],tsp[j-1],tsp[(i-1)%n])]+t_cost(V[tsp[(i-1)%n]],V[tsp[i%n]])
80 | operation[(tsp[dronenode],tsp[j-1],tsp[i%n])]=max(flyop[(tsp[dronenode],tsp[j-1],tsp[i%n])],driveop[(tsp[dronenode],tsp[j-1],tsp[i%n])])
81 | break
82 | j=j-1
83 | elif i//n==2:#pushrightsaving
84 | label[tsp[i%n]]='combined'
85 | label[tsp[(i+1)%n]]='truck'
86 | j=(i+2)%n
87 | while label[tsp[j]]!='combined':
88 | if label[tsp[j]]=='drone':
89 | dronenode=j
90 | if label[tsp[(j+1)%n]]=='combined':
91 | flyop[(tsp[dronenode],tsp[i%n],tsp[(j+1)%n])]=d_cost(V[tsp[i%n]],V[tsp[dronenode]],alpha)+d_cost(V[tsp[dronenode]],V[tsp[(j+1)%n]],alpha)
92 | driveop[(tsp[dronenode],tsp[i%n],tsp[(j+1)%n])]=driveop[(tsp[dronenode],tsp[(i+1)%n],tsp[(j+1)%n])]+t_cost(V[tsp[i%n]],V[tsp[(i+1)%n]])
93 | operation[(tsp[dronenode],tsp[i%n],tsp[(j+1)%n])]=max(flyop[(tsp[dronenode],tsp[i%n],tsp[(j+1)%n])],driveop[(tsp[dronenode],tsp[i%n],tsp[(j+1)%n])])
94 | break
95 | j=(j+1)%n
96 | else:
97 | for l in label:
98 | if label[l]=='simple':
99 | label[l]='combined'
100 |
101 |
102 | dset=set()
103 | for i in label:
104 | if label[i]=='drone':
105 | dset.add(i)
106 | return tspdtotal,label,dset
107 |
108 | # initial route is calculated by using mst 2-approximation algorithm for TSP.
109 | def MST_greedy_partitioning(V,depot,alpha):
110 | tsp=two_approximation_for_TSP(V)
111 | return greedy_partitioning(V,tsp,depot,alpha)
112 |
113 | # initial route is calculated by using 2-opt algorithm for TSP
114 | def two_opt_greedy_partitioning(V,depot,alpha):
115 | tsp = two_opt_for_TSP(V)
116 | return greedy_partitioning(V,tsp,depot,alpha)
117 |
118 | # initial route is calculated by using DP for TSP.
119 | def DP_greedy_partitioning(V,depot,alpha):
120 | tsp=DP_for_TSP(V)
121 | return greedy_partitioning(V,tsp,depot,alpha)
122 |
123 | ## using iterative improvement procedure
124 | def improve_twopmove_greedy(alg,V,depot,alpha):
125 | tsp=improve(two_points_move,greedy_partitioning,alg(V),depot,V,alpha)
126 | return greedy_partitioning(V,tsp,depot,alpha)
127 |
128 | def improve_twooptmove_greedy(alg,V,depot,alpha):
129 | tsp=improve(two_opt_move,greedy_partitioning,alg(V),depot,V,alpha)
130 | return greedy_partitioning(V,tsp,depot,alpha)
131 |
132 | def improve_onepmove_greedy(alg,V,depot,alpha):
133 | tsp=improve(one_point_move,greedy_partitioning,alg(V),depot,V,alpha)
134 | return greedy_partitioning(V,tsp,depot,alpha)
135 |
136 | def improve_all_greedy(alg,V,depot,alpha):
137 | tsp=improve_all(greedy_partitioning,alg(V),depot,V,alpha)
138 | return greedy_partitioning(V,tsp,depot,alpha)
139 |
140 | def MST_greedy_partitioning_all_improved(V,depot,alpha):
141 | tsp=improve_all(greedy_partitioning,two_approximation_for_TSP(V),depot,V,alpha)
142 | return greedy_partitioning(V,tsp,depot,alpha)
143 |
144 | def two_opt_greedy_partitioning_all_improved(V,depot,alpha):
145 | tsp = improve_all(greedy_partitioning,two_opt_for_TSP(V),depot,V,alpha)
146 | return greedy_partitioning(V,tsp,depot,alpha)
147 |
148 | def DP_greedy_partitioning_all_improved(V,depot,alpha):
149 | tsp=improve_all(greedy_partitioning,DP_for_TSP(V),depot,V,alpha)
150 | return greedy_partitioning(V,tsp,depot,alpha)
151 |
152 | def main():
153 | # you can change the size of the problems here
154 | n = 15
155 | # you can change the character of the testcases here
156 | V = testcase_donuts_center(n)
157 | # you can change the spped rate between truck and drone here
158 | alpha = 2
159 |
160 | print("------------------------------------------------------------------------------------------------------------------------------------------------")
161 | start = time.time()
162 | total_cost,label,drone_nodes = two_opt_greedy_partitioning(V,0,alpha)
163 | end = time.time()
164 | print(f"running time of two_opt_greedy_partitioning : {round(end-start,4)} sec")
165 | print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
166 | drawing_routes_using_labels(V,label,0,drone_nodes)
167 |
168 | # print("------------------------------------------------------------------------------------------------------------------------------------------------")
169 | # start = time.time()
170 | # total_cost,path,drone_nodes = DP_greedy_partitioning(V,0,alpha)
171 | # end = time.time()
172 | # print(f"running time of DP_greedy_partitioning : {round(end-start,4)} sec")
173 | # print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
174 |
175 | print("------------------------------------------------------------------------------------------------------------------------------------------------")
176 | start = time.time()
177 | total_cost,label,drone_nodes = two_opt_greedy_partitioning_all_improved(V,0,alpha)
178 | end = time.time()
179 | print(f"running time of two_opt_greedy_partitioning_all_improved : {round(end-start,4)} sec")
180 | print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
181 | drawing_routes_using_labels(V,label,0,drone_nodes)
182 |
183 | # print("------------------------------------------------------------------------------------------------------------------------------------------------")
184 | # start = time.time()
185 | # total_cost,path,drone_nodes = DP_greedy_partitioning_all_improved(V,0,alpha)
186 | # end = time.time()
187 | # print(f"running time of DP_greedy_partitioning_all_improved : {round(end-start,4)} sec")
188 | # print(f"total cost (time) to deliver all of the customers : {round(total_cost,4)}")
189 |
190 | print("------------------------------------------------------------------------------------------------------------------------------------------------")
191 |
192 | # drawing_routes(V,route,0,drone_nodes)
193 |
194 | if __name__ == '__main__':
195 | main()
--------------------------------------------------------------------------------
/heuristics/iterative_improvement_procedure.py:
--------------------------------------------------------------------------------
1 | import itertools
2 |
3 | # iとjの順番を入れ替える
4 | # swap index i and j
5 | def two_points_move(lis,i,j):
6 | if iheuristic(V,newroute,depot,alpha)[0]:
41 | update=True
42 | initial=newroute
43 | f=heuristic(V,newroute,depot,alpha)[0]
44 | if update:
45 | lis=initial
46 | return initial
47 |
48 | # improving procedure using all of the moves
49 | def improve_all(heuristic,lis,depot,V,alpha):
50 | n=len(lis)
51 | initial=lis
52 | f=heuristic(V,initial,depot,alpha)[0]
53 | update=True
54 | while update:
55 | update=False
56 | for (i,j) in itertools.permutations(range(n),2):
57 | moves=[two_points_move(lis,i,j),two_opt_move(lis,i,j),one_point_move(lis,i,j)]
58 | for newroute in moves:
59 | if f>heuristic(V,newroute,depot,alpha)[0]:
60 | update=True
61 | initial=newroute
62 | f=heuristic(V,newroute,depot,alpha)[0]
63 | if update:
64 | lis=initial
65 | return initial
66 |
67 |
--------------------------------------------------------------------------------
/other_functions/__pycache__/basic_functions.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaito2399/TSP-D-algorithms/3cfbb2adf30dbe4aa3137d4ec79898a614552aec/other_functions/__pycache__/basic_functions.cpython-39.pyc
--------------------------------------------------------------------------------
/other_functions/__pycache__/generating_functions.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaito2399/TSP-D-algorithms/3cfbb2adf30dbe4aa3137d4ec79898a614552aec/other_functions/__pycache__/generating_functions.cpython-39.pyc
--------------------------------------------------------------------------------
/other_functions/__pycache__/route_drawing.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaito2399/TSP-D-algorithms/3cfbb2adf30dbe4aa3137d4ec79898a614552aec/other_functions/__pycache__/route_drawing.cpython-39.pyc
--------------------------------------------------------------------------------
/other_functions/__pycache__/solving_TSP.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaito2399/TSP-D-algorithms/3cfbb2adf30dbe4aa3137d4ec79898a614552aec/other_functions/__pycache__/solving_TSP.cpython-39.pyc
--------------------------------------------------------------------------------
/other_functions/basic_functions.py:
--------------------------------------------------------------------------------
1 | # cost(time) of trucks
2 | def t_cost(s,t):
3 | return ((s[0]-t[0])**2+(s[1]-t[1])**2)**(0.5)
4 |
5 | # cost(time) of drones
6 | def d_cost(s,t,alpha):
7 | return (1/alpha)*(((s[0]-t[0])**2+(s[1]-t[1])**2)**(0.5))
8 |
9 | ## t_cost > d_cost holds
10 |
11 |
12 | def t_pathcost(a,b,route,V):
13 | pathcost=0
14 | if ab:
18 | for i in range(a,len(route)):
19 | pathcost=pathcost+t_cost(V[route[i]],V[route[(i+1)%len(route)]])
20 | for i in range(b):
21 | pathcost=pathcost+t_cost(V[route[i]],V[route[(i+1)%len(route)]])
22 | if a==b:
23 | pathcost=0
24 |
25 | return pathcost
--------------------------------------------------------------------------------
/other_functions/generating_functions.py:
--------------------------------------------------------------------------------
1 | import random
2 | import math
3 | import numpy
4 | random.seed(0)
5 |
6 | # customers are located uniformly
7 | def testcase_uniform(n):
8 | V=[(random.uniform(0,100),random.uniform(0,100)) for i in range(n)]
9 | return V
10 |
11 | # customers are located in the shape of donut
12 | def testcase_donuts(n):
13 | V=[]
14 | for i in range(n):
15 | angle=random.uniform(0,2*math.pi)
16 | V.append((25*random.uniform(0.9,1.1)*math.cos(angle)+50,25*random.uniform(0.9,1.1)*math.sin(angle)+50))
17 | return V
18 |
19 | # customers are located in the shape of donuts but depot is in the center
20 | def testcase_donuts_center(n):
21 | V=[(50,50)]
22 | for i in range(n-1):
23 | angle=random.uniform(0,2*math.pi)
24 | V.append((25*random.uniform(0.9,1.1)*math.cos(angle)+50,25*random.uniform(0.9,1.1)*math.sin(angle)+50))
25 | return V
26 |
27 | # customers are located in more in center but less in outsides
28 | def testcase_center(n):
29 | V=[]
30 | for i in range(n):
31 | angle=random.uniform(0,2*math.pi)
32 | r=numpy.random.normal(0,25)
33 | V.append((r*math.cos(angle)+50,r*math.sin(angle)+50))
34 | return V
--------------------------------------------------------------------------------
/other_functions/route_drawing.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 |
3 | # red for truck, blue for drone
4 | def drawing_routes_for_DP(V,path,depot,drone_nodes):
5 | n = len(V)
6 | text_dict = dict(boxstyle = "round",fc = "silver", ec = "mediumblue")
7 | for i in range(n):
8 | plt.scatter(V[depot][0],V[depot][1],c='k')
9 | plt.annotate("DEPOT",size = 6, xy = (V[depot][0],V[depot][1]), bbox = text_dict)
10 | plt.scatter(V[i][0],V[i][1],c='k')
11 | if i in drone_nodes:
12 | plt.annotate(f"d{i}",size = 6, xy = (V[i][0],V[i][1]),bbox = text_dict)
13 | elif i != 0:
14 | plt.annotate(f"t{i}",size = 6, xy = (V[i][0],V[i][1]),bbox = text_dict)
15 | for i in range(len(path)):
16 | if len(path[i])>=3:
17 | for j in range(len(path[i])-2):
18 | truck_x=[V[path[i][j]][0],V[path[i][j+1]][0]]
19 | truck_y=[V[path[i][j]][1],V[path[i][j+1]][1]]
20 | plt.plot(truck_x, truck_y,c='red')
21 | truck_x=[V[path[i][-2]][0],V[path[(i+1)%len(path)][0]][0]]
22 | truck_y=[V[path[i][-2]][1],V[path[(i+1)%len(path)][0]][1]]
23 | drone_x1=[V[path[i][0]][0],V[path[i][-1][0]][0]]
24 | drone_y1=[V[path[i][0]][1],V[path[i][-1][0]][1]]
25 | drone_x2=[V[path[i][-1][0]][0],V[path[i][-2]][0]]
26 | drone_y2=[V[path[i][-1][0]][1],V[path[i][-2]][1]]
27 | plt.plot(truck_x,truck_y,c='red')
28 | plt.plot(drone_x1,drone_y1, c='blue')
29 | plt.plot(drone_x2,drone_y2, c='blue')
30 | elif len(path[i])==1:
31 | truck_x=[V[path[i][0]][0],V[path[i+1][0]][0]]
32 | truck_y=[V[path[i][0]][1],V[path[i+1][0]][1]]
33 | plt.plot(truck_x,truck_y, c='red')
34 | else:
35 | truck_x=[V[path[i][-2]][0],V[path[(i+1)%len(path)][0]][0]]
36 | truck_y=[V[path[i][-2]][1],V[path[(i+1)%len(path)][0]][1]]
37 | drone_x1=[V[path[i-1][0]][0],V[path[i][-1][0]][0]]
38 | drone_y1=[V[path[i-1][0]][1],V[path[i][-1][0]][1]]
39 | drone_x2=[V[path[i][-1][0]][0],V[path[i][-2]][0]]
40 | drone_y2=[V[path[i][-1][0]][1],V[path[i][-2]][1]]
41 | plt.plot(truck_x,truck_y,c='red')
42 | plt.plot(drone_x1,drone_y1, c='blue')
43 | plt.plot(drone_x2,drone_y2, c='blue')
44 | plt.show()
45 |
46 | def drawing_routes_using_labels(V,label,depot,drone_nodes):
47 | tsp_route = [i for i in label.keys()]
48 | n = len(V)
49 | text_dict = dict(boxstyle = "round",fc = "silver", ec = "mediumblue")
50 | for i in range(n):
51 | plt.scatter(V[depot][0],V[depot][1],c='k')
52 | plt.annotate("DEPOT",size = 6, xy = (V[depot][0],V[depot][1]), bbox = text_dict)
53 | plt.scatter(V[i][0],V[i][1],c='k')
54 | if i in drone_nodes:
55 | plt.annotate(f"d{i}",size = 6, xy = (V[i][0],V[i][1]),bbox = text_dict)
56 | elif i != 0:
57 | plt.annotate(f"t{i}",size = 6, xy = (V[i][0],V[i][1]),bbox = text_dict)
58 | for i in range(n):
59 | if label[tsp_route[i]] == "combined":
60 | if label[tsp_route[(i+1)%n]] == "combined":
61 | truck_x = (V[tsp_route[i]][0],V[tsp_route[(i+1)%n]][0])
62 | truck_y = (V[tsp_route[i]][1],V[tsp_route[(i+1)%n]][1])
63 | plt.plot(truck_x,truck_y,c="red")
64 | else:
65 | cnt = 1
66 | while label[tsp_route[(i+cnt)%n]] != "drone":
67 | cnt += 1
68 | drone_x = (V[tsp_route[i]][0],V[tsp_route[(i+cnt)%n]][0])
69 | drone_y = (V[tsp_route[i]][1],V[tsp_route[(i+cnt)%n]][1])
70 | plt.plot(drone_x,drone_y,c="blue")
71 | cnt = 1
72 | while label[tsp_route[(i+cnt)%n]] == "drone":
73 | cnt += 1
74 | truck_x = (V[tsp_route[i]][0],V[tsp_route[(i+cnt)%n]][0])
75 | truck_y = (V[tsp_route[i]][1],V[tsp_route[(i+cnt)%n]][1])
76 | plt.plot(truck_x,truck_y,c="red")
77 | elif label[tsp_route[i]] == "drone":
78 | cnt = 1
79 | while label[tsp_route[(i+cnt)%n]] != "combined":
80 | cnt += 1
81 | drone_x = (V[tsp_route[i]][0],V[tsp_route[(i+cnt)%n]][0])
82 | drone_y = (V[tsp_route[i]][1],V[tsp_route[(i+cnt)%n]][1])
83 | plt.plot(drone_x,drone_y,c="blue")
84 | else:
85 | cnt = 1
86 | while label[tsp_route[(i+cnt)%n]] == "drone":
87 | cnt += 1
88 | truck_x = (V[tsp_route[i]][0],V[tsp_route[(i+cnt)%n]][0])
89 | truck_y = (V[tsp_route[i]][1],V[tsp_route[(i+cnt)%n]][1])
90 | plt.plot(truck_x,truck_y,c="red")
91 | plt.show()
--------------------------------------------------------------------------------
/other_functions/solving_TSP.py:
--------------------------------------------------------------------------------
1 | import heapq
2 | from basic_functions import t_cost
3 | import itertools
4 |
5 | ## these algorithms return the routes
6 |
7 | # 2-approximation algorithm using minimum spanning tree
8 | def two_approximation_for_TSP(V):
9 | n = len(V)
10 | #prim
11 | mst = {i:[] for i in range(n)} # MST の隣接リスト
12 | X = set()
13 | heap = []
14 | for i in range(1,n):
15 | heapq.heappush(heap,(t_cost(V[0],V[i]),0,i))
16 | while len(heap)>0:
17 | (d,u,i)=heapq.heappop(heap)
18 | if i not in X:
19 | X.add(i)
20 | mst[u].append(i)
21 | mst[i].append(u)
22 | for w in range(n):
23 | if w not in X: heapq.heappush(heap,(t_cost(V[i],V[w]),i,w))
24 | #dfs
25 | res = []
26 | stack = [0]
27 | visited = [False]*n
28 | while len(stack)>0:
29 | i = stack.pop()
30 | if visited[i]: continue
31 | visited[i]=True
32 | res.append(i)
33 | for u in mst[i]: stack.append(u)
34 | return res
35 |
36 | # 2-opt algorithm using edge swap
37 | def two_opt_for_TSP(V):
38 | n = len(V)
39 | res = list(range(n))
40 | update = True
41 | while update:
42 | update = False
43 | for (i,j) in itertools.combinations(range(n),2):
44 | if ((t_cost(V[res[i]],V[res[i+1]])+t_cost(V[res[j]],V[res[(j+1)%n]]))>
45 | (t_cost(V[res[i]],V[res[j]])+t_cost(V[res[i+1]],V[res[(j+1)%n]]))):
46 | res[i+1:j+1] = res[j:i:-1]
47 | update = True
48 | return res
49 |
50 | # dynamic programming
51 | def DP_for_TSP(V):
52 | length = {} # length[(u,S)]: u を始点とし S の点すべてを回る最小経路長、ディクショナリ
53 | route = {} # route[(u,S)]: 最小経路長を達成するためのルート、ディクショナリ
54 | v = V[0]
55 | n = len(V)
56 | for i in range(1,n+1):
57 | for a in itertools.combinations(range(n),i):
58 | S = frozenset(a)
59 | for j in S:
60 | u = V[j]
61 | if i==1:
62 | length[(j,S)] = t_cost(v,u)
63 | route[(j,S)] = [j]
64 | else:
65 | Sj = S-set([j]) # S から j を除いたもの
66 | k=min(Sj,key=lambda k: length[(k,Sj)]+t_cost(V[k],u))#Sjの中でlength[(k,Sj)]+dist(V[k],u)が最小のものを返している
67 | length[(j,S)] = length[(k,Sj)]+t_cost(V[k],u)
68 | route[(j,S)] = route[(k,Sj)]+[j]
69 | return route[(0,frozenset(range(n)))]
--------------------------------------------------------------------------------