using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Msagl.Core;
using Microsoft.Msagl.Core.GraphAlgorithms;
using Microsoft.Msagl.Core.Layout;
namespace Microsoft.Msagl.Layout.MDS {
///
/// Provides functionality for computing distances in a graph.
///
public class SingleSourceDistances : AlgorithmBase {
private GeometryGraph graph;
private Node source;
private bool directed;
///
/// Dijkstra algorithm. Computes graph-theoretic distances from a node to
/// all other nodes in a graph with nonnegative edge lengths.
/// The distance between a node and itself is 0; the distance between a pair of
/// nodes for which no connecting path exists is Double.PositiveInfinity.
///
/// A graph.
/// The source node.
/// Whether the graph is directed.
public SingleSourceDistances(GeometryGraph graph, Node source, bool directed)
{
this.graph = graph;
this.source = source;
this.directed = directed;
}
///
/// An array of distances from the source node to all nodes.
/// Nodes are indexed in their natural order when iterating over them.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is performance critical. Copying the array would be slow.")]
public double[] Result { get; private set; }
///
/// Executes the algorithm.
///
protected override void RunInternal() {
this.StartListenToLocalProgress(graph.Nodes.Count);
Result = new double[graph.Nodes.Count];
var q = new Microsoft.Msagl.Core.DataStructures.GenericBinaryHeapPriorityQueue();
Dictionary d = new Dictionary();
foreach (Node node in graph.Nodes) {
q.Enqueue(node, Double.PositiveInfinity);
d[node] = Double.PositiveInfinity;
}
q.DecreasePriority(source, 0);
while (q.Count>0) {
ProgressStep();
double prio;
Node u = q.Dequeue(out prio);
d[u] = prio;
IEnumerator enumerator;
if (directed)
enumerator = u.OutEdges.GetEnumerator();
else
enumerator = u.Edges.GetEnumerator();
while (enumerator.MoveNext()) {
Edge uv = enumerator.Current;
Node v = uv.Target;
if (u == v)
v = uv.Source;
// relaxation step
if (d[v] > d[u] + uv.Length) {
d[v] = d[u] + uv.Length;
q.DecreasePriority(v, d[v]);
}
}
}
int i = 0;
foreach (Node v in graph.Nodes) {
#if SHARPKIT //https://github.com/SharpKit/SharpKit/issues/7 out keyword not working with arrays
double dummy;
if (!d.TryGetValue(v, out dummy))
dummy = Double.PositiveInfinity;
Result[i] = dummy;
#else
if (!d.TryGetValue(v, out Result[i]))
Result[i] = Double.PositiveInfinity;
#endif
i++;
}
}
/////
///// Computes distances between a selected set of nodes and all nodes.
///// Pivot nodes are selected with maxmin strategy (first at random, later
///// ones to maximize distances to all previously selected ones).
/////
///// A graph.
///// Whether shortest paths are directed.
///// Number of pivots.
///// A square matrix with shortest path distances.
//public static double[][] PivotUniformDistances(GeometryGraph graph, bool directed, int numberOfPivots) {
// double[][] d = new double[numberOfPivots][];
// Node[] nodes = new Node[graph.Nodes.Count];
// graph.Nodes.CopyTo(nodes, 0);
// double[] min = new double[graph.Nodes.Count];
// for (int i = 0; i < min.Length; i++) {
// min[i] = Double.PositiveInfinity;
// }
// System.Console.Write("pivoting ");
// Node pivot = nodes[0];
// for (int i = 0; i < numberOfPivots; i++) {
// System.Console.Write(".");
// d[i] = SingleSourceUniformDistances(graph, pivot, directed);
// int argmax = 0;
// for (int j = 0; j < d[i].Length; j++) {
// min[j] = Math.Min(min[j], d[i][j]);
// if (min[j] > min[argmax])
// argmax = j;
// }
// pivot = nodes[argmax];
// }
// System.Console.WriteLine();
// return d;
//}
/////
///// Determines whether the graph is (weakly) connected, that is,
///// if there is a path connecting every two nodes.
/////
///// A graph.
///// true iff the graph is connected.
//public static bool IsConnected(GeometryGraph graph) {
// IEnumerator enumerator = graph.Nodes.GetEnumerator();
// enumerator.MoveNext();
// Node node=enumerator.Current;
// double[] distances=SingleSourceUniformDistances(graph, node, false);
// for (int i = 0; i < distances.Length; i++) {
// if (distances[i] == Double.PositiveInfinity) return false;
// }
// return true;
//}
}
}