Skip to content

Commit 001e85b

Browse files
author
Kapil Borle
committed
Add class to create and analyze directed graph
1 parent b84c219 commit 001e85b

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

Engine/Helper.cs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,4 +3555,130 @@ public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)
35553555
return null;
35563556
}
35573557
}
3558+
3559+
/// Class to represent a directed graph
3560+
public class Digraph<T>
3561+
{
3562+
public int NumVertices
3563+
{
3564+
get { return graph.Count; }
3565+
}
3566+
3567+
private List<List<int>> graph;
3568+
private Dictionary<T, int> vertexIndexMap;
3569+
3570+
3571+
private int GetIndex(T vertex)
3572+
{
3573+
int idx;
3574+
return vertexIndexMap.TryGetValue(vertex, out idx) ? idx : -1;
3575+
}
3576+
3577+
public IEnumerable<T> GetNeighbors(T vertex)
3578+
{
3579+
ValidateVertexArgument(vertex);
3580+
var idx = GetIndex(vertex);
3581+
var idxVertexMap = vertexIndexMap.ToDictionary(x => x.Value, x => x.Key);
3582+
foreach (var neighbor in graph[idx])
3583+
{
3584+
yield return idxVertexMap[neighbor];
3585+
}
3586+
}
3587+
3588+
public int GetNumNeighbors(T vertex)
3589+
{
3590+
ValidateVertexArgument(vertex);
3591+
return graph[GetIndex(vertex)].Count;
3592+
}
3593+
3594+
public Digraph()
3595+
{
3596+
graph = new List<List<int>> ();
3597+
vertexIndexMap = new Dictionary<T, int>();
3598+
}
3599+
3600+
public void AddVertex(T vertex)
3601+
{
3602+
if (vertex == null)
3603+
{
3604+
throw new ArgumentNullException("vertex");
3605+
}
3606+
3607+
if (GetIndex(vertex) != -1)
3608+
{
3609+
throw new ArgumentException("Vertex already present! Cannot add it to the Digraph", "vertex");
3610+
}
3611+
3612+
vertexIndexMap.Add(vertex, graph.Count);
3613+
graph.Add(new List<int>());
3614+
}
3615+
3616+
public void AddEdge(T fromVertex, T toVertex)
3617+
{
3618+
ValidateVertexArgument(fromVertex);
3619+
ValidateVertexArgument(toVertex);
3620+
3621+
var toIdx = GetIndex(toVertex);
3622+
var fromVertexList = graph[GetIndex(fromVertex)];
3623+
if (!fromVertexList.Contains(toIdx))
3624+
{
3625+
fromVertexList.Add(toIdx);
3626+
}
3627+
}
3628+
3629+
public bool IsConnected(T vertex1, T vertex2)
3630+
{
3631+
ValidateVertexArgument(vertex1);
3632+
ValidateVertexArgument(vertex2);
3633+
var visited = new bool[graph.Count];
3634+
return IsConnected(GetIndex(vertex1), GetIndex(vertex2), ref visited);
3635+
}
3636+
3637+
private bool IsConnected(int fromIdx, int toIdx, ref bool[] visited)
3638+
{
3639+
visited[fromIdx] = true;
3640+
if (fromIdx == toIdx)
3641+
{
3642+
return true;
3643+
}
3644+
3645+
bool isConnected = false;
3646+
foreach(var vertexIdx in graph[fromIdx])
3647+
{
3648+
if (!visited[vertexIdx])
3649+
{
3650+
isConnected |= IsConnected(vertexIdx, toIdx, ref visited);
3651+
}
3652+
3653+
if (isConnected) // no need to search further
3654+
{
3655+
break;
3656+
}
3657+
}
3658+
3659+
return isConnected;
3660+
}
3661+
3662+
private void ValidateNotNull(T vertex)
3663+
{
3664+
if (vertex == null)
3665+
{
3666+
throw new ArgumentNullException("vertex");
3667+
}
3668+
}
3669+
3670+
private void ValidateVertexPresence(T vertex)
3671+
{
3672+
if (GetIndex(vertex) == -1)
3673+
{
3674+
throw new ArgumentOutOfRangeException("vertex not present in the Digraph.", "vertex");
3675+
}
3676+
}
3677+
3678+
private void ValidateVertexArgument(T vertex)
3679+
{
3680+
ValidateNotNull(vertex);
3681+
ValidateVertexPresence(vertex);
3682+
}
3683+
}
35583684
}

Tests/Engine/Helpers.tests.ps1

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Import-Module PSScriptAnalyzer
2+
$helperNamespace = 'Microsoft.Windows.PowerShell.ScriptAnalyzer';
3+
4+
5+
Describe "Test Directed Graph" {
6+
Context "When a graph is created" {
7+
$digraph = New-Object -TypeName 'Microsoft.Windows.PowerShell.ScriptAnalyzer.DiGraph[string]'
8+
$digraph.AddVertex('v1');
9+
$digraph.AddVertex('v2');
10+
$digraph.AddVertex('v3');
11+
$digraph.AddVertex('v4');
12+
$digraph.AddEdge('v1', 'v2');
13+
$digraph.AddEdge('v2', 'v4');
14+
15+
It "correctly adds the vertices" {
16+
$digraph.NumVertices | Should Be 4
17+
}
18+
19+
It "correctly adds the edges" {
20+
$digraph.GetNumNeighbors('v1') | Should Be 1
21+
$neighbors = $digraph.GetNeighbors('v1')
22+
$neighbors[0] | Should Be 'v2'
23+
}
24+
25+
It "finds the connection" {
26+
$digraph.IsConnected('v1', 'v4') | Should Be $true
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)