コード例 #1
0
ファイル: Lab08.cs プロジェクト: L-Dogg/ASD2
        private static void CloseCycle(Graph g, ref Graph tree)
        {
            if (tree == null)
            {
                return;
            }
            int first = -1, last = -1;

            for (int i = 0; i < tree.VerticesCount; i++)
            {
                if (tree.InDegree(i) == 0)
                {
                    first = i;
                }
                if (tree.OutDegree(i) == 0)
                {
                    last = i;
                }
            }
            if (first == -1 || last == -1)
            {
                tree = null;
                return;
            }
            int?weight = g.GetEdgeWeight(last, first);

            if (weight.HasValue)
            {
                tree.AddEdge(last, first, weight.Value);
            }
            else
            {
                tree = null;
            }
        }
コード例 #2
0
ファイル: Lab08.cs プロジェクト: L-Dogg/ASD2
        }          // TSP_Kruskal

        private static Graph GetTree(Graph g)
        {
            Graph helper = g.IsolatedVerticesGraph(true, g.VerticesCount);
            var   queue  = new EdgesMinPriorityQueue();

            for (int i = 0; i < g.VerticesCount; i++)
            {
                foreach (var e in g.OutEdges(i))
                {
                    helper.AddEdge(e);
                    queue.Put(e);
                }
            }

            Graph     tree = g.IsolatedVerticesGraph(true, g.VerticesCount);
            UnionFind uf   = new UnionFind(g.VerticesCount);

            while (tree.EdgesCount != tree.VerticesCount - 1)
            {
                if (queue.Empty)
                {
                    return(null);
                }
                Edge e = queue.Get();
                if (uf.Find(e.To) != uf.Find(e.From) &&
                    tree.OutDegree(e.From) < 1 &&
                    tree.InDegree(e.To) < 1)
                {
                    tree.AddEdge(e);
                    uf.Union(e.From, e.To);
                }
            }
            return(tree);
        }
コード例 #3
0
        /// <summary>
        /// Bada czy zadane grafy są jednakowe
        /// </summary>
        /// <param name="g">Pierwszy badany graf</param>
        /// <param name="h">Drugi badany graf</param>
        /// <returns>Informacja czy zadane grafy są jednakowe</returns>
        /// <remarks>
        /// Badana jest struktura grafu, sposób reprezentacji nie ma znaczenia.<para/>
        /// Metoda wykonuje obliczenia równolegle w wielu wątkach.
        /// </remarks>
        /// <seealso cref="GraphHelperExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool IsEqualParallel(this Graph g, Graph h)
        {
            if (g.VerticesCount != h.VerticesCount || g.EdgesCount != h.EdgesCount)
            {
                return(false);
            }
            if (g.Directed != h.Directed)
            {
                return(false);
            }
            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (g.OutDegree(i) != h.OutDegree(i) || g.InDegree(i) != h.InDegree(i))
                {
                    return(false);
                }
            }

            var result = Parallel.For(0, g.VerticesCount, (i, state) =>
            {
                foreach (var edge in g.OutEdges(i))
                {
                    if (h.GetEdgeWeight(i, edge.To) != edge.Weight)
                    {
                        state.Stop();
                    }
                }
            });

            return(result.IsCompleted);
        }
