static void Main(string [] args) { List <Order> orders = new List <Order>(); Node node = new Node(); //read order file bool decimalComma = float.Parse("12.5") == 125f; int maxMatrixID = 0; StreamReader orderFile = new StreamReader("Orderbestand.txt"); string line = orderFile.ReadLine(); while (line != null) { line = orderFile.ReadLine(); if (line != null) { string[] parameters = line.Split(';'); int orderID = int.Parse(parameters[0]); int frequence = int.Parse(parameters[2].Substring(0, 1)); int containerVolume = int.Parse(parameters[3]) * int.Parse(parameters[4]); string durationString = decimalComma ? parameters [5].Replace('.', ',') : parameters [5]; float duration = float.Parse(durationString); int matrixID = int.Parse(parameters[6]); if (matrixID > maxMatrixID) { maxMatrixID = matrixID; } if (frequence == 1) { orders.Add(new Order(orderID, frequence, containerVolume, duration, matrixID)); //add order to list } else { completeOrderList.Add(new Order(orderID, frequence, containerVolume, duration, matrixID)); } } } completeOrderList.AddRange(orders); distances = new int [maxMatrixID + 1, maxMatrixID + 1]; StreamReader distanceFile = new StreamReader("AfstandenMatrix.txt"); line = distanceFile.ReadLine(); while (line != null) { line = distanceFile.ReadLine(); if (line != null) { string [] parameters = line.Split(';'); int matrixID1 = int.Parse(parameters [0]); int matrixID2 = int.Parse(parameters [1]); int distance = int.Parse(parameters [3]); distances [matrixID1, matrixID2] = distance; } } int currentLocation = dumpID; List <Order> todayOrders = new List <Order>(); for (int day = 1; day <= 5; day++) { for (int truck = 1; truck <= 2; truck++) { float timeLeft = 12f * 60f; float currentCapacity = 20000; todayOrders.AddRange(orders); while (todayOrders.Count > 0) { for (int i = todayOrders.Count - 1; i >= 0; i--) { Order order = todayOrders [i]; if (timeLeft < GetDistance(currentLocation, order.matrixID) + order.duration + GetDistance(order.matrixID, dumpID) + dumpDuration) { todayOrders.RemoveAt(i); } } List <Order> currentOrders = new List <Order>(); SubLoop newSubLoop = new SubLoop(); currentOrders.AddRange(todayOrders); float heuristicSumTravel = 0, heuristicSumEmpty = 0, loopduration = 0, loopCapacity = 0; int loopPos = currentLocation; while (currentOrders.Count > 0) { float bestHeuristic = float.NegativeInfinity, bestHeuristicTravel = float.NegativeInfinity, bestHeuristicEmpty = float.NegativeInfinity; Order bestOrder = currentOrders [0]; for (int i = currentOrders.Count - 1; i >= 0; i--) { Order order = currentOrders [i]; float newHeuristicTravel, newHeuristicEmpty; bool enoughCapacity = currentCapacity >= loopCapacity + order.containerVolume * 0.2f; bool enoughTime = timeLeft >= loopduration + GetDistance(loopPos, order.matrixID) + order.duration + GetDistance(order.matrixID, dumpID) + dumpDuration; if (enoughCapacity && enoughTime) { newHeuristicTravel = GetDistance(loopPos, order.matrixID); newHeuristicEmpty = order.duration; float newHeuristic = 2f * newHeuristicEmpty - newHeuristicTravel; if (newHeuristic > bestHeuristic) { bestHeuristic = newHeuristic; bestHeuristicEmpty = newHeuristicEmpty; bestHeuristicTravel = newHeuristicTravel; bestOrder = order; } } else { currentOrders.Remove(order); } } if (currentOrders.Count > 0) { heuristicSumEmpty += bestHeuristicEmpty; heuristicSumTravel += bestHeuristicTravel; newSubLoop.orders.Add(bestOrder); loopduration += GetDistance(loopPos, bestOrder.matrixID); loopduration += bestOrder.duration; loopPos = bestOrder.matrixID; loopCapacity += bestOrder.containerVolume * 0.2f; currentOrders.Remove(bestOrder); } } heuristicSumTravel += GetDistance(loopPos, dumpID); heuristicSumEmpty += dumpDuration; //sort the new loop if (newSubLoop.orders.Count > 0) { Order dump = new Order(); newSubLoop.orders.Add(dump); Tuple <SubLoop, float> SM = SolveTravellingSM(newSubLoop); if (SM.Item2 < heuristicSumTravel) { heuristicSumTravel = SM.Item2; newSubLoop = SM.Item1; } int dumpIndex = newSubLoop.orders.IndexOf(dump); newSubLoop = OffsetSubLoop(newSubLoop, -(dumpIndex + 1)); } //Console.WriteLine("SUM: " + heuristicSum); if ((2f * heuristicSumEmpty - heuristicSumTravel) > 0 && newSubLoop.orders.Count > 0) { for (int i = 0; i < newSubLoop.orders.Count; i++) { Order order = newSubLoop.orders [i]; //collect garbage timeLeft -= GetDistance(currentLocation, order.matrixID); //move to order currentLocation = order.matrixID; timeLeft -= order.duration; //collect garbage currentCapacity -= order.containerVolume * 0.2f; //lose capacity todayOrders.Remove(order); orders.Remove(order); } node.loops [truck - 1, day - 1].subLoops.Add(newSubLoop); //empty timeLeft -= GetDistance(currentLocation, dumpID); //move to dump currentLocation = dumpID; //set location to dump timeLeft -= dumpDuration; //empty currentCapacity = 20000; //reset capacity //dayLoop.AddDump(); } else { todayOrders.Clear(); } } } } /*Node test = new Node(); * SubLoop testSubLoop = new SubLoop(); * testSubLoop.orders.Add(completeOrderList[5]); * testSubLoop.orders.Add(new Order()); * test.loops [0, 0].subLoops.Add(testSubLoop); * * SubLoop testSubLoop2 = new SubLoop(); * testSubLoop2.orders.Add(completeOrderList [5]); * testSubLoop2.orders.Add(new Order()); * test.loops [0, 3].subLoops.Add(testSubLoop2); * PrintResult(test); * Console.WriteLine(test.GetScore()); * Neighbour testNeighbour = new Neighbour(test, null, 1, 1, 0); * * Console.WriteLine(test.GetScore()); * * Console.WriteLine(testNeighbour.GetScore()); * Node testNode = testNeighbour.ToNode(); * Console.WriteLine(CalculateScore(testNode)); * * //PrintResult(testNode); * * /*SubLoop testNewSubLoop = new SubLoop(); * testNewSubLoop.orders.AddRange(testSubLoop.orders); * testNewSubLoop.orders.Insert(1, completeOrderList[65]); * testNewSubLoop.orders.Insert(1, new Order()); * Neighbour testNeighbour2 = new Neighbour(test, testNewSubLoop, 1, 1, 0); * Console.WriteLine(test.GetScore()); * Console.WriteLine(testNeighbour.GetScore()); * Console.WriteLine(testNeighbour2.GetScore()); * Dictionary<int, List<int>> pds = testNeighbour.CalculatePickupDays(); * Node node2 = testNeighbour2.ToNode(); * PrintResult(node2); * Console.WriteLine(node2.GetScore()); * Console.WriteLine(testNewSubLoop.GetTimeAndVolume());*/ node = new Node(); Tuple <float, float> bestScore = node.GetScore(); int a = 1; DateTime start = DateTime.Now; int totalNeighbourCount = 0; //settings float T = 5; int stepsPerT = 16 * 50; float Tfactor = 0.95f; float TTreshold = 0.05f; int stepsTillThreshold = (int)Math.Ceiling(Math.Log(TTreshold / T, Tfactor)); while (T > TTreshold) { for (int i = 0; i < stepsPerT; i++) { if (a % 10 == 0) { Console.WriteLine(a + " / " + stepsPerT * stepsTillThreshold + ": " + (bestScore.Item1 + bestScore.Item2)); Console.WriteLine("extrapolated time remaining: " + TimeSpan.FromSeconds((int)Math.Round((DateTime.Now.Subtract(start).TotalSeconds / (float)a) * (float)(stepsPerT * stepsTillThreshold - a)))); } a++; DateTime startTime = DateTime.Now; List <Neighbour> neighbours = GetNeighbours(node); totalNeighbourCount += neighbours.Count; //Console.WriteLine("neighbourDuration: " + (DateTime.Now.Subtract(startTime))); //Console.WriteLine("neighbours: " + neighbours.Count); bool accepted = false; Neighbour neighbour = null; Tuple <float, float> score = null; int x = 0; startTime = DateTime.Now; while (accepted == false) { neighbour = neighbours [random.Next(neighbours.Count)]; score = neighbour.GetScore(); float scoreSum = score.Item1 + score.Item2; if (scoreSum < bestScore.Item1 + bestScore.Item2) { accepted = true; } else { float delta = scoreSum - (bestScore.Item1 + bestScore.Item2); double p = Math.Exp(-delta / T); double r = random.NextDouble(); if (r < p) { accepted = true; } } x++; } //Console.WriteLine("acceptDuration: " + (DateTime.Now.Subtract(startTime)) + " in " +x+" tries"); node = neighbour.ToNode(); bestScore = score; } T *= Tfactor; } //remove unfeasable single pickups Dictionary <int, List <int> > pickupDays = node.GetPickupDays(); for (int i = 0; i < completeOrderList.Count; i++) { bool accept = false; List <int> days = pickupDays [completeOrderList [i].orderID]; switch (completeOrderList [i].frequence) { case 1: if (days.Count > 0) { accept = true; } break; case 2: if ((days.Contains(1) && days.Contains(4)) || (days.Contains(2) && days.Contains(5))) { accept = true; } break; case 3: if (days.Contains(1) && days.Contains(3) && days.Contains(5)) { accept = true; } break; case 4: if ((days.Contains(1) && days.Contains(2) && days.Contains(3) && days.Contains(4)) || (days.Contains(1) && days.Contains(2) && days.Contains(3) && days.Contains(5)) || (days.Contains(1) && days.Contains(2) && days.Contains(4) && days.Contains(5)) || (days.Contains(1) && days.Contains(3) && days.Contains(4) && days.Contains(5)) || (days.Contains(2) && days.Contains(3) && days.Contains(4) && days.Contains(5))) { accept = true; } break; } if (!accept) { for (int truck = 1; truck <= 2; truck++) { foreach (int day in days) { for (int x = 0; x < node.loops [truck - 1, day - 1].subLoops.Count; x++) { node.loops [truck - 1, day - 1].subLoops [x].orders.Remove(completeOrderList [i]); } } } } } bestScore = CalculateScore(node); PrintResult(node); Console.WriteLine("search duration: " + DateTime.Now.Subtract(start)); Console.WriteLine("average neighbour count: " + (totalNeighbourCount / a)); Console.WriteLine("Traveling time: " + bestScore.Item1); Console.WriteLine("Decline penalty: " + bestScore.Item2); Console.WriteLine("Total score: " + (bestScore.Item1 + bestScore.Item2)); Console.Read(); }