/* * Copyright (C) 2012-2018 CypherCore * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using System; using System.Collections.Generic; using System.Text; namespace Game.Entities { /// /// The IndexMinPriorityQueue class represents an indexed priority queue of generic keys. /// /// IndexMinPQ class from Princeton University's Java Algorithms /// Type must implement IComparable interface public class IndexMinPriorityQueue where T : IComparable { private readonly T[] _keys; private readonly int _maxSize; private readonly int[] _pq; private readonly int[] _qp; /// /// Constructs an empty indexed priority queue with indices between 0 and the specified maxSize - 1 /// /// The maximum size of the indexed priority queue public IndexMinPriorityQueue(int maxSize) { _maxSize = maxSize; Size = 0; _keys = new T[_maxSize + 1]; _pq = new int[_maxSize + 1]; _qp = new int[_maxSize + 1]; for (int i = 0; i < _maxSize; i++) { _qp[i] = -1; } } /// /// The number of keys on this indexed priority queue /// public int Size { get; private set; } /// /// Is the indexed priority queue empty? /// /// True if the indexed priority queue is empty, false otherwise public bool IsEmpty() { return Size == 0; } /// /// Is the specified parameter i an index on the priority queue? /// /// An index to check for on the priority queue /// True if the specified parameter i is an index on the priority queue, false otherwise public bool Contains(int i) { return _qp[i] != -1; } /// /// Associates the specified key with the specified index /// /// The index to associate the key with /// The key to associate with the index public void Insert(int index, T key) { Size++; _qp[index] = Size; _pq[Size] = index; _keys[index] = key; Swim(Size); } /// /// Returns an index associated with a minimum key /// /// An index associated with a minimum key public int MinIndex() { return _pq[1]; } /// /// Returns a minimum key /// /// A minimum key public T MinKey() { return _keys[_pq[1]]; } /// /// Removes a minimum key and returns its associated index /// /// An index associated with a minimum key that was removed public int DeleteMin() { int min = _pq[1]; Exchange(1, Size--); Sink(1); _qp[min] = -1; _keys[_pq[Size + 1]] = default(T); _pq[Size + 1] = -1; return min; } /// /// Returns the key associated with the specified index /// /// The index of the key to return /// The key associated with the specified index public T KeyAt(int index) { return _keys[index]; } /// /// Change the key associated with the specified index to the specified value /// /// The index of the key to change /// Change the key associated with the specified index to this key public void ChangeKey(int index, T key) { _keys[index] = key; Swim(_qp[index]); Sink(_qp[index]); } /// /// Decrease the key associated with the specified index to the specified value /// /// The index of the key to decrease /// Decrease the key associated with the specified index to this key public void DecreaseKey(int index, T key) { _keys[index] = key; Swim(_qp[index]); } /// /// Increase the key associated with the specified index to the specified value /// /// The index of the key to increase /// Increase the key associated with the specified index to this key public void IncreaseKey(int index, T key) { _keys[index] = key; Sink(_qp[index]); } /// /// Remove the key associated with the specified index /// /// The index of the key to remove public void Delete(int index) { int i = _qp[index]; Exchange(i, Size--); Swim(i); Sink(i); _keys[index] = default(T); _qp[index] = -1; } private bool Greater(int i, int j) { return _keys[_pq[i]].CompareTo(_keys[_pq[j]]) > 0; } private void Exchange(int i, int j) { int swap = _pq[i]; _pq[i] = _pq[j]; _pq[j] = swap; _qp[_pq[i]] = i; _qp[_pq[j]] = j; } private void Swim(int k) { while (k > 1 && Greater(k / 2, k)) { Exchange(k, k / 2); k = k / 2; } } private void Sink(int k) { while (2 * k <= Size) { int j = 2 * k; if (j < Size && Greater(j, j + 1)) { j++; } if (!Greater(k, j)) { break; } Exchange(k, j); k = j; } } } /// /// The EdgeWeightedDigrpah class represents an edge-weighted directed graph of vertices named 0 through V-1, where each directed edge /// is of type DirectedEdge and has real-valued weight. /// /// EdgeWeightedDigraph class from Princeton University's Java Algorithms public class EdgeWeightedDigraph { private readonly LinkedList[] _adjacent; /// /// Constructs an empty edge-weighted digraph with the specified number of vertices and 0 edges /// /// Number of vertices in the Graph public EdgeWeightedDigraph(int vertices) { NumberOfVertices = vertices; NumberOfEdges = 0; _adjacent = new LinkedList[NumberOfVertices]; for (int v = 0; v < NumberOfVertices; v++) { _adjacent[v] = new LinkedList(); } } /// /// The number of vertices in the edge-weighted digraph /// public int NumberOfVertices { get; private set; } /// /// The number of edges in the edge-weighted digraph /// public int NumberOfEdges { get; private set; } /// /// Adds the specified directed edge to the edge-weighted digraph /// /// The DirectedEdge to add /// DirectedEdge cannot be null public void AddEdge(DirectedEdge edge) { if (edge == null) { throw new ArgumentNullException("edge", "DirectedEdge cannot be null"); } _adjacent[edge.From].AddLast(edge); } /// /// Returns an IEnumerable of the DirectedEdges incident from the specified vertex /// /// The vertex to find incident DirectedEdges from /// IEnumerable of the DirectedEdges incident from the specified vertex public IEnumerable Adjacent(int vertex) { return _adjacent[vertex]; } /// /// Returns an IEnumerable of all directed edges in the edge-weighted digraph /// /// IEnumerable of of all directed edges in the edge-weighted digraph public IEnumerable Edges() { for (int v = 0; v < NumberOfVertices; v++) { foreach (DirectedEdge edge in _adjacent[v]) { yield return edge; } } } /// /// Returns the number of directed edges incident from the specified vertex /// This is known as the outdegree of the vertex /// /// The vertex to find find the outdegree of /// The number of directed edges incident from the specified vertex public int OutDegree(int vertex) { return _adjacent[vertex].Count; } /// /// Returns a string that represents the current edge-weighted digraph /// /// /// A string that represents the current edge-weighted digraph /// public override string ToString() { var formattedString = new StringBuilder(); formattedString.AppendFormat("{0} vertices, {1} edges {2}", NumberOfVertices, NumberOfEdges, Environment.NewLine); for (int v = 0; v < NumberOfVertices; v++) { formattedString.AppendFormat("{0}: ", v); foreach (DirectedEdge edge in _adjacent[v]) { formattedString.AppendFormat("{0} ", edge.To); } formattedString.AppendLine(); } return formattedString.ToString(); } } /// /// The DirectedEdge class represents a weighted edge in an edge-weighted directed graph. /// /// DirectedEdge class from Princeton University's Java Algorithms public class DirectedEdge { /// /// Constructs a directed edge from one specified vertex to another with the given weight /// /// The start vertex /// The destination vertex /// The weight of the DirectedEdge public DirectedEdge(uint from, uint to, double weight) { From = from; To = to; Weight = weight; } /// /// Returns the destination vertex of the DirectedEdge /// public uint From { get; private set; } /// /// Returns the start vertex of the DirectedEdge /// public uint To { get; private set; } /// /// Returns the weight of the DirectedEdge /// public double Weight { get; private set; } /// /// Returns a string that represents the current DirectedEdge /// /// /// A string that represents the current DirectedEdge /// public override string ToString() { return string.Format("From: {0}, To: {1}, Weight: {2}", From, To, Weight); } } /// /// The DijkstraShortestPath class represents a data type for solving the single-source shortest paths problem /// in edge-weighted digraphs where the edge weights are non-negative /// /// DijkstraSP class from Princeton University's Java Algorithms public class DijkstraShortestPath { private readonly double[] _distanceTo; private readonly DirectedEdge[] _edgeTo; private readonly IndexMinPriorityQueue _priorityQueue; /// /// Computes a shortest paths tree from the specified sourceVertex to every other vertex in the edge-weighted directed graph /// /// The edge-weighted directed graph /// The source vertex to compute the shortest paths tree from /// Throws an ArgumentOutOfRangeException if an edge weight is negative /// Thrown if EdgeWeightedDigraph is null public DijkstraShortestPath(EdgeWeightedDigraph graph, int sourceVertex) { if (graph == null) { throw new ArgumentNullException("graph", "EdgeWeightedDigraph cannot be null"); } foreach (DirectedEdge edge in graph.Edges()) { if (edge.Weight < 0) { throw new ArgumentOutOfRangeException(string.Format("Edge: '{0}' has negative weight", edge)); } } _distanceTo = new double[graph.NumberOfVertices]; _edgeTo = new DirectedEdge[graph.NumberOfVertices]; for (int v = 0; v < graph.NumberOfVertices; v++) { _distanceTo[v] = double.PositiveInfinity; } _distanceTo[sourceVertex] = 0.0; _priorityQueue = new IndexMinPriorityQueue(graph.NumberOfVertices); _priorityQueue.Insert(sourceVertex, _distanceTo[sourceVertex]); while (!_priorityQueue.IsEmpty()) { int v = _priorityQueue.DeleteMin(); foreach (DirectedEdge edge in graph.Adjacent(v)) { Relax(edge); } } } private void Relax(DirectedEdge edge) { uint v = edge.From; uint w = edge.To; if (_distanceTo[w] > _distanceTo[v] + edge.Weight) { _distanceTo[w] = _distanceTo[v] + edge.Weight; _edgeTo[w] = edge; if (_priorityQueue.Contains((int)w)) { _priorityQueue.DecreaseKey((int)w, _distanceTo[w]); } else { _priorityQueue.Insert((int)w, _distanceTo[w]); } } } /// /// Returns the length of a shortest path from the sourceVertex to the specified destinationVertex /// /// The destination vertex to find a shortest path to /// The length of a shortest path from the sourceVertex to the specified destinationVertex or double.PositiveInfinity if no such path exists public double DistanceTo(int destinationVertex) { return _distanceTo[destinationVertex]; } /// /// Is there a path from the sourceVertex to the specified destinationVertex? /// /// The destination vertex to see if there is a path to /// True if there is a path from the sourceVertex to the specified destinationVertex, false otherwise public bool HasPathTo(int destinationVertex) { return _distanceTo[destinationVertex] < double.PositiveInfinity; } /// /// Returns an IEnumerable of DirectedEdges representing a shortest path from the sourceVertex to the specified destinationVertex /// /// The destination vertex to find a shortest path to /// IEnumerable of DirectedEdges representing a shortest path from the sourceVertex to the specified destinationVertex public IEnumerable PathTo(int destinationVertex) { if (!HasPathTo(destinationVertex)) { return null; } var path = new Stack(); for (DirectedEdge edge = _edgeTo[destinationVertex]; edge != null; edge = _edgeTo[edge.From]) { path.Push(edge); } return path; } // TODO: This method should be private and should be called from the bottom of the constructor /// /// check optimality conditions: /// /// The edge-weighted directed graph /// The source vertex to check optimality conditions from /// True if all optimality conditions are met, false otherwise /// Thrown on null EdgeWeightedDigraph public bool Check(EdgeWeightedDigraph graph, int sourceVertex) { if (graph == null) { throw new ArgumentNullException("graph", "EdgeWeightedDigraph cannot be null"); } if (_distanceTo[sourceVertex] != 0.0 || _edgeTo[sourceVertex] != null) { return false; } for (int v = 0; v < graph.NumberOfVertices; v++) { if (v == sourceVertex) { continue; } if (_edgeTo[v] == null && _distanceTo[v] != double.PositiveInfinity) { return false; } } for (int v = 0; v < graph.NumberOfVertices; v++) { foreach (DirectedEdge edge in graph.Adjacent(v)) { uint w = edge.To; if (_distanceTo[v] + edge.Weight < _distanceTo[w]) { return false; } } } for (int w = 0; w < graph.NumberOfVertices; w++) { if (_edgeTo[w] == null) { continue; } DirectedEdge edge = _edgeTo[w]; uint v = edge.From; if (w != edge.To) { return false; } if (_distanceTo[v] + edge.Weight != _distanceTo[w]) { return false; } } return true; } } }