SNAP Library 4.0, Developer Reference  2017-07-27 13:18:06
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
triad.h
Go to the documentation of this file.
1 #ifndef TRIAD_H
2 #define TRIAD_H
3 
4 namespace TSnap {
5 
7 // Triads and clustering coefficient
8 
10 
12 template <class PGraph> double GetClustCf(const PGraph& Graph, int SampleNodes=-1);
14 
18 template <class PGraph> double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int SampleNodes=-1);
20 
24 template <class PGraph> double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int64& ClosedTriadsX, int64& OpenTriadsX, int SampleNodes=-1);
26 
28 template <class PGraph> double GetNodeClustCf(const PGraph& Graph, const int& NId);
30 
34 template <class PGraph> void GetNodeClustCf(const PGraph& Graph, TIntFltH& NIdCCfH);
35 
37 
41 template <class PGraph> int64 GetTriads(const PGraph& Graph, int SampleNodes=-1);
43 
46 template <class PGraph> int64 GetTriads(const PGraph& Graph, int64& ClosedTriadsX, int64& OpenTriadsX, int SampleNodes);
48 
52 template <class PGraph> void GetTriads(const PGraph& Graph, TIntTrV& NIdCOTriadV, int SampleNodes=-1);
54 
57 template <class PGraph> int GetTriadEdges(const PGraph& Graph, int SampleEdges=-1);
58 
60 
64 template <class PGraph> int GetNodeTriads(const PGraph& Graph, const int& NId);
66 
72 template <class PGraph> int GetNodeTriads(const PGraph& Graph, const int& NId, int& ClosedNTriadsX, int& OpenNTriadsX);
74 
82 template <class PGraph>
83 int GetNodeTriads(const PGraph& Graph, const int& NId, const TIntSet& GroupSet, int& InGroupEdgesX, int& InOutGroupEdgesX, int& OutGroupEdgesX);
85 
87 template <class PGraph> void GetTriadParticip(const PGraph& Graph, TIntPrV& TriadCntV);
88 
90 template<class PGraph> int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2);
92 template<class PGraph> int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV);
94 template<class PGraph> int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2);
96 
98 template<class PGraph> int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV);
100 template<class PGraph> int64 GetTriangleCnt(const PGraph& Graph);
102 template<class PGraph> void MergeNbrs(TIntV& NeighbourV, const typename PGraph::TObj::TNodeI& NI);
103 
105 template <class PGraph> void GetUniqueNbrV(const PGraph& Graph, const int& NId, TIntV& NbrV);
106 
108 int GetCommon(TIntV& A, TIntV& B);
109 
111 // Implementation
112 
113 template <class PGraph> double GetClustCf(const PGraph& Graph, int SampleNodes) {
114  TIntTrV NIdCOTriadV;
115  GetTriads(Graph, NIdCOTriadV, SampleNodes);
116  if (NIdCOTriadV.Empty()) { return 0.0; }
117  double SumCcf = 0.0;
118  for (int i = 0; i < NIdCOTriadV.Len(); i++) {
119  const double OpenCnt = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3();
120  if (OpenCnt > 0) {
121  SumCcf += NIdCOTriadV[i].Val2() / OpenCnt; }
122  }
123  IAssert(SumCcf>=0);
124  return SumCcf / double(NIdCOTriadV.Len());
125 }
126 
127 template <class PGraph> double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int SampleNodes) {
128  TIntTrV NIdCOTriadV;
129  GetTriads(Graph, NIdCOTriadV, SampleNodes);
130  THash<TInt, TFltPr> DegSumCnt;
131  double SumCcf = 0.0;
132  for (int i = 0; i < NIdCOTriadV.Len(); i++) {
133  const int D = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3();
134  const double Ccf = D!=0 ? NIdCOTriadV[i].Val2() / double(D) : 0.0;
135  TFltPr& SumCnt = DegSumCnt.AddDat(Graph->GetNI(NIdCOTriadV[i].Val1).GetDeg());
136  SumCnt.Val1 += Ccf;
137  SumCnt.Val2 += 1;
138  SumCcf += Ccf;
139  }
140  // get average clustering coefficient for each degree
141  DegToCCfV.Gen(DegSumCnt.Len(), 0);
142  for (int d = 0; d < DegSumCnt.Len(); d++) {
143  DegToCCfV.Add(TFltPr(DegSumCnt.GetKey(d).Val, double(DegSumCnt[d].Val1()/DegSumCnt[d].Val2())));
144  }
145  DegToCCfV.Sort();
146  return SumCcf / double(NIdCOTriadV.Len());
147 }
148 
149 template <class PGraph>
150 double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int64& ClosedTriads, int64& OpenTriads, int SampleNodes) {
151  TIntTrV NIdCOTriadV;
152  GetTriads(Graph, NIdCOTriadV, SampleNodes);
153  THash<TInt, TFltPr> DegSumCnt;
154  double SumCcf = 0.0;
155  int64 closedTriads = 0;
156  int64 openTriads = 0;
157  for (int i = 0; i < NIdCOTriadV.Len(); i++) {
158  const int D = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3();
159  const double Ccf = D!=0 ? NIdCOTriadV[i].Val2() / double(D) : 0.0;
160  closedTriads += NIdCOTriadV[i].Val2;
161  openTriads += NIdCOTriadV[i].Val3;
162  TFltPr& SumCnt = DegSumCnt.AddDat(Graph->GetNI(NIdCOTriadV[i].Val1).GetDeg());
163  SumCnt.Val1 += Ccf;
164  SumCnt.Val2 += 1;
165  SumCcf += Ccf;
166  }
167  // get average clustering coefficient for each degree
168  DegToCCfV.Gen(DegSumCnt.Len(), 0);
169  for (int d = 0; d < DegSumCnt.Len(); d++) {
170  DegToCCfV.Add(TFltPr(DegSumCnt.GetKey(d).Val, DegSumCnt[d].Val1()/DegSumCnt[d].Val2()));
171  }
172  //if(closedTriads/3 > (uint64) TInt::Mx) { WarnNotify(TStr::Fmt("[%s line %d] %g closed triads.\n", __FILE__, __LINE__, float(closedTriads/3)).CStr()); }
173  //if(openTriads > (uint64) TInt::Mx) { WarnNotify(TStr::Fmt("[%s line %d] %g open triads.\n", __FILE__, __LINE__, float(openTriads/3)).CStr()); }
174  ClosedTriads = closedTriads/int64(3); // each triad is counted 3 times
175  OpenTriads = openTriads;
176  DegToCCfV.Sort();
177  return SumCcf / double(NIdCOTriadV.Len());
178 }
179 
180 template <class PGraph>
181 double GetNodeClustCf(const PGraph& Graph, const int& NId) {
182  int Open, Closed;
183  GetNodeTriads(Graph, NId, Open, Closed);
184  //const double Deg = Graph->GetNI(NId).GetDeg();
185  return (Open+Closed)==0 ? 0 : double(Open)/double(Open+Closed);
186 }
187 
188 template <class PGraph>
189 void GetNodeClustCf(const PGraph& Graph, TIntFltH& NIdCCfH) {
190  TIntTrV NIdCOTriadV;
191  GetTriads(Graph, NIdCOTriadV);
192  NIdCCfH.Clr(false);
193  for (int i = 0; i < NIdCOTriadV.Len(); i++) {
194  const int D = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3();
195  const double CCf = D!=0 ? NIdCOTriadV[i].Val2() / double(D) : 0.0;
196  NIdCCfH.AddDat(NIdCOTriadV[i].Val1, CCf);
197  }
198 }
199 
200 template <class PGraph>
201 int64 GetTriads(const PGraph& Graph, int SampleNodes) {
202  int64 OpenTriads, ClosedTriads;
203  return GetTriads(Graph, ClosedTriads, OpenTriads, SampleNodes);
204 }
205 
206 template <class PGraph>
207 int64 GetTriads(const PGraph& Graph, int64& ClosedTriads, int64& OpenTriads, int SampleNodes) {
208  TIntTrV NIdCOTriadV;
209  GetTriads(Graph, NIdCOTriadV, SampleNodes);
210  uint64 closedTriads = 0;
211  uint64 openTriads = 0;
212  for (int i = 0; i < NIdCOTriadV.Len(); i++) {
213  closedTriads += NIdCOTriadV[i].Val2;
214  openTriads += NIdCOTriadV[i].Val3;
215  }
216  //IAssert(closedTriads/3 < (uint64) TInt::Mx);
217  //IAssert(openTriads < (uint64) TInt::Mx);
218  ClosedTriads = int64(closedTriads/3); // each triad is counted 3 times
219  OpenTriads = int64(openTriads);
220  return ClosedTriads;
221 }
222 
223 // Function pretends that the graph is undirected (count unique connected triples of nodes)
224 // This implementation is slower, it uses hash tables directly
225 template <class PGraph>
226 void GetTriads_v0(const PGraph& Graph, TIntTrV& NIdCOTriadV, int SampleNodes) {
227  const bool IsDir = Graph->HasFlag(gfDirected);
228  TIntSet NbrH;
229  TIntV NIdV;
230  TRnd Rnd(0);
231 
232  Graph->GetNIdV(NIdV);
233  NIdV.Shuffle(Rnd);
234  if (SampleNodes == -1) {
235  SampleNodes = Graph->GetNodes(); }
236  NIdCOTriadV.Clr(false);
237  NIdCOTriadV.Reserve(SampleNodes);
238  for (int node = 0; node < SampleNodes; node++) {
239  typename PGraph::TObj::TNodeI NI = Graph->GetNI(NIdV[node]);
240  if (NI.GetDeg() < 2) {
241  NIdCOTriadV.Add(TIntTr(NI.GetId(), 0, 0)); // zero triangles
242  continue;
243  }
244  // find neighborhood
245  NbrH.Clr(false);
246  for (int e = 0; e < NI.GetOutDeg(); e++) {
247  if (NI.GetOutNId(e) != NI.GetId()) {
248  NbrH.AddKey(NI.GetOutNId(e)); }
249  }
250  if (IsDir) {
251  for (int e = 0; e < NI.GetInDeg(); e++) {
252  if (NI.GetInNId(e) != NI.GetId()) {
253  NbrH.AddKey(NI.GetInNId(e)); }
254  }
255  }
256  // count connected neighbors
257  int OpenCnt=0, CloseCnt=0;
258  for (int srcNbr = 0; srcNbr < NbrH.Len(); srcNbr++) {
259  const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NbrH.GetKey(srcNbr));
260  for (int dstNbr = srcNbr+1; dstNbr < NbrH.Len(); dstNbr++) {
261  const int dstNId = NbrH.GetKey(dstNbr);
262  if (SrcNode.IsNbrNId(dstNId)) { CloseCnt++; } // is edge
263  else { OpenCnt++; }
264  }
265  }
266  IAssert(2*(OpenCnt+CloseCnt) == NbrH.Len()*(NbrH.Len()-1));
267  NIdCOTriadV.Add(TIntTr(NI.GetId(), CloseCnt, OpenCnt));
268  }
269 }
270 
271 // Function pretends that the graph is undirected (count unique connected triples of nodes)
272 // This implementation is faster, it converts hash tables to vectors
273 template <class PGraph>
274 void GetTriads(const PGraph& Graph, TIntTrV& NIdCOTriadV, int SampleNodes) {
275  const bool IsDir = Graph->HasFlag(gfDirected);
276  TIntSet NbrH;
277  TIntV NIdV;
278  //TRnd Rnd(0);
279  TRnd Rnd(1);
280  int NNodes;
281  TIntV Nbrs;
282  int NId;
283 
284  int64 hcount;
285 
286  hcount = 0;
287 
288  NNodes = Graph->GetNodes();
289  Graph->GetNIdV(NIdV);
290  NIdV.Shuffle(Rnd);
291  if (SampleNodes == -1) {
292  SampleNodes = NNodes;
293  }
294 
295  int MxId = -1;
296  for (int i = 0; i < NNodes; i++) {
297  if (NIdV[i] > MxId) {
298  MxId = NIdV[i];
299  }
300  }
301 
302  TVec<TIntV> NbrV(MxId + 1);
303 
304  if (IsDir) {
305  // get in and out neighbors
306  for (int node = 0; node < NNodes; node++) {
307  int NId = NIdV[node];
308  NbrV[NId] = TIntV();
309  GetUniqueNbrV(Graph, NId, NbrV[NId]);
310  }
311  } else {
312  // get only out neighbors
313  for (int node = 0; node < NNodes; node++) {
314  int NId = NIdV[node];
315  typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
316  NbrV[NId] = TIntV();
317  NbrV[NId].Reserve(NI.GetOutDeg());
318  NbrV[NId].Reduce(0);
319  for (int i = 0; i < NI.GetOutDeg(); i++) {
320  NbrV[NId].Add(NI.GetOutNId(i));
321  }
322  }
323  }
324 
325  NIdCOTriadV.Clr(false);
326  NIdCOTriadV.Reserve(SampleNodes);
327  for (int node = 0; node < SampleNodes; node++) {
328  typename PGraph::TObj::TNodeI NI = Graph->GetNI(NIdV[node]);
329  int NLen;
330 
331  NId = NI.GetId();
332  hcount++;
333  if (NI.GetDeg() < 2) {
334  NIdCOTriadV.Add(TIntTr(NId, 0, 0)); // zero triangles
335  continue;
336  }
337 
338  Nbrs = NbrV[NId];
339  NLen = Nbrs.Len();
340 
341  // count connected neighbors
342  int OpenCnt1 = 0, CloseCnt1 = 0;
343  for (int srcNbr = 0; srcNbr < NLen; srcNbr++) {
344  int Count = GetCommon(NbrV[NbrV[NId][srcNbr]],Nbrs);
345  CloseCnt1 += Count;
346  }
347  CloseCnt1 /= 2;
348  OpenCnt1 = (NLen*(NLen-1))/2 - CloseCnt1;
349  NIdCOTriadV.Add(TIntTr(NId, CloseCnt1, OpenCnt1));
350  }
351 }
352 
353 #if 0
354 // OP RS 2016/08/25, this is an alternative implementation of GetTriangleCnt()
355 template<class PGraph>
356 int64 CountTriangles(const PGraph& Graph) {
358  TIntV MapV;
359 
360  int ind = 0;
361  for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
362  H.AddDat(NI.GetId(), ind);
363  MapV.Add(NI.GetId());
364  ind += 1;
365  }
366 
367  TVec<TIntV> HigherDegNbrV(ind);
368 
369 #ifdef USE_OPENMP
370 #pragma omp parallel for schedule(dynamic)
371 #endif
372  for (int i = 0; i < ind; i++) {
373  typename PGraph::TObj::TNodeI NI = Graph->GetNI(MapV[i]);
374  TIntV NbrV;
375 
376  MergeNbrs<PGraph>(NbrV, NI);
377 
378  TIntV V;
379  for (int j = 0; j < NbrV.Len(); j++) {
380  TInt Vert = NbrV[j];
381  TInt Deg = Graph->GetNI(Vert).GetDeg();
382  if (Deg > NI.GetDeg() ||
383  (Deg == NI.GetDeg() && Vert > NI.GetId())) {
384  V.Add(Vert);
385  }
386  }
387 
388  HigherDegNbrV[i] = V;
389 
390  }
391 
392  int64 cnt = 0;
393 #ifdef USE_OPENMP
394 #pragma omp parallel for schedule(dynamic) reduction(+:cnt)
395 #endif
396  for (int i = 0; i < HigherDegNbrV.Len(); i++) {
397  for (int j = 0; j < HigherDegNbrV[i].Len(); j++) {
398  TInt NbrInd = H.GetDat(HigherDegNbrV[i][j]);
399 
400  int64 num = GetCommon(HigherDegNbrV[i], HigherDegNbrV[NbrInd]);
401  cnt += num;
402  }
403  }
404 
405  return cnt;
406 }
407 #endif
408 
409 template<class PGraph>
410 int64 GetTriangleCnt(const PGraph& Graph) {
411  const int NNodes = Graph->GetNodes();
412 
413  TIntV MapV(NNodes);
415  NV.Reduce(0);
416 
417  int MxId = -1;
418  int ind = 0;
419  for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
420  NV.Add(NI);
421  int Id = NI.GetId();
422  if (Id > MxId) {
423  MxId = Id;
424  }
425  MapV[ind] = Id;
426  ind++;
427  }
428 
429  TIntV IndV(MxId+1);
430 
431  for (int j = 0; j < NNodes; j++) {
432  IndV[MapV[j]] = j;
433  }
434 
435  ind = MapV.Len();
436 
437  TVec<TIntV> HigherDegNbrV(ind);
438 
439  for (int i = 0; i < ind; i++) {
440  HigherDegNbrV[i] = TVec<TInt>();
441  HigherDegNbrV[i].Reserve(NV[i].GetDeg());
442  HigherDegNbrV[i].Reduce(0);
443  }
444 
445 #ifdef USE_OPENMP
446 #pragma omp parallel for schedule(dynamic)
447 #endif
448  for (int i = 0; i < ind; i++) {
449  typename PGraph::TObj::TNodeI NI = NV[i];
450  MergeNbrs<PGraph>(HigherDegNbrV[i], NI);
451 
452  int k = 0;
453  for (int j = 0; j < HigherDegNbrV[i].Len(); j++) {
454  TInt Vert = HigherDegNbrV[i][j];
455  TInt Deg = NV[IndV[Vert]].GetDeg();
456  if (Deg > NI.GetDeg() ||
457  (Deg == NI.GetDeg() && Vert > NI.GetId())) {
458  HigherDegNbrV[i][k] = Vert;
459  k++;
460  }
461  }
462  HigherDegNbrV[i].Reduce(k);
463  }
464 
465  int64 cnt = 0;
466 #ifdef USE_OPENMP
467 #pragma omp parallel for schedule(dynamic) reduction(+:cnt)
468 #endif
469  for (int i = 0; i < HigherDegNbrV.Len(); i++) {
470  for (int j = 0; j < HigherDegNbrV[i].Len(); j++) {
471  TInt NbrInd = IndV[HigherDegNbrV[i][j]];
472 
473  int64 num = GetCommon(HigherDegNbrV[i], HigherDegNbrV[NbrInd]);
474  cnt += num;
475  }
476  }
477 
478  return cnt;
479 }
480 
481 template<class PGraph>
482 void MergeNbrs(TIntV& NeighbourV, const typename PGraph::TObj::TNodeI& NI) {
483  int j = 0;
484  int k = 0;
485  int prev = -1;
486  int indeg = NI.GetInDeg();
487  int outdeg = NI.GetOutDeg();
488  if (indeg > 0 && outdeg > 0) {
489  int v1 = NI.GetInNId(j);
490  int v2 = NI.GetOutNId(k);
491  while (1) {
492  if (v1 <= v2) {
493  if (prev != v1) {
494  NeighbourV.Add(v1);
495  prev = v1;
496  }
497  j += 1;
498  if (j >= indeg) {
499  break;
500  }
501  v1 = NI.GetInNId(j);
502  } else {
503  if (prev != v2) {
504  NeighbourV.Add(v2);
505  prev = v2;
506  }
507  k += 1;
508  if (k >= outdeg) {
509  break;
510  }
511  v2 = NI.GetOutNId(k);
512  }
513  }
514  }
515  while (j < indeg) {
516  int v = NI.GetInNId(j);
517  if (prev != v) {
518  NeighbourV.Add(v);
519  prev = v;
520  }
521  j += 1;
522  }
523  while (k < outdeg) {
524  int v = NI.GetOutNId(k);
525  if (prev != v) {
526  NeighbourV.Add(v);
527  prev = v;
528  }
529  k += 1;
530  }
531 }
532 
533 // Count the number of edges that participate in at least one triad
534 template <class PGraph>
535 int GetTriadEdges(const PGraph& Graph, int SampleEdges) {
536  const bool IsDir = Graph->HasFlag(gfDirected);
537  TIntSet NbrH;
538  int TriadEdges = 0;
539  for(typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
540  NbrH.Clr(false);
541  for (int e = 0; e < NI.GetOutDeg(); e++) {
542  if (NI.GetOutNId(e) != NI.GetId()) {
543  NbrH.AddKey(NI.GetOutNId(e)); }
544  }
545  if (IsDir) {
546  for (int e = 0; e < NI.GetInDeg(); e++) {
547  if (NI.GetInNId(e) != NI.GetId()) {
548  NbrH.AddKey(NI.GetInNId(e)); }
549  }
550  }
551  for (int e = 0; e < NI.GetOutDeg(); e++) {
552  if (!IsDir && NI.GetId()<NI.GetOutNId(e)) { continue; } // for undirected graphs count each edge only once
553  const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NI.GetOutNId(e));
554  bool Triad=false;
555  for (int e1 = 0; e1 < SrcNode.GetOutDeg(); e1++) {
556  if (NbrH.IsKey(SrcNode.GetOutNId(e1))) { Triad=true; break; }
557  }
558  if (IsDir && ! Triad) {
559  for (int e1 = 0; e1 < SrcNode.GetInDeg(); e1++) {
560  if (NbrH.IsKey(SrcNode.GetInNId(e1))) { Triad=true; break; }
561  }
562  }
563  if (Triad) { TriadEdges++; }
564  }
565  }
566  return TriadEdges;
567 }
568 
569 // Returns number of undirected triads a node participates in
570 template <class PGraph>
571 int GetNodeTriads(const PGraph& Graph, const int& NId) {
572  int ClosedTriads=0, OpenTriads=0;
573  return GetNodeTriads(Graph, NId, ClosedTriads, OpenTriads);
574 }
575 
576 // Return number of undirected triads a node participates in
577 template <class PGraph>
578 int GetNodeTriads(const PGraph& Graph, const int& NId, int& ClosedTriads, int& OpenTriads) {
579  const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
580  ClosedTriads=0; OpenTriads=0;
581  if (NI.GetDeg() < 2) { return 0; }
582  // find neighborhood
583  TIntSet NbrSet(NI.GetDeg());
584  for (int e = 0; e < NI.GetOutDeg(); e++) {
585  if (NI.GetOutNId(e) != NI.GetId()) { // exclude self edges
586  NbrSet.AddKey(NI.GetOutNId(e)); }
587  }
588  if (Graph->HasFlag(gfDirected)) {
589  for (int e = 0; e < NI.GetInDeg(); e++) {
590  if (NI.GetInNId(e) != NI.GetId()) { // exclude self edges
591  NbrSet.AddKey(NI.GetInNId(e)); }
592  }
593  }
594  // count connected neighbors
595  for (int srcNbr = 0; srcNbr < NbrSet.Len(); srcNbr++) {
596  const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NbrSet.GetKey(srcNbr));
597  for (int dstNbr = srcNbr+1; dstNbr < NbrSet.Len(); dstNbr++) {
598  const int dstNId = NbrSet.GetKey(dstNbr);
599  if (SrcNode.IsNbrNId(dstNId)) { ClosedTriads++; }
600  else { OpenTriads++; }
601  }
602  }
603  return ClosedTriads;
604 }
605 
606 // Node NId and a subset of its neighbors GroupSet
607 // InGroupEdges ... triads (NId, g1, g2), where g1 and g2 are in GroupSet
608 // InOutGroupEdges ... triads (NId, g1, o1), where g1 in GroupSet and o1 not in GroupSet
609 // OutGroupEdges ... triads (NId, o1, o2), where o1 and o2 are not in GroupSet
610 template <class PGraph>
611 int GetNodeTriads(const PGraph& Graph, const int& NId, const TIntSet& GroupSet, int& InGroupEdges, int& InOutGroupEdges, int& OutGroupEdges) {
612  const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
613  const bool IsDir = Graph->HasFlag(gfDirected);
614  InGroupEdges=0; InOutGroupEdges=0; OutGroupEdges=0;
615  if (NI.GetDeg() < 2) { return 0; }
616  // find neighborhood
617  TIntSet NbrSet(NI.GetDeg());
618  for (int e = 0; e < NI.GetOutDeg(); e++) {
619  if (NI.GetOutNId(e) != NI.GetId()) { // exclude self edges
620  NbrSet.AddKey(NI.GetOutNId(e)); }
621  }
622  if (IsDir) {
623  for (int e = 0; e < NI.GetInDeg(); e++) {
624  if (NI.GetInNId(e) != NI.GetId()) {
625  NbrSet.AddKey(NI.GetInNId(e)); }
626  }
627  }
628  // count connected neighbors
629  for (int srcNbr = 0; srcNbr < NbrSet.Len(); srcNbr++) {
630  const int NbrId = NbrSet.GetKey(srcNbr);
631  const bool NbrIn = GroupSet.IsKey(NbrId);
632  const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NbrId);
633  for (int dstNbr = srcNbr+1; dstNbr < NbrSet.Len(); dstNbr++) {
634  const int DstNId = NbrSet.GetKey(dstNbr);
635  if (SrcNode.IsNbrNId(DstNId)) { // triad (NId, NbrId, DstNid)
636  bool DstIn = GroupSet.IsKey(DstNId);
637  if (NbrIn && DstIn) { InGroupEdges++; }
638  else if (NbrIn || DstIn) { InOutGroupEdges++; }
639  else { OutGroupEdges++; }
640  }
641  }
642  }
643  return InGroupEdges;
644 }
645 
646 // For each node count how many triangles it participates in
647 template <class PGraph>
648 void GetTriadParticip(const PGraph& Graph, TIntPrV& TriadCntV) {
649  TIntH TriadCntH;
650  for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
651  const int Triads = GetNodeTriads(Graph, NI.GetId());
652  TriadCntH.AddDat(Triads) += 1;
653  }
654  TriadCntH.GetKeyDatPrV(TriadCntV);
655  TriadCntV.Sort();
656 }
657 
658 template<class PGraph>
659 int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2) {
660  TIntV NbrV;
661  return GetCmnNbrs(Graph, NId1, NId2, NbrV);
662 }
663 
664 // Get common neighbors between a pair of nodes (undirected)
665 template<class PGraph>
666 int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV) {
667  if (! Graph->IsNode(NId1) || ! Graph->IsNode(NId2)) { NbrV.Clr(false); return 0; }
668  typename PGraph::TObj::TNodeI NI1 = Graph->GetNI(NId1);
669  typename PGraph::TObj::TNodeI NI2 = Graph->GetNI(NId2);
670  NbrV.Clr(false);
671  NbrV.Reserve(TMath::Mn(NI1.GetDeg(), NI2.GetDeg()));
672  TIntSet NSet1(NI1.GetDeg()), NSet2(NI2.GetDeg());
673  for (int i = 0; i < NI1.GetDeg(); i++) {
674  const int nid = NI1.GetNbrNId(i);
675  if (nid!=NId1 && nid!=NId2) {
676  NSet1.AddKey(nid); }
677  }
678  for (int i = 0; i < NI2.GetDeg(); i++) {
679  const int nid = NI2.GetNbrNId(i);
680  if (NSet1.IsKey(nid)) {
681  NSet2.AddKey(nid);
682  }
683  }
684  NSet2.GetKeyV(NbrV);
685  return NbrV.Len();
686 }
687 
688 template<>
689 inline int GetCmnNbrs<PUNGraph>(const PUNGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV) {
690  if (! Graph->IsNode(NId1) || ! Graph->IsNode(NId2)) { NbrV.Clr(false); return 0; }
691  const TUNGraph::TNodeI NI1 = Graph->GetNI(NId1);
692  const TUNGraph::TNodeI NI2 = Graph->GetNI(NId2);
693  int i=0, j=0;
694  NbrV.Clr(false);
695  NbrV.Reserve(TMath::Mn(NI1.GetDeg(), NI2.GetDeg()));
696  while (i < NI1.GetDeg() && j < NI2.GetDeg()) {
697  const int nid = NI1.GetNbrNId(i);
698  while (j < NI2.GetDeg() && NI2.GetNbrNId(j) < nid) { j++; }
699  if (j < NI2.GetDeg() && nid==NI2.GetNbrNId(j) && nid!=NId1 && nid!=NId2) {
700  IAssert(NbrV.Empty() || NbrV.Last() < nid);
701  NbrV.Add(nid);
702  j++;
703  }
704  i++;
705  }
706  return NbrV.Len();
707 }
708 
709 // get number of length 2 directed paths between a pair of nodes
710 // for a pair of nodes (i,j): |{u: (i,u) and (u,j) }|
711 template<class PGraph>
712 int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2) {
713  TIntV NbrV;
714  return GetLen2Paths(Graph, NId1, NId2, NbrV);
715 }
716 
717 // get number of length 2 directed paths between a pair of nodes
718 // for a pair of nodes (i,j): {u: (i,u) and (u,j) }
719 template<class PGraph>
720 int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV) {
721  const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId1);
722  NbrV.Clr(false);
723  NbrV.Reserve(NI.GetOutDeg());
724  for (int e = 0; e < NI.GetOutDeg(); e++) {
725  const typename PGraph::TObj::TNodeI MidNI = Graph->GetNI(NI.GetOutNId(e));
726  if (MidNI.IsOutNId(NId2)) {
727  NbrV.Add(MidNI.GetId());
728  }
729  }
730  return NbrV.Len();
731 }
732 
733 template <class PGraph>
734 void GetUniqueNbrV(const PGraph& Graph, const int& NId, TIntV& NbrV) {
735  typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
736  NbrV.Reserve(NI.GetDeg());
737  NbrV.Reduce(0);
738 
739  int j = 0;
740  int k = 0;
741  int Prev = -1;
742  int InDeg = NI.GetInDeg();
743  int OutDeg = NI.GetOutDeg();
744  if (InDeg > 0 && OutDeg > 0) {
745  int v1 = NI.GetInNId(j);
746  int v2 = NI.GetOutNId(k);
747  while (1) {
748  if (v1 <= v2) {
749  if (Prev != v1) {
750  if (v1 != NId) {
751  NbrV.Add(v1);
752  Prev = v1;
753  }
754  }
755  j += 1;
756  if (j >= InDeg) {
757  break;
758  }
759  v1 = NI.GetInNId(j);
760  } else {
761  if (Prev != v2) {
762  if (v2 != NId) {
763  NbrV.Add(v2);
764  }
765  Prev = v2;
766  }
767  k += 1;
768  if (k >= OutDeg) {
769  break;
770  }
771  v2 = NI.GetOutNId(k);
772  }
773  }
774  }
775  while (j < InDeg) {
776  int v = NI.GetInNId(j);
777  if (Prev != v) {
778  if (v != NId) {
779  NbrV.Add(v);
780  }
781  Prev = v;
782  }
783  j += 1;
784  }
785  while (k < OutDeg) {
786  int v = NI.GetOutNId(k);
787  if (Prev != v) {
788  if (v != NId) {
789  NbrV.Add(v);
790  }
791  Prev = v;
792  }
793  k += 1;
794  }
795 }
796 
797 }; // mamespace TSnap
798 
800 // Node and Edge Network Constraint (by Ron Burt)
801 // works for directed and undirected graphs (but not for multigraphs)
802 template <class PGraph>
804 public:
805  PGraph Graph;
806  THash<TIntPr, TFlt> NodePrCH; // pairs of nodes that have non-zero network constraint
807 public:
808  TNetConstraint(const PGraph& GraphPt, const bool& CalcaAll=true);
809  int Len() const { return NodePrCH.Len(); }
810  double GetC(const int& ConstraintN) const { return NodePrCH[ConstraintN]; }
811  TIntPr GetNodePr(const int& ConstraintN) const { return NodePrCH.GetKey(ConstraintN); }
812  double GetEdgeC(const int& NId1, const int& NId2) const;
813  double GetNodeC(const int& NId) const;
814  void AddConstraint(const int& NId1, const int& NId2);
815  void CalcConstraints();
816  void CalcConstraints(const int& NId);
817  void Dump() const;
818  static void Test();
819 };
820 
821 template <class PGraph>
822 TNetConstraint<PGraph>::TNetConstraint(const PGraph& GraphPt, const bool& CalcaAll) : Graph(GraphPt) {
823  CAssert(! HasGraphFlag(typename PGraph::TObj, gfMultiGraph)); // must not be multigraph
824  if (CalcaAll) {
825  CalcConstraints();
826  }
827 }
828 
829 template <class PGraph>
830 double TNetConstraint<PGraph>::GetEdgeC(const int& NId1, const int& NId2) const {
831  if (NodePrCH.IsKey(TIntPr(NId1, NId2))) {
832  return NodePrCH.GetDat(TIntPr(NId1, NId2)); }
833  else {
834  return 0.0; }
835 }
836 
837 template <class PGraph>
838 double TNetConstraint<PGraph>::GetNodeC(const int& NId) const {
839  typename PGraph::TObj::TNodeI NI1 = Graph->GetNI(NId);
840  if (NI1.GetOutDeg() == 0) { return 0.0; }
841  int KeyId = -1;
842  for (int k = 0; k<NI1.GetOutDeg(); k++) {
843  KeyId = NodePrCH.GetKeyId(TIntPr(NI1.GetId(), NI1.GetOutNId(k)));
844  if (KeyId > -1) { break; }
845  }
846  if (KeyId < 0) { return 0.0; }
847  double Constraint = NodePrCH[KeyId];
848  for (int i = KeyId-1; i >-1 && NodePrCH.GetKey(i).Val1()==NId; i--) {
849  Constraint += NodePrCH[i];
850  }
851  for (int i = KeyId+1; i < NodePrCH.Len() && NodePrCH.GetKey(i).Val1()==NId; i++) {
852  Constraint += NodePrCH[i];
853  }
854  return Constraint;
855 }
856 
857 template <class PGraph>
858 void TNetConstraint<PGraph>::AddConstraint(const int& NId1, const int& NId2) {
859  if (NId1==NId2 || NodePrCH.IsKey(TIntPr(NId1, NId2))) {
860  return;
861  }
862  typename PGraph::TObj::TNodeI NI1 = Graph->GetNI(NId1);
863  double Constraint = 0.0;
864  if (NI1.IsOutNId(NId2)) { // is direct edge
865  Constraint += 1.0/(double) NI1.GetOutDeg();
866  }
867  const double SrcC = 1.0/(double) NI1.GetOutDeg();
868  for (int e = 0; e < NI1.GetOutDeg(); e++) {
869  const int MidNId = NI1.GetOutNId(e);
870  if (MidNId == NId1 || MidNId == NId2) { continue; }
871  const typename PGraph::TObj::TNodeI MidNI = Graph->GetNI(MidNId);
872  if (MidNI.IsOutNId(NId2)) {
873  Constraint += SrcC * (1.0/(double)MidNI.GetOutDeg());
874  }
875  }
876  if (Constraint==0) { return; }
877  Constraint = TMath::Sqr(Constraint);
878  NodePrCH.AddDat(TIntPr(NId1, NId2), Constraint);
879 }
880 
881 template <class PGraph>
883  // add edges
884  for (typename PGraph::TObj::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) {
885  AddConstraint(EI.GetSrcNId(), EI.GetDstNId());
886  AddConstraint(EI.GetDstNId(), EI.GetSrcNId());
887  }
888  // add open triads
889  for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
890  for (int i = 0; i < NI.GetDeg(); i++) {
891  const int NId1 = NI.GetNbrNId(i);
892  for (int j = 0; j < NI.GetDeg(); j++) {
893  const int NId2 = NI.GetNbrNId(j);
894  AddConstraint(NId1, NId2);
895  }
896  }
897  }
898  NodePrCH.SortByKey();
899 }
900 
901 // calculate constraints around a node id
902 template <class PGraph>
904  typename PGraph::TObj::TNodeI StartNI = Graph->GetNI(NId);
905  TIntSet SeenSet;
906  for (int e = 0; e < StartNI.GetOutDeg(); e++) {
907  typename PGraph::TObj::TNodeI MidNI = Graph->GetNI(StartNI.GetOutNId(e));
908  AddConstraint(NId, MidNI.GetId());
909  for (int i = 0; i < MidNI.GetOutDeg(); i++) {
910  const int EndNId = MidNI.GetOutNId(i);
911  if (! SeenSet.IsKey(EndNId)) {
912  AddConstraint(NId, EndNId);
913  SeenSet.AddKey(EndNId);
914  }
915  }
916  }
917 }
918 
919 template <class PGraph>
921  printf("Edge network constraint: (%d, %d)\n", Graph->GetNodes(), Graph->GetEdges());
922  for (int e = 0; e < NodePrCH.Len(); e++) {
923  printf(" %4d %4d : %f\n", NodePrCH.GetKey(e).Val1(), NodePrCH.GetKey(e).Val2(), NodePrCH[e].Val);
924  }
925  printf("\n");
926 }
927 
928 // example from page 56 of Structural Holes by Ronald S. Burt
929 // (http://www.amazon.com/Structural-Holes-Social-Structure-Competition/dp/0674843711)
930 template <class PGraph>
932  PUNGraph G = TUNGraph::New();
933  G->AddNode(0); G->AddNode(1); G->AddNode(2); G->AddNode(3);
934  G->AddNode(4); G->AddNode(5); G->AddNode(6);
935  G->AddEdge(0,1); G->AddEdge(0,2); G->AddEdge(0,3); G->AddEdge(0,4); G->AddEdge(0,5); G->AddEdge(0,6);
936  G->AddEdge(1,2); G->AddEdge(1,5); G->AddEdge(1,6);
937  G->AddEdge(2,4);
938  TNetConstraint<PUNGraph> NetConstraint(G, true);
939  // NetConstraint.CalcConstraints(0);
940  NetConstraint.Dump();
941  printf("middle node network constraint: %f\n", NetConstraint.GetNodeC(0));
942 }
943 
944 #endif // TRIAD_H
945 
void Clr(const bool &DoDel=true, const int &NoDelLim=-1)
Definition: shash.h:1243
#define IAssert(Cond)
Definition: bd.h:262
static const T & Mn(const T &LVal, const T &RVal)
Definition: xmath.h:36
void GetUniqueNbrV(const PGraph &Graph, const int &NId, TIntV &NbrV)
Returns sorted vector NbrV containing unique in or out neighbors of node NId in graph Graph...
Definition: triad.h:734
TPair< TInt, TInt > TIntPr
Definition: ds.h:83
int64 GetTriads(const PGraph &Graph, int64 &ClosedTriads, int64 &OpenTriads, int SampleNodes=-1)
Computes the number of Closed and Open triads.
Definition: triad.h:207
void CalcConstraints()
Definition: triad.h:882
Definition: dt.h:11
int64 GetTriangleCnt(const PGraph &Graph)
Returns the number of triangles in graph Graph.
Definition: triad.h:410
int Val
Definition: dt.h:1136
double GetNodeClustCf(const PGraph &Graph, const int &NId)
Returns clustering coefficient of a particular node.
Definition: triad.h:181
static void Test()
Definition: triad.h:931
int GetLen2Paths(const PGraph &Graph, const int &NId1, const int &NId2)
Returns the number of length 2 directed paths between a pair of nodes NId1, NId2 (NId1 –> U –> NId2...
Definition: triad.h:712
int AddNode(int NId=-1)
Adds a node of ID NId to the graph.
Definition: graph.cpp:8
TSizeTy Len() const
Returns the number of elements in the vector.
Definition: ds.h:575
Node iterator. Only forward iteration (operator++) is supported.
Definition: graph.h:68
PGraph Graph
Definition: triad.h:805
int GetCmnNbrs< PUNGraph >(const PUNGraph &Graph, const int &NId1, const int &NId2, TIntV &NbrV)
Definition: triad.h:689
void MergeNbrs(TIntV &NeighbourV, const typename PGraph::TObj::TNodeI &NI)
Merges neighbors by removing duplicates and produces one sorted vector of neighbors.
Definition: triad.h:482
const TDat & GetDat(const TKey &Key) const
Definition: hash.h:262
static double Sqr(const double &x)
Definition: xmath.h:12
TNetConstraint(const PGraph &GraphPt, const bool &CalcaAll=true)
Definition: triad.h:822
void Reduce(const TSizeTy &_Vals=-1)
Reduces the vector's length to _Vals elements, which must be less than the current length...
Definition: ds.h:556
bool IsKey(const TKey &Key) const
Definition: shash.h:1148
const TKey & GetKey(const int &KeyId) const
Definition: shash.h:1141
bool Empty() const
Tests whether the vector is empty.
Definition: ds.h:570
have explicit edges (multigraph): TNEGraph, TNodeEdgeNet
Definition: gbase.h:14
int GetDeg() const
Returns degree of the current node.
Definition: graph.h:90
void Clr(const bool &DoDel=true, const TSizeTy &NoDelLim=-1)
Clears the contents of the vector.
Definition: ds.h:1022
void Sort(const bool &Asc=true)
Sorts the elements of the vector.
Definition: ds.h:1318
#define HasGraphFlag(TGraph, Flag)
For quick testing of the properties of the graph/network object (see TGraphFlag). ...
Definition: gbase.h:41
unsigned long long uint64
Definition: bd.h:38
void GetTriads_v0(const PGraph &Graph, TIntTrV &NIdCOTriadV, int SampleNodes)
Definition: triad.h:226
void AddConstraint(const int &NId1, const int &NId2)
Definition: triad.h:858
double GetNodeC(const int &NId) const
Definition: triad.h:838
static PUNGraph New()
Static constructor that returns a pointer to the graph. Call: PUNGraph Graph = TUNGraph::New().
Definition: graph.h:172
int AddKey(const TKey &Key)
Definition: shash.h:1254
int GetNodeTriads(const PGraph &Graph, const int &NId)
Returns the number of undirected triads a node NId participates in.
Definition: triad.h:571
double GetC(const int &ConstraintN) const
Definition: triad.h:810
TPair< TFlt, TFlt > TFltPr
Definition: ds.h:99
int AddEdge(const int &SrcNId, const int &DstNId)
Adds an edge between node IDs SrcNId and DstNId to the graph.
Definition: graph.cpp:92
void Dump() const
Definition: triad.h:920
Definition: dt.h:1134
directed graph (TNGraph, TNEGraph), else graph is undirected TUNGraph
Definition: gbase.h:13
double GetEdgeC(const int &NId1, const int &NId2) const
Definition: triad.h:830
#define CAssert(Cond)
Definition: bd.h:302
int Len() const
Definition: shash.h:1121
long long int64
Definition: bd.h:27
int GetTriadEdges(const PGraph &Graph, int SampleEdges=-1)
Counts the number of edges that participate in at least one triad.
Definition: triad.h:535
int GetCommon(TIntV &A, TIntV &B)
Returns the number of common elements in two sorted TInt vectors.
Definition: triad.cpp:59
void Shuffle(TRnd &Rnd)
Randomly shuffles the elements of the vector.
Definition: ds.h:1335
void GetTriadParticip(const PGraph &Graph, TIntPrV &TriadCntV)
Triangle Participation Ratio: For each node counts how many triangles it participates in and then ret...
Definition: triad.h:648
void GetKeyDatPrV(TVec< TPair< TKey, TDat > > &KeyDatPrV) const
Definition: hash.h:500
double GetClustCf(const PGraph &Graph, int SampleNodes=-1)
Computes the average clustering coefficient as defined in Watts and Strogatz, Collective dynamics of ...
Definition: triad.h:113
TVal1 Val1
Definition: ds.h:34
int GetNbrNId(const int &NodeN) const
Returns ID of NodeN-th neighboring node.
Definition: graph.h:111
TVec< TInt > TIntV
Definition: ds.h:1594
TVal2 Val2
Definition: ds.h:35
void Clr(const bool &DoDel=true, const int &NoDelLim=-1, const bool &ResetDat=true)
Definition: hash.h:361
Definition: bd.h:196
TIntPr GetNodePr(const int &ConstraintN) const
Definition: triad.h:811
TTriple< TInt, TInt, TInt > TIntTr
Definition: ds.h:171
void Gen(const TSizeTy &_Vals)
Constructs a vector (an array) of _Vals elements.
Definition: ds.h:523
void Reserve(const TSizeTy &_MxVals)
Reserves enough memory for the vector to store _MxVals elements.
Definition: ds.h:543
THash< TIntPr, TFlt > NodePrCH
Definition: triad.h:806
TSizeTy Add()
Adds a new element at the end of the vector, after its current last element.
Definition: ds.h:602
int Len() const
Definition: hash.h:228
TDat & AddDat(const TKey &Key)
Definition: hash.h:238
int GetCmnNbrs(const PGraph &Graph, const int &NId1, const int &NId2)
Returns a number of shared neighbors between a pair of nodes NId1 and NId2.
Definition: triad.h:659
const TKey & GetKey(const int &KeyId) const
Definition: hash.h:252
int Len() const
Definition: triad.h:809
Vector is a sequence TVal objects representing an array that can change in size.
Definition: ds.h:430