示例#1
0
        public void Reconstruct(Tuple <int, int> next, int subset, int from, int[][] parentSet, int[][] parentVia)
        {
            if (subset == 0)
            {
                return;
            }

            int leftSet  = next.Item1;
            int rightSet = subset ^ leftSet;
            int via      = next.Item2;

            Tuple <int, int> nextLeft  = Tuple.Create(parentSet[via][leftSet], parentVia[via][leftSet]);
            Tuple <int, int> nextRight = Tuple.Create(parentSet[via][rightSet], parentVia[via][rightSet]);

            if (!nextLeft.Equals(next))
            {
                Reconstruct(nextLeft, leftSet, via, parentSet, parentVia);
            }
            if (!nextRight.Equals(next))
            {
                Reconstruct(nextRight, rightSet, via, parentSet, parentVia);
            }

            Edge?e = G.pred[from, via];

            while (e != null)
            {
                Edge e2 = (Edge)e;
                result.Add(e2);
                e = G.pred[from, e2.From.Id];
            }
        }
示例#2
0
    private IEnumerable <Edge> ExtractEdgeFromPoints(IEnumerable <Vector2> points)
    {
        Vector2?first = null;
        Vector2?last  = null;

        foreach (var point in points)
        {
            if (first == null)
            {
                first = point;
            }
            if (last != null)
            {
                Edge?edge = GetValidEdge(last.Value, point);
                if (edge != null)
                {
                    yield return(edge.Value);
                }
            }
            last = point;
        }
        if (first != null && first.Value != last.Value)
        {
            Edge?edge = GetValidEdge(last.Value, first.Value);
            if (edge != null)
            {
                yield return(edge.Value);
            }
        }
    }
示例#3
0
        /// <inheritdoc/>
        public bool Equals(Edge?other)
        {
            if (other is null)
            {
                return(false);
            }

            return(A == other.A && B == other.B);
        }
