def update_input(self): logger.info(f"Start to update the input of {datetime.datetime.fromtimestamp(self.cur_time)}") # 获取车辆的位置信息和订单状态 # Get the updated status of vehicles and orders according to the simulator self.vehicle_simulator.run(self.id_to_vehicle, self.pre_time) self.vehicle_simulator.parse_simulation_result(self.id_to_vehicle, self.cur_time) # 增加历史记录, add history self.history.add_history_of_vehicles(self.id_to_vehicle, self.cur_time) self.history.add_history_of_order_items(self.id_to_vehicle, self.cur_time) # 更新订单状态 self.update_status_of_orders(self.vehicle_simulator.completed_item_ids, self.vehicle_simulator.ongoing_item_ids) # 更新车辆状态 self.update_status_of_vehicles(self.vehicle_simulator.vehicle_id_to_cur_position_info, self.vehicle_simulator.vehicle_id_to_destination, self.vehicle_simulator.vehicle_id_to_carrying_items) # 根据当前时间选择待分配订单的物料集合 # Select the item collection of the orders to be allocated according to the current time self.id_to_generated_order_item = get_order_items_to_be_dispatched_of_cur_time(self.id_to_order_item, self.cur_time) # 汇总车辆、订单和路网信息, 作为派单算法的输入 # create the input of algorithm updated_input_info = InputInfo(self.id_to_generated_order_item, self.id_to_ongoing_order_item, self.id_to_vehicle, self.id_to_factory, self.route_map) logger.info(f"Get {len(self.id_to_generated_order_item)} unallocated order items, " f"{len(self.id_to_ongoing_order_item)} ongoing order items, " f"{len(self.id_to_completed_order_item)} completed order items") return updated_input_info
def __initial_position_of_vehicles(id_to_factory: dict, id_to_vehicle: dict, ini_time: int): factory_id_list = [*id_to_factory] random.seed(Configs.RANDOM_SEED) for vehicle_id, vehicle in id_to_vehicle.items(): index = random.randint(0, len(factory_id_list) - 1) factory_id = factory_id_list[index] vehicle.set_cur_position_info(factory_id, ini_time, ini_time, ini_time) logger.info(f"Initial position of {vehicle_id} is {factory_id}")
def __contain_duplicate_nodes(route): node_id_list = [] for node in route: if node.id not in node_id_list: node_id_list.append(node.id) else: logger.info(f"Duplicate node {node.id}") return True return False
def complete_the_dispatch_of_all_orders(self): for item in self.id_to_order_item.values(): if item.delivery_state <= 1: logger.info(f"{datetime.datetime.fromtimestamp(self.cur_time)}, Item {item.id}: " f"state = {item.delivery_state} < 2, we can not finish the simulation") return False logger.info(f"{datetime.datetime.fromtimestamp(self.cur_time)}, the status of all items is greater than 1, " f"we could finish the simulation") return True
def __initialize(factory_info_file_name: str, route_info_file_name: str, instance_folder: str): """ 模拟器初始化, Initialize the simulator :param factory_info_file_name: 工厂数据文件名, name of the file containing information of factories :param route_info_file_name: 地图数据文件名, name of the file containing information of route map :param instance_folder: 测试例对应的文件夹, folder name of the instance :return: SimulateEnvironment """ route_info_file_path = os.path.join(Configs.benchmark_folder_path, route_info_file_name) factory_info_file_path = os.path.join(Configs.benchmark_folder_path, factory_info_file_name) instance_folder_path = os.path.join(Configs.benchmark_folder_path, instance_folder) # 车辆数据文件名, name of the file containing information of vehicles vehicle_info_file_path = "" # 订单数据文件名, name of the file containing information of orders data_file_path = "" for file_name in os.listdir(instance_folder_path): if file_name.startswith("vehicle"): vehicle_info_file_path = os.path.join(instance_folder_path, file_name) else: data_file_path = os.path.join(instance_folder_path, file_name) # 初始化时间, initial the start time of simulator now = datetime.datetime.now() initial_datetime = datetime.datetime(now.year, now.month, now.day) initial_time = int(time.mktime(initial_datetime.timetuple())) time_interval = Configs.ALG_RUN_FREQUENCY * 60 logger.info( f"Start time of the simulator: {initial_datetime}, time interval: {time_interval: .2f}" ) try: # 获取初始化数据, get the input id_to_order, id_to_vehicle, route_map, id_to_factory = get_initial_data( data_file_path, vehicle_info_file_path, route_info_file_path, factory_info_file_path, initial_time) # 初始化车辆位置, set the initial position of vehicles __initial_position_of_vehicles(id_to_factory, id_to_vehicle, initial_time) # return the instance of the object SimulateEnvironment return SimulateEnvironment(initial_time, time_interval, id_to_order, id_to_vehicle, id_to_factory, route_map) except Exception as exception: logger.error("Failed to read initial data") logger.error(f"Error: {exception}, {traceback.format_exc()}") return None
def get_initial_data(data_file_path: str, vehicle_info_file_path: str, route_info_file_path: str, factory_info_file_path: str, initial_time: int): """ 获取模拟器的输入数据, get the input of simulator :param data_file_path: 订单数据文件路径, path of the file containing information of orders :param vehicle_info_file_path: 车辆数据文件路径, path of the file containing information of vehicles :param route_info_file_path: 地图数据文件路径, path of the file containing information of route map :param factory_info_file_path: 工厂数据文件路径, path of the file containing information of factories :param initial_time: unix timestamp :return: id_to_order: dict, id_to_vehicle: dict, route_map, id_to_factory: dict """ # 获取工厂信息, get the factories id_to_factory = get_factory_info(factory_info_file_path) logger.info(f"Get {len(id_to_factory)} factories") # 获取地图信息, get the route map containing distance and time matrix between factories code_to_route = get_route_map(route_info_file_path) logger.info(f"Get {len(code_to_route)} routes") route_map = Map(code_to_route) # 车辆基本信息, get the vehicles id_to_vehicle = get_vehicle_info(vehicle_info_file_path) logger.info(f"Get {len(id_to_vehicle)} vehicles") # 获取订单信息, get the orders id_to_order = get_order_info(data_file_path, initial_time) logger.info(f"Get {len(id_to_order)} orders") return id_to_order, id_to_vehicle, route_map, id_to_factory
def calculate_total_distance(vehicle_id_to_node_list: dict, route_map): total_distance = 0 if not vehicle_id_to_node_list: return total_distance for vehicle_id, nodes in vehicle_id_to_node_list.items(): travel_factory_list = [] for node in nodes: travel_factory_list.append(node['factory_id']) distance = calculate_traveling_distance_of_routes( travel_factory_list, route_map) total_distance += distance logger.info( f"Traveling Distance of Vehicle {vehicle_id} is {distance: .3f}, " f"visited node list: {len(travel_factory_list)}") return total_distance
def run(self): used_seconds = 0 # 迭代 while True: logger.info(f"{'*' * 50}") # 确定当前时间, 取算法执行时间和模拟器的切片时间的大值 self.cur_time = self.pre_time + ( used_seconds // self.time_interval + 1) * self.time_interval logger.info( f"cur time: {datetime.datetime.fromtimestamp(self.cur_time)}, " f"pre time: {datetime.datetime.fromtimestamp(self.pre_time)}") # update the status of vehicles and orders in a given interval [self.pre_time, self.cur_time] updated_input_info = self.update_input() # 派单环节, 设计与算法交互 used_seconds, dispatch_result = self.dispatch(updated_input_info) self.time_to_dispatch_result[self.cur_time] = dispatch_result # 校验, 车辆目的地不能改变 if not Checker.check_dispatch_result( dispatch_result, self.id_to_vehicle, self.id_to_order): logger.error("Dispatch result is infeasible") return # 根据派单指令更新车辆 self.deliver_control_command_to_vehicles(dispatch_result) # 判断是否完成所有订单的派发 if self.complete_the_dispatch_of_all_orders(): break self.pre_time = self.cur_time # 若订单已经超时, 但是算法依旧未分配, 模拟终止 if self.ignore_allocating_timeout_orders(dispatch_result): logger.error('Simulator terminated') sys.exit(-1) # 模拟完成车辆剩下的订单 self.simulate_the_left_ongoing_orders_of_vehicles(self.id_to_vehicle) # 根据self.history 计算指标 self.total_score = Evaluator.calculate_total_score( self.history, self.route_map, len(self.id_to_vehicle))
def calculate_total_score(history, route_map, vehicle_num: int): total_distance = Evaluator.calculate_total_distance( history.get_vehicle_position_history(), route_map) logger.info(f"Total distance: {total_distance: .3f}") total_over_time = Evaluator.calculate_total_over_time( history.get_order_item_status_history()) logger.info(f"Sum over time: {total_over_time: .3f}") total_score = total_distance / vehicle_num + total_over_time * Configs.LAMDA logger.info(f"Total score: {total_score: .3f}") return total_score
# if you want to traverse all instances, set the selected_instances to [] selected_instances = Configs.selected_instances if selected_instances: test_instances = selected_instances else: test_instances = Configs.all_test_instances score_list = [] for idx in test_instances: # Initial the log log_file_name = f"dpdp_{datetime.datetime.now().strftime('%y%m%d%H%M%S')}.log" ini_logger(log_file_name) instance = "instance_%d" % idx logger.info(f"Start to run {instance}") try: score = simulate(Configs.factory_info_file, Configs.route_info_file, instance) score_list.append(score) except Exception as e: logger.error("Failed to run simulator") logger.error(f"Error: {e}, {traceback.format_exc()}") # 删除日志句柄 remove_file_handler_of_logging(log_file_name) avg_score = np.mean(score_list) # with report(True) as logs: # logs.log_metrics('score', [avg_score])
# if you want to traverse all instances, set the selected_instances to [] selected_instances = Configs.selected_instances if selected_instances: test_instances = selected_instances else: test_instances = Configs.all_test_instances score_list = [] for idx in test_instances: # Initial the log log_file_name = f"dpdp_{datetime.datetime.now().strftime('%y%m%d%H%M%S')}.log" ini_logger(log_file_name) instance = "instance_%d" % idx logger.info(f"Start to run {instance}") try: score = simulate(Configs.factory_info_file, Configs.route_info_file, instance) score_list.append(score) logger.info(f"Score of {instance}: {score}") except Exception as e: logger.error("Failed to run simulator") logger.error(f"Error: {e}, {traceback.format_exc()}") score_list.append(sys.maxsize) # 删除日志句柄 remove_file_handler_of_logging(log_file_name) avg_score = np.mean(score_list) # with report(True) as logs: