/// <summary> /// Initializes the P array for the algorithm. /// </summary> /// <param name="startingNode"> /// The node that has been designated the starting node for the entire algorithm. /// </param> /// <returns> /// The new P array. /// </returns> /// <remarks> /// A fresh P array will set every single node's source node to be /// the starting node, including the starting node itself. /// </remarks> protected virtual int[] GetStartingBestPath(int startingNode, DijkstraInfo di) { int[] p = new int[TotalNodeCount]; for (int i = 0; i < p.Length; i++) { p[i] = startingNode; } return(p); }
/// <summary> /// Initializes the D array for the start of the algorithm. /// </summary> /// <param name="start"> /// The starting node. /// </param> /// <returns> /// The contents of the new D array. /// </returns> /// <remarks> /// The traversal cost for every node will be set to impossible /// (int.MaxValue) unless a connecting edge is found between the /// <paramref name="start"/>ing node and the node in question. /// </remarks> protected virtual int[] GetStartingTraversalCost(int start, DijkstraInfo di) { int[] subset = new int[TotalNodeCount]; for (int i = 0; i < subset.Length; i++) { subset[i] = int.MaxValue; // all are unreachable } subset[start] = 0; // zero cost from start to start foreach (int nearby in Hint(start, di)) { subset[nearby] = TraversalCost(start, nearby, di); } return(subset); }
private int getInternodeTraversalCost(int start, int finish, DijkstraInfo di) { //TODO: If Dijkstra gets slow //This is sloppy: //(1) It loops through all edges/arrows: could have pointers in the nodes themselves ('parents' and 'children') // Then we could check the start node and see if it points to finish node. (Or make a hashtable of connections) //See also nearbyNodesHint() foreach (EdgeData ed in di.edges) { if (ed.to == start && ed.from == finish) { return(1); } } return(int.MaxValue); }
/// <summary> /// Performs the Dijkstra algorithm on the data provided when the /// <see cref="Dijkstra"/> object was instantiated. /// </summary> /// <param name="start"> /// The node to use as a starting location. /// </param> /// <returns> /// A struct containing both the minimum distance and minimum path /// to every node from the given <paramref name="start"/> node. /// </returns> public virtual Results Perform(int start, DijkstraInfo di) { // Initialize the distance to every node from the starting node. int[] d = GetStartingTraversalCost(start, di); // Initialize best path to every node as from the starting node. int[] p = GetStartingBestPath(start, di); ICollection <int> c = GetChoices(); c.Remove(start); // take starting node out of the list of choices //Debug.WriteLine("Step v C D P"); //Debug.WriteLine(string.Format("init - {{{0}}} [{1}] [{2}]", // ArrayToString<int>(",", c), ArrayToString<int>(",", d), ArrayToString<int>(",", p))); //int step = 0; // begin greedy loop while (c.Count > 1) { // Find element v in c, that minimizes d[v] int v = FindMinimizingDinC(d, c); c.Remove(v); // remove v from the list of future solutions // Consider all unselected nodes and consider their cost from v. foreach (int w in (Hint != null ? Hint(v, di) : c)) { if (!c.Contains(w)) { continue; // discard pixels not in c } // At this point, relative(Index) points to a candidate pixel, // that has not yet been selected, and lies within our area of interest. // Consider whether it is now within closer reach. int cost = TraversalCost(v, w, di); if (cost < int.MaxValue && d[v] + cost < d[w]) // don't let wrap-around negatives slip by { // We have found a better way to get at relative d[w] = d[v] + cost; // record new distance // Record how we came to this new pixel p[w] = v; } } //Debug.WriteLine(string.Format("{4} {3} {{{0}}} [{1}] [{2}]", // ArrayToString<int>(",", c), ArrayToString<int>(",", d), ArrayToString<int>(",", p), v + 1, ++step)); } return(new Results(p, d)); }
private IEnumerable <int> nearbyNodesHint(int startingNode, DijkstraInfo di) { //TODO: If Dijkstra gets slow //This is sloppy in two ways: //(1) It loops through all edges/arrows: could have pointers in the nodes themselves ('parents' and 'children') //(2) It creates a new List<int>. If the above is done, we could just point to the 'children' list. //See also getInternodeTraversalCost() List <int> nearbyNodes = new List <int>(); foreach (EdgeData ed in di.edges) { if (ed.to == startingNode) { nearbyNodes.Add(ed.from); //there should be no dublets in this list } } return(nearbyNodes); }
public DataModel(int iterations, double weightMax, bool firstTime) { if (FruchtermanReingoldLayout.h == null) { return; } // // Populate the data model with some example data. // if (firstTime || FlowGlobals.rectangles == null) { FlowGlobals.rectangles = new ObservableCollection <RectangleData>(); FlowGlobals.arrows = new ObservableCollection <ArrowData>(); } else { FlowGlobals.rectangles.Clear(); FlowGlobals.arrows.Clear(); } ObservableCollection <RectangleData> rectangles = FlowGlobals.rectangles; ObservableCollection <ArrowData> arrows = FlowGlobals.arrows; double width = 90; double height = 70; Random r = new Random(12345); r = new Random(54321); r = new Random(11111); List <EdgeData> edges = new List <EdgeData>(); List <NodeData> nodes = new List <NodeData>(); NodeData startNode = null; foreach (FlowArrow fa in FruchtermanReingoldLayout.h.flowArrows) { if (!double.IsNaN(weightMax) && Math.Abs(fa.weight) < weightMax) { continue; } EdgeData ed = new EdgeData { from = fa.counter1, to = fa.counter2, weight = fa.weight }; edges.Add(ed); } foreach (FlowNode fa in FruchtermanReingoldLayout.h.flowNodes) { NodeData nd = new NodeData { x = r.Next((int)(0.005d * contentWidth), (int)contentWidth), y = r.Next((int)(0.005d * contentWidth), (int)contentWidth), name = fa.varName, labelBig = fa.labelBig, isExogenous = fa.isExogenous, isStartNode = fa.isStartNode, id = fa.id }; nodes.Add(nd); if (nd.isStartNode) { startNode = nd; } } Dictionary <int, NodeData> d = new Dictionary <int, NodeData>(); foreach (NodeData nd in nodes) { d.Add(nd.id, nd); } //TODO: The Dijkstra algorithm is a bit sloppy, for instance using List<int> and removing items from this list (use Dictionary instead) DijkstraInfo di = new DijkstraInfo(); di.nodes = nodes; di.edges = edges; Dijkstra dijkstra = new Dijkstra(nodes.Count, new Dijkstra.InternodeTraversalCost(getInternodeTraversalCost), new Dijkstra.NearbyNodesHint(nearbyNodesHint), di); Dijkstra.Results results = dijkstra.Perform(startNode.id, di); //int[] minimumPath = dijkstra.GetMinimumPath(0, 102, di); //Now we filter out List <EdgeData> edges2 = new List <EdgeData>(); List <NodeData> nodes2 = new List <NodeData>(); int large = 1000000000; Dictionary <int, int> rename = new Dictionary <int, int>(); foreach (NodeData nd in nodes) { int value = results.MinimumDistance[nd.id]; if (value < 0) { value = large; //do not minus it: -int.MinValue gives a strange result! } if (value < large) //it seems these distances can become = int.MinValue, maybe int.MaxValue+1. So this is to identify those. { int number = nodes2.Count; rename.Add(nd.id, number); nd.id = number; //now id numbers in List 'nodes' are inconsistent, but never mind that nodes2.Add(nd); } } foreach (EdgeData ed in edges) { if (rename.ContainsKey(ed.from) && rename.ContainsKey(ed.to)) { ed.from = rename[ed.from]; ed.to = rename[ed.to]; edges2.Add(ed); //now id numbers in List 'edges' are inconsistent, but never mind that } } SolveInfo si = new SolveInfo(); si.width = width; si.height = height; si.rectangles = rectangles; si.arrows = arrows; si.edges = edges2; si.nodes = nodes2; si.iterations = iterations; if (si.iterations == -12345) { si.iterations = 200; } si.useSmartRepulse = true; si.useWeight = true; FruchtermanReingoldLayout.Solve(si); }
/// <summary> /// Creates an instance of the <see cref="Dijkstra"/> class. /// </summary> /// <param name="totalNodeCount"> /// The total number of nodes in the graph. /// </param> /// <param name="traversalCost"> /// The delegate that can provide the cost of a transition between /// any two nodes. /// </param> /// <param name="hint"> /// An optional delegate that can provide a small subset of nodes /// that a given node may be connected to. /// </param> public Dijkstra(int totalNodeCount, InternodeTraversalCost traversalCost, NearbyNodesHint hint, DijkstraInfo di) { if (totalNodeCount < 3) { throw new ArgumentOutOfRangeException("totalNodeCount", totalNodeCount, "Expected a minimum of 3."); } if (traversalCost == null) { throw new ArgumentNullException("traversalCost"); } Hint = hint; TraversalCost = traversalCost; TotalNodeCount = totalNodeCount; }
/// <summary> /// Finds an array of nodes that provide the shortest path /// from one given node to another. /// </summary> /// <param name="start"> /// The starting node. /// </param> /// <param name="finish"> /// The finishing node. /// </param> /// <param name="shortestPath"> /// The P array of the completed algorithm. /// </param> /// <returns> /// The list of nodes that provide the one step at a time path /// from <paramref name="start"/> to <paramref name="finish"/> nodes. /// </returns> protected virtual int[] GetMinimumPath(int start, int finish, int[] shortestPath, DijkstraInfo di) { Stack <int> path = new Stack <int>(); do { path.Push(finish); finish = shortestPath[finish]; // step back one step toward the start point }while (finish != start); return(path.ToArray()); }
/// <summary> /// Uses the Dijkstra algorithhm to find the minimum path /// from one node to another. /// </summary> /// <param name="start"> /// The node to use as a starting location. /// </param> /// <param name="finish"> /// The node to use as a finishing location. /// </param> /// <returns> /// A struct containing both the minimum distance and minimum path /// to every node from the given <paramref name="start"/> node. /// </returns> public virtual int[] GetMinimumPath(int start, int finish, DijkstraInfo di) { Results results = Perform(start, di); return(GetMinimumPath(start, finish, results.MinimumPath, di)); }