using System;
using System.Collections.Generic;
using System.Linq;
public class Test {
public static void Main()
{
var graph = GenerateGraph(50, 0.4);
var source = graph.Nodes.First();
Console.WriteLine("Nodes: {0}, Edges: {1}", graph.NodeCount, graph.EdgeCount);
BellmanFord(graph, source);
BellmanFordQueue(graph, source);
}
private static IEnumerable<PathFindNode> BellmanFord(Graph graph, Node origin)
{
var nodes = new Dictionary<Node, PathFindNode>();
foreach (var node in graph.Nodes)
{
var pfNode = new PathFindNode(node, null, double.PositiveInfinity);
if (node == origin) pfNode.Distance = 0;
nodes[node] = pfNode;
}
int checks = 0;
int relaxes = 0;
foreach (var node in graph.Nodes)
{
foreach (var edge in graph.Edges)
{
checks++;
var source = nodes[edge.Source];
var destination = nodes[edge.Destination];
if (source.Distance + edge.Weight < destination.Distance)
{
relaxes++;
destination.Distance = source.Distance + edge.Weight;
destination.Predecessor = source;
}
}
}
Console.WriteLine("BF original: {0} checks, {1} relaxes", checks, relaxes);
foreach (var edge in graph.Edges)
{
var source = nodes[edge.Source];
var destination = nodes[edge.Destination];
if (source.Distance + edge.Weight < destination.Distance)
{
throw new Exception("Graph contains a negative-weight cycle");
}
}
return nodes.Values
.OrderBy(pfn => pfn.Node.Index)
.AsEnumerable();
}
private static IEnumerable<PathFindNode> BellmanFordQueue(Graph graph, Node source)
{
var nodes = new Dictionary<Node, PathFindNode>();
foreach (var node in graph.Nodes)
{
var pfNode = new PathFindNode(node, null, double.PositiveInfinity);
if (node == source) pfNode.Distance = 0;
nodes[node] = pfNode;
}
var active = new Queue<PathFindNode>();
active.Enqueue(nodes[source]);
int checks = 0;
int relaxes = 0;
while (active.Count > 0)
{
var node = active.Dequeue();
foreach (var edge in node.Node.Edges)
{
checks++;
var destination = nodes[edge.Destination];
if (node.Distance + edge.Weight < destination.Distance)
{
relaxes++;
destination.Distance = node.Distance + edge.Weight;
destination.Predecessor = node;
active.Enqueue(destination);
}
}
}
Console.WriteLine("BF with queue: {0} checks, {1} relaxes", checks, relaxes);
// Checking for negative-weight cycles does not make sense, since they would
// pull the algorithm into an infinite loop.
return nodes.Values
.OrderBy(pfn => pfn.Node.Index)
.AsEnumerable();
}
private static Random _rnd = new Random();
private static Graph GenerateGraph(int nodeCount, double edgeProbability)
{
var graph = new Graph();
var nodes = Enumerable.Range(0, nodeCount).Select(_ => graph.AddNode()).ToList();
for (int i = 0; i < nodeCount; i++)
for (int j = i + 1; j < nodeCount; j++)
if (_rnd.NextDouble() < edgeProbability)
{
nodes[i].Add(nodes[j], 1 + 99*_rnd.NextDouble());
}
return graph;
}
}
public class PathFindNode
{
public Node Node { get; private set; }
public PathFindNode Predecessor { get; set; }
public double Distance { get; set; }
public PathFindNode(Node node, PathFindNode predecessor = null, double distance = 0)
{
Node = node;
Predecessor = predecessor;
Distance = distance;
}
}
public class Graph
{
private SortedList<int, Edge> _edges = new SortedList<int, Edge>();
public IEnumerable<Edge> Edges { get { return _edges.Values.AsEnumerable(); } }
public int EdgeCount { get { return _edges.Count; } }
private SortedList<int, Node> _nodes = new SortedList<int, Node>();
public IEnumerable<Node> Nodes { get { return _nodes.Values.AsEnumerable(); } }
public int NodeCount { get { return _nodes.Count; } }
public Node AddNode()
{
var node = new Node(this);
_nodes[node.Index] = node;
return node;
}
public Edge AddEdge(Node n1, Node n2, double weight)
{
if (n1.Graph != this || n2.Graph != this || n1 == n2) throw new Exception();
var edge = new Edge(this, n1, n2, weight);
_edges[edge.Index] = edge;
n1.Add(edge);
return edge;
}
}
public class Edge : IEquatable<Edge>
{
private static int _indexCounter = 0;
public int Index { get; private set; }
public Graph Graph { get; private set; }
public Node Source { get; private set; }
public Node Destination { get; private set; }
public double Weight { get; private set; }
public Edge(Graph graph, Node source, Node destination, double weight)
{
Index = _indexCounter++;
Graph = graph;
Source = source;
Destination = destination;
Weight = weight;
}
public bool Equals(Edge other)
{
return other != null && Index == other.Index;
}
public override bool Equals(object other)
{
return Equals(other as Edge);
}
public override int GetHashCode()
{
return Index;
}
}
public class Node : IEquatable<Node>
{
private static int _indexCounter = 0;
public int Index { get; private set; }
private SortedList<int, Edge> _edges = new SortedList<int, Edge>();
public IEnumerable<Edge> Edges { get { return _edges.Values.AsEnumerable(); } }
public Graph Graph { get; private set; }
public Node(Graph graph)
{
Index = _indexCounter++;
Graph = graph;
}
public void Add(Edge edge)
{
if (edge.Source != this || edge.Graph != Graph) throw new ArgumentException("edge");
_edges[edge.Destination.Index] = edge;
}
public Edge Add(Node node, double weight)
{
return Graph.AddEdge(this, node, weight);
}
public bool IsConnectedTo(Node other)
{
return _edges.ContainsKey(other.Index);
}
public bool Equals(Node other)
{
return other != null && Index == other.Index;
}
public override bool Equals(object other)
{
return Equals(other as Node);
}
public override int GetHashCode()
{
return Index;
}
}