├── ML └── README.md ├── OR ├── ESPPRC │ ├── GetData.py │ ├── R101.txt │ ├── README.md │ ├── __pycache__ │ │ └── GetData.cpython-37.pyc │ └── spprc_gp.py ├── README.md ├── VRPTW │ ├── GetData.py │ ├── R101.txt │ ├── README.md │ ├── __pycache__ │ │ └── GetData.cpython-37.pyc │ ├── c101.txt │ └── vrptw_gb.py ├── VRPTW_CCG │ ├── GetData.py │ ├── c101.txt │ ├── r101.txt │ └── vrptw_ccg_gp.py └── labeling algorithm │ ├── GetData.py │ ├── README.md │ ├── labeling_espprc.py │ └── r101.txt ├── README.md ├── RL ├── A3C │ └── readme.md ├── DDPG │ └── readme.md ├── DQN │ ├── DQN │ │ └── DQN.py │ ├── DoubleDQN │ │ └── DoubleDQN_main.py │ ├── Dueling DDQN │ │ └── DuelingDQN_main.py │ └── readme.md ├── PPO │ └── readme.md └── README.md ├── SCIP └── README.md ├── TSP-heuristic ├── Genetic Algorithm TSP │ └── readme.md ├── Genetic Algorithm │ ├── GA_TSP.py │ ├── GetData.py │ ├── R101.txt │ └── readme.md ├── Large Scale Neighborhood Search │ └── readme.md ├── README.md ├── Simulated Annealing │ └── readme.md ├── Tabu Search-TSP │ └── README.md └── Tabu Search │ ├── GetData.py │ ├── R101.txt │ ├── README.md │ └── tabu_tsp.py └── Tools ├── README.md └── socket ├── README.md ├── client.py └── server.py /ML/README.md: -------------------------------------------------------------------------------- 1 | # ML 2 | 3 | Machine learning related materials and code 4 | 5 | 6 | 7 | 8 | Continuously updating.... 9 | 10 | -------------------------------------------------------------------------------- /OR/ESPPRC/GetData.py: -------------------------------------------------------------------------------- 1 | import math,re 2 | import numpy as np 3 | import networkx as nx 4 | import matplotlib.pyplot as plt 5 | from numpy import random 6 | 7 | np.random.seed(2021) 8 | 9 | class Data(): 10 | def __init__(self): 11 | self.color_names() 12 | self.location = [] 13 | self.capacity = 200 # 无要求 14 | self.demand = [] 15 | self.servicetime = [] 16 | self.nodeNum = [] 17 | 18 | def generate_node(self,num,map_size=100,time_upper=5000,demand_limit=20,servicetime_limit=20,capacity=200): 19 | """generate number of locations randomly in a block unit 20 | default TSP : num_vehicles=1,depot=0 21 | """ 22 | locations = [(0,0)] # locations = [(24, 3), (21, 4), (5, 1),...] 23 | demands = [0] 24 | servicetimes = [0] 25 | readyTime = [0] 26 | dueTime = [0] 27 | for _ in range(num): 28 | locations.append(tuple(np.random.randint(low=0,high=map_size,size=2))) 29 | t_ = np.random.randint(low=0,high=time_upper) 30 | readyTime.append(t_) 31 | dueTime.append(t_ + 10) # timewindows size = 10 32 | demands.append(np.random.randint(low=0,high=demand_limit)) 33 | servicetimes.append(np.random.randint(low=0,high=servicetime_limit)) 34 | # add the destination 35 | locations.append(locations[0]) 36 | readyTime.append(0) 37 | dueTime.append(time_upper*10) # notice: no more than bigM 38 | demands.append(0) 39 | servicetimes.append(0) 40 | 41 | self.location = locations 42 | self.readyTime = readyTime 43 | self.dueTime = dueTime 44 | self.demand = demands 45 | self.servicetime = servicetimes 46 | self.nodeNum = len(locations) 47 | self.capacity = capacity 48 | 49 | 50 | def get_euclidean_distance_matrix(self): 51 | """Creates callback to return distance between locations.""" 52 | distances = {} 53 | for from_counter, from_node in enumerate(self.location): 54 | distances[from_counter] = {} 55 | for to_counter, to_node in enumerate(self.location): 56 | if from_counter == to_counter: 57 | distances[from_counter][to_counter] = 0 58 | else: 59 | # Euclidean distance 60 | distances[from_counter][to_counter] = ( 61 | math.hypot((from_node[0] - to_node[0]), 62 | (from_node[1] - to_node[1]))) 63 | self.disMatrix = distances 64 | 65 | 66 | def read_solomon(self,path,customerNum=100): 67 | '''Description: load solomon dataset''' 68 | f = open(path, 'r') 69 | lines = f.readlines() 70 | locations,demand,readyTime,dueTime,serviceTime=[],[],[],[],[] 71 | for count,line in enumerate(lines): 72 | count = count + 1 73 | if(count == 5): 74 | line = line[:-1].strip() 75 | str = re.split(r" +", line) 76 | vehicleNum = int(str[0]) 77 | capacity = float(str[1]) 78 | elif(count >= 10 and count <= 10 + customerNum): 79 | line = line[:-1] 80 | str = re.split(r" +", line) 81 | locations.append((float(str[2]),float(str[3]))) 82 | demand.append(float(str[4])) 83 | readyTime.append(float(str[5])) 84 | dueTime.append(float(str[6])) 85 | serviceTime.append(float(str[7])) 86 | self.location = locations 87 | self.demand = demand 88 | readyTime[0],dueTime[0] = 0,0 89 | self.readyTime = readyTime 90 | self.dueTime = dueTime 91 | self.serviceTime = serviceTime 92 | self.vehicleNum = vehicleNum 93 | self.capacity =capacity 94 | self.add_deport() 95 | self.nodeNum = len(locations) 96 | 97 | def add_deport(self): 98 | self.location.append(self.location[0]) 99 | self.demand.append(self.demand[0]) 100 | self.readyTime.append(self.readyTime[0]) 101 | self.dueTime.append(1000) 102 | self.serviceTime.append(self.serviceTime[0]) 103 | 104 | 105 | def plot_nodes(self,locations): 106 | ''' function to plot locations''' 107 | Graph = nx.DiGraph() 108 | nodes_name = [str(x) for x in list(range(len(locations)))] 109 | Graph.add_nodes_from(nodes_name) 110 | pos_location = {nodes_name[i]:x for i,x in enumerate(locations)} 111 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-2) + ['r'] 112 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,labels=None) 113 | plt.show(Graph) 114 | 115 | def plot_route(self,locations,route,edgecolor='k',showoff=True): 116 | ''' function to plot locations and route''' 117 | 'e.g. [0,1,5,9,0]' 118 | Graph = nx.DiGraph() 119 | edge = [] 120 | edges = [] 121 | for i in route : 122 | edge.append(i) 123 | if len(edge) == 2 : 124 | edges.append(tuple(edge)) 125 | edge.pop(0) 126 | nodes_name = [x for x in list(range(len(locations)))] 127 | Graph.add_nodes_from(nodes_name) 128 | Graph.add_edges_from(edges) 129 | pos_location = {nodes_name[i] : x for i,x in enumerate(locations)} 130 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-2) + ['r'] # 第一个和最后一个红色 131 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,edge_color=edgecolor,labels=None) 132 | if showoff: 133 | plt.show(Graph) 134 | 135 | def color_names(self): 136 | self.colornames = [ 137 | '#F0F8FF', 138 | '#FAEBD7', 139 | '#00FFFF', 140 | '#7FFFD4', 141 | '#F0FFFF', 142 | '#F5F5DC', 143 | '#FFE4C4', 144 | '#000000', 145 | '#FFEBCD', 146 | '#0000FF', 147 | '#8A2BE2', 148 | '#A52A2A', 149 | '#DEB887', 150 | '#5F9EA0', 151 | '#7FFF00', 152 | '#D2691E', 153 | '#FF7F50', 154 | '#6495ED', 155 | '#FFF8DC', 156 | '#DC143C', 157 | '#00FFFF', 158 | '#00008B', 159 | '#008B8B', 160 | '#B8860B', 161 | '#A9A9A9', 162 | '#006400', 163 | '#BDB76B', 164 | '#8B008B', 165 | '#556B2F', 166 | '#FF8C00', 167 | '#9932CC', 168 | '#8B0000', 169 | '#E9967A', 170 | '#8FBC8F', 171 | '#483D8B', 172 | '#2F4F4F', 173 | '#00CED1', 174 | '#9400D3', 175 | '#FF1493', 176 | '#00BFFF', 177 | '#696969', 178 | '#1E90FF', 179 | '#B22222', 180 | '#FFFAF0', 181 | '#228B22', 182 | '#FF00FF', 183 | '#DCDCDC', 184 | '#F8F8FF', 185 | '#FFD700', 186 | '#DAA520', 187 | '#808080', 188 | '#008000', 189 | '#ADFF2F', 190 | '#F0FFF0', 191 | '#FF69B4', 192 | '#CD5C5C', 193 | '#4B0082', 194 | '#FFFFF0', 195 | '#F0E68C', 196 | '#E6E6FA', 197 | '#FFF0F5', 198 | '#7CFC00', 199 | '#FFFACD', 200 | '#ADD8E6', 201 | '#F08080', 202 | '#E0FFFF', 203 | '#FAFAD2', 204 | '#90EE90', 205 | '#D3D3D3', 206 | '#FFB6C1', 207 | '#FFA07A', 208 | '#20B2AA', 209 | '#87CEFA', 210 | '#778899', 211 | '#B0C4DE', 212 | '#FFFFE0', 213 | '#00FF00', 214 | '#32CD32', 215 | '#FAF0E6', 216 | '#FF00FF', 217 | '#800000', 218 | '#66CDAA', 219 | '#0000CD', 220 | '#BA55D3', 221 | '#9370DB', 222 | '#3CB371', 223 | '#7B68EE', 224 | '#00FA9A', 225 | '#48D1CC', 226 | '#C71585', 227 | '#191970', 228 | '#F5FFFA', 229 | '#FFE4E1', 230 | '#FFE4B5', 231 | '#FFDEAD', 232 | '#000080', 233 | '#FDF5E6', 234 | '#808000', 235 | '#6B8E23', 236 | '#FFA500', 237 | '#FF4500', 238 | '#DA70D6', 239 | '#EEE8AA', 240 | '#98FB98', 241 | '#AFEEEE', 242 | '#DB7093', 243 | '#FFEFD5', 244 | '#FFDAB9', 245 | '#CD853F', 246 | '#FFC0CB', 247 | '#DDA0DD', 248 | '#B0E0E6', 249 | '#800080', 250 | '#FF0000', 251 | '#BC8F8F', 252 | '#4169E1', 253 | '#8B4513', 254 | '#FA8072', 255 | '#FAA460', 256 | '#2E8B57', 257 | '#FFF5EE', 258 | '#A0522D', 259 | '#C0C0C0', 260 | '#87CEEB', 261 | '#6A5ACD', 262 | '#708090', 263 | '#FFFAFA', 264 | '#00FF7F', 265 | '#4682B4', 266 | '#D2B48C', 267 | '#008080', 268 | '#D8BFD8', 269 | '#FF6347', 270 | '#40E0D0', 271 | '#EE82EE', 272 | '#F5DEB3', 273 | '#FFFFFF', 274 | '#F5F5F5', 275 | '#FFFF00', 276 | '#9ACD32'] 277 | 278 | 279 | if __name__ == "__main__": 280 | ## generate data randomly 281 | nodes = Data() 282 | # nodes.generate_node(num=10) 283 | nodes.read_solomon(path=r'r101.txt',customerNum=30) 284 | nodes.get_euclidean_distance_matrix() 285 | nodes.plot_nodes(nodes.location) 286 | 287 | 288 | -------------------------------------------------------------------------------- /OR/ESPPRC/R101.txt: -------------------------------------------------------------------------------- 1 | R101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 35 35 0 0 230 0 11 | 1 41 49 10 161 171 10 12 | 2 35 17 7 50 60 10 13 | 3 55 45 13 116 126 10 14 | 4 55 20 19 149 159 10 15 | 5 15 30 26 34 44 10 16 | 6 25 30 3 99 109 10 17 | 7 20 50 5 81 91 10 18 | 8 10 43 9 95 105 10 19 | 9 55 60 16 97 107 10 20 | 10 30 60 16 124 134 10 21 | 11 20 65 12 67 77 10 22 | 12 50 35 19 63 73 10 23 | 13 30 25 23 159 169 10 24 | 14 15 10 20 32 42 10 25 | 15 30 5 8 61 71 10 26 | 16 10 20 19 75 85 10 27 | 17 5 30 2 157 167 10 28 | 18 20 40 12 87 97 10 29 | 19 15 60 17 76 86 10 30 | 20 45 65 9 126 136 10 31 | 21 45 20 11 62 72 10 32 | 22 45 10 18 97 107 10 33 | 23 55 5 29 68 78 10 34 | 24 65 35 3 153 163 10 35 | 25 65 20 6 172 182 10 36 | 26 45 30 17 132 142 10 37 | 27 35 40 16 37 47 10 38 | 28 41 37 16 39 49 10 39 | 29 64 42 9 63 73 10 40 | 30 40 60 21 71 81 10 41 | 31 31 52 27 50 60 10 42 | 32 35 69 23 141 151 10 43 | 33 53 52 11 37 47 10 44 | 34 65 55 14 117 127 10 45 | 35 63 65 8 143 153 10 46 | 36 2 60 5 41 51 10 47 | 37 20 20 8 134 144 10 48 | 38 5 5 16 83 93 10 49 | 39 60 12 31 44 54 10 50 | 40 40 25 9 85 95 10 51 | 41 42 7 5 97 107 10 52 | 42 24 12 5 31 41 10 53 | 43 23 3 7 132 142 10 54 | 44 11 14 18 69 79 10 55 | 45 6 38 16 32 42 10 56 | 46 2 48 1 117 127 10 57 | 47 8 56 27 51 61 10 58 | 48 13 52 36 165 175 10 59 | 49 6 68 30 108 118 10 60 | 50 47 47 13 124 134 10 61 | 51 49 58 10 88 98 10 62 | 52 27 43 9 52 62 10 63 | 53 37 31 14 95 105 10 64 | 54 57 29 18 140 150 10 65 | 55 63 23 2 136 146 10 66 | 56 53 12 6 130 140 10 67 | 57 32 12 7 101 111 10 68 | 58 36 26 18 200 210 10 69 | 59 21 24 28 18 28 10 70 | 60 17 34 3 162 172 10 71 | 61 12 24 13 76 86 10 72 | 62 24 58 19 58 68 10 73 | 63 27 69 10 34 44 10 74 | 64 15 77 9 73 83 10 75 | 65 62 77 20 51 61 10 76 | 66 49 73 25 127 137 10 77 | 67 67 5 25 83 93 10 78 | 68 56 39 36 142 152 10 79 | 69 37 47 6 50 60 10 80 | 70 37 56 5 182 192 10 81 | 71 57 68 15 77 87 10 82 | 72 47 16 25 35 45 10 83 | 73 44 17 9 78 88 10 84 | 74 46 13 8 149 159 10 85 | 75 49 11 18 69 79 10 86 | 76 49 42 13 73 83 10 87 | 77 53 43 14 179 189 10 88 | 78 61 52 3 96 106 10 89 | 79 57 48 23 92 102 10 90 | 80 56 37 6 182 192 10 91 | 81 55 54 26 94 104 10 92 | 82 15 47 16 55 65 10 93 | 83 14 37 11 44 54 10 94 | 84 11 31 7 101 111 10 95 | 85 16 22 41 91 101 10 96 | 86 4 18 35 94 104 10 97 | 87 28 18 26 93 103 10 98 | 88 26 52 9 74 84 10 99 | 89 26 35 15 176 186 10 100 | 90 31 67 3 95 105 10 101 | 91 15 19 1 160 170 10 102 | 92 22 22 2 18 28 10 103 | 93 18 24 22 188 198 10 104 | 94 26 27 27 100 110 10 105 | 95 25 24 20 39 49 10 106 | 96 22 27 11 135 145 10 107 | 97 25 21 12 133 143 10 108 | 98 19 21 10 58 68 10 109 | 99 20 26 9 83 93 10 110 | 100 18 18 17 185 195 10 111 | -------------------------------------------------------------------------------- /OR/ESPPRC/README.md: -------------------------------------------------------------------------------- 1 | # ESPPRC 2 | ESPPRC(Elementary Shortest Path Problem with Resource Constraints) often appears in many VRPs,the subproblem encountered in the column generation procedure would advantageously be solved as an ESPPRC. If one node can be visited mre than once, the problem can be relaxed into SPRRC. 3 | 4 | 5 | ## model 6 | 7 | The ESPPRC can be described with the following model: 8 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210410152250353.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RDWFk3MQ==,size_16,color_FFFFFF,t_70) 9 | 10 | 11 | 12 | ## Numerical example 13 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /OR/ESPPRC/__pycache__/GetData.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/OR/ESPPRC/__pycache__/GetData.cpython-37.pyc -------------------------------------------------------------------------------- /OR/ESPPRC/spprc_gp.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description: ESPPRC solved by gurobi 3 | Version: 1.0 4 | Author: 71 5 | Date: 2021-04-01 11:48:47 6 | ''' 7 | import numpy as np 8 | from gurobipy import * 9 | from GetData import * 10 | 11 | 12 | def spprc_gp(nodes): 13 | 14 | BigM = 1e8 15 | model = Model('SPPRC') 16 | #定义决策变量 17 | x = {} 18 | for i in range(nodes.nodeNum): 19 | for j in range(nodes.nodeNum): 20 | if(i != j): 21 | name = 'x_' + str(i) + '_' + str(j) 22 | x[i,j] = model.addVar(0,1,vtype= GRB.BINARY,name= name) 23 | 24 | model.update() 25 | #定义目标函数 26 | obj = LinExpr(0) 27 | for i in range(nodes.nodeNum): 28 | for j in range(nodes.nodeNum): 29 | if(i != j): 30 | obj.addTerms(-nodes.disMatrix[i][j], x[i,j]) 31 | model.setObjective(obj, GRB.MINIMIZE) 32 | 33 | # s.t 1 34 | for h in range(1, nodes.nodeNum - 1): 35 | expr1 = LinExpr(0) 36 | expr2 = LinExpr(0) 37 | for i in range(nodes.nodeNum-1): 38 | if (h != i): 39 | expr1.addTerms(1, x[i,h]) 40 | for j in range(1,nodes.nodeNum): 41 | if (h != j): 42 | expr2.addTerms(1, x[h,j]) 43 | model.addConstr(expr1 == expr2, name= 'flow_conservation_' + str(i) + str(j)) 44 | expr1.clear() 45 | expr2.clear() 46 | 47 | # s.t 2 48 | lhs = LinExpr(0) 49 | for j in range(1,nodes.nodeNum-1): 50 | lhs.addTerms(1, x[0,j]) 51 | model.addConstr(lhs == 1, name= 'depart_' + str(j)) 52 | 53 | # s.t 3 54 | lhs = LinExpr(0) 55 | for i in range(0,nodes.nodeNum-1): 56 | lhs.addTerms(1, x[i,nodes.nodeNum-1]) 57 | model.addConstr(lhs == 1, name= 'arrive_' + str(i)) 58 | 59 | # s.t 4 60 | for i in range(nodes.nodeNum): 61 | for j in range(nodes.nodeNum): 62 | if (i != j): 63 | model.addConstr(nodes.dueTime[i] + nodes.disMatrix[i][j] - nodes.dueTime[j] <= BigM*(1-x[i,j]), name = 'time_window' + str(i) + str(j)) 64 | 65 | # s.t 5 66 | lhs = LinExpr(0) 67 | for i in range(nodes.nodeNum-1): 68 | for j in range(nodes.nodeNum): 69 | if (i!=j): 70 | lhs.addTerms(nodes.demand[j], x[i,j]) 71 | model.addConstr(lhs <= nodes.capacity, name= 'capacity_limited' ) 72 | 73 | model.setParam("OutputFlag", 0) 74 | model.optimize() 75 | 76 | return model 77 | 78 | 79 | def demand_meet(custums,nodes): 80 | demand_meet_value = 0 81 | for i in custums: 82 | demand_meet_value += nodes.demand[i] 83 | return demand_meet_value 84 | 85 | def get_route(x): 86 | route = [0] 87 | while(1): 88 | count_flag = 1 89 | for i in range(len(x)): 90 | n = list(map(int, re.findall("\d+",x[i]))) 91 | if (route[-1] == n[0]): 92 | route.append(n[1]) 93 | count_flag = 0 94 | if count_flag: 95 | break 96 | return route 97 | 98 | 99 | if __name__=='__main__': 100 | nodes = Data() 101 | nodes.read_solomon(path=r'r101.txt',customerNum=10) 102 | nodes.get_euclidean_distance_matrix() 103 | model = spprc_gp(nodes) 104 | x_set,x_i,x_j = [],[],[] 105 | if model.Status==2: 106 | for item in model.getVars(): # self.model.getVars()[i]. 107 | n = list(map(int, re.findall("\d+",item.varname))) # transfer to int 108 | if item.x == 1: 109 | x_set.append(item.varname) 110 | x_i.append(n[0]) 111 | x_j.append(n[1]) 112 | if x_set: 113 | print('--------------------------------') 114 | print('obj:',-model.objVal) 115 | print('number of nodes:',nodes.nodeNum-2) 116 | print('number of meet nodes:',len(x_set)-1) 117 | print('capacity:',nodes.capacity) 118 | print('demand meet:',demand_meet(x_j,nodes)) 119 | print('x:',x_set) 120 | print('route:',get_route(x_set)) 121 | nodes.plot_route(locations=nodes.location,route=get_route(x_set),edgecolor='k') 122 | else: 123 | print('no solution!!!') 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /OR/README.md: -------------------------------------------------------------------------------- 1 | # OR exact algorithm 2 | -------------------------------------------------------------------------------- /OR/VRPTW/GetData.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description: solomon case for vrptw, distance matrix change to float type, add demand,readytime... properties, add colors 3 | Version: 1.1 4 | Author: 71 5 | Date: 2021-03-02 13:58:24 6 | ''' 7 | 8 | import math,re,copy 9 | import numpy as np 10 | import networkx as nx 11 | import matplotlib.pyplot as plt 12 | 13 | class GetData(): 14 | def __init__(self): 15 | self.color_names() 16 | 17 | def generate_locations(self,num_points,map_size,num_vehicles=1,depot=0): 18 | """generate number of locations randomly in a block unit 19 | default TSP : num_vehicles=1,depot=0 20 | """ 21 | locations=[] # locations = [(24, 3), (21, 4), (5, 1),...] 22 | for i in range(num_points): 23 | locations.append(tuple(np.random.randint(low=0,high=map_size,size=2))) 24 | class random_data(): 25 | def __init__(self): 26 | self.locations = locations 27 | self.num_vehicles = num_vehicles 28 | self.depot = depot 29 | return random_data() 30 | 31 | def get_euclidean_distance_matrix(self,locations): 32 | """Creates callback to return distance between locations.""" 33 | distances = {} 34 | for from_counter, from_node in enumerate(locations): 35 | distances[from_counter] = {} 36 | for to_counter, to_node in enumerate(locations): 37 | if from_counter == to_counter: 38 | distances[from_counter][to_counter] = 0 39 | else: 40 | # Euclidean distance 41 | distances[from_counter][to_counter] = ( 42 | math.hypot((from_node[0] - to_node[0]), 43 | (from_node[1] - to_node[1]))) 44 | return distances 45 | 46 | 47 | def read_solomon(self,path,customerNum=100): 48 | '''Description: load solomon dataset''' 49 | f = open(path, 'r') 50 | lines = f.readlines() 51 | locations,demand,readyTime,dueTime,serviceTime=[],[],[],[],[] 52 | for count,line in enumerate(lines): 53 | count = count + 1 54 | if(count == 5): 55 | line = line[:-1].strip() 56 | str = re.split(r" +", line) 57 | vehicleNum = int(str[0]) 58 | capacity = float(str[1]) 59 | elif(count >= 10 and count <= 10 + customerNum): 60 | line = line[:-1] 61 | str = re.split(r" +", line) 62 | locations.append((float(str[2]),float(str[3]))) 63 | demand.append(float(str[4])) 64 | readyTime.append(float(str[5])) 65 | dueTime.append(float(str[6])) 66 | serviceTime.append(float(str[7])) 67 | self.locations=locations 68 | self.demand = demand 69 | self.readyTime = readyTime 70 | self.dueTime = dueTime 71 | self.serviceTime = serviceTime 72 | self.vehicleNum = vehicleNum 73 | self.capacity =capacity 74 | self.add_deport() 75 | 76 | def add_deport(self): 77 | self.locations.append(self.locations[0]) 78 | self.demand.append(self.demand[0]) 79 | self.readyTime.append(self.readyTime[0]) 80 | self.dueTime.append(self.dueTime[0]) 81 | self.serviceTime.append(self.serviceTime[0]) 82 | 83 | 84 | def plot_nodes(self,locations): 85 | ''' function to plot locations''' 86 | Graph = nx.DiGraph() 87 | nodes_name = [str(x) for x in list(range(len(locations)))] 88 | Graph.add_nodes_from(nodes_name) 89 | pos_location = {nodes_name[i]:x for i,x in enumerate(locations)} 90 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-1) 91 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,labels=None) 92 | plt.show(Graph) 93 | 94 | def plot_route(self,locations,route,edgecolor='k',showoff=True): 95 | ''' function to plot locations and route''' 96 | 'e.g. [0,1,5,9,0]' 97 | Graph = nx.DiGraph() 98 | edge = [] 99 | edges = [] 100 | for i in route : 101 | edge.append(i) 102 | if len(edge) == 2 : 103 | edges.append(tuple(edge)) 104 | edge.pop(0) 105 | nodes_name = [x for x in list(range(len(locations)))] 106 | Graph.add_nodes_from(nodes_name) 107 | Graph.add_edges_from(edges) 108 | pos_location = {nodes_name[i] : x for i,x in enumerate(locations)} 109 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-2) + ['r'] # 第一个和最后一个红色 110 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,edge_color=edgecolor,labels=None) 111 | if showoff: 112 | plt.show(Graph) 113 | 114 | def color_names(self): 115 | self.colornames = [ 116 | '#F0F8FF', 117 | '#FAEBD7', 118 | '#00FFFF', 119 | '#7FFFD4', 120 | '#F0FFFF', 121 | '#F5F5DC', 122 | '#FFE4C4', 123 | '#000000', 124 | '#FFEBCD', 125 | '#0000FF', 126 | '#8A2BE2', 127 | '#A52A2A', 128 | '#DEB887', 129 | '#5F9EA0', 130 | '#7FFF00', 131 | '#D2691E', 132 | '#FF7F50', 133 | '#6495ED', 134 | '#FFF8DC', 135 | '#DC143C', 136 | '#00FFFF', 137 | '#00008B', 138 | '#008B8B', 139 | '#B8860B', 140 | '#A9A9A9', 141 | '#006400', 142 | '#BDB76B', 143 | '#8B008B', 144 | '#556B2F', 145 | '#FF8C00', 146 | '#9932CC', 147 | '#8B0000', 148 | '#E9967A', 149 | '#8FBC8F', 150 | '#483D8B', 151 | '#2F4F4F', 152 | '#00CED1', 153 | '#9400D3', 154 | '#FF1493', 155 | '#00BFFF', 156 | '#696969', 157 | '#1E90FF', 158 | '#B22222', 159 | '#FFFAF0', 160 | '#228B22', 161 | '#FF00FF', 162 | '#DCDCDC', 163 | '#F8F8FF', 164 | '#FFD700', 165 | '#DAA520', 166 | '#808080', 167 | '#008000', 168 | '#ADFF2F', 169 | '#F0FFF0', 170 | '#FF69B4', 171 | '#CD5C5C', 172 | '#4B0082', 173 | '#FFFFF0', 174 | '#F0E68C', 175 | '#E6E6FA', 176 | '#FFF0F5', 177 | '#7CFC00', 178 | '#FFFACD', 179 | '#ADD8E6', 180 | '#F08080', 181 | '#E0FFFF', 182 | '#FAFAD2', 183 | '#90EE90', 184 | '#D3D3D3', 185 | '#FFB6C1', 186 | '#FFA07A', 187 | '#20B2AA', 188 | '#87CEFA', 189 | '#778899', 190 | '#B0C4DE', 191 | '#FFFFE0', 192 | '#00FF00', 193 | '#32CD32', 194 | '#FAF0E6', 195 | '#FF00FF', 196 | '#800000', 197 | '#66CDAA', 198 | '#0000CD', 199 | '#BA55D3', 200 | '#9370DB', 201 | '#3CB371', 202 | '#7B68EE', 203 | '#00FA9A', 204 | '#48D1CC', 205 | '#C71585', 206 | '#191970', 207 | '#F5FFFA', 208 | '#FFE4E1', 209 | '#FFE4B5', 210 | '#FFDEAD', 211 | '#000080', 212 | '#FDF5E6', 213 | '#808000', 214 | '#6B8E23', 215 | '#FFA500', 216 | '#FF4500', 217 | '#DA70D6', 218 | '#EEE8AA', 219 | '#98FB98', 220 | '#AFEEEE', 221 | '#DB7093', 222 | '#FFEFD5', 223 | '#FFDAB9', 224 | '#CD853F', 225 | '#FFC0CB', 226 | '#DDA0DD', 227 | '#B0E0E6', 228 | '#800080', 229 | '#FF0000', 230 | '#BC8F8F', 231 | '#4169E1', 232 | '#8B4513', 233 | '#FA8072', 234 | '#FAA460', 235 | '#2E8B57', 236 | '#FFF5EE', 237 | '#A0522D', 238 | '#C0C0C0', 239 | '#87CEEB', 240 | '#6A5ACD', 241 | '#708090', 242 | '#FFFAFA', 243 | '#00FF7F', 244 | '#4682B4', 245 | '#D2B48C', 246 | '#008080', 247 | '#D8BFD8', 248 | '#FF6347', 249 | '#40E0D0', 250 | '#EE82EE', 251 | '#F5DEB3', 252 | '#FFFFFF', 253 | '#F5F5F5', 254 | '#FFFF00', 255 | '#9ACD32'] 256 | 257 | 258 | if __name__ == "__main__": 259 | ## generate data randomly 260 | data=GetData() 261 | random_data = data.generate_locations(num_points=10,map_size=100) 262 | dismatrix = data.get_euclidean_distance_matrix(random_data.locations) 263 | print(dismatrix) # get dismatrix randomly 264 | 265 | ## read solomon data 266 | path = r'R101.txt' 267 | solomon_data = data.read_solomon(path,customerNum=9) 268 | solomon_data_dismatrix = data.get_euclidean_distance_matrix(solomon_data.locations) 269 | print(solomon_data_dismatrix) 270 | data.plot_nodes(solomon_data.locations) 271 | ## plot function 272 | # data.plot_nodes(solomon_data.locations) 273 | route = list(range(10)) 274 | route.append(0) 275 | data.plot_route(solomon_data.locations,route) 276 | 277 | -------------------------------------------------------------------------------- /OR/VRPTW/R101.txt: -------------------------------------------------------------------------------- 1 | R101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 35 35 0 0 230 0 11 | 1 41 49 10 161 171 10 12 | 2 35 17 7 50 60 10 13 | 3 55 45 13 116 126 10 14 | 4 55 20 19 149 159 10 15 | 5 15 30 26 34 44 10 16 | 6 25 30 3 99 109 10 17 | 7 20 50 5 81 91 10 18 | 8 10 43 9 95 105 10 19 | 9 55 60 16 97 107 10 20 | 10 30 60 16 124 134 10 21 | 11 20 65 12 67 77 10 22 | 12 50 35 19 63 73 10 23 | 13 30 25 23 159 169 10 24 | 14 15 10 20 32 42 10 25 | 15 30 5 8 61 71 10 26 | 16 10 20 19 75 85 10 27 | 17 5 30 2 157 167 10 28 | 18 20 40 12 87 97 10 29 | 19 15 60 17 76 86 10 30 | 20 45 65 9 126 136 10 31 | 21 45 20 11 62 72 10 32 | 22 45 10 18 97 107 10 33 | 23 55 5 29 68 78 10 34 | 24 65 35 3 153 163 10 35 | 25 65 20 6 172 182 10 36 | 26 45 30 17 132 142 10 37 | 27 35 40 16 37 47 10 38 | 28 41 37 16 39 49 10 39 | 29 64 42 9 63 73 10 40 | 30 40 60 21 71 81 10 41 | 31 31 52 27 50 60 10 42 | 32 35 69 23 141 151 10 43 | 33 53 52 11 37 47 10 44 | 34 65 55 14 117 127 10 45 | 35 63 65 8 143 153 10 46 | 36 2 60 5 41 51 10 47 | 37 20 20 8 134 144 10 48 | 38 5 5 16 83 93 10 49 | 39 60 12 31 44 54 10 50 | 40 40 25 9 85 95 10 51 | 41 42 7 5 97 107 10 52 | 42 24 12 5 31 41 10 53 | 43 23 3 7 132 142 10 54 | 44 11 14 18 69 79 10 55 | 45 6 38 16 32 42 10 56 | 46 2 48 1 117 127 10 57 | 47 8 56 27 51 61 10 58 | 48 13 52 36 165 175 10 59 | 49 6 68 30 108 118 10 60 | 50 47 47 13 124 134 10 61 | 51 49 58 10 88 98 10 62 | 52 27 43 9 52 62 10 63 | 53 37 31 14 95 105 10 64 | 54 57 29 18 140 150 10 65 | 55 63 23 2 136 146 10 66 | 56 53 12 6 130 140 10 67 | 57 32 12 7 101 111 10 68 | 58 36 26 18 200 210 10 69 | 59 21 24 28 18 28 10 70 | 60 17 34 3 162 172 10 71 | 61 12 24 13 76 86 10 72 | 62 24 58 19 58 68 10 73 | 63 27 69 10 34 44 10 74 | 64 15 77 9 73 83 10 75 | 65 62 77 20 51 61 10 76 | 66 49 73 25 127 137 10 77 | 67 67 5 25 83 93 10 78 | 68 56 39 36 142 152 10 79 | 69 37 47 6 50 60 10 80 | 70 37 56 5 182 192 10 81 | 71 57 68 15 77 87 10 82 | 72 47 16 25 35 45 10 83 | 73 44 17 9 78 88 10 84 | 74 46 13 8 149 159 10 85 | 75 49 11 18 69 79 10 86 | 76 49 42 13 73 83 10 87 | 77 53 43 14 179 189 10 88 | 78 61 52 3 96 106 10 89 | 79 57 48 23 92 102 10 90 | 80 56 37 6 182 192 10 91 | 81 55 54 26 94 104 10 92 | 82 15 47 16 55 65 10 93 | 83 14 37 11 44 54 10 94 | 84 11 31 7 101 111 10 95 | 85 16 22 41 91 101 10 96 | 86 4 18 35 94 104 10 97 | 87 28 18 26 93 103 10 98 | 88 26 52 9 74 84 10 99 | 89 26 35 15 176 186 10 100 | 90 31 67 3 95 105 10 101 | 91 15 19 1 160 170 10 102 | 92 22 22 2 18 28 10 103 | 93 18 24 22 188 198 10 104 | 94 26 27 27 100 110 10 105 | 95 25 24 20 39 49 10 106 | 96 22 27 11 135 145 10 107 | 97 25 21 12 133 143 10 108 | 98 19 21 10 58 68 10 109 | 99 20 26 9 83 93 10 110 | 100 18 18 17 185 195 10 111 | -------------------------------------------------------------------------------- /OR/VRPTW/README.md: -------------------------------------------------------------------------------- 1 | # VRPTW 2 | The Vehicle Routing Problem with Time Windows (VRPTW) is the extension of the Capacitated Vehicle Routing Problem (CVRP) where the service at each customer must start within an associated time interval, called a time window. Time windows may be hard or soft. In case of hard time windows, a vehicle that arrives too early at a customer must wait until the customer is ready to begin service. In general, waiting before the start of a time window incurs no cost. In the case of soft time windows, every time window can be violated barring a penalty cost. The time windows may be one-sided, e.g., stated as the latest time for delivery. 3 | 4 | ## model 5 | 6 | The VRPTW can be formulated as the following multi-commodity network flow model with time-window and capacity constraints: 7 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210410162330452.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RDWFk3MQ==,size_16,color_FFFFFF,t_70) 8 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210410163058871.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RDWFk3MQ==,size_16,color_FFFFFF,t_70) 9 | 10 | 11 | 12 | 13 | 14 | ## Numerical example 15 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 16 | -------------------------------------------------------------------------------- /OR/VRPTW/__pycache__/GetData.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/OR/VRPTW/__pycache__/GetData.cpython-37.pyc -------------------------------------------------------------------------------- /OR/VRPTW/c101.txt: -------------------------------------------------------------------------------- 1 | C101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 40 50 0 0 1236 0 11 | 1 45 68 10 912 967 90 12 | 2 45 70 30 825 870 90 13 | 3 42 66 10 65 146 90 14 | 4 42 68 10 727 782 90 15 | 5 42 65 10 15 67 90 16 | 6 40 69 20 621 702 90 17 | 7 40 66 20 170 225 90 18 | 8 38 68 20 255 324 90 19 | 9 38 70 10 534 605 90 20 | 10 35 66 10 357 410 90 21 | 11 35 69 10 448 505 90 22 | 12 25 85 20 652 721 90 23 | 13 22 75 30 30 92 90 24 | 14 22 85 10 567 620 90 25 | 15 20 80 40 384 429 90 26 | 16 20 85 40 475 528 90 27 | 17 18 75 20 99 148 90 28 | 18 15 75 20 179 254 90 29 | 19 15 80 10 278 345 90 30 | 20 30 50 10 10 73 90 31 | 21 30 52 20 914 965 90 32 | 22 28 52 20 812 883 90 33 | 23 28 55 10 732 777 90 34 | 24 25 50 10 65 144 90 35 | 25 25 52 40 169 224 90 36 | 26 25 55 10 622 701 90 37 | 27 23 52 10 261 316 90 38 | 28 23 55 20 546 593 90 39 | 29 20 50 10 358 405 90 40 | 30 20 55 10 449 504 90 41 | 31 10 35 20 200 237 90 42 | 32 10 40 30 31 100 90 43 | 33 8 40 40 87 158 90 44 | 34 8 45 20 751 816 90 45 | 35 5 35 10 283 344 90 46 | 36 5 45 10 665 716 90 47 | 37 2 40 20 383 434 90 48 | 38 0 40 30 479 522 90 49 | 39 0 45 20 567 624 90 50 | 40 35 30 10 264 321 90 51 | 41 35 32 10 166 235 90 52 | 42 33 32 20 68 149 90 53 | 43 33 35 10 16 80 90 54 | 44 32 30 10 359 412 90 55 | 45 30 30 10 541 600 90 56 | 46 30 32 30 448 509 90 57 | 47 30 35 10 1054 1127 90 58 | 48 28 30 10 632 693 90 59 | 49 28 35 10 1001 1066 90 60 | 50 26 32 10 815 880 90 61 | 51 25 30 10 725 786 90 62 | 52 25 35 10 912 969 90 63 | 53 44 5 20 286 347 90 64 | 54 42 10 40 186 257 90 65 | 55 42 15 10 95 158 90 66 | 56 40 5 30 385 436 90 67 | 57 40 15 40 35 87 90 68 | 58 38 5 30 471 534 90 69 | 59 38 15 10 651 740 90 70 | 60 35 5 20 562 629 90 71 | 61 50 30 10 531 610 90 72 | 62 50 35 20 262 317 90 73 | 63 50 40 50 171 218 90 74 | 64 48 30 10 632 693 90 75 | 65 48 40 10 76 129 90 76 | 66 47 35 10 826 875 90 77 | 67 47 40 10 12 77 90 78 | 68 45 30 10 734 777 90 79 | 69 45 35 10 916 969 90 80 | 70 95 30 30 387 456 90 81 | 71 95 35 20 293 360 90 82 | 72 53 30 10 450 505 90 83 | 73 92 30 10 478 551 90 84 | 74 53 35 50 353 412 90 85 | 75 45 65 20 997 1068 90 86 | 76 90 35 10 203 260 90 87 | 77 88 30 10 574 643 90 88 | 78 88 35 20 109 170 90 89 | 79 87 30 10 668 731 90 90 | 80 85 25 10 769 820 90 91 | 81 85 35 30 47 124 90 92 | 82 75 55 20 369 420 90 93 | 83 72 55 10 265 338 90 94 | 84 70 58 20 458 523 90 95 | 85 68 60 30 555 612 90 96 | 86 66 55 10 173 238 90 97 | 87 65 55 20 85 144 90 98 | 88 65 60 30 645 708 90 99 | 89 63 58 10 737 802 90 100 | 90 60 55 10 20 84 90 101 | 91 60 60 10 836 889 90 102 | 92 67 85 20 368 441 90 103 | 93 65 85 40 475 518 90 104 | 94 65 82 10 285 336 90 105 | 95 62 80 30 196 239 90 106 | 96 60 80 10 95 156 90 107 | 97 60 85 30 561 622 90 108 | 98 58 75 20 30 84 90 109 | 99 55 80 10 743 820 90 110 | 100 55 85 20 647 726 90 111 | -------------------------------------------------------------------------------- /OR/VRPTW/vrptw_gb.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description: gurobi for vrptw 3 | Version: 1.0 4 | Author: 71 5 | Date: 2021-03-02 13:55:02 6 | ''' 7 | import gurobipy as gp 8 | from gurobipy import * 9 | import numpy as np 10 | from GetData import * 11 | import time,re 12 | 13 | 14 | def add_vrptw_st(data): 15 | x={} 16 | s={} 17 | model = gp.Model("VRPTW") 18 | BigM = 100000 19 | #定义决策变量 20 | for k in range(data.vehicleNum): 21 | for i in range(data.nodeNum): 22 | name = 's_' + str(i) + '_' + str(k) 23 | s[i,k] = model.addVar(0 24 | , 1500 25 | , vtype= GRB.CONTINUOUS 26 | , name= name) 27 | for j in range(data.nodeNum): 28 | if(i != j): 29 | name = 'x_' + str(i) + '_' + str(j) + '_' + str(k) 30 | x[i,j,k] = model.addVar(0 31 | , 1 32 | , vtype= GRB.BINARY 33 | , name= name) 34 | #更新模型 35 | model.update() 36 | #定义目标函数 37 | obj = LinExpr(0) 38 | for k in range(data.vehicleNum): 39 | for i in range(data.nodeNum): 40 | for j in range(data.nodeNum): 41 | if(i != j): 42 | obj.addTerms(data.disMatrix[i][j], x[i,j,k]) 43 | model.setObjective(obj, GRB.MINIMIZE) 44 | 45 | # s.t.1 : leave from depot once 46 | for k in range(data.vehicleNum): 47 | lhs = LinExpr(0) 48 | for j in range(1,data.nodeNum): 49 | lhs.addTerms(1, x[0,j,k]) 50 | model.addConstr(lhs == 1, name= 'vehicle_depart_' + str(k)) 51 | 52 | # s.t.2 : flow balance 53 | for k in range(data.vehicleNum): 54 | for h in range(1, data.nodeNum - 1): 55 | expr1 = LinExpr(0) 56 | expr2 = LinExpr(0) 57 | for i in range(data.nodeNum): 58 | if (h != i): 59 | expr1.addTerms(1, x[i,h,k]) 60 | for j in range(data.nodeNum): 61 | if (h != j): 62 | expr2.addTerms(1, x[h,j,k]) 63 | model.addConstr(expr1 == expr2, name= 'flow_conservation_' + str(i)) 64 | expr1.clear() 65 | expr2.clear() 66 | 67 | # s.t.3 : comeback depot once 68 | for k in range(data.vehicleNum): 69 | lhs = LinExpr(0) 70 | for j in range(1,data.nodeNum - 1): 71 | lhs.addTerms(1, x[j, data.nodeNum-1, k]) 72 | model.addConstr(lhs == 1, name= 'vehicle_depart_' + str(k)) 73 | 74 | # s.t.4 : visit every custumer once 75 | for i in range(1, data.nodeNum - 1): 76 | lhs = LinExpr(0) 77 | for k in range(data.vehicleNum): 78 | for j in range(1, data.nodeNum): 79 | if(i != j): 80 | lhs.addTerms(1, x[i,j,k]) 81 | model.addConstr(lhs == 1, name= 'customer_visit_' + str(i)) 82 | 83 | # s.t.5 : time windows 84 | for k in range(data.vehicleNum): 85 | for i in range(data.nodeNum): 86 | for j in range(data.nodeNum): 87 | if(i != j): 88 | model.addConstr(s[i,k] + data.disMatrix[i][j] + data.serviceTime[i] - s[j,k] 89 | - BigM + BigM * x[i,j,k] <= 0 , name= 'time_windows_') 90 | 91 | # s.t.6 : time windows 92 | for i in range(1,data.nodeNum-1): 93 | for k in range(data.vehicleNum): 94 | model.addConstr(data.readyTime[i] <= s[i,k], name= 'ready_time') 95 | model.addConstr(s[i,k] <= data.dueTime[i], name= 'due_time') 96 | 97 | # s.t.7 : capacity limited 98 | for k in range(data.vehicleNum): 99 | lhs = LinExpr(0) 100 | for i in range(1, data.nodeNum - 1): 101 | for j in range(data.nodeNum): 102 | if(i != j): 103 | lhs.addTerms(data.demand[i], x[i,j,k]) 104 | model.addConstr(lhs <= data.capacity, name= 'capacity_vehicle' + str(k)) 105 | 106 | return model 107 | 108 | 109 | if __name__=='__main__': 110 | 111 | # data read 112 | data=GetData() 113 | # parameters 114 | data.customerNum = 25 #100 115 | ## read solomon data 116 | path = r'c101.txt' 117 | data.read_solomon(path,data.customerNum) 118 | data.disMatrix = data.get_euclidean_distance_matrix(data.locations) 119 | data.nodeNum = len(data.disMatrix) 120 | data.vehicleNum = 20 #10 121 | 122 | start_time =time.time() 123 | model = add_vrptw_st(data) 124 | model.optimize() 125 | end_time =time.time() 126 | 127 | print('\n--solving time-- :',model.Runtime) 128 | print('\n--running time-- :',end_time-start_time) 129 | print("\n-----optimal value-----") 130 | print('Obj:',model.ObjVal) 131 | print('vehicles:',data.vehicleNum) 132 | # model.printAttr('x') 133 | 134 | try: 135 | x_available = [] 136 | for i in range(len(model._Model__vars)): 137 | if model._Model__vars[i].Varname[0]=='x' and model._Model__vars[i].x ==1: # take x=1 138 | x_available.append(model._Model__vars[i].Varname) 139 | colors_ = np.random.choice(a=data.colornames, size=data.vehicleNum,replace=False) 140 | 141 | for i in range(data.vehicleNum): 142 | route_v = [] 143 | for j in x_available: # take vechile_x route 144 | n = list(map(int, re.findall("\d+",j))) # transfer to int 145 | if n[-1]==i: 146 | n.pop() 147 | route_v.append(n) 148 | route = [y for x in route_v for y in x] # flatten list 149 | route = list(set(route)) # Eliminate the same elements 150 | route.append(0) # back to depot 151 | 152 | print('vehicle_{}:{}'.format(str(i),route)) 153 | if i==data.vehicleNum-1: 154 | data.plot_route(data.locations,route,edgecolor=colors_[i],showoff=True) 155 | else: 156 | data.plot_route(data.locations,route,edgecolor=colors_[i],showoff=False) 157 | except: 158 | print('infeasible!') 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /OR/VRPTW_CCG/GetData.py: -------------------------------------------------------------------------------- 1 | import math,re 2 | import numpy as np 3 | import networkx as nx 4 | import matplotlib.pyplot as plt 5 | from numpy import random 6 | 7 | 8 | class Data(): 9 | def __init__(self): 10 | self.color_names() 11 | self.location = [] 12 | self.capacity = 200 # 无要求 13 | self.demand = [] 14 | self.servicetime = [] 15 | self.nodeNum = [] 16 | 17 | def generate_node(self,num,map_size=100,time_upper=1000,tw_size=100,demand_limit=20,servicetime_limit=20,capacity=200): 18 | """generate number of locations randomly in a block unit 19 | default TSP : num_vehicles=1,depot=0 20 | """ 21 | locations = [(0,0)] # locations = [(24, 3), (21, 4), (5, 1),...] 22 | demands = [0] 23 | servicetimes = [0] 24 | readyTime = [0] 25 | dueTime = [0] 26 | for _ in range(num): 27 | locations.append(tuple(np.random.randint(low=0,high=map_size,size=2))) 28 | t_ = np.random.randint(low=0,high=time_upper) 29 | readyTime.append(t_) 30 | dueTime.append(t_ + np.random.randint(tw_size)) # timewindows size = 10 31 | demands.append(np.random.randint(low=0,high=demand_limit)) 32 | servicetimes.append(np.random.randint(low=0,high=servicetime_limit)) 33 | # add the destination 34 | locations.append(locations[0]) 35 | readyTime.append(0) 36 | dueTime.append(time_upper*100) # notice: no more than bigM 37 | demands.append(0) 38 | servicetimes.append(0) 39 | 40 | self.location = locations 41 | self.readyTime = readyTime 42 | self.dueTime = dueTime 43 | self.demand = demands 44 | self.servicetime = servicetimes 45 | self.nodeNum = len(locations) 46 | self.capacity = capacity 47 | 48 | 49 | def get_euclidean_distance_matrix(self): 50 | """Creates callback to return distance between locations.""" 51 | distances = {} 52 | for from_counter, from_node in enumerate(self.location): 53 | distances[from_counter] = [] 54 | temp_list = [] 55 | for to_counter, to_node in enumerate(self.location): 56 | if from_counter == to_counter: 57 | temp_list.append(0) 58 | # distances[from_counter][to_counter] = 0 59 | else: 60 | # Euclidean distance 61 | temp_list.append( 62 | math.hypot((from_node[0] - to_node[0]), 63 | (from_node[1] - to_node[1])) 64 | ) 65 | # distances[from_counter][to_counter] = ( 66 | # math.hypot((from_node[0] - to_node[0]), 67 | # (from_node[1] - to_node[1]))) 68 | distances[from_counter] = temp_list 69 | self.disMatrix = distances 70 | 71 | def get_time_dismatrix(self): 72 | time_distances={} 73 | for i in range(len(self.dueTime)): 74 | time_dis = (np.array(self.dueTime)-np.array(self.dueTime[i])).tolist() 75 | # print(time_dis) 76 | for j in range(len(time_dis)): 77 | if time_dis[j]<0 or self.disMatrix[i][j]+self.dueTime[i]>self.dueTime[j]: 78 | time_dis[j] = 100000 79 | time_distances[i] = time_dis 80 | self.timedisMatrix = time_distances 81 | 82 | def read_solomon(self,path,customerNum=100): 83 | '''Description: load solomon dataset''' 84 | f = open(path, 'r') 85 | lines = f.readlines() 86 | locations,demand,readyTime,dueTime,serviceTime=[],[],[],[],[] 87 | for count,line in enumerate(lines): 88 | count = count + 1 89 | if(count == 5): 90 | line = line[:-1].strip() 91 | str = re.split(r" +", line) 92 | vehicleNum = int(str[0]) 93 | capacity = float(str[1]) 94 | elif(count >= 10 and count <= 10 + customerNum): 95 | line = line[:-1] 96 | str = re.split(r" +", line) 97 | locations.append((float(str[2]),float(str[3]))) 98 | demand.append(float(str[4])) 99 | readyTime.append(float(str[5])) 100 | dueTime.append(float(str[6])) 101 | serviceTime.append(float(str[7])) 102 | self.location = locations 103 | self.demand = demand 104 | readyTime[0],dueTime[0] = 0,0 105 | self.readyTime = readyTime 106 | self.dueTime = dueTime 107 | self.serviceTime = serviceTime 108 | self.vehicleNum = vehicleNum 109 | self.capacity =capacity 110 | self.add_deport() 111 | self.nodeNum = len(locations) 112 | self.customerNum = customerNum 113 | 114 | def add_deport(self): 115 | self.location.append(self.location[0]) 116 | self.demand.append(self.demand[0]) 117 | self.readyTime.append(self.readyTime[0]) 118 | self.dueTime.append(1000) 119 | self.serviceTime.append(self.serviceTime[0]) 120 | 121 | 122 | def plot_nodes(self): 123 | ''' function to plot locations''' 124 | self.location 125 | Graph = nx.DiGraph() 126 | nodes_name = [str(x) for x in list(range(len(self.location)))] 127 | Graph.add_nodes_from(nodes_name) 128 | pos_location = {nodes_name[i]:x for i,x in enumerate(self.location)} 129 | nodes_color_dict = ['r'] + ['gray'] * (len(self.location)-2) + ['r'] 130 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,labels=None) 131 | plt.show(Graph) 132 | 133 | def plot_route(self,locations,route,edgecolor='k',showoff=True): 134 | ''' function to plot locations and route''' 135 | 'e.g. [0,1,5,9,0]' 136 | Graph = nx.DiGraph() 137 | edge = [] 138 | edges = [] 139 | for i in route : 140 | edge.append(i) 141 | if len(edge) == 2 : 142 | edges.append(tuple(edge)) 143 | edge.pop(0) 144 | nodes_name = [x for x in list(range(len(locations)))] 145 | Graph.add_nodes_from(nodes_name) 146 | Graph.add_edges_from(edges) 147 | pos_location = {nodes_name[i] : x for i,x in enumerate(locations)} 148 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-2) + ['r'] # 第一个和最后一个红色 149 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,edge_color=edgecolor,labels=None) 150 | if showoff: 151 | plt.show(Graph) 152 | 153 | def color_names(self): 154 | self.colornames = [ 155 | '#F0F8FF', 156 | '#FAEBD7', 157 | '#00FFFF', 158 | '#7FFFD4', 159 | '#F0FFFF', 160 | '#F5F5DC', 161 | '#FFE4C4', 162 | '#000000', 163 | '#FFEBCD', 164 | '#0000FF', 165 | '#8A2BE2', 166 | '#A52A2A', 167 | '#DEB887', 168 | '#5F9EA0', 169 | '#7FFF00', 170 | '#D2691E', 171 | '#FF7F50', 172 | '#6495ED', 173 | '#FFF8DC', 174 | '#DC143C', 175 | '#00FFFF', 176 | '#00008B', 177 | '#008B8B', 178 | '#B8860B', 179 | '#A9A9A9', 180 | '#006400', 181 | '#BDB76B', 182 | '#8B008B', 183 | '#556B2F', 184 | '#FF8C00', 185 | '#9932CC', 186 | '#8B0000', 187 | '#E9967A', 188 | '#8FBC8F', 189 | '#483D8B', 190 | '#2F4F4F', 191 | '#00CED1', 192 | '#9400D3', 193 | '#FF1493', 194 | '#00BFFF', 195 | '#696969', 196 | '#1E90FF', 197 | '#B22222', 198 | '#FFFAF0', 199 | '#228B22', 200 | '#FF00FF', 201 | '#DCDCDC', 202 | '#F8F8FF', 203 | '#FFD700', 204 | '#DAA520', 205 | '#808080', 206 | '#008000', 207 | '#ADFF2F', 208 | '#F0FFF0', 209 | '#FF69B4', 210 | '#CD5C5C', 211 | '#4B0082', 212 | '#FFFFF0', 213 | '#F0E68C', 214 | '#E6E6FA', 215 | '#FFF0F5', 216 | '#7CFC00', 217 | '#FFFACD', 218 | '#ADD8E6', 219 | '#F08080', 220 | '#E0FFFF', 221 | '#FAFAD2', 222 | '#90EE90', 223 | '#D3D3D3', 224 | '#FFB6C1', 225 | '#FFA07A', 226 | '#20B2AA', 227 | '#87CEFA', 228 | '#778899', 229 | '#B0C4DE', 230 | '#FFFFE0', 231 | '#00FF00', 232 | '#32CD32', 233 | '#FAF0E6', 234 | '#FF00FF', 235 | '#800000', 236 | '#66CDAA', 237 | '#0000CD', 238 | '#BA55D3', 239 | '#9370DB', 240 | '#3CB371', 241 | '#7B68EE', 242 | '#00FA9A', 243 | '#48D1CC', 244 | '#C71585', 245 | '#191970', 246 | '#F5FFFA', 247 | '#FFE4E1', 248 | '#FFE4B5', 249 | '#FFDEAD', 250 | '#000080', 251 | '#FDF5E6', 252 | '#808000', 253 | '#6B8E23', 254 | '#FFA500', 255 | '#FF4500', 256 | '#DA70D6', 257 | '#EEE8AA', 258 | '#98FB98', 259 | '#AFEEEE', 260 | '#DB7093', 261 | '#FFEFD5', 262 | '#FFDAB9', 263 | '#CD853F', 264 | '#FFC0CB', 265 | '#DDA0DD', 266 | '#B0E0E6', 267 | '#800080', 268 | '#FF0000', 269 | '#BC8F8F', 270 | '#4169E1', 271 | '#8B4513', 272 | '#FA8072', 273 | '#FAA460', 274 | '#2E8B57', 275 | '#FFF5EE', 276 | '#A0522D', 277 | '#C0C0C0', 278 | '#87CEEB', 279 | '#6A5ACD', 280 | '#708090', 281 | '#FFFAFA', 282 | '#00FF7F', 283 | '#4682B4', 284 | '#D2B48C', 285 | '#008080', 286 | '#D8BFD8', 287 | '#FF6347', 288 | '#40E0D0', 289 | '#EE82EE', 290 | '#F5DEB3', 291 | '#FFFFFF', 292 | '#F5F5F5', 293 | '#FFFF00', 294 | '#9ACD32'] 295 | 296 | 297 | if __name__ == "__main__": 298 | ## generate data randomly 299 | nodes = Data() 300 | # nodes.generate_node(num=10) 301 | # nodes.read_solomon(path=r'r101.txt',customerNum=30) 302 | nodes.generate_node(num=20) 303 | nodes.get_euclidean_distance_matrix() 304 | nodes.get_time_dismatrix() 305 | 306 | nodes.plot_nodes() 307 | 308 | 309 | -------------------------------------------------------------------------------- /OR/VRPTW_CCG/c101.txt: -------------------------------------------------------------------------------- 1 | C101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 40 50 0 0 1236 0 11 | 1 45 68 10 912 967 90 12 | 2 45 70 30 825 870 90 13 | 3 42 66 10 65 146 90 14 | 4 42 68 10 727 782 90 15 | 5 42 65 10 15 67 90 16 | 6 40 69 20 621 702 90 17 | 7 40 66 20 170 225 90 18 | 8 38 68 20 255 324 90 19 | 9 38 70 10 534 605 90 20 | 10 35 66 10 357 410 90 21 | 11 35 69 10 448 505 90 22 | 12 25 85 20 652 721 90 23 | 13 22 75 30 30 92 90 24 | 14 22 85 10 567 620 90 25 | 15 20 80 40 384 429 90 26 | 16 20 85 40 475 528 90 27 | 17 18 75 20 99 148 90 28 | 18 15 75 20 179 254 90 29 | 19 15 80 10 278 345 90 30 | 20 30 50 10 10 73 90 31 | 21 30 52 20 914 965 90 32 | 22 28 52 20 812 883 90 33 | 23 28 55 10 732 777 90 34 | 24 25 50 10 65 144 90 35 | 25 25 52 40 169 224 90 36 | 26 25 55 10 622 701 90 37 | 27 23 52 10 261 316 90 38 | 28 23 55 20 546 593 90 39 | 29 20 50 10 358 405 90 40 | 30 20 55 10 449 504 90 41 | 31 10 35 20 200 237 90 42 | 32 10 40 30 31 100 90 43 | 33 8 40 40 87 158 90 44 | 34 8 45 20 751 816 90 45 | 35 5 35 10 283 344 90 46 | 36 5 45 10 665 716 90 47 | 37 2 40 20 383 434 90 48 | 38 0 40 30 479 522 90 49 | 39 0 45 20 567 624 90 50 | 40 35 30 10 264 321 90 51 | 41 35 32 10 166 235 90 52 | 42 33 32 20 68 149 90 53 | 43 33 35 10 16 80 90 54 | 44 32 30 10 359 412 90 55 | 45 30 30 10 541 600 90 56 | 46 30 32 30 448 509 90 57 | 47 30 35 10 1054 1127 90 58 | 48 28 30 10 632 693 90 59 | 49 28 35 10 1001 1066 90 60 | 50 26 32 10 815 880 90 61 | 51 25 30 10 725 786 90 62 | 52 25 35 10 912 969 90 63 | 53 44 5 20 286 347 90 64 | 54 42 10 40 186 257 90 65 | 55 42 15 10 95 158 90 66 | 56 40 5 30 385 436 90 67 | 57 40 15 40 35 87 90 68 | 58 38 5 30 471 534 90 69 | 59 38 15 10 651 740 90 70 | 60 35 5 20 562 629 90 71 | 61 50 30 10 531 610 90 72 | 62 50 35 20 262 317 90 73 | 63 50 40 50 171 218 90 74 | 64 48 30 10 632 693 90 75 | 65 48 40 10 76 129 90 76 | 66 47 35 10 826 875 90 77 | 67 47 40 10 12 77 90 78 | 68 45 30 10 734 777 90 79 | 69 45 35 10 916 969 90 80 | 70 95 30 30 387 456 90 81 | 71 95 35 20 293 360 90 82 | 72 53 30 10 450 505 90 83 | 73 92 30 10 478 551 90 84 | 74 53 35 50 353 412 90 85 | 75 45 65 20 997 1068 90 86 | 76 90 35 10 203 260 90 87 | 77 88 30 10 574 643 90 88 | 78 88 35 20 109 170 90 89 | 79 87 30 10 668 731 90 90 | 80 85 25 10 769 820 90 91 | 81 85 35 30 47 124 90 92 | 82 75 55 20 369 420 90 93 | 83 72 55 10 265 338 90 94 | 84 70 58 20 458 523 90 95 | 85 68 60 30 555 612 90 96 | 86 66 55 10 173 238 90 97 | 87 65 55 20 85 144 90 98 | 88 65 60 30 645 708 90 99 | 89 63 58 10 737 802 90 100 | 90 60 55 10 20 84 90 101 | 91 60 60 10 836 889 90 102 | 92 67 85 20 368 441 90 103 | 93 65 85 40 475 518 90 104 | 94 65 82 10 285 336 90 105 | 95 62 80 30 196 239 90 106 | 96 60 80 10 95 156 90 107 | 97 60 85 30 561 622 90 108 | 98 58 75 20 30 84 90 109 | 99 55 80 10 743 820 90 110 | 100 55 85 20 647 726 90 111 | -------------------------------------------------------------------------------- /OR/VRPTW_CCG/r101.txt: -------------------------------------------------------------------------------- 1 | R101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 35 35 0 0 230 0 11 | 1 41 49 10 161 171 10 12 | 2 35 17 7 50 60 10 13 | 3 55 45 13 116 126 10 14 | 4 55 20 19 149 159 10 15 | 5 15 30 26 34 44 10 16 | 6 25 30 3 99 109 10 17 | 7 20 50 5 81 91 10 18 | 8 10 43 9 95 105 10 19 | 9 55 60 16 97 107 10 20 | 10 30 60 16 124 134 10 21 | 11 20 65 12 67 77 10 22 | 12 50 35 19 63 73 10 23 | 13 30 25 23 159 169 10 24 | 14 15 10 20 32 42 10 25 | 15 30 5 8 61 71 10 26 | 16 10 20 19 75 85 10 27 | 17 5 30 2 157 167 10 28 | 18 20 40 12 87 97 10 29 | 19 15 60 17 76 86 10 30 | 20 45 65 9 126 136 10 31 | 21 45 20 11 62 72 10 32 | 22 45 10 18 97 107 10 33 | 23 55 5 29 68 78 10 34 | 24 65 35 3 153 163 10 35 | 25 65 20 6 172 182 10 36 | 26 45 30 17 132 142 10 37 | 27 35 40 16 37 47 10 38 | 28 41 37 16 39 49 10 39 | 29 64 42 9 63 73 10 40 | 30 40 60 21 71 81 10 41 | 31 31 52 27 50 60 10 42 | 32 35 69 23 141 151 10 43 | 33 53 52 11 37 47 10 44 | 34 65 55 14 117 127 10 45 | 35 63 65 8 143 153 10 46 | 36 2 60 5 41 51 10 47 | 37 20 20 8 134 144 10 48 | 38 5 5 16 83 93 10 49 | 39 60 12 31 44 54 10 50 | 40 40 25 9 85 95 10 51 | 41 42 7 5 97 107 10 52 | 42 24 12 5 31 41 10 53 | 43 23 3 7 132 142 10 54 | 44 11 14 18 69 79 10 55 | 45 6 38 16 32 42 10 56 | 46 2 48 1 117 127 10 57 | 47 8 56 27 51 61 10 58 | 48 13 52 36 165 175 10 59 | 49 6 68 30 108 118 10 60 | 50 47 47 13 124 134 10 61 | 51 49 58 10 88 98 10 62 | 52 27 43 9 52 62 10 63 | 53 37 31 14 95 105 10 64 | 54 57 29 18 140 150 10 65 | 55 63 23 2 136 146 10 66 | 56 53 12 6 130 140 10 67 | 57 32 12 7 101 111 10 68 | 58 36 26 18 200 210 10 69 | 59 21 24 28 18 28 10 70 | 60 17 34 3 162 172 10 71 | 61 12 24 13 76 86 10 72 | 62 24 58 19 58 68 10 73 | 63 27 69 10 34 44 10 74 | 64 15 77 9 73 83 10 75 | 65 62 77 20 51 61 10 76 | 66 49 73 25 127 137 10 77 | 67 67 5 25 83 93 10 78 | 68 56 39 36 142 152 10 79 | 69 37 47 6 50 60 10 80 | 70 37 56 5 182 192 10 81 | 71 57 68 15 77 87 10 82 | 72 47 16 25 35 45 10 83 | 73 44 17 9 78 88 10 84 | 74 46 13 8 149 159 10 85 | 75 49 11 18 69 79 10 86 | 76 49 42 13 73 83 10 87 | 77 53 43 14 179 189 10 88 | 78 61 52 3 96 106 10 89 | 79 57 48 23 92 102 10 90 | 80 56 37 6 182 192 10 91 | 81 55 54 26 94 104 10 92 | 82 15 47 16 55 65 10 93 | 83 14 37 11 44 54 10 94 | 84 11 31 7 101 111 10 95 | 85 16 22 41 91 101 10 96 | 86 4 18 35 94 104 10 97 | 87 28 18 26 93 103 10 98 | 88 26 52 9 74 84 10 99 | 89 26 35 15 176 186 10 100 | 90 31 67 3 95 105 10 101 | 91 15 19 1 160 170 10 102 | 92 22 22 2 18 28 10 103 | 93 18 24 22 188 198 10 104 | 94 26 27 27 100 110 10 105 | 95 25 24 20 39 49 10 106 | 96 22 27 11 135 145 10 107 | 97 25 21 12 133 143 10 108 | 98 19 21 10 58 68 10 109 | 99 20 26 9 83 93 10 110 | 100 18 18 17 185 195 10 111 | -------------------------------------------------------------------------------- /OR/VRPTW_CCG/vrptw_ccg_gp.py: -------------------------------------------------------------------------------- 1 | # _*_coding:utf-8 _*_ 2 | from __future__ import print_function 3 | from gurobipy import * 4 | from GetData import * 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | import time 8 | 9 | 10 | 11 | def VRPTW_RMP(Graph): 12 | 13 | RMP = Model('RMP') 14 | customerNum = Graph.customerNum 15 | path_set = {} 16 | # define decision variable 17 | y = {} 18 | for i in range(customerNum): 19 | var_name = 'y_' + str(i) 20 | y[i] = RMP.addVar(lb = 0, ub = 1, obj = round(Graph.disMatrix[0][i] + Graph.disMatrix[i][0], 1), vtype = GRB.CONTINUOUS, name = var_name) 21 | path_set[var_name] = [0, i + 1, Graph.nodeNum - 1] 22 | 23 | RMP.setAttr('ModelSense',GRB.MINIMIZE) 24 | 25 | rmp_con = [] 26 | row_coeff = [1] * customerNum 27 | for i in range(customerNum): 28 | rmp_con.append(RMP.addConstr(y[i] == 1)) 29 | 30 | # set objective function 31 | # RMP.write('RMP.lp') 32 | # RMP.setParas('') 33 | RMP.optimize() 34 | 35 | rmp_pi = RMP.getAttr("Pi", RMP.getConstrs()) 36 | rmp_pi.insert(0, 0) 37 | rmp_pi.append(0) 38 | return RMP,rmp_pi,rmp_con,path_set 39 | 40 | def VRPTW_SPP(Graph,rmp_pi): 41 | # build subproblem 42 | SP = Model('SP') 43 | # decision variables 44 | x = {} 45 | s = {} 46 | # mu = {} 47 | big_M = 1e5 48 | for i in range(Graph.nodeNum): 49 | name = 's_' + str(i) 50 | s[i] = SP.addVar(lb = Graph.readyTime[i], 51 | ub = Graph.dueTime[i], 52 | vtype = GRB.CONTINUOUS, 53 | name = name) 54 | for j in range(Graph.nodeNum): 55 | if(i != j): 56 | name = 'x_' + str(i) + '_' + str(j) 57 | x[i, j] = SP.addVar(lb = 0, 58 | ub = 1, 59 | vtype = GRB.BINARY, 60 | name = name) 61 | 62 | # set objective function of SP 63 | sub_obj = LinExpr(0) 64 | for key in x.keys(): 65 | node_i = key[0] 66 | node_j = key[1] 67 | sub_obj.addTerms(Graph.disMatrix[node_i][node_j], x[key]) 68 | sub_obj.addTerms(-rmp_pi[node_i], x[key]) 69 | 70 | SP.setObjective(sub_obj, GRB.MINIMIZE) 71 | 72 | # constraints 1 73 | lhs = LinExpr(0) 74 | for key in x.keys(): 75 | node_i = key[0] 76 | node_j = key[1] 77 | lhs.addTerms(Graph.demand[node_i], x[key]) 78 | SP.addConstr(lhs <= Graph.capacity, name = 'cons_1') 79 | 80 | # constraints 2 81 | lhs = LinExpr(0) 82 | for key in x.keys(): 83 | if(key[0] == 0): 84 | lhs.addTerms(1, x[key]) 85 | SP.addConstr(lhs == 1, name = 'cons_2') 86 | 87 | # constraints 3 88 | for h in range(1, Graph.nodeNum - 1): 89 | lhs = LinExpr(0) 90 | for i in range(Graph.nodeNum): 91 | temp_key = (i, h) 92 | if(temp_key in x.keys()): 93 | lhs.addTerms(1, x[temp_key]) 94 | for j in range(Graph.nodeNum): 95 | temp_key = (h, j) 96 | if(temp_key in x.keys()): 97 | lhs.addTerms(-1, x[temp_key]) 98 | SP.addConstr(lhs == 0, name = 'cons_3') 99 | 100 | # constraints 4 101 | lhs = LinExpr(0) 102 | for key in x.keys(): 103 | if(key[1] == Graph.nodeNum - 1): 104 | lhs.addTerms(1, x[key]) 105 | SP.addConstr(lhs == 1, name = 'cons_4') 106 | 107 | # constraints 5 108 | for key in x.keys(): 109 | node_i = key[0] 110 | node_j = key[1] 111 | SP.addConstr(s[node_i] + Graph.disMatrix[node_i][node_j] - s[node_j] - big_M + big_M * x[key] <= 0, name = 'cons_5') 112 | 113 | SP.optimize() 114 | 115 | return SP,x 116 | 117 | 118 | def get_new_path(Graph,x): 119 | ''' 120 | @description: get new path from SPP model 121 | ''' 122 | new_path = [] 123 | current_node = 0 124 | new_path.append(current_node) 125 | path_length = 0 126 | while(current_node != Graph.nodeNum - 1): 127 | for key in x.keys(): 128 | if(x[key].x > 0 and key[0] == current_node): 129 | current_node = key[1] 130 | new_path.append(current_node) 131 | path_length += Graph.disMatrix[key[0]][key[1]] 132 | return new_path,path_length 133 | 134 | 135 | 136 | if __name__=='__main__': 137 | 138 | # reading data 139 | Graph = Data() 140 | path = 'r101.txt' 141 | Graph.read_solomon(path='c101.txt',customerNum=25) 142 | Graph.get_euclidean_distance_matrix() 143 | # Graph.vehicleNum = 20 144 | s_time = time.time() 145 | 146 | RMP,rmp_pi,rmp_con,path_set = VRPTW_RMP(Graph) 147 | SP,x = VRPTW_SPP(Graph,rmp_pi) 148 | 149 | RMP.setParam("OutputFlag", 0) 150 | SP.setParam("OutputFlag", 0) 151 | #solve SP 152 | SP.optimize() 153 | eps = -0.01 154 | cnt = 0 155 | while(SP.ObjVal < eps): 156 | cnt += 1 157 | print('--------cnt={}---------- '.format(cnt)) 158 | ''' 159 | ADD NEW COLUMN 160 | ''' 161 | new_path,path_length = get_new_path(Graph,x) 162 | path_length = round(path_length,2) 163 | 164 | # creat new column 165 | col_coef = [0] * Graph.customerNum 166 | for key in x.keys(): 167 | if(x[key].x > 0): 168 | node_i = key[0] 169 | if(node_i > 0 and node_i < Graph.nodeNum - 1): 170 | col_coef[node_i - 1] = 1 171 | 172 | print('new path length :', new_path) 173 | print('new path length :', path_length) 174 | print('new column :', col_coef) 175 | 176 | # Update RMP 177 | rmp_col = Column(col_coef, rmp_con) 178 | var_name = "cg_" + str(cnt) 179 | RMP.addVar(lb = 0.0, ub = 1, obj = path_length, vtype = GRB.CONTINUOUS, name = var_name, column = rmp_col) 180 | RMP.update() 181 | path_set[var_name] = new_path 182 | 183 | print('current column number :', RMP.NumVars) 184 | RMP.write('RMP.lp') 185 | RMP.optimize() 186 | 187 | # get the dual variable of RMP constraints 188 | rmp_pi = RMP.getAttr("Pi", RMP.getConstrs()) 189 | rmp_pi.insert(0, 0) 190 | rmp_pi.append(0) 191 | 192 | # Update objective of SP 193 | sub_obj = LinExpr(0) 194 | for key in x.keys(): 195 | node_i = key[0] 196 | node_j = key[1] 197 | sub_obj.addTerms(Graph.disMatrix[node_i][node_j], x[key]) 198 | sub_obj.addTerms(-rmp_pi[node_i], x[key]) 199 | 200 | SP.setObjective(sub_obj, GRB.MINIMIZE) 201 | SP.optimize() 202 | print('reduced cost :', SP.ObjVal) 203 | 204 | mip_var = RMP.getVars() 205 | for i in range(RMP.numVars): 206 | mip_var[i].setAttr("VType", GRB.INTEGER) 207 | RMP.optimize() 208 | print('--------------------------------') 209 | print('RMP.ObjVal :',RMP.ObjVal) 210 | for var in RMP.getVars(): 211 | if(var.x > 0): 212 | print(var.VarName, ' = ', var.x, '\t path :', path_set[var.VarName]) 213 | 214 | print('time cost:',time.time()-s_time) 215 | 216 | 217 | -------------------------------------------------------------------------------- /OR/labeling algorithm/GetData.py: -------------------------------------------------------------------------------- 1 | import math,re 2 | import numpy as np 3 | import networkx as nx 4 | import matplotlib.pyplot as plt 5 | from numpy import random 6 | 7 | 8 | class Data(): 9 | def __init__(self): 10 | self.color_names() 11 | self.location = [] 12 | self.capacity = 200 # 无要求 13 | self.demand = [] 14 | self.servicetime = [] 15 | self.nodeNum = [] 16 | 17 | def generate_node(self,num,map_size=100,time_upper=1000,tw_size=100,demand_limit=20,servicetime_limit=20,capacity=200): 18 | """generate number of locations randomly in a block unit 19 | default TSP : num_vehicles=1,depot=0 20 | """ 21 | locations = [(0,0)] # locations = [(24, 3), (21, 4), (5, 1),...] 22 | demands = [0] 23 | servicetimes = [0] 24 | readyTime = [0] 25 | dueTime = [0] 26 | for _ in range(num): 27 | locations.append(tuple(np.random.randint(low=0,high=map_size,size=2))) 28 | t_ = np.random.randint(low=0,high=time_upper) 29 | readyTime.append(t_) 30 | dueTime.append(t_ + np.random.randint(tw_size)) # timewindows size = 10 31 | demands.append(np.random.randint(low=0,high=demand_limit)) 32 | servicetimes.append(np.random.randint(low=0,high=servicetime_limit)) 33 | # add the destination 34 | locations.append(locations[0]) 35 | readyTime.append(0) 36 | dueTime.append(time_upper*100) # notice: no more than bigM 37 | demands.append(0) 38 | servicetimes.append(0) 39 | 40 | self.location = locations 41 | self.readyTime = readyTime 42 | self.dueTime = dueTime 43 | self.demand = demands 44 | self.servicetime = servicetimes 45 | self.nodeNum = len(locations) 46 | self.capacity = capacity 47 | 48 | 49 | def get_euclidean_distance_matrix(self): 50 | """Creates callback to return distance between locations.""" 51 | distances = {} 52 | for from_counter, from_node in enumerate(self.location): 53 | distances[from_counter] = [] 54 | temp_list = [] 55 | for to_counter, to_node in enumerate(self.location): 56 | if from_counter == to_counter: 57 | temp_list.append(0) 58 | # distances[from_counter][to_counter] = 0 59 | else: 60 | # Euclidean distance 61 | temp_list.append( 62 | math.hypot((from_node[0] - to_node[0]), 63 | (from_node[1] - to_node[1])) 64 | ) 65 | # distances[from_counter][to_counter] = ( 66 | # math.hypot((from_node[0] - to_node[0]), 67 | # (from_node[1] - to_node[1]))) 68 | distances[from_counter] = temp_list 69 | self.disMatrix = distances 70 | 71 | def get_time_dismatrix(self): 72 | time_distances={} 73 | for i in range(len(self.dueTime)): 74 | time_dis = (np.array(self.dueTime)-np.array(self.dueTime[i])).tolist() 75 | # print(time_dis) 76 | for j in range(len(time_dis)): 77 | if time_dis[j]<0 or self.disMatrix[i][j]+self.dueTime[i]>self.dueTime[j]: 78 | time_dis[j] = 100000 79 | time_distances[i] = time_dis 80 | self.timedisMatrix = time_distances 81 | 82 | def read_solomon(self,path,customerNum=100): 83 | '''Description: load solomon dataset''' 84 | f = open(path, 'r') 85 | lines = f.readlines() 86 | locations,demand,readyTime,dueTime,serviceTime=[],[],[],[],[] 87 | for count,line in enumerate(lines): 88 | count = count + 1 89 | if(count == 5): 90 | line = line[:-1].strip() 91 | str = re.split(r" +", line) 92 | vehicleNum = int(str[0]) 93 | capacity = float(str[1]) 94 | elif(count >= 10 and count <= 10 + customerNum): 95 | line = line[:-1] 96 | str = re.split(r" +", line) 97 | locations.append((float(str[2]),float(str[3]))) 98 | demand.append(float(str[4])) 99 | readyTime.append(float(str[5])) 100 | dueTime.append(float(str[6])) 101 | serviceTime.append(float(str[7])) 102 | self.location = locations 103 | self.demand = demand 104 | # readyTime[0],dueTime[0] = 0,0 105 | self.readyTime = readyTime 106 | self.dueTime = dueTime 107 | self.serviceTime = serviceTime 108 | self.vehicleNum = vehicleNum 109 | self.capacity =capacity 110 | self.add_deport() 111 | self.nodeNum = len(locations) 112 | self.customerNum = customerNum 113 | 114 | def add_deport(self): 115 | self.location.append(self.location[0]) 116 | self.demand.append(self.demand[0]) 117 | self.readyTime.append(self.readyTime[0]) 118 | self.dueTime.append(self.dueTime[0]) 119 | self.serviceTime.append(self.serviceTime[0]) 120 | self.dueTime[0] = 0 121 | 122 | 123 | def plot_nodes(self): 124 | ''' function to plot locations''' 125 | self.location 126 | Graph = nx.DiGraph() 127 | nodes_name = [str(x) for x in list(range(len(self.location)))] 128 | Graph.add_nodes_from(nodes_name) 129 | pos_location = {nodes_name[i]:x for i,x in enumerate(self.location)} 130 | nodes_color_dict = ['r'] + ['gray'] * (len(self.location)-2) + ['r'] 131 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,labels=None) 132 | plt.show(Graph) 133 | 134 | def plot_route(self,locations,route,edgecolor='k',showoff=True): 135 | ''' function to plot locations and route''' 136 | 'e.g. [0,1,5,9,0]' 137 | Graph = nx.DiGraph() 138 | edge = [] 139 | edges = [] 140 | for i in route : 141 | edge.append(i) 142 | if len(edge) == 2 : 143 | edges.append(tuple(edge)) 144 | edge.pop(0) 145 | nodes_name = [x for x in list(range(len(locations)))] 146 | Graph.add_nodes_from(nodes_name) 147 | Graph.add_edges_from(edges) 148 | pos_location = {nodes_name[i] : x for i,x in enumerate(locations)} 149 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-2) + ['r'] # 第一个和最后一个红色 150 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,edge_color=edgecolor,labels=None) 151 | if showoff: 152 | plt.show(Graph) 153 | 154 | def color_names(self): 155 | self.colornames = [ 156 | '#F0F8FF', 157 | '#FAEBD7', 158 | '#00FFFF', 159 | '#7FFFD4', 160 | '#F0FFFF', 161 | '#F5F5DC', 162 | '#FFE4C4', 163 | '#000000', 164 | '#FFEBCD', 165 | '#0000FF', 166 | '#8A2BE2', 167 | '#A52A2A', 168 | '#DEB887', 169 | '#5F9EA0', 170 | '#7FFF00', 171 | '#D2691E', 172 | '#FF7F50', 173 | '#6495ED', 174 | '#FFF8DC', 175 | '#DC143C', 176 | '#00FFFF', 177 | '#00008B', 178 | '#008B8B', 179 | '#B8860B', 180 | '#A9A9A9', 181 | '#006400', 182 | '#BDB76B', 183 | '#8B008B', 184 | '#556B2F', 185 | '#FF8C00', 186 | '#9932CC', 187 | '#8B0000', 188 | '#E9967A', 189 | '#8FBC8F', 190 | '#483D8B', 191 | '#2F4F4F', 192 | '#00CED1', 193 | '#9400D3', 194 | '#FF1493', 195 | '#00BFFF', 196 | '#696969', 197 | '#1E90FF', 198 | '#B22222', 199 | '#FFFAF0', 200 | '#228B22', 201 | '#FF00FF', 202 | '#DCDCDC', 203 | '#F8F8FF', 204 | '#FFD700', 205 | '#DAA520', 206 | '#808080', 207 | '#008000', 208 | '#ADFF2F', 209 | '#F0FFF0', 210 | '#FF69B4', 211 | '#CD5C5C', 212 | '#4B0082', 213 | '#FFFFF0', 214 | '#F0E68C', 215 | '#E6E6FA', 216 | '#FFF0F5', 217 | '#7CFC00', 218 | '#FFFACD', 219 | '#ADD8E6', 220 | '#F08080', 221 | '#E0FFFF', 222 | '#FAFAD2', 223 | '#90EE90', 224 | '#D3D3D3', 225 | '#FFB6C1', 226 | '#FFA07A', 227 | '#20B2AA', 228 | '#87CEFA', 229 | '#778899', 230 | '#B0C4DE', 231 | '#FFFFE0', 232 | '#00FF00', 233 | '#32CD32', 234 | '#FAF0E6', 235 | '#FF00FF', 236 | '#800000', 237 | '#66CDAA', 238 | '#0000CD', 239 | '#BA55D3', 240 | '#9370DB', 241 | '#3CB371', 242 | '#7B68EE', 243 | '#00FA9A', 244 | '#48D1CC', 245 | '#C71585', 246 | '#191970', 247 | '#F5FFFA', 248 | '#FFE4E1', 249 | '#FFE4B5', 250 | '#FFDEAD', 251 | '#000080', 252 | '#FDF5E6', 253 | '#808000', 254 | '#6B8E23', 255 | '#FFA500', 256 | '#FF4500', 257 | '#DA70D6', 258 | '#EEE8AA', 259 | '#98FB98', 260 | '#AFEEEE', 261 | '#DB7093', 262 | '#FFEFD5', 263 | '#FFDAB9', 264 | '#CD853F', 265 | '#FFC0CB', 266 | '#DDA0DD', 267 | '#B0E0E6', 268 | '#800080', 269 | '#FF0000', 270 | '#BC8F8F', 271 | '#4169E1', 272 | '#8B4513', 273 | '#FA8072', 274 | '#FAA460', 275 | '#2E8B57', 276 | '#FFF5EE', 277 | '#A0522D', 278 | '#C0C0C0', 279 | '#87CEEB', 280 | '#6A5ACD', 281 | '#708090', 282 | '#FFFAFA', 283 | '#00FF7F', 284 | '#4682B4', 285 | '#D2B48C', 286 | '#008080', 287 | '#D8BFD8', 288 | '#FF6347', 289 | '#40E0D0', 290 | '#EE82EE', 291 | '#F5DEB3', 292 | '#FFFFFF', 293 | '#F5F5F5', 294 | '#FFFF00', 295 | '#9ACD32'] 296 | 297 | 298 | if __name__ == "__main__": 299 | ## generate data randomly 300 | nodes = Data() 301 | # nodes.generate_node(num=10) 302 | # nodes.read_solomon(path=r'r101.txt',customerNum=30) 303 | nodes.generate_node(num=20) 304 | nodes.get_euclidean_distance_matrix() 305 | nodes.get_time_dismatrix() 306 | 307 | nodes.plot_nodes() 308 | 309 | 310 | -------------------------------------------------------------------------------- /OR/labeling algorithm/README.md: -------------------------------------------------------------------------------- 1 | 7 | # labeling algorithm 8 | 9 | 10 | 11 | ## Algorithm flow 12 | 13 | 14 | 15 | ## Numerical example 16 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /OR/labeling algorithm/labeling_espprc.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: 71 3 | Date: 2021-11-26 20:00:39 4 | LastEditTime: 2022-02-22 16:06:09 5 | Description: Feillet (2004). implementation with python 6 | ''' 7 | 8 | import numpy as np 9 | import time 10 | import matplotlib.pyplot as plt 11 | import copy,json 12 | from GetData import * 13 | import torch as tf 14 | 15 | class Label: 16 | def __init__(self): 17 | self.path = [0] 18 | self.travel_time = 0 19 | self.obj = 0 20 | self.demand=0 21 | self.unreachNum = 0 22 | 23 | class Labeling(): 24 | def __init__(self,Graph) -> None: 25 | self.Graph = Graph 26 | self.Q = {} # initial Queue 27 | self.des = Graph.nodeNum-1 28 | self.unreachNum = 0 29 | 30 | def preprocess(self,tabu_list=None): 31 | # preprocessing for ARCS 32 | if tabu_list is None: 33 | tabu_list = [] 34 | self.query_arc = {} # 任意节点的可行路径, 关键 35 | Graph = self.Graph 36 | Graph.arcs = {} 37 | self.arcNum = 0 38 | self.neg_arcs = 0 39 | for i in range(Graph.nodeNum): 40 | self.query_arc[i] = [] # list 41 | for j in range(Graph.nodeNum): 42 | if (i!=Graph.nodeNum-1) and (j!=0) and (i!=j)and (Graph.readyTime[i]+Graph.serviceTime[i]+Graph.disMatrix[i][j] < Graph.dueTime[j]) and i not in tabu_list and j not in tabu_list: 43 | Graph.arcs[i,j] = 1 44 | self.arcNum += 1 45 | self.query_arc[i].append(j) 46 | if Graph.disMatrix[i][j]-Graph.rmp[i]<0: 47 | self.neg_arcs += 1 48 | else: 49 | Graph.arcs[i,j] = 0 50 | self.Graph = Graph # update 51 | 52 | def dominant_rule(self,node_num): #espprc 53 | cur_node = self.Q[node_num][-1] 54 | remove_list = [] 55 | for node in self.Q[node_num]: 56 | if node.path[-1] == cur_node.path[-1] and node.path != cur_node.path: # 如果终点相同 57 | if node.obj<=cur_node.obj and node.travel_time<=cur_node.travel_time and node.demand<=cur_node.demand and node.unreachNum<=cur_node.unreachNum: 58 | cur_node = node # replace 59 | elif node.obj>=cur_node.obj and node.travel_time>=cur_node.travel_time and node.demand>=cur_node.demand and node.unreachNum>=cur_node.unreachNum: 60 | remove_list.append(node) #记录dominant的节点 61 | for i in remove_list: 62 | self.Q[node_num].remove(i) 63 | 64 | def get_unreached_nodes(self,extended_label): 65 | count = 0 66 | last_node = extended_label.path[-1] 67 | for n in extended_label.path: 68 | if n in self.query_arc[last_node]: 69 | count += 1 70 | return count 71 | 72 | def select_opt(self): 73 | opt_sol = self.Q[self.Graph.nodeNum-1].pop() 74 | for sol in self.Q[self.Graph.nodeNum-1]: 75 | if opt_sol.obj > sol.obj: 76 | opt_sol = sol 77 | self.opt_sol = opt_sol 78 | self.Q[self.Graph.nodeNum-1] = [opt_sol] 79 | 80 | 81 | def run(self,tabu_list=None): 82 | self.preprocess(tabu_list) # 去处理,去掉不用的弧 83 | print('the total number of arcs is :{}, neg arcs:{}'.format(self.arcNum,self.neg_arcs)) 84 | for i in range(self.Graph.nodeNum): 85 | self.Q[i] = [] 86 | current_label = Label() #从0开始 87 | self.Q[0].append(current_label) 88 | break_flag = 1 89 | self.epoch = 0 90 | while(break_flag): 91 | self.epoch += 1 92 | for i in range(self.Graph.nodeNum-1): 93 | break_flag = 0 94 | if self.Q[i]: 95 | break_flag = 1 96 | break 97 | if len(self.Q[self.Graph.nodeNum-1]): # feasible solution 98 | self.select_opt() 99 | # print('current obj:{}, feasible path:{}'.format(self.opt_sol.obj,self.opt_sol.path)) 100 | for node in range(self.Graph.nodeNum-1): 101 | if len(self.Q[node])>100: # dominante before extend label 102 | self.dominant_rule(node) 103 | while(len(self.Q[node])>0) : 104 | current_label = self.Q[node].pop() 105 | for next_node in self.query_arc[node]: 106 | if next_node in current_label.path: # 禁止重复探索 107 | continue 108 | extended_label = copy.deepcopy(current_label) 109 | extended_label.path.append(next_node) 110 | extended_label.demand += self.Graph.demand[next_node] 111 | extended_label.obj += self.Graph.disMatrix[node][next_node]-self.Graph.rmp[node] 112 | extended_label.unreachNum = self.get_unreached_nodes(extended_label) 113 | arrive_time = extended_label.travel_time+self.Graph.disMatrix[node][next_node]+self.Graph.serviceTime[node] 114 | if arrive_time < self.Graph.readyTime[next_node]: 115 | extended_label.travel_time = self.Graph.readyTime[next_node] 116 | elif arrive_time <= self.Graph.dueTime[next_node]: 117 | extended_label.travel_time = arrive_time 118 | else: 119 | extended_label.travel_time = np.Inf 120 | 121 | if extended_label.demand <= self.Graph.capacity: # capacity 122 | if extended_label.travel_time >= self.Graph.readyTime[next_node] and extended_label.travel_time <= self.Graph.dueTime[next_node]: 123 | self.Q[next_node].append(extended_label) 124 | self.select_opt() 125 | 126 | 127 | # np.random.seed(1) 128 | if __name__=='__main__': 129 | 130 | customerNum = 30 131 | Graph = Data() 132 | Graph.read_solomon(path=r'r101.txt',customerNum=customerNum) 133 | Graph.get_euclidean_distance_matrix() 134 | start = time.time() 135 | Graph.rmp = np.random.randint(0,50,customerNum+2) 136 | # Graph.rmp = [100] * (customerNum+2) 137 | espprc = Labeling(Graph) 138 | espprc.run() 139 | print('time cost:',time.time()-start) 140 | print('best obj:',espprc.opt_sol.obj) 141 | print('best path:',espprc.opt_sol.path) 142 | print('demand:',espprc.opt_sol.demand) 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /OR/labeling algorithm/r101.txt: -------------------------------------------------------------------------------- 1 | R101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 35 35 0 0 230 0 11 | 1 41 49 10 161 171 10 12 | 2 35 17 7 50 60 10 13 | 3 55 45 13 116 126 10 14 | 4 55 20 19 149 159 10 15 | 5 15 30 26 34 44 10 16 | 6 25 30 3 99 109 10 17 | 7 20 50 5 81 91 10 18 | 8 10 43 9 95 105 10 19 | 9 55 60 16 97 107 10 20 | 10 30 60 16 124 134 10 21 | 11 20 65 12 67 77 10 22 | 12 50 35 19 63 73 10 23 | 13 30 25 23 159 169 10 24 | 14 15 10 20 32 42 10 25 | 15 30 5 8 61 71 10 26 | 16 10 20 19 75 85 10 27 | 17 5 30 2 157 167 10 28 | 18 20 40 12 87 97 10 29 | 19 15 60 17 76 86 10 30 | 20 45 65 9 126 136 10 31 | 21 45 20 11 62 72 10 32 | 22 45 10 18 97 107 10 33 | 23 55 5 29 68 78 10 34 | 24 65 35 3 153 163 10 35 | 25 65 20 6 172 182 10 36 | 26 45 30 17 132 142 10 37 | 27 35 40 16 37 47 10 38 | 28 41 37 16 39 49 10 39 | 29 64 42 9 63 73 10 40 | 30 40 60 21 71 81 10 41 | 31 31 52 27 50 60 10 42 | 32 35 69 23 141 151 10 43 | 33 53 52 11 37 47 10 44 | 34 65 55 14 117 127 10 45 | 35 63 65 8 143 153 10 46 | 36 2 60 5 41 51 10 47 | 37 20 20 8 134 144 10 48 | 38 5 5 16 83 93 10 49 | 39 60 12 31 44 54 10 50 | 40 40 25 9 85 95 10 51 | 41 42 7 5 97 107 10 52 | 42 24 12 5 31 41 10 53 | 43 23 3 7 132 142 10 54 | 44 11 14 18 69 79 10 55 | 45 6 38 16 32 42 10 56 | 46 2 48 1 117 127 10 57 | 47 8 56 27 51 61 10 58 | 48 13 52 36 165 175 10 59 | 49 6 68 30 108 118 10 60 | 50 47 47 13 124 134 10 61 | 51 49 58 10 88 98 10 62 | 52 27 43 9 52 62 10 63 | 53 37 31 14 95 105 10 64 | 54 57 29 18 140 150 10 65 | 55 63 23 2 136 146 10 66 | 56 53 12 6 130 140 10 67 | 57 32 12 7 101 111 10 68 | 58 36 26 18 200 210 10 69 | 59 21 24 28 18 28 10 70 | 60 17 34 3 162 172 10 71 | 61 12 24 13 76 86 10 72 | 62 24 58 19 58 68 10 73 | 63 27 69 10 34 44 10 74 | 64 15 77 9 73 83 10 75 | 65 62 77 20 51 61 10 76 | 66 49 73 25 127 137 10 77 | 67 67 5 25 83 93 10 78 | 68 56 39 36 142 152 10 79 | 69 37 47 6 50 60 10 80 | 70 37 56 5 182 192 10 81 | 71 57 68 15 77 87 10 82 | 72 47 16 25 35 45 10 83 | 73 44 17 9 78 88 10 84 | 74 46 13 8 149 159 10 85 | 75 49 11 18 69 79 10 86 | 76 49 42 13 73 83 10 87 | 77 53 43 14 179 189 10 88 | 78 61 52 3 96 106 10 89 | 79 57 48 23 92 102 10 90 | 80 56 37 6 182 192 10 91 | 81 55 54 26 94 104 10 92 | 82 15 47 16 55 65 10 93 | 83 14 37 11 44 54 10 94 | 84 11 31 7 101 111 10 95 | 85 16 22 41 91 101 10 96 | 86 4 18 35 94 104 10 97 | 87 28 18 26 93 103 10 98 | 88 26 52 9 74 84 10 99 | 89 26 35 15 176 186 10 100 | 90 31 67 3 95 105 10 101 | 91 15 19 1 160 170 10 102 | 92 22 22 2 18 28 10 103 | 93 18 24 22 188 198 10 104 | 94 26 27 27 100 110 10 105 | 95 25 24 20 39 49 10 106 | 96 22 27 11 135 145 10 107 | 97 25 21 12 133 143 10 108 | 98 19 21 10 58 68 10 109 | 99 20 26 9 83 93 10 110 | 100 18 18 17 185 195 10 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithm-Implementation 2 | 3 | This repository is for learning and understanding how algorithms work, including kinds of algorithm(ML,RL,OR) implementation in details and each with a brief introduction. 4 | 5 | Mainly covers: 6 | 7 | **OR** 8 | - Various heuristic algorithms (e.g. Tabu search,Genetic algorithm,Simulated annealing,...) 9 | - exact algorithm (e.g. Branch and Bound,Branch and Cut,Branch and Price,...) 10 | - gurobi for kinds of VRPs 11 | - ... 12 | 13 | 14 | **RL** 15 | - DQNs (double dqn, dueling dqn,...) 16 | - DDPG 17 | - PPO 18 | - ... 19 | 20 | **ML** 21 | - ... 22 | 23 | 24 | 25 | Continuously updating.... 26 | 27 | -------------------------------------------------------------------------------- /RL/A3C/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/RL/A3C/readme.md -------------------------------------------------------------------------------- /RL/DDPG/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/RL/DDPG/readme.md -------------------------------------------------------------------------------- /RL/DQN/DQN/DQN.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | import numpy as np 5 | import gym 6 | 7 | class Net(nn.Module): 8 | def __init__(self,n_input,n_hidden,n_output): 9 | super(Net, self).__init__() 10 | self.fc1 = nn.Linear(n_input, n_hidden) 11 | self.fc1.weight.data.normal_(0, 0.1) # initialization 12 | self.out = nn.Linear(n_hidden, n_output) 13 | self.out.weight.data.normal_(0, 0.1) # initialization 14 | 15 | def forward(self, x): 16 | x = self.fc1(x) 17 | x = F.relu(x) 18 | actions_value = self.out(x) 19 | return actions_value 20 | 21 | 22 | env = gym.make('CartPole-v0') 23 | env = env.unwrapped 24 | N_ACTIONS = env.action_space.n #2 25 | N_STATES = env.observation_space.shape[0] #4 26 | ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(), int) else env.action_space.sample().shape # to confirm the shape 27 | 28 | # DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 29 | # reward discount 30 | class DQN(object): 31 | def __init__(self): 32 | # # Hyper Parameters 33 | self.lr = 0.01 34 | self.memory_capacity = 200 35 | self.max_episode = 300 36 | self.batch_size = 32 37 | self.epsilon = 0.9 # e-greedy policy 38 | self.gamma = 0.9 39 | self.target_update_freq = 10 40 | 41 | self.learn_step_counter = 0 # for target updating 42 | self.memory_counter = 0 # for storing memory 43 | self.memory = np.zeros((self.memory_capacity, N_STATES * 2 + 2)) # initialize memory 44 | 45 | self.eval_net = Net(N_STATES,50,N_ACTIONS) # network 46 | self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=self.lr) 47 | self.loss_func = nn.MSELoss() 48 | 49 | def get_reward(self,s_): 50 | # modify the reward to learn ,如果简单的给一些值容易跑飞 51 | x, x_dot, theta, theta_dot = s_ 52 | # r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8 53 | # r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5 54 | r1 = -abs(x) 55 | r2 = -20*abs(theta) #角度奖励大一点,负奖励(惩罚)效果好一些,引入一些先验经验,比如控制力矩小一些比较好 56 | r = r1 + r2 57 | return r 58 | 59 | def choose_action(self, x): 60 | x = torch.unsqueeze(torch.FloatTensor(x), 0) 61 | # input only one sample 62 | if np.random.uniform() > self.epsilon : # greedy 63 | actions_value = self.eval_net.forward(x) 64 | action = torch.max(actions_value, 1)[1].data.numpy() 65 | action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) # return the argmax index 66 | else: # random 67 | action = np.random.randint(0, N_ACTIONS) 68 | action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) 69 | self.epsilon -= self.epsilon/self.max_episode # decrease epsilon, 从“强探索弱利用”过渡到“弱探索强利用” 70 | return action 71 | 72 | def store_transition(self, s, a, r, s_): 73 | transition = np.hstack((s, [a, r], s_)) 74 | # replace the old memory with new memory 75 | index = self.memory_counter % self.memory_capacity 76 | self.memory[index, :] = transition 77 | self.memory_counter += 1 78 | 79 | def training(self): 80 | # sample batch transitions 81 | sample_index = np.random.choice(self.memory_capacity, self.batch_size) 82 | b_memory = self.memory[sample_index, :] 83 | b_s = torch.FloatTensor(b_memory[:, :N_STATES]) 84 | b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int)) 85 | b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2]) 86 | b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:]) 87 | 88 | # # DQN 89 | # #q_eval w.r.t the action in experience 90 | q_eval = self.eval_net(b_s).gather(1, b_a) # shape (batch, 1) 91 | q_next = self.eval_net(b_s_).max(1)[0].view(self.batch_size, 1) 92 | q_target = b_r + self.gamma * q_next 93 | 94 | loss = self.loss_func(q_eval, q_target) 95 | self.optimizer.zero_grad() 96 | loss.backward() 97 | self.optimizer.step() 98 | self.loss_value = loss.item() 99 | 100 | 101 | if __name__ == "__main__": 102 | dqn = DQN() 103 | print('\nCollecting experience...') 104 | for i_episode in range(dqn.max_episode): 105 | s = env.reset() 106 | exp_r = 0 107 | step_record = 0 108 | while True: 109 | env.render() 110 | a = dqn.choose_action(s) # take action 111 | # step 函数,包含reward的定义 112 | s_, r, done, info = env.step(a) # s_, r, done, info 新状态,采取这个行动的奖励,是否结束当前回合,其他信息,如性能和表现可用于调优 113 | r = dqn.get_reward(s_) # modify the reward to learn 114 | dqn.store_transition(s, a, r, s_) 115 | exp_r += r 116 | step_record+=1 117 | if dqn.memory_counter > dqn.memory_capacity: #积累到一定数量开始训练 118 | dqn.training() 119 | if done: 120 | print('loss:', dqn.loss_value) 121 | print('i_episode: ', i_episode, 122 | '| Expect_r: ', round(exp_r, 2)) 123 | if done: 124 | print("step_record:",step_record) 125 | print("x:",s[0],"|theta:",s[2],'\n') 126 | break 127 | s = s_ -------------------------------------------------------------------------------- /RL/DQN/DoubleDQN/DoubleDQN_main.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | import numpy as np 5 | import gym 6 | 7 | class Net(nn.Module): 8 | def __init__(self,n_input,n_hidden,n_output): 9 | super(Net, self).__init__() 10 | self.fc1 = nn.Linear(n_input, n_hidden) 11 | self.fc1.weight.data.normal_(0, 0.1) # initialization 12 | self.out = nn.Linear(n_hidden, n_output) 13 | self.out.weight.data.normal_(0, 0.1) # initialization 14 | 15 | def forward(self, x): 16 | x = self.fc1(x) 17 | x = F.relu(x) 18 | actions_value = self.out(x) 19 | return actions_value 20 | 21 | env = gym.make('CartPole-v0') 22 | env = env.unwrapped 23 | N_ACTIONS = env.action_space.n #2 24 | N_STATES = env.observation_space.shape[0] #4 25 | ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(), int) else env.action_space.sample().shape # to confirm the shape 26 | 27 | class DQN(object): 28 | def __init__(self): 29 | # # Hyper Parameters 30 | self.lr = 0.01 31 | self.memory_capacity = 200 32 | self.max_episode = 300 33 | self.batch_size = 32 34 | self.epsilon = 0.9 # e-greedy policy 35 | self.gamma = 0.9 36 | self.target_update_freq = 10 37 | 38 | self.learn_step_counter = 0 # for target updating 39 | self.memory_counter = 0 40 | # for storing memory 41 | self.memory = np.zeros((self.memory_capacity, N_STATES * 2 + 2)) # initialize memory 42 | 43 | self.eval_net , self.target_net = Net(N_STATES,50,N_ACTIONS),Net(N_STATES,50,N_ACTIONS) 44 | self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=self.lr ) 45 | self.loss_func = nn.MSELoss() 46 | 47 | def get_reward(self,s_): 48 | # modify the reward to learn ,如果简单的给一些值容易跑飞 49 | x, x_dot, theta, theta_dot = s_ 50 | # r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8 51 | # r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5 52 | r1 = -abs(x) 53 | r2 = -20*abs(theta) #角度奖励大一点,负奖励(惩罚)效果好一些,引入一些先验经验,比如控制力矩小一些比较好 54 | r = r1 + r2 55 | return r 56 | 57 | def choose_action(self, x): 58 | x = torch.unsqueeze(torch.FloatTensor(x), 0) 59 | # input only one sample 60 | if np.random.uniform() > self.epsilon : # greedy 61 | actions_value = self.eval_net.forward(x) 62 | action = torch.max(actions_value, 1)[1].data.numpy() 63 | action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) # return the argmax index 64 | else: # random 65 | action = np.random.randint(0, N_ACTIONS) 66 | action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) 67 | self.epsilon -= self.epsilon/self.max_episode # decrease epsilon, 从“强探索弱利用”过渡到“弱探索强利用” 68 | return action 69 | 70 | def store_transition(self, s, a, r, s_): 71 | transition = np.hstack((s, [a, r], s_)) 72 | # replace the old memory with new memory 73 | index = self.memory_counter % self.memory_capacity 74 | self.memory[index, :] = transition 75 | self.memory_counter += 1 76 | 77 | def get_samples(self): 78 | sample_index = np.random.choice(self.memory_capacity, self.batch_size) 79 | b_memory = self.memory[sample_index, :] 80 | b_s = torch.FloatTensor(b_memory[:, :N_STATES]) 81 | b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int)) 82 | b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2]) 83 | b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:]) 84 | return b_s,b_a,b_r,b_s_ 85 | 86 | def update_target_net(self): 87 | if self.learn_step_counter % self.target_update_freq == 0: # 每n step更新一次target net 88 | self.target_net.load_state_dict(self.eval_net.state_dict()) 89 | self.learn_step_counter += 1 90 | 91 | def training(self): 92 | # target parameter update 93 | self.update_target_net() 94 | 95 | # sample batch transitions 96 | b_s,b_a,b_r,b_s_ = self.get_samples() 97 | 98 | ### Nature DQN 99 | # q_eval = self.eval_net(b_s).gather(1, b_a) # shape (batch, 1) 100 | # q_next = self.target_net(b_s_).max(1)[0].reshape(self.batch_size, 1).detach() # detach from graph, don't backpropagate 101 | # q_target = b_r + self.gamma * q_next # shape (batch, 1) 102 | 103 | # # Double DQN 104 | # #q_eval w.r.t the action in experience 105 | q_eval = self.eval_net(b_s).gather(1, b_a) # shape (batch, 1) 106 | next_action = self.eval_net(b_s_).max(1)[1].reshape(self.batch_size, 1) # the different from nature DQN 先从q_eval net 中选出价值最大的动作 107 | q_next = self.target_net(b_s_).gather(1, next_action).detach() # detach from graph, don't backpropagate 108 | q_target = b_r + self.gamma * q_next 109 | 110 | loss = self.loss_func(q_eval, q_target) 111 | self.optimizer.zero_grad() 112 | loss.backward() 113 | self.optimizer.step() 114 | self.loss_value = loss.item() #record loss 115 | 116 | 117 | if __name__ == "__main__": 118 | dqn = DQN() 119 | print('\nCollecting experience...') 120 | for i_episode in range(dqn.max_episode): 121 | s = env.reset() 122 | exp_r = 0 123 | step_record = 0 124 | while True: 125 | env.render() 126 | a = dqn.choose_action(s) # take action 127 | # step 函数,包含reward的定义 128 | s_, r, done, info = env.step(a) # s_, r, done, info 新状态,采取这个行动的奖励,是否结束当前回合,其他信息,如性能和表现可用于调优 129 | r = dqn.get_reward(s_) # modify the reward to learn, speed up convergence 130 | dqn.store_transition(s, a, r, s_) 131 | exp_r += r 132 | step_record+=1 133 | if dqn.memory_counter > dqn.memory_capacity: #积累到一定数量开始训练 134 | dqn.training() 135 | if done: 136 | print('loss:', dqn.loss_value) 137 | print('i_episode: ', i_episode, 138 | '| Expect_r: ', round(exp_r, 2)) 139 | print("step_record:",step_record) 140 | print("x:",s[0],"|theta:",s[2],'\n') 141 | break 142 | s = s_ -------------------------------------------------------------------------------- /RL/DQN/Dueling DDQN/DuelingDQN_main.py: -------------------------------------------------------------------------------- 1 | # Double DQN + Dueling 2 | 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | import numpy as np 7 | import gym 8 | 9 | 10 | class Dueling_Net(nn.Module): 11 | def __init__(self,n_input,n_hidden,n_output): 12 | super(Dueling_Net, self).__init__() 13 | self.fc1 = nn.Linear(n_input, n_hidden) 14 | self.fc1.weight.data.normal_(0, 0.1) # initialization 15 | self.out1 = nn.Linear(n_hidden, n_output) 16 | self.out1.weight.data.normal_(0, 0.1) # initialization 17 | 18 | self.fc2 = nn.Linear(n_input,n_hidden) 19 | self.fc2.weight.data.normal_(0,0.1) 20 | self.out2 = nn.Linear(n_hidden,n_output) 21 | self.out2.weight.data.normal_(0,0.1) 22 | 23 | def forward(self, x): 24 | x1 = self.fc1(x) 25 | x1 = F.relu(x1) 26 | y1 = self.out1(x1) # value function: just related with value V(S,w,α) 27 | 28 | x2 = self.fc1(x) 29 | x2 = F.relu(x2) 30 | y2 = self.out2(x2) # Advantage Function : A(S,A,w,β) 31 | 32 | x3 = y1 + (y2 - y2.mean(1).reshape(-1,1)) # 去中心化 33 | actions_value = x3 34 | return actions_value 35 | 36 | 37 | env = gym.make('CartPole-v0') 38 | env = env.unwrapped 39 | N_ACTIONS = env.action_space.n #2 40 | N_STATES = env.observation_space.shape[0] #4 41 | ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(), int) else env.action_space.sample().shape # to confirm the shape 42 | 43 | class DQN(object): 44 | def __init__(self): 45 | # # Hyper Parameters 46 | self.lr = 0.01 47 | self.epsilon = 0.9 # e-greedy policy 48 | self.gamma = 0.9 49 | self.memory_capacity = 200 50 | self.max_episode = 300 51 | self.batch_size = 32 52 | self.target_update_freq = 10 53 | 54 | self.learn_step_counter = 0 # for target updating 55 | self.memory_counter = 0 # for storing memory 56 | self.memory = np.zeros((self.memory_capacity, N_STATES * 2 + 2)) # initialize memory 57 | 58 | self.eval_net, self.target_net = Dueling_Net(N_STATES,50,N_ACTIONS), Dueling_Net(N_STATES,50,N_ACTIONS) # network 59 | self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=self.lr) 60 | self.loss_func = nn.MSELoss() 61 | 62 | def get_reward(self,s_): 63 | # modify the reward to learn ,如果简单的给一些值容易跑飞 64 | x, x_dot, theta, theta_dot = s_ 65 | # r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8 66 | # r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5 67 | r1 = -abs(x) 68 | r2 = -20*abs(theta) #角度奖励大一点,负奖励(惩罚)效果好一些,引入一些先验经验,比如控制力矩小一些比较好 69 | r = r1 + r2 70 | return r 71 | 72 | def choose_action(self, x): 73 | x = torch.unsqueeze(torch.FloatTensor(x), 0) 74 | # input only one sample 75 | if np.random.uniform() > self.epsilon : # greedy 76 | actions_value = self.eval_net.forward(x) 77 | action = torch.max(actions_value, 1)[1].data.numpy() 78 | action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) # return the argmax index 79 | else: # random 80 | action = np.random.randint(0, N_ACTIONS) 81 | action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) 82 | self.epsilon -= self.epsilon/self.max_episode # decrease epsilon, 从“强探索弱利用”过渡到“弱探索强利用” 83 | return action 84 | 85 | def store_transition(self, s, a, r, s_): 86 | transition = np.hstack((s, [a, r], s_)) 87 | # replace the old memory with new memory 88 | index = self.memory_counter % self.memory_capacity 89 | self.memory[index, :] = transition 90 | self.memory_counter += 1 91 | 92 | def get_samples(self,batchs): 93 | # sample batch transitions 94 | sample_index = np.random.choice(self.memory_capacity, batchs) 95 | b_memory = self.memory[sample_index, :] 96 | b_s = torch.FloatTensor(b_memory[:, :N_STATES]) 97 | b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int)) 98 | b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2]) 99 | b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:]) 100 | return b_s,b_a,b_r,b_s_ 101 | 102 | def training(self): 103 | # target parameter update 104 | if self.learn_step_counter % self.target_update_freq == 0: 105 | self.target_net.load_state_dict(self.eval_net.state_dict()) 106 | self.learn_step_counter += 1 107 | 108 | b_s,b_a,b_r,b_s_ = self.get_samples(batchs=self.batch_size) 109 | 110 | # # Double DQN 111 | # #q_eval w.r.t the action in experience 112 | q_eval = self.eval_net(b_s).gather(1, b_a) # shape (batch, 1) 113 | next_action = self.eval_net(b_s_).argmax(1).reshape(self.batch_size, 1) # the different from nature DQN 先从q_eval net 中选出价值最大的动作 114 | q_next = self.target_net(b_s_).gather(1, next_action).detach() # detach from graph, don't backpropagate 115 | q_target = b_r + self.gamma * q_next 116 | 117 | loss = self.loss_func(q_eval, q_target) 118 | self.optimizer.zero_grad() 119 | loss.backward() 120 | self.optimizer.step() 121 | self.loss_value = loss.item() 122 | 123 | 124 | if __name__ == "__main__": 125 | dqn = DQN() 126 | print('\nCollecting experience...') 127 | for i_episode in range(dqn.max_episode): 128 | s = env.reset() 129 | exp_r = 0 130 | step_record = 0 131 | while True: 132 | env.render() 133 | a = dqn.choose_action(s) # take action 134 | # step 函数,包含reward的定义 135 | s_, r, done, info = env.step(a) # s_, r, done, info 新状态,采取这个行动的奖励,是否结束当前回合,其他信息,如性能和表现可用于调优 136 | r = dqn.get_reward(s_) # modify the reward to learn 137 | dqn.store_transition(s, a, r, s_) 138 | exp_r += r 139 | step_record+=1 140 | if dqn.memory_counter > dqn.memory_capacity: #积累到一定数量开始训练 141 | dqn.training() 142 | if done: 143 | print('loss:', dqn.loss_value) 144 | print('i_episode: ', i_episode, 145 | '| Expect_reward: ', round(exp_r, 2)) 146 | if done: 147 | print("step_record:",step_record) 148 | print("x:",s[0],"|theta:",s[2],'\n') 149 | if step_record>1000: 150 | print('convergence!!!') 151 | break 152 | s = s_ 153 | 154 | -------------------------------------------------------------------------------- /RL/DQN/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/RL/DQN/readme.md -------------------------------------------------------------------------------- /RL/PPO/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/RL/PPO/readme.md -------------------------------------------------------------------------------- /RL/README.md: -------------------------------------------------------------------------------- 1 | # Reinforcement Learning 2 | 3 | this part includes the Python implementation of RL. 4 | 5 | 6 | -------------------------------------------------------------------------------- /SCIP/README.md: -------------------------------------------------------------------------------- 1 | # SCIP instances 2 | 3 | Some hands-on tutorials on SCIP are here, It also can be used as a tool manual in the future 4 | 5 | 6 | ## installing 7 | 8 | the installing details can be seen as https://blog.csdn.net/DCXY71/article/details/118346707?spm=1001.2014.3001.5501 9 | 10 | 11 | 12 | 13 | 14 | Continuously updating.... 15 | 16 | -------------------------------------------------------------------------------- /TSP-heuristic/Genetic Algorithm TSP/readme.md: -------------------------------------------------------------------------------- 1 | # Genetic Algorithm 2 | The basic Genetic Algorithm implementaion of pyhton using TSP as an example. 3 | 4 | 5 | ## GA flow chart 6 | The basic idea of GA: 7 | 8 | ![](https://img-blog.csdnimg.cn/20210331202449553.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RDWFk3MQ==,size_16,color_FFFFFF,t_70) 9 | 10 | 11 | 12 | ## Numerical example 13 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 14 | 15 | 16 | 17 | 18 | ## My blog 19 | See [my blog](https://blog.csdn.net/DCXY71/article/details/110727046?spm=1001.2014.3001.5501) for more detailed explanation 20 | 21 | -------------------------------------------------------------------------------- /TSP-heuristic/Genetic Algorithm/GA_TSP.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import random,time 3 | import matplotlib.pyplot as plt 4 | from GetData import * 5 | 6 | class GA(): 7 | 8 | def __init__(self,disMatrix,MaxGens,pop_size,cross_rate,mutation_rate): 9 | "pop_size > 1 " 10 | self.disMatrix = disMatrix 11 | self.gene_size = len(disMatrix) # 基因长度,路径长度,0为Depot 12 | self.pop_size = pop_size #种群大小,每一代解的数量 13 | self.MaxGens = MaxGens #最大迭代次数 14 | self.cross_rate = cross_rate #交叉概率 15 | self.mutation_rate = mutation_rate #变异概率 16 | 17 | def get_init_solution(self): 18 | init_routes = np.array([]) 19 | route = np.arange(1,self.gene_size) # 生成初始解 20 | for i in range(self.pop_size): 21 | np.random.shuffle(route) 22 | init_routes = np.append(init_routes,route) 23 | return init_routes.reshape(self.pop_size,self.gene_size-1).astype(int) 24 | 25 | def get_route_distance(self,route): 26 | routes = list(route) 27 | routes = [0] + routes +[0] 28 | total_distance = 0 29 | for i,n in enumerate(routes): 30 | if i != 0 : 31 | total_distance = total_distance + self.disMatrix[last_pos][n] 32 | last_pos = n 33 | return total_distance 34 | 35 | def get_fitness(self,pop_routes): 36 | fitness = [] 37 | for route in pop_routes: 38 | fitness.append(self.get_route_distance(route)) 39 | fitness = 1 - fitness/np.sum(fitness) # 归一化后取反 40 | return np.array(fitness) 41 | 42 | def select(self,pop_routes): 43 | fitness = self.get_fitness(pop_routes) 44 | #轮盘赌的形式进行选择,适应度高的被选中的概率就大 45 | selected_label = np.random.choice(range(self.pop_size), size=self.pop_size, replace=True, p=fitness/np.sum(fitness)) 46 | return pop_routes[selected_label] 47 | 48 | def crossover(self,pop_routes): 49 | for i in range(self.pop_size): 50 | if np.random.rand() < self.cross_rate : 51 | obj = pop_routes[np.random.randint(self.pop_size)] #随机选一个交叉对象,也可以选到自己,生成新的一代 52 | cross_point = np.random.randint(self.gene_size) #在DNA片段中随机选一个交叉点 53 | new_one = np.hstack((pop_routes[i][0:cross_point],obj[cross_point::])) #从交叉点往后交换基因片段 54 | if len(set(new_one)) < self.gene_size-1 : #交换片段后可能是无效解,即有重复元素,处理一下 55 | new_one__ = [] 56 | for num in new_one: 57 | if num not in new_one__: 58 | new_one__.append(num) 59 | else: 60 | for j in range(1,self.gene_size): 61 | if j not in new_one__: 62 | new_one__.append(j) 63 | pop_routes[i] = new_one__ 64 | continue 65 | pop_routes[i] = new_one 66 | return pop_routes 67 | 68 | def mutate(self,pop_routes): 69 | for i in range(self.pop_size): 70 | if np.random.rand() < self.mutation_rate : 71 | pos1 = np.random.randint(0,self.gene_size-1) # 随机选取某一个基因位置发生变异 72 | pos2 = np.random.randint(0,self.gene_size-1) 73 | pop_routes[i][pos1],pop_routes[i][pos2] = pop_routes[i][pos2],pop_routes[i][pos1] #交换位置,完成变异 74 | return pop_routes 75 | 76 | def ga_evolution(self): 77 | routes = self.get_init_solution() #生成初始解 78 | result=[] #记录迭代过程中的信息 79 | while(self.MaxGens): 80 | self.MaxGens -=1 81 | routes = self.select(routes) 82 | routes = self.crossover(routes) 83 | routes = self.mutate(routes) 84 | result.append(max(self.get_fitness(routes))) #记录一下迭代过程中的信息 85 | plt.plot(range(len(result)),result) 86 | plt.show() 87 | idx = np.where(self.get_fitness(routes)==max(self.get_fitness(routes))) #挑出适应度最大的,可能不止一个 88 | best_id = random.sample(list(idx[0]), 1) #从中拿一个 89 | best_route = routes[best_id] 90 | return np.squeeze(best_route).tolist() 91 | 92 | if __name__ == "__main__": 93 | data=GetData() 94 | solomon_data = data.read_solomon(path ='E:\MIP启发式算法编辑部\Part-71\data\R101.txt',customerNum=7) #定义多少个点 95 | dismatrix = data.get_euclidean_distance_matrix(solomon_data.locations) 96 | 97 | ga = GA(disMatrix=dismatrix,MaxGens=500,pop_size=100,cross_rate=0.3,mutation_rate=0.1) 98 | best_route = ga.ga_evolution() 99 | print('best_route:',best_route) 100 | print('best distance:',ga.get_route_distance(best_route)) 101 | 102 | data.plot_route(solomon_data.locations,[0]+best_route+[0]) 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /TSP-heuristic/Genetic Algorithm/GetData.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description: data generation for vehicle routing problem and visualization 3 | Version: 1.0 4 | Author: 71 5 | Date: 2020-12-10 17:20:09 6 | ''' 7 | import math,re,copy 8 | import numpy as np 9 | import networkx as nx 10 | import matplotlib.pyplot as plt 11 | 12 | class GetData(): 13 | 14 | def generate_locations(self,num_points,map_size,num_vehicles=1,depot=0): 15 | """generate number of locations randomly in a block unit 16 | default TSP : num_vehicles=1,depot=0 17 | """ 18 | locations=[] # locations = [(24, 3), (21, 4), (5, 1),...] 19 | for i in range(num_points): 20 | locations.append(tuple(np.random.randint(low=0,high=map_size,size=2))) 21 | class random_data(): 22 | def __init__(self): 23 | self.locations = locations 24 | self.num_vehicles = num_vehicles 25 | self.depot = depot 26 | return random_data() 27 | 28 | def get_euclidean_distance_matrix(self,locations): 29 | """Creates callback to return distance between locations.""" 30 | distances = {} 31 | for from_counter, from_node in enumerate(locations): 32 | distances[from_counter] = {} 33 | for to_counter, to_node in enumerate(locations): 34 | if from_counter == to_counter: 35 | distances[from_counter][to_counter] = 0 36 | else: 37 | # Euclidean distance 38 | distances[from_counter][to_counter] = (int( 39 | math.hypot((from_node[0] - to_node[0]), 40 | (from_node[1] - to_node[1])))) 41 | return distances 42 | 43 | 44 | def read_solomon(self,path,customerNum=100): 45 | '''Description: load solomon dataset''' 46 | f = open(path, 'r') 47 | lines = f.readlines() 48 | locations,demand,readyTime,dueTime,serviceTime=[],[],[],[],[] 49 | for count,line in enumerate(lines): 50 | count = count + 1 51 | if(count == 5): 52 | line = line[:-1].strip() 53 | str = re.split(r" +", line) 54 | vehicleNum = int(str[0]) 55 | capacity = float(str[1]) 56 | elif(count >= 10 and count <= 10 + customerNum): 57 | line = line[:-1] 58 | str = re.split(r" +", line) 59 | locations.append((float(str[2]),float(str[3]))) 60 | demand.append(float(str[4])) 61 | readyTime.append(float(str[5])) 62 | dueTime.append(float(str[6])) 63 | serviceTime.append(float(str[7])) 64 | class Solomon_data(): 65 | def __init__(self): 66 | self.locations=locations 67 | self.demand = demand 68 | self.readyTime = readyTime 69 | self.dueTime = dueTime 70 | self.serviceTime = serviceTime 71 | self.vehicleNum = vehicleNum 72 | self.capacity =capacity 73 | return Solomon_data() 74 | 75 | 76 | def plot_nodes(self,locations): 77 | ''' function to plot locations''' 78 | Graph = nx.DiGraph() 79 | nodes_name = [str(x) for x in list(range(len(locations)))] 80 | Graph.add_nodes_from(nodes_name) 81 | pos_location = {nodes_name[i]:x for i,x in enumerate(locations)} 82 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-1) 83 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,labels=None) 84 | plt.show(Graph) 85 | 86 | def plot_route(self,locations,route,color='k'): 87 | ''' function to plot locations and route''' 88 | Graph = nx.DiGraph() 89 | edge = [] 90 | edges = [] 91 | for i in route : 92 | edge.append(i) 93 | if len(edge) == 2 : 94 | edges.append(tuple(edge)) 95 | edge.pop(0) 96 | nodes_name = [x for x in list(range(len(locations)))] 97 | Graph.add_nodes_from(nodes_name) 98 | Graph.add_edges_from(edges) 99 | pos_location = {nodes_name[i] : x for i,x in enumerate(locations)} 100 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-1) 101 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,edge_color=color, labels=None) 102 | plt.show(Graph) 103 | 104 | 105 | if __name__ == "__main__": 106 | ## generate data randomly 107 | data=GetData() 108 | random_data = data.generate_locations(num_points=10,map_size=100) 109 | dismatrix = data.get_euclidean_distance_matrix(random_data.locations) 110 | print(dismatrix) # get dismatrix randomly 111 | 112 | ## read solomon data 113 | path = 'E:\MIP启发式算法编辑部\Part-71\data\R101.txt' 114 | solomon_data = data.read_solomon(path,customerNum=9) 115 | solomon_data_dismatrix = data.get_euclidean_distance_matrix(solomon_data.locations) 116 | print(solomon_data_dismatrix) 117 | data.plot_nodes(solomon_data.locations) 118 | ## plot function 119 | # data.plot_nodes(solomon_data.locations) 120 | route = list(range(10)) 121 | route.append(0) 122 | data.plot_route(solomon_data.locations,route) 123 | 124 | -------------------------------------------------------------------------------- /TSP-heuristic/Genetic Algorithm/R101.txt: -------------------------------------------------------------------------------- 1 | R101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 35 35 0 0 230 0 11 | 1 41 49 10 161 171 10 12 | 2 35 17 7 50 60 10 13 | 3 55 45 13 116 126 10 14 | 4 55 20 19 149 159 10 15 | 5 15 30 26 34 44 10 16 | 6 25 30 3 99 109 10 17 | 7 20 50 5 81 91 10 18 | 8 10 43 9 95 105 10 19 | 9 55 60 16 97 107 10 20 | 10 30 60 16 124 134 10 21 | 11 20 65 12 67 77 10 22 | 12 50 35 19 63 73 10 23 | 13 30 25 23 159 169 10 24 | 14 15 10 20 32 42 10 25 | 15 30 5 8 61 71 10 26 | 16 10 20 19 75 85 10 27 | 17 5 30 2 157 167 10 28 | 18 20 40 12 87 97 10 29 | 19 15 60 17 76 86 10 30 | 20 45 65 9 126 136 10 31 | 21 45 20 11 62 72 10 32 | 22 45 10 18 97 107 10 33 | 23 55 5 29 68 78 10 34 | 24 65 35 3 153 163 10 35 | 25 65 20 6 172 182 10 36 | 26 45 30 17 132 142 10 37 | 27 35 40 16 37 47 10 38 | 28 41 37 16 39 49 10 39 | 29 64 42 9 63 73 10 40 | 30 40 60 21 71 81 10 41 | 31 31 52 27 50 60 10 42 | 32 35 69 23 141 151 10 43 | 33 53 52 11 37 47 10 44 | 34 65 55 14 117 127 10 45 | 35 63 65 8 143 153 10 46 | 36 2 60 5 41 51 10 47 | 37 20 20 8 134 144 10 48 | 38 5 5 16 83 93 10 49 | 39 60 12 31 44 54 10 50 | 40 40 25 9 85 95 10 51 | 41 42 7 5 97 107 10 52 | 42 24 12 5 31 41 10 53 | 43 23 3 7 132 142 10 54 | 44 11 14 18 69 79 10 55 | 45 6 38 16 32 42 10 56 | 46 2 48 1 117 127 10 57 | 47 8 56 27 51 61 10 58 | 48 13 52 36 165 175 10 59 | 49 6 68 30 108 118 10 60 | 50 47 47 13 124 134 10 61 | 51 49 58 10 88 98 10 62 | 52 27 43 9 52 62 10 63 | 53 37 31 14 95 105 10 64 | 54 57 29 18 140 150 10 65 | 55 63 23 2 136 146 10 66 | 56 53 12 6 130 140 10 67 | 57 32 12 7 101 111 10 68 | 58 36 26 18 200 210 10 69 | 59 21 24 28 18 28 10 70 | 60 17 34 3 162 172 10 71 | 61 12 24 13 76 86 10 72 | 62 24 58 19 58 68 10 73 | 63 27 69 10 34 44 10 74 | 64 15 77 9 73 83 10 75 | 65 62 77 20 51 61 10 76 | 66 49 73 25 127 137 10 77 | 67 67 5 25 83 93 10 78 | 68 56 39 36 142 152 10 79 | 69 37 47 6 50 60 10 80 | 70 37 56 5 182 192 10 81 | 71 57 68 15 77 87 10 82 | 72 47 16 25 35 45 10 83 | 73 44 17 9 78 88 10 84 | 74 46 13 8 149 159 10 85 | 75 49 11 18 69 79 10 86 | 76 49 42 13 73 83 10 87 | 77 53 43 14 179 189 10 88 | 78 61 52 3 96 106 10 89 | 79 57 48 23 92 102 10 90 | 80 56 37 6 182 192 10 91 | 81 55 54 26 94 104 10 92 | 82 15 47 16 55 65 10 93 | 83 14 37 11 44 54 10 94 | 84 11 31 7 101 111 10 95 | 85 16 22 41 91 101 10 96 | 86 4 18 35 94 104 10 97 | 87 28 18 26 93 103 10 98 | 88 26 52 9 74 84 10 99 | 89 26 35 15 176 186 10 100 | 90 31 67 3 95 105 10 101 | 91 15 19 1 160 170 10 102 | 92 22 22 2 18 28 10 103 | 93 18 24 22 188 198 10 104 | 94 26 27 27 100 110 10 105 | 95 25 24 20 39 49 10 106 | 96 22 27 11 135 145 10 107 | 97 25 21 12 133 143 10 108 | 98 19 21 10 58 68 10 109 | 99 20 26 9 83 93 10 110 | 100 18 18 17 185 195 10 111 | -------------------------------------------------------------------------------- /TSP-heuristic/Genetic Algorithm/readme.md: -------------------------------------------------------------------------------- 1 | # Genetic Algorithm 2 | The basic Genetic Algorithm implementaion of pyhton using TSP as an example. 3 | 4 | 5 | ## GA flow chart 6 | The basic idea of GA: 7 | 8 | ![](https://img-blog.csdnimg.cn/20210331202449553.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RDWFk3MQ==,size_16,color_FFFFFF,t_70) 9 | 10 | 11 | 12 | ## Numerical example 13 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 14 | 15 | 16 | 17 | 18 | ## My blog 19 | See [my blog](https://blog.csdn.net/DCXY71/article/details/110727046?spm=1001.2014.3001.5501) for more detailed explanation 20 | 21 | -------------------------------------------------------------------------------- /TSP-heuristic/Large Scale Neighborhood Search/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/TSP-heuristic/Large Scale Neighborhood Search/readme.md -------------------------------------------------------------------------------- /TSP-heuristic/README.md: -------------------------------------------------------------------------------- 1 | # meta-Heuristic 2 | 3 | the meta-Heuristic algorithm implementations with an example of TSP, including : 4 | - Tabu Search (TS) 5 | - Genetic Algorithm (GA) 6 | - Simulated Annealing (SA) 7 | - Large Scale Neighborhood Search (LSNS) 8 | - 9 | 10 | Certainly,It can be applied not only in TSP, but also in many problems which depends on your need. 11 | 12 | 13 | ## Numerical example 14 | 15 | 'R101.txt' is from solomon benchmark, more details can be found in https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/ 16 | -------------------------------------------------------------------------------- /TSP-heuristic/Simulated Annealing/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DDD71/code71/e7d4262582dc4e4c5d710b10ae0d1cf9a34c94eb/TSP-heuristic/Simulated Annealing/readme.md -------------------------------------------------------------------------------- /TSP-heuristic/Tabu Search-TSP/README.md: -------------------------------------------------------------------------------- 1 | # Tabu Search 2 | the basic tabu search implementaion of pyhton using TSP as an example. 3 | 4 | 5 | Tabu search is a metaheuristic search method employing local search methods used for mathematical optimization. It was created by Fred W. Glover in 1986[1] and formalized in 1989. 6 | 7 | 8 | ## Pseudo code 9 | ``` 10 | sBest ← s0 11 | 2 bestCandidate ← s0 12 | 3 tabuList ← [] 13 | 4 tabuList.push(s0) 14 | 5 while (not stoppingCondition()) 15 | 6 sNeighborhood ← getNeighbors(bestCandidate) 16 | 7 bestCandidate ← sNeighborhood[0] 17 | 8 for (sCandidate in sNeighborhood) 18 | 9 if ( (not tabuList.contains(sCandidate)) and (fitness(sCandidate) > fitness(bestCandidate)) ) 19 | 10 bestCandidate ← sCandidate 20 | 11 end 21 | 12 end 22 | 13 if (fitness(bestCandidate) > fitness(sBest)) 23 | 14 sBest ← bestCandidate 24 | 15 end 25 | 16 tabuList.push(bestCandidate) 26 | 17 if (tabuList.size > maxTabuSize) 27 | 18 tabuList.removeFirst() 28 | 19 end 29 | 20 end 30 | 21 return sBest 31 | ``` 32 | (the Pseudo code from [wikipedia](https://en.wikipedia.org/wiki/Tabu_search)) 33 | 34 | 35 | ## Numerical example 36 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 37 | 38 | 39 | ## My blog 40 | See [my blog](https://blog.csdn.net/DCXY71/article/details/109597801?spm=1001.2014.3001.5501) for more detailed explanation 41 | 42 | 43 | ## Ref 44 | 1. Fred Glover (1986). "Future Paths for Integer Programming and Links to Artificial Intelligence". Computers and Operations Research. 13 (5): 533–549. doi:10.1016/0305-0548(86)90048-1. 45 | 2. Fred Glover (1989). "Tabu Search – Part 1". ORSA Journal on Computing. 1 (2): 190–206. doi:10.1287/ijoc.1.3.190. 46 | -------------------------------------------------------------------------------- /TSP-heuristic/Tabu Search/GetData.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description: data generation for vehicle routing problem and visualization 3 | Version: 1.0 4 | Author: 71 5 | Date: 2020-12-10 17:20:09 6 | ''' 7 | import math,re,copy 8 | import numpy as np 9 | import networkx as nx 10 | import matplotlib.pyplot as plt 11 | 12 | class GetData(): 13 | 14 | def generate_locations(self,num_points,map_size,num_vehicles=1,depot=0): 15 | """generate number of locations randomly in a block unit 16 | default TSP : num_vehicles=1,depot=0 17 | """ 18 | locations=[] # locations = [(24, 3), (21, 4), (5, 1),...] 19 | for i in range(num_points): 20 | locations.append(tuple(np.random.randint(low=0,high=map_size,size=2))) 21 | class random_data(): 22 | def __init__(self): 23 | self.locations = locations 24 | self.num_vehicles = num_vehicles 25 | self.depot = depot 26 | return random_data() 27 | 28 | def get_euclidean_distance_matrix(self,locations): 29 | """Creates callback to return distance between locations.""" 30 | distances = {} 31 | for from_counter, from_node in enumerate(locations): 32 | distances[from_counter] = {} 33 | for to_counter, to_node in enumerate(locations): 34 | if from_counter == to_counter: 35 | distances[from_counter][to_counter] = 0 36 | else: 37 | # Euclidean distance 38 | distances[from_counter][to_counter] = (int( 39 | math.hypot((from_node[0] - to_node[0]), 40 | (from_node[1] - to_node[1])))) 41 | return distances 42 | 43 | 44 | def read_solomon(self,path,customerNum=100): 45 | '''Description: load solomon dataset''' 46 | f = open(path, 'r') 47 | lines = f.readlines() 48 | locations,demand,readyTime,dueTime,serviceTime=[],[],[],[],[] 49 | for count,line in enumerate(lines): 50 | count = count + 1 51 | if(count == 5): 52 | line = line[:-1].strip() 53 | str = re.split(r" +", line) 54 | vehicleNum = int(str[0]) 55 | capacity = float(str[1]) 56 | elif(count >= 10 and count <= 10 + customerNum): 57 | line = line[:-1] 58 | str = re.split(r" +", line) 59 | locations.append((float(str[2]),float(str[3]))) 60 | demand.append(float(str[4])) 61 | readyTime.append(float(str[5])) 62 | dueTime.append(float(str[6])) 63 | serviceTime.append(float(str[7])) 64 | class Solomon_data(): 65 | def __init__(self): 66 | self.locations=locations 67 | self.demand = demand 68 | self.readyTime = readyTime 69 | self.dueTime = dueTime 70 | self.serviceTime = serviceTime 71 | self.vehicleNum = vehicleNum 72 | self.capacity =capacity 73 | return Solomon_data() 74 | 75 | 76 | def plot_nodes(self,locations): 77 | ''' function to plot locations''' 78 | Graph = nx.DiGraph() 79 | nodes_name = [str(x) for x in list(range(len(locations)))] 80 | Graph.add_nodes_from(nodes_name) 81 | pos_location = {nodes_name[i]:x for i,x in enumerate(locations)} 82 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-1) 83 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,labels=None) 84 | plt.show(Graph) 85 | 86 | def plot_route(self,locations,route,color='k'): 87 | ''' function to plot locations and route''' 88 | Graph = nx.DiGraph() 89 | edge = [] 90 | edges = [] 91 | for i in route : 92 | edge.append(i) 93 | if len(edge) == 2 : 94 | edges.append(tuple(edge)) 95 | edge.pop(0) 96 | nodes_name = [x for x in list(range(len(locations)))] 97 | Graph.add_nodes_from(nodes_name) 98 | Graph.add_edges_from(edges) 99 | pos_location = {nodes_name[i] : x for i,x in enumerate(locations)} 100 | nodes_color_dict = ['r'] + ['gray'] * (len(locations)-1) 101 | nx.draw_networkx(Graph,pos_location,node_size=200,node_color=nodes_color_dict,edge_color=color, labels=None) 102 | plt.show(Graph) 103 | 104 | 105 | if __name__ == "__main__": 106 | ## generate data randomly 107 | data=GetData() 108 | random_data = data.generate_locations(num_points=10,map_size=100) 109 | dismatrix = data.get_euclidean_distance_matrix(random_data.locations) 110 | print(dismatrix) # get dismatrix randomly 111 | 112 | ## read solomon data 113 | path = 'R101.txt' 114 | solomon_data = data.read_solomon(path,customerNum=9) 115 | solomon_data_dismatrix = data.get_euclidean_distance_matrix(solomon_data.locations) 116 | print(solomon_data_dismatrix) 117 | data.plot_nodes(solomon_data.locations) 118 | ## plot function 119 | # data.plot_nodes(solomon_data.locations) 120 | route = list(range(10)) 121 | route.append(0) 122 | data.plot_route(solomon_data.locations,route) 123 | 124 | -------------------------------------------------------------------------------- /TSP-heuristic/Tabu Search/R101.txt: -------------------------------------------------------------------------------- 1 | R101 2 | 3 | VEHICLE 4 | NUMBER CAPACITY 5 | 25 200 6 | 7 | CUSTOMER 8 | CUST NO. XCOORD. YCOORD. DEMAND READY TIME DUE DATE SERVICE TIME 9 | 10 | 0 35 35 0 0 230 0 11 | 1 41 49 10 161 171 10 12 | 2 35 17 7 50 60 10 13 | 3 55 45 13 116 126 10 14 | 4 55 20 19 149 159 10 15 | 5 15 30 26 34 44 10 16 | 6 25 30 3 99 109 10 17 | 7 20 50 5 81 91 10 18 | 8 10 43 9 95 105 10 19 | 9 55 60 16 97 107 10 20 | 10 30 60 16 124 134 10 21 | 11 20 65 12 67 77 10 22 | 12 50 35 19 63 73 10 23 | 13 30 25 23 159 169 10 24 | 14 15 10 20 32 42 10 25 | 15 30 5 8 61 71 10 26 | 16 10 20 19 75 85 10 27 | 17 5 30 2 157 167 10 28 | 18 20 40 12 87 97 10 29 | 19 15 60 17 76 86 10 30 | 20 45 65 9 126 136 10 31 | 21 45 20 11 62 72 10 32 | 22 45 10 18 97 107 10 33 | 23 55 5 29 68 78 10 34 | 24 65 35 3 153 163 10 35 | 25 65 20 6 172 182 10 36 | 26 45 30 17 132 142 10 37 | 27 35 40 16 37 47 10 38 | 28 41 37 16 39 49 10 39 | 29 64 42 9 63 73 10 40 | 30 40 60 21 71 81 10 41 | 31 31 52 27 50 60 10 42 | 32 35 69 23 141 151 10 43 | 33 53 52 11 37 47 10 44 | 34 65 55 14 117 127 10 45 | 35 63 65 8 143 153 10 46 | 36 2 60 5 41 51 10 47 | 37 20 20 8 134 144 10 48 | 38 5 5 16 83 93 10 49 | 39 60 12 31 44 54 10 50 | 40 40 25 9 85 95 10 51 | 41 42 7 5 97 107 10 52 | 42 24 12 5 31 41 10 53 | 43 23 3 7 132 142 10 54 | 44 11 14 18 69 79 10 55 | 45 6 38 16 32 42 10 56 | 46 2 48 1 117 127 10 57 | 47 8 56 27 51 61 10 58 | 48 13 52 36 165 175 10 59 | 49 6 68 30 108 118 10 60 | 50 47 47 13 124 134 10 61 | 51 49 58 10 88 98 10 62 | 52 27 43 9 52 62 10 63 | 53 37 31 14 95 105 10 64 | 54 57 29 18 140 150 10 65 | 55 63 23 2 136 146 10 66 | 56 53 12 6 130 140 10 67 | 57 32 12 7 101 111 10 68 | 58 36 26 18 200 210 10 69 | 59 21 24 28 18 28 10 70 | 60 17 34 3 162 172 10 71 | 61 12 24 13 76 86 10 72 | 62 24 58 19 58 68 10 73 | 63 27 69 10 34 44 10 74 | 64 15 77 9 73 83 10 75 | 65 62 77 20 51 61 10 76 | 66 49 73 25 127 137 10 77 | 67 67 5 25 83 93 10 78 | 68 56 39 36 142 152 10 79 | 69 37 47 6 50 60 10 80 | 70 37 56 5 182 192 10 81 | 71 57 68 15 77 87 10 82 | 72 47 16 25 35 45 10 83 | 73 44 17 9 78 88 10 84 | 74 46 13 8 149 159 10 85 | 75 49 11 18 69 79 10 86 | 76 49 42 13 73 83 10 87 | 77 53 43 14 179 189 10 88 | 78 61 52 3 96 106 10 89 | 79 57 48 23 92 102 10 90 | 80 56 37 6 182 192 10 91 | 81 55 54 26 94 104 10 92 | 82 15 47 16 55 65 10 93 | 83 14 37 11 44 54 10 94 | 84 11 31 7 101 111 10 95 | 85 16 22 41 91 101 10 96 | 86 4 18 35 94 104 10 97 | 87 28 18 26 93 103 10 98 | 88 26 52 9 74 84 10 99 | 89 26 35 15 176 186 10 100 | 90 31 67 3 95 105 10 101 | 91 15 19 1 160 170 10 102 | 92 22 22 2 18 28 10 103 | 93 18 24 22 188 198 10 104 | 94 26 27 27 100 110 10 105 | 95 25 24 20 39 49 10 106 | 96 22 27 11 135 145 10 107 | 97 25 21 12 133 143 10 108 | 98 19 21 10 58 68 10 109 | 99 20 26 9 83 93 10 110 | 100 18 18 17 185 195 10 111 | -------------------------------------------------------------------------------- /TSP-heuristic/Tabu Search/README.md: -------------------------------------------------------------------------------- 1 | # Tabu Search 2 | the basic tabu search implementaion of pyhton using TSP as an example. 3 | 4 | 5 | Tabu search is a metaheuristic search method employing local search methods used for mathematical optimization. It was created by Fred W. Glover in 1986[1] and formalized in 1989. 6 | 7 | 8 | ## Pseudo code 9 | ``` 10 | sBest ← s0 11 | 2 bestCandidate ← s0 12 | 3 tabuList ← [] 13 | 4 tabuList.push(s0) 14 | 5 while (not stoppingCondition()) 15 | 6 sNeighborhood ← getNeighbors(bestCandidate) 16 | 7 bestCandidate ← sNeighborhood[0] 17 | 8 for (sCandidate in sNeighborhood) 18 | 9 if ( (not tabuList.contains(sCandidate)) and (fitness(sCandidate) > fitness(bestCandidate)) ) 19 | 10 bestCandidate ← sCandidate 20 | 11 end 21 | 12 end 22 | 13 if (fitness(bestCandidate) > fitness(sBest)) 23 | 14 sBest ← bestCandidate 24 | 15 end 25 | 16 tabuList.push(bestCandidate) 26 | 17 if (tabuList.size > maxTabuSize) 27 | 18 tabuList.removeFirst() 28 | 19 end 29 | 20 end 30 | 21 return sBest 31 | ``` 32 | (the Pseudo code from [wikipedia](https://en.wikipedia.org/wiki/Tabu_search)) 33 | 34 | 35 | ## Numerical example 36 | 'R101.txt' is from solomon benchmark, more details can be found in [solomon-benchmark](https://www.sintef.no/projectweb/top/vrptw/solomon-benchmark/). 37 | 38 | 39 | ## My blog 40 | See [my blog](https://blog.csdn.net/DCXY71/article/details/109597801?spm=1001.2014.3001.5501) for more detailed explanation 41 | 42 | 43 | ## Ref 44 | 1. Fred Glover (1986). "Future Paths for Integer Programming and Links to Artificial Intelligence". Computers and Operations Research. 13 (5): 533–549. doi:10.1016/0305-0548(86)90048-1. 45 | 2. Fred Glover (1989). "Tabu Search – Part 1". ORSA Journal on Computing. 1 (2): 190–206. doi:10.1287/ijoc.1.3.190. 46 | -------------------------------------------------------------------------------- /TSP-heuristic/Tabu Search/tabu_tsp.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description: tabu search for TSP 3 | Version: 1.0 (original tabu search without any optimization) 4 | Author: 71 5 | Date: 2020-10-31 6 | ''' 7 | from itertools import combinations 8 | import os,sys,copy 9 | import numpy as np 10 | import time 11 | import matplotlib.pyplot as plt 12 | from GetData import * 13 | from tqdm import tqdm 14 | 15 | class Tabu(): 16 | def __init__(self,disMatrix,max_iters=50,maxTabuSize=10): 17 | """parameters definition""" 18 | self.disMatrix = disMatrix 19 | self.maxTabuSize = maxTabuSize 20 | self.max_iters = max_iters 21 | self.tabu_list=[] 22 | 23 | def get_route_distance(self,route): 24 | ''' 25 | Description: function to calculate total distance of a route. evaluate function. 26 | parameters: route : list 27 | return : total distance : folat 28 | ''' 29 | routes = [0] + route + [0] # add the start and end point 30 | total_distance = 0 31 | for i,n in enumerate(routes): 32 | if i != 0 : 33 | total_distance = total_distance + self.disMatrix[last_pos][n] 34 | last_pos = n 35 | return total_distance 36 | 37 | def exchange(self,s1,s2,arr): 38 | """ 39 | function to Swap positions of two elements in an arr 40 | Args: int,int,list 41 | s1 : target 1 42 | s2 : target 2 43 | arr : target array 44 | Ouput: list 45 | current_list : target array 46 | """ 47 | current_list = copy.deepcopy(arr) 48 | index1 , index2 = current_list.index(s1) , current_list.index(s2) # get index 49 | current_list[index1], current_list[index2]= arr[index2] , arr[index1] 50 | return current_list 51 | 52 | def generate_initial_solution(self,num=10,mode='greedy'): 53 | """ 54 | function to get the initial solution,there two different way to generate route_init. 55 | Args: 56 | num : int 57 | the number of points 58 | mode : string 59 | "greedy" : advance step by choosing optimal one 60 | "random" : randomly generate a series number 61 | Ouput: list 62 | s_init : initial solution route_init 63 | """ 64 | if mode == 'greedy': 65 | route_init=[0] 66 | for i in range(num): 67 | best_distance = 10000000 68 | for j in range(num+1): 69 | if self.disMatrix[i][j] < best_distance and j not in route_init: 70 | best_distance = self.disMatrix[i][j] 71 | best_candidate = j 72 | route_init.append(best_candidate) 73 | route_init.remove(0) 74 | 75 | if mode == 'random': 76 | route_init = np.arange(1,num+1) #init solution from 1 to num 77 | np.random.shuffle(route_init) #shuffle the list randomly 78 | 79 | return list(route_init) 80 | 81 | def tabu_search(self,s_init): 82 | """tabu search""" 83 | s_best = s_init 84 | bestCandidate = copy.deepcopy(s_best) 85 | routes , temp_tabu = [] , [] # init 86 | routes.append(s_best) 87 | while(self.max_iters): 88 | self.max_iters -= 1 # Number of iterations 89 | neighbors = copy.deepcopy(s_best) 90 | for s in combinations(neighbors, 2): 91 | sCandidate = self.exchange(s[0],s[1],neighbors) # exchange number to generate candidates 92 | if s not in self.tabu_list and self.get_route_distance(sCandidate) < self.get_route_distance(bestCandidate): 93 | bestCandidate = sCandidate 94 | temp_tabu = s 95 | if self.get_route_distance(bestCandidate) < self.get_route_distance(s_best): # record the best solution 96 | s_best = bestCandidate 97 | if temp_tabu not in self.tabu_list: 98 | self.tabu_list.append(temp_tabu) 99 | if len(self.tabu_list) > self.maxTabuSize : 100 | self.tabu_list.pop(0) 101 | routes.append(bestCandidate) 102 | return s_best, routes 103 | 104 | if __name__ == "__main__": 105 | np.random.seed(2020) 106 | customerNum = 10 # 定义多少个点 107 | data=GetData() 108 | tsp_data = data.generate_locations(num_points=customerNum+1,map_size=100) #在100*100的图中,随机生成位置,customerNum+1 多一个depot点 109 | dismatrix = data.get_euclidean_distance_matrix(tsp_data.locations) 110 | # data.plot_nodes(tsp_data.locations) 111 | tsp = Tabu(disMatrix=dismatrix ,max_iters=20,maxTabuSize=10) 112 | # two different way to generate initial solution 113 | # num : the number of points 114 | s_init = tsp.generate_initial_solution(num=customerNum,mode='greedy') # mode = "greedy" or "random" 115 | print('init route : ' , s_init) 116 | print('init distance : ' , tsp.get_route_distance(s_init)) 117 | 118 | start = time.time() 119 | best_route , routes = tsp.tabu_search(s_init) # tabu search 120 | end = time.time() 121 | 122 | print('best route : ' , best_route) 123 | print('best best_distance : ' , tsp.get_route_distance(best_route)) 124 | print('the time cost : ',end - start ) 125 | 126 | # plot the result changes with iterations 127 | results=[] 128 | for i in routes: 129 | results.append(tsp.get_route_distance(i)) 130 | plt.plot(np.arange(len(results)) , results) 131 | plt.show() 132 | # plot the route 133 | data.plot_route(tsp_data.locations,[0]+best_route+[0]) 134 | -------------------------------------------------------------------------------- /Tools/README.md: -------------------------------------------------------------------------------- 1 | # scripts 2 | 3 | This repository is some scripts implemented by pyhton 4 | 5 | - socket 6 | - ... 7 | 8 | 9 | 10 | Continuously updating.... 11 | 12 | -------------------------------------------------------------------------------- /Tools/socket/README.md: -------------------------------------------------------------------------------- 1 | # socket 2 | 3 | This is an example for sending a file by using socket with python 4 | 5 | # Install 6 | pip install socket 7 | 8 | # Usage 9 | server : port = 8888 (by default) 10 | 11 | client : port = 6666 (by default) 12 | 13 | target_IP = '219.223.175.200' 14 | target_PORT = 8888 15 | filepath = 'F:\\Swim_Proj\\Photo_0611_1a.MOV' 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Tools/socket/client.py: -------------------------------------------------------------------------------- 1 | import socket,time,os 2 | 3 | class Client(): 4 | def __init__(self) -> None: 5 | self.hostname = socket.gethostname() 6 | self.ip = socket.gethostbyname(self.hostname) 7 | print('hostname:', self.hostname) 8 | print('ip:', self.ip) 9 | 10 | def connect(self,target_ip,target_port,host_PORT=None): 11 | self.target_ip = target_ip 12 | self.target_port = target_port 13 | self.client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 14 | server_addr = (target_ip , target_port) # ip port 15 | if host_PORT: #默认随机端口号 16 | self.client.bind((self.ip, host_PORT)) 17 | try: 18 | self.client.connect(server_addr) 19 | print('successful, connected the target IP, wait for next order...') 20 | 21 | except: 22 | print('error, fail to connect the target IP,',socket.error) 23 | 24 | def file_read(self,file_path): #读取文件的方法 25 | mes = b'' 26 | try: 27 | file = open(file_path,'rb') 28 | mes = file.read() 29 | except: 30 | print('error{}'.format(file_path)) 31 | else: 32 | file.close() 33 | return mes 34 | 35 | def send_file(self,filepath): 36 | st = time.time() 37 | dirname, filename = os.path.split(filepath) 38 | data = self.file_read(filepath) 39 | self.client.send('{}|{}'.format(len(data), filename).encode()) #默认编码 utf-8,发送文件长度和文件名 40 | reply = self.client.recv(1024) 41 | if 'ok' == reply.decode(): #确认一下服务器get到文件长度和文件名数据 42 | go = 0 43 | total = len(data) 44 | while go < total: #发送文件 45 | data_to_send = data[go:go + 102400000] # 10M/s 46 | self.client.send(data_to_send) 47 | go += len(data_to_send) 48 | reply = self.client.recv(1024) 49 | if 'done' == reply.decode(): 50 | print('{} send successfully'.format(filepath)) 51 | self.client.close() 52 | et = time.time() 53 | print('time cost:',et-st) 54 | 55 | 56 | target_IP = '219.223.175.200' 57 | target_PORT = 8888 58 | filepath = 'F:\\Swim_Proj\\Photo_0611_1a.MOV' 59 | 60 | client = Client() 61 | client.connect(target_IP,target_PORT,host_PORT=6666) # host_PORT 可以为空,随机端口 62 | client.send_file(filepath) 63 | 64 | 65 | -------------------------------------------------------------------------------- /Tools/socket/server.py: -------------------------------------------------------------------------------- 1 | import socket,time,os,sys 2 | 3 | 4 | class Server(): 5 | def __init__(self) -> None: 6 | self.hostname = socket.gethostname() 7 | self.ip = socket.gethostbyname(self.hostname) 8 | print('hostname:', self.hostname) 9 | print('ip:', self.ip) 10 | 11 | def build_server(self,port=8888): 12 | try: 13 | self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 | self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | self.server.bind(('', port)) # 绑定端口 16 | self.server.listen(16) # 设置监听数 17 | print('successful building a server,PORT:',port) 18 | print('Waiting connection...') 19 | except socket.error as msg: 20 | print (msg) 21 | sys.exit(1) 22 | print('failt to build a server, try again...') 23 | 24 | def get_file(self): 25 | 26 | while True: 27 | new_client,client_addr = self.server.accept() 28 | print('a new client coming!!! new client :',client_addr) 29 | st = time.time() 30 | info = new_client.recv(1024) #首先接收一段数据,这段数据包含文件的长度和文件的名字,使用|分隔,具体规则可以在客户端自己指定 31 | length,file_name = info.decode().split('|') 32 | print('length {},filename {}'.format(length,file_name)) 33 | if length and file_name: 34 | newfile = open(file_name,'wb') #这里可以使用从客户端解析出来的文件名 35 | new_client.send(b'ok') #表示收到文件长度和文件名 36 | file = b'' 37 | total = int(length) 38 | get = 0 39 | while get < total: #接收文件 40 | data = new_client.recv(102400000) 41 | file += data 42 | get = get + len(data) 43 | et = time.time() 44 | print('time cost:',et-st) 45 | print('应该接收{},实际接收{}'.format(length,len(file))) 46 | if file: 47 | print('acturally length:{}'.format(len(file))) 48 | newfile.write(file[:]) 49 | newfile.close() 50 | new_client.send(b'done') #告诉完整的收到文件了 51 | new_client.close() 52 | 53 | 54 | PORT = 8888 55 | 56 | server = Server() 57 | server.build_server(PORT) 58 | server.get_file() 59 | 60 | --------------------------------------------------------------------------------