コード例 #4
0
        /// <summary>
        /// Bada czy zadane grafy są jednakowe
        /// </summary>
        /// <param name="g">Pierwszy badany graf</param>
        /// <param name="h">Drugi badany graf</param>
        /// <returns>Informacja czy zadane grafy są jednakowe</returns>
        /// <remarks>Badana jest struktura grafu, sposób reprezentacji nie ma znaczenia.</remarks>
        /// <seealso cref="GraphHelperExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool IsEqual(this Graph g, Graph h)
        {
            if (g.VerticesCount != h.VerticesCount || g.EdgesCount != h.EdgesCount)
            {
                return(false);
            }
            if (g.Directed != h.Directed)
            {
                return(false);
            }
            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (g.OutDegree(i) != h.OutDegree(i) || g.InDegree(i) != h.InDegree(i))
                {
                    return(false);
                }
            }

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (g.OutEdges(i).Any(edge => h.GetEdgeWeight(i, edge.To) != edge.Weight))
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #5
0
        /// <summary>
        /// Bada czy zadane mapowanie wierzchołków definiuje izomorfizm grafów
        /// </summary>
        /// <param name="g">Pierwszy badany graf</param>
        /// <param name="h">Drugi badany graf</param>
        /// <param name="map">Zadane mapowanie wierzchołków</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <remarks>
        /// Mapowanie wierzchołków zdefiniowane jest w ten sposób,
        /// że wierzchołkowi v w grafie g odpowiada wierzchołek map[v] w grafie h.<para/>
        /// Badana jest struktura grafu, sposób reprezentacji nie ma znaczenia.<para/>
        /// Metoda wykonuje obliczenia równolegle w wielu wątkach.
        /// </remarks>
        /// <seealso cref="IsomorphismGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool IsIsomorphicParallel(this Graph g, Graph h, int[] map)
        {
            if (g.VerticesCount != h.VerticesCount)
            {
                return(false);
            }
            if (g.EdgesCount != h.EdgesCount)
            {
                return(false);
            }
            if (g.Directed != h.Directed)
            {
                return(false);
            }
            if (map == null)
            {
                throw new ArgumentException("Invalid mapping");
            }
            if (map.Length != g.VerticesCount)
            {
                throw new ArgumentException("Invalid mapping");
            }
            var used = new bool[g.VerticesCount];

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (map[i] < 0 || map[i] >= g.VerticesCount || used[map[i]])
                {
                    throw new ArgumentException("Invalid mapping");
                }
                used[map[i]] = true;
            }

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (g.OutDegree(i) != h.OutDegree(map[i]) || g.InDegree(i) != h.InDegree(map[i]))
                {
                    return(false);
                }
            }

            var result = Parallel.For(0, g.VerticesCount, (i, state) =>
            {
                foreach (var edge in g.OutEdges(i))
                {
                    if (edge.Weight != h.GetEdgeWeight(map[edge.From], map[edge.To]))
                    {
                        state.Stop();
                    }
                }
            });

            return(result.IsCompleted);
        }
コード例 #6
0
        /// <summary>
        /// Bada czy zadane mapowanie wierzchołków definiuje izomorfizm grafów
        /// </summary>
        /// <param name="g">Pierwszy badany graf</param>
        /// <param name="h">Drugi badany graf</param>
        /// <param name="map">Zadane mapowanie wierzchołków</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <remarks>
        /// Mapowanie wierzchołków zdefiniowane jest w ten sposób,
        /// że wierzchołkowi v w grafie g odpowiada wierzchołek map[v] w grafie h.<para/>
        /// Badana jest struktura grafu, sposób reprezentacji nie ma znaczenia.
        /// </remarks>
        /// <seealso cref="IsomorphismGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool IsIsomorphic(this Graph g, Graph h, int[] map)
        {
            if (g.VerticesCount != h.VerticesCount || g.EdgesCount != h.EdgesCount)
            {
                return(false);
            }
            if (g.Directed != h.Directed)
            {
                return(false);
            }

            if (map == null)
            {
                throw new ArgumentException("Invalid mapping");
            }
            if (map.Length != g.VerticesCount)
            {
                throw new ArgumentException("Invalid mapping");
            }
            var used = new bool[g.VerticesCount];

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (map[i] < 0 || map[i] >= g.VerticesCount || used[map[i]])
                {
                    throw new ArgumentException("Invalid mapping");
                }
                used[map[i]] = true;
            }

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (g.OutDegree(i) != h.OutDegree(map[i]) || g.InDegree(i) != h.InDegree(map[i]))
                {
                    return(false);
                }
            }

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (g.OutEdges(i).Any(edge => edge.Weight != h.GetEdgeWeight(map[edge.From], map[edge.To])))
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #7
0
        // Helper method so as not to duplicate code in the CliqueNumberRecursive method
        private static void CheckNewCliqueVertex(Graph g, int v, int cliqueSize, ref bool[] isVertexInClique, ref bool[] biggestClique, ref int biggestCliqueSize)
        {
            // If vertex has a lower degree than there are already vertices in the clique
            // it definitely cannot be added to the clique
            if (g.OutDegree(v) < cliqueSize || g.InDegree(v) < cliqueSize)
            {
                return;
            }

            // Check if there are edges between this vertex (v) and all the vertices already in the clique
            bool validVertex = true;

            for (int cliqueVertex = 0; cliqueVertex < v; cliqueVertex++)
            {
                if (isVertexInClique[cliqueVertex] && (g.GetEdgeWeight(v, cliqueVertex).IsNaN() || g.GetEdgeWeight(cliqueVertex, v).IsNaN()))
                {
                    validVertex = false;
                    break;
                }
            }

            if (!validVertex)
            {
                return;
            }

            isVertexInClique[v] = true;
            bool[] newClique     = isVertexInClique.Clone() as bool[];
            int    newCliqueSize = CliqueNumberRecursive(g, ref newClique, cliqueSize + 1, v + 1);

            if (newCliqueSize > biggestCliqueSize)
            {
                biggestClique     = newClique;
                biggestCliqueSize = newCliqueSize;
            }
            isVertexInClique[v] = false;
        }