示例#4
0
文件: Graph.cs 项目: resc/redpipes
            public bool Equals(Edge?other)
            {
                if (ReferenceEquals(null, other))
                {
                    return(false);
                }

                if (ReferenceEquals(this, other))
                {
                    return(true);
                }

                return(Equals(Source, other.Source) && Equals(Target, other.Target));
            }
        /// <summary>
        /// Wyznacza minimalne drzewo rozpinające grafu algorytmem Boruvki
        /// </summary>
        /// <param name="g">Badany graf</param>
        /// <returns>
        /// Krotka (weight, mst) składająca się z wagi minimalnego drzewa rozpinającego i grafu opisującego to drzewo
        /// </returns>
        /// <exception cref="ArgumentException"></exception>
        /// <remarks>
        /// Jeśli graf g jest typu <see cref="AdjacencyMatrixGraph"/> to wyznaczone drzewo rozpinające mst jest typu
        /// <see cref="AdjacencyListsGraph{AVLAdjacencyList}"/>, w przeciwnym
        /// przypadku drzewo rozpinające mst jest takiego samego typu jak graf g.<para/>
        /// Dla grafu skierowanego metoda zgłasza wyjątek <see cref="ArgumentException"/>.<para/>
        /// Wyznaczone drzewo reprezentowane jest jako graf bez cykli,
        /// to umożliwia jednolitą obsługę sytuacji gdy analizowany graf jest niespójny,
        /// wyznaczany jest wówczas las rozpinający.<para/>
        /// Jest to nieco zmodyfikowana wersja algorytmu Boruvki
        /// (nie ma operacji "sciągania" spójnych składowych w jeden wierzchołek).
        /// </remarks>
        /// <seealso cref="MSTGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static (double weight, Graph mst) Boruvka(this Graph g)
        {
            if (g.Directed)
            {
                throw new ArgumentException("Directed graphs are not allowed");
            }

            var unionFind             = new UnionFind(g.VerticesCount);
            var edgesMinPriorityQueue = new EdgesMinPriorityQueue();
            var tree   = g is AdjacencyMatrixGraph ? new AdjacencyListsGraph <AVLAdjacencyList>(false, g.VerticesCount) : g.IsolatedVerticesGraph();
            var weight = 0.0;
            var change = true;

            while (change)
            {
                change = false;
                for (var i = 0; i < g.VerticesCount; i++)
                {
                    Edge?edge = null;
                    foreach (var e in g.OutEdges(i))
                    {
                        if (unionFind.Find(i) != unionFind.Find(e.To) && (edge == null || e.Weight < edge.Value.Weight))
                        {
                            edge = e;
                        }
                    }
                    if (edge != null)
                    {
                        edgesMinPriorityQueue.Put(edge.Value);
                    }
                }
                while (!edgesMinPriorityQueue.Empty)
                {
                    var edge = edgesMinPriorityQueue.Get();
                    if (!unionFind.Union(edge.From, edge.To))
                    {
                        continue;
                    }
                    tree.AddEdge(edge);
                    weight += edge.Weight;
                    if (tree.EdgesCount == g.VerticesCount - 1)
                    {
                        return(weight, tree);
                    }
                    change = true;
                }
            }
            return(weight, tree);
        }
        /// <summary>
        /// Znajduje cykl o ujemnej długości (wadze)
        /// </summary>
        /// <param name="g">Badany graf</param>
        /// <param name="d">Informacje o najkrótszych ścieżkach</param>
        /// <returns>
        /// Krotka (weight, cycle) składająca się z długości (sumy wag krawędzi)
        /// znalezionego cyklu i tablicy krawędzi tworzących ten cykl)
        /// </returns>
        /// <remarks>
        /// Elementy tablicy d powinny zawierać odległości wyznaczone algorytmem Forda-Bellmana,
        /// który zatrzymał się z wynikiem false.<para/>
        /// Jeśli analiza tablicy d nie wykryła cyklu o ujemnej długości metoda zwraca (0,null).<para/>
        /// Nie oznacza to, że w grafie nie ma żadnego cyklu o ujemnej dlugości, a jedynie że nie ma takiego cyklu,
        /// który zakłóciłby działanie uruchomionego wcześciej algorytmu Forda-Bellmana (dla danego źródła).<para/>
        /// Elementy (krawędzie) umieszczone są w zwracanej tablicy w kolejności swojego następstwa w znalezionym cyklu.
        /// </remarks>
        /// <seealso cref="ShortestPathsGraphExtender"/>
        /// <seealso cref="ASD.Graphs"/>
        public static (double weight, Edge[] cycle) FindNegativeCostCycle(this ASD.Graphs.Graph g, PathsInfo[] d)
        {
            Edge?edge = null;
            var  vert = 0;

            while (edge == null && vert < g.VerticesCount)
            {
                if (!d[vert].Dist.IsNaN())
                {
                    foreach (var e in g.OutEdges(vert))
                    {
                        if (!d[e.To].Dist.IsNaN() && !(d[e.To].Dist > d[vert].Dist + e.Weight))
                        {
                            continue;
                        }
                        edge = e;
                        break;
                    }
                }
                vert++;
            }
            if (edge == null)
            {
                return(0.0, null);
            }

            var hashSet = new HashSet <int> {
                edge.Value.To
            };
            var from = d[edge.Value.To].Last.Value.From;

            while (!hashSet.Contains(from))
            {
                hashSet.Add(from);
                from = d[from].Last.Value.From;
            }
            var start      = from;
            var weight     = 0.0;
            var edgesStack = new EdgesStack();

            do
            {
                edge = d[from].Last;
                edgesStack.Put(edge.Value);
                weight += edge.Value.Weight;
                from    = edge.Value.From;
            }while (from != start);
            return(weight, edgesStack.ToArray());
        }
示例#7
0
        public int EdgeDegree(int edgeID, Graph graph)
        {
            Edge?edge = null;

            foreach (Edge e in graph.Edges)
            {
                if (e.ID == edgeID)
                {
                    edge = e;
                }
            }
            int degree = graph.Edges.FindAll(x =>
                                             edge.Nodes.Item1 == x.Nodes.Item1 ||
                                             edge.Nodes.Item1 == x.Nodes.Item2 ||
                                             edge.Nodes.Item2 == x.Nodes.Item1 ||
                                             edge.Nodes.Item2 == x.Nodes.Item2).Count();

            return(degree - 1);
        }
