コード例 #1
0
        /// <summary>
        /// Wyznacza najkrótsze ścieżki algorytmem Floyda-Warshalla
        /// </summary>
        /// <param name="g">Badany graf</param>
        /// <param name="d">Znalezione najkrótsze ścieżki (parametr wyjściowy)</param>
        /// <returns>Informacja czy graf nie zawiera cyklu o ujemnej długości</returns>
        /// <exception cref="ArgumentException">Gdy uruchomiona dla grafu nieskierowanego</exception>
        /// <remarks>
        /// Elementy tablicy d zawierają odległości pomiedzy każdą parą wierzchołków grafu.<para/>
        /// Jeśli dla danej pary wierzchołków odpowiednia ścieżka nie istnieje, to odległość ma wartość NaN.<para/>
        /// Metoda uruchomiona dla grafu nieskierowanego zgłasza wyjątek <see cref="ArgumentException"/>.<para/>
        /// Jeśli badany graf zawiera cykl o ujemnej długości, to metoda zwraca false.
        /// Parametr d jest wówczas równy null.<para/>
        /// Metoda wykonuje obliczenia równolegle w wielu wątkach.
        /// </remarks>
        /// <seealso cref="ShortestPathsGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool FloydWarshallShortestPathsParallel(this ASD.Graphs.Graph g, out PathsInfo[,] d)
        {
            if (!g.Directed)
            {
                throw new ArgumentException("Undirected graphs are not allowed");
            }

            var dTemp = new PathsInfo[g.VerticesCount, g.VerticesCount];

            void Init(int i, ParallelLoopState pls)
            {
                for (var j = 0; j < g.VerticesCount; j++)
                {
                    dTemp[i, j].Dist = double.NaN;
                }

                foreach (var edge in g.OutEdges(i))
                {
                    dTemp[i, edge.To].Dist = edge.Weight;
                    dTemp[i, edge.To].Last = edge;
                }
                if (dTemp[i, i].Dist.IsNaN() || dTemp[i, i].Dist >= 0.0)
                {
                    dTemp[i, i].Dist = 0.0;
                    dTemp[i, i].Last = null;
                }
                if (dTemp[i, i].Dist < 0.0)
                {
                    pls.Stop();
                }
            }

            var parallelLoopResult = Parallel.For(0, g.VerticesCount, Init);
            var k = 0;

            void Action(int i, ParallelLoopState pls)
            {
                for (var j = 0; j < g.VerticesCount; j++)
                {
                    if (!dTemp[i, j].Dist.IsNaN() && !(dTemp[i, j].Dist > dTemp[i, k].Dist + dTemp[k, j].Dist))
                    {
                        continue;
                    }
                    dTemp[i, j].Dist = dTemp[i, k].Dist + dTemp[k, j].Dist;
                    dTemp[i, j].Last = dTemp[k, j].Last;
                    if (i == j && dTemp[i, j].Dist < 0.0)
                    {
                        pls.Stop();
                    }
                }
            }

            while (k < g.VerticesCount)
            {
                if (!parallelLoopResult.IsCompleted)
                {
                    break;
                }
                parallelLoopResult = Parallel.For(0, g.VerticesCount, Action);
                k++;
            }
            d = parallelLoopResult.IsCompleted ? dTemp : null;
            return(parallelLoopResult.IsCompleted);
        }
コード例 #2
0
        /// <summary>
        /// Wyznacza najkrótsze ścieżki algorytmem Forda-Bellmana
        /// </summary>
        /// <param name="g">Badany graf</param>
        /// <param name="s">Wierzchołek źródłowy</param>
        /// <param name="d">Znalezione najkrótsze ścieżki (parametr wyjściowy)</param>
        /// <returns>Informacja czy graf spełnia założenia algorytmu Forda-Bellmana</returns>
        /// <exception cref="ArgumentException">Gdy uruchomiona dla grafu nieskierowanego</exception>
        /// <remarks>
        /// Elementy tablicy d zawierają odległości od źródła do wierzchołka określonego przez indeks elementu.<para/>
        /// Jeśli ścieżka od źródła do danego wierzchołka nie istnieje, to odległość ma wartość NaN.<para/>
        /// Metoda uruchomiona dla grafu nieskierowanego zgłasza wyjątek <see cref="ArgumentException"/>.<para/>
        /// Jeśli badany graf nie spełnia założeń algorytmu Forda-Bellmana, to metoda zwraca false.
        /// Parametr d zawiera wówczas informacje umożliwiające wyznaczenie cyklu o ujemnej długości.<para/>
        /// Założenia badane są jedynie częściowo, w zakresie mogącym wpłynąć na działanie algorytmu
        /// (na przykład dla grafu niespójnego cykle o ujemnej długości w innej składowej spójnej
        /// niż źródło nie zostaną wykryte - metoda zwróci true).<para/>
        /// Metoda wykonuje obliczenia równolegle w wielu wątkach.
        /// </remarks>
        /// <seealso cref="ShortestPathsGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool FordBellmanShortestPathsParallel(this ASD.Graphs.Graph g, int s, out PathsInfo[] d)
        {
            if (!g.Directed)
            {
                throw new ArgumentException("Undirected graphs are not allowed");
            }

            var change = g.VerticesCount > 1;

            var array1 = new bool[g.VerticesCount];
            var array2 = new bool[g.VerticesCount];
            var mutex  = new object[g.VerticesCount];

            var dTemp = new PathsInfo[g.VerticesCount];

            for (var i = 0; i < g.VerticesCount; i++)
            {
                dTemp[i].Dist = double.NaN;
            }
            dTemp[s].Dist = 0.0;

            array2[s] = true;

            var rotations = 0;

            for (var i = 0; i < g.VerticesCount; i++)
            {
                mutex[i] = new object();
            }

            void Action(int vert)
            {
                if (!array2[vert])
                {
                    return;
                }
                array2[vert] = false;
                foreach (var edge in g.OutEdges(vert))
                {
                    if (!dTemp[edge.To].Dist.IsNaN() && !(dTemp[edge.To].Dist > dTemp[edge.From].Dist + edge.Weight))
                    {
                        continue;
                    }
                    lock (mutex[edge.To])
                    {
                        if (!dTemp[edge.To].Dist.IsNaN() && !(dTemp[edge.To].Dist > dTemp[edge.From].Dist + edge.Weight))
                        {
                            continue;
                        }
                        change              = true;
                        array1[edge.To]     = true;
                        dTemp[edge.To].Dist = dTemp[vert].Dist + edge.Weight;
                        dTemp[edge.To].Last = edge;
                    }
                }
            }

            while (change && rotations++ != g.VerticesCount)
            {
                change = false;
                Parallel.For(0, g.VerticesCount, Action);
                var temp = array2;
                array2 = array1;
                array1 = temp;
            }
            d = dTemp;
            return(!change);
        }