コード例 #8
0
            /// <summary>
            /// Bada izomorfizm grafów metodą pełnego przeglądu (rekurencyjnie)
            /// </summary>
            /// <param name="currentV">Aktualnie rozważany wierzchołek</param>
            /// <param name="map">Mapowanie wierzchołków grafu h na wierzchołki grafu g</param>
            /// <returns>Informacja czy znaleziono mapowanie definiujące izomotfizm</returns>
            internal bool FindMapping(int currentV, int[] map, bool[] isVertexInMapping)
            {
                // Wskazówki
                // 1) w sposób systematyczny sprawdzać wszystkie potencjalne mapowania
                // 2) unikać wielokrotnego sprawdzania tego samego mapowania
                // 3) zastosować algorytm z powrotami (backtracking)
                // 4) do badania krawędzi pomiędzy wierzchołkami i oraz j użyć metody GetEdgeWeight(i,j)

                // We assume that vertices 0 - (currentV - 1) are already mapped
                int n = g.VerticesCount;

                if (currentV >= n)
                {
                    return(true);
                }

                // I assume that map[i] = j means, that vertex i in graph G is isomorphic with vertex j in graph H

                // We check every possible vertex from graph H that is not yet used
                // and try to match it with currentV (from graph G)
                for (int vH = 0; vH < n; vH++)
                {
                    if (isVertexInMapping[vH])
                    {
                        continue;
                    }
                    if (g.OutDegree(currentV) != h.OutDegree(vH) || g.InDegree(currentV) != h.InDegree(vH))
                    {
                        continue;
                    }

                    // Check every neighbor of currentV that is already in mapping, if it matches neighbors of vH
                    map[currentV] = vH;
                    bool validMatch = true;
                    foreach (Edge eG in g.OutEdges(currentV))
                    {
                        // Edge leads to a neighbor that is not yet in the mapping (because we already analyzed vertices 0 - (currentVertex - 1))
                        if (eG.To > currentV)
                        {
                            continue;
                        }

                        // Edge weights should be equal in both graphs
                        double edgeWeightH = h.GetEdgeWeight(vH, map[eG.To]);
                        if (eG.Weight != edgeWeightH)
                        {
                            validMatch = false;
                            break;
                        }

                        // The same goes for reverse edges
                        double reverseEdgeWeightG = g.GetEdgeWeight(eG.To, currentV);
                        double reverseEdgeWeightH = h.GetEdgeWeight(map[eG.To], vH);
                        if ((!reverseEdgeWeightG.IsNaN() || !reverseEdgeWeightH.IsNaN()) && reverseEdgeWeightG != reverseEdgeWeightH)
                        {
                            validMatch = false;
                            break;
                        }
                    }
                    if (!validMatch)
                    {
                        continue;
                    }

                    // vH in H is isomorphic with currentV in G
                    isVertexInMapping[vH] = true;
                    bool isomorphismFound = FindMapping(currentV + 1, map, isVertexInMapping);
                    if (isomorphismFound)
                    {
                        return(true);
                    }

                    isVertexInMapping[vH] = false;

                    // Isomorphism with this matching not found, look for other possibilities of vertices isomorphic with currentV
                }

                // No isomorphism found
                return(false);
            }