示例#8
0
        public List <Edge> NeighbourEdges(int edgeID, Graph graph)
        {
            Edge?edge = null;

            foreach (Edge e in graph.Edges)
            {
                if (e.ID == edgeID)
                {
                    edge = e;
                }
            }
            List <Edge> neighbours = graph.Edges.FindAll(x =>
                                                         edge.Nodes.Item1 == x.Nodes.Item1 ||
                                                         edge.Nodes.Item1 == x.Nodes.Item2 ||
                                                         edge.Nodes.Item2 == x.Nodes.Item1 ||
                                                         edge.Nodes.Item2 == x.Nodes.Item2
                                                         ).Where(x => edge.ID != x.ID).ToList();

            return(neighbours);
        }
示例#9
0
 public IEnumerable <Edge> ExtractEdge()
 {
     Collider2D[] colliders = Physics2D.OverlapCircleAll(center, radius);
     foreach (var collider in colliders)
     {
         PolygonCollider2D polygon = collider.GetComponent <PolygonCollider2D>();
         if (polygon != null)
         {
             for (int i = 0; i < polygon.pathCount; i++)
             {
                 Vector2?first = null;
                 Vector2?last  = null;
                 foreach (var point in polygon.GetPath(i))
                 {
                     if (first == null)
                     {
                         first = point;
                     }
                     if (last != null)
                     {
                         Edge?edge = GetValidEdge(polygon, last.Value, point);
                         if (edge != null)
                         {
                             yield return(edge.Value);
                         }
                     }
                     last = point;
                 }
                 if (first != null && first.Value != last.Value)
                 {
                     Edge?edge = GetValidEdge(polygon, last.Value, first.Value);
                     if (edge != null)
                     {
                         yield return(edge.Value);
                     }
                 }
             }
         }
     }
     yield break;
 }
        private static Vector2 GetEndTangent(Vector2 start, Vector2 end, Edge startEdge, Edge?endEdge, float relativeBend, float minBend)
        {
            var endDirection = endEdge?.Normal() ?? startEdge.Opposite().Normal();

            var endBend = Mathf.Abs(Vector2.Dot(start - end, endDirection)) * relativeBend;

            if (endDirection.y != 0)
            {
                endBend *= -1;
            }

            if (Mathf.Abs(endBend) < Mathf.Abs(minBend))
            {
                endBend = Mathf.Sign(endBend) * minBend;
            }

            var endTangent = end + endDirection * endBend;

            return(endTangent);
        }
        private static Vector2 GetStartTangent(Vector2 start, Vector2 end, Edge startEdge, Edge?endEdge, float relativeBend, float minBend)
        {
            var startDirection = startEdge.Normal();

            var startBend = Mathf.Abs(Vector2.Dot(end - start, startDirection)) * relativeBend;

            if (startDirection.y != 0)
            {
                startBend *= -1;
            }

            if (Mathf.Abs(startBend) < Mathf.Abs(minBend))
            {
                startBend = Mathf.Sign(startBend) * minBend;
            }

            var startTangent = start + startDirection * startBend;

            return(startTangent);
        }
        public static void DrawConnection(Color color, Vector2 start, Vector2 end, Edge startEdge, Edge?endEdge, Texture cap = null, Vector2 capSize = default(Vector2), float relativeBend = 1 / 4f, float minBend = 0, float thickness = 3)
        {
            if (cap)
            {
                var capPosition = new Rect
                                  (
                    end,
                    capSize
                                  );

                Vector2 capOffset;
                Vector2 endOffset;

                if (endEdge.HasValue)
                {
                    switch (endEdge)
                    {
                    case Edge.Left:
                        capOffset = new Vector2(-capSize.x, -capSize.y / 2);
                        endOffset = new Vector2(capSize.x, 0);
                        break;

                    case Edge.Right:
                        capOffset = new Vector2(0, -capSize.y / 2);
                        endOffset = new Vector2(-capSize.x, 0);
                        break;

                    case Edge.Top:
                        capOffset = new Vector2(-capSize.x / 2, -capSize.y);
                        endOffset = new Vector2(0, capSize.y);
                        break;

                    case Edge.Bottom:
                        capOffset = new Vector2(-capSize.x / 2, 0);
                        endOffset = new Vector2(0, -capSize.y);
                        break;

                    default:
                        throw new UnexpectedEnumValueException <Edge>(endEdge.Value);
                    }
                }
                else
                {
                    capOffset = new Vector2(-capSize.x / 2, -capSize.y / 2);
                    endOffset = Vector2.zero;
                }

                capPosition.position += capOffset;
                end -= endOffset;

                if (BoltCore.Configuration.developerMode && BoltCore.Configuration.debug)
                {
                    EditorGUI.DrawRect(capPosition, new Color(0, 0, 1, 0.25f));
                }

                using (LudiqGUI.color.Override(LudiqGUI.color.value * color))
                {
                    GUI.DrawTexture(capPosition, cap);
                }
            }

            var startTangent = GetStartTangent(start, end, startEdge, endEdge, relativeBend, minBend);
            var endTangent   = GetEndTangent(start, end, startEdge, endEdge, relativeBend, minBend);

            Handles.DrawBezier(start, end, startTangent, endTangent, LudiqGUI.color.value * color, AliasedBezierTexture(thickness), thickness);

            if (BoltCore.Configuration.developerMode && BoltCore.Configuration.debug)
            {
                Handles.color = Color.yellow;
                Handles.DrawLine(start, startTangent);
                Handles.DrawLine(end, endTangent);
            }
        }
        public static Vector2 GetPointOnConnection(float t, Vector2 start, Vector2 end, Edge startEdge, Edge?endEdge, float relativeBend = 1 / 4f, float minBend = 0)
        {
            var startTangent = GetStartTangent(start, end, startEdge, endEdge, relativeBend, minBend);
            var endTangent   = GetEndTangent(start, end, startEdge, endEdge, relativeBend, minBend);

            return(MathfEx.Bezier(start, end, startTangent, endTangent, t));
        }
示例#14
0
 public bool Equals(Edge?other)
 {
     return(other is not null &&
            From.Equals(other.From) &&
            To.Equals(other.To));
 }
示例#15
0
        private static bool PerformTest(int id, Test t)
        {
            double fv;
            ulong  start, end;

            start = Graph.Counter;
            Console.Out.Write("Test {0}", id);
            Edge?result = t.graph.ImprovementChecker(t.ins, t.outs, out fv);

            end = Graph.Counter;
            Console.Out.WriteLine(", czas {1}, spodziewany oko³o: poziom2: {2}, poziom1: {3}", id, end - start, t.expectedTime, t.acceptableTime);
            Console.Out.WriteLine("Test {0} -- {1}, wartosc przeplywu {2}, spodziewane {3}", id, fv == t.flowValue ? "OK" : "B£¥D", fv, t.flowValue);
            if (id == 6)
            {
                if (result == null)
                {
                    Console.Out.WriteLine("Test {0} -- B£¥D, nie znaleziono rozwi¹zania", id);
                    return(false);
                }
                else
                if (result.Value.From >= 0 && result.Value.From < 20000 && result.Value.To >= 20000 && result.Value.To < 40000 && (result.Value.From != 0 || result.Value.To != 39999))
                {
                    Console.Out.WriteLine("Test {0} -- OK, znaleziono {1}", id, result);
                    return(true);
                }
                else
                {
                    Console.Out.WriteLine("Test {0} -- B£¥D, niepoprawne rozwi¹zanie {1}", id, result);
                    return(false);
                }
            }
            if (t.solutions == null)
            {
                if (result == null)
                {
                    Console.Out.WriteLine("Test {0} -- OK, brak rozwi¹zañ", id);
                    return(true);
                }
                else
                {
                    Console.Out.WriteLine("Test {0} -- B£¥D, powinno byæ: brak rozwi¹zañ, jest: {1}", id, result);
                    return(false);
                }
            }
            else
            {
                if (result == null)
                {
                    Console.Out.WriteLine("Test {0} -- B£¥D, nie znaleziono rozwi¹zania", id);
                    return(false);
                }
                else if (!t.solutions.Contains((Edge)result))
                {
                    Console.Out.WriteLine("Test {0} -- B£¥D, niepoprawne rozwi¹zanie {1}", id, result);
                    return(false);
                }
                else
                {
                    Console.Out.WriteLine("Test {0} -- OK, znaleziono {1}", id, result);
                    return(true);
                }
            }
        }
示例#16
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