} // end of function CreateT_S_S_Network_db void initVirStartNode(ref List <T_S_S_Node> stateNodeList, ref Queue <T_S_S_Node> queue_T_S_S_Node) { foreach (T_S_Node base_start_point in base_start_pointList) { T_S_S_Node t_s_s_node = new T_S_S_Node(); // 将起点放在编号前列,便于连续编号 // 这段丑陋,先这样 //foreach (CrewBase crewbase in CrewBaseList) { // if (base_start_point.StaCode == crewbase.StaCode) { // t_s_s_node.ID = crewbase.OIDinTSS; // break; // } //} t_s_s_node.ID = BaseStationToODIDDict[base_start_point.StaCode][0]; t_s_s_node.Init_db(t_s_s_node.ID, -1, -1, 0, base_start_point.TrainCode, base_start_point.StaCode, base_start_point.TimeCode, 0, base_start_point.StaCode, base_start_point.ID, -1, null, base_start_point, null); t_s_s_node.Resources = new Resource(LineList.Count); t_s_s_node.Price = 0; stateNodeList.Add(t_s_s_node); queue_T_S_S_Node.Enqueue(t_s_s_node); } }
bool FeasibleDayCrewTime(T_S_S_Node curStateNode, T_S_Arc arc, ref Resource extendResource) { if (arc.ArcType == 31 || arc.ArcType == 33) { return(true); } int dayCrewTime_accumu = curStateNode.Resources.DayCrewTime_accumu; if (arc.ArcType != 32) { dayCrewTime_accumu += arc.Len; } if (dayCrewTime_accumu > BasicTimeRules.MaxDayCrewTime) { // 任何时候,dayCrewTime都不允许超过最大值 return(false); } else if (arc.ArcType == 32 && (dayCrewTime_accumu < BasicTimeRules.MinDayCrewTime || dayCrewTime_accumu > BasicTimeRules.MaxDayCrewTime)) { // 如果退乘时,dayCrewTime not in dayCrewTimeWindow [min, max],不可行 return(false); } extendResource.SetDayCrewTime(dayCrewTime_accumu); return(true); }
public void Init_db(int id, int prevID, int lineID, int routingID, string trainCode, string station, int timeCode, int pointType, string OStation, int superID, int prevSuperID, T_S_S_Node prevNode, T_S_Node superPoint, T_S_Node prevSuperPoint) { this.iD = id; this.prevID = prevID; this.lineID = lineID; this.rountingID = routingID; this.trainCode = trainCode; this.staCode = station; this.timeCode = timeCode; this.pointType = pointType; this.OStation = OStation; this.superPointID = superID; this.prevSuperID = prevSuperID; this.PrevNode = prevNode; this.SuperPoint = superPoint; this.PrevSuperPoint = prevSuperPoint; }
public static string stateNodePartialPathToStr(T_S_S_Node curStateNode, OutputMode mode) { StringBuilder strBuilder = new StringBuilder(); if (mode == OutputMode.console) { strBuilder.AppendLine("----curStateNode's partial path info[Line]:"); } if (curStateNode.PassLine.Count == 0) { strBuilder.Append("[Empty],"); } else { strBuilder.Append("["); for (int i = 0; i < curStateNode.PassLine.Count - 1; i++) { strBuilder.AppendFormat("{0}-", curStateNode.PassLine[i]); } strBuilder.AppendFormat("{0}],", curStateNode.PassLine.Last()); } if (mode == OutputMode.console) { strBuilder.AppendLine("----curStateNode's partial path info[stateNode]:"); } Stack <int> nodePahStack = new Stack <int>(); var preNode = curStateNode; while (preNode != null) { nodePahStack.Push(preNode.ID); preNode = preNode.PrevNode; if (nodePahStack.Count > 10000) { return(strBuilder.ToString()); throw new StackOverflowException("stateNodePartialPathToStr()死循环"); } } if (nodePahStack.Count == 0) { strBuilder.AppendLine("[Empty]"); } else { strBuilder.Append("["); while (nodePahStack.Count > 1) { strBuilder.AppendFormat("{0}-", nodePahStack.Pop()); } strBuilder.AppendFormat("{0}]", nodePahStack.Pop()); } return(strBuilder.ToString()); }
// 处理用餐约束 void handleMealConstraint(T_S_S_Node curStateNode, T_S_Arc arc, ref T_S_S_Node extendStateNode) { if (withinMealWindow(arc, STLunch, ETLunch, minMealTime)) { if (/*curStateNode.Resources.LunchStatus < 2 &&*/ getRealMealSlot(arc, STLunch, ETLunch) < minMealTime) { // 还未用过午餐,且当前弧应该用餐但无法用餐 // 则施加惩罚 extendStateNode.PenaltyMealViolate = arcPenaltyMealViolate; extendStateNode.Resources.SetLunchStatus(curStateNode.Resources.LunchStatus); } else { extendStateNode.Resources.SetLunchStatus(2); } } else if (withinMealWindow(arc, STDinner, ETDinner, minMealTime)) { if (/*curStateNode.Resources.DinnerStatus < 2 &&*/ getRealMealSlot(arc, STDinner, ETDinner) < minMealTime) { // 还未用过晚餐,且当前弧应该用餐但无法用餐 // 则施加惩罚 extendStateNode.PenaltyMealViolate = arcPenaltyMealViolate; extendStateNode.Resources.SetDinnerStatus(curStateNode.Resources.DinnerStatus); } else { extendStateNode.Resources.SetDinnerStatus(2); } } else { extendStateNode.Resources.SetLunchStatus(curStateNode.Resources.LunchStatus); extendStateNode.Resources.SetDinnerStatus(curStateNode.Resources.DinnerStatus); } }
public static string stateNodeInfoToStr(T_S_S_Node curStateNode, OutputMode mode) { StringBuilder strBuilder = new StringBuilder(); if (mode == OutputMode.console) { strBuilder.AppendLine("----curStateNode's basic info"); strBuilder.AppendFormat("ID[{0}],NodeType[{1}],OStation[{2}],LineID[{3}],Train[{4}]," + "Station[{5}],Time[{6}],SuperPointID[{7}],SuperPointType[{8}],PrevNodeID[{9}]\n", curStateNode.ID, curStateNode.PointType, curStateNode.OStation, curStateNode.LineID, curStateNode.TrainCode, curStateNode.StaCode, curStateNode.TimeCode, curStateNode.SuperPointID, curStateNode.SuperPoint.PointType, curStateNode.PrevID); strBuilder.AppendLine("----curStateNode's state info"); var resource = curStateNode.Resources; strBuilder.AppendFormat("DriveTime[{0}],DayCrewTime[{1}],Lunch[{2}],Dinner[{3}]\n", resource.DriveTime_accumu, resource.DayCrewTime_accumu, resource.LunchStatus, resource.DinnerStatus); } else if (mode == OutputMode.file) { strBuilder.AppendFormat("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},", curStateNode.ID, curStateNode.PointType, curStateNode.OStation, curStateNode.LineID, curStateNode.TrainCode, curStateNode.StaCode, curStateNode.TimeCode, curStateNode.SuperPointID, curStateNode.SuperPoint.PointType, curStateNode.PrevID); var resource = curStateNode.Resources; strBuilder.AppendFormat("{0},{1},{2},{3}", resource.DriveTime_accumu, resource.DayCrewTime_accumu, resource.LunchStatus, resource.DinnerStatus); } return(strBuilder.ToString()); }
// end 更新时间属性值 void keepAllFeasibleStateNode(List <T_S_S_Node> allStateNodes) { T_S_S_NodeList = new List <T_S_S_Node>(allStateNodes); bool existIsolatedNode = false; do { existIsolatedNode = false; for (int i = T_S_S_NodeList.Count - 1; i >= 0; i--) { T_S_S_Node node = T_S_S_NodeList[i]; if ((node.PointType == 32 || node.PointType == 33)) { continue; } else if (node.Out_T_S_S_NodeList.Count == 0) { //Console.WriteLine(Logger.stateNodeInfoToStr(node, OutputMode.console)); node.PrevNode.Out_T_S_S_NodeList.Remove(node); T_S_S_NodeList.RemoveAt(i); existIsolatedNode = true; continue; } } } while (existIsolatedNode); // 重新编号 // 按时间排序 List <int> temp_debug = new List <int>() { 2030, 2155, 2278, 2415, 2479, 2657, 2736, 2916 }; T_S_S_NodeList.Sort(T_S_S_Node_AscByTime.nodeAsc); int virODNum = CrewBaseList.Count * 2; int newIDCount = virODNum; foreach (var node in T_S_S_NodeList) { if (node.ID >= virODNum) { node.ID = newIDCount; ++newIDCount; //debug //if (temp_debug.Contains(node.ID)) { // Console.WriteLine("cur node Price:" + node.Price); // Console.WriteLine("cur node PenaltyMealViolate:" + node.PenaltyMealViolate); //} } } foreach (var node in T_S_S_NodeList) { if (node.PrevID >= 0) { node.PrevID = node.PrevNode.ID; } } }
/// <summary> /// arc为运行弧时使用 /// 判断是否当前状态点(表示的部分路径)已经访问过该Line /// 避免同一Line被一条路径多次访问 /// </summary> /// <param name="curStateNode"></param> /// <param name="arc"></param> /// <returns></returns> bool visitedCurLine(T_S_S_Node curStateNode, T_S_Arc arc) { return(curStateNode.Resources.LinesVisitedArray[arc.LineID - 1] > 0); }
// end 处理用餐约束 // 更新时间属性值,不涉及用餐约束 bool FeasibleDriveTime(T_S_S_Node curStateNode, T_S_Arc arc, ref Resource extendResource) { if (arc.ArcType == 1) { //运行弧 if (!visitedCurLine(curStateNode, arc)) { int driveTime_accumu = curStateNode.Resources.DriveTime_accumu + arc.Len; if (driveTime_accumu <= BasicTimeRules.MaxDriveTime /*&& dayCrewTime_accumu <= BasicTimeRules.MaxDayCrewTime*/) { // NOTE:只检查驾驶时间,不检查dayCrewTime // 若执行该arc代表的Line后,驾驶时间 <= max,则可行 extendResource.SetDriveTime(driveTime_accumu); } else // 若驾驶时间大于最大允许值,则不可extend,cut掉 { return(false); } } } else if (arc.ArcType == 21) { //日间连接弧 int driveTime_accumu = curStateNode.Resources.DriveTime_accumu; if (BasicTimeRules.MinDriveTime <= driveTime_accumu && driveTime_accumu < BasicTimeRules.MaxDriveTime) { // 1.若驾驶时间 in [min. max),则可行,但要判断是否可以间休 // NOTE:这里将最小间休时间等于最小接续时间 // 那么下面这个判断始终是true,即只要是接续弧,就视为间休,驾驶时间清零 if (arc.Len >= BasicTimeRules.MinConnTime) { // 若弧长 >= 最小间休时长,视为在此间休 extendResource.SetDriveTime(0); } } else if (driveTime_accumu < BasicTimeRules.MinDriveTime) { // 2.若驾驶时间 < 最小驾驶时间,则不间休,视为接续 extendResource.SetDriveTime(driveTime_accumu + arc.Len); } else if (driveTime_accumu == BasicTimeRules.MaxDriveTime) { // 3.若驾驶时间 == 必须间休 if (arc.Len < BasicTimeRules.MinConnTime) { // 若弧长小于最小间休时长,则不可行 return(false); } // 否则,间休 extendResource.SetDriveTime(0); } } else if (arc.ArcType == 31 || arc.ArcType == 32 || arc.ArcType == 33) { //虚拟出乘弧, //虚拟退乘弧, //虚拟停驻弧 if (arc.ArcType != 32) //虚拟出乘,虚拟停驻,当前的状态点的驾驶时间都是0 { Debug.Assert(curStateNode.Resources.DriveTime_accumu == 0); Debug.Assert(curStateNode.Resources.DayCrewTime_accumu == 0); } extendResource.SetDriveTime(curStateNode.Resources.DriveTime_accumu); } else { Debug.Print("检查驾驶时间约束,出现未定义的T_S_Arc.ArcType:{0}\n", arc.ArcType); } return(true); }
public void CreateT_S_S_Network_db(/*CrewRule crewRule*/) { Debug.Assert(BasicTimeRules.MinConnTime != -1); List <T_S_S_Node> allStateNodes = new List <T_S_S_Node>(); Queue <T_S_S_Node> queue = new Queue <T_S_S_Node>(); initVirStartNode(ref allStateNodes, ref queue); //List<T_S_S_Node> tempDNodeList = new List<T_S_S_Node>(); //Dictionary<int, T_S_S_Node> IDToNodeDict = new Dictionary<int, T_S_S_Node>(); //foreach (var startNode in allStateNodes) { // IDToNodeDict.Add(startNode.ID, startNode); //} int debug_count = 100000; int debug_iter = 0; int nodeCount = CrewBaseList.Count * 2; //其余时空状态点的编号从乘务基地虚拟起终点之后开始 T_S_S_Node top_node; while (queue.Count > 0) { //if (--debug_count < 0) { // debug_count = 100000; // debug_iter++; // Console.WriteLine("current Queue.Count is [{0}]", queue.Count); // Console.WriteLine("debug iter is [{0}]", debug_iter); //} top_node = queue.Dequeue(); //Console.WriteLine(Logger.stateNodeInfoToStr(top_node, OutputMode.console)); //if (debug_iter >= 10) { // if (debug_count < 3000) { // Console.WriteLine("cur debug count is [{0}]", debug_count); // } //} T_S_Node cur_super_point = top_node.SuperPoint; List <T_S_Arc> out_T_S_ArcList = cur_super_point.Out_T_S_ArcList; for (int i = 0; i < out_T_S_ArcList.Count; i++) { T_S_Arc cur_t_s_arc = out_T_S_ArcList[i]; // debug //if (top_node.PassLine.Contains(30) // && top_node.PassLine.Contains(143) // //&& top_node.PassLine.Contains(64) // //&& top_node.PassLine.Contains(157) // && cur_t_s_arc.EndTimeCode == 1029 // && cur_t_s_arc.ArcType == 21) { // Console.WriteLine("top_node.PenaltyMealViolate:" + top_node.PenaltyMealViolate); //} //end debug T_S_S_Node extendStateNode = new T_S_S_Node(); extendStateNode.Resources = new Resource(lineList.Count); if (!FeasibleDriveTime(top_node, cur_t_s_arc, ref extendStateNode.Resources)) { continue; } if (!FeasibleDayCrewTime(top_node, cur_t_s_arc, ref extendStateNode.Resources)) { continue; } // 交路退乘点必须与出乘点相同 (必须回基地的约束) if (cur_t_s_arc.ArcType == 32 && cur_t_s_arc.EndStaCode != top_node.OStation) { continue; } // 用餐软约束 // 必须是非运行弧,才可能可以用餐 if (cur_t_s_arc.ArcType != 1) { handleMealConstraint(top_node, cur_t_s_arc, ref extendStateNode); // NOTE:可以处理一下,若当前弧用餐成功,则标记为用餐弧 } else { extendStateNode.Resources.SetLunchStatus(top_node.Resources.LunchStatus); extendStateNode.Resources.SetDinnerStatus(top_node.Resources.DinnerStatus); } // extendStartNode基本属性赋值 extendStateNode.Init_db(nodeCount, top_node.ID, cur_t_s_arc.LineID, cur_t_s_arc.RountingID, cur_t_s_arc.TrainCode, cur_t_s_arc.EndStaCode, cur_t_s_arc.EndTimeCode, cur_t_s_arc.ArcType, top_node.OStation, cur_t_s_arc.EndPointID, cur_super_point.ID, top_node, cur_t_s_arc.EndPoint, cur_super_point); // 还有其他属性 // 1 途径运行线 extendStateNode.PassLine.AddRange(top_node.PassLine); if (cur_t_s_arc.ArcType == 1) { extendStateNode.PassLine.Add(cur_t_s_arc.LineID); extendStateNode.Resources.LinesVisitedArray[cur_t_s_arc.LineID - 1] += 1; } // 2 起终点的编号 if (cur_t_s_arc.ArcType == 31) { extendStateNode.Price = 1440; Debug.Assert(extendStateNode.PenaltyMealViolate == 0); } else if (cur_t_s_arc.ArcType == 32) { extendStateNode.ID = BaseStationToODIDDict[extendStateNode.StaCode][1]; extendStateNode.Price = 0; --nodeCount; // 终点有自己的编号,所以此次不用增加nodeCount; Debug.Assert(extendStateNode.PenaltyMealViolate == 0); } else if (cur_t_s_arc.ArcType == 33) { extendStateNode.ID = BaseStationToODIDDict[extendStateNode.StaCode][1]; extendStateNode.Price = virtualRoutingCost; --nodeCount; // 终点有自己的编号,所以此次不用增加nodeCount; Debug.Assert(extendStateNode.PenaltyMealViolate == 0); } else { extendStateNode.Price = cur_t_s_arc.Len;// + extendStateNode.PenaltyMealViolate; //后续对弧再赋值Penalty } // 比较标号优劣 //for (int stateIdx = cur_t_s_arc.EndPoint.StateNodeSet.Count; stateIdx >= 0; stateIdx--) { //} top_node.Out_T_S_S_NodeList.Add(extendStateNode); allStateNodes.Add(extendStateNode); queue.Enqueue(extendStateNode); ++nodeCount; //if (cur_t_s_arc.ArcType != 32 && cur_t_s_arc.ArcType != 33) { // IDToNodeDict.Add(extendStateNode.ID, extendStateNode); //} //else { // tempDNodeList.Add(extendStateNode); //} } // end of loop "out_T_S_ArcList" } // end of loop "while" // 找出所有可行的状态点(即可以到达虚拟终点的状态点) #region //基于回溯 //T_S_S_NodeList = new List<T_S_S_Node>(); //foreach (T_S_S_Node note in tempDNodeList) { // int d = note.PrevID; // do { // if (IDToNodeDict.ContainsKey(d)) { // IDToNodeDict[d].Isfeasible = 1; // T_S_S_NodeList.Add(IDToNodeDict[d]); // d = IDToNodeDict[d].PrevID; // } // } // while (d != -1); //} //T_S_S_NodeList.AddRange(tempDNodeList); //T_S_S_NodeList.Sort(T_S_S_Node_AscByTime.nodeAsc); //int virODNum = CrewBaseList.Count * 2; //int newIDCount = virODNum; //foreach (var node in T_S_S_NodeList) { // if (node.ID >= virODNum) { // node.ID = newIDCount; // ++newIDCount; // } //} //foreach (var node in T_S_S_NodeList) { // if (node.PrevID >= 0) { // node.PrevID = node.PrevNode.ID; // } //} #endregion keepAllFeasibleStateNode(allStateNodes); // 根据可行状态点建立时空状态弧 createT_S_S_Arcs(); } // end of function CreateT_S_S_Network_db
// 创建时空状态弧 void createT_S_S_Arcs() { T_S_S_ArcList = new List <T_S_S_Arc>(); for (int i = 0; i < T_S_S_NodeList.Count; i++) { // NOTE:i应该从虚拟起点后开始 T_S_S_Node curNode = T_S_S_NodeList[i]; if (curNode.PointType == 0) { continue; } T_S_S_Node prevNode = curNode.PrevNode; T_S_S_Arc t_s_s_arc = new T_S_S_Arc(); t_s_s_arc.ID = T_S_S_ArcList.Count; t_s_s_arc.StartPointID = prevNode.ID; t_s_s_arc.EndPointID = curNode.ID; t_s_s_arc.StartNode = prevNode; t_s_s_arc.EndNode = curNode; if (curNode.PointType == 31) { Debug.Assert(prevNode.TimeCode == 0); } else if (curNode.PointType == 32) { Debug.Assert(curNode.TimeCode == 1440); } else if (curNode.PointType == 33) { Debug.Assert(prevNode.TimeCode == 0 && curNode.TimeCode == 1440); } t_s_s_arc.StartTimeCode = prevNode.TimeCode; t_s_s_arc.EndTimeCode = curNode.TimeCode; t_s_s_arc.NumSelected = 0; t_s_s_arc.LineID = curNode.LineID; t_s_s_arc.TrainCode = curNode.PointType == 1 ? curNode.TrainCode : ""; t_s_s_arc.ArcType = curNode.PointType; // Price t_s_s_arc.SetPenaltyMealViolate(curNode.PenaltyMealViolate); t_s_s_arc.SetArcPrice(curNode.Price, curNode.PenaltyMealViolate); t_s_s_arc.LagPrice = t_s_s_arc.Price; t_s_s_arc.HeurPrice = t_s_s_arc.Price; if (t_s_s_arc.ArcType == 1 || t_s_s_arc.ArcType == 33) { t_s_s_arc.LagMultiplier = 0; } else { t_s_s_arc.LagMultiplier = -1; } // meal status t_s_s_arc.EndCumuLunch = curNode.Resources.LunchStatus; t_s_s_arc.EndCumuDinner = curNode.Resources.DinnerStatus; T_S_S_ArcList.Add(t_s_s_arc); } }