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]; } }
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); } } }
/// <inheritdoc/> public bool Equals(Edge?other) { if (other is null) { return(false); } return(A == other.A && B == other.B); }
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()); }
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); }
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); }
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)); }
public bool Equals(Edge?other) { return(other is not null && From.Equals(other.From) && To.Equals(other.To)); }
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); } } }
/// <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