コード例 #9
0
        /// <summary>
        /// Bada izomorfizm grafów metodą pełnego przeglądu (backtracking)
        /// </summary>
        /// <param name="g">Pierwszy badany graf</param>
        /// <param name="h">Drugi badany graf</param>
        /// <returns>Znalezione mapowanie wierzchołków</returns>
        /// <remarks>
        /// Jeśli grafy są izomorficzne metoda zwraca mapowanie wierzchołków grafu g na wierzchołki grafu h,
        /// w przeciwnym przypadku metoda zwraca null<para/>
        /// Odpowiedniość wierzchołków zdefiniowana jest w ten sposób,
        /// że wierzchołkowi v w grafie g odpowiada wierzchołek map[v] w grafie h.<para/>
        /// Badana jest struktura grafu, sposób reprezentacji nie ma znaczenia.
        /// </remarks>
        /// <seealso cref="IsomorphismGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static int[] Isomorphism(this Graph g, Graph h)
        {
            if (g.VerticesCount != h.VerticesCount || g.EdgesCount != h.EdgesCount ||
                g.Directed != h.Directed)
            {
                return(null);
            }

            var vertCount = g.VerticesCount;
            var mapping   = new int[vertCount];
            var mapped    = new bool[vertCount];
            var int_2     = new int[vertCount];
            var int_3     = new int[vertCount];

            for (var i = 0; i < vertCount; i++)
            {
                int_3[i] = -1;
            }
            var order   = 0;
            var visited = new bool[vertCount];

            bool PreVisitVertex(int i)
            {
                visited[i]     = true;
                int_2[order++] = i;
                return(true);
            }

            bool VisitEdge(Edge edge)
            {
                if (!visited[edge.To] && int_3[edge.To] == -1)
                {
                    int_3[edge.To] = edge.From;
                }
                return(true);
            }

            g.GeneralSearchAll <EdgesStack>(PreVisitVertex, null, VisitEdge, out _);

            bool FindIsomorphism(int vert)
            {
                (int int_0, int int_1)s;
                s.int_1 = vert;
                if (s.int_1 == vertCount)
                {
                    return(true);
                }

                s.int_0 = int_2[s.int_1];
                if (int_3[s.int_0] != -1)
                {
                    return(h.OutEdges(mapping[int_3[s.int_0]]).Any(edge => Check(edge.To, ref s)));
                }

                for (var i = 0; i < vertCount; i++)
                {
                    if (Check(i, ref s))
                    {
                        return(true);
                    }
                }
                return(false);
            }

            bool Check(int int_4, ref (int int_0, int int_1) pair)
            {
                if (mapped[int_4] || g.OutDegree(pair.int_0) != h.OutDegree(int_4) ||
                    g.InDegree(pair.int_0) != h.InDegree(int_4))
                {
                    return(false);
                }
                for (var i = 0; i < pair.int_1; i++)
                {
                    var w1 = g.GetEdgeWeight(int_2[i], pair.int_0);
                    var w2 = h.GetEdgeWeight(mapping[int_2[i]], int_4);
                    if (w1 != w2 && (!w1.IsNaN() || !w2.IsNaN()))
                    {
                        return(false);
                    }

                    w1 = g.GetEdgeWeight(pair.int_0, int_2[i]);
                    w2 = h.GetEdgeWeight(int_4, mapping[int_2[i]]);
                    if (w1 != w2 && (!w1.IsNaN() || !w2.IsNaN()))
                    {
                        return(false);
                    }
                }
                mapped[int_4]       = true;
                mapping[pair.int_0] = int_4;
                if (FindIsomorphism(pair.int_1 + 1))
                {
                    return(true);
                }

                mapped[int_4] = false;
                return(false);
            }

            return(FindIsomorphism(0) ? mapping : null);
        }
コード例 #10
0
        /// <summary>
        /// Znajduje rozwiązanie przybliżone problemu komiwojażera algorytmem zachłannym "kruskalopodobnym"
        /// </summary>
        /// <param name="g">Badany graf</param>
        /// <param name="cycle">Znaleziony cykl (parametr wyjściowy)</param>
        /// <returns>Długość znalezionego cyklu (suma wag krawędzi)</returns>
        /// <remarks>
        /// Elementy (krawędzie) umieszczone są w tablicy <i>cycle</i> w kolejności swojego następstwa w znalezionym cyklu Hamiltona.<br/>
        /// <br/>
        /// Jeśli algorytm "kruskalopodobny" nie znajdzie w badanym grafie cyklu Hamiltona
        /// (co oczywiście nie znaczy, że taki cykl nie istnieje) to metoda zwraca <b>null</b>,
        /// parametr wyjściowy <i>cycle</i> również ma wówczas wartość <b>null</b>.<br/>
        /// <br/>
        /// Metodę można stosować dla grafów skierowanych i nieskierowanych.<br/>
        /// <br/>
        /// Metodę można stosować dla dla grafów z dowolnymi (również ujemnymi) wagami krawędzi.
        /// </remarks>
        public static double TSP_Kruskal(this Graph g, out Edge[] cycle)
        {
            // ToDo - algorytm "kruskalopodobny"
            int n = g.VerticesCount;
            EdgesMinPriorityQueue edgesQueue = new EdgesMinPriorityQueue();

            for (int v = 0; v < n; v++)
            {
                foreach (Edge e in g.OutEdges(v))
                {
                    // For undirected graphs only add edges once
                    if (!g.Directed && e.From >= e.To)
                    {
                        continue;
                    }

                    edgesQueue.Put(e);
                }
            }

            UnionFind uf = new UnionFind(n);
            Graph     minSpanningTree = g.IsolatedVerticesGraph();

            while (!edgesQueue.Empty && minSpanningTree.EdgesCount < n - 1)
            {
                Edge e = edgesQueue.Get();
                if (uf.Find(e.From) == uf.Find(e.To))   // Edge would preemptively create a cycle
                {
                    continue;
                }
                if (g.Directed)
                {
                    if (minSpanningTree.OutDegree(e.From) != 0 || minSpanningTree.InDegree(e.To) != 0)  // Two out edges or two in edges for some vertex
                    {
                        continue;
                    }
                }
                else
                {
                    if (minSpanningTree.OutDegree(e.From) == 2 || minSpanningTree.OutDegree(e.To) == 2) // Edge would create a diversion on the path
                    {
                        continue;
                    }
                }

                minSpanningTree.AddEdge(e);
                uf.Union(e.From, e.To);
            }

            if (minSpanningTree.EdgesCount < n - 1)
            {
                // Unable to construct a spanning path with n-1 edges
                cycle = null;
                return(double.NaN);
            }


            // Look for vertices at the beginning and end of the path
            int cycleBeginV = -1,
                cycleEndV   = -1;

            for (int v = 0; v < n; v++)
            {
                if (!minSpanningTree.Directed)
                {
                    if (minSpanningTree.OutDegree(v) == 1)
                    {
                        if (cycleBeginV == -1)
                        {
                            cycleBeginV = v;
                        }
                        else
                        {
                            cycleEndV = v;
                            break;
                        }
                    }
                }
                else
                {
                    if (minSpanningTree.OutDegree(v) == 0)
                    {
                        cycleBeginV = v;
                    }
                    if (minSpanningTree.InDegree(v) == 0)
                    {
                        cycleEndV = v;
                    }

                    if (cycleBeginV != -1 && cycleEndV != -1)
                    {
                        break;
                    }
                }
            }

            if (cycleBeginV == -1 || cycleEndV == -1)
            {
                // This if is superfluous, but I'm leaving it just for clarity
                cycle = null;
                return(double.NaN);
            }

            // Closing the cycle
            minSpanningTree.AddEdge(new Edge(cycleBeginV, cycleEndV, g.GetEdgeWeight(cycleBeginV, cycleEndV)));
            cycle = new Edge[n];
            int    currentCycleV = 0;
            double cycleLength   = 0;

            for (int i = 0; i < n; i++)
            {
                Edge?cycleEdge = minSpanningTree.OutEdges(currentCycleV).First();
                if (!minSpanningTree.Directed && i > 0)
                {
                    // Make sure the edge goes further into the cycle, not backwards (only for undirected graphs)
                    foreach (Edge e in minSpanningTree.OutEdges(currentCycleV))
                    {
                        if (e.To != cycle[i - 1].From)
                        {
                            cycleEdge = e;
                            break;
                        }
                    }
                }

                cycle[i]      = cycleEdge.Value;
                currentCycleV = cycleEdge.Value.To;
                cycleLength  += cycleEdge.Value.Weight;
            }

            return(cycleLength);
        }  // TSP_Kruskal
コード例 #11
0
        /// <summary>
        /// Znajduje scieżkę Eulera w grafie
        /// </summary>
        /// <param name="g">Badany graf</param>
        /// <param name="ec">Znaleziona ścieżka (parametr wyjściowy)</param>
        /// <returns>Informacja czy ścieżka Eulera istnieje</returns>
        /// <remarks>
        /// Jeśli w badanym grafie nie istnieje ścieżka Eulera metoda zwraca false,
        /// parametr ec ma wówczas wartość null.<para/>
        /// Metoda nie modyfikuje badanego grafu.<para/>
        /// Metoda implementuje algorytm Fleury'ego.
        /// </remarks>
        /// <seealso cref="EulerPathGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static bool EulerPath(this Graph g, out Edge[] ec)
        {
            ec = null;
            var oddDegreeCounter    = 0;
            var startVertex         = 0;
            var hasOutGreaterThanIn = false;
            var hasInGreaterThanOut = false;

            if (g.Directed)
            {
                for (var i = 0; i < g.VerticesCount; i++)
                {
                    var outDegree = g.OutDegree(i);
                    var inDegree  = g.InDegree(i);
                    if (Math.Abs(outDegree - inDegree) > 1)
                    {
                        return(false);
                    }
                    if (outDegree > inDegree)
                    {
                        if (hasOutGreaterThanIn)
                        {
                            return(false);
                        }
                        startVertex         = i;
                        hasOutGreaterThanIn = true;
                    }
                    if (inDegree > outDegree)
                    {
                        if (hasInGreaterThanOut)
                        {
                            return(false);
                        }
                        hasInGreaterThanOut = true;
                    }
                }
            }
            else
            {
                for (var i = 0; i < g.VerticesCount; i++)
                {
                    if ((g.OutDegree(i) & 1) != 1)
                    {
                        continue;
                    }
                    startVertex = i;
                    if (++oddDegreeCounter > 2)
                    {
                        return(false);
                    }
                }
            }
            var visited = new bool[g.VerticesCount];
            var graph   = g.Clone();
            var s1      = new EdgesStack();
            var s2      = new EdgesStack();

            s2.Put(new Edge(startVertex, startVertex));
            while (!s2.Empty)
            {
                var vertex = s2.Peek().To;
                visited[vertex] = true;
                if (graph.OutDegree(vertex) > 0)
                {
                    var edge = graph.OutEdges(vertex).First();
                    s2.Put(edge);
                    graph.DelEdge(edge);
                }
                else
                {
                    s1.Put(s2.Get());
                }
            }
            s1.Get();

            if (graph.EdgesCount > 0)
            {
                return(false);
            }

            for (var i = 0; i < g.VerticesCount; i++)
            {
                if (!visited[i])
                {
                    return(false);
                }
            }

            ec = s1.ToArray();
            return(true);
        }