using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using QuickGraph; using QuickGraph.Algorithms.ShortestPath; using System.Diagnostics; namespace GraphSharp { public static class GraphHelper { /// /// Returns with the adjacent vertices of the vertex. /// /// The graph. /// The vertex which neighbours' we want to get. /// List of the adjacent vertices of the vertex. public static IEnumerable GetNeighbours( this IBidirectionalGraph g, TVertex vertex ) where TEdge : IEdge { return ( ( from e in g.InEdges( vertex ) select e.Source ) .Concat( ( from e in g.OutEdges( vertex ) select e.Target ) ) ).Distinct(); } public static IEnumerable GetOutNeighbours( this IVertexAndEdgeListGraph g, TVertex vertex ) where TEdge : IEdge { return ( from e in g.OutEdges( vertex ) select e.Target ).Distinct(); } /// /// If the graph g is directed, then returns every edges which source is one of the vertices in the set1 /// and the target is one of the vertices in set2. /// /// Type of the vertex. /// Type of the edge. /// The graph. /// /// /// Return the list of the selected edges. public static IEnumerable GetEdgesBetween( this IVertexAndEdgeListGraph g, List set1, List set2 ) where TEdge : IEdge { var edgesBetween = new List(); //vegig kell menni az osszes vertex minden elen, es megnezni, hogy a target hol van foreach ( TVertex v in set1 ) { foreach ( TEdge edge in g.OutEdges( v ) ) { if ( set2.Contains( edge.Target ) ) edgesBetween.Add( edge ); } } return edgesBetween; } /// /// Returns with the sources in the graph. /// /// /// /// The graph. /// Returns with the sources in the graph. public static IEnumerable GetSources( this IBidirectionalGraph g ) where TEdge : IEdge { return from v in g.Vertices where g.InDegree( v ) == 0 select v; } /// /// Gets the diameter of a graph. /// The diameter is the greatest distance between two vertices. /// /// The graph. /// The diameter of the Graph g. public static float GetDiameter( this Graph g ) where Edge : IEdge where Graph : IBidirectionalGraph { float[,] distances; return g.GetDiameter( out distances ); } /// /// Gets the diameter of a graph. /// The diameter is the greatest distance between two vertices. /// /// The graph. /// This is an out parameter. It gives the distances between every vertex-pair. /// The diameter of the Graph g. public static float GetDiameter( this Graph g, out float[,] distances ) where Edge : IEdge where Graph : IBidirectionalGraph { distances = GetDistances( g ); int n = g.VertexCount; float distance = float.NegativeInfinity; for ( int i = 0; i < n - 1; i++ ) { for ( int j = i + 1; j < n; j++ ) { if ( float.MaxValue == distances[i, j] ) continue; distance = Math.Max( distance, distances[i, j] ); } } return distance; } /// The graph. /// Returns with the distance between the vertices (distance: number of the edges). public static float[,] GetDistances( Graph g ) where Edge : IEdge where Graph : IBidirectionalGraph { var distances = new float[g.VertexCount, g.VertexCount]; for ( int k = 0; k < g.VertexCount; k++ ) { for ( int j = 0; j < g.VertexCount; j++ ) { distances[k, j] = float.PositiveInfinity; } } var undirected = new UndirectedBidirectionalGraph( g ); //minden élet egy hosszal veszünk figyelembe - unweighted var weights = new Dictionary(); foreach ( Edge edge in undirected.Edges ) { weights[edge] = 1; } //compute the distances from every vertex: O(n(n^2 + e)) complexity int i = 0; foreach ( Vertex source in g.Vertices ) { //compute the distances from the 'source' var spaDijkstra = new UndirectedDijkstraShortestPathAlgorithm( undirected, edge => weights[edge], ShortestDistanceRelaxer.Instance ); spaDijkstra.Compute( source ); int j = 0; foreach ( Vertex v in undirected.Vertices ) { float d = (float) spaDijkstra.Distances[v]; distances[i, j] = Math.Min( distances[i, j], d ); distances[i, j] = Math.Min( distances[i, j], distances[j, i] ); distances[j, i] = Math.Min( distances[i, j], distances[j, i] ); j++; } i++; } return distances; } public static BidirectionalGraph> CreateGraph( IEnumerable vertices, IEnumerable edges, string sourcePropertyName, string targetPropertyName ) where TVertex : class { var graph = new BidirectionalGraph>(); graph.AddVertexRange( vertices ); //get the property infos System.Reflection.PropertyInfo spi = typeof( TOtherEdge ).GetProperty( sourcePropertyName ); System.Reflection.PropertyInfo tpi = typeof( TOtherEdge ).GetProperty( targetPropertyName ); //creating the new edges foreach ( TOtherEdge oe in edges ) { var edge = new Edge( spi.GetValue( oe, null ) as TVertex, tpi.GetValue( oe, null ) as TVertex ); graph.AddEdge( edge ); } return graph; } /// /// Creates a new BidirectionalGraph with the given types from the /// list of vertices, and the list of edges. /// /// The type of the vertices. /// The type of the edges in the new graph. /// The type of the items in the list of the edges. /// The list of the vertices. /// The list of the edges. /// Delegate which converts an edge from the type TOtherEdge /// to the type TEdge. /// Parallel edges are allowed or not?. /// The new BidirectionalGraph public static BidirectionalGraph CreateGraph( IEnumerable vertices, IEnumerable edges, Func factoryMethod, bool allowParallelEdges ) where TEdge : IEdge { var graph = new BidirectionalGraph( allowParallelEdges ); //add the vertices to the graph graph.AddVertexRange( vertices ); //create the edges foreach ( TOtherEdge oe in edges ) { TEdge e = factoryMethod( oe ); graph.AddEdge( e ); } return graph; } public static BidirectionalGraph CreateGraph( IEnumerable vertices, IEnumerable edges, Func factoryMethod ) where TEdge : IEdge { return CreateGraph( vertices, edges, factoryMethod, true ); } public static TVertex OtherVertex( this IEdge edge, TVertex thisVertex ) { return edge.Source.Equals( thisVertex ) ? edge.Target : edge.Source; } public static void AddEdgeRange( this IMutableEdgeListGraph graph, IEnumerable edges ) where TEdge : IEdge { foreach ( var edge in edges ) graph.AddEdge( edge ); } public static BidirectionalGraph Convert( this IVertexAndEdgeListGraph oldGraph, Func vertexMapperFunc, Func edgeMapperFunc ) where TOldEdge : IEdge where TNewEdge : IEdge { return oldGraph.Convert( new BidirectionalGraph( oldGraph.AllowParallelEdges, oldGraph.VertexCount ), vertexMapperFunc, edgeMapperFunc ); } public static BidirectionalGraph Convert( this IVertexAndEdgeListGraph oldGraph, Func edgeMapperFunc ) where TOldEdge : IEdge where TNewEdge : IEdge { return oldGraph.Convert( null, edgeMapperFunc ); } public static TNewGraph Convert( this IVertexAndEdgeListGraph oldGraph, TNewGraph newGraph, Func vertexMapperFunc, Func edgeMapperFunc ) where TOldEdge : IEdge where TNewEdge : IEdge where TNewGraph : IMutableVertexAndEdgeListGraph { //VERTICES if ( vertexMapperFunc != null ) newGraph.AddVertexRange( oldGraph.Vertices.Select( vertexMapperFunc ) ); else newGraph.AddVertexRange( oldGraph.Vertices.Cast() ); //EDGES if ( edgeMapperFunc != null ) newGraph.AddEdgeRange( oldGraph.Edges.Select( edgeMapperFunc ) ); else newGraph.AddEdgeRange( oldGraph.Edges.Cast() ); return newGraph; } public static TNewGraph Convert( this IVertexAndEdgeListGraph oldGraph, TNewGraph newGraph, Func edgeMapperFunc ) where TOldEdge : IEdge where TNewEdge : IEdge where TNewGraph : IMutableVertexAndEdgeListGraph { return oldGraph.Convert( newGraph, null, edgeMapperFunc ); } public static TNewGraph Convert( this IVertexAndEdgeListGraph oldGraph, TNewGraph newGraph ) where TOldEdge : IEdge where TNewGraph : IMutableVertexAndEdgeListGraph { return oldGraph.Convert( newGraph, null, null ); } public static BidirectionalGraph CopyToBidirectionalGraph( this IVertexAndEdgeListGraph graph) where TEdge : IEdge { var newGraph = new BidirectionalGraph(); //copy the vertices newGraph.AddVerticesAndEdgeRange(graph.Edges); return newGraph; } } }