private readonly DirectedEdge[] _edgeTo; // edgeTo[v] = last edge on shortest s->v path /// <summary> /// Computes a shortest paths tree from <tt>s</tt> to every other vertex in /// the directed acyclic graph <tt>G</tt>. /// </summary> /// <param name="g">g the acyclic digraph</param> /// <param name="s">s the source vertex</param> /// <exception cref="ArgumentException">if the digraph is not acyclic</exception> /// <exception cref="ArgumentException">unless 0 <= <tt>s</tt> <= <tt>V</tt> - 1</exception> public AcyclicSP(EdgeWeightedDigraph g, int s) { _distTo = new double[g.V]; _edgeTo = new DirectedEdge[g.V]; for (var v = 0; v < g.V; v++) { _distTo[v] = double.PositiveInfinity; } _distTo[s] = 0.0; // visit vertices in toplogical order var topological = new Topological(g); if (!topological.HasOrder()) { throw new ArgumentException("Digraph is not acyclic."); } foreach (int v in topological.Order()) { foreach (var e in g.Adj(v)) { Relax(e); } } }
/// <summary> /// certify that digraph is either acyclic or has a directed cycle /// </summary> /// <param name="g"></param> /// <returns></returns> public bool Check(EdgeWeightedDigraph g) { // edge-weighted digraph is cyclic if (HasCycle()) { // verify cycle DirectedEdge first = null, last = null; foreach (var e in Cycle()) { if (first == null) first = e; if (last != null) { if (last.To() != e.From()) { Console.Error.WriteLine($"cycle edges {last} and {e} not incident{Environment.NewLine}"); return false; } } last = e; } if (last != null && last.To() != first.From()) { Console.Error.WriteLine($"cycle edges {last} and {first} not incident{Environment.NewLine}"); return false; } } return true; }
private readonly IndexMinPQ<Double> _pq; // priority queue of vertices #endregion Fields #region Constructors /// <summary> /// Computes a shortest-paths tree from the source vertex <tt>s</tt> to every other /// vertex in the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted digraph</param> /// <param name="s">s the source vertex</param> /// <exception cref="ArgumentException">if an edge weight is negative</exception> /// <exception cref="ArgumentException">unless 0 <= <tt>s</tt> <= <tt>V</tt> - 1</exception> public DijkstraSP(EdgeWeightedDigraph g, int s) { foreach (var e in g.Edges()) { if (e.Weight < 0) throw new ArgumentException($"edge {e} has negative weight"); } _distTo = new double[g.V]; _edgeTo = new DirectedEdge[g.V]; for (var v = 0; v < g.V; v++) _distTo[v] = double.PositiveInfinity; _distTo[s] = 0.0; // relax vertices in order of distance from s _pq = new IndexMinPQ<Double>(g.V); _pq.Insert(s, _distTo[s]); while (!_pq.IsEmpty()) { var v = _pq.DelMin(); foreach (var e in g.Adj(v)) Relax(e); } // check optimality conditions //assert check(G, s); }
/// <summary> /// Computes a shortest paths tree from each vertex to to every other vertex in /// the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">G the edge-weighted digraph</param> /// <exception cref="ArgumentException">if an edge weight is negative</exception> /// <exception cref="ArgumentException">unless 0 <= <tt>s</tt> <= <tt>V</tt> - 1</exception> public DijkstraAllPairsSP(EdgeWeightedDigraph g) { _all = new DijkstraSP[g.V]; for (var v = 0; v < g.V; v++) { _all[v] = new DijkstraSP(g, v); } }
/// <summary> /// Determines whether the edge-weighted digraph <tt>G</tt> has a topological /// order and, if so, finds such an order. /// </summary> /// <param name="g">g the edge-weighted digraph</param> public Topological(EdgeWeightedDigraph g) { var finder = new EdgeWeightedDirectedCycle(g); if (!finder.HasCycle()) { var dfs = new DepthFirstOrder(g); _order = dfs.ReversePost(); } }
/// <summary> /// Determines a depth-first order for the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted digraph</param> public DepthFirstOrder(EdgeWeightedDigraph g) { _pre = new int[g.V]; _post = new int[g.V]; _postorder = new Collections.Queue<Integer>(); _preorder = new Collections.Queue<Integer>(); _marked = new bool[g.V]; for (var v = 0; v < g.V; v++) if (!_marked[v]) Dfs(g, v); }
private Collections.Stack<DirectedEdge> _cycle; // directed cycle (or null if no such cycle) #endregion Fields #region Constructors /// <summary> /// Determines whether the edge-weighted digraph <tt>G</tt> has a directed cycle and, /// if so, finds such a cycle. /// </summary> /// <param name="g">g the edge-weighted digraph</param> public EdgeWeightedDirectedCycle(EdgeWeightedDigraph g) { _marked = new bool[g.V]; _onStack = new bool[g.V]; _edgeTo = new DirectedEdge[g.V]; for (var v = 0; v < g.V; v++) if (!_marked[v]) Dfs(g, v); // check that digraph has a cycle //assert check(G); }
public void Run() { // create random DAG with V vertices and E edges; then add F random edges const int vv = 50; const int e = 100; const int f = 20; var digraph = new EdgeWeightedDigraph(vv); var vertices = new int[vv]; for (var i = 0; i < vv; i++) vertices[i] = i; StdRandom.Shuffle(vertices); for (var i = 0; i < e; i++) { int v, w; do { v = StdRandom.Uniform(vv); w = StdRandom.Uniform(vv); } while (v >= w); var weight = StdRandom.Uniform(); digraph.AddEdge(new DirectedEdge(v, w, weight)); } // add F extra edges for (var i = 0; i < f; i++) { var v = StdRandom.Uniform(vv); var w = StdRandom.Uniform(vv); var weight = StdRandom.Uniform(0.0, 1.0); digraph.AddEdge(new DirectedEdge(v, w, weight)); } Console.WriteLine(digraph); // find a directed cycle var finder = new EdgeWeightedDirectedCycle(digraph); if (finder.HasCycle()) { Console.Write("Cycle: "); foreach (var edge in finder.Cycle()) { Console.Write(edge + " "); } Console.WriteLine(); } // or give topologial sort else { Console.WriteLine("No directed cycle"); } Console.ReadLine(); }
/// <summary> /// check optimality conditions: /// (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight() /// (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight() /// </summary> /// <param name="g"></param> /// <param name="s"></param> /// <returns></returns> public bool Check(EdgeWeightedDigraph g, int s) { // check that edge weights are nonnegative if (g.Edges().Any(e => e.Weight < 0)) { Console.Error.WriteLine("negative edge weight detected"); return false; } // check that distTo[v] and edgeTo[v] are consistent if (Math.Abs(_distTo[s]) > 1E12 || _edgeTo[s] != null) { Console.Error.WriteLine("distTo[s] and edgeTo[s] inconsistent"); return false; } for (var v = 0; v < g.V; v++) { if (v == s) continue; if (_edgeTo[v] == null && !double.IsPositiveInfinity(_distTo[v])) { Console.Error.WriteLine("distTo[] and edgeTo[] inconsistent"); return false; } } // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { int w = e.To(); if (_distTo[v] + e.Weight < _distTo[w]) { Console.Error.WriteLine($"edge {e} not relaxed"); return false; } } } // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (var w = 0; w < g.V; w++) { if (_edgeTo[w] == null) continue; var e = _edgeTo[w]; var v = e.From(); if (w != e.To()) return false; if (Math.Abs(_distTo[v] + e.Weight - _distTo[w]) > 1E12) { Console.Error.WriteLine($"edge {e} on shortest path not tight"); return false; } } return true; }
/// <summary> /// Determines a depth-first order for the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted digraph</param> public DepthFirstOrder(EdgeWeightedDigraph g) { _pre = new int[g.V]; _post = new int[g.V]; _postorder = new Collections.Queue <Integer>(); _preorder = new Collections.Queue <Integer>(); _marked = new bool[g.V]; for (var v = 0; v < g.V; v++) { if (!_marked[v]) { Dfs(g, v); } } }
private Collections.Stack <DirectedEdge> _cycle; // directed cycle (or null if no such cycle) /// <summary> /// Determines whether the edge-weighted digraph <tt>G</tt> has a directed cycle and, /// if so, finds such a cycle. /// </summary> /// <param name="g">g the edge-weighted digraph</param> public EdgeWeightedDirectedCycle(EdgeWeightedDigraph g) { _marked = new bool[g.V]; _onStack = new bool[g.V]; _edgeTo = new DirectedEdge[g.V]; for (var v = 0; v < g.V; v++) { if (!_marked[v]) { Dfs(g, v); } } // check that digraph has a cycle //assert check(G); }
/// <summary> /// run DFS in edge-weighted digraph G from vertex v and compute preorder/postorder /// </summary> /// <param name="g"></param> /// <param name="v"></param> private void Dfs(EdgeWeightedDigraph g, int v) { _marked[v] = true; _pre[v] = _preCounter++; _preorder.Enqueue(v); foreach (var e in g.Adj(v)) { var w = e.To(); if (!_marked[w]) { Dfs(g, w); } } _postorder.Enqueue(v); _post[v] = _postCounter++; }
// by finding a cycle in predecessor graph private void FindNegativeCycle() { var vv = _edgeTo.Length; var spt = new EdgeWeightedDigraph(vv); for (var v = 0; v < vv; v++) { if (_edgeTo[v] != null) { spt.AddEdge(_edgeTo[v]); } } var finder = new EdgeWeightedDirectedCycle(spt); _cycle = finder.Cycle(); }
private readonly DirectedEdge[] _edgeTo; // edgeTo[v] = last edge on longest s->v path #endregion Fields #region Constructors /// <summary> /// Computes a longest paths tree from <tt>s</tt> to every other vertex in /// the directed acyclic graph <tt>G</tt>. /// </summary> /// <param name="g">g the acyclic digraph</param> /// <param name="s">s the source vertex</param> /// <exception cref="ArgumentException">if the digraph is not acyclic</exception> /// <exception cref="ArgumentException">unless 0 <= <tt>s</tt> <= <tt>V</tt> - 1</exception> public AcyclicLP(EdgeWeightedDigraph g, int s) { _distTo = new double[g.V]; _edgeTo = new DirectedEdge[g.V]; for (var v = 0; v < g.V; v++) _distTo[v] = double.NegativeInfinity; _distTo[s] = 0.0; // relax vertices in toplogical order var topological = new Topological(g); if (!topological.HasOrder()) throw new ArgumentException("Digraph is not acyclic."); foreach (int v in topological.Order()) { foreach (var e in g.Adj(v)) Relax(e); } }
private IEnumerable<DirectedEdge> _cycle; // negative cycle (or null if no such cycle) #endregion Fields #region Constructors /// <summary> /// Computes a shortest paths tree from <tt>s</tt> to every other vertex in /// the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">g the acyclic digraph</param> /// <param name="s">s the source vertex</param> /// <exception cref="ArgumentException">unless 0 le; <tt>s</tt> le; <tt>V</tt> - 1</exception> public BellmanFordSP(EdgeWeightedDigraph g, int s) { _distTo = new double[g.V]; _edgeTo = new DirectedEdge[g.V]; _onQueue = new bool[g.V]; for (var v = 0; v < g.V; v++) _distTo[v] = double.PositiveInfinity; _distTo[s] = 0.0; // Bellman-Ford algorithm _queue = new Collections.Queue<Integer>(); _queue.Enqueue(s); _onQueue[s] = true; while (!_queue.IsEmpty() && !HasNegativeCycle()) { int v = _queue.Dequeue(); _onQueue[v] = false; Relax(g, v); } }
/// <summary> /// Returns a negative cycle, or <tt>null</tt> if there is no such cycle. /// </summary> /// <returns>a negative cycle as an iterable of edges, or <tt>null</tt> if there is no such cycle</returns> public IEnumerable <DirectedEdge> NegativeCycle() { for (var v = 0; v < _distTo.Length; v++) { // negative cycle in v's predecessor graph if (_distTo[v][v] < 0.0) { var spt = new EdgeWeightedDigraph(_edgeTo.Length); for (var w = 0; w < _edgeTo.Length; w++) { if (_edgeTo[v][w] != null) { spt.AddEdge(_edgeTo[v][w]); } } var finder = new EdgeWeightedDirectedCycle(spt); return(finder.Cycle()); } } return(null); }
/// <summary> /// Initializes a new edge-weighted digraph that is a deep copy of <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted digraph to copy</param> public EdgeWeightedDigraph(EdgeWeightedDigraph g) : this(g.V) { E = g.E; for (var v = 0; v < g.V; v++) { _indegree[v] = g.Indegree(v); } for (var v = 0; v < g.V; v++) { // reverse so that adjacency list is in same order as original var reverse = new Collections.Stack <DirectedEdge>(); foreach (var e in g._adj[v]) { reverse.Push(e); } foreach (var e in reverse) { _adj[v].Add(e); } } }
private IEnumerable <DirectedEdge> _cycle; // negative cycle (or null if no such cycle) /// <summary> /// Computes a shortest paths tree from <tt>s</tt> to every other vertex in /// the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">g the acyclic digraph</param> /// <param name="s">s the source vertex</param> /// <exception cref="ArgumentException">unless 0 le; <tt>s</tt> le; <tt>V</tt> - 1</exception> public BellmanFordSP(EdgeWeightedDigraph g, int s) { _distTo = new double[g.V]; _edgeTo = new DirectedEdge[g.V]; _onQueue = new bool[g.V]; for (var v = 0; v < g.V; v++) { _distTo[v] = double.PositiveInfinity; } _distTo[s] = 0.0; // Bellman-Ford algorithm _queue = new Collections.Queue <Integer>(); _queue.Enqueue(s); _onQueue[s] = true; while (!_queue.IsEmpty() && !HasNegativeCycle()) { int v = _queue.Dequeue(); _onQueue[v] = false; Relax(g, v); } }
// check optimality conditions private bool Check(EdgeWeightedDigraph g, int s) { // no negative cycle if (!HasNegativeCycle) { for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { var w = e.To(); for (var i = 0; i < g.V; i++) { if (_distTo[i][w] > _distTo[i][v] + e.Weight) { Console.WriteLine($"edge {e} is eligible"); return(false); } } } } } return(true); }
// check optimality conditions: either // (i) there exists a negative cycle reacheable from s // or // (ii) for all edges e = v->w: distTo[w] <= distTo[v] + e.weight() // (ii') for all edges e = v->w on the SPT: distTo[w] == distTo[v] + e.weight() private bool Check(EdgeWeightedDigraph g, int s) { // has a negative cycle if (HasNegativeCycle()) { var weight = NegativeCycle().Sum(e => e.Weight); if (weight >= 0.0) { Console.WriteLine($"error: weight of negative cycle = {weight}"); return(false); } } // no negative cycle reachable from source else { // check that distTo[v] and edgeTo[v] are consistent if (Math.Abs(_distTo[s]) > 0.0001 || _edgeTo[s] != null) { Console.WriteLine("distanceTo[s] and edgeTo[s] inconsistent"); return(false); } for (var v = 0; v < g.V; v++) { if (v == s) { continue; } if (_edgeTo[v] != null || double.IsPositiveInfinity(_distTo[v])) { continue; } Console.WriteLine("distTo[] and edgeTo[] inconsistent"); return(false); } // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { var w = e.To(); if (!(_distTo[v] + e.Weight < _distTo[w])) { continue; } Console.WriteLine($"edge {e} not relaxed"); return(false); } } // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (var w = 0; w < g.V; w++) { if (_edgeTo[w] == null) { continue; } var e = _edgeTo[w]; var v = e.From(); if (w != e.To()) { return(false); } if (Math.Abs(_distTo[v] + e.Weight - _distTo[w]) < 0.0001) { continue; } Console.WriteLine($"edge {e} on shortest path not tight"); return(false); } } Console.WriteLine("Satisfies optimality conditions"); Console.WriteLine(); return(true); }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyEWD.txt"); // Prompt Console.WriteLine("2 - mediumEWD.txt"); // Prompt //Console.WriteLine("3 - mediumEWG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); string fileName; switch (fileNumber) { case "1": fileName = "tinyEWD.txt"; break; case "2": fileName = "mediumEWD.txt"; break; //case "3": // fileName = "largeEWG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fileName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<DirectedEdge>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var weight = Convert.ToDouble(lineSplitted[2], CultureInfo.InvariantCulture); var edge = new DirectedEdge(ve, we, weight); edges.Add(edge); } lineIterator++; } var edgeWeightedGraph = new EdgeWeightedDigraph(v, e, edges); Console.WriteLine(edgeWeightedGraph); Console.ReadLine(); }
/// <summary> /// check optimality conditions: /// (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight() /// (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight() /// </summary> /// <param name="g"></param> /// <param name="s"></param> /// <returns></returns> public bool Check(EdgeWeightedDigraph g, int s) { // check that edge weights are nonnegative if (g.Edges().Any(e => e.Weight < 0)) { Console.Error.WriteLine("negative edge weight detected"); return(false); } // check that distTo[v] and edgeTo[v] are consistent if (Math.Abs(_distTo[s]) > 1E12 || _edgeTo[s] != null) { Console.Error.WriteLine("distTo[s] and edgeTo[s] inconsistent"); return(false); } for (var v = 0; v < g.V; v++) { if (v == s) { continue; } if (_edgeTo[v] == null && !double.IsPositiveInfinity(_distTo[v])) { Console.Error.WriteLine("distTo[] and edgeTo[] inconsistent"); return(false); } } // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { int w = e.To(); if (_distTo[v] + e.Weight < _distTo[w]) { Console.Error.WriteLine($"edge {e} not relaxed"); return(false); } } } // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (var w = 0; w < g.V; w++) { if (_edgeTo[w] == null) { continue; } var e = _edgeTo[w]; var v = e.From(); if (w != e.To()) { return(false); } if (Math.Abs(_distTo[v] + e.Weight - _distTo[w]) > 1E12) { Console.Error.WriteLine($"edge {e} on shortest path not tight"); return(false); } } return(true); }
/// <summary> /// Computes a shortest paths tree from each vertex to to every other vertex in /// the edge-weighted digraph <tt>G</tt>. /// </summary> /// <param name="g">G the edge-weighted digraph</param> /// <exception cref="ArgumentException">if an edge weight is negative</exception> /// <exception cref="ArgumentException">unless 0 <= <tt>s</tt> <= <tt>V</tt> - 1</exception> public DijkstraAllPairsSP(EdgeWeightedDigraph g) { _all = new DijkstraSP[g.V]; for (var v = 0; v < g.V; v++) _all[v] = new DijkstraSP(g, v); }
// check optimality conditions private bool Check(EdgeWeightedDigraph g, int s) { // no negative cycle if (!HasNegativeCycle) { for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { var w = e.To(); for (var i = 0; i < g.V; i++) { if (_distTo[i][w] > _distTo[i][v] + e.Weight) { Console.WriteLine($"edge {e} is eligible"); return false; } } } } } return true; }
/// <summary> /// Returns a negative cycle, or <tt>null</tt> if there is no such cycle. /// </summary> /// <returns>a negative cycle as an iterable of edges, or <tt>null</tt> if there is no such cycle</returns> public IEnumerable<DirectedEdge> NegativeCycle() { for (var v = 0; v < _distTo.Length; v++) { // negative cycle in v's predecessor graph if (_distTo[v][v] < 0.0) { var spt = new EdgeWeightedDigraph(_edgeTo.Length); for (var w = 0; w < _edgeTo.Length; w++) if (_edgeTo[v][w] != null) spt.AddEdge(_edgeTo[v][w]); var finder = new EdgeWeightedDirectedCycle(spt); return finder.Cycle(); } } return null; }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - rates.txt"); // Prompt //Console.WriteLine("2 - mediumEWD.txt"); // Prompt //Console.WriteLine("3 - mediumEWG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); string fileName; switch (fileNumber) { case "1": fileName = "rates.txt"; break; //case "2": // fileName = "mediumEWD.txt"; // break; //case "3": // fileName = "largeEWG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fileName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var currencyIterator = 0; // number of jobs var n = 0; // source and sink var source = 0; var sink = 0; var v = 0; var e = 0; var edges = new List<DirectedEdge>(); string[] names = {}; foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); names = new string[v]; } if (lineIterator > 0) { var wordsIterator = 0; var ratesIterator = 0; var lineSplitted = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (var word in lineSplitted) { if (wordsIterator == 0) { names[wordsIterator] = word; } if (wordsIterator > 0) { double rate = Convert.ToSingle(word,CultureInfo.InvariantCulture); var edge = new DirectedEdge(currencyIterator, ratesIterator, -Math.Log(rate)); edges.Add(edge); e++; ratesIterator++; } wordsIterator ++; } currencyIterator++; } lineIterator++; } var edgeWeightedDigraph = new EdgeWeightedDigraph(v, e, edges); Console.WriteLine(edgeWeightedDigraph); // find shortest path from s to each other vertex in DAG var arbitrage = new Arbitrage(edgeWeightedDigraph,source); var spt = arbitrage.GetShotestPath(); // print results Console.WriteLine(" job start finish"); Console.WriteLine("--------------------"); if (spt.HasNegativeCycle()) { var stake = 1000.0; foreach (var edge in spt.NegativeCycle()) { Console.Write($"{stake:0.00000} {names[edge.From()]} "); stake *= Math.Exp(-edge.Weight); Console.Write($"= {stake:0.00000} {names[edge.To()]}{Environment.NewLine}"); } } else { Console.WriteLine("No arbitrage opportunity"); } Console.ReadLine(); }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyEWDAG.txt"); // Prompt //Console.WriteLine("2 - mediumEWD.txt"); // Prompt //Console.WriteLine("3 - mediumEWG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); string fileName; switch (fileNumber) { case "1": fileName = "tinyEWDAG.txt"; break; //case "2": // fileName = "mediumEWD.txt"; // break; //case "3": // fileName = "largeEWG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fileName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<DirectedEdge>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var weight = Convert.ToDouble(lineSplitted[2], CultureInfo.InvariantCulture); var edge = new DirectedEdge(ve, we, weight); edges.Add(edge); } lineIterator++; } var edgeWeightedDigraph = new EdgeWeightedDigraph(v, e, edges); Console.WriteLine(edgeWeightedDigraph); const int s = 5; // find shortest path from s to each other vertex in DAG var sp = new AcyclicSP(edgeWeightedDigraph, s); for (var vi = 0; vi < edgeWeightedDigraph.V; vi++) { if (sp.HasPathTo(vi)) { Console.Write($"{s} to {vi} {$"{sp.DistTo(vi):0.00}"} "); foreach (var ei in sp.PathTo(vi)) { Console.Write($"{ei} "); } Console.WriteLine(); } else { Console.Write($"{s} to {vi} no path{Environment.NewLine}"); } } Console.ReadLine(); }
/// <summary> /// check that algorithm computes either the topological order or finds a directed cycle /// </summary> /// <param name="g"></param> /// <param name="v"></param> private void Dfs(EdgeWeightedDigraph g, int v) { _onStack[v] = true; _marked[v] = true; foreach (var e in g.Adj(v)) { var w = e.To(); // short circuit if directed cycle found if (_cycle != null) return; //found new vertex, so recur if (!_marked[w]) { _edgeTo[w] = e; Dfs(g, w); } // trace back directed cycle else if (_onStack[w]) { TraceBackDirectedCycle(e, w); return; } } _onStack[v] = false; }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - jobsPC.txt"); // Prompt //Console.WriteLine("2 - mediumEWD.txt"); // Prompt //Console.WriteLine("3 - mediumEWG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); string fileName; switch (fileNumber) { case "1": fileName = "jobsPC.txt"; break; //case "2": // fileName = "mediumEWD.txt"; // break; //case "3": // fileName = "largeEWG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fileName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var i = 0; // number of jobs var n = 0; // source and sink var source = 0; var sink = 0; var v = 0; var e = 0; var edges = new List<DirectedEdge>(); foreach (var line in lines) { if (lineIterator == 0) { n = Convert.ToInt32(line); source = 2*n; sink = 2*n + 1; v = sink+1; } if (lineIterator > 0) { var lineSplitted = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var duration = Convert.ToDouble(lineSplitted[0], CultureInfo.InvariantCulture); edges.Add(new DirectedEdge(source, i, 0.0)); e++; edges.Add(new DirectedEdge(i + n, sink, 0.0)); e++; edges.Add(new DirectedEdge(i, i + n, duration)); e++; // precedence constraints var m = Convert.ToInt32(lineSplitted[1], CultureInfo.InvariantCulture); for (var j = 0; j < m; j++) { var precedent = Convert.ToInt32(lineSplitted[1 + (j + 1)], CultureInfo.InvariantCulture); edges.Add(new DirectedEdge(n + i, precedent, 0.0)); e++; } i++; } lineIterator++; } var edgeWeightedDigraph = new EdgeWeightedDigraph(v, e, edges); Console.WriteLine(edgeWeightedDigraph); // find shortest path from s to each other vertex in DAG var lp = new AcyclicLP(edgeWeightedDigraph, source); // print results Console.WriteLine(" job start finish"); Console.WriteLine("--------------------"); for (var k = 0; k < n; k++) { Console.Write($"{k} {lp.DistTo(k)} {lp.DistTo(k + n)}{Environment.NewLine}"); } Console.Write($"Finish time: {lp.DistTo(sink)}{Environment.NewLine}"); Console.ReadLine(); }
// by finding a cycle in predecessor graph private void FindNegativeCycle() { var vv = _edgeTo.Length; var spt = new EdgeWeightedDigraph(vv); for (var v = 0; v < vv; v++) if (_edgeTo[v] != null) spt.AddEdge(_edgeTo[v]); var finder = new EdgeWeightedDirectedCycle(spt); _cycle = finder.Cycle(); }
// relax vertex v and put other endpoints on queue if changed private void Relax(EdgeWeightedDigraph g, int v) { foreach (var e in g.Adj(v)) { var w = e.To(); if (_distTo[w] > _distTo[v] + e.Weight) { _distTo[w] = _distTo[v] + e.Weight; _edgeTo[w] = e; if (!_onQueue[w]) { _queue.Enqueue(w); _onQueue[w] = true; } } if (_cost++ % g.V == 0) { FindNegativeCycle(); if (HasNegativeCycle()) return; // found a negative cycle } } }
/// <summary> /// Initializes a new edge-weighted digraph that is a deep copy of <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted digraph to copy</param> public EdgeWeightedDigraph(EdgeWeightedDigraph g) : this(g.V) { E = g.E; for (var v = 0; v < g.V; v++) _indegree[v] = g.Indegree(v); for (var v = 0; v < g.V; v++) { // reverse so that adjacency list is in same order as original var reverse = new Collections.Stack<DirectedEdge>(); foreach (var e in g._adj[v]) { reverse.Push(e); } foreach (var e in reverse) { _adj[v].Add(e); } } }
// check optimality conditions: either // (i) there exists a negative cycle reacheable from s // or // (ii) for all edges e = v->w: distTo[w] <= distTo[v] + e.weight() // (ii') for all edges e = v->w on the SPT: distTo[w] == distTo[v] + e.weight() private bool Check(EdgeWeightedDigraph g, int s) { // has a negative cycle if (HasNegativeCycle()) { var weight = NegativeCycle().Sum(e => e.Weight); if (weight >= 0.0) { Console.WriteLine($"error: weight of negative cycle = {weight}"); return false; } } // no negative cycle reachable from source else { // check that distTo[v] and edgeTo[v] are consistent if (Math.Abs(_distTo[s]) > 0.0001 || _edgeTo[s] != null) { Console.WriteLine("distanceTo[s] and edgeTo[s] inconsistent"); return false; } for (var v = 0; v < g.V; v++) { if (v == s) continue; if (_edgeTo[v] != null || double.IsPositiveInfinity(_distTo[v])) continue; Console.WriteLine("distTo[] and edgeTo[] inconsistent"); return false; } // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { var w = e.To(); if (!(_distTo[v] + e.Weight < _distTo[w])) continue; Console.WriteLine($"edge {e} not relaxed"); return false; } } // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (var w = 0; w < g.V; w++) { if (_edgeTo[w] == null) continue; var e = _edgeTo[w]; var v = e.From(); if (w != e.To()) return false; if (Math.Abs(_distTo[v] + e.Weight - _distTo[w]) < 0.0001) continue; Console.WriteLine($"edge {e} on shortest path not tight"); return false; } } Console.WriteLine("Satisfies optimality conditions"); Console.WriteLine(); return true; }