Esempio n. 1
0
        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();
        }