1+ using System ;
2+ using System . Collections ;
3+ using System . Collections . Generic ;
4+ using System . Linq ;
5+
6+ namespace PageRank . Graph
7+ {
8+ /// <summary>
9+ ///
10+ /// </summary>
11+ /// <typeparam name="T"></typeparam>
12+ public abstract class Graph < T > : IEnumerable < GraphNode < T > >
13+ {
14+ protected NodeSet < T > _nodeSet ;
15+ protected LookUp < T > _lookupTable ;
16+ protected int _capacity = Int32 . MaxValue ;
17+
18+ protected Graph ( )
19+ {
20+ _lookupTable = new LookUp < T > ( ) ;
21+ _nodeSet = new NodeSet < T > ( ) ;
22+ _capacity = Int32 . MaxValue ;
23+ }
24+
25+ internal Graph ( NodeSet < T > nodeSet ) : this ( )
26+ {
27+ // add all node to lookup list
28+ foreach ( var node in _nodeSet )
29+ {
30+ if ( node != null )
31+ {
32+ _lookupTable . Add ( node . Value , node ) ;
33+ _nodeSet . Add ( node ) ;
34+ }
35+ }
36+ }
37+
38+ /// <summary>
39+ ///
40+ /// </summary>
41+ /// <param name="source"></param>
42+ /// <param name="destination"></param>
43+ /// <returns></returns>
44+ public double this [ GraphNode < T > source , GraphNode < T > destination ] => GetWeight ( source , destination ) ;
45+
46+ private double GetWeight ( GraphNode < T > source , GraphNode < T > destination )
47+ {
48+ if ( ! ( _nodeSet . Contains ( source ) && _nodeSet . Contains ( destination ) ) )
49+ return - 1 ;
50+
51+ //weight = Graph[Source][destination]
52+ double nabs = source [ destination ] ;
53+ return nabs ;
54+ }
55+
56+ /// <summary>
57+ ///
58+ /// </summary>
59+ /// <param name="source"></param>
60+ /// <returns></returns>
61+ public Neighbors < T > this [ GraphNode < T > source ] => GetNeighbors ( source ) ;
62+
63+ /// <summary>
64+ ///
65+ /// </summary>
66+ /// <param name="source"></param>
67+ /// <returns></returns>
68+ private Neighbors < T > GetNeighbors ( GraphNode < T > source )
69+ {
70+ return source . Neighbors ;
71+ }
72+
73+ /// <summary>
74+ ///
75+ /// </summary>
76+ /// <param name="node"></param>
77+ /// <returns></returns>
78+ internal bool Remove ( T node )
79+ {
80+ //check the node in lookup table
81+ if ( node == null && ! _lookupTable . Contains ( node ) )
82+ return false ;
83+
84+ // first remove the node from the nodeset
85+ var nodeToRemove = _nodeSet . Get ( node ) ;
86+
87+ // node wasn't found
88+ if ( nodeToRemove == null )
89+ return false ;
90+
91+ var danglingNeighbors = nodeToRemove . Neighbors . Where ( nab => nab . Weight == 0 ) . ToDictionary ( nab => nab . GraphNode ) ;
92+
93+ // otherwise, the node was found
94+ bool status = _nodeSet . Remove ( nodeToRemove ) ;
95+
96+ // enumerate through each node in the nodeSet, removing edges to this node
97+ // if its neighbor is dangling node then
98+ // we remove the neighbor but if its neighbor is not dengling then then preserve it in graph.
99+ // if we not want forest.
100+
101+ return status ;
102+ }
103+
104+ /// <summary>
105+ ///
106+ /// </summary>
107+ internal List < GraphNode < T > > DanglingNodes
108+ {
109+ get
110+ {
111+ List < GraphNode < T > > _danglinNodes = new List < GraphNode < T > > ( ) ;
112+ foreach ( var node in this . OutDegree )
113+ {
114+ if ( node . Value == 0 )
115+ _danglinNodes . Add ( node . Key ) ;
116+ }
117+
118+ return _danglinNodes ;
119+ }
120+ }
121+
122+ internal bool Contains ( T value )
123+ {
124+ return _nodeSet . FindByValue ( value ) != null ;
125+ }
126+
127+ public IEnumerator < GraphNode < T > > GetEnumerator ( )
128+ {
129+ return ( IEnumerator < GraphNode < T > > ) _nodeSet . GetEnumerator ( ) ;
130+ }
131+
132+ IEnumerator IEnumerable . GetEnumerator ( )
133+ {
134+ return GetEnumerator ( ) ;
135+ }
136+
137+ public List < GraphNode < T > > Nodes
138+ {
139+ get
140+ {
141+ return _nodeSet . ToList ;
142+ }
143+ }
144+
145+ public bool IsEmpty
146+ {
147+ get
148+ {
149+ return this . Count > 0 ? false : true ;
150+ }
151+ }
152+
153+ public int Count
154+ {
155+ get { return _nodeSet . Count ; }
156+ }
157+
158+ public Dictionary < GraphNode < T > , double > OutDegree
159+ {
160+ get
161+ {
162+ if ( this . IsEmpty )
163+ return null ;
164+ else
165+ return GetOutDegree ( ) ;
166+ }
167+ }
168+
169+ public abstract bool IsDirected { get ; }
170+
171+ private Dictionary < GraphNode < T > , double > GetOutDegree ( )
172+ {
173+ Dictionary < GraphNode < T > , double > outDegree = new Dictionary < GraphNode < T > , double > ( ) ;
174+
175+ //build graph outdegree dictionary
176+ foreach ( GraphNode < T > node in this )
177+ outDegree . Add ( node , node . OutDegree ) ;
178+
179+ return outDegree ;
180+ }
181+
182+ internal GraphNode < T > FindByValue ( T value )
183+ {
184+ GraphNode < T > node = null ;
185+ node = this . _nodeSet . FindByValue ( value ) ;
186+
187+ return node ;
188+ }
189+
190+ /// <summary>
191+ ///
192+ /// </summary>
193+ /// <param name="value"></param>
194+ /// <returns></returns>
195+ protected GraphNode < T > Add ( T value )
196+ {
197+ if ( value == null )
198+ return null ;
199+ try
200+ {
201+ //first check the value in _lookup table
202+ if ( _lookupTable . Contains ( value ) )
203+ {
204+ var lookup = _lookupTable . Get ( value ) ;
205+ return lookup ;
206+ }
207+
208+ GraphNode < T > node = new GraphNode < T > ( ) ;
209+ node . Value = value ;
210+ _lookupTable . Add ( value , node ) ;
211+ _nodeSet . Add ( node ) ;
212+ return node ;
213+ }
214+ catch ( Exception ex )
215+ {
216+ return null ;
217+ }
218+ }
219+
220+ /// <summary>
221+ ///
222+ /// </summary>
223+ /// <param name="source"></param>
224+ /// <param name="destination"></param>
225+ /// <param name="weight"></param>
226+ protected void AddEdges ( GraphNode < T > source , GraphNode < T > destination , double weight = 1.0 )
227+ {
228+ if ( source == null || destination == null )
229+ return ;
230+
231+ var lookup = _lookupTable . Get ( source . Value ) ;
232+
233+ if ( lookup == null || ! ( source == lookup ) )
234+ {
235+ _lookupTable . Add ( source . Value , source ) ;
236+ _nodeSet . Add ( source ) ;
237+ }
238+ if ( ! ( destination == _lookupTable . Get ( destination . Value ) ) )
239+ {
240+ _lookupTable . Add ( destination . Value , destination ) ;
241+ _nodeSet . Add ( destination ) ;
242+ }
243+
244+ source . Neighbors . Add ( destination as GraphNode < T > , weight ) ;
245+ }
246+
247+ /// <summary>
248+ ///
249+ /// </summary>
250+ /// <param name="source"></param>
251+ /// <param name="destination"></param>
252+ /// <param name="weight"></param>
253+ protected void AddEdges ( T source , T destination , double weight = 1.0 )
254+ {
255+ if ( source == null || destination == null )
256+ return ;
257+
258+ var gsource = this . Add ( source ) ;
259+ var gdestination = this . Add ( destination ) ;
260+
261+ this . AddEdges ( gsource , gdestination , weight ) ;
262+ }
263+ }
264+ }
0 commit comments