private void FinishedReset(DijkstraNode current, DijkstraNode prev) { if (hitTarget(current)) { foreach (var tentative in _tentative) { tentative.Reset(); } _tentative.Clear(); if (_cont && _visualise && prev != null) { if (_text) { Say("A route to the target was found. The algorithm is finished"); } current.Reset(); } } else { if (_cont && _visualise && prev != null) { if (_text) { Say("There are no more nodes in the tentative list. The algorithm is finished"); } prev.Reset(); } } }
/// <summary> /// Check a neighbour of the current node to see if it needs to be added to the tentative list /// or the shortest route to it needs to be updated. /// </summary> /// <param name="neighbour">The neighbour to check.</param> /// <param name="current">The current node.</param> /// <param name="dist">The distance from the root to the current node.</param> /// <param name="link">The link between current and neighbour.</param> private void checkNeighbour(DijkstraNode neighbour, DijkstraNode current, float dist, IMLink link) { float newDistance = dist + link.Weight; try { //If the new route from root to neighbour is shorter than the old route or there was no old route //set the current node as the first step towards the root from neighbour if (_cont && !_tentative.Contains(neighbour)) { _tentative.AddFirst(neighbour); neighbour.SetDistanceFromRoot(ID, newDistance, current, link); } else if (_cont && newDistance <= neighbour.GetDistanceFromRoot(ID)) { neighbour.SetDistanceFromRoot(ID, newDistance, current, link); } } catch (KeyNotFoundException e) { //If the AddLink being checked is no Keyer in the list of links the algorithm needs to stop _cont = false; if (_visualise) { VisualisedNode = null; } Logger.Debug("Trying to work with a neighbour (" + neighbour.Name + ") which is not actually connected to " + current.Name + " (root = " + Name + ")"); } //Incase another thread has modified the distance if (_cont && newDistance < neighbour.GetDistanceFromRoot(ID)) { neighbour.SetDistanceFromRoot(ID, newDistance, neighbour, link); } }
/// <summary> /// Once the algorithm has finished use the information it has stored to update the routing table. /// </summary> private void UpdateRoutingTable() { IKeyTable <IMLink> oldTable = ForwardingTable; foreach (DijkstraNode target in _confirmed) { if (target.ID != ID) { //Work backwards along the route, starting at the target, until the first hop is found DijkstraNode prev = target; while (prev != null && !Equals(prev.GetPrev(ID))) { prev = prev.GetPrev(ID); } if (prev != null && Links.ContainsKey(prev.ID)) { IMLink l = Links[prev.ID]; SetRoute(Algorithm, target.ID, l, target.GetDistanceFromRoot(ID)); oldTable.Remove(target.ID); } } } //Trigger events for any nodes that can no longer be routed to foreach (IMNodeInternal n in KnownNodes) { if (oldTable.ContainsKey(n.ID)) { RemoveRoute(Algorithm, n.ID); } } }
//public override event ForwardingTableChangeDelegate OnRouteChange; public override void Stop() { if (_visualise && Equals(VisualisedNode)) { ResetAlgorithm(); _visualise = false; _text = false; VisualisedNode = null; RunAlgorithm(Name + " visualisation stopped. Re-running algorithm silently.", null, false); } }
/// <summary> /// Check whether the target to be routed to has been found. /// </summary> /// <param name="current">The current node.</param> /// <returns>True if the current node is the target node.</returns> private bool hitTarget(DijkstraNode current) { if (!_cont || _target == null) { return(false); } if (_cont && _text && _visualise && current.ID == _target.ID) { Say("Found the shortest route to target " + _target.Name); } return(current.ID == _target.ID); }
/// <summary> /// The main loop which is the body of the algorithm. /// Loops through every neighbour of the current node checking to see if they: /// A. Have been visited before /// B. Have been visited before but are now a shorter route /// </summary> /// <param name="current">The node currently being checked.</param> /// <param name="prev">The previous node that was checked.</param> /// <returns>The last node to be checked.</returns> private void MainLoop(DijkstraNode current, DijkstraNode prev) { while (_cont && current != null && !hitTarget(current)) { //If necessary display text and wait if (_cont && _text && _visualise) { current.Say("4. Iterating through neighbours excluding neighbours in Confirmed"); Pause(); } //Get the current distance to the target float dist = current.GetDistanceFromRoot(ID); foreach (var n in current.Neighbours) { IMLink link = current.Links[n.ID]; if (_visualise) { _links.AddFirst(link); } var neighbour = this.GetAlgNode <DijkstraNode>(n.ID); if (_cont && !_confirmed.Contains(neighbour)) { if (_visualise && _text) { VisualiseCheckNeighbourText(neighbour, current, dist, link); } else if (_visualise) { VisualiseCheckNeighbour(neighbour, current, dist, link); } checkNeighbour(neighbour, current, dist, link); } if (!_cont) { break; } } //Store the old previous node prev = current; if (_cont && _text && _visualise) { Say("Finished iterating through current's (" + current.Name + "'s) neighbours, getting next current from tentative list"); Pause(); } //Get the next node to be checked (the one which has the shortest path to it) current = getNext(current); } FinishedReset(current, prev); }
/// <summary> /// Visualise the process of choosing the next node. Will output text about what is going on if necessary. /// </summary> /// <param name="next">The next node to be current.</param> /// <param name="prev">The node that was previously current.</param> private void VisualiseChooseNext(DijkstraNode next, DijkstraNode prev) { if (_cont && !next.Equals(this)) { if (_cont && _text) { Say("8. There are nodes in the tentative list. Finding the node in tentative with the smallest cost"); Pause(); } Pause(3f); if (_cont && _text) { Say("9. new current = " + next.Name + " with cost " + next.GetDistanceFromRoot(ID)); Pause(); Say("10. Adding link between ct (" + prev.Name + ") and new current (" + next.Name + ") to the shortest path"); Pause(); } } prev.Reset(); IMLink confirmedLink = next.GetWIPRoute(ID); if (_cont && confirmedLink != null) { Pause(6f); confirmedLink.Colour = Color.Red; } if (_cont && _text) { Say((next.Equals(this) ? "2a" : "11a") + ". Adding " + (next.Equals(this) ? "root" : "new current") + " (" + next.Name + ") to Confirmed"); Pause(); Say((next.Equals(this) ? "2b" : "11b") + ". Setting current to " + (next.Equals(this) ? "root" : "new current") + " (" + next.Name + ")"); } next.Reset(); next.Selected = currentGlow; next.Colour = Color.White; if (_cont && _text && !next.Equals(this)) { Pause(); Say("11c. Going to step 4"); Pause(); } }
/// <summary> /// Get the next node to be checked. Next node is the node in the tentative list which is closest to the root. /// </summary> /// <param name="prev">The node that was previously checked.</param> /// <returns>The new current node.</returns> private DijkstraNode getNext(DijkstraNode prev) { if (_cont && _tentative.Count > 0) { DijkstraNode next = _tentative.OrderBy(node => node.GetDistanceFromRoot(ID)).First(); if (!_cont) { return(null); } _tentative.Remove(next); _confirmed.AddLast(next); if (_cont && _visualise) { VisualiseChooseNext(next, prev); } return(next); } return(null); }
public override void VisualiseAlgorithm(UUID to, Parameters parameters) { if (Equals(VisualisedNode)) { ResetAlgorithm(); _visualise = false; VisualisedNode = null; return; } else if (VisualisedNode != null) { VisualisedNode.Stop(); } IMNodeInternal target = KnownNodes.ContainsKey(to) ? KnownNodes[to] : null; _text = Dijkstra.AlwaysPrint || (Dijkstra.EverPrint && parameters != null && parameters.Get <bool>("Text")); VisualisedNode = this; RunAlgorithm("Visualise Dijkstra's Algorithm", target, true); }
internal void SetDistanceFromRoot(UUID root, float value, DijkstraNode prevNode, IMLink link) { //if (prevNode != null/* && !Links.ContainsKey(prevNode.ID)*/) // return; lock (_distances) { if (_distances.ContainsKey(root)) { _distances[root] = value; _prev[root] = prevNode; } else { _distances.Add(root, value); _prev.Add(root, prevNode); } } if (prevNode != null) { SetWIPRoute(root, link); } }
private void RunAlgorithm(IMNodeInternal to) { lock (_runLock) { Init(to); if (_visualise) { Logger.Debug("Dijkstra visualising routing from " + Name); } if (_cont && _text && _visualise) { Say("Starting Algorithm"); Say("1. Initialising Confirmed and Tentative lists"); } DijkstraNode current = getNext(this); DijkstraNode prev = current; if (_cont && _text && _visualise) { Pause(); Say("3. Cost for root (" + Node.Name + ") = 0"); Pause(); } MainLoop(current, prev); //If the algorithm didn't finish prematurely if (_cont) { UpdateRoutingTable(); } algorithmFinished(); } }
/// <summary> /// Visualises the process of checking a neighbour node. /// </summary> /// <param name="neighbour">The neighbour to check.</param> /// <param name="current">The current node.</param> /// <param name="dist">The distance from the root to the current node.</param> /// <param name="link">The link between current and neighbour.</param> private void VisualiseCheckNeighbour(DijkstraNode neighbour, DijkstraNode current, float dist, IMLink link) { if (!_visualise) { return; } if (_cont) { Pause(4f); link.Colour = Color.Blue; Pause(6); } try { if (_cont && !_tentative.Contains(neighbour)) { neighbour.Selected = tentativeGlow; Pause(6); } } catch (KeyNotFoundException e) { //If the AddLink being checked is no Keyer in the list of links the algorithm needs to stop _cont = false; if (_visualise) { VisualisedNode = null; } Logger.Debug("Trying to work with a neighbour (" + neighbour.Name + ") which is not actually connected to " + current.Name + " (root = " + Name + ")"); } if (_cont) { link.Colour = Color.White; } }
/// <summary> /// Check whether the target to be routed to has been found. /// </summary> /// <param name="current">The current node.</param> /// <returns>True if the current node is the target node.</returns> private bool hitTarget(DijkstraNode current) { if (!_cont || _target == null) return false; if (_cont && _text && _visualise && current.ID == _target.ID) Say("Found the shortest route to target " + _target.Name); return current.ID == _target.ID; }
/// <summary> /// Get the next node to be checked. Next node is the node in the tentative list which is closest to the root. /// </summary> /// <param name="prev">The node that was previously checked.</param> /// <returns>The new current node.</returns> private DijkstraNode getNext(DijkstraNode prev) { if (_cont && _tentative.Count > 0) { DijkstraNode next = _tentative.OrderBy(node => node.GetDistanceFromRoot(ID)).First(); if (!_cont) return null; _tentative.Remove(next); _confirmed.AddLast(next); if (_cont && _visualise) VisualiseChooseNext(next, prev); return next; } return null; }
private void FinishedReset(DijkstraNode current, DijkstraNode prev) { if (hitTarget(current)) { foreach (var tentative in _tentative) tentative.Reset(); _tentative.Clear(); if (_cont && _visualise && prev != null) { if (_text) Say("A route to the target was found. The algorithm is finished"); current.Reset(); } } else { if (_cont && _visualise && prev != null) { if (_text) Say("There are no more nodes in the tentative list. The algorithm is finished"); prev.Reset(); } } }
/// <summary> /// Check a neighbour of the current node to see if it needs to be added to the tentative list /// or the shortest route to it needs to be updated. /// </summary> /// <param name="neighbour">The neighbour to check.</param> /// <param name="current">The current node.</param> /// <param name="dist">The distance from the root to the current node.</param> /// <param name="link">The link between current and neighbour.</param> private void checkNeighbour(DijkstraNode neighbour, DijkstraNode current, float dist, IMLink link) { float newDistance = dist + link.Weight; try { //If the new route from root to neighbour is shorter than the old route or there was no old route //set the current node as the first step towards the root from neighbour if (_cont && !_tentative.Contains(neighbour)) { _tentative.AddFirst(neighbour); neighbour.SetDistanceFromRoot(ID, newDistance, current, link); } else if (_cont && newDistance <= neighbour.GetDistanceFromRoot(ID)) neighbour.SetDistanceFromRoot(ID, newDistance, current, link); } catch (KeyNotFoundException e) { //If the AddLink being checked is no Keyer in the list of links the algorithm needs to stop _cont = false; if (_visualise) VisualisedNode = null; Logger.Debug("Trying to work with a neighbour (" + neighbour.Name + ") which is not actually connected to " + current.Name + " (root = " + Name + ")"); } //Incase another thread has modified the distance if (_cont && newDistance < neighbour.GetDistanceFromRoot(ID)) neighbour.SetDistanceFromRoot(ID, newDistance, neighbour, link); }
internal void SetDistanceFromRoot(UUID root, float value, DijkstraNode prevNode, IMLink link) { //if (prevNode != null/* && !Links.ContainsKey(prevNode.ID)*/) // return; lock (_distances) { if (_distances.ContainsKey(root)) { _distances[root] = value; _prev[root] = prevNode; } else { _distances.Add(root, value); _prev.Add(root, prevNode); } } if (prevNode != null) SetWIPRoute(root, link); }
/// <summary> /// Visualises the process of checking a neighbour node and prints out text explaining what is happening. /// </summary> /// <param name="neighbour">The neighbour to check.</param> /// <param name="current">The current node.</param> /// <param name="dist">The distance from the root to the current node.</param> /// <param name="link">The link between current and neighbour.</param> private void VisualiseCheckNeighbourText(DijkstraNode neighbour, DijkstraNode current, float dist, IMLink link) { if (!_visualise && !_text) return; float newDistance = dist + link.Weight; if (_cont) { //if (_cont && _text) // current.Say("Examining neighbour " + neighbour.Name); Pause(4f); link.Colour = Color.Blue; if (_cont && _text) { Pause(); current.Say("5. Test cost to " + neighbour.Name + " = " + dist + " + " + link.Weight + " = " + newDistance); Pause(); } Pause(4f); } try { if (_cont && !_tentative.Contains(neighbour)) { if (_cont && _text) current.Say(neighbour.Name + " is not in tentative list"); _tentative.AddFirst(neighbour); neighbour.SetDistanceFromRoot(ID, newDistance, current, link); if (_cont) { Pause(4f); neighbour.Selected = tentativeGlow; if (_cont && _text) { current.Say("6a. Adding " + neighbour.Name + " to the tentative list"); Pause(); current.Say("6b. " + neighbour.Name + ".cost = test cost (" + newDistance + ")"); } } } //If the new route from root to neighbour is shorter than the old route or there was no old route //set the current node as the first step towards the root from neighbour else if (_cont && newDistance <= neighbour.GetDistanceFromRoot(ID)) { neighbour.SetDistanceFromRoot(ID, newDistance, current, link); if (_cont && _text) { current.Say(neighbour.Name + ".cost (" + neighbour.GetDistanceFromRoot(ID) + ") > test cost (" + newDistance + ")"); Pause(); current.Say("7. " + neighbour.Name + ".cost = test cost (" + newDistance + ")"); Pause(); } } } catch (KeyNotFoundException e) { //If the AddLink being checked is no Keyer in the list of links the algorithm needs to stop _cont = false; if (_visualise) VisualisedNode = null; Logger.Debug("Trying to work with a neighbour (" + neighbour.Name + ") which is not actually connected to " + current.Name + " (root = " + Name + ")"); } if (_cont && newDistance < neighbour.GetDistanceFromRoot(ID)) neighbour.SetDistanceFromRoot(ID, newDistance, neighbour, link); if (_cont) { Pause(4f); link.Colour = Color.White; Pause(6f); } }
/// <summary> /// Visualises the process of checking a neighbour node and prints out text explaining what is happening. /// </summary> /// <param name="neighbour">The neighbour to check.</param> /// <param name="current">The current node.</param> /// <param name="dist">The distance from the root to the current node.</param> /// <param name="link">The link between current and neighbour.</param> private void VisualiseCheckNeighbourText(DijkstraNode neighbour, DijkstraNode current, float dist, IMLink link) { if (!_visualise && !_text) { return; } float newDistance = dist + link.Weight; if (_cont) { //if (_cont && _text) // current.Say("Examining neighbour " + neighbour.Name); Pause(4f); link.Colour = Color.Blue; if (_cont && _text) { Pause(); current.Say("5. Test cost to " + neighbour.Name + " = " + dist + " + " + link.Weight + " = " + newDistance); Pause(); } Pause(4f); } try { if (_cont && !_tentative.Contains(neighbour)) { if (_cont && _text) { current.Say(neighbour.Name + " is not in tentative list"); } _tentative.AddFirst(neighbour); neighbour.SetDistanceFromRoot(ID, newDistance, current, link); if (_cont) { Pause(4f); neighbour.Selected = tentativeGlow; if (_cont && _text) { current.Say("6a. Adding " + neighbour.Name + " to the tentative list"); Pause(); current.Say("6b. " + neighbour.Name + ".cost = test cost (" + newDistance + ")"); } } } //If the new route from root to neighbour is shorter than the old route or there was no old route //set the current node as the first step towards the root from neighbour else if (_cont && newDistance <= neighbour.GetDistanceFromRoot(ID)) { neighbour.SetDistanceFromRoot(ID, newDistance, current, link); if (_cont && _text) { current.Say(neighbour.Name + ".cost (" + neighbour.GetDistanceFromRoot(ID) + ") > test cost (" + newDistance + ")"); Pause(); current.Say("7. " + neighbour.Name + ".cost = test cost (" + newDistance + ")"); Pause(); } } } catch (KeyNotFoundException e) { //If the AddLink being checked is no Keyer in the list of links the algorithm needs to stop _cont = false; if (_visualise) { VisualisedNode = null; } Logger.Debug("Trying to work with a neighbour (" + neighbour.Name + ") which is not actually connected to " + current.Name + " (root = " + Name + ")"); } if (_cont && newDistance < neighbour.GetDistanceFromRoot(ID)) { neighbour.SetDistanceFromRoot(ID, newDistance, neighbour, link); } if (_cont) { Pause(4f); link.Colour = Color.White; Pause(6f); } }
/// <summary> /// The main loop which is the body of the algorithm. /// Loops through every neighbour of the current node checking to see if they: /// A. Have been visited before /// B. Have been visited before but are now a shorter route /// </summary> /// <param name="current">The node currently being checked.</param> /// <param name="prev">The previous node that was checked.</param> /// <returns>The last node to be checked.</returns> private void MainLoop(DijkstraNode current, DijkstraNode prev) { while (_cont && current != null && !hitTarget(current)) { //If necessary display text and wait if (_cont && _text && _visualise) { current.Say("4. Iterating through neighbours excluding neighbours in Confirmed"); Pause(); } //Get the current distance to the target float dist = current.GetDistanceFromRoot(ID); foreach (var n in current.Neighbours) { IMLink link = current.Links[n.ID]; if (_visualise) _links.AddFirst(link); var neighbour = this.GetAlgNode<DijkstraNode>(n.ID); if (_cont && !_confirmed.Contains(neighbour)) { if (_visualise && _text) VisualiseCheckNeighbourText(neighbour, current, dist, link); else if (_visualise) VisualiseCheckNeighbour(neighbour, current, dist, link); checkNeighbour(neighbour, current, dist, link); } if (!_cont) break; } //Store the old previous node prev = current; if (_cont && _text && _visualise) { Say("Finished iterating through current's (" + current.Name + "'s) neighbours, getting next current from tentative list"); Pause(); } //Get the next node to be checked (the one which has the shortest path to it) current = getNext(current); } FinishedReset(current, prev); }
/// <summary> /// Visualises the process of checking a neighbour node. /// </summary> /// <param name="neighbour">The neighbour to check.</param> /// <param name="current">The current node.</param> /// <param name="dist">The distance from the root to the current node.</param> /// <param name="link">The link between current and neighbour.</param> private void VisualiseCheckNeighbour(DijkstraNode neighbour, DijkstraNode current, float dist, IMLink link) { if (!_visualise) return; if (_cont) { Pause(4f); link.Colour = Color.Blue; Pause(6); } try { if (_cont && !_tentative.Contains(neighbour)) { neighbour.Selected = tentativeGlow; Pause(6); } } catch (KeyNotFoundException e) { //If the AddLink being checked is no Keyer in the list of links the algorithm needs to stop _cont = false; if (_visualise) VisualisedNode = null; Logger.Debug("Trying to work with a neighbour (" + neighbour.Name + ") which is not actually connected to " + current.Name + " (root = " + Name + ")"); } if (_cont) link.Colour = Color.White; }
//public override event ForwardingTableChangeDelegate OnRouteChange; public override void Stop() { if (_visualise && Equals(VisualisedNode)) { ResetAlgorithm(); _visualise = false; _text = false; VisualisedNode = null; RunAlgorithm(Name + " visualisation stopped. Re-running algorithm silently.", null, false); } }
/// <summary> /// Visualise the process of choosing the next node. Will output text about what is going on if necessary. /// </summary> /// <param name="next">The next node to be current.</param> /// <param name="prev">The node that was previously current.</param> private void VisualiseChooseNext(DijkstraNode next, DijkstraNode prev) { if (_cont && !next.Equals(this)) { if (_cont && _text) { Say("8. There are nodes in the tentative list. Finding the node in tentative with the smallest cost"); Pause(); } Pause(3f); if (_cont && _text) { Say("9. new current = " + next.Name + " with cost " + next.GetDistanceFromRoot(ID)); Pause(); Say("10. Adding link between ct (" + prev.Name + ") and new current (" + next.Name + ") to the shortest path"); Pause(); } } prev.Reset(); IMLink confirmedLink = next.GetWIPRoute(ID); if (_cont && confirmedLink != null) { Pause(6f); confirmedLink.Colour = Color.Red; } if (_cont && _text) { Say((next.Equals(this) ? "2a" : "11a") + ". Adding " + (next.Equals(this) ? "root" : "new current") + " (" + next.Name + ") to Confirmed"); Pause(); Say((next.Equals(this) ? "2b" : "11b") + ". Setting current to " + (next.Equals(this) ? "root" : "new current") + " (" + next.Name + ")"); } next.Reset(); next.Selected = currentGlow; next.Colour = Color.White; if (_cont && _text && !next.Equals(this)) { Pause(); Say("11c. Going to step 4"); Pause(); } }
public override void VisualiseAlgorithm(UUID to, Parameters parameters) { if (Equals(VisualisedNode)) { ResetAlgorithm(); _visualise = false; VisualisedNode = null; return; } else if (VisualisedNode != null) VisualisedNode.Stop(); IMNodeInternal target = KnownNodes.ContainsKey(to) ? KnownNodes[to] : null; _text = Dijkstra.AlwaysPrint || (Dijkstra.EverPrint && parameters != null && parameters.Get<bool>("Text")); VisualisedNode = this; RunAlgorithm("Visualise Dijkstra's Algorithm", target, true); }