Ejemplo n.º 1
0
        public TwoOptSolution(Problem _problem, TwoOptSolution _bestSolution)   //konstruktor kopiujący
        {
            problem      = _problem;
            CitySequence = new int[problem.Cities.Length];
            Array.Copy(_bestSolution.CitySequence, CitySequence, CitySequence.Length);

            ReversePath();

            CalculateScore();
        }
Ejemplo n.º 2
0
        //główny algorytm annealingu. Wersja 4.
        public void Main4(Problem problem)
        {
            //Na początek czysczę trace log i wizualicję problemu.
            outputTB.Text = "";
            canvasTSP.Children.Clear();

            //zmienna do przetrzymywania traceloga. kwestie optymalizacji.
            string debugOutput = "";



            //Solution to klasa do initialSolution. Jest to całkowicie losowa ścieżka uzyta jako początkowa.
            Solution initialSolution = new Solution(problem);   //"Initial Solution s 0"
            //na początku best solution to initial solution. w tym momencie pojawia się pierwsze losowe przekształcenie, jest ono zawsze akceptowane.
            TwoOptSolution bestSolution = new TwoOptSolution(problem, initialSolution);
            TwoOptSolution newSolution;

            //"Initial Temperature" temperatura układu. Zwiększenie jej zwiększa ilość iteracji, ale też zwiększa szansę na to, że w Metropolis criterion
            //zostanie wybrane gorsze rozwiązanie.
            double temperature = 0.5;
            //Cooling rate.
            double coolingRate = 0.9;



            //EXPLORATION CRITERION I COOLING SCHEME, JAK DZIAŁA
            //Exploration criterion bazowane jest na https://www.fourmilab.ch/documents/travelling/anneal/
            //Annealing dziala na bazie cykli. W każdym cyklu wykonywany jest szereg przekształceń.  | zmienna globalIterations
            //Przekształcenia dzielę na 2 kategorie
            //- udane, czyli takie gdy koszt zmniejszył się, lub rozwiązanie zostało zaakceptowane na bazie Metropolis criterion    | zmienna changes
            //- nieudane, czyli takie które nie zostało zaakceptowane
            //Każdy cykl ma 2 maksymalne ilości przekształceń do wykonania
            //Maksymalna ilość udanych przekształceń w każdym cyklu to Nmiast * 10 | zmienna minSucc
            //Maksymalna ilość nieudanych + udanych przekształceń w każdym cyklu to Nmiast * 100 | zmienna over
            //Cykl kończy się, ilość udanych przekroczy minSucc lub ilosc udanych + nieudanych przekroczy over
            //Na końcu każdego cyklu zmniejszana jest temperatura | temperature *= coolingRate
            //Algorytm kończy się, gdy na końcu cyklu ilość udanych przekształceń będzie wynosić 0

            //Podstawową operacją przekształcania jest odwracanie części ścieżki, bazujące na algorytmie 2-opt https://en.wikipedia.org/wiki/2-opt
            //W każdym nowym rozwiązaniu losowane jest X elementów połączonych ze sobą po kolei, po czym są one odwracane kolejnością


            int iterations = 0;                        //ilosc nowych rozwiązań

            int over    = problem.Cities.Length * 100; //maksymalna ilość rozwiązań
            int minSucc = problem.Cities.Length * 10;  //maksymalna ilość udanych przekształceń

            int globalIterations = 0;                  //ilość cykli
            int changes          = 1;                  //ilość udanych przekształceń


            while (changes != 0)    //nowy cykl zaczyna się, gdy w poprzednim cyklu nastąpiły jakieś udane przekształcenia
            {
                iterations = 0;
                changes    = 0;
                while (iterations < over && minSucc > changes)               //właściwy annealing
                {
                    newSolution = new TwoOptSolution(problem, bestSolution); //generowane jest nowe rozwiązanie na bazie najlepszego.

                    iterations++;

                    //delta(s, s')
                    double delta = newSolution.Score - bestSolution.Score;

                    //Acceptance Criterion. W tym przypadku, Metropolis-based criteria.
                    //W niektórych przypadkach (nie wiem skąd to się bierze, prawdopodobnie błąd zaokrągleń) Metropolis może przyjąć dokładnie
                    //takie same rozwiązanie za lepsze. Stąd delta > 0.0000001
                    if (delta < 0 || (delta > 0.0000001 && Functions.Metropolis(problem.RNG, temperature, delta)))
                    {
                        bestSolution = newSolution; //nowe rozwiązanie staje się najlepszym rozwiązaniem
                        changes++;
                    }
                }

                //Na końcu każdego cyklu zapisuję informacje o zmianach do loga.

                if (debugCM.IsChecked == true)
                {
                    //debugOutput += "Path: ";
                    //foreach (int j in bestSolution.CitySequence)
                    //{
                    //    debugOutput += j + " ";
                    //}

                    debugOutput += "    Temperature: " + temperature + "    Score: " + bestSolution.Score + "    Iteration: " + globalIterations + "    Changes: " + changes + "\n";
                }

                //zmniejszenie temperatury
                temperature = temperature * coolingRate;
                globalIterations++;

                //restart temperatury uważam za zbędny.
            }

            //koniec annealingu

            outputTB.Text += debugOutput;//wypisuję debug na ekran

            //-----------------------------
            //rysowanie
            //-----------------------------

            //dla każdego miasta dodaję czerwoną kropkę na canvas
            Ellipse[] dots = new Ellipse[bestSolution.CitySequence.Length];

            for (int i = 0; i < bestSolution.CitySequence.Length; i++)
            {
                dots[i] = new Ellipse
                {
                    Stroke          = new SolidColorBrush(Colors.Red),
                    StrokeThickness = 3,
                    Height          = 10,
                    Width           = 10,
                    Fill            = new SolidColorBrush(Colors.Red),


                    Margin = new Thickness(bestSolution.Cities[bestSolution.CitySequence[i]].X * 900, canvasTSP.Height - bestSolution.Cities[bestSolution.CitySequence[i]].Y * 900, 0, 0)
                };

                canvasTSP.Children.Add(dots[i]);
            }

            //dla każdego połączenia między miastami dodaję linie na canvas
            Line[] lines = new Line[bestSolution.CitySequence.Length];

            for (int i = 0; i < bestSolution.CitySequence.Length - 1; i++)
            {
                Thickness margin1 = dots[i].Margin;
                Thickness margin2 = dots[i + 1].Margin;
                lines[i] = new Line
                {
                    Stroke          = Brushes.Black,
                    StrokeThickness = 1,
                    X1 = margin1.Left,
                    X2 = margin2.Left,
                    Y1 = margin1.Top,
                    Y2 = margin2.Top
                };

                canvasTSP.Children.Add(lines[i]);
            }

            Line lastLine = new Line
            {
                Stroke          = Brushes.Black,
                StrokeThickness = 1,
                X1 = dots[dots.Length - 1].Margin.Left,
                X2 = dots[0].Margin.Left,
                Y1 = dots[dots.Length - 1].Margin.Top,
                Y2 = dots[0].Margin.Top
            };

            canvasTSP.Children.Add(lastLine);